diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..86faffa --- /dev/null +++ b/LICENSE @@ -0,0 +1,42 @@ +End-User License Agreement (EULA) of Security Lite + +This End-User License Agreement ("EULA") is a legal agreement between you and Mathias Reker. + +This EULA agreement governs your acquisition and use of our Security Lite software ("Software") directly from Mathias Reker or indirectly through a Mathias Reker authorized reseller or distributor (a "Reseller"). + +Please read this EULA agreement carefully before completing the installation process and using the Security Lite software. It provides a license to use the Security Lite software and contains warranty information and liability disclaimers. + +If you are entering into this EULA agreement on behalf of a company or other legal entity, you represent that you have the authority to bind such entity and its affiliates to these terms and conditions. If you do not have such authority or if you do not agree with the terms and conditions of this EULA agreement, do not install or use the Software, and you must not accept this EULA agreement. + +This EULA agreement shall apply only to the Software supplied by Mathias Reker herewith regardless of whether other software is referred to or described herein. The terms also apply to any Mathias Reker updates, supplements, Internet-based services, and support services for the Software, unless other terms accompany those items on delivery. If so, those terms apply. + +This Software is provided by Mathias Reker "as is" and any express or implied warranties, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose are disclaimed. In no event shall Mathias Reker be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage. + +License Grant + +The Software you bought is sold with a single license, you can use it on one website only. You can install it on a test shop, but this must be the URL of the final website and in accordance with the terms of this EULA agreement. + +You are permitted to install the Security Lite software on a server under your control. You are responsible for ensuring your server meets the minimum requirements of the Security Lite software. + +You are not permitted to: + + Reproduce, copy, distribute, resell or otherwise use the Software for any commercial purpose + Allow any third party to use the Software on behalf of or for the benefit of any third party + Use the Software in any way which breaches any applicable local, national or internationallaw + use the Software for any purpose that Mathias Reker considers is a breach of this EULA agreement. + +Intellectual Property and Ownership + +Mathias Reker shall at all times retain ownership of the Software as originally downloaded by you and all subsequent downloads of the Software by you. The Software (and the copyright, and other intellectual property rights of whatever nature in the Software, including any modifications made thereto) are and shall remain the property of Mathias Reker. + +Mathias Reker reserves the right to grant licenses to use the Software to third parties. + +Termination + +This EULA agreement is effective from the date you first use the Software and shall continue until terminated. You may terminate it at any time upon written notice to Mathias Reker. + +It will also terminate immediately if you fail to comply with any term of this EULA agreement. Upon such termination, the licenses granted by this EULA agreement will immediately terminate and you agree to stop all access and use of the Software. The provisions that by their nature continue and survive will survive any termination of this EULA agreement. + +Governing Law + +This EULA agreement, and any dispute arising out of or in connection with this EULA agreement, shall be governed by and construed in accordance with the laws of Denmark. diff --git a/backup/database/index.php b/backup/database/index.php deleted file mode 100644 index f002f69..0000000 --- a/backup/database/index.php +++ /dev/null @@ -1,25 +0,0 @@ -active) { - $securitypro->cron = 1; - $securitypro->backupDatabase(); -} diff --git a/composer.json b/composer.json deleted file mode 100644 index 9785ed6..0000000 --- a/composer.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "Security Lite", - "require": { - "php": ">=5.6", - "mlocati/ip-lib": "^1.9", - "nelexa/zip": "^3.3", - "robthree/twofactorauth": "^1.7" - }, - "config": { - "preferred-install": "dist", - "prepend-autoloader": false, - "platform": { - "php": "5.6" - }, - "sort-packages": true - }, - "type": "prestashop-module", - "author": "Mathias Reker", - "license": "Commercial license", - "description": "This module increase the overall security of your PrestaShop website.", - "keywords": [ - "security", "protect" - ], - "homepage": "https://addons.prestashop.com/en/website-security-access/44413-security-pro-all-in-one.html" -} diff --git a/controllers/admin/AdminSecurityLiteController.php b/controllers/admin/AdminSecurityLiteController.php index 148b4a1..11cde27 100644 --- a/controllers/admin/AdminSecurityLiteController.php +++ b/controllers/admin/AdminSecurityLiteController.php @@ -1,24 +1,25 @@ link->getAdminLink('AdminModules', true) . '&configure=securitylite'); + return \Tools::redirectAdmin(\Context::getContext()->link->getAdminLink('AdminModules', true) . '&configure=securitylite&tab_reset=1'); } } diff --git a/controllers/admin/index.php b/controllers/admin/index.php index f002f69..fa24a5a 100644 --- a/controllers/admin/index.php +++ b/controllers/admin/index.php @@ -1,16 +1,13 @@ ajax = 1; + + // Check token + if (!Tools::isPHPCLI()) { + if ($this->module->encrypt('securitylite/cron') !== Tools::getValue('token') || !Module::isInstalled('securitylite')) { + $response = $this->module->l('Forbidden call.', 'cron'); + $this->getResponse($response); + } + } + + // Try to run cronjob + try { + $response = $this->runCronjob(); + } catch (Exception $e) { + if (true === (bool) Configuration::get('PRO_DEBUG_CRON')) { + $response = $e; + } else { + $response = $this->module->l('Something went wrong.', 'cron'); + } + } finally { + $this->getResponse($response); + } + } + + /** + * Write to log and display response + * + * @param string $response + */ + private function getResponse($response) + { + $name = Tools::getValue('name'); + + $this->module->logCron($name, $response); + + $this->ajaxDie($response); + } + + /** + * Run cronjob + * + * @return string + */ + private function runCronjob() + { + // Check if module is activated + if (true === (bool) $this->module->active) { + $this->module->cron = 1; + + // Run the cronjob + $name = Tools::getValue('name'); + switch ($name) { + case 'DeleteOldCarts': + $this->module->deleteOldCarts(); + break; + case 'BackupDatabase': + $this->module->backupDatabase(); + break; + default: + return $this->module->l('Cronjob does not exist.', 'cron'); + } + } else { + return $this->module->l('securitylite is not active.', 'cron'); + } + + return $this->module->l('Success!', 'cron'); + } +} diff --git a/controllers/front/index.php b/controllers/front/index.php new file mode 100644 index 0000000..fa24a5a --- /dev/null +++ b/controllers/front/index.php @@ -0,0 +1,22 @@ +ajax = 1; + + // Check token + if (!Tools::isPHPCLI()) { + if ($this->module->encrypt('securitylite/unlock') !== Tools::getValue('token') || !Module::isInstalled('securitylite')) { + $response = $this->module->l('Forbidden call.', 'unlock'); + $this->ajaxDie($response); + } + } + + // Try to run cronjob + try { + $response = $this->runCronjob(); + } catch (Exception $e) { + if (true === (bool) Configuration::get('PRO_DEBUG_CRON')) { + $response = $e; + } else { + $response = $this->module->l('Something went wrong.', 'unlock'); + } + } finally { + $this->ajaxDie($response); + } + } + + /** + * Run cronjob + * + * @return string + */ + private function runCronjob() + { + // Check if module is activated + if (true === (bool) $this->module->active) { + $this->module->cron = 1; + } else { + return $this->module->l('securitylite is not active.', 'unlock'); + } + + return $this->module->l('Success!', 'unlock'); + } +} diff --git a/controllers/index.php b/controllers/index.php index f002f69..fa24a5a 100644 --- a/controllers/index.php +++ b/controllers/index.php @@ -1,16 +1,13 @@ name = 'securitylite'; $this->tab = 'administration'; - $this->version = '4.5.1'; + $this->version = '5.0.0'; $this->author = 'Mathias Reker'; $this->module_key = '71a0dda36237f958642fb61a15ccc695'; $this->need_instance = 0; @@ -56,38 +63,97 @@ public function __construct() $this->description = $this->l('This module increases the overall security of your PrestaShop website.'); $this->confirmUninstall = $this->l('Are you sure you want to uninstall?'); - $this->proFeature = '' . $this->l('PRO FEATURE') . ' '; + $this->proFeature = '' . $this->l('PRO FEATURE') . ' '; } /** * Install module, database table and set default values. + * + * @return bool */ public function install() { - $this->installTab(); if (Shop::isFeatureActive()) { Shop::setContext(Shop::CONTEXT_ALL); } - include _PS_MODULE_DIR_ . 'securitylite/sql/install.php'; + $sql = []; + + $sql[] = 'CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'securitylite` ( + `id_securitylite` int(11) NOT NULL, + `email` varchar(64) NOT NULL, + `access_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `ip` varchar(64) NOT NULL, + `banned` int(1) NOT NULL + ) ENGINE=' . _MYSQL_ENGINE_ . ' DEFAULT CHARSET=UTF8; + ALTER TABLE `' . _DB_PREFIX_ . 'securitylite` + ADD PRIMARY KEY (`id_securitylite`); + ALTER TABLE `' . _DB_PREFIX_ . 'securitylite` + MODIFY `id_securitylite` int(11) NOT NULL AUTO_INCREMENT;'; + + $sql[] = 'CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'securitylite_tfa` ( + `enabled` int(1) NOT NULL, + `secret` varchar(32) NOT NULL + ) ENGINE=' . _MYSQL_ENGINE_ . ' DEFAULT CHARSET=UTF8; + '; + + foreach ($sql as $query) { + if (false === Db::getInstance()->execute($query)) { + return false; + } + } + + $this->installTab(); Configuration::updateValue('LITE_BAN_TIME', 30); Configuration::updateValue('LITE_MAX_RETRY', 5); Configuration::updateValue('LITE_FIND_TIME', 10); Configuration::updateValue('LITE_ADMIN_DIRECTORY_NAME', \basename(_PS_ADMIN_DIR_)); - Configuration::updateValue('LITE_ANTI_MAX_REQUESTS', 50); - Configuration::updateValue('LITE_ANTI_REQ_TIMEOUT', 5); - Configuration::updateValue('LITE_ANTI_BAN_TIME', 600); + Configuration::updateValue('LITE_DELETE_OLD_CARTS_DAYS', 14); Configuration::updateValue('LITE_BACKUP_DB_SAVED', 7); - Configuration::updateValue('LITE_BACKUP_FILE_SAVED', 1); - Configuration::updateValue('LITE_BLOCK_FILE_UPLOAD_BACK_OFFICE', 'exe,com,bat,vb,vbs,wsf,pif,php'); + Configuration::updateValue('LITE_ADVANCED_MAINTENANCE_MODE_COMPANY', Configuration::get('PS_SHOP_NAME')); + + $address = []; + if (true === (bool) Configuration::get('PS_SHOP_ADDR1')) { + $address[] = Configuration::get('PS_SHOP_ADDR1'); + } + if (true === (bool) Configuration::get('PS_SHOP_ADDR2')) { + $address[] = Configuration::get('PS_SHOP_ADDR2'); + } + if (true === (bool) Configuration::get('PS_SHOP_CODE')) { + $address[] = Configuration::get('PS_SHOP_CODE'); + } + if (true === (bool) Configuration::get('PS_SHOP_CITY')) { + $address[] = Configuration::get('PS_SHOP_CITY'); + } + + if (!empty($address)) { + Configuration::updateValue('LITE_ADVANCED_MAINTENANCE_MODE_ADDRESS', \implode(', ', $address)); + } + + if (true === (bool) Configuration::get('PS_SHOP_PHONE')) { + Configuration::updateValue('LITE_ADVANCED_MAINTENANCE_MODE_PHONE', Configuration::get('PS_SHOP_PHONE')); + } + + Configuration::updateValue('LITE_ADVANCED_MAINTENANCE_MODE_EMAIL', Configuration::get('PS_SHOP_EMAIL')); + Configuration::updateValue('LITE_ADVANCED_MAINTENANCE_MODE_FACEBOOK', '#'); + Configuration::updateValue('LITE_ADVANCED_MAINTENANCE_MODE_TWITTER', '#'); + Configuration::updateValue('LITE_ADVANCED_MAINTENANCE_MODE_INSTAGRAM', '#'); + Configuration::updateValue('LITE_ADVANCED_MAINTENANCE_MODE_PINTEREST', '#'); + Configuration::updateValue('LITE_ADVANCED_MAINTENANCE_MODE_YOUTUBE', '#'); + Configuration::updateValue('LITE_ADVANCED_MAINTENANCE_MODE_COPYRIGHT', true); + Configuration::updateValue('LITE_ADVANCED_MAINTENANCE_MODE_LOGO_PATH', _PS_IMG_ . Configuration::get('PS_LOGO')); + Configuration::updateValue('LITE_ADVANCED_MAINTENANCE_MODE_LOGO', true); + Configuration::updateValue('LITE_ANTI_FRAUD_UNIT', 'km'); + Configuration::updateValue('LITE_ANTI_FRAUD_HOOK', 'left'); $hooks = [ 'displayBackOfficeTop', 'displayHeader', + 'displayMaintenance', ]; - if (!parent::install() || !$this->registerHook($hooks)) { + if (false === parent::install() || false === $this->registerHook($hooks)) { return false; } @@ -96,36 +162,159 @@ public function install() /** * Uninstall the module, reverse any changes and delete database table. + * + * @return bool */ public function uninstall() { + // Force default group + if (Shop::isFeatureActive()) { + Shop::setContext(Shop::CONTEXT_ALL); + } + $this->uninstallTab(); - include _PS_MODULE_DIR_ . 'securitylite/sql/uninstall.php'; + + $sql = []; + + $sql[] = 'DROP TABLE IF EXISTS `' . _DB_PREFIX_ . 'securitylite`'; + $sql[] = 'DROP TABLE IF EXISTS `' . _DB_PREFIX_ . 'securitylite_tfa`'; + + foreach ($sql as $query) { + if (false === Db::getInstance()->execute($query)) { + return false; + } + } + + $this->removeHtaccessContent(); + + $logs = [ + self::LOG_PAGE_NOT_FOUND, + self::LOG_FIREWALL, + self::LOG_BRUTE_FORCE, + self::LOG_MALWARE_SCAN, + self::LOG_FILE_CHANGES, + self::LOG_CRONJOB, + ]; + + foreach ($logs as $log) { + Tools::deleteFile($this->getLogFile($log)); + } foreach (\array_keys($this->getConfigFormValues()) as $key) { Configuration::deleteByName($key); } + $this->clearCacheSecuritylite(false); + return parent::uninstall(); } /** - * Get secret TwoFactorAuth. + * Display advanced maintenance. * - * @return string + * @param array $params */ - public function getSecret() + public function hookDisplayMaintenance($params) { - $tfa = new RobThree\Auth\TwoFactorAuth(Configuration::get('PS_SHOP_NAME'), 6, 30, 'sha1'); - if (empty($this->getTwoFactorAuthDB('secret'))) { - Db::getInstance()->insert('securitylite_tfa', [ - 'enabled' => '0', - 'secret' => '', - ]); - $this->updateTwoFactorAuthDB('secret', $tfa->createSecret(160, true)); + if (false === (bool) Configuration::get('LITE_ADVANCED_MAINTENANCE_MODE')) { + return; } - return $this->getTwoFactorAuthDB('secret'); + \http_response_code(503); + + $lang = $this->context->language->iso_code; + $company = Configuration::get('LITE_ADVANCED_MAINTENANCE_MODE_COMPANY'); + $address = Configuration::get('LITE_ADVANCED_MAINTENANCE_MODE_ADDRESS'); + $phone = Configuration::get('LITE_ADVANCED_MAINTENANCE_MODE_PHONE'); + $email = Configuration::get('LITE_ADVANCED_MAINTENANCE_MODE_EMAIL'); + $facebook = Configuration::get('LITE_ADVANCED_MAINTENANCE_MODE_FACEBOOK'); + $twitter = Configuration::get('LITE_ADVANCED_MAINTENANCE_MODE_TWITTER'); + $instagram = Configuration::get('LITE_ADVANCED_MAINTENANCE_MODE_INSTAGRAM'); + $pinterest = Configuration::get('LITE_ADVANCED_MAINTENANCE_MODE_PINTEREST'); + $youtube = Configuration::get('LITE_ADVANCED_MAINTENANCE_MODE_YOUTUBE'); + $shopName = Configuration::get('PS_SHOP_NAME'); + $logoPath = Configuration::get('LITE_ADVANCED_MAINTENANCE_MODE_LOGO_PATH'); + $copyright = Configuration::get('LITE_ADVANCED_MAINTENANCE_MODE_COPYRIGHT'); + $showLogo = Configuration::get('LITE_ADVANCED_MAINTENANCE_MODE_LOGO'); + $message = $this->l('Our webserver is currently down for scheduled maintenance. We expect to be back very soon. Apologies for the inconvenience!'); + $title = $this->l('Coming soon'); + + $logoOutput = null; + if (true === (bool) $showLogo) { + if (false === (bool) $logoPath) { + $logoPath = _PS_IMG_ . Configuration::get('PS_LOGO'); + } + $logoOutput = ''; + } + $imgCover = $this->_path . 'views/img/cover.jpg'; + + $copyrightOutput = null; + if (true === (bool) $copyright) { + if (true === (bool) $company) { + $copyrightOutput = '

© ' . \date('Y') . ' ' . $company . '

'; + } + } + $addressArray = \array_filter([ + $company, + $address, + $phone, + $email, + ]); + + if (!empty($addressArray)) { + $addressOutput = '

' . \implode(' | ', $addressArray) . '

'; + } else { + $addressOutput = null; + } + + if (false !== (bool) $facebook) { + $facebookLink = ''; + } else { + $facebookLink = null; + } + + if (false !== (bool) $twitter) { + $twitterLink = ''; + } else { + $twitterLink = null; + } + + if (false !== (bool) $instagram) { + $instagramLink = ''; + } else { + $instagramLink = null; + } + + if (false !== (bool) $pinterest) { + $pinterestLink = ''; + } else { + $pinterestLink = null; + } + + if (false !== (bool) $youtube) { + $youtubeLink = ''; + } else { + $youtubeLink = null; + } + + $socialMediaArray = \array_filter([ + $facebookLink, + $twitterLink, + $instagramLink, + $pinterestLink, + $youtubeLink, + ]); + + $socialMediaOutput = \implode('', $socialMediaArray); + + $bootstrap = ''; + + $fontAwesome = ''; + + $style = ''; + + echo ' ' . $fontAwesome . $bootstrap . $this->getFavicon() . ' ' . $shopName . ' ' . $this->l('is in maintenance mode') . ' ' . $style . '
' . $logoOutput . '

' . $title . '

' . $message . '

' . $addressOutput . $copyrightOutput . '
'; + exit; } /** @@ -135,9 +324,41 @@ public function getSecret() */ public function getContent() { - $cron = []; - $out = "'; + + if (true === (bool) $this->context->language->is_rtl) { + $out[] = ''; // RTL + } else { + $out[] = ''; // LTR + } + + // Hide confirmation message after 10 sec. + $out[] = ''; + + $out[] = ''; + + $out[] = '

' . $this->l('Security Lite') . '

'; + + $out[] = ""; + function addMyIp(id) { + if ($(id).val() !== '') { + var comma = ','; + } else { + var comma = ''; + } + $(function() { + var pass = '" . $clientIp . "'; + var text = $(id); + text.val(text.val() + comma + pass); + }); + } + function copyToClipboard(text) { + var dummy = document.createElement('textarea'); + document.body.appendChild(dummy); + dummy.value = text; + dummy.select(); + document.execCommand('copy'); + document.body.removeChild(dummy); + } +"; // todo + + // Add Version tab + if (\defined('_TB_VERSION_')) { + $cmsName = 'Thirty bees'; + $cmsVersion = _TB_VERSION_; + } else { + $cmsName = 'PrestaShop'; + $cmsVersion = _PS_VERSION_; + } + + if (true === (bool) Configuration::get('PS_DISABLE_NON_NATIVE_MODULE')) { + $out[] = $this->displayError($this->l('You must enable non PrestaShop modules at') . ' ' . $this->generateLink($this->getAdminLink('AdminPerformance', true), $this->l('\'Advanced Parameters\' > \'Performance\'')) . '.'); + } + + $moduleVersion = Module::getInstanceByName('securitylite')->version; + + if (true === (bool) Tools::isSubmit('tab_reset')) { + $out[] = ''; + } + + $out[] = ''; + + $localBackups = [ + [ + 'BackupDatabaseDownload', + self::DIR_BACKUP_DATABASE, + ], + ]; + + foreach ($localBackups as $localBackup) { + if (true === (bool) Tools::isSubmit($localBackup[0])) { + $dir = _PS_MODULE_DIR_ . $this->name . $localBackup[1]; + $file = Tools::getValue('file'); - // Validate input: permissions - if (true === (bool) Tools::isSubmit('btnPermissions')) { - $this->chmodFileDirectory(_PS_ROOT_DIR_); // Change permissions + $this->downloadFile($dir . $file); + } + } - $out .= $this->displayConfirmation($this->l('Permissions updated!')); + $deleteFile = false; + + $deleteLocalBackups = [ + [ + 'BackupDatabaseDelete', + self::DIR_BACKUP_DATABASE, + ], + ]; - if (!empty($this->error_dir)) { - $out .= $this->displayWarning($this->error_dir); + foreach ($deleteLocalBackups as $deleteLocalBackup) { + if (true === (bool) Tools::isSubmit($deleteLocalBackup[0])) { + $dir = _PS_MODULE_DIR_ . $this->name . $deleteLocalBackup[1]; + $file = Tools::getValue('file'); + Tools::deleteFile($dir . $file); + $deleteFile = true; } + } - if (!empty($this->error_file)) { - $out .= $this->displayWarning($this->error_file); + if (true === $deleteFile) { + if (\file_exists($file)) { + $out[] = $this->displayConfirmation($this->l('File') . ' ' . $dir . $file . ' ' . $this->l('has been deleted.')); } } - // Download translations - if (true === (bool) Tools::isSubmit('transDownload')) { - $this->exportTranslation(); + // Clear cache + if (true === (bool) Tools::isSubmit('clear_cache')) { + $this->clearCacheSecuritylite(true); + + $out[] = $this->displayConfirmation($this->l('All caches cleared successfully.')); } - // Submit save - if (true === (bool) Tools::isSubmit('submitSecurityLiteModule')) { - $this->postProcess(); + // Logs + if (true === (bool) Tools::isSubmit('log')) { + $logs = [ + 'PageNotFound' => self::LOG_PAGE_NOT_FOUND, + 'Firewall' => self::LOG_FIREWALL, + 'BruteForce' => self::LOG_BRUTE_FORCE, + 'MalwareScan' => self::LOG_MALWARE_SCAN, + 'FileChanges' => self::LOG_FILE_CHANGES, + 'Cronjob' => self::LOG_CRONJOB, + ]; + + foreach ($logs as $key => $log) { + if ($key === Tools::getValue('log')) { + // Clear + if ('1' === Tools::getValue('clear_log')) { + $out[] = $this->displayConfirmation($this->l('File') . ' ' . $log . ' ' . $this->l('has been cleared.')); + \file_put_contents($this->getLogFile($log), ''); + } + + // Download + if ('1' === Tools::getValue('download_log')) { + \clearstatcache(); + if (0 === \filesize($this->getLogFile($log))) { + $out[] = $this->displayConfirmation($this->l('File') . ' ' . $log . ' ' . $this->l('is empty. Nothing to download.')); + } else { + $this->downloadFile($this->getLogFile($log)); + } + } + } + } + } - $out .= $this->displayConfirmation($this->l('Settings updated!')); + // Btn: Port Scanner + if (true === (bool) Tools::isSubmit('PortScannerAnalyze')) { + $this->portScanner(); - // Validate Fail2ban - if (true === (bool) Configuration::get('LITE_FAIL2BAN')) { - if (!(int) Configuration::get('LITE_BAN_TIME') > 0) { - $out .= $this->displayWarning('"' . $this->l('Ban time') . '"' . $this->l('must be greater than 0.')); - Configuration::updateValue('LITE_FAIL2BAN', false); + $portScannerReportPath = _PS_MODULE_DIR_ . self::REPORT_PORT_SCANNER; + if (\file_exists($portScannerReportPath)) { + $this->downloadFile($portScannerReportPath, true); + } else { + $out[] = $this->displayWarning($this->l('Something went wrong.')); + } + } + + // Btn: Port Scanner + if (true === (bool) Tools::isSubmit('RblCheckerAnalyze')) { + $serverIp = $_SERVER['SERVER_ADDR']; + if (empty($serverIp) || '::1' === $serverIp || '127.0.0.1' === $serverIp) { + $out[] = $this->displayWarning($this->l('You cannot generate this report while you are on localhost.')); + } else { + $this->generateReportRbl(); + + $rblCheckerReportPath = _PS_MODULE_DIR_ . self::REPORT_RBL_CHECKER; + if (\file_exists($rblCheckerReportPath)) { + $this->downloadFile($rblCheckerReportPath, true); + } else { + $out[] = $this->displayWarning($this->l('Something went wrong.')); } + } + } + + // Validate input: Permissions + if (true === (bool) Tools::isSubmit('PermissionsAnalyze')) { + if (true === $this->isWindowsOs()) { + $out[] = $this->displayConfirmation($this->l('Windows is not using file permissions. Nothing to fix!')); + } else { + $permissionsReportPath = _PS_MODULE_DIR_ . self::REPORT_PERMISSIONS; + + $this->chmodFileFolderAnalyze(_PS_ROOT_DIR_ . \DIRECTORY_SEPARATOR); - if (!(int) Configuration::get('LITE_FIND_TIME') > 0) { - $out .= $this->displayWarning('"' . $this->l('Request timeout') . '"' . $this->l('must be greater than 0.')); - Configuration::updateValue('LITE_FAIL2BAN', false); + // Delete file if empty + \clearstatcache(); + if (0 === \filesize($permissionsReportPath)) { + Tools::deleteFile($permissionsReportPath); } - if (!(int) Configuration::get('LITE_MAX_RETRY') > 0) { - $out .= $this->displayWarning('"' . $this->l('Max retry') . '"' . $this->l('must be greater than 0.')); - Configuration::updateValue('LITE_FAIL2BAN', false); + // Download + if (\file_exists($permissionsReportPath)) { + $this->downloadFile($permissionsReportPath, true); + } else { + $out[] = $this->displayConfirmation($this->l('The report is empty. Everything is good!')); } } } + // Validate and create Index + if (true === (bool) Tools::isSubmit('CreateIndexAnalyze')) { + $dirsIndex = [ + _PS_MODULE_DIR_, + _PS_ALL_THEMES_DIR_, + ]; + + foreach ($dirsIndex as $dirIndex) { + $this->addIndexRecursively($dirIndex, true); + } + + $createIndexPath = _PS_MODULE_DIR_ . self::REPORT_CREATE_INDEX; + + if (\file_exists($createIndexPath)) { + $this->downloadFile($createIndexPath, true); + } else { + $out[] = $this->displayConfirmation($this->l('The report is empty. Everything is good!')); + } + } + + // Submit save + if (true === (bool) Tools::isSubmit('SubmitSecurityLiteModule')) { + $this->postProcess(); + + $out[] = $this->displayConfirmation($this->l('Settings updated!')); + } + + if ((int) Configuration::get('LITE_DELETE_OLD_CARTS_DAYS') < 2) { + Configuration::updateValue('LITE_DELETE_OLD_CARTS_DAYS', 2); + } + // Validate IP activated setting - if (Tools::isEmpty(Configuration::get('LITE_BAN_IP')) && false === Configuration::get('LITE_BAN_IP')) { - Configuration::updateValue('LITE_BAN_IP_ACTIVATE', false); + if (false === (bool) Configuration::get('LITE_BAN_IP')) { + Configuration::updateValue('LITE_BAN_IP_ACTIVATE', 0); } // Validate UA activated setting if (false === (bool) Configuration::get('LITE_BLOCK_USER_AGENT')) { - Configuration::updateValue('LITE_BLOCK_USER_AGENT_ACTIVATE', false); - } - - // Validate file upload activated setting - if (false === (bool) Configuration::get('LITE_BLOCK_FILE_UPLOAD_BACK_OFFICE')) { - Configuration::updateValue('LITE_BLOCK_FILE_UPLOAD_BACK_OFFICE_ACTIVATE', false); + Configuration::updateValue('LITE_BLOCK_USER_AGENT_ACTIVATE', 0); } // Validate IP addresses $fieldIps = [ 'LITE_BAN_IP', + 'LITE_FIREWALL_WHITELIST', + 'LITE_WHITELIST_IPS', 'LITE_WHITELIST_PROTECT_CONTENT', ]; @@ -222,367 +595,148 @@ function add_field() { $this->validateIps($fieldIp); } - // Validate user agents and whitelists + // Validate user agents and other lists $fieldStrings = [ 'LITE_BLOCK_USER_AGENT', ]; foreach ($fieldStrings as $fieldString) { - $this->validateCommaSeperatedString($fieldString); + $this->validateCommaSeparatedString($fieldString); } - // Files that should be deleted - $files = [ - '0x666.php', - '1.rar', - '1.sql', - '1.tar', - '1.tar.gz', - '1.tgz', - '1.zip', - 'anonsha1a0.php', - 'backup.bz2', - 'backup.gz', - 'backup.rar', - 'backup.sql', - 'backup.sql.zip', - 'backup.tar', - 'backup.tar.gz', - 'backup.tgz', - 'backup.zip', - 'backup/backup.bz2', - 'backup/backup.gz', - 'backup/backup.rar', - 'backup/backup.tar', - 'backup/backup.tar.gz', - 'backup/backup.tgz', - 'backup/backup.zip', - 'bak.sql', - 'data.sql', - 'database.sql', - 'db_backup.sql', - 'db_backup.sql.gz', - 'docs/CHANGELOG.txt', - 'docs/readme_de.txt', - 'docs/readme_en.txt', - 'docs/readme_es.txt', - 'docs/readme_fr.txt', - 'docs/readme_it.txt', - 'dump.rar', - 'dump.sql', - 'dump.sql.gz', - 'dump.sql.tgz', - 'dump.tar', - 'dump.tar.gz', - 'dump.tgz', - 'dump.zip', - 'efi.php', - 'example.7z', - 'example.gz', - 'example.rar', - 'example.sql', - 'example.sql.gz', - 'example.tar', - 'example.tar.gz', - 'example.tgz', - 'example.zip', - 'f.php', - 'home.rar', - 'home.tar', - 'home.tar.gz', - 'home.tgz', - 'home.zip', - 'htdocs.tar', - 'htdocs.tar.gz', - 'htdocs.zip', - 'htodcs.rar', - 'info.php', - 'localhost.sql', - 'phpinfo.php', - 'phppsinfo.php', - 'public_html.rar', - 'public_html.tar', - 'public_html.tar.gz', - 'public_html.tgz', - 'public_html.zip', - 'README.md', - 'site.rar', - 'site.tar', - 'site.tar.gz', - 'site.tgz', - 'site.zip', - 'sql.sql', - 'sql.txt', - 'upload.rar', - 'upload.zip', - 'web.rar', - 'web.tar', - 'web.tar.gz', - 'web.zip', - 'www.7z', - 'www.gz', - 'www.rar', - 'www.sql', - 'www.sql.gz', - 'www.tar', - 'www.tar.bz2', - 'www.tar.gz', - 'www.tgz', - 'www.zip', - 'XsamXadoo_Bot.php', - 'XsamXadoo_Bot_All.php', - 'XsamXadoo_deface.php', - 'Xsam_Xadoo.html', - 'zjsjuddzjw.php', - '_db_.sql', - '_DB_.sql.zip', - '_DB_.tar.gz', - ]; - - $checkedFiles = []; + if (true === (bool) Tools::isSubmit('RemoveFilesAnalyze')) { + $elements = \array_merge($this->getFilesRoot(), $this->checkFilesCVE20179841(), $this->getFilePathExt(_PS_MODULE_DIR_), $this->getFilePathExt(_PS_ROOT_DIR_)); + if (!empty($elements)) { + $reportPath = _PS_MODULE_DIR_ . self::REPORT_REMOVE_FILES; + \file_put_contents($reportPath, \implode(\PHP_EOL, $elements), \FILE_APPEND | \LOCK_EX); - foreach ($files as $file) { - $dir = _PS_ROOT_DIR_ . \DIRECTORY_SEPARATOR . $file; - if (\file_exists($dir)) { - $checkedFiles[] = $dir; + $this->downloadFile($reportPath, true); + } else { + $out[] = $this->displayConfirmation($this->l('The report is empty. Everything is good!')); } } - $elements = \array_merge($checkedFiles, $this->checkFilesCVE20179841()); + Configuration::updateValue('LITE_ADMIN_DIRECTORY_NAME', \basename(_PS_ADMIN_DIR_)); - if (!empty($elements)) { - $show = true; - } else { - $show = false; - } + // Empty password + Configuration::updateValue('LITE_PASSWORD_GENERATOR', null); - // Btn files - if ((bool) Tools::isSubmit('btnFiles')) { - if (!empty($elements)) { - foreach ($this->checkFilesCVE20179841() as $checkedDir) { - if (\is_dir($checkedDir)) { - Tools::deleteDirectory($checkedDir); - } - } - foreach ($checkedFiles as $checkedFile) { - Tools::deleteFile($checkedFile); - } - $show = false; - $out .= $this->displayConfirmation($this->l('Files successfully removed!')); - } - } + $out[] = $this->displayInformation($this->l('You are using Security Lite. Some features are locked in this version. To unlock all features, you must upgrade to Security Pro. You can buy it from here') . ': ' . $this->generateLink('https://addons.prestashop.com/en/website-security-access/44413-security-pro-all-in-one.html', 'https://addons.prestashop.com/en/website-security-access/44413-security-pro-all-in-one.html')); - if ('localhost' === $_SERVER['HTTP_HOST']) { - $hostName = 'https://google.com'; - } else { - $hostName = $this->getBaseURL(); - } - $orignalParse = \parse_url($hostName, \PHP_URL_HOST); - $get = \stream_context_create( - [ - 'ssl' => [ - 'capture_peer_cert' => true, - ], - ] - ); - $read = \stream_socket_client( - 'ssl://' . $orignalParse . ':443', - $errno, - $errstr, - 30, - \STREAM_CLIENT_CONNECT, - $get - ); - $cert = \stream_context_get_params($read); - $certInfo = \openssl_x509_parse( - $cert['options']['ssl']['peer_certificate'] - ); + // Load JS + $this->context->controller->addJS($this->_path . 'views/js/menu.js'); + $this->context->controller->addJS($this->_path . 'views/js/secure-random-password.js'); - switch ($certInfo['version']) { - case 1: - $tlsVersion = 'TLS 1.1'; - break; - case 2: - $tlsVersion = 'TLS 1.2'; - break; - case 3: - $tlsVersion = 'TLS 1.3'; - break; + // Reset URL + $url = $this->getAdminLink('AdminModules', true) . '&configure=securitylite'; + $parseUrl = \parse_url($url); + $parseUrlPath = $parseUrl['path']; + $parseUrlQuery = $parseUrl['query']; + $finalUrl = $parseUrlPath . '?' . $parseUrlQuery; + $resetUrl = ''; - default: - $tlsVersion = $this->l('Unknown'); + // Return the output + return \implode('', $out) . $this->renderForm() . $resetUrl; + } + + /** + * Hook stuff in front office header. + * + * @param array $params + * + * @return string + */ + public function hookDisplayHeader($params) + { + // Disable browser features with javascript + $this->protectContent(); + + // Load firewall rules + $this->getFirewall(); + + // Disable contact form + if (true === (bool) Configuration::get('LITE_DISABLE_CONTACT_FORM')) { + if ($this->context->controller instanceof ContactController) { + \Tools::redirect('pagenotfound'); + } + $this->context->controller->addCSS($this->_path . '/views/css/disable-contact-form.css'); } - $lang = $this->context->language->iso_code; + $out = []; - switch ($lang) { - case 'fr': - $trans = 'fr/contactez-nous'; - break; - case 'es': - $trans = 'es/contacte-con-nosotros'; - break; - case 'de': - $trans = 'de/contact-us'; - break; - case 'it': - $trans = 'it/contact-us'; - break; - case 'nl': - $trans = 'nl/contact-us'; - break; - case 'pl': - $trans = 'pl/contact-us'; - break; - case 'pt': - $trans = 'pt/contact-us'; - break; - case 'ru': - $trans = 'ru/contact-us'; - break; - - default: - $trans = 'en/contact-us'; - } - - $contactUrl = 'https://addons.prestashop.com/' . $trans . '?id_product=44413'; - - // Assign variables to smarty - $this->context->smarty->assign([ - 'currentUrl' => $this->context->link->getAdminLink('AdminModules', true) . '&configure=securitylite', - 'shopUrl' => $hostName, - 'elements' => $elements, - 'show' => $show, - 'getVarified' => $certInfo['issuer']['O'], - 'sslEnabled' => (bool) Configuration::get('PS_SSL_ENABLED'), - 'getIssuer' => $certInfo['issuer']['CN'], - 'expirationDate' => \date('Y-m-d', ($certInfo['validTo_time_t'])), - 'diffInDays' => \round(($certInfo['validTo_time_t'] - \time()) / (86400)), - 'getSignatureAlgorithm' => $certInfo['signatureTypeSN'], - 'getTlsVersion' => $tlsVersion, - 'mixedContentScannerUrl' => '#', - 'contactUrl' => $contactUrl, - ]); - - // Validate input: Database backup - if (true === (bool) Configuration::get('LITE_BACKUP_DB') || true === (bool) Configuration::get('LITE_BACKUP_DB_DROPBOX')) { - $linkBackupDbCron = $this->getBaseURL() . 'modules/securitylite/backupdb-cron.php?token=' . \Tools::substr(\Tools::encrypt('backupdb/cron'), 0, 32); - $cron[] = $this->l('Database backup') . '. ' . $this->l('URL') . ': ' . $linkBackupDbCron . ''; - } - - // Empty password - Configuration::updateValue('LITE_PASSWORD_GENERATOR', null); - - if (!empty($cron)) { - $text = '' . $this->l('Setup following links as cronjobs (it is recommended to run the cronjobs once a day)') . ':
'; - if (Tools::version_compare(_PS_VERSION_, '1.7.4', '>=')) { - $out .= $this->displayInformation($text . \implode('
', $cron)); - } else { - $out .= $this->displayConfirmation($text . \implode('
', $cron)); - } - } - - // Return the output - return $out . - $this->renderForm() . - $this->display(__FILE__, 'views/templates/admin/scripts.tpl') . - $this->analyzeSystem() . - $this->analyzePhpIni() . - $this->display(__FILE__, 'views/templates/admin/ssl.tpl') . - $this->display(__FILE__, 'views/templates/admin/contact.tpl'); + return \implode('', $out); } /** - * Hook stuff in front office header. + * Hook stuff in back office header. * * @param array $params */ - public function hookDisplayHeader($params) + public function hookDisplayBackOfficeTop($params) { - // Disable browser features - if ('2' === Configuration::get('LITE_DISABLE_RIGHT_CLICK')) { - $this->context->controller->addJS($this->_path . 'views/js/contextmenu.js'); - } elseif ('3' === Configuration::get('LITE_DISABLE_RIGHT_CLICK')) { - $this->context->controller->addJS($this->_path . 'views/js/contextmenu-img.js'); - } + // Menu icon on PrestaShop 1.6 + $this->context->controller->addCss($this->_path . 'views/css/menuTabIcon.css'); + } - // Ban IP addresses - if (true === (bool) Configuration::get('LITE_BAN_IP_ACTIVATE') && !Tools::isEmpty(Configuration::get('LITE_BAN_IP')) && false !== Configuration::get('LITE_BAN_IP')) { - if (true === $this->blockIp()) { - $this->blockRequest(); - } + /** + * Install tab. + * + * @return bool + */ + public function installTab() + { + $tab = new Tab(); + + $tab->module = $this->name; + + $languages = \Language::getLanguages(false); + $name = []; + foreach ($languages as $language) { + $name[$language['id_lang']] = 'Security Lite'; } - // Block user agents - if (true === (bool) Configuration::get('LITE_BLOCK_USER_AGENT_ACTIVATE') && !Tools::isEmpty(Configuration::get('LITE_BLOCK_USER_AGENT')) && false !== Configuration::get('LITE_BLOCK_USER_AGENT')) { - if (true === $this->blockUserAgent()) { - $this->blockRequest(); - } + $tab->name = $name; + $tab->class_name = 'Adminsecuritylite'; + + if (Tools::version_compare(_PS_VERSION_, '1.7.0.0', '>=')) { + $tab->icon = 'security'; + $tab->id_parent = (int) Tab::getIdFromClassName('IMPROVE'); + $tab->save(); + } else { + $tab->id_parent = 0; + $tab->add(); } } /** - * Hook stuff in back office header. + * Uninstall tab. * - * @param array $params + * @return bool */ - public function hookDisplayBackOfficeTop($params) + public function uninstallTab() { - $this->context->controller->addCss($this->_path . 'views/css/menuTabIcon.css'); - - if ('securitylite' === Tools::getValue('configure')) { - $this->context->controller->addJS($this->_path . 'views/js/secure-random-password.min.js'); + $tabId = (int) Tab::getIdFromClassName('Adminsecuritylite'); + if (!$tabId) { + return true; } - if (true === (bool) Configuration::get('LITE_FAIL2BAN')) { - $email = Tools::getValue('email'); - $passwd = Tools::getValue('passwd'); - $findTime = (int) Configuration::get('LITE_FIND_TIME') * 60; - $eldestAccessTime = $this->getEldestAccessTry($email); - - if (Tools::isSubmit('submitLogin') && $email && $passwd) { - $banTime = (int) Configuration::get('LITE_BAN_TIME') * 60; - $employeeBanTime = $this->getBanTime($email); - - if (\time() - $employeeBanTime <= $banTime) { - $this->ban(); - } - $employee = new Employee(); - $isLoaded = $employee->getByEmail($email, $passwd); - - if (!$isLoaded) { - Db::getInstance()->insert('securitylite', [ - 'email' => $email, - 'ip' => \Tools::getRemoteAddr(), - ]); - } + $tab = new Tab($tabId); - if ($eldestAccessTime && \time() - $eldestAccessTime <= $findTime) { - Db::getInstance()->insert('securitylite', [ - 'email' => $email, - 'ip' => \Tools::getRemoteAddr(), - 'banned' => 1, - ]); - $this->ban(); - } - } - } + return $tab->delete(); } /** - * Creates a new backup file. + * Creates a new backup file. Return true on successful backup. * - * @return bool true on successful backup + * @return bool */ public function backupDatabase() { - if (false === (bool) Configuration::get('LITE_BACKUP_DB') && false === (bool) Configuration::get('LITE_BACKUP_DB_DROPBOX')) { + if (false === (bool) Configuration::get('LITE_BACKUP_DB')) { return false; } - $dirBackupDatabase = '/backup/database/'; - - $ignore_insert_table = [ + $ignoreInsertTable = [ _DB_PREFIX_ . 'connections', _DB_PREFIX_ . 'connections_page', _DB_PREFIX_ . 'connections_source', @@ -594,7 +748,7 @@ public function backupDatabase() $rand = Tools::strtolower(Tools::passwdGen(16)); $date = \time(); - $backupFile = _PS_MODULE_DIR_ . $this->name . $dirBackupDatabase . $date . '-' . $rand . '.sql'; + $backupFile = _PS_MODULE_DIR_ . $this->name . self::DIR_BACKUP_DATABASE . $date . '-' . $rand . '.sql'; // Figure out what compression is available and open the file if (\function_exists('bzopen')) { @@ -611,12 +765,10 @@ public function backupDatabase() return false; } - $this->id = \realpath($backupFile); - - \fwrite($fp, '/* Backup for ' . Tools::getHttpHost(false, false) . __PS_BASE_URI__ . "\n * at " . \date($date) . "\n */\n"); - \fwrite($fp, "\n" . 'SET NAMES \'utf8\';'); - \fwrite($fp, "\n" . 'SET FOREIGN_KEY_CHECKS = 0;'); - \fwrite($fp, "\n" . 'SET SESSION sql_mode = \'\';' . "\n\n"); + \fwrite($fp, '/* Backup for ' . $this->getBaseURL() . \PHP_EOL . ' * at ' . \date('Y-m-d', $date) . \PHP_EOL . ' */' . \PHP_EOL); + \fwrite($fp, \PHP_EOL . 'SET NAMES \'utf8\';'); + \fwrite($fp, \PHP_EOL . 'SET FOREIGN_KEY_CHECKS = 0;'); + \fwrite($fp, \PHP_EOL . 'SET SESSION sql_mode = \'\';' . \PHP_EOL . \PHP_EOL); // Find all tables $tables = Db::getInstance()->executeS('SHOW TABLES'); @@ -624,7 +776,7 @@ public function backupDatabase() foreach ($tables as $table) { $table = \current($table); - // Skip tables which do not start with _DB_PREFIX_ + // Skip tables which don\'t start with _DB_PREFIX_ if (\Tools::strlen($table) < \Tools::strlen(_DB_PREFIX_) || 0 !== \strncmp($table, _DB_PREFIX_, \Tools::strlen(_DB_PREFIX_))) { continue; } @@ -638,31 +790,31 @@ public function backupDatabase() return false; } - \fwrite($fp, '/* Scheme for table ' . $schema[0]['Table'] . " */\n"); + \fwrite($fp, '/* Scheme for table ' . $schema[0]['Table'] . ' */' . \PHP_EOL); - \fwrite($fp, $schema[0]['Create Table'] . ";\n\n"); + \fwrite($fp, $schema[0]['Create Table'] . ';' . \PHP_EOL . \PHP_EOL); - if (!\in_array($schema[0]['Table'], $ignore_insert_table, true)) { + if (!\in_array($schema[0]['Table'], $ignoreInsertTable, true)) { $data = Db::getInstance()->query('SELECT * FROM `' . $schema[0]['Table'] . '`', false); $sizeof = Db::getInstance()->numRows(); - $lines = \explode("\n", $schema[0]['Create Table']); + $lines = \explode(\PHP_EOL, $schema[0]['Create Table']); if ($data && $sizeof > 0) { // Export the table data - \fwrite($fp, 'INSERT INTO `' . $schema[0]['Table'] . "` VALUES\n"); + \fwrite($fp, 'INSERT INTO `' . $schema[0]['Table'] . '` VALUES' . \PHP_EOL); $i = 1; while ($row = Db::getInstance()->nextRow($data)) { $s = '('; foreach ($row as $field => $value) { - $tmp = "'" . pSQL($value, true) . "',"; - if ("''," !== $tmp) { + $tmp = '\'' . pSQL($value, true) . '\','; + if ('\'\',' !== $tmp) { $s .= $tmp; } else { foreach ($lines as $line) { if (false !== \mb_strpos($line, '`' . $field . '`')) { if (\preg_match('/(.*NOT NULL.*)/Ui', $line)) { - $s .= "'',"; + $s .= '\'\','; } else { $s .= 'NULL,'; } @@ -675,11 +827,11 @@ public function backupDatabase() $s = \rtrim($s, ','); if (0 === $i % 200 && $i < $sizeof) { - $s .= ");\nINSERT INTO `" . $schema[0]['Table'] . "` VALUES\n"; + $s .= ');' . \PHP_EOL . 'INSERT INTO `' . $schema[0]['Table'] . '` VALUES' . \PHP_EOL; } elseif ($i < $sizeof) { - $s .= "),\n"; + $s .= '),' . \PHP_EOL; } else { - $s .= ");\n"; + $s .= ');' . \PHP_EOL; } \fwrite($fp, $s); @@ -701,108 +853,78 @@ public function backupDatabase() if (false === (bool) Configuration::get('LITE_BACKUP_DB')) { Tools::deleteFile($backupFile); } else { - $this->deleteOldBackups($backupSaved, $dirBackupDatabase); + $this->deleteOldBackups($backupSaved, self::DIR_BACKUP_DATABASE); } return true; } /** - * Delete old backups from local. - * - * @param $backupSaved - * @param $dir + * Delete old carts. */ - public function deleteOldBackups($backupSaved, $dir) + public function deleteOldCarts() { - $ext = [ - 'bz2', - 'gz', - 'zip', - ]; - $backupFile = []; + if (Configuration::get('LITE_DELETE_OLD_CARTS')) { + $query = 'DELETE FROM `' . _DB_PREFIX_ . 'cart` + WHERE id_cart NOT IN (SELECT id_cart FROM `' . _DB_PREFIX_ . 'orders`) + AND date_add < "' . pSQL(\date('Y-m-d', \strtotime('-' . Configuration::get('LITE_DELETE_OLD_CARTS_DAYS') . ' day'))) . '"'; - if ($handle = \opendir(_PS_MODULE_DIR_ . $this->name . $dir)) { - while (false !== ($entry = \readdir($handle))) { - if ('.' !== $entry && '..' !== $entry) { - if (\in_array(\pathinfo(\basename($entry), \PATHINFO_EXTENSION), $ext, true)) { - $backupFile[] = $entry; - } - } - } - if (!empty($backupFile)) { - $x = \count($backupFile); - $y = 0; - while ($x > $backupSaved) { - Tools::deleteFile(_PS_MODULE_DIR_ . $this->name . $dir . $backupFile[$y]); - --$x; - ++$y; - } - } - \closedir($handle); + Db::getInstance()->Execute($query); } } /** - * Lookup ban time for specific e-mail in database. - * - * @param string $email + * Encrypt data. * - * @return int + * @param string $data */ - public function getBanTime($email) + public function encrypt($data) { - $sql = new DbQuery(); - $sql->select('MAX(access_time) AS access_time'); - $sql->from('securitylite'); - $sql->where('banned = 1'); - $sql->where(\sprintf('email = "%s"', pSQL($email))); - $result = Db::getInstance()->executeS($sql); + if (Tools::version_compare(_PS_VERSION_, '1.7.0.0', '>=')) { + return Tools::hashIV($data); // PS 1.7 + } - return $result ? \strtotime($sql) : 0; + return Tools::encryptIV($data); // PS 1.6 } /** - * Install tab. + * Log cronjobs. + * + * @param string $name + * @param string $response */ - public function installTab() + public function logCron($name, $response) { - $tab = new Tab(); - - $tab->module = $this->name; - - $languages = \Language::getLanguages(false); - $name = []; - foreach ($languages as $language) { - $name[$language['id_lang']] = 'Security Lite'; - } - - $tab->name = $name; - $tab->class_name = 'AdminSecurityLite'; - - if (Tools::version_compare(_PS_VERSION_, '1.7.0', '>=')) { - $tab->icon = 'security'; - $tab->id_parent = (int) Tab::getIdFromClassName('IMPROVE'); - $tab->save(); - } else { - $tab->id_parent = 0; - $tab->add(); - } + $data = []; + $data[] = '[' . \date('Y-m-d H:i:s') . ']'; + $data[] = '[' . $name . ']'; + $data[] = $this->l('Response') . ': "' . $response . '"'; + \file_put_contents($this->getLogFile(self::LOG_CRONJOB), \implode(' ', $data) . \PHP_EOL, \FILE_APPEND); } /** - * Uninstall tab. + * Remove generated content from .htaccess file. */ - public function uninstallTab() + public function removeHtaccessContent() { - $tabId = (int) Tab::getIdFromClassName('AdminSecurityLite'); - if (!$tabId) { - return true; + Tools::deleteFile(_PS_ROOT_DIR_ . \DIRECTORY_SEPARATOR . '.htpasswd'); + $path = _PS_ADMIN_DIR_ . \DIRECTORY_SEPARATOR . '.htaccess'; + + if (!\file_exists($path)) { + return; } - $tab = new Tab($tabId); + $htaccessContent = \Tools::file_get_contents($path); - return $tab->delete(); + if (\preg_match('/\# ~security_pro~(.*?)\# ~security_LITE_end~/s', $htaccessContent, $m)) { + $contentToRemove = $m[0]; + $htaccessContent = \str_replace($contentToRemove, '', $htaccessContent); + } + \file_put_contents($path, $htaccessContent); + + if (0 === \filesize($path)) { + Tools::deleteFile($path); + } } /** @@ -819,8 +941,8 @@ protected function renderForm() $helper->default_form_language = $this->context->language->id; $helper->allow_employee_form_lang = (bool) Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG', false); $helper->identifier = $this->identifier; - $helper->submit_action = 'submitSecurityLiteModule'; - $helper->currentIndex = $this->context->link->getAdminLink('AdminModules', false) . '&configure=securitylite&tab_module=' . $this->tab; + $helper->submit_action = 'SubmitSecurityLiteModule'; + $helper->currentIndex = $this->getAdminLink('AdminModules', false) . '&configure=securitylite&tab_module=' . $this->tab; $helper->token = \Tools::getAdminTokenLite('AdminModules'); $helper->tpl_vars = [ 'fields_value' => $this->getConfigFormValues(), @@ -828,43 +950,107 @@ protected function renderForm() 'id_language' => $this->context->language->id, ]; - if (!\defined('_TB_VERSION_')) { - $displayForms = [ - $this->fieldsFormSecuritySettings(), - $this->fieldsFormBackup(), - $this->fieldsFormAdminDir(), - $this->fieldsFormPasswdGen(), - ]; - } else { - $displayForms = [ - $this->fieldsFormSecuritySettings(), - $this->fieldsFormBackup(), - $this->fieldsFormPasswdGen(), - ]; - } + $dashboard = [ + $this->fieldsFormDashboard(), + ]; + + $generalSettings = [ + $this->fieldsFormGeneralSettings(), + ]; + + $loginProtection = [ + $this->fieldsFormBruteForceProtection(), + $this->fieldsFormTwoFactorAuth(), + $this->fieldsFormSecondLogin(), + $this->fieldsFormAdminStealthLogin(), + ]; + + $passwordstrength = [ + $this->fieldsFormPasswordStrengh(), + ]; + + $httpHeaders = [ + $this->fieldsFormHttpSecurityHeaders(), + ]; + + $firewall = [ + $this->fieldsFormFirewall(), + $this->fieldsFormAntiSpam(), + ]; + + $malwareScanner = [ + $this->fieldsFormMalwareScan(), + ]; + + $cartProtection = [ + $this->fieldsFormAntiFakeCarts(), + ]; + + $montoring = [ + $this->fieldsFormWebsiteMonitoringService(), + $this->fieldsFormMonitoringChanges(), + ]; + + $antiFraud = [ + $this->fieldsFormAntiFraud(), + ]; + + $contentProtection = [ + $this->fieldsFormProtectContent(), + ]; + + $backup = [ + $this->fieldsFormBackup(), + ]; + + $tools = [ + $this->fieldsFormAdminDir(), + $this->fieldsFormTools(), + $this->fieldsFormPasswdGen(), + ]; + + $analysis = [ + $this->fieldsFormAnalyzeSystem(), + $this->fieldsFormAnalyzeServerConfig(), + $this->fieldsFormAnalyzeSsl(), + $this->fieldsFormAnalyzeModules(), + ]; + + $maintenance = [ + $this->fieldsFormMaintenanceMode(), + ]; + + $help = [ + $this->fieldsFormAutoConfig(), + $this->fieldsFormHelp(), + ]; + + $displayForms = \array_merge($dashboard, $generalSettings, $loginProtection, $httpHeaders, $passwordstrength, $firewall, $malwareScanner, $cartProtection, $montoring, $antiFraud, $contentProtection, $backup, $tools, $analysis, $maintenance, $help); return $helper->generateForm($displayForms); } /** - * Build forms. + * @return array */ protected function fieldsFormAdminDir() { return [ 'form' => [ 'legend' => [ - 'title' => $this->l('Admin directory'), + 'title' => $this->l('Admin Folder'), 'icon' => 'icon-folder-o', ], + 'description' => $this->l('You should always keep the path to your admin login secret. If you need to change it, you can change it with this tool.'), 'input' => [ [ - 'disabled' => true, 'type' => 'switch', - 'label' => $this->l('Are you sure, you want to change name of admin directory?'), + 'col' => 8, + 'label' => $this->l('Are you sure, you want to change the name of your admin folder?'), 'name' => 'LITE_ADMIN_DIRECTORY', 'is_bool' => true, - 'desc' => $this->proFeature . $this->l('You will be redirected to the new URL once you click') . ' "' . $this->l('Save') . '" ' . $this->l('if this is set to') . ' "' . $this->l('Yes') . '"', + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('You will be redirected to the new URL once you click') . ' \'' . $this->l('Save') . '\' ' . $this->l('if this option is set to') . ' \'' . $this->l('Yes') . '\'.', 'values' => [ [ 'id' => 'active_on', @@ -879,14 +1065,14 @@ protected function fieldsFormAdminDir() ], ], [ - 'disabled' => true, - 'col' => 4, + 'col' => 6, 'type' => 'text', 'prefix' => $this->getBaseURL(), - 'desc' => $this->proFeature . $this->l('Your admin directory name should include both letters and numbers. Make it hard to guess; don\'t use something like admin123, administrator, backoffice etc.') . ' ' . $this->l('Generate secure directory name') . '.', + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('Your admin folder name should include both letters and numbers. Make it hard to guess; don\'t use something like admin123, administrator, back office, etc.') . ' ' . $this->l('Generate a secure folder name') . '.', 'name' => 'LITE_ADMIN_DIRECTORY_NAME', 'label' => $this->l('Directory name'), - 'hint' => $this->l('Accepted characters') . ': "a-z A-Z 0-9 _ . -"', + 'hint' => $this->l('Accepted characters') . ': \'a-z A-Z 0-9 _ . -\'', ], ], 'submit' => [ @@ -897,163 +1083,223 @@ protected function fieldsFormAdminDir() } /** - * Build forms. + * @return array */ - protected function fieldsFormBackup() + protected function fieldsFormGeneralSettings() { - $dirBackupDatabase = '/backup/database/'; - $dirBackupFiles = '/backup/files/'; - $featured = []; - $featuredFiles = []; - $list = []; - $listFiles = []; + $dropboxToken = [ + $this->l('Log on to your Dropbox account.'), + $this->l('Access') . ' ' . $this->generateLink('https://www.dropbox.com/developers/apps/create') . ' ' . $this->l('from your browser.'), + $this->l('Choose Dropbox Legacy API on the first step.'), + $this->l('Choose App folder access on the second step.'), + $this->l('Give your App a name. That name will become a folder in your Dropbox account.'), + $this->l('Click the \'Create App\' button.'), + $this->l('Scroll down to the \'OAuth 2\' block and hit the \'Generate\' button near the \'Generated access token\' text.'), + $this->l('After the token is generated, you\'ll see a string of letters and numbers. This is your Dropbox API access token. You should now copy this token into the field above.'), + ]; - if (!empty($featured)) { - foreach ($featured as $value) { - $list[] = $value['path_lower'] . ' (' . \date('Y-m-d', \Tools::substr(\basename($value['path_lower']), 0, 10)) . ')'; - } - } + $googleApiV2 = [ + $this->l('Log on to your Google account.'), + $this->l('Access') . ' ' . $this->generateLink('https://www.google.com/recaptcha/admin/create') . ' ' . $this->l('from your browser.'), + $this->l('Select the reCAPTCHA v2 radio button.'), + $this->l('Register your domain.'), + $this->l('Copy your Site key and your Secret key into the fields above.'), + ]; - if (!empty($featuredFiles)) { - foreach ($featuredFiles as $valueFiles) { - $listFiles[] = $valueFiles['path_lower'] . ' (' . \date('Y-m-d', \Tools::substr(\basename($valueFiles['path_lower']), 0, 10)) . ')'; - } - } + $googleApiV3 = [ + $this->l('Log on to your Google account.'), + $this->l('Access') . ' ' . $this->generateLink('https://www.google.com/recaptcha/admin/create') . ' ' . $this->l('from your browser.'), + $this->l('Select the reCAPTCHA v3 radio button.'), + $this->l('Register your domain.'), + $this->l('Copy your Site key and your Secret key into the fields above.'), + ]; - $backupDir = _PS_MODULE_DIR_ . 'securitylite/backup'; - if (!\is_dir($backupDir . '/database')) { - \mkdir($backupDir . '/database', 0755, true); - } - if (!\is_dir($backupDir . '/files')) { - \mkdir($backupDir . '/files', 0755, true); - } - $this->addIndexRecursively($backupDir); + $googleSafeBrowsingApiV4 = [ + $this->l('Log on to your Google account.'), + $this->l('Access') . ' ' . $this->generateLink('https://console.developers.google.com/apis/library/safebrowsing.googleapis.com') . ' ' . $this->l('from your browser.'), + $this->l('Enable Safe Browsing API.'), + $this->l('Select a project or create a new one.'), + $this->l('Click Credentials.'), + $this->l('Click Create credentials.'), + $this->l('Copy your API key into the field above.'), + ]; - $dirPath = []; - $ext = ['bz2', 'gz']; - if ($handle = \opendir(_PS_MODULE_DIR_ . $this->name . $dirBackupDatabase)) { - while (false !== ($entry = \readdir($handle))) { - if ('.' !== $entry && '..' !== $entry) { - if (\in_array(\pathinfo(\basename($entry), \PATHINFO_EXTENSION), $ext, true)) { - $dirPath[] = \realpath(_PS_MODULE_DIR_ . $this->name . $dirBackupDatabase . $entry) . ' (' . \date('Y-m-d', \Tools::substr(\basename($entry), 0, 10)) . ')'; - } - } - } - } + $honeypotApi = [ + $this->l('Log on to your Honeypot Project account.'), + $this->l('Access') . ' ' . $this->generateLink('https://www.projecthoneypot.org/account_login.php') . ' ' . $this->l('from your browser.'), + $this->l('Your API key is found on the top left of your Project Honey Pot Dashboard. It will be the first line under \'Your Stats\'.'), + $this->l('Copy your Honeypot API key into the field above.'), + ]; - $filePath = []; - if ($handle = \opendir(_PS_MODULE_DIR_ . $this->name . $dirBackupFiles)) { - while (false !== ($entry = \readdir($handle))) { - if ('.' !== $entry && '..' !== $entry) { - if ('zip' === \pathinfo(\basename($entry), \PATHINFO_EXTENSION)) { - $filePath[] = \realpath(_PS_MODULE_DIR_ . $this->name . $dirBackupFiles . $entry) . ' (' . \date('Y-m-d', \Tools::substr(\basename($entry), 0, 10)) . ')'; - } - } - } + $montasticApi = [ + $this->l('Log on to your Montastic account.'), + $this->l('Access') . ' ' . $this->generateLink('https://montastic.com/me?tab=form_profile') . ' ' . $this->l('from your browser.'), + $this->l('Copy your REST API key into the field above.'), + ]; + + $timeZoneLink = $this->getAdminLink('AdminLocalization', true); + + $timeZoneText = $this->l('As some of the features in this module are based on time, it is very important that you have chosen the correct time zone. Your current chosen time zone is') . ' ' . Configuration::get('PS_TIMEZONE') . '. ' . $this->generateLink($timeZoneLink, $this->l('Change the time zone')) . '.'; + + if (false === \function_exists('mail')) { + $errorMessage = $this->l('PHP mail function is disabled on your system. You must PHP mail function to use the mail notification features.'); + } else { + $errorMessage = null; } return [ 'form' => [ 'legend' => [ - 'title' => $this->l('Automatic backups'), - 'icon' => 'icon-files-o', + 'title' => $this->l('General Settings'), + 'icon' => 'icon-cog', ], - 'description' => $this->l('Security Lite is not responsible for your database/files, its backups and/or recovery.') . '
' . - $this->l('You should back up your data on a regular basis (both files and database).') . '
' . - $this->l('Security Lite can back up your database and files and save it local and to Dropbox.') . '
' . - $this->l('Always verify the quality and integrity of your backup files!') . '
' . - $this->l('Always verify that your backup files are complete, up-to-date and valid, even if you had a success message appear during the backup process.') . '
' . - $this->l('Always check your data.') . '
' . - $this->l('Never restore a backup on a live site.'), + 'description' => $this->l('Some features in this module use external free services (no paid subscription is required for any of the services). To use these features, you must get an API key/token from the services.') . '
' . $timeZoneText, + 'warning' => $this->l('Please save the following link to a safe place') . ': ' . $this->generateUnlockLink() . '
' . $this->l('Running this link will disable brute force protection, two-factor authentication and admin stealth login. This link can be used for when you get locked out from your back office.'), + 'error' => $errorMessage, 'input' => [ [ - 'disabled' => true, - 'col' => 5, + 'col' => 8, 'type' => 'text', - 'desc' => $this->proFeature . $this->l('You must set up your Dropbox access token before you can activate backup to Dropbox. Get your access token here') . ': ' . $this->l('Get access token') . '. ' . $this->l('You will have to register to get a token, but it\'s free.'), + 'desc' => $this->proFeature . '

  1. ' . \implode('
  2. ', $dropboxToken) . '

', 'name' => 'LITE_BACKUP_DB_TOKEN', 'label' => $this->l('Dropbox access token'), 'prefix' => '', 'hint' => $this->l('Your Dropbox token'), 'required' => true, + 'disabled' => true, ], [ - 'disabled' => true, - 'type' => 'switch', - 'label' => $this->l('Backup database to Dropbox'), - 'name' => 'LITE_BACKUP_DB_DROPBOX', - 'is_bool' => true, - 'desc' => $this->proFeature . $this->l('Save a backup of your database to your Dropbox. Statistical data are excluded.') . ' ' . $this->l('Once this option is enabled, you will get a link you have set up as a cronjob.') . '
' . (!empty($list) ? $this->l('You can find the path to your backups below') . ':
' . \implode('
', $list) : $this->l('You have no backups yet.')) . '
', - 'values' => [ - [ - 'id' => 'active_on', - 'value' => 1, - 'label' => $this->l('Enabled'), - ], - [ - 'id' => 'active_off', - 'value' => 0, - 'label' => $this->l('Disabled'), + 'col' => 8, + 'type' => 'text', + 'prefix' => '', + 'name' => 'LITE_FIREWALL_RECAPTCHA_SITE_KEY', + 'label' => 'Site key (reCAPTCHA v2)', + 'hint' => $this->l('Your reCAPTCHA v2 site key'), + 'required' => true, + ], + [ + 'col' => 8, + 'type' => 'text', + 'prefix' => '', + 'desc' => '

  1. ' . \implode('
  2. ', $googleApiV2) . '

', + 'name' => 'LITE_FIREWALL_RECAPTCHA_SECRET', + 'label' => 'Secret key (reCAPTCHA v2)', + 'hint' => $this->l('Your reCAPTCHA v2 secret key'), + 'required' => true, + ], + [ + 'col' => 8, + 'type' => 'text', + 'prefix' => '', + 'name' => 'LITE_RECAPTCHA_V3_SITE_KEY', + 'label' => 'Site key (reCAPTCHA v3)', + 'hint' => $this->l('Your reCAPTCHA v3 site key'), + 'required' => true, + 'disabled' => true, + ], + [ + 'col' => 8, + 'type' => 'text', + 'prefix' => '', + 'desc' => $this->proFeature . '

  1. ' . \implode('
  2. ', $googleApiV3) . '

', + 'name' => 'LITE_RECAPTCHA_V3_SECRET', + 'label' => 'Secret key (reCAPTCHA v3)', + 'hint' => $this->l('Your reCAPTCHA v3 secret key'), + 'required' => true, + 'disabled' => true, + ], + [ + 'type' => 'select', + 'label' => $this->l('Display') . ' (reCAPTCHA v3)', + 'desc' => $this->proFeature . $this->l('Choose where to show the badge.'), + 'name' => 'LITE_DISPLAY_RECAPTCHA_V3', + 'disabled' => true, + 'options' => [ + 'query' => [ + [ + 'id_option' => 'bottomleft', + 'name' => $this->l('Bottom left'), + ], + [ + 'id_option' => 'bottomright', + 'name' => $this->l('Bottom right'), + ], ], + 'id' => 'id_option', + 'name' => 'name', ], ], [ - 'type' => 'switch', - 'label' => $this->l('Backup database to local'), - 'name' => 'LITE_BACKUP_DB', - 'is_bool' => true, - 'desc' => $this->l('Save a local backup of your database. Statistical data are excluded.') . ' ' . $this->l('Once this option is enabled, you will get a link you have set up as a cronjob.') . '
' . (!empty($dirPath) ? $this->l('You can find the path to your backups below') . ':
' . \implode('
', $dirPath) : $this->l('You have no backups yet.')) . '
', - 'values' => [ - [ - 'id' => 'active_on', - 'value' => 1, - 'label' => $this->l('Enabled'), - ], - [ - 'id' => 'active_off', - 'value' => 0, - 'label' => $this->l('Disabled'), + 'type' => 'select', + 'label' => $this->l('Theme') . ' (reCAPTCHA v3)', + 'desc' => $this->proFeature . $this->l('Choose the color theme of the badge.'), + 'name' => 'LITE_RECAPTCHA_V3_THEME', + 'disabled' => true, + 'options' => [ + 'query' => [ + [ + 'id_option' => 'light', + 'name' => $this->l('Light'), + ], + [ + 'id_option' => 'dark', + 'name' => $this->l('Dark'), + ], ], + 'id' => 'id_option', + 'name' => 'name', ], ], [ - 'col' => 2, + 'col' => 8, 'type' => 'text', - 'prefix' => '', - 'desc' => $this->l('Old backups will be deleted when newer one is generated. How many backups do you want to keep at the time? Write "0" for unlimited backups.'), - 'name' => 'LITE_BACKUP_DB_SAVED', - 'label' => $this->l('Database backups to save'), - 'suffix' => $this->l('backups'), - 'hint' => $this->l('Must be an integer'), + 'prefix' => '', + 'desc' => $this->proFeature . '

  1. ' . \implode('
  2. ', $googleSafeBrowsingApiV4) . '

', + 'name' => 'LITE_GOOGLE_SAFE_BROWSING_V4_API', + 'label' => 'Google Safe Browsing v4', + 'hint' => $this->l('Your Google Safe Browsing v4 API key'), 'required' => true, + 'disabled' => true, ], [ + 'col' => 8, + 'type' => 'text', + 'prefix' => '', + 'desc' => $this->proFeature . '

  1. ' . \implode('
  2. ', $honeypotApi) . '

', + 'name' => 'LITE_HONEYPOT_API', + 'label' => $this->l('Honeypot API'), + 'hint' => $this->l('Access keys are 12-alpha characters (no numbers). They are lower-case.'), + 'required' => true, 'disabled' => true, - 'type' => 'switch', - 'label' => $this->l('Backup files to Dropbox'), - 'name' => 'LITE_BACKUP_FILE_DROPBOX', - 'is_bool' => true, - 'desc' => $this->proFeature . $this->l('Save a full backup of your files to your Dropbox. Cache and log files are excluded.') . ' ' . $this->l('Once this option is enabled, you will get a link you have set up as a cronjob.') . '
' . (!empty($listFiles) ? $this->l('You can find the path to your backups below') . ':
' . \implode('
', $listFiles) : $this->l('You have no backups yet.')) . '
', - 'values' => [ - [ - 'id' => 'active_on', - 'value' => 1, - 'label' => $this->l('Enabled'), - ], - [ - 'id' => 'active_off', - 'value' => 0, - 'label' => $this->l('Disabled'), - ], - ], ], [ + 'col' => 8, + 'type' => 'text', + 'prefix' => '', + 'desc' => '

  1. ' . \implode('
  2. ', $montasticApi) . '

', + 'name' => 'LITE_MONTASTIC_API', + 'label' => 'Montastic API', + 'hint' => $this->l('Access keys are 40 characters.'), + 'required' => true, + ], + [ + 'col' => 8, + 'type' => 'text', + 'desc' => $this->proFeature . $this->l('You can enable e-mail notifications on some of the features. To use these features, you must enter your e-mail in the above field.'), + 'name' => 'LITE_GENERAL_EMAIL', + 'prefix' => '', + 'label' => $this->l('E-mail'), + 'hint' => $this->l('Must be a valid e-mail address'), + 'required' => true, 'disabled' => true, + ], + [ 'type' => 'switch', - 'label' => $this->l('Backup files to local'), - 'name' => 'LITE_BACKUP_FILE', + 'col' => 8, + 'label' => $this->l('Debug cronjobs'), + 'name' => 'LITE_DEBUG_CRON', 'is_bool' => true, - 'desc' => $this->proFeature . $this->l('Save a full backup of your files on your PrestaShop installation.') . ' ' . $this->l('Once this option is enabled, you will get a link you have set up as a cronjob.') . '
' . (!empty($filePath) ? $this->l('You can find the path to your backups below') . ':
' . \implode('
', $filePath) : $this->l('You have no backups yet.')) . '
', + 'desc' => $this->l('If one of your cronjobs fails, you can enable this option to find the problem. Run your cronjob manually in your browser to see the error.'), 'values' => [ [ 'id' => 'active_on', @@ -1067,43 +1313,6 @@ protected function fieldsFormBackup() ], ], ], - [ - 'disabled' => true, - 'col' => 2, - 'type' => 'text', - 'prefix' => '', - 'desc' => $this->proFeature . $this->l('Old backups will be deleted if newer one is generated. How many backups do you want to keep at the time? Write "0" for unlimited backups.'), - 'name' => 'LITE_BACKUP_FILE_SAVED', - 'label' => $this->l('File backups to save'), - 'suffix' => $this->l('backups'), - 'hint' => $this->l('Must be an integer'), - 'required' => true, - ], - [ - 'disabled' => true, - 'type' => 'select', - 'label' => $this->l('Zip compression level for file backup'), - 'desc' => $this->proFeature . $this->l('The values range from 1 (super-fast) to 9 (maximum) are supported. The higher the number, the better and longer the compression.'), - 'name' => 'LITE_BACKUP_COMPRESSION', - 'options' => [ - 'query' => [ - [ - 'id_option' => 'SUPER_FAST', - 'name' => '1 ' . $this->l('super-fast'), - ], - [ - 'id_option' => 'NORMAL', - 'name' => '5 ' . $this->l('normal'), - ], - [ - 'id_option' => 'MAXIMUM', - 'name' => '9 ' . $this->l('maximum'), - ], - ], - 'id' => 'id_option', - 'name' => 'name', - ], - ], ], 'submit' => [ 'title' => $this->l('Save'), @@ -1113,72 +1322,28 @@ protected function fieldsFormBackup() } /** - * Build forms. - */ - protected function fieldsFormPasswdGen() - { - return [ - 'form' => [ - 'legend' => [ - 'title' => $this->l('Password generator'), - 'icon' => 'icon-key', - ], - 'description' => $this->l('You should use a strong and unique password for each of: MySQL database, FTP, hosting panel/cPanel, SSH access and back office. You can use this tool to generate the passwords.'), - 'input' => [ - [ - 'col' => 4, - 'type' => 'textbutton', - 'label' => $this->l('Generate strong password'), - 'desc' => $this->l('The password is not saved anywhere by this module.'), - 'name' => 'LITE_PASSWORD_GENERATOR', - 'button' => [ - 'label' => $this->l('Generate'), - 'attributes' => [ - 'onclick' => 'add_field();', - ], - ], - ], - ], - ], - ]; - } - - /** - * Build forms. + * Display form for monitoring changes. + * + * @return array */ - protected function fieldsFormSecuritySettings() + protected function fieldsFormMonitoringChanges() { - $tfa = new RobThree\Auth\TwoFactorAuth(Configuration::get('PS_SHOP_NAME'), 6, 30, 'sha1'); - $linkGoogleApi = 'https://www.google.com/recaptcha/admin/create'; - $linkHoneypotApi = 'https://www.projecthoneypot.org/httpbl_configure.php'; - return [ 'form' => [ 'legend' => [ - 'title' => $this->l('Security settings'), - 'icon' => 'icon-cogs', - ], - 'tabs' => [ - 'protectBackOffice' => ' ' . $this->l('Brute force protection'), - 'tfa' => ' ' . $this->l('Two-Factor Authentication'), - 'secondLogin' => ' ' . $this->l('Second login'), - 'secureFrontOffice' => ' ' . $this->l('HTTP headers'), - 'antiSpam' => ' ' . $this->l('Anti-SPAM'), - 'permissions' => ' ' . $this->l('Permissions'), - 'index' => ' ' . $this->l('Index'), - 'antiVirus' => ' ' . $this->l('Anti-virus'), - 'firewall' => ' ' . $this->l('Firewall (WAF)'), - 'protectContent' => ' ' . $this->l('Protect content'), + 'title' => $this->l('Change Monitoring'), + 'icon' => 'icon-bell-o', ], + 'description' => $this->l('If you can\'t monitor changes, you can\'t manage them. To control your environment, you need the ability to analyze and respond to changes. The module allows you to monitor some important changes like file changes.'), 'input' => [ [ - 'col' => 6, - 'tab' => 'protectBackOffice', 'type' => 'switch', - 'label' => $this->l('Activate brute force protection'), - 'name' => 'LITE_FAIL2BAN', + 'col' => 8, + 'label' => $this->l('Get an e-mail if file changes'), + 'name' => 'LITE_FILE_CHANGES_EMAIL', 'is_bool' => true, - 'desc' => $this->l('A brute force attack is the simplest method to gain access to a site. The hacker tries various combinations of usernames and passwords again and again until he gets in. Enable this feature to limits the maximum amount of tries to your back office.'), + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('Track every file change on your server and let you know by e-mail if something has changed.') . ' ' . $this->l('The module also does reports file changes during PrestaShop update, module update, theme update, etc.') . ' ' . $this->l('Once this option is enabled, a cronjob will appear in your dashboard that you need to set up.'), 'values' => [ [ 'id' => 'active_on', @@ -1193,49 +1358,13 @@ protected function fieldsFormSecuritySettings() ], ], [ - 'col' => 2, - 'tab' => 'protectBackOffice', - 'type' => 'text', - 'desc' => $this->l('Wrong answers before ban.'), - 'name' => 'LITE_MAX_RETRY', - 'prefix' => '', - 'suffix' => $this->l('times'), - 'label' => $this->l('Max retry'), - 'hint' => $this->l('Must be an integer'), - 'required' => true, - ], - [ - 'col' => 2, - 'tab' => 'protectBackOffice', - 'type' => 'text', - 'desc' => $this->l('A host is banned if it has generated') . ' "' . $this->l('Max retry') . '" ' . $this->l('during the last') . ' "' . $this->l('Request timeout') . '" ' . $this->l('Enter time in minutes') . '.', - 'name' => 'LITE_FIND_TIME', - 'prefix' => '', - 'suffix' => $this->l('minutes'), - 'label' => $this->l('Request timeout'), - 'hint' => $this->l('Must be an integer'), - 'required' => true, - ], - [ - 'col' => 2, - 'tab' => 'protectBackOffice', - 'type' => 'text', - 'desc' => $this->l('Time a host is banned. Enter time in minutes.'), - 'name' => 'LITE_BAN_TIME', - 'prefix' => '', - 'suffix' => $this->l('minutes'), - 'label' => $this->l('Ban time'), - 'hint' => $this->l('Must be an integer'), - 'required' => true, - ], - [ - 'disabled' => true, - 'tab' => 'protectBackOffice', 'type' => 'switch', - 'label' => $this->l('Receive e-mail on fail to login'), - 'name' => 'LITE_SEND_MAIL', + 'col' => 8, + 'label' => $this->l('Log file changes'), + 'name' => 'LITE_FILE_CHANGES_LOG', 'is_bool' => true, - 'desc' => $this->proFeature . $this->l('Receive an e-mail in case someone input a wrong password. This setting can only be enabled if brute force protection is activated.'), + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('Track every file change on your server and log it if something has changed.') . ' ' . $this->l('The module does also reports file changes during PrestaShop update, module update, theme update, etc.') . ' ' . $this->l('The log can be found on your dashboard.'), 'values' => [ [ 'id' => 'active_on', @@ -1250,13 +1379,22 @@ protected function fieldsFormSecuritySettings() ], ], [ + 'type' => 'textarea', + 'col' => 8, 'disabled' => true, - 'tab' => 'protectBackOffice', + 'desc' => $this->proFeature . $this->l('Whitelists dynamic files') . '. ' . $this->l('Separate files by a comma') . ' (\',\') ' . $this->l('without space.'), + 'name' => 'LITE_FILE_CHANGES_WHITELIST', + 'label' => $this->l('Whitelist filter for file changes'), + 'hint' => $this->l('E.g.') . ' file.json,file.xml', + ], + [ 'type' => 'switch', - 'label' => $this->l('Receive e-mail on successfully login'), - 'name' => 'LITE_SEND_MAIL_LOGIN', + 'col' => 8, + 'label' => $this->l('Get an e-mail if server IP changes'), + 'name' => 'LITE_SERVER_IP', 'is_bool' => true, - 'desc' => $this->proFeature . $this->l('Receive an e-mail in case someone input the correct password. This setting can only be enabled if brute force protection is activated.'), + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('Get notified if the server IP changes.') . ' ' . $this->l('Once this option is enabled, a cronjob will appear in your dashboard that you need to set up.'), 'values' => [ [ 'id' => 'active_on', @@ -1271,42 +1409,13 @@ protected function fieldsFormSecuritySettings() ], ], [ - 'disabled' => true, - 'col' => 3, - 'tab' => 'protectBackOffice', - 'type' => 'text', - 'desc' => $this->proFeature . $this->l('Enter the e-mail which you would like to be notified at.'), - 'name' => 'LITE_FAIL2BAN_EMAIL', - 'prefix' => '', - 'label' => $this->l('E-mail'), - 'hint' => $this->l('Must be a valid e-mail address'), - 'required' => true, - ], - [ - 'disabled' => true, - 'tab' => 'protectBackOffice', - 'type' => 'textbutton', - 'col' => 6, - 'desc' => $this->proFeature . $this->l('You can list your own IP addresses to avoid getting an e-mail if you write the password wrong. You can still get banned for a period of time if you fail to login according to your own rules above.') . '
' . $this->l('The module can handle IPv4, IPv6 addresses, as well as IP ranges, in CIDR formats') . ' (' . $this->l('like') . ' ::1/128 ' . $this->l('or') . ' 127.0.0.1/32) ' . $this->l('and in pattern format') . ' (' . $this->l('like') . ' ::*:* ' . $this->l('or') . ' 127.0.*.*). ' . $this->l('Separate by comma (\',\').'), - - 'name' => 'LITE_WHITELIST_IPS', - 'button' => [ - 'label' => ' ' . $this->l('Add my IP'), - 'attributes' => [ - 'onclick' => '', - ], - ], - 'label' => $this->l('Whitelist IP addresses'), - 'hint' => $this->l('E.g.') . ' 123.456.789,123.456.*,123.*,...', - ], - [ - 'disabled' => true, - 'tab' => 'protectBackOffice', 'type' => 'switch', - 'label' => $this->l('Activate log'), - 'name' => 'LITE_FAIL2BAN_LOG', + 'col' => 8, + 'label' => $this->l('Get an e-mail if the country of the server changes'), + 'name' => 'LITE_SERVER_LOCATION', 'is_bool' => true, - 'desc' => $this->proFeature . $this->l('Record banned users into a log file.'), + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('Get notified if the location of the server country changes.') . ' ' . $this->l('Once this option is enabled, a cronjob will appear in your dashboard that you need to set up.'), 'values' => [ [ 'id' => 'active_on', @@ -1321,13 +1430,13 @@ protected function fieldsFormSecuritySettings() ], ], [ - 'disabled' => true, - 'tab' => 'secureFrontOffice', 'type' => 'switch', - 'label' => $this->l('Click-jack protection'), - 'name' => 'LITE_CLICK_JACKING', + 'col' => 8, + 'label' => $this->l('Get an e-mail if your ISP changes'), + 'name' => 'LITE_SERVER_ISP', 'is_bool' => true, - 'desc' => $this->proFeature . $this->l('Prevent browsers from framing your site. This will defend you against attacks like click-jacking.'), + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('Get notified if the name of your ISP changes.') . ' ' . $this->l('Once this option is enabled, a cronjob will appear in your dashboard that you need to set up.'), 'values' => [ [ 'id' => 'active_on', @@ -1342,13 +1451,13 @@ protected function fieldsFormSecuritySettings() ], ], [ - 'disabled' => true, - 'tab' => 'secureFrontOffice', 'type' => 'switch', - 'label' => $this->l('XSS protection'), - 'name' => 'LITE_X_XSS_PPROTECTION', + 'col' => 8, + 'label' => $this->l('Get an e-mail if your domain is about to expire'), + 'name' => 'LITE_DOMAIN_EXPIRE', 'is_bool' => true, - 'desc' => $this->proFeature . $this->l('Set secure configuration for the cross-site scripting filters built into most browsers.'), + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('Get notified if your domain is about to expire.') . ' ' . $this->l('Once this option is enabled, a cronjob will appear in your dashboard that you need to set up.'), 'values' => [ [ 'id' => 'active_on', @@ -1363,13 +1472,13 @@ protected function fieldsFormSecuritySettings() ], ], [ - 'disabled' => true, - 'tab' => 'secureFrontOffice', 'type' => 'switch', - 'label' => $this->l('Disable content sniffing'), - 'name' => 'LITE_X_CONTENT_TYPE_OPTIONS', - 'is_bool' => false, - 'desc' => $this->proFeature . $this->l('Stop browsers from trying to MIME-sniff the content type and forces it to stick with the declared content-type.'), + 'col' => 8, + 'label' => $this->l('Get an e-mail if your TLS certificate is about to expire'), + 'name' => 'LITE_TLS_EXPIRE', + 'disabled' => true, + 'is_bool' => true, + 'desc' => $this->proFeature . $this->l('Get notified if your TLS certificate is about to expire.') . ' ' . $this->l('Once this option is enabled, a cronjob will appear in your dashboard that you need to set up.'), 'values' => [ [ 'id' => 'active_on', @@ -1383,60 +1492,340 @@ protected function fieldsFormSecuritySettings() ], ], ], - [ - 'disabled' => true, - 'tab' => 'secureFrontOffice', - 'type' => 'switch', - 'label' => $this->l('Force secure connection with HSTS'), - 'name' => 'LITE_STRICT_TRANSPORT_SECURITY', - 'is_bool' => true, - 'desc' => $this->proFeature . $this->l('Strengthens your implementation of TLS by getting the user agent to enforce the use of HTTPS.'), - 'values' => [ - [ - 'id' => 'active_on', - 'value' => 1, - 'label' => $this->l('Enabled'), - ], - [ - 'id' => 'active_off', - 'value' => 0, - 'label' => $this->l('Disabled'), - ], - ], + ], + 'submit' => [ + 'title' => $this->l('Save'), + ], + ], + ]; + } + + /** + * Display dashboard. + * + * @return array + */ + protected function fieldsFormDashboard() + { + $cronJobs = []; + $link = ' ' . $this->l('Run cronjob'); + + // Cronjobs + if (true === (bool) Configuration::get('LITE_FILE_CHANGES_EMAIL') + || true === (bool) Configuration::get('LITE_FILE_CHANGES_LOG') + || true === (bool) Configuration::get('LITE_SERVER_IP') + || true === (bool) Configuration::get('LITE_SERVER_LOCATION') + || true === (bool) Configuration::get('LITE_SERVER_ISP') + || true === (bool) Configuration::get('LITE_DOMAIN_EXPIRE') + || true === (bool) Configuration::get('LITE_TLS_EXPIRE') + ) { + $cronJobs[] = [ + $this->l('Title') => $this->l('Monitoring'), + $this->l('Cronjob') => '' . $this->generateCronLink('Monitoring') . '', + null => '' . $this->generateBtnLink($link, $this->generateCronLink('Monitoring', true)) . '', + ]; + } + + // Validate input: Database backup + if (true === (bool) Configuration::get('LITE_BACKUP_DB')) { + $cronJobs[] = [ + $this->l('Title') => $this->l('Backup database'), + $this->l('Cronjob') => '' . $this->generateCronLink('BackupDatabase') . '', + null => '' . $this->generateBtnLink($link, $this->generateCronLink('BackupDatabase', true)) . '', + ]; + } + + $backupDir = _PS_MODULE_DIR_ . 'securitylite/backup'; + if (!\is_dir($backupDir . '/database/')) { + \mkdir($backupDir . '/database/', 0755, true); + $this->addIndexRecursively($backupDir); + \file_put_contents($backupDir . '/.htaccess', $this->getHtaccessContent()); + } + + $ext = [ + 'bz2', + 'gz', + 'zip', + ]; + + $fileBackupTotal = [ + [ + self::DIR_BACKUP_DATABASE, + 'BackupDatabaseDownload', + 'BackupDatabaseDelete', + $this->l('Database'), + ], + ]; + + $localBackup = []; + foreach ($fileBackupTotal as $fileBackupSingle) { + if ($handle = \opendir(_PS_MODULE_DIR_ . $this->name . $fileBackupSingle[0])) { + while (false !== ($entry = \readdir($handle))) { + if ('.' !== $entry && '..' !== $entry) { + if (\in_array(\pathinfo(\basename($entry), \PATHINFO_EXTENSION), $ext, true)) { + $pathToFile = \realpath(_PS_MODULE_DIR_ . $this->name . $fileBackupSingle[0] . $entry); + $date = \date('Y-m-d', \Tools::substr(\basename($entry), 0, 10)); + $localBackup[] = [ + $this->l('Type') => $fileBackupSingle[3], + $this->l('Size') => Tools::formatBytes(\filesize($pathToFile), 1) . 'B', + $this->l('Date') => $date, + $this->l('Path') => $pathToFile, + null => ' ' . $this->l('Delete') . ' ' . $this->l('Download') . '', + ]; + } + } + } + } + } + + $enabled = ''; + $disabled = ''; + + // Logs + $logTotal = [ + [ + $this->l('Firewall'), + self::LOG_FIREWALL, + 'Firewall', + (true === (bool) Configuration::get('LITE_FIREWALL_LOG')) ? $enabled : $disabled, + ], + [ + $this->l('Page not found'), + self::LOG_PAGE_NOT_FOUND, + 'PageNotFound', + (true === (bool) Configuration::get('LITE_PAGE_NOT_FOUND_LOG')) ? $enabled : $disabled, + ], + [ + $this->l('Malware scan'), + self::LOG_MALWARE_SCAN, + 'MalwareScan', + $disabled, + ], + [ + $this->l('File changes'), + self::LOG_FILE_CHANGES, + 'FileChanges', + $disabled, + ], + [ + $this->l('Cronjobs'), + self::LOG_CRONJOB, + 'Cronjob', + (!empty($cronJobs)) ? $enabled : $disabled, + ], + ]; + + $log = []; + foreach ($logTotal as $logSingle) { + $log[] = [ + $this->l('Title') => $logSingle[0], + $this->l('Size') => Tools::formatBytes(\filesize($this->getLogFile($logSingle[1])), 1) . 'B', + $this->l('Last modified') => \date('Y-m-d', \filemtime($this->getLogFile($logSingle[1]))), + $this->l('Path') => \realpath($this->getLogFile($logSingle[1])), + $this->l('Activated') => $logSingle[3], + null => ' ' . $this->l('Clear') . ' ' . $this->l('Download') . '', + ]; + } + + $cachePath = _PS_CACHE_DIR_ . 'securitylite'; + $cache = []; + $cache[] = [ + $this->l('Title') => $this->l('Cache'), + $this->l('Size') => Tools::formatBytes($this->getDirectorySize([$cachePath]), 1) . 'B', + $this->l('Description') => $this->l('Clear cache and statistics generated by this module.'), + null => ' ' . $this->l('Clear cache') . '', + ]; + + $employeeData = $this->getEmployees(false); + + $employee = []; + foreach ($employeeData as $data) { + $employee[] = [ + $this->l('Name') => $data['firstname'] . ' ' . $data['lastname'], + $this->l('E-mail') => $data['email'], + $this->l('Last password generated') => $data['last_passwd_gen'], + $this->l('Last connection') => (!empty($data['last_connection_date'])) ? $data['last_connection_date'] : '--', + $this->l('Activated') => $data['active'] ? $enabled : $disabled, + null => '' . $this->generateBtnLink(' ' . $this->l('Edit'), $this->getEmployeeAdminLink($data['id_employee'])) . '', + ]; + } + + $out = []; + + $out[] = $this->addHeading($this->l('Logs'), true) . $this->arrayToTable($log); + + $out[] = $this->addHeading($this->l('Employee statistics')) . $this->arrayToTable($employee); + + $outCron = []; + if (!empty($cronJobs)) { + $outCron[] = $this->addHeading($this->l('Cronjobs')); + + if (false === (bool) Configuration::get('PS_SHOP_ENABLE')) { + $outCron[] = $this->addAlertWarning($this->l('Information: You cannot run cronjobs while your shop is in maintenance mode.')); + } + + $outCron[] = $this->addAlertInfo($this->l('Please set up below cronjobs. It is recommended to run the cronjobs once a day') . ': ' . \htmlentities('0 3 * * * <' . $this->l('cronjob') . '>') . '
' . $this->l('If your host does not allow you to set up cronjobs, you can use this service instead') . ': ' . $this->generateLink('https://cron-job.org/en/members/jobs/add/') . '
' . $this->l('Learn more about cronjobs') . ' ' . $this->generateLink('https://en.wikipedia.org/wiki/Cron', $this->l('here')) . '.'); + + $outCron[] = $this->arrayToTable($cronJobs); + } + + $out[] = \implode('', $outCron); + + if (!empty($localBackup)) { + $out[] = $this->addHeading($this->l('Local backups')) . $this->arrayToTable($localBackup); + } + + $out[] = $this->addHeading($this->l('Cache')) . $this->arrayToTable($cache); + + return [ + 'form' => [ + 'legend' => [ + 'title' => $this->l('Dashboard'), + 'icon' => 'icon-dashboard', + ], + 'input' => [ + [ + 'type' => 'html', + 'label' => '', + 'html_content' => \implode('
', $out), + 'col' => 12, + 'name' => '', ], + ], + ], + ]; + } + + /** + * Display analyze of system table. + * + * @return array + */ + protected function fieldsFormAnalyzeSystem() + { + $checkCves = [ + $this->checkCve202015162(), + $this->checkCve202015161(), + $this->checkCve202015160(), + $this->checkCve202015083(), + $this->checkCve202015082(), + $this->checkCve202015081(), + $this->checkCve202015080(), + $this->checkCve202015079(), + $this->checkCve20205293(), + $this->checkCve20205288(), + $this->checkCve20205287(), + $this->checkCve20205286(), + $this->checkCve20205285(), + $this->checkCve20205279(), + $this->checkCve20205278(), + $this->checkCve20205276(), + $this->checkCve20205272(), + $this->checkCve20205271(), + $this->checkCve20205270(), + $this->checkCve20205269(), + $this->checkCve20205265(), + $this->checkCve20205264(), + $this->checkCve20205250(), + $this->checkCve20204074(), + $this->checkCve201913461(), + $this->checkCve201911876(), + $this->checkCve20188824(), + $this->checkCve20188823(), + $this->checkCve201819355(), + $this->checkCve201819125(), + $this->checkCve201819126(), + $this->checkCve201819124(), + $this->checkCve201813784(), + $this->checkCve20187491(), + $this->checkCve20179841(), + ]; + + $checkSettings = [ + $this->checkPrestaShopVersion(), + $this->checkPhpVersion(), + $this->checkTlsEnabled(), + $this->checkTlsEnabledEverywhere(), + $this->checkPrestashopToken(), + $this->checkModSecurity(), + $this->checkAdminDirectoryName(), + $this->checkCookieIpAddress(), + $this->checkPrestashopDevMode(), + ]; + + $check = ''; + $vulnerable = ''; + $possible = ''; + $good = '--'; + + $cveResult = []; + foreach ($checkCves as $checkCve) { + (true === $checkCve[1]) ? $nvdNist = $this->getCachedJsonDecodedContent('https://services.nvd.nist.gov/rest/json/cve/1.0/' . $checkCve[0], null, $checkCve[0], 604800)['result']['CVE_Items'][0] : $nvdNist = null; + + $cveResult[] = [ + 'CVE' => $this->generateLink('https://nvd.nist.gov/vuln/detail/' . $checkCve[0], $checkCve[0]), + $this->l('Status') => (true === $checkCve[1]) ? $possible : $check, + $this->l('Base score') => (true === $checkCve[1]) ? $nvdNist['impact']['baseMetricV3']['cvssV3']['baseScore'] . ' ' . $nvdNist['impact']['baseMetricV3']['cvssV3']['baseSeverity'] : $good, + $this->l('Description') => (true === $checkCve[1]) ? $nvdNist['cve']['description']['description_data'][0]['value'] : $good, + $this->l('How to fix') => (true === $checkCve[1]) ? $this->proFeature : $good, + ]; + } + + $prestaResult = []; + foreach ($checkSettings as $checkSetting) { + $prestaResult[] = [ + $this->l('Check') => $checkSetting[0], + $this->l('Status') => $checkSetting[1] ? $vulnerable : $check, + $this->l('Description') => $checkSetting[1] ? $checkSetting[3] : $good, + $this->l('How to fix') => $this->proFeature, + ]; + } + + $result = $this->addHeading($this->l('Check for insecure PrestaShop settings'), true) . $this->addAlertInfo($this->l('Recommend more secure options for your installation.')) . $this->arrayToTable($prestaResult) . '
' . $this->addHeading($this->l('Check for common vulnerabilities and exposures')) . $this->addAlertInfo($this->l('Scan your PrestaShop website for common vulnerabilities and exposures.')) . $this->arrayToTable($cveResult); + + return [ + 'form' => [ + 'legend' => [ + 'title' => $this->l('Analyze System'), + 'icon' => 'icon-list', + ], + 'input' => [ [ - 'disabled' => true, - 'tab' => 'secureFrontOffice', - 'type' => 'checkbox', - 'desc' => $this->proFeature . $this->l('Please follow this link to understand these settings: ') . ' https://hstspreload.org/?domain=' . $this->getShopUrl() . '.', - 'label' => $this->l('HSTS settings'), - 'name' => 'LITE_HSTS_SETTINGS', - 'values' => [ - 'query' => [ - [ - 'id_option' => '0', - 'name' => 'Preload', - 'value' => 0, - ], - [ - 'id_option' => '1', - 'name' => 'Include subdomains', - 'value' => 1, - ], - ], - 'id' => 'id_option', - 'name' => 'name', - 'value' => 'value', - ], + 'type' => 'html', + 'label' => '', + 'html_content' => $result, + 'col' => 12, + 'name' => '', ], + ], + ], + ]; + } + + /** + * Display form for configuration of maintenance mode. + * + * @return array + */ + protected function fieldsFormMaintenanceMode() + { + $maintenanceLink = $this->getAdminLink('AdminMaintenance', true); + + return [ + 'form' => [ + 'legend' => [ + 'title' => $this->l('Advanced Maintenance Mode'), + 'icon' => 'icon-wrench', + ], + 'description' => $this->l('PrestaShop\'s default maintenance mode is very limited. To lower the risk of losing customers while having your shop in maintenance mode, you can use this advanced maintenance mode which is much more user-friendly.') . ' ' . $this->l('If you need to change the text or translate its content, you must do it by PrestaShop\'s translate system.') . ' ' . $this->l('You can enable/disable maintenance mode') . ' ' . $this->generateLink($maintenanceLink, $this->l('here')) . '.', + 'input' => [ [ - 'disabled' => true, - 'tab' => 'secureFrontOffice', 'type' => 'switch', - 'label' => $this->l('Expect CT'), - 'name' => 'LITE_EXPECT_CT', + 'col' => 8, + 'label' => $this->l('Use advanced maintenance mode'), + 'name' => 'LITE_ADVANCED_MAINTENANCE_MODE', 'is_bool' => true, - 'desc' => $this->proFeature . $this->l('Signals to the user agent that compliance with the certificate transparency policy should be enforced.'), + 'desc' => $this->l('This feature does not activate maintenance mode. It does just replace the default maintenance mode with Security Lite\'s advanced maintenance mode.'), 'values' => [ [ 'id' => 'active_on', @@ -1451,13 +1840,84 @@ protected function fieldsFormSecuritySettings() ], ], [ - 'disabled' => true, - 'tab' => 'secureFrontOffice', + 'col' => 4, + 'type' => 'text', + 'prefix' => '', + 'desc' => $this->l('Company name to be displayed.') . ' ' . $this->l('You can leave this field empty if you don\'t want to show this information.'), + 'name' => 'LITE_ADVANCED_MAINTENANCE_MODE_COMPANY', + 'label' => $this->l('Company'), + ], + [ + 'col' => 4, + 'type' => 'text', + 'prefix' => '', + 'desc' => $this->l('Address to be displayed.') . ' ' . $this->l('You can leave this field empty if you don\'t want to show this information.'), + 'name' => 'LITE_ADVANCED_MAINTENANCE_MODE_ADDRESS', + 'label' => $this->l('Address'), + ], + [ + 'col' => 4, + 'type' => 'text', + 'prefix' => '', + 'desc' => $this->l('The phone number to be displayed.') . ' ' . $this->l('You can leave this field empty if you don\'t want to show this information.'), + 'name' => 'LITE_ADVANCED_MAINTENANCE_MODE_PHONE', + 'label' => $this->l('Phone'), + ], + [ + 'col' => 4, + 'type' => 'text', + 'prefix' => '', + 'desc' => $this->l('E-mail address to be displayed.') . ' ' . $this->l('You can leave this field empty if you don\'t want to show this information.'), + 'name' => 'LITE_ADVANCED_MAINTENANCE_MODE_EMAIL', + 'label' => $this->l('E-mail'), + ], + [ + 'col' => 4, + 'type' => 'text', + 'prefix' => '', + 'desc' => $this->l('Your Facebook page.') . ' ' . $this->l('You can leave this field empty if you don\'t want to show this information.'), + 'name' => 'LITE_ADVANCED_MAINTENANCE_MODE_FACEBOOK', + 'label' => 'Facebook', + ], + [ + 'col' => 4, + 'type' => 'text', + 'prefix' => '', + 'desc' => $this->l('Your Twitter profile.') . ' ' . $this->l('You can leave this field empty if you don\'t want to show this information.'), + 'name' => 'LITE_ADVANCED_MAINTENANCE_MODE_TWITTER', + 'label' => 'Twitter', + ], + [ + 'col' => 4, + 'type' => 'text', + 'prefix' => '', + 'desc' => $this->l('Your Instagram page.') . ' ' . $this->l('You can leave this field empty if you don\'t want to show this information.'), + 'name' => 'LITE_ADVANCED_MAINTENANCE_MODE_INSTAGRAM', + 'label' => 'Instagram', + ], + [ + 'col' => 4, + 'type' => 'text', + 'prefix' => '', + 'desc' => $this->l('Your Pinterest page.') . ' ' . $this->l('You can leave this field empty if you don\'t want to show this information.'), + 'name' => 'LITE_ADVANCED_MAINTENANCE_MODE_PINTEREST', + 'label' => 'Pinterest', + ], + [ + 'col' => 4, + 'type' => 'text', + 'prefix' => '', + 'desc' => $this->l('Your YouTube channel.') . ' ' . $this->l('You can leave this field empty if you don\'t want to show this information.'), + 'name' => 'LITE_ADVANCED_MAINTENANCE_MODE_YOUTUBE', + 'label' => 'YouTube', + ], + [ 'type' => 'switch', - 'label' => $this->l('Referrer policy'), - 'name' => 'LITE_REFFERER_POLICY', + 'col' => 8, + 'label' => $this->l('Show copyright'), + 'name' => 'LITE_ADVANCED_MAINTENANCE_MODE_COPYRIGHT', 'is_bool' => true, - 'desc' => $this->proFeature . $this->l('The browser will only set the referrer header on requests to the same origin. If the destination is another origin then no referrer information will be sent.') . '


Analyze security HTTP headers
' . $this->l('Security Pro can fix all warnings and errors reported by') . ' https://securityheaders.com; ' . $this->l('you can get an') . ' A+ ' . $this->l('score') . '!', + 'desc' => $this->l('Show copyright at the bottom of the maintenance site.'), 'values' => [ [ 'id' => 'active_on', @@ -1472,14 +1932,12 @@ protected function fieldsFormSecuritySettings() ], ], [ - 'disabled' => true, - 'col' => 6, - 'tab' => 'secondLogin', 'type' => 'switch', - 'label' => $this->l('Activate second login'), - 'name' => 'LITE_HTPASSWD', + 'col' => 8, + 'label' => $this->l('Display logo'), + 'name' => 'LITE_ADVANCED_MAINTENANCE_MODE_LOGO', 'is_bool' => true, - 'desc' => $this->proFeature . $this->l('Even if your back office is already secured by PrestaShop\'s login, you might want to add another layer of security from your webserver itself. This is done using .htpasswd (Apache-servers only).'), + 'desc' => $this->l('Display your logo in the top left corner of the maintenance site.'), 'values' => [ [ 'id' => 'active_on', @@ -1494,184 +1952,689 @@ protected function fieldsFormSecuritySettings() ], ], [ - 'disabled' => true, - 'col' => 3, - 'tab' => 'secondLogin', - 'type' => 'text', - 'prefix' => '', - 'desc' => $this->proFeature . $this->l('You should use another username than you do for your regular back office login.') . ' ' . $this->l('Generate secure username') . '.', - 'name' => 'LITE_HTPASSWD_USER', - 'label' => $this->l('Username'), - 'hint' => $this->l('Invalid character') . ': ":"', - ], - [ - 'disabled' => true, - 'col' => 3, - 'tab' => 'secondLogin', + 'col' => 4, 'type' => 'text', - 'prefix' => '', - 'desc' => $this->proFeature . $this->l('You should use another password than you do for your regular back office login.') . ' ' . $this->l('Generate secure password') . '.', - 'name' => 'LITE_HTPASSWD_PASS', - 'label' => $this->l('Password'), - 'hint' => $this->l('Invalid character') . ': ":"', - ], - [ - 'disabled' => true, - 'tab' => 'antiSpam', - 'type' => 'switch', - 'col' => 6, - 'label' => $this->l('Prevent fake accounts'), - 'name' => 'LITE_FAKE_ACCOUNTS', - 'is_bool' => true, - 'desc' => $this->proFeature . $this->l('Prevent bots from making fake accounts by setting a token and verify that first name and last name is not an URL.'), - 'values' => [ - [ - 'id' => 'active_on', - 'value' => 1, - 'label' => $this->l('Enabled'), - ], - [ - 'id' => 'active_off', - 'value' => 0, - 'label' => $this->l('Disabled'), - ], - ], - ], - [ - 'disabled' => true, - 'tab' => 'antiSpam', - 'type' => 'switch', - 'col' => 6, - 'label' => $this->l('Disable contact form'), - 'name' => 'LITE_DISABLE_CONTACT_FORM', - 'is_bool' => true, - 'desc' => $this->proFeature . $this->l('Sometimes you just want to leave a simple e-mail link in your footer and let users use their own e-mail client to send e-mails instead of the built-in contact form. If you want to disable the contact form you can enable this feature.'), - 'values' => [ - [ - 'id' => 'active_on', - 'value' => 1, - 'label' => $this->l('Enabled'), - ], - [ - 'id' => 'active_off', - 'value' => 0, - 'label' => $this->l('Disabled'), - ], - ], - ], - [ - 'disabled' => true, - 'tab' => 'antiSpam', - 'type' => 'switch', - 'col' => 6, - 'label' => $this->l('Block TOR IPv4 and IPv6 addresses'), - 'name' => 'LITE_BLOCK_TOR', - 'is_bool' => true, - 'desc' => $this->proFeature . $this->l('In some cases, TOR browsers are used by criminals to hide themselves while buying from a stolen credit card. If you are having this problem, you can block TOR IPv4/IPv6 addresses with this feature.'), - 'values' => [ - [ - 'id' => 'active_on', - 'value' => 1, - 'label' => $this->l('Enabled'), - ], - [ - 'id' => 'active_off', - 'value' => 0, - 'label' => $this->l('Disabled'), - ], - ], - ], - [ - 'tab' => 'antiSpam', - 'type' => 'switch', - 'col' => 6, - 'label' => $this->l('Block custom list of IP addresses'), - 'name' => 'LITE_BAN_IP_ACTIVATE', - 'is_bool' => true, - 'desc' => $this->l('Block hosts with below IP addresses from your website. You cannot block hosts that are already on this') . ' ' . $this->l('whitelist') . '. ' . $this->l('If you want to ban a country, please use this built-in PrestaShop feature') . ': ' . $this->l('Ban countries') . '. ', - 'values' => [ - [ - 'id' => 'active_on', - 'value' => 1, - 'label' => $this->l('Enabled'), - ], - [ - 'id' => 'active_off', - 'value' => 0, - 'label' => $this->l('Disabled'), - ], - ], + 'desc' => $this->l('Path to the logo that you would like to be displayed.') . ' ' . $this->l('If the field is empty the default logo will be used.'), + 'name' => 'LITE_ADVANCED_MAINTENANCE_MODE_LOGO_PATH', + 'label' => $this->l('Logo path'), ], + ], + 'submit' => [ + 'title' => $this->l('Save'), + ], + ], + ]; + } + + /** + * Display form for help. + * + * @return array + */ + protected function fieldsFormHelp() + { + $lang = $this->context->language->iso_code; + + switch ($lang) { + case 'fr': + $trans = 'fr/contactez-nous'; + break; + case 'es': + $trans = 'es/contacte-con-nosotros'; + break; + case 'de': + $trans = 'de/contact-us'; + break; + case 'it': + $trans = 'it/contact-us'; + break; + case 'nl': + $trans = 'nl/contact-us'; + break; + case 'pl': + $trans = 'pl/contact-us'; + break; + case 'pt': + $trans = 'pt/contact-us'; + break; + case 'ru': + $trans = 'ru/contact-us'; + break; + + default: + $trans = 'en/contact-us'; + } + $total = []; + $total[] = $this->addParagraph($this->l('Thanks for using Security Lite! Questions, issues, or feature requests?')); + + $url = 'https://addons.prestashop.com/' . $trans . '?id_product=44413'; + $total[] = $this->generateBtnLink($this->l('Contact module developer'), $url) . '

'; + + $total[] = $this->addParagraph($this->l('Would you like to translate this module into your language or improve the wording?')); + + $list = [ + $this->l('Click \'Translate\' (flag icon) in the upper right corner.'), + $this->l('Choose language.'), + $this->l('Make your changes and save.'), + ]; + + $total[] = '

  1. ' . \implode('
  2. ', $list) . '
'; + + $total[] = $this->addParagraph($this->l('If you make any improvements to the wording, please export your translation and send it to the module developer, then your improvements will be merged into the next release. Your contribution is appreciated!')); + + $total[] = $this->disabledBtn($this->l('Export translations')); + + return [ + 'form' => [ + 'legend' => [ + 'title' => $this->l('Help'), + 'icon' => 'icon-question-circle', + ], + 'input' => [ [ - 'tab' => 'antiSpam', - 'type' => 'text', - 'col' => 6, - 'desc' => $this->l('The module can handle IPv4, IPv6 addresses, as well as IP ranges, in CIDR formats') . '( ' . $this->l('like') . ' ::1/128 ' . $this->l('or') . ' 127.0.0.1/32) ' . $this->l('and in pattern format') . ' (' . $this->l('like') . ' ::*:* ' . $this->l('or') . ' 127.0.*.*). ' . $this->l('Separate by comma (\',\').'), - 'name' => 'LITE_BAN_IP', - 'label' => $this->l('Custom list of IP addresses'), - 'hint' => $this->l('E.g.') . ' 123.456.789,123.456.*,123.*,...', + 'type' => 'html', + 'label' => '', + 'html_content' => \implode('', $total), + 'col' => 12, + 'name' => '', ], + ], + ], + ]; + } + + /** + * Display form for help. + * + * @return array + */ + protected function fieldsFormAutoConfig() + { + $total = []; + + $total[] = ''; + + $total[] = $this->addHeading($this->l('Step 1: Configuration of Security Lite'), true); + + $total[] = $this->addParagraph($this->l('It\'s recommended doing a manual configuration of the module. However, if the many features seem overwhelming, you can run a basic auto-configuration of the module. Then you can afterwards fine-tune the settings depending on your needs.')); + + $total[] = $this->addParagraph($this->l('Before we go on it is highly recommended, to add the following keys at') . ' ' . $this->l('General Settings') . '.'); + + $list = [ + $this->l('Site key (reCAPTCHA v2)'), + $this->l('Secret key (reCAPTCHA v2)'), + $this->l('Honeypot API'), + ]; + + $total[] = '
  1. ' . \implode('
  2. ', $list) . '
'; + + $total[] = '
' . $this->disabledBtn(' ' . $this->l('Run auto-configuration')) . ' ' . $this->addParagraph(' ' . $this->l('Running the auto-configuration will change your current settings of Security Lite, so don\'t do it, if you have already configured the module.'), true) . '
'; + + $total[] = $this->addHeading($this->l('Step 2: Fix vulnerabilities on your system')); + + $total[] = $this->addParagraph($this->l('Go to') . ' ' . $this->l('Tools') . '. ' . $this->l('There you will find tools to fix insecure file permissions, directory traversal vulnerability, and a tool to delete files that make your shop vulnerable. It is possible to generate a report, to understand what changes the tools will do.')); + + $total[] = $this->addHeading($this->l('Step 3: Analyze your system')); + + $total[] = $this->addParagraph($this->l('Go to') . ' ' . $this->l('Analyze System') . ' ' . $this->l('and fix as many vulnerabilities as possible.')); + + $total[] = $this->addHeading($this->l('Step 4: Analyze your server configuration')); + + $total[] = $this->addParagraph($this->l('Go to') . ' ' . $this->l('Analyze Server Configuration') . ' ' . $this->l('and have a look at the analysis. Here you will see some advanced tips to improve your PHP configuration file. If you are not familiar with this kind of configuration, you can ask your host for help.')); + + $total[] = $this->addHeading($this->l('Step 5: Analyze your modules')); + + $total[] = $this->addParagraph($this->l('Go to') . ' ' . $this->l('Analyze Modules') . '. ' . $this->l('Here you will see all modules installed in your shop. If you are not using some of the modules, it\'s recommended to uninstall them, especially if those modules are not trusted modules.')); + + $total[] = $this->addHeading($this->l('Step 6: Test your shop')); + + $total[] = $this->addParagraph($this->l('Now test your website to confirm that everything is running:')); + + $test = [ + $this->l('Register a new customer'), + $this->l('Make a test order'), + $this->l('Navigate to different products'), + $this->l('Navigate to different categories'), + ]; + + $total[] = '
  1. ' . \implode('
  2. ', $test) . '
'; + + $total[] = $this->addHeading($this->l('Step 7: Setup cronjobs')); + + $total[] = $this->addParagraph($this->l('Go to the') . ' ' . $this->l('Dashboard') . '. ' . $this->l('There you will see a section named \'Cronjobs\'. Cronjobs are time-based job scheduler in Unix-like computer operating systems. The cronjobs are used to run features like the malware scanner, the monitoring service, backups, etc. It\'s recommended to set up these cronjobs to run once a day. If you are not familiar with cronjobs, you can ask your host for help.')); + + return [ + 'form' => [ + 'legend' => [ + 'title' => $this->l('Documentation'), + 'icon' => 'icon-book', + ], + 'input' => [ [ - 'tab' => 'antiSpam', - 'type' => 'switch', - 'col' => 4, - 'label' => $this->l('Block custom list of user agents'), - 'name' => 'LITE_BLOCK_USER_AGENT_ACTIVATE', - 'is_bool' => true, - 'desc' => $this->l('Block user agents with below names from your website.'), - 'values' => [ - [ - 'id' => 'active_on', - 'value' => 1, - 'label' => $this->l('Enabled'), - ], - [ - 'id' => 'active_off', - 'value' => 0, - 'label' => $this->l('Disabled'), - ], - ], + 'type' => 'html', + 'label' => '', + 'html_content' => \implode('', $total), + 'col' => 12, + 'name' => '', ], + ], + ], + ]; + } + + /** + * @return array + */ + protected function fieldsFormAnalyzeServerConfig() + { + $checkGrids = [ + $this->checkSessionAutoStart(), + $this->checkSessionUseCookies(), + $this->checkSessionUseOnlyCookies(), + $this->checkSessionCookieHttponly(), + $this->checkPhpUseTransSid(), + $this->checkCookieSecure(), + $this->checkUseScrickMode(), + $this->checkCookieLifetime(), + $this->checkLazyWrite(), + $this->checkSidLength(), + $this->checkSessionGcProbability(), + $this->checkSessionGcDivisor(), + $this->checkSidBitsPerCharacter(), + $this->checkUrlFopen(), + $this->checkUrlInclude(), + $this->checkDisplayErrors(), + $this->checkLogErrors(), + $this->checkErrorReporting(), + $this->checkDisplayStartupErrors(), + $this->checkExposePhp(), + $this->checkRegisterArgcArgv(), + $this->checkShortOpenTag(), + $this->checkFileUploads(), + $this->checkUploadMaxFileSize(), + $this->checkPostMaxSize(), + $this->checkMaxInputVars(), + $this->checkMaxInputTime(), + $this->checkMemoryLimit(), + $this->checkMaxExecutionTime(), + $this->checkDefaultCharset(), + ]; + + $check = ''; + $vulnerable = ''; + $good = '--'; + + $result = []; + foreach ($checkGrids as $checkGrid) { + $result[] = [ + $this->l('Key') => $checkGrid[0], + $this->l('Current') => $checkGrid[1], + $this->l('Recommended') => $this->proFeature, + $this->l('Status') => $checkGrid[3] ? $vulnerable : $check, + $this->l('Description') => $checkGrid[3] ? $checkGrid[4] : $good, + ]; + } + + return [ + 'form' => [ + 'legend' => [ + 'title' => $this->l('Analyze Server Configuration'), + 'icon' => 'icon-list', + ], + 'description' => $this->l('Here are some advanced tips to secure your PHP configuration file. Your PHP configuration file is named php.ini. This file could be stored in different locations according to your setup. If you are not familiar with php.ini, you can ask your host for help.') . '
' . $this->l('According to your system, the loaded php.ini file is located here') . ': ' . \php_ini_loaded_file() . ', ' . $this->l('but keep in mind that this php.ini file could be overridden somewhere, depending on your setup.'), + 'input' => [ [ - 'tab' => 'antiSpam', - 'type' => 'text', - 'col' => 6, - 'desc' => $this->l('Separate by comma (\',\').'), - 'name' => 'LITE_BLOCK_USER_AGENT', - 'label' => $this->l('Custom list of User agents'), - 'hint' => $this->l('E.g.') . ' 360Spider,Alexibot,BackWeb,...', + 'type' => 'html', + 'label' => '', + 'html_content' => $this->arrayToTable($result), + 'col' => 12, + 'name' => '', ], - [ - 'disabled' => true, - 'tab' => 'antiVirus', - 'type' => 'switch', - 'col' => 6, - 'label' => $this->l('Get an e-mail if file changes'), - 'name' => 'LITE_FILE_CHANGES_EMAIL', - 'is_bool' => true, - 'desc' => $this->proFeature . $this->l('Track every file change on your server and let you know by e-mail if something has changed.') . ' ' . $this->l('Once this option is enabled, you will get a link you have set up as a cronjob.'), - 'values' => [ - [ - 'id' => 'active_on', - 'value' => 1, - 'label' => $this->l('Enabled'), - ], - [ - 'id' => 'active_off', - 'value' => 0, - 'label' => $this->l('Disabled'), - ], - ], + ], + ], + ]; + } + + /** + * @return array + */ + protected function fieldsFormAnalyzeSsl() + { + $url = 'https://www.howsmyssl.com/a/check'; + + $ssl = $this->getCertInfo(); + + $data = $this->getCachedJsonDecodedContent($url, null, 'certificate', 604800); + + $check = ''; + $vulnerable = ''; + $possible = ''; + + if (isset($ssl['validTo_time_t']) && ($ssl['validTo_time_t'] - \time() > 0)) { + $isValid = $check; + } else { + $isValid = $vulnerable; + } + + if (false !== $ssl) { + $certInfos = [ + $this->l('Is valid') => $isValid, + $this->l('Common name') => $ssl['subject']['CN'], + $this->l('Alternative names') => \str_replace('DNS:', '', $ssl['extensions']['subjectAltName']), + $this->l('Issuer') => $ssl['issuer']['CN'], + $this->l('Valid from') => \date('Y-m-d', ($ssl['validFrom_time_t'])), + $this->l('Valid to') => \date('Y-m-d', ($ssl['validTo_time_t'])), + $this->l('Expires in') => \round(($ssl['validTo_time_t'] - \time()) / (86400)) . ' ' . $this->l('days'), + ]; + + $tlsVersion = []; + $tlsVersion['name'] = $this->l('Version') . ' (' . $data['tls_version'] . ')'; + if ('TLS 1.2' === $data['tls_version'] || 'TLS 1.3' === $data['tls_version']) { + $tlsVersion['description'] = $this->l('Your client is using') . ' ' . $data['tls_version'] . ', ' . $this->l('the most modern version of the encryption protocol. It gives you access to the fastest, most secure encryption possible on the web.'); + $tlsVersion['check'] = $check; + } elseif ('TLS 1.1' === $data['tls_version']) { + $tlsVersion['description'] = $this->l('Your client is using + TLS 1.1. It would be better to be TLS 1.2, but at least it isn\'t + susceptible to the BEAST attack. But, it also doesn\'t have the + AES-GCM cipher suite available.'); + $tlsVersion['check'] = $vulnerable; + } else { + $tlsVersion['description'] = $this->l('Your client is using') . ' ' . $data['tls_version'] . ', ' . $this->l('which is very old, possibly susceptible to the BEAST attack, and doesn\'t have the best cipher suites available on it. Additions like AES-GCM, and SHA256 to replace MD5-SHA-1 are unavailable to a TLS 1.0 client as well as many more modern cipher suites.'); + $tlsVersion['check'] = $vulnerable; + } + $tlsVersion['btn'] = $this->generateBtnLink($this->l('Learn more'), 'https://www.howsmyssl.com/s/about.html#version'); + + $ephemeralKeysSupported = []; + $ephemeralKeysSupported['name'] = $this->l('Ephemeral Key Support'); + if (true === $data['ephemeral_keys_supported']) { + $ephemeralKeysSupported['description'] = $this->l('Ephemeral keys are used in some of the cipher suites your client supports. This means your client may be used to provide') . ' ' . $this->generateLink('https://en.wikipedia.org/wiki/Forward_secrecy', $this->l('forward secrecy')) . '. ' . $this->l('If the server supports it. This greatly increases your protection against snoopers, including global passive adversaries who scoop up large amounts of encrypted traffic and store them until their attacks (or their computers) improve.'); + $ephemeralKeysSupported['check'] = $check; + } else { + $ephemeralKeysSupported['description'] = $this->l('Ephemeral keys are not used in any of the cipher suites your client supports. This means your client cannot be used to provide') . ' ' . $this->generateLink('https://en.wikipedia.org/wiki/Forward_secrecy', $this->l('forward secrecy')) . '. ' . $this->l('Without it, global passive adversaries will be able to scoop up all of your encrypted traffic and decode it when their attacks or their computers are faster. This is actually happening.'); + $ephemeralKeysSupported['check'] = $vulnerable; + } + $ephemeralKeysSupported['btn'] = $this->generateBtnLink($this->l('Learn more'), 'https://www.howsmyssl.com/s/about.html#ephemeral-key-support'); + + $sessionTicketSupported = []; + $sessionTicketSupported['name'] = $this->l('Session Ticket Support'); + if (false === $data['session_ticket_supported']) { + $sessionTicketSupported['description'] = $this->l('Session tickets are supported in your client. Services you use will be able to scale out their TLS connections more easily with this feature.'); + $sessionTicketSupported['check'] = $check; + } else { + $sessionTicketSupported['description'] = $this->l('Session tickets are not supported in your client. Without them, services will have a harder time making your client\'s connections fast. Generally, clients with ephemeral key support get this for free.'); + $sessionTicketSupported['check'] = $vulnerable; + } + $sessionTicketSupported['btn'] = $this->generateBtnLink($this->l('Learn more'), 'https://www.howsmyssl.com/s/about.html#session-ticket-support'); + + $tlsCompressionSupported = []; + $tlsCompressionSupported['name'] = $this->l('TLS Compression'); + if (true === $data['tls_compression_supported']) { + $tlsCompressionSupported['description'] = $this->l('Your TLS client supports compressing the settings that encrypt your connection. This is really not good. It makes your TLS connections susceptible to the') . ' ' . $this->generateLink('https://en.wikipedia.org/wiki/CRIME', $this->l('CRIME attack')) . ' ' . $this->l('and your encrypted data could be leaked!'); + $tlsCompressionSupported['check'] = $vulnerable; + } else { + $tlsCompressionSupported['description'] = $this->l('Your TLS client does not attempt to compress the settings that encrypt your connection, avoiding information leaks from the') . ' ' . $this->generateLink('https://en.wikipedia.org/wiki/CRIME', $this->l('CRIME attack')) . '.'; + $tlsCompressionSupported['check'] = $check; + } + $tlsCompressionSupported['btn'] = $this->generateBtnLink($this->l('Learn more'), 'https://www.howsmyssl.com/s/about.html#tls-compression'); + + $beastVuln = []; + $beastVuln['name'] = $this->l('BEAST Vulnerability'); + if (true === $data['beast_vuln']) { + if (true === $data['able_to_detect_n_minus_one_splitting']) { + $beastVuln['description'] = $this->l('Your client is open to the') . ' ' . $this->generateLink('https://en.wikipedia.org/wiki/Transport_Layer_Security#BEAST_attack', $this->l('BEAST attack')) . '. ' . $this->l('It\'s using TLS 1.0 or earlier while also supporting a cipher suite that uses') . ' ' . $this->generateLink('https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation', $this->l('Cipher-Block Chaining')) . ' ' . $this->l('and doesn\'t implement the 1/n-1 record splitting mitigation. That combination will leak information.'); + $beastVuln['check'] = $vulnerable; + } else { + $beastVuln['description'] = $this->l('Your client is probably open to the') . $this->generateBtnLink('https://en.wikipedia.org/wiki/Transport_Layer_Security#BEAST_attack', $this->l('BEAST attack')) . ' ' . $this->l('because it\'s using TLS 1.0 or earlier while also supporting a cipher suite that uses') . ' ' . $this->generateLink('https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation', $this->l('Cipher-Block Chaining')) . '. ' . $this->l('However, the CBC cipher suites your client supports is not one How\'s My SSL is able to use, so it was unable to determine if your client implements the 1/n-1 record splitting mitigation. Clients with that uncommon of cipher suite selection rarely implement it, however, so it\'s best to assume the worst.'); + } + $beastVuln['check'] = $check; + } else { + if (true === $data['able_to_detect_n_minus_one_splitting']) { + $beastVuln['description'] = $this->l('Your client is not vulnerable to the') . ' ' . $this->generateLink('https://en.wikipedia.org/wiki/Transport_Layer_Security#BEAST_attack', $this->l('BEAST attack')) . ' ' . $this->l('While it\'s using TLS 1.0 in conjunction with') . ' ' . $this->generateLink('https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher-block_chaining_.28CBC.29', $this->l('Cipher-Block Chaining')) . ' ' . $this->l('cipher suites, it has implemented the 1/n-1 record splitting mitigation.'); + $beastVuln['check'] = $check; + } else { + $beastVuln['description'] = $this->l('Your client is not vulnerable to the') . ' ' . $this->generateLink('https://en.wikipedia.org/wiki/Transport_Layer_Security#BEAST_attack', $this->l('BEAST attack')) . ' ' . $this->l('because it\'s using a TLS protocol newer than TLS 1.0. The BEAST attack is only possible against clients using TLS 1.0 or earlier using') . ' ' . $this->generateLink('https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher-block_chaining_.28CBC.29', $this->l('Cipher-Block Chaining')) . ' ' . $this->l('cipher suites that don\'t implement the 1/n-1 record splitting mitigation.'); + $beastVuln['check'] = $check; + } + } + $beastVuln['btn'] = $this->generateBtnLink($this->l('Learn more'), 'https://www.howsmyssl.com/s/about.html#beast-vulnerability'); + + $insecureCipherSuites = []; + $insecureCipherSuites['name'] = $this->l('Insecure Cipher Suites'); + if (!empty($data['insecure_cipher_suites'])) { + $insecureCipherSuites['description'] = $this->l('Your client supports cipher suites that are known to be insecure') . ': ' . \implode(', ', $data['insecure_cipher_suites']); + $insecureCipherSuites['check'] = $vulnerable; + } else { + $insecureCipherSuites['description'] = $this->l('Your client doesn\'t use any cipher suites that are known to be insecure.'); + $insecureCipherSuites['check'] = $check; + } + $insecureCipherSuites['btn'] = $this->generateBtnLink($this->l('Learn more'), 'https://www.howsmyssl.com/s/about.html#insecure-cipher-suites'); + + $givenCipherSuites = []; + $givenCipherSuites['name'] = $this->l('Given cipher suites'); + if (!empty($data['given_cipher_suites'])) { + $givenCipherSuites['description'] = $this->l('The cipher suites your client said it supports, in the order it sent them, are') . ': ' . \implode(', ', $data['given_cipher_suites']); + } else { + $givenCipherSuites['description'] = $this->l('Your client doesn\'t use any cipher suites that are known to be insecure.'); + } + $givenCipherSuites['check'] = $possible; + $givenCipherSuites['btn'] = $this->generateBtnLink($this->l('Learn more'), 'https://www.howsmyssl.com/s/about.html#given-cipher-suites'); + + $mixedContent = []; + $mixedContent['name'] = $this->l('Mixed content'); + $mixedContent['description'] = $this->l('Mixed content occurs when initial HTML is loaded over a secure HTTPS connection, but other resources (such as images, videos, stylesheets, scripts) are loaded over an insecure HTTP connection. This is called mixed content because both HTTP and HTTPS content are being loaded to display the same page, and the initial request was secure over HTTPS. Modern browsers display warnings about this type of content to indicate to the user that this page contains insecure resources.'); + $mixedContent['check'] = $possible; + $mixedContent['btn'] = $this->disabledBtn($this->l('Scan for mixed content')); + + $sslAnalyze = []; + $sslAnalyze['name'] = $this->l('Analyze SSL/TLS'); + $sslAnalyze['description'] = $this->l('Scan your website with SSL Labs. It can give you a better understanding of how your SSL/TLS is deployed.'); + $sslAnalyze['check'] = $possible; + $sslAnalyze['btn'] = $this->disabledBtn($this->l('Analyze SSL/TLS')); + + $certChecks = [ + [ + $tlsVersion['name'], + $tlsVersion['description'], + $tlsVersion['check'], + $tlsVersion['btn'], + ], + [ + $ephemeralKeysSupported['name'], + $ephemeralKeysSupported['description'], + $ephemeralKeysSupported['check'], + $ephemeralKeysSupported['btn'], + ], + [ + $sessionTicketSupported['name'], + $sessionTicketSupported['description'], + $sessionTicketSupported['check'], + $sessionTicketSupported['btn'], + ], + [ + $tlsCompressionSupported['name'], + $tlsCompressionSupported['description'], + $tlsCompressionSupported['check'], + $tlsCompressionSupported['btn'], + ], + [ + $beastVuln['name'], + $beastVuln['description'], + $beastVuln['check'], + $beastVuln['btn'], + ], + [ + $insecureCipherSuites['name'], + $insecureCipherSuites['description'], + $insecureCipherSuites['check'], + $insecureCipherSuites['btn'], + ], + [ + $givenCipherSuites['name'], + $givenCipherSuites['description'], + $givenCipherSuites['check'], + $givenCipherSuites['btn'], + ], + [ + $mixedContent['name'], + $mixedContent['description'], + $mixedContent['check'], + $mixedContent['btn'], + ], + [ + $sslAnalyze['name'], + $sslAnalyze['description'], + $sslAnalyze['check'], + $sslAnalyze['btn'], + ], + ]; + + $certResult = []; + foreach ($certInfos as $certInfo => $key) { + $certResult[] = [ + $this->l('Title') => $certInfo, + $this->l('Description') => $key, + ]; + } + + $checkResult = []; + foreach ($certChecks as $certCheck) { + $checkResult[] = [ + $this->l('Title') => $certCheck[0], + $this->l('Description') => $certCheck[1], + $this->l('Check') => $certCheck[2], + null => '' . $certCheck[3] . '', + ]; + } + + $total = $this->arrayToTable($certResult) . '
' . $this->addAlertWarning($this->l('The test below is performed between your client/browser and your website.')) . $this->arrayToTable($checkResult); + } else { + $total = $this->addAlertWarning($this->l('You must install a TLS certificate and') . ' ' . $this->generateLink($this->getAdminLink('AdminPreferences', true), $this->l('enable SSL everywhere')) . ' ' . $this->l('before the analysis can be performed.')); + } + + return [ + 'form' => [ + 'legend' => [ + 'title' => $this->l('Analyze SSL/TLS'), + 'icon' => 'icon-list', + ], + 'description' => $this->l('The main use case for SSL/TLS is secure communications between a client and a server, but it is also used to secure your e-mails.'), + 'input' => [ + [ + 'type' => 'html', + 'label' => '', + 'html_content' => $total, + 'col' => 12, + 'name' => '', ], + ], + ], + ]; + } + + /** + * @return array + */ + protected function fieldsFormAnalyzeModules() + { + $trusted = []; + $result = null; + + // Not trusted modules + if (null !== $this->getModules(false)) { + foreach ($this->getModules(false) as $notTrustedModule) { + $trusted[] = [ + $this->l('Module') => $notTrustedModule, + $this->l('Trusted') => $this->proFeature, + ]; + } + } + + // Trusted modules + if (null !== $this->getModules(true)) { + foreach ($this->getModules(true) as $trustedModule) { + $trusted[] = [ + $this->l('Module') => $trustedModule, + $this->l('Trusted') => $this->proFeature, + ]; + } + } + + if (!empty($trusted)) { + $result = $this->arrayToTable($trusted); + } + + return [ + 'form' => [ + 'legend' => [ + 'title' => $this->l('Analyze Modules'), + 'icon' => 'icon-list', + ], + 'description' => $this->l('Modules that are nonnative PrestaShop modules or are not bought from PrestaShop Addons are untrusted. This means that they are not verified by PrestaShop. All of these modules can be safe even though they are not verified by PrestaShop, but be careful - in some cases these modules don\'t follow PrestaShop guidance and they can be insecure.') . ' ' . $this->l('Generally, third party modules provide additional security risks. Sometimes websites are hacked though insecure third-party modules. If there are any modules that you don\'t need, it is recommended to uninstall them.'), + 'input' => [ + [ + 'type' => 'html', + 'label' => '', + 'html_content' => $result, + 'col' => 12, + 'name' => '', + ], + ], + ], + ]; + } + + /** + * @return array + */ + protected function fieldsFormTools() + { + $buttons = [ + [ + $this->l('Port scanner'), + $this->l('Check for open ports on your network. If you have unused open ports, consider closing them.') . '
' . $this->l('Generate a report to see which ports are open.'), + '' . $this->generateBtnPost(' ' . $this->l('Generate report'), 'PortScannerAnalyze', false) . '', + ], + [ + $this->l('RBL checker'), + $this->l('Check if your server IP address is listed on the most common RBL\'s (Realtime Blackhole List).') . '
' . $this->l('Generate a report with the test results.'), + '' . $this->generateBtnPost(' ' . $this->l('Generate report'), 'RblCheckerAnalyze', false) . '', + ], + [ + $this->l('File permissions'), + $this->l('Check the systems file- and folder permissions. This tool can fix insecure file- and folder permissions.') . ' ' . $this->l('File permission must be 644 and folder permissions must be 755.') . '
' . $this->l('Generate a report to see permissions that must be changed.') . ' ' . $this->l('Start by generating a report to see the consequence.'), + '' . $this->disabledBtn(' ' . $this->l('Fix vulnerability')) . '' . $this->generateBtnPost(' ' . $this->l('Generate report'), 'PermissionsAnalyze', false) . '', + ], + [ + $this->l('Directory traversal'), + $this->l('Check the system for directory traversal security vulnerability.') . ' ' . $this->l('This tool can add missing index.php files to the theme- and module directories.') . '
' . $this->l('Generate a report to see which paths are missing the index.php file.'), + '' . $this->disabledBtn(' ' . $this->l('Fix vulnerability')) . '' . $this->generateBtnPost(' ' . $this->l('Generate report'), 'CreateIndexAnalyze', false) . '', + ], + [ + $this->l('Delete files'), + $this->l('Check the system for files that should be removed due to security reasons.') . ' ' . $this->l('This tool can remove these files. These files could be files leftover from the installation.') . '
' . $this->l('Generate a report to see which files should be deleted.') . ' ' . $this->l('Deleting files is permanent. Start by generating a report to see the consequence.'), + '' . $this->disabledBtn(' ' . $this->l('Fix vulnerability')) . '' . $this->generateBtnPost(' ' . $this->l('Generate report'), 'RemoveFilesAnalyze', false) . '', + ], + ]; + + $table = []; + $text = []; + + foreach ($buttons as $button) { + $table[] = [ + $this->l('Title') => $button[0], + $this->l('Description') => $button[1], + null => '' . $button[2] . '', + ]; + } + + $text[] = $this->arrayToTable($table); + + return [ + 'form' => [ + 'legend' => [ + 'title' => $this->l('Tools'), + 'icon' => 'icon-wrench', + ], + 'description' => $this->l('These tools can fix some known vulnerabilities. Some of these tools need up to 2 min. to run. Please wait until the page has finished loading.'), + 'input' => [ + [ + 'type' => 'html', + 'label' => '', + 'html_content' => \implode('', $text), + 'col' => 12, + 'name' => '', + ], + ], + ], + ]; + } + + /** + * @return array + */ + protected function fieldsFormBackup() + { + $backupDir = _PS_MODULE_DIR_ . 'securitylite/backup'; + if (!\is_dir($backupDir . '/database/')) { + \mkdir($backupDir . '/database/', 0755, true); + $this->addIndexRecursively($backupDir); + \file_put_contents($backupDir . '/.htaccess', $this->getHtaccessContent()); + } + + $dirPath = []; + $ext = [ + 'bz2', + 'gz', + ]; + + if ($handle = \opendir(_PS_MODULE_DIR_ . $this->name . self::DIR_BACKUP_DATABASE)) { + while (false !== ($entry = \readdir($handle))) { + if ('.' !== $entry && '..' !== $entry) { + if (\in_array(\pathinfo(\basename($entry), \PATHINFO_EXTENSION), $ext, true)) { + $pathToFile = \realpath(_PS_MODULE_DIR_ . $this->name . self::DIR_BACKUP_DATABASE . $entry); + $date = \date('Y-m-d', \Tools::substr(\basename($entry), 0, 10)); + $dirPath[] = ' ' . Tools::formatBytes(\filesize($pathToFile), 1) . 'B | ' . $pathToFile . ' (' . $date . ')'; + } + } + } + } + + return [ + 'form' => [ + 'legend' => [ + 'title' => $this->l('Automatic Backups'), + 'icon' => 'icon-files-o', + ], + 'description' => $this->l('Keeping a backup may be your easiest and best protection; allowing you to turn back the clock after an attack. While this doesn\'t prevent attacks, it does cure them when needed.') . ' ' . $this->generateLink('https://en.wikipedia.org/wiki/Backup', $this->l('Read more')) . '.', + 'warning' => $this->l('Security Lite') . ' ' . $this->l('is not responsible for your database/files, its backups, and/or recovery.') . '
' . + $this->l('You should back up your data regularly (both files and databases).') . '
' . + $this->l('Security Lite') . ' ' . $this->l('can back up your database and saves it locally.') . '
' . + $this->l('Always verify the quality and integrity of your backup files!') . '
' . + $this->l('Always verify that your backup files are complete, up-to-date, and valid, even if you had a success message appear during the backup process.') . '
' . + $this->l('Always check your data.') . '
' . + $this->l('Never restore a backup on a live site.'), + 'input' => [ [ - 'disabled' => true, - 'tab' => 'antiVirus', 'type' => 'switch', - 'col' => 6, - 'label' => $this->l('Log filechanges'), - 'name' => 'LITE_FILE_CHANGES_LOG', + 'col' => 8, + 'label' => $this->l('Backup database to Dropbox'), + 'name' => 'LITE_BACKUP_DB_DROPBOX', 'is_bool' => true, - 'desc' => $this->proFeature . $this->l('Track every file change on your server and log it if something has changed.'), + 'desc' => $this->proFeature . $this->l('Save a backup of your database to your Dropbox. Statistical data are excluded.') . ' ' . $this->l('Once this option is enabled, a cronjob will appear in your dashboard that you need to set up.'), + 'disabled' => true, 'values' => [ [ 'id' => 'active_on', @@ -1686,24 +2649,12 @@ protected function fieldsFormSecuritySettings() ], ], [ - 'disabled' => true, - 'tab' => 'antiVirus', - 'type' => 'text', - 'col' => 6, - 'desc' => $this->proFeature . $this->l('Whitelist dynamic files') . '. ' . $this->l('Separate files by comma (\',\')') . '.', - 'name' => 'LITE_FILE_CHANGES_WHITELIST', - 'label' => $this->l('Whitelist filter for file changes'), - 'hint' => $this->l('E.g.') . ' file.json,file.xml', - ], - [ - 'disabled' => true, - 'tab' => 'antiVirus', 'type' => 'switch', - 'col' => 6, - 'label' => $this->l('Get an e-mail if malware is detected'), - 'name' => 'LITE_MALWARE_SCAN_EMAIL', + 'col' => 8, + 'label' => $this->l('Backup database to local'), + 'name' => 'LITE_BACKUP_DB', 'is_bool' => true, - 'desc' => $this->proFeature . $this->l('Scan all your directories for malicious code and let you know by e-mail if something is found.') . ' ' . $this->l('Once this option is enabled, you will get a link you have set up as a cronjob.'), + 'desc' => $this->l('Save a local backup of your database. Statistical data are excluded.') . ' ' . $this->l('Once this option is enabled, a cronjob will appear in your dashboard that you need to set up.'), 'values' => [ [ 'id' => 'active_on', @@ -1718,14 +2669,24 @@ protected function fieldsFormSecuritySettings() ], ], [ - 'disabled' => true, - 'tab' => 'antiVirus', + 'col' => 4, + 'type' => 'text', + 'prefix' => '', + 'desc' => $this->l('Old backups will be deleted when a newer one is generated. How many backups do you want to keep at the time? Write, \'0\' for unlimited backups.'), + 'name' => 'LITE_BACKUP_DB_SAVED', + 'label' => $this->l('Database backups to save'), + 'suffix' => $this->l('backups'), + 'hint' => $this->l('Must be an integer'), + 'required' => true, + ], + [ 'type' => 'switch', - 'col' => 6, - 'label' => $this->l('Log malware'), - 'name' => 'LITE_MALWARE_SCAN_LOG', + 'col' => 8, + 'label' => $this->l('Backup files to Dropbox'), + 'name' => 'LITE_BACKUP_FILE_DROPBOX', 'is_bool' => true, - 'desc' => $this->proFeature . $this->l('Scan all your directories for malicious code and log it if something is found.'), + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('Save a full backup of your files to your Dropbox. Cache and log files are excluded.') . ' ' . $this->l('Once this option is enabled, a cronjob will appear in your dashboard that you need to set up.'), 'values' => [ [ 'id' => 'active_on', @@ -1740,36 +2701,13 @@ protected function fieldsFormSecuritySettings() ], ], [ - 'disabled' => true, - 'tab' => 'antiVirus', - 'type' => 'text', - 'col' => 6, - 'desc' => $this->l('Whitelist false positives, caused by custom modules etc.') . $this->l('Separate files by comma (\',\')') . '.', - 'name' => 'LITE_WHITELIST_MALWARE', - 'label' => $this->l('Whitelist filter for malware'), - 'hint' => $this->l('E.g.') . ' file.js,file.php', - ], - [ - 'disabled' => true, - 'col' => 3, - 'tab' => 'antiVirus', - 'type' => 'text', - 'prefix' => '', - 'desc' => $this->proFeature . $this->l('Enter the e-mail which you would like to be notified at.'), - 'name' => 'LITE_ANTI_VIRUS_EMAIL', - 'label' => $this->l('E-mail'), - 'hint' => $this->l('Need to be a valid e-mail address'), - 'required' => true, - ], - [ - 'disabled' => true, - 'tab' => 'antiVirus', 'type' => 'switch', - 'col' => 6, - 'label' => $this->l('Block file uploads'), - 'name' => 'LITE_BLOCK_FILE_UPLOAD_BACK_OFFICE_ACTIVATE', + 'col' => 8, + 'label' => $this->l('Backup files to local'), + 'name' => 'LITE_BACKUP_FILE', 'is_bool' => true, - 'desc' => $this->l('Block fileupload for specific files in back office. Add your custom list below.'), + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('Save a full backup of your files on your PrestaShop installation.') . ' ' . $this->l('Once this option is enabled, a cronjob will appear in your dashboard that you need to set up.'), 'values' => [ [ 'id' => 'active_on', @@ -1784,69 +2722,102 @@ protected function fieldsFormSecuritySettings() ], ], [ - 'disabled' => true, - 'tab' => 'antiVirus', + 'col' => 4, 'type' => 'text', - 'col' => 6, - 'desc' => $this->proFeature . $this->l('List all file extensions that you want to block in back office.') . ' ' . $this->l('Separate files by comma (\',\')') . '.', - 'name' => 'LITE_BLOCK_FILE_UPLOAD_BACK_OFFICE', - 'label' => $this->l('Custom list of file-extensions'), - 'hint' => $this->l('E.g.') . ' exe,com,bat', + 'prefix' => '', + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('Old backups will be deleted if a newer one is generated. How many backups do you want to keep at the time? Write, "0" for unlimited backups.'), + 'name' => 'LITE_BACKUP_FILE_SAVED', + 'label' => $this->l('File backups to save'), + 'suffix' => $this->l('backups'), + 'hint' => $this->l('Must be an integer'), + 'required' => true, ], [ - 'tab' => 'protectContent', 'type' => 'select', - 'label' => $this->l('Disable right click'), - 'desc' => $this->l('Disable right click mouse event.'), - 'name' => 'LITE_DISABLE_RIGHT_CLICK', + 'label' => $this->l('Zip compression level for file backup'), + 'desc' => $this->proFeature . $this->l('The values range from 1 (super-fast) to 9 (maximum) are supported. The higher the number, the better and longer the compression.'), + 'name' => 'LITE_BACKUP_COMPRESSION', + 'disabled' => true, 'options' => [ 'query' => [ [ - 'id_option' => '1', - 'name' => $this->l('No'), + 'id_option' => 'SUPER_FAST', + 'name' => '1 (' . $this->l('super-fast') . ')', ], [ - 'id_option' => '2', - 'name' => $this->l('Yes'), + 'id_option' => 'NORMAL', + 'name' => '5 (' . $this->l('normal') . ')', ], [ - 'id_option' => '3', - 'name' => $this->l('Only on images'), + 'id_option' => 'MAXIMUM', + 'name' => '9 (' . $this->l('maximum') . ')', ], ], 'id' => 'id_option', 'name' => 'name', ], ], + ], + 'submit' => [ + 'title' => $this->l('Save'), + ], + ], + ]; + } + + /** + * @return array + */ + protected function fieldsFormPasswdGen() + { + return [ + 'form' => [ + 'legend' => [ + 'title' => $this->l('Password Generator'), + 'icon' => 'icon-refresh', + ], + 'description' => $this->l('You should use a strong and unique password for each of MySQL database, FTP, hosting panel/cPanel, SSH access, and back office. You can use this tool to generate passwords.') . ' ' . $this->generateLink('https://en.wikipedia.org/wiki/Password_strength', $this->l('Read more')) . '.', + 'input' => [ [ - 'disabled' => true, - 'tab' => 'protectContent', - 'type' => 'switch', - 'label' => $this->l('Disable drag and drop'), - 'name' => 'LITE_DISABLE_DRAG', - 'is_bool' => true, - 'desc' => $this->proFeature . $this->l('Disable drag and drop mouse event.'), - 'values' => [ - [ - 'id' => 'active_on', - 'value' => 1, - 'label' => $this->l('Enabled'), - ], - [ - 'id' => 'active_off', - 'value' => 0, - 'label' => $this->l('Disabled'), + 'col' => 6, + 'type' => 'textbutton', + 'label' => $this->l('Generate a strong password'), + 'desc' => $this->l('The password is not saved anywhere by this module.'), + 'name' => 'LITE_PASSWORD_GENERATOR', + 'button' => [ + 'label' => $this->l('Generate'), + 'attributes' => [ + 'onclick' => 'addField1();', ], ], ], + ], + ], + ]; + } + + /** + * @return array + */ + protected function fieldsFormBruteForceProtection() + { + return [ + 'form' => [ + 'legend' => [ + 'title' => $this->l('Admin Brute Force Protection'), + 'icon' => 'icon-lock', + ], + 'description' => $this->l('A brute force attack is one of the simplest methods to gain access to a website. The hacker tries various combinations of usernames and passwords again and again until he gets in. The module can limit the tries to protect you from the attack.') . ' ' . $this->generateLink('https://en.wikipedia.org/wiki/Brute-force_attack', $this->l('Read more')) . '.', + 'input' => [ [ - 'disabled' => true, - 'tab' => 'protectContent', + 'col' => 8, 'type' => 'switch', - 'label' => $this->l('Disable copy'), - 'name' => 'LITE_DISABLE_COPY', + 'col' => 8, + 'label' => $this->l('Brute force protection'), + 'name' => 'LITE_FAIL2BAN', 'is_bool' => true, - 'desc' => $this->proFeature . $this->l('Disable copy (E.g. Ctrl + c / ⌘ + c).'), + 'desc' => $this->l('Enable brute force protection to limits the greatest amount of login tries to your back office.'), 'values' => [ [ 'id' => 'active_on', @@ -1861,34 +2832,46 @@ protected function fieldsFormSecuritySettings() ], ], [ - 'disabled' => true, - 'tab' => 'protectContent', - 'type' => 'switch', - 'label' => $this->l('Disable cut'), - 'name' => 'LITE_DISABLE_CUT', - 'is_bool' => true, - 'desc' => $this->proFeature . $this->l('Disable cut (E.g. Ctrl + x / ⌘ + x).'), - 'values' => [ - [ - 'id' => 'active_on', - 'value' => 1, - 'label' => $this->l('Enabled'), - ], - [ - 'id' => 'active_off', - 'value' => 0, - 'label' => $this->l('Disabled'), - ], - ], + 'col' => 4, + 'type' => 'text', + 'desc' => $this->l('Wrong answers before the ban.') . ' ' . $this->l('The default value is') . ' 5.', + 'name' => 'LITE_MAX_RETRY', + 'prefix' => '', + 'suffix' => $this->l('times'), + 'label' => $this->l('Max retries'), + 'hint' => $this->l('Must be an integer'), + 'required' => true, + ], + [ + 'col' => 4, + 'type' => 'text', + 'desc' => $this->l('A host is banned if it has generated') . ' \'' . $this->l('Max retry') . '\' ' . $this->l('during the last') . ' \'' . $this->l('Request timeout') . '\'. ' . $this->l('Enter time in minutes') . '. ' . $this->l('The default value is') . ' 10.', + 'name' => 'LITE_FIND_TIME', + 'prefix' => '', + 'suffix' => $this->l('minutes'), + 'label' => $this->l('Request timeout'), + 'hint' => $this->l('Must be an integer'), + 'required' => true, + ], + [ + 'col' => 4, + 'type' => 'text', + 'desc' => $this->l('Time a host is banned. Enter time in minutes.') . ' ' . $this->l('The default value is') . ' 30.', + 'name' => 'LITE_BAN_TIME', + 'prefix' => '', + 'suffix' => $this->l('minutes'), + 'label' => $this->l('Ban time'), + 'hint' => $this->l('Must be an integer'), + 'required' => true, ], [ - 'disabled' => true, - 'tab' => 'protectContent', 'type' => 'switch', - 'label' => $this->l('Disable paste'), - 'name' => 'LITE_DISABLE_PASTE', + 'col' => 8, + 'label' => $this->l('Receive e-mail on failing to login'), + 'name' => 'LITE_SEND_MAIL', 'is_bool' => true, - 'desc' => $this->proFeature . $this->l('Disable paste (E.g. Ctrl + v / ⌘ + v).'), + 'desc' => $this->proFeature . $this->l('Receive an e-mail if someone inputs a wrong password. This setting can only be enabled if brute force protection is activated.'), + 'disabled' => true, 'values' => [ [ 'id' => 'active_on', @@ -1903,13 +2886,13 @@ protected function fieldsFormSecuritySettings() ], ], [ - 'disabled' => true, - 'tab' => 'protectContent', 'type' => 'switch', - 'label' => $this->l('Disable text selection'), - 'name' => 'LITE_DISABLE_TEXT_SELECTION', + 'col' => 8, + 'label' => $this->l('Receive e-mail on successful login'), + 'name' => 'LITE_SEND_MAIL_LOGIN', 'is_bool' => true, - 'desc' => $this->proFeature . $this->l('Disable text selection.'), + 'desc' => $this->proFeature . $this->l('Receive an e-mail in case someone inputs the correct password. This feature is great to give you the information if anyone else got access. This setting can only be enabled if brute force protection is activated.'), + 'disabled' => true, 'values' => [ [ 'id' => 'active_on', @@ -1924,52 +2907,29 @@ protected function fieldsFormSecuritySettings() ], ], [ - 'disabled' => true, - 'tab' => 'protectContent', - 'col' => 6, 'type' => 'textbutton', - 'label' => $this->l('Whitelist'), - 'hint' => $this->l('E.g.') . ' 123.456.789,123.456.*,123.*,...', - 'desc' => $this->proFeature . $this->l('You can list your own IP addresses if you want to bypass your rules above.') . '
' . $this->l('The module can handle IPv4, IPv6 addresses, as well as IP ranges, in CIDR formats') . ' (' . $this->l('like') . ' ::1/128 ' . $this->l('or') . ' 127.0.0.1/32) ' . $this->l('and in pattern format') . ' (' . $this->l('like') . ' ::*:* ' . $this->l('or') . ' 127.0.*.*). ' . $this->l('Separate by comma (\',\').'), - 'name' => 'LITE_WHITELIST_PROTECT_CONTENT', + 'col' => 8, + 'desc' => $this->proFeature . $this->l('You can list your IP addresses to avoid getting an e-mail if you write the password wrong. You can still get banned for some time if you fail to login according to your own rules above.') . '
' . $this->l('The module can handle IPv4 and IPv6 addresses, as well as IP ranges, in CIDR formats like') . ' ::1/128 ' . $this->l('or') . ' 127.0.0.1/32 ' . $this->l('and pattern format like') . ' ::*:* ' . $this->l('or') . ' 127.0.*.*. ' . $this->l('Separates by a comma') . ' (\',\') ' . $this->l('without space.'), + + 'name' => 'LITE_WHITELIST_IPS', 'button' => [ 'label' => ' ' . $this->l('Add my IP'), 'attributes' => [ 'onclick' => '', ], ], - ], - [ - 'disabled' => true, - 'col' => 5, - 'tab' => 'firewall', - 'type' => 'text', - 'prefix' => '', - 'desc' => $this->proFeature . $this->l('To get your own public key (site key) please click on the following link') . ': ' . $linkGoogleApi . '. ' . $this->l('You will have to register to get a key, but it\'s completely free.'), - 'name' => 'LITE_FIREWALL_RECAPCHA_SITE_KEY', - 'label' => $this->l('Site key (reCAPTCHA v2)'), - 'required' => true, - ], - [ 'disabled' => true, - 'col' => 5, - 'tab' => 'firewall', - 'type' => 'text', - 'prefix' => '', - 'desc' => $this->proFeature . $this->l('To get your own private key (secret key) please click on the following link') . ': ' . $linkGoogleApi . '. ' . $this->l('You will have to register to get a key, but it\'s completely free.'), - 'name' => 'LITE_FIREWALL_RECAPCHA_SECRET', - 'label' => $this->l('Secret key (reCAPTCHA v2)'), - 'required' => true, + 'label' => $this->l('Whitelist IP addresses'), + 'hint' => $this->l('E.g.') . ' 123.456.789,123.456.*,123.*,...', ], [ - 'disabled' => true, - 'tab' => 'firewall', 'type' => 'switch', - 'col' => 6, - 'label' => $this->l('Activate anti-flood'), - 'name' => 'LITE_ANTI_FLOOD', + 'col' => 8, + 'label' => $this->l('Log banned users'), + 'name' => 'LITE_FAIL2BAN_LOG', 'is_bool' => true, - 'desc' => $this->proFeature . $this->l('Anti-flood script that does not need cookies. This script is great for preventing most DDoS attacks and automatic multiple requests.'), + 'desc' => $this->proFeature . $this->l('Record banned users into a log file.') . ' ' . $this->l('The log can be found on your dashboard.'), + 'disabled' => true, 'values' => [ [ 'id' => 'active_on', @@ -1983,67 +2943,35 @@ protected function fieldsFormSecuritySettings() ], ], ], + ], + 'submit' => [ + 'title' => $this->l('Save'), + ], + ], + ]; + } + + /** + * @return array + */ + protected function fieldsFormHttpSecurityHeaders() + { + return [ + 'form' => [ + 'legend' => [ + 'title' => $this->l('HTTP Security Headers'), + 'icon' => 'icon-shield', + ], + 'description' => $this->l('Security headers are HTTP response headers that your application can use to increase the security of your application. Once set, these HTTP response headers can restrict browsers from running into easily preventable vulnerabilities.') . ' ' . $this->l('This module makes the configuration of these security headers easy.'), + 'input' => [ [ - 'disabled' => true, - 'col' => 2, - 'tab' => 'firewall', - 'type' => 'text', - 'suffix' => $this->l('requests'), - 'prefix' => '', - 'desc' => $this->proFeature . $this->l('Number of allowed page requests for the user.'), - 'name' => 'LITE_ANTI_MAX_REQUESTS', - 'label' => $this->l('Max requests'), - 'hint' => $this->l('Must be an integer'), - 'required' => true, - ], - [ - 'disabled' => true, - 'col' => 2, - 'tab' => 'firewall', - 'type' => 'text', - 'suffix' => $this->l('seconds'), - 'prefix' => '', - 'desc' => $this->proFeature . $this->l('Time interval to start counting page requests.'), - 'name' => 'LITE_ANTI_REQ_TIMEOUT', - 'label' => $this->l('Request timeout'), - 'hint' => $this->l('Must be an integer'), - 'required' => true, - ], - [ - 'disabled' => true, - 'col' => 2, - 'tab' => 'firewall', - 'type' => 'text', - 'suffix' => $this->l('seconds'), - 'prefix' => '', - 'desc' => $this->proFeature . $this->l('Time to punish the user who has exceeded in doing requests.'), - 'name' => 'LITE_ANTI_BAN_TIME', - 'label' => $this->l('Ban time'), - 'hint' => $this->l('Must be an integer'), - 'required' => true, - ], - [ - 'disabled' => true, - 'col' => 5, - 'tab' => 'firewall', - 'type' => 'text', - 'prefix' => '', - 'desc' => $this->proFeature . $this->l('To get your own honeypot key please click on the following link') . ': ' . $linkHoneypotApi . '. ' . $this->l('You will have to register to get a key, but it\'s completely free.'), - 'name' => 'LITE_HONEYPOT_API', - 'label' => 'Honeypot API', - 'hint' => $this->l('Access keys are 12-alpha characters (no numbers). They are lower-case.'), - 'required' => true, - ], - [ - 'disabled' => true, - 'tab' => 'firewall', 'type' => 'switch', - 'col' => 6, - 'label' => $this->l('Activate bot check'), - 'name' => 'LITE_FIREWALL_CHECK_BOT', + 'col' => 8, + 'label' => $this->l('Click-jack protection'), + 'name' => 'LITE_CLICK_JACKING', 'is_bool' => true, - 'desc' => $this->proFeature . $this->l('Detect if the client is listed in honeypot project or is connected though TOR network IPv4/IPv6. If positive, the client will need to solve a reCAPCHA to get whitelisted.'), - + 'desc' => $this->proFeature . $this->l('Prevent browsers from framing your site. This will defend you against attacks like click-jacking.'), + 'disabled' => true, 'values' => [ [ 'id' => 'active_on', @@ -2058,14 +2986,13 @@ protected function fieldsFormSecuritySettings() ], ], [ - 'disabled' => true, - 'tab' => 'firewall', 'type' => 'switch', - 'col' => 6, - 'label' => $this->l('Activate anti-SQL injection'), - 'name' => 'LITE_FIREWALL_SQL_CHECK', + 'col' => 8, + 'label' => $this->l('XSS protection'), + 'name' => 'LITE_X_XSS_PPROTECTION', 'is_bool' => true, - 'desc' => $this->proFeature . $this->l('SQL injection is a web security vulnerability that allows an attacker to interfere with the queries that an application makes to its database.') . ' ' . $this->l('If the request looks like an attack, the client will need to solve a reCAPCHA before the request can proceed.'), + 'desc' => $this->proFeature . $this->l('Set secure configuration for the cross-site scripting filters built into most browsers.'), + 'disabled' => true, 'values' => [ [ 'id' => 'active_on', @@ -2080,14 +3007,13 @@ protected function fieldsFormSecuritySettings() ], ], [ - 'disabled' => true, - 'tab' => 'firewall', 'type' => 'switch', - 'col' => 6, - 'label' => $this->l('Activate anti-XXS injection'), - 'name' => 'LITE_FIREWALL_XXS_CHECK', - 'is_bool' => true, - 'desc' => $this->proFeature . $this->l('XSS (Cross-Site Scripting) injection is a web security vulnerability that allows an attacker to inject code (basically client-side scripting) to the remote server.') . ' ' . $this->l('If the request looks like an attack, the client will need to solve a reCAPCHA before the request can proceed.'), + 'col' => 8, + 'label' => $this->l('Disable content sniffing'), + 'name' => 'LITE_X_CONTENT_TYPE_OPTIONS', + 'is_bool' => false, + 'desc' => $this->proFeature . $this->l('Stop browsers from trying to MIME-sniff the content type and forces it to stick with the declared content-type.'), + 'disabled' => true, 'values' => [ [ 'id' => 'active_on', @@ -2102,14 +3028,13 @@ protected function fieldsFormSecuritySettings() ], ], [ - 'disabled' => true, - 'tab' => 'firewall', 'type' => 'switch', - 'col' => 6, - 'label' => $this->l('Activate anti-SHELL injection'), - 'name' => 'LITE_FIREWALL_SHELL_CHECK', + 'col' => 8, + 'label' => $this->l('Force secure connection with HSTS'), + 'name' => 'LITE_STRICT_TRANSPORT_SECURITY', 'is_bool' => true, - 'desc' => $this->proFeature . $this->l('SHELL injection is a web security vulnerability that allows an attacker to inject code to the remote server.') . ' ' . $this->l('If the request looks like an attack, the client will need to solve a reCAPCHA before the request can proceed.'), + 'desc' => $this->proFeature . $this->l('Strengthens your implementation of TLS by getting the user agent to enforce the use of HTTPS.'), + 'disabled' => true, 'values' => [ [ 'id' => 'active_on', @@ -2124,14 +3049,37 @@ protected function fieldsFormSecuritySettings() ], ], [ + 'type' => 'checkbox', + 'desc' => $this->proFeature . $this->l('Please follow this link to understand these settings') . ': ' . $this->generateLink('https://hstspreload.org/?domain=' . $this->getShopUrl()) . '.', + 'label' => $this->l('HSTS settings'), + 'name' => 'LITE_HSTS_SETTINGS', 'disabled' => true, - 'tab' => 'firewall', + 'values' => [ + 'query' => [ + [ + 'id_option' => 0, + 'name' => 'Preload', + 'value' => 0, + ], + [ + 'id_option' => 1, + 'name' => 'Include subdomains', + 'value' => 1, + ], + ], + 'id' => 'id_option', + 'name' => 'name', + 'value' => 'value', + ], + ], + [ 'type' => 'switch', - 'col' => 6, - 'label' => $this->l('Activate anti-HTML injection'), - 'name' => 'LITE_FIREWALL_HTML_CHECK', + 'col' => 8, + 'label' => $this->l('Expect CT'), + 'name' => 'LITE_EXPECT_CT', 'is_bool' => true, - 'desc' => $this->proFeature . $this->l('HTML injection is a web security vulnerability that allows an attacker to change the website\'s design or any information, that is displayed to the user.') . ' ' . $this->l('If the request looks like an attack, the client will need to solve a reCAPCHA before the request can proceed.'), + 'desc' => $this->proFeature . $this->l('Signals to the user agent that compliance with the certificate transparency policy should be enforced.'), + 'disabled' => true, 'values' => [ [ 'id' => 'active_on', @@ -2146,14 +3094,13 @@ protected function fieldsFormSecuritySettings() ], ], [ - 'disabled' => true, - 'tab' => 'firewall', 'type' => 'switch', - 'col' => 6, - 'label' => $this->l('Activate anti-XST injection'), - 'name' => 'LITE_FIREWALL_XST_CHECK', + 'col' => 8, + 'label' => $this->l('Referrer policy'), + 'name' => 'LITE_REFFERER_POLICY', 'is_bool' => true, - 'desc' => $this->proFeature . $this->l('Cross-Site Tracing (XST) is a network security vulnerability exploiting the HTTP TRACE method. Enable this option to block HTTP TRACK and HTTP TRACE requests.'), + 'desc' => $this->proFeature . $this->l('The browser will send a full URL along with requests from a TLS-protected environment settings object to a potentially trustworthy URL and requests from clients which are not TLS-protected to any origin.'), + 'disabled' => true, 'values' => [ [ 'id' => 'active_on', @@ -2168,14 +3115,13 @@ protected function fieldsFormSecuritySettings() ], ], [ - 'disabled' => true, - 'tab' => 'firewall', 'type' => 'switch', - 'col' => 6, - 'label' => $this->l('Block too long HTTP requests'), - 'name' => 'LITE_FIREWALL_CHECK_REQUEST', + 'col' => 8, + 'label' => $this->l('Access control allows methods'), + 'name' => 'LITE_ACCESS_CONTROL_ALLOW_METHODS', 'is_bool' => true, - 'desc' => $this->proFeature . $this->l('Block the request if the HTTP request is more than 2500 characters.'), + 'desc' => $this->proFeature . $this->l('The server responds and says that only POST, GET, OPTIONS are viable methods to query the resource in question.'), + 'disabled' => true, 'values' => [ [ 'id' => 'active_on', @@ -2190,14 +3136,13 @@ protected function fieldsFormSecuritySettings() ], ], [ - 'disabled' => true, - 'tab' => 'firewall', 'type' => 'switch', - 'col' => 6, - 'label' => $this->l('Block user agents with too long names'), - 'name' => 'LITE_FIREWALL_CHECK_USERAGENT', + 'col' => 8, + 'label' => $this->l('Permitted cross-domain policies'), + 'name' => 'LITE_X_PERITTED_CROSS_DOMAIN_POLICY', 'is_bool' => true, - 'desc' => $this->proFeature . $this->l('Block the request if the user agent name is more than 472 characters.'), + 'desc' => $this->proFeature . $this->l('Prevent Adobe Flash and Adobe Acrobat from loading content on your site. This protects against cross-domain middleware.'), + 'disabled' => true, 'values' => [ [ 'id' => 'active_on', @@ -2212,14 +3157,13 @@ protected function fieldsFormSecuritySettings() ], ], [ - 'disabled' => true, - 'tab' => 'firewall', 'type' => 'switch', - 'col' => 6, - 'label' => $this->l('Block old HTTP protocols'), - 'name' => 'LITE_FIREWALL_OLD_PROTOCOL', + 'col' => 8, + 'label' => $this->l('Download options'), + 'name' => 'LITE_X_DOWNLOAD_OPTIONS', 'is_bool' => true, - 'desc' => $this->proFeature . $this->l('Block HTTP/0.9 and HTTP/1.0 requests. Real humans will connect with HTTP/1.1, HTTP/2.0 or HTTP/3.0.'), + 'desc' => $this->proFeature . $this->l('This disables the option to open a file directly on download.') . ' ' . $this->l('This header is only supported by Internet Explorer.'), + 'disabled' => true, 'values' => [ [ 'id' => 'active_on', @@ -2234,14 +3178,13 @@ protected function fieldsFormSecuritySettings() ], ], [ - 'disabled' => true, - 'tab' => 'firewall', 'type' => 'switch', - 'col' => 6, - 'label' => $this->l('Block file-upload'), - 'name' => 'LITE_BLOCK_FILE_UPLOAD', + 'col' => 8, + 'label' => $this->l('Hide server information'), + 'name' => 'LITE_UNSET_HEADERS', 'is_bool' => true, - 'desc' => $this->proFeature . $this->l('Block file uploads in front office. Don\'t enable this if you use contact form.'), + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('Remove all') . ' \'Powered-by\' ' . $this->l('HTTP headers and hide server information.') . '


' . $this->l('Analyze security HTTP headers') . '
' . $this->l('Security Lite') . ' ' . $this->l('can fix all warnings and errors reported by') . ' ' . $this->generateLink('https://securityheaders.com') . ' ' . $this->l('you can get an') . ' A+ ' . $this->l('score') . '!', 'values' => [ [ 'id' => 'active_on', @@ -2255,15 +3198,36 @@ protected function fieldsFormSecuritySettings() ], ], ], + ], + 'submit' => [ + 'title' => $this->l('Save'), + ], + ], + ]; + } + + /** + * @return array + */ + protected function fieldsFormSecondLogin() + { + return [ + 'form' => [ + 'legend' => [ + 'title' => $this->l('Second Login'), + 'icon' => 'icon-sign-in', + ], + 'description' => $this->l('Your shop is already secured by PrestaShop\'s login, but you can add another layer of security by adding a second login from your webserver itself. This is done using .htpasswd (Apache-servers only).') . ' ' . $this->l('The second login is the same for each employee, as this is set on the server level.'), + 'warning' => $this->l('This feature is for advanced users only. It is recommended to leave this feature off in most cases.'), + 'input' => [ [ - 'disabled' => true, - 'tab' => 'firewall', 'type' => 'switch', - 'col' => 6, - 'label' => $this->l('Activate log'), - 'name' => 'LITE_FIREWALL_LOG', + 'col' => 8, + 'label' => $this->l('Second login'), + 'name' => 'LITE_HTPASSWD', 'is_bool' => true, - 'desc' => $this->proFeature . $this->l('Record hacking attempts into a log file.'), + 'desc' => $this->proFeature . $this->l('Activate a second login from your webserver itself.'), + 'disabled' => true, 'values' => [ [ 'id' => 'active_on', @@ -2278,14 +3242,56 @@ protected function fieldsFormSecuritySettings() ], ], [ + 'col' => 4, + 'type' => 'text', + 'prefix' => '', + 'desc' => $this->proFeature . $this->l('You should use another username then you do for your regular back office login.') . ' ' . $this->l('Generate a secure username') . '.', + 'name' => 'LITE_HTPASSWD_USER', + 'label' => $this->l('Username'), + 'hint' => $this->l('Invalid character') . ': \':\'', + 'disabled' => true, + ], + [ + 'col' => 4, + 'type' => 'text', + 'prefix' => '', + 'desc' => $this->proFeature . $this->l('You should use another password than you do for your regular back office login.') . ' ' . $this->l('Generate a secure password') . '.', + 'name' => 'LITE_HTPASSWD_PASS', + 'label' => $this->l('Password'), + 'hint' => $this->l('Invalid character') . ': \':\'', 'disabled' => true, - 'tab' => 'tfa', + ], + ], + 'submit' => [ + 'title' => $this->l('Save'), + ], + ], + ]; + } + + /** + * @return array + */ + protected function fieldsFormAdminStealthLogin() + { + return [ + 'form' => [ + 'legend' => [ + 'title' => $this->l('Admin Stealth Login'), + 'icon' => 'icon-eye-slash', + ], + 'description' => $this->l('Admin Stealth Login makes your admin directory invisible for hosts with unknown IP addresses.'), + 'warning' => $this->l('This feature is for advanced users only. It is recommended to leave this feature off in most cases.'), + 'disabled' => true, + 'input' => [ + [ 'type' => 'switch', - 'col' => 6, - 'label' => $this->l('Activate Two-Factor Authentication'), - 'name' => 'LITE_TWO_FACTOR_AUTH', + 'col' => 8, + 'label' => $this->l('Admin stealth login'), + 'name' => 'LITE_STEALTH_LOGIN', 'is_bool' => true, - 'desc' => $this->proFeature . $this->l('Download') . ' ' . $this->l('Google Authenticator') . ' ' . $this->l('app on your phone. Open the app and scan the QR code. Insert the code you see on your phone in the code input field below to verify that everything is working. Then save settings.') . '

' . $this->l('Your key') . ' (' . $this->l('for manual input') . '):
' . \chunk_split($this->getSecret(), 4, ' ') . '

QR-code:
', + 'desc' => $this->proFeature . $this->l('Block access to the back office for everyone except the IP addresses on the list below.') . ' ' . $this->l('You must have a static IP address') . '. ' . $this->generateLink('https://en.wikipedia.org/wiki/IP_address#Static_IP', $this->l('Read more')) . '.', + 'disabled' => true, 'values' => [ [ 'id' => 'active_on', @@ -2300,32 +3306,19 @@ protected function fieldsFormSecuritySettings() ], ], [ - 'disabled' => true, - 'col' => 2, - 'tab' => 'tfa', - 'type' => 'text', - 'prefix' => '', - 'desc' => $this->proFeature . $this->l('To validate that everything is correct, you must enter your code from your app before you save settings.'), - 'name' => 'LITE_TWO_FACTOR_AUTH_CODE', - 'label' => $this->l('Code'), - 'hint' => $this->l('Must be 6 digitals'), - 'required' => true, - ], - [ - 'disabled' => true, - 'tab' => 'tfa', + 'col' => 8, 'type' => 'textbutton', - 'col' => 6, - 'desc' => $this->proFeature . $this->l('You can list your own IP addresses if you want to skip the Two-Factor Authentication when you are on a specific network.') . '
' . $this->l('The module can handle IPv4, IPv6 addresses, as well as IP ranges, in CIDR formats') . $this->l('like') . ' ::1/128 ' . $this->l('or') . ' 127.0.0.1/32) ' . $this->l('and in pattern format') . ' (' . $this->l('like') . ' ::*:* ' . $this->l('or') . ' 127.0.*.*). ' . $this->l('Separate by comma (\',\').'), - 'name' => 'LITE_TWO_FACTOR_AUTH_WHITELIST', + 'label' => $this->l('Whitelist'), + 'hint' => $this->l('E.g.') . ' 123.456.789,123.456.*,123.*,...', + 'desc' => $this->proFeature . $this->l('List all the IP addresses that should have access to back office.') . '
' . $this->l('The module can handle IPv4 and IPv6 addresses, as well as IP ranges, in CIDR formats like') . ' ::1/128 ' . $this->l('or') . ' 127.0.0.1/32 ' . $this->l('and pattern format like') . ' ::*:* ' . $this->l('or') . ' 127.0.*.*. ' . $this->l('Separates by a comma') . ' (\',\') ' . $this->l('without space.'), + 'name' => 'LITE_STEALTH_LOGIN_WHITELIST', + 'disabled' => true, 'button' => [ 'label' => ' ' . $this->l('Add my IP'), 'attributes' => [ 'onclick' => '', ], ], - 'label' => $this->l('Whitelist IP addresses'), - 'hint' => $this->l('E.g.') . ' 123.456.789,123.456.*,123.*,...', ], ], 'submit' => [ @@ -2336,109 +3329,2938 @@ protected function fieldsFormSecuritySettings() } /** - * Configure form values. + * @return array + */ + protected function fieldsFormAntiSpam() + { + $linkRegistrationForm = $this->context->link->getPageLink('authentication') . '?create_account=1'; + + return [ + 'form' => [ + 'legend' => [ + 'title' => $this->l('Anti-SPAM'), + 'icon' => 'icon-ban', + ], + 'description' => $this->l('SPAM (Shit Posing As Mail) is a problem for most businesses. There are still people who fall victim to cyber-attacks such as') . ' ' . $this->generateLink('https://en.wikipedia.org/wiki/Spamming', $this->l('spamming')) . ' ' . $this->l('and') . ' ' . $this->generateLink('https://en.wikipedia.org/wiki/Phishing', $this->l('phishing')) . '.', + 'input' => [ + [ + 'type' => 'html', + 'label' => '', + 'html_content' => $this->addHeading($this->l('Contact form'), true), + 'col' => 12, + 'name' => '', + ], + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('Disable contact form'), + 'name' => 'LITE_DISABLE_CONTACT_FORM', + 'is_bool' => true, + 'desc' => $this->l('If you want to disable the contact form, you can enable this feature.'), + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('Enable') . ' reCAPTCHA v3', + 'name' => 'LITE_RECAPTCHA_V3_CONTACT_ACTIVATE', + 'is_bool' => true, + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('reCAPTCHA v3 returns a risk score for each request without user friction. This risk-score is used by the module to decide whether the user is a bot or a human. Bots will be prevented from sending e-mails.') . ' ' . $this->generateLink('https://www.google.com/recaptcha/about/', $this->l('Read more')) . '.', + 'disabled' => true, + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('Block vulnerable messages'), + 'name' => 'LITE_GOOGLE_SAFE_BROWSING_V4_ACTIVATE', + 'is_bool' => true, + 'desc' => $this->proFeature . $this->l('Prevent users from sending e-mails with links to known phishing and deceptive sites using Google safe browsing API. The safe browsing API automatically checks the URLs in the message against Google\'s constantly updated lists of unsafe web resources. If any URL in the message is found on the safe browsing list, the message will be not be sent.') . ' ' . $this->generateLink('https://developers.google.com/safe-browsing', $this->l('Read more')) . '.', + 'disabled' => true, + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('Block custom words'), + 'name' => 'LITE_MESSAGE_CHECKER_ACTIVATE', + 'is_bool' => true, + 'desc' => $this->proFeature . $this->l('Block message if it contains at least one word from your custom list of blacklisted words.'), + 'disabled' => true, + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + [ + 'type' => 'textarea', + 'col' => 8, + 'desc' => $this->proFeature . $this->l('Custom list of bad words') . ' ' . $this->l('Separates by a comma') . ' (\',\') ' . $this->l('without space.'), + 'name' => 'LITE_MESSAGE_CHECKER_CUSTOM_LIST', + 'label' => $this->l('Blacklisted words'), + 'hint' => $this->l('E.g.') . ' viagra,cialis,poker,casino', + 'disabled' => true, + ], + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('Block disposable e-mails'), + 'name' => 'LITE_DISPOSABLE_EMAIL_PROVIDERS_ACTIVATE', + 'is_bool' => true, + 'desc' => $this->proFeature . $this->l('Block e-mails from disposable providers.'), + 'disabled' => true, + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('Block custom list of TLD\'s'), + 'name' => 'LITE_EMAIL_CHECKER_ACTIVATE', + 'is_bool' => true, + 'desc' => $this->proFeature . $this->l('Block e-mails with specific top-level domains.'), + 'disabled' => true, + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + [ + 'type' => 'textarea', + 'col' => 8, + 'name' => 'LITE_EMAIL_CHECKER_CUSTOM_LIST', + 'label' => $this->l('Custom list of TLD\'s'), + 'desc' => $this->proFeature . $this->l('Custom blacklist of top-level domains.') . ' ' . $this->l('Separates by a comma') . ' (\',\') ' . $this->l('without space.'), + 'hint' => $this->l('E.g.') . ' ru,qq.com,vn', + 'disabled' => true, + ], + [ + 'type' => 'html', + 'label' => '', + 'html_content' => $this->addHeading($this->l('Registration form')) . $this->addAlertInfo($this->l('This module does not use overrides. Therefore, it is not possible to add these checks on the registration at the checkout process. These checks are limited to this registration form') . ': ' . $this->generateLink($linkRegistrationForm)), + 'col' => 12, + 'name' => '', + ], + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('Prevent fake accounts'), + 'name' => 'LITE_FAKE_ACCOUNTS', + 'is_bool' => true, + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('Prevent bots from making fake accounts by setting a token.'), + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('Disallow URL in customer name'), + 'name' => 'LITE_DISALLOW_URL_CUSTOMER_NAME', + 'is_bool' => true, + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('Prevent bots from making fake accounts by verifying that first name and last name is not a URL.'), + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('Enable') . ' reCAPTCHA v3', + 'name' => 'LITE_RECAPTCHA_V3_REGISTRATION_ACTIVATE', + 'is_bool' => true, + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('reCAPTCHA v3 returns a risk score for each request without user friction. This risk-score is used by the module to determine whether the user is a bot or a human. Bots will be prevented from register accounts.') . ' ' . $this->generateLink('https://www.google.com/recaptcha/about/', $this->l('Read more')) . '.', + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('Block disposable e-mails'), + 'name' => 'LITE_DISPOSABLE_EMAIL_PROVIDERS_REGISTRATION_ACTIVATE', + 'is_bool' => true, + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('Block e-mails from disposable providers.'), + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('Block custom list of TLD\'s'), + 'name' => 'LITE_EMAIL_CHECKER_REGISTRATION_ACTIVATE', + 'is_bool' => true, + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('Block e-mails with a custom list of top-level domains.'), + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + [ + 'type' => 'textarea', + 'col' => 8, + 'name' => 'LITE_EMAIL_CHECKER_CUSTOM_LIST_REGISTRATION', + 'label' => $this->l('Custom list of TLD\'s'), + 'desc' => $this->proFeature . $this->l('Custom blacklist of top-level domains.') . ' ' . $this->l('Separates by a comma') . ' (\',\') ' . $this->l('without space.'), + 'hint' => $this->l('E.g.') . ' ru,qq.com,vn', + ], + ], + 'submit' => [ + 'title' => $this->l('Save'), + ], + ], + ]; + } + + /** + * @return array + */ + protected function fieldsFormMalwareScan() + { + return [ + 'form' => [ + 'legend' => [ + 'title' => $this->l('Anti Malware'), + 'icon' => 'icon-user-secret', + ], + 'description' => $this->l('The term malware refers to software that damages devices, steal data, and causes chaos. There are many types of malware — viruses, trojans, spyware, ransomware, and more.') . ' ' . $this->generateLink('https://en.wikipedia.org/wiki/Malware', $this->l('Read more')) . '.', + 'input' => [ + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('Get an e-mail if malware is detected'), + 'name' => 'LITE_MALWARE_SCAN_EMAIL', + 'is_bool' => true, + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('Scan all your directories for malware and let you know by e-mail if something was found.') . ' ' . $this->l('Once this option is enabled, a cronjob will appear in your dashboard that you need to set up.'), + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('Log malware'), + 'name' => 'LITE_MALWARE_SCAN_LOG', + 'is_bool' => true, + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('Scan all your directories for malware and log it if something was found.') . ' ' . $this->l('The log can be found on your dashboard.'), + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + [ + 'type' => 'textarea', + 'col' => 8, + 'desc' => $this->proFeature . $this->l('Whitelist false positives, caused by custom modules, etc.') . ' ' . $this->l('Separate files by a comma') . ' (\',\') ' . $this->l('without space.'), + 'name' => 'LITE_WHITELIST_MALWARE', + 'label' => $this->l('Whitelist filter for malware'), + 'hint' => $this->l('E.g.') . ' file.js,file.php', + ], + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('Log error 404'), + 'name' => 'LITE_PAGE_NOT_FOUND_LOG', + 'is_bool' => true, + 'desc' => $this->l('Track every \'page not found\' (error 404) and log them into a log file. This is very useful to detect hacking attempts.'), + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + ], + 'submit' => [ + 'title' => $this->l('Save'), + ], + ], + ]; + } + + /** + * @return array + */ + protected function fieldsFormAntiFakeCarts() + { + return [ + 'form' => [ + 'legend' => [ + 'title' => $this->l('Anti-Fake Carts'), + 'icon' => 'icon-shopping-cart', + ], + 'description' => $this->l('The module can automatically delete abandoned carts. Abandoned carts can be generated both by users and by crawlers, resulting in a massive amount of useless data that severely affects the performances of your shop database.'), + 'input' => [ + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('Delete old carts'), + 'name' => 'LITE_DELETE_OLD_CARTS', + 'is_bool' => true, + 'desc' => $this->l('Delete unused carts after a certain number of days.') . ' ' . $this->l('Once this option is enabled, a cronjob will appear in your dashboard that you need to set up.'), + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + [ + 'col' => 4, + 'type' => 'text', + 'suffix' => $this->l('days'), + 'desc' => $this->l('Allowed days a cart must be saved before it is automatically deleted.') . ' ' . $this->l('14 days is recommended.'), + 'name' => 'LITE_DELETE_OLD_CARTS_DAYS', + 'label' => $this->l('Max days'), + 'hint' => $this->l('Must be an integer'), + 'required' => true, + ], + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('Prevent crawlers from adding to the cart'), + 'name' => 'LITE_BLOCK_ADD_TO_CART', + 'is_bool' => true, + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('Crawlers that don\'t respect your robot.txt rules might click the add to cart button. This can lead to a lot of unused carts that will slow down your site. This feature will block crawlers from adding to cart.'), + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + ], + 'submit' => [ + 'title' => $this->l('Save'), + ], + ], + ]; + } + + /** + * @return array + */ + protected function fieldsFormFirewall() + { + return [ + 'form' => [ + 'legend' => [ + 'title' => $this->l('Web Application Firewall'), + 'icon' => 'icon-repeat', + ], + 'description' => $this->l('This web application firewall helps to protect your web applications against common web exploits that may affect availability, compromise security, or consume excessive resources. It makes your applications secure by enabling security rules that block common attack patterns, such as SQL injection, cross-site scripting, etc.') . ' ' . $this->l('Once you have configured the firewall, remember to test that everything works normally in your front office.') . ' ' . $this->generateLink('https://en.wikipedia.org/wiki/Web_application_firewall', $this->l('Read more')) . '.', + 'input' => [ + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('DDoS protection'), + 'name' => 'LITE_ANTI_FLOOD', + 'disabled' => true, + 'is_bool' => true, + 'desc' => $this->proFeature . $this->l('Anti-flood/DDoS protection. This feature is great for preventing most DDoS attacks and automatic multiple requests.') . ' ' . $this->generateLink('https://en.wikipedia.org/wiki/Denial-of-service_attack', $this->l('Read more')) . '.', + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + [ + 'col' => 4, + 'type' => 'text', + 'suffix' => $this->l('requests'), + 'prefix' => '', + 'desc' => $this->proFeature . $this->l('Allowed page requests for the user.') . ' ' . $this->l('The default value is') . ' 100.', + 'name' => 'LITE_ANTI_MAX_REQUESTS', + 'label' => $this->l('Max requests'), + 'hint' => $this->l('Must be an integer'), + 'required' => true, + 'disabled' => true, + ], + [ + 'col' => 4, + 'type' => 'text', + 'suffix' => $this->l('seconds'), + 'prefix' => '', + 'desc' => $this->proFeature . $this->l('Time interval to start counting page requests.') . ' ' . $this->l('The default value is') . ' 5.', + 'name' => 'LITE_ANTI_REQ_TIMEOUT', + 'label' => $this->l('Request timeout'), + 'hint' => $this->l('Must be an integer'), + 'required' => true, + 'disabled' => true, + ], + [ + 'col' => 4, + 'type' => 'text', + 'suffix' => $this->l('seconds'), + 'prefix' => '', + 'desc' => $this->proFeature . $this->l('Time to punish the user who has exceeded in doing requests.') . ' ' . $this->l('The default value is') . ' 600.', + 'name' => 'LITE_ANTI_BAN_TIME', + 'label' => $this->l('Ban time'), + 'hint' => $this->l('Must be an integer'), + 'required' => true, + 'disabled' => true, + ], + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('Honeypot bot check'), + 'name' => 'LITE_FIREWALL_CHECK_BOT', + 'is_bool' => true, + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('The honeypot project has a big database of bad bots/spammers. If this feature is enabled, the module will look up the IP of clients accessing your site against this database. If there is a match, the client will need to solve a reCAPTCHA to continue using the website. Search engines are excluded from this check.') . ' ' . $this->generateLink('https://www.projecthoneypot.org/about_us.php', $this->l('Read more')) . '.', + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + [ + 'type' => 'select', + 'col' => 8, + 'label' => $this->l('Anti-SQL injection'), + 'name' => 'LITE_FIREWALL_SQL_CHECK', + 'desc' => $this->proFeature . $this->l('SQL injection is a web security vulnerability that allows an attacker to interfere with the queries that an application makes to its database.') . ' ' . $this->l('If the request looks like an attack, choose whether the client can proceed after solving a challenge (reCAPTCHA v2), get blocked (403) or get redirected to \'page not found\' (404).') . ' ' . $this->generateLink('https://owasp.org/www-community/attacks/SQL_Injection', $this->l('Read more')) . '.', + 'disabled' => true, + 'options' => [ + 'query' => [ + [ + 'id_option' => 0, + 'name' => $this->l('Disabled'), + ], + [ + 'id_option' => 1, + 'name' => $this->l('Block request (403)'), + ], + [ + 'id_option' => 2, + 'name' => $this->l('Page-not-found (404)'), + ], + [ + 'id_option' => 3, + 'name' => $this->l('Challenge (reCAPTCHA v2)'), + ], + ], + 'id' => 'id_option', + 'name' => 'name', + ], + ], + [ + 'type' => 'select', + 'col' => 8, + 'label' => $this->l('Anti XXS injection'), + 'name' => 'LITE_FIREWALL_XXS_CHECK', + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('XSS (Cross-Site Scripting) injection is a web security vulnerability that allows an attacker to inject code (basically client-side scripting) to the remote server.') . ' ' . $this->l('If the request looks like an attack, choose whether the client can proceed after solving a challenge (reCAPTCHA v2), get blocked (403) or get redirected to \'page not found\' (404).') . ' ' . $this->generateLink('https://owasp.org/www-community/attacks/xss/', $this->l('Read more')) . '.', + 'options' => [ + 'query' => [ + [ + 'id_option' => 0, + 'name' => $this->l('Disabled'), + ], + [ + 'id_option' => 1, + 'name' => $this->l('Block (403)'), + ], + [ + 'id_option' => 2, + 'name' => $this->l('Page-not-found (404)'), + ], + [ + 'id_option' => 3, + 'name' => 'Challenge (reCAPTCHA v2)', + ], + ], + 'id' => 'id_option', + 'name' => 'name', + ], + ], + [ + 'type' => 'select', + 'col' => 8, + 'label' => $this->l('Anti command injection'), + 'name' => 'LITE_FIREWALL_SHELL_CHECK', + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('Command injection is a web security vulnerability that allows an attacker to inject code into the remote server.') . ' ' . $this->l('If the request looks like an attack, choose whether the client can proceed after solving a challenge (reCAPTCHA v2), get blocked (403) or get redirected to \'page not found\' (404).') . ' ' . $this->generateLink('https://owasp.org/www-community/attacks/Command_Injection', $this->l('Read more')) . '.', + 'options' => [ + 'query' => [ + [ + 'id_option' => 0, + 'name' => $this->l('Disabled'), + ], + [ + 'id_option' => 1, + 'name' => $this->l('Block request (403)'), + ], + [ + 'id_option' => 2, + 'name' => $this->l('Page-not-found (404)'), + ], + [ + 'id_option' => 3, + 'name' => 'challenge (reCAPTCHA v2)', + ], + ], + 'id' => 'id_option', + 'name' => 'name', + ], + ], + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('RFI protection'), + 'name' => 'LITE_FIREWALL_RFI_CHECK', + 'is_bool' => true, + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('Remote file inclusion (RFI) is an attack targeting vulnerabilities in web applications that dynamically reference external scripts. Block the request if the request looks like an RFI attack.') . ' ' . $this->l('This feature is for advanced users. Watch the firewall log if you enable this feature, in case you have installed a third-party module that gets blocked by this feature due to the design of the request.') . ' ' . $this->generateLink('https://owasp.org/www-community/vulnerabilities/PHP_File_Inclusion', $this->l('Read more')) . '.', + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('XST protection'), + 'name' => 'LITE_FIREWALL_XST_CHECK', + 'is_bool' => true, + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('Cross-Site Tracing (XST) is a network security vulnerability exploiting the HTTP TRACE method. Enable this option to block HTTP TRACK and HTTP TRACE requests.') . ' ' . $this->generateLink('https://en.wikipedia.org/wiki/Cross-site_tracing', $this->l('Read more')) . '.', + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('Block TOR IPv4 and IPv6 addresses'), + 'name' => 'LITE_BLOCK_TOR', + 'is_bool' => true, + 'desc' => $this->l('In some cases, TOR browsers are used by criminals to hide while buying from a stolen credit card. If you are having this problem, you can block TOR IPv4 and IPv6 addresses with this feature.') . ' ' . $this->generateLink('https://en.wikipedia.org/wiki/Tor_(anonymity_network)', $this->l('Read more')) . '.', + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('Block directory traversal'), + 'name' => 'LITE_DIR_TRAVERSAL', + 'is_bool' => true, + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('Directory traversal attacks use the webserver software to exploit inadequate security mechanisms and access directories and files stored outside of the webroot folder. This option protects against traversal attacks.') . ' ' . $this->generateLink('https://en.wikipedia.org/wiki/Directory_traversal_attack', $this->l('Read more')) . '.', + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('Block too long HTTP requests'), + 'name' => 'LITE_FIREWALL_CHECK_REQUEST', + 'is_bool' => true, + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('Block the request if the HTTP request is more than 2500 characters.'), + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('Block user agents with too long names'), + 'name' => 'LITE_FIREWALL_CHECK_USERAGENT', + 'is_bool' => true, + 'desc' => $this->proFeature . $this->l('Block the request if the user agent name is more than 472 characters.'), + 'disabled' => true, + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + [ + 'type' => 'select', + 'col' => 8, + 'label' => $this->l('Block custom list of IP addresses'), + 'name' => 'LITE_BAN_IP_ACTIVATE', + 'desc' => $this->l('Block hosts with below IP addresses from your website. You cannot block hosts that are already on this') . ' ' . $this->generateLink($this->getAdminLink('AdminGeolocation', true), $this->l('whitelist')) . '. ' . $this->l('If you want to ban a country, please use this built-in PrestaShop feature') . ': ' . $this->generateLink($this->getAdminLink('AdminGeolocation', true), $this->l('Ban countries')) . '. ' . $this->l('It is generally not recommended to block countries. Blocking countries could lockout customers that are using a VPN or customers that are on vacation, etc.') . ' ' . $this->l('If the client is on the blacklist, choose whether the client can proceed after solving a challenge (reCAPTCHA v2) or get blocked (403).'), + 'options' => [ + 'query' => [ + [ + 'id_option' => 0, + 'name' => $this->l('Disabled'), + ], + [ + 'id_option' => 1, + 'name' => $this->l('Block request (403)'), + ], + [ + 'id_option' => 3, + 'name' => $this->l('Challenge (reCAPTCHA v2)'), + ], + ], + 'id' => 'id_option', + 'name' => 'name', + ], + ], + [ + 'type' => 'textarea', + 'col' => 8, + 'desc' => $this->l('The module can handle IPv4 and IPv6 addresses, as well as IP ranges, in CIDR formats like') . ' ::1/128 ' . $this->l('or') . ' 127.0.0.1/32 ' . $this->l('and pattern format like') . ' ::*:* ' . $this->l('or') . ' 127.0.*.*. ' . $this->l('Separates by a comma') . ' (\',\') ' . $this->l('without space.'), + 'name' => 'LITE_BAN_IP', + 'label' => $this->l('Custom list of IP addresses'), + 'hint' => $this->l('E.g.') . ' 123.456.789,123.456.*,123.*,...', + ], + [ + 'type' => 'select', + 'col' => 8, + 'label' => $this->l('Block custom list of user agents'), + 'name' => 'LITE_BLOCK_USER_AGENT_ACTIVATE', + 'is_bool' => true, + 'desc' => $this->l('Block user agents with the below names from your website.'), + 'options' => [ + 'query' => [ + [ + 'id_option' => 0, + 'name' => $this->l('Disabled'), + ], + [ + 'id_option' => 1, + 'name' => $this->l('Block request (403)'), + ], + [ + 'id_option' => 3, + 'name' => $this->l('Challenge (reCAPTCHA v2)'), + ], + ], + 'id' => 'id_option', + 'name' => 'name', + ], + ], + [ + 'type' => 'textarea', + 'col' => 8, + 'desc' => $this->l('Separates by a comma') . ' (\',\') ' . $this->l('without space.'), + 'name' => 'LITE_BLOCK_USER_AGENT', + 'label' => $this->l('Custom list of User agents'), + 'hint' => $this->l('E.g.') . ' 360Spider,Alexibot,BackWeb,...', + ], + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('Block file-upload'), + 'name' => 'LITE_BLOCK_FILE_UPLOAD', + 'disabled' => true, + 'is_bool' => true, + 'desc' => $this->proFeature . $this->l('Block the ability to upload files in the front office. don\'t enable this if you are using the contact form or another front office module that has a file transfer function.'), + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('Scan file on upload'), + 'name' => 'LITE_BLOCK_SCAN_FILE_UPLOAD', + 'is_bool' => true, + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('Scan uploaded files in the front office for trojans, viruses, malware and, other threats and block the request if the file is suspicious.'), + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('Log hacking attempts'), + 'name' => 'LITE_FIREWALL_LOG', + 'is_bool' => true, + 'desc' => $this->l('Record hacking attempts into a log file.') . ' ' . $this->l('This is recommended.'), + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + [ + 'type' => 'textbutton', + 'col' => 8, + 'desc' => $this->l('Whitelist IP addresses that should not be should be blocked by the firewall.') . '
' . $this->l('The module can handle IPv4 and IPv6 addresses, as well as IP ranges, in CIDR formats like') . ' ::1/128 ' . $this->l('or') . ' 127.0.0.1/32 ' . $this->l('and pattern format like') . ' ::*:* ' . $this->l('or') . ' 127.0.*.*. ' . $this->l('Separates by a comma') . ' (\',\') ' . $this->l('without space.'), + 'name' => 'LITE_FIREWALL_WHITELIST', + 'button' => [ + 'label' => ' ' . $this->l('Add my IP'), + 'attributes' => [ + 'onclick' => 'addMyIp("#LITE_FIREWALL_WHITELIST");', + ], + ], + 'label' => $this->l('Whitelist IP addresses'), + 'hint' => $this->l('E.g.') . ' 123.456.789,123.456.*,123.*,...', + ], + ], + 'submit' => [ + 'title' => $this->l('Save'), + ], + ], + ]; + } + + /** + * @return array + */ + protected function fieldsFormProtectContent() + { + return [ + 'form' => [ + 'legend' => [ + 'title' => $this->l('Protect Content'), + 'icon' => 'icon-hand-o-up', + ], + 'description' => $this->l('The module allows you to disable a list of mouse- and key-events. These settings make it harder for users that manually try to steal your content. These settings will affect the front office only.'), + 'input' => [ + [ + 'type' => 'select', + 'label' => $this->l('Disable right-click'), + 'desc' => $this->l('Disable right-click mouse event.') . ' ' . $this->l('Input and Textarea fields are excluded from this rule.'), + 'name' => 'LITE_DISABLE_RIGHT_CLICK', + 'options' => [ + 'query' => [ + [ + 'id_option' => 0, + 'name' => $this->l('No'), + ], + [ + 'id_option' => 1, + 'name' => $this->l('Yes'), + ], + [ + 'id_option' => 2, + 'name' => $this->l('Images only'), + ], + ], + 'id' => 'id_option', + 'name' => 'name', + ], + ], + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('Disable drag and drop'), + 'name' => 'LITE_DISABLE_DRAG', + 'is_bool' => true, + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('Disable drag and drop mouse event.') . ' ' . $this->l('Input and Textarea fields are excluded from this rule.'), + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('Disable copy'), + 'name' => 'LITE_DISABLE_COPY', + 'is_bool' => true, + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('Disable copy (E.g. Ctrl + c / ⌘ + c).') . ' ' . $this->l('Input and Textarea fields are excluded from this rule.'), + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('Disable cut'), + 'name' => 'LITE_DISABLE_CUT', + 'is_bool' => true, + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('Disable cut (E.g. Ctrl + x / ⌘ + x).') . ' ' . $this->l('Input and Textarea fields are excluded from this rule.'), + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('Disable paste'), + 'name' => 'LITE_DISABLE_PASTE', + 'is_bool' => true, + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('Disable paste (E.g. Ctrl + v / ⌘ + v).') . ' ' . $this->l('Input and Textarea fields are excluded from this rule.'), + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('Disable text selection'), + 'name' => 'LITE_DISABLE_TEXT_SELECTION', + 'is_bool' => true, + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('Disable text selection') . '. ' . $this->l('Input and Textarea fields are excluded from this rule.'), + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('Disable print'), + 'name' => 'LITE_DISABLE_PRINT', + 'is_bool' => true, + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('Disable print (E.g. Ctrl + p / ⌘ + p).'), + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('Disable save'), + 'name' => 'LITE_DISABLE_SAVE', + 'is_bool' => true, + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('Disable save (E.g. Ctrl + s / ⌘ + s).'), + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('Disable developer tool hotkeys'), + 'name' => 'LITE_DISABLE_VIEW_PAGE_SOURCE', + 'is_bool' => true, + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('Disable developer tool hotkeys') . '.', + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('Disable console'), + 'name' => 'LITE_DISABLE_CONSOLE', + 'is_bool' => true, + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('Disable console') . '.', + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + [ + 'col' => 8, + 'type' => 'textbutton', + 'label' => $this->l('Whitelist'), + 'hint' => $this->l('E.g.') . ' 123.456.789,123.456.*,123.*,...', + 'desc' => $this->l('You can list your IP addresses if you want to bypass your rules above.') . '
' . $this->l('The module can handle IPv4 and IPv6 addresses, as well as IP ranges, in CIDR formats like') . ' ::1/128 ' . $this->l('or') . ' 127.0.0.1/32 ' . $this->l('and pattern format like') . ' ::*:* ' . $this->l('or') . ' 127.0.*.*. ' . $this->l('Separates by a comma') . ' (\',\') ' . $this->l('without space.'), + 'name' => 'LITE_WHITELIST_PROTECT_CONTENT', + 'button' => [ + 'label' => ' ' . $this->l('Add my IP'), + 'attributes' => [ + 'onclick' => 'addMyIp("#LITE_WHITELIST_PROTECT_CONTENT");', + ], + ], + ], + ], + 'submit' => [ + 'title' => $this->l('Save'), + ], + ], + ]; + } + + /** + * @return array + */ + protected function fieldsFormPasswordStrengh() + { + return [ + 'form' => [ + 'legend' => [ + 'title' => $this->l('Password Strength'), + 'icon' => 'icon-tasks', + ], + 'input' => [ + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('Password strength meter'), + 'name' => 'LITE_PASSWORD_STRENGHTBAR', + 'is_bool' => true, + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('Add a meter under the password field giving your customers instant feedback on the strength of their passwords, thus giving your customers a more secure shopping experience.'), + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + ], + 'submit' => [ + 'title' => $this->l('Save'), + ], + ], + ]; + } + + /** + * @return array + */ + protected function fieldsFormAntiFraud() + { + return [ + 'form' => [ + 'legend' => [ + 'title' => $this->l('Fraud Detection'), + 'icon' => 'icon-user-times', + ], + 'description' => $this->l('The module can analyze your orders on different criteria. A score is established to determine whether the order looks suspicious or not.'), + 'input' => [ + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('Fraud detection'), + 'name' => 'LITE_ANTI_FRAUD', + 'is_bool' => true, + 'disabled' => true, + 'desc' => $this->proFeature . $this->l('Display a section on each order, that tells if the order looks suspicious.'), + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + [ + 'type' => 'select', + 'label' => $this->l('Distance unit'), + 'desc' => $this->proFeature . $this->l('Choose your default distance unit. \'km\' for kilometer, \'mi\' for mile.'), + 'name' => 'LITE_ANTI_FRAUD_UNIT', + 'disabled' => true, + 'options' => [ + 'query' => [ + [ + 'id_option' => 'km', + 'name' => 'km', + ], + [ + 'id_option' => 'mi', + 'name' => 'mi', + ], + ], + 'id' => 'id_option', + 'name' => 'name', + ], + ], + [ + 'type' => 'select', + 'label' => $this->l('Display'), + 'desc' => $this->proFeature . $this->l('Choose where you want to display the section at the admin order page.'), + 'disabled' => true, + 'name' => 'LITE_ANTI_FRAUD_HOOK', + 'options' => [ + 'query' => [ + [ + 'id_option' => 'left', + 'name' => $this->l('Left column'), + ], + [ + 'id_option' => 'right', + 'name' => $this->l('Right column'), + ], + ], + 'id' => 'id_option', + 'name' => 'name', + ], + ], + ], + 'submit' => [ + 'title' => $this->l('Save'), + ], + ], + ]; + } + + /** + * Build forms. + * + * @return array + */ + protected function fieldsFormTwoFactorAuth() + { + $tfa = new \RobThree\Auth\TwoFactorAuth(Configuration::get('PS_SHOP_NAME'), 6, 30, 'sha1'); + $content = \Tools::substr(\mb_strtoupper($this->encrypt('2fa-recovery')), 0, 12); + + $twoFactorAuth = [ + $this->l('Download a 2FA app on your phone') . ': Google Authenticator, Microsoft Authenticator, ' . $this->l('or any app supporting the TOTP algorithm.'), + $this->l('Open the app and scan the QR code below') . ':
', + $this->l('If you for some reason cannot scan the QR-code, you can use this code for manual input instead') . ': ' . Tools::substr(\chunk_split($this->getSecret(), 4, ' '), 0, -1) . '', + $this->l('Insert the code you see on your phone in the code field below to verify that everything is working.'), + $this->l('Save settings in the module, before the code expires.'), + ]; + + $employees = $this->getEmployees(true); + + $tfaLinks = []; + foreach ($employees as $employee) { + $tfaLinks[] = [ + $this->l('Name') => $employee['firstname'] . ' ' . $employee['lastname'], + $this->l('E-mail') => $employee['email'], + $this->l('Link') => '' . $this->getAdminLink('AdminLogin', true) . '&2fa=' . \htmlentities($this->encrypt($employee['passwd'])) . '', + ]; + } + + $result = $this->addAlertInfo($this->l('If any of your employees need the ability to skip the two-factor authentication, then they can use the links below. These links have an extra parameter in the login URL. When accessing this link, the two-factor authentication is skipped.')) . $this->addAlertWarning($this->l('Important information for the webmaster') . ': ' . $this->l('The 2FA-token is linked to the password of the employee, so if the employee resets his login-password, the TFA-token will change as well due to security reasons.')) . $this->arrayToTable($tfaLinks); + + return [ + 'form' => [ + 'legend' => [ + 'title' => $this->l('Two-Factor Authentication'), + 'icon' => 'icon-key', + ], + 'description' => $this->l('Two-factor authentication is an extra layer of security for your PrestaShop admin panel, designed to make sure that you\'re the only person who can get access to your back office, even if someone knows your password.') . ' ' . $this->generateLink('https://en.wikipedia.org/wiki/Multi-factor_authentication', $this->l('Read more')) . '.', + 'warning' => $this->l('Please write down and store this 12-character recovery code somewhere safe. In case you lose access to your device, you can use this code to pass the 2FA-step') . ': ' . Tools::substr(\chunk_split($content, 4, ' '), 0, -1) . ' ', + 'input' => [ + [ + 'type' => 'switch', + 'col' => 8, + 'label' => $this->l('Two-Factor Authentication'), + 'name' => 'LITE_TWO_FACTOR_AUTH', + 'is_bool' => true, + 'desc' => $this->proFeature . '

  1. ' . \implode('
  2. ', $twoFactorAuth) . '

', + 'disabled' => true, + 'values' => [ + [ + 'id' => 'active_on', + 'value' => 1, + 'label' => $this->l('Enabled'), + ], + [ + 'id' => 'active_off', + 'value' => 0, + 'label' => $this->l('Disabled'), + ], + ], + ], + [ + 'col' => 4, + 'type' => 'text', + 'prefix' => '', + 'desc' => $this->proFeature . $this->l('To confirm that everything is correct, you must enter your code from your app before you save settings.'), + 'name' => 'LITE_TWO_FACTOR_AUTH_CODE', + 'label' => $this->l('Code'), + 'hint' => $this->l('Must be 6 digitals'), + 'disabled' => $this->proFeature . $this->getTwoFactorAuthDB('enabled') ? true : false, + 'required' => true, + 'disabled' => true, + ], + [ + 'type' => 'textbutton', + 'col' => 8, + 'desc' => $this->proFeature . $this->l('You can list your IP addresses if you want to skip the Two-Factor Authentication when you are on a specific network.') . '
' . $this->l('The module can handle IPv4 and IPv6 addresses, as well as IP ranges, in CIDR formats') . $this->l('like') . ' ::1/128 ' . $this->l('or') . ' 127.0.0.1/32 ' . $this->l('and pattern format like') . ' ::*:* ' . $this->l('or') . ' 127.0.*.*. ' . $this->l('Separates by a comma') . ' (\',\') ' . $this->l('without space.'), + 'name' => 'LITE_TWO_FACTOR_AUTH_WHITELIST', + 'button' => [ + 'label' => ' ' . $this->l('Add my IP'), + 'attributes' => [ + 'onclick' => '', + ], + ], + 'label' => $this->l('Whitelist IP addresses'), + 'hint' => $this->l('E.g.') . ' 123.456.789,123.456.*,123.*,...', + 'disabled' => true, + ], + [ + 'type' => 'html', + 'label' => '', + 'html_content' => $result, + 'col' => 12, + 'name' => '', + ], + ], + 'submit' => [ + 'title' => $this->l('Save'), + ], + ], + ]; + } + + /** + * Configure form values. + * + * @return array + */ + protected function getConfigFormValues() + { + return [ + 'LITE_GENERAL_EMAIL' => Configuration::get('LITE_GENERAL_EMAIL'), + 'LITE_CLICK_JACKING' => Configuration::get('LITE_CLICK_JACKING'), + 'LITE_X_XSS_PPROTECTION' => Configuration::get('LITE_X_XSS_PPROTECTION'), + 'LITE_X_CONTENT_TYPE_OPTIONS' => Configuration::get('LITE_X_CONTENT_TYPE_OPTIONS'), + 'LITE_STRICT_TRANSPORT_SECURITY' => Configuration::get('LITE_STRICT_TRANSPORT_SECURITY'), + 'LITE_HSTS_SETTINGS_0' => Configuration::get('LITE_HSTS_SETTINGS_0'), + 'LITE_HSTS_SETTINGS_1' => Configuration::get('LITE_HSTS_SETTINGS_1'), + 'LITE_EXPECT_CT' => Configuration::get('LITE_EXPECT_CT'), + 'LITE_ACCESS_CONTROL_ALLOW_METHODS' => Configuration::get('LITE_ACCESS_CONTROL_ALLOW_METHODS'), + 'LITE_REFFERER_POLICY' => Configuration::get('LITE_REFFERER_POLICY'), + 'LITE_X_PERITTED_CROSS_DOMAIN_POLICY' => Configuration::get('LITE_X_PERITTED_CROSS_DOMAIN_POLICY'), + 'LITE_X_DOWNLOAD_OPTIONS' => Configuration::get('LITE_X_DOWNLOAD_OPTIONS'), + 'LITE_UNSET_HEADERS' => Configuration::get('LITE_UNSET_HEADERS'), + 'LITE_HTPASSWD' => Configuration::get('LITE_HTPASSWD'), + 'LITE_HTPASSWD_USER' => Configuration::get('LITE_HTPASSWD_USER'), + 'LITE_HTPASSWD_PASS' => Configuration::get('LITE_HTPASSWD_PASS'), + 'LITE_BAN_IP' => Configuration::get('LITE_BAN_IP'), + 'LITE_BAN_IP_ACTIVATE' => Configuration::get('LITE_BAN_IP_ACTIVATE'), + 'LITE_FAIL2BAN' => Configuration::get('LITE_FAIL2BAN'), + 'LITE_FAIL2BAN_LOG' => Configuration::get('LITE_FAIL2BAN_LOG'), + 'LITE_BAN_TIME' => (int) Configuration::get('LITE_BAN_TIME'), + 'LITE_MAX_RETRY' => (int) Configuration::get('LITE_MAX_RETRY'), + 'LITE_FIND_TIME' => (int) Configuration::get('LITE_FIND_TIME'), + 'LITE_SEND_MAIL' => Configuration::get('LITE_SEND_MAIL'), + 'LITE_SEND_MAIL_LOGIN' => Configuration::get('LITE_SEND_MAIL_LOGIN'), + 'LITE_WHITELIST_IPS' => Configuration::get('LITE_WHITELIST_IPS'), + 'LITE_FILE_CHANGES_EMAIL' => Configuration::get('LITE_FILE_CHANGES_EMAIL'), + 'LITE_FILE_CHANGES_LOG' => Configuration::get('LITE_FILE_CHANGES_LOG'), + 'LITE_FILE_CHANGES_WHITELIST' => Configuration::get('LITE_FILE_CHANGES_WHITELIST'), + 'LITE_MALWARE_SCAN_EMAIL' => Configuration::get('LITE_MALWARE_SCAN_EMAIL'), + 'LITE_MALWARE_SCAN_LOG' => Configuration::get('LITE_MALWARE_SCAN_LOG'), + 'LITE_WHITELIST_MALWARE' => Configuration::get('LITE_WHITELIST_MALWARE'), + 'LITE_DISABLE_RIGHT_CLICK' => Configuration::get('LITE_DISABLE_RIGHT_CLICK'), + 'LITE_DISABLE_DRAG' => Configuration::get('LITE_DISABLE_DRAG'), + 'LITE_DISABLE_COPY' => Configuration::get('LITE_DISABLE_COPY'), + 'LITE_DISABLE_CUT' => Configuration::get('LITE_DISABLE_CUT'), + 'LITE_DISABLE_PRINT' => Configuration::get('LITE_DISABLE_PRINT'), + 'LITE_DISABLE_SAVE' => Configuration::get('LITE_DISABLE_SAVE'), + 'LITE_DISABLE_VIEW_PAGE_SOURCE' => Configuration::get('LITE_DISABLE_VIEW_PAGE_SOURCE'), + 'LITE_DISABLE_CONSOLE' => Configuration::get('LITE_DISABLE_CONSOLE'), + 'LITE_DISABLE_PASTE' => Configuration::get('LITE_DISABLE_PASTE'), + 'LITE_DISABLE_TEXT_SELECTION' => Configuration::get('LITE_DISABLE_TEXT_SELECTION'), + 'LITE_ADMIN_DIRECTORY' => Configuration::get('LITE_ADMIN_DIRECTORY'), + 'LITE_ADMIN_DIRECTORY_NAME' => Configuration::get('LITE_ADMIN_DIRECTORY_NAME'), + 'LITE_BACKUP_DB_TOKEN' => Configuration::get('LITE_BACKUP_DB_TOKEN'), + 'LITE_BLOCK_ADD_TO_CART' => Configuration::get('LITE_BLOCK_ADD_TO_CART'), + 'LITE_DELETE_OLD_CARTS' => Configuration::get('LITE_DELETE_OLD_CARTS'), + 'LITE_DELETE_OLD_CARTS_DAYS' => Configuration::get('LITE_DELETE_OLD_CARTS_DAYS'), + 'LITE_ANTI_FLOOD' => Configuration::get('LITE_ANTI_FLOOD'), + 'LITE_ANTI_MAX_REQUESTS' => (int) Configuration::get('LITE_ANTI_MAX_REQUESTS'), + 'LITE_ANTI_REQ_TIMEOUT' => (int) Configuration::get('LITE_ANTI_REQ_TIMEOUT'), + 'LITE_ANTI_BAN_TIME' => (int) Configuration::get('LITE_ANTI_BAN_TIME'), + 'LITE_FIREWALL_RECAPTCHA_SECRET' => Configuration::get('LITE_FIREWALL_RECAPTCHA_SECRET'), + 'LITE_FIREWALL_RECAPTCHA_SITE_KEY' => Configuration::get('LITE_FIREWALL_RECAPTCHA_SITE_KEY'), + 'LITE_RECAPTCHA_V3_SECRET' => Configuration::get('LITE_RECAPTCHA_V3_SECRET'), + 'LITE_RECAPTCHA_V3_SITE_KEY' => Configuration::get('LITE_RECAPTCHA_V3_SITE_KEY'), + 'LITE_DISPLAY_RECAPTCHA_V3' => Configuration::get('LITE_DISPLAY_RECAPTCHA_V3'), + 'LITE_GOOGLE_SAFE_BROWSING_V4_API' => Configuration::get('LITE_GOOGLE_SAFE_BROWSING_V4_API'), + 'LITE_GOOGLE_SAFE_BROWSING_V4_ACTIVATE' => Configuration::get('LITE_GOOGLE_SAFE_BROWSING_V4_ACTIVATE'), + 'LITE_DISPOSABLE_EMAIL_PROVIDERS_ACTIVATE' => Configuration::get('LITE_DISPOSABLE_EMAIL_PROVIDERS_ACTIVATE'), + 'LITE_DISPOSABLE_EMAIL_PROVIDERS_REGISTRATION_ACTIVATE' => Configuration::get('LITE_DISPOSABLE_EMAIL_PROVIDERS_REGISTRATION_ACTIVATE'), + 'LITE_EMAIL_CHECKER_REGISTRATION_ACTIVATE' => Configuration::get('LITE_EMAIL_CHECKER_REGISTRATION_ACTIVATE'), + 'LITE_EMAIL_CHECKER_CUSTOM_LIST_REGISTRATION' => Configuration::get('LITE_EMAIL_CHECKER_CUSTOM_LIST_REGISTRATION'), + 'LITE_EMAIL_CHECKER_ACTIVATE' => Configuration::get('LITE_EMAIL_CHECKER_ACTIVATE'), + 'LITE_EMAIL_CHECKER_CUSTOM_LIST' => Configuration::get('LITE_EMAIL_CHECKER_CUSTOM_LIST'), + 'LITE_MESSAGE_CHECKER_ACTIVATE' => Configuration::get('LITE_MESSAGE_CHECKER_ACTIVATE'), + 'LITE_MESSAGE_CHECKER_CUSTOM_LIST' => Configuration::get('LITE_MESSAGE_CHECKER_CUSTOM_LIST'), + 'LITE_HONEYPOT_API' => Configuration::get('LITE_HONEYPOT_API'), + 'LITE_MONTASTIC_API' => Configuration::get('LITE_MONTASTIC_API'), + 'LITE_FIREWALL_CHECK_BOT' => Configuration::get('LITE_FIREWALL_CHECK_BOT'), + 'LITE_FIREWALL_SQL_CHECK' => Configuration::get('LITE_FIREWALL_SQL_CHECK'), + 'LITE_FIREWALL_XXS_CHECK' => Configuration::get('LITE_FIREWALL_XXS_CHECK'), + 'LITE_FIREWALL_SHELL_CHECK' => Configuration::get('LITE_FIREWALL_SHELL_CHECK'), + 'LITE_FIREWALL_XST_CHECK' => Configuration::get('LITE_FIREWALL_XST_CHECK'), + 'LITE_DIR_TRAVERSAL' => Configuration::get('LITE_DIR_TRAVERSAL'), + 'LITE_FIREWALL_RFI_CHECK' => Configuration::get('LITE_FIREWALL_RFI_CHECK'), + 'LITE_FIREWALL_CHECK_REQUEST' => Configuration::get('LITE_FIREWALL_CHECK_REQUEST'), + 'LITE_FIREWALL_CHECK_USERAGENT' => Configuration::get('LITE_FIREWALL_CHECK_USERAGENT'), + 'LITE_BLOCK_FILE_UPLOAD' => Configuration::get('LITE_BLOCK_FILE_UPLOAD'), + 'LITE_BLOCK_SCAN_FILE_UPLOAD' => Configuration::get('LITE_BLOCK_SCAN_FILE_UPLOAD'), + 'LITE_FIREWALL_LOG' => Configuration::get('LITE_FIREWALL_LOG'), + 'LITE_PASSWORD_GENERATOR' => Configuration::get('LITE_PASSWORD_GENERATOR'), + 'LITE_BACKUP_DB' => Configuration::get('LITE_BACKUP_DB'), + 'LITE_BACKUP_DB_DROPBOX' => Configuration::get('LITE_BACKUP_DB_DROPBOX'), + 'LITE_BACKUP_DB_TOKEN' => Configuration::get('LITE_BACKUP_DB_TOKEN'), + 'LITE_BACKUP_DB_SAVED' => (int) Configuration::get('LITE_BACKUP_DB_SAVED'), + 'LITE_BACKUP_FILE_SAVED' => (int) Configuration::get('LITE_BACKUP_FILE_SAVED'), + 'LITE_BACKUP_FILE' => Configuration::get('LITE_BACKUP_FILE'), + 'LITE_BACKUP_FILE_DROPBOX' => Configuration::get('LITE_BACKUP_FILE_DROPBOX'), + 'LITE_BACKUP_COMPRESSION' => Configuration::get('LITE_BACKUP_COMPRESSION'), + 'LITE_TWO_FACTOR_AUTH' => Configuration::get('LITE_TWO_FACTOR_AUTH'), + 'LITE_TWO_FACTOR_AUTH_CODE' => Configuration::get('LITE_TWO_FACTOR_AUTH_CODE'), + 'LITE_TWO_FACTOR_AUTH_WHITELIST' => Configuration::get('LITE_TWO_FACTOR_AUTH_WHITELIST'), + 'LITE_FIREWALL_WHITELIST' => Configuration::get('LITE_FIREWALL_WHITELIST'), + 'LITE_FAKE_ACCOUNTS' => Configuration::get('LITE_FAKE_ACCOUNTS'), + 'LITE_DISALLOW_URL_CUSTOMER_NAME' => Configuration::get('LITE_DISALLOW_URL_CUSTOMER_NAME'), + 'LITE_WHITELIST_PROTECT_CONTENT' => Configuration::get('LITE_WHITELIST_PROTECT_CONTENT'), + 'LITE_BLOCK_USER_AGENT_ACTIVATE' => Configuration::get('LITE_BLOCK_USER_AGENT_ACTIVATE'), + 'LITE_BLOCK_USER_AGENT' => Configuration::get('LITE_BLOCK_USER_AGENT'), + 'LITE_BLOCK_TOR' => Configuration::get('LITE_BLOCK_TOR'), + 'LITE_DISABLE_CONTACT_FORM' => Configuration::get('LITE_DISABLE_CONTACT_FORM'), + 'LITE_RECAPTCHA_V3_CONTACT_ACTIVATE' => Configuration::get('LITE_RECAPTCHA_V3_CONTACT_ACTIVATE'), + 'LITE_RECAPTCHA_V3_REGISTRATION_ACTIVATE' => Configuration::get('LITE_RECAPTCHA_V3_REGISTRATION_ACTIVATE'), + 'LITE_RECAPTCHA_V3_THEME' => Configuration::get('LITE_RECAPTCHA_V3_THEME'), + 'LITE_PAGE_NOT_FOUND_LOG' => Configuration::get('LITE_PAGE_NOT_FOUND_LOG'), + 'LITE_PASSWORD_STRENGHTBAR' => Configuration::get('LITE_PASSWORD_STRENGHTBAR'), + 'LITE_ANTI_FRAUD' => Configuration::get('LITE_ANTI_FRAUD'), + 'LITE_ANTI_FRAUD_UNIT' => Configuration::get('LITE_ANTI_FRAUD_UNIT'), + 'LITE_ANTI_FRAUD_HOOK' => Configuration::get('LITE_ANTI_FRAUD_HOOK'), + 'LITE_SERVER_IP' => Configuration::get('LITE_SERVER_IP'), + 'LITE_SERVER_LOCATION' => Configuration::get('LITE_SERVER_LOCATION'), + 'LITE_SERVER_ISP' => Configuration::get('LITE_SERVER_ISP'), + 'LITE_DOMAIN_EXPIRE' => Configuration::get('LITE_DOMAIN_EXPIRE'), + 'LITE_TLS_EXPIRE' => Configuration::get('LITE_TLS_EXPIRE'), + 'LITE_STEALTH_LOGIN' => Configuration::get('LITE_STEALTH_LOGIN'), + 'LITE_STEALTH_LOGIN_WHITELIST' => Configuration::get('LITE_STEALTH_LOGIN_WHITELIST'), + 'LITE_ADVANCED_MAINTENANCE_MODE' => Configuration::get('LITE_ADVANCED_MAINTENANCE_MODE'), + 'LITE_ADVANCED_MAINTENANCE_MODE_COMPANY' => Configuration::get('LITE_ADVANCED_MAINTENANCE_MODE_COMPANY'), + 'LITE_ADVANCED_MAINTENANCE_MODE_ADDRESS' => Configuration::get('LITE_ADVANCED_MAINTENANCE_MODE_ADDRESS'), + 'LITE_ADVANCED_MAINTENANCE_MODE_PHONE' => Configuration::get('LITE_ADVANCED_MAINTENANCE_MODE_PHONE'), + 'LITE_ADVANCED_MAINTENANCE_MODE_EMAIL' => Configuration::get('LITE_ADVANCED_MAINTENANCE_MODE_EMAIL'), + 'LITE_ADVANCED_MAINTENANCE_MODE_FACEBOOK' => Configuration::get('LITE_ADVANCED_MAINTENANCE_MODE_FACEBOOK'), + 'LITE_ADVANCED_MAINTENANCE_MODE_TWITTER' => Configuration::get('LITE_ADVANCED_MAINTENANCE_MODE_TWITTER'), + 'LITE_ADVANCED_MAINTENANCE_MODE_INSTAGRAM' => Configuration::get('LITE_ADVANCED_MAINTENANCE_MODE_INSTAGRAM'), + 'LITE_ADVANCED_MAINTENANCE_MODE_PINTEREST' => Configuration::get('LITE_ADVANCED_MAINTENANCE_MODE_PINTEREST'), + 'LITE_ADVANCED_MAINTENANCE_MODE_YOUTUBE' => Configuration::get('LITE_ADVANCED_MAINTENANCE_MODE_YOUTUBE'), + 'LITE_ADVANCED_MAINTENANCE_MODE_COPYRIGHT' => Configuration::get('LITE_ADVANCED_MAINTENANCE_MODE_COPYRIGHT'), + 'LITE_ADVANCED_MAINTENANCE_MODE_LOGO' => Configuration::get('LITE_ADVANCED_MAINTENANCE_MODE_LOGO'), + 'LITE_ADVANCED_MAINTENANCE_MODE_LOGO_PATH' => Configuration::get('LITE_ADVANCED_MAINTENANCE_MODE_LOGO_PATH'), + 'LITE_DEBUG_CRON' => Configuration::get('LITE_DEBUG_CRON'), + ]; + } + + /** + * Post configure form values. + */ + protected function postProcess() + { + $form_values = $this->getConfigFormValues(); + + foreach (\array_keys($form_values) as $key) { + Configuration::updateValue($key, Tools::getValue($key)); + } + } + + /** + * @return array + */ + protected function fieldsFormWebsiteMonitoringService() + { + $apiKey = (bool) Configuration::get('LITE_MONTASTIC_API'); + $result = null; + if (true === ($apiKey)) { + $ids = $this->getMontasticIds(); + if (!empty($ids)) { + $yes = ''; + $no = ''; + $table = []; + + foreach ($ids as $id) { + $data = $this->getMontasticData($id); + $table[] = [ + $this->l('Checkpoint') => $data['url'], + $this->l('Enabled') => ($data['is_monitoring_enabled']) ? $yes : $no, + $this->l('Monitoring interval') => $data['check_interval_id'] . ' ' . $this->l('min.'), + $this->l('Status') => (-1 !== $data['status']) ? $yes : $no, + ]; + } + + $result = $this->arrayToTable($table); + } + } + + return [ + 'form' => [ + 'legend' => [ + 'title' => $this->l('Website Monitoring Service'), + 'icon' => 'icon-clock-o', + ], + 'description' => $this->l('By connecting up with Montastic, you can be notified by e-mail if your website is down. The free plan allows you to ping your website(s) every 30 min. You can have up to 9 checkpoints at the same time. Try it out!') . '
' . $this->l('You can manage your checkpoints here') . ': ' . $this->generateLink('https://montastic.com/checkpoints') . '.', + 'warning' => (false === $apiKey) ? $this->l('You need to add your API key in \'General Settings\' to get access to this content. You can get an API key here at') . ' ' . $this->generateLink('https://montastic.com/me?tab=form_profile') . ' (' . $this->l('You can choose the free plan') . ').' : null, + 'input' => [ + [ + 'type' => 'html', + 'label' => '', + 'html_content' => (null !== ($result)) ? $result : '', + 'col' => 12, + 'name' => '', + ], + ], + ], + ]; + } + + /** + * Return HTML code for display of favicon. + */ + private function getFavicon() + { + $favicon = Configuration::get('PS_FAVICON'); + + if (true === (bool) $favicon) { + $faviconUpdateTime = Configuration::get('PS_IMG_UPDATE_TIME'); + + return ' '; + } + } + + /** + * Get Firewall. + */ + private function getFirewall() + { + if (false === $this->validateGoogleBotIp()) { + $ip = \Tools::getRemoteAddr(); + if (false === $this->checkWhitelist('LITE_FIREWALL_WHITELIST') && '54.243.46.120' !== $ip) { + $this->googleRecaptchaCheck(); + + // Anti-SPAM: Log 404 requests + if (true === (bool) Configuration::get('LITE_PAGE_NOT_FOUND_LOG')) { + if ('pagenotfound' === Tools::getValue('controller')) { + if (false === \strpos($_SERVER['REQUEST_URI'], 'index.php?controller=404')) { + $this->logPageNotFound(self::LOG_PAGE_NOT_FOUND); + } + } + } + + // Anti-SPAM: Block TOR network + if (true === (bool) Configuration::get('LITE_BLOCK_TOR')) { + if (false === $this->context->cookie->__get('securityliteTor')) { + if (true === $this->isTorExitPoint(Tools::getRemoteAddr())) { + $this->context->cookie->__set('securityliteTor', '1'); // is TOR + } else { + $this->context->cookie->__set('securityliteTor', '0'); // is not TOR + } + $this->context->cookie->write(); + } + + // Block if TOR + if ('1' === $this->context->cookie->__get('securityliteTor')) { + $this->blockRequest(403); + } + } + + // Ban IP addresses + if (0 !== (int) Configuration::get('LITE_BAN_IP_ACTIVATE') && true === (bool) Configuration::get('LITE_BAN_IP')) { + $this->blockIp(); + } + + // Block user agents + if (0 !== (int) Configuration::get('LITE_BLOCK_USER_AGENT_ACTIVATE') && true === (bool) Configuration::get('LITE_BLOCK_USER_AGENT')) { + $this->blockUserAgent(); + } + } + } + } + + /** + * Add record time to database. + * + * @param string $email + * @param string $ip + * @param string $ban + */ + private function addRecordTime($email, $ip, $ban) + { + Db::getInstance()->insert('securitylite', [ + 'email' => pSQL($email), + 'ip' => pSQL($ip), + 'banned' => (int) $ban, + ]); + } + + /** + * Load protect content section. + */ + private function protectContent() + { + // Protect content + if (false === $this->checkWhitelist('LITE_WHITELIST_PROTECT_CONTENT')) { + // Disable browser features + if (1 === (int) Configuration::get('LITE_DISABLE_RIGHT_CLICK')) { + $this->context->controller->addJS($this->_path . 'views/js/contextmenu.js'); + } elseif (2 === (int) Configuration::get('LITE_DISABLE_RIGHT_CLICK')) { + $this->context->controller->addJS($this->_path . 'views/js/contextmenu-img.js'); + } + } + } + + /** + * @param string $link + * @param bool|null $target + * @param bool $blank + * + * @return string + */ + private function generateLink($link, $target = null, $blank = true) + { + if (null === $target) { + $target = $link; + } + + if (true === $blank) { + return '' . $target . ''; + } + + return '' . $link . ''; + } + + /** + * Return array of files that should be deleted. + * + * @return array + */ + private function getFilesRoot() + { + // Files that should be deleted + $files = [ + '0x666.php', + 'IndoXploit.php', + 'README.md', + 'Sh3ll.php', + 'XsamXadoo_Bot.php', + 'XsamXadoo_Bot_All.php', + 'XsamXadoo_deface.php', + 'Xsam_Xadoo.html', + 'anonsha1a0.php', + 'atx_bot.php', + 'azzoulshell.php', + 'b374k.php', + 'bajatax_xsam.php', + 'bigdump.php', + 'bypass.php', + 'c100.php', + 'c99.php', + 'cPanelCracker.php', + 'composer.json', + 'database.php', + 'docker-compose.yml', + 'docs/CHANGELOG.txt', + 'docs/readme_de.txt', + 'docs/readme_en.txt', + 'docs/readme_es.txt', + 'docs/readme_fr.txt', + 'docs/readme_it.txt', + 'efi.php', + 'f.php', + 'hacked.php', + 'httptest.php', + 'info.php', + 'kill.php', + 'lfishell.php', + 'olux.php', + 'perlinfo.php', + 'php.php', + 'phpinfo.php', + 'phppsinfo.php', + 'phpversion.php', + 'prestashop.zip', + 'proshell.php', + 'r00t.php', + 'r57.php', + 'sado.php', + 'shellwow.php', + 'simulasi.php', + 'sssp.php', + 'test.php', + 'testproxy.php', + 'upload.php', + 'wawa.php', + 'wolfm.php', + 'wso.php', + 'xGSx.php', + 'xaishell.php', + 'xcontact182.php', + 'xsam_xadoo_bot.php', + 'xsambot.php', + 'xsambot2.php', + 'xsamxadoo.php', + 'xsamxadoo101.php', + 'xsamxadoo102.php', + 'xsamxadoo95.php', + ]; + + $getFilesRoot = []; + + foreach ($files as $file) { + $dir = _PS_ROOT_DIR_ . \DIRECTORY_SEPARATOR . $file; + if (\file_exists($dir)) { + $getFilesRoot[] = \realpath($dir); + } + } + + return $getFilesRoot; + } + + /** + * Get information about TLS certificate. + * + * @return string + */ + private function getCertInfo() + { + if (false === $this->isSsl()) { + return false; + } + + if ('localhost' === \Tools::getHttpHost(false, true, true)) { + $hostName = 'https://google.com'; + } else { + $hostName = $this->getBaseURL(); + } + $orignalParse = \parse_url($hostName, \PHP_URL_HOST); + $get = \stream_context_create( + [ + 'ssl' => [ + 'capture_peer_cert' => true, + ], + ] + ); + $read = \stream_socket_client( + 'ssl://' . $orignalParse . ':443', + $errno, + $errstr, + 30, + \STREAM_CLIENT_CONNECT, + $get + ); + $cert = \stream_context_get_params($read); + + return \openssl_x509_parse($cert['options']['ssl']['peer_certificate']); + } + + /** + * Generate button for links. + * + * @param string $text + * @param string $url + * + * @return string + */ + private function generateBtnLink($text, $url) + { + return '' . $text . ''; + } + + /** + * Generate paragraph. + * + * @param string $text + * @param bool $italic + * + * @return string + */ + private function addParagraph($text, $italic = false) + { + if (true === $italic) { + return '

' . $text . '

'; + } + + return '

' . $text . '

'; + } + + /** + * Generate button for POST requests. + * + * @param string $id + * @param bool $disabled + * @param string $name + * + * @return string + */ + private function generateBtnPost($name, $id, $disabled) + { + $current = $this->getAdminLink('AdminModules', true) . '&configure=securitylite'; + + $script = ''; + + if (true === $disabled) { + return '' . $script; + } + + return ''; + } + + private function disabledBtn($name) + { + return ''; + } + + /** + * @param array $array + * @param bool $table + * + * @return string + */ + private function arrayToTable($array, $table = true) + { + $out = []; + $tableHeader = null; + foreach ($array as $value) { + if (\is_array($value)) { + if (null === ($tableHeader)) { + $tableHeader = + '' . \implode('', \array_keys($value)) . ''; + } + \array_keys($value); + $out[] = '' . $this->arrayToTable($value, false) . ''; + } else { + $out[] = '' . $value . ''; + } + } + + if (true === $table) { + return '' . $tableHeader . '' . \implode('', $out) . '
'; + } + + return \implode('', $out); + } + + /** + * Delete old backups from local. + * + * @param string $backupSaved + * @param string $dir + */ + private function deleteOldBackups($backupSaved, $dir) + { + $ext = [ + 'bz2', + 'gz', + 'zip', + ]; + $backupFile = []; + + if ($handle = \opendir(_PS_MODULE_DIR_ . $this->name . $dir)) { + while (false !== ($entry = \readdir($handle))) { + if ('.' !== $entry && '..' !== $entry) { + if (\in_array(\pathinfo(\basename($entry), \PATHINFO_EXTENSION), $ext, true)) { + $backupFile[] = $entry; + } + } + } + if (!empty($backupFile)) { + $x = \count($backupFile); + $y = 0; + while ($x > $backupSaved) { + Tools::deleteFile(_PS_MODULE_DIR_ . $this->name . $dir . $backupFile[$y]); + --$x; + ++$y; + } + } + \closedir($handle); + } + } + + /** + * Lookup ban time for specific e-mail in database. + * + * @param string $email + * + * @return int + */ + private function getBanTime($email) + { + $sql = new DbQuery(); + $sql->select('MAX(access_time) AS access_time'); + $sql->from('securitylite'); + $sql->where('banned = 1'); + $sql->where(\sprintf('email = "%s"', pSQL($email))); + $result = Db::getInstance()->executeS($sql); + + return $result ? \strtotime($sql) : 0; + } + + /** + * Get base URL. + * + * @return string + */ + private function getBaseURL() + { + return \Tools::getHttpHost(true, true, true) . __PS_BASE_URI__; + } + + /** + * Get secret TwoFactorAuth. + * + * @return string + */ + private function getSecret() + { + if (empty($this->getTwoFactorAuthDB('secret'))) { + Db::getInstance()->insert('securitylite_tfa', [ + 'enabled' => '0', + 'secret' => '', + ]); + $tfa = new \RobThree\Auth\TwoFactorAuth(Configuration::get('PS_SHOP_NAME'), 6, 30, 'sha1'); + $this->updateTwoFactorAuthDB('secret', $tfa->createSecret(160, true)); + } + + return $this->getTwoFactorAuthDB('secret'); + } + + /** + * Display reCAPTCHA and set headers. + */ + private function displayRecaptcha() + { + \http_response_code(403); + + if (true === (bool) \Configuration::get('LITE_FIREWALL_RECAPTCHA_SITE_KEY')) { + $siteKey = \Configuration::get('LITE_FIREWALL_RECAPTCHA_SITE_KEY'); + } else { + $siteKey = '6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI'; + } + $lang = $this->context->language->iso_code; + \header('Connection: Close'); + \header('Cache-Control: max-age=0, private, no-store, no-cache, must-revalidate'); + + echo ' ' . \Configuration::get('PS_SHOP_NAME') . ' ' . $this->l('is secured by') . ' ' . $this->l('Security Lite') . ' ' . $this->getFavicon() . '

' . $this->l('We detected unusual activity from your') . ' ' . $this->l('IP') . ' ' . \Tools::getRemoteAddr() . ' ' . $this->l('and has blocked access to this website') . '

' . $this->l('Please confirm that you are not a robot') . '

'; + exit; + } + + /** + * Return current admin index. + * + * @return string + */ + private function currentAdminIndex() + { + return $this->getAdminLink('AdminModules', true) . '&configure=securitylite'; + } + + /** + * Check CVE-2020-15162. + * + * @return array + */ + private function checkCve202015162() + { + $check = 'CVE-2020-15162'; + + if (Tools::version_compare(_PS_VERSION_, '1.7.6.8', '>=') || true === (bool) Configuration::get('LITE_DISABLE_CONTACT_FORM') || true === (bool) Configuration::get('LITE_BLOCK_FILE_UPLOAD')) { + $status = false; + } else { + $status = true; + } + + $fix = $this->l('Update PrestaShop to the latest version.'); + + return [ + $check, + $status, + $fix, + ]; + } + + /** + * Check CVE-2020-15161. + * + * @return array + */ + private function checkCve202015161() + { + $check = 'CVE-2020-15161'; + + $status = false; + if (Tools::version_compare(_PS_VERSION_, '1.7.6.8', '<')) { + $status = true; + } + + $fix = $this->l('Update PrestaShop to the latest version.'); + + return [ + $check, + $status, + $fix, + ]; + } + + /** + * Check CVE-2020-15160. + * + * @return array + */ + private function checkCve202015160() + { + $check = 'CVE-2020-15160'; + + $status = false; + if (Tools::version_compare(_PS_VERSION_, '1.7.6.8', '<')) { + $status = true; + } + + $fix = $this->l('Update PrestaShop to the latest version.'); + + return [ + $check, + $status, + $fix, + ]; + } + + /** + * @return array + */ + private function checkCve201819355() + { + $check = 'CVE-2018-19355'; + + $status = \file_exists(_PS_MODULE_DIR_ . 'orderfiles/upload.php'); + + $fix = $this->l('Update') . ' "orderfiles" ' . $this->l('module to the latest version.'); + + return [ + $check, + $status, + $fix, + ]; + } + + /** + * Google reCAPTCHA check. + */ + private function googleRecaptchaCheck() + { + if (null !== Tools::getValue('g-recaptcha-submit')) { + // Validate reCAPTCHA box + if (null !== Tools::getValue('g-recaptcha-response') && !empty(Tools::getValue('g-recaptcha-response'))) { + // Google reCAPTCHA API secret key + if (true === (bool) Configuration::get('LITE_FIREWALL_RECAPTCHA_SECRET')) { + $secretKey = Configuration::get('LITE_FIREWALL_RECAPTCHA_SECRET'); + } else { + $secretKey = '6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe'; + } + // Verify the reCAPTCHA response + + $url = 'https://www.google.com/recaptcha/api/siteverify'; + $params = [ + 'secret' => $secretKey, + 'response' => Tools::getValue('g-recaptcha-response'), + ]; + + $content = $this->getRemoteContent($url, $params); + + if (false !== $content) { + // Decode json data + $responseData = \json_decode($content, true); + // If reCAPTCHA response is valid + if ($responseData['success']) { + // Posted form data + + // Unlock security vulnerability + $this->context->cookie->__set('securityliteRecaptcha', '1'); + + // Unlock honeypot + $this->context->cookie->__set('securityliteHoneypot', '0'); + $this->context->cookie->write(); + } + } else { + return; + } + } + } + } + + /** + * Lookup country by IP addres. + * + * @param string $ip + * + * @return string|null + */ + private function getCountry($ip) + { + $url = 'https://www.iplocate.io/api/lookup/' . $ip; + + $content = $this->getCachedJsonDecodedContent($url, null, $ip, 2629746); + + if (false !== $content) { + $country = $content['country']; + } else { + $country = null; + } + + return $country; + } + + /** + * Log page not found. + * + * @param string $fileName + */ + private function logPageNotFound($fileName) + { + $ip = \Tools::getRemoteAddr(); + + $data = []; + $data[] = '[' . \date('Y-m-d H:i:s') . ']'; + $data[] = '[' . $ip . ']'; + $data[] = $this->l('Error 404 at URL') . ' "' . \rawurldecode(Tools::getHttpHost(true, true, true) . $_SERVER['REQUEST_URI']) . '"'; + + \file_put_contents($this->getLogFile($fileName), \implode(' ', $data) . \PHP_EOL, \FILE_APPEND); + } + + /** + * Log vulnerabilities. + * + * @param string $value + * @param string $typeVuln + * @param string $fileName + */ + private function logVuln($value, $typeVuln, $fileName) + { + $data = []; + $data[] = '[' . \date('Y-m-d H:i:s') . ']'; + $data[] = '[' . \Tools::getRemoteAddr() . ']'; + if (null !== $typeVuln) { + $data[] = '[' . $typeVuln . ']'; + } + if (null !== $value) { + $value = \str_replace(["\r", "\n"], '', $value); + $data[] = $this->l('request') . ' "' . ($value) . '",'; + } + $data[] = $this->l('URL') . ' "' . \rawurldecode(Tools::getHttpHost(true, true, true) . $_SERVER['REQUEST_URI']) . '"'; + + \file_put_contents($this->getLogFile($fileName), \implode(' ', $data) . \PHP_EOL, \FILE_APPEND); + } + + /** + * Vuln detected HTML. + * + * @param string|null $value + * @param string $typeVuln + * @param int $conf + * + * @return bool|string + */ + private function vulnDetectedHtml($value, $typeVuln, $conf) + { + // PrestaShop core whitelist + if ($this->isInWhitelistForGeolocation(\Tools::getRemoteAddr())) { + return false; + } + + if (true === (bool) Configuration::get('LITE_FIREWALL_LOG')) { + $this->logVuln( + $value, + $typeVuln, + self::LOG_FIREWALL + ); + } + + switch ($conf) { + case 0: + return; + case 1: + return $this->blockRequest(403); + case 2: + return \Tools::redirect('pagenotfound'); + case 3: + return $this->displayRecaptcha(); + + default: + return; + } + } + + /** + * Get two-factor authentication database value. + * + * @param string $column + * + * @return array + */ + private function getTwoFactorAuthDB($column) + { + $sql = new DbQuery(); + $sql->from('securitylite_tfa'); + $sql->select($column); + + return Db::getInstance()->getValue($sql); + } + + /** + * Update two-factor authentication in database. + * + * @param string $column + * @param int $value + * + * @return array + */ + private function updateTwoFactorAuthDB($column, $value) + { + $query = 'UPDATE `' . _DB_PREFIX_ . 'securitylite_tfa` SET ' . pSQL($column) . '="' . pSQL($value) . '"'; + + return Db::getInstance()->Execute($query); + } + + /** + * @param string $userIp + * + * @return bool|null + */ + private function isInWhitelistForGeolocation($userIp) + { + $ips = \explode(';', Configuration::get('PS_GEOLOCATION_WHITELIST')); + if (\is_array($ips) && \count($ips)) { + foreach ($ips as $ip) { + if (!empty($ip) && 0 === \mb_strpos($userIp, $ip)) { + return true; + } + } + } + + return false; + } + + /** + * Validate IP addresses. + * + * @param string $field + */ + private function validateIps($field) + { + if (false === (bool) Configuration::get($field)) { + return; + } + + $input = \preg_replace('/\s+/', '', Configuration::get($field)); + $input = \preg_replace('/,,+/', ',', $input); + if (',' === \Tools::substr($input, -1)) { + $input = \Tools::substr($input, 0, -1); + } + $input = \implode(',', Tools::arrayUnique(\explode(',', $input))); + + $ips = \explode(',', $input); + $output = []; + foreach ($ips as &$ip) { + if (!empty(\IPLib\Factory::rangeFromString($ip))) { + if ('LITE_BAN_IP' === $field) { + if (false === $this->isInWhitelistForGeolocation($ip)) { + $output[] = $ip; + } + } else { + $output[] = $ip; + } + } + } + + Configuration::updateValue($field, \implode(',', $output)); + } + + /** + * Validate comma separated string. + * + * @param string $field + */ + private function validateCommaSeparatedString($field) + { + if (false === (bool) Configuration::get($field)) { + return; + } + + $input = \preg_replace('/\s+/', '', Configuration::get($field)); + $input = \preg_replace('/,,+/', ',', $input); + if (',' === \Tools::substr($input, -1)) { + $input = \Tools::substr($input, 0, -1); + } + if (',' === \Tools::substr($input, 0, 1)) { + $input = \Tools::substr($input, 1); + } + $input = \implode(',', Tools::arrayUnique(\explode(',', $input))); + + Configuration::updateValue($field, $input); + } + + /** + * Check CVE-2019-13461. + * + * @return array + */ + private function checkCve201913461() + { + $check = 'CVE-2019-13461'; + $status = Tools::version_compare(_PS_VERSION_, '1.7.6.0', '<='); + $fix = $this->l('Update PrestaShop to the latest version.'); + + return [ + $check, + $status, + $fix, + ]; + } + + /** + * Check CVE-2019-11876. + * + * @return array + */ + private function checkCve201911876() + { + $check = 'CVE-2019-11876'; + + $path = \realpath(_PS_ROOT_DIR_ . \DIRECTORY_SEPARATOR . 'install'); + $status = \is_dir($path); + $fix = $this->l('Delete folder') . ': ' . $path; + + return [ + $check, + $status, + $fix, + ]; + } + + /** + * Check CVE-2018-19124. + * + * @return array + */ + private function checkCve201819124() + { + $check = 'CVE-2018-19124'; + + $status = false; + + if ((Tools::version_compare((float) _PS_VERSION_, '1.6', '==') && Tools::version_compare(_PS_VERSION_, '1.6.1.23', '<')) || (Tools::version_compare((float) _PS_VERSION_, '1.7', '==') && Tools::version_compare(_PS_VERSION_, '1.7.4.4', '<'))) { + if (\extension_loaded('phar') && !\ini_get('phar.readonly')) { + $status = true; + } + } + + $fix = $this->l('Set') . ' "phar.readonly = 0" ' . $this->l('in your php.ini file.'); + + return [ + $check, + $status, + $fix, + ]; + } + + /** + * Check CVE-2018-19125. + * + * @return array + */ + private function checkCve201819125() + { + $check = 'CVE-2018-19125'; + + $status = false; + + if ((Tools::version_compare((float) _PS_VERSION_, '1.6', '==') && Tools::version_compare(_PS_VERSION_, '1.6.1.23', '<')) || (Tools::version_compare((float) _PS_VERSION_, '1.7', '==') && Tools::version_compare(_PS_VERSION_, '1.7.4.4', '<'))) { + if (\extension_loaded('phar') && !\ini_get('phar.readonly')) { + $status = true; + } + } + + $fix = $this->l('Set') . ' "phar.readonly = 0" ' . $this->l('in your php.ini file.'); + + return [ + $check, + $status, + $fix, + ]; + } + + /** + * Check CVE-2018-19126. + * + * @return array + */ + private function checkCve201819126() + { + $check = 'CVE-2018-19126'; + + $status = false; + + if ((Tools::version_compare((float) _PS_VERSION_, '1.6', '==') && Tools::version_compare(_PS_VERSION_, '1.6.1.23', '<')) || (Tools::version_compare((float) _PS_VERSION_, '1.7', '==') && Tools::version_compare(_PS_VERSION_, '1.7.4.4', '<'))) { + if (\extension_loaded('phar') && !\ini_get('phar.readonly')) { + $status = true; + } + } + + $fix = $this->l('Set') . ' "phar.readonly = 0" ' . $this->l('in your php.ini file.'); + + return [ + $check, + $status, + $fix, + ]; + } + + /** + * Check CVE-2018-13784. + * + * @return array + */ + private function checkCve201813784() + { + $check = 'CVE-2018-13784'; + + $status = false; + + if ((Tools::version_compare((float) _PS_VERSION_, '1.6', '==') && Tools::version_compare(_PS_VERSION_, '1.6.1.20', '<')) || (Tools::version_compare((float) _PS_VERSION_, '1.7', '==') && Tools::version_compare(_PS_VERSION_, '1.7.3.4', '<'))) { + $status = true; + } + $fix = $this->l('Update PrestaShop to the latest version.'); + + return [ + $check, + $status, + $fix, + ]; + } + + /** + * Check CVE-2018-8823. + * + * @return array + */ + private function checkCve20188823() + { + $check = 'CVE-2018-8823'; + $status = false; + + if (\file_exists(_PS_MODULE_DIR_ . 'bamegamenu/ajax_phpcode.php')) { + $moduleVersion = Module::getInstanceByName('bamegamenu')->version; + if (!empty($moduleVersion)) { + if (Tools::version_compare($moduleVersion, '1.0.32', '<=')) { + $status = true; + } + } + } + $fix = $this->l('Update module') . '\' Responsive Mega Menu (Horizontal+Vertical+Dropdown) Pro\''; + + return [ + $check, + $status, + $fix, + ]; + } + + /** + * Check CVE-2018-8824. + * + * @return array + */ + private function checkCve20188824() + { + $check = 'CVE-2018-8824'; + $status = false; + + if (\file_exists(_PS_MODULE_DIR_ . 'bamegamenu/ajax_phpcode.php')) { + $moduleVersion = Module::getInstanceByName('bamegamenu')->version; + if (!empty($moduleVersion)) { + if (Tools::version_compare($moduleVersion, '1.0.32', '<=')) { + $status = true; + } + } + } + $fix = $this->l('Update module') . '\' Responsive Mega Menu (Horizontal+Vertical+Dropdown) Pro\''; + + return [ + $check, + $status, + $fix, + ]; + } + + /** + * Check CVE-2018-7491. + * + * @return array + */ + private function checkCve20187491() + { + $check = 'CVE-2018-7491'; + + if (Language::countActiveLanguages() > 1) { + $url = $this->getBaseURL() . '/' . $this->context->language->iso_code . '/'; + } else { + $url = $this->getBaseURL(); + } + + $headers = @\get_headers($url, 1); + + $status = true; + + if ('sameorigin' === \is_array(Tools::strtolower(isset($headers['X-Frame-Options']) ? $headers['X-Frame-Options'] : '')) || + 'sameorigin' === Tools::strtolower(isset($headers['X-Frame-Options']) ? $headers['X-Frame-Options'] : '') || + Configuration::get('LITE_CLICK_JACKING')) { + $status = false; + } + + $fix = $this->l('Enable') . ' ' . $this->l('Click-jack protection') . ' ' . $this->l('in') . ' \'' . $this->l('HTTP Security Headers') . '\'.'; + + return [ + $check, + $status, + $fix, + ]; + } + + /** + * Check CVE-2017-9841. + * + * @return array + */ + private function checkCve20179841() + { + $check = 'CVE-2017-9841'; + + $status = false; + + if (!empty($this->checkFilesCVE20179841())) { + $status = true; + } + + $fix = $this->l('Delete') . ' phpunit ' . $this->l('folders') . ':
' . \implode('
', $this->checkFilesCVE20179841()); + + return [ + $check, + $status, + $fix, + ]; + } + + /** + * Check if PrestaShop version is up to date. + * + * @return array + */ + private function checkPrestaShopVersion() + { + // Add Version tab + if (\defined('_TB_VERSION_')) { + $cmsName = 'Thirty bees'; + $cmsVersion = _TB_VERSION_; + $status = false; + } else { + $cmsName = 'PrestaShop'; + $cmsVersion = _PS_VERSION_; + $status = $this->checkPrestaShopUpToDate(); + } + + $check = $cmsName . ' ' . $this->l('version') . ' (' . $cmsVersion . ')'; + + $fix = $this->l('Update PrestaShop to the latest version.'); + + $desc = $this->l('It is strongly recommended to upgrade the store to the latest version of PrestaShop as new versions include bug fixes and security fixes.'); + + return [ + $check, + $status, + $fix, + $desc, + ]; + } + + /** + * Check if PHP version is up to date. + * + * @return array */ - protected function getConfigFormValues() + private function checkPhpVersion() { + $check = $this->l('PHP version') . ' (' . Tools::checkPhpVersion() . ')'; + + if (Tools::version_compare(_PS_VERSION_, '1.7.5.0', '<')) { + $status = Tools::version_compare(Tools::checkPhpVersion(), $this->getNewestPhpVersion('7.1'), '<'); + $fix = $this->l('Update the PHP version to') . ' ' . $this->getNewestPhpVersion('7.1') . '.'; + } elseif (Tools::version_compare(_PS_VERSION_, '1.7.7.0', '<')) { + $status = Tools::version_compare(Tools::checkPhpVersion(), $this->getNewestPhpVersion('7.2'), '<'); + $fix = $this->l('Update the PHP version to') . ' ' . $this->getNewestPhpVersion('7.2') . '.'; + } elseif (Tools::version_compare(_PS_VERSION_, '1.7.7.0', '>=')) { + $status = Tools::version_compare(Tools::checkPhpVersion(), $this->getNewestPhpVersion('7.3'), '<'); + $fix = $this->l('Update the PHP version to') . ' ' . $this->getNewestPhpVersion('7.3') . '.'; + } else { + $status = Tools::version_compare(Tools::checkPhpVersion(), $this->getNewestPhpVersion('7.4'), '<'); + $fix = $this->l('Update the PHP version to') . ' ' . $this->getNewestPhpVersion('7.4') . '.'; + } + + $desc = $this->l('The most obvious reason to update PHP is security. Newer versions are better at countering hackers, but the performance is also better in the newer PHP versions.'); + return [ - 'LITE_CLICK_JACKING' => Configuration::get('LITE_CLICK_JACKING'), - 'LITE_X_XSS_PPROTECTION' => Configuration::get('LITE_X_XSS_PPROTECTION'), - 'LITE_X_CONTENT_TYPE_OPTIONS' => Configuration::get('LITE_X_CONTENT_TYPE_OPTIONS'), - 'LITE_STRICT_TRANSPORT_SECURITY' => Configuration::get('LITE_STRICT_TRANSPORT_SECURITY'), - 'LITE_HSTS_SETTINGS_0' => Configuration::get('LITE_HSTS_SETTINGS_0'), - 'LITE_HSTS_SETTINGS_1' => Configuration::get('LITE_HSTS_SETTINGS_1'), - 'LITE_EXPECT_CT' => Configuration::get('LITE_EXPECT_CT'), - 'LITE_REFFERER_POLICY' => Configuration::get('LITE_REFFERER_POLICY'), - 'LITE_HTPASSWD' => Configuration::get('LITE_HTPASSWD'), - 'LITE_HTPASSWD_USER' => Configuration::get('LITE_HTPASSWD_USER'), - 'LITE_HTPASSWD_PASS' => Configuration::get('LITE_HTPASSWD_PASS'), - 'LITE_BAN_IP' => Configuration::get('LITE_BAN_IP'), - 'LITE_BAN_IP_ACTIVATE' => Configuration::get('LITE_BAN_IP_ACTIVATE'), - 'LITE_FAIL2BAN' => Configuration::get('LITE_FAIL2BAN'), - 'LITE_FAIL2BAN_EMAIL' => Configuration::get('LITE_FAIL2BAN_EMAIL'), - 'LITE_FAIL2BAN_LOG' => Configuration::get('LITE_FAIL2BAN_LOG'), - 'LITE_BAN_TIME' => (int) Configuration::get('LITE_BAN_TIME'), - 'LITE_MAX_RETRY' => (int) Configuration::get('LITE_MAX_RETRY'), - 'LITE_FIND_TIME' => (int) Configuration::get('LITE_FIND_TIME'), - 'LITE_SEND_MAIL' => Configuration::get('LITE_SEND_MAIL'), - 'LITE_SEND_MAIL_LOGIN' => Configuration::get('LITE_SEND_MAIL_LOGIN'), - 'LITE_WHITELIST_IPS' => Configuration::get('LITE_WHITELIST_IPS'), - 'LITE_FILE_CHANGES_EMAIL' => Configuration::get('LITE_FILE_CHANGES_EMAIL'), - 'LITE_FILE_CHANGES_LOG' => Configuration::get('LITE_FILE_CHANGES_LOG'), - 'LITE_FILE_CHANGES_WHITELIST' => Configuration::get('LITE_FILE_CHANGES_WHITELIST'), - 'LITE_MALWARE_SCAN_EMAIL' => Configuration::get('LITE_MALWARE_SCAN_EMAIL'), - 'LITE_MALWARE_SCAN_LOG' => Configuration::get('LITE_MALWARE_SCAN_LOG'), - 'LITE_WHITELIST_MALWARE' => Configuration::get('LITE_WHITELIST_MALWARE'), - 'LITE_BLOCK_FILE_UPLOAD_BACK_OFFICE_ACTIVATE' => Configuration::get('LITE_BLOCK_FILE_UPLOAD_BACK_OFFICE_ACTIVATE'), - 'LITE_BLOCK_FILE_UPLOAD_BACK_OFFICE' => Configuration::get('LITE_BLOCK_FILE_UPLOAD_BACK_OFFICE'), - 'LITE_ANTI_VIRUS_EMAIL' => Configuration::get('LITE_ANTI_VIRUS_EMAIL'), - 'LITE_DISABLE_RIGHT_CLICK' => Configuration::get('LITE_DISABLE_RIGHT_CLICK'), - 'LITE_DISABLE_DRAG' => Configuration::get('LITE_DISABLE_DRAG'), - 'LITE_DISABLE_COPY' => Configuration::get('LITE_DISABLE_COPY'), - 'LITE_DISABLE_CUT' => Configuration::get('LITE_DISABLE_CUT'), - 'LITE_DISABLE_PASTE' => Configuration::get('LITE_DISABLE_PASTE'), - 'LITE_DISABLE_TEXT_SELECTION' => Configuration::get('LITE_DISABLE_TEXT_SELECTION'), - 'LITE_ADMIN_DIRECTORY' => Configuration::get('LITE_ADMIN_DIRECTORY'), - 'LITE_ADMIN_DIRECTORY_NAME' => Configuration::get('LITE_ADMIN_DIRECTORY_NAME'), - 'LITE_BACKUP_DB_TOKEN' => Configuration::get('LITE_BACKUP_DB_TOKEN'), - 'LITE_ANTI_FLOOD' => Configuration::get('LITE_ANTI_FLOOD'), - 'LITE_ANTI_MAX_REQUESTS' => (int) Configuration::get('LITE_ANTI_MAX_REQUESTS'), - 'LITE_ANTI_REQ_TIMEOUT' => (int) Configuration::get('LITE_ANTI_REQ_TIMEOUT'), - 'LITE_ANTI_BAN_TIME' => (int) Configuration::get('LITE_ANTI_BAN_TIME'), - 'LITE_FIREWALL_RECAPCHA_SECRET' => Configuration::get('LITE_FIREWALL_RECAPCHA_SECRET'), - 'LITE_FIREWALL_RECAPCHA_SITE_KEY' => Configuration::get('LITE_FIREWALL_RECAPCHA_SITE_KEY'), - 'LITE_HONEYPOT_API' => Configuration::get('LITE_HONEYPOT_API'), - 'LITE_FIREWALL_CHECK_BOT' => Configuration::get('LITE_FIREWALL_CHECK_BOT'), - 'LITE_FIREWALL_SQL_CHECK' => Configuration::get('LITE_FIREWALL_SQL_CHECK'), - 'LITE_FIREWALL_XXS_CHECK' => Configuration::get('LITE_FIREWALL_XXS_CHECK'), - 'LITE_FIREWALL_SHELL_CHECK' => Configuration::get('LITE_FIREWALL_SHELL_CHECK'), - 'LITE_FIREWALL_XST_CHECK' => Configuration::get('LITE_FIREWALL_XST_CHECK'), - 'LITE_FIREWALL_HTML_CHECK' => Configuration::get('LITE_FIREWALL_HTML_CHECK'), - 'LITE_FIREWALL_CHECK_REQUEST' => Configuration::get('LITE_FIREWALL_CHECK_REQUEST'), - 'LITE_FIREWALL_CHECK_USERAGENT' => Configuration::get('LITE_FIREWALL_CHECK_USERAGENT'), - 'LITE_FIREWALL_OLD_PROTOCOL' => Configuration::get('LITE_FIREWALL_OLD_PROTOCOL'), - 'LITE_BLOCK_FILE_UPLOAD' => Configuration::get('LITE_BLOCK_FILE_UPLOAD'), - 'LITE_FIREWALL_LOG' => Configuration::get('LITE_FIREWALL_LOG'), - 'LITE_PASSWORD_GENERATOR' => Configuration::get('LITE_PASSWORD_GENERATOR'), - 'LITE_BACKUP_DB' => Configuration::get('LITE_BACKUP_DB'), - 'LITE_BACKUP_DB_DROPBOX' => Configuration::get('LITE_BACKUP_DB_DROPBOX'), - 'LITE_BACKUP_DB_TOKEN' => Configuration::get('LITE_BACKUP_DB_TOKEN'), - 'LITE_BACKUP_DB_SAVED' => (int) Configuration::get('LITE_BACKUP_DB_SAVED'), - 'LITE_BACKUP_FILE_SAVED' => (int) Configuration::get('LITE_BACKUP_FILE_SAVED'), - 'LITE_BACKUP_FILE' => Configuration::get('LITE_BACKUP_FILE'), - 'LITE_BACKUP_FILE_DROPBOX' => Configuration::get('LITE_BACKUP_FILE_DROPBOX'), - 'LITE_BACKUP_COMPRESSION' => Configuration::get('LITE_BACKUP_COMPRESSION'), - 'LITE_TWO_FACTOR_AUTH' => Configuration::get('LITE_TWO_FACTOR_AUTH'), - 'LITE_TWO_FACTOR_AUTH_CODE' => Configuration::get('LITE_TWO_FACTOR_AUTH_CODE'), - 'LITE_TWO_FACTOR_AUTH_WHITELIST' => Configuration::get('LITE_TWO_FACTOR_AUTH_WHITELIST'), - 'LITE_FAKE_ACCOUNTS' => Configuration::get('LITE_FAKE_ACCOUNTS'), - 'LITE_WHITELIST_PROTECT_CONTENT' => Configuration::get('LITE_WHITELIST_PROTECT_CONTENT'), - 'LITE_BLOCK_USER_AGENT_ACTIVATE' => Configuration::get('LITE_BLOCK_USER_AGENT_ACTIVATE'), - 'LITE_BLOCK_USER_AGENT' => Configuration::get('LITE_BLOCK_USER_AGENT'), - 'LITE_BLOCK_TOR' => Configuration::get('LITE_BLOCK_TOR'), - 'LITE_DISABLE_CONTACT_FORM' => Configuration::get('LITE_DISABLE_CONTACT_FORM'), + $check, + $status, + $fix, + $desc, + ]; + } + + /** + * Check if PrestaShop TLS is enabled. + * + * @return array + */ + private function checkTlsEnabled() + { + $check = $this->l('SSL enabled'); + + $status = false === (bool) Configuration::get('PS_SSL_ENABLED'); + + $fix = $this->l('Enable SSL in') . ' ' . $this->generateLink($this->getAdminLink('AdminPreferences', true), $this->l('\'Shop Parameters\' > \'General\'')); + + $desc = $this->l('If you own an SSL certificate for your shop\'s domain name, you can activate SSL encryption (https://) for customer account identification and order processing.'); + + return [ + $check, + $status, + $fix, + $desc, + ]; + } + + /** + * Check if PrestaShop TLS everywhere is enabled. + * + * @return array + */ + private function checkTlsEnabledEverywhere() + { + $check = $this->l('SSL enabled everywhere'); + + $status = false === (bool) Configuration::get('PS_SSL_ENABLED_EVERYWHERE'); + + $fix = $this->l('Enable SSL everywhere in') . ' ' . $this->generateLink($this->getAdminLink('AdminPreferences', true), $this->l('\'Shop Parameters\' > \'General\'')); + + $desc = $this->l('When enabled, all the pages of your shop will be SSL-secured.'); + + return [ + $check, + $status, + $fix, + $desc, + ]; + } + + /** + * Check if PrestaShop token is activated. + * + * @return array + */ + private function checkPrestashopToken() + { + $check = $this->l('Security token'); + + $status = false === (bool) Configuration::get('PS_TOKEN_ENABLE'); + + $fix = $this->l('Enable Increase front office security in') . ' ' . $this->generateLink($this->getAdminLink('AdminPreferences', true), $this->l('\'Shop Parameters\' > \'General\'')); + + $desc = $this->l('Enable token in the front office to improve PrestaShop\'s security.'); + + return [ + $check, + $status, + $fix, + $desc, + ]; + } + + /** + * Check if Mod Secure is active. + * + * @return array + */ + private function checkModSecurity() + { + $check = 'ModSecurity'; + + $status = (bool) Configuration::get('PS_HTACCESS_DISABLE_MODSEC'); + + $fix = $this->l('Enable Apache\'s \'mod_security\' module in') . ' ' . $this->generateLink($this->getAdminLink('AdminMeta', true), $this->l('\'Shop Parameters\' > \'Traffic and SEO\'')); + + $desc = $this->l('Enable Apache\'s mod_security module to harden the security of your shop.'); + + return [ + $check, + $status, + $fix, + $desc, + ]; + } + + /** + * Check if PrestaShop admin directory name is secure. + * + * @return array + */ + private function checkAdminDirectoryName() + { + $check = $this->l('Admin folder name'); + + $status = !\preg_match('/[A-Za-z].*[0-9]|[0-9].*[A-Za-z]/', \basename(_PS_ADMIN_DIR_)); + + $fix = $this->l('Use both letters and numbers in the name of your admin folder.'); + + $desc = $this->l('To make it harder for attackers to guess the URL, use both letters and numbers in the name of your admin folder.'); + + return [ + $check, + $status, + $fix, + $desc, + ]; + } + + /** + * Check if PrestaShop develop mode is active. + * + * @return array + */ + private function checkPrestashopDevMode() + { + $check = $this->l('Debug mode'); + + $status = _PS_MODE_DEV_; + + $fix = $this->l('Disabling the debug mode at') . ' ' . $this->generateLink($this->getAdminLink('AdminPerformance', true), $this->l('\'Advanced Parameters\' > \'Performance\'')); + + $desc = $this->l('Once your shop is in production, you must disable the debug mode. It can leak pieces of information that a hacker can use.'); + + return [ + $check, + $status, + $fix, + $desc, + ]; + } + + /** + * Check the cookie's IP address. + * + * @return array + */ + private function checkCookieIpAddress() + { + $check = $this->l('Cookie\'s IP address'); + + $status = false === (bool) Configuration::get('PS_COOKIE_CHECKIP'); + + $fix = $this->l('Enable check of cookie IP address at') . ' ' . $this->generateLink($this->getAdminLink('AdminAdminPreferences', true), $this->l('\'Advanced Parameters\' > \'Administration\'')); + + $desc = $this->l('Check the IP address of the cookie to prevent your cookie from being stolen.'); + + return [ + $check, + $status, + $fix, + $desc, + ]; + } + + /** + * Check CVE-2020-15083. + * + * @return array + */ + private function checkCve202015083() + { + $check = 'CVE-2020-15083'; + $status = false; + if (Tools::version_compare(_PS_VERSION_, '1.7.0.0', '>=') && Tools::version_compare(_PS_VERSION_, '1.7.6.6', '<')) { + $status = true; + } + + $fix = $this->l('Update PrestaShop to the latest version.'); + + return [ + $check, + $status, + $fix, + ]; + } + + /** + * Check CVE-2020-15079. + * + * @return array + */ + private function checkCve202015079() + { + $check = 'CVE-2020-15079'; + $status = false; + if (Tools::version_compare(_PS_VERSION_, '1.7.6.6', '<')) { + $status = true; + } + + $fix = $this->l('Update PrestaShop to the latest version.'); + + return [ + $check, + $status, + $fix, ]; } /** - * Post configure form values. + * Check CVE-2020-4074. + * + * @return array */ - protected function postProcess() + private function checkCve20204074() { - $form_values = $this->getConfigFormValues(); - - foreach (\array_keys($form_values) as $key) { - Configuration::updateValue($key, Tools::getValue($key)); + $check = 'CVE-2020-4074'; + $status = false; + if (Tools::version_compare(_PS_VERSION_, '1.7.6.6', '<')) { + $status = true; } + + $fix = $this->l('Update PrestaShop to the latest version.'); + + return [ + $check, + $status, + $fix, + ]; } - private function checkCVE201819355() + /** + * Check CVE-2020-5250. + * + * @return array + */ + private function checkCve20205250() { - $check = 'CVE-2018-19355'; - - $status = \file_exists(_PS_MODULE_DIR_ . 'orderfiles/upload.php'); + $check = 'CVE-2020-5250'; + $status = false; + if (Tools::version_compare(_PS_VERSION_, '1.7.0.0', '>=') && Tools::version_compare(_PS_VERSION_, '1.7.6.4', '<')) { + $status = true; + } - $fix = $this->l('Update') . ' "orderfiles" ' . $this->l('module to latest version.'); + $fix = $this->l('Update PrestaShop to the latest version.'); return [ $check, @@ -2447,8 +6269,6 @@ private function checkCVE201819355() ]; } - //start - /** * Check CVE-2020-5264. * @@ -2456,14 +6276,14 @@ private function checkCVE201819355() */ private function checkCve20205264() { - $check = 'CVE-2020-5264'; + $check = 'CVE-2020-5264'; $status = false; if (Tools::version_compare(_PS_VERSION_, '1.7.0.0', '>=') && Tools::version_compare(_PS_VERSION_, '1.7.6.5', '<')) { $status = true; } - $fix = $this->l('Update PrestaShop to latest version.'); + $fix = $this->l('Update PrestaShop to the latest version.'); return [ $check, @@ -2479,14 +6299,14 @@ private function checkCve20205264() */ private function checkCve20205265() { - $check = 'CVE-2020-5265'; + $check = 'CVE-2020-5265'; $status = false; if (Tools::version_compare(_PS_VERSION_, '1.7.6.1', '>=') && Tools::version_compare(_PS_VERSION_, '1.7.6.5', '<')) { $status = true; } - $fix = $this->l('Update PrestaShop to latest version.'); + $fix = $this->l('Update PrestaShop to the latest version.'); return [ $check, @@ -2502,14 +6322,14 @@ private function checkCve20205265() */ private function checkCve20205269() { - $check = 'CVE-2020-5269'; + $check = 'CVE-2020-5269'; $status = false; if (Tools::version_compare(_PS_VERSION_, '1.7.6.1', '>=') && Tools::version_compare(_PS_VERSION_, '1.7.6.5', '<')) { $status = true; } - $fix = $this->l('Update PrestaShop to latest version.'); + $fix = $this->l('Update PrestaShop to the latest version.'); return [ $check, @@ -2525,14 +6345,14 @@ private function checkCve20205269() */ private function checkCve20205270() { - $check = 'CVE-2020-5270'; + $check = 'CVE-2020-5270'; $status = false; if (Tools::version_compare(_PS_VERSION_, '1.7.6.0', '>=') && Tools::version_compare(_PS_VERSION_, '1.7.6.5', '<')) { $status = true; } - $fix = $this->l('Update PrestaShop to latest version.'); + $fix = $this->l('Update PrestaShop to the latest version.'); return [ $check, @@ -2548,14 +6368,14 @@ private function checkCve20205270() */ private function checkCve20205272() { - $check = 'CVE-2020-5272'; + $check = 'CVE-2020-5272'; $status = false; if (Tools::version_compare(_PS_VERSION_, '1.5.5.0', '>=') && Tools::version_compare(_PS_VERSION_, '1.7.6.5', '<')) { $status = true; } - $fix = $this->l('Update PrestaShop to latest version.'); + $fix = $this->l('Update PrestaShop to the latest version.'); return [ $check, @@ -2571,14 +6391,14 @@ private function checkCve20205272() */ private function checkCve20205279() { - $check = 'CVE-2020-5279'; + $check = 'CVE-2020-5279'; $status = false; if (Tools::version_compare(_PS_VERSION_, '1.5.0.0', '>=') && Tools::version_compare(_PS_VERSION_, '1.7.6.5', '<')) { $status = true; } - $fix = $this->l('Update PrestaShop to latest version.'); + $fix = $this->l('Update PrestaShop to the latest version.'); return [ $check, @@ -2594,14 +6414,14 @@ private function checkCve20205279() */ private function checkCve20205276() { - $check = 'CVE-2020-5276'; + $check = 'CVE-2020-5276'; $status = false; if (Tools::version_compare(_PS_VERSION_, '1.7.1.0', '>=') && Tools::version_compare(_PS_VERSION_, '1.7.6.5', '<')) { $status = true; } - $fix = $this->l('Update PrestaShop to latest version.'); + $fix = $this->l('Update PrestaShop to the latest version.'); return [ $check, @@ -2617,14 +6437,14 @@ private function checkCve20205276() */ private function checkCve20205278() { - $check = 'CVE-2020-5278'; + $check = 'CVE-2020-5278'; $status = false; if (Tools::version_compare(_PS_VERSION_, '1.5.4.0', '>=') && Tools::version_compare(_PS_VERSION_, '1.7.6.5', '<')) { $status = true; } - $fix = $this->l('Update PrestaShop to latest version.'); + $fix = $this->l('Update PrestaShop to the latest version.'); return [ $check, @@ -2640,14 +6460,14 @@ private function checkCve20205278() */ private function checkCve20205286() { - $check = 'CVE-2020-5286'; + $check = 'CVE-2020-5286'; $status = false; if (Tools::version_compare(_PS_VERSION_, '1.7.4.0', '>=') && Tools::version_compare(_PS_VERSION_, '1.7.6.5', '<')) { $status = true; } - $fix = $this->l('Update PrestaShop to latest version.'); + $fix = $this->l('Update PrestaShop to the latest version.'); return [ $check, @@ -2663,14 +6483,14 @@ private function checkCve20205286() */ private function checkCve20205285() { - $check = 'CVE-2020-5285'; + $check = 'CVE-2020-5285'; $status = false; if (Tools::version_compare(_PS_VERSION_, '1.7.6.0', '>=') && Tools::version_compare(_PS_VERSION_, '1.7.6.5', '<')) { $status = true; } - $fix = $this->l('Update PrestaShop to latest version.'); + $fix = $this->l('Update PrestaShop to the latest version.'); return [ $check, @@ -2686,14 +6506,14 @@ private function checkCve20205285() */ private function checkCve20205287() { - $check = 'CVE-2020-5287'; + $check = 'CVE-2020-5287'; $status = false; if (Tools::version_compare(_PS_VERSION_, '1.5.5.0', '>=') && Tools::version_compare(_PS_VERSION_, '1.7.6.5', '<')) { $status = true; } - $fix = $this->l('Update PrestaShop to latest version.'); + $fix = $this->l('Update PrestaShop to the latest version.'); return [ $check, @@ -2709,14 +6529,97 @@ private function checkCve20205287() */ private function checkCve20205288() { - $check = 'CVE-2020-5288'; + $check = 'CVE-2020-5288'; $status = false; if (Tools::version_compare(_PS_VERSION_, '1.7.0.0', '>=') && Tools::version_compare(_PS_VERSION_, '1.7.6.5', '<')) { $status = true; } - $fix = $this->l('Update PrestaShop to latest version.'); + $fix = $this->l('Update PrestaShop to the latest version.'); + + return [ + $check, + $status, + $fix, + ]; + } + + /** + * Check CVE-2020-15080. + * + * @return array + */ + private function checkCve202015080() + { + $check = 'CVE-2020-15080'; + + $files = [ + 'composer.json', + 'docker-compose.yml', + ]; + + $root = _PS_CORE_DIR_ . \DIRECTORY_SEPARATOR; + $result = []; + foreach ($files as $file) { + if (\file_exists($root . $file)) { + $result[] = $root . $file; + } + } + + if (!empty($result)) { + $status = true; + } else { + $status = false; + } + + $fix = $this->l('Delete following files') . ':
' . \implode('
', $result); + + return [ + $check, + $status, + $fix, + ]; + } + + /** + * Check CVE-2020-15081. + * + * @return array + */ + private function checkCve202015081() + { + $check = 'CVE-2020-15081'; + + $status = false; + if (Tools::version_compare(_PS_VERSION_, '1.7.6.6', '<')) { + $status = true; + } + + $fix = $this->l('Update PrestaShop to the latest version.'); + + return [ + $check, + $status, + $fix, + ]; + } + + /** + * Check CVE-2020-15082. + * + * @return array + */ + private function checkCve202015082() + { + $check = 'CVE-2020-15082'; + + $status = false; + if (Tools::version_compare(_PS_VERSION_, '1.7.6.6', '<')) { + $status = true; + } + + $fix = $this->l('Update PrestaShop to the latest version.'); return [ $check, @@ -2732,14 +6635,14 @@ private function checkCve20205288() */ private function checkCve20205293() { - $check = 'CVE-2020-5293'; + $check = 'CVE-2020-5293'; $status = false; if (Tools::version_compare(_PS_VERSION_, '1.7.0.0', '>=') && Tools::version_compare(_PS_VERSION_, '1.7.6.5', '<')) { $status = true; } - $fix = $this->l('Update PrestaShop to latest version.'); + $fix = $this->l('Update PrestaShop to the latest version.'); return [ $check, @@ -2755,14 +6658,14 @@ private function checkCve20205293() */ private function checkCve20205271() { - $check = 'CVE-2020-5271'; + $check = 'CVE-2020-5271'; $status = false; if (Tools::version_compare(_PS_VERSION_, '1.6.0.0', '>=') && Tools::version_compare(_PS_VERSION_, '1.7.6.5', '<')) { $status = true; } - $fix = $this->l('Update PrestaShop to latest version.'); + $fix = $this->l('Update PrestaShop to the latest version.'); return [ $check, @@ -2771,1462 +6674,2035 @@ private function checkCve20205271() ]; } - private function analyzeSystem() + /** + * Check php.ini conf: session.use_cookies. + * + * @return array + */ + private function checkSessionAutoStart() { - $helper = new HelperList(); - $helper->module = $this; - $helper->title = $this->l('Analyze your system for known security vulnerabilities and recommend options for increased protection'); - $helper->simple_header = false; - $helper->title_icon = 'icon-list'; - $helper->shopLinkType = ''; - $helper->no_link = true; - $helper->show_toolbar = true; - $helper->simple_header = false; - $helper->currentIndex = $this->context->link->getAdminLink('AdminModules', false) . '&configure=securitylite'; - $helper->token = \Tools::getAdminTokenLite('AdminModules'); - $check = ''; - $vulnerable = ''; - $good = '--'; - $fields_list = [ - 'check' => [ - 'title' => '' . $this->l('Check') . '', - 'search' => false, - 'float' => true, - ], - 'status' => [ - 'title' => '' . $this->l('Status') . '', - 'search' => false, - 'float' => true, - ], - 'fix' => [ - 'title' => '' . $this->l('How to fix') . '', - 'search' => false, - 'float' => true, - ], - ]; + $key = 'session.auto_start'; + if (false !== $this->isOn(\ini_get($key))) { + $current = $this->isOn(\ini_get($key)); + } else { + $current = '0'; + } - $checkGrids = [ - $this->checkCve20205293(), - $this->checkCve20205288(), - $this->checkCve20205287(), - $this->checkCve20205286(), - $this->checkCve20205285(), - $this->checkCve20205279(), - $this->checkCve20205278(), - $this->checkCve20205276(), - $this->checkCve20205272(), - $this->checkCve20205271(), - $this->checkCve20205270(), - $this->checkCve20205269(), - $this->checkCve20205265(), - $this->checkCve20205264(), - $this->checkCve20205250(), - $this->checkCve201913461(), - $this->checkCve201911876(), - $this->checkCve20188824(), - $this->checkCve20187491(), - $this->checkCve201819355(), - $this->checkCve201819126(), - $this->checkCve201813784(), - $this->checkCve20179841(), - $this->checkCve20151175(), - $this->checkPhpVersion(), - $this->checkSslEnabled(), - $this->checkSslEnabledEverywhere(), - $this->checkPrestashopToken(), - $this->checkModSecurity(), - $this->checkAdminDirectoryName(), - $this->checkPsTablePrefix(), - $this->checkPrestashopDevMode(), - ]; - $result = []; - foreach ($checkGrids as $checkGrid) { - $result[] = [ - 'check' => $checkGrid[0], - 'status' => $checkGrid[1] ? $vulnerable : $check, - 'fix' => $checkGrid[1] ? $checkGrid[2] : $good, - ]; + $recommended = '0'; + + if ($current === $recommended) { + $status = false; + } else { + $status = true; } + $desc = $this->l('It is considered to bad practice to autostart sessions.'); - return $helper->generateList($result, $fields_list); + return [ + $key, + $current, + $recommended, + $status, + $desc, + ]; } - private function analyzePhpIni() + /** + * Check php.ini conf: session.use_cookies. + * + * @return array + */ + private function checkSessionUseCookies() { - $helper = new HelperList(); - $helper->module = $this; - $helper->title = $this->l('Analyze your php.ini configuration'); - $helper->shopLinkType = ''; - $helper->simple_header = false; - $helper->title_icon = 'icon-list'; - $helper->no_link = true; - $helper->show_toolbar = true; - $helper->simple_header = false; - $helper->currentIndex = $this->context->link->getAdminLink('AdminModules', false) . '&configure=securitylite'; - $helper->token = \Tools::getAdminTokenLite('AdminModules'); - $fields_list = [ - 'key' => [ - 'title' => '' . $this->l('Setting') . '', - 'search' => false, - 'float' => true, - ], - 'current' => [ - 'title' => '' . $this->l('Current value') . '', - 'search' => false, - 'float' => true, - ], - 'recommended' => [ - 'title' => '' . $this->l('Recommended value') . '', - 'search' => false, - 'float' => true, - ], - 'status' => [ - 'title' => '' . $this->l('Status') . '', - 'search' => false, - 'float' => true, - ], - 'desc' => [ - 'title' => '' . $this->l('Description') . '', - 'search' => false, - 'float' => true, - ], + $key = 'session.use_cookies'; + if (false !== $this->isOn(\ini_get($key))) { + $current = $this->isOn(\ini_get($key)); + } else { + $current = '1'; + } + + $recommended = '1'; + + if ($current === $recommended) { + $status = false; + } else { + $status = true; + } + $desc = $this->l('Accepts cookies to manage sessions.'); + + return [ + $key, + $current, + $recommended, + $status, + $desc, ]; - $checkGrids = [ - $this->checkSessionUseCookies(), - $this->checkSessionUseOnlyCookies(), - $this->checkSessionCookieHttponly(), - $this->checkAessionHashFunction(), - $this->checkPhpUseTransSid(), - $this->checkCookieSecure(), - $this->checkUseScrickMode(), - $this->checkCookieLifetime(), - $this->checkLazyWrite(), - $this->checkSidLength(), - $this->checkSessionGcDivisor(), - $this->checkSidBitsPerCharacter(), - $this->checkUrlFopen(), - $this->checkUrlInclude(), - $this->checkDisplayErrors(), - $this->checkLogErrors(), - $this->checkErrorReporting(), - $this->checkDisplayStartupErrors(), - $this->checkExposePhp(), - $this->checkRegisterGlobals(), - $this->checkRegisterArgcArgv(), - $this->checkShortOpenTag(), - $this->checkXdebugDefaultEnable(), - $this->checkXdebugRemoteEnable(), - $this->checkFileUploads(), - $this->checkUploadMaxFileSize(), - $this->checkPostMaxSize(), - $this->checkMaxInputVars(), - $this->checkMaxInputTime(), - $this->checkMemoryLimit(), - $this->checkMaxExecutionTime(), - $this->checkDefaultCharset(), + } + + /** + * Check php.ini conf: session.use_only_cookies. + * + * @return array + */ + private function checkSessionUseOnlyCookies() + { + $key = 'session.use_only_cookies'; + if (false !== $this->isOn(\ini_get($key))) { + $current = $this->isOn(\ini_get($key)); + } else { + $current = '1'; + } + + $recommended = '1'; + + if ($current === $recommended) { + $status = false; + } else { + $status = true; + } + $desc = $this->l('Must use cookies to manage sessions, don\'t accept session-ids in a link.'); + + return [ + $key, + $current, + $recommended, + $status, + $desc, ]; - $result = []; - foreach ($checkGrids as $checkGrid) { - $result[] = [ - 'key' => $checkGrid[0], - 'current' => $checkGrid[1], - 'recommended' => $this->proFeature, - 'status' => $this->proFeature, - 'desc' => $this->proFeature, - ]; + } + + /** + * Check php.ini conf: session.cookie_httponly. + * + * @return array + */ + private function checkSessionCookieHttponly() + { + $key = 'session.cookie_httponly'; + if (false !== $this->isOn(\ini_get($key))) { + $current = $this->isOn(\ini_get($key)); + } else { + $current = ''; + } + + $recommended = '1'; + + if ($current === $recommended) { + $status = false; + } else { + $status = true; } - return $helper->generateList($result, $fields_list); + $desc = $this->l('Setting session cookies to \'HTTP only\' makes them only readable by the browser.'); + + return [ + $key, + $current, + $recommended, + $status, + $desc, + ]; } - private function getBaseURL() + /** + * Check php.ini conf: session.use_trans_sid. + * + * @return array + */ + private function checkPhpUseTransSid() { - if (Tools::version_compare(_PS_VERSION_, '1.7', '>=')) { - return $this->context->link->getBaseLink(); + $key = 'session.use_trans_sid'; + if (false !== $this->isOn(\ini_get($key))) { + $current = $this->isOn(\ini_get($key)); + } else { + $current = '0'; } - if (true === (bool) Configuration::get('PS_SSL_ENABLED')) { - return \Context::getContext()->shop->getBaseURL(true); + $recommended = '0'; + if ($current === $recommended) { + $status = false; + } else { + $status = true; } - return \Context::getContext()->shop->getBaseURL(false); + $desc = $this->l('If used') . ' \'use_trans_sid\' ' . $this->l('setting puts the session ID on the URL, making it easier to hijack.'); + + return [ + $key, + $current, + $recommended, + $status, + $desc, + ]; } - private function getTwoFactorAuthDB($column) + /** + * Check php.ini conf: session.cookie_secure. + * + * @return array + */ + private function checkCookieSecure() { - $sql = new DbQuery(); - $sql->from('securitylite_tfa'); - $sql->select($column); + $key = 'session.cookie_secure'; + if (false !== $this->isOn(\ini_get($key))) { + $current = $this->isOn(\ini_get($key)); + } else { + $current = ''; + } - return Db::getInstance()->getValue($sql); + if (true === $this->isSsl()) { + $recommended = '1'; + } else { + $recommended = '0'; + } + + if ($current === $recommended) { + $status = false; + } else { + $status = true; + } + + $desc = $this->l('Cookie secure specifies whether cookies should only be sent over secure connections.') . ' ' . $this->l('This setting requires SSL/TLS to be enabled.'); + + return [ + $key, + $current, + $recommended, + $status, + $desc, + ]; } - private function updateTwoFactorAuthDB($column, $value) + /** + * Check php.ini conf: session.cookie_lifetime. + * + * @return array + */ + private function checkCookieLifetime() { - $query = 'UPDATE `' . _DB_PREFIX_ . 'securitylite_tfa` SET ' . $column . '="' . $value . '"'; + $key = 'session.cookie_lifetime'; + if (false !== $this->isOn(\ini_get($key))) { + $current = $this->isOn(\ini_get($key)); + } else { + $current = '0'; + } + $recommended = '0'; + if ($current === $recommended) { + $status = false; + } else { + $status = true; + } - return Db::getInstance()->Execute($query); + $desc = $this->l('It tells browsers not to store the session cookie to permanent storage. Therefore, when the browser is terminated, the session ID cookie is deleted immediately.'); + + return [ + $key, + $current, + $recommended, + $status, + $desc, + ]; } - private function isInWhitelistForGeolocation($userIp) + /** + * Check php.ini conf: session.use_strict_mode. + * + * @return array + */ + private function checkUseScrickMode() { - $ips = \explode(';', Configuration::get('PS_GEOLOCATION_WHITELIST')); - if (\is_array($ips) && \count($ips)) { - foreach ($ips as $ip) { - if (!empty($ip) && 0 === \mb_strpos($userIp, $ip)) { - return true; - } - } + $key = 'session.use_strict_mode'; + if (false !== $this->isOn(\ini_get($key))) { + $current = $this->isOn(\ini_get($key)); + } else { + $current = '0'; + } + $recommended = '1'; + if ($current === $recommended) { + $status = false; + } else { + $status = true; } - return false; + $desc = $this->l('Strict mode prevents uninitialized session ID\'s in the built-in session handling.'); + + return [ + $key, + $current, + $recommended, + $status, + $desc, + ]; } - private function validateIps($field) + /** + * Check php.ini conf: session.lazy_write. + * + * @return array + */ + private function checkLazyWrite() { - if (false === (bool) Configuration::get($field)) { - return; - } + $key = 'session.lazy_write'; - $input = \preg_replace('/\s+/', '', Configuration::get($field)); - $input = \preg_replace('/,,+/', ',', $input); - if (',' === \Tools::substr($input, -1)) { - $input = \Tools::substr($input, 0, -1); + if (Tools::version_compare(Tools::checkPhpVersion(), '7.0.0', '>=')) { + if (false !== $this->isOn(\ini_get($key))) { + $current = $this->isOn(\ini_get($key)); + } else { + $current = '0'; + } + $recommended = '1'; + $desc = $this->l('Lazy session writes only when the session data has been modified. This should be enabled to prevent potential information exposure.'); + } else { + $current = false; + $recommended = false; + $desc = $this->l('The INI setting') . ' \'' . $key . '\' ' . $this->l('was added in') . ' PHP 7.0.0.'; } - $input = \implode(',', Tools::arrayUnique(\explode(',', $input))); - $lists = \explode(',', $input); - $output = []; - foreach ($lists as &$list) { - if (!empty(\IPLib\Factory::rangeFromString($list))) { - if ('LITE_BAN_IP' === $field) { - if (false === $this->isInWhitelistForGeolocation($list)) { - $output[] = $list; - } - } else { - $output[] = $list; - } - } + if ($current === $recommended) { + $status = false; + } else { + $status = true; } - Configuration::updateValue($field, \implode(',', $output)); + return [ + $key, + $current, + $recommended, + $status, + $desc, + ]; } - private function validateCommaSeperatedString($field) + /** + * Check php.ini conf: session.sid_length. + * + * @return array + */ + private function checkSidLength() { - if (false === (bool) Configuration::get($field)) { - return; - } + $key = 'session.sid_length'; - $input = \preg_replace('/\s+/', '', Configuration::get($field)); - $input = \preg_replace('/,,+/', ',', $input); - if (',' === \Tools::substr($input, -1)) { - $input = \Tools::substr($input, 0, -1); - } - if (',' === \Tools::substr($input, 0, 1)) { - $input = \Tools::substr($input, 1); + if (Tools::version_compare(Tools::checkPhpVersion(), '7.1.0', '>=')) { + if (false !== \ini_get($key)) { + $current = \ini_get($key); + } else { + $current = '32'; + } + $recommended = '128'; + $desc = $this->l('Increasing the session ID length will make it harder for an attacker to guess it (via brute force or more likely side-channel attacks).'); + if ((int) $current >= (int) $recommended) { + $status = false; + } else { + $status = true; + } + } else { + $current = false; + $recommended = false; + $status = false; + $desc = $this->l('The INI setting') . ' \'' . $key . '\' ' . $this->l('was added in') . ' PHP 7.1.0.'; } - $input = \implode(',', Tools::arrayUnique(\explode(',', $input))); - Configuration::updateValue($field, $input); + return [ + $key, + $current, + $recommended, + $status, + $desc, + ]; } - private function checkCVE201913461() + /** + * Check php.ini conf: session.gc_probability. + * + * @return array + */ + private function checkSessionGcProbability() { - $check = 'CVE-2019-13461'; - $status = Tools::version_compare(_PS_VERSION_, '1.7.6.0', '<'); - $fix = $this->l('Update PrestaShop to latest version.'); + $key = 'session.gc_probability'; + if (false !== $this->isOn(\ini_get($key))) { + $current = $this->isOn(\ini_get($key)); + } else { + $current = '1'; + } + $recommended = '1'; + if ($current === $recommended) { + $status = false; + } else { + $status = true; + } + + $desc = $this->l('Defines the probability that the \'garbage collection\' process is started on every session initialization.'); return [ - $check, + $key, + $current, + $recommended, $status, - $fix, + $desc, ]; } - private function checkCVE201911876() + /** + * Check php.ini conf: session.gc_divisor. + * + * @return array + */ + private function checkSessionGcDivisor() { - $check = 'CVE-2019-11876'; - $status = \is_dir(_PS_ROOT_DIR_ . '/install'); - $fix = $this->l('Delete folder') . ': ' . _PS_ROOT_DIR_ . \DIRECTORY_SEPARATOR . 'install'; + $key = 'session.gc_divisor'; + if (false !== \ini_get($key)) { + $current = \ini_get($key); + } else { + $current = '100'; + } + $recommended = '1000'; + if ($current === $recommended) { + $status = false; + } else { + $status = true; + } + + $desc = $this->l('Defines the probability that the \'garbage collection\' process is started on every session initialization.'); return [ - $check, + $key, + $current, + $recommended, $status, - $fix, + $desc, ]; } - private function checkCVE201819126() + /** + * Check php.ini conf: session.sid_bits_per_character. + * + * @return array + */ + private function checkSidBitsPerCharacter() { - $check = 'CVE-2018-19124, ' . - 'CVE-2018-19125, ' . - 'CVE-2018-19126'; - - $status = false; + $key = 'session.sid_bits_per_character'; - if ((Tools::version_compare(_PS_VERSION_, '1.6', '==') && Tools::version_compare(_PS_VERSION_, '1.6.1.23', '<')) || (Tools::version_compare(_PS_VERSION_, '1.7', '==') && Tools::version_compare(_PS_VERSION_, '1.7.4.4', '<'))) { - if (\extension_loaded('phar') && !\ini_get('phar.readonly')) { + if (Tools::version_compare(Tools::checkPhpVersion(), '7.1.0', '>=')) { + if (false !== \ini_get($key)) { + $current = \ini_get($key); + } else { + $current = '4'; + } + $recommended = '6'; + $desc = $this->l('The more bits result in stronger session ID.'); + if ((int) $current >= (int) $recommended) { + $status = false; + } else { $status = true; } + } else { + $current = false; + $recommended = false; + $status = false; + $desc = $this->l('The INI setting') . ' \'' . $key . '\' ' . $this->l('was added in') . ' PHP 7.1.0.'; } - $fix = $this->l('Set') . ' "phar.readonly = Off" ' . $this->l('in your php.ini file.'); - return [ - $check, + $key, + $current, + $recommended, $status, - $fix, + $desc, ]; } - private function checkCVE201813784() + /** + * Check php.ini conf: allow_url_fopen. + * + * @return array + */ + private function checkUrlFopen() { - $check = 'CVE-2018-13784'; - - $status = false; - - if ((Tools::version_compare(_PS_VERSION_, '1.6', '==') && Tools::version_compare(_PS_VERSION_, '1.6.1.20', '<')) || (Tools::version_compare(_PS_VERSION_, '1.7', '==') && Tools::version_compare(_PS_VERSION_, '1.7.3.4', '<'))) { + $key = 'allow_url_fopen'; + if (false !== $this->isOn(\ini_get($key))) { + $current = $this->isOn(\ini_get($key)); + } else { + $current = '1'; + } + $recommended = '1'; + if ($current === $recommended) { + $status = false; + } else { $status = true; } - $fix = $this->l('Update PrestaShop to latest version.'); + + $desc = $this->l('This directive enables PrestaShop to access remote files, which is an essential part of the payment process, among other things. it\'s therefore imperative to have it enabled.'); return [ - $check, + $key, + $current, + $recommended, $status, - $fix, + $desc, ]; } - private function checkCVE20188824() + /** + * Check php.ini conf: allow_url_include. + * + * @return array + */ + private function checkUrlInclude() { - $check = 'CVE-2018-8823, CVE-2018-8824'; - - $status = false; - - if (\file_exists(_PS_MODULE_DIR_ . 'bamegamenu/ajax_phpcode.php')) { - $moduleVersion = Module::getInstanceByName('bamegamenu')->version; - if (!empty($moduleVersion)) { - if (Tools::version_compare($moduleVersion, '1.0.32', '<=')) { - $status = true; - } - } + $key = 'allow_url_include'; + if (false !== $this->isOn(\ini_get($key))) { + $current = $this->isOn(\ini_get($key)); + } else { + $current = '1'; + } + $recommended = '0'; + if ($current === $recommended) { + $status = false; + } else { + $status = true; } - $fix = $this->l('Update module') . '" Responsive Mega Menu (Horizontal+Vertical+Dropdown) Pro"'; + + $desc = $this->l('don\'t allow the inclusion of remote file resources.'); return [ - $check, + $key, + $current, + $recommended, $status, - $fix, + $desc, ]; } - private function checkCVE20187491() + /** + * Check php.ini conf: display_errors. + * + * @return array + */ + private function checkDisplayErrors() { - $check = 'CVE-2018-7491'; - - if (Language::countActiveLanguages() > 1) { - $url = $this->getBaseURL() . '/' . $this->context->language->iso_code . '/'; + $key = 'display_errors'; + if (false !== $this->isOn(\ini_get($key))) { + $current = $this->isOn(\ini_get($key)); } else { - $url = $this->getBaseURL(); + $current = '1'; } - - $headers = @\get_headers($url, 1); - - $status = true; - - if ('sameorigin' === \is_array(Tools::strtolower(!empty($headers['X-Frame-Options']) ? $headers['X-Frame-Options'] : '')) || - 'sameorigin' === Tools::strtolower(!empty($headers['X-Frame-Options']) ? $headers['X-Frame-Options'] : '') || - Configuration::get('LITE_CLICK_JACKING')) { + $recommended = '0'; + if ($current === $recommended) { $status = false; + } else { + $status = true; } - $fix = $this->l('Enable') . $this->l('Click-jack protection') . ' ' . $this->l('in') . ' "' . $this->l('HTTP headers') . '" ' . $this->l('above') . '.'; + $desc = $this->l('Don\'t show errors in production.'); return [ - $check, + $key, + $current, + $recommended, $status, - $fix, + $desc, ]; } - private function checkCVE20151175() + /** + * Check php.ini conf: log_errors. + * + * @return array + */ + private function checkLogErrors() { - $check = 'CVE-2015-1175'; - - $status = false; - - if (\file_exists(_PS_MODULE_DIR_ . 'blocklayered/blocklayered-ajax.php')) { - $moduleVersion = Module::getInstanceByName('blocklayered')->version; - if (!empty($moduleVersion) && Tools::version_compare($moduleVersion, '2.0.7', '<')) { - $status = true; - } + $key = 'log_errors'; + if (false !== $this->isOn(\ini_get($key))) { + $current = $this->isOn(\ini_get($key)); + } else { + $current = '0'; + } + $recommended = '1'; + if ($current === $recommended) { + $status = false; + } else { + $status = true; } - $fix = $this->l('Update') . ' "blocklayered" ' . $this->l('module') . '.'; + $desc = $this->l('Log errors in production.'); return [ - $check, + $key, + $current, + $recommended, $status, - $fix, + $desc, ]; } - private function checkCVE20179841() + /** + * Check php.ini conf: expose_php. + * + * @return array + */ + private function checkExposePhp() { - $check = 'CVE-2017-9841'; - - $status = false; - - if (!empty($this->checkFilesCVE20179841())) { + $key = 'expose_php'; + if (false !== $this->isOn(\ini_get($key))) { + $current = $this->isOn(\ini_get($key)); + } else { + $current = '1'; + } + $recommended = '0'; + if ($current === $recommended) { + $status = false; + } else { $status = true; } - $fix = $this->l('Delete') . ' phpunit ' . $this->l('folders') . ':
' . \implode('
', $this->checkFilesCVE20179841()); + $desc = $this->l('Showing the PHP signature exposes additional information.'); return [ - $check, + $key, + $current, + $recommended, $status, - $fix, + $desc, ]; } /** - * Check if PHP version is up to date. + * Check php.ini conf: register_argc_argv. * * @return array */ - private function checkPhpVersion() + private function checkRegisterArgcArgv() { - $check = $this->l('PHP version') . ' (' . Tools::checkPhpVersion() . ')'; - - if (Tools::version_compare(_PS_VERSION_, '1.7.4', '<=')) { - $status = Tools::version_compare(Tools::checkPhpVersion(), '7.1.0', '<='); - $fix = $this->proFeature; + $key = 'register_argc_argv'; + if (false !== $this->isOn(\ini_get($key))) { + $current = $this->isOn(\ini_get($key)); + } else { + $current = '0'; + } + $recommended = '0'; + if ($current === $recommended) { + $status = false; } else { - $status = Tools::version_compare(Tools::checkPhpVersion(), '7.2.0', '<='); - $fix = $this->proFeature; + $status = true; } + $desc = $this->l('Whether to declare the argv & argc variables (that would contain the GET information).'); + return [ - $check, + $key, + $current, + $recommended, $status, - $fix, + $desc, ]; } /** - * Check if PrestaShop SSL is enabled. + * Check php.ini conf: short_open_tag. * * @return array */ - private function checkSslEnabled() + private function checkShortOpenTag() { - $check = $this->l('SSL enabled'); - $status = false === (bool) Configuration::get('PS_SSL_ENABLED'); + $key = 'short_open_tag'; + if (false !== $this->isOn(\ini_get($key))) { + $current = $this->isOn(\ini_get($key)); + } else { + $current = '1'; + } + + $recommended = '0'; + if ($current === $recommended) { + $status = false; + } else { + $status = true; + } - $fix = $this->proFeature; + $desc = $this->l('Not a direct security vulnerability but it could become one given the proper conditions.'); return [ - $check, + $key, + $current, + $recommended, $status, - $fix, + $desc, ]; } /** - * Check if PrestaShop SSL everywhere is enabled. + * Check php.ini conf: post_max_size. * * @return array */ - private function checkSslEnabledEverywhere() + private function checkPostMaxSize() { - $check = $this->l('SSL Enabled everywhere'); - $status = false === (bool) Configuration::get('PS_SSL_ENABLED_EVERYWHERE'); - $fix = $this->proFeature; + $key = 'post_max_size'; + if (false !== \ini_get($key)) { + $current = \ini_get($key); + } else { + $current = '8M'; + } + $recommended = '22M'; + if ($this->convertToBytes($current) <= $this->convertToBytes($recommended)) { + $status = false; + } else { + $status = true; + } + + $desc = $this->l('Unless necessary, a maximum post size of') . ' ' . $current . ' ' . $this->l('is too large.'); return [ - $check, + $key, + $current, + $recommended, $status, - $fix, + $desc, ]; } /** - * Check if PrestaShop token is activated. + * Check php.ini conf: max_input_vars. * * @return array */ - private function checkPrestashopToken() + private function checkMaxInputVars() { - $check = $this->l('PrestaShop token'); - $status = false === (bool) Configuration::get('PS_TOKEN_ENABLE'); - $fix = $this->proFeature; + $key = 'max_input_vars'; + if (false !== \ini_get($key)) { + $current = \ini_get($key); + } else { + $current = '1000'; + } + $recommended = '20000'; + if ((int) $current <= (int) $recommended) { + $status = false; + } else { + $status = true; + } + + $desc = $this->l('A maximum number of input variables should be defined to prevent performance issues.'); return [ - $check, + $key, + $current, + $recommended, $status, - $fix, + $desc, ]; } /** - * Check if Mod Secure is active. + * Check php.ini conf: max_input_vars. * * @return array */ - private function checkModSecurity() + private function checkMaxInputTime() { - $check = 'Mod Security'; - $status = (bool) Configuration::get('PS_HTACCESS_DISABLE_MODSEC'); - $fix = $this->proFeature; + $key = 'max_input_time'; + if (false !== \ini_get($key)) { + $current = \ini_get($key); + } else { + $current = '-1'; + } + $recommended = '300'; + if ((int) $current <= (int) $recommended && '-1' !== $current && 0 !== (int) $current) { + $status = false; + } else { + $status = true; + } + + $desc = $this->l('Maximum amount of time each script may spend parsing request data. It\'s a good idea to limit this time on productions servers to eliminate unexpectedly long-running scripts.'); return [ - $check, + $key, + $current, + $recommended, $status, - $fix, + $desc, ]; } /** - * Check if PrestaShop admin directory name is secure. + * Check php.ini conf: display_startup_errors. * * @return array */ - private function checkAdminDirectoryName() + private function checkDisplayStartupErrors() { - $check = $this->l('PrestaShop admin directory name'); - $status = !\preg_match('/[A-Za-z].*[0-9]|[0-9].*[A-Za-z]/', \basename(_PS_ADMIN_DIR_)); - $fix = $this->proFeature; + $key = 'display_startup_errors'; + if (false !== $this->isOn(\ini_get($key))) { + $current = $this->isOn(\ini_get($key)); + } else { + $current = '0'; + } + $recommended = '0'; + if ($current === $recommended) { + $status = false; + } else { + $status = true; + } + + $desc = $this->l('Showing startup errors could provide extra information to potential attackers.'); return [ - $check, + $key, + $current, + $recommended, $status, - $fix, + $desc, ]; } /** - * Check if PrestaShop table prefix is different from default. + * Check php.ini conf: error_reporting. * * @return array */ - private function checkPsTablePrefix() + private function checkErrorReporting() { - $check = $this->l('Database table prefix'); - - if (!\defined('_TB_VERSION_')) { - $status = 'ps_' === _DB_PREFIX_; - $fix = $this->proFeature; + $key = 'error_reporting'; + if (false !== $this->isOn(\ini_get($key))) { + $current = $this->isOn(\ini_get($key)); + } else { + $current = '0'; + } + $recommended = '0'; + if ($current === $recommended) { + $status = false; } else { - $status = 'tb_' === _DB_PREFIX_; - $fix = $this->proFeature; + $status = true; } + $desc = $this->l('Error reporting should be different based on context.'); + return [ - $check, + $key, + $current, + $recommended, $status, - $fix, + $desc, ]; } /** - * Check if PrestaShop develop mode is active. + * Check php.ini conf: upload_max_filesize. * * @return array */ - private function checkPrestashopDevMode() + private function checkUploadMaxFileSize() { - $check = $this->l('PrestaShop debug mode'); - $status = _PS_MODE_DEV_; - $fix = $this->proFeature; + $key = 'upload_max_filesize'; + if (false !== \ini_get($key)) { + $current = \ini_get($key); + } else { + $current = '2M'; + } + $recommended = '20M'; + + if ($this->convertToBytes($current) <= $this->convertToBytes($recommended)) { + $status = false; + } else { + $status = true; + } + + $desc = $this->l('A maximum upload size should be defined to prevent server overload from large requests.'); return [ - $check, + $key, + $current, + $recommended, $status, - $fix, + $desc, ]; } /** - * Check CVE-2020-5250. + * Check php.ini conf: memory_limit. * * @return array */ - private function checkCVE20205250() + private function checkMemoryLimit() { - $check = 'CVE-2020-5250'; - - $status = false; - if (Tools::version_compare(_PS_VERSION_, '1.7.0.0', '>=') && Tools::version_compare(_PS_VERSION_, '1.7.6.4', '<')) { + $key = 'memory_limit'; + if (false !== \ini_get($key)) { + $current = \ini_get($key); + } else { + $current = '128M'; + } + $recommended = '512M'; + if ($this->convertToBytes($current) <= $this->convertToBytes($recommended) && '-1' !== $current) { + $status = false; + } else { $status = true; } - $fix = $this->l('Update PrestaShop to latest version.'); + $desc = $this->l('The standard memory limit should not be too high, if you need more memory for a single script you can adjust that during runtime using') . ' ini_set().'; return [ - $check, + $key, + $current, + $recommended, $status, - $fix, + $desc, ]; } /** - * Check php.ini conf: session.use_cookies. + * Check php.ini conf: default_charset. * * @return array */ - private function checkSessionUseCookies() + private function checkDefaultCharset() { - $key = 'session.use_cookies'; - if (false !== $this->isOn(\ini_get($key))) { - $current = $this->isOn(\ini_get($key)); + $key = 'default_charset'; + if (false !== \ini_get($key)) { + $current = \ini_get($key); } else { - $current = '1'; + $current = 'utf-8'; + } + $recommended = 'utf-8'; + if (Tools::strtolower($current) === $recommended) { + $status = false; + } else { + $status = true; } + $desc = $this->l('Ensure that a default character set is defined, utf-8 is preferred.'); + return [ $key, $current, + $recommended, + $status, + $desc, ]; } /** - * Check php.ini conf: session.use_only_cookies. + * Check php.ini conf: max_execution_time. * * @return array */ - private function checkSessionUseOnlyCookies() + private function checkMaxExecutionTime() { - $key = 'session.use_only_cookies'; - if (false !== $this->isOn(\ini_get($key))) { - $current = $this->isOn(\ini_get($key)); + $key = 'max_execution_time'; + if (false !== \ini_get($key)) { + $current = \ini_get($key); } else { - $current = '1'; + $current = '30'; + } + $recommended = '300'; + if ($current <= $recommended) { + $status = false; + } else { + $status = true; } + $desc = $this->l('To prevent denial-of-service attacks where an attacker tries to keep your server\'s CPU busy, this value should be set to the lowest possible value.'); + return [ $key, $current, + $recommended, + $status, + $desc, ]; } /** - * Check php.ini conf: session.cookie_httponly. + * Check php.ini conf: file_uploads. * * @return array */ - private function checkSessionCookieHttponly() + private function checkFileUploads() { - $key = 'session.cookie_httponly'; + $key = 'file_uploads'; if (false !== $this->isOn(\ini_get($key))) { $current = $this->isOn(\ini_get($key)); } else { - $current = ''; + $current = '1'; + } + $recommended = '1'; + if ($current === $recommended) { + $status = false; + } else { + $status = true; } + $desc = $this->l('PrestaShop require HTTP file uploads.'); + return [ $key, $current, + $recommended, + $status, + $desc, ]; } /** - * Check php.ini conf: session.hash_function. + * Get URL of shop. * - * @return array + * @return string */ - private function checkAessionHashFunction() + private function getShopUrl() { - $key = 'session.hash_function'; - - if (false !== $this->isOn(\ini_get($key))) { - $current = $this->isOn(\ini_get($key)); - } else { - $current = '0'; + if (Language::countActiveLanguages() > 1) { + return $this->getBaseURL() . $this->context->language->iso_code . '/'; } - return [ - $key, - $current, - ]; + return $this->getBaseURL(); } /** - * Check php.ini conf: session.use_trans_sid. - * - * @return array + * Reset in case of error. */ - private function checkPhpUseTransSid() + private function onErrorHtpasswd() { - $key = 'session.use_trans_sid'; - if (false !== $this->isOn(\ini_get($key))) { - $current = $this->isOn(\ini_get($key)); - } else { - $current = '0'; - } + Configuration::updateValue('LITE_HTPASSWD', false); - return [ - $key, - $current, - ]; + $this->removeHtaccessContent(); } /** - * Check php.ini conf: session.cookie_secure. + * Add missing index.php files. * - * @return array + * @param string $path + * @param bool $analyze */ - private function checkCookieSecure() + private function addIndexRecursively($path, $analyze = false) { - $key = 'session.cookie_secure'; - if (false !== $this->isOn(\ini_get($key))) { - $current = $this->isOn(\ini_get($key)); - } else { - $current = ''; + if (0 === \mb_strpos(\basename($path), '.')) { + return; } - return [ - $key, - $current, - ]; + $indexFilePath = $path . \DIRECTORY_SEPARATOR . 'index.php'; + + if (false === \file_exists($indexFilePath)) { + if (true === $analyze) { + $reportPath = _PS_MODULE_DIR_; + if (!\is_dir($reportPath)) { + \mkdir($reportPath, 0755, true); + } + \file_put_contents($reportPath . \DIRECTORY_SEPARATOR . self::REPORT_CREATE_INDEX, \realpath($path) . \PHP_EOL, \FILE_APPEND | \LOCK_EX); + } else { + \file_put_contents($indexFilePath, Tools::getDefaultIndexContent()); + } + } + + $dirs = \glob($path . \DIRECTORY_SEPARATOR . '*', \GLOB_ONLYDIR); + + if (false === $dirs) { + return; + } + + foreach ($dirs as $dir) { + if (true === $analyze) { + $this->addIndexRecursively($dir, true); + } else { + $this->addIndexRecursively($dir); + } + } + } + + private function getHtaccessContent() + { + return '# Apache 2.2 + + Order deny,allow + Deny from all + + +# Apache 2.4 + + Require all denied + +'; } /** - * Check php.ini conf: session.cookie_lifetime. + * Analyze file- and directory permissions. * - * @return array + * @param string $dir */ - private function checkCookieLifetime() + private function chmodFileFolderAnalyze($dir) { - $key = 'session.cookie_lifetime'; - if (false !== $this->isOn(\ini_get($key))) { - $current = $this->isOn(\ini_get($key)); - } else { - $current = '0'; - } + $perms = []; + $perms['file'] = 0644; + $perms['folder'] = 0755; + $dh = @\opendir($dir); - return [ - $key, - $current, - ]; + $reportPath = _PS_MODULE_DIR_ . self::REPORT_PERMISSIONS; + + if ($dh) { + $myfile = \fopen($reportPath, 'ab'); + while (false !== ($file = \readdir($dh))) { + if ('.' !== $file && '..' !== $file) { + $fullpath = $dir . '/' . $file; + if (!\is_dir($fullpath)) { + if (Tools::substr(\sprintf('%o', \fileperms($fullpath)), -3) !== \decoct($perms['file'])) { + \fwrite($myfile, $this->l('Permission') . ' ' . Tools::substr(\decoct(\fileperms($fullpath)), -3) . ': ' . $fullpath . \PHP_EOL); + } + } else { + if (Tools::substr(\sprintf('%o', \fileperms($fullpath)), -3) !== \decoct($perms['folder'])) { + \fwrite($myfile, $this->l('Permission') . ' ' . Tools::substr(\decoct(\fileperms($fullpath)), -3) . ': ' . $fullpath . \PHP_EOL); + + $this->chmodFileFolderAnalyze($fullpath); + } + } + } + } + \fclose($myfile); + \closedir($dh); + } } /** - * Check php.ini conf: session.use_strict_mode. + * Block custom list of IP addresses. * - * @return array + * @param string $ip + * + * @return bool */ - private function checkUseScrickMode() + private function blockIp() { - $key = 'session.use_strict_mode'; - if (false !== $this->isOn(\ini_get($key))) { - $current = $this->isOn(\ini_get($key)); - } else { - $current = '0'; + $conf = (int) Configuration::get('LITE_BAN_IP_ACTIVATE'); + if (3 === $conf) { + if ('1' === $this->context->cookie->__get('securityliteRecaptcha')) { + return false; + } } - return [ - $key, - $current, - ]; + if (false === (bool) Configuration::get('LITE_BAN_IP')) { + return false; + } + + $blacklist = \explode(',', Configuration::get('LITE_BAN_IP')); + foreach ($blacklist as &$list) { + $range = \IPLib\Factory::rangeFromString($list); + if ($range->contains(\IPLib\Factory::addressFromString(\Tools::getRemoteAddr()))) { + $this->vulnDetectedHtml( + null, + $this->l('Block IP'), + $conf + ); + } + } + + return false; } /** - * Check php.ini conf: session.lazy_write. + * Check if Google IP. * - * @return array + * @return bool */ - private function checkLazyWrite() + private function validateGoogleBotIp() { - $key = 'session.lazy_write'; + $userAgent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : ''; - if (false !== $this->isOn(\ini_get($key))) { - $current = $this->isOn(\ini_get($key)); - } else { - $current = '0'; + if (!empty($userAgent)) { + if (\preg_match('/Google/', $userAgent)) { + $hostname = \gethostbyaddr(\Tools::getRemoteAddr()); + + return \preg_match('/\.googlebot\.com$/i', $hostname); // True if Google + } } - return [ - $key, - $current, - ]; + return false; // Not Google } /** - * Check php.ini conf: session.sid_length. + * Block custom list of User agents. * - * @return array + * @return bool */ - private function checkSidLength() + private function blockUserAgent() { - $key = 'session.sid_length'; + $conf = (int) Configuration::get('LITE_BLOCK_USER_AGENT_ACTIVATE'); + if (3 === $conf) { + if ('1' === $this->context->cookie->__get('securityliteRecaptcha')) { + return false; + } + } - if (false !== \ini_get($key)) { - $current = \ini_get($key); - } else { - $current = '32'; + $userAgent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : ''; + + if (!empty($_SERVER['HTTP_USER_AGENT'])) { + $userAgent = $_SERVER['HTTP_USER_AGENT']; + $blacklist = \explode(',', Configuration::get('LITE_BLOCK_USER_AGENT')); + foreach ($blacklist as &$list) { + if (false !== \mb_strpos($userAgent, $list)) { + $this->vulnDetectedHtml( + null, + $this->l('Block UA'), + $conf + ); + } + } } - return [ - $key, - $current, - ]; + return false; } - private function checkSessionGcDivisor() + /** + * Whitelist IP addresses. + * + * @param $field string + * + * @return bool + */ + private function checkWhitelist($field) { - $key = 'session.gc_divisor'; - if (false !== $this->isOn(\ini_get($key))) { - $current = $this->isOn(\ini_get($key)); - } else { - $current = '1'; + if (false === (bool) Configuration::get($field)) { + return false; + } + $whitelist = \explode(',', Configuration::get($field)); + foreach ($whitelist as &$list) { + $range = \IPLib\Factory::rangeFromString($list); + if ($range->contains(\IPLib\Factory::addressFromString(\Tools::getRemoteAddr()))) { + return true; + } } - return [ - $key, - $current, - ]; + return false; } /** - * Check php.ini conf: session.sid_bits_per_character. - * - * @return array + * Ban user. */ - private function checkSidBitsPerCharacter() + private function ban() { - $key = 'session.sid_bits_per_character'; - - if (false !== \ini_get($key)) { - $current = \ini_get($key); - } else { - $current = '4'; - } - - return [ - $key, - $current, - ]; + $this->context->employee->logout(); + exit; } /** - * Check php.ini conf: allow_url_fopen. + * Check CVE-2017-9841. * * @return array */ - private function checkUrlFopen() + private function checkFilesCVE20179841() { - $key = 'allow_url_fopen'; - if (false !== $this->isOn(\ini_get($key))) { - $current = $this->isOn(\ini_get($key)); - } else { - $current = '1'; + $result = []; + + $rootPath = _PS_CORE_DIR_ . \DIRECTORY_SEPARATOR . 'vendor' . \DIRECTORY_SEPARATOR . 'phpunit'; + if (\is_dir($rootPath)) { + $result[] = $rootPath; } - return [ - $key, - $current, - ]; + $modulePath = _PS_MODULE_DIR_; + + $iter = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($modulePath, RecursiveDirectoryIterator::SKIP_DOTS), + RecursiveIteratorIterator::SELF_FIRST, + RecursiveIteratorIterator::CATCH_GET_CHILD // Ignore "Permission denied" + ); + + foreach ($iter as $dir) { + if ($dir->isDir()) { + if ('phpunit' === $dir->getFilename()) { + $result[] = $dir->getRealpath(); + } + } + } + + return $result; } - /** - * Check php.ini conf: allow_url_include. - * - * @return array - */ - private function checkUrlInclude() + private function getFilePathExt($dir) { - $key = 'allow_url_include'; - if (false !== $this->isOn(\ini_get($key))) { - $current = $this->isOn(\ini_get($key)); - } else { - $current = '1'; + $files = \glob($dir . \DIRECTORY_SEPARATOR . '*.{7z,bz2,gz,rar,sql,tar,tgz,zip}', \GLOB_BRACE); + $result = []; + foreach ($files as $file) { + $result[] = \realpath($file); } - return [ - $key, - $current, - ]; + return $result; } /** - * Check php.ini conf: display_errors. + * Get path to log file. * - * @return array + * @param string $fileName + * + * @return string */ - private function checkDisplayErrors() + private function getLogFile($fileName) { - $key = 'display_errors'; - if (false !== $this->isOn(\ini_get($key))) { - $current = $this->isOn(\ini_get($key)); + if (Tools::version_compare(_PS_VERSION_, '1.7.0.0', '<')) { + $path = '/log/'; + } elseif (Tools::version_compare(_PS_VERSION_, '1.7.3.0', '<=')) { + $path = '/app/logs/'; } else { - $current = '1'; + $path = '/var/logs/'; } - return [ - $key, - $current, - ]; + $logPath = _PS_CORE_DIR_ . $path . $fileName; + + if (!\file_exists($logPath)) { + \file_put_contents($logPath, ''); + } + + return $logPath; } /** - * Check php.ini conf: log_errors. + * Download file. * - * @return array + * @param string $filePath + * @param bool $deleteFile + * + * @return bool|null */ - private function checkLogErrors() + private function downloadFile($filePath, $deleteFile = false) { - $key = 'log_errors'; - if (false !== $this->isOn(\ini_get($key))) { - $current = $this->isOn(\ini_get($key)); - } else { - $current = '0'; + if (\file_exists($filePath)) { + \header('Content-Description: File Transfer'); + \header('Content-Type: application/x-octet-stream'); + \header('Content-Disposition: attachment; filename="' . \basename($filePath) . '"'); + \header('Expires: 0'); + \header('Cache-Control: must-revalidate'); + \header('Pragma: public'); + \header('Content-Length: ' . \filesize($filePath)); + \flush(); // Flush system output buffer + \readfile($filePath); + + if (true === $deleteFile) { + Tools::deleteFile($filePath); + } + + exit; } - return [ - $key, - $current, - ]; + return false; } /** - * Check php.ini conf: expose_php. + * Response HTTP header 403 and block the request. * - * @return array + * @param int $code */ - private function checkExposePhp() + private function blockRequest($code) { - $key = 'expose_php'; - if (false !== $this->isOn(\ini_get($key))) { - $current = $this->isOn(\ini_get($key)); - } else { - $current = '1'; - } + \http_response_code($code); + \header('Connection: Close'); + \header('Cache-Control: max-age=0, private, no-store, no-cache, must-revalidate'); - return [ - $key, - $current, - ]; + $lang = $this->context->language->iso_code; + + echo ' ' . $this->l('Error') . ' ' . $code . ' ' . $this->getFavicon() . '

' . $this->l('Permission denied!') . '

' . $this->l('Error') . ' ' . $code . '

'; + exit; } /** - * Check php.ini conf: register_globals. + * Normalize php ini value. * - * @return array + * @param string $v + * + * @return string */ - private function checkRegisterGlobals() + private function isOn($v) { - $key = 'register_globals'; - if (false !== $this->isOn(\ini_get($key))) { - $current = $this->isOn(\ini_get($key)); - } else { - $current = '0'; + if ('0' === $v || 'off' === Tools::strtolower($v) || '' === $v) { + return '0'; } - return [ - $key, - $current, - ]; + return '1'; } /** - * Check php.ini conf: register_argc_argv. + * Scan for open ports. * * @return array */ - private function checkRegisterArgcArgv() + private function portScanner() { - $key = 'register_argc_argv'; - if (false !== $this->isOn(\ini_get($key))) { - $current = $this->isOn(\ini_get($key)); - } else { - $current = '0'; + $host = \Tools::getHttpHost(false, false, true); + $ports = [ + 20, + 21, + 22, + 23, + 25, + 53, + 80, + 110, + 119, + 135, + 137, + 138, + 139, + 143, + 443, + 445, + 465, + 520, + 587, + 993, + 995, + 1027, + 1433, + 1434, + 1457, + 1521, + 1723, + 2082, + 2086, + 2095, + 3306, + 3389, + 5060, + 5900, + 8080, + 8443, + 9100, + ]; + $response = []; + + foreach ($ports as $port) { + $connection = @\fsockopen($host, $port, $errno, $errstr, 2); + + $serv = \getservbyport($port, 'tcp'); + if (!empty($serv)) { + $name = ' (' . $serv . ') '; + } else { + $name = ' '; + } + if (\is_resource($connection)) { + $response[] = $host . ':' . $port . $name . $this->l('is open') . '.'; + + \fclose($connection); + } else { + $response[] = $host . ':' . $port . $name . $this->l('is closed') . '.'; + } } - return [ - $key, - $current, - ]; + \file_put_contents(_PS_MODULE_DIR_ . self::REPORT_PORT_SCANNER, \implode(\PHP_EOL, $response), \FILE_APPEND | \LOCK_EX); } /** - * Check php.ini conf: short_open_tag. + * Make the Honeypot query (Honeypot API). * - * @return array + * @param string $ip + * + * @return int */ - private function checkShortOpenTag() + private function honeypotQuery($ip) { - $key = 'short_open_tag'; - if (false !== $this->isOn(\ini_get($key))) { - $current = $this->isOn(\ini_get($key)); - } else { - $current = '1'; + $response = \explode('.', \gethostbyname(Configuration::get('LITE_HONEYPOT_API') . '.' . \implode('.', \array_reverse(\explode('.', $ip))) . '.dnsbl.httpbl.org')); + + if ('127' !== (string) $response[0]) { + return false; // Not a threat } - return [ - $key, - $current, - ]; + return (int) $response[3]; } /** - * Check php.ini conf: post_max_size. + * Check if the client is a bot (Honeypot API). * - * @return array + * @param string $ip + * + * @return bool */ - private function checkPostMaxSize() + private function isBot($ip) { - $key = 'post_max_size'; - if (false !== \ini_get($key)) { - $current = \ini_get($key); - } else { - $current = '8M'; + $honeypotQuery = $this->honeypotQuery($ip); + if (false !== $honeypotQuery) { + if (0 === $honeypotQuery) { + return false; + } + + return true; } - return [ - $key, - $current, - ]; + return false; } /** - * Check php.ini conf: max_input_vars. + * Check if the IP is a TOR. * - * @return array + * @param string $ip + * + * @return bool */ - private function checkMaxInputVars() + private function isTorExitPoint($ip) { - $key = 'max_input_vars'; - if (false !== \ini_get($key)) { - $current = \ini_get($key); - } else { - $current = '1000'; + $url = 'https://check.torproject.org/torbulkexitlist'; + + $content = $this->getCachedRemoteContent($url, null, 'tor', 86400); + + if (false !== \strpos($content, $ip)) { + return true; // Is tor } - return [ - $key, - $current, - ]; + return false; // Is not tor } /** - * Check php.ini conf: max_input_vars. + * Generate link for cronjob. * - * @return array + * @param string $name + * @param bool $simple + * + * @return string */ - private function checkMaxInputTime() + private function generateCronLink($name, $simple = false) { - $key = 'max_input_time'; - if (false !== \ini_get($key)) { - $current = \ini_get($key); - } else { - $current = '-1'; + $token = $this->encrypt('securitylite/cron'); + $link = $this->context->link->getModuleLink('securitylite', 'cron', ['name' => $name, 'token' => $token]); + + if (true === $simple) { + return $link; } - return [ - $key, - $current, - ]; + $content = 'wget -q -O - "' . $link . '" >/dev/null 2>&1'; + + return \htmlentities($content); } /** - * Check php.ini conf: display_startup_errors. + * Generate unlock link for Admin Stealth Login. * - * @return array + * @return string */ - private function checkDisplayStartupErrors() + private function generateUnlockLink() { - $key = 'display_startup_errors'; - if (false !== $this->isOn(\ini_get($key))) { - $current = $this->isOn(\ini_get($key)); - } else { - $current = '0'; - } + $token = $this->encrypt('securitylite/unlock'); + $link = \htmlentities($this->context->link->getModuleLink('securitylite', 'unlock', ['token' => $token])); - return [ - $key, - $current, - ]; + return '' . $link . ' '; } /** - * Check php.ini conf: error_reporting. + * Check if PrestaShop is up to date. * - * @return array + * @return bool */ - private function checkErrorReporting() + private function checkPrestaShopUpToDate() { - $key = 'error_reporting'; - if (false !== $this->isOn(\ini_get($key))) { - $current = $this->isOn(\ini_get($key)); - } else { - $current = '0'; - } + $url = 'https://api.prestashop.com/version/check_version.php'; - return [ - $key, - $current, + $params = [ + 'v' => _PS_VERSION_, + 'lang' => $this->context->language->iso_code, + 'autoupgrade' => '0', + 'hosted_mode' => '0', ]; + + $content = $this->getCachedRemoteContent($url, $params, 'ps_version', 86400); + if (false === $content) { + return true; // Error + } + + if (false !== \mb_strpos($content, 'btn-default')) { + return true; // Not up to date + } + + return false; // Up to date } /** - * Check php.ini conf: upload_max_filesize. + * Get an array of trusted / untrusted modules. + * + * @param bool $trusted * * @return array */ - private function checkUploadMaxFileSize() + private function getModules($trusted) { - $key = 'upload_max_filesize'; - if (false !== \ini_get($key)) { - $current = \ini_get($key); + if (true === $trusted) { + $path = _PS_ROOT_DIR_ . '/config/xml/trusted_modules_list.xml'; } else { - $current = '2M'; + $path = _PS_ROOT_DIR_ . '/config/xml/untrusted_modules_list.xml'; + } + if (!\file_exists($path)) { + ModuleCore::generateTrustedXml(); } + $xml = \simplexml_load_string(Tools::file_get_contents($path)); - return [ - $key, - $current, - ]; + if (!empty($xml->modules)) { + $modules = []; + foreach ($xml->modules->module as $module) { + if (Module::isInstalled($module['name'])) { + $modules[] = $module['name']; + } + } + + return \array_unique($modules); + } } /** - * Check php.ini conf: memory_limit. + * Get newest PHP version. * - * @return array + * @param string $currentVersion + * + * @return string */ - private function checkMemoryLimit() + private function getNewestPhpVersion($currentVersion) { - $key = 'memory_limit'; - if (false !== \ini_get($key)) { - $current = \ini_get($key); - } else { - $current = '128M'; - } + $url = 'https://www.php.net/releases/'; - return [ - $key, - $current, + $params = [ + 'json' => '1', + 'version' => $currentVersion, ]; + + $content = $this->getCachedJsonDecodedContent($url, $params, $currentVersion, 3600); + + return $content['version']; } /** - * Check php.ini conf: default_charset. + * Return distance in km. * - * @return array + * @param float $lat1 + * @param float $lon1 + * @param float $lat2 + * @param float $lon2 + * @param string $unit + * + * @return float */ - private function checkDefaultCharset() + private function getDistance($lat1, $lon1, $lat2, $lon2, $unit) { - $key = 'default_charset'; - if (false !== \ini_get($key)) { - $current = \ini_get($key); - } else { - $current = 'utf-8'; + if (($lat1 === $lat2) && ($lon1 === $lon2)) { + return 0; } - return [ - $key, - $current, - ]; + $theta = $lon1 - $lon2; + $dist = \sin(\deg2rad($lat1)) * \sin(\deg2rad($lat2)) + \cos(\deg2rad($lat1)) * \cos(\deg2rad($lat2)) * \cos(\deg2rad($theta)); + $dist = \acos($dist); + $dist = \rad2deg($dist); + + if ('km' === $unit) { + $factor = 1; + } elseif ('mi' === $unit) { + $factor = 0.621371; + } + + return (float) \round($dist * 60 * 1.1515 * 1.609344 * $factor, 1); } /** - * Check php.ini conf: xdebug.default_enable. + * Download content with cURL. * - * @return array + * @param string $url + * @param array|null $params + * + * @return false|string */ - private function checkXdebugDefaultEnable() + private function getRemoteContent($url, $params = null) { - $key = 'xdebug.default_enable'; - if (false !== $this->isOn(\ini_get($key))) { - $current = $this->isOn(\ini_get($key)); - } else { - $current = '0'; + $options = [ + \CURLOPT_URL => (null !== $params) ? \sprintf('%s?%s', $url, \http_build_query($params)) : $url, + \CURLOPT_RETURNTRANSFER => true, + \CURLOPT_HEADER => false, + \CURLOPT_FOLLOWLOCATION => true, + \CURLOPT_ENCODING => '', + \CURLOPT_USERAGENT => '', + \CURLOPT_REFERER => '', + \CURLOPT_CONNECTTIMEOUT => 5, + \CURLOPT_TIMEOUT => 5, + \CURLOPT_MAXREDIRS => 5, + \CURLOPT_SSL_VERIFYPEER => false, + \CURLOPT_IPRESOLVE => \CURL_IPRESOLVE_V4, + ]; + + $ch = \curl_init(); + \curl_setopt_array($ch, $options); + $content = \curl_exec($ch); + $error = \curl_error($ch); + \curl_close($ch); + + if (true === (bool) $error) { + return false; // Error } - return [ - $key, - $current, - ]; + return $content; } /** - * Check php.ini conf: xdebug.remote_enable. + * Convert size to bytes. * - * @return array + * @param string $sizeStr + * + * @return int */ - private function checkXdebugRemoteEnable() + private function convertToBytes($sizeStr) { - $key = 'xdebug.remote_enable'; - if (false !== $this->isOn(\ini_get($key))) { - $current = $this->isOn(\ini_get($key)); - } else { - $current = '0'; - } + $type = Tools::substr(\mb_strtolower($sizeStr), -1); + switch ($type) { + case 'm': + return (int) $sizeStr * 1048576; + case 'k': + return (int) $sizeStr * 1024; + case 'g': + return (int) $sizeStr * 1073741824; - return [ - $key, - $current, - ]; + default: + return (int) $sizeStr; + } } /** - * Check php.ini conf: max_execution_time. + * Get montastic ids. * * @return array */ - private function checkMaxExecutionTime() + private function getMontasticIds() { - $key = 'max_execution_time'; - if (false !== \ini_get($key)) { - $current = \ini_get($key); - } else { - $current = '30'; + $ch = \curl_init(); + + \curl_setopt($ch, \CURLOPT_URL, 'https://montastic.com/checkpoints'); + \curl_setopt($ch, \CURLOPT_RETURNTRANSFER, 1); + \curl_setopt($ch, \CURLOPT_CUSTOMREQUEST, 'GET'); + + $headers = []; + $headers[] = 'X-Api-Key: ' . Configuration::get('LITE_MONTASTIC_API'); + $headers[] = 'Accept: application/json'; + \curl_setopt($ch, \CURLOPT_HTTPHEADER, $headers); + + $result = \curl_exec($ch); + \curl_close($ch); + + $arr = \json_decode($result, true); + + $ids = []; + foreach ($arr as $id) { + $ids[] = $id['id']; } - return [ - $key, - $current, - ]; + return $ids; } /** - * Check php.ini conf: file_uploads. + * Get monastic data. + * + * @param int $id * * @return array */ - private function checkFileUploads() + private function getMontasticData($id) { - $key = 'file_uploads'; - if (false !== $this->isOn(\ini_get($key))) { - $current = $this->isOn(\ini_get($key)); - } else { - $current = '1'; - } + $ch = \curl_init(); - return [ - $key, - $current, - ]; + \curl_setopt($ch, \CURLOPT_URL, "https://montastic.com/checkpoints/$id"); + \curl_setopt($ch, \CURLOPT_RETURNTRANSFER, 1); + \curl_setopt($ch, \CURLOPT_CUSTOMREQUEST, 'GET'); + + $headers = []; + $headers[] = 'X-Api-Key: ' . Configuration::get('LITE_MONTASTIC_API'); + $headers[] = 'Accept: application/json'; + \curl_setopt($ch, \CURLOPT_HTTPHEADER, $headers); + + $result = \curl_exec($ch); + \curl_close($ch); + + return \json_decode($result, true); } /** - * Get URL of shop. + * Check if OS is windows. * - * @return string + * @return bool */ - private function getShopUrl() + private function isWindowsOs() { - if (Language::countActiveLanguages() > 1) { - return $this->getBaseURL() . $this->context->language->iso_code . '/'; - } - - return $this->getBaseURL(); + return (0 === \mb_stripos(\PHP_OS, 'WIN')) ? true : false; } /** - * Add missing index.php files. + * Cache a json request. Default cache-time is 24 hours. * - * @param string $path + * @param string $url + * @param array $params + * @param string $name + * @param int $cacheTime + * + * @return array */ - private function addIndexRecursively($path) + private function getCachedJsonDecodedContent($url, $params, $name, $cacheTime = 86400) { - if (0 === \mb_strpos(\basename($path), '.')) { - return; + $cachePath = _PS_CACHE_DIR_ . 'securitylite'; + $filename = $cachePath . \DIRECTORY_SEPARATOR . $this->encrypt($name) . '.json'; + + if (\file_exists($filename) && (\time() - $cacheTime < \filemtime($filename))) { + return \json_decode(Tools::file_get_contents($filename), true); } - $indexFilePath = $path . \DIRECTORY_SEPARATOR . 'index.php'; + $content = $this->getRemoteContent($url, $params); - if (false === \file_exists($indexFilePath)) { - \file_put_contents($path . \DIRECTORY_SEPARATOR . 'index.php', Tools::getDefaultIndexContent()); + if (false === $this->isJson($content)) { + return false; // Error } - $dirs = \glob($path . \DIRECTORY_SEPARATOR . '*', \GLOB_ONLYDIR); + if (false !== $content) { + if (!\is_dir($cachePath)) { + \mkdir($cachePath, 0755, true); + $this->addIndexRecursively($cachePath); + \file_put_contents($cachePath . '/.htaccess', $this->getHtaccessContent()); + } + \file_put_contents($filename, $content); // Save cache - if (false === $dirs) { - return; + return \json_decode($content, true); } - foreach ($dirs as $dir) { - $this->addIndexRecursively($dir); + if (\file_exists($filename)) { + return \json_decode(Tools::file_get_contents($filename), true); // If the response is false, we want to use the cached version even though it is outdated. } + + return false; // If the connection fails to the API and no cache is stored. } /** - * change file- and directory permissions. + * Cache a request. Default is cache time is 24 hours. * - * @param string $dir + * @param string $url + * @param array $params + * @param string $name + * @param int $cacheTime + * + * @return array */ - private function chmodFileDirectory($dir) + private function getCachedRemoteContent($url, $params, $name, $cacheTime = 86400) { - $perms = []; - $perms['file'] = 0644; - $perms['directory'] = 0755; - $errorDir = null; - $errorFile = null; - $dh = @\opendir($dir); + $cachePath = _PS_CACHE_DIR_ . 'securitylite'; + $filename = $cachePath . \DIRECTORY_SEPARATOR . $this->encrypt($name) . '.txt'; - if ($dh) { - while (false !== ($file = \readdir($dh))) { - if ('.' !== $file && '..' !== $file) { - $fullPath = $dir . \DIRECTORY_SEPARATOR . $file; + if (\file_exists($filename) && (\time() - $cacheTime < \filemtime($filename))) { + return Tools::file_get_contents($filename); + } - if (!\is_dir($fullPath)) { - if (!\chmod($fullPath, $perms['file'])) { - $errorFile .= '' . $this->l('Failed') . ' ' . $this->l('to set file permissions on') . ' ' . $fullPath . \PHP_EOL; - } - } else { - if (\chmod($fullPath, $perms['directory'])) { - $this->chmodFileDirectory($fullPath); - } else { - $errorDir .= '' . $this->l('Failed') . ' ' . $this->l('to set directory permissions on') . ' ' . $fullPath . \PHP_EOL; - } - } - } + $content = $this->getRemoteContent($url, $params); + + if (false !== $content) { + if (!\is_dir($cachePath)) { + \mkdir($cachePath, 0755, true); + $this->addIndexRecursively($cachePath); + \file_put_contents($cachePath . '/.htaccess', $this->getHtaccessContent()); } - \closedir($dh); + \file_put_contents($filename, $content); // Save cache + + return $content; } + + if (\file_exists($filename)) { + return Tools::file_get_contents($filename); // If the response is false, we want to use the cached version even though it is outdated. + } + + return false; // If the connection fails to the API and no cache is stored. } /** - * Block custom list of IP addresses. + * Check if string is valid json. + * + * @param string $string + * + * @return bool */ - private function blockIp() + private function isJson($string) { - if (Tools::isEmpty(Configuration::get('LITE_BAN_IP')) && false === Configuration::get('LITE_BAN_IP')) { - return false; - } + \json_decode($string); - $blacklist = \explode(',', Configuration::get('LITE_BAN_IP')); - foreach ($blacklist as &$list) { - $range = \IPLib\Factory::rangeFromString($list); - if ($range->contains(\IPLib\Factory::addressFromString(\Tools::getRemoteAddr()))) { - return true; + return \JSON_ERROR_NONE === \json_last_error(); + } + + /** + * Get size of directories. + * + * @param array $paths + * + * @return int + */ + private function getDirectorySize($paths) + { + $bytestotal = 0; + foreach ($paths as $path) { + $path = \realpath($path); + if (!empty($path) && \file_exists($path)) { + foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS)) as $object) { + if ('index.php' !== $object->getFilename() && '.htaccess' !== $object->getFilename()) { + $bytestotal += $object->getSize(); + } + } } } - return false; + return $bytestotal; } /** - * Block custom list of User agents. + * Clear cache of securitylite. + * + * @param bool $clearTable */ - private function blockUserAgent() + private function clearCacheSecuritylite($clearTable = true) { - if (!empty($_SERVER['HTTP_USER_AGENT'])) { - $userAgent = $_SERVER['HTTP_USER_AGENT']; - $blacklist = \explode(',', Configuration::get('LITE_BLOCK_USER_AGENT')); - foreach ($blacklist as &$list) { - if (false !== \mb_strpos($userAgent, $list)) { - return true; + // Clear cache of folders + $folders = [ + _PS_CACHE_DIR_ . 'securitylite', + ]; + foreach ($folders as $folder) { + if (\is_dir($folder)) { + foreach (new DirectoryIterator($folder) as $fileInfo) { + if (!$fileInfo->isDot()) { + Tools::deleteFile($fileInfo->getPathname(), ['index.php', '.htaccess']); + } } } } - return false; + // Regenerate XML + ModuleCore::generateTrustedXml(); + + // Clear table + if (true === $clearTable) { + $query = 'TRUNCATE TABLE `' . _DB_PREFIX_ . 'securitylite`'; + Db::getInstance()->execute($query); + } } /** - * Lookup eldest access try by specific e-mail in database. + * Get array of employees information. * - * @param string $email + * @param bool $activeOnly * - * @return int + * @return array */ - private function getEldestAccessTry($email) + private function getEmployees($activeOnly = true) { - $maxRetry = (int) Configuration::get('LITE_MAX_RETRY'); - $email = pSQL($email); - $query = 'SELECT IF(COUNT(*) = ' . $maxRetry . ', MIN(access_time), \'0000-00-00 00:00:00\') AS access_time FROM (SELECT access_time FROM ' . _DB_PREFIX_ . 'securitylite WHERE banned = 0 AND email = "' . $email . '" ORDER BY access_time DESC LIMIT ' . $maxRetry . ') tmp'; - $accessStats = Db::getInstance()->getRow($query); - - return $accessStats ? \strtotime($accessStats['access_time']) : 0; + return Db::getInstance()->executeS(' + SELECT `id_employee`, `firstname`, `lastname`, `email`, `passwd`, `last_passwd_gen`, `last_connection_date`, `active` + FROM `' . _DB_PREFIX_ . 'employee` + ' . ($activeOnly ? ' WHERE `active` = 1' : '') . ' + ORDER BY `lastname` ASC + '); } /** - * Check CVE-2017-9841. + * Generate TFA token. * - * @return array + * @return string */ - private function checkFilesCVE20179841() + private function getTfaToken() { - $result = []; + $employees = $this->getEmployees(true); - $rootPath = _PS_CORE_DIR_ . \DIRECTORY_SEPARATOR . 'vendor' . \DIRECTORY_SEPARATOR . 'phpunit'; - if (\is_dir($rootPath)) { - $result[] .= $rootPath; + $tfaToken = []; + foreach ($employees as $employee) { + $tfaToken[] = $this->encrypt($employee['passwd']); } - $modulePath = _PS_MODULE_DIR_; + return $tfaToken; + } - $iter = new RecursiveIteratorIterator( - new RecursiveDirectoryIterator($modulePath, RecursiveDirectoryIterator::SKIP_DOTS), - RecursiveIteratorIterator::SELF_FIRST, - RecursiveIteratorIterator::CATCH_GET_CHILD // Ignore "Permission denied" - ); + /** + * Generate RBL report. + */ + private function generateReportRbl() + { + $serverIp = $_SERVER['SERVER_ADDR']; + + $url = 'https://rbl-check.org/rbl_api.php?ipaddress=' . $serverIp; + + //Open the file. + $fileHandle = \fopen($url, 'rb'); + + //Loop through the CSV rows. + $response = []; + while (false !== ($row = \fgetcsv($fileHandle, 0, ';'))) { + $rbl = $row[0]; + $host = $row[1]; + if ('listed' === $row[3]) { + $status = $this->l('You are listed in'); + } elseif ('notlisted' === $row[3]) { + $status = $this->l('You are not listed in'); + } - $paths = [$modulePath]; - foreach ($iter as $path => $dir) { - if ($dir->isDir()) { - $paths[] = $path; - if ('phpunit' === $dir->getFilename()) { - $result[] .= $dir->getRealpath(); - } + if (isset($rbl, $host, $status)) { + $response[] = $status . ' ' . $rbl . ' (' . $host . ')'; } } - return $result; + \fclose($url); + + \file_put_contents(_PS_MODULE_DIR_ . self::REPORT_RBL_CHECKER, \implode(\PHP_EOL, $response), \FILE_APPEND | \LOCK_EX); } /** - * Response HTTP header 403 and block the request. + * Get employee admin link. + * + * @param string $id + * + * @return string */ - private function blockRequest() + private function getEmployeeAdminLink($id) { - \http_response_code(403); - \header('Connection: Close'); - \header('Cache-Control: max-age=0, private, no-store, no-cache, must-revalidate'); - exit; + if (Tools::version_compare(_PS_VERSION_, '1.7.6.0', '<')) { // < 1.7.6 + $url = $this->getAdminLink('AdminEmployees', true) . '&id_employee=' . $id . '&updateemployee'; + } else { // >= 1.7.6 + $explode = \explode('?', $this->getAdminLink('AdminEmployees', true)); + $url = $explode[0] . $id . '/edit?' . $explode[1]; + } + + return $url; } /** - * Normalize php ini value. + * Get admin link. * - * @param $v string + * @param string $controller + * @param bool $withToken * - * @return bool + * @return string */ - private function isOn($v) + private function getAdminLink($controller, $withToken = true) { - if ('0' === $v || false === $v || 'off' === Tools::strtolower($v)) { - return '0'; + if (Tools::version_compare(_PS_VERSION_, '1.7.0.0', '>=')) { // 1.7 + return $this->context->link->getAdminLink($controller, $withToken); } - return '1'; + // 1.6 + return $this->getBaseURL() . \basename(_PS_ADMIN_DIR_) . '/' . $this->context->link->getAdminLink($controller, $withToken); } /** - * Download a compressed zip file with all translations. + * Check if SSL/TLS is enabled. + * + * @return bool */ - private function exportTranslation() + private function isSsl() { - $date = \time(); - $backupFile = 'securitylite-trans-' . $date . '.zip'; - $ignoreFiles = [ - 'index.php', - ]; - $dir = _PS_MODULE_DIR_ . 'securitylite/translations'; + // Check if SSL is enabled + if (false === (bool) Configuration::get('PS_SSL_ENABLED')) { + return false; + } - $directoryIterator = new RecursiveDirectoryIterator($dir); + // Check if port 433 is open + if (isset($_SERVER['SERVER_PORT']) && '443' !== $_SERVER['SERVER_PORT']) { + return false; + } - $ignoreIterator = new \PhpZip\Util\Iterator\IgnoreFilesRecursiveFilterIterator( - $directoryIterator, - $ignoreFiles - ); + return true; + } - $zipFile = new \PhpZip\ZipFile(); - $zipFile->setCompressionLevel(\PhpZip\Constants\ZipCompressionLevel::SUPER_FAST); - $zipFile->addFilesFromIterator($ignoreIterator, \PhpZip\Constants\ZipCompressionMethod::STORED); - $zipFile->outputAsAttachment($backupFile); - exit; + private function addHeading($content, $noTop = false) + { + if (true === $noTop) { + return '

' . $content . '

'; + } + + return '

' . $content . '

'; + } + + private function addAlertWarning($content) + { + return '
' . $content . '
'; + } + + private function addAlertInfo($content) + { + return '
' . $content . '
'; } } diff --git a/sql/index.php b/sql/index.php deleted file mode 100644 index f002f69..0000000 --- a/sql/index.php +++ /dev/null @@ -1,25 +0,0 @@ -execute($query)) { - return false; - } -} diff --git a/sql/uninstall.php b/sql/uninstall.php deleted file mode 100644 index d50ac95..0000000 --- a/sql/uninstall.php +++ /dev/null @@ -1,25 +0,0 @@ -execute($query)) { - return false; - } -} diff --git a/translations/index.php b/translations/index.php index f002f69..fa24a5a 100644 --- a/translations/index.php +++ b/translations/index.php @@ -1,16 +1,13 @@ registerHook( - [ - 'displayAdminLogin', - 'actionBeforeSubmitAccount', - ] - ); - - $sql = []; - $sql[] = 'CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'securitylite_tfa` ( - `enabled` int(1) NOT NULL, - `secret` varchar(32) NOT NULL - ) ENGINE=' . _MYSQL_ENGINE_ . ' DEFAULT CHARSET=UTF8; - '; - - foreach ($sql as $query) { - if (false === Db::getInstance()->execute($query)) { - return false; - } - - return true; - } -} diff --git a/upgrade/install-4.3.0.php b/upgrade/install-4.3.0.php deleted file mode 100644 index c0d5bdb..0000000 --- a/upgrade/install-4.3.0.php +++ /dev/null @@ -1,29 +0,0 @@ -registerHook( - [ - 'actionDispatcher', - ] - ); - - return true; -} diff --git a/upgrade/upgrade-5.0.0.php b/upgrade/upgrade-5.0.0.php new file mode 100644 index 0000000..5c635cf --- /dev/null +++ b/upgrade/upgrade-5.0.0.php @@ -0,0 +1,41 @@ +registerHook( + [ + 'displayBackOfficeTop', + 'displayHeader', + 'displayMaintenance', + ] + ); + + if (Tools::version_compare(_PS_VERSION_, '1.7.7.0', '>=')) { + $module->registerHook( + [ + 'actionAdminLoginControllerBefore', + ] + ); + } + + return true; +} diff --git a/vendor/autoload.php b/vendor/autoload.php index 2fbe987..65bb91a 100644 --- a/vendor/autoload.php +++ b/vendor/autoload.php @@ -4,4 +4,4 @@ require_once __DIR__ . '/composer/autoload_real.php'; -return ComposerAutoloaderInit3925021fccd9b7bb9c1949323f8f16f3::getLoader(); +return ComposerAutoloaderInitb33f02c2794c19668c2dba8dd3d94f2c::getLoader(); diff --git a/vendor/composer/ClassLoader.php b/vendor/composer/ClassLoader.php index 95f7e09..03b9bb9 100644 --- a/vendor/composer/ClassLoader.php +++ b/vendor/composer/ClassLoader.php @@ -60,7 +60,7 @@ class ClassLoader public function getPrefixes() { if (!empty($this->prefixesPsr0)) { - return call_user_func_array('array_merge', $this->prefixesPsr0); + return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); } return array(); @@ -279,7 +279,7 @@ public function isClassMapAuthoritative() */ public function setApcuPrefix($apcuPrefix) { - $this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null; + $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; } /** diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index d9e35e6..f42fcf2 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -6,89 +6,20 @@ $baseDir = dirname($vendorDir); return array( + 'DG\\ComposerCleaner\\Cleaner' => $vendorDir . '/dg/composer-cleaner/src/ComposerCleaner/Cleaner.php', + 'DG\\ComposerCleaner\\Plugin' => $vendorDir . '/dg/composer-cleaner/src/ComposerCleaner/Plugin.php', 'IPLib\\Address\\AddressInterface' => $vendorDir . '/mlocati/ip-lib/src/Address/AddressInterface.php', 'IPLib\\Address\\AssignedRange' => $vendorDir . '/mlocati/ip-lib/src/Address/AssignedRange.php', 'IPLib\\Address\\IPv4' => $vendorDir . '/mlocati/ip-lib/src/Address/IPv4.php', 'IPLib\\Address\\IPv6' => $vendorDir . '/mlocati/ip-lib/src/Address/IPv6.php', 'IPLib\\Address\\Type' => $vendorDir . '/mlocati/ip-lib/src/Address/Type.php', 'IPLib\\Factory' => $vendorDir . '/mlocati/ip-lib/src/Factory.php', + 'IPLib\\Range\\AbstractRange' => $vendorDir . '/mlocati/ip-lib/src/Range/AbstractRange.php', 'IPLib\\Range\\Pattern' => $vendorDir . '/mlocati/ip-lib/src/Range/Pattern.php', 'IPLib\\Range\\RangeInterface' => $vendorDir . '/mlocati/ip-lib/src/Range/RangeInterface.php', 'IPLib\\Range\\Single' => $vendorDir . '/mlocati/ip-lib/src/Range/Single.php', 'IPLib\\Range\\Subnet' => $vendorDir . '/mlocati/ip-lib/src/Range/Subnet.php', 'IPLib\\Range\\Type' => $vendorDir . '/mlocati/ip-lib/src/Range/Type.php', - 'PhpZip\\Constants\\DosAttrs' => $vendorDir . '/nelexa/zip/src/Constants/DosAttrs.php', - 'PhpZip\\Constants\\DosCodePage' => $vendorDir . '/nelexa/zip/src/Constants/DosCodePage.php', - 'PhpZip\\Constants\\GeneralPurposeBitFlag' => $vendorDir . '/nelexa/zip/src/Constants/GeneralPurposeBitFlag.php', - 'PhpZip\\Constants\\UnixStat' => $vendorDir . '/nelexa/zip/src/Constants/UnixStat.php', - 'PhpZip\\Constants\\ZipCompressionLevel' => $vendorDir . '/nelexa/zip/src/Constants/ZipCompressionLevel.php', - 'PhpZip\\Constants\\ZipCompressionMethod' => $vendorDir . '/nelexa/zip/src/Constants/ZipCompressionMethod.php', - 'PhpZip\\Constants\\ZipConstants' => $vendorDir . '/nelexa/zip/src/Constants/ZipConstants.php', - 'PhpZip\\Constants\\ZipEncryptionMethod' => $vendorDir . '/nelexa/zip/src/Constants/ZipEncryptionMethod.php', - 'PhpZip\\Constants\\ZipOptions' => $vendorDir . '/nelexa/zip/src/Constants/ZipOptions.php', - 'PhpZip\\Constants\\ZipPlatform' => $vendorDir . '/nelexa/zip/src/Constants/ZipPlatform.php', - 'PhpZip\\Constants\\ZipVersion' => $vendorDir . '/nelexa/zip/src/Constants/ZipVersion.php', - 'PhpZip\\Exception\\Crc32Exception' => $vendorDir . '/nelexa/zip/src/Exception/Crc32Exception.php', - 'PhpZip\\Exception\\InvalidArgumentException' => $vendorDir . '/nelexa/zip/src/Exception/InvalidArgumentException.php', - 'PhpZip\\Exception\\RuntimeException' => $vendorDir . '/nelexa/zip/src/Exception/RuntimeException.php', - 'PhpZip\\Exception\\ZipAuthenticationException' => $vendorDir . '/nelexa/zip/src/Exception/ZipAuthenticationException.php', - 'PhpZip\\Exception\\ZipCryptoException' => $vendorDir . '/nelexa/zip/src/Exception/ZipCryptoException.php', - 'PhpZip\\Exception\\ZipEntryNotFoundException' => $vendorDir . '/nelexa/zip/src/Exception/ZipEntryNotFoundException.php', - 'PhpZip\\Exception\\ZipException' => $vendorDir . '/nelexa/zip/src/Exception/ZipException.php', - 'PhpZip\\Exception\\ZipUnsupportMethodException' => $vendorDir . '/nelexa/zip/src/Exception/ZipUnsupportMethodException.php', - 'PhpZip\\IO\\Filter\\Cipher\\Pkware\\PKCryptContext' => $vendorDir . '/nelexa/zip/src/IO/Filter/Cipher/Pkware/PKCryptContext.php', - 'PhpZip\\IO\\Filter\\Cipher\\Pkware\\PKDecryptionStreamFilter' => $vendorDir . '/nelexa/zip/src/IO/Filter/Cipher/Pkware/PKDecryptionStreamFilter.php', - 'PhpZip\\IO\\Filter\\Cipher\\Pkware\\PKEncryptionStreamFilter' => $vendorDir . '/nelexa/zip/src/IO/Filter/Cipher/Pkware/PKEncryptionStreamFilter.php', - 'PhpZip\\IO\\Filter\\Cipher\\WinZipAes\\WinZipAesContext' => $vendorDir . '/nelexa/zip/src/IO/Filter/Cipher/WinZipAes/WinZipAesContext.php', - 'PhpZip\\IO\\Filter\\Cipher\\WinZipAes\\WinZipAesDecryptionStreamFilter' => $vendorDir . '/nelexa/zip/src/IO/Filter/Cipher/WinZipAes/WinZipAesDecryptionStreamFilter.php', - 'PhpZip\\IO\\Filter\\Cipher\\WinZipAes\\WinZipAesEncryptionStreamFilter' => $vendorDir . '/nelexa/zip/src/IO/Filter/Cipher/WinZipAes/WinZipAesEncryptionStreamFilter.php', - 'PhpZip\\IO\\Stream\\ResponseStream' => $vendorDir . '/nelexa/zip/src/IO/Stream/ResponseStream.php', - 'PhpZip\\IO\\Stream\\ZipEntryStreamWrapper' => $vendorDir . '/nelexa/zip/src/IO/Stream/ZipEntryStreamWrapper.php', - 'PhpZip\\IO\\ZipReader' => $vendorDir . '/nelexa/zip/src/IO/ZipReader.php', - 'PhpZip\\IO\\ZipWriter' => $vendorDir . '/nelexa/zip/src/IO/ZipWriter.php', - 'PhpZip\\Model\\Data\\ZipFileData' => $vendorDir . '/nelexa/zip/src/Model/Data/ZipFileData.php', - 'PhpZip\\Model\\Data\\ZipNewData' => $vendorDir . '/nelexa/zip/src/Model/Data/ZipNewData.php', - 'PhpZip\\Model\\Data\\ZipSourceFileData' => $vendorDir . '/nelexa/zip/src/Model/Data/ZipSourceFileData.php', - 'PhpZip\\Model\\EndOfCentralDirectory' => $vendorDir . '/nelexa/zip/src/Model/EndOfCentralDirectory.php', - 'PhpZip\\Model\\Extra\\ExtraFieldsCollection' => $vendorDir . '/nelexa/zip/src/Model/Extra/ExtraFieldsCollection.php', - 'PhpZip\\Model\\Extra\\Fields\\AbstractUnicodeExtraField' => $vendorDir . '/nelexa/zip/src/Model/Extra/Fields/AbstractUnicodeExtraField.php', - 'PhpZip\\Model\\Extra\\Fields\\ApkAlignmentExtraField' => $vendorDir . '/nelexa/zip/src/Model/Extra/Fields/ApkAlignmentExtraField.php', - 'PhpZip\\Model\\Extra\\Fields\\AsiExtraField' => $vendorDir . '/nelexa/zip/src/Model/Extra/Fields/AsiExtraField.php', - 'PhpZip\\Model\\Extra\\Fields\\ExtendedTimestampExtraField' => $vendorDir . '/nelexa/zip/src/Model/Extra/Fields/ExtendedTimestampExtraField.php', - 'PhpZip\\Model\\Extra\\Fields\\JarMarkerExtraField' => $vendorDir . '/nelexa/zip/src/Model/Extra/Fields/JarMarkerExtraField.php', - 'PhpZip\\Model\\Extra\\Fields\\NewUnixExtraField' => $vendorDir . '/nelexa/zip/src/Model/Extra/Fields/NewUnixExtraField.php', - 'PhpZip\\Model\\Extra\\Fields\\NtfsExtraField' => $vendorDir . '/nelexa/zip/src/Model/Extra/Fields/NtfsExtraField.php', - 'PhpZip\\Model\\Extra\\Fields\\OldUnixExtraField' => $vendorDir . '/nelexa/zip/src/Model/Extra/Fields/OldUnixExtraField.php', - 'PhpZip\\Model\\Extra\\Fields\\UnicodeCommentExtraField' => $vendorDir . '/nelexa/zip/src/Model/Extra/Fields/UnicodeCommentExtraField.php', - 'PhpZip\\Model\\Extra\\Fields\\UnicodePathExtraField' => $vendorDir . '/nelexa/zip/src/Model/Extra/Fields/UnicodePathExtraField.php', - 'PhpZip\\Model\\Extra\\Fields\\UnrecognizedExtraField' => $vendorDir . '/nelexa/zip/src/Model/Extra/Fields/UnrecognizedExtraField.php', - 'PhpZip\\Model\\Extra\\Fields\\WinZipAesExtraField' => $vendorDir . '/nelexa/zip/src/Model/Extra/Fields/WinZipAesExtraField.php', - 'PhpZip\\Model\\Extra\\Fields\\Zip64ExtraField' => $vendorDir . '/nelexa/zip/src/Model/Extra/Fields/Zip64ExtraField.php', - 'PhpZip\\Model\\Extra\\ZipExtraDriver' => $vendorDir . '/nelexa/zip/src/Model/Extra/ZipExtraDriver.php', - 'PhpZip\\Model\\Extra\\ZipExtraField' => $vendorDir . '/nelexa/zip/src/Model/Extra/ZipExtraField.php', - 'PhpZip\\Model\\ImmutableZipContainer' => $vendorDir . '/nelexa/zip/src/Model/ImmutableZipContainer.php', - 'PhpZip\\Model\\ZipContainer' => $vendorDir . '/nelexa/zip/src/Model/ZipContainer.php', - 'PhpZip\\Model\\ZipData' => $vendorDir . '/nelexa/zip/src/Model/ZipData.php', - 'PhpZip\\Model\\ZipEntry' => $vendorDir . '/nelexa/zip/src/Model/ZipEntry.php', - 'PhpZip\\Model\\ZipEntryMatcher' => $vendorDir . '/nelexa/zip/src/Model/ZipEntryMatcher.php', - 'PhpZip\\Model\\ZipInfo' => $vendorDir . '/nelexa/zip/src/Model/ZipInfo.php', - 'PhpZip\\Util\\CryptoUtil' => $vendorDir . '/nelexa/zip/src/Util/CryptoUtil.php', - 'PhpZip\\Util\\DateTimeConverter' => $vendorDir . '/nelexa/zip/src/Util/DateTimeConverter.php', - 'PhpZip\\Util\\FileAttribUtil' => $vendorDir . '/nelexa/zip/src/Util/FileAttribUtil.php', - 'PhpZip\\Util\\FilesUtil' => $vendorDir . '/nelexa/zip/src/Util/FilesUtil.php', - 'PhpZip\\Util\\Iterator\\IgnoreFilesFilterIterator' => $vendorDir . '/nelexa/zip/src/Util/Iterator/IgnoreFilesFilterIterator.php', - 'PhpZip\\Util\\Iterator\\IgnoreFilesRecursiveFilterIterator' => $vendorDir . '/nelexa/zip/src/Util/Iterator/IgnoreFilesRecursiveFilterIterator.php', - 'PhpZip\\Util\\PackUtil' => $vendorDir . '/nelexa/zip/src/Util/PackUtil.php', - 'PhpZip\\Util\\StringUtil' => $vendorDir . '/nelexa/zip/src/Util/StringUtil.php', - 'PhpZip\\ZipFile' => $vendorDir . '/nelexa/zip/src/ZipFile.php', - 'PhpZip\\ZipFileInterface' => $vendorDir . '/nelexa/zip/src/ZipFileInterface.php', - 'Psr\\Http\\Message\\MessageInterface' => $vendorDir . '/psr/http-message/src/MessageInterface.php', - 'Psr\\Http\\Message\\RequestInterface' => $vendorDir . '/psr/http-message/src/RequestInterface.php', - 'Psr\\Http\\Message\\ResponseInterface' => $vendorDir . '/psr/http-message/src/ResponseInterface.php', - 'Psr\\Http\\Message\\ServerRequestInterface' => $vendorDir . '/psr/http-message/src/ServerRequestInterface.php', - 'Psr\\Http\\Message\\StreamInterface' => $vendorDir . '/psr/http-message/src/StreamInterface.php', - 'Psr\\Http\\Message\\UploadedFileInterface' => $vendorDir . '/psr/http-message/src/UploadedFileInterface.php', - 'Psr\\Http\\Message\\UriInterface' => $vendorDir . '/psr/http-message/src/UriInterface.php', 'RobThree\\Auth\\Providers\\Qr\\BaseHTTPQRCodeProvider' => $vendorDir . '/robthree/twofactorauth/lib/Providers/Qr/BaseHTTPQRCodeProvider.php', 'RobThree\\Auth\\Providers\\Qr\\IQRCodeProvider' => $vendorDir . '/robthree/twofactorauth/lib/Providers/Qr/IQRCodeProvider.php', 'RobThree\\Auth\\Providers\\Qr\\ImageChartsQRCodeProvider' => $vendorDir . '/robthree/twofactorauth/lib/Providers/Qr/ImageChartsQRCodeProvider.php', @@ -105,25 +36,4 @@ 'RobThree\\Auth\\Providers\\Time\\NTPTimeProvider' => $vendorDir . '/robthree/twofactorauth/lib/Providers/Time/NTPTimeProvider.php', 'RobThree\\Auth\\TwoFactorAuth' => $vendorDir . '/robthree/twofactorauth/lib/TwoFactorAuth.php', 'RobThree\\Auth\\TwoFactorAuthException' => $vendorDir . '/robthree/twofactorauth/lib/TwoFactorAuthException.php', - 'Symfony\\Component\\Finder\\Comparator\\Comparator' => $vendorDir . '/symfony/finder/Comparator/Comparator.php', - 'Symfony\\Component\\Finder\\Comparator\\DateComparator' => $vendorDir . '/symfony/finder/Comparator/DateComparator.php', - 'Symfony\\Component\\Finder\\Comparator\\NumberComparator' => $vendorDir . '/symfony/finder/Comparator/NumberComparator.php', - 'Symfony\\Component\\Finder\\Exception\\AccessDeniedException' => $vendorDir . '/symfony/finder/Exception/AccessDeniedException.php', - 'Symfony\\Component\\Finder\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/finder/Exception/ExceptionInterface.php', - 'Symfony\\Component\\Finder\\Finder' => $vendorDir . '/symfony/finder/Finder.php', - 'Symfony\\Component\\Finder\\Glob' => $vendorDir . '/symfony/finder/Glob.php', - 'Symfony\\Component\\Finder\\Iterator\\CustomFilterIterator' => $vendorDir . '/symfony/finder/Iterator/CustomFilterIterator.php', - 'Symfony\\Component\\Finder\\Iterator\\DateRangeFilterIterator' => $vendorDir . '/symfony/finder/Iterator/DateRangeFilterIterator.php', - 'Symfony\\Component\\Finder\\Iterator\\DepthRangeFilterIterator' => $vendorDir . '/symfony/finder/Iterator/DepthRangeFilterIterator.php', - 'Symfony\\Component\\Finder\\Iterator\\ExcludeDirectoryFilterIterator' => $vendorDir . '/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php', - 'Symfony\\Component\\Finder\\Iterator\\FileTypeFilterIterator' => $vendorDir . '/symfony/finder/Iterator/FileTypeFilterIterator.php', - 'Symfony\\Component\\Finder\\Iterator\\FilecontentFilterIterator' => $vendorDir . '/symfony/finder/Iterator/FilecontentFilterIterator.php', - 'Symfony\\Component\\Finder\\Iterator\\FilenameFilterIterator' => $vendorDir . '/symfony/finder/Iterator/FilenameFilterIterator.php', - 'Symfony\\Component\\Finder\\Iterator\\FilterIterator' => $vendorDir . '/symfony/finder/Iterator/FilterIterator.php', - 'Symfony\\Component\\Finder\\Iterator\\MultiplePcreFilterIterator' => $vendorDir . '/symfony/finder/Iterator/MultiplePcreFilterIterator.php', - 'Symfony\\Component\\Finder\\Iterator\\PathFilterIterator' => $vendorDir . '/symfony/finder/Iterator/PathFilterIterator.php', - 'Symfony\\Component\\Finder\\Iterator\\RecursiveDirectoryIterator' => $vendorDir . '/symfony/finder/Iterator/RecursiveDirectoryIterator.php', - 'Symfony\\Component\\Finder\\Iterator\\SizeRangeFilterIterator' => $vendorDir . '/symfony/finder/Iterator/SizeRangeFilterIterator.php', - 'Symfony\\Component\\Finder\\Iterator\\SortableIterator' => $vendorDir . '/symfony/finder/Iterator/SortableIterator.php', - 'Symfony\\Component\\Finder\\SplFileInfo' => $vendorDir . '/symfony/finder/SplFileInfo.php', ); diff --git a/vendor/composer/autoload_files.php b/vendor/composer/autoload_files.php deleted file mode 100644 index 4d80bcb..0000000 --- a/vendor/composer/autoload_files.php +++ /dev/null @@ -1,10 +0,0 @@ - $vendorDir . '/paragonie/random_compat/lib/random.php', -); diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php index 5220dfc..a1cdb72 100644 --- a/vendor/composer/autoload_psr4.php +++ b/vendor/composer/autoload_psr4.php @@ -6,9 +6,6 @@ $baseDir = dirname($vendorDir); return array( - 'Symfony\\Component\\Finder\\' => array($vendorDir . '/symfony/finder'), 'RobThree\\Auth\\' => array($vendorDir . '/robthree/twofactorauth/lib'), - 'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src'), - 'PhpZip\\' => array($vendorDir . '/nelexa/zip/src'), 'IPLib\\' => array($vendorDir . '/mlocati/ip-lib/src'), ); diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php index 6ef5ca0..028d737 100644 --- a/vendor/composer/autoload_real.php +++ b/vendor/composer/autoload_real.php @@ -2,7 +2,7 @@ // autoload_real.php @generated by Composer -class ComposerAutoloaderInit3925021fccd9b7bb9c1949323f8f16f3 +class ComposerAutoloaderInitb33f02c2794c19668c2dba8dd3d94f2c { private static $loader; @@ -13,58 +13,34 @@ public static function loadClassLoader($class) } } + /** + * @return \Composer\Autoload\ClassLoader + */ public static function getLoader() { if (null !== self::$loader) { return self::$loader; } - spl_autoload_register(array('ComposerAutoloaderInit3925021fccd9b7bb9c1949323f8f16f3', 'loadClassLoader'), true, false); + spl_autoload_register(array('ComposerAutoloaderInitb33f02c2794c19668c2dba8dd3d94f2c', 'loadClassLoader'), true, false); self::$loader = $loader = new \Composer\Autoload\ClassLoader(); - spl_autoload_unregister(array('ComposerAutoloaderInit3925021fccd9b7bb9c1949323f8f16f3', 'loadClassLoader')); + spl_autoload_unregister(array('ComposerAutoloaderInitb33f02c2794c19668c2dba8dd3d94f2c', 'loadClassLoader')); $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); if ($useStaticLoader) { require_once __DIR__ . '/autoload_static.php'; - call_user_func(\Composer\Autoload\ComposerStaticInit3925021fccd9b7bb9c1949323f8f16f3::getInitializer($loader)); + call_user_func(\Composer\Autoload\ComposerStaticInitb33f02c2794c19668c2dba8dd3d94f2c::getInitializer($loader)); } else { - $map = require __DIR__ . '/autoload_namespaces.php'; - foreach ($map as $namespace => $path) { - $loader->set($namespace, $path); - } - - $map = require __DIR__ . '/autoload_psr4.php'; - foreach ($map as $namespace => $path) { - $loader->setPsr4($namespace, $path); - } - $classMap = require __DIR__ . '/autoload_classmap.php'; if ($classMap) { $loader->addClassMap($classMap); } } + $loader->setClassMapAuthoritative(true); $loader->register(false); - if ($useStaticLoader) { - $includeFiles = Composer\Autoload\ComposerStaticInit3925021fccd9b7bb9c1949323f8f16f3::$files; - } else { - $includeFiles = require __DIR__ . '/autoload_files.php'; - } - foreach ($includeFiles as $fileIdentifier => $file) { - composerRequire3925021fccd9b7bb9c1949323f8f16f3($fileIdentifier, $file); - } - return $loader; } } - -function composerRequire3925021fccd9b7bb9c1949323f8f16f3($fileIdentifier, $file) -{ - if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { - require $file; - - $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; - } -} diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index 8535239..57204c1 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -4,26 +4,13 @@ namespace Composer\Autoload; -class ComposerStaticInit3925021fccd9b7bb9c1949323f8f16f3 +class ComposerStaticInitb33f02c2794c19668c2dba8dd3d94f2c { - public static $files = array ( - '5255c38a0faeba867671b61dfda6d864' => __DIR__ . '/..' . '/paragonie/random_compat/lib/random.php', - ); - public static $prefixLengthsPsr4 = array ( - 'S' => - array ( - 'Symfony\\Component\\Finder\\' => 25, - ), 'R' => array ( 'RobThree\\Auth\\' => 14, ), - 'P' => - array ( - 'Psr\\Http\\Message\\' => 17, - 'PhpZip\\' => 7, - ), 'I' => array ( 'IPLib\\' => 6, @@ -31,22 +18,10 @@ class ComposerStaticInit3925021fccd9b7bb9c1949323f8f16f3 ); public static $prefixDirsPsr4 = array ( - 'Symfony\\Component\\Finder\\' => - array ( - 0 => __DIR__ . '/..' . '/symfony/finder', - ), 'RobThree\\Auth\\' => array ( 0 => __DIR__ . '/..' . '/robthree/twofactorauth/lib', ), - 'Psr\\Http\\Message\\' => - array ( - 0 => __DIR__ . '/..' . '/psr/http-message/src', - ), - 'PhpZip\\' => - array ( - 0 => __DIR__ . '/..' . '/nelexa/zip/src', - ), 'IPLib\\' => array ( 0 => __DIR__ . '/..' . '/mlocati/ip-lib/src', @@ -54,89 +29,20 @@ class ComposerStaticInit3925021fccd9b7bb9c1949323f8f16f3 ); public static $classMap = array ( + 'DG\\ComposerCleaner\\Cleaner' => __DIR__ . '/..' . '/dg/composer-cleaner/src/ComposerCleaner/Cleaner.php', + 'DG\\ComposerCleaner\\Plugin' => __DIR__ . '/..' . '/dg/composer-cleaner/src/ComposerCleaner/Plugin.php', 'IPLib\\Address\\AddressInterface' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Address/AddressInterface.php', 'IPLib\\Address\\AssignedRange' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Address/AssignedRange.php', 'IPLib\\Address\\IPv4' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Address/IPv4.php', 'IPLib\\Address\\IPv6' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Address/IPv6.php', 'IPLib\\Address\\Type' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Address/Type.php', 'IPLib\\Factory' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Factory.php', + 'IPLib\\Range\\AbstractRange' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Range/AbstractRange.php', 'IPLib\\Range\\Pattern' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Range/Pattern.php', 'IPLib\\Range\\RangeInterface' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Range/RangeInterface.php', 'IPLib\\Range\\Single' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Range/Single.php', 'IPLib\\Range\\Subnet' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Range/Subnet.php', 'IPLib\\Range\\Type' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Range/Type.php', - 'PhpZip\\Constants\\DosAttrs' => __DIR__ . '/..' . '/nelexa/zip/src/Constants/DosAttrs.php', - 'PhpZip\\Constants\\DosCodePage' => __DIR__ . '/..' . '/nelexa/zip/src/Constants/DosCodePage.php', - 'PhpZip\\Constants\\GeneralPurposeBitFlag' => __DIR__ . '/..' . '/nelexa/zip/src/Constants/GeneralPurposeBitFlag.php', - 'PhpZip\\Constants\\UnixStat' => __DIR__ . '/..' . '/nelexa/zip/src/Constants/UnixStat.php', - 'PhpZip\\Constants\\ZipCompressionLevel' => __DIR__ . '/..' . '/nelexa/zip/src/Constants/ZipCompressionLevel.php', - 'PhpZip\\Constants\\ZipCompressionMethod' => __DIR__ . '/..' . '/nelexa/zip/src/Constants/ZipCompressionMethod.php', - 'PhpZip\\Constants\\ZipConstants' => __DIR__ . '/..' . '/nelexa/zip/src/Constants/ZipConstants.php', - 'PhpZip\\Constants\\ZipEncryptionMethod' => __DIR__ . '/..' . '/nelexa/zip/src/Constants/ZipEncryptionMethod.php', - 'PhpZip\\Constants\\ZipOptions' => __DIR__ . '/..' . '/nelexa/zip/src/Constants/ZipOptions.php', - 'PhpZip\\Constants\\ZipPlatform' => __DIR__ . '/..' . '/nelexa/zip/src/Constants/ZipPlatform.php', - 'PhpZip\\Constants\\ZipVersion' => __DIR__ . '/..' . '/nelexa/zip/src/Constants/ZipVersion.php', - 'PhpZip\\Exception\\Crc32Exception' => __DIR__ . '/..' . '/nelexa/zip/src/Exception/Crc32Exception.php', - 'PhpZip\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/nelexa/zip/src/Exception/InvalidArgumentException.php', - 'PhpZip\\Exception\\RuntimeException' => __DIR__ . '/..' . '/nelexa/zip/src/Exception/RuntimeException.php', - 'PhpZip\\Exception\\ZipAuthenticationException' => __DIR__ . '/..' . '/nelexa/zip/src/Exception/ZipAuthenticationException.php', - 'PhpZip\\Exception\\ZipCryptoException' => __DIR__ . '/..' . '/nelexa/zip/src/Exception/ZipCryptoException.php', - 'PhpZip\\Exception\\ZipEntryNotFoundException' => __DIR__ . '/..' . '/nelexa/zip/src/Exception/ZipEntryNotFoundException.php', - 'PhpZip\\Exception\\ZipException' => __DIR__ . '/..' . '/nelexa/zip/src/Exception/ZipException.php', - 'PhpZip\\Exception\\ZipUnsupportMethodException' => __DIR__ . '/..' . '/nelexa/zip/src/Exception/ZipUnsupportMethodException.php', - 'PhpZip\\IO\\Filter\\Cipher\\Pkware\\PKCryptContext' => __DIR__ . '/..' . '/nelexa/zip/src/IO/Filter/Cipher/Pkware/PKCryptContext.php', - 'PhpZip\\IO\\Filter\\Cipher\\Pkware\\PKDecryptionStreamFilter' => __DIR__ . '/..' . '/nelexa/zip/src/IO/Filter/Cipher/Pkware/PKDecryptionStreamFilter.php', - 'PhpZip\\IO\\Filter\\Cipher\\Pkware\\PKEncryptionStreamFilter' => __DIR__ . '/..' . '/nelexa/zip/src/IO/Filter/Cipher/Pkware/PKEncryptionStreamFilter.php', - 'PhpZip\\IO\\Filter\\Cipher\\WinZipAes\\WinZipAesContext' => __DIR__ . '/..' . '/nelexa/zip/src/IO/Filter/Cipher/WinZipAes/WinZipAesContext.php', - 'PhpZip\\IO\\Filter\\Cipher\\WinZipAes\\WinZipAesDecryptionStreamFilter' => __DIR__ . '/..' . '/nelexa/zip/src/IO/Filter/Cipher/WinZipAes/WinZipAesDecryptionStreamFilter.php', - 'PhpZip\\IO\\Filter\\Cipher\\WinZipAes\\WinZipAesEncryptionStreamFilter' => __DIR__ . '/..' . '/nelexa/zip/src/IO/Filter/Cipher/WinZipAes/WinZipAesEncryptionStreamFilter.php', - 'PhpZip\\IO\\Stream\\ResponseStream' => __DIR__ . '/..' . '/nelexa/zip/src/IO/Stream/ResponseStream.php', - 'PhpZip\\IO\\Stream\\ZipEntryStreamWrapper' => __DIR__ . '/..' . '/nelexa/zip/src/IO/Stream/ZipEntryStreamWrapper.php', - 'PhpZip\\IO\\ZipReader' => __DIR__ . '/..' . '/nelexa/zip/src/IO/ZipReader.php', - 'PhpZip\\IO\\ZipWriter' => __DIR__ . '/..' . '/nelexa/zip/src/IO/ZipWriter.php', - 'PhpZip\\Model\\Data\\ZipFileData' => __DIR__ . '/..' . '/nelexa/zip/src/Model/Data/ZipFileData.php', - 'PhpZip\\Model\\Data\\ZipNewData' => __DIR__ . '/..' . '/nelexa/zip/src/Model/Data/ZipNewData.php', - 'PhpZip\\Model\\Data\\ZipSourceFileData' => __DIR__ . '/..' . '/nelexa/zip/src/Model/Data/ZipSourceFileData.php', - 'PhpZip\\Model\\EndOfCentralDirectory' => __DIR__ . '/..' . '/nelexa/zip/src/Model/EndOfCentralDirectory.php', - 'PhpZip\\Model\\Extra\\ExtraFieldsCollection' => __DIR__ . '/..' . '/nelexa/zip/src/Model/Extra/ExtraFieldsCollection.php', - 'PhpZip\\Model\\Extra\\Fields\\AbstractUnicodeExtraField' => __DIR__ . '/..' . '/nelexa/zip/src/Model/Extra/Fields/AbstractUnicodeExtraField.php', - 'PhpZip\\Model\\Extra\\Fields\\ApkAlignmentExtraField' => __DIR__ . '/..' . '/nelexa/zip/src/Model/Extra/Fields/ApkAlignmentExtraField.php', - 'PhpZip\\Model\\Extra\\Fields\\AsiExtraField' => __DIR__ . '/..' . '/nelexa/zip/src/Model/Extra/Fields/AsiExtraField.php', - 'PhpZip\\Model\\Extra\\Fields\\ExtendedTimestampExtraField' => __DIR__ . '/..' . '/nelexa/zip/src/Model/Extra/Fields/ExtendedTimestampExtraField.php', - 'PhpZip\\Model\\Extra\\Fields\\JarMarkerExtraField' => __DIR__ . '/..' . '/nelexa/zip/src/Model/Extra/Fields/JarMarkerExtraField.php', - 'PhpZip\\Model\\Extra\\Fields\\NewUnixExtraField' => __DIR__ . '/..' . '/nelexa/zip/src/Model/Extra/Fields/NewUnixExtraField.php', - 'PhpZip\\Model\\Extra\\Fields\\NtfsExtraField' => __DIR__ . '/..' . '/nelexa/zip/src/Model/Extra/Fields/NtfsExtraField.php', - 'PhpZip\\Model\\Extra\\Fields\\OldUnixExtraField' => __DIR__ . '/..' . '/nelexa/zip/src/Model/Extra/Fields/OldUnixExtraField.php', - 'PhpZip\\Model\\Extra\\Fields\\UnicodeCommentExtraField' => __DIR__ . '/..' . '/nelexa/zip/src/Model/Extra/Fields/UnicodeCommentExtraField.php', - 'PhpZip\\Model\\Extra\\Fields\\UnicodePathExtraField' => __DIR__ . '/..' . '/nelexa/zip/src/Model/Extra/Fields/UnicodePathExtraField.php', - 'PhpZip\\Model\\Extra\\Fields\\UnrecognizedExtraField' => __DIR__ . '/..' . '/nelexa/zip/src/Model/Extra/Fields/UnrecognizedExtraField.php', - 'PhpZip\\Model\\Extra\\Fields\\WinZipAesExtraField' => __DIR__ . '/..' . '/nelexa/zip/src/Model/Extra/Fields/WinZipAesExtraField.php', - 'PhpZip\\Model\\Extra\\Fields\\Zip64ExtraField' => __DIR__ . '/..' . '/nelexa/zip/src/Model/Extra/Fields/Zip64ExtraField.php', - 'PhpZip\\Model\\Extra\\ZipExtraDriver' => __DIR__ . '/..' . '/nelexa/zip/src/Model/Extra/ZipExtraDriver.php', - 'PhpZip\\Model\\Extra\\ZipExtraField' => __DIR__ . '/..' . '/nelexa/zip/src/Model/Extra/ZipExtraField.php', - 'PhpZip\\Model\\ImmutableZipContainer' => __DIR__ . '/..' . '/nelexa/zip/src/Model/ImmutableZipContainer.php', - 'PhpZip\\Model\\ZipContainer' => __DIR__ . '/..' . '/nelexa/zip/src/Model/ZipContainer.php', - 'PhpZip\\Model\\ZipData' => __DIR__ . '/..' . '/nelexa/zip/src/Model/ZipData.php', - 'PhpZip\\Model\\ZipEntry' => __DIR__ . '/..' . '/nelexa/zip/src/Model/ZipEntry.php', - 'PhpZip\\Model\\ZipEntryMatcher' => __DIR__ . '/..' . '/nelexa/zip/src/Model/ZipEntryMatcher.php', - 'PhpZip\\Model\\ZipInfo' => __DIR__ . '/..' . '/nelexa/zip/src/Model/ZipInfo.php', - 'PhpZip\\Util\\CryptoUtil' => __DIR__ . '/..' . '/nelexa/zip/src/Util/CryptoUtil.php', - 'PhpZip\\Util\\DateTimeConverter' => __DIR__ . '/..' . '/nelexa/zip/src/Util/DateTimeConverter.php', - 'PhpZip\\Util\\FileAttribUtil' => __DIR__ . '/..' . '/nelexa/zip/src/Util/FileAttribUtil.php', - 'PhpZip\\Util\\FilesUtil' => __DIR__ . '/..' . '/nelexa/zip/src/Util/FilesUtil.php', - 'PhpZip\\Util\\Iterator\\IgnoreFilesFilterIterator' => __DIR__ . '/..' . '/nelexa/zip/src/Util/Iterator/IgnoreFilesFilterIterator.php', - 'PhpZip\\Util\\Iterator\\IgnoreFilesRecursiveFilterIterator' => __DIR__ . '/..' . '/nelexa/zip/src/Util/Iterator/IgnoreFilesRecursiveFilterIterator.php', - 'PhpZip\\Util\\PackUtil' => __DIR__ . '/..' . '/nelexa/zip/src/Util/PackUtil.php', - 'PhpZip\\Util\\StringUtil' => __DIR__ . '/..' . '/nelexa/zip/src/Util/StringUtil.php', - 'PhpZip\\ZipFile' => __DIR__ . '/..' . '/nelexa/zip/src/ZipFile.php', - 'PhpZip\\ZipFileInterface' => __DIR__ . '/..' . '/nelexa/zip/src/ZipFileInterface.php', - 'Psr\\Http\\Message\\MessageInterface' => __DIR__ . '/..' . '/psr/http-message/src/MessageInterface.php', - 'Psr\\Http\\Message\\RequestInterface' => __DIR__ . '/..' . '/psr/http-message/src/RequestInterface.php', - 'Psr\\Http\\Message\\ResponseInterface' => __DIR__ . '/..' . '/psr/http-message/src/ResponseInterface.php', - 'Psr\\Http\\Message\\ServerRequestInterface' => __DIR__ . '/..' . '/psr/http-message/src/ServerRequestInterface.php', - 'Psr\\Http\\Message\\StreamInterface' => __DIR__ . '/..' . '/psr/http-message/src/StreamInterface.php', - 'Psr\\Http\\Message\\UploadedFileInterface' => __DIR__ . '/..' . '/psr/http-message/src/UploadedFileInterface.php', - 'Psr\\Http\\Message\\UriInterface' => __DIR__ . '/..' . '/psr/http-message/src/UriInterface.php', 'RobThree\\Auth\\Providers\\Qr\\BaseHTTPQRCodeProvider' => __DIR__ . '/..' . '/robthree/twofactorauth/lib/Providers/Qr/BaseHTTPQRCodeProvider.php', 'RobThree\\Auth\\Providers\\Qr\\IQRCodeProvider' => __DIR__ . '/..' . '/robthree/twofactorauth/lib/Providers/Qr/IQRCodeProvider.php', 'RobThree\\Auth\\Providers\\Qr\\ImageChartsQRCodeProvider' => __DIR__ . '/..' . '/robthree/twofactorauth/lib/Providers/Qr/ImageChartsQRCodeProvider.php', @@ -153,35 +59,14 @@ class ComposerStaticInit3925021fccd9b7bb9c1949323f8f16f3 'RobThree\\Auth\\Providers\\Time\\NTPTimeProvider' => __DIR__ . '/..' . '/robthree/twofactorauth/lib/Providers/Time/NTPTimeProvider.php', 'RobThree\\Auth\\TwoFactorAuth' => __DIR__ . '/..' . '/robthree/twofactorauth/lib/TwoFactorAuth.php', 'RobThree\\Auth\\TwoFactorAuthException' => __DIR__ . '/..' . '/robthree/twofactorauth/lib/TwoFactorAuthException.php', - 'Symfony\\Component\\Finder\\Comparator\\Comparator' => __DIR__ . '/..' . '/symfony/finder/Comparator/Comparator.php', - 'Symfony\\Component\\Finder\\Comparator\\DateComparator' => __DIR__ . '/..' . '/symfony/finder/Comparator/DateComparator.php', - 'Symfony\\Component\\Finder\\Comparator\\NumberComparator' => __DIR__ . '/..' . '/symfony/finder/Comparator/NumberComparator.php', - 'Symfony\\Component\\Finder\\Exception\\AccessDeniedException' => __DIR__ . '/..' . '/symfony/finder/Exception/AccessDeniedException.php', - 'Symfony\\Component\\Finder\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/finder/Exception/ExceptionInterface.php', - 'Symfony\\Component\\Finder\\Finder' => __DIR__ . '/..' . '/symfony/finder/Finder.php', - 'Symfony\\Component\\Finder\\Glob' => __DIR__ . '/..' . '/symfony/finder/Glob.php', - 'Symfony\\Component\\Finder\\Iterator\\CustomFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/CustomFilterIterator.php', - 'Symfony\\Component\\Finder\\Iterator\\DateRangeFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/DateRangeFilterIterator.php', - 'Symfony\\Component\\Finder\\Iterator\\DepthRangeFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/DepthRangeFilterIterator.php', - 'Symfony\\Component\\Finder\\Iterator\\ExcludeDirectoryFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php', - 'Symfony\\Component\\Finder\\Iterator\\FileTypeFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/FileTypeFilterIterator.php', - 'Symfony\\Component\\Finder\\Iterator\\FilecontentFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/FilecontentFilterIterator.php', - 'Symfony\\Component\\Finder\\Iterator\\FilenameFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/FilenameFilterIterator.php', - 'Symfony\\Component\\Finder\\Iterator\\FilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/FilterIterator.php', - 'Symfony\\Component\\Finder\\Iterator\\MultiplePcreFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/MultiplePcreFilterIterator.php', - 'Symfony\\Component\\Finder\\Iterator\\PathFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/PathFilterIterator.php', - 'Symfony\\Component\\Finder\\Iterator\\RecursiveDirectoryIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/RecursiveDirectoryIterator.php', - 'Symfony\\Component\\Finder\\Iterator\\SizeRangeFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/SizeRangeFilterIterator.php', - 'Symfony\\Component\\Finder\\Iterator\\SortableIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/SortableIterator.php', - 'Symfony\\Component\\Finder\\SplFileInfo' => __DIR__ . '/..' . '/symfony/finder/SplFileInfo.php', ); public static function getInitializer(ClassLoader $loader) { return \Closure::bind(function () use ($loader) { - $loader->prefixLengthsPsr4 = ComposerStaticInit3925021fccd9b7bb9c1949323f8f16f3::$prefixLengthsPsr4; - $loader->prefixDirsPsr4 = ComposerStaticInit3925021fccd9b7bb9c1949323f8f16f3::$prefixDirsPsr4; - $loader->classMap = ComposerStaticInit3925021fccd9b7bb9c1949323f8f16f3::$classMap; + $loader->prefixLengthsPsr4 = ComposerStaticInitb33f02c2794c19668c2dba8dd3d94f2c::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInitb33f02c2794c19668c2dba8dd3d94f2c::$prefixDirsPsr4; + $loader->classMap = ComposerStaticInitb33f02c2794c19668c2dba8dd3d94f2c::$classMap; }, null, ClassLoader::class); } diff --git a/vendor/composer/index.php b/vendor/composer/index.php index df24d3e..fa24a5a 100644 --- a/vendor/composer/index.php +++ b/vendor/composer/index.php @@ -1,35 +1,22 @@ - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. */ -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); +\header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); +\header('Last-Modified: ' . \gmdate('D, d M Y H:i:s') . ' GMT'); + +\header('Cache-Control: no-store, no-cache, must-revalidate'); +\header('Cache-Control: post-check=0, pre-check=0', false); +\header('Pragma: no-cache'); -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); +\header('Location: ../'); -header("Location: ../"); exit; diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index a0ce88d..22b6364 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -1,105 +1,81 @@ [ { - "name": "mlocati/ip-lib", - "version": "1.9.0", - "version_normalized": "1.9.0.0", + "name": "dg/composer-cleaner", + "version": "v2.1", + "version_normalized": "2.1.0.0", "source": { "type": "git", - "url": "https://github.com/mlocati/ip-lib.git", - "reference": "b844659e3b87a461d1a8fe8e3e374aa6c4a5d902" + "url": "https://github.com/dg/composer-cleaner.git", + "reference": "91f865f0b50c66dd647955a0e5ba7745d8086945" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mlocati/ip-lib/zipball/b844659e3b87a461d1a8fe8e3e374aa6c4a5d902", - "reference": "b844659e3b87a461d1a8fe8e3e374aa6c4a5d902", + "url": "https://api.github.com/repos/dg/composer-cleaner/zipball/91f865f0b50c66dd647955a0e5ba7745d8086945", + "reference": "91f865f0b50c66dd647955a0e5ba7745d8086945", "shasum": "" }, "require": { - "php": ">=5.3.3" + "composer-plugin-api": "^1.0", + "php": ">=5.4.0" }, "require-dev": { - "ext-pdo_sqlite": "*", - "phpunit/dbunit": "^1.4 || ^2 || ^3 || ^4", - "phpunit/phpunit": "^4.8 || ^5.7 || ^6.5" + "nette/tester": "^1.7" + }, + "time": "2019-02-05T21:18:31+00:00", + "type": "composer-plugin", + "extra": { + "class": "DG\\ComposerCleaner\\Plugin" }, - "time": "2019-09-20T08:26:10+00:00", - "type": "library", "installation-source": "dist", "autoload": { - "psr-4": { - "IPLib\\": "src/" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Michele Locati", - "email": "mlocati@gmail.com", - "homepage": "https://github.com/mlocati", - "role": "Author" + "name": "David Grudl", + "homepage": "https://davidgrudl.com" } ], - "description": "Handle IPv4, IPv6 addresses and ranges", - "homepage": "https://github.com/mlocati/ip-lib", + "description": "Victor The Cleaner: removes unnecessary files from vendor directory.", "keywords": [ - "IP", - "address", - "addresses", - "ipv4", - "ipv6", - "matching", - "network", - "networking", - "range", - "subnet" + "composer" ] }, { - "name": "nelexa/zip", - "version": "3.3.1", - "version_normalized": "3.3.1.0", + "name": "mlocati/ip-lib", + "version": "1.13.0", + "version_normalized": "1.13.0.0", "source": { "type": "git", - "url": "https://github.com/Ne-Lexa/php-zip.git", - "reference": "52ce79d4d255cc1134863b3564feae8eb00a0991" + "url": "https://github.com/mlocati/ip-lib.git", + "reference": "334de586c7894afd838be44d73e72d8e97e5b0ff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Ne-Lexa/php-zip/zipball/52ce79d4d255cc1134863b3564feae8eb00a0991", - "reference": "52ce79d4d255cc1134863b3564feae8eb00a0991", + "url": "https://api.github.com/repos/mlocati/ip-lib/zipball/334de586c7894afd838be44d73e72d8e97e5b0ff", + "reference": "334de586c7894afd838be44d73e72d8e97e5b0ff", "shasum": "" }, "require": { - "ext-zlib": "*", - "paragonie/random_compat": "*", - "php": "^5.5.9 || ^7.0", - "psr/http-message": "^1.0", - "symfony/finder": "^3.0|^4.0|^5.0" + "php": ">=5.3.3" }, "require-dev": { - "ext-bz2": "*", - "ext-fileinfo": "*", - "ext-openssl": "*", - "ext-xml": "*", - "guzzlehttp/psr7": "^1.6", - "phpunit/phpunit": "^4.8|^5.7", - "symfony/var-dumper": "^3.0|^4.0|^5.0" - }, - "suggest": { - "ext-bz2": "Needed to support BZIP2 compression", - "ext-fileinfo": "Needed to get mime-type file", - "ext-mcrypt": "Needed to support encrypt zip entries or use ext-openssl", - "ext-openssl": "Needed to support encrypt zip entries or use ext-mcrypt" + "ext-pdo_sqlite": "*", + "phpunit/dbunit": "^1.4 || ^2 || ^3 || ^4", + "phpunit/phpunit": "^4.8 || ^5.7 || ^6.5" }, - "time": "2020-04-01T13:33:45+00:00", + "time": "2020-10-04T12:22:58+00:00", "type": "library", "installation-source": "dist", "autoload": { "psr-4": { - "PhpZip\\": "src/" + "IPLib\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -108,124 +84,37 @@ ], "authors": [ { - "name": "Ne-Lexa", - "email": "alexey@nelexa.ru", - "role": "Developer" + "name": "Michele Locati", + "email": "mlocati@gmail.com", + "homepage": "https://github.com/mlocati", + "role": "Author" } ], - "description": "PhpZip is a php-library for extended work with ZIP-archives. Open, create, update, delete, extract and get info tool. Supports appending to existing ZIP files, WinZip AES encryption, Traditional PKWARE Encryption, ZipAlign tool, BZIP2 compression, external file attributes and ZIP64 extensions. Alternative ZipArchive. It does not require php-zip extension.", - "homepage": "https://github.com/Ne-Lexa/php-zip", + "description": "Handle IPv4, IPv6 addresses and ranges", + "homepage": "https://github.com/mlocati/ip-lib", "keywords": [ - "archive", - "extract", - "unzip", - "winzip", - "zip", - "zipalign", - "ziparchive" - ] - }, - { - "name": "paragonie/random_compat", - "version": "v2.0.18", - "version_normalized": "2.0.18.0", - "source": { - "type": "git", - "url": "https://github.com/paragonie/random_compat.git", - "reference": "0a58ef6e3146256cc3dc7cc393927bcc7d1b72db" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/paragonie/random_compat/zipball/0a58ef6e3146256cc3dc7cc393927bcc7d1b72db", - "reference": "0a58ef6e3146256cc3dc7cc393927bcc7d1b72db", - "shasum": "" - }, - "require": { - "php": ">=5.2.0" - }, - "require-dev": { - "phpunit/phpunit": "4.*|5.*" - }, - "suggest": { - "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." - }, - "time": "2019-01-03T20:59:08+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "files": [ - "lib/random.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" + "IP", + "address", + "addresses", + "ipv4", + "ipv6", + "manage", + "managing", + "matching", + "network", + "networking", + "range", + "subnet" ], - "authors": [ + "funding": [ { - "name": "Paragon Initiative Enterprises", - "email": "security@paragonie.com", - "homepage": "https://paragonie.com" - } - ], - "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", - "keywords": [ - "csprng", - "polyfill", - "pseudorandom", - "random" - ] - }, - { - "name": "psr/http-message", - "version": "1.0.1", - "version_normalized": "1.0.1.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-message.git", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "time": "2016-08-06T14:39:51+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "Psr\\Http\\Message\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ + "url": "https://github.com/sponsors/mlocati", + "type": "github" + }, { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "url": "https://paypal.me/mlocati", + "type": "other" } - ], - "description": "Common interface for HTTP messages", - "homepage": "https://github.com/php-fig/http-message", - "keywords": [ - "http", - "http-message", - "psr", - "psr-7", - "request", - "response" ] }, { @@ -280,56 +169,5 @@ "php", "tfa" ] - }, - { - "name": "symfony/finder", - "version": "v3.4.40", - "version_normalized": "3.4.40.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/finder.git", - "reference": "5ec813ccafa8164ef21757e8c725d3a57da59200" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/5ec813ccafa8164ef21757e8c725d3a57da59200", - "reference": "5ec813ccafa8164ef21757e8c725d3a57da59200", - "shasum": "" - }, - "require": { - "php": "^5.5.9|>=7.0.8" - }, - "time": "2020-02-14T07:34:21+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.4-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "Symfony\\Component\\Finder\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony Finder Component", - "homepage": "https://symfony.com" } ] diff --git a/vendor/dg/composer-cleaner/index.php b/vendor/dg/composer-cleaner/index.php new file mode 100644 index 0000000..fa24a5a --- /dev/null +++ b/vendor/dg/composer-cleaner/index.php @@ -0,0 +1,22 @@ +io = $io; + $this->fileSystem = $fileSystem; + } + + + /** + * @return void + */ + public function clean($vendorDir, array $ignorePaths = []) + { + foreach (new FilesystemIterator($vendorDir) as $packageVendor) { + if (!$packageVendor->isDir()) { + continue; + } + foreach (new FilesystemIterator($packageVendor) as $packageName) { + if (!$packageName->isDir()) { + continue; + } + $name = $packageVendor->getFileName() . '/' . $packageName->getFileName(); + $ignore = isset($ignorePaths[$name]) ? $ignorePaths[$name] : null; + if ($ignore === true) { + $this->io->write("Composer cleaner: Skipped package $name", true, IOInterface::VERBOSE); + } else { + $this->io->write("Composer cleaner: Package $name", true, IOInterface::VERBOSE); + $this->processPackage((string) $packageName, (array) $ignore); + } + } + } + $this->io->write("Composer cleaner: Removed $this->removedCount files or directories."); + } + + + /** + * @return void + */ + private function processPackage($packageDir, array $ignoreFiles) + { + $data = $this->loadComposerJson($packageDir); + $type = isset($data->type) ? $data->type : null; + if (!$data || !in_array($type, self::$allowedComposerTypes, true)) { + return; + } + + foreach ($this->getExcludes($data) as $exclude) { + $dir = trim(ltrim($exclude, '.'), '/'); + if ($dir && strpos($dir, '..') === false && !self::matchMask($dir, $ignoreFiles)) { + $path = $packageDir . '/' . $dir; + $this->io->write("Composer cleaner: Removing $path", true, IOInterface::VERBOSE); + $this->fileSystem->remove($path); + $this->removedCount++; + } + } + + foreach ($this->getSources($data) as $source) { + $dir = strstr(ltrim(ltrim($source, '.'), '/') . '/', '/', true); + $ignoreFiles[] = $dir; + } + + if (!$ignoreFiles || self::matchMask('', $ignoreFiles)) { + return; + } + + $ignoreFiles = array_merge($ignoreFiles, self::$alwaysIgnore); + + foreach (new FilesystemIterator($packageDir) as $path) { + $fileName = $path->getFileName(); + if (!self::matchMask($fileName, $ignoreFiles)) { + $this->io->write("Composer cleaner: Removing $path", true, IOInterface::VERBOSE); + $this->fileSystem->remove($path); + $this->removedCount++; + } + } + } + + + /** + * @param string + * @param string[] + * @return bool + */ + public static function matchMask($fileName, array $patterns) + { + foreach ($patterns as $pattern) { + if (fnmatch($pattern, $fileName)) { + return true; + } + } + return false; + } + + + /** + * @return string[] + */ + private function getSources(stdClass $data) + { + if (empty($data->autoload)) { + return []; + } + + $sources = isset($data->bin) ? (array) $data->bin : []; + + foreach ($data->autoload as $type => $items) { + if ($type === 'psr-0') { + foreach ($items as $namespace => $paths) { + $namespace = strtr($namespace, '\\_', '//'); + foreach ((array) $paths as $path) { + $sources[] = rtrim($path, '\\/') . '/' . $namespace; + } + } + + } elseif ($type === 'psr-4') { + foreach ($items as $namespace => $paths) { + $sources = array_merge($sources, (array) $paths); + } + + } elseif ($type === 'classmap' || $type === 'files') { + $sources = array_merge($sources, (array) $items); + + } elseif ($type === 'exclude-from-classmap') { + // ignore + + } else { + $this->io->writeError("unknown autoload type $type"); + return []; + } + } + + return $sources; + } + + + /** + * @return string[] + */ + private function getExcludes(stdClass $data) + { + return empty($data->autoload->{'exclude-from-classmap'}) + ? [] + : (array) $data->autoload->{'exclude-from-classmap'}; + } + + + /** + * @return stdClass|null + */ + public function loadComposerJson($dir) + { + $file = $dir . '/composer.json'; + if (!is_file($file)) { + $this->io->writeError("Composer cleaner: File $file not found.", true, IOInterface::VERBOSE); + return; + } + $data = json_decode(file_get_contents($file)); + if (!$data instanceof stdClass) { + $this->io->writeError("Composer cleaner: Invalid $file."); + return; + } + return $data; + } +} diff --git a/vendor/dg/composer-cleaner/src/ComposerCleaner/Plugin.php b/vendor/dg/composer-cleaner/src/ComposerCleaner/Plugin.php new file mode 100644 index 0000000..1af85a1 --- /dev/null +++ b/vendor/dg/composer-cleaner/src/ComposerCleaner/Plugin.php @@ -0,0 +1,40 @@ + 'clean', + ScriptEvents::POST_INSTALL_CMD => 'clean', + ]; + } + + + public function clean(Event $event) + { + $vendorDir = $event->getComposer()->getConfig()->get('vendor-dir'); + $extra = $event->getComposer()->getPackage()->getExtra(); + $ignorePaths = isset($extra['cleaner-ignore']) ? $extra['cleaner-ignore'] : (array) $event->getComposer()->getConfig()->get('cleaner-ignore'); + $fileSystem = new Filesystem(new ProcessExecutor($event->getIO())); + $cleaner = new Cleaner($event->getIO(), $fileSystem); + $cleaner->clean($vendorDir, $ignorePaths); + } +} diff --git a/vendor/dg/composer-cleaner/src/ComposerCleaner/index.php b/vendor/dg/composer-cleaner/src/ComposerCleaner/index.php new file mode 100644 index 0000000..fa24a5a --- /dev/null +++ b/vendor/dg/composer-cleaner/src/ComposerCleaner/index.php @@ -0,0 +1,22 @@ + - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. */ -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); +\header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); +\header('Last-Modified: ' . \gmdate('D, d M Y H:i:s') . ' GMT'); + +\header('Cache-Control: no-store, no-cache, must-revalidate'); +\header('Cache-Control: post-check=0, pre-check=0', false); +\header('Pragma: no-cache'); -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); +\header('Location: ../'); -header("Location: ../"); exit; diff --git a/vendor/mlocati/index.php b/vendor/mlocati/index.php index df24d3e..fa24a5a 100644 --- a/vendor/mlocati/index.php +++ b/vendor/mlocati/index.php @@ -1,35 +1,22 @@ - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. */ -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); +\header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); +\header('Last-Modified: ' . \gmdate('D, d M Y H:i:s') . ' GMT'); + +\header('Cache-Control: no-store, no-cache, must-revalidate'); +\header('Cache-Control: post-check=0, pre-check=0', false); +\header('Pragma: no-cache'); -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); +\header('Location: ../'); -header("Location: ../"); exit; diff --git a/vendor/mlocati/ip-lib/README.md b/vendor/mlocati/ip-lib/README.md deleted file mode 100644 index 729cd4c..0000000 --- a/vendor/mlocati/ip-lib/README.md +++ /dev/null @@ -1,311 +0,0 @@ -[![TravisCI Build Status](https://api.travis-ci.org/mlocati/ip-lib.svg?branch=master)](https://travis-ci.org/mlocati/ip-lib) -[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/mlocati/ip-lib?branch=master&svg=true)](https://ci.appveyor.com/project/mlocati/ip-lib) -[![StyleCI Status](https://styleci.io/repos/54139375/shield)](https://styleci.io/repos/54139375) -[![Coverage Status](https://coveralls.io/repos/github/mlocati/ip-lib/badge.svg?branch=master)](https://coveralls.io/github/mlocati/ip-lib?branch=master) -[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/mlocati/ip-lib/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/mlocati/ip-lib/?branch=master) - -# IPLib - Handle IPv4, IPv6 and IP ranges - - -## Introduction - -This library can handle IPv4, IPv6 addresses, as well as IP ranges, in CIDR formats (like `::1/128` or `127.0.0.1/32`) and in pattern format (like `::*:*` or `127.0.*.*`). - - -## Requirements - -The only requirement is PHP 5.3.3. -__No external dependencies__ and __no special PHP configuration__ are needed (yes, it will __always work__ even if PHP has not been built with IPv6 support!). - - -## Manual installation - -[Download](https://github.com/mlocati/ip-lib/releases) the latest version, unzip it and add these lines in our PHP files: - -```php -require_once 'path/to/iplib/ip-lib.php'; -``` - - -## Installation with Composer - -Simply run `composer require mlocati/ip-lib`, or add these lines to your `composer.json` file: - -```json -"require": { - "mlocati/ip-lib": "1.*" -} -``` - - -## Sample usage - - -### Parse an address - -To parse an IPv4 address: - -```php -$address = \IPLib\Address\IPv4::fromString('127.0.0.1'); -``` - -To parse an IPv6 address: - -```php -$address = \IPLib\Address\IPv6::fromString('::1'); -``` - -To parse an address in any format (IPv4 or IPv6): - -```php -$address = \IPLib\Factory::addressFromString('::1'); -$address = \IPLib\Factory::addressFromString('127.0.0.1'); -``` - - -### Get the next/previous addresses - -```php -$address = \IPLib\Factory::addressFromString('::1'); -echo (string) $address->getPreviousAddress(); -// prints :: -echo (string) $address->getNextAddress(); -// prints ::2 -``` - - -### Parse an IP address range - -To parse a subnet (CIDR) range: - -```php -$range = \IPLib\Range\Subnet::fromString('127.0.0.1/24'); -$range = \IPLib\Range\Subnet::fromString('::1/128'); -``` - -To parse a pattern (asterisk notation) range: - -```php -$range = \IPLib\Range\Pattern::fromString('127.0.0.*'); -$range = \IPLib\Range\Pattern::fromString('::*'); -``` - -To parse an andress as a range: - -```php -$range = \IPLib\Range\Single::fromString('127.0.0.1'); -$range = \IPLib\Range\Single::fromString('::1'); -``` - -To parse a range in any format: - -```php -$range = \IPLib\Factory::rangeFromString('127.0.0.*'); -$range = \IPLib\Factory::rangeFromString('::1/128'); -$range = \IPLib\Factory::rangeFromString('::'); -``` - - -### Retrive a range from its boundaries - -```php -$range = \IPLib\Factory::rangeFromBoundaries('192.168.0.1', '192.168.255.255'); -echo (string) $range; -// prints 192.168.0.0/16 -``` - - -### Retrive the boundaries of a range - -```php -$range = \IPLib\Factory::rangeFromString('127.0.0.*'); -echo (string) $range->getStartAddress(); -// prints 127.0.0.0 -echo (string) $range->getEndAddress(); -// prints 127.0.0.255 -``` - - -### Format addresses and ranges - -Both IP addresses and ranges have a `toString` method that you can use to retrieve a textual representation: - -```php -echo \IPLib\Factory::addressFromString('127.0.0.1')->toString(); -// prints 127.0.0.1 -echo \IPLib\Factory::addressFromString('127.000.000.001')->toString(); -// prints 127.0.0.1 -echo \IPLib\Factory::addressFromString('::1')->toString(); -// prints ::1 -echo \IPLib\Factory::addressFromString('0:0::1')->toString(); -// prints ::1 -echo \IPLib\Factory::rangeFromString('0:0::1/64')->toString(); -// prints ::1/64 -``` - -When working with IPv6, you may want the full (expanded) representation of the addresses. In this case, simply use a `true` parameter for the `toString` method: - -```php -echo \IPLib\Factory::addressFromString('::')->toString(true); -// prints 0000:0000:0000:0000:0000:0000:0000:0000 -echo \IPLib\Factory::addressFromString('::1')->toString(true); -// prints 0000:0000:0000:0000:0000:0000:0000:0001 -echo \IPLib\Factory::addressFromString('fff::')->toString(true); -// prints 0fff:0000:0000:0000:0000:0000:0000:0000 -echo \IPLib\Factory::addressFromString('::0:0')->toString(true); -// prints 0000:0000:0000:0000:0000:0000:0000:0000 -echo \IPLib\Factory::addressFromString('1:2:3:4:5:6:7:8')->toString(true); -// prints 0001:0002:0003:0004:0005:0006:0007:0008 -echo \IPLib\Factory::rangeFromString('0:0::1/64')->toString(); -// prints 0000:0000:0000:0000:0000:0000:0000:0001/64 -``` - - -### Check if an address is contained in a range - -All the range types offer a `contains` method, and all the IP address types offer a `matches` method: you can call them to check if an address is contained in a range: - -```php -$address = \IPLib\Factory::addressFromString('1:2:3:4:5:6:7:8'); -$range = \IPLib\Factory::rangeFromString('0:0::1/64'); - -$contained = $address->matches($range); -// that's equivalent to -$contained = $range->contains($address); -``` - -Please remark that if the address is IPv4 and the range is IPv6 (or vice-versa), the result will always be `false`. - - -### Check if a range contains another range - -All the range types offer a `containsRange` method: you can call them to check if an address range fully contains another range: - -```php -$range1 = \IPLib\Factory::rangeFromString('0:0::1/64'); -$range2 = \IPLib\Factory::rangeFromString('0:0::1/65'); -$contained = $range1->containsRange($range2); -``` - - -### Getting the type of an IP address - -If you want to know if an address is within a private network, or if it's a public IP, or whatever you want, you can use the `getRangeType` method: - -```php -$address = \IPLib\Factory::addressFromString('::'); - -$typeID = $address->getRangeType(); - -$typeName = \IPLib\Range\Type::getName(); -``` - -The most notable values of the range type ID are: -- `\IPLib\Range\Type::T_UNSPECIFIED` if the address is all zeros (`0.0.0.0` or `::`) -- `\IPLib\Range\Type::T_LOOPBACK` if the address is the localhost (usually `127.0.0.1` or `::1`) -- `\IPLib\Range\Type::T_PRIVATENETWORK` if the address is in the local network (for instance `192.168.0.1` or `fc00::1`) -- `\IPLib\Range\Type::T_PUBLIC` if the address is for public usage (for instance `104.25.25.33` or `2001:503:ba3e::2:30`) - - -### Getting the type of an IP address range - -If you want to know the type of an address range, you can use the `getRangeType` method: - -```php -$range = \IPLib\Factory::rangeFromString('2000:0::1/64'); -$type = $range->getRangeType(); -// $type is \IPLib\Range\Type::T_PUBLIC -echo \IPLib\Range\Type::getName($type); -// 'Public address' -``` - -Please remark that if a range spans across multiple range types, you'll get NULL as the range type: - -```php -$range = \IPLib\Factory::rangeFromString('::/127'); -$type = $range->getRangeType(); -// $type is null -echo \IPLib\Range\Type::getName($type); -// 'Unknown type' -``` - -### Converting IP ranges - -This library supports IPv4/IPv6 ranges in pattern format (eg. `192.168.*.*`) and in CIDR/subnet format (eg. `192.168.0.0/16`), and it offers a way to convert between the two formats: - -```php -// This will print ::*:*:*:* -echo \IPLib\Factory::rangeFromString('::/64')->asPattern()->toString(); - -// This will print 1:2::/96 -echo \IPLib\Factory::rangeFromString('1:2::*:*')->asSubnet()->toString(); - -// This will print 192.168.0.0/24 -echo \IPLib\Factory::rangeFromString('192.168.0.*')->asSubnet()->toString(); - -// This will print 10.*.*.* -echo \IPLib\Factory::rangeFromString('10.0.0.0/8')->asPattern()->toString(); -``` - -### Getting the subnet mask for IPv4 ranges - -You can use the `getSubnetMask()` to get the subnet mask for IPv4 ranges: - -```php -// This will print 255.255.255.0 -echo \IPLib\Factory::rangeFromString('192.168.0.*')->getSubnetMask()->toString(); - -// This will print 255.255.255.252 -echo \IPLib\Factory::rangeFromString('192.168.0.12/30')->getSubnetMask()->toString(); -``` - -### Using a database - -This package offers a great feature: you can store address ranges in a database table, and check if an address is contained in one of the saved ranges with a simple query. - -To save a range, you need to store the address type (for IPv4 it's `4`, for IPv6 it's `6`), as well as two values representing the start and the end of the range. -These methods are: -```php -$range->getAddressType(); -$range->getComparableStartString(); -$range->getComparableEndString(); -``` - -Let's assume that you saved the type in a field called `addressType`, and the range boundaries in two fields called `rangeFrom` and `rangeTo`. - -When you want to check if an address is within a stored range, simply use the `getComparableString` method of the address and check if it's between the fields `rangeFrom` and `rangeTo`, and check if the stored `addressType` is the same as the one of the address instance you want to check. - -Here's a sample code: - -```php -/* - * Let's assume that: - * - $pdo is a PDO instance - * - $range is a range object - * - $address is an address object - */ - -// Save the $range object -$insertQuery = $pdo->prepare(' - insert into ranges (addressType, rangeFrom, rangeTo) - values (:addressType, :rangeFrom, :rangeTo) -'); -$insertQuery->execute(array( - ':addressType' => $range->getAddressType(), - ':rangeFrom' => $range->getComparableStartString(), - ':rangeTo' => $range->getComparableEndString(), -)); - -// Retrieve the saved ranges where an address $address falls: -$searchQuery = $pdo->prepare(' - select * from ranges - where addressType = :addressType - and :address between rangeFrom and rangeTo -'); -$searchQuery->execute(array( - ':addressType' => $address->getAddressType(), - ':address' => $address->getComparableString(), -)); -$rows = $searchQuery->fetchAll(); -$searchQuery->closeCursor(); -``` diff --git a/vendor/mlocati/ip-lib/composer.json b/vendor/mlocati/ip-lib/composer.json deleted file mode 100644 index 579147c..0000000 --- a/vendor/mlocati/ip-lib/composer.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "name": "mlocati/ip-lib", - "type": "library", - "description": "Handle IPv4, IPv6 addresses and ranges", - "keywords": [ - "ip", - "ipv4", - "ipv6", - "range", - "network", - "networking", - "address", - "addresses", - "subnet", - "matching" - ], - "homepage": "https://github.com/mlocati/ip-lib", - "license": "MIT", - "authors": [ - { - "name": "Michele Locati", - "homepage": "https://github.com/mlocati", - "email": "mlocati@gmail.com", - "role": "Author" - } - ], - "autoload": { - "psr-4": { - "IPLib\\": "src/" - } - }, - "require": { - "php": ">=5.3.3" - }, - "autoload-dev": { - "psr-4": { - "IPLib\\Test\\": "test/tests/" - } - }, - "require-dev": { - "ext-pdo_sqlite": "*", - "phpunit/phpunit": "^4.8 || ^5.7 || ^6.5", - "phpunit/dbunit": "^1.4 || ^2 || ^3 || ^4" - }, - "scripts": { - "test": "phpunit" - } -} diff --git a/vendor/mlocati/ip-lib/index.php b/vendor/mlocati/ip-lib/index.php index df24d3e..fa24a5a 100644 --- a/vendor/mlocati/ip-lib/index.php +++ b/vendor/mlocati/ip-lib/index.php @@ -1,35 +1,22 @@ - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. */ -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); +\header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); +\header('Last-Modified: ' . \gmdate('D, d M Y H:i:s') . ' GMT'); + +\header('Cache-Control: no-store, no-cache, must-revalidate'); +\header('Cache-Control: post-check=0, pre-check=0', false); +\header('Pragma: no-cache'); -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); +\header('Location: ../'); -header("Location: ../"); exit; diff --git a/vendor/mlocati/ip-lib/ip-lib.php b/vendor/mlocati/ip-lib/ip-lib.php deleted file mode 100644 index c1590ef..0000000 --- a/vendor/mlocati/ip-lib/ip-lib.php +++ /dev/null @@ -1,13 +0,0 @@ -comparableString = null; } + /** + * {@inheritdoc} + * + * @see \IPLib\Address\AddressInterface::__toString() + */ + public function __toString() + { + return $this->address; + } + /** * Parse a string and returns an IPv4 instance if the string is valid, or null otherwise. * * @param string|mixed $address the address to parse * @param bool $mayIncludePort set to false to avoid parsing addresses with ports + * @param bool $supportNonDecimalIPv4 set to true to support parsing non decimal (that is, octal and hexadecimal) IPv4 addresses * * @return static|null */ - public static function fromString($address, $mayIncludePort = true) + public static function fromString($address, $mayIncludePort = true, $supportNonDecimalIPv4 = false) { - $result = null; - if (is_string($address) && strpos($address, '.')) { - $rx = '([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})'; - if ($mayIncludePort) { - $rx .= '(?::\d+)?'; - } - $matches = null; - if (preg_match('/^'.$rx.'$/', $address, $matches)) { - $ok = true; - $nums = array(); - for ($i = 1; $ok && $i <= 4; ++$i) { - $ok = false; - $n = (int) $matches[$i]; - if ($n >= 0 && $n <= 255) { - $ok = true; - $nums[] = (string) $n; + if (!is_string($address) || !strpos($address, '.')) { + return null; + } + $rxChunk = '0?[0-9]{1,3}'; + if ($supportNonDecimalIPv4) { + $rxChunk = "(?:0[Xx]0*[0-9A-Fa-f]{1,2})|(?:{$rxChunk})"; + } + $rx = "0*?({$rxChunk})\.0*?({$rxChunk})\.0*?({$rxChunk})\.0*?({$rxChunk})"; + if ($mayIncludePort) { + $rx .= '(?::\d+)?'; + } + $matches = null; + if (!preg_match('/^' . $rx . '$/', $address, $matches)) { + return null; + } + $nums = array(); + for ($i = 1; $i <= 4; $i++) { + $s = $matches[$i]; + if ($supportNonDecimalIPv4) { + if (stripos($s, '0x') === 0) { + $n = hexdec(substr($s, 2)); + } elseif ($s[0] === '0') { + if (!preg_match('/^[0-7]+$/', $s)) { + return null; } + $n = octdec(substr($s, 1)); + } else { + $n = (int) $s; } - if ($ok) { - $result = new static(implode('.', $nums)); - } + } else { + $n = (int) $s; } + if ($n < 0 || $n > 255) { + return null; + } + $nums[] = (string) $n; } - return $result; + return new static(implode('.', $nums)); } /** @@ -138,13 +163,51 @@ public function toString($long = false) } /** - * {@inheritdoc} + * Get the octal representation of this IP address. * - * @see \IPLib\Address\AddressInterface::__toString() + * @param bool $long + * + * @return string + * + * @example if $long == false: if the decimal representation is '0.7.8.255': '0.7.010.0377' + * @example if $long == true: if the decimal representation is '0.7.8.255': '0000.0007.0010.0377' */ - public function __toString() + public function toOctal($long = false) { - return $this->address; + $chunks = array(); + foreach ($this->getBytes() as $byte) { + if ($long) { + $chunks[] = sprintf('%04o', $byte); + } else { + $chunks[] = '0' . decoct($byte); + } + } + + return implode('.', $chunks); + } + + /** + * Get the hexadecimal representation of this IP address. + * + * @param bool $long + * + * @return string + * + * @example if $long == false: if the decimal representation is '0.9.10.255': '0.9.0xa.0xff' + * @example if $long == true: if the decimal representation is '0.9.10.255': '0x00.0x09.0x0a.0xff' + */ + public function toHexadecimal($long = false) + { + $chunks = array(); + foreach ($this->getBytes() as $byte) { + if ($long) { + $chunks[] = sprintf('0x%02x', $byte); + } else { + $chunks[] = '0x' . dechex($byte); + } + } + + return implode('.', $chunks); } /** @@ -200,6 +263,8 @@ public static function getReservedRanges() '0.0.0.0/8' => array(RangeType::T_THISNETWORK, array('0.0.0.0/32' => RangeType::T_UNSPECIFIED)), // RFC 5735 '10.0.0.0/8' => array(RangeType::T_PRIVATENETWORK), + // RFC 6598 + '100.64.0.0/10' => array(RangeType::T_CGNAT), // RFC 5735 '127.0.0.0/8' => array(RangeType::T_LOOPBACK), // RFC 5735 @@ -261,7 +326,7 @@ public function getRangeType() } /** - * Create an IPv6 representation of this address. + * Create an IPv6 representation of this address (in 6to4 notation). * * @return \IPLib\Address\IPv6 */ @@ -269,7 +334,17 @@ public function toIPv6() { $myBytes = $this->getBytes(); - return IPv6::fromString('2002:'.sprintf('%02x', $myBytes[0]).sprintf('%02x', $myBytes[1]).':'.sprintf('%02x', $myBytes[2]).sprintf('%02x', $myBytes[3]).'::'); + return IPv6::fromString('2002:' . sprintf('%02x', $myBytes[0]) . sprintf('%02x', $myBytes[1]) . ':' . sprintf('%02x', $myBytes[2]) . sprintf('%02x', $myBytes[3]) . '::'); + } + + /** + * Create an IPv6 representation of this address (in IPv6 IPv4-mapped notation). + * + * @return \IPLib\Address\IPv6 + */ + public function toIPv6IPv4Mapped() + { + return IPv6::fromBytes(array_merge(array(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff), $this->getBytes())); } /** @@ -309,7 +384,7 @@ public function getNextAddress() { $overflow = false; $bytes = $this->getBytes(); - for ($i = count($bytes) - 1; $i >= 0; --$i) { + for ($i = count($bytes) - 1; $i >= 0; $i--) { if ($bytes[$i] === 255) { if ($i === 0) { $overflow = true; @@ -317,7 +392,7 @@ public function getNextAddress() } $bytes[$i] = 0; } else { - ++$bytes[$i]; + $bytes[$i]++; break; } } @@ -334,7 +409,7 @@ public function getPreviousAddress() { $overflow = false; $bytes = $this->getBytes(); - for ($i = count($bytes) - 1; $i >= 0; --$i) { + for ($i = count($bytes) - 1; $i >= 0; $i--) { if ($bytes[$i] === 0) { if ($i === 0) { $overflow = true; @@ -342,11 +417,24 @@ public function getPreviousAddress() } $bytes[$i] = 255; } else { - --$bytes[$i]; + $bytes[$i]--; break; } } return $overflow ? null : static::fromBytes($bytes); } + + /** + * {@inheritdoc} + * + * @see \IPLib\Address\AddressInterface::getReverseDNSLookupName() + */ + public function getReverseDNSLookupName() + { + return implode( + '.', + array_reverse($this->getBytes()) + ) . '.in-addr.arpa'; + } } diff --git a/vendor/mlocati/ip-lib/src/Address/IPv6.php b/vendor/mlocati/ip-lib/src/Address/IPv6.php index 170af8b..c133be0 100644 --- a/vendor/mlocati/ip-lib/src/Address/IPv6.php +++ b/vendor/mlocati/ip-lib/src/Address/IPv6.php @@ -71,6 +71,16 @@ public function __construct($longAddress) $this->rangeType = null; } + /** + * {@inheritdoc} + * + * @see \IPLib\Address\AddressInterface::__toString() + */ + public function __toString() + { + return $this->toString(); + } + /** * Parse a string and returns an IPv6 instance if the string is valid, or null otherwise. * @@ -85,7 +95,7 @@ public static function fromString($address, $mayIncludePort = true, $mayIncludeZ $result = null; if (is_string($address) && strpos($address, ':') !== false && strpos($address, ':::') === false) { $matches = null; - if ($mayIncludePort && $address[0] === '[' && preg_match('/^\[(.+)\]:\d+$/', $address, $matches)) { + if ($mayIncludePort && $address[0] === '[' && preg_match('/^\[(.+)]:\d+$/', $address, $matches)) { $address = $matches[1]; } if ($mayIncludeZoneID) { @@ -95,12 +105,12 @@ public static function fromString($address, $mayIncludePort = true, $mayIncludeZ } } if (preg_match('/^((?:[0-9a-f]*:+)+)(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/i', $address, $matches)) { - $address6 = static::fromString($matches[1].'0:0', false); + $address6 = static::fromString($matches[1] . '0:0', false); if ($address6 !== null) { $address4 = IPv4::fromString($matches[2], false); if ($address4 !== null) { $bytes4 = $address4->getBytes(); - $address6->longAddress = substr($address6->longAddress, 0, -9).sprintf('%02x%02x:%02x%02x', $bytes4[0], $bytes4[1], $bytes4[2], $bytes4[3]); + $address6->longAddress = substr($address6->longAddress, 0, -9) . sprintf('%02x%02x:%02x%02x', $bytes4[0], $bytes4[1], $bytes4[2], $bytes4[3]); $result = $address6; } } @@ -161,7 +171,7 @@ public static function fromBytes(array $bytes) $result = null; if (count($bytes) === 16) { $address = ''; - for ($i = 0; $i < 16; ++$i) { + for ($i = 0; $i < 16; $i++) { if ($i !== 0 && $i % 2 === 0) { $address .= ':'; } @@ -193,7 +203,7 @@ public static function fromWords(array $words) $result = null; if (count($words) === 8) { $chunks = array(); - for ($i = 0; $i < 8; ++$i) { + for ($i = 0; $i < 8; $i++) { $word = $words[$i]; if (is_int($word) && $word >= 0 && $word <= 0xffff) { $chunks[] = sprintf('%04x', $word); @@ -223,7 +233,7 @@ public function toString($long = false) if ($this->shortAddress === null) { if (strpos($this->longAddress, '0000:0000:0000:0000:0000:ffff:') === 0) { $lastBytes = array_slice($this->getBytes(), -4); - $this->shortAddress = '::ffff:'.implode('.', $lastBytes); + $this->shortAddress = '::ffff:' . implode('.', $lastBytes); } else { $chunks = array_map( function ($word) { @@ -233,10 +243,10 @@ function ($word) { ); $shortAddress = implode(':', $chunks); $matches = null; - for ($i = 8; $i > 1; --$i) { - $search = '(?:^|:)'.rtrim(str_repeat('0:', $i), ':').'(?:$|:)'; - if (preg_match('/^(.*?)'.$search.'(.*)$/', $shortAddress, $matches)) { - $shortAddress = $matches[1].'::'.$matches[2]; + for ($i = 8; $i > 1; $i--) { + $search = '(?:^|:)' . rtrim(str_repeat('0:', $i), ':') . '(?:$|:)'; + if (preg_match('/^(.*?)' . $search . '(.*)$/', $shortAddress, $matches)) { + $shortAddress = $matches[1] . '::' . $matches[2]; break; } } @@ -249,16 +259,6 @@ function ($word) { return $result; } - /** - * {@inheritdoc} - * - * @see \IPLib\Address\AddressInterface::__toString() - */ - public function __toString() - { - return $this->toString(); - } - /** * {@inheritdoc} * @@ -420,12 +420,16 @@ public function getRangeType() */ public function toIPv4() { - $result = null; if (strpos($this->longAddress, '2002:') === 0) { - $result = IPv4::fromBytes(array_slice($this->getBytes(), 2, 4)); + // 6to4 + return IPv4::fromBytes(array_slice($this->getBytes(), 2, 4)); + } + if (strpos($this->longAddress, '0000:0000:0000:0000:0000:ffff:') === 0) { + // IPv4-mapped IPv6 addresses + return IPv4::fromBytes(array_slice($this->getBytes(), -4)); } - return $result; + return null; } /** @@ -483,7 +487,7 @@ public function getNextAddress() { $overflow = false; $words = $this->getWords(); - for ($i = count($words) - 1; $i >= 0; --$i) { + for ($i = count($words) - 1; $i >= 0; $i--) { if ($words[$i] === 0xffff) { if ($i === 0) { $overflow = true; @@ -491,7 +495,7 @@ public function getNextAddress() } $words[$i] = 0; } else { - ++$words[$i]; + $words[$i]++; break; } } @@ -508,7 +512,7 @@ public function getPreviousAddress() { $overflow = false; $words = $this->getWords(); - for ($i = count($words) - 1; $i >= 0; --$i) { + for ($i = count($words) - 1; $i >= 0; $i--) { if ($words[$i] === 0) { if ($i === 0) { $overflow = true; @@ -516,11 +520,24 @@ public function getPreviousAddress() } $words[$i] = 0xffff; } else { - --$words[$i]; + $words[$i]--; break; } } return $overflow ? null : static::fromWords($words); } + + /** + * {@inheritdoc} + * + * @see \IPLib\Address\AddressInterface::getReverseDNSLookupName() + */ + public function getReverseDNSLookupName() + { + return implode( + '.', + array_reverse(str_split(str_replace(':', '', $this->toString(true)), 1)) + ) . '.ip6.arpa'; + } } diff --git a/vendor/mlocati/ip-lib/src/Address/index.php b/vendor/mlocati/ip-lib/src/Address/index.php index df24d3e..fa24a5a 100644 --- a/vendor/mlocati/ip-lib/src/Address/index.php +++ b/vendor/mlocati/ip-lib/src/Address/index.php @@ -1,35 +1,22 @@ - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. */ -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); +\header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); +\header('Last-Modified: ' . \gmdate('D, d M Y H:i:s') . ' GMT'); + +\header('Cache-Control: no-store, no-cache, must-revalidate'); +\header('Cache-Control: post-check=0, pre-check=0', false); +\header('Pragma: no-cache'); -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); +\header('Location: ../'); -header("Location: ../"); exit; diff --git a/vendor/mlocati/ip-lib/src/Factory.php b/vendor/mlocati/ip-lib/src/Factory.php index 9476559..2d981a5 100644 --- a/vendor/mlocati/ip-lib/src/Factory.php +++ b/vendor/mlocati/ip-lib/src/Factory.php @@ -15,14 +15,15 @@ class Factory * @param string $address the address to parse * @param bool $mayIncludePort set to false to avoid parsing addresses with ports * @param bool $mayIncludeZoneID set to false to avoid parsing IPv6 addresses with zone IDs (see RFC 4007) + * @param bool $supportNonDecimalIPv4 set to true to support parsing non decimal (that is, octal and hexadecimal) IPv4 addresses * * @return \IPLib\Address\AddressInterface|null */ - public static function addressFromString($address, $mayIncludePort = true, $mayIncludeZoneID = true) + public static function addressFromString($address, $mayIncludePort = true, $mayIncludeZoneID = true, $supportNonDecimalIPv4 = false) { $result = null; if ($result === null) { - $result = Address\IPv4::fromString($address, $mayIncludePort); + $result = Address\IPv4::fromString($address, $mayIncludePort, $supportNonDecimalIPv4); } if ($result === null) { $result = Address\IPv6::fromString($address, $mayIncludePort, $mayIncludeZoneID); @@ -55,20 +56,21 @@ public static function addressFromBytes(array $bytes) * Parse an IP range string. * * @param string $range + * @param bool $supportNonDecimalIPv4 set to true to support parsing non decimal (that is, octal and hexadecimal) IPv4 addresses * * @return \IPLib\Range\RangeInterface|null */ - public static function rangeFromString($range) + public static function rangeFromString($range, $supportNonDecimalIPv4 = false) { $result = null; if ($result === null) { - $result = Range\Subnet::fromString($range); + $result = Range\Subnet::fromString($range, $supportNonDecimalIPv4); } if ($result === null) { - $result = Range\Pattern::fromString($range); + $result = Range\Pattern::fromString($range, $supportNonDecimalIPv4); } if ($result === null) { - $result = Range\Single::fromString($range); + $result = Range\Single::fromString($range, $supportNonDecimalIPv4); } return $result; @@ -79,10 +81,11 @@ public static function rangeFromString($range) * * @param string|\IPLib\Address\AddressInterface $from * @param string|\IPLib\Address\AddressInterface $to + * @param bool $supportNonDecimalIPv4 set to true to support parsing non decimal (that is, octal and hexadecimal) IPv4 addresses * * @return \IPLib\Range\RangeInterface|null */ - public static function rangeFromBoundaries($from, $to) + public static function rangeFromBoundaries($from, $to, $supportNonDecimalIPv4 = false) { $result = null; $invalid = false; @@ -92,7 +95,7 @@ public static function rangeFromBoundaries($from, $to) if ($$param === '') { $$param = null; } else { - $$param = static::addressFromString($$param); + $$param = static::addressFromString($$param, true, true, $supportNonDecimalIPv4); if ($$param === null) { $invalid = true; } @@ -135,7 +138,7 @@ protected static function rangeFromBoundaryAddresses(AddressInterface $from = nu $toBytes = $to->getBytes(); $numBytes = count($fromBytes); $sameBits = 0; - for ($byteIndex = 0; $byteIndex < $numBytes; ++$byteIndex) { + for ($byteIndex = 0; $byteIndex < $numBytes; $byteIndex++) { $fromByte = $fromBytes[$byteIndex]; $toByte = $toBytes[$byteIndex]; if ($fromByte === $toByte) { @@ -146,7 +149,7 @@ protected static function rangeFromBoundaryAddresses(AddressInterface $from = nu break; } } - $result = static::rangeFromString($from->toString(true).'/'.(string) $sameBits); + $result = static::rangeFromString($from->toString(true) . '/' . (string) $sameBits); } } } diff --git a/vendor/mlocati/ip-lib/src/Range/AbstractRange.php b/vendor/mlocati/ip-lib/src/Range/AbstractRange.php new file mode 100644 index 0000000..1da94d0 --- /dev/null +++ b/vendor/mlocati/ip-lib/src/Range/AbstractRange.php @@ -0,0 +1,95 @@ +rangeType === null) { + $addressType = $this->getAddressType(); + if ($addressType === AddressType::T_IPv6 && Subnet::get6to4()->containsRange($this)) { + $this->rangeType = Factory::rangeFromBoundaries($this->fromAddress->toIPv4(), $this->toAddress->toIPv4())->getRangeType(); + } else { + switch ($addressType) { + case AddressType::T_IPv4: + $defaultType = IPv4::getDefaultReservedRangeType(); + $reservedRanges = IPv4::getReservedRanges(); + break; + case AddressType::T_IPv6: + $defaultType = IPv6::getDefaultReservedRangeType(); + $reservedRanges = IPv6::getReservedRanges(); + break; + default: + throw new \Exception('@todo'); // @codeCoverageIgnore + } + $rangeType = null; + foreach ($reservedRanges as $reservedRange) { + $rangeType = $reservedRange->getRangeType($this); + if ($rangeType !== null) { + break; + } + } + $this->rangeType = $rangeType === null ? $defaultType : $rangeType; + } + } + + return $this->rangeType === false ? null : $this->rangeType; + } + + /** + * {@inheritdoc} + * + * @see \IPLib\Range\RangeInterface::contains() + */ + public function contains(AddressInterface $address) + { + $result = false; + if ($address->getAddressType() === $this->getAddressType()) { + $cmp = $address->getComparableString(); + $from = $this->getComparableStartString(); + if ($cmp >= $from) { + $to = $this->getComparableEndString(); + if ($cmp <= $to) { + $result = true; + } + } + } + + return $result; + } + + /** + * {@inheritdoc} + * + * @see \IPLib\Range\RangeInterface::containsRange() + */ + public function containsRange(RangeInterface $range) + { + $result = false; + if ($range->getAddressType() === $this->getAddressType()) { + $myStart = $this->getComparableStartString(); + $itsStart = $range->getComparableStartString(); + if ($itsStart >= $myStart) { + $myEnd = $this->getComparableEndString(); + $itsEnd = $range->getComparableEndString(); + if ($itsEnd <= $myEnd) { + $result = true; + } + } + } + + return $result; + } +} diff --git a/vendor/mlocati/ip-lib/src/Range/Pattern.php b/vendor/mlocati/ip-lib/src/Range/Pattern.php index 32a7864..fc19d1e 100644 --- a/vendor/mlocati/ip-lib/src/Range/Pattern.php +++ b/vendor/mlocati/ip-lib/src/Range/Pattern.php @@ -6,7 +6,6 @@ use IPLib\Address\IPv4; use IPLib\Address\IPv6; use IPLib\Address\Type as AddressType; -use IPLib\Factory; /** * Represents an address range in pattern format (only ending asterisks are supported). @@ -14,7 +13,7 @@ * @example 127.0.*.* * @example ::/8 */ -class Pattern implements RangeInterface +class Pattern extends AbstractRange { /** * Starting address of the range. @@ -40,7 +39,7 @@ class Pattern implements RangeInterface /** * The type of the range of this IP range. * - * @var int|null|false false if this range crosses multiple range types, null if yet to be determined + * @var int|false|null false if this range crosses multiple range types, null if yet to be determined */ protected $rangeType; @@ -58,51 +57,69 @@ public function __construct(AddressInterface $fromAddress, AddressInterface $toA $this->asterisksCount = $asterisksCount; } + /** + * {@inheritdoc} + * + * @see \IPLib\Range\RangeInterface::__toString() + */ + public function __toString() + { + return $this->toString(); + } + /** * Try get the range instance starting from its string representation. * * @param string|mixed $range + * @param bool $supportNonDecimalIPv4 set to true to support parsing non decimal (that is, octal and hexadecimal) IPv4 addresses * * @return static|null */ - public static function fromString($range) + public static function fromString($range, $supportNonDecimalIPv4 = false) { - $result = null; - if (is_string($range) && strpos($range, '*') !== false) { - $matches = null; - if ($range === '*.*.*.*') { - $result = new static(IPv4::fromString('0.0.0.0'), IPv4::fromString('255.255.255.255'), 4); - } elseif (strpos($range, '.') !== false && preg_match('/^[^*]+((?:\.\*)+)$/', $range, $matches)) { - $asterisksCount = strlen($matches[1]) >> 1; - if ($asterisksCount > 0) { - $missingDots = 3 - substr_count($range, '.'); - if ($missingDots > 0) { - $range .= str_repeat('.*', $missingDots); - $asterisksCount += $missingDots; - } - } - $fromAddress = IPv4::fromString(str_replace('*', '0', $range)); - if ($fromAddress !== null) { - $fixedBytes = array_slice($fromAddress->getBytes(), 0, -$asterisksCount); - $otherBytes = array_fill(0, $asterisksCount, 255); - $toAddress = IPv4::fromBytes(array_merge($fixedBytes, $otherBytes)); - $result = new static($fromAddress, $toAddress, $asterisksCount); - } - } elseif ($range === '*:*:*:*:*:*:*:*') { - $result = new static(IPv6::fromString('::'), IPv6::fromString('ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff'), 8); - } elseif (strpos($range, ':') !== false && preg_match('/^[^*]+((?::\*)+)$/', $range, $matches)) { - $asterisksCount = strlen($matches[1]) >> 1; - $fromAddress = IPv6::fromString(str_replace('*', '0', $range)); - if ($fromAddress !== null) { - $fixedWords = array_slice($fromAddress->getWords(), 0, -$asterisksCount); - $otherWords = array_fill(0, $asterisksCount, 0xffff); - $toAddress = IPv6::fromWords(array_merge($fixedWords, $otherWords)); - $result = new static($fromAddress, $toAddress, $asterisksCount); + if (!is_string($range) || strpos($range, '*') === false) { + return null; + } + if ($range === '*.*.*.*') { + return new static(IPv4::fromString('0.0.0.0'), IPv4::fromString('255.255.255.255'), 4); + } + if ($range === '*:*:*:*:*:*:*:*') { + return new static(IPv6::fromString('::'), IPv6::fromString('ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff'), 8); + } + $matches = null; + if (strpos($range, '.') !== false && preg_match('/^[^*]+((?:\.\*)+)$/', $range, $matches)) { + $asterisksCount = strlen($matches[1]) >> 1; + if ($asterisksCount > 0) { + $missingDots = 3 - substr_count($range, '.'); + if ($missingDots > 0) { + $range .= str_repeat('.*', $missingDots); + $asterisksCount += $missingDots; } } + $fromAddress = IPv4::fromString(str_replace('*', '0', $range), true, $supportNonDecimalIPv4); + if ($fromAddress === null) { + return null; + } + $fixedBytes = array_slice($fromAddress->getBytes(), 0, -$asterisksCount); + $otherBytes = array_fill(0, $asterisksCount, 255); + $toAddress = IPv4::fromBytes(array_merge($fixedBytes, $otherBytes)); + + return new static($fromAddress, $toAddress, $asterisksCount); } + if (strpos($range, ':') !== false && preg_match('/^[^*]+((?::\*)+)$/', $range, $matches)) { + $asterisksCount = strlen($matches[1]) >> 1; + $fromAddress = IPv6::fromString(str_replace('*', '0', $range)); + if ($fromAddress === null) { + return null; + } + $fixedWords = array_slice($fromAddress->getWords(), 0, -$asterisksCount); + $otherWords = array_fill(0, $asterisksCount, 0xffff); + $toAddress = IPv6::fromWords(array_merge($fixedWords, $otherWords)); - return $result; + return new static($fromAddress, $toAddress, $asterisksCount); + } + + return null; } /** @@ -136,7 +153,7 @@ public function toString($long = false) $bytes = array_pad($bytes, 16, 1); $address = IPv6::fromBytes($bytes); $before = substr($address->toString(false), 0, -strlen(':101') * $this->asterisksCount); - $result = $before.str_repeat(':*', $this->asterisksCount); + $result = $before . str_repeat(':*', $this->asterisksCount); } break; default: @@ -146,16 +163,6 @@ public function toString($long = false) return $result; } - /** - * {@inheritdoc} - * - * @see \IPLib\Range\RangeInterface::__toString() - */ - public function __toString() - { - return $this->toString(); - } - /** * {@inheritdoc} * @@ -166,89 +173,6 @@ public function getAddressType() return $this->fromAddress->getAddressType(); } - /** - * {@inheritdoc} - * - * @see \IPLib\Range\RangeInterface::getRangeType() - */ - public function getRangeType() - { - if ($this->rangeType === null) { - $addressType = $this->getAddressType(); - if ($addressType === AddressType::T_IPv6 && Subnet::get6to4()->containsRange($this)) { - $this->rangeType = Factory::rangeFromBoundaries($this->fromAddress->toIPv4(), $this->toAddress->toIPv4())->getRangeType(); - } else { - switch ($addressType) { - case AddressType::T_IPv4: - $defaultType = IPv4::getDefaultReservedRangeType(); - $reservedRanges = IPv4::getReservedRanges(); - break; - case AddressType::T_IPv6: - $defaultType = IPv6::getDefaultReservedRangeType(); - $reservedRanges = IPv6::getReservedRanges(); - break; - default: - throw new \Exception('@todo'); // @codeCoverageIgnore - } - $rangeType = null; - foreach ($reservedRanges as $reservedRange) { - $rangeType = $reservedRange->getRangeType($this); - if ($rangeType !== null) { - break; - } - } - $this->rangeType = $rangeType === null ? $defaultType : $rangeType; - } - } - - return $this->rangeType === false ? null : $this->rangeType; - } - - /** - * {@inheritdoc} - * - * @see \IPLib\Range\RangeInterface::contains() - */ - public function contains(AddressInterface $address) - { - $result = false; - if ($address->getAddressType() === $this->getAddressType()) { - $cmp = $address->getComparableString(); - $from = $this->getComparableStartString(); - if ($cmp >= $from) { - $to = $this->getComparableEndString(); - if ($cmp <= $to) { - $result = true; - } - } - } - - return $result; - } - - /** - * {@inheritdoc} - * - * @see \IPLib\Range\RangeInterface::containsRange() - */ - public function containsRange(RangeInterface $range) - { - $result = false; - if ($range->getAddressType() === $this->getAddressType()) { - $myStart = $this->getComparableStartString(); - $itsStart = $range->getComparableStartString(); - if ($itsStart >= $myStart) { - $myEnd = $this->getComparableEndString(); - $itsEnd = $range->getComparableEndString(); - if ($itsEnd <= $myEnd) { - $result = true; - } - } - } - - return $result; - } - /** * {@inheritdoc} * @@ -290,9 +214,9 @@ public function getComparableEndString() } /** - * Get the subnet/CIDR representation of this range. + * {@inheritdoc} * - * @return \IPLib\Range\Subnet + * @see \IPLib\Range\RangeInterface::asSubnet() */ public function asSubnet() { @@ -304,6 +228,16 @@ public function asSubnet() } } + /** + * {@inheritdoc} + * + * @see \IPLib\Range\RangeInterface::asPattern() + */ + public function asPattern() + { + return $this; + } + /** * {@inheritdoc} * @@ -328,4 +262,14 @@ public function getSubnetMask() return IPv4::fromBytes($bytes); } + + /** + * {@inheritdoc} + * + * @see \IPLib\Range\RangeInterface::getReverseDNSLookupName() + */ + public function getReverseDNSLookupName() + { + return $this->asterisksCount === 0 ? array($this->getStartAddress()->getReverseDNSLookupName()) : $this->asSubnet()->getReverseDNSLookupName(); + } } diff --git a/vendor/mlocati/ip-lib/src/Range/RangeInterface.php b/vendor/mlocati/ip-lib/src/Range/RangeInterface.php index 1ddd9d6..468df3e 100644 --- a/vendor/mlocati/ip-lib/src/Range/RangeInterface.php +++ b/vendor/mlocati/ip-lib/src/Range/RangeInterface.php @@ -9,6 +9,13 @@ */ interface RangeInterface { + /** + * Get the short string representation of this address. + * + * @return string + */ + public function __toString(); + /** * Get the string representation of this address. * @@ -20,13 +27,6 @@ interface RangeInterface */ public function toString($long = false); - /** - * Get the short string representation of this address. - * - * @return string - */ - public function __toString(); - /** * Get the type of the IP addresses contained in this range. * @@ -93,4 +93,28 @@ public function getComparableEndString(); * @return \IPLib\Address\IPv4|null return NULL if the range is an IPv6 range, the subnet mask otherwise */ public function getSubnetMask(); + + /** + * Get the subnet/CIDR representation of this range. + * + * @return \IPLib\Range\Subnet + */ + public function asSubnet(); + + /** + * Get the pattern/asterisk representation (if applicable) of this range. + * + * @return \IPLib\Range\Pattern|null return NULL if this range can't be represented by a pattern notation + */ + public function asPattern(); + + /** + * Get the Reverse DNS Lookup Addresses of this IP range. + * + * @return string[] + * + * @example for IPv4 it returns something like array('x.x.x.x.in-addr.arpa', 'x.x.x.x.in-addr.arpa') (where the number of 'x.' ranges from 1 to 4) + * @example for IPv6 it returns something like array('x.x.x.x..x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.ip6.arpa', 'x.x.x.x..x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.ip6.arpa') (where the number of 'x.' ranges from 1 to 32) + */ + public function getReverseDNSLookupName(); } diff --git a/vendor/mlocati/ip-lib/src/Range/Single.php b/vendor/mlocati/ip-lib/src/Range/Single.php index 5bbd437..6f08850 100644 --- a/vendor/mlocati/ip-lib/src/Range/Single.php +++ b/vendor/mlocati/ip-lib/src/Range/Single.php @@ -13,7 +13,7 @@ * @example 127.0.0.1 * @example ::1 */ -class Single implements RangeInterface +class Single extends AbstractRange { /** * @var \IPLib\Address\AddressInterface @@ -30,17 +30,28 @@ protected function __construct(AddressInterface $address) $this->address = $address; } + /** + * {@inheritdoc} + * + * @see \IPLib\Range\RangeInterface::__toString() + */ + public function __toString() + { + return $this->address->__toString(); + } + /** * Try get the range instance starting from its string representation. * * @param string|mixed $range + * @param bool $supportNonDecimalIPv4 set to true to support parsing non decimal (that is, octal and hexadecimal) IPv4 addresses * * @return static|null */ - public static function fromString($range) + public static function fromString($range, $supportNonDecimalIPv4 = false) { $result = null; - $address = Factory::addressFromString($range); + $address = Factory::addressFromString($range, true, true, $supportNonDecimalIPv4); if ($address !== null) { $result = new static($address); } @@ -70,16 +81,6 @@ public function toString($long = false) return $this->address->toString($long); } - /** - * {@inheritdoc} - * - * @see \IPLib\Range\RangeInterface::__toString() - */ - public function __toString() - { - return $this->address->__toString(); - } - /** * {@inheritdoc} * @@ -174,6 +175,31 @@ public function getComparableEndString() return $this->address->getComparableString(); } + /** + * {@inheritdoc} + * + * @see \IPLib\Range\RangeInterface::asSubnet() + */ + public function asSubnet() + { + $networkPrefixes = array( + AddressType::T_IPv4 => 32, + AddressType::T_IPv6 => 128, + ); + + return new Subnet($this->address, $this->address, $networkPrefixes[$this->address->getAddressType()]); + } + + /** + * {@inheritdoc} + * + * @see \IPLib\Range\RangeInterface::asPattern() + */ + public function asPattern() + { + return new Pattern($this->address, $this->address, 0); + } + /** * {@inheritdoc} * @@ -187,4 +213,14 @@ public function getSubnetMask() return IPv4::fromBytes(array(255, 255, 255, 255)); } + + /** + * {@inheritdoc} + * + * @see \IPLib\Range\RangeInterface::getReverseDNSLookupName() + */ + public function getReverseDNSLookupName() + { + return array($this->getStartAddress()->getReverseDNSLookupName()); + } } diff --git a/vendor/mlocati/ip-lib/src/Range/Subnet.php b/vendor/mlocati/ip-lib/src/Range/Subnet.php index 6f4aebd..2ce166b 100644 --- a/vendor/mlocati/ip-lib/src/Range/Subnet.php +++ b/vendor/mlocati/ip-lib/src/Range/Subnet.php @@ -14,7 +14,7 @@ * @example 127.0.0.1/32 * @example ::/8 */ -class Subnet implements RangeInterface +class Subnet extends AbstractRange { /** * Starting address of the range. @@ -67,63 +67,6 @@ public function __construct(AddressInterface $fromAddress, AddressInterface $toA $this->networkPrefix = $networkPrefix; } - /** - * Try get the range instance starting from its string representation. - * - * @param string|mixed $range - * - * @return static|null - */ - public static function fromString($range) - { - $result = null; - if (is_string($range)) { - $parts = explode('/', $range); - if (count($parts) === 2) { - $address = Factory::addressFromString($parts[0]); - if ($address !== null) { - if (preg_match('/^[0-9]{1,9}$/', $parts[1])) { - $networkPrefix = (int) $parts[1]; - if ($networkPrefix >= 0) { - $addressBytes = $address->getBytes(); - $totalBytes = count($addressBytes); - $numDifferentBits = $totalBytes * 8 - $networkPrefix; - if ($numDifferentBits >= 0) { - $numSameBytes = $networkPrefix >> 3; - $sameBytes = array_slice($addressBytes, 0, $numSameBytes); - $differentBytesStart = ($totalBytes === $numSameBytes) ? array() : array_fill(0, $totalBytes - $numSameBytes, 0); - $differentBytesEnd = ($totalBytes === $numSameBytes) ? array() : array_fill(0, $totalBytes - $numSameBytes, 255); - $startSameBits = $networkPrefix % 8; - if ($startSameBits !== 0) { - $varyingByte = $addressBytes[$numSameBytes]; - $differentBytesStart[0] = $varyingByte & bindec(str_pad(str_repeat('1', $startSameBits), 8, '0', STR_PAD_RIGHT)); - $differentBytesEnd[0] = $differentBytesStart[0] + bindec(str_repeat('1', 8 - $startSameBits)); - } - $result = new static( - Factory::addressFromBytes(array_merge($sameBytes, $differentBytesStart)), - Factory::addressFromBytes(array_merge($sameBytes, $differentBytesEnd)), - $networkPrefix - ); - } - } - } - } - } - } - - return $result; - } - - /** - * {@inheritdoc} - * - * @see \IPLib\Range\RangeInterface::toString() - */ - public function toString($long = false) - { - return $this->fromAddress->toString($long).'/'.$this->networkPrefix; - } - /** * {@inheritdoc} * @@ -135,96 +78,72 @@ public function __toString() } /** - * {@inheritdoc} + * Try get the range instance starting from its string representation. * - * @see \IPLib\Range\RangeInterface::getAddressType() - */ - public function getAddressType() - { - return $this->fromAddress->getAddressType(); - } - - /** - * {@inheritdoc} + * @param string|mixed $range + * @param bool $supportNonDecimalIPv4 set to true to support parsing non decimal (that is, octal and hexadecimal) IPv4 addresses * - * @see \IPLib\Range\RangeInterface::getRangeType() + * @return static|null */ - public function getRangeType() + public static function fromString($range, $supportNonDecimalIPv4 = false) { - if ($this->rangeType === null) { - $addressType = $this->getAddressType(); - if ($addressType === AddressType::T_IPv6 && static::get6to4()->containsRange($this)) { - $this->rangeType = Factory::rangeFromBoundaries($this->fromAddress->toIPv4(), $this->toAddress->toIPv4())->getRangeType(); - } else { - switch ($addressType) { - case AddressType::T_IPv4: - $defaultType = IPv4::getDefaultReservedRangeType(); - $reservedRanges = IPv4::getReservedRanges(); - break; - case AddressType::T_IPv6: - $defaultType = IPv6::getDefaultReservedRangeType(); - $reservedRanges = IPv6::getReservedRanges(); - break; - default: - throw new \Exception('@todo'); // @codeCoverageIgnore - } - $rangeType = null; - foreach ($reservedRanges as $reservedRange) { - $rangeType = $reservedRange->getRangeType($this); - if ($rangeType !== null) { - break; - } - } - $this->rangeType = $rangeType === null ? $defaultType : $rangeType; - } + if (!is_string($range)) { + return null; + } + $parts = explode('/', $range); + if (count($parts) !== 2) { + return null; + } + $address = Factory::addressFromString($parts[0], true, true, $supportNonDecimalIPv4); + if ($address === null) { + return null; + } + if (!preg_match('/^[0-9]{1,9}$/', $parts[1])) { + return null; + } + $networkPrefix = (int) $parts[1]; + $addressBytes = $address->getBytes(); + $totalBytes = count($addressBytes); + $numDifferentBits = $totalBytes * 8 - $networkPrefix; + if ($numDifferentBits < 0) { + return null; + } + $numSameBytes = $networkPrefix >> 3; + $sameBytes = array_slice($addressBytes, 0, $numSameBytes); + $differentBytesStart = ($totalBytes === $numSameBytes) ? array() : array_fill(0, $totalBytes - $numSameBytes, 0); + $differentBytesEnd = ($totalBytes === $numSameBytes) ? array() : array_fill(0, $totalBytes - $numSameBytes, 255); + $startSameBits = $networkPrefix % 8; + if ($startSameBits !== 0) { + $varyingByte = $addressBytes[$numSameBytes]; + $differentBytesStart[0] = $varyingByte & bindec(str_pad(str_repeat('1', $startSameBits), 8, '0', STR_PAD_RIGHT)); + $differentBytesEnd[0] = $differentBytesStart[0] + bindec(str_repeat('1', 8 - $startSameBits)); } - return $this->rangeType === false ? null : $this->rangeType; + return new static( + Factory::addressFromBytes(array_merge($sameBytes, $differentBytesStart)), + Factory::addressFromBytes(array_merge($sameBytes, $differentBytesEnd)), + $networkPrefix + ); } /** * {@inheritdoc} * - * @see \IPLib\Range\RangeInterface::contains() + * @see \IPLib\Range\RangeInterface::toString() */ - public function contains(AddressInterface $address) + public function toString($long = false) { - $result = false; - if ($address->getAddressType() === $this->getAddressType()) { - $cmp = $address->getComparableString(); - $from = $this->getComparableStartString(); - if ($cmp >= $from) { - $to = $this->getComparableEndString(); - if ($cmp <= $to) { - $result = true; - } - } - } - - return $result; + return $this->fromAddress->toString($long) . '/' . $this->networkPrefix; } /** * {@inheritdoc} * - * @see \IPLib\Range\RangeInterface::containsRange() + * @see \IPLib\Range\RangeInterface::getAddressType() */ - public function containsRange(RangeInterface $range) + public function getAddressType() { - $result = false; - if ($range->getAddressType() === $this->getAddressType()) { - $myStart = $this->getComparableStartString(); - $itsStart = $range->getComparableStartString(); - if ($itsStart >= $myStart) { - $myEnd = $this->getComparableEndString(); - $itsEnd = $range->getComparableEndString(); - if ($itsEnd <= $myEnd) { - $result = true; - } - } - } - - return $result; + return $this->fromAddress->getAddressType(); } /** @@ -267,6 +186,33 @@ public function getComparableEndString() return $this->toAddress->getComparableString(); } + /** + * {@inheritdoc} + * + * @see \IPLib\Range\RangeInterface::asSubnet() + */ + public function asSubnet() + { + return $this; + } + + /** + * Get the pattern (asterisk) representation (if applicable) of this range. + * + * @return \IPLib\Range\Pattern|null return NULL if this range can't be represented by a pattern notation + */ + public function asPattern() + { + $address = $this->getStartAddress(); + $networkPrefix = $this->getNetworkPrefix(); + switch ($address->getAddressType()) { + case AddressType::T_IPv4: + return $networkPrefix % 8 === 0 ? new Pattern($address, $address, 4 - $networkPrefix / 8) : null; + case AddressType::T_IPv6: + return $networkPrefix % 16 === 0 ? new Pattern($address, $address, 8 - $networkPrefix / 16) : null; + } + } + /** * Get the 6to4 address IPv6 address range. * @@ -291,23 +237,6 @@ public function getNetworkPrefix() return $this->networkPrefix; } - /** - * Get the pattern representation (if applicable) of this range. - * - * @return \IPLib\Range\Pattern|null return NULL if this range can't be represented by a pattern notation - */ - public function asPattern() - { - $address = $this->getStartAddress(); - $networkPrefix = $this->getNetworkPrefix(); - switch ($address->getAddressType()) { - case AddressType::T_IPv4: - return $networkPrefix % 8 === 0 ? new Pattern($address, $address, 4 - $networkPrefix / 8) : null; - case AddressType::T_IPv6: - return $networkPrefix % 16 === 0 ? new Pattern($address, $address, 8 - $networkPrefix / 16) : null; - } - } - /** * {@inheritdoc} * @@ -331,4 +260,46 @@ public function getSubnetMask() return IPv4::fromBytes($bytes); } + + /** + * {@inheritdoc} + * + * @see \IPLib\Range\RangeInterface::getReverseDNSLookupName() + */ + public function getReverseDNSLookupName() + { + switch ($this->getAddressType()) { + case AddressType::T_IPv4: + $unitSize = 8; // bytes + $maxUnits = 4; + $isHex = false; + $rxUnit = '\d+'; + break; + case AddressType::T_IPv6: + $unitSize = 4; // nibbles + $maxUnits = 32; + $isHex = true; + $rxUnit = '[0-9A-Fa-f]'; + break; + } + $totBits = $unitSize * $maxUnits; + $prefixUnits = (int) ($this->networkPrefix / $unitSize); + $extraBits = ($totBits - $this->networkPrefix) % $unitSize; + if ($extraBits !== 0) { + $prefixUnits += 1; + } + $numVariants = 1 << $extraBits; + $result = array(); + $unitsToRemove = $maxUnits - $prefixUnits; + $initialPointer = preg_replace("/^(({$rxUnit})\.){{$unitsToRemove}}/", '', $this->getStartAddress()->getReverseDNSLookupName()); + $chunks = explode('.', $initialPointer, 2); + for ($index = 0; $index < $numVariants; $index++) { + if ($index !== 0) { + $chunks[0] = $isHex ? dechex(1 + hexdec($chunks[0])) : (string) (1 + (int) $chunks[0]); + } + $result[] = implode('.', $chunks); + } + + return $result; + } } diff --git a/vendor/mlocati/ip-lib/src/Range/Type.php b/vendor/mlocati/ip-lib/src/Range/Type.php index 503178b..cfc268b 100644 --- a/vendor/mlocati/ip-lib/src/Range/Type.php +++ b/vendor/mlocati/ip-lib/src/Range/Type.php @@ -98,6 +98,13 @@ class Type */ const T_PUBLIC = 13; + /** + * Carrier-grade NAT address. + * + * @var int + */ + const T_CGNAT = 14; + /** * Get the name of a type. * @@ -134,6 +141,8 @@ public static function getName($type) return 'For use in private networks'; case static::T_PUBLIC: return 'Public address'; + case static::T_CGNAT: + return 'Carrier-grade NAT'; default: return $type === null ? 'Unknown type' : sprintf('Unknown type (%s)', $type); } diff --git a/vendor/mlocati/ip-lib/src/Range/index.php b/vendor/mlocati/ip-lib/src/Range/index.php index df24d3e..fa24a5a 100644 --- a/vendor/mlocati/ip-lib/src/Range/index.php +++ b/vendor/mlocati/ip-lib/src/Range/index.php @@ -1,35 +1,22 @@ - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. */ -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); +\header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); +\header('Last-Modified: ' . \gmdate('D, d M Y H:i:s') . ' GMT'); + +\header('Cache-Control: no-store, no-cache, must-revalidate'); +\header('Cache-Control: post-check=0, pre-check=0', false); +\header('Pragma: no-cache'); -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); +\header('Location: ../'); -header("Location: ../"); exit; diff --git a/vendor/mlocati/ip-lib/src/index.php b/vendor/mlocati/ip-lib/src/index.php index df24d3e..fa24a5a 100644 --- a/vendor/mlocati/ip-lib/src/index.php +++ b/vendor/mlocati/ip-lib/src/index.php @@ -1,35 +1,22 @@ - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. */ -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); +\header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); +\header('Last-Modified: ' . \gmdate('D, d M Y H:i:s') . ' GMT'); + +\header('Cache-Control: no-store, no-cache, must-revalidate'); +\header('Cache-Control: post-check=0, pre-check=0', false); +\header('Pragma: no-cache'); -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); +\header('Location: ../'); -header("Location: ../"); exit; diff --git a/vendor/nelexa/index.php b/vendor/nelexa/index.php deleted file mode 100644 index df24d3e..0000000 --- a/vendor/nelexa/index.php +++ /dev/null @@ -1,35 +0,0 @@ - - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA - */ - -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); - -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); - -header("Location: ../"); -exit; diff --git a/vendor/nelexa/zip/composer.json b/vendor/nelexa/zip/composer.json deleted file mode 100644 index b1b5927..0000000 --- a/vendor/nelexa/zip/composer.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "name": "nelexa/zip", - "type": "library", - "description": "PhpZip is a php-library for extended work with ZIP-archives. Open, create, update, delete, extract and get info tool. Supports appending to existing ZIP files, WinZip AES encryption, Traditional PKWARE Encryption, ZipAlign tool, BZIP2 compression, external file attributes and ZIP64 extensions. Alternative ZipArchive. It does not require php-zip extension.", - "keywords": [ - "zip", - "unzip", - "archive", - "extract", - "winzip", - "zipalign", - "ziparchive" - ], - "homepage": "https://github.com/Ne-Lexa/php-zip", - "license": "MIT", - "authors": [ - { - "name": "Ne-Lexa", - "email": "alexey@nelexa.ru", - "role": "Developer" - } - ], - "require": { - "php": "^5.5.9 || ^7.0", - "ext-zlib": "*", - "psr/http-message": "^1.0", - "paragonie/random_compat": "*", - "symfony/finder": "^3.0|^4.0|^5.0" - }, - "require-dev": { - "ext-bz2": "*", - "ext-openssl": "*", - "ext-fileinfo": "*", - "ext-xml": "*", - "guzzlehttp/psr7": "^1.6", - "phpunit/phpunit": "^4.8|^5.7", - "symfony/var-dumper": "^3.0|^4.0|^5.0" - }, - "autoload": { - "psr-4": { - "PhpZip\\": "src/" - } - }, - "autoload-dev": { - "psr-4": { - "PhpZip\\Tests\\": "tests/" - } - }, - "suggest": { - "ext-openssl": "Needed to support encrypt zip entries or use ext-mcrypt", - "ext-mcrypt": "Needed to support encrypt zip entries or use ext-openssl", - "ext-bz2": "Needed to support BZIP2 compression", - "ext-fileinfo": "Needed to get mime-type file" - }, - "minimum-stability": "stable", - "scripts": { - "php:fix": "php .php_cs --force", - "php:fix:debug": "php .php_cs" - } -} diff --git a/vendor/nelexa/zip/index.php b/vendor/nelexa/zip/index.php deleted file mode 100644 index df24d3e..0000000 --- a/vendor/nelexa/zip/index.php +++ /dev/null @@ -1,35 +0,0 @@ - - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA - */ - -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); - -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); - -header("Location: ../"); -exit; diff --git a/vendor/nelexa/zip/src/Constants/DosAttrs.php b/vendor/nelexa/zip/src/Constants/DosAttrs.php deleted file mode 100644 index 5bebe65..0000000 --- a/vendor/nelexa/zip/src/Constants/DosAttrs.php +++ /dev/null @@ -1,33 +0,0 @@ - 'Stored', - 1 => 'Shrunk', - 2 => 'Reduced compression factor 1', - 3 => 'Reduced compression factor 2', - 4 => 'Reduced compression factor 3', - 5 => 'Reduced compression factor 4', - 6 => 'Imploded', - 7 => 'Reserved for Tokenizing compression algorithm', - self::DEFLATED => 'Deflated', - 9 => 'Enhanced Deflating using Deflate64(tm)', - 10 => 'PKWARE Data Compression Library Imploding', - 11 => 'Reserved by PKWARE', - self::BZIP2 => 'BZIP2', - 13 => 'Reserved by PKWARE', - 14 => 'LZMA', - 15 => 'Reserved by PKWARE', - 16 => 'Reserved by PKWARE', - 17 => 'Reserved by PKWARE', - 18 => 'File is compressed using IBM TERSE (new)', - 19 => 'IBM LZ77 z Architecture (PFS)', - 96 => 'WinZip JPEG Compression', - 97 => 'WavPack compressed data', - 98 => 'PPMd version I, Rev 1', - self::WINZIP_AES => 'AES Encryption', - ]; - - /** - * @param int $value - * - * @return string - */ - public static function getCompressionMethodName($value) - { - return isset(self::$ZIP_COMPRESSION_METHODS[$value]) ? - self::$ZIP_COMPRESSION_METHODS[$value] : - 'Unknown Method'; - } - - /** - * @return int[] - */ - public static function getSupportMethods() - { - static $methods; - - if ($methods === null) { - $methods = [ - self::STORED, - self::DEFLATED, - ]; - - if (\extension_loaded('bz2')) { - $methods[] = self::BZIP2; - } - } - - return $methods; - } - - /** - * @param int $compressionMethod - * - * @throws ZipUnsupportMethodException - */ - public static function checkSupport($compressionMethod) - { - $compressionMethod = (int) $compressionMethod; - - if (!\in_array($compressionMethod, self::getSupportMethods(), true)) { - throw new ZipUnsupportMethodException(sprintf( - 'Compression method %d (%s) is not supported.', - $compressionMethod, - self::getCompressionMethodName($compressionMethod) - )); - } - } -} diff --git a/vendor/nelexa/zip/src/Constants/ZipConstants.php b/vendor/nelexa/zip/src/Constants/ZipConstants.php deleted file mode 100644 index 39fca0f..0000000 --- a/vendor/nelexa/zip/src/Constants/ZipConstants.php +++ /dev/null @@ -1,99 +0,0 @@ - */ - private static $ENCRYPTION_METHODS = [ - self::NONE => 'no encryption', - self::PKWARE => 'Traditional PKWARE encryption', - self::WINZIP_AES_128 => 'WinZip AES-128', - self::WINZIP_AES_192 => 'WinZip AES-192', - self::WINZIP_AES_256 => 'WinZip AES-256', - ]; - - /** - * @param int $value - * - * @return string - */ - public static function getEncryptionMethodName($value) - { - $value = (int) $value; - - return isset(self::$ENCRYPTION_METHODS[$value]) ? - self::$ENCRYPTION_METHODS[$value] : - 'Unknown Encryption Method'; - } - - /** - * @param int $encryptionMethod - * - * @return bool - */ - public static function hasEncryptionMethod($encryptionMethod) - { - return isset(self::$ENCRYPTION_METHODS[$encryptionMethod]); - } - - /** - * @param int $encryptionMethod - * - * @return bool - */ - public static function isWinZipAesMethod($encryptionMethod) - { - return \in_array( - (int) $encryptionMethod, - [ - self::WINZIP_AES_256, - self::WINZIP_AES_192, - self::WINZIP_AES_128, - ], - true - ); - } - - /** - * @param int $encryptionMethod - * - * @throws InvalidArgumentException - */ - public static function checkSupport($encryptionMethod) - { - $encryptionMethod = (int) $encryptionMethod; - - if (!self::hasEncryptionMethod($encryptionMethod)) { - throw new InvalidArgumentException(sprintf( - 'Encryption method %d is not supported.', - $encryptionMethod - )); - } - } -} diff --git a/vendor/nelexa/zip/src/Constants/ZipOptions.php b/vendor/nelexa/zip/src/Constants/ZipOptions.php deleted file mode 100644 index c5d9671..0000000 --- a/vendor/nelexa/zip/src/Constants/ZipOptions.php +++ /dev/null @@ -1,62 +0,0 @@ - 'MS-DOS', - 1 => 'Amiga', - 2 => 'OpenVMS', - self::OS_UNIX => 'Unix', - 4 => 'VM/CMS', - 5 => 'Atari ST', - 6 => 'HPFS (OS/2, NT 3.x)', - 7 => 'Macintosh', - 8 => 'Z-System', - 9 => 'CP/M', - 10 => 'Windows NTFS or TOPS-20', - 11 => 'MVS or NTFS', - 12 => 'VSE or SMS/QDOS', - 13 => 'Acorn RISC OS', - 14 => 'VFAT', - 15 => 'alternate MVS', - 16 => 'BeOS', - 17 => 'Tandem', - 18 => 'OS/400', - self::OS_MAC_OSX => 'OS/X (Darwin)', - 30 => 'AtheOS/Syllable', - ]; - - /** - * @param int $platform - * - * @return string - */ - public static function getPlatformName($platform) - { - return isset(self::$platforms[$platform]) ? self::$platforms[$platform] : 'Unknown'; - } -} diff --git a/vendor/nelexa/zip/src/Constants/ZipVersion.php b/vendor/nelexa/zip/src/Constants/ZipVersion.php deleted file mode 100644 index 58c090d..0000000 --- a/vendor/nelexa/zip/src/Constants/ZipVersion.php +++ /dev/null @@ -1,81 +0,0 @@ - - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA - */ - -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); - -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); - -header("Location: ../"); -exit; diff --git a/vendor/nelexa/zip/src/Exception/Crc32Exception.php b/vendor/nelexa/zip/src/Exception/Crc32Exception.php deleted file mode 100644 index 04feb19..0000000 --- a/vendor/nelexa/zip/src/Exception/Crc32Exception.php +++ /dev/null @@ -1,71 +0,0 @@ -expectedCrc = $expected; - $this->actualCrc = $actual; - } - - /** - * Returns expected crc. - * - * @return int - */ - public function getExpectedCrc() - { - return $this->expectedCrc; - } - - /** - * Returns actual crc. - * - * @return int - */ - public function getActualCrc() - { - return $this->actualCrc; - } -} diff --git a/vendor/nelexa/zip/src/Exception/InvalidArgumentException.php b/vendor/nelexa/zip/src/Exception/InvalidArgumentException.php deleted file mode 100644 index 24ccc22..0000000 --- a/vendor/nelexa/zip/src/Exception/InvalidArgumentException.php +++ /dev/null @@ -1,14 +0,0 @@ -getName() : $entryName; - parent::__construct(sprintf( - 'Zip Entry "%s" was not found in the archive.', - $entryName - )); - $this->entryName = $entryName; - } - - /** - * @return string - */ - public function getEntryName() - { - return $this->entryName; - } -} diff --git a/vendor/nelexa/zip/src/Exception/ZipException.php b/vendor/nelexa/zip/src/Exception/ZipException.php deleted file mode 100644 index e59ec60..0000000 --- a/vendor/nelexa/zip/src/Exception/ZipException.php +++ /dev/null @@ -1,15 +0,0 @@ - - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA - */ - -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); - -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); - -header("Location: ../"); -exit; diff --git a/vendor/nelexa/zip/src/IO/Filter/Cipher/Pkware/PKCryptContext.php b/vendor/nelexa/zip/src/IO/Filter/Cipher/Pkware/PKCryptContext.php deleted file mode 100644 index bffa4d6..0000000 --- a/vendor/nelexa/zip/src/IO/Filter/Cipher/Pkware/PKCryptContext.php +++ /dev/null @@ -1,419 +0,0 @@ -keys = [ - 305419896, - 591751049, - 878082192, - ]; - - foreach (unpack('C*', $password) as $b) { - $this->updateKeys($b); - } - } - - /** - * @param string $header - * @param int $checkByte - * - * @throws ZipAuthenticationException - */ - public function checkHeader($header, $checkByte) - { - $byte = 0; - - foreach (unpack('C*', $header) as $byte) { - $byte = ($byte ^ $this->decryptByte()) & 0xff; - $this->updateKeys($byte); - } - - if ($byte !== $checkByte) { - throw new ZipAuthenticationException(sprintf('Invalid password')); - } - } - - /** - * @param string $content - * - * @return string - */ - public function decryptString($content) - { - $decryptContent = ''; - - foreach (unpack('C*', $content) as $byte) { - $byte = ($byte ^ $this->decryptByte()) & 0xff; - $this->updateKeys($byte); - $decryptContent .= \chr($byte); - } - - return $decryptContent; - } - - /** - * Decrypt byte. - * - * @return int - */ - private function decryptByte() - { - $temp = $this->keys[2] | 2; - - return (($temp * ($temp ^ 1)) >> 8) & 0xffffff; - } - - /** - * Update keys. - * - * @param int $charAt - */ - private function updateKeys($charAt) - { - $this->keys[0] = $this->crc32($this->keys[0], $charAt); - $this->keys[1] += ($this->keys[0] & 0xff); - $this->keys[1] = PackUtil::toSignedInt32($this->keys[1] * 134775813 + 1); - $this->keys[2] = PackUtil::toSignedInt32($this->crc32($this->keys[2], ($this->keys[1] >> 24) & 0xff)); - } - - /** - * Update crc. - * - * @param int $oldCrc - * @param int $charAt - * - * @return int - */ - private function crc32($oldCrc, $charAt) - { - return (($oldCrc >> 8) & 0xffffff) ^ self::$CRC_TABLE[($oldCrc ^ $charAt) & 0xff]; - } - - /** - * @param string $content - * - * @return string - */ - public function encryptString($content) - { - $encryptContent = ''; - - foreach (unpack('C*', $content) as $val) { - $encryptContent .= pack('c', $this->encryptByte($val)); - } - - return $encryptContent; - } - - /** - * @param int $byte - * - * @return int - */ - private function encryptByte($byte) - { - $tempVal = $byte ^ $this->decryptByte() & 0xff; - $this->updateKeys($byte); - - return $tempVal; - } -} diff --git a/vendor/nelexa/zip/src/IO/Filter/Cipher/Pkware/PKDecryptionStreamFilter.php b/vendor/nelexa/zip/src/IO/Filter/Cipher/Pkware/PKDecryptionStreamFilter.php deleted file mode 100644 index 97b1276..0000000 --- a/vendor/nelexa/zip/src/IO/Filter/Cipher/Pkware/PKDecryptionStreamFilter.php +++ /dev/null @@ -1,118 +0,0 @@ -params['entry'])) { - return false; - } - - if (!($this->params['entry'] instanceof ZipEntry)) { - throw new \RuntimeException('ZipEntry expected'); - } - /** @var ZipEntry $entry */ - $entry = $this->params['entry']; - $password = $entry->getPassword(); - - if ($password === null) { - return false; - } - - $this->size = $entry->getCompressedSize(); - - // init context - $this->context = new PKCryptContext($password); - - // init check byte - if ($entry->isDataDescriptorEnabled()) { - $this->checkByte = ($entry->getDosTime() >> 8) & 0xff; - } else { - $this->checkByte = ($entry->getCrc() >> 24) & 0xff; - } - - $this->readLength = 0; - $this->readHeader = false; - - return true; - } - - /** - * Decryption filter. - * - * @param resource $in - * @param resource $out - * @param int $consumed - * @param bool $closing - * - * @throws ZipException - * - * @return int - * - * @todo USE FFI in php 7.4 - */ - public function filter($in, $out, &$consumed, $closing) - { - while ($bucket = stream_bucket_make_writeable($in)) { - $buffer = $bucket->data; - $this->readLength += $bucket->datalen; - - if ($this->readLength > $this->size) { - $buffer = substr($buffer, 0, $this->size - $this->readLength); - } - - if (!$this->readHeader) { - $header = substr($buffer, 0, PKCryptContext::STD_DEC_HDR_SIZE); - $this->context->checkHeader($header, $this->checkByte); - - $buffer = substr($buffer, PKCryptContext::STD_DEC_HDR_SIZE); - $this->readHeader = true; - } - - $bucket->data = $this->context->decryptString($buffer); - - $consumed += $bucket->datalen; - stream_bucket_append($out, $bucket); - } - - return \PSFS_PASS_ON; - } -} diff --git a/vendor/nelexa/zip/src/IO/Filter/Cipher/Pkware/PKEncryptionStreamFilter.php b/vendor/nelexa/zip/src/IO/Filter/Cipher/Pkware/PKEncryptionStreamFilter.php deleted file mode 100644 index cd54145..0000000 --- a/vendor/nelexa/zip/src/IO/Filter/Cipher/Pkware/PKEncryptionStreamFilter.php +++ /dev/null @@ -1,128 +0,0 @@ -params['entry'], $this->params['size'])) { - return false; - } - - if (!($this->params['entry'] instanceof ZipEntry)) { - throw new \RuntimeException('ZipEntry expected'); - } - /** @var ZipEntry $entry */ - $entry = $this->params['entry']; - $password = $entry->getPassword(); - - if ($password === null) { - return false; - } - - $this->size = (int) $this->params['size']; - - // init keys - $this->context = new PKCryptContext($password); - - $crc = $entry->isDataDescriptorRequired() || $entry->getCrc() === ZipEntry::UNKNOWN ? - ($entry->getDosTime() & 0x0000ffff) << 16 : - $entry->getCrc(); - - try { - $headerBytes = random_bytes(PKCryptContext::STD_DEC_HDR_SIZE); - } catch (\Exception $e) { - throw new \RuntimeException('Oops, our server is bust and cannot generate any random data.', 1, $e); - } - - $headerBytes[PKCryptContext::STD_DEC_HDR_SIZE - 1] = pack('c', ($crc >> 24) & 0xff); - $headerBytes[PKCryptContext::STD_DEC_HDR_SIZE - 2] = pack('c', ($crc >> 16) & 0xff); - - $this->headerBytes = $headerBytes; - $this->writeLength = 0; - $this->writeHeader = false; - - return true; - } - - /** - * Encryption filter. - * - * @param resource $in - * @param resource $out - * @param int $consumed - * @param bool $closing - * - * @return int - * - * @todo USE FFI in php 7.4 - */ - public function filter($in, $out, &$consumed, $closing) - { - while ($bucket = stream_bucket_make_writeable($in)) { - $buffer = $bucket->data; - $this->writeLength += $bucket->datalen; - - if ($this->writeLength > $this->size) { - $buffer = substr($buffer, 0, $this->size - $this->writeLength); - } - - $data = ''; - - if (!$this->writeHeader) { - $data .= $this->context->encryptString($this->headerBytes); - $this->writeHeader = true; - } - - $data .= $this->context->encryptString($buffer); - - $bucket->data = $data; - - $consumed += $bucket->datalen; - stream_bucket_append($out, $bucket); - } - - return \PSFS_PASS_ON; - } -} diff --git a/vendor/nelexa/zip/src/IO/Filter/Cipher/Pkware/index.php b/vendor/nelexa/zip/src/IO/Filter/Cipher/Pkware/index.php deleted file mode 100644 index df24d3e..0000000 --- a/vendor/nelexa/zip/src/IO/Filter/Cipher/Pkware/index.php +++ /dev/null @@ -1,35 +0,0 @@ - - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA - */ - -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); - -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); - -header("Location: ../"); -exit; diff --git a/vendor/nelexa/zip/src/IO/Filter/Cipher/WinZipAes/WinZipAesContext.php b/vendor/nelexa/zip/src/IO/Filter/Cipher/WinZipAes/WinZipAesContext.php deleted file mode 100644 index 2691160..0000000 --- a/vendor/nelexa/zip/src/IO/Filter/Cipher/WinZipAes/WinZipAesContext.php +++ /dev/null @@ -1,166 +0,0 @@ -iv = str_repeat("\0", self::IV_SIZE); - $keyStrengthBytes = (int) ($encryptionStrengthBits / 8); - $hashLength = $keyStrengthBytes * 2 + self::PASSWORD_VERIFIER_SIZE * 8; - - $hash = hash_pbkdf2( - 'sha1', - $password, - $salt, - self::ITERATION_COUNT, - $hashLength, - true - ); - - $this->key = substr($hash, 0, $keyStrengthBytes); - $sha1Mac = substr($hash, $keyStrengthBytes, $keyStrengthBytes); - $this->hmacContext = hash_init('sha1', \HASH_HMAC, $sha1Mac); - $this->passwordVerifier = substr($hash, 2 * $keyStrengthBytes, self::PASSWORD_VERIFIER_SIZE); - } - - /** - * @return string - */ - public function getPasswordVerifier() - { - return $this->passwordVerifier; - } - - public function updateIv() - { - for ($ivCharIndex = 0; $ivCharIndex < self::IV_SIZE; $ivCharIndex++) { - $ivByte = \ord($this->iv[$ivCharIndex]); - - if (++$ivByte === 256) { - // overflow, set this one to 0, increment next - $this->iv[$ivCharIndex] = "\0"; - } else { - // no overflow, just write incremented number back and abort - $this->iv[$ivCharIndex] = \chr($ivByte); - - break; - } - } - } - - /** - * @param string $data - * - * @return string - */ - public function decryption($data) - { - hash_update($this->hmacContext, $data); - - return CryptoUtil::decryptAesCtr($data, $this->key, $this->iv); - } - - /** - * @param string $data - * - * @return string - */ - public function encrypt($data) - { - $encryptionData = CryptoUtil::encryptAesCtr($data, $this->key, $this->iv); - hash_update($this->hmacContext, $encryptionData); - - return $encryptionData; - } - - /** - * @param string $authCode - * - * @throws ZipAuthenticationException - */ - public function checkAuthCode($authCode) - { - $hmac = $this->getHmac(); - - // check authenticationCode - if (strcmp($hmac, $authCode) !== 0) { - throw new ZipAuthenticationException('Authenticated WinZip AES entry content has been tampered with.'); - } - } - - /** - * @return string - */ - public function getHmac() - { - return substr( - hash_final($this->hmacContext, true), - 0, - self::FOOTER_SIZE - ); - } -} diff --git a/vendor/nelexa/zip/src/IO/Filter/Cipher/WinZipAes/WinZipAesDecryptionStreamFilter.php b/vendor/nelexa/zip/src/IO/Filter/Cipher/WinZipAes/WinZipAesDecryptionStreamFilter.php deleted file mode 100644 index 7839172..0000000 --- a/vendor/nelexa/zip/src/IO/Filter/Cipher/WinZipAes/WinZipAesDecryptionStreamFilter.php +++ /dev/null @@ -1,187 +0,0 @@ -params['entry'])) { - return false; - } - - if (!($this->params['entry'] instanceof ZipEntry)) { - throw new \RuntimeException('ZipEntry expected'); - } - $this->entry = $this->params['entry']; - - if ( - $this->entry->getPassword() === null || - !$this->entry->isEncrypted() || - !$this->entry->hasExtraField(WinZipAesExtraField::HEADER_ID) - ) { - return false; - } - - $this->buffer = ''; - - return true; - } - - /** - * @param resource $in - * @param resource $out - * @param int $consumed - * @param bool $closing - * - * @throws ZipAuthenticationException - * - * @return int - */ - public function filter($in, $out, &$consumed, $closing) - { - while ($bucket = stream_bucket_make_writeable($in)) { - $this->buffer .= $bucket->data; - $this->readLength += $bucket->datalen; - - if ($this->readLength > $this->entry->getCompressedSize()) { - $this->buffer = substr($this->buffer, 0, $this->entry->getCompressedSize() - $this->readLength); - } - - // read header - if ($this->context === null) { - /** - * @var WinZipAesExtraField|null $winZipExtra - */ - $winZipExtra = $this->entry->getExtraField(WinZipAesExtraField::HEADER_ID); - - if ($winZipExtra === null) { - throw new RuntimeException('$winZipExtra is null'); - } - $saltSize = $winZipExtra->getSaltSize(); - $headerSize = $saltSize + WinZipAesContext::PASSWORD_VERIFIER_SIZE; - - if (\strlen($this->buffer) < $headerSize) { - return \PSFS_FEED_ME; - } - - $salt = substr($this->buffer, 0, $saltSize); - $passwordVerifier = substr($this->buffer, $saltSize, WinZipAesContext::PASSWORD_VERIFIER_SIZE); - $password = $this->entry->getPassword(); - - if ($password === null) { - throw new RuntimeException('$password is null'); - } - $this->context = new WinZipAesContext($winZipExtra->getEncryptionStrength(), $password, $salt); - unset($password); - - // Verify password. - if ($passwordVerifier !== $this->context->getPasswordVerifier()) { - throw new ZipAuthenticationException('Invalid password'); - } - - $this->encBlockPosition = 0; - $this->encBlockLength = $this->entry->getCompressedSize() - $headerSize - WinZipAesContext::FOOTER_SIZE; - - $this->buffer = substr($this->buffer, $headerSize); - } - - // encrypt data - $plainText = ''; - $offset = 0; - $len = \strlen($this->buffer); - $remaining = $this->encBlockLength - $this->encBlockPosition; - - if ($remaining >= WinZipAesContext::BLOCK_SIZE && $len < WinZipAesContext::BLOCK_SIZE) { - return \PSFS_FEED_ME; - } - $limit = min($len, $remaining); - - if ($remaining > $limit && ($limit % WinZipAesContext::BLOCK_SIZE) !== 0) { - $limit -= ($limit % WinZipAesContext::BLOCK_SIZE); - } - - while ($offset < $limit) { - $this->context->updateIv(); - $length = min(WinZipAesContext::BLOCK_SIZE, $limit - $offset); - $data = substr($this->buffer, 0, $length); - $plainText .= $this->context->decryption($data); - $offset += $length; - $this->buffer = substr($this->buffer, $length); - } - $this->encBlockPosition += $offset; - - if ( - $this->encBlockPosition === $this->encBlockLength && - \strlen($this->buffer) === WinZipAesContext::FOOTER_SIZE - ) { - $this->authenticationCode = $this->buffer; - $this->buffer = ''; - } - - $bucket->data = $plainText; - $consumed += $bucket->datalen; - stream_bucket_append($out, $bucket); - } - - return \PSFS_PASS_ON; - } - - /** - * @see http://php.net/manual/en/php-user-filter.onclose.php - * - * @throws ZipAuthenticationException - */ - public function onClose() - { - $this->buffer = ''; - - if ($this->context !== null) { - $this->context->checkAuthCode($this->authenticationCode); - } - } -} diff --git a/vendor/nelexa/zip/src/IO/Filter/Cipher/WinZipAes/WinZipAesEncryptionStreamFilter.php b/vendor/nelexa/zip/src/IO/Filter/Cipher/WinZipAes/WinZipAesEncryptionStreamFilter.php deleted file mode 100644 index 12d12fe..0000000 --- a/vendor/nelexa/zip/src/IO/Filter/Cipher/WinZipAes/WinZipAesEncryptionStreamFilter.php +++ /dev/null @@ -1,158 +0,0 @@ -params['entry'])) { - return false; - } - - if (!($this->params['entry'] instanceof ZipEntry)) { - throw new \RuntimeException('ZipEntry expected'); - } - $this->entry = $this->params['entry']; - - if ( - $this->entry->getPassword() === null || - !$this->entry->isEncrypted() || - !$this->entry->hasExtraField(WinZipAesExtraField::HEADER_ID) - ) { - return false; - } - - $this->size = (int) $this->params['size']; - $this->context = null; - $this->buffer = ''; - - return true; - } - - /** - * @param resource $in - * @param resource $out - * @param int $consumed - * @param bool $closing - * - * @return int - */ - public function filter($in, $out, &$consumed, $closing) - { - while ($bucket = stream_bucket_make_writeable($in)) { - $this->buffer .= $bucket->data; - $this->remaining += $bucket->datalen; - - if ($this->remaining > $this->size) { - $this->buffer = substr($this->buffer, 0, $this->size - $this->remaining); - $this->remaining = $this->size; - } - - $encryptionText = ''; - - // write header - if ($this->context === null) { - /** - * @var WinZipAesExtraField|null $winZipExtra - */ - $winZipExtra = $this->entry->getExtraField(WinZipAesExtraField::HEADER_ID); - - if ($winZipExtra === null) { - throw new RuntimeException('$winZipExtra is null'); - } - $saltSize = $winZipExtra->getSaltSize(); - - try { - $salt = random_bytes($saltSize); - } catch (\Exception $e) { - throw new \RuntimeException('Oops, our server is bust and cannot generate any random data.', 1, $e); - } - $password = $this->entry->getPassword(); - - if ($password === null) { - throw new RuntimeException('$password is null'); - } - $this->context = new WinZipAesContext( - $winZipExtra->getEncryptionStrength(), - $password, - $salt - ); - - $encryptionText .= $salt . $this->context->getPasswordVerifier(); - } - - // encrypt data - $offset = 0; - $len = \strlen($this->buffer); - $remaining = $this->remaining - $this->size; - - if ($remaining >= WinZipAesContext::BLOCK_SIZE && $len < WinZipAesContext::BLOCK_SIZE) { - return \PSFS_FEED_ME; - } - $limit = max($len, $remaining); - - if ($remaining > $limit && ($limit % WinZipAesContext::BLOCK_SIZE) !== 0) { - $limit -= ($limit % WinZipAesContext::BLOCK_SIZE); - } - - while ($offset < $limit) { - $this->context->updateIv(); - $length = min(WinZipAesContext::BLOCK_SIZE, $limit - $offset); - $encryptionText .= $this->context->encrypt( - substr($this->buffer, 0, $length) - ); - $offset += $length; - $this->buffer = substr($this->buffer, $length); - } - - if ($remaining === 0) { - $encryptionText .= $this->context->getHmac(); - } - - $bucket->data = $encryptionText; - $consumed += $bucket->datalen; - - stream_bucket_append($out, $bucket); - } - - return \PSFS_PASS_ON; - } -} diff --git a/vendor/nelexa/zip/src/IO/Filter/Cipher/WinZipAes/index.php b/vendor/nelexa/zip/src/IO/Filter/Cipher/WinZipAes/index.php deleted file mode 100644 index df24d3e..0000000 --- a/vendor/nelexa/zip/src/IO/Filter/Cipher/WinZipAes/index.php +++ /dev/null @@ -1,35 +0,0 @@ - - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA - */ - -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); - -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); - -header("Location: ../"); -exit; diff --git a/vendor/nelexa/zip/src/IO/Filter/Cipher/index.php b/vendor/nelexa/zip/src/IO/Filter/Cipher/index.php deleted file mode 100644 index df24d3e..0000000 --- a/vendor/nelexa/zip/src/IO/Filter/Cipher/index.php +++ /dev/null @@ -1,35 +0,0 @@ - - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA - */ - -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); - -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); - -header("Location: ../"); -exit; diff --git a/vendor/nelexa/zip/src/IO/Filter/index.php b/vendor/nelexa/zip/src/IO/Filter/index.php deleted file mode 100644 index df24d3e..0000000 --- a/vendor/nelexa/zip/src/IO/Filter/index.php +++ /dev/null @@ -1,35 +0,0 @@ - - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA - */ - -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); - -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); - -header("Location: ../"); -exit; diff --git a/vendor/nelexa/zip/src/IO/Stream/ResponseStream.php b/vendor/nelexa/zip/src/IO/Stream/ResponseStream.php deleted file mode 100644 index e016103..0000000 --- a/vendor/nelexa/zip/src/IO/Stream/ResponseStream.php +++ /dev/null @@ -1,338 +0,0 @@ - [ - 'r' => true, - 'w+' => true, - 'r+' => true, - 'x+' => true, - 'c+' => true, - 'rb' => true, - 'w+b' => true, - 'r+b' => true, - 'x+b' => true, - 'c+b' => true, - 'rt' => true, - 'w+t' => true, - 'r+t' => true, - 'x+t' => true, - 'c+t' => true, - 'a+' => true, - ], - 'write' => [ - 'w' => true, - 'w+' => true, - 'rw' => true, - 'r+' => true, - 'x+' => true, - 'c+' => true, - 'wb' => true, - 'w+b' => true, - 'r+b' => true, - 'x+b' => true, - 'c+b' => true, - 'w+t' => true, - 'r+t' => true, - 'x+t' => true, - 'c+t' => true, - 'a' => true, - 'a+' => true, - ], - ]; - - /** @var resource */ - private $stream; - - /** @var int|null */ - private $size; - - /** @var bool */ - private $seekable; - - /** @var bool */ - private $readable; - - /** @var bool */ - private $writable; - - /** @var string|null */ - private $uri; - - /** - * @param resource $stream stream resource to wrap - * - * @throws \InvalidArgumentException if the stream is not a stream resource - */ - public function __construct($stream) - { - if (!\is_resource($stream)) { - throw new \InvalidArgumentException('Stream must be a resource'); - } - $this->stream = $stream; - $meta = stream_get_meta_data($this->stream); - $this->seekable = $meta['seekable']; - $this->readable = isset(self::$readWriteHash['read'][$meta['mode']]); - $this->writable = isset(self::$readWriteHash['write'][$meta['mode']]); - $this->uri = $this->getMetadata('uri'); - } - - /** - * Get stream metadata as an associative array or retrieve a specific key. - * - * The keys returned are identical to the keys returned from PHP's - * stream_get_meta_data() function. - * - * @see http://php.net/manual/en/function.stream-get-meta-data.php - * - * @param string $key specific metadata to retrieve - * - * @return array|mixed|null Returns an associative array if no key is - * provided. Returns a specific key value if a key is provided and the - * value is found, or null if the key is not found. - */ - public function getMetadata($key = null) - { - if (!$this->stream) { - return $key ? null : []; - } - $meta = stream_get_meta_data($this->stream); - - return isset($meta[$key]) ? $meta[$key] : null; - } - - /** - * Reads all data from the stream into a string, from the beginning to end. - * - * This method MUST attempt to seek to the beginning of the stream before - * reading data and read the stream until the end is reached. - * - * Warning: This could attempt to load a large amount of data into memory. - * - * This method MUST NOT raise an exception in order to conform with PHP's - * string casting operations. - * - * @see http://php.net/manual/en/language.oop5.magic.php#object.tostring - * - * @return string - */ - public function __toString() - { - if (!$this->stream) { - return ''; - } - $this->rewind(); - - return (string) stream_get_contents($this->stream); - } - - /** - * Seek to the beginning of the stream. - * - * If the stream is not seekable, this method will raise an exception; - * otherwise, it will perform a seek(0). - * - * @throws \RuntimeException on failure - * - * @see http://www.php.net/manual/en/function.fseek.php - * @see seek() - */ - public function rewind() - { - $this->seekable && rewind($this->stream); - } - - /** - * Get the size of the stream if known. - * - * @return int|null returns the size in bytes if known, or null if unknown - */ - public function getSize() - { - if ($this->size !== null) { - return $this->size; - } - - if (!$this->stream) { - return null; - } - // Clear the stat cache if the stream has a URI - if ($this->uri !== null) { - clearstatcache(true, $this->uri); - } - $stats = fstat($this->stream); - - if (isset($stats['size'])) { - $this->size = $stats['size']; - - return $this->size; - } - - return null; - } - - /** - * Returns the current position of the file read/write pointer. - * - * @throws \RuntimeException on error - * - * @return int Position of the file pointer - */ - public function tell() - { - return $this->stream ? ftell($this->stream) : false; - } - - /** - * Returns true if the stream is at the end of the stream. - * - * @return bool - */ - public function eof() - { - return !$this->stream || feof($this->stream); - } - - /** - * Returns whether or not the stream is seekable. - * - * @return bool - */ - public function isSeekable() - { - return $this->seekable; - } - - /** - * Seek to a position in the stream. - * - * @see http://www.php.net/manual/en/function.fseek.php - * - * @param int $offset Stream offset - * @param int $whence Specifies how the cursor position will be calculated - * based on the seek offset. Valid values are identical to the built-in - * PHP $whence values for `fseek()`. SEEK_SET: Set position equal to - * offset bytes SEEK_CUR: Set position to current location plus offset - * SEEK_END: Set position to end-of-stream plus offset. - * - * @throws \RuntimeException on failure - */ - public function seek($offset, $whence = \SEEK_SET) - { - $this->seekable && fseek($this->stream, $offset, $whence); - } - - /** - * Returns whether or not the stream is writable. - * - * @return bool - */ - public function isWritable() - { - return $this->writable; - } - - /** - * Write data to the stream. - * - * @param string $string the string that is to be written - * - * @throws \RuntimeException on failure - * - * @return int returns the number of bytes written to the stream - */ - public function write($string) - { - $this->size = null; - - return $this->writable ? fwrite($this->stream, $string) : false; - } - - /** - * Returns whether or not the stream is readable. - * - * @return bool - */ - public function isReadable() - { - return $this->readable; - } - - /** - * Read data from the stream. - * - * @param int $length Read up to $length bytes from the object and return - * them. Fewer than $length bytes may be returned if underlying stream - * call returns fewer bytes. - * - * @throws \RuntimeException if an error occurs - * - * @return string returns the data read from the stream, or an empty string - * if no bytes are available - */ - public function read($length) - { - return $this->readable ? fread($this->stream, $length) : ''; - } - - /** - * Returns the remaining contents in a string. - * - * @throws \RuntimeException if unable to read or an error occurs while - * reading - * - * @return string - */ - public function getContents() - { - return $this->stream ? stream_get_contents($this->stream) : ''; - } - - /** - * Closes the stream when the destructed. - */ - public function __destruct() - { - $this->close(); - } - - /** - * Closes the stream and any underlying resources. - */ - public function close() - { - if (\is_resource($this->stream)) { - fclose($this->stream); - } - $this->detach(); - } - - /** - * Separates any underlying resources from the stream. - * - * After the stream has been detached, the stream is in an unusable state. - * - * @return resource|null Underlying PHP stream, if any - */ - public function detach() - { - $result = $this->stream; - $this->stream = null; - $this->size = null; - $this->uri = null; - $this->readable = false; - $this->writable = false; - $this->seekable = false; - - return $result; - } -} diff --git a/vendor/nelexa/zip/src/IO/Stream/ZipEntryStreamWrapper.php b/vendor/nelexa/zip/src/IO/Stream/ZipEntryStreamWrapper.php deleted file mode 100644 index aa13f07..0000000 --- a/vendor/nelexa/zip/src/IO/Stream/ZipEntryStreamWrapper.php +++ /dev/null @@ -1,309 +0,0 @@ - [ - 'entry' => $entry, - ], - ] - ); - - $uri = self::PROTOCOL . '://' . $entry->getName(); - $fp = fopen($uri, 'r+b', false, $context); - - if ($fp === false) { - throw new \RuntimeException('Error open ' . $uri); - } - - return $fp; - } - - /** - * Opens file or URL. - * - * This method is called immediately after the wrapper is - * initialized (f.e. by {@see fopen()} and {@see file_get_contents()}). - * - * @param string $path specifies the URL that was passed to - * the original function - * @param string $mode the mode used to open the file, as detailed - * for {@see fopen()} - * @param int $options Holds additional flags set by the streams - * API. It can hold one or more of the - * following values OR'd together. - * @param string $opened_path if the path is opened successfully, and - * STREAM_USE_PATH is set in options, - * opened_path should be set to the - * full path of the file/resource that - * was actually opened - * - * @throws ZipException - * - * @return bool - * - * @see https://www.php.net/streamwrapper.stream-open - */ - public function stream_open($path, $mode, $options, &$opened_path) - { - if ($this->context === null) { - throw new \RuntimeException('stream context is null'); - } - $streamOptions = stream_context_get_options($this->context); - - if (!isset($streamOptions[self::PROTOCOL]['entry'])) { - throw new \RuntimeException('no stream option ["' . self::PROTOCOL . '"]["entry"]'); - } - $zipEntry = $streamOptions[self::PROTOCOL]['entry']; - - if (!$zipEntry instanceof ZipEntry) { - throw new \RuntimeException('invalid stream context'); - } - - $zipData = $zipEntry->getData(); - - if ($zipData === null) { - throw new ZipException(sprintf('No data for zip entry "%s"', $zipEntry->getName())); - } - $this->fp = $zipData->getDataAsStream(); - - return $this->fp !== false; - } - - /** - * Read from stream. - * - * This method is called in response to {@see fread()} and {@see fgets()}. - * - * Note: Remember to update the read/write position of the stream - * (by the number of bytes that were successfully read). - * - * @param int $count how many bytes of data from the current - * position should be returned - * - * @return false|string If there are less than count bytes available, - * return as many as are available. If no more data - * is available, return either FALSE or - * an empty string. - * - * @see https://www.php.net/streamwrapper.stream-read - */ - public function stream_read($count) - { - return fread($this->fp, $count); - } - - /** - * Seeks to specific location in a stream. - * - * This method is called in response to {@see fseek()}. - * The read/write position of the stream should be updated according - * to the offset and whence. - * - * @param int $offset the stream offset to seek to - * @param int $whence Possible values: - * {@see \SEEK_SET} - Set position equal to offset bytes. - * {@see \SEEK_CUR} - Set position to current location plus offset. - * {@see \SEEK_END} - Set position to end-of-file plus offset. - * - * @return bool return TRUE if the position was updated, FALSE otherwise - * - * @see https://www.php.net/streamwrapper.stream-seek - */ - public function stream_seek($offset, $whence = \SEEK_SET) - { - return fseek($this->fp, $offset, $whence) === 0; - } - - /** - * Retrieve the current position of a stream. - * - * This method is called in response to {@see fseek()} to determine - * the current position. - * - * @return int should return the current position of the stream - * - * @see https://www.php.net/streamwrapper.stream-tell - */ - public function stream_tell() - { - $pos = ftell($this->fp); - - if ($pos === false) { - throw new \RuntimeException('Cannot get stream position.'); - } - - return $pos; - } - - /** - * Tests for end-of-file on a file pointer. - * - * This method is called in response to {@see feof()}. - * - * @return bool should return TRUE if the read/write position is at - * the end of the stream and if no more data is available - * to be read, or FALSE otherwise - * - * @see https://www.php.net/streamwrapper.stream-eof - */ - public function stream_eof() - { - return feof($this->fp); - } - - /** - * Retrieve information about a file resource. - * - * This method is called in response to {@see fstat()}. - * - * @return array - * - * @see https://www.php.net/streamwrapper.stream-stat - * @see https://www.php.net/stat - * @see https://www.php.net/fstat - */ - public function stream_stat() - { - return fstat($this->fp); - } - - /** - * Flushes the output. - * - * This method is called in response to {@see fflush()} and when the - * stream is being closed while any unflushed data has been written to - * it before. - * If you have cached data in your stream but not yet stored it into - * the underlying storage, you should do so now. - * - * @return bool should return TRUE if the cached data was successfully - * stored (or if there was no data to store), or FALSE - * if the data could not be stored - * - * @see https://www.php.net/streamwrapper.stream-flush - */ - public function stream_flush() - { - return fflush($this->fp); - } - - /** - * Truncate stream. - * - * Will respond to truncation, e.g., through {@see ftruncate()}. - * - * @param int $new_size the new size - * - * @return bool returns TRUE on success or FALSE on failure - * - * @see https://www.php.net/streamwrapper.stream-truncate - */ - public function stream_truncate($new_size) - { - return ftruncate($this->fp, (int) $new_size); - } - - /** - * Write to stream. - * - * This method is called in response to {@see fwrite().} - * - * Note: Remember to update the current position of the stream by - * number of bytes that were successfully written. - * - * @param string $data should be stored into the underlying stream - * - * @return int should return the number of bytes that were successfully stored, or 0 if none could be stored - * - * @see https://www.php.net/streamwrapper.stream-write - */ - public function stream_write($data) - { - $bytes = fwrite($this->fp, $data); - - return $bytes === false ? 0 : $bytes; - } - - /** - * Retrieve the underlaying resource. - * - * This method is called in response to {@see stream_select()}. - * - * @param int $cast_as can be {@see STREAM_CAST_FOR_SELECT} when {@see stream_select()} - * is callingstream_cast() or {@see STREAM_CAST_AS_STREAM} when - * stream_cast() is called for other uses - * - * @return resource - */ - public function stream_cast($cast_as) - { - return $this->fp; - } - - /** - * Close a resource. - * - * This method is called in response to {@see fclose()}. - * All resources that were locked, or allocated, by the wrapper should be released. - * - * @see https://www.php.net/streamwrapper.stream-close - */ - public function stream_close() - { - } -} diff --git a/vendor/nelexa/zip/src/IO/Stream/index.php b/vendor/nelexa/zip/src/IO/Stream/index.php deleted file mode 100644 index df24d3e..0000000 --- a/vendor/nelexa/zip/src/IO/Stream/index.php +++ /dev/null @@ -1,35 +0,0 @@ - - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA - */ - -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); - -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); - -header("Location: ../"); -exit; diff --git a/vendor/nelexa/zip/src/IO/ZipReader.php b/vendor/nelexa/zip/src/IO/ZipReader.php deleted file mode 100644 index 7dfc97e..0000000 --- a/vendor/nelexa/zip/src/IO/ZipReader.php +++ /dev/null @@ -1,896 +0,0 @@ -size = fstat($inStream)['size']; - $this->inStream = $inStream; - - /** @noinspection AdditionOperationOnArraysInspection */ - $options += $this->getDefaultOptions(); - $this->options = $options; - } - - /** - * @return array - */ - protected function getDefaultOptions() - { - return [ - ZipOptions::CHARSET => null, - ]; - } - - /** - * @throws ZipException - * - * @return ImmutableZipContainer - */ - public function read() - { - if ($this->size < ZipConstants::END_CD_MIN_LEN) { - throw new ZipException('Corrupt zip file'); - } - - $endOfCentralDirectory = $this->readEndOfCentralDirectory(); - $entries = $this->readCentralDirectory($endOfCentralDirectory); - - return new ImmutableZipContainer($entries, $endOfCentralDirectory->getComment()); - } - - /** - * @return array - */ - public function getStreamMetaData() - { - return stream_get_meta_data($this->inStream); - } - - /** - * Read End of central directory record. - * - * end of central dir signature 4 bytes (0x06054b50) - * number of this disk 2 bytes - * number of the disk with the - * start of the central directory 2 bytes - * total number of entries in the - * central directory on this disk 2 bytes - * total number of entries in - * the central directory 2 bytes - * size of the central directory 4 bytes - * offset of start of central - * directory with respect to - * the starting disk number 4 bytes - * .ZIP file comment length 2 bytes - * .ZIP file comment (variable size) - * - * @throws ZipException - * - * @return EndOfCentralDirectory - */ - protected function readEndOfCentralDirectory() - { - if (!$this->findEndOfCentralDirectory()) { - throw new ZipException('Invalid zip file. The end of the central directory could not be found.'); - } - - $positionECD = ftell($this->inStream) - 4; - $sizeECD = $this->size - ftell($this->inStream); - $buffer = fread($this->inStream, $sizeECD); - - $unpack = unpack( - 'vdiskNo/vcdDiskNo/vcdEntriesDisk/' . - 'vcdEntries/VcdSize/VcdPos/vcommentLength', - substr($buffer, 0, 18) - ); - - if ( - $unpack['diskNo'] !== 0 || - $unpack['cdDiskNo'] !== 0 || - $unpack['cdEntriesDisk'] !== $unpack['cdEntries'] - ) { - throw new ZipException( - 'ZIP file spanning/splitting is not supported!' - ); - } - // .ZIP file comment (variable sizeECD) - $comment = null; - - if ($unpack['commentLength'] > 0) { - $comment = substr($buffer, 18, $unpack['commentLength']); - } - - // Check for ZIP64 End Of Central Directory Locator exists. - $zip64ECDLocatorPosition = $positionECD - ZipConstants::ZIP64_END_CD_LOC_LEN; - fseek($this->inStream, $zip64ECDLocatorPosition); - // zip64 end of central dir locator - // signature 4 bytes (0x07064b50) - if ($zip64ECDLocatorPosition > 0 && unpack( - 'V', - fread($this->inStream, 4) - )[1] === ZipConstants::ZIP64_END_CD_LOC) { - if (!$this->isZip64Support()) { - throw new ZipException('ZIP64 not supported this archive.'); - } - - $positionECD = $this->findZip64ECDPosition(); - $endCentralDirectory = $this->readZip64EndOfCentralDirectory($positionECD); - $endCentralDirectory->setComment($comment); - } else { - $endCentralDirectory = new EndOfCentralDirectory( - $unpack['cdEntries'], - $unpack['cdPos'], - $unpack['cdSize'], - false, - $comment - ); - } - - return $endCentralDirectory; - } - - /** - * @return bool - */ - protected function findEndOfCentralDirectory() - { - $max = $this->size - ZipConstants::END_CD_MIN_LEN; - $min = $max >= 0xffff ? $max - 0xffff : 0; - // Search for End of central directory record. - for ($position = $max; $position >= $min; $position--) { - fseek($this->inStream, $position); - // end of central dir signature 4 bytes (0x06054b50) - if (unpack('V', fread($this->inStream, 4))[1] !== ZipConstants::END_CD) { - continue; - } - - return true; - } - - return false; - } - - /** - * Read Zip64 end of central directory locator and returns - * Zip64 end of central directory position. - * - * number of the disk with the - * start of the zip64 end of - * central directory 4 bytes - * relative offset of the zip64 - * end of central directory record 8 bytes - * total number of disks 4 bytes - * - * @throws ZipException - * - * @return int Zip64 End Of Central Directory position - */ - protected function findZip64ECDPosition() - { - $diskNo = unpack('V', fread($this->inStream, 4))[1]; - $zip64ECDPos = PackUtil::unpackLongLE(fread($this->inStream, 8)); - $totalDisks = unpack('V', fread($this->inStream, 4))[1]; - - if ($diskNo !== 0 || $totalDisks > 1) { - throw new ZipException('ZIP file spanning/splitting is not supported!'); - } - - return $zip64ECDPos; - } - - /** - * Read zip64 end of central directory locator and zip64 end - * of central directory record. - * - * zip64 end of central dir - * signature 4 bytes (0x06064b50) - * size of zip64 end of central - * directory record 8 bytes - * version made by 2 bytes - * version needed to extract 2 bytes - * number of this disk 4 bytes - * number of the disk with the - * start of the central directory 4 bytes - * total number of entries in the - * central directory on this disk 8 bytes - * total number of entries in the - * central directory 8 bytes - * size of the central directory 8 bytes - * offset of start of central - * directory with respect to - * the starting disk number 8 bytes - * zip64 extensible data sector (variable size) - * - * @param int $zip64ECDPosition - * - * @throws ZipException - * - * @return EndOfCentralDirectory - */ - protected function readZip64EndOfCentralDirectory($zip64ECDPosition) - { - fseek($this->inStream, $zip64ECDPosition); - - $buffer = fread($this->inStream, ZipConstants::ZIP64_END_OF_CD_LEN); - - if (unpack('V', $buffer)[1] !== ZipConstants::ZIP64_END_CD) { - throw new ZipException('Expected ZIP64 End Of Central Directory Record!'); - } - - $data = unpack( -// 'Psize/vversionMadeBy/vextractVersion/' . - 'VdiskNo/VcdDiskNo', - substr($buffer, 16, 8) - ); - - $cdEntriesDisk = PackUtil::unpackLongLE(substr($buffer, 24, 8)); - $entryCount = PackUtil::unpackLongLE(substr($buffer, 32, 8)); - $cdSize = PackUtil::unpackLongLE(substr($buffer, 40, 8)); - $cdPos = PackUtil::unpackLongLE(substr($buffer, 48, 8)); - -// $platform = ZipPlatform::fromValue(($data['versionMadeBy'] & 0xFF00) >> 8); -// $softwareVersion = $data['versionMadeBy'] & 0x00FF; - - if ($data['diskNo'] !== 0 || $data['cdDiskNo'] !== 0 || $entryCount !== $cdEntriesDisk) { - throw new ZipException('ZIP file spanning/splitting is not supported!'); - } - - if ($entryCount < 0 || $entryCount > 0x7fffffff) { - throw new ZipException('Total Number Of Entries In The Central Directory out of range!'); - } - - // skip zip64 extensible data sector (variable sizeEndCD) - - return new EndOfCentralDirectory( - $entryCount, - $cdPos, - $cdSize, - true - ); - } - - /** - * Reads the central directory from the given seekable byte channel - * and populates the internal tables with ZipEntry instances. - * - * The ZipEntry's will know all data that can be obtained from the - * central directory alone, but not the data that requires the local - * file header or additional data to be read. - * - * @param EndOfCentralDirectory $endCD - * - * @throws ZipException - * - * @return ZipEntry[] - */ - protected function readCentralDirectory(EndOfCentralDirectory $endCD) - { - $entries = []; - - $cdOffset = $endCD->getCdOffset(); - fseek($this->inStream, $cdOffset); - - if (!($cdStream = fopen('php://temp', 'w+b'))) { - throw new ZipException('Temp resource can not open from write'); - } - stream_copy_to_stream($this->inStream, $cdStream, $endCD->getCdSize()); - rewind($cdStream); - for ($numEntries = $endCD->getEntryCount(); $numEntries > 0; $numEntries--) { - $zipEntry = $this->readZipEntry($cdStream); - - $entryName = $zipEntry->getName(); - - /** @var UnicodePathExtraField|null $unicodePathExtraField */ - $unicodePathExtraField = $zipEntry->getExtraField(UnicodePathExtraField::HEADER_ID); - - if ($unicodePathExtraField !== null && $unicodePathExtraField->getCrc32() === crc32($entryName)) { - $unicodePath = $unicodePathExtraField->getUnicodeValue(); - - if ($unicodePath !== null) { - $unicodePath = str_replace('\\', '/', $unicodePath); - - if ( - $unicodePath !== '' && - substr_count($entryName, '/') === substr_count($unicodePath, '/') - ) { - $entryName = $unicodePath; - } - } - } - - $entries[$entryName] = $zipEntry; - } - - return $entries; - } - - /** - * Read central directory entry. - * - * central file header signature 4 bytes (0x02014b50) - * version made by 2 bytes - * version needed to extract 2 bytes - * general purpose bit flag 2 bytes - * compression method 2 bytes - * last mod file time 2 bytes - * last mod file date 2 bytes - * crc-32 4 bytes - * compressed size 4 bytes - * uncompressed size 4 bytes - * file name length 2 bytes - * extra field length 2 bytes - * file comment length 2 bytes - * disk number start 2 bytes - * internal file attributes 2 bytes - * external file attributes 4 bytes - * relative offset of local header 4 bytes - * - * file name (variable size) - * extra field (variable size) - * file comment (variable size) - * - * @param resource $stream - * - * @throws ZipException - * - * @return ZipEntry - */ - protected function readZipEntry($stream) - { - if (unpack('V', fread($stream, 4))[1] !== ZipConstants::CENTRAL_FILE_HEADER) { - throw new ZipException('Corrupt zip file. Cannot read zip entry.'); - } - - $unpack = unpack( - 'vversionMadeBy/vversionNeededToExtract/' . - 'vgeneralPurposeBitFlag/vcompressionMethod/' . - 'VlastModFile/Vcrc/VcompressedSize/' . - 'VuncompressedSize/vfileNameLength/vextraFieldLength/' . - 'vfileCommentLength/vdiskNumberStart/vinternalFileAttributes/' . - 'VexternalFileAttributes/VoffsetLocalHeader', - fread($stream, 42) - ); - - if ($unpack['diskNumberStart'] !== 0) { - throw new ZipException('ZIP file spanning/splitting is not supported!'); - } - - $generalPurposeBitFlags = $unpack['generalPurposeBitFlag']; - $isUtf8 = ($generalPurposeBitFlags & GeneralPurposeBitFlag::UTF8) !== 0; - - $name = fread($stream, $unpack['fileNameLength']); - - $createdOS = ($unpack['versionMadeBy'] & 0xFF00) >> 8; - $softwareVersion = $unpack['versionMadeBy'] & 0x00FF; - - $extractedOS = ($unpack['versionNeededToExtract'] & 0xFF00) >> 8; - $extractVersion = $unpack['versionNeededToExtract'] & 0x00FF; - - $dosTime = $unpack['lastModFile']; - - $comment = null; - - if ($unpack['fileCommentLength'] > 0) { - $comment = fread($stream, $unpack['fileCommentLength']); - } - - // decode code page names - $fallbackCharset = null; - - if (!$isUtf8 && isset($this->options[ZipOptions::CHARSET])) { - $charset = $this->options[ZipOptions::CHARSET]; - - $fallbackCharset = $charset; - $name = DosCodePage::toUTF8($name, $charset); - - if ($comment !== null) { - $comment = DosCodePage::toUTF8($comment, $charset); - } - } - - $zipEntry = ZipEntry::create( - $name, - $createdOS, - $extractedOS, - $softwareVersion, - $extractVersion, - $unpack['compressionMethod'], - $generalPurposeBitFlags, - $dosTime, - $unpack['crc'], - $unpack['compressedSize'], - $unpack['uncompressedSize'], - $unpack['internalFileAttributes'], - $unpack['externalFileAttributes'], - $unpack['offsetLocalHeader'], - $comment, - $fallbackCharset - ); - - if ($unpack['extraFieldLength'] > 0) { - $this->parseExtraFields( - fread($stream, $unpack['extraFieldLength']), - $zipEntry, - false - ); - - /** @var Zip64ExtraField|null $extraZip64 */ - $extraZip64 = $zipEntry->getCdExtraField(Zip64ExtraField::HEADER_ID); - - if ($extraZip64 !== null) { - $this->handleZip64Extra($extraZip64, $zipEntry); - } - } - - $this->loadLocalExtraFields($zipEntry); - $this->handleExtraEncryptionFields($zipEntry); - $this->handleExtraFields($zipEntry); - - return $zipEntry; - } - - /** - * @param string $buffer - * @param ZipEntry $zipEntry - * @param bool $local - * - * @return ExtraFieldsCollection - */ - protected function parseExtraFields($buffer, ZipEntry $zipEntry, $local = false) - { - $collection = $local ? - $zipEntry->getLocalExtraFields() : - $zipEntry->getCdExtraFields(); - - if (!empty($buffer)) { - $pos = 0; - $endPos = \strlen($buffer); - - while ($endPos - $pos >= 4) { - /** @var int[] $data */ - $data = unpack('vheaderId/vdataSize', substr($buffer, $pos, 4)); - $pos += 4; - - if ($endPos - $pos - $data['dataSize'] < 0) { - break; - } - $bufferData = substr($buffer, $pos, $data['dataSize']); - $headerId = $data['headerId']; - - /** @var string|ZipExtraField|null $className */ - $className = ZipExtraDriver::getClassNameOrNull($headerId); - - try { - if ($className !== null) { - try { - $extraField = $local ? - \call_user_func([$className, 'unpackLocalFileData'], $bufferData, $zipEntry) : - \call_user_func([$className, 'unpackCentralDirData'], $bufferData, $zipEntry); - } catch (\Throwable $e) { - // skip errors while parsing invalid data - continue; - } - } else { - $extraField = new UnrecognizedExtraField($headerId, $bufferData); - } - $collection->add($extraField); - } finally { - $pos += $data['dataSize']; - } - } - } - - return $collection; - } - - /** - * @param Zip64ExtraField $extraZip64 - * @param ZipEntry $zipEntry - */ - protected function handleZip64Extra(Zip64ExtraField $extraZip64, ZipEntry $zipEntry) - { - $uncompressedSize = $extraZip64->getUncompressedSize(); - $compressedSize = $extraZip64->getCompressedSize(); - $localHeaderOffset = $extraZip64->getLocalHeaderOffset(); - - if ($uncompressedSize !== null) { - $zipEntry->setUncompressedSize($uncompressedSize); - } - - if ($compressedSize !== null) { - $zipEntry->setCompressedSize($compressedSize); - } - - if ($localHeaderOffset !== null) { - $zipEntry->setLocalHeaderOffset($localHeaderOffset); - } - } - - /** - * Read Local File Header. - * - * local file header signature 4 bytes (0x04034b50) - * version needed to extract 2 bytes - * general purpose bit flag 2 bytes - * compression method 2 bytes - * last mod file time 2 bytes - * last mod file date 2 bytes - * crc-32 4 bytes - * compressed size 4 bytes - * uncompressed size 4 bytes - * file name length 2 bytes - * extra field length 2 bytes - * file name (variable size) - * extra field (variable size) - * - * @param ZipEntry $entry - * - * @throws ZipException - */ - protected function loadLocalExtraFields(ZipEntry $entry) - { - $offsetLocalHeader = $entry->getLocalHeaderOffset(); - - fseek($this->inStream, $offsetLocalHeader); - - if (unpack('V', fread($this->inStream, 4))[1] !== ZipConstants::LOCAL_FILE_HEADER) { - throw new ZipException(sprintf('%s (expected Local File Header)', $entry->getName())); - } - - fseek($this->inStream, $offsetLocalHeader + ZipConstants::LFH_FILENAME_LENGTH_POS); - $unpack = unpack('vfileNameLength/vextraFieldLength', fread($this->inStream, 4)); - $offsetData = ftell($this->inStream) - + $unpack['fileNameLength'] - + $unpack['extraFieldLength']; - - fseek($this->inStream, $unpack['fileNameLength'], \SEEK_CUR); - - if ($unpack['extraFieldLength'] > 0) { - $this->parseExtraFields( - fread($this->inStream, $unpack['extraFieldLength']), - $entry, - true - ); - } - - $zipData = new ZipSourceFileData($this, $entry, $offsetData); - $entry->setData($zipData); - } - - /** - * @param ZipEntry $zipEntry - * - * @throws ZipException - */ - private function handleExtraEncryptionFields(ZipEntry $zipEntry) - { - if ($zipEntry->isEncrypted()) { - if ($zipEntry->getCompressionMethod() === ZipCompressionMethod::WINZIP_AES) { - /** @var WinZipAesExtraField|null $extraField */ - $extraField = $zipEntry->getExtraField(WinZipAesExtraField::HEADER_ID); - - if ($extraField === null) { - throw new ZipException( - sprintf( - 'Extra field 0x%04x (WinZip-AES Encryption) expected for compression method %d', - WinZipAesExtraField::HEADER_ID, - $zipEntry->getCompressionMethod() - ) - ); - } - $zipEntry->setCompressionMethod($extraField->getCompressionMethod()); - $zipEntry->setEncryptionMethod($extraField->getEncryptionMethod()); - } else { - $zipEntry->setEncryptionMethod(ZipEncryptionMethod::PKWARE); - } - } - } - - /** - * Handle extra data in zip records. - * - * This is a special method in which you can process ExtraField - * and make changes to ZipEntry. - * - * @param ZipEntry $zipEntry - */ - protected function handleExtraFields(ZipEntry $zipEntry) - { - } - - /** - * @param ZipSourceFileData $zipFileData - * - * @throws ZipException - * @throws Crc32Exception - * - * @return resource - */ - public function getEntryStream(ZipSourceFileData $zipFileData) - { - $outStream = fopen('php://temp', 'w+b'); - $this->copyUncompressedDataToStream($zipFileData, $outStream); - rewind($outStream); - - return $outStream; - } - - /** - * @param ZipSourceFileData $zipFileData - * @param resource $outStream - * - * @throws Crc32Exception - * @throws ZipException - */ - public function copyUncompressedDataToStream(ZipSourceFileData $zipFileData, $outStream) - { - if (!\is_resource($outStream)) { - throw new InvalidArgumentException('outStream is not resource'); - } - - $entry = $zipFileData->getSourceEntry(); - -// if ($entry->isDirectory()) { -// throw new InvalidArgumentException('Streams not supported for directories'); -// } - - if ($entry->isStrongEncryption()) { - throw new ZipException('Not support encryption zip.'); - } - - $compressionMethod = $entry->getCompressionMethod(); - - fseek($this->inStream, $zipFileData->getOffset()); - - $filters = []; - - $skipCheckCrc = false; - $isEncrypted = $entry->isEncrypted(); - - if ($isEncrypted) { - if ($entry->getPassword() === null) { - throw new ZipException('Can not password from entry ' . $entry->getName()); - } - - if (ZipEncryptionMethod::isWinZipAesMethod($entry->getEncryptionMethod())) { - /** @var WinZipAesExtraField|null $winZipAesExtra */ - $winZipAesExtra = $entry->getExtraField(WinZipAesExtraField::HEADER_ID); - - if ($winZipAesExtra === null) { - throw new ZipException( - sprintf('WinZip AES must contain the extra field %s', WinZipAesExtraField::HEADER_ID) - ); - } - $compressionMethod = $winZipAesExtra->getCompressionMethod(); - - WinZipAesDecryptionStreamFilter::register(); - $cipherFilterName = WinZipAesDecryptionStreamFilter::FILTER_NAME; - - if ($winZipAesExtra->isV2()) { - $skipCheckCrc = true; - } - } else { - PKDecryptionStreamFilter::register(); - $cipherFilterName = PKDecryptionStreamFilter::FILTER_NAME; - } - $encContextFilter = stream_filter_append( - $this->inStream, - $cipherFilterName, - \STREAM_FILTER_READ, - [ - 'entry' => $entry, - ] - ); - - if (!$encContextFilter) { - throw new \RuntimeException('Not apply filter ' . $cipherFilterName); - } - $filters[] = $encContextFilter; - } - - // hack, see https://groups.google.com/forum/#!topic/alt.comp.lang.php/37_JZeW63uc - $pos = ftell($this->inStream); - rewind($this->inStream); - fseek($this->inStream, $pos); - - $contextDecompress = null; - switch ($compressionMethod) { - case ZipCompressionMethod::STORED: - // file without compression, do nothing - break; - - case ZipCompressionMethod::DEFLATED: - if (!($contextDecompress = stream_filter_append( - $this->inStream, - 'zlib.inflate', - \STREAM_FILTER_READ - ))) { - throw new \RuntimeException('Could not append filter "zlib.inflate" to stream'); - } - $filters[] = $contextDecompress; - - break; - - case ZipCompressionMethod::BZIP2: - if (!($contextDecompress = stream_filter_append( - $this->inStream, - 'bzip2.decompress', - \STREAM_FILTER_READ - ))) { - throw new \RuntimeException('Could not append filter "bzip2.decompress" to stream'); - } - $filters[] = $contextDecompress; - - break; - - default: - throw new ZipException( - sprintf( - '%s (compression method %d (%s) is not supported)', - $entry->getName(), - $compressionMethod, - ZipCompressionMethod::getCompressionMethodName($compressionMethod) - ) - ); - } - - $limit = $zipFileData->getUncompressedSize(); - - $offset = 0; - $chunkSize = 8192; - - try { - if ($skipCheckCrc) { - while ($offset < $limit) { - $length = min($chunkSize, $limit - $offset); - $buffer = fread($this->inStream, $length); - - if ($buffer === false) { - throw new ZipException(sprintf('Error reading the contents of entry "%s".', $entry->getName())); - } - fwrite($outStream, $buffer); - $offset += $length; - } - } else { - $contextHash = hash_init('crc32b'); - - while ($offset < $limit) { - $length = min($chunkSize, $limit - $offset); - $buffer = fread($this->inStream, $length); - - if ($buffer === false) { - throw new ZipException(sprintf('Error reading the contents of entry "%s".', $entry->getName())); - } - fwrite($outStream, $buffer); - hash_update($contextHash, $buffer); - $offset += $length; - } - - $expectedCrc = (int) hexdec(hash_final($contextHash)); - - if ($expectedCrc !== $entry->getCrc()) { - throw new Crc32Exception($entry->getName(), $expectedCrc, $entry->getCrc()); - } - } - } finally { - for ($i = \count($filters); $i > 0; $i--) { - stream_filter_remove($filters[$i - 1]); - } - } - } - - /** - * @param ZipSourceFileData $zipData - * @param resource $outStream - */ - public function copyCompressedDataToStream(ZipSourceFileData $zipData, $outStream) - { - if ($zipData->getCompressedSize() > 0) { - fseek($this->inStream, $zipData->getOffset()); - stream_copy_to_stream($this->inStream, $outStream, $zipData->getCompressedSize()); - } - } - - /** - * @return bool - */ - protected function isZip64Support() - { - return \PHP_INT_SIZE === 8; // true for 64bit system - } - - public function close() - { - if (\is_resource($this->inStream)) { - fclose($this->inStream); - } - } - - public function __destruct() - { - $this->close(); - } -} diff --git a/vendor/nelexa/zip/src/IO/ZipWriter.php b/vendor/nelexa/zip/src/IO/ZipWriter.php deleted file mode 100644 index b5cc8a8..0000000 --- a/vendor/nelexa/zip/src/IO/ZipWriter.php +++ /dev/null @@ -1,886 +0,0 @@ -zipContainer = clone $container; - } - - /** - * @param resource $outStream - * - * @throws ZipException - */ - public function write($outStream) - { - if (!\is_resource($outStream)) { - throw new \InvalidArgumentException('$outStream must be resource'); - } - $this->beforeWrite(); - $this->writeLocalBlock($outStream); - $cdOffset = ftell($outStream); - $this->writeCentralDirectoryBlock($outStream); - $cdSize = ftell($outStream) - $cdOffset; - $this->writeEndOfCentralDirectoryBlock($outStream, $cdOffset, $cdSize); - } - - protected function beforeWrite() - { - } - - /** - * @param resource $outStream - * - * @throws ZipException - */ - protected function writeLocalBlock($outStream) - { - $zipEntries = $this->zipContainer->getEntries(); - - foreach ($zipEntries as $zipEntry) { - $this->writeLocalHeader($outStream, $zipEntry); - $this->writeData($outStream, $zipEntry); - - if ($zipEntry->isDataDescriptorEnabled()) { - $this->writeDataDescriptor($outStream, $zipEntry); - } - } - } - - /** - * @param resource $outStream - * @param ZipEntry $entry - * - * @throws ZipException - */ - protected function writeLocalHeader($outStream, ZipEntry $entry) - { - // todo in 4.0 version move zipalign functional to ApkWriter class - if ($this->zipContainer->isZipAlign()) { - $this->zipAlign($outStream, $entry); - } - - $relativeOffset = ftell($outStream); - $entry->setLocalHeaderOffset($relativeOffset); - - if ($entry->isEncrypted() && $entry->getEncryptionMethod() === ZipEncryptionMethod::PKWARE) { - $entry->enableDataDescriptor(true); - } - - $dd = $entry->isDataDescriptorRequired() || - $entry->isDataDescriptorEnabled(); - - $compressedSize = $entry->getCompressedSize(); - $uncompressedSize = $entry->getUncompressedSize(); - - $entry->getLocalExtraFields()->remove(Zip64ExtraField::HEADER_ID); - - if ($compressedSize > ZipConstants::ZIP64_MAGIC || $uncompressedSize > ZipConstants::ZIP64_MAGIC) { - $entry->getLocalExtraFields()->add( - new Zip64ExtraField($uncompressedSize, $compressedSize) - ); - - $compressedSize = ZipConstants::ZIP64_MAGIC; - $uncompressedSize = ZipConstants::ZIP64_MAGIC; - } - - $compressionMethod = $entry->getCompressionMethod(); - $crc = $entry->getCrc(); - - if ($entry->isEncrypted() && ZipEncryptionMethod::isWinZipAesMethod($entry->getEncryptionMethod())) { - /** @var WinZipAesExtraField|null $winZipAesExtra */ - $winZipAesExtra = $entry->getLocalExtraField(WinZipAesExtraField::HEADER_ID); - - if ($winZipAesExtra === null) { - $winZipAesExtra = WinZipAesExtraField::create($entry); - } - - if ($winZipAesExtra->isV2()) { - $crc = 0; - } - $compressionMethod = ZipCompressionMethod::WINZIP_AES; - } - - $extra = $this->getExtraFieldsContents($entry, true); - $name = $entry->getName(); - $dosCharset = $entry->getCharset(); - - if ($dosCharset !== null && !$entry->isUtf8Flag()) { - $name = DosCodePage::fromUTF8($name, $dosCharset); - } - - $nameLength = \strlen($name); - $extraLength = \strlen($extra); - - $size = $nameLength + $extraLength; - - if ($size > 0xffff) { - throw new ZipException( - sprintf( - '%s (the total size of %s bytes for the name, extra fields and comment exceeds the maximum size of %d bytes)', - $entry->getName(), - $size, - 0xffff - ) - ); - } - - $extractedBy = ($entry->getExtractedOS() << 8) | $entry->getExtractVersion(); - - fwrite( - $outStream, - pack( - 'VvvvVVVVvv', - // local file header signature 4 bytes (0x04034b50) - ZipConstants::LOCAL_FILE_HEADER, - // version needed to extract 2 bytes - $extractedBy, - // general purpose bit flag 2 bytes - $entry->getGeneralPurposeBitFlags(), - // compression method 2 bytes - $compressionMethod, - // last mod file time 2 bytes - // last mod file date 2 bytes - $entry->getDosTime(), - // crc-32 4 bytes - $dd ? 0 : $crc, - // compressed size 4 bytes - $dd ? 0 : $compressedSize, - // uncompressed size 4 bytes - $dd ? 0 : $uncompressedSize, - // file name length 2 bytes - $nameLength, - // extra field length 2 bytes - $extraLength - ) - ); - - if ($nameLength > 0) { - fwrite($outStream, $name); - } - - if ($extraLength > 0) { - fwrite($outStream, $extra); - } - } - - /** - * @param resource $outStream - * @param ZipEntry $entry - * - * @throws ZipException - */ - private function zipAlign($outStream, ZipEntry $entry) - { - if (!$entry->isDirectory() && $entry->getCompressionMethod() === ZipCompressionMethod::STORED) { - $entry->removeExtraField(ApkAlignmentExtraField::HEADER_ID); - - $extra = $this->getExtraFieldsContents($entry, true); - $extraLength = \strlen($extra); - $name = $entry->getName(); - - $dosCharset = $entry->getCharset(); - - if ($dosCharset !== null && !$entry->isUtf8Flag()) { - $name = DosCodePage::fromUTF8($name, $dosCharset); - } - $nameLength = \strlen($name); - - $multiple = ApkAlignmentExtraField::ALIGNMENT_BYTES; - - if (StringUtil::endsWith($name, '.so')) { - $multiple = ApkAlignmentExtraField::COMMON_PAGE_ALIGNMENT_BYTES; - } - - $offset = ftell($outStream); - - $dataMinStartOffset = - $offset + - ZipConstants::LFH_FILENAME_POS + - $extraLength + - $nameLength; - - $padding = - ($multiple - ($dataMinStartOffset % $multiple)) - % $multiple; - - if ($padding > 0) { - $dataMinStartOffset += ApkAlignmentExtraField::MIN_SIZE; - $padding = - ($multiple - ($dataMinStartOffset % $multiple)) - % $multiple; - - $entry->getLocalExtraFields()->add( - new ApkAlignmentExtraField($multiple, $padding) - ); - } - } - } - - /** - * Merges the local file data fields of the given ZipExtraFields. - * - * @param ZipEntry $entry - * @param bool $local - * - * @throws ZipException - * - * @return string - */ - protected function getExtraFieldsContents(ZipEntry $entry, $local) - { - $local = (bool) $local; - $collection = $local ? - $entry->getLocalExtraFields() : - $entry->getCdExtraFields(); - $extraData = ''; - - foreach ($collection as $extraField) { - if ($local) { - $data = $extraField->packLocalFileData(); - } else { - $data = $extraField->packCentralDirData(); - } - $extraData .= pack( - 'vv', - $extraField->getHeaderId(), - \strlen($data) - ); - $extraData .= $data; - } - - $size = \strlen($extraData); - - if ($size > 0xffff) { - throw new ZipException( - sprintf( - 'Size extra out of range: %d. Extra data: %s', - $size, - $extraData - ) - ); - } - - return $extraData; - } - - /** - * @param resource $outStream - * @param ZipEntry $entry - * - * @throws ZipException - */ - protected function writeData($outStream, ZipEntry $entry) - { - $zipData = $entry->getData(); - - if ($zipData === null) { - if ($entry->isDirectory()) { - return; - } - - throw new ZipException(sprintf('No zip data for entry "%s"', $entry->getName())); - } - - // data write variants: - // -------------------- - // * data of source zip file -> copy compressed data - // * store - simple write - // * store and encryption - apply encryption filter and simple write - // * deflate or bzip2 - apply compression filter and simple write - // * (deflate or bzip2) and encryption - create temp stream and apply - // compression filter to it, then apply encryption filter to root - // stream and write temp stream data. - // (PHP cannot apply the filter for encryption after the compression - // filter, so a temporary stream is created for the compressed data) - - if ($zipData instanceof ZipSourceFileData && !$zipData->hasRecompressData($entry)) { - // data of source zip file -> copy compressed data - $zipData->copyCompressedDataToStream($outStream); - - return; - } - - $entryStream = $zipData->getDataAsStream(); - - if (stream_get_meta_data($entryStream)['seekable']) { - rewind($entryStream); - } - - $uncompressedSize = $entry->getUncompressedSize(); - - $posBeforeWrite = ftell($outStream); - $compressionMethod = $entry->getCompressionMethod(); - - if ($entry->isEncrypted()) { - if ($compressionMethod === ZipCompressionMethod::STORED) { - $contextFilter = $this->appendEncryptionFilter($outStream, $entry, $uncompressedSize); - $checksum = $this->writeAndCountChecksum($entryStream, $outStream, $uncompressedSize); - } else { - $compressStream = fopen('php://temp', 'w+b'); - $contextFilter = $this->appendCompressionFilter($compressStream, $entry); - $checksum = $this->writeAndCountChecksum($entryStream, $compressStream, $uncompressedSize); - - if ($contextFilter !== null) { - stream_filter_remove($contextFilter); - $contextFilter = null; - } - - rewind($compressStream); - - $compressedSize = fstat($compressStream)['size']; - $contextFilter = $this->appendEncryptionFilter($outStream, $entry, $compressedSize); - - stream_copy_to_stream($compressStream, $outStream); - } - } else { - $contextFilter = $this->appendCompressionFilter($outStream, $entry); - $checksum = $this->writeAndCountChecksum($entryStream, $outStream, $uncompressedSize); - } - - if ($contextFilter !== null) { - stream_filter_remove($contextFilter); - $contextFilter = null; - } - - // my hack {@see https://bugs.php.net/bug.php?id=49874} - fseek($outStream, 0, \SEEK_END); - $compressedSize = ftell($outStream) - $posBeforeWrite; - - $entry->setCompressedSize($compressedSize); - $entry->setCrc($checksum); - - if (!$entry->isDataDescriptorEnabled()) { - if ($uncompressedSize > ZipConstants::ZIP64_MAGIC || $compressedSize > ZipConstants::ZIP64_MAGIC) { - /** @var Zip64ExtraField|null $zip64ExtraLocal */ - $zip64ExtraLocal = $entry->getLocalExtraField(Zip64ExtraField::HEADER_ID); - - // if there is a zip64 extra record, then update it; - // if not, write data to data descriptor - if ($zip64ExtraLocal !== null) { - $zip64ExtraLocal->setCompressedSize($compressedSize); - $zip64ExtraLocal->setUncompressedSize($uncompressedSize); - - $posExtra = $entry->getLocalHeaderOffset() + ZipConstants::LFH_FILENAME_POS + \strlen($entry->getName()); - fseek($outStream, $posExtra); - fwrite($outStream, $this->getExtraFieldsContents($entry, true)); - } else { - $posGPBF = $entry->getLocalHeaderOffset() + 6; - $entry->enableDataDescriptor(true); - fseek($outStream, $posGPBF); - fwrite( - $outStream, - pack( - 'v', - // general purpose bit flag 2 bytes - $entry->getGeneralPurposeBitFlags() - ) - ); - } - - $compressedSize = ZipConstants::ZIP64_MAGIC; - $uncompressedSize = ZipConstants::ZIP64_MAGIC; - } - - $posChecksum = $entry->getLocalHeaderOffset() + 14; - - /** @var WinZipAesExtraField|null $winZipAesExtra */ - $winZipAesExtra = $entry->getLocalExtraField(WinZipAesExtraField::HEADER_ID); - - if ($winZipAesExtra !== null && $winZipAesExtra->isV2()) { - $checksum = 0; - } - - fseek($outStream, $posChecksum); - fwrite( - $outStream, - pack( - 'VVV', - // crc-32 4 bytes - $checksum, - // compressed size 4 bytes - $compressedSize, - // uncompressed size 4 bytes - $uncompressedSize - ) - ); - fseek($outStream, 0, \SEEK_END); - } - } - - /** - * @param resource $inStream - * @param resource $outStream - * @param int $size - * - * @return int - */ - private function writeAndCountChecksum($inStream, $outStream, $size) - { - $contextHash = hash_init('crc32b'); - $offset = 0; - - while ($offset < $size) { - $read = min(self::CHUNK_SIZE, $size - $offset); - $buffer = fread($inStream, $read); - fwrite($outStream, $buffer); - hash_update($contextHash, $buffer); - $offset += $read; - } - - return (int) hexdec(hash_final($contextHash)); - } - - /** - * @param resource $outStream - * @param ZipEntry $entry - * - * @throws ZipUnsupportMethodException - * - * @return resource|null - */ - protected function appendCompressionFilter($outStream, ZipEntry $entry) - { - $contextCompress = null; - switch ($entry->getCompressionMethod()) { - case ZipCompressionMethod::DEFLATED: - if (!($contextCompress = stream_filter_append( - $outStream, - 'zlib.deflate', - \STREAM_FILTER_WRITE, - ['level' => $entry->getCompressionLevel()] - ))) { - throw new \RuntimeException('Could not append filter "zlib.deflate" to out stream'); - } - break; - - case ZipCompressionMethod::BZIP2: - if (!($contextCompress = stream_filter_append( - $outStream, - 'bzip2.compress', - \STREAM_FILTER_WRITE, - ['blocks' => $entry->getCompressionLevel(), 'work' => 0] - ))) { - throw new \RuntimeException('Could not append filter "bzip2.compress" to out stream'); - } - break; - - case ZipCompressionMethod::STORED: - // file without compression, do nothing - break; - - default: - throw new ZipUnsupportMethodException( - sprintf( - '%s (compression method %d (%s) is not supported)', - $entry->getName(), - $entry->getCompressionMethod(), - ZipCompressionMethod::getCompressionMethodName($entry->getCompressionMethod()) - ) - ); - } - - return $contextCompress; - } - - /** - * @param resource $outStream - * @param ZipEntry $entry - * @param int $size - * - * @return resource|null - */ - protected function appendEncryptionFilter($outStream, ZipEntry $entry, $size) - { - $encContextFilter = null; - - if ($entry->isEncrypted()) { - if ($entry->getEncryptionMethod() === ZipEncryptionMethod::PKWARE) { - PKEncryptionStreamFilter::register(); - $cipherFilterName = PKEncryptionStreamFilter::FILTER_NAME; - } else { - WinZipAesEncryptionStreamFilter::register(); - $cipherFilterName = WinZipAesEncryptionStreamFilter::FILTER_NAME; - } - $encContextFilter = stream_filter_append( - $outStream, - $cipherFilterName, - \STREAM_FILTER_WRITE, - [ - 'entry' => $entry, - 'size' => $size, - ] - ); - - if (!$encContextFilter) { - throw new \RuntimeException('Not apply filter ' . $cipherFilterName); - } - } - - return $encContextFilter; - } - - /** - * @param resource $outStream - * @param ZipEntry $entry - */ - protected function writeDataDescriptor($outStream, ZipEntry $entry) - { - $crc = $entry->getCrc(); - - /** @var WinZipAesExtraField|null $winZipAesExtra */ - $winZipAesExtra = $entry->getLocalExtraField(WinZipAesExtraField::HEADER_ID); - - if ($winZipAesExtra !== null && $winZipAesExtra->isV2()) { - $crc = 0; - } - - fwrite( - $outStream, - pack( - 'VV', - // data descriptor signature 4 bytes (0x08074b50) - ZipConstants::DATA_DESCRIPTOR, - // crc-32 4 bytes - $crc - ) - ); - - if ( - $entry->isZip64ExtensionsRequired() || - $entry->getLocalExtraFields()->has(Zip64ExtraField::HEADER_ID) - ) { - $dd = - // compressed size 8 bytes - PackUtil::packLongLE($entry->getCompressedSize()) . - // uncompressed size 8 bytes - PackUtil::packLongLE($entry->getUncompressedSize()); - } else { - $dd = pack( - 'VV', - // compressed size 4 bytes - $entry->getCompressedSize(), - // uncompressed size 4 bytes - $entry->getUncompressedSize() - ); - } - - fwrite($outStream, $dd); - } - - /** - * @param resource $outStream - * - * @throws ZipException - */ - protected function writeCentralDirectoryBlock($outStream) - { - foreach ($this->zipContainer->getEntries() as $outputEntry) { - $this->writeCentralDirectoryHeader($outStream, $outputEntry); - } - } - - /** - * Writes a Central File Header record. - * - * @param resource $outStream - * @param ZipEntry $entry - * - * @throws ZipException - */ - protected function writeCentralDirectoryHeader($outStream, ZipEntry $entry) - { - $compressedSize = $entry->getCompressedSize(); - $uncompressedSize = $entry->getUncompressedSize(); - $localHeaderOffset = $entry->getLocalHeaderOffset(); - - $entry->getCdExtraFields()->remove(Zip64ExtraField::HEADER_ID); - - if ( - $localHeaderOffset > ZipConstants::ZIP64_MAGIC || - $compressedSize > ZipConstants::ZIP64_MAGIC || - $uncompressedSize > ZipConstants::ZIP64_MAGIC - ) { - $zip64ExtraField = new Zip64ExtraField(); - - if ($uncompressedSize >= ZipConstants::ZIP64_MAGIC) { - $zip64ExtraField->setUncompressedSize($uncompressedSize); - $uncompressedSize = ZipConstants::ZIP64_MAGIC; - } - - if ($compressedSize >= ZipConstants::ZIP64_MAGIC) { - $zip64ExtraField->setCompressedSize($compressedSize); - $compressedSize = ZipConstants::ZIP64_MAGIC; - } - - if ($localHeaderOffset >= ZipConstants::ZIP64_MAGIC) { - $zip64ExtraField->setLocalHeaderOffset($localHeaderOffset); - $localHeaderOffset = ZipConstants::ZIP64_MAGIC; - } - - $entry->getCdExtraFields()->add($zip64ExtraField); - } - - $extra = $this->getExtraFieldsContents($entry, false); - $extraLength = \strlen($extra); - - $name = $entry->getName(); - $comment = $entry->getComment(); - - $dosCharset = $entry->getCharset(); - - if ($dosCharset !== null && !$entry->isUtf8Flag()) { - $name = DosCodePage::fromUTF8($name, $dosCharset); - - if ($comment) { - $comment = DosCodePage::fromUTF8($comment, $dosCharset); - } - } - - $commentLength = \strlen($comment); - - $compressionMethod = $entry->getCompressionMethod(); - $crc = $entry->getCrc(); - - /** @var WinZipAesExtraField|null $winZipAesExtra */ - $winZipAesExtra = $entry->getLocalExtraField(WinZipAesExtraField::HEADER_ID); - - if ($winZipAesExtra !== null) { - if ($winZipAesExtra->isV2()) { - $crc = 0; - } - $compressionMethod = ZipCompressionMethod::WINZIP_AES; - } - - fwrite( - $outStream, - pack( - 'VvvvvVVVVvvvvvVV', - // central file header signature 4 bytes (0x02014b50) - ZipConstants::CENTRAL_FILE_HEADER, - // version made by 2 bytes - ($entry->getCreatedOS() << 8) | $entry->getSoftwareVersion(), - // version needed to extract 2 bytes - ($entry->getExtractedOS() << 8) | $entry->getExtractVersion(), - // general purpose bit flag 2 bytes - $entry->getGeneralPurposeBitFlags(), - // compression method 2 bytes - $compressionMethod, - // last mod file datetime 4 bytes - $entry->getDosTime(), - // crc-32 4 bytes - $crc, - // compressed size 4 bytes - $compressedSize, - // uncompressed size 4 bytes - $uncompressedSize, - // file name length 2 bytes - \strlen($name), - // extra field length 2 bytes - $extraLength, - // file comment length 2 bytes - $commentLength, - // disk number start 2 bytes - 0, - // internal file attributes 2 bytes - $entry->getInternalAttributes(), - // external file attributes 4 bytes - $entry->getExternalAttributes(), - // relative offset of local header 4 bytes - $localHeaderOffset - ) - ); - - // file name (variable size) - fwrite($outStream, $name); - - if ($extraLength > 0) { - // extra field (variable size) - fwrite($outStream, $extra); - } - - if ($commentLength > 0) { - // file comment (variable size) - fwrite($outStream, $comment); - } - } - - /** - * @param resource $outStream - * @param int $centralDirectoryOffset - * @param int $centralDirectorySize - */ - protected function writeEndOfCentralDirectoryBlock( - $outStream, - $centralDirectoryOffset, - $centralDirectorySize - ) { - $cdEntriesCount = \count($this->zipContainer); - - $cdEntriesZip64 = $cdEntriesCount > 0xffff; - $cdSizeZip64 = $centralDirectorySize > ZipConstants::ZIP64_MAGIC; - $cdOffsetZip64 = $centralDirectoryOffset > ZipConstants::ZIP64_MAGIC; - - $zip64Required = $cdEntriesZip64 - || $cdSizeZip64 - || $cdOffsetZip64; - - if ($zip64Required) { - $zip64EndOfCentralDirectoryOffset = ftell($outStream); - - // find max software version, version needed to extract and most common platform - list($softwareVersion, $versionNeededToExtract) = array_reduce( - $this->zipContainer->getEntries(), - static function (array $carry, ZipEntry $entry) { - $carry[0] = max($carry[0], $entry->getSoftwareVersion() & 0xFF); - $carry[1] = max($carry[1], $entry->getExtractVersion() & 0xFF); - - return $carry; - }, - [ZipVersion::v10_DEFAULT_MIN, ZipVersion::v45_ZIP64_EXT] - ); - - $createdOS = $extractedOS = ZipPlatform::OS_DOS; - $versionMadeBy = ($createdOS << 8) | max($softwareVersion, ZipVersion::v45_ZIP64_EXT); - $versionExtractedBy = ($extractedOS << 8) | max($versionNeededToExtract, ZipVersion::v45_ZIP64_EXT); - - // write zip64 end of central directory signature - fwrite( - $outStream, - pack( - 'V', - // signature 4 bytes (0x06064b50) - ZipConstants::ZIP64_END_CD - ) - ); - // size of zip64 end of central - // directory record 8 bytes - fwrite($outStream, PackUtil::packLongLE(ZipConstants::ZIP64_END_OF_CD_LEN - 12)); - fwrite( - $outStream, - pack( - 'vvVV', - // version made by 2 bytes - $versionMadeBy & 0xFFFF, - // version needed to extract 2 bytes - $versionExtractedBy & 0xFFFF, - // number of this disk 4 bytes - 0, - // number of the disk with the - // start of the central directory 4 bytes - 0 - ) - ); - - fwrite( - $outStream, - // total number of entries in the - // central directory on this disk 8 bytes - PackUtil::packLongLE($cdEntriesCount) . - // total number of entries in the - // central directory 8 bytes - PackUtil::packLongLE($cdEntriesCount) . - // size of the central directory 8 bytes - PackUtil::packLongLE($centralDirectorySize) . - // offset of start of central - // directory with respect to - // the starting disk number 8 bytes - PackUtil::packLongLE($centralDirectoryOffset) - ); - - // write zip64 end of central directory locator - fwrite( - $outStream, - pack( - 'VV', - // zip64 end of central dir locator - // signature 4 bytes (0x07064b50) - ZipConstants::ZIP64_END_CD_LOC, - // number of the disk with the - // start of the zip64 end of - // central directory 4 bytes - 0 - ) . - // relative offset of the zip64 - // end of central directory record 8 bytes - PackUtil::packLongLE($zip64EndOfCentralDirectoryOffset) . - // total number of disks 4 bytes - pack('V', 1) - ); - } - - $comment = $this->zipContainer->getArchiveComment(); - $commentLength = $comment !== null ? \strlen($comment) : 0; - - fwrite( - $outStream, - pack( - 'VvvvvVVv', - // end of central dir signature 4 bytes (0x06054b50) - ZipConstants::END_CD, - // number of this disk 2 bytes - 0, - // number of the disk with the - // start of the central directory 2 bytes - 0, - // total number of entries in the - // central directory on this disk 2 bytes - $cdEntriesZip64 ? 0xffff : $cdEntriesCount, - // total number of entries in - // the central directory 2 bytes - $cdEntriesZip64 ? 0xffff : $cdEntriesCount, - // size of the central directory 4 bytes - $cdSizeZip64 ? ZipConstants::ZIP64_MAGIC : $centralDirectorySize, - // offset of start of central - // directory with respect to - // the starting disk number 4 bytes - $cdOffsetZip64 ? ZipConstants::ZIP64_MAGIC : $centralDirectoryOffset, - // .ZIP file comment length 2 bytes - $commentLength - ) - ); - - if ($comment !== null && $commentLength > 0) { - // .ZIP file comment (variable size) - fwrite($outStream, $comment); - } - } -} diff --git a/vendor/nelexa/zip/src/IO/index.php b/vendor/nelexa/zip/src/IO/index.php deleted file mode 100644 index df24d3e..0000000 --- a/vendor/nelexa/zip/src/IO/index.php +++ /dev/null @@ -1,35 +0,0 @@ - - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA - */ - -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); - -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); - -header("Location: ../"); -exit; diff --git a/vendor/nelexa/zip/src/Model/Data/ZipFileData.php b/vendor/nelexa/zip/src/Model/Data/ZipFileData.php deleted file mode 100644 index 43590c5..0000000 --- a/vendor/nelexa/zip/src/Model/Data/ZipFileData.php +++ /dev/null @@ -1,81 +0,0 @@ -isFile()) { - throw new ZipException('$fileInfo is not a file.'); - } - - if (!$fileInfo->isReadable()) { - throw new ZipException('$fileInfo is not readable.'); - } - - $this->file = $fileInfo; - $zipEntry->setUncompressedSize($fileInfo->getSize()); - } - - /** - * @throws ZipException - * - * @return resource returns stream data - */ - public function getDataAsStream() - { - if (!$this->file->isReadable()) { - throw new ZipException(sprintf('The %s file is no longer readable.', $this->file->getPathname())); - } - - return fopen($this->file->getPathname(), 'rb'); - } - - /** - * @throws ZipException - * - * @return string returns data as string - */ - public function getDataAsString() - { - if (!$this->file->isReadable()) { - throw new ZipException(sprintf('The %s file is no longer readable.', $this->file->getPathname())); - } - - return file_get_contents($this->file->getPathname()); - } - - /** - * @param resource $outStream - * - * @throws ZipException - */ - public function copyDataToStream($outStream) - { - try { - $stream = $this->getDataAsStream(); - stream_copy_to_stream($stream, $outStream); - } finally { - fclose($stream); - } - } -} diff --git a/vendor/nelexa/zip/src/Model/Data/ZipNewData.php b/vendor/nelexa/zip/src/Model/Data/ZipNewData.php deleted file mode 100644 index 68f76f6..0000000 --- a/vendor/nelexa/zip/src/Model/Data/ZipNewData.php +++ /dev/null @@ -1,130 +0,0 @@ - array of resource ids and the number of class clones - */ - private static $guardClonedStream = []; - - /** @var ZipEntry */ - private $zipEntry; - - /** @var resource */ - private $stream; - - /** - * ZipStringData constructor. - * - * @param ZipEntry $zipEntry - * @param string|resource $data - */ - public function __construct(ZipEntry $zipEntry, $data) - { - $this->zipEntry = $zipEntry; - - if (\is_string($data)) { - $zipEntry->setUncompressedSize(\strlen($data)); - - if (!($handle = fopen('php://temp', 'w+b'))) { - throw new \RuntimeException('Temp resource can not open from write.'); - } - fwrite($handle, $data); - rewind($handle); - $this->stream = $handle; - } elseif (\is_resource($data)) { - $this->stream = $data; - } - - $resourceId = (int) $this->stream; - self::$guardClonedStream[$resourceId] = - isset(self::$guardClonedStream[$resourceId]) ? - self::$guardClonedStream[$resourceId] + 1 : - 0; - } - - /** - * @return resource returns stream data - */ - public function getDataAsStream() - { - if (!\is_resource($this->stream)) { - throw new \LogicException(sprintf('Resource was closed (entry=%s).', $this->zipEntry->getName())); - } - - return $this->stream; - } - - /** - * @return string returns data as string - */ - public function getDataAsString() - { - $stream = $this->getDataAsStream(); - $pos = ftell($stream); - - try { - rewind($stream); - - return stream_get_contents($stream); - } finally { - fseek($stream, $pos); - } - } - - /** - * @param resource $outStream - */ - public function copyDataToStream($outStream) - { - $stream = $this->getDataAsStream(); - rewind($stream); - stream_copy_to_stream($stream, $outStream); - } - - /** - * @see https://php.net/manual/en/language.oop5.cloning.php - */ - public function __clone() - { - $resourceId = (int) $this->stream; - self::$guardClonedStream[$resourceId] = - isset(self::$guardClonedStream[$resourceId]) ? - self::$guardClonedStream[$resourceId] + 1 : - 1; - } - - /** - * The stream will be closed when closing the zip archive. - * - * The method implements protection against closing the stream of the cloned object. - * - * @see ZipFile::close() - */ - public function __destruct() - { - $resourceId = (int) $this->stream; - - if (isset(self::$guardClonedStream[$resourceId]) && self::$guardClonedStream[$resourceId] > 0) { - self::$guardClonedStream[$resourceId]--; - - return; - } - - if (\is_resource($this->stream)) { - fclose($this->stream); - } - } -} diff --git a/vendor/nelexa/zip/src/Model/Data/ZipSourceFileData.php b/vendor/nelexa/zip/src/Model/Data/ZipSourceFileData.php deleted file mode 100644 index c53df05..0000000 --- a/vendor/nelexa/zip/src/Model/Data/ZipSourceFileData.php +++ /dev/null @@ -1,172 +0,0 @@ -zipReader = $zipReader; - $this->offset = $offsetData; - $this->sourceEntry = $zipEntry; - $this->compressedSize = $zipEntry->getCompressedSize(); - $this->uncompressedSize = $zipEntry->getUncompressedSize(); - } - - /** - * @param ZipEntry $entry - * - * @return bool - */ - public function hasRecompressData(ZipEntry $entry) - { - return $this->sourceEntry->getCompressionLevel() !== $entry->getCompressionLevel() || - $this->sourceEntry->getCompressionMethod() !== $entry->getCompressionMethod() || - $this->sourceEntry->isEncrypted() !== $entry->isEncrypted() || - $this->sourceEntry->getEncryptionMethod() !== $entry->getEncryptionMethod() || - $this->sourceEntry->getPassword() !== $entry->getPassword() || - $this->sourceEntry->getCompressedSize() !== $entry->getCompressedSize() || - $this->sourceEntry->getUncompressedSize() !== $entry->getUncompressedSize() || - $this->sourceEntry->getCrc() !== $entry->getCrc(); - } - - /** - * @throws ZipException - * - * @return resource returns stream data - */ - public function getDataAsStream() - { - if (!\is_resource($this->stream)) { - $this->stream = $this->zipReader->getEntryStream($this); - } - - return $this->stream; - } - - /** - * @throws ZipException - * - * @return string returns data as string - */ - public function getDataAsString() - { - $autoClosable = $this->stream === null; - - $stream = $this->getDataAsStream(); - $pos = ftell($stream); - - try { - rewind($stream); - - return stream_get_contents($stream); - } finally { - if ($autoClosable) { - fclose($stream); - $this->stream = null; - } else { - fseek($stream, $pos); - } - } - } - - /** - * @param resource $outputStream Output stream - * - * @throws ZipException - * @throws Crc32Exception - */ - public function copyDataToStream($outputStream) - { - if (\is_resource($this->stream)) { - rewind($this->stream); - stream_copy_to_stream($this->stream, $outputStream); - } else { - $this->zipReader->copyUncompressedDataToStream($this, $outputStream); - } - } - - /** - * @param resource $outputStream Output stream - */ - public function copyCompressedDataToStream($outputStream) - { - $this->zipReader->copyCompressedDataToStream($this, $outputStream); - } - - /** - * @return ZipEntry - */ - public function getSourceEntry() - { - return $this->sourceEntry; - } - - /** - * @return int - */ - public function getCompressedSize() - { - return $this->compressedSize; - } - - /** - * @return int - */ - public function getUncompressedSize() - { - return $this->uncompressedSize; - } - - /** - * @return int - */ - public function getOffset() - { - return $this->offset; - } - - /** - * {@inheritdoc} - */ - public function __destruct() - { - if (\is_resource($this->stream)) { - fclose($this->stream); - } - } -} diff --git a/vendor/nelexa/zip/src/Model/Data/index.php b/vendor/nelexa/zip/src/Model/Data/index.php deleted file mode 100644 index df24d3e..0000000 --- a/vendor/nelexa/zip/src/Model/Data/index.php +++ /dev/null @@ -1,35 +0,0 @@ - - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA - */ - -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); - -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); - -header("Location: ../"); -exit; diff --git a/vendor/nelexa/zip/src/Model/EndOfCentralDirectory.php b/vendor/nelexa/zip/src/Model/EndOfCentralDirectory.php deleted file mode 100644 index d312cfe..0000000 --- a/vendor/nelexa/zip/src/Model/EndOfCentralDirectory.php +++ /dev/null @@ -1,93 +0,0 @@ -entryCount = $entryCount; - $this->cdOffset = $cdOffset; - $this->cdSize = $cdSize; - $this->zip64 = $zip64; - $this->comment = $comment; - } - - /** - * @param string|null $comment - */ - public function setComment($comment) - { - $this->comment = $comment; - } - - /** - * @return int - */ - public function getEntryCount() - { - return $this->entryCount; - } - - /** - * @return int - */ - public function getCdOffset() - { - return $this->cdOffset; - } - - /** - * @return int - */ - public function getCdSize() - { - return $this->cdSize; - } - - /** - * @return string|null - */ - public function getComment() - { - return $this->comment; - } - - /** - * @return bool - */ - public function isZip64() - { - return $this->zip64; - } -} diff --git a/vendor/nelexa/zip/src/Model/Extra/ExtraFieldsCollection.php b/vendor/nelexa/zip/src/Model/Extra/ExtraFieldsCollection.php deleted file mode 100644 index 9cc2020..0000000 --- a/vendor/nelexa/zip/src/Model/Extra/ExtraFieldsCollection.php +++ /dev/null @@ -1,276 +0,0 @@ -collection); - } - - /** - * Returns the Extra Field with the given Header ID or null - * if no such Extra Field exists. - * - * @param int $headerId the requested Header ID - * - * @return ZipExtraField|null the Extra Field with the given Header ID or - * if no such Extra Field exists - */ - public function get($headerId) - { - $this->validateHeaderId($headerId); - - return isset($this->collection[$headerId]) ? $this->collection[$headerId] : null; - } - - /** - * @param int $headerId - */ - private function validateHeaderId($headerId) - { - if ($headerId < 0 || $headerId > 0xffff) { - throw new \InvalidArgumentException('$headerId out of range'); - } - } - - /** - * Stores the given Extra Field in this collection. - * - * @param ZipExtraField $extraField the Extra Field to store in this collection - * - * @return ZipExtraField the Extra Field previously associated with the Header ID of - * of the given Extra Field or null if no such Extra Field existed - */ - public function add(ZipExtraField $extraField) - { - $headerId = $extraField->getHeaderId(); - - $this->validateHeaderId($headerId); - $this->collection[$headerId] = $extraField; - - return $extraField; - } - - /** - * @param ZipExtraField[] $extraFields - */ - public function addAll(array $extraFields) - { - foreach ($extraFields as $extraField) { - $this->add($extraField); - } - } - - /** - * @param ExtraFieldsCollection $collection - */ - public function addCollection(self $collection) - { - $this->addAll($collection->collection); - } - - /** - * @return ZipExtraField[] - */ - public function getAll() - { - return $this->collection; - } - - /** - * Returns Extra Field exists. - * - * @param int $headerId the requested Header ID - * - * @return bool - */ - public function has($headerId) - { - return isset($this->collection[$headerId]); - } - - /** - * Removes the Extra Field with the given Header ID. - * - * @param int $headerId the requested Header ID - * - * @return ZipExtraField|null the Extra Field with the given Header ID or null - * if no such Extra Field exists - */ - public function remove($headerId) - { - $this->validateHeaderId($headerId); - - if (isset($this->collection[$headerId])) { - $ef = $this->collection[$headerId]; - unset($this->collection[$headerId]); - - return $ef; - } - - return null; - } - - /** - * Whether a offset exists. - * - * @see http://php.net/manual/en/arrayaccess.offsetexists.php - * - * @param int $offset an offset to check for - * - * @return bool true on success or false on failure - */ - public function offsetExists($offset) - { - return isset($this->collection[(int) $offset]); - } - - /** - * Offset to retrieve. - * - * @see http://php.net/manual/en/arrayaccess.offsetget.php - * - * @param int $offset the offset to retrieve - * - * @return ZipExtraField|null - */ - public function offsetGet($offset) - { - return isset($this->collection[$offset]) ? $this->collection[$offset] : null; - } - - /** - * Offset to set. - * - * @see http://php.net/manual/en/arrayaccess.offsetset.php - * - * @param mixed $offset the offset to assign the value to - * @param ZipExtraField $value the value to set - */ - public function offsetSet($offset, $value) - { - if (!$value instanceof ZipExtraField) { - throw new \InvalidArgumentException('value is not instanceof ' . ZipExtraField::class); - } - $this->add($value); - } - - /** - * Offset to unset. - * - * @see http://php.net/manual/en/arrayaccess.offsetunset.php - * - * @param mixed $offset the offset to unset - */ - public function offsetUnset($offset) - { - $this->remove($offset); - } - - /** - * Return the current element. - * - * @see http://php.net/manual/en/iterator.current.php - * - * @return ZipExtraField - */ - public function current() - { - return current($this->collection); - } - - /** - * Move forward to next element. - * - * @see http://php.net/manual/en/iterator.next.php - */ - public function next() - { - next($this->collection); - } - - /** - * Return the key of the current element. - * - * @see http://php.net/manual/en/iterator.key.php - * - * @return int scalar on success, or null on failure - */ - public function key() - { - return key($this->collection); - } - - /** - * Checks if current position is valid. - * - * @see http://php.net/manual/en/iterator.valid.php - * - * @return bool The return value will be casted to boolean and then evaluated. - * Returns true on success or false on failure. - */ - public function valid() - { - return key($this->collection) !== null; - } - - /** - * Rewind the Iterator to the first element. - * - * @see http://php.net/manual/en/iterator.rewind.php - */ - public function rewind() - { - reset($this->collection); - } - - public function clear() - { - $this->collection = []; - } - - /** - * @return string - */ - public function __toString() - { - $formats = []; - - foreach ($this->collection as $key => $value) { - $formats[] = (string) $value; - } - - return implode("\n", $formats); - } - - /** - * If clone extra fields. - */ - public function __clone() - { - foreach ($this->collection as $k => $v) { - $this->collection[$k] = clone $v; - } - } -} diff --git a/vendor/nelexa/zip/src/Model/Extra/Fields/AbstractUnicodeExtraField.php b/vendor/nelexa/zip/src/Model/Extra/Fields/AbstractUnicodeExtraField.php deleted file mode 100644 index dd6f566..0000000 --- a/vendor/nelexa/zip/src/Model/Extra/Fields/AbstractUnicodeExtraField.php +++ /dev/null @@ -1,133 +0,0 @@ -crc32 = (int) $crc32; - $this->unicodeValue = (string) $unicodeValue; - } - - /** - * @return int the CRC32 checksum of the filename or comment as - * encoded in the central directory of the zip file - */ - public function getCrc32() - { - return $this->crc32; - } - - /** - * @param int $crc32 - */ - public function setCrc32($crc32) - { - $this->crc32 = (int) $crc32; - } - - /** - * @return string - */ - public function getUnicodeValue() - { - return $this->unicodeValue; - } - - /** - * @param string $unicodeValue the UTF-8 encoded name to set - */ - public function setUnicodeValue($unicodeValue) - { - $this->unicodeValue = $unicodeValue; - } - - /** - * Populate data from this array as if it was in local file data. - * - * @param string $buffer the buffer to read data from - * @param ZipEntry|null $entry - * - * @throws ZipException on error - * - * @return static - */ - public static function unpackLocalFileData($buffer, ZipEntry $entry = null) - { - if (\strlen($buffer) < 5) { - throw new ZipException('Unicode path extra data must have at least 5 bytes.'); - } - - $data = unpack('Cversion/Vcrc32', $buffer); - - if ($data['version'] !== self::DEFAULT_VERSION) { - throw new ZipException(sprintf('Unsupported version [%d] for Unicode path extra data.', $data['version'])); - } - - $unicodeValue = substr($buffer, 5); - - return new static($data['crc32'], $unicodeValue); - } - - /** - * Populate data from this array as if it was in central directory data. - * - * @param string $buffer the buffer to read data from - * @param ZipEntry|null $entry - * - * @throws ZipException on error - * - * @return static - */ - public static function unpackCentralDirData($buffer, ZipEntry $entry = null) - { - return self::unpackLocalFileData($buffer, $entry); - } - - /** - * The actual data to put into local file data - without Header-ID - * or length specifier. - * - * @return string the data - */ - public function packLocalFileData() - { - return pack( - 'CV', - self::DEFAULT_VERSION, - $this->crc32 - ) . - $this->unicodeValue; - } - - /** - * The actual data to put into central directory - without Header-ID or - * length specifier. - * - * @return string the data - */ - public function packCentralDirData() - { - return $this->packLocalFileData(); - } -} diff --git a/vendor/nelexa/zip/src/Model/Extra/Fields/ApkAlignmentExtraField.php b/vendor/nelexa/zip/src/Model/Extra/Fields/ApkAlignmentExtraField.php deleted file mode 100644 index 69c26b8..0000000 --- a/vendor/nelexa/zip/src/Model/Extra/Fields/ApkAlignmentExtraField.php +++ /dev/null @@ -1,176 +0,0 @@ -multiple = $multiple; - $this->padding = $padding; - } - - /** - * Returns the Header ID (type) of this Extra Field. - * The Header ID is an unsigned short integer (two bytes) - * which must be constant during the life cycle of this object. - * - * @return int - */ - public function getHeaderId() - { - return self::HEADER_ID; - } - - /** - * @return int - */ - public function getMultiple() - { - return $this->multiple; - } - - /** - * @return int - */ - public function getPadding() - { - return $this->padding; - } - - /** - * @param int $multiple - */ - public function setMultiple($multiple) - { - $this->multiple = (int) $multiple; - } - - /** - * @param int $padding - */ - public function setPadding($padding) - { - $this->padding = (int) $padding; - } - - /** - * Populate data from this array as if it was in local file data. - * - * @param string $buffer the buffer to read data from - * @param ZipEntry|null $entry - * - * @throws ZipException - * - * @return ApkAlignmentExtraField - */ - public static function unpackLocalFileData($buffer, ZipEntry $entry = null) - { - $length = \strlen($buffer); - - if ($length < 2) { - // This is APK alignment field. - // FORMAT: - // * uint16 alignment multiple (in bytes) - // * remaining bytes -- padding to achieve alignment of data which starts after - // the extra field - throw new ZipException( - 'Minimum 6 bytes of the extensible data block/field used for alignment of uncompressed entries.' - ); - } - $multiple = unpack('v', $buffer)[1]; - $padding = $length - 2; - - return new self($multiple, $padding); - } - - /** - * Populate data from this array as if it was in central directory data. - * - * @param string $buffer the buffer to read data from - * @param ZipEntry|null $entry - * - * @throws ZipException on error - * - * @return ApkAlignmentExtraField - */ - public static function unpackCentralDirData($buffer, ZipEntry $entry = null) - { - return self::unpackLocalFileData($buffer, $entry); - } - - /** - * The actual data to put into local file data - without Header-ID - * or length specifier. - * - * @return string the data - */ - public function packLocalFileData() - { - return pack('vx' . $this->padding, $this->multiple); - } - - /** - * The actual data to put into central directory - without Header-ID or - * length specifier. - * - * @return string the data - */ - public function packCentralDirData() - { - return $this->packLocalFileData(); - } - - /** - * @return string - */ - public function __toString() - { - return sprintf( - '0x%04x APK Alignment: Multiple=%d Padding=%d', - self::HEADER_ID, - $this->multiple, - $this->padding - ); - } -} diff --git a/vendor/nelexa/zip/src/Model/Extra/Fields/AsiExtraField.php b/vendor/nelexa/zip/src/Model/Extra/Fields/AsiExtraField.php deleted file mode 100644 index 3bf62b9..0000000 --- a/vendor/nelexa/zip/src/Model/Extra/Fields/AsiExtraField.php +++ /dev/null @@ -1,302 +0,0 @@ -mode = $mode; - $this->uid = $uid; - $this->gid = $gid; - $this->link = $link; - } - - /** - * Returns the Header ID (type) of this Extra Field. - * The Header ID is an unsigned short integer (two bytes) - * which must be constant during the life cycle of this object. - * - * @return int - */ - public function getHeaderId() - { - return self::HEADER_ID; - } - - /** - * Populate data from this array as if it was in local file data. - * - * @param string $buffer the buffer to read data from - * @param ZipEntry|null $entry - * - * @throws Crc32Exception - * - * @return static - */ - public static function unpackLocalFileData($buffer, ZipEntry $entry = null) - { - $givenChecksum = unpack('V', $buffer)[1]; - $buffer = substr($buffer, 4); - $realChecksum = crc32($buffer); - - if ($givenChecksum !== $realChecksum) { - throw new Crc32Exception('Asi Unix Extra Filed Data', $givenChecksum, $realChecksum); - } - - $data = unpack('vmode/VlinkSize/vuid/vgid', $buffer); - $link = ''; - - if ($data['linkSize'] > 0) { - $link = substr($buffer, 10); - } - - return new self($data['mode'], $data['uid'], $data['gid'], $link); - } - - /** - * Populate data from this array as if it was in central directory data. - * - * @param string $buffer the buffer to read data from - * @param ZipEntry|null $entry - * - * @throws Crc32Exception - * - * @return AsiExtraField - */ - public static function unpackCentralDirData($buffer, ZipEntry $entry = null) - { - return self::unpackLocalFileData($buffer, $entry); - } - - /** - * The actual data to put into local file data - without Header-ID - * or length specifier. - * - * @return string the data - */ - public function packLocalFileData() - { - $data = pack( - 'vVvv', - $this->mode, - \strlen($this->link), - $this->uid, - $this->gid - ) . $this->link; - - return pack('V', crc32($data)) . $data; - } - - /** - * The actual data to put into central directory - without Header-ID or - * length specifier. - * - * @return string the data - */ - public function packCentralDirData() - { - return $this->packLocalFileData(); - } - - /** - * Name of linked file. - * - * @return string name of the file this entry links to if it is a - * symbolic link, the empty string otherwise - */ - public function getLink() - { - return $this->link; - } - - /** - * Indicate that this entry is a symbolic link to the given filename. - * - * @param string $link name of the file this entry links to, empty - * string if it is not a symbolic link - */ - public function setLink($link) - { - $this->link = (string) $link; - $this->mode = $this->getPermissionsMode($this->mode); - } - - /** - * Is this entry a symbolic link? - * - * @return bool true if this is a symbolic link - */ - public function isLink() - { - return !empty($this->link); - } - - /** - * Get the file mode for given permissions with the correct file type. - * - * @param int $mode the mode - * - * @return int the type with the mode - */ - protected function getPermissionsMode($mode) - { - $type = 0; - - if ($this->isLink()) { - $type = UnixStat::UNX_IFLNK; - } elseif (($mode & UnixStat::UNX_IFREG) !== 0) { - $type = UnixStat::UNX_IFREG; - } elseif (($mode & UnixStat::UNX_IFDIR) !== 0) { - $type = UnixStat::UNX_IFDIR; - } - - return $type | ($mode & self::PERM_MASK); - } - - /** - * Is this entry a directory? - * - * @return bool true if this entry is a directory - */ - public function isDirectory() - { - return ($this->mode & UnixStat::UNX_IFDIR) !== 0 && !$this->isLink(); - } - - /** - * @return int - */ - public function getMode() - { - return $this->mode; - } - - /** - * @param int $mode - */ - public function setMode($mode) - { - $this->mode = $this->getPermissionsMode($mode); - } - - /** - * @return int - */ - public function getUserId() - { - return $this->uid; - } - - /** - * @param int $uid - */ - public function setUserId($uid) - { - $this->uid = (int) $uid; - } - - /** - * @return int - */ - public function getGroupId() - { - return $this->gid; - } - - /** - * @param int $gid - */ - public function setGroupId($gid) - { - $this->gid = (int) $gid; - } - - /** - * @return string - */ - public function __toString() - { - return sprintf( - '0x%04x ASI: Mode=%o UID=%d GID=%d Link="%s', - self::HEADER_ID, - $this->mode, - $this->uid, - $this->gid, - $this->link - ); - } -} diff --git a/vendor/nelexa/zip/src/Model/Extra/Fields/ExtendedTimestampExtraField.php b/vendor/nelexa/zip/src/Model/Extra/Fields/ExtendedTimestampExtraField.php deleted file mode 100644 index 909c783..0000000 --- a/vendor/nelexa/zip/src/Model/Extra/Fields/ExtendedTimestampExtraField.php +++ /dev/null @@ -1,446 +0,0 @@ -flags = (int) $flags; - $this->modifyTime = $modifyTime; - $this->accessTime = $accessTime; - $this->createTime = $createTime; - } - - /** - * @param int|null $modifyTime - * @param int|null $accessTime - * @param int|null $createTime - * - * @return ExtendedTimestampExtraField - */ - public static function create($modifyTime, $accessTime, $createTime) - { - $flags = 0; - - if ($modifyTime !== null) { - $modifyTime = (int) $modifyTime; - $flags |= self::MODIFY_TIME_BIT; - } - - if ($accessTime !== null) { - $accessTime = (int) $accessTime; - $flags |= self::ACCESS_TIME_BIT; - } - - if ($createTime !== null) { - $createTime = (int) $createTime; - $flags |= self::CREATE_TIME_BIT; - } - - return new self($flags, $modifyTime, $accessTime, $createTime); - } - - /** - * Returns the Header ID (type) of this Extra Field. - * The Header ID is an unsigned short integer (two bytes) - * which must be constant during the life cycle of this object. - * - * @return int - */ - public function getHeaderId() - { - return self::HEADER_ID; - } - - /** - * Populate data from this array as if it was in local file data. - * - * @param string $buffer the buffer to read data from - * @param ZipEntry|null $entry - * - * @return ExtendedTimestampExtraField - */ - public static function unpackLocalFileData($buffer, ZipEntry $entry = null) - { - $length = \strlen($buffer); - $flags = unpack('C', $buffer)[1]; - $offset = 1; - - $modifyTime = null; - $accessTime = null; - $createTime = null; - - if (($flags & self::MODIFY_TIME_BIT) === self::MODIFY_TIME_BIT) { - $modifyTime = unpack('V', substr($buffer, $offset, 4))[1]; - $offset += 4; - } - - // Notice the extra length check in case we are parsing the shorter - // central data field (for both access and create timestamps). - if ((($flags & self::ACCESS_TIME_BIT) === self::ACCESS_TIME_BIT) && $offset + 4 <= $length) { - $accessTime = unpack('V', substr($buffer, $offset, 4))[1]; - $offset += 4; - } - - if ((($flags & self::CREATE_TIME_BIT) === self::CREATE_TIME_BIT) && $offset + 4 <= $length) { - $createTime = unpack('V', substr($buffer, $offset, 4))[1]; - } - - return new self($flags, $modifyTime, $accessTime, $createTime); - } - - /** - * Populate data from this array as if it was in central directory data. - * - * @param string $buffer the buffer to read data from - * @param ZipEntry|null $entry - * - * @return ExtendedTimestampExtraField - */ - public static function unpackCentralDirData($buffer, ZipEntry $entry = null) - { - return self::unpackLocalFileData($buffer, $entry); - } - - /** - * The actual data to put into local file data - without Header-ID - * or length specifier. - * - * @return string the data - */ - public function packLocalFileData() - { - $data = ''; - - if (($this->flags & self::MODIFY_TIME_BIT) === self::MODIFY_TIME_BIT && $this->modifyTime !== null) { - $data .= pack('V', $this->modifyTime); - } - - if (($this->flags & self::ACCESS_TIME_BIT) === self::ACCESS_TIME_BIT && $this->accessTime !== null) { - $data .= pack('V', $this->accessTime); - } - - if (($this->flags & self::CREATE_TIME_BIT) === self::CREATE_TIME_BIT && $this->createTime !== null) { - $data .= pack('V', $this->createTime); - } - - return pack('C', $this->flags) . $data; - } - - /** - * The actual data to put into central directory - without Header-ID or - * length specifier. - * - * Note: even if bit1 and bit2 are set, the Central data will still - * not contain access/create fields: only local data ever holds those! - * - * @return string the data - */ - public function packCentralDirData() - { - $cdLength = 1 + ($this->modifyTime !== null ? 4 : 0); - - return substr($this->packLocalFileData(), 0, $cdLength); - } - - /** - * Gets flags byte. - * - * The flags byte tells us which of the three datestamp fields are - * present in the data: - * bit0 - modify time - * bit1 - access time - * bit2 - create time - * - * Only first 3 bits of flags are used according to the - * latest version of the spec (December 2012). - * - * @return int flags byte indicating which of the - * three datestamp fields are present - */ - public function getFlags() - { - return $this->flags; - } - - /** - * Returns the modify time (seconds since epoch) of this zip entry, - * or null if no such timestamp exists in the zip entry. - * - * @return int|null modify time (seconds since epoch) or null - */ - public function getModifyTime() - { - return $this->modifyTime; - } - - /** - * Returns the access time (seconds since epoch) of this zip entry, - * or null if no such timestamp exists in the zip entry. - * - * @return int|null access time (seconds since epoch) or null - */ - public function getAccessTime() - { - return $this->accessTime; - } - - /** - * Returns the create time (seconds since epoch) of this zip entry, - * or null if no such timestamp exists in the zip entry. - * - * Note: modern linux file systems (e.g., ext2) - * do not appear to store a "create time" value, and so - * it's usually omitted altogether in the zip extra - * field. Perhaps other unix systems track this. - * - * @return int|null create time (seconds since epoch) or null - */ - public function getCreateTime() - { - return $this->createTime; - } - - /** - * Returns the modify time as a \DateTimeInterface - * of this zip entry, or null if no such timestamp exists in the zip entry. - * The milliseconds are always zeroed out, since the underlying data - * offers only per-second precision. - * - * @return \DateTimeInterface|null modify time as \DateTimeInterface or null - */ - public function getModifyDateTime() - { - return self::timestampToDateTime($this->modifyTime); - } - - /** - * Returns the access time as a \DateTimeInterface - * of this zip entry, or null if no such timestamp exists in the zip entry. - * The milliseconds are always zeroed out, since the underlying data - * offers only per-second precision. - * - * @return \DateTimeInterface|null access time as \DateTimeInterface or null - */ - public function getAccessDateTime() - { - return self::timestampToDateTime($this->accessTime); - } - - /** - * Returns the create time as a a \DateTimeInterface - * of this zip entry, or null if no such timestamp exists in the zip entry. - * The milliseconds are always zeroed out, since the underlying data - * offers only per-second precision. - * - * Note: modern linux file systems (e.g., ext2) - * do not appear to store a "create time" value, and so - * it's usually omitted altogether in the zip extra - * field. Perhaps other unix systems track $this->. - * - * @return \DateTimeInterface|null create time as \DateTimeInterface or null - */ - public function getCreateDateTime() - { - return self::timestampToDateTime($this->createTime); - } - - /** - * Sets the modify time (seconds since epoch) of this zip entry - * using a integer. - * - * @param int|null $unixTime unix time of the modify time (seconds per epoch) or null - */ - public function setModifyTime($unixTime) - { - $this->modifyTime = $unixTime; - $this->updateFlags(); - } - - private function updateFlags() - { - $flags = 0; - - if ($this->modifyTime !== null) { - $flags |= self::MODIFY_TIME_BIT; - } - - if ($this->accessTime !== null) { - $flags |= self::ACCESS_TIME_BIT; - } - - if ($this->createTime !== null) { - $flags |= self::CREATE_TIME_BIT; - } - $this->flags = $flags; - } - - /** - * Sets the access time (seconds since epoch) of this zip entry - * using a integer. - * - * @param int|null $unixTime Unix time of the access time (seconds per epoch) or null - */ - public function setAccessTime($unixTime) - { - $this->accessTime = $unixTime; - $this->updateFlags(); - } - - /** - * Sets the create time (seconds since epoch) of this zip entry - * using a integer. - * - * @param int|null $unixTime Unix time of the create time (seconds per epoch) or null - */ - public function setCreateTime($unixTime) - { - $this->createTime = $unixTime; - $this->updateFlags(); - } - - /** - * @param int|null $timestamp - * - * @return \DateTimeInterface|null - */ - private static function timestampToDateTime($timestamp) - { - try { - return $timestamp !== null ? new \DateTimeImmutable('@' . $timestamp) : null; - } catch (\Exception $e) { - return null; - } - } - - /** - * @return string - */ - public function __toString() - { - $args = [self::HEADER_ID]; - $format = '0x%04x ExtendedTimestamp:'; - - if ($this->modifyTime !== null) { - $format .= ' Modify:[%s]'; - $args[] = date(\DATE_W3C, $this->modifyTime); - } - - if ($this->accessTime !== null) { - $format .= ' Access:[%s]'; - $args[] = date(\DATE_W3C, $this->accessTime); - } - - if ($this->createTime !== null) { - $format .= ' Create:[%s]'; - $args[] = date(\DATE_W3C, $this->createTime); - } - - return vsprintf($format, $args); - } -} diff --git a/vendor/nelexa/zip/src/Model/Extra/Fields/JarMarkerExtraField.php b/vendor/nelexa/zip/src/Model/Extra/Fields/JarMarkerExtraField.php deleted file mode 100644 index e1683aa..0000000 --- a/vendor/nelexa/zip/src/Model/Extra/Fields/JarMarkerExtraField.php +++ /dev/null @@ -1,118 +0,0 @@ -getEntries(); - - if (!empty($zipEntries)) { - foreach ($zipEntries as $zipEntry) { - $zipEntry->removeExtraField(self::HEADER_ID); - } - // set jar execute bit - reset($zipEntries); - $zipEntry = current($zipEntries); - $zipEntry->getCdExtraFields()[] = new self(); - } - } - - /** - * Returns the Header ID (type) of this Extra Field. - * The Header ID is an unsigned short integer (two bytes) - * which must be constant during the life cycle of this object. - * - * @return int - */ - public function getHeaderId() - { - return self::HEADER_ID; - } - - /** - * The actual data to put into local file data - without Header-ID - * or length specifier. - * - * @return string the data - */ - public function packLocalFileData() - { - return ''; - } - - /** - * The actual data to put into central directory - without Header-ID or - * length specifier. - * - * @return string the data - */ - public function packCentralDirData() - { - return ''; - } - - /** - * Populate data from this array as if it was in local file data. - * - * @param string $buffer the buffer to read data from - * @param ZipEntry|null $entry - * - * @throws ZipException on error - * - * @return JarMarkerExtraField - */ - public static function unpackLocalFileData($buffer, ZipEntry $entry = null) - { - if (!empty($buffer)) { - throw new ZipException("JarMarker doesn't expect any data"); - } - - return new self(); - } - - /** - * Populate data from this array as if it was in central directory data. - * - * @param string $buffer the buffer to read data from - * @param ZipEntry|null $entry - * - * @throws ZipException on error - * - * @return JarMarkerExtraField - */ - public static function unpackCentralDirData($buffer, ZipEntry $entry = null) - { - return self::unpackLocalFileData($buffer, $entry); - } - - /** - * @return string - */ - public function __toString() - { - return sprintf('0x%04x Jar Marker', self::HEADER_ID); - } -} diff --git a/vendor/nelexa/zip/src/Model/Extra/Fields/NewUnixExtraField.php b/vendor/nelexa/zip/src/Model/Extra/Fields/NewUnixExtraField.php deleted file mode 100644 index 807de72..0000000 --- a/vendor/nelexa/zip/src/Model/Extra/Fields/NewUnixExtraField.php +++ /dev/null @@ -1,237 +0,0 @@ -version = (int) $version; - $this->uid = (int) $uid; - $this->gid = (int) $gid; - } - - /** - * Returns the Header ID (type) of this Extra Field. - * The Header ID is an unsigned short integer (two bytes) - * which must be constant during the life cycle of this object. - * - * @return int - */ - public function getHeaderId() - { - return self::HEADER_ID; - } - - /** - * Populate data from this array as if it was in local file data. - * - * @param string $buffer the buffer to read data from - * @param ZipEntry|null $entry - * - * @throws ZipException - * - * @return NewUnixExtraField - */ - public static function unpackLocalFileData($buffer, ZipEntry $entry = null) - { - $length = \strlen($buffer); - - if ($length < 3) { - throw new ZipException(sprintf('X7875_NewUnix length is too short, only %s bytes', $length)); - } - $offset = 0; - $data = unpack('Cversion/CuidSize', $buffer); - $offset += 2; - $uidSize = $data['uidSize']; - $gid = self::readSizeIntegerLE(substr($buffer, $offset, $uidSize), $uidSize); - $offset += $uidSize; - $gidSize = unpack('C', $buffer[$offset])[1]; - $offset++; - $uid = self::readSizeIntegerLE(substr($buffer, $offset, $gidSize), $gidSize); - - return new self($data['version'], $gid, $uid); - } - - /** - * Populate data from this array as if it was in central directory data. - * - * @param string $buffer the buffer to read data from - * @param ZipEntry|null $entry - * - * @throws ZipException - * - * @return NewUnixExtraField - */ - public static function unpackCentralDirData($buffer, ZipEntry $entry = null) - { - return self::unpackLocalFileData($buffer, $entry); - } - - /** - * The actual data to put into local file data - without Header-ID - * or length specifier. - * - * @return string the data - */ - public function packLocalFileData() - { - return pack( - 'CCVCV', - $this->version, - 4, // UIDSize - $this->uid, - 4, // GIDSize - $this->gid - ); - } - - /** - * The actual data to put into central directory - without Header-ID or - * length specifier. - * - * @return string the data - */ - public function packCentralDirData() - { - return $this->packLocalFileData(); - } - - /** - * @param string $data - * @param int $size - * - * @throws ZipException - * - * @return int - */ - private static function readSizeIntegerLE($data, $size) - { - $format = [ - 1 => 'C', // unsigned byte - 2 => 'v', // unsigned short LE - 4 => 'V', // unsigned int LE - ]; - - if (!isset($format[$size])) { - throw new ZipException(sprintf('Invalid size bytes: %d', $size)); - } - - return unpack($format[$size], $data)[1]; - } - - /** - * @return int - */ - public function getUid() - { - return $this->uid; - } - - /** - * @param int $uid - */ - public function setUid($uid) - { - $this->uid = $uid & 0xffffffff; - } - - /** - * @return int - */ - public function getGid() - { - return $this->gid; - } - - /** - * @param int $gid - */ - public function setGid($gid) - { - $this->gid = $gid & 0xffffffff; - } - - /** - * @return int - */ - public function getVersion() - { - return $this->version; - } - - /** - * @return string - */ - public function __toString() - { - return sprintf( - '0x%04x NewUnix: UID=%d GID=%d', - self::HEADER_ID, - $this->uid, - $this->gid - ); - } -} diff --git a/vendor/nelexa/zip/src/Model/Extra/Fields/NtfsExtraField.php b/vendor/nelexa/zip/src/Model/Extra/Fields/NtfsExtraField.php deleted file mode 100644 index 213e925..0000000 --- a/vendor/nelexa/zip/src/Model/Extra/Fields/NtfsExtraField.php +++ /dev/null @@ -1,339 +0,0 @@ -modifyNtfsTime = (int) $modifyNtfsTime; - $this->accessNtfsTime = (int) $accessNtfsTime; - $this->createNtfsTime = (int) $createNtfsTime; - } - - /** - * @param \DateTimeInterface $modifyDateTime - * @param \DateTimeInterface $accessDateTime - * @param \DateTimeInterface $createNtfsTime - * - * @return NtfsExtraField - */ - public static function create( - \DateTimeInterface $modifyDateTime, - \DateTimeInterface $accessDateTime, - \DateTimeInterface $createNtfsTime - ) { - return new self( - self::dateTimeToNtfsTime($modifyDateTime), - self::dateTimeToNtfsTime($accessDateTime), - self::dateTimeToNtfsTime($createNtfsTime) - ); - } - - /** - * Returns the Header ID (type) of this Extra Field. - * The Header ID is an unsigned short integer (two bytes) - * which must be constant during the life cycle of this object. - * - * @return int - */ - public function getHeaderId() - { - return self::HEADER_ID; - } - - /** - * Populate data from this array as if it was in local file data. - * - * @param string $buffer the buffer to read data from - * @param ZipEntry|null $entry - * - * @throws ZipException - * - * @return NtfsExtraField - */ - public static function unpackLocalFileData($buffer, ZipEntry $entry = null) - { - if (\PHP_INT_SIZE === 4) { - throw new ZipException('not supported for php-32bit'); - } - - $buffer = substr($buffer, 4); - - $modifyTime = 0; - $accessTime = 0; - $createTime = 0; - - while ($buffer || $buffer !== '') { - $unpack = unpack('vtag/vsizeAttr', $buffer); - - if ($unpack['tag'] === self::TIME_ATTR_TAG && $unpack['sizeAttr'] === self::TIME_ATTR_SIZE) { - // refactoring will be needed when php 5.5 support ends - $modifyTime = PackUtil::unpackLongLE(substr($buffer, 4, 8)); - $accessTime = PackUtil::unpackLongLE(substr($buffer, 12, 8)); - $createTime = PackUtil::unpackLongLE(substr($buffer, 20, 8)); - - break; - } - $buffer = substr($buffer, 4 + $unpack['sizeAttr']); - } - - return new self($modifyTime, $accessTime, $createTime); - } - - /** - * Populate data from this array as if it was in central directory data. - * - * @param string $buffer the buffer to read data from - * @param ZipEntry|null $entry - * - * @throws ZipException - * - * @return NtfsExtraField - */ - public static function unpackCentralDirData($buffer, ZipEntry $entry = null) - { - return self::unpackLocalFileData($buffer, $entry); - } - - /** - * The actual data to put into local file data - without Header-ID - * or length specifier. - * - * @return string the data - */ - public function packLocalFileData() - { - $data = pack('Vvv', 0, self::TIME_ATTR_TAG, self::TIME_ATTR_SIZE); - // refactoring will be needed when php 5.5 support ends - $data .= PackUtil::packLongLE($this->modifyNtfsTime); - $data .= PackUtil::packLongLE($this->accessNtfsTime); - $data .= PackUtil::packLongLE($this->createNtfsTime); - - return $data; - } - - /** - * @return int - */ - public function getModifyNtfsTime() - { - return $this->modifyNtfsTime; - } - - /** - * @param int $modifyNtfsTime - */ - public function setModifyNtfsTime($modifyNtfsTime) - { - $this->modifyNtfsTime = (int) $modifyNtfsTime; - } - - /** - * @return int - */ - public function getAccessNtfsTime() - { - return $this->accessNtfsTime; - } - - /** - * @param int $accessNtfsTime - */ - public function setAccessNtfsTime($accessNtfsTime) - { - $this->accessNtfsTime = (int) $accessNtfsTime; - } - - /** - * @return int - */ - public function getCreateNtfsTime() - { - return $this->createNtfsTime; - } - - /** - * @param int $createNtfsTime - */ - public function setCreateNtfsTime($createNtfsTime) - { - $this->createNtfsTime = (int) $createNtfsTime; - } - - /** - * The actual data to put into central directory - without Header-ID or - * length specifier. - * - * @return string the data - */ - public function packCentralDirData() - { - return $this->packLocalFileData(); - } - - /** - * @return \DateTimeInterface - */ - public function getModifyDateTime() - { - return self::ntfsTimeToDateTime($this->modifyNtfsTime); - } - - /** - * @param \DateTimeInterface $modifyTime - */ - public function setModifyDateTime(\DateTimeInterface $modifyTime) - { - $this->modifyNtfsTime = self::dateTimeToNtfsTime($modifyTime); - } - - /** - * @return \DateTimeInterface - */ - public function getAccessDateTime() - { - return self::ntfsTimeToDateTime($this->accessNtfsTime); - } - - /** - * @param \DateTimeInterface $accessTime - */ - public function setAccessDateTime(\DateTimeInterface $accessTime) - { - $this->accessNtfsTime = self::dateTimeToNtfsTime($accessTime); - } - - /** - * @return \DateTimeInterface - */ - public function getCreateDateTime() - { - return self::ntfsTimeToDateTime($this->createNtfsTime); - } - - /** - * @param \DateTimeInterface $createTime - */ - public function setCreateDateTime(\DateTimeInterface $createTime) - { - $this->createNtfsTime = self::dateTimeToNtfsTime($createTime); - } - - /** - * @param float $timestamp Float timestamp - * - * @return int - */ - public static function timestampToNtfsTime($timestamp) - { - return (int) (((float) $timestamp * 10000000) - self::EPOCH_OFFSET); - } - - /** - * @param \DateTimeInterface $dateTime - * - * @return int - */ - public static function dateTimeToNtfsTime(\DateTimeInterface $dateTime) - { - return self::timestampToNtfsTime((float) $dateTime->format('U.u')); - } - - /** - * @param int $ntfsTime - * - * @return float Float unix timestamp - */ - public static function ntfsTimeToTimestamp($ntfsTime) - { - return (float) (($ntfsTime + self::EPOCH_OFFSET) / 10000000); - } - - /** - * @param int $ntfsTime - * - * @return \DateTimeInterface - */ - public static function ntfsTimeToDateTime($ntfsTime) - { - $timestamp = self::ntfsTimeToTimestamp($ntfsTime); - $dateTime = \DateTimeImmutable::createFromFormat('U.u', sprintf('%.6f', $timestamp)); - - if ($dateTime === false) { - throw new InvalidArgumentException('Cannot create date/time object for timestamp ' . $timestamp); - } - - return $dateTime; - } - - /** - * @return string - */ - public function __toString() - { - $args = [self::HEADER_ID]; - $format = '0x%04x NtfsExtra:'; - - if ($this->modifyNtfsTime !== 0) { - $format .= ' Modify:[%s]'; - $args[] = $this->getModifyDateTime()->format(\DATE_ATOM); - } - - if ($this->accessNtfsTime !== 0) { - $format .= ' Access:[%s]'; - $args[] = $this->getAccessDateTime()->format(\DATE_ATOM); - } - - if ($this->createNtfsTime !== 0) { - $format .= ' Create:[%s]'; - $args[] = $this->getCreateDateTime()->format(\DATE_ATOM); - } - - return vsprintf($format, $args); - } -} diff --git a/vendor/nelexa/zip/src/Model/Extra/Fields/OldUnixExtraField.php b/vendor/nelexa/zip/src/Model/Extra/Fields/OldUnixExtraField.php deleted file mode 100644 index 1f69487..0000000 --- a/vendor/nelexa/zip/src/Model/Extra/Fields/OldUnixExtraField.php +++ /dev/null @@ -1,327 +0,0 @@ -accessTime = $accessTime; - $this->modifyTime = $modifyTime; - $this->uid = $uid; - $this->gid = $gid; - } - - /** - * Returns the Header ID (type) of this Extra Field. - * The Header ID is an unsigned short integer (two bytes) - * which must be constant during the life cycle of this object. - * - * @return int - */ - public function getHeaderId() - { - return self::HEADER_ID; - } - - /** - * Populate data from this array as if it was in local file data. - * - * @param string $buffer the buffer to read data from - * @param ZipEntry|null $entry - * - * @return OldUnixExtraField - */ - public static function unpackLocalFileData($buffer, ZipEntry $entry = null) - { - $length = \strlen($buffer); - - $accessTime = $modifyTime = $uid = $gid = null; - - if ($length >= 4) { - $accessTime = unpack('V', $buffer)[1]; - } - - if ($length >= 8) { - $modifyTime = unpack('V', substr($buffer, 4, 4))[1]; - } - - if ($length >= 10) { - $uid = unpack('v', substr($buffer, 8, 2))[1]; - } - - if ($length >= 12) { - $gid = unpack('v', substr($buffer, 10, 2))[1]; - } - - return new self($accessTime, $modifyTime, $uid, $gid); - } - - /** - * Populate data from this array as if it was in central directory data. - * - * @param string $buffer the buffer to read data from - * @param ZipEntry|null $entry - * - * @return OldUnixExtraField - */ - public static function unpackCentralDirData($buffer, ZipEntry $entry = null) - { - $length = \strlen($buffer); - - $accessTime = $modifyTime = null; - - if ($length >= 4) { - $accessTime = unpack('V', $buffer)[1]; - } - - if ($length >= 8) { - $modifyTime = unpack('V', substr($buffer, 4, 4))[1]; - } - - return new self($accessTime, $modifyTime, null, null); - } - - /** - * The actual data to put into local file data - without Header-ID - * or length specifier. - * - * @return string the data - */ - public function packLocalFileData() - { - $data = ''; - - if ($this->accessTime !== null) { - $data .= pack('V', $this->accessTime); - - if ($this->modifyTime !== null) { - $data .= pack('V', $this->modifyTime); - - if ($this->uid !== null) { - $data .= pack('v', $this->uid); - - if ($this->gid !== null) { - $data .= pack('v', $this->gid); - } - } - } - } - - return $data; - } - - /** - * The actual data to put into central directory - without Header-ID or - * length specifier. - * - * @return string the data - */ - public function packCentralDirData() - { - $data = ''; - - if ($this->accessTime !== null) { - $data .= pack('V', $this->accessTime); - - if ($this->modifyTime !== null) { - $data .= pack('V', $this->modifyTime); - } - } - - return $data; - } - - /** - * @return int|null - */ - public function getAccessTime() - { - return $this->accessTime; - } - - /** - * @param int|null $accessTime - */ - public function setAccessTime($accessTime) - { - $this->accessTime = $accessTime; - } - - /** - * @return \DateTimeInterface|null - */ - public function getAccessDateTime() - { - try { - return $this->accessTime === null ? null : - new \DateTimeImmutable('@' . $this->accessTime); - } catch (\Exception $e) { - return null; - } - } - - /** - * @return int|null - */ - public function getModifyTime() - { - return $this->modifyTime; - } - - /** - * @param int|null $modifyTime - */ - public function setModifyTime($modifyTime) - { - $this->modifyTime = $modifyTime; - } - - /** - * @return \DateTimeInterface|null - */ - public function getModifyDateTime() - { - try { - return $this->modifyTime === null ? null : - new \DateTimeImmutable('@' . $this->modifyTime); - } catch (\Exception $e) { - return null; - } - } - - /** - * @return int|null - */ - public function getUid() - { - return $this->uid; - } - - /** - * @param int|null $uid - */ - public function setUid($uid) - { - $this->uid = $uid; - } - - /** - * @return int|null - */ - public function getGid() - { - return $this->gid; - } - - /** - * @param int|null $gid - */ - public function setGid($gid) - { - $this->gid = $gid; - } - - /** - * @return string - */ - public function __toString() - { - $args = [self::HEADER_ID]; - $format = '0x%04x OldUnix:'; - - if (($modifyTime = $this->getModifyDateTime()) !== null) { - $format .= ' Modify:[%s]'; - $args[] = $modifyTime->format(\DATE_ATOM); - } - - if (($accessTime = $this->getAccessDateTime()) !== null) { - $format .= ' Access:[%s]'; - $args[] = $accessTime->format(\DATE_ATOM); - } - - if ($this->uid !== null) { - $format .= ' UID=%d'; - $args[] = $this->uid; - } - - if ($this->gid !== null) { - $format .= ' GID=%d'; - $args[] = $this->gid; - } - - return vsprintf($format, $args); - } -} diff --git a/vendor/nelexa/zip/src/Model/Extra/Fields/UnicodeCommentExtraField.php b/vendor/nelexa/zip/src/Model/Extra/Fields/UnicodeCommentExtraField.php deleted file mode 100644 index d8280b6..0000000 --- a/vendor/nelexa/zip/src/Model/Extra/Fields/UnicodeCommentExtraField.php +++ /dev/null @@ -1,76 +0,0 @@ -getUnicodeValue() - ); - } -} diff --git a/vendor/nelexa/zip/src/Model/Extra/Fields/UnicodePathExtraField.php b/vendor/nelexa/zip/src/Model/Extra/Fields/UnicodePathExtraField.php deleted file mode 100644 index 047b2d0..0000000 --- a/vendor/nelexa/zip/src/Model/Extra/Fields/UnicodePathExtraField.php +++ /dev/null @@ -1,77 +0,0 @@ -getUnicodeValue() - ); - } -} diff --git a/vendor/nelexa/zip/src/Model/Extra/Fields/UnrecognizedExtraField.php b/vendor/nelexa/zip/src/Model/Extra/Fields/UnrecognizedExtraField.php deleted file mode 100644 index 699c193..0000000 --- a/vendor/nelexa/zip/src/Model/Extra/Fields/UnrecognizedExtraField.php +++ /dev/null @@ -1,116 +0,0 @@ -headerId = (int) $headerId; - $this->data = (string) $data; - } - - /** - * @param int $headerId - */ - public function setHeaderId($headerId) - { - $this->headerId = $headerId; - } - - /** - * Returns the Header ID (type) of this Extra Field. - * The Header ID is an unsigned short integer (two bytes) - * which must be constant during the life cycle of this object. - * - * @return int - */ - public function getHeaderId() - { - return $this->headerId; - } - - /** - * Populate data from this array as if it was in local file data. - * - * @param string $buffer the buffer to read data from - * @param ZipEntry|null $entry - */ - public static function unpackLocalFileData($buffer, ZipEntry $entry = null) - { - throw new RuntimeException('Unsupport parse'); - } - - /** - * Populate data from this array as if it was in central directory data. - * - * @param string $buffer the buffer to read data from - * @param ZipEntry|null $entry - */ - public static function unpackCentralDirData($buffer, ZipEntry $entry = null) - { - throw new RuntimeException('Unsupport parse'); - } - - /** - * {@inheritdoc} - */ - public function packLocalFileData() - { - return $this->data; - } - - /** - * {@inheritdoc} - */ - public function packCentralDirData() - { - return $this->data; - } - - /** - * @return string - */ - public function getData() - { - return $this->data; - } - - /** - * @param string $data - */ - public function setData($data) - { - $this->data = (string) $data; - } - - /** - * @return string - */ - public function __toString() - { - $args = [$this->headerId, $this->data]; - $format = '0x%04x Unrecognized Extra Field: "%s"'; - - return vsprintf($format, $args); - } -} diff --git a/vendor/nelexa/zip/src/Model/Extra/Fields/WinZipAesExtraField.php b/vendor/nelexa/zip/src/Model/Extra/Fields/WinZipAesExtraField.php deleted file mode 100644 index 0a50dca..0000000 --- a/vendor/nelexa/zip/src/Model/Extra/Fields/WinZipAesExtraField.php +++ /dev/null @@ -1,387 +0,0 @@ - */ - private static $encryptionStrengths = [ - self::KEY_STRENGTH_128BIT => 128, - self::KEY_STRENGTH_192BIT => 192, - self::KEY_STRENGTH_256BIT => 256, - ]; - - /** @var array */ - private static $MAP_KEY_STRENGTH_METHODS = [ - self::KEY_STRENGTH_128BIT => ZipEncryptionMethod::WINZIP_AES_128, - self::KEY_STRENGTH_192BIT => ZipEncryptionMethod::WINZIP_AES_192, - self::KEY_STRENGTH_256BIT => ZipEncryptionMethod::WINZIP_AES_256, - ]; - - /** @var int Integer version number specific to the zip vendor */ - private $vendorVersion = self::VERSION_AE1; - - /** @var int Integer mode value indicating AES encryption strength */ - private $keyStrength = self::KEY_STRENGTH_256BIT; - - /** @var int The actual compression method used to compress the file */ - private $compressionMethod; - - /** - * @param int $vendorVersion Integer version number specific to the zip vendor - * @param int $keyStrength Integer mode value indicating AES encryption strength - * @param int $compressionMethod The actual compression method used to compress the file - * - * @throws ZipUnsupportMethodException - */ - public function __construct($vendorVersion, $keyStrength, $compressionMethod) - { - $this->setVendorVersion($vendorVersion); - $this->setKeyStrength($keyStrength); - $this->setCompressionMethod($compressionMethod); - } - - /** - * @param ZipEntry $entry - * - * @throws ZipUnsupportMethodException - * - * @return WinZipAesExtraField - */ - public static function create(ZipEntry $entry) - { - $keyStrength = array_search($entry->getEncryptionMethod(), self::$MAP_KEY_STRENGTH_METHODS, true); - - if ($keyStrength === false) { - throw new InvalidArgumentException('Not support encryption method ' . $entry->getEncryptionMethod()); - } - - // WinZip 11 will continue to use AE-2, with no CRC, for very small files - // of less than 20 bytes. It will also use AE-2 for files compressed in - // BZIP2 format, because this format has internal integrity checks - // equivalent to a CRC check built in. - // - // https://www.winzip.com/win/en/aes_info.html - $vendorVersion = ( - $entry->getUncompressedSize() < 20 || - $entry->getCompressionMethod() === ZipCompressionMethod::BZIP2 - ) ? - self::VERSION_AE2 : - self::VERSION_AE1; - - $field = new self($vendorVersion, $keyStrength, $entry->getCompressionMethod()); - - $entry->getLocalExtraFields()->add($field); - $entry->getCdExtraFields()->add($field); - - return $field; - } - - /** - * Returns the Header ID (type) of this Extra Field. - * The Header ID is an unsigned short integer (two bytes) - * which must be constant during the life cycle of this object. - * - * @return int - */ - public function getHeaderId() - { - return self::HEADER_ID; - } - - /** - * Populate data from this array as if it was in local file data. - * - * @param string $buffer the buffer to read data from - * @param ZipEntry|null $entry - * - * @throws ZipException on error - * - * @return WinZipAesExtraField - */ - public static function unpackLocalFileData($buffer, ZipEntry $entry = null) - { - $size = \strlen($buffer); - - if ($size !== self::DATA_SIZE) { - throw new ZipException( - sprintf( - 'WinZip AES Extra data invalid size: %d. Must be %d', - $size, - self::DATA_SIZE - ) - ); - } - - $data = unpack('vvendorVersion/vvendorId/ckeyStrength/vcompressionMethod', $buffer); - - if ($data['vendorId'] !== self::VENDOR_ID) { - throw new ZipException( - sprintf( - 'Vendor id invalid: %d. Must be %d', - $data['vendorId'], - self::VENDOR_ID - ) - ); - } - - return new self( - $data['vendorVersion'], - $data['keyStrength'], - $data['compressionMethod'] - ); - } - - /** - * Populate data from this array as if it was in central directory data. - * - * @param string $buffer the buffer to read data from - * @param ZipEntry|null $entry - * - * @throws ZipException - * - * @return WinZipAesExtraField - */ - public static function unpackCentralDirData($buffer, ZipEntry $entry = null) - { - return self::unpackLocalFileData($buffer, $entry); - } - - /** - * The actual data to put into local file data - without Header-ID - * or length specifier. - * - * @return string the data - */ - public function packLocalFileData() - { - return pack( - 'vvcv', - $this->vendorVersion, - self::VENDOR_ID, - $this->keyStrength, - $this->compressionMethod - ); - } - - /** - * The actual data to put into central directory - without Header-ID or - * length specifier. - * - * @return string the data - */ - public function packCentralDirData() - { - return $this->packLocalFileData(); - } - - /** - * Returns the vendor version. - * - * @return int - * - * @see WinZipAesExtraField::VERSION_AE2 - * @see WinZipAesExtraField::VERSION_AE1 - */ - public function getVendorVersion() - { - return $this->vendorVersion; - } - - /** - * Sets the vendor version. - * - * @param int $vendorVersion the vendor version - * - * @see WinZipAesExtraField::VERSION_AE2 - * @see WinZipAesExtraField::VERSION_AE1 - */ - public function setVendorVersion($vendorVersion) - { - $vendorVersion = (int) $vendorVersion; - - if (!\in_array($vendorVersion, self::$allowVendorVersions, true)) { - throw new InvalidArgumentException( - sprintf( - 'Unsupport WinZip AES vendor version: %d', - $vendorVersion - ) - ); - } - $this->vendorVersion = $vendorVersion; - } - - /** - * Returns vendor id. - * - * @return int - */ - public function getVendorId() - { - return self::VENDOR_ID; - } - - /** - * @return int - */ - public function getKeyStrength() - { - return $this->keyStrength; - } - - /** - * Set key strength. - * - * @param int $keyStrength - */ - public function setKeyStrength($keyStrength) - { - $keyStrength = (int) $keyStrength; - - if (!isset(self::$encryptionStrengths[$keyStrength])) { - throw new InvalidArgumentException( - sprintf( - 'Key strength %d not support value. Allow values: %s', - $keyStrength, - implode(', ', array_keys(self::$encryptionStrengths)) - ) - ); - } - $this->keyStrength = $keyStrength; - } - - /** - * @return int - */ - public function getCompressionMethod() - { - return $this->compressionMethod; - } - - /** - * @param int $compressionMethod - * - * @throws ZipUnsupportMethodException - */ - public function setCompressionMethod($compressionMethod) - { - $compressionMethod = (int) $compressionMethod; - ZipCompressionMethod::checkSupport($compressionMethod); - $this->compressionMethod = $compressionMethod; - } - - /** - * @return int - */ - public function getEncryptionStrength() - { - return self::$encryptionStrengths[$this->keyStrength]; - } - - /** - * @return int - */ - public function getEncryptionMethod() - { - $keyStrength = $this->getKeyStrength(); - - if (!isset(self::$MAP_KEY_STRENGTH_METHODS[$keyStrength])) { - throw new InvalidArgumentException('Invalid encryption method'); - } - - return self::$MAP_KEY_STRENGTH_METHODS[$keyStrength]; - } - - /** - * @return bool - */ - public function isV1() - { - return $this->vendorVersion === self::VERSION_AE1; - } - - /** - * @return bool - */ - public function isV2() - { - return $this->vendorVersion === self::VERSION_AE2; - } - - /** - * @return int - */ - public function getSaltSize() - { - return (int) ($this->getEncryptionStrength() / 8 / 2); - } - - /** - * @return string - */ - public function __toString() - { - return sprintf( - '0x%04x WINZIP AES: VendorVersion=%d KeyStrength=0x%02x CompressionMethod=%s', - __CLASS__, - $this->vendorVersion, - $this->keyStrength, - $this->compressionMethod - ); - } -} diff --git a/vendor/nelexa/zip/src/Model/Extra/Fields/Zip64ExtraField.php b/vendor/nelexa/zip/src/Model/Extra/Fields/Zip64ExtraField.php deleted file mode 100644 index 4393a9c..0000000 --- a/vendor/nelexa/zip/src/Model/Extra/Fields/Zip64ExtraField.php +++ /dev/null @@ -1,311 +0,0 @@ -uncompressedSize = $uncompressedSize; - $this->compressedSize = $compressedSize; - $this->localHeaderOffset = $localHeaderOffset; - $this->diskStart = $diskStart; - } - - /** - * Returns the Header ID (type) of this Extra Field. - * The Header ID is an unsigned short integer (two bytes) - * which must be constant during the life cycle of this object. - * - * @return int - */ - public function getHeaderId() - { - return self::HEADER_ID; - } - - /** - * Populate data from this array as if it was in local file data. - * - * @param string $buffer the buffer to read data from - * @param ZipEntry|null $entry - * - * @throws ZipException on error - * - * @return Zip64ExtraField - */ - public static function unpackLocalFileData($buffer, ZipEntry $entry = null) - { - $length = \strlen($buffer); - - if ($length === 0) { - // no local file data at all, may happen if an archive - // only holds a ZIP64 extended information extra field - // inside the central directory but not inside the local - // file header - return new self(); - } - - if ($length < 16) { - throw new ZipException( - 'Zip64 extended information must contain both size values in the local file header.' - ); - } - - $uncompressedSize = PackUtil::unpackLongLE(substr($buffer, 0, 8)); - $compressedSize = PackUtil::unpackLongLE(substr($buffer, 8, 8)); - - return new self($uncompressedSize, $compressedSize); - } - - /** - * Populate data from this array as if it was in central directory data. - * - * @param string $buffer the buffer to read data from - * @param ZipEntry|null $entry - * - * @throws ZipException - * - * @return Zip64ExtraField - */ - public static function unpackCentralDirData($buffer, ZipEntry $entry = null) - { - if ($entry === null) { - throw new RuntimeException('zipEntry is null'); - } - - $length = \strlen($buffer); - $remaining = $length; - - $uncompressedSize = null; - $compressedSize = null; - $localHeaderOffset = null; - $diskStart = null; - - if ($entry->getUncompressedSize() === ZipConstants::ZIP64_MAGIC) { - if ($remaining < 8) { - throw new ZipException('ZIP64 extension corrupt (no uncompressed size).'); - } - $uncompressedSize = PackUtil::unpackLongLE(substr($buffer, $length - $remaining, 8)); - $remaining -= 8; - } - - if ($entry->getCompressedSize() === ZipConstants::ZIP64_MAGIC) { - if ($remaining < 8) { - throw new ZipException('ZIP64 extension corrupt (no compressed size).'); - } - $compressedSize = PackUtil::unpackLongLE(substr($buffer, $length - $remaining, 8)); - $remaining -= 8; - } - - if ($entry->getLocalHeaderOffset() === ZipConstants::ZIP64_MAGIC) { - if ($remaining < 8) { - throw new ZipException('ZIP64 extension corrupt (no relative local header offset).'); - } - $localHeaderOffset = PackUtil::unpackLongLE(substr($buffer, $length - $remaining, 8)); - $remaining -= 8; - } - - if ($remaining === 4) { - $diskStart = unpack('V', substr($buffer, $length - $remaining, 4))[1]; - } - - return new self($uncompressedSize, $compressedSize, $localHeaderOffset, $diskStart); - } - - /** - * The actual data to put into local file data - without Header-ID - * or length specifier. - * - * @return string the data - */ - public function packLocalFileData() - { - if ($this->uncompressedSize !== null || $this->compressedSize !== null) { - if ($this->uncompressedSize === null || $this->compressedSize === null) { - throw new \InvalidArgumentException( - 'Zip64 extended information must contain both size values in the local file header.' - ); - } - - return $this->packSizes(); - } - - return ''; - } - - /** - * @return string - */ - private function packSizes() - { - $data = ''; - - if ($this->uncompressedSize !== null) { - $data .= PackUtil::packLongLE($this->uncompressedSize); - } - - if ($this->compressedSize !== null) { - $data .= PackUtil::packLongLE($this->compressedSize); - } - - return $data; - } - - /** - * The actual data to put into central directory - without Header-ID or - * length specifier. - * - * @return string the data - */ - public function packCentralDirData() - { - $data = $this->packSizes(); - - if ($this->localHeaderOffset !== null) { - $data .= PackUtil::packLongLE($this->localHeaderOffset); - } - - if ($this->diskStart !== null) { - $data .= pack('V', $this->diskStart); - } - - return $data; - } - - /** - * @return int|null - */ - public function getUncompressedSize() - { - return $this->uncompressedSize; - } - - /** - * @param int|null $uncompressedSize - */ - public function setUncompressedSize($uncompressedSize) - { - $this->uncompressedSize = $uncompressedSize; - } - - /** - * @return int|null - */ - public function getCompressedSize() - { - return $this->compressedSize; - } - - /** - * @param int|null $compressedSize - */ - public function setCompressedSize($compressedSize) - { - $this->compressedSize = $compressedSize; - } - - /** - * @return int|null - */ - public function getLocalHeaderOffset() - { - return $this->localHeaderOffset; - } - - /** - * @param int|null $localHeaderOffset - */ - public function setLocalHeaderOffset($localHeaderOffset) - { - $this->localHeaderOffset = $localHeaderOffset; - } - - /** - * @return int|null - */ - public function getDiskStart() - { - return $this->diskStart; - } - - /** - * @param int|null $diskStart - */ - public function setDiskStart($diskStart) - { - $this->diskStart = $diskStart; - } - - /** - * @return string - */ - public function __toString() - { - $args = [self::HEADER_ID]; - $format = '0x%04x ZIP64: '; - $formats = []; - - if ($this->uncompressedSize !== null) { - $formats[] = 'SIZE=%d'; - $args[] = $this->uncompressedSize; - } - - if ($this->compressedSize !== null) { - $formats[] = 'COMP_SIZE=%d'; - $args[] = $this->compressedSize; - } - - if ($this->localHeaderOffset !== null) { - $formats[] = 'OFFSET=%d'; - $args[] = $this->localHeaderOffset; - } - - if ($this->diskStart !== null) { - $formats[] = 'DISK_START=%d'; - $args[] = $this->diskStart; - } - $format .= implode(' ', $formats); - - return vsprintf($format, $args); - } -} diff --git a/vendor/nelexa/zip/src/Model/Extra/Fields/index.php b/vendor/nelexa/zip/src/Model/Extra/Fields/index.php deleted file mode 100644 index df24d3e..0000000 --- a/vendor/nelexa/zip/src/Model/Extra/Fields/index.php +++ /dev/null @@ -1,35 +0,0 @@ - - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA - */ - -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); - -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); - -header("Location: ../"); -exit; diff --git a/vendor/nelexa/zip/src/Model/Extra/ZipExtraDriver.php b/vendor/nelexa/zip/src/Model/Extra/ZipExtraDriver.php deleted file mode 100644 index e1332f0..0000000 --- a/vendor/nelexa/zip/src/Model/Extra/ZipExtraDriver.php +++ /dev/null @@ -1,107 +0,0 @@ - - * @psalm-var array> - */ - private static $implementations = [ - ApkAlignmentExtraField::HEADER_ID => ApkAlignmentExtraField::class, - AsiExtraField::HEADER_ID => AsiExtraField::class, - ExtendedTimestampExtraField::HEADER_ID => ExtendedTimestampExtraField::class, - JarMarkerExtraField::HEADER_ID => JarMarkerExtraField::class, - NewUnixExtraField::HEADER_ID => NewUnixExtraField::class, - NtfsExtraField::HEADER_ID => NtfsExtraField::class, - OldUnixExtraField::HEADER_ID => OldUnixExtraField::class, - UnicodeCommentExtraField::HEADER_ID => UnicodeCommentExtraField::class, - UnicodePathExtraField::HEADER_ID => UnicodePathExtraField::class, - WinZipAesExtraField::HEADER_ID => WinZipAesExtraField::class, - Zip64ExtraField::HEADER_ID => Zip64ExtraField::class, - ]; - - private function __construct() - { - } - - /** - * @param string|ZipExtraField $extraField ZipExtraField object or class name - */ - public static function register($extraField) - { - if (!is_a($extraField, ZipExtraField::class, true)) { - throw new InvalidArgumentException( - sprintf( - '$extraField "%s" is not implements interface %s', - (string) $extraField, - ZipExtraField::class - ) - ); - } - self::$implementations[\call_user_func([$extraField, 'getHeaderId'])] = $extraField; - } - - /** - * @param int|string|ZipExtraField $extraType ZipExtraField object or class name or extra header id - * - * @return bool - */ - public static function unregister($extraType) - { - $headerId = null; - - if (\is_int($extraType)) { - $headerId = $extraType; - } elseif (is_a($extraType, ZipExtraField::class, true)) { - $headerId = \call_user_func([$extraType, 'getHeaderId']); - } else { - return false; - } - - if (isset(self::$implementations[$headerId])) { - unset(self::$implementations[$headerId]); - - return true; - } - - return false; - } - - /** - * @param int $headerId - * - * @return string|null - */ - public static function getClassNameOrNull($headerId) - { - $headerId = (int) $headerId; - - if ($headerId < 0 || $headerId > 0xffff) { - throw new \InvalidArgumentException('$headerId out of range: ' . $headerId); - } - - if (isset(self::$implementations[$headerId])) { - return self::$implementations[$headerId]; - } - - return null; - } -} diff --git a/vendor/nelexa/zip/src/Model/Extra/ZipExtraField.php b/vendor/nelexa/zip/src/Model/Extra/ZipExtraField.php deleted file mode 100644 index ce69aaf..0000000 --- a/vendor/nelexa/zip/src/Model/Extra/ZipExtraField.php +++ /dev/null @@ -1,63 +0,0 @@ - - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA - */ - -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); - -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); - -header("Location: ../"); -exit; diff --git a/vendor/nelexa/zip/src/Model/ImmutableZipContainer.php b/vendor/nelexa/zip/src/Model/ImmutableZipContainer.php deleted file mode 100644 index 69722a0..0000000 --- a/vendor/nelexa/zip/src/Model/ImmutableZipContainer.php +++ /dev/null @@ -1,72 +0,0 @@ -entries = $entries; - $this->archiveComment = $archiveComment; - } - - /** - * @return ZipEntry[] - */ - public function &getEntries() - { - return $this->entries; - } - - /** - * @return string|null - */ - public function getArchiveComment() - { - return $this->archiveComment; - } - - /** - * Count elements of an object. - * - * @see https://php.net/manual/en/countable.count.php - * - * @return int The custom count as an integer. - * The return value is cast to an integer. - */ - public function count() - { - return \count($this->entries); - } - - /** - * When an object is cloned, PHP 5 will perform a shallow copy of all of the object's properties. - * Any properties that are references to other variables, will remain references. - * Once the cloning is complete, if a __clone() method is defined, - * then the newly created object's __clone() method will be called, to allow any necessary properties that need to - * be changed. NOT CALLABLE DIRECTLY. - * - * @see https://php.net/manual/en/language.oop5.cloning.php - */ - public function __clone() - { - foreach ($this->entries as $key => $value) { - $this->entries[$key] = clone $value; - } - } -} diff --git a/vendor/nelexa/zip/src/Model/ZipContainer.php b/vendor/nelexa/zip/src/Model/ZipContainer.php deleted file mode 100644 index 6cfe87e..0000000 --- a/vendor/nelexa/zip/src/Model/ZipContainer.php +++ /dev/null @@ -1,386 +0,0 @@ -getEntries() as $entryName => $entry) { - $entries[$entryName] = clone $entry; - } - $archiveComment = $sourceContainer->getArchiveComment(); - } - parent::__construct($entries, $archiveComment); - $this->sourceContainer = $sourceContainer; - } - - /** - * @return ImmutableZipContainer|null - */ - public function getSourceContainer() - { - return $this->sourceContainer; - } - - /** - * @param ZipEntry $entry - */ - public function addEntry(ZipEntry $entry) - { - $this->entries[$entry->getName()] = $entry; - } - - /** - * @param string|ZipEntry $entry - * - * @return bool - */ - public function deleteEntry($entry) - { - $entry = $entry instanceof ZipEntry ? $entry->getName() : (string) $entry; - - if (isset($this->entries[$entry])) { - unset($this->entries[$entry]); - - return true; - } - - return false; - } - - /** - * @param string|ZipEntry $old - * @param string|ZipEntry $new - * - * @throws ZipException - * - * @return ZipEntry New zip entry - */ - public function renameEntry($old, $new) - { - $old = $old instanceof ZipEntry ? $old->getName() : (string) $old; - $new = $new instanceof ZipEntry ? $new->getName() : (string) $new; - - if (isset($this->entries[$new])) { - throw new InvalidArgumentException('New entry name ' . $new . ' is exists.'); - } - - $entry = $this->getEntry($old); - $newEntry = $entry->rename($new); - - $this->deleteEntry($entry); - $this->addEntry($newEntry); - - return $newEntry; - } - - /** - * @param string|ZipEntry $entryName - * - * @throws ZipEntryNotFoundException - * - * @return ZipEntry - */ - public function getEntry($entryName) - { - $entry = $this->getEntryOrNull($entryName); - - if ($entry !== null) { - return $entry; - } - - throw new ZipEntryNotFoundException($entryName); - } - - /** - * @param string|ZipEntry $entryName - * - * @return ZipEntry|null - */ - public function getEntryOrNull($entryName) - { - $entryName = $entryName instanceof ZipEntry ? $entryName->getName() : (string) $entryName; - - return isset($this->entries[$entryName]) ? $this->entries[$entryName] : null; - } - - /** - * @param string|ZipEntry $entryName - * - * @return bool - */ - public function hasEntry($entryName) - { - $entryName = $entryName instanceof ZipEntry ? $entryName->getName() : (string) $entryName; - - return isset($this->entries[$entryName]); - } - - /** - * Delete all entries. - */ - public function deleteAll() - { - $this->entries = []; - } - - /** - * Delete entries by regex pattern. - * - * @param string $regexPattern Regex pattern - * - * @return ZipEntry[] Deleted entries - */ - public function deleteByRegex($regexPattern) - { - if (empty($regexPattern)) { - throw new InvalidArgumentException('The regex pattern is not specified'); - } - - /** @var ZipEntry[] $found */ - $found = []; - - foreach ($this->entries as $entryName => $entry) { - if (preg_match($regexPattern, $entryName)) { - $found[] = $entry; - } - } - - foreach ($found as $entry) { - $this->deleteEntry($entry); - } - - return $found; - } - - /** - * Undo all changes done in the archive. - */ - public function unchangeAll() - { - $this->entries = []; - - if ($this->sourceContainer !== null) { - foreach ($this->sourceContainer->getEntries() as $entry) { - $this->entries[$entry->getName()] = clone $entry; - } - } - $this->unchangeArchiveComment(); - } - - /** - * Undo change archive comment. - */ - public function unchangeArchiveComment() - { - $this->archiveComment = null; - - if ($this->sourceContainer !== null) { - $this->archiveComment = $this->sourceContainer->archiveComment; - } - } - - /** - * Revert all changes done to an entry with the given name. - * - * @param string|ZipEntry $entry Entry name or ZipEntry - * - * @return bool - */ - public function unchangeEntry($entry) - { - $entry = $entry instanceof ZipEntry ? $entry->getName() : (string) $entry; - - if ( - $this->sourceContainer !== null && - isset($this->entries[$entry], $this->sourceContainer->entries[$entry]) - ) { - $this->entries[$entry] = clone $this->sourceContainer->entries[$entry]; - - return true; - } - - return false; - } - - /** - * Entries sort by name. - * - * Example: - * ```php - * $zipContainer->sortByName(static function (string $nameA, string $nameB): int { - * return strcmp($nameA, $nameB); - * }); - * ``` - * - * @param callable $cmp - */ - public function sortByName(callable $cmp) - { - uksort($this->entries, $cmp); - } - - /** - * Entries sort by entry. - * - * Example: - * ```php - * $zipContainer->sortByEntry(static function (ZipEntry $a, ZipEntry $b): int { - * return strcmp($a->getName(), $b->getName()); - * }); - * ``` - * - * @param callable $cmp - */ - public function sortByEntry(callable $cmp) - { - uasort($this->entries, $cmp); - } - - /** - * @param string|null $archiveComment - */ - public function setArchiveComment($archiveComment) - { - if ($archiveComment !== null && $archiveComment !== '') { - $archiveComment = (string) $archiveComment; - $length = \strlen($archiveComment); - - if ($length > 0xffff) { - throw new InvalidArgumentException('Length comment out of range'); - } - } - $this->archiveComment = $archiveComment; - } - - /** - * @return ZipEntryMatcher - */ - public function matcher() - { - return new ZipEntryMatcher($this); - } - - /** - * Specify a password for extracting files. - * - * @param string|null $password - */ - public function setReadPassword($password) - { - if ($this->sourceContainer !== null) { - foreach ($this->sourceContainer->entries as $entry) { - if ($entry->isEncrypted()) { - $entry->setPassword($password); - } - } - } - } - - /** - * @param string $entryName - * @param string $password - * - * @throws ZipEntryNotFoundException - * @throws ZipException - */ - public function setReadPasswordEntry($entryName, $password) - { - if (!isset($this->sourceContainer->entries[$entryName])) { - throw new ZipEntryNotFoundException($entryName); - } - - if ($this->sourceContainer->entries[$entryName]->isEncrypted()) { - $this->sourceContainer->entries[$entryName]->setPassword($password); - } - } - - /** - * @return int|null - */ - public function getZipAlign() - { - return $this->zipAlign; - } - - /** - * @param int|null $zipAlign - */ - public function setZipAlign($zipAlign) - { - $this->zipAlign = $zipAlign === null ? null : (int) $zipAlign; - } - - /** - * @return bool - */ - public function isZipAlign() - { - return $this->zipAlign !== null; - } - - /** - * @param string|null $writePassword - */ - public function setWritePassword($writePassword) - { - $this->matcher()->all()->setPassword($writePassword); - } - - /** - * Remove password. - */ - public function removePassword() - { - $this->matcher()->all()->setPassword(null); - } - - /** - * @param string|ZipEntry $entryName - */ - public function removePasswordEntry($entryName) - { - $this->matcher()->add($entryName)->setPassword(null); - } - - /** - * @param int $encryptionMethod - */ - public function setEncryptionMethod($encryptionMethod = ZipEncryptionMethod::WINZIP_AES_256) - { - $this->matcher()->all()->setEncryptionMethod($encryptionMethod); - } -} diff --git a/vendor/nelexa/zip/src/Model/ZipData.php b/vendor/nelexa/zip/src/Model/ZipData.php deleted file mode 100644 index 30f8289..0000000 --- a/vendor/nelexa/zip/src/Model/ZipData.php +++ /dev/null @@ -1,28 +0,0 @@ -setName($name, $charset); - - $this->cdExtraFields = new ExtraFieldsCollection(); - $this->localExtraFields = new ExtraFieldsCollection(); - } - - /** - * This method only internal use. - * - * @param string $name - * @param int $createdOS - * @param int $extractedOS - * @param int $softwareVersion - * @param int $extractVersion - * @param int $compressionMethod - * @param int $gpbf - * @param int $dosTime - * @param int $crc - * @param int $compressedSize - * @param int $uncompressedSize - * @param int $internalAttributes - * @param int $externalAttributes - * @param int $offsetLocalHeader - * @param string|null $comment - * @param string|null $charset - * - * @return ZipEntry - * - * @internal - * - * @noinspection PhpTooManyParametersInspection - */ - public static function create( - $name, - $createdOS, - $extractedOS, - $softwareVersion, - $extractVersion, - $compressionMethod, - $gpbf, - $dosTime, - $crc, - $compressedSize, - $uncompressedSize, - $internalAttributes, - $externalAttributes, - $offsetLocalHeader, - $comment, - $charset - ) { - $entry = new self($name); - $entry->createdOS = (int) $createdOS; - $entry->extractedOS = (int) $extractedOS; - $entry->softwareVersion = (int) $softwareVersion; - $entry->extractVersion = (int) $extractVersion; - $entry->compressionMethod = (int) $compressionMethod; - $entry->generalPurposeBitFlags = (int) $gpbf; - $entry->dosTime = (int) $dosTime; - $entry->crc = (int) $crc; - $entry->compressedSize = (int) $compressedSize; - $entry->uncompressedSize = (int) $uncompressedSize; - $entry->internalAttributes = (int) $internalAttributes; - $entry->externalAttributes = (int) $externalAttributes; - $entry->localHeaderOffset = (int) $offsetLocalHeader; - $entry->setComment($comment); - $entry->setCharset($charset); - $entry->updateCompressionLevel(); - - return $entry; - } - - /** - * Set entry name. - * - * @param string $name New entry name - * @param string|null $charset - * - * @return ZipEntry - */ - private function setName($name, $charset = null) - { - if ($name === null) { - throw new InvalidArgumentException('zip entry name is null'); - } - - $name = ltrim((string) $name, '\\/'); - - if ($name === '') { - throw new InvalidArgumentException('Empty zip entry name'); - } - - $name = (string) $name; - $length = \strlen($name); - - if ($length > 0xffff) { - throw new InvalidArgumentException('Illegal zip entry name parameter'); - } - - $this->setCharset($charset); - - if ($this->charset === null && !StringUtil::isASCII($name)) { - $this->enableUtf8Name(true); - } - $this->name = $name; - $this->isDirectory = ($length = \strlen($name)) >= 1 && $name[$length - 1] === '/'; - $this->externalAttributes = $this->isDirectory ? DosAttrs::DOS_DIRECTORY : DosAttrs::DOS_ARCHIVE; - - if ($this->extractVersion !== self::UNKNOWN) { - $this->extractVersion = max( - $this->extractVersion, - $this->isDirectory ? - ZipVersion::v20_DEFLATED_FOLDER_ZIPCRYPTO : - ZipVersion::v10_DEFAULT_MIN - ); - } - - return $this; - } - - /** - * @param string|null $charset - * - * @return ZipEntry - * - * @see DosCodePage::getCodePages() - */ - public function setCharset($charset = null) - { - if ($charset !== null && $charset === '') { - throw new InvalidArgumentException('Empty charset'); - } - $this->charset = $charset; - - return $this; - } - - /** - * @return string|null - */ - public function getCharset() - { - return $this->charset; - } - - /** - * @param string $newName New entry name - * - * @return ZipEntry new {@see ZipEntry} object with new name - * - * @internal - */ - public function rename($newName) - { - $newEntry = clone $this; - $newEntry->setName($newName); - - $newEntry->removeExtraField(UnicodePathExtraField::HEADER_ID); - - return $newEntry; - } - - /** - * Returns the ZIP entry name. - * - * @return string - */ - public function getName() - { - return $this->name; - } - - /** - * @return ZipData|null - * - * @internal - */ - public function getData() - { - return $this->data; - } - - /** - * @param ZipData|null $data - * - * @internal - */ - public function setData($data) - { - $this->data = $data; - } - - /** - * @return int Get platform - * - * @deprecated Use {@see ZipEntry::getCreatedOS()} - */ - public function getPlatform() - { - @trigger_error(__METHOD__ . ' is deprecated. Use ' . __CLASS__ . '::getCreatedOS()', \E_USER_DEPRECATED); - - return $this->getCreatedOS(); - } - - /** - * @param int $platform - * - * @return ZipEntry - * - * @deprecated Use {@see ZipEntry::setCreatedOS()} - */ - public function setPlatform($platform) - { - @trigger_error(__METHOD__ . ' is deprecated. Use ' . __CLASS__ . '::setCreatedOS()', \E_USER_DEPRECATED); - - return $this->setCreatedOS($platform); - } - - /** - * @return int platform - */ - public function getCreatedOS() - { - return $this->createdOS; - } - - /** - * Set platform. - * - * @param int $platform - * - * @return ZipEntry - */ - public function setCreatedOS($platform) - { - $platform = (int) $platform; - - if ($platform < 0x00 || $platform > 0xff) { - throw new InvalidArgumentException('Platform out of range'); - } - $this->createdOS = $platform; - - return $this; - } - - /** - * @return int - */ - public function getExtractedOS() - { - return $this->extractedOS; - } - - /** - * Set extracted OS. - * - * @param int $platform - * - * @return ZipEntry - */ - public function setExtractedOS($platform) - { - $platform = (int) $platform; - - if ($platform < 0x00 || $platform > 0xff) { - throw new InvalidArgumentException('Platform out of range'); - } - $this->extractedOS = $platform; - - return $this; - } - - /** - * @return int - */ - public function getSoftwareVersion() - { - if ($this->softwareVersion === self::UNKNOWN) { - return $this->getExtractVersion(); - } - - return $this->softwareVersion; - } - - /** - * @param int $softwareVersion - * - * @return ZipEntry - */ - public function setSoftwareVersion($softwareVersion) - { - $this->softwareVersion = (int) $softwareVersion; - - return $this; - } - - /** - * Version needed to extract. - * - * @return int - * - * @deprecated Use {@see ZipEntry::getExtractVersion()} - */ - public function getVersionNeededToExtract() - { - @trigger_error(__METHOD__ . ' is deprecated. Use ' . __CLASS__ . '::getExtractVersion()', \E_USER_DEPRECATED); - - return $this->getExtractVersion(); - } - - /** - * Version needed to extract. - * - * @return int - */ - public function getExtractVersion() - { - if ($this->extractVersion === self::UNKNOWN) { - if (ZipEncryptionMethod::isWinZipAesMethod($this->encryptionMethod)) { - return ZipVersion::v51_ENCR_AES_RC2_CORRECT; - } - - if ($this->compressionMethod === ZipCompressionMethod::BZIP2) { - return ZipVersion::v46_BZIP2; - } - - if ($this->isZip64ExtensionsRequired()) { - return ZipVersion::v45_ZIP64_EXT; - } - - if ( - $this->compressionMethod === ZipCompressionMethod::DEFLATED || - $this->isDirectory || - $this->encryptionMethod === ZipEncryptionMethod::PKWARE - ) { - return ZipVersion::v20_DEFLATED_FOLDER_ZIPCRYPTO; - } - - return ZipVersion::v10_DEFAULT_MIN; - } - - return $this->extractVersion; - } - - /** - * Set version needed to extract. - * - * @param int $version - * - * @return ZipEntry - * - * @deprecated Use {@see ZipEntry::setExtractVersion()} - */ - public function setVersionNeededToExtract($version) - { - @trigger_error(__METHOD__ . ' is deprecated. Use ' . __CLASS__ . '::setExtractVersion()', \E_USER_DEPRECATED); - - return $this->setExtractVersion($version); - } - - /** - * Set version needed to extract. - * - * @param int $version - * - * @return ZipEntry - */ - public function setExtractVersion($version) - { - $this->extractVersion = max(ZipVersion::v10_DEFAULT_MIN, (int) $version); - - return $this; - } - - /** - * Returns the compressed size of this entry. - * - * @return int - */ - public function getCompressedSize() - { - return $this->compressedSize; - } - - /** - * Sets the compressed size of this entry. - * - * @param int $compressedSize the Compressed Size - * - * @return ZipEntry - * - * @internal - */ - public function setCompressedSize($compressedSize) - { - $compressedSize = (int) $compressedSize; - - if ($compressedSize < self::UNKNOWN) { - throw new InvalidArgumentException('Compressed size < ' . self::UNKNOWN); - } - $this->compressedSize = $compressedSize; - - return $this; - } - - /** - * Returns the uncompressed size of this entry. - * - * @return int - * - * @deprecated Use {@see ZipEntry::getUncompressedSize()} - */ - public function getSize() - { - @trigger_error(__METHOD__ . ' is deprecated. Use ' . __CLASS__ . '::getUncompressedSize()', \E_USER_DEPRECATED); - - return $this->getUncompressedSize(); - } - - /** - * Sets the uncompressed size of this entry. - * - * @param int $size the (Uncompressed) Size - * - * @return ZipEntry - * - * @deprecated Use {@see ZipEntry::setUncompressedSize()} - * - * @internal - */ - public function setSize($size) - { - @trigger_error(__METHOD__ . ' is deprecated. Use ' . __CLASS__ . '::setUncompressedSize()', \E_USER_DEPRECATED); - - return $this->setUncompressedSize($size); - } - - /** - * Returns the uncompressed size of this entry. - * - * @return int - */ - public function getUncompressedSize() - { - return $this->uncompressedSize; - } - - /** - * Sets the uncompressed size of this entry. - * - * @param int $uncompressedSize the (Uncompressed) Size - * - * @return ZipEntry - * - * @internal - */ - public function setUncompressedSize($uncompressedSize) - { - $uncompressedSize = (int) $uncompressedSize; - - if ($uncompressedSize < self::UNKNOWN) { - throw new InvalidArgumentException('Uncompressed size < ' . self::UNKNOWN); - } - $this->uncompressedSize = $uncompressedSize; - - return $this; - } - - /** - * Return relative Offset Of Local File Header. - * - * @return int - */ - public function getLocalHeaderOffset() - { - return $this->localHeaderOffset; - } - - /** - * @param int $localHeaderOffset - * - * @return ZipEntry - * - * @internal - */ - public function setLocalHeaderOffset($localHeaderOffset) - { - $localHeaderOffset = (int) $localHeaderOffset; - - if ($localHeaderOffset < 0) { - throw new InvalidArgumentException('Negative $localHeaderOffset'); - } - $this->localHeaderOffset = $localHeaderOffset; - - return $this; - } - - /** - * Return relative Offset Of Local File Header. - * - * @return int - * - * @deprecated Use {@see ZipEntry::getLocalHeaderOffset()} - */ - public function getOffset() - { - @trigger_error( - __METHOD__ . ' is deprecated. Use ' . __CLASS__ . '::getLocalHeaderOffset()', - \E_USER_DEPRECATED - ); - - return $this->getLocalHeaderOffset(); - } - - /** - * @param int $offset - * - * @return ZipEntry - * - * @deprecated Use {@see ZipEntry::setLocalHeaderOffset()} - * - * @internal - */ - public function setOffset($offset) - { - @trigger_error( - __METHOD__ . ' is deprecated. Use ' . __CLASS__ . '::setLocalHeaderOffset()', - \E_USER_DEPRECATED - ); - - return $this->setLocalHeaderOffset($offset); - } - - /** - * Returns the General Purpose Bit Flags. - * - * @return int - */ - public function getGeneralPurposeBitFlags() - { - return $this->generalPurposeBitFlags; - } - - /** - * Sets the General Purpose Bit Flags. - * - * @param int $gpbf general purpose bit flags - * - * @return ZipEntry - * - * @internal - */ - public function setGeneralPurposeBitFlags($gpbf) - { - $gpbf = (int) $gpbf; - - if ($gpbf < 0x0000 || $gpbf > 0xffff) { - throw new InvalidArgumentException('general purpose bit flags out of range'); - } - $this->generalPurposeBitFlags = $gpbf; - $this->updateCompressionLevel(); - - return $this; - } - - private function updateCompressionLevel() - { - if ($this->compressionMethod === ZipCompressionMethod::DEFLATED) { - $bit1 = $this->isSetGeneralBitFlag(GeneralPurposeBitFlag::COMPRESSION_FLAG1); - $bit2 = $this->isSetGeneralBitFlag(GeneralPurposeBitFlag::COMPRESSION_FLAG2); - - if ($bit1 && !$bit2) { - $this->compressionLevel = ZipCompressionLevel::MAXIMUM; - } elseif (!$bit1 && $bit2) { - $this->compressionLevel = ZipCompressionLevel::FAST; - } elseif ($bit1 && $bit2) { - $this->compressionLevel = ZipCompressionLevel::SUPER_FAST; - } else { - $this->compressionLevel = ZipCompressionLevel::NORMAL; - } - } - } - - /** - * @param int $mask - * @param bool $enable - * - * @return ZipEntry - */ - private function setGeneralBitFlag($mask, $enable) - { - if ($enable) { - $this->generalPurposeBitFlags |= $mask; - } else { - $this->generalPurposeBitFlags &= ~$mask; - } - - return $this; - } - - /** - * @param int $mask - * - * @return bool - */ - private function isSetGeneralBitFlag($mask) - { - return ($this->generalPurposeBitFlags & $mask) === $mask; - } - - /** - * @return bool - */ - public function isDataDescriptorEnabled() - { - return $this->isSetGeneralBitFlag(GeneralPurposeBitFlag::DATA_DESCRIPTOR); - } - - /** - * Enabling or disabling the use of the Data Descriptor block. - * - * @param bool $enabled - */ - public function enableDataDescriptor($enabled = true) - { - $this->setGeneralBitFlag(GeneralPurposeBitFlag::DATA_DESCRIPTOR, (bool) $enabled); - } - - /** - * @param bool $enabled - */ - public function enableUtf8Name($enabled) - { - $this->setGeneralBitFlag(GeneralPurposeBitFlag::UTF8, (bool) $enabled); - } - - /** - * @return bool - */ - public function isUtf8Flag() - { - return $this->isSetGeneralBitFlag(GeneralPurposeBitFlag::UTF8); - } - - /** - * Returns true if and only if this ZIP entry is encrypted. - * - * @return bool - */ - public function isEncrypted() - { - return $this->isSetGeneralBitFlag(GeneralPurposeBitFlag::ENCRYPTION); - } - - /** - * @return bool - */ - public function isStrongEncryption() - { - return $this->isSetGeneralBitFlag(GeneralPurposeBitFlag::STRONG_ENCRYPTION); - } - - /** - * Sets the encryption property to false and removes any other - * encryption artifacts. - * - * @return ZipEntry - */ - public function disableEncryption() - { - $this->setEncrypted(false); - $this->removeExtraField(WinZipAesExtraField::HEADER_ID); - $this->encryptionMethod = ZipEncryptionMethod::NONE; - $this->password = null; - $this->extractVersion = self::UNKNOWN; - - return $this; - } - - /** - * Sets the encryption flag for this ZIP entry. - * - * @param bool $encrypted - * - * @return ZipEntry - */ - private function setEncrypted($encrypted) - { - $encrypted = (bool) $encrypted; - $this->setGeneralBitFlag(GeneralPurposeBitFlag::ENCRYPTION, $encrypted); - - return $this; - } - - /** - * Returns the compression method for this entry. - * - * @return int - * - * @deprecated Use {@see ZipEntry::getCompressionMethod()} - */ - public function getMethod() - { - @trigger_error( - __METHOD__ . ' is deprecated. Use ' . __CLASS__ . '::getCompressionMethod()', - \E_USER_DEPRECATED - ); - - return $this->getCompressionMethod(); - } - - /** - * Returns the compression method for this entry. - * - * @return int - */ - public function getCompressionMethod() - { - return $this->compressionMethod; - } - - /** - * Sets the compression method for this entry. - * - * @param int $method - * - * @throws ZipUnsupportMethodException - * - * @return ZipEntry - * - * @deprecated Use {@see ZipEntry::setCompressionMethod()} - */ - public function setMethod($method) - { - @trigger_error( - __METHOD__ . ' is deprecated. Use ' . __CLASS__ . '::setCompressionMethod()', - \E_USER_DEPRECATED - ); - - return $this->setCompressionMethod($method); - } - - /** - * Sets the compression method for this entry. - * - * @param int $compressionMethod - * - * @throws ZipUnsupportMethodException - * - * @return ZipEntry - * - * @see ZipCompressionMethod::STORED - * @see ZipCompressionMethod::DEFLATED - * @see ZipCompressionMethod::BZIP2 - */ - public function setCompressionMethod($compressionMethod) - { - $compressionMethod = (int) $compressionMethod; - - if ($compressionMethod < 0x0000 || $compressionMethod > 0xffff) { - throw new InvalidArgumentException('method out of range: ' . $compressionMethod); - } - - ZipCompressionMethod::checkSupport($compressionMethod); - - $this->compressionMethod = $compressionMethod; - $this->updateCompressionLevel(); - $this->extractVersion = self::UNKNOWN; - - return $this; - } - - /** - * Get Unix Timestamp. - * - * @return int - */ - public function getTime() - { - if ($this->getDosTime() === self::UNKNOWN) { - return self::UNKNOWN; - } - - return DateTimeConverter::msDosToUnix($this->getDosTime()); - } - - /** - * Get Dos Time. - * - * @return int - */ - public function getDosTime() - { - return $this->dosTime; - } - - /** - * Set Dos Time. - * - * @param int $dosTime - * - * @return ZipEntry - */ - public function setDosTime($dosTime) - { - $dosTime = (int) $dosTime; - - if (\PHP_INT_SIZE === 8) { - if ($dosTime < 0x00000000 || $dosTime > 0xffffffff) { - throw new InvalidArgumentException('DosTime out of range'); - } - } - - $this->dosTime = $dosTime; - - return $this; - } - - /** - * Set time from unix timestamp. - * - * @param int $unixTimestamp - * - * @return ZipEntry - */ - public function setTime($unixTimestamp) - { - if ($unixTimestamp !== self::UNKNOWN) { - $this->setDosTime(DateTimeConverter::unixToMsDos($unixTimestamp)); - } else { - $this->dosTime = 0; - } - - return $this; - } - - /** - * Returns the external file attributes. - * - * @return int the external file attributes - */ - public function getExternalAttributes() - { - return $this->externalAttributes; - } - - /** - * Sets the external file attributes. - * - * @param int $externalAttributes the external file attributes - * - * @return ZipEntry - */ - public function setExternalAttributes($externalAttributes) - { - $this->externalAttributes = (int) $externalAttributes; - - if (\PHP_INT_SIZE === 8) { - if ($externalAttributes < 0x00000000 || $externalAttributes > 0xffffffff) { - throw new InvalidArgumentException('external attributes out of range: ' . $externalAttributes); - } - } - - $this->externalAttributes = $externalAttributes; - - return $this; - } - - /** - * Returns the internal file attributes. - * - * @return int the internal file attributes - */ - public function getInternalAttributes() - { - return $this->internalAttributes; - } - - /** - * Sets the internal file attributes. - * - * @param int $internalAttributes the internal file attributes - * - * @return ZipEntry - */ - public function setInternalAttributes($internalAttributes) - { - $internalAttributes = (int) $internalAttributes; - - if ($internalAttributes < 0x0000 || $internalAttributes > 0xffff) { - throw new InvalidArgumentException('internal attributes out of range'); - } - $this->internalAttributes = $internalAttributes; - - return $this; - } - - /** - * Returns true if and only if this ZIP entry represents a directory entry - * (i.e. end with '/'). - * - * @return bool - */ - final public function isDirectory() - { - return $this->isDirectory; - } - - /** - * @return ExtraFieldsCollection - */ - public function getCdExtraFields() - { - return $this->cdExtraFields; - } - - /** - * @param int $headerId - * - * @return ZipExtraField|null - */ - public function getCdExtraField($headerId) - { - return $this->cdExtraFields->get((int) $headerId); - } - - /** - * @param ExtraFieldsCollection $cdExtraFields - * - * @return ZipEntry - */ - public function setCdExtraFields(ExtraFieldsCollection $cdExtraFields) - { - $this->cdExtraFields = $cdExtraFields; - - return $this; - } - - /** - * @return ExtraFieldsCollection - */ - public function getLocalExtraFields() - { - return $this->localExtraFields; - } - - /** - * @param int $headerId - * - * @return ZipExtraField|null - */ - public function getLocalExtraField($headerId) - { - return $this->localExtraFields[(int) $headerId]; - } - - /** - * @param ExtraFieldsCollection $localExtraFields - * - * @return ZipEntry - */ - public function setLocalExtraFields(ExtraFieldsCollection $localExtraFields) - { - $this->localExtraFields = $localExtraFields; - - return $this; - } - - /** - * @param int $headerId - * - * @return ZipExtraField|null - */ - public function getExtraField($headerId) - { - $headerId = (int) $headerId; - $local = $this->getLocalExtraField($headerId); - - if ($local === null) { - return $this->getCdExtraField($headerId); - } - - return $local; - } - - /** - * @param int $headerId - * - * @return bool - */ - public function hasExtraField($headerId) - { - $headerId = (int) $headerId; - - return - isset($this->localExtraFields[$headerId]) || - isset($this->cdExtraFields[$headerId]); - } - - /** - * @param int $headerId - */ - public function removeExtraField($headerId) - { - $headerId = (int) $headerId; - - $this->cdExtraFields->remove($headerId); - $this->localExtraFields->remove($headerId); - } - - /** - * @param ZipExtraField $zipExtraField - */ - public function addExtraField(ZipExtraField $zipExtraField) - { - $this->addLocalExtraField($zipExtraField); - $this->addCdExtraField($zipExtraField); - } - - /** - * @param ZipExtraField $zipExtraField - */ - public function addLocalExtraField(ZipExtraField $zipExtraField) - { - $this->localExtraFields->add($zipExtraField); - } - - /** - * @param ZipExtraField $zipExtraField - */ - public function addCdExtraField(ZipExtraField $zipExtraField) - { - $this->cdExtraFields->add($zipExtraField); - } - - /** - * Returns comment entry. - * - * @return string - */ - public function getComment() - { - return $this->comment !== null ? $this->comment : ''; - } - - /** - * Set entry comment. - * - * @param string|null $comment - * - * @return ZipEntry - */ - public function setComment($comment) - { - if ($comment !== null) { - $commentLength = \strlen($comment); - - if ($commentLength > 0xffff) { - throw new InvalidArgumentException('Comment too long'); - } - - if ($this->charset === null && !StringUtil::isASCII($comment)) { - $this->enableUtf8Name(true); - } - } - $this->comment = $comment; - - return $this; - } - - /** - * @return bool - */ - public function isDataDescriptorRequired() - { - return ($this->getCrc() | $this->getCompressedSize() | $this->getUncompressedSize()) === self::UNKNOWN; - } - - /** - * Return crc32 content or 0 for WinZip AES v2. - * - * @return int - */ - public function getCrc() - { - return $this->crc; - } - - /** - * Set crc32 content. - * - * @param int $crc - * - * @return ZipEntry - * - * @internal - */ - public function setCrc($crc) - { - $this->crc = (int) $crc; - - return $this; - } - - /** - * @return string|null - */ - public function getPassword() - { - return $this->password; - } - - /** - * Set password and encryption method from entry. - * - * @param string|null $password - * @param int|null $encryptionMethod - * - * @return ZipEntry - */ - public function setPassword($password, $encryptionMethod = null) - { - if (!$this->isDirectory) { - if ($password === null || $password === '') { - $this->password = null; - $this->disableEncryption(); - } else { - $this->password = (string) $password; - - if ($encryptionMethod === null && $this->encryptionMethod === ZipEncryptionMethod::NONE) { - $encryptionMethod = ZipEncryptionMethod::WINZIP_AES_256; - } - - if ($encryptionMethod !== null) { - $this->setEncryptionMethod($encryptionMethod); - } - $this->setEncrypted(true); - } - } - - return $this; - } - - /** - * @return int - */ - public function getEncryptionMethod() - { - return $this->encryptionMethod; - } - - /** - * Set encryption method. - * - * @param int|null $encryptionMethod - * - * @return ZipEntry - * - * @see ZipEncryptionMethod::NONE - * @see ZipEncryptionMethod::PKWARE - * @see ZipEncryptionMethod::WINZIP_AES_256 - * @see ZipEncryptionMethod::WINZIP_AES_192 - * @see ZipEncryptionMethod::WINZIP_AES_128 - */ - public function setEncryptionMethod($encryptionMethod) - { - if ($encryptionMethod === null) { - $encryptionMethod = ZipEncryptionMethod::NONE; - } - - $encryptionMethod = (int) $encryptionMethod; - ZipEncryptionMethod::checkSupport($encryptionMethod); - $this->encryptionMethod = $encryptionMethod; - - $this->setEncrypted($this->encryptionMethod !== ZipEncryptionMethod::NONE); - $this->extractVersion = self::UNKNOWN; - - return $this; - } - - /** - * @return int - */ - public function getCompressionLevel() - { - return $this->compressionLevel; - } - - /** - * @param int $compressionLevel - * - * @return ZipEntry - */ - public function setCompressionLevel($compressionLevel) - { - $compressionLevel = (int) $compressionLevel; - - if ($compressionLevel === self::UNKNOWN) { - $compressionLevel = ZipCompressionLevel::NORMAL; - } - - if ( - $compressionLevel < ZipCompressionLevel::LEVEL_MIN || - $compressionLevel > ZipCompressionLevel::LEVEL_MAX - ) { - throw new InvalidArgumentException( - 'Invalid compression level. Minimum level ' . - ZipCompressionLevel::LEVEL_MIN . '. Maximum level ' . ZipCompressionLevel::LEVEL_MAX - ); - } - $this->compressionLevel = $compressionLevel; - - $this->updateGbpfCompLevel(); - - return $this; - } - - /** - * Update general purpose bit flogs. - */ - private function updateGbpfCompLevel() - { - if ($this->compressionMethod === ZipCompressionMethod::DEFLATED) { - $bit1 = false; - $bit2 = false; - - switch ($this->compressionLevel) { - case ZipCompressionLevel::MAXIMUM: - $bit1 = true; - break; - - case ZipCompressionLevel::FAST: - $bit2 = true; - break; - - case ZipCompressionLevel::SUPER_FAST: - $bit1 = true; - $bit2 = true; - break; - // default is ZipCompressionLevel::NORMAL - } - - $this->generalPurposeBitFlags |= ($bit1 ? GeneralPurposeBitFlag::COMPRESSION_FLAG1 : 0); - $this->generalPurposeBitFlags |= ($bit2 ? GeneralPurposeBitFlag::COMPRESSION_FLAG2 : 0); - } - } - - /** - * Sets Unix permissions in a way that is understood by Info-Zip's - * unzip command. - * - * @param int $mode mode an int value - * - * @return ZipEntry - */ - public function setUnixMode($mode) - { - $mode = (int) $mode; - $this->setExternalAttributes( - ($mode << 16) - // MS-DOS read-only attribute - | (($mode & UnixStat::UNX_IWUSR) === 0 ? DosAttrs::DOS_HIDDEN : 0) - // MS-DOS directory flag - | ($this->isDirectory() ? DosAttrs::DOS_DIRECTORY : DosAttrs::DOS_ARCHIVE) - ); - $this->createdOS = ZipPlatform::OS_UNIX; - - return $this; - } - - /** - * Unix permission. - * - * @return int the unix permissions - */ - public function getUnixMode() - { - $mode = 0; - - if ($this->createdOS === ZipPlatform::OS_UNIX) { - $mode = ($this->externalAttributes >> 16) & 0xFFFF; - } elseif ($this->hasExtraField(AsiExtraField::HEADER_ID)) { - /** @var AsiExtraField $asiExtraField */ - $asiExtraField = $this->getExtraField(AsiExtraField::HEADER_ID); - $mode = $asiExtraField->getMode(); - } - - if ($mode > 0) { - return $mode; - } - - return $this->isDirectory ? 040755 : 0100644; - } - - /** - * Offset MUST be considered in decision about ZIP64 format - see - * description of Data Descriptor in ZIP File Format Specification. - * - * @return bool - */ - public function isZip64ExtensionsRequired() - { - return $this->compressedSize > ZipConstants::ZIP64_MAGIC - || $this->uncompressedSize > ZipConstants::ZIP64_MAGIC; - } - - /** - * Returns true if this entry represents a unix symlink, - * in which case the entry's content contains the target path - * for the symlink. - * - * @return bool true if the entry represents a unix symlink, - * false otherwise - */ - public function isUnixSymlink() - { - return ($this->getUnixMode() & UnixStat::UNX_IFMT) === UnixStat::UNX_IFLNK; - } - - /** - * @return \DateTimeInterface - */ - public function getMTime() - { - /** @var NtfsExtraField|null $ntfsExtra */ - $ntfsExtra = $this->getExtraField(NtfsExtraField::HEADER_ID); - - if ($ntfsExtra !== null) { - return $ntfsExtra->getModifyDateTime(); - } - - /** @var ExtendedTimestampExtraField|null $extendedExtra */ - $extendedExtra = $this->getExtraField(ExtendedTimestampExtraField::HEADER_ID); - - if ($extendedExtra !== null && ($mtime = $extendedExtra->getModifyDateTime()) !== null) { - return $mtime; - } - - /** @var OldUnixExtraField|null $oldUnixExtra */ - $oldUnixExtra = $this->getExtraField(OldUnixExtraField::HEADER_ID); - - if ($oldUnixExtra !== null && ($mtime = $oldUnixExtra->getModifyDateTime()) !== null) { - return $mtime; - } - - $timestamp = $this->getTime(); - - try { - return new \DateTimeImmutable('@' . $timestamp); - } catch (\Exception $e) { - throw new RuntimeException('Error create DateTime object with timestamp ' . $timestamp, 1, $e); - } - } - - /** - * @return \DateTimeInterface|null - */ - public function getATime() - { - /** @var NtfsExtraField|null $ntfsExtra */ - $ntfsExtra = $this->getExtraField(NtfsExtraField::HEADER_ID); - - if ($ntfsExtra !== null) { - return $ntfsExtra->getAccessDateTime(); - } - - /** @var ExtendedTimestampExtraField|null $extendedExtra */ - $extendedExtra = $this->getExtraField(ExtendedTimestampExtraField::HEADER_ID); - - if ($extendedExtra !== null && ($atime = $extendedExtra->getAccessDateTime()) !== null) { - return $atime; - } - - /** @var OldUnixExtraField|null $oldUnixExtra */ - $oldUnixExtra = $this->getExtraField(OldUnixExtraField::HEADER_ID); - - if ($oldUnixExtra !== null) { - return $oldUnixExtra->getAccessDateTime(); - } - - return null; - } - - /** - * @return \DateTimeInterface|null - */ - public function getCTime() - { - /** @var NtfsExtraField|null $ntfsExtra */ - $ntfsExtra = $this->getExtraField(NtfsExtraField::HEADER_ID); - - if ($ntfsExtra !== null) { - return $ntfsExtra->getCreateDateTime(); - } - - /** @var ExtendedTimestampExtraField|null $extendedExtra */ - $extendedExtra = $this->getExtraField(ExtendedTimestampExtraField::HEADER_ID); - - if ($extendedExtra !== null) { - return $extendedExtra->getCreateDateTime(); - } - - return null; - } - - public function __clone() - { - $this->cdExtraFields = clone $this->cdExtraFields; - $this->localExtraFields = clone $this->localExtraFields; - - if ($this->data !== null) { - $this->data = clone $this->data; - } - } -} diff --git a/vendor/nelexa/zip/src/Model/ZipEntryMatcher.php b/vendor/nelexa/zip/src/Model/ZipEntryMatcher.php deleted file mode 100644 index 9b91ba7..0000000 --- a/vendor/nelexa/zip/src/Model/ZipEntryMatcher.php +++ /dev/null @@ -1,206 +0,0 @@ -zipContainer = $zipContainer; - } - - /** - * @param string|ZipEntry|string[]|ZipEntry[] $entries - * - * @return ZipEntryMatcher - */ - public function add($entries) - { - $entries = (array) $entries; - $entries = array_map( - static function ($entry) { - return $entry instanceof ZipEntry ? $entry->getName() : (string) $entry; - }, - $entries - ); - $this->matches = array_values( - array_map( - 'strval', - array_unique( - array_merge( - $this->matches, - array_keys( - array_intersect_key( - $this->zipContainer->getEntries(), - array_flip($entries) - ) - ) - ) - ) - ) - ); - - return $this; - } - - /** - * @param string $regexp - * - * @return ZipEntryMatcher - * - * @noinspection PhpUnusedParameterInspection - */ - public function match($regexp) - { - array_walk( - $this->zipContainer->getEntries(), - /** - * @param ZipEntry $entry - * @param string $entryName - */ - function (ZipEntry $entry, $entryName) use ($regexp) { - if (preg_match($regexp, $entryName)) { - $this->matches[] = (string) $entryName; - } - } - ); - $this->matches = array_unique($this->matches); - - return $this; - } - - /** - * @return ZipEntryMatcher - */ - public function all() - { - $this->matches = array_map( - 'strval', - array_keys($this->zipContainer->getEntries()) - ); - - return $this; - } - - /** - * Callable function for all select entries. - * - * Callable function signature: - * function(string $entryName){} - * - * @param callable $callable - */ - public function invoke(callable $callable) - { - if (!empty($this->matches)) { - array_walk( - $this->matches, - /** @param string $entryName */ - static function ($entryName) use ($callable) { - $callable($entryName); - } - ); - } - } - - /** - * @return array - */ - public function getMatches() - { - return $this->matches; - } - - public function delete() - { - array_walk( - $this->matches, - /** @param string $entryName */ - function ($entryName) { - $this->zipContainer->deleteEntry($entryName); - } - ); - $this->matches = []; - } - - /** - * @param string|null $password - * @param int|null $encryptionMethod - */ - public function setPassword($password, $encryptionMethod = null) - { - array_walk( - $this->matches, - /** @param string $entryName */ - function ($entryName) use ($password, $encryptionMethod) { - $entry = $this->zipContainer->getEntry($entryName); - - if (!$entry->isDirectory()) { - $entry->setPassword($password, $encryptionMethod); - } - } - ); - } - - /** - * @param int $encryptionMethod - */ - public function setEncryptionMethod($encryptionMethod) - { - array_walk( - $this->matches, - /** @param string $entryName */ - function ($entryName) use ($encryptionMethod) { - $entry = $this->zipContainer->getEntry($entryName); - - if (!$entry->isDirectory()) { - $entry->setEncryptionMethod($encryptionMethod); - } - } - ); - } - - public function disableEncryption() - { - array_walk( - $this->matches, - /** @param string $entryName */ - function ($entryName) { - $entry = $this->zipContainer->getEntry($entryName); - - if (!$entry->isDirectory()) { - $entry->disableEncryption(); - } - } - ); - } - - /** - * Count elements of an object. - * - * @see http://php.net/manual/en/countable.count.php - * - * @return int the custom count as an integer - * - * @since 5.1.0 - */ - public function count() - { - return \count($this->matches); - } -} diff --git a/vendor/nelexa/zip/src/Model/ZipInfo.php b/vendor/nelexa/zip/src/Model/ZipInfo.php deleted file mode 100644 index 42eebbf..0000000 --- a/vendor/nelexa/zip/src/Model/ZipInfo.php +++ /dev/null @@ -1,266 +0,0 @@ -entry = $entry; - } - - /** - * @param ZipEntry $entry - * - * @return string - * - * @deprecated Use {@see ZipPlatform::getPlatformName()} - */ - public static function getPlatformName(ZipEntry $entry) - { - return ZipPlatform::getPlatformName($entry->getExtractedOS()); - } - - /** - * @return string - */ - public function getName() - { - return $this->entry->getName(); - } - - /** - * @return bool - */ - public function isFolder() - { - return $this->entry->isDirectory(); - } - - /** - * @return int - */ - public function getSize() - { - return $this->entry->getUncompressedSize(); - } - - /** - * @return int - */ - public function getCompressedSize() - { - return $this->entry->getCompressedSize(); - } - - /** - * @return int - */ - public function getMtime() - { - return $this->entry->getMTime()->getTimestamp(); - } - - /** - * @return int|null - */ - public function getCtime() - { - $ctime = $this->entry->getCTime(); - - return $ctime === null ? null : $ctime->getTimestamp(); - } - - /** - * @return int|null - */ - public function getAtime() - { - $atime = $this->entry->getATime(); - - return $atime === null ? null : $atime->getTimestamp(); - } - - /** - * @return string - */ - public function getAttributes() - { - $externalAttributes = $this->entry->getExternalAttributes(); - - if ($this->entry->getCreatedOS() === ZipPlatform::OS_UNIX) { - $permission = (($externalAttributes >> 16) & 0xFFFF); - - return FileAttribUtil::getUnixMode($permission); - } - - return FileAttribUtil::getDosMode($externalAttributes); - } - - /** - * @return bool - */ - public function isEncrypted() - { - return $this->entry->isEncrypted(); - } - - /** - * @return string|null - */ - public function getComment() - { - return $this->entry->getComment(); - } - - /** - * @return int - */ - public function getCrc() - { - return $this->entry->getCrc(); - } - - /** - * @return string - * - * @deprecated use \PhpZip\Model\ZipInfo::getMethodName() - */ - public function getMethod() - { - return $this->getMethodName(); - } - - /** - * @return string - */ - public function getMethodName() - { - return ZipCompressionMethod::getCompressionMethodName($this->entry->getCompressionMethod()); - } - - /** - * @return string - */ - public function getEncryptionMethodName() - { - return ZipEncryptionMethod::getEncryptionMethodName($this->entry->getEncryptionMethod()); - } - - /** - * @return string - */ - public function getPlatform() - { - return ZipPlatform::getPlatformName($this->entry->getExtractedOS()); - } - - /** - * @return int - */ - public function getVersion() - { - return $this->entry->getExtractVersion(); - } - - /** - * @return int|null - */ - public function getEncryptionMethod() - { - $encryptionMethod = $this->entry->getEncryptionMethod(); - - return $encryptionMethod === ZipEncryptionMethod::NONE ? null : $encryptionMethod; - } - - /** - * @return int|null - */ - public function getCompressionLevel() - { - return $this->entry->getCompressionLevel(); - } - - /** - * @return int - */ - public function getCompressionMethod() - { - return $this->entry->getCompressionMethod(); - } - - /** - * @return array - */ - public function toArray() - { - return [ - 'name' => $this->getName(), - 'folder' => $this->isFolder(), - 'size' => $this->getSize(), - 'compressed_size' => $this->getCompressedSize(), - 'modified' => $this->getMtime(), - 'created' => $this->getCtime(), - 'accessed' => $this->getAtime(), - 'attributes' => $this->getAttributes(), - 'encrypted' => $this->isEncrypted(), - 'encryption_method' => $this->getEncryptionMethod(), - 'encryption_method_name' => $this->getEncryptionMethodName(), - 'comment' => $this->getComment(), - 'crc' => $this->getCrc(), - 'method_name' => $this->getMethodName(), - 'compression_method' => $this->getCompressionMethod(), - 'platform' => $this->getPlatform(), - 'version' => $this->getVersion(), - ]; - } - - /** - * @return string - */ - public function __toString() - { - $ctime = $this->entry->getCTime(); - $atime = $this->entry->getATime(); - $comment = $this->getComment(); - - return __CLASS__ . ' {' - . 'Name="' . $this->getName() . '", ' - . ($this->isFolder() ? 'Folder, ' : '') - . 'Size="' . FilesUtil::humanSize($this->getSize()) . '"' - . ', Compressed size="' . FilesUtil::humanSize($this->getCompressedSize()) . '"' - . ', Modified time="' . $this->entry->getMTime()->format(\DATE_W3C) . '", ' - . ($ctime !== null ? 'Created time="' . $ctime->format(\DATE_W3C) . '", ' : '') - . ($atime !== null ? 'Accessed time="' . $atime->format(\DATE_W3C) . '", ' : '') - . ($this->isEncrypted() ? 'Encrypted, ' : '') - . ($comment !== null ? 'Comment="' . $comment . '", ' : '') - . (!empty($this->crc) ? 'Crc=0x' . dechex($this->crc) . ', ' : '') - . 'Method name="' . $this->getMethodName() . '", ' - . 'Attributes="' . $this->getAttributes() . '", ' - . 'Platform="' . $this->getPlatform() . '", ' - . 'Version=' . $this->getVersion() - . '}'; - } -} diff --git a/vendor/nelexa/zip/src/Model/index.php b/vendor/nelexa/zip/src/Model/index.php deleted file mode 100644 index df24d3e..0000000 --- a/vendor/nelexa/zip/src/Model/index.php +++ /dev/null @@ -1,35 +0,0 @@ - - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA - */ - -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); - -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); - -header("Location: ../"); -exit; diff --git a/vendor/nelexa/zip/src/Util/CryptoUtil.php b/vendor/nelexa/zip/src/Util/CryptoUtil.php deleted file mode 100644 index 852a5e1..0000000 --- a/vendor/nelexa/zip/src/Util/CryptoUtil.php +++ /dev/null @@ -1,77 +0,0 @@ -> 1); - - /** - * Convert a 32 bit integer DOS date/time value to a UNIX timestamp value. - * - * @param int $dosTime Dos date/time - * - * @return int Unix timestamp - */ - public static function msDosToUnix($dosTime) - { - if ($dosTime <= self::MIN_DOS_TIME) { - $dosTime = 0; - } elseif ($dosTime > self::MAX_DOS_TIME) { - $dosTime = self::MAX_DOS_TIME; - } -// date_default_timezone_set('UTC'); - return mktime( - (($dosTime >> 11) & 0x1f), // hours - (($dosTime >> 5) & 0x3f), // minutes - (($dosTime << 1) & 0x3e), // seconds - (($dosTime >> 21) & 0x0f), // month - (($dosTime >> 16) & 0x1f), // day - ((($dosTime >> 25) & 0x7f) + 1980) // year - ); - } - - /** - * Converts a UNIX timestamp value to a DOS date/time value. - * - * @param int $unixTimestamp the number of seconds since midnight, January 1st, - * 1970 AD UTC - * - * @return int a DOS date/time value reflecting the local time zone and - * rounded down to even seconds - * and is in between DateTimeConverter::MIN_DOS_TIME and DateTimeConverter::MAX_DOS_TIME - */ - public static function unixToMsDos($unixTimestamp) - { - if ($unixTimestamp < 0) { - throw new \InvalidArgumentException('Negative unix timestamp: ' . $unixTimestamp); - } - - $date = getdate($unixTimestamp); - $dosTime = ( - (($date['year'] - 1980) << 25) | - ($date['mon'] << 21) | - ($date['mday'] << 16) | - ($date['hours'] << 11) | - ($date['minutes'] << 5) | - ($date['seconds'] >> 1) - ); - - if ($dosTime <= self::MIN_DOS_TIME) { - $dosTime = 0; - } - - return $dosTime; - } -} diff --git a/vendor/nelexa/zip/src/Util/FileAttribUtil.php b/vendor/nelexa/zip/src/Util/FileAttribUtil.php deleted file mode 100644 index 06247ae..0000000 --- a/vendor/nelexa/zip/src/Util/FileAttribUtil.php +++ /dev/null @@ -1,108 +0,0 @@ -isDir() ? 'rmdir' : 'unlink'); - $function($fileInfo->getPathname()); - } - rmdir($dir); - } - - /** - * Convert glob pattern to regex pattern. - * - * @param string $globPattern - * - * @return string - */ - public static function convertGlobToRegEx($globPattern) - { - // Remove beginning and ending * globs because they're useless - $globPattern = trim($globPattern, '*'); - $escaping = false; - $inCurrent = 0; - $chars = str_split($globPattern); - $regexPattern = ''; - - foreach ($chars as $currentChar) { - switch ($currentChar) { - case '*': - $regexPattern .= ($escaping ? '\\*' : '.*'); - $escaping = false; - break; - - case '?': - $regexPattern .= ($escaping ? '\\?' : '.'); - $escaping = false; - break; - - case '.': - case '(': - case ')': - case '+': - case '|': - case '^': - case '$': - case '@': - case '%': - $regexPattern .= '\\' . $currentChar; - $escaping = false; - break; - - case '\\': - if ($escaping) { - $regexPattern .= '\\\\'; - $escaping = false; - } else { - $escaping = true; - } - break; - - case '{': - if ($escaping) { - $regexPattern .= '\\{'; - } else { - $regexPattern = '('; - $inCurrent++; - } - $escaping = false; - break; - - case '}': - if ($inCurrent > 0 && !$escaping) { - $regexPattern .= ')'; - $inCurrent--; - } elseif ($escaping) { - $regexPattern = '\\}'; - } else { - $regexPattern = '}'; - } - $escaping = false; - break; - - case ',': - if ($inCurrent > 0 && !$escaping) { - $regexPattern .= '|'; - } elseif ($escaping) { - $regexPattern .= '\\,'; - } else { - $regexPattern = ','; - } - break; - default: - $escaping = false; - $regexPattern .= $currentChar; - } - } - - return $regexPattern; - } - - /** - * Search files. - * - * @param string $inputDir - * @param bool $recursive - * @param array $ignoreFiles - * - * @return array Searched file list - */ - public static function fileSearchWithIgnore($inputDir, $recursive = true, array $ignoreFiles = []) - { - if ($recursive) { - $directoryIterator = new \RecursiveDirectoryIterator($inputDir); - - if (!empty($ignoreFiles)) { - $directoryIterator = new IgnoreFilesRecursiveFilterIterator($directoryIterator, $ignoreFiles); - } - $iterator = new \RecursiveIteratorIterator($directoryIterator); - } else { - $directoryIterator = new \DirectoryIterator($inputDir); - - if (!empty($ignoreFiles)) { - $directoryIterator = new IgnoreFilesFilterIterator($directoryIterator, $ignoreFiles); - } - $iterator = new \IteratorIterator($directoryIterator); - } - - $fileList = []; - - foreach ($iterator as $file) { - if ($file instanceof \SplFileInfo) { - $fileList[] = $file->getPathname(); - } - } - - return $fileList; - } - - /** - * Search files from glob pattern. - * - * @param string $globPattern - * @param int $flags - * @param bool $recursive - * - * @return array Searched file list - */ - public static function globFileSearch($globPattern, $flags = 0, $recursive = true) - { - $flags = (int) $flags; - $recursive = (bool) $recursive; - $files = glob($globPattern, $flags); - - if (!$recursive) { - return $files; - } - - foreach (glob(\dirname($globPattern) . '/*', \GLOB_ONLYDIR | \GLOB_NOSORT) as $dir) { - // Unpacking the argument via ... is supported starting from php 5.6 only - /** @noinspection SlowArrayOperationsInLoopInspection */ - $files = array_merge($files, self::globFileSearch($dir . '/' . basename($globPattern), $flags, $recursive)); - } - - return $files; - } - - /** - * Search files from regex pattern. - * - * @param string $folder - * @param string $pattern - * @param bool $recursive - * - * @return array Searched file list - */ - public static function regexFileSearch($folder, $pattern, $recursive = true) - { - if ($recursive) { - $directoryIterator = new \RecursiveDirectoryIterator($folder); - $iterator = new \RecursiveIteratorIterator($directoryIterator); - } else { - $directoryIterator = new \DirectoryIterator($folder); - $iterator = new \IteratorIterator($directoryIterator); - } - - $regexIterator = new \RegexIterator($iterator, $pattern, \RegexIterator::MATCH); - $fileList = []; - - foreach ($regexIterator as $file) { - if ($file instanceof \SplFileInfo) { - $fileList[] = $file->getPathname(); - } - } - - return $fileList; - } - - /** - * Convert bytes to human size. - * - * @param int $size Size bytes - * @param string|null $unit Unit support 'GB', 'MB', 'KB' - * - * @return string - */ - public static function humanSize($size, $unit = null) - { - if (($unit === null && $size >= 1 << 30) || $unit === 'GB') { - return number_format($size / (1 << 30), 2) . 'GB'; - } - - if (($unit === null && $size >= 1 << 20) || $unit === 'MB') { - return number_format($size / (1 << 20), 2) . 'MB'; - } - - if (($unit === null && $size >= 1 << 10) || $unit === 'KB') { - return number_format($size / (1 << 10), 2) . 'KB'; - } - - return number_format($size) . ' bytes'; - } - - /** - * Normalizes zip path. - * - * @param string $path Zip path - * - * @return string - */ - public static function normalizeZipPath($path) - { - return implode( - '/', - array_filter( - explode('/', (string) $path), - static function ($part) { - return $part !== '.' && $part !== '..'; - } - ) - ); - } - - /** - * Returns whether the file path is an absolute path. - * - * @param string $file A file path - * - * @return bool - * - * @see source symfony filesystem component - */ - public static function isAbsolutePath($file) - { - return strspn($file, '/\\', 0, 1) - || ( - \strlen($file) > 3 && ctype_alpha($file[0]) - && $file[1] === ':' - && strspn($file, '/\\', 2, 1) - ) - || parse_url($file, \PHP_URL_SCHEME) !== null; - } - - /** - * @param string $target - * @param string $path - * @param bool $allowSymlink - * - * @return bool - */ - public static function symlink($target, $path, $allowSymlink) - { - if (\DIRECTORY_SEPARATOR === '\\' || !$allowSymlink) { - return file_put_contents($path, $target) !== false; - } - - return symlink($target, $path); - } - - /** - * @param string $file - * - * @return bool - */ - public static function isBadCompressionFile($file) - { - $badCompressFileExt = [ - 'dic', - 'dng', - 'f4v', - 'flipchart', - 'h264', - 'lrf', - 'mobi', - 'mts', - 'nef', - 'pspimage', - ]; - - $ext = strtolower(pathinfo($file, \PATHINFO_EXTENSION)); - - if (\in_array($ext, $badCompressFileExt, true)) { - return true; - } - - $mimeType = self::getMimeTypeFromFile($file); - - return self::isBadCompressionMimeType($mimeType); - } - - /** - * @param string $mimeType - * - * @return bool - */ - public static function isBadCompressionMimeType($mimeType) - { - static $badDeflateCompMimeTypes = [ - 'application/epub+zip', - 'application/gzip', - 'application/vnd.debian.binary-package', - 'application/vnd.oasis.opendocument.graphics', - 'application/vnd.oasis.opendocument.presentation', - 'application/vnd.oasis.opendocument.text', - 'application/vnd.oasis.opendocument.text-master', - 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', - 'application/vnd.rn-realmedia', - 'application/x-7z-compressed', - 'application/x-arj', - 'application/x-bzip2', - 'application/x-hwp', - 'application/x-lzip', - 'application/x-lzma', - 'application/x-ms-reader', - 'application/x-rar', - 'application/x-rpm', - 'application/x-stuffit', - 'application/x-tar', - 'application/x-xz', - 'application/zip', - 'application/zlib', - 'audio/flac', - 'audio/mpeg', - 'audio/ogg', - 'audio/vnd.dolby.dd-raw', - 'audio/webm', - 'audio/x-ape', - 'audio/x-hx-aac-adts', - 'audio/x-m4a', - 'audio/x-m4a', - 'audio/x-wav', - 'image/gif', - 'image/heic', - 'image/jp2', - 'image/jpeg', - 'image/png', - 'image/vnd.djvu', - 'image/webp', - 'image/x-canon-cr2', - 'video/ogg', - 'video/webm', - 'video/x-matroska', - 'video/x-ms-asf', - 'x-epoc/x-sisx-app', - ]; - - if (\in_array($mimeType, $badDeflateCompMimeTypes, true)) { - return true; - } - - return false; - } - - /** - * @param string $file - * - * @return string - * - * @noinspection PhpComposerExtensionStubsInspection - */ - public static function getMimeTypeFromFile($file) - { - if (\function_exists('mime_content_type')) { - return mime_content_type($file); - } - - return 'application/octet-stream'; - } - - /** - * @param string $contents - * - * @return string - * @noinspection PhpComposerExtensionStubsInspection - */ - public static function getMimeTypeFromString($contents) - { - $contents = (string) $contents; - $finfo = new \finfo(\FILEINFO_MIME); - $mimeType = $finfo->buffer($contents); - - if ($mimeType === false) { - $mimeType = 'application/octet-stream'; - } - - return explode(';', $mimeType)[0]; - } -} diff --git a/vendor/nelexa/zip/src/Util/Iterator/IgnoreFilesFilterIterator.php b/vendor/nelexa/zip/src/Util/Iterator/IgnoreFilesFilterIterator.php deleted file mode 100644 index c13734e..0000000 --- a/vendor/nelexa/zip/src/Util/Iterator/IgnoreFilesFilterIterator.php +++ /dev/null @@ -1,66 +0,0 @@ -ignoreFiles = array_merge($this->ignoreFiles, $ignoreFiles); - } - - /** - * Check whether the current element of the iterator is acceptable. - * - * @see http://php.net/manual/en/filteriterator.accept.php - * - * @return bool true if the current element is acceptable, otherwise false - * - * @since 5.1.0 - */ - public function accept() - { - /** - * @var \SplFileInfo $fileInfo - */ - $fileInfo = $this->current(); - $pathname = str_replace('\\', '/', $fileInfo->getPathname()); - - foreach ($this->ignoreFiles as $ignoreFile) { - // handler dir and sub dir - if ($fileInfo->isDir() - && StringUtil::endsWith($ignoreFile, '/') - && StringUtil::endsWith($pathname, substr($ignoreFile, 0, -1)) - ) { - return false; - } - - // handler filename - if (StringUtil::endsWith($pathname, $ignoreFile)) { - return false; - } - } - - return true; - } -} diff --git a/vendor/nelexa/zip/src/Util/Iterator/IgnoreFilesRecursiveFilterIterator.php b/vendor/nelexa/zip/src/Util/Iterator/IgnoreFilesRecursiveFilterIterator.php deleted file mode 100644 index 8935127..0000000 --- a/vendor/nelexa/zip/src/Util/Iterator/IgnoreFilesRecursiveFilterIterator.php +++ /dev/null @@ -1,74 +0,0 @@ -ignoreFiles = array_merge($this->ignoreFiles, $ignoreFiles); - } - - /** - * Check whether the current element of the iterator is acceptable. - * - * @see http://php.net/manual/en/filteriterator.accept.php - * - * @return bool true if the current element is acceptable, otherwise false - * - * @since 5.1.0 - */ - public function accept() - { - /** - * @var \SplFileInfo $fileInfo - */ - $fileInfo = $this->current(); - $pathname = str_replace('\\', '/', $fileInfo->getPathname()); - - foreach ($this->ignoreFiles as $ignoreFile) { - // handler dir and sub dir - if ($fileInfo->isDir() - && $ignoreFile[\strlen($ignoreFile) - 1] === '/' - && StringUtil::endsWith($pathname, substr($ignoreFile, 0, -1)) - ) { - return false; - } - - // handler filename - if (StringUtil::endsWith($pathname, $ignoreFile)) { - return false; - } - } - - return true; - } - - /** - * @return IgnoreFilesRecursiveFilterIterator - */ - public function getChildren() - { - return new self($this->getInnerIterator()->getChildren(), $this->ignoreFiles); - } -} diff --git a/vendor/nelexa/zip/src/Util/Iterator/index.php b/vendor/nelexa/zip/src/Util/Iterator/index.php deleted file mode 100644 index df24d3e..0000000 --- a/vendor/nelexa/zip/src/Util/Iterator/index.php +++ /dev/null @@ -1,35 +0,0 @@ - - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA - */ - -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); - -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); - -header("Location: ../"); -exit; diff --git a/vendor/nelexa/zip/src/Util/PackUtil.php b/vendor/nelexa/zip/src/Util/PackUtil.php deleted file mode 100644 index 653fab7..0000000 --- a/vendor/nelexa/zip/src/Util/PackUtil.php +++ /dev/null @@ -1,69 +0,0 @@ -= 506030) { - return pack('P', $longValue); - } - - $left = 0xffffffff00000000; - $right = 0x00000000ffffffff; - - $r = ($longValue & $left) >> 32; - $l = $longValue & $right; - - return pack('VV', $l, $r); - } - - /** - * @param string $value - * - * @return int - */ - public static function unpackLongLE($value) - { - if (\PHP_VERSION_ID >= 506030) { - return unpack('P', $value)[1]; - } - $unpack = unpack('Va/Vb', $value); - - return $unpack['a'] + ($unpack['b'] << 32); - } - - /** - * Cast to signed int 32-bit. - * - * @param int $int - * - * @return int - */ - public static function toSignedInt32($int) - { - if (\PHP_INT_SIZE === 8) { - $int &= 0xffffffff; - - if ($int & 0x80000000) { - return $int - 0x100000000; - } - } - - return $int; - } -} diff --git a/vendor/nelexa/zip/src/Util/StringUtil.php b/vendor/nelexa/zip/src/Util/StringUtil.php deleted file mode 100644 index bce2a17..0000000 --- a/vendor/nelexa/zip/src/Util/StringUtil.php +++ /dev/null @@ -1,48 +0,0 @@ - - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA - */ - -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); - -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); - -header("Location: ../"); -exit; diff --git a/vendor/nelexa/zip/src/ZipFile.php b/vendor/nelexa/zip/src/ZipFile.php deleted file mode 100644 index 32560c6..0000000 --- a/vendor/nelexa/zip/src/ZipFile.php +++ /dev/null @@ -1,2003 +0,0 @@ - 'application/zip', - 'apk' => 'application/vnd.android.package-archive', - 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', - 'epub' => 'application/epub+zip', - 'jar' => 'application/java-archive', - 'odt' => 'application/vnd.oasis.opendocument.text', - 'pptx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', - 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', - 'xpi' => 'application/x-xpinstall', - ]; - - /** @var ZipContainer */ - protected $zipContainer; - - /** @var ZipReader|null */ - private $reader; - - /** - * ZipFile constructor. - */ - public function __construct() - { - $this->zipContainer = $this->createZipContainer(null); - } - - /** - * @param resource $inputStream - * @param array $options - * - * @return ZipReader - */ - protected function createZipReader($inputStream, array $options = []) - { - return new ZipReader($inputStream, $options); - } - - /** - * @return ZipWriter - */ - protected function createZipWriter() - { - return new ZipWriter($this->zipContainer); - } - - /** - * @param ImmutableZipContainer|null $sourceContainer - * - * @return ZipContainer - */ - protected function createZipContainer(ImmutableZipContainer $sourceContainer = null) - { - return new ZipContainer($sourceContainer); - } - - /** - * Open zip archive from file. - * - * @param string $filename - * @param array $options - * - * @throws ZipException if can't open file - * - * @return ZipFile - */ - public function openFile($filename, array $options = []) - { - if (!file_exists($filename)) { - throw new ZipException("File {$filename} does not exist."); - } - - if (!($handle = @fopen($filename, 'rb'))) { - throw new ZipException("File {$filename} can't open."); - } - - return $this->openFromStream($handle, $options); - } - - /** - * Open zip archive from raw string data. - * - * @param string $data - * @param array $options - * - * @throws ZipException if can't open temp stream - * - * @return ZipFile - */ - public function openFromString($data, array $options = []) - { - if ($data === null || $data === '') { - throw new InvalidArgumentException('Empty string passed'); - } - - if (!($handle = fopen('php://temp', 'r+b'))) { - // @codeCoverageIgnoreStart - throw new ZipException("Can't open temp stream."); - // @codeCoverageIgnoreEnd - } - fwrite($handle, $data); - rewind($handle); - - return $this->openFromStream($handle, $options); - } - - /** - * Open zip archive from stream resource. - * - * @param resource $handle - * @param array $options - * - * @throws ZipException - * - * @return ZipFile - */ - public function openFromStream($handle, array $options = []) - { - $this->reader = $this->createZipReader($handle, $options); - $this->zipContainer = $this->createZipContainer($this->reader->read()); - - return $this; - } - - /** - * @return string[] returns the list files - */ - public function getListFiles() - { - // strval is needed to cast entry names to string type - return array_map('strval', array_keys($this->zipContainer->getEntries())); - } - - /** - * @return int returns the number of entries in this ZIP file - */ - public function count() - { - return $this->zipContainer->count(); - } - - /** - * Returns the file comment. - * - * @return string|null the file comment - */ - public function getArchiveComment() - { - return $this->zipContainer->getArchiveComment(); - } - - /** - * Set archive comment. - * - * @param string|null $comment - * - * @return ZipFile - */ - public function setArchiveComment($comment = null) - { - $this->zipContainer->setArchiveComment($comment); - - return $this; - } - - /** - * Checks if there is an entry in the archive. - * - * @param string $entryName - * - * @return bool - */ - public function hasEntry($entryName) - { - return $this->zipContainer->hasEntry($entryName); - } - - /** - * Returns ZipEntry object. - * - * @param string $entryName - * - * @throws ZipEntryNotFoundException - * - * @return ZipEntry - */ - public function getEntry($entryName) - { - return $this->zipContainer->getEntry($entryName); - } - - /** - * Checks that the entry in the archive is a directory. - * Returns true if and only if this ZIP entry represents a directory entry - * (i.e. end with '/'). - * - * @param string $entryName - * - * @throws ZipEntryNotFoundException - * - * @return bool - */ - public function isDirectory($entryName) - { - return $this->getEntry($entryName)->isDirectory(); - } - - /** - * Returns entry comment. - * - * @param string $entryName - * - * @throws ZipException - * @throws ZipEntryNotFoundException - * - * @return string - */ - public function getEntryComment($entryName) - { - return $this->getEntry($entryName)->getComment(); - } - - /** - * Set entry comment. - * - * @param string $entryName - * @param string|null $comment - * - * @throws ZipEntryNotFoundException - * @throws ZipException - * - * @return ZipFile - */ - public function setEntryComment($entryName, $comment = null) - { - $this->getEntry($entryName)->setComment($comment); - - return $this; - } - - /** - * Returns the entry contents. - * - * @param string $entryName - * - * @throws ZipEntryNotFoundException - * @throws ZipException - * - * @return string - */ - public function getEntryContents($entryName) - { - $zipData = $this->zipContainer->getEntry($entryName)->getData(); - - if ($zipData === null) { - throw new ZipException(sprintf('No data for zip entry %s', $entryName)); - } - - return $zipData->getDataAsString(); - } - - /** - * @param string $entryName - * - * @throws ZipEntryNotFoundException - * @throws ZipException - * - * @return resource - */ - public function getEntryStream($entryName) - { - $resource = ZipEntryStreamWrapper::wrap($this->zipContainer->getEntry($entryName)); - rewind($resource); - - return $resource; - } - - /** - * Get info by entry. - * - * @param string|ZipEntry $entryName - * - * @throws ZipException - * @throws ZipEntryNotFoundException - * - * @return ZipInfo - */ - public function getEntryInfo($entryName) - { - return new ZipInfo($this->zipContainer->getEntry($entryName)); - } - - /** - * Get info by all entries. - * - * @return ZipInfo[] - */ - public function getAllInfo() - { - $infoMap = []; - - foreach ($this->zipContainer->getEntries() as $name => $entry) { - $infoMap[$name] = new ZipInfo($entry); - } - - return $infoMap; - } - - /** - * @return ZipEntryMatcher - */ - public function matcher() - { - return $this->zipContainer->matcher(); - } - - /** - * Returns an array of zip records (ex. for modify time). - * - * @return ZipEntry[] array of raw zip entries - */ - public function getEntries() - { - return $this->zipContainer->getEntries(); - } - - /** - * Extract the archive contents (unzip). - * - * Extract the complete archive or the given files to the specified destination. - * - * @param string $destDir location where to extract the files - * @param array|string|null $entries entries to extract - * @param array $options extract options - * @param array $extractedEntries if the extractedEntries argument - * is present, then the specified - * array will be filled with - * information about the - * extracted entries - * - * @throws ZipException - * - * @return ZipFile - */ - public function extractTo($destDir, $entries = null, array $options = [], &$extractedEntries = []) - { - if (!file_exists($destDir)) { - throw new ZipException(sprintf('Destination %s not found', $destDir)); - } - - if (!is_dir($destDir)) { - throw new ZipException('Destination is not directory'); - } - - if (!is_writable($destDir)) { - throw new ZipException('Destination is not writable directory'); - } - - if ($extractedEntries === null) { - $extractedEntries = []; - } - - $defaultOptions = [ - ZipOptions::EXTRACT_SYMLINKS => false, - ]; - $options += $defaultOptions; - - $zipEntries = $this->zipContainer->getEntries(); - - if (!empty($entries)) { - if (\is_string($entries)) { - $entries = (array) $entries; - } - - if (\is_array($entries)) { - $entries = array_unique($entries); - $zipEntries = array_intersect_key($zipEntries, array_flip($entries)); - } - } - - if (empty($zipEntries)) { - return $this; - } - - /** @var int[] $lastModDirs */ - $lastModDirs = []; - - krsort($zipEntries, \SORT_NATURAL); - - $symlinks = []; - $destDir = rtrim($destDir, '/\\'); - - foreach ($zipEntries as $entryName => $entry) { - $unixMode = $entry->getUnixMode(); - $entryName = FilesUtil::normalizeZipPath($entryName); - $file = $destDir . \DIRECTORY_SEPARATOR . $entryName; - - if (\DIRECTORY_SEPARATOR === '\\') { - $file = str_replace('/', '\\', $file); - } - $extractedEntries[$file] = $entry; - $modifyTimestamp = $entry->getMTime()->getTimestamp(); - $atime = $entry->getATime(); - $accessTimestamp = $atime === null ? null : $atime->getTimestamp(); - - $dir = $entry->isDirectory() ? $file : \dirname($file); - - if (!is_dir($dir)) { - $dirMode = $entry->isDirectory() ? $unixMode : 0755; - - if ($dirMode === 0) { - $dirMode = 0755; - } - - if (!mkdir($dir, $dirMode, true) && !is_dir($dir)) { - // @codeCoverageIgnoreStart - throw new \RuntimeException(sprintf('Directory "%s" was not created', $dir)); - // @codeCoverageIgnoreEnd - } - chmod($dir, $dirMode); - } - - $parts = explode('/', rtrim($entryName, '/')); - $path = $destDir . \DIRECTORY_SEPARATOR; - - foreach ($parts as $part) { - if (!isset($lastModDirs[$path]) || $lastModDirs[$path] > $modifyTimestamp) { - $lastModDirs[$path] = $modifyTimestamp; - } - - $path .= $part . \DIRECTORY_SEPARATOR; - } - - if ($entry->isDirectory()) { - $lastModDirs[$dir] = $modifyTimestamp; - - continue; - } - - $zipData = $entry->getData(); - - if ($zipData === null) { - continue; - } - - if ($entry->isUnixSymlink()) { - $symlinks[$file] = $zipData->getDataAsString(); - - continue; - } - - /** @noinspection PhpUsageOfSilenceOperatorInspection */ - if (!($handle = @fopen($file, 'w+b'))) { - // @codeCoverageIgnoreStart - throw new ZipException( - sprintf( - 'Cannot extract zip entry %s. File %s cannot open for write.', - $entry->getName(), - $file - ) - ); - // @codeCoverageIgnoreEnd - } - - try { - $zipData->copyDataToStream($handle); - } catch (ZipException $e) { - unlink($file); - - throw $e; - } - fclose($handle); - - if ($unixMode === 0) { - $unixMode = 0644; - } - chmod($file, $unixMode); - - if ($accessTimestamp !== null) { - /** @noinspection PotentialMalwareInspection */ - touch($file, $modifyTimestamp, $accessTimestamp); - } else { - touch($file, $modifyTimestamp); - } - } - - $allowSymlink = (bool) $options[ZipOptions::EXTRACT_SYMLINKS]; - - foreach ($symlinks as $linkPath => $target) { - if (!FilesUtil::symlink($target, $linkPath, $allowSymlink)) { - unset($extractedEntries[$linkPath]); - } - } - - krsort($lastModDirs, \SORT_NATURAL); - - foreach ($lastModDirs as $dir => $lastMod) { - touch($dir, $lastMod); - } - - ksort($extractedEntries); - - return $this; - } - - /** - * Add entry from the string. - * - * @param string $entryName zip entry name - * @param string $contents string contents - * @param int|null $compressionMethod Compression method. - * Use {@see ZipCompressionMethod::STORED}, - * {@see ZipCompressionMethod::DEFLATED} or - * {@see ZipCompressionMethod::BZIP2}. - * If null, then auto choosing method. - * - * @throws ZipException - * - * @return ZipFile - */ - public function addFromString($entryName, $contents, $compressionMethod = null) - { - if ($entryName === null) { - throw new InvalidArgumentException('Entry name is null'); - } - - if ($contents === null) { - throw new InvalidArgumentException('Contents is null'); - } - - $entryName = ltrim((string) $entryName, '\\/'); - - if ($entryName === '') { - throw new InvalidArgumentException('Empty entry name'); - } - $contents = (string) $contents; - $length = \strlen($contents); - - if ($compressionMethod === null || $compressionMethod === ZipEntry::UNKNOWN) { - if ($length < 512) { - $compressionMethod = ZipCompressionMethod::STORED; - } else { - $mimeType = FilesUtil::getMimeTypeFromString($contents); - $compressionMethod = FilesUtil::isBadCompressionMimeType($mimeType) ? - ZipCompressionMethod::STORED : - ZipCompressionMethod::DEFLATED; - } - } - - $zipEntry = new ZipEntry($entryName); - $zipEntry->setData(new ZipNewData($zipEntry, $contents)); - $zipEntry->setUncompressedSize($length); - $zipEntry->setCompressionMethod($compressionMethod); - $zipEntry->setCreatedOS(ZipPlatform::OS_UNIX); - $zipEntry->setExtractedOS(ZipPlatform::OS_UNIX); - $zipEntry->setUnixMode(0100644); - $zipEntry->setTime(time()); - - $this->addZipEntry($zipEntry); - - return $this; - } - - /** - * @param Finder $finder - * @param array $options - * - * @throws ZipException - * - * @return ZipEntry[] - */ - public function addFromFinder(Finder $finder, array $options = []) - { - $defaultOptions = [ - ZipOptions::STORE_ONLY_FILES => false, - ZipOptions::COMPRESSION_METHOD => null, - ZipOptions::MODIFIED_TIME => null, - ]; - $options += $defaultOptions; - - if ($options[ZipOptions::STORE_ONLY_FILES]) { - $finder->files(); - } - - $entries = []; - - foreach ($finder as $fileInfo) { - if ($fileInfo->isReadable()) { - $entry = $this->addSplFile($fileInfo, null, $options); - $entries[$entry->getName()] = $entry; - } - } - - return $entries; - } - - /** - * @param \SplFileInfo $file - * @param string|null $entryName - * @param array $options - * - * @throws ZipException - * - * @return ZipEntry - */ - public function addSplFile(\SplFileInfo $file, $entryName = null, array $options = []) - { - if ($file instanceof \DirectoryIterator) { - throw new InvalidArgumentException('File should not be \DirectoryIterator.'); - } - $defaultOptions = [ - ZipOptions::COMPRESSION_METHOD => null, - ZipOptions::MODIFIED_TIME => null, - ]; - $options += $defaultOptions; - - if (!$file->isReadable()) { - throw new InvalidArgumentException(sprintf('File %s is not readable', $file->getPathname())); - } - - if ($entryName === null) { - if ($file instanceof SymfonySplFileInfo) { - $entryName = $file->getRelativePathname(); - } else { - $entryName = $file->getBasename(); - } - } - - $entryName = ltrim((string) $entryName, '\\/'); - - if ($entryName === '') { - throw new InvalidArgumentException('Empty entry name'); - } - - $entryName = $file->isDir() ? rtrim($entryName, '/\\') . '/' : $entryName; - - $zipEntry = new ZipEntry($entryName); - $zipEntry->setCreatedOS(ZipPlatform::OS_UNIX); - $zipEntry->setExtractedOS(ZipPlatform::OS_UNIX); - - $zipData = null; - $filePerms = $file->getPerms(); - - if ($file->isLink()) { - $linkTarget = $file->getLinkTarget(); - $lengthLinkTarget = \strlen($linkTarget); - - $zipEntry->setCompressionMethod(ZipCompressionMethod::STORED); - $zipEntry->setUncompressedSize($lengthLinkTarget); - $zipEntry->setCompressedSize($lengthLinkTarget); - $zipEntry->setCrc(crc32($linkTarget)); - $filePerms |= UnixStat::UNX_IFLNK; - - $zipData = new ZipNewData($zipEntry, $linkTarget); - } elseif ($file->isFile()) { - if (isset($options[ZipOptions::COMPRESSION_METHOD])) { - $compressionMethod = $options[ZipOptions::COMPRESSION_METHOD]; - } elseif ($file->getSize() < 512) { - $compressionMethod = ZipCompressionMethod::STORED; - } else { - $compressionMethod = FilesUtil::isBadCompressionFile($file->getPathname()) ? - ZipCompressionMethod::STORED : - ZipCompressionMethod::DEFLATED; - } - - $zipEntry->setCompressionMethod($compressionMethod); - - $zipData = new ZipFileData($zipEntry, $file); - } elseif ($file->isDir()) { - $zipEntry->setCompressionMethod(ZipCompressionMethod::STORED); - $zipEntry->setUncompressedSize(0); - $zipEntry->setCompressedSize(0); - $zipEntry->setCrc(0); - } - - $zipEntry->setUnixMode($filePerms); - - $timestamp = null; - - if (isset($options[ZipOptions::MODIFIED_TIME])) { - $mtime = $options[ZipOptions::MODIFIED_TIME]; - - if ($mtime instanceof \DateTimeInterface) { - $timestamp = $mtime->getTimestamp(); - } elseif (is_numeric($mtime)) { - $timestamp = (int) $mtime; - } elseif (\is_string($mtime)) { - $timestamp = strtotime($mtime); - - if ($timestamp === false) { - $timestamp = null; - } - } - } - - if ($timestamp === null) { - $timestamp = $file->getMTime(); - } - - $zipEntry->setTime($timestamp); - $zipEntry->setData($zipData); - - $this->addZipEntry($zipEntry); - - return $zipEntry; - } - - /** - * @param ZipEntry $zipEntry - */ - protected function addZipEntry(ZipEntry $zipEntry) - { - $this->zipContainer->addEntry($zipEntry); - } - - /** - * Add entry from the file. - * - * @param string $filename destination file - * @param string|null $entryName zip Entry name - * @param int|null $compressionMethod Compression method. - * Use {@see ZipCompressionMethod::STORED}, - * {@see ZipCompressionMethod::DEFLATED} or - * {@see ZipCompressionMethod::BZIP2}. - * If null, then auto choosing method. - * - * @throws ZipException - * - * @return ZipFile - */ - public function addFile($filename, $entryName = null, $compressionMethod = null) - { - if ($filename === null) { - throw new InvalidArgumentException('Filename is null'); - } - - $this->addSplFile( - new \SplFileInfo($filename), - $entryName, - [ - ZipOptions::COMPRESSION_METHOD => $compressionMethod, - ] - ); - - return $this; - } - - /** - * Add entry from the stream. - * - * @param resource $stream stream resource - * @param string $entryName zip Entry name - * @param int|null $compressionMethod Compression method. - * Use {@see ZipCompressionMethod::STORED}, - * {@see ZipCompressionMethod::DEFLATED} or - * {@see ZipCompressionMethod::BZIP2}. - * If null, then auto choosing method. - * - * @throws ZipException - * - * @return ZipFile - */ - public function addFromStream($stream, $entryName, $compressionMethod = null) - { - if (!\is_resource($stream)) { - throw new InvalidArgumentException('Stream is not resource'); - } - - if ($entryName === null) { - throw new InvalidArgumentException('Entry name is null'); - } - $entryName = ltrim((string) $entryName, '\\/'); - - if ($entryName === '') { - throw new InvalidArgumentException('Empty entry name'); - } - $fstat = fstat($stream); - - $zipEntry = new ZipEntry($entryName); - - if ($fstat !== false) { - $unixMode = $fstat['mode']; - $length = $fstat['size']; - - if ($compressionMethod === null || $compressionMethod === ZipEntry::UNKNOWN) { - if ($length < 512) { - $compressionMethod = ZipCompressionMethod::STORED; - } else { - rewind($stream); - $bufferContents = stream_get_contents($stream, min(1024, $length)); - rewind($stream); - $mimeType = FilesUtil::getMimeTypeFromString($bufferContents); - $compressionMethod = FilesUtil::isBadCompressionMimeType($mimeType) ? - ZipCompressionMethod::STORED : - ZipCompressionMethod::DEFLATED; - } - $zipEntry->setUncompressedSize($length); - } - } else { - $unixMode = 0100644; - - if ($compressionMethod === null || $compressionMethod === ZipEntry::UNKNOWN) { - $compressionMethod = ZipCompressionMethod::DEFLATED; - } - } - - $zipEntry->setCreatedOS(ZipPlatform::OS_UNIX); - $zipEntry->setExtractedOS(ZipPlatform::OS_UNIX); - $zipEntry->setUnixMode($unixMode); - $zipEntry->setCompressionMethod($compressionMethod); - $zipEntry->setTime(time()); - $zipEntry->setData(new ZipNewData($zipEntry, $stream)); - - $this->addZipEntry($zipEntry); - - return $this; - } - - /** - * Add an empty directory in the zip archive. - * - * @param string $dirName - * - * @throws ZipException - * - * @return ZipFile - */ - public function addEmptyDir($dirName) - { - if ($dirName === null) { - throw new InvalidArgumentException('Dir name is null'); - } - $dirName = ltrim((string) $dirName, '\\/'); - - if ($dirName === '') { - throw new InvalidArgumentException('Empty dir name'); - } - $dirName = rtrim($dirName, '\\/') . '/'; - - $zipEntry = new ZipEntry($dirName); - $zipEntry->setCompressionMethod(ZipCompressionMethod::STORED); - $zipEntry->setUncompressedSize(0); - $zipEntry->setCompressedSize(0); - $zipEntry->setCrc(0); - $zipEntry->setCreatedOS(ZipPlatform::OS_UNIX); - $zipEntry->setExtractedOS(ZipPlatform::OS_UNIX); - $zipEntry->setUnixMode(040755); - $zipEntry->setTime(time()); - - $this->addZipEntry($zipEntry); - - return $this; - } - - /** - * Add directory not recursively to the zip archive. - * - * @param string $inputDir Input directory - * @param string $localPath add files to this directory, or the root - * @param int|null $compressionMethod Compression method. - * - * Use {@see ZipCompressionMethod::STORED}, {@see - * ZipCompressionMethod::DEFLATED} or - * {@see ZipCompressionMethod::BZIP2}. If null, then auto choosing method. - * - * @throws ZipException - * - * @return ZipFile - */ - public function addDir($inputDir, $localPath = '/', $compressionMethod = null) - { - if ($inputDir === null) { - throw new InvalidArgumentException('Input dir is null'); - } - $inputDir = (string) $inputDir; - - if ($inputDir === '') { - throw new InvalidArgumentException('The input directory is not specified'); - } - - if (!is_dir($inputDir)) { - throw new InvalidArgumentException(sprintf('The "%s" directory does not exist.', $inputDir)); - } - $inputDir = rtrim($inputDir, '/\\') . \DIRECTORY_SEPARATOR; - - $directoryIterator = new \DirectoryIterator($inputDir); - - return $this->addFilesFromIterator($directoryIterator, $localPath, $compressionMethod); - } - - /** - * Add recursive directory to the zip archive. - * - * @param string $inputDir Input directory - * @param string $localPath add files to this directory, or the root - * @param int|null $compressionMethod Compression method. - * Use {@see ZipCompressionMethod::STORED}, {@see - * ZipCompressionMethod::DEFLATED} or - * {@see ZipCompressionMethod::BZIP2}. If null, then auto choosing method. - * - * @throws ZipException - * - * @return ZipFile - * - * @see ZipCompressionMethod::STORED - * @see ZipCompressionMethod::DEFLATED - * @see ZipCompressionMethod::BZIP2 - */ - public function addDirRecursive($inputDir, $localPath = '/', $compressionMethod = null) - { - if ($inputDir === null) { - throw new InvalidArgumentException('Input dir is null'); - } - $inputDir = (string) $inputDir; - - if ($inputDir === '') { - throw new InvalidArgumentException('The input directory is not specified'); - } - - if (!is_dir($inputDir)) { - throw new InvalidArgumentException(sprintf('The "%s" directory does not exist.', $inputDir)); - } - $inputDir = rtrim($inputDir, '/\\') . \DIRECTORY_SEPARATOR; - - $directoryIterator = new \RecursiveDirectoryIterator($inputDir); - - return $this->addFilesFromIterator($directoryIterator, $localPath, $compressionMethod); - } - - /** - * Add directories from directory iterator. - * - * @param \Iterator $iterator directory iterator - * @param string $localPath add files to this directory, or the root - * @param int|null $compressionMethod Compression method. - * Use {@see ZipCompressionMethod::STORED}, {@see - * ZipCompressionMethod::DEFLATED} or - * {@see ZipCompressionMethod::BZIP2}. If null, then auto choosing method. - * - * @throws ZipException - * - * @return ZipFile - * - * @see ZipCompressionMethod::STORED - * @see ZipCompressionMethod::DEFLATED - * @see ZipCompressionMethod::BZIP2 - */ - public function addFilesFromIterator( - \Iterator $iterator, - $localPath = '/', - $compressionMethod = null - ) { - $localPath = (string) $localPath; - - if ($localPath !== '') { - $localPath = trim($localPath, '\\/'); - } else { - $localPath = ''; - } - - $iterator = $iterator instanceof \RecursiveIterator ? - new \RecursiveIteratorIterator($iterator) : - new \IteratorIterator($iterator); - /** - * @var string[] $files - * @var string $path - */ - $files = []; - - foreach ($iterator as $file) { - if ($file instanceof \SplFileInfo) { - if ($file->getBasename() === '..') { - continue; - } - - if ($file->getBasename() === '.') { - $files[] = \dirname($file->getPathname()); - } else { - $files[] = $file->getPathname(); - } - } - } - - if (empty($files)) { - return $this; - } - - natcasesort($files); - $path = array_shift($files); - - $this->doAddFiles($path, $files, $localPath, $compressionMethod); - - return $this; - } - - /** - * Add files from glob pattern. - * - * @param string $inputDir Input directory - * @param string $globPattern glob pattern - * @param string $localPath add files to this directory, or the root - * @param int|null $compressionMethod Compression method. - * Use {@see ZipCompressionMethod::STORED}, - * {@see ZipCompressionMethod::DEFLATED} or - * {@see ZipCompressionMethod::BZIP2}. If null, then auto choosing method. - * - * @throws ZipException - * - * @return ZipFile - * @sse https://en.wikipedia.org/wiki/Glob_(programming) Glob pattern syntax - */ - public function addFilesFromGlob($inputDir, $globPattern, $localPath = '/', $compressionMethod = null) - { - return $this->addGlob($inputDir, $globPattern, $localPath, false, $compressionMethod); - } - - /** - * Add files from glob pattern. - * - * @param string $inputDir Input directory - * @param string $globPattern glob pattern - * @param string $localPath add files to this directory, or the root - * @param bool $recursive recursive search - * @param int|null $compressionMethod Compression method. - * Use {@see ZipCompressionMethod::STORED}, - * {@see ZipCompressionMethod::DEFLATED} or - * {@see ZipCompressionMethod::BZIP2}. If null, then auto choosing method. - * - * @throws ZipException - * - * @return ZipFile - * @sse https://en.wikipedia.org/wiki/Glob_(programming) Glob pattern syntax - */ - private function addGlob( - $inputDir, - $globPattern, - $localPath = '/', - $recursive = true, - $compressionMethod = null - ) { - if ($inputDir === null) { - throw new InvalidArgumentException('Input dir is null'); - } - $inputDir = (string) $inputDir; - - if ($inputDir === '') { - throw new InvalidArgumentException('The input directory is not specified'); - } - - if (!is_dir($inputDir)) { - throw new InvalidArgumentException(sprintf('The "%s" directory does not exist.', $inputDir)); - } - $globPattern = (string) $globPattern; - - if (empty($globPattern)) { - throw new InvalidArgumentException('The glob pattern is not specified'); - } - - $inputDir = rtrim($inputDir, '/\\') . \DIRECTORY_SEPARATOR; - $globPattern = $inputDir . $globPattern; - - $filesFound = FilesUtil::globFileSearch($globPattern, \GLOB_BRACE, $recursive); - - if ($filesFound === false || empty($filesFound)) { - return $this; - } - - $this->doAddFiles($inputDir, $filesFound, $localPath, $compressionMethod); - - return $this; - } - - /** - * Add files recursively from glob pattern. - * - * @param string $inputDir Input directory - * @param string $globPattern glob pattern - * @param string $localPath add files to this directory, or the root - * @param int|null $compressionMethod Compression method. - * Use {@see ZipCompressionMethod::STORED}, - * {@see ZipCompressionMethod::DEFLATED} or - * {@see ZipCompressionMethod::BZIP2}. If null, then auto choosing method. - * - * @throws ZipException - * - * @return ZipFile - * @sse https://en.wikipedia.org/wiki/Glob_(programming) Glob pattern syntax - */ - public function addFilesFromGlobRecursive($inputDir, $globPattern, $localPath = '/', $compressionMethod = null) - { - return $this->addGlob($inputDir, $globPattern, $localPath, true, $compressionMethod); - } - - /** - * Add files from regex pattern. - * - * @param string $inputDir search files in this directory - * @param string $regexPattern regex pattern - * @param string $localPath add files to this directory, or the root - * @param int|null $compressionMethod Compression method. - * Use {@see ZipCompressionMethod::STORED}, - * {@see ZipCompressionMethod::DEFLATED} or - * {@see ZipCompressionMethod::BZIP2}. If null, then auto choosing method. - * - * @throws ZipException - * - * @return ZipFile - * - * @internal param bool $recursive Recursive search - */ - public function addFilesFromRegex($inputDir, $regexPattern, $localPath = '/', $compressionMethod = null) - { - return $this->addRegex($inputDir, $regexPattern, $localPath, false, $compressionMethod); - } - - /** - * Add files from regex pattern. - * - * @param string $inputDir search files in this directory - * @param string $regexPattern regex pattern - * @param string $localPath add files to this directory, or the root - * @param bool $recursive recursive search - * @param int|null $compressionMethod Compression method. - * Use {@see ZipCompressionMethod::STORED}, - * {@see ZipCompressionMethod::DEFLATED} or - * {@see ZipCompressionMethod::BZIP2}. - * If null, then auto choosing method. - * - * @throws ZipException - * - * @return ZipFile - */ - private function addRegex( - $inputDir, - $regexPattern, - $localPath = '/', - $recursive = true, - $compressionMethod = null - ) { - $regexPattern = (string) $regexPattern; - - if (empty($regexPattern)) { - throw new InvalidArgumentException('The regex pattern is not specified'); - } - $inputDir = (string) $inputDir; - - if ($inputDir === '') { - throw new InvalidArgumentException('The input directory is not specified'); - } - - if (!is_dir($inputDir)) { - throw new InvalidArgumentException(sprintf('The "%s" directory does not exist.', $inputDir)); - } - $inputDir = rtrim($inputDir, '/\\') . \DIRECTORY_SEPARATOR; - - $files = FilesUtil::regexFileSearch($inputDir, $regexPattern, $recursive); - - if (empty($files)) { - return $this; - } - - $this->doAddFiles($inputDir, $files, $localPath, $compressionMethod); - - return $this; - } - - /** - * @param string $fileSystemDir - * @param array $files - * @param string $zipPath - * @param int|null $compressionMethod - * - * @throws ZipException - */ - private function doAddFiles($fileSystemDir, array $files, $zipPath, $compressionMethod = null) - { - $fileSystemDir = rtrim($fileSystemDir, '/\\') . \DIRECTORY_SEPARATOR; - - if (!empty($zipPath) && \is_string($zipPath)) { - $zipPath = trim($zipPath, '\\/') . '/'; - } else { - $zipPath = '/'; - } - - /** - * @var string $file - */ - foreach ($files as $file) { - $filename = str_replace($fileSystemDir, $zipPath, $file); - $filename = ltrim($filename, '\\/'); - - if (is_dir($file) && FilesUtil::isEmptyDir($file)) { - $this->addEmptyDir($filename); - } elseif (is_file($file)) { - $this->addFile($file, $filename, $compressionMethod); - } - } - } - - /** - * Add files recursively from regex pattern. - * - * @param string $inputDir search files in this directory - * @param string $regexPattern regex pattern - * @param string $localPath add files to this directory, or the root - * @param int|null $compressionMethod Compression method. - * Use {@see ZipCompressionMethod::STORED}, - * {@see ZipCompressionMethod::DEFLATED} or - * {@see ZipCompressionMethod::BZIP2}. If null, then auto choosing method. - * - * @throws ZipException - * - * @return ZipFile - * - * @internal param bool $recursive Recursive search - */ - public function addFilesFromRegexRecursive($inputDir, $regexPattern, $localPath = '/', $compressionMethod = null) - { - return $this->addRegex($inputDir, $regexPattern, $localPath, true, $compressionMethod); - } - - /** - * Add array data to archive. - * Keys is local names. - * Values is contents. - * - * @param array $mapData associative array for added to zip - */ - public function addAll(array $mapData) - { - foreach ($mapData as $localName => $content) { - $this[$localName] = $content; - } - } - - /** - * Rename the entry. - * - * @param string $oldName old entry name - * @param string $newName new entry name - * - * @throws ZipException - * - * @return ZipFile - */ - public function rename($oldName, $newName) - { - if ($oldName === null || $newName === null) { - throw new InvalidArgumentException('name is null'); - } - $oldName = ltrim((string) $oldName, '\\/'); - $newName = ltrim((string) $newName, '\\/'); - - if ($oldName !== $newName) { - $this->zipContainer->renameEntry($oldName, $newName); - } - - return $this; - } - - /** - * Delete entry by name. - * - * @param string $entryName zip Entry name - * - * @throws ZipEntryNotFoundException if entry not found - * - * @return ZipFile - */ - public function deleteFromName($entryName) - { - $entryName = ltrim((string) $entryName, '\\/'); - - if (!$this->zipContainer->deleteEntry($entryName)) { - throw new ZipEntryNotFoundException($entryName); - } - - return $this; - } - - /** - * Delete entries by glob pattern. - * - * @param string $globPattern Glob pattern - * - * @return ZipFile - * @sse https://en.wikipedia.org/wiki/Glob_(programming) Glob pattern syntax - */ - public function deleteFromGlob($globPattern) - { - if ($globPattern === null || !\is_string($globPattern) || empty($globPattern)) { - throw new InvalidArgumentException('The glob pattern is not specified'); - } - $globPattern = '~' . FilesUtil::convertGlobToRegEx($globPattern) . '~si'; - $this->deleteFromRegex($globPattern); - - return $this; - } - - /** - * Delete entries by regex pattern. - * - * @param string $regexPattern Regex pattern - * - * @return ZipFile - */ - public function deleteFromRegex($regexPattern) - { - if ($regexPattern === null || !\is_string($regexPattern) || empty($regexPattern)) { - throw new InvalidArgumentException('The regex pattern is not specified'); - } - $this->matcher()->match($regexPattern)->delete(); - - return $this; - } - - /** - * Delete all entries. - * - * @return ZipFile - */ - public function deleteAll() - { - $this->zipContainer->deleteAll(); - - return $this; - } - - /** - * Set compression level for new entries. - * - * @param int $compressionLevel - * - * @return ZipFile - * - * @see ZipCompressionLevel::NORMAL - * @see ZipCompressionLevel::SUPER_FAST - * @see ZipCompressionLevel::FAST - * @see ZipCompressionLevel::MAXIMUM - */ - public function setCompressionLevel($compressionLevel = ZipCompressionLevel::NORMAL) - { - $compressionLevel = (int) $compressionLevel; - - foreach ($this->zipContainer->getEntries() as $entry) { - $entry->setCompressionLevel($compressionLevel); - } - - return $this; - } - - /** - * @param string $entryName - * @param int $compressionLevel - * - * @throws ZipException - * - * @return ZipFile - * - * @see ZipCompressionLevel::NORMAL - * @see ZipCompressionLevel::SUPER_FAST - * @see ZipCompressionLevel::FAST - * @see ZipCompressionLevel::MAXIMUM - */ - public function setCompressionLevelEntry($entryName, $compressionLevel) - { - $compressionLevel = (int) $compressionLevel; - $this->getEntry($entryName)->setCompressionLevel($compressionLevel); - - return $this; - } - - /** - * @param string $entryName - * @param int $compressionMethod Compression method. - * Use {@see ZipCompressionMethod::STORED}, {@see ZipCompressionMethod::DEFLATED} - * or - * {@see ZipCompressionMethod::BZIP2}. If null, then auto choosing method. - * - * @throws ZipException - * - * @return ZipFile - * - * @see ZipCompressionMethod::STORED - * @see ZipCompressionMethod::DEFLATED - * @see ZipCompressionMethod::BZIP2 - */ - public function setCompressionMethodEntry($entryName, $compressionMethod) - { - $this->zipContainer - ->getEntry($entryName) - ->setCompressionMethod($compressionMethod) - ; - - return $this; - } - - /** - * zipalign is optimization to Android application (APK) files. - * - * @param int|null $align - * - * @return ZipFile - * - * @see https://developer.android.com/studio/command-line/zipalign.html - */ - public function setZipAlign($align = null) - { - $this->zipContainer->setZipAlign($align); - - return $this; - } - - /** - * Set password to all input encrypted entries. - * - * @param string $password Password - * - * @return ZipFile - */ - public function setReadPassword($password) - { - $this->zipContainer->setReadPassword($password); - - return $this; - } - - /** - * Set password to concrete input entry. - * - * @param string $entryName - * @param string $password Password - * - * @throws ZipException - * - * @return ZipFile - */ - public function setReadPasswordEntry($entryName, $password) - { - $this->zipContainer->setReadPasswordEntry($entryName, $password); - - return $this; - } - - /** - * Sets a new password for all files in the archive. - * - * @param string $password Password - * @param int|null $encryptionMethod Encryption method - * - * @return ZipFile - */ - public function setPassword($password, $encryptionMethod = ZipEncryptionMethod::WINZIP_AES_256) - { - $this->zipContainer->setWritePassword($password); - - if ($encryptionMethod !== null) { - $this->zipContainer->setEncryptionMethod($encryptionMethod); - } - - return $this; - } - - /** - * Sets a new password of an entry defined by its name. - * - * @param string $entryName - * @param string $password - * @param int|null $encryptionMethod - * - * @throws ZipException - * - * @return ZipFile - */ - public function setPasswordEntry($entryName, $password, $encryptionMethod = null) - { - $this->getEntry($entryName)->setPassword($password, $encryptionMethod); - - return $this; - } - - /** - * Disable encryption for all entries that are already in the archive. - * - * @return ZipFile - */ - public function disableEncryption() - { - $this->zipContainer->removePassword(); - - return $this; - } - - /** - * Disable encryption of an entry defined by its name. - * - * @param string $entryName - * - * @return ZipFile - */ - public function disableEncryptionEntry($entryName) - { - $this->zipContainer->removePasswordEntry($entryName); - - return $this; - } - - /** - * Undo all changes done in the archive. - * - * @return ZipFile - */ - public function unchangeAll() - { - $this->zipContainer->unchangeAll(); - - return $this; - } - - /** - * Undo change archive comment. - * - * @return ZipFile - */ - public function unchangeArchiveComment() - { - $this->zipContainer->unchangeArchiveComment(); - - return $this; - } - - /** - * Revert all changes done to an entry with the given name. - * - * @param string|ZipEntry $entry Entry name or ZipEntry - * - * @return ZipFile - */ - public function unchangeEntry($entry) - { - $this->zipContainer->unchangeEntry($entry); - - return $this; - } - - /** - * Save as file. - * - * @param string $filename Output filename - * - * @throws ZipException - * - * @return ZipFile - */ - public function saveAsFile($filename) - { - $filename = (string) $filename; - - $tempFilename = $filename . '.temp' . uniqid('', true); - - if (!($handle = @fopen($tempFilename, 'w+b'))) { - throw new InvalidArgumentException('File ' . $tempFilename . ' can not open from write.'); - } - $this->saveAsStream($handle); - - if (!@rename($tempFilename, $filename)) { - if (is_file($tempFilename)) { - unlink($tempFilename); - } - - throw new ZipException('Can not move ' . $tempFilename . ' to ' . $filename); - } - - return $this; - } - - /** - * Save as stream. - * - * @param resource $handle Output stream resource - * - * @throws ZipException - * - * @return ZipFile - */ - public function saveAsStream($handle) - { - if (!\is_resource($handle)) { - throw new InvalidArgumentException('handle is not resource'); - } - ftruncate($handle, 0); - $this->writeZipToStream($handle); - fclose($handle); - - return $this; - } - - /** - * Output .ZIP archive as attachment. - * Die after output. - * - * @param string $outputFilename Output filename - * @param string|null $mimeType Mime-Type - * @param bool $attachment Http Header 'Content-Disposition' if true then attachment otherwise inline - * - * @throws ZipException - */ - public function outputAsAttachment($outputFilename, $mimeType = null, $attachment = true) - { - $outputFilename = (string) $outputFilename; - - if ($mimeType === null) { - $mimeType = $this->getMimeTypeByFilename($outputFilename); - } - - if (!($handle = fopen('php://temp', 'w+b'))) { - throw new InvalidArgumentException('php://temp cannot open for write.'); - } - $this->writeZipToStream($handle); - $this->close(); - - $size = fstat($handle)['size']; - - $headerContentDisposition = 'Content-Disposition: ' . ($attachment ? 'attachment' : 'inline'); - - if (!empty($outputFilename)) { - $headerContentDisposition .= '; filename="' . basename($outputFilename) . '"'; - } - - header($headerContentDisposition); - header('Content-Type: ' . $mimeType); - header('Content-Length: ' . $size); - - rewind($handle); - - try { - echo stream_get_contents($handle, -1, 0); - } finally { - fclose($handle); - } - } - - /** - * @param string $outputFilename - * - * @return string - */ - protected function getMimeTypeByFilename($outputFilename) - { - $outputFilename = (string) $outputFilename; - $ext = strtolower(pathinfo($outputFilename, \PATHINFO_EXTENSION)); - - if (!empty($ext) && isset(self::$defaultMimeTypes[$ext])) { - return self::$defaultMimeTypes[$ext]; - } - - return self::$defaultMimeTypes['zip']; - } - - /** - * Output .ZIP archive as PSR-7 Response. - * - * @param ResponseInterface $response Instance PSR-7 Response - * @param string $outputFilename Output filename - * @param string|null $mimeType Mime-Type - * @param bool $attachment Http Header 'Content-Disposition' if true then attachment otherwise inline - * - * @throws ZipException - * - * @return ResponseInterface - */ - public function outputAsResponse(ResponseInterface $response, $outputFilename, $mimeType = null, $attachment = true) - { - $outputFilename = (string) $outputFilename; - - if ($mimeType === null) { - $mimeType = $this->getMimeTypeByFilename($outputFilename); - } - - if (!($handle = fopen('php://temp', 'w+b'))) { - throw new InvalidArgumentException('php://temp cannot open for write.'); - } - $this->writeZipToStream($handle); - $this->close(); - rewind($handle); - - $contentDispositionValue = ($attachment ? 'attachment' : 'inline'); - - if (!empty($outputFilename)) { - $contentDispositionValue .= '; filename="' . basename($outputFilename) . '"'; - } - - $stream = new ResponseStream($handle); - $size = $stream->getSize(); - - if ($size !== null) { - /** @noinspection CallableParameterUseCaseInTypeContextInspection */ - $response = $response->withHeader('Content-Length', (string) $size); - } - - return $response - ->withHeader('Content-Type', $mimeType) - ->withHeader('Content-Disposition', $contentDispositionValue) - ->withBody($stream) - ; - } - - /** - * @param resource $handle - * - * @throws ZipException - */ - protected function writeZipToStream($handle) - { - $this->onBeforeSave(); - - $this->createZipWriter()->write($handle); - } - - /** - * Returns the zip archive as a string. - * - * @throws ZipException - * - * @return string - */ - public function outputAsString() - { - if (!($handle = fopen('php://temp', 'w+b'))) { - throw new InvalidArgumentException('php://temp cannot open for write.'); - } - $this->writeZipToStream($handle); - rewind($handle); - - try { - return stream_get_contents($handle); - } finally { - fclose($handle); - } - } - - /** - * Event before save or output. - */ - protected function onBeforeSave() - { - } - - /** - * Close zip archive and release input stream. - */ - public function close() - { - if ($this->reader !== null) { - $this->reader->close(); - $this->reader = null; - } - $this->zipContainer = $this->createZipContainer(null); - gc_collect_cycles(); - } - - /** - * Save and reopen zip archive. - * - * @throws ZipException - * - * @return ZipFile - */ - public function rewrite() - { - if ($this->reader === null) { - throw new ZipException('input stream is null'); - } - - $meta = $this->reader->getStreamMetaData(); - - if ($meta['wrapper_type'] === 'plainfile' && isset($meta['uri'])) { - $this->saveAsFile($meta['uri']); - $this->close(); - - if (!($handle = @fopen($meta['uri'], 'rb'))) { - throw new ZipException("File {$meta['uri']} can't open."); - } - } else { - $handle = @fopen('php://temp', 'r+b'); - - if (!$handle) { - throw new ZipException('php://temp cannot open for write.'); - } - $this->writeZipToStream($handle); - $this->close(); - } - - return $this->openFromStream($handle); - } - - /** - * Release all resources. - */ - public function __destruct() - { - $this->close(); - } - - /** - * Offset to set. - * - * @see http://php.net/manual/en/arrayaccess.offsetset.php - * - * @param string $entryName the offset to assign the value to - * @param string|\DirectoryIterator|\SplFileInfo|resource $contents the value to set - * - * @throws ZipException - * - * @see ZipFile::addFromString - * @see ZipFile::addEmptyDir - * @see ZipFile::addFile - * @see ZipFile::addFilesFromIterator - */ - public function offsetSet($entryName, $contents) - { - if ($entryName === null) { - throw new InvalidArgumentException('Key must not be null, but must contain the name of the zip entry.'); - } - $entryName = ltrim((string) $entryName, '\\/'); - - if ($entryName === '') { - throw new InvalidArgumentException('Key is empty, but must contain the name of the zip entry.'); - } - - if ($contents instanceof \DirectoryIterator) { - $this->addFilesFromIterator($contents, $entryName); - } elseif ($contents instanceof \SplFileInfo) { - $this->addSplFile($contents, $entryName); - } elseif (StringUtil::endsWith($entryName, '/')) { - $this->addEmptyDir($entryName); - } elseif (\is_resource($contents)) { - $this->addFromStream($contents, $entryName); - } else { - $this->addFromString($entryName, (string) $contents); - } - } - - /** - * Offset to unset. - * - * @see http://php.net/manual/en/arrayaccess.offsetunset.php - * - * @param string $entryName the offset to unset - * - * @throws ZipEntryNotFoundException - */ - public function offsetUnset($entryName) - { - $this->deleteFromName($entryName); - } - - /** - * Return the current element. - * - * @see http://php.net/manual/en/iterator.current.php - * - * @throws ZipException - * - * @return mixed can return any type - * - * @since 5.0.0 - */ - public function current() - { - return $this->offsetGet($this->key()); - } - - /** - * Offset to retrieve. - * - * @see http://php.net/manual/en/arrayaccess.offsetget.php - * - * @param string $entryName the offset to retrieve - * - * @throws ZipException - * - * @return string|null - */ - public function offsetGet($entryName) - { - return $this->getEntryContents($entryName); - } - - /** - * Return the key of the current element. - * - * @see http://php.net/manual/en/iterator.key.php - * - * @return mixed scalar on success, or null on failure - * - * @since 5.0.0 - */ - public function key() - { - return key($this->zipContainer->getEntries()); - } - - /** - * Move forward to next element. - * - * @see http://php.net/manual/en/iterator.next.php - * @since 5.0.0 - */ - public function next() - { - next($this->zipContainer->getEntries()); - } - - /** - * Checks if current position is valid. - * - * @see http://php.net/manual/en/iterator.valid.php - * - * @return bool The return value will be casted to boolean and then evaluated. - * Returns true on success or false on failure. - * - * @since 5.0.0 - */ - public function valid() - { - return $this->offsetExists($this->key()); - } - - /** - * Whether a offset exists. - * - * @see http://php.net/manual/en/arrayaccess.offsetexists.php - * - * @param string $entryName an offset to check for - * - * @return bool true on success or false on failure. - * The return value will be casted to boolean if non-boolean was returned. - */ - public function offsetExists($entryName) - { - return $this->hasEntry($entryName); - } - - /** - * Rewind the Iterator to the first element. - * - * @see http://php.net/manual/en/iterator.rewind.php - * @since 5.0.0 - */ - public function rewind() - { - reset($this->zipContainer->getEntries()); - } -} diff --git a/vendor/nelexa/zip/src/ZipFileInterface.php b/vendor/nelexa/zip/src/ZipFileInterface.php deleted file mode 100644 index 07108d1..0000000 --- a/vendor/nelexa/zip/src/ZipFileInterface.php +++ /dev/null @@ -1,902 +0,0 @@ - - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA - */ - -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); - -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); - -header("Location: ../"); -exit; diff --git a/vendor/paragonie/index.php b/vendor/paragonie/index.php deleted file mode 100644 index df24d3e..0000000 --- a/vendor/paragonie/index.php +++ /dev/null @@ -1,35 +0,0 @@ - - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA - */ - -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); - -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); - -header("Location: ../"); -exit; diff --git a/vendor/paragonie/random_compat/LICENSE b/vendor/paragonie/random_compat/LICENSE deleted file mode 100644 index 45c7017..0000000 --- a/vendor/paragonie/random_compat/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Paragon Initiative Enterprises - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - diff --git a/vendor/paragonie/random_compat/composer.json b/vendor/paragonie/random_compat/composer.json deleted file mode 100644 index 34f1381..0000000 --- a/vendor/paragonie/random_compat/composer.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "name": "paragonie/random_compat", - "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", - "keywords": [ - "csprng", - "random", - "polyfill", - "pseudorandom" - ], - "license": "MIT", - "type": "library", - "authors": [ - { - "name": "Paragon Initiative Enterprises", - "email": "security@paragonie.com", - "homepage": "https://paragonie.com" - } - ], - "support": { - "issues": "https://github.com/paragonie/random_compat/issues", - "email": "info@paragonie.com", - "source": "https://github.com/paragonie/random_compat" - }, - "require": { - "php": ">=5.2.0" - }, - "require-dev": { - "phpunit/phpunit": "4.*|5.*" - }, - "suggest": { - "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." - }, - "autoload": { - "files": [ - "lib/random.php" - ] - } -} diff --git a/vendor/paragonie/random_compat/dist/index.php b/vendor/paragonie/random_compat/dist/index.php deleted file mode 100644 index df24d3e..0000000 --- a/vendor/paragonie/random_compat/dist/index.php +++ /dev/null @@ -1,35 +0,0 @@ - - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA - */ - -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); - -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); - -header("Location: ../"); -exit; diff --git a/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey b/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey deleted file mode 100644 index eb50ebf..0000000 --- a/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PUBLIC KEY----- -MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEEd+wCqJDrx5B4OldM0dQE0ZMX+lx1ZWm -pui0SUqD4G29L3NGsz9UhJ/0HjBdbnkhIK5xviT0X5vtjacF6ajgcCArbTB+ds+p -+h7Q084NuSuIpNb6YPfoUFgC/CL9kAoc ------END PUBLIC KEY----- diff --git a/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey.asc b/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey.asc deleted file mode 100644 index 6a1d7f3..0000000 --- a/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey.asc +++ /dev/null @@ -1,11 +0,0 @@ ------BEGIN PGP SIGNATURE----- -Version: GnuPG v2.0.22 (MingW32) - -iQEcBAABAgAGBQJWtW1hAAoJEGuXocKCZATaJf0H+wbZGgskK1dcRTsuVJl9IWip -QwGw/qIKI280SD6/ckoUMxKDCJiFuPR14zmqnS36k7N5UNPnpdTJTS8T11jttSpg -1LCmgpbEIpgaTah+cELDqFCav99fS+bEiAL5lWDAHBTE/XPjGVCqeehyPYref4IW -NDBIEsvnHPHPLsn6X5jq4+Yj5oUixgxaMPiR+bcO4Sh+RzOVB6i2D0upWfRXBFXA -NNnsg9/zjvoC7ZW73y9uSH+dPJTt/Vgfeiv52/v41XliyzbUyLalf02GNPY+9goV -JHG1ulEEBJOCiUD9cE1PUIJwHA/HqyhHIvV350YoEFiHl8iSwm7SiZu5kPjaq74= -=B6+8 ------END PGP SIGNATURE----- diff --git a/vendor/paragonie/random_compat/index.php b/vendor/paragonie/random_compat/index.php deleted file mode 100644 index df24d3e..0000000 --- a/vendor/paragonie/random_compat/index.php +++ /dev/null @@ -1,35 +0,0 @@ - - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA - */ - -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); - -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); - -header("Location: ../"); -exit; diff --git a/vendor/paragonie/random_compat/lib/byte_safe_strings.php b/vendor/paragonie/random_compat/lib/byte_safe_strings.php deleted file mode 100644 index ef24488..0000000 --- a/vendor/paragonie/random_compat/lib/byte_safe_strings.php +++ /dev/null @@ -1,195 +0,0 @@ - RandomCompat_strlen($binary_string)) { - return ''; - } - - return (string) mb_substr( - (string) $binary_string, - (int) $start, - (int) $length, - '8bit' - ); - } - - } else { - - /** - * substr() implementation that isn't brittle to mbstring.func_overload - * - * This version just uses the default substr() - * - * @param string $binary_string - * @param int $start - * @param int|null $length (optional) - * - * @throws TypeError - * - * @return string - */ - function RandomCompat_substr($binary_string, $start, $length = null) - { - if (!is_string($binary_string)) { - throw new TypeError( - 'RandomCompat_substr(): First argument should be a string' - ); - } - - if (!is_int($start)) { - throw new TypeError( - 'RandomCompat_substr(): Second argument should be an integer' - ); - } - - if ($length !== null) { - if (!is_int($length)) { - throw new TypeError( - 'RandomCompat_substr(): Third argument should be an integer, or omitted' - ); - } - - return (string) substr( - (string )$binary_string, - (int) $start, - (int) $length - ); - } - - return (string) substr( - (string) $binary_string, - (int) $start - ); - } - } -} diff --git a/vendor/paragonie/random_compat/lib/cast_to_int.php b/vendor/paragonie/random_compat/lib/cast_to_int.php deleted file mode 100644 index 1b1bbfe..0000000 --- a/vendor/paragonie/random_compat/lib/cast_to_int.php +++ /dev/null @@ -1,77 +0,0 @@ - operators might accidentally let a float - * through. - * - * @param int|float $number The number we want to convert to an int - * @param bool $fail_open Set to true to not throw an exception - * - * @return float|int - * @psalm-suppress InvalidReturnType - * - * @throws TypeError - */ - function RandomCompat_intval($number, $fail_open = false) - { - if (is_int($number) || is_float($number)) { - $number += 0; - } elseif (is_numeric($number)) { - /** @psalm-suppress InvalidOperand */ - $number += 0; - } - /** @var int|float $number */ - - if ( - is_float($number) - && - $number > ~PHP_INT_MAX - && - $number < PHP_INT_MAX - ) { - $number = (int) $number; - } - - if (is_int($number)) { - return (int) $number; - } elseif (!$fail_open) { - throw new TypeError( - 'Expected an integer.' - ); - } - return $number; - } -} diff --git a/vendor/paragonie/random_compat/lib/error_polyfill.php b/vendor/paragonie/random_compat/lib/error_polyfill.php deleted file mode 100644 index c02c5c8..0000000 --- a/vendor/paragonie/random_compat/lib/error_polyfill.php +++ /dev/null @@ -1,49 +0,0 @@ - - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA - */ - -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); - -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); - -header("Location: ../"); -exit; diff --git a/vendor/paragonie/random_compat/lib/random.php b/vendor/paragonie/random_compat/lib/random.php deleted file mode 100644 index 36245f5..0000000 --- a/vendor/paragonie/random_compat/lib/random.php +++ /dev/null @@ -1,225 +0,0 @@ -= 70000) { - return; -} - -if (!defined('RANDOM_COMPAT_READ_BUFFER')) { - define('RANDOM_COMPAT_READ_BUFFER', 8); -} - -$RandomCompatDIR = dirname(__FILE__); - -require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'byte_safe_strings.php'; -require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'cast_to_int.php'; -require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'error_polyfill.php'; - -if (!is_callable('random_bytes')) { - /** - * PHP 5.2.0 - 5.6.x way to implement random_bytes() - * - * We use conditional statements here to define the function in accordance - * to the operating environment. It's a micro-optimization. - * - * In order of preference: - * 1. Use libsodium if available. - * 2. fread() /dev/urandom if available (never on Windows) - * 3. mcrypt_create_iv($bytes, MCRYPT_DEV_URANDOM) - * 4. COM('CAPICOM.Utilities.1')->GetRandom() - * - * See RATIONALE.md for our reasoning behind this particular order - */ - if (extension_loaded('libsodium')) { - // See random_bytes_libsodium.php - if (PHP_VERSION_ID >= 50300 && is_callable('\\Sodium\\randombytes_buf')) { - require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_libsodium.php'; - } elseif (method_exists('Sodium', 'randombytes_buf')) { - require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_libsodium_legacy.php'; - } - } - - /** - * Reading directly from /dev/urandom: - */ - if (DIRECTORY_SEPARATOR === '/') { - // DIRECTORY_SEPARATOR === '/' on Unix-like OSes -- this is a fast - // way to exclude Windows. - $RandomCompatUrandom = true; - $RandomCompat_basedir = ini_get('open_basedir'); - - if (!empty($RandomCompat_basedir)) { - $RandomCompat_open_basedir = explode( - PATH_SEPARATOR, - strtolower($RandomCompat_basedir) - ); - $RandomCompatUrandom = (array() !== array_intersect( - array('/dev', '/dev/', '/dev/urandom'), - $RandomCompat_open_basedir - )); - $RandomCompat_open_basedir = null; - } - - if ( - !is_callable('random_bytes') - && - $RandomCompatUrandom - && - @is_readable('/dev/urandom') - ) { - // Error suppression on is_readable() in case of an open_basedir - // or safe_mode failure. All we care about is whether or not we - // can read it at this point. If the PHP environment is going to - // panic over trying to see if the file can be read in the first - // place, that is not helpful to us here. - - // See random_bytes_dev_urandom.php - require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_dev_urandom.php'; - } - // Unset variables after use - $RandomCompat_basedir = null; - } else { - $RandomCompatUrandom = false; - } - - /** - * mcrypt_create_iv() - * - * We only want to use mcypt_create_iv() if: - * - * - random_bytes() hasn't already been defined - * - the mcrypt extensions is loaded - * - One of these two conditions is true: - * - We're on Windows (DIRECTORY_SEPARATOR !== '/') - * - We're not on Windows and /dev/urandom is readabale - * (i.e. we're not in a chroot jail) - * - Special case: - * - If we're not on Windows, but the PHP version is between - * 5.6.10 and 5.6.12, we don't want to use mcrypt. It will - * hang indefinitely. This is bad. - * - If we're on Windows, we want to use PHP >= 5.3.7 or else - * we get insufficient entropy errors. - */ - if ( - !is_callable('random_bytes') - && - // Windows on PHP < 5.3.7 is broken, but non-Windows is not known to be. - (DIRECTORY_SEPARATOR === '/' || PHP_VERSION_ID >= 50307) - && - // Prevent this code from hanging indefinitely on non-Windows; - // see https://bugs.php.net/bug.php?id=69833 - ( - DIRECTORY_SEPARATOR !== '/' || - (PHP_VERSION_ID <= 50609 || PHP_VERSION_ID >= 50613) - ) - && - extension_loaded('mcrypt') - ) { - // See random_bytes_mcrypt.php - require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_mcrypt.php'; - } - $RandomCompatUrandom = null; - - /** - * This is a Windows-specific fallback, for when the mcrypt extension - * isn't loaded. - */ - if ( - !is_callable('random_bytes') - && - extension_loaded('com_dotnet') - && - class_exists('COM') - ) { - $RandomCompat_disabled_classes = preg_split( - '#\s*,\s*#', - strtolower(ini_get('disable_classes')) - ); - - if (!in_array('com', $RandomCompat_disabled_classes)) { - try { - $RandomCompatCOMtest = new COM('CAPICOM.Utilities.1'); - if (method_exists($RandomCompatCOMtest, 'GetRandom')) { - // See random_bytes_com_dotnet.php - require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_com_dotnet.php'; - } - } catch (com_exception $e) { - // Don't try to use it. - } - } - $RandomCompat_disabled_classes = null; - $RandomCompatCOMtest = null; - } - - /** - * throw new Exception - */ - if (!is_callable('random_bytes')) { - /** - * We don't have any more options, so let's throw an exception right now - * and hope the developer won't let it fail silently. - * - * @param mixed $length - * @psalm-suppress InvalidReturnType - * @throws Exception - * @return string - */ - function random_bytes($length) - { - unset($length); // Suppress "variable not used" warnings. - throw new Exception( - 'There is no suitable CSPRNG installed on your system' - ); - return ''; - } - } -} - -if (!is_callable('random_int')) { - require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_int.php'; -} - -$RandomCompatDIR = null; diff --git a/vendor/paragonie/random_compat/lib/random_bytes_com_dotnet.php b/vendor/paragonie/random_compat/lib/random_bytes_com_dotnet.php deleted file mode 100644 index 537d02b..0000000 --- a/vendor/paragonie/random_compat/lib/random_bytes_com_dotnet.php +++ /dev/null @@ -1,91 +0,0 @@ -GetRandom($bytes, 0)); - if (RandomCompat_strlen($buf) >= $bytes) { - /** - * Return our random entropy buffer here: - */ - return (string) RandomCompat_substr($buf, 0, $bytes); - } - ++$execCount; - } while ($execCount < $bytes); - - /** - * If we reach here, PHP has failed us. - */ - throw new Exception( - 'Could not gather sufficient random data' - ); - } -} diff --git a/vendor/paragonie/random_compat/lib/random_bytes_dev_urandom.php b/vendor/paragonie/random_compat/lib/random_bytes_dev_urandom.php deleted file mode 100644 index c4e31cc..0000000 --- a/vendor/paragonie/random_compat/lib/random_bytes_dev_urandom.php +++ /dev/null @@ -1,190 +0,0 @@ - $st */ - $st = fstat($fp); - if (($st['mode'] & 0170000) !== 020000) { - fclose($fp); - $fp = false; - } - } - } - - if (is_resource($fp)) { - /** - * stream_set_read_buffer() does not exist in HHVM - * - * If we don't set the stream's read buffer to 0, PHP will - * internally buffer 8192 bytes, which can waste entropy - * - * stream_set_read_buffer returns 0 on success - */ - if (is_callable('stream_set_read_buffer')) { - stream_set_read_buffer($fp, RANDOM_COMPAT_READ_BUFFER); - } - if (is_callable('stream_set_chunk_size')) { - stream_set_chunk_size($fp, RANDOM_COMPAT_READ_BUFFER); - } - } - } - - try { - /** @var int $bytes */ - $bytes = RandomCompat_intval($bytes); - } catch (TypeError $ex) { - throw new TypeError( - 'random_bytes(): $bytes must be an integer' - ); - } - - if ($bytes < 1) { - throw new Error( - 'Length must be greater than 0' - ); - } - - /** - * This if() block only runs if we managed to open a file handle - * - * It does not belong in an else {} block, because the above - * if (empty($fp)) line is logic that should only be run once per - * page load. - */ - if (is_resource($fp)) { - /** - * @var int - */ - $remaining = $bytes; - - /** - * @var string|bool - */ - $buf = ''; - - /** - * We use fread() in a loop to protect against partial reads - */ - do { - /** - * @var string|bool - */ - $read = fread($fp, $remaining); - if (!is_string($read)) { - /** - * We cannot safely read from the file. Exit the - * do-while loop and trigger the exception condition - * - * @var string|bool - */ - $buf = false; - break; - } - /** - * Decrease the number of bytes returned from remaining - */ - $remaining -= RandomCompat_strlen($read); - /** - * @var string $buf - */ - $buf .= $read; - } while ($remaining > 0); - - /** - * Is our result valid? - * @var string|bool $buf - */ - if (is_string($buf)) { - if (RandomCompat_strlen($buf) === $bytes) { - /** - * Return our random entropy buffer here: - */ - return $buf; - } - } - } - - /** - * If we reach here, PHP has failed us. - */ - throw new Exception( - 'Error reading from source device' - ); - } -} diff --git a/vendor/paragonie/random_compat/lib/random_bytes_libsodium.php b/vendor/paragonie/random_compat/lib/random_bytes_libsodium.php deleted file mode 100644 index 2e56290..0000000 --- a/vendor/paragonie/random_compat/lib/random_bytes_libsodium.php +++ /dev/null @@ -1,91 +0,0 @@ - 2147483647) { - $buf = ''; - for ($i = 0; $i < $bytes; $i += 1073741824) { - $n = ($bytes - $i) > 1073741824 - ? 1073741824 - : $bytes - $i; - $buf .= \Sodium\randombytes_buf($n); - } - } else { - /** @var string|bool $buf */ - $buf = \Sodium\randombytes_buf($bytes); - } - - if (is_string($buf)) { - if (RandomCompat_strlen($buf) === $bytes) { - return $buf; - } - } - - /** - * If we reach here, PHP has failed us. - */ - throw new Exception( - 'Could not gather sufficient random data' - ); - } -} diff --git a/vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php b/vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php deleted file mode 100644 index f78b219..0000000 --- a/vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php +++ /dev/null @@ -1,93 +0,0 @@ - 2147483647) { - for ($i = 0; $i < $bytes; $i += 1073741824) { - $n = ($bytes - $i) > 1073741824 - ? 1073741824 - : $bytes - $i; - $buf .= Sodium::randombytes_buf((int) $n); - } - } else { - $buf .= Sodium::randombytes_buf((int) $bytes); - } - - if (is_string($buf)) { - if (RandomCompat_strlen($buf) === $bytes) { - return $buf; - } - } - - /** - * If we reach here, PHP has failed us. - */ - throw new Exception( - 'Could not gather sufficient random data' - ); - } -} diff --git a/vendor/paragonie/random_compat/lib/random_bytes_mcrypt.php b/vendor/paragonie/random_compat/lib/random_bytes_mcrypt.php deleted file mode 100644 index 0b13fa7..0000000 --- a/vendor/paragonie/random_compat/lib/random_bytes_mcrypt.php +++ /dev/null @@ -1,79 +0,0 @@ - operators might accidentally let a float - * through. - */ - - try { - /** @var int $min */ - $min = RandomCompat_intval($min); - } catch (TypeError $ex) { - throw new TypeError( - 'random_int(): $min must be an integer' - ); - } - - try { - /** @var int $max */ - $max = RandomCompat_intval($max); - } catch (TypeError $ex) { - throw new TypeError( - 'random_int(): $max must be an integer' - ); - } - - /** - * Now that we've verified our weak typing system has given us an integer, - * let's validate the logic then we can move forward with generating random - * integers along a given range. - */ - if ($min > $max) { - throw new Error( - 'Minimum value must be less than or equal to the maximum value' - ); - } - - if ($max === $min) { - return (int) $min; - } - - /** - * Initialize variables to 0 - * - * We want to store: - * $bytes => the number of random bytes we need - * $mask => an integer bitmask (for use with the &) operator - * so we can minimize the number of discards - */ - $attempts = $bits = $bytes = $mask = $valueShift = 0; - /** @var int $attempts */ - /** @var int $bits */ - /** @var int $bytes */ - /** @var int $mask */ - /** @var int $valueShift */ - - /** - * At this point, $range is a positive number greater than 0. It might - * overflow, however, if $max - $min > PHP_INT_MAX. PHP will cast it to - * a float and we will lose some precision. - * - * @var int|float $range - */ - $range = $max - $min; - - /** - * Test for integer overflow: - */ - if (!is_int($range)) { - - /** - * Still safely calculate wider ranges. - * Provided by @CodesInChaos, @oittaa - * - * @ref https://gist.github.com/CodesInChaos/03f9ea0b58e8b2b8d435 - * - * We use ~0 as a mask in this case because it generates all 1s - * - * @ref https://eval.in/400356 (32-bit) - * @ref http://3v4l.org/XX9r5 (64-bit) - */ - $bytes = PHP_INT_SIZE; - /** @var int $mask */ - $mask = ~0; - - } else { - - /** - * $bits is effectively ceil(log($range, 2)) without dealing with - * type juggling - */ - while ($range > 0) { - if ($bits % 8 === 0) { - ++$bytes; - } - ++$bits; - $range >>= 1; - /** @var int $mask */ - $mask = $mask << 1 | 1; - } - $valueShift = $min; - } - - /** @var int $val */ - $val = 0; - /** - * Now that we have our parameters set up, let's begin generating - * random integers until one falls between $min and $max - */ - /** @psalm-suppress RedundantCondition */ - do { - /** - * The rejection probability is at most 0.5, so this corresponds - * to a failure probability of 2^-128 for a working RNG - */ - if ($attempts > 128) { - throw new Exception( - 'random_int: RNG is broken - too many rejections' - ); - } - - /** - * Let's grab the necessary number of random bytes - */ - $randomByteString = random_bytes($bytes); - - /** - * Let's turn $randomByteString into an integer - * - * This uses bitwise operators (<< and |) to build an integer - * out of the values extracted from ord() - * - * Example: [9F] | [6D] | [32] | [0C] => - * 159 + 27904 + 3276800 + 201326592 => - * 204631455 - */ - $val &= 0; - for ($i = 0; $i < $bytes; ++$i) { - $val |= ord($randomByteString[$i]) << ($i * 8); - } - /** @var int $val */ - - /** - * Apply mask - */ - $val &= $mask; - $val += $valueShift; - - ++$attempts; - /** - * If $val overflows to a floating point number, - * ... or is larger than $max, - * ... or smaller than $min, - * then try again. - */ - } while (!is_int($val) || $val > $max || $val < $min); - - return (int) $val; - } -} diff --git a/vendor/psr/http-message/CHANGELOG.md b/vendor/psr/http-message/CHANGELOG.md deleted file mode 100644 index 74b1ef9..0000000 --- a/vendor/psr/http-message/CHANGELOG.md +++ /dev/null @@ -1,36 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file, in reverse chronological order by release. - -## 1.0.1 - 2016-08-06 - -### Added - -- Nothing. - -### Deprecated - -- Nothing. - -### Removed - -- Nothing. - -### Fixed - -- Updated all `@return self` annotation references in interfaces to use - `@return static`, which more closelly follows the semantics of the - specification. -- Updated the `MessageInterface::getHeaders()` return annotation to use the - value `string[][]`, indicating the format is a nested array of strings. -- Updated the `@link` annotation for `RequestInterface::withRequestTarget()` - to point to the correct section of RFC 7230. -- Updated the `ServerRequestInterface::withUploadedFiles()` parameter annotation - to add the parameter name (`$uploadedFiles`). -- Updated a `@throws` annotation for the `UploadedFileInterface::moveTo()` - method to correctly reference the method parameter (it was referencing an - incorrect parameter name previously). - -## 1.0.0 - 2016-05-18 - -Initial stable release; reflects accepted PSR-7 specification. diff --git a/vendor/psr/http-message/LICENSE b/vendor/psr/http-message/LICENSE deleted file mode 100644 index c2d8e45..0000000 --- a/vendor/psr/http-message/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2014 PHP Framework Interoperability Group - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/vendor/psr/http-message/README.md b/vendor/psr/http-message/README.md deleted file mode 100644 index 2818533..0000000 --- a/vendor/psr/http-message/README.md +++ /dev/null @@ -1,13 +0,0 @@ -PSR Http Message -================ - -This repository holds all interfaces/classes/traits related to -[PSR-7](http://www.php-fig.org/psr/psr-7/). - -Note that this is not a HTTP message implementation of its own. It is merely an -interface that describes a HTTP message. See the specification for more details. - -Usage ------ - -We'll certainly need some stuff in here. \ No newline at end of file diff --git a/vendor/psr/http-message/composer.json b/vendor/psr/http-message/composer.json deleted file mode 100644 index b0d2937..0000000 --- a/vendor/psr/http-message/composer.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "psr/http-message", - "description": "Common interface for HTTP messages", - "keywords": ["psr", "psr-7", "http", "http-message", "request", "response"], - "homepage": "https://github.com/php-fig/http-message", - "license": "MIT", - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "require": { - "php": ">=5.3.0" - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Message\\": "src/" - } - }, - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - } -} diff --git a/vendor/psr/http-message/index.php b/vendor/psr/http-message/index.php deleted file mode 100644 index df24d3e..0000000 --- a/vendor/psr/http-message/index.php +++ /dev/null @@ -1,35 +0,0 @@ - - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA - */ - -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); - -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); - -header("Location: ../"); -exit; diff --git a/vendor/psr/http-message/src/MessageInterface.php b/vendor/psr/http-message/src/MessageInterface.php deleted file mode 100644 index dd46e5e..0000000 --- a/vendor/psr/http-message/src/MessageInterface.php +++ /dev/null @@ -1,187 +0,0 @@ -getHeaders() as $name => $values) { - * echo $name . ": " . implode(", ", $values); - * } - * - * // Emit headers iteratively: - * foreach ($message->getHeaders() as $name => $values) { - * foreach ($values as $value) { - * header(sprintf('%s: %s', $name, $value), false); - * } - * } - * - * While header names are not case-sensitive, getHeaders() will preserve the - * exact case in which headers were originally specified. - * - * @return string[][] Returns an associative array of the message's headers. Each - * key MUST be a header name, and each value MUST be an array of strings - * for that header. - */ - public function getHeaders(); - - /** - * Checks if a header exists by the given case-insensitive name. - * - * @param string $name Case-insensitive header field name. - * @return bool Returns true if any header names match the given header - * name using a case-insensitive string comparison. Returns false if - * no matching header name is found in the message. - */ - public function hasHeader($name); - - /** - * Retrieves a message header value by the given case-insensitive name. - * - * This method returns an array of all the header values of the given - * case-insensitive header name. - * - * If the header does not appear in the message, this method MUST return an - * empty array. - * - * @param string $name Case-insensitive header field name. - * @return string[] An array of string values as provided for the given - * header. If the header does not appear in the message, this method MUST - * return an empty array. - */ - public function getHeader($name); - - /** - * Retrieves a comma-separated string of the values for a single header. - * - * This method returns all of the header values of the given - * case-insensitive header name as a string concatenated together using - * a comma. - * - * NOTE: Not all header values may be appropriately represented using - * comma concatenation. For such headers, use getHeader() instead - * and supply your own delimiter when concatenating. - * - * If the header does not appear in the message, this method MUST return - * an empty string. - * - * @param string $name Case-insensitive header field name. - * @return string A string of values as provided for the given header - * concatenated together using a comma. If the header does not appear in - * the message, this method MUST return an empty string. - */ - public function getHeaderLine($name); - - /** - * Return an instance with the provided value replacing the specified header. - * - * While header names are case-insensitive, the casing of the header will - * be preserved by this function, and returned from getHeaders(). - * - * This method MUST be implemented in such a way as to retain the - * immutability of the message, and MUST return an instance that has the - * new and/or updated header and value. - * - * @param string $name Case-insensitive header field name. - * @param string|string[] $value Header value(s). - * @return static - * @throws \InvalidArgumentException for invalid header names or values. - */ - public function withHeader($name, $value); - - /** - * Return an instance with the specified header appended with the given value. - * - * Existing values for the specified header will be maintained. The new - * value(s) will be appended to the existing list. If the header did not - * exist previously, it will be added. - * - * This method MUST be implemented in such a way as to retain the - * immutability of the message, and MUST return an instance that has the - * new header and/or value. - * - * @param string $name Case-insensitive header field name to add. - * @param string|string[] $value Header value(s). - * @return static - * @throws \InvalidArgumentException for invalid header names or values. - */ - public function withAddedHeader($name, $value); - - /** - * Return an instance without the specified header. - * - * Header resolution MUST be done without case-sensitivity. - * - * This method MUST be implemented in such a way as to retain the - * immutability of the message, and MUST return an instance that removes - * the named header. - * - * @param string $name Case-insensitive header field name to remove. - * @return static - */ - public function withoutHeader($name); - - /** - * Gets the body of the message. - * - * @return StreamInterface Returns the body as a stream. - */ - public function getBody(); - - /** - * Return an instance with the specified message body. - * - * The body MUST be a StreamInterface object. - * - * This method MUST be implemented in such a way as to retain the - * immutability of the message, and MUST return a new instance that has the - * new body stream. - * - * @param StreamInterface $body Body. - * @return static - * @throws \InvalidArgumentException When the body is not valid. - */ - public function withBody(StreamInterface $body); -} diff --git a/vendor/psr/http-message/src/RequestInterface.php b/vendor/psr/http-message/src/RequestInterface.php deleted file mode 100644 index a96d4fd..0000000 --- a/vendor/psr/http-message/src/RequestInterface.php +++ /dev/null @@ -1,129 +0,0 @@ -getQuery()` - * or from the `QUERY_STRING` server param. - * - * @return array - */ - public function getQueryParams(); - - /** - * Return an instance with the specified query string arguments. - * - * These values SHOULD remain immutable over the course of the incoming - * request. They MAY be injected during instantiation, such as from PHP's - * $_GET superglobal, or MAY be derived from some other value such as the - * URI. In cases where the arguments are parsed from the URI, the data - * MUST be compatible with what PHP's parse_str() would return for - * purposes of how duplicate query parameters are handled, and how nested - * sets are handled. - * - * Setting query string arguments MUST NOT change the URI stored by the - * request, nor the values in the server params. - * - * This method MUST be implemented in such a way as to retain the - * immutability of the message, and MUST return an instance that has the - * updated query string arguments. - * - * @param array $query Array of query string arguments, typically from - * $_GET. - * @return static - */ - public function withQueryParams(array $query); - - /** - * Retrieve normalized file upload data. - * - * This method returns upload metadata in a normalized tree, with each leaf - * an instance of Psr\Http\Message\UploadedFileInterface. - * - * These values MAY be prepared from $_FILES or the message body during - * instantiation, or MAY be injected via withUploadedFiles(). - * - * @return array An array tree of UploadedFileInterface instances; an empty - * array MUST be returned if no data is present. - */ - public function getUploadedFiles(); - - /** - * Create a new instance with the specified uploaded files. - * - * This method MUST be implemented in such a way as to retain the - * immutability of the message, and MUST return an instance that has the - * updated body parameters. - * - * @param array $uploadedFiles An array tree of UploadedFileInterface instances. - * @return static - * @throws \InvalidArgumentException if an invalid structure is provided. - */ - public function withUploadedFiles(array $uploadedFiles); - - /** - * Retrieve any parameters provided in the request body. - * - * If the request Content-Type is either application/x-www-form-urlencoded - * or multipart/form-data, and the request method is POST, this method MUST - * return the contents of $_POST. - * - * Otherwise, this method may return any results of deserializing - * the request body content; as parsing returns structured content, the - * potential types MUST be arrays or objects only. A null value indicates - * the absence of body content. - * - * @return null|array|object The deserialized body parameters, if any. - * These will typically be an array or object. - */ - public function getParsedBody(); - - /** - * Return an instance with the specified body parameters. - * - * These MAY be injected during instantiation. - * - * If the request Content-Type is either application/x-www-form-urlencoded - * or multipart/form-data, and the request method is POST, use this method - * ONLY to inject the contents of $_POST. - * - * The data IS NOT REQUIRED to come from $_POST, but MUST be the results of - * deserializing the request body content. Deserialization/parsing returns - * structured data, and, as such, this method ONLY accepts arrays or objects, - * or a null value if nothing was available to parse. - * - * As an example, if content negotiation determines that the request data - * is a JSON payload, this method could be used to create a request - * instance with the deserialized parameters. - * - * This method MUST be implemented in such a way as to retain the - * immutability of the message, and MUST return an instance that has the - * updated body parameters. - * - * @param null|array|object $data The deserialized body data. This will - * typically be in an array or object. - * @return static - * @throws \InvalidArgumentException if an unsupported argument type is - * provided. - */ - public function withParsedBody($data); - - /** - * Retrieve attributes derived from the request. - * - * The request "attributes" may be used to allow injection of any - * parameters derived from the request: e.g., the results of path - * match operations; the results of decrypting cookies; the results of - * deserializing non-form-encoded message bodies; etc. Attributes - * will be application and request specific, and CAN be mutable. - * - * @return array Attributes derived from the request. - */ - public function getAttributes(); - - /** - * Retrieve a single derived request attribute. - * - * Retrieves a single derived request attribute as described in - * getAttributes(). If the attribute has not been previously set, returns - * the default value as provided. - * - * This method obviates the need for a hasAttribute() method, as it allows - * specifying a default value to return if the attribute is not found. - * - * @see getAttributes() - * @param string $name The attribute name. - * @param mixed $default Default value to return if the attribute does not exist. - * @return mixed - */ - public function getAttribute($name, $default = null); - - /** - * Return an instance with the specified derived request attribute. - * - * This method allows setting a single derived request attribute as - * described in getAttributes(). - * - * This method MUST be implemented in such a way as to retain the - * immutability of the message, and MUST return an instance that has the - * updated attribute. - * - * @see getAttributes() - * @param string $name The attribute name. - * @param mixed $value The value of the attribute. - * @return static - */ - public function withAttribute($name, $value); - - /** - * Return an instance that removes the specified derived request attribute. - * - * This method allows removing a single derived request attribute as - * described in getAttributes(). - * - * This method MUST be implemented in such a way as to retain the - * immutability of the message, and MUST return an instance that removes - * the attribute. - * - * @see getAttributes() - * @param string $name The attribute name. - * @return static - */ - public function withoutAttribute($name); -} diff --git a/vendor/psr/http-message/src/StreamInterface.php b/vendor/psr/http-message/src/StreamInterface.php deleted file mode 100644 index f68f391..0000000 --- a/vendor/psr/http-message/src/StreamInterface.php +++ /dev/null @@ -1,158 +0,0 @@ - - * [user-info@]host[:port] - * - * - * If the port component is not set or is the standard port for the current - * scheme, it SHOULD NOT be included. - * - * @see https://tools.ietf.org/html/rfc3986#section-3.2 - * @return string The URI authority, in "[user-info@]host[:port]" format. - */ - public function getAuthority(); - - /** - * Retrieve the user information component of the URI. - * - * If no user information is present, this method MUST return an empty - * string. - * - * If a user is present in the URI, this will return that value; - * additionally, if the password is also present, it will be appended to the - * user value, with a colon (":") separating the values. - * - * The trailing "@" character is not part of the user information and MUST - * NOT be added. - * - * @return string The URI user information, in "username[:password]" format. - */ - public function getUserInfo(); - - /** - * Retrieve the host component of the URI. - * - * If no host is present, this method MUST return an empty string. - * - * The value returned MUST be normalized to lowercase, per RFC 3986 - * Section 3.2.2. - * - * @see http://tools.ietf.org/html/rfc3986#section-3.2.2 - * @return string The URI host. - */ - public function getHost(); - - /** - * Retrieve the port component of the URI. - * - * If a port is present, and it is non-standard for the current scheme, - * this method MUST return it as an integer. If the port is the standard port - * used with the current scheme, this method SHOULD return null. - * - * If no port is present, and no scheme is present, this method MUST return - * a null value. - * - * If no port is present, but a scheme is present, this method MAY return - * the standard port for that scheme, but SHOULD return null. - * - * @return null|int The URI port. - */ - public function getPort(); - - /** - * Retrieve the path component of the URI. - * - * The path can either be empty or absolute (starting with a slash) or - * rootless (not starting with a slash). Implementations MUST support all - * three syntaxes. - * - * Normally, the empty path "" and absolute path "/" are considered equal as - * defined in RFC 7230 Section 2.7.3. But this method MUST NOT automatically - * do this normalization because in contexts with a trimmed base path, e.g. - * the front controller, this difference becomes significant. It's the task - * of the user to handle both "" and "/". - * - * The value returned MUST be percent-encoded, but MUST NOT double-encode - * any characters. To determine what characters to encode, please refer to - * RFC 3986, Sections 2 and 3.3. - * - * As an example, if the value should include a slash ("/") not intended as - * delimiter between path segments, that value MUST be passed in encoded - * form (e.g., "%2F") to the instance. - * - * @see https://tools.ietf.org/html/rfc3986#section-2 - * @see https://tools.ietf.org/html/rfc3986#section-3.3 - * @return string The URI path. - */ - public function getPath(); - - /** - * Retrieve the query string of the URI. - * - * If no query string is present, this method MUST return an empty string. - * - * The leading "?" character is not part of the query and MUST NOT be - * added. - * - * The value returned MUST be percent-encoded, but MUST NOT double-encode - * any characters. To determine what characters to encode, please refer to - * RFC 3986, Sections 2 and 3.4. - * - * As an example, if a value in a key/value pair of the query string should - * include an ampersand ("&") not intended as a delimiter between values, - * that value MUST be passed in encoded form (e.g., "%26") to the instance. - * - * @see https://tools.ietf.org/html/rfc3986#section-2 - * @see https://tools.ietf.org/html/rfc3986#section-3.4 - * @return string The URI query string. - */ - public function getQuery(); - - /** - * Retrieve the fragment component of the URI. - * - * If no fragment is present, this method MUST return an empty string. - * - * The leading "#" character is not part of the fragment and MUST NOT be - * added. - * - * The value returned MUST be percent-encoded, but MUST NOT double-encode - * any characters. To determine what characters to encode, please refer to - * RFC 3986, Sections 2 and 3.5. - * - * @see https://tools.ietf.org/html/rfc3986#section-2 - * @see https://tools.ietf.org/html/rfc3986#section-3.5 - * @return string The URI fragment. - */ - public function getFragment(); - - /** - * Return an instance with the specified scheme. - * - * This method MUST retain the state of the current instance, and return - * an instance that contains the specified scheme. - * - * Implementations MUST support the schemes "http" and "https" case - * insensitively, and MAY accommodate other schemes if required. - * - * An empty scheme is equivalent to removing the scheme. - * - * @param string $scheme The scheme to use with the new instance. - * @return static A new instance with the specified scheme. - * @throws \InvalidArgumentException for invalid or unsupported schemes. - */ - public function withScheme($scheme); - - /** - * Return an instance with the specified user information. - * - * This method MUST retain the state of the current instance, and return - * an instance that contains the specified user information. - * - * Password is optional, but the user information MUST include the - * user; an empty string for the user is equivalent to removing user - * information. - * - * @param string $user The user name to use for authority. - * @param null|string $password The password associated with $user. - * @return static A new instance with the specified user information. - */ - public function withUserInfo($user, $password = null); - - /** - * Return an instance with the specified host. - * - * This method MUST retain the state of the current instance, and return - * an instance that contains the specified host. - * - * An empty host value is equivalent to removing the host. - * - * @param string $host The hostname to use with the new instance. - * @return static A new instance with the specified host. - * @throws \InvalidArgumentException for invalid hostnames. - */ - public function withHost($host); - - /** - * Return an instance with the specified port. - * - * This method MUST retain the state of the current instance, and return - * an instance that contains the specified port. - * - * Implementations MUST raise an exception for ports outside the - * established TCP and UDP port ranges. - * - * A null value provided for the port is equivalent to removing the port - * information. - * - * @param null|int $port The port to use with the new instance; a null value - * removes the port information. - * @return static A new instance with the specified port. - * @throws \InvalidArgumentException for invalid ports. - */ - public function withPort($port); - - /** - * Return an instance with the specified path. - * - * This method MUST retain the state of the current instance, and return - * an instance that contains the specified path. - * - * The path can either be empty or absolute (starting with a slash) or - * rootless (not starting with a slash). Implementations MUST support all - * three syntaxes. - * - * If the path is intended to be domain-relative rather than path relative then - * it must begin with a slash ("/"). Paths not starting with a slash ("/") - * are assumed to be relative to some base path known to the application or - * consumer. - * - * Users can provide both encoded and decoded path characters. - * Implementations ensure the correct encoding as outlined in getPath(). - * - * @param string $path The path to use with the new instance. - * @return static A new instance with the specified path. - * @throws \InvalidArgumentException for invalid paths. - */ - public function withPath($path); - - /** - * Return an instance with the specified query string. - * - * This method MUST retain the state of the current instance, and return - * an instance that contains the specified query string. - * - * Users can provide both encoded and decoded query characters. - * Implementations ensure the correct encoding as outlined in getQuery(). - * - * An empty query string value is equivalent to removing the query string. - * - * @param string $query The query string to use with the new instance. - * @return static A new instance with the specified query string. - * @throws \InvalidArgumentException for invalid query strings. - */ - public function withQuery($query); - - /** - * Return an instance with the specified URI fragment. - * - * This method MUST retain the state of the current instance, and return - * an instance that contains the specified URI fragment. - * - * Users can provide both encoded and decoded fragment characters. - * Implementations ensure the correct encoding as outlined in getFragment(). - * - * An empty fragment value is equivalent to removing the fragment. - * - * @param string $fragment The fragment to use with the new instance. - * @return static A new instance with the specified fragment. - */ - public function withFragment($fragment); - - /** - * Return the string representation as a URI reference. - * - * Depending on which components of the URI are present, the resulting - * string is either a full URI or relative reference according to RFC 3986, - * Section 4.1. The method concatenates the various components of the URI, - * using the appropriate delimiters: - * - * - If a scheme is present, it MUST be suffixed by ":". - * - If an authority is present, it MUST be prefixed by "//". - * - The path can be concatenated without delimiters. But there are two - * cases where the path has to be adjusted to make the URI reference - * valid as PHP does not allow to throw an exception in __toString(): - * - If the path is rootless and an authority is present, the path MUST - * be prefixed by "/". - * - If the path is starting with more than one "/" and no authority is - * present, the starting slashes MUST be reduced to one. - * - If a query is present, it MUST be prefixed by "?". - * - If a fragment is present, it MUST be prefixed by "#". - * - * @see http://tools.ietf.org/html/rfc3986#section-4.1 - * @return string - */ - public function __toString(); -} diff --git a/vendor/psr/http-message/src/index.php b/vendor/psr/http-message/src/index.php deleted file mode 100644 index df24d3e..0000000 --- a/vendor/psr/http-message/src/index.php +++ /dev/null @@ -1,35 +0,0 @@ - - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA - */ - -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); - -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); - -header("Location: ../"); -exit; diff --git a/vendor/psr/index.php b/vendor/psr/index.php deleted file mode 100644 index df24d3e..0000000 --- a/vendor/psr/index.php +++ /dev/null @@ -1,35 +0,0 @@ - - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA - */ - -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); - -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); - -header("Location: ../"); -exit; diff --git a/vendor/robthree/index.php b/vendor/robthree/index.php index df24d3e..fa24a5a 100644 --- a/vendor/robthree/index.php +++ b/vendor/robthree/index.php @@ -1,35 +1,22 @@ - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. */ -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); +\header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); +\header('Last-Modified: ' . \gmdate('D, d M Y H:i:s') . ' GMT'); + +\header('Cache-Control: no-store, no-cache, must-revalidate'); +\header('Cache-Control: post-check=0, pre-check=0', false); +\header('Pragma: no-cache'); -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); +\header('Location: ../'); -header("Location: ../"); exit; diff --git a/vendor/robthree/twofactorauth/.travis.yml b/vendor/robthree/twofactorauth/.travis.yml deleted file mode 100644 index fdc6ff5..0000000 --- a/vendor/robthree/twofactorauth/.travis.yml +++ /dev/null @@ -1,15 +0,0 @@ -language: php - -php: - - 5.6 - - 7.0 - - 7.1 - - 7.2 - - 7.3 - - 7.4 - -before_script: - - composer install - -script: - - vendor/bin/phpunit --coverage-text tests \ No newline at end of file diff --git a/vendor/robthree/twofactorauth/README.md b/vendor/robthree/twofactorauth/README.md deleted file mode 100644 index 3574ae9..0000000 --- a/vendor/robthree/twofactorauth/README.md +++ /dev/null @@ -1,199 +0,0 @@ -# ![Logo](https://raw.githubusercontent.com/RobThree/TwoFactorAuth/master/logo.png) PHP library for Two Factor Authentication - -[![Build status](https://img.shields.io/travis/RobThree/TwoFactorAuth.svg?style=flat-square)](https://travis-ci.org/RobThree/TwoFactorAuth/) [![Latest Stable Version](https://img.shields.io/packagist/v/robthree/twofactorauth.svg?style=flat-square)](https://packagist.org/packages/robthree/twofactorauth) [![License](https://img.shields.io/packagist/l/robthree/twofactorauth.svg?style=flat-square)](LICENSE) [![Downloads](https://img.shields.io/packagist/dt/robthree/twofactorauth.svg?style=flat-square)](https://packagist.org/packages/robthree/twofactorauth) [![Code Climate](https://img.shields.io/codeclimate/github/RobThree/TwoFactorAuth.svg?style=flat-square)](https://codeclimate.com/github/RobThree/TwoFactorAuth) [![PayPal donate button](http://img.shields.io/badge/paypal-donate-orange.svg?style=flat-square)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=6MB5M2SQLP636 "Keep me off the streets") - -PHP library for [two-factor (or multi-factor) authentication](http://en.wikipedia.org/wiki/Multi-factor_authentication) using [TOTP](http://en.wikipedia.org/wiki/Time-based_One-time_Password_Algorithm) and [QR-codes](http://en.wikipedia.org/wiki/QR_code). Inspired by, based on but most importantly an *improvement* on '[PHPGangsta/GoogleAuthenticator](https://github.com/PHPGangsta/GoogleAuthenticator)'. There's a [.Net implementation](https://github.com/RobThree/TwoFactorAuth.Net) of this library as well. - -

- -

- -## Requirements - -* Tested on PHP 5.6 up to 7.4 -* [cURL](http://php.net/manual/en/book.curl.php) when using the provided `ImageChartsQRCodeProvider` (default), `QRServerProvider` or `QRicketProvider` but you can also provide your own QR-code provider. -* [random_bytes()](http://php.net/manual/en/function.random-bytes.php), [MCrypt](http://php.net/manual/en/book.mcrypt.php), [OpenSSL](http://php.net/manual/en/book.openssl.php) or [Hash](http://php.net/manual/en/book.hash.php) depending on which built-in RNG you use (TwoFactorAuth will try to 'autodetect' and use the best available); however: feel free to provide your own (CS)RNG. - -## Installation - -Run the following command: - -`php composer.phar require robthree/twofactorauth` - -## Quick start - -If you want to hit the ground running then have a look at the [demo](demo/demo.php). It's very simple and easy! - -## Usage - -Here are some code snippets that should help you get started... - -````php -// Create a TwoFactorAuth instance -$tfa = new RobThree\Auth\TwoFactorAuth('My Company'); -```` - -The TwoFactorAuth class constructor accepts 7 arguments (all optional): - -Argument | Default value | Use -------------------|---------------|-------------------------------------------------- -`$issuer` | `null` | Will be displayed in the app as issuer name -`$digits` | `6` | The number of digits the resulting codes will be -`$period` | `30` | The number of seconds a code will be valid -`$algorithm` | `sha1` | The algorithm used -`$qrcodeprovider` | `null` | QR-code provider (more on this later) -`$rngprovider` | `null` | Random Number Generator provider (more on this later) -`$timeprovider` | `null` | Time provider (more on this later) - -These arguments are all '`write once`'; the class will, for it's lifetime, use these values when generating / calculating codes. The number of digits, the period and algorithm are all set to values Google's Authticator app uses (and supports). You may specify `8` digits, a period of `45` seconds and the `sha256` algorithm but the authenticator app (be it Google's implementation, Authy or any other app) may or may not support these values. Your mileage may vary; keep it on the safe side if you don't control which app your audience uses. - -### Step 1: Set up secret shared key - -When a user wants to setup two-factor auth (or, more correctly, multi-factor auth) you need to create a secret. This will be your **shared secret**. This secret will need to be entered by the user in their app. This can be done manually, in which case you simply display the secret and have the user type it in the app: - -````php -$secret = $tfa->createSecret(); -```` - -The `createSecret()` method accepts two arguments: `$bits` (default: `80`) and `$requirecryptosecure` (default: `true`). The former is the number of bits generated for the shared secret. Make sure this argument is a multiple of 8 and, again, keep in mind that not all combinations may be supported by all apps. Google authenticator seems happy with 80 and 160, the default is set to 80 because that's what most sites (that I know of) currently use; however a value of 160 or higher is recommended (see [RFC 4226 - Algorithm Requirements](https://tools.ietf.org/html/rfc4226#section-4)). The latter is used to ensure that the secret is cryptographically secure; if you don't care very much for cryptographically secure secrets you can specify `false` and use a **non**-cryptographically secure RNG provider. - -````php -// Display shared secret -

Please enter the following code in your app: ''

-```` - -Another, more user-friendly, way to get the shared secret into the app is to generate a [QR-code](http://en.wikipedia.org/wiki/QR_code) which can be scanned by the app. To generate these QR codes you can use any one of the built-in `QRProvider` classes: - -1. `ImageChartsQRCodeProvider` (default) -2. `QRServerProvider` -3. `QRicketProvider` - -...or implement your own provider. To implement your own provider all you need to do is implement the `IQRCodeProvider` interface. You can use the built-in providers mentioned before to serve as an example or read the next chapter in this file. The built-in classes all use a 3rd (e.g. external) party (Image-charts, QRServer and QRicket) for the hard work of generating QR-codes (note: each of these services might at some point not be available or impose limitations to the number of codes generated per day, hour etc.). You could, however, easily use a project like [PHP QR Code](http://phpqrcode.sourceforge.net/) (or one of the [many others](https://packagist.org/search/?q=qr)) to generate your QR-codes without depending on external sources. Later on we'll [demonstrate](#qr-code-providers) how to do this. - -The built-in providers all have some provider-specific 'tweaks' you can 'apply'. Some provide support for different colors, others may let you specify the desired image-format etc. What they all have in common is that they return a QR-code as binary blob which, in turn, will be turned into a [data URI](http://en.wikipedia.org/wiki/Data_URI_scheme) by the `TwoFactorAuth` class. This makes it easy for you to display the image without requiring extra 'roundtrips' from browser to server and vice versa. - -````php -// Display QR code to user -

Scan the following image with your app:

-

-```` - -When outputting a QR-code you can choose a `$label` for the user (which, when entering a shared secret manually, will have to be chosen by the user). This label may be an empty string or `null`. Also a `$size` may be specified (in pixels, width == height) for which we use a default value of `200`. - -### Step 2: Verify secret shared key - -When the shared secret is added to the app, the app will be ready to start generating codes which 'expire' each '`$period`' number of seconds. To make sure the secret was entered, or scanned, correctly you need to verify this by having the user enter a generated code. To check if the generated code is valid you call the `verifyCode()` method: - -````php -// Verify code -$result = $tfa->verifyCode($_SESSION['secret'], $_POST['verification']); -```` - -`verifyCode()` will return either `true` (the code was valid) or `false` (the code was invalid; no points for you!). You may need to store `$secret` in a `$_SESSION` or other persistent storage between requests. The `verifyCode()` accepts, aside from `$secret` and `$code`, three more arguments. The first being `$discrepancy`. Since TOTP codes are based on time("slices") it is very important that the server (but also client) have a correct date/time. But because the two *may* differ a bit we usually allow a certain amount of leeway. Because generated codes are valid for a specific period (remember the `$period` argument in the `TwoFactorAuth`'s constructor?) we usually check the period directly before and the period directly after the current time when validating codes. So when the current time is `14:34:21`, which results in a 'current timeslice' of `14:34:00` to `14:34:30` we also calculate/verify the codes for `14:33:30` to `14:34:00` and for `14:34:30` to `14:35:00`. This gives us a 'window' of `14:33:30` to `14:35:00`. The `$discrepancy` argument specifies how many periods (or: timeslices) we check in either direction of the current time. The default `$discrepancy` of `1` results in (max.) 3 period checks: -1, current and +1 period. A `$discrepancy` of `4` would result in a larger window (or: bigger time difference between client and server) of -4, -3, -2, -1, current, +1, +2, +3 and +4 periods. - -The second, `$time`, allows you to check a code for a specific point in time. This argument has no real practical use but can be handy for unittesting etc. The default value, `null`, means: use the current time. - -The third, `$timeslice`, is an out-argument; the value returned in `$timeslice` is the value of the timeslice that matched the code (if any). This value will be 0 when the code doesn't match and non-zero when the code matches. This value can be stored with the user and can be used to prevent replay-attacks. All you need to do is, on successful login, make sure `$timeslice` is greater than the previously stored timeslice. - -### Step 3: Store `$secret` with user and we're done! - -Ok, so now the code has been verified and found to be correct. Now we can store the `$secret` with our user in our database (or elsewhere) and whenever the user begins a new session we ask for a code generated by the authentication app of their choice. All we need to do is call `verifyCode()` again with the shared secret and the entered code and we know if the user is legit or not. - -Simple as 1-2-3. - -All we need is 3 methods and a constructor: - -````php -public function __construct( - $issuer = null, - $digits = 6, - $period = 30, - $algorithm = 'sha1', - RobThree\Auth\Providers\Qr\IQRCodeProvider $qrcodeprovider = null, - RobThree\Auth\Providers\Rng\IRNGProvider $rngprovider = null -); -public function createSecret($bits = 80, $requirecryptosecure = true): string; -public function getQRCodeImageAsDataUri($label, $secret, $size = 200): string; -public function verifyCode($secret, $code, $discrepancy = 1, $time = null): bool; -```` - -### QR-code providers - -As mentioned before, this library comes with three 'built-in' QR-code providers. This chapter will touch the subject a bit but most of it should be self-explanatory. The `TwoFactorAuth`-class accepts a `$qrcodeprovider` argument which lets you specify a built-in or custom QR-code provider. All three built-in providers do a simple HTTP request to retrieve an image using cURL and implement the [`IQRCodeProvider`](lib/Providers/Qr/IQRCodeProvider.php) interface which is all you need to implement to write your own QR-code provider. - -The default provider is the [`ImageChartsQRCodeProvider`](lib/Providers/Qr/ImageChartsQRCodeProvider.php) which uses the [image-charts.com replacement for Google Image Charts](https://image-charts.com) to render QR-codes. Then we have the [`QRServerProvider`](lib/Providers/Qr/QRServerProvider.php) which uses the [goqr.me API](http://goqr.me/api/doc/create-qr-code/) and finally we have the [`QRicketProvider`](lib/Providers/Qr/QRicketProvider.php) which uses the [QRickit API](http://qrickit.com/qrickit_apps/qrickit_api.php). All three inherit from a common (abstract) baseclass named [`BaseHTTPQRCodeProvider`](lib/Providers/Qr/BaseHTTPQRCodeProvider.php) because all three share the same functionality: retrieve an image from a 3rd party over HTTP. All three classes have constructors that allow you to tweak some settings and most, if not all, arguments should speak for themselves. If you're not sure which values are supported, click the links in this paragraph for documentation on the API's that are utilized by these classes. - -If you don't like any of the built-in classes because you don't want to rely on external resources for example or because you're paranoid about sending the TOTP secret to these 3rd parties (which is useless to them since they miss *at least one* other factor in the [MFA process](http://en.wikipedia.org/wiki/Multi-factor_authentication)), feel tree to implement your own. The `IQRCodeProvider` interface couldn't be any simpler. All you need to do is implement 2 methods: - -````php -getMimeType(); -getQRCodeImage($qrtext, $size); -```` - -The `getMimeType()` method should return the [MIME type](http://en.wikipedia.org/wiki/Internet_media_type) of the image that is returned by our implementation of `getQRCodeImage()`. In this example it's simply `image/png`. The `getQRCodeImage()` method is passed two arguments: `$qrtext` and `$size`. The latter, `$size`, is simply the width/height in pixels of the image desired by the caller. The first, `$qrtext` is the text that should be encoded in the QR-code. An example of such a text would be: - -`otpauth://totp/LABEL:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=ISSUER` - -All you need to do is return the QR-code as binary image data and you're done. All parts of the `$qrtext` have been escaped for you (but note: you *may* need to escape the entire `$qrtext` just once more when passing the data to another server as GET-argument). - -Let's see if we can use [PHP QR Code](http://phpqrcode.sourceforge.net/) to implement our own, custom, no-3rd-parties-allowed-here, provider. We start with downloading the [required (single) file](https://github.com/t0k4rt/phpqrcode/blob/master/phpqrcode.php) and putting it in the directory where `TwoFactorAuth.php` is located as well. Now let's implement the provider: create another file named `myprovider.php` in the `Providers\Qr` directory and paste in this content: - -````php -createSecret(); -?> -

-```` - -Voilà. Couldn't make it any simpler. - -### RNG providers - -This library also comes with three 'built-in' RNG providers ([Random Number Generator](https://en.wikipedia.org/wiki/Random_number_generation)). The RNG provider generates a number of random bytes and returns these bytes as a string. These values are then used to create the secret. By default (no RNG provider specified) TwoFactorAuth will try to determine the best available RNG provider to use. It will, by default, try to use the [`CSRNGProvider`](lib/Providers/Rng/CSRNGProvider.php) for PHP7+ or the [`MCryptRNGProvider`](lib/Providers/Rng/MCryptRNGProvider.php); if this is not available/supported for any reason it will try to use the [`OpenSSLRNGProvider`](lib/Providers/Rng/OpenSSLRNGProvider.php) and if that is also not available/supported it will try to use the final RNG provider: [`HashRNGProvider`](lib/Providers/Rng/HashRNGProvider.php). Each of these providers use their own method of generating a random sequence of bytes. The first three (`CSRNGProvider`, `OpenSSLRNGProvider` and `MCryptRNGProvider`) return a [cryptographically secure](https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator) sequence of random bytes whereas the `HashRNGProvider` returns a **non-cryptographically secure** sequence. - -You can easily implement your own `RNGProvider` by simply implementing the `IRNGProvider` interface. Each of the 'built-in' RNG providers have some constructor arguments that allow you to 'tweak' some of the settings to use when creating the random bytes such as which source to use (`MCryptRNGProvider`) or which hashing algorithm (`HashRNGProvider`). I encourage you to have a look at some of the ['built-in' RNG providers](lib/Providers/Rng) for details and the [`IRNGProvider` interface](lib/Providers/Rng/IRNGProvider.php). - -### Time providers - -Another set of providers in this library are the Time Providers; this library provides three 'built-in' ones. The default Time Provider used is the [`LocalMachineTimeProvider`](lib/Providers/Time/LocalMachineTimeProvider.php); this provider simply returns the output of `Time()` and is *highly recommended* as default provider. The [`HttpTimeProvider`](lib/Providers/Time/HttpTimeProvider.php) executes a `HEAD` request against a given webserver (default: google.com) and tries to extract the `Date:`-HTTP header and returns it's date. Other url's/domains can be used by specifying the url in the constructor. The final Time Provider is the [`NTPTimeProvider`](lib/Providers/Time/NTPTimeProvider.php) which does an NTP request to a specified NTP server. - -You can easily implement your own `TimeProvider` by simply implementing the `ITimeProvider` interface. - -As to *why* these Time Providers are implemented: it allows the TwoFactorAuth library to ensure the hosts time is correct (or rather: within a margin). You can use the `ensureCorrectTime()` method to ensure the hosts time is correct. By default this method will compare the hosts time (returned by calling `time()` on the `LocalMachineTimeProvider`) to the default `NTPTimeProvider` and `HttpTimeProvider`. You can pass an array of `ITimeProvider`s to change this and specify the `leniency` (second argument) allowed (default: 5 seconds). The method will throw when the TwoFactorAuth's timeprovider (which can be any `ITimeProvider`, see constructor) differs more than the given amount of seconds from any of the given `ITimeProviders`. We advise to call this method sparingly when relying on 3rd parties (which both the `HttpTimeProvider` and `NTPTimeProvider` do) or, if you need to ensure time is correct on a (very) regular basis to implement an `ITimeProvider` that is more efficient than the 'built-in' ones (like use a GPS signal). The `ensureCorrectTime()` method is mostly to be used to make sure the server is configured correctly. - -## Integrations - -- [CakePHP 3](https://github.com/andrej-griniuk/cakephp-two-factor-auth) - -## License - -Licensed under MIT license. See [LICENSE](https://raw.githubusercontent.com/RobThree/TwoFactorAuth/master/LICENSE) for details. - -[Logo / icon](http://www.iconmay.com/Simple/Travel_and_Tourism_Part_2/luggage_lock_safety_baggage_keys_cylinder_lock_hotel_travel_tourism_luggage_lock_icon_465) under CC0 1.0 Universal (CC0 1.0) Public Domain Dedication ([Archived page](http://riii.nl/tm7ap)) diff --git a/vendor/robthree/twofactorauth/composer.json b/vendor/robthree/twofactorauth/composer.json deleted file mode 100644 index 50f8b86..0000000 --- a/vendor/robthree/twofactorauth/composer.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "name": "robthree/twofactorauth", - "description": "Two Factor Authentication", - "version": "1.7.0", - "type": "library", - "keywords": [ "Authentication", "Two Factor Authentication", "Multi Factor Authentication", "TFA", "MFA", "PHP", "Authenticator", "Authy" ], - "homepage": "https://github.com/RobThree/TwoFactorAuth", - "license": "MIT", - "authors": [ - { - "name": "Rob Janssen", - "homepage": "http://robiii.me", - "role": "Developer" - } - ], - "support": { - "issues": "https://github.com/RobThree/TwoFactorAuth/issues", - "source": "https://github.com/RobThree/TwoFactorAuth" - }, - "require": { - "php": ">=5.6.0" - }, - "require-dev": { - "phpunit/phpunit": "@stable" - }, - "autoload": { - "psr-4": { - "RobThree\\Auth\\": "lib" - } - }, - "autoload-dev": { - "psr-4": { - "RobThree\\Auth\\Test\\": "tests" - } - } -} diff --git a/vendor/robthree/twofactorauth/composer.lock b/vendor/robthree/twofactorauth/composer.lock deleted file mode 100644 index 63df937..0000000 --- a/vendor/robthree/twofactorauth/composer.lock +++ /dev/null @@ -1,980 +0,0 @@ -{ - "_readme": [ - "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", - "This file is @generated automatically" - ], - "content-hash": "9647de85f54ba6db237f5ff42ff85a1f", - "packages": [], - "packages-dev": [ - { - "name": "doctrine/instantiator", - "version": "1.0.5", - "source": { - "type": "git", - "url": "https://github.com/doctrine/instantiator.git", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", - "shasum": "" - }, - "require": { - "php": ">=5.3,<8.0-DEV" - }, - "require-dev": { - "athletic/athletic": "~0.1.8", - "ext-pdo": "*", - "ext-phar": "*", - "phpunit/phpunit": "~4.0", - "squizlabs/php_codesniffer": "~2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "homepage": "http://ocramius.github.com/" - } - ], - "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://github.com/doctrine/instantiator", - "keywords": [ - "constructor", - "instantiate" - ], - "time": "2015-06-14T21:17:01+00:00" - }, - { - "name": "phpdocumentor/reflection-docblock", - "version": "2.0.4", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d68dbdc53dc358a816f00b300704702b2eaff7b8", - "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.0" - }, - "suggest": { - "dflydev/markdown": "~1.0", - "erusev/parsedown": "~1.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "psr-0": { - "phpDocumentor": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "mike.vanriel@naenius.com" - } - ], - "time": "2015-02-03T12:10:50+00:00" - }, - { - "name": "phpspec/prophecy", - "version": "v1.6.2", - "source": { - "type": "git", - "url": "https://github.com/phpspec/prophecy.git", - "reference": "6c52c2722f8460122f96f86346600e1077ce22cb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/6c52c2722f8460122f96f86346600e1077ce22cb", - "reference": "6c52c2722f8460122f96f86346600e1077ce22cb", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.0.2", - "php": "^5.3|^7.0", - "phpdocumentor/reflection-docblock": "^2.0|^3.0.2", - "sebastian/comparator": "^1.1", - "sebastian/recursion-context": "^1.0|^2.0" - }, - "require-dev": { - "phpspec/phpspec": "^2.0", - "phpunit/phpunit": "^4.8 || ^5.6.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.6.x-dev" - } - }, - "autoload": { - "psr-0": { - "Prophecy\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - }, - { - "name": "Marcello Duarte", - "email": "marcello.duarte@gmail.com" - } - ], - "description": "Highly opinionated mocking framework for PHP 5.3+", - "homepage": "https://github.com/phpspec/prophecy", - "keywords": [ - "Double", - "Dummy", - "fake", - "mock", - "spy", - "stub" - ], - "time": "2016-11-21T14:58:47+00:00" - }, - { - "name": "phpunit/php-code-coverage", - "version": "2.2.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979", - "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "phpunit/php-file-iterator": "~1.3", - "phpunit/php-text-template": "~1.2", - "phpunit/php-token-stream": "~1.3", - "sebastian/environment": "^1.3.2", - "sebastian/version": "~1.0" - }, - "require-dev": { - "ext-xdebug": ">=2.1.4", - "phpunit/phpunit": "~4" - }, - "suggest": { - "ext-dom": "*", - "ext-xdebug": ">=2.2.1", - "ext-xmlwriter": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.2.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", - "homepage": "https://github.com/sebastianbergmann/php-code-coverage", - "keywords": [ - "coverage", - "testing", - "xunit" - ], - "time": "2015-10-06T15:47:00+00:00" - }, - { - "name": "phpunit/php-file-iterator", - "version": "1.4.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5", - "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", - "keywords": [ - "filesystem", - "iterator" - ], - "time": "2016-10-03T07:40:28+00:00" - }, - { - "name": "phpunit/php-text-template", - "version": "1.2.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Simple template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", - "keywords": [ - "template" - ], - "time": "2015-06-21T13:50:34+00:00" - }, - { - "name": "phpunit/php-timer", - "version": "1.0.8", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/38e9124049cf1a164f1e4537caf19c99bf1eb260", - "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4|~5" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Utility class for timing", - "homepage": "https://github.com/sebastianbergmann/php-timer/", - "keywords": [ - "timer" - ], - "time": "2016-05-12T18:03:57+00:00" - }, - { - "name": "phpunit/php-token-stream", - "version": "1.4.9", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "3b402f65a4cc90abf6e1104e388b896ce209631b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3b402f65a4cc90abf6e1104e388b896ce209631b", - "reference": "3b402f65a4cc90abf6e1104e388b896ce209631b", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.2" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Wrapper around PHP's tokenizer extension.", - "homepage": "https://github.com/sebastianbergmann/php-token-stream/", - "keywords": [ - "tokenizer" - ], - "time": "2016-11-15T14:06:22+00:00" - }, - { - "name": "phpunit/phpunit", - "version": "4.8.35", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "791b1a67c25af50e230f841ee7a9c6eba507dc87" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/791b1a67c25af50e230f841ee7a9c6eba507dc87", - "reference": "791b1a67c25af50e230f841ee7a9c6eba507dc87", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-json": "*", - "ext-pcre": "*", - "ext-reflection": "*", - "ext-spl": "*", - "php": ">=5.3.3", - "phpspec/prophecy": "^1.3.1", - "phpunit/php-code-coverage": "~2.1", - "phpunit/php-file-iterator": "~1.4", - "phpunit/php-text-template": "~1.2", - "phpunit/php-timer": "^1.0.6", - "phpunit/phpunit-mock-objects": "~2.3", - "sebastian/comparator": "~1.2.2", - "sebastian/diff": "~1.2", - "sebastian/environment": "~1.3", - "sebastian/exporter": "~1.2", - "sebastian/global-state": "~1.0", - "sebastian/version": "~1.0", - "symfony/yaml": "~2.1|~3.0" - }, - "suggest": { - "phpunit/php-invoker": "~1.1" - }, - "bin": [ - "phpunit" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.8.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "The PHP Unit Testing framework.", - "homepage": "https://phpunit.de/", - "keywords": [ - "phpunit", - "testing", - "xunit" - ], - "time": "2017-02-06T05:18:07+00:00" - }, - { - "name": "phpunit/phpunit-mock-objects", - "version": "2.3.8", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983", - "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.0.2", - "php": ">=5.3.3", - "phpunit/php-text-template": "~1.2", - "sebastian/exporter": "~1.2" - }, - "require-dev": { - "phpunit/phpunit": "~4.4" - }, - "suggest": { - "ext-soap": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Mock Object library for PHPUnit", - "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", - "keywords": [ - "mock", - "xunit" - ], - "time": "2015-10-02T06:51:40+00:00" - }, - { - "name": "sebastian/comparator", - "version": "1.2.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", - "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "sebastian/diff": "~1.2", - "sebastian/exporter": "~1.2 || ~2.0" - }, - "require-dev": { - "phpunit/phpunit": "~4.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides the functionality to compare PHP values for equality", - "homepage": "http://www.github.com/sebastianbergmann/comparator", - "keywords": [ - "comparator", - "compare", - "equality" - ], - "time": "2017-01-29T09:50:25+00:00" - }, - { - "name": "sebastian/diff", - "version": "1.4.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e", - "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.8" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Diff implementation", - "homepage": "https://github.com/sebastianbergmann/diff", - "keywords": [ - "diff" - ], - "time": "2015-12-08T07:14:41+00:00" - }, - { - "name": "sebastian/environment", - "version": "1.3.8", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/be2c607e43ce4c89ecd60e75c6a85c126e754aea", - "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea", - "shasum": "" - }, - "require": { - "php": "^5.3.3 || ^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.8 || ^5.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides functionality to handle HHVM/PHP environments", - "homepage": "http://www.github.com/sebastianbergmann/environment", - "keywords": [ - "Xdebug", - "environment", - "hhvm" - ], - "time": "2016-08-18T05:49:44+00:00" - }, - { - "name": "sebastian/exporter", - "version": "1.2.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4", - "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "sebastian/recursion-context": "~1.0" - }, - "require-dev": { - "ext-mbstring": "*", - "phpunit/phpunit": "~4.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - } - ], - "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "http://www.github.com/sebastianbergmann/exporter", - "keywords": [ - "export", - "exporter" - ], - "time": "2016-06-17T09:04:28+00:00" - }, - { - "name": "sebastian/global-state", - "version": "1.1.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", - "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.2" - }, - "suggest": { - "ext-uopz": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Snapshotting of global state", - "homepage": "http://www.github.com/sebastianbergmann/global-state", - "keywords": [ - "global state" - ], - "time": "2015-10-12T03:26:01+00:00" - }, - { - "name": "sebastian/recursion-context", - "version": "1.0.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "913401df809e99e4f47b27cdd781f4a258d58791" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/913401df809e99e4f47b27cdd781f4a258d58791", - "reference": "913401df809e99e4f47b27cdd781f4a258d58791", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - } - ], - "description": "Provides functionality to recursively process PHP variables", - "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2015-11-11T19:50:13+00:00" - }, - { - "name": "sebastian/version", - "version": "1.0.6", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/version.git", - "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", - "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", - "shasum": "" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library that helps with managing the version number of Git-hosted PHP projects", - "homepage": "https://github.com/sebastianbergmann/version", - "time": "2015-06-21T13:59:46+00:00" - }, - { - "name": "symfony/yaml", - "version": "v2.8.17", - "source": { - "type": "git", - "url": "https://github.com/symfony/yaml.git", - "reference": "322a8c2dfbca15ad6b1b27e182899f98ec0e0153" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/322a8c2dfbca15ad6b1b27e182899f98ec0e0153", - "reference": "322a8c2dfbca15ad6b1b27e182899f98ec0e0153", - "shasum": "" - }, - "require": { - "php": ">=5.3.9" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.8-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Yaml\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony Yaml Component", - "homepage": "https://symfony.com", - "time": "2017-01-21T16:40:50+00:00" - } - ], - "aliases": [], - "minimum-stability": "stable", - "stability-flags": { - "phpunit/phpunit": 0 - }, - "prefer-stable": false, - "prefer-lowest": false, - "platform": { - "php": ">=5.3.0" - }, - "platform-dev": [] -} diff --git a/vendor/robthree/twofactorauth/index.php b/vendor/robthree/twofactorauth/index.php index df24d3e..fa24a5a 100644 --- a/vendor/robthree/twofactorauth/index.php +++ b/vendor/robthree/twofactorauth/index.php @@ -1,35 +1,22 @@ - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. */ -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); +\header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); +\header('Last-Modified: ' . \gmdate('D, d M Y H:i:s') . ' GMT'); + +\header('Cache-Control: no-store, no-cache, must-revalidate'); +\header('Cache-Control: post-check=0, pre-check=0', false); +\header('Pragma: no-cache'); -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); +\header('Location: ../'); -header("Location: ../"); exit; diff --git a/vendor/robthree/twofactorauth/lib/Providers/Qr/index.php b/vendor/robthree/twofactorauth/lib/Providers/Qr/index.php index df24d3e..fa24a5a 100644 --- a/vendor/robthree/twofactorauth/lib/Providers/Qr/index.php +++ b/vendor/robthree/twofactorauth/lib/Providers/Qr/index.php @@ -1,35 +1,22 @@ - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. */ -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); +\header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); +\header('Last-Modified: ' . \gmdate('D, d M Y H:i:s') . ' GMT'); + +\header('Cache-Control: no-store, no-cache, must-revalidate'); +\header('Cache-Control: post-check=0, pre-check=0', false); +\header('Pragma: no-cache'); -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); +\header('Location: ../'); -header("Location: ../"); exit; diff --git a/vendor/robthree/twofactorauth/lib/Providers/Rng/index.php b/vendor/robthree/twofactorauth/lib/Providers/Rng/index.php index df24d3e..fa24a5a 100644 --- a/vendor/robthree/twofactorauth/lib/Providers/Rng/index.php +++ b/vendor/robthree/twofactorauth/lib/Providers/Rng/index.php @@ -1,35 +1,22 @@ - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. */ -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); +\header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); +\header('Last-Modified: ' . \gmdate('D, d M Y H:i:s') . ' GMT'); + +\header('Cache-Control: no-store, no-cache, must-revalidate'); +\header('Cache-Control: post-check=0, pre-check=0', false); +\header('Pragma: no-cache'); -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); +\header('Location: ../'); -header("Location: ../"); exit; diff --git a/vendor/robthree/twofactorauth/lib/Providers/Time/index.php b/vendor/robthree/twofactorauth/lib/Providers/Time/index.php index df24d3e..fa24a5a 100644 --- a/vendor/robthree/twofactorauth/lib/Providers/Time/index.php +++ b/vendor/robthree/twofactorauth/lib/Providers/Time/index.php @@ -1,35 +1,22 @@ - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. */ -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); +\header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); +\header('Last-Modified: ' . \gmdate('D, d M Y H:i:s') . ' GMT'); + +\header('Cache-Control: no-store, no-cache, must-revalidate'); +\header('Cache-Control: post-check=0, pre-check=0', false); +\header('Pragma: no-cache'); -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); +\header('Location: ../'); -header("Location: ../"); exit; diff --git a/vendor/robthree/twofactorauth/lib/Providers/index.php b/vendor/robthree/twofactorauth/lib/Providers/index.php index df24d3e..fa24a5a 100644 --- a/vendor/robthree/twofactorauth/lib/Providers/index.php +++ b/vendor/robthree/twofactorauth/lib/Providers/index.php @@ -1,35 +1,22 @@ - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. */ -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); +\header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); +\header('Last-Modified: ' . \gmdate('D, d M Y H:i:s') . ' GMT'); + +\header('Cache-Control: no-store, no-cache, must-revalidate'); +\header('Cache-Control: post-check=0, pre-check=0', false); +\header('Pragma: no-cache'); -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); +\header('Location: ../'); -header("Location: ../"); exit; diff --git a/vendor/robthree/twofactorauth/lib/index.php b/vendor/robthree/twofactorauth/lib/index.php index df24d3e..fa24a5a 100644 --- a/vendor/robthree/twofactorauth/lib/index.php +++ b/vendor/robthree/twofactorauth/lib/index.php @@ -1,35 +1,22 @@ - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. */ -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); +\header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); +\header('Last-Modified: ' . \gmdate('D, d M Y H:i:s') . ' GMT'); + +\header('Cache-Control: no-store, no-cache, must-revalidate'); +\header('Cache-Control: post-check=0, pre-check=0', false); +\header('Pragma: no-cache'); -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); +\header('Location: ../'); -header("Location: ../"); exit; diff --git a/vendor/robthree/twofactorauth/logo.png b/vendor/robthree/twofactorauth/logo.png deleted file mode 100644 index 65af9b2..0000000 Binary files a/vendor/robthree/twofactorauth/logo.png and /dev/null differ diff --git a/vendor/robthree/twofactorauth/multifactorauthforeveryone.png b/vendor/robthree/twofactorauth/multifactorauthforeveryone.png deleted file mode 100644 index 086bd92..0000000 Binary files a/vendor/robthree/twofactorauth/multifactorauthforeveryone.png and /dev/null differ diff --git a/vendor/symfony/finder/Comparator/Comparator.php b/vendor/symfony/finder/Comparator/Comparator.php deleted file mode 100644 index 6aee21c..0000000 --- a/vendor/symfony/finder/Comparator/Comparator.php +++ /dev/null @@ -1,98 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Finder\Comparator; - -/** - * Comparator. - * - * @author Fabien Potencier - */ -class Comparator -{ - private $target; - private $operator = '=='; - - /** - * Gets the target value. - * - * @return string The target value - */ - public function getTarget() - { - return $this->target; - } - - /** - * Sets the target value. - * - * @param string $target The target value - */ - public function setTarget($target) - { - $this->target = $target; - } - - /** - * Gets the comparison operator. - * - * @return string The operator - */ - public function getOperator() - { - return $this->operator; - } - - /** - * Sets the comparison operator. - * - * @param string $operator A valid operator - * - * @throws \InvalidArgumentException - */ - public function setOperator($operator) - { - if (!$operator) { - $operator = '=='; - } - - if (!\in_array($operator, ['>', '<', '>=', '<=', '==', '!='])) { - throw new \InvalidArgumentException(sprintf('Invalid operator "%s".', $operator)); - } - - $this->operator = $operator; - } - - /** - * Tests against the target. - * - * @param mixed $test A test value - * - * @return bool - */ - public function test($test) - { - switch ($this->operator) { - case '>': - return $test > $this->target; - case '>=': - return $test >= $this->target; - case '<': - return $test < $this->target; - case '<=': - return $test <= $this->target; - case '!=': - return $test != $this->target; - } - - return $test == $this->target; - } -} diff --git a/vendor/symfony/finder/Comparator/DateComparator.php b/vendor/symfony/finder/Comparator/DateComparator.php deleted file mode 100644 index 3de43ef..0000000 --- a/vendor/symfony/finder/Comparator/DateComparator.php +++ /dev/null @@ -1,51 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Finder\Comparator; - -/** - * DateCompare compiles date comparisons. - * - * @author Fabien Potencier - */ -class DateComparator extends Comparator -{ - /** - * @param string $test A comparison string - * - * @throws \InvalidArgumentException If the test is not understood - */ - public function __construct($test) - { - if (!preg_match('#^\s*(==|!=|[<>]=?|after|since|before|until)?\s*(.+?)\s*$#i', $test, $matches)) { - throw new \InvalidArgumentException(sprintf('Don\'t understand "%s" as a date test.', $test)); - } - - try { - $date = new \DateTime($matches[2]); - $target = $date->format('U'); - } catch (\Exception $e) { - throw new \InvalidArgumentException(sprintf('"%s" is not a valid date.', $matches[2])); - } - - $operator = isset($matches[1]) ? $matches[1] : '=='; - if ('since' === $operator || 'after' === $operator) { - $operator = '>'; - } - - if ('until' === $operator || 'before' === $operator) { - $operator = '<'; - } - - $this->setOperator($operator); - $this->setTarget($target); - } -} diff --git a/vendor/symfony/finder/Comparator/NumberComparator.php b/vendor/symfony/finder/Comparator/NumberComparator.php deleted file mode 100644 index f62c0e5..0000000 --- a/vendor/symfony/finder/Comparator/NumberComparator.php +++ /dev/null @@ -1,79 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Finder\Comparator; - -/** - * NumberComparator compiles a simple comparison to an anonymous - * subroutine, which you can call with a value to be tested again. - * - * Now this would be very pointless, if NumberCompare didn't understand - * magnitudes. - * - * The target value may use magnitudes of kilobytes (k, ki), - * megabytes (m, mi), or gigabytes (g, gi). Those suffixed - * with an i use the appropriate 2**n version in accordance with the - * IEC standard: http://physics.nist.gov/cuu/Units/binary.html - * - * Based on the Perl Number::Compare module. - * - * @author Fabien Potencier PHP port - * @author Richard Clamp Perl version - * @copyright 2004-2005 Fabien Potencier - * @copyright 2002 Richard Clamp - * - * @see http://physics.nist.gov/cuu/Units/binary.html - */ -class NumberComparator extends Comparator -{ - /** - * @param string|int $test A comparison string or an integer - * - * @throws \InvalidArgumentException If the test is not understood - */ - public function __construct($test) - { - if (!preg_match('#^\s*(==|!=|[<>]=?)?\s*([0-9\.]+)\s*([kmg]i?)?\s*$#i', $test, $matches)) { - throw new \InvalidArgumentException(sprintf('Don\'t understand "%s" as a number test.', $test)); - } - - $target = $matches[2]; - if (!is_numeric($target)) { - throw new \InvalidArgumentException(sprintf('Invalid number "%s".', $target)); - } - if (isset($matches[3])) { - // magnitude - switch (strtolower($matches[3])) { - case 'k': - $target *= 1000; - break; - case 'ki': - $target *= 1024; - break; - case 'm': - $target *= 1000000; - break; - case 'mi': - $target *= 1024 * 1024; - break; - case 'g': - $target *= 1000000000; - break; - case 'gi': - $target *= 1024 * 1024 * 1024; - break; - } - } - - $this->setTarget($target); - $this->setOperator(isset($matches[1]) ? $matches[1] : '=='); - } -} diff --git a/vendor/symfony/finder/Comparator/index.php b/vendor/symfony/finder/Comparator/index.php deleted file mode 100644 index df24d3e..0000000 --- a/vendor/symfony/finder/Comparator/index.php +++ /dev/null @@ -1,35 +0,0 @@ - - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA - */ - -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); - -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); - -header("Location: ../"); -exit; diff --git a/vendor/symfony/finder/Exception/AccessDeniedException.php b/vendor/symfony/finder/Exception/AccessDeniedException.php deleted file mode 100644 index ee195ea..0000000 --- a/vendor/symfony/finder/Exception/AccessDeniedException.php +++ /dev/null @@ -1,19 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Finder\Exception; - -/** - * @author Jean-François Simon - */ -class AccessDeniedException extends \UnexpectedValueException -{ -} diff --git a/vendor/symfony/finder/Exception/ExceptionInterface.php b/vendor/symfony/finder/Exception/ExceptionInterface.php deleted file mode 100644 index 161e968..0000000 --- a/vendor/symfony/finder/Exception/ExceptionInterface.php +++ /dev/null @@ -1,25 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Finder\Exception; - -/** - * @author Jean-François Simon - * - * @deprecated since 3.3, to be removed in 4.0. - */ -interface ExceptionInterface -{ - /** - * @return \Symfony\Component\Finder\Adapter\AdapterInterface - */ - public function getAdapter(); -} diff --git a/vendor/symfony/finder/Exception/index.php b/vendor/symfony/finder/Exception/index.php deleted file mode 100644 index df24d3e..0000000 --- a/vendor/symfony/finder/Exception/index.php +++ /dev/null @@ -1,35 +0,0 @@ - - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA - */ - -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); - -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); - -header("Location: ../"); -exit; diff --git a/vendor/symfony/finder/Finder.php b/vendor/symfony/finder/Finder.php deleted file mode 100644 index 33a76cc..0000000 --- a/vendor/symfony/finder/Finder.php +++ /dev/null @@ -1,759 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Finder; - -use Symfony\Component\Finder\Comparator\DateComparator; -use Symfony\Component\Finder\Comparator\NumberComparator; -use Symfony\Component\Finder\Iterator\CustomFilterIterator; -use Symfony\Component\Finder\Iterator\DateRangeFilterIterator; -use Symfony\Component\Finder\Iterator\DepthRangeFilterIterator; -use Symfony\Component\Finder\Iterator\ExcludeDirectoryFilterIterator; -use Symfony\Component\Finder\Iterator\FilecontentFilterIterator; -use Symfony\Component\Finder\Iterator\FilenameFilterIterator; -use Symfony\Component\Finder\Iterator\SizeRangeFilterIterator; -use Symfony\Component\Finder\Iterator\SortableIterator; - -/** - * Finder allows to build rules to find files and directories. - * - * It is a thin wrapper around several specialized iterator classes. - * - * All rules may be invoked several times. - * - * All methods return the current Finder object to allow chaining: - * - * $finder = Finder::create()->files()->name('*.php')->in(__DIR__); - * - * @author Fabien Potencier - */ -class Finder implements \IteratorAggregate, \Countable -{ - const IGNORE_VCS_FILES = 1; - const IGNORE_DOT_FILES = 2; - - private $mode = 0; - private $names = []; - private $notNames = []; - private $exclude = []; - private $filters = []; - private $depths = []; - private $sizes = []; - private $followLinks = false; - private $sort = false; - private $ignore = 0; - private $dirs = []; - private $dates = []; - private $iterators = []; - private $contains = []; - private $notContains = []; - private $paths = []; - private $notPaths = []; - private $ignoreUnreadableDirs = false; - - private static $vcsPatterns = ['.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg']; - - public function __construct() - { - $this->ignore = static::IGNORE_VCS_FILES | static::IGNORE_DOT_FILES; - } - - /** - * Creates a new Finder. - * - * @return static - */ - public static function create() - { - return new static(); - } - - /** - * Restricts the matching to directories only. - * - * @return $this - */ - public function directories() - { - $this->mode = Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES; - - return $this; - } - - /** - * Restricts the matching to files only. - * - * @return $this - */ - public function files() - { - $this->mode = Iterator\FileTypeFilterIterator::ONLY_FILES; - - return $this; - } - - /** - * Adds tests for the directory depth. - * - * Usage: - * - * $finder->depth('> 1') // the Finder will start matching at level 1. - * $finder->depth('< 3') // the Finder will descend at most 3 levels of directories below the starting point. - * - * @param string|int $level The depth level expression - * - * @return $this - * - * @see DepthRangeFilterIterator - * @see NumberComparator - */ - public function depth($level) - { - $this->depths[] = new Comparator\NumberComparator($level); - - return $this; - } - - /** - * Adds tests for file dates (last modified). - * - * The date must be something that strtotime() is able to parse: - * - * $finder->date('since yesterday'); - * $finder->date('until 2 days ago'); - * $finder->date('> now - 2 hours'); - * $finder->date('>= 2005-10-15'); - * - * @param string $date A date range string - * - * @return $this - * - * @see strtotime - * @see DateRangeFilterIterator - * @see DateComparator - */ - public function date($date) - { - $this->dates[] = new Comparator\DateComparator($date); - - return $this; - } - - /** - * Adds rules that files must match. - * - * You can use patterns (delimited with / sign), globs or simple strings. - * - * $finder->name('*.php') - * $finder->name('/\.php$/') // same as above - * $finder->name('test.php') - * - * @param string $pattern A pattern (a regexp, a glob, or a string) - * - * @return $this - * - * @see FilenameFilterIterator - */ - public function name($pattern) - { - $this->names[] = $pattern; - - return $this; - } - - /** - * Adds rules that files must not match. - * - * @param string $pattern A pattern (a regexp, a glob, or a string) - * - * @return $this - * - * @see FilenameFilterIterator - */ - public function notName($pattern) - { - $this->notNames[] = $pattern; - - return $this; - } - - /** - * Adds tests that file contents must match. - * - * Strings or PCRE patterns can be used: - * - * $finder->contains('Lorem ipsum') - * $finder->contains('/Lorem ipsum/i') - * - * @param string $pattern A pattern (string or regexp) - * - * @return $this - * - * @see FilecontentFilterIterator - */ - public function contains($pattern) - { - $this->contains[] = $pattern; - - return $this; - } - - /** - * Adds tests that file contents must not match. - * - * Strings or PCRE patterns can be used: - * - * $finder->notContains('Lorem ipsum') - * $finder->notContains('/Lorem ipsum/i') - * - * @param string $pattern A pattern (string or regexp) - * - * @return $this - * - * @see FilecontentFilterIterator - */ - public function notContains($pattern) - { - $this->notContains[] = $pattern; - - return $this; - } - - /** - * Adds rules that filenames must match. - * - * You can use patterns (delimited with / sign) or simple strings. - * - * $finder->path('some/special/dir') - * $finder->path('/some\/special\/dir/') // same as above - * - * Use only / as dirname separator. - * - * @param string $pattern A pattern (a regexp or a string) - * - * @return $this - * - * @see FilenameFilterIterator - */ - public function path($pattern) - { - $this->paths[] = $pattern; - - return $this; - } - - /** - * Adds rules that filenames must not match. - * - * You can use patterns (delimited with / sign) or simple strings. - * - * $finder->notPath('some/special/dir') - * $finder->notPath('/some\/special\/dir/') // same as above - * - * Use only / as dirname separator. - * - * @param string $pattern A pattern (a regexp or a string) - * - * @return $this - * - * @see FilenameFilterIterator - */ - public function notPath($pattern) - { - $this->notPaths[] = $pattern; - - return $this; - } - - /** - * Adds tests for file sizes. - * - * $finder->size('> 10K'); - * $finder->size('<= 1Ki'); - * $finder->size(4); - * - * @param string|int $size A size range string or an integer - * - * @return $this - * - * @see SizeRangeFilterIterator - * @see NumberComparator - */ - public function size($size) - { - $this->sizes[] = new Comparator\NumberComparator($size); - - return $this; - } - - /** - * Excludes directories. - * - * Directories passed as argument must be relative to the ones defined with the `in()` method. For example: - * - * $finder->in(__DIR__)->exclude('ruby'); - * - * @param string|array $dirs A directory path or an array of directories - * - * @return $this - * - * @see ExcludeDirectoryFilterIterator - */ - public function exclude($dirs) - { - $this->exclude = array_merge($this->exclude, (array) $dirs); - - return $this; - } - - /** - * Excludes "hidden" directories and files (starting with a dot). - * - * This option is enabled by default. - * - * @param bool $ignoreDotFiles Whether to exclude "hidden" files or not - * - * @return $this - * - * @see ExcludeDirectoryFilterIterator - */ - public function ignoreDotFiles($ignoreDotFiles) - { - if ($ignoreDotFiles) { - $this->ignore |= static::IGNORE_DOT_FILES; - } else { - $this->ignore &= ~static::IGNORE_DOT_FILES; - } - - return $this; - } - - /** - * Forces the finder to ignore version control directories. - * - * This option is enabled by default. - * - * @param bool $ignoreVCS Whether to exclude VCS files or not - * - * @return $this - * - * @see ExcludeDirectoryFilterIterator - */ - public function ignoreVCS($ignoreVCS) - { - if ($ignoreVCS) { - $this->ignore |= static::IGNORE_VCS_FILES; - } else { - $this->ignore &= ~static::IGNORE_VCS_FILES; - } - - return $this; - } - - /** - * Adds VCS patterns. - * - * @see ignoreVCS() - * - * @param string|string[] $pattern VCS patterns to ignore - */ - public static function addVCSPattern($pattern) - { - foreach ((array) $pattern as $p) { - self::$vcsPatterns[] = $p; - } - - self::$vcsPatterns = array_unique(self::$vcsPatterns); - } - - /** - * Sorts files and directories by an anonymous function. - * - * The anonymous function receives two \SplFileInfo instances to compare. - * - * This can be slow as all the matching files and directories must be retrieved for comparison. - * - * @return $this - * - * @see SortableIterator - */ - public function sort(\Closure $closure) - { - $this->sort = $closure; - - return $this; - } - - /** - * Sorts files and directories by name. - * - * This can be slow as all the matching files and directories must be retrieved for comparison. - * - * @return $this - * - * @see SortableIterator - */ - public function sortByName() - { - $this->sort = Iterator\SortableIterator::SORT_BY_NAME; - - return $this; - } - - /** - * Sorts files and directories by type (directories before files), then by name. - * - * This can be slow as all the matching files and directories must be retrieved for comparison. - * - * @return $this - * - * @see SortableIterator - */ - public function sortByType() - { - $this->sort = Iterator\SortableIterator::SORT_BY_TYPE; - - return $this; - } - - /** - * Sorts files and directories by the last accessed time. - * - * This is the time that the file was last accessed, read or written to. - * - * This can be slow as all the matching files and directories must be retrieved for comparison. - * - * @return $this - * - * @see SortableIterator - */ - public function sortByAccessedTime() - { - $this->sort = Iterator\SortableIterator::SORT_BY_ACCESSED_TIME; - - return $this; - } - - /** - * Sorts files and directories by the last inode changed time. - * - * This is the time that the inode information was last modified (permissions, owner, group or other metadata). - * - * On Windows, since inode is not available, changed time is actually the file creation time. - * - * This can be slow as all the matching files and directories must be retrieved for comparison. - * - * @return $this - * - * @see SortableIterator - */ - public function sortByChangedTime() - { - $this->sort = Iterator\SortableIterator::SORT_BY_CHANGED_TIME; - - return $this; - } - - /** - * Sorts files and directories by the last modified time. - * - * This is the last time the actual contents of the file were last modified. - * - * This can be slow as all the matching files and directories must be retrieved for comparison. - * - * @return $this - * - * @see SortableIterator - */ - public function sortByModifiedTime() - { - $this->sort = Iterator\SortableIterator::SORT_BY_MODIFIED_TIME; - - return $this; - } - - /** - * Filters the iterator with an anonymous function. - * - * The anonymous function receives a \SplFileInfo and must return false - * to remove files. - * - * @return $this - * - * @see CustomFilterIterator - */ - public function filter(\Closure $closure) - { - $this->filters[] = $closure; - - return $this; - } - - /** - * Forces the following of symlinks. - * - * @return $this - */ - public function followLinks() - { - $this->followLinks = true; - - return $this; - } - - /** - * Tells finder to ignore unreadable directories. - * - * By default, scanning unreadable directories content throws an AccessDeniedException. - * - * @param bool $ignore - * - * @return $this - */ - public function ignoreUnreadableDirs($ignore = true) - { - $this->ignoreUnreadableDirs = (bool) $ignore; - - return $this; - } - - /** - * Searches files and directories which match defined rules. - * - * @param string|string[] $dirs A directory path or an array of directories - * - * @return $this - * - * @throws \InvalidArgumentException if one of the directories does not exist - */ - public function in($dirs) - { - $resolvedDirs = []; - - foreach ((array) $dirs as $dir) { - if (is_dir($dir)) { - $resolvedDirs[] = $this->normalizeDir($dir); - } elseif ($glob = glob($dir, (\defined('GLOB_BRACE') ? GLOB_BRACE : 0) | GLOB_ONLYDIR | GLOB_NOSORT)) { - sort($glob); - $resolvedDirs = array_merge($resolvedDirs, array_map([$this, 'normalizeDir'], $glob)); - } else { - throw new \InvalidArgumentException(sprintf('The "%s" directory does not exist.', $dir)); - } - } - - $this->dirs = array_merge($this->dirs, $resolvedDirs); - - return $this; - } - - /** - * Returns an Iterator for the current Finder configuration. - * - * This method implements the IteratorAggregate interface. - * - * @return \Iterator|SplFileInfo[] An iterator - * - * @throws \LogicException if the in() method has not been called - */ - public function getIterator() - { - if (0 === \count($this->dirs) && 0 === \count($this->iterators)) { - throw new \LogicException('You must call one of in() or append() methods before iterating over a Finder.'); - } - - if (1 === \count($this->dirs) && 0 === \count($this->iterators)) { - return $this->searchInDirectory($this->dirs[0]); - } - - $iterator = new \AppendIterator(); - foreach ($this->dirs as $dir) { - $iterator->append($this->searchInDirectory($dir)); - } - - foreach ($this->iterators as $it) { - $iterator->append($it); - } - - return $iterator; - } - - /** - * Appends an existing set of files/directories to the finder. - * - * The set can be another Finder, an Iterator, an IteratorAggregate, or even a plain array. - * - * @param iterable $iterator - * - * @return $this - * - * @throws \InvalidArgumentException when the given argument is not iterable - */ - public function append($iterator) - { - if ($iterator instanceof \IteratorAggregate) { - $this->iterators[] = $iterator->getIterator(); - } elseif ($iterator instanceof \Iterator) { - $this->iterators[] = $iterator; - } elseif ($iterator instanceof \Traversable || \is_array($iterator)) { - $it = new \ArrayIterator(); - foreach ($iterator as $file) { - $it->append($file instanceof \SplFileInfo ? $file : new \SplFileInfo($file)); - } - $this->iterators[] = $it; - } else { - throw new \InvalidArgumentException('Finder::append() method wrong argument type.'); - } - - return $this; - } - - /** - * Check if the any results were found. - * - * @return bool - */ - public function hasResults() - { - foreach ($this->getIterator() as $_) { - return true; - } - - return false; - } - - /** - * Counts all the results collected by the iterators. - * - * @return int - */ - public function count() - { - return iterator_count($this->getIterator()); - } - - /** - * @param string $dir - * - * @return \Iterator - */ - private function searchInDirectory($dir) - { - $exclude = $this->exclude; - $notPaths = $this->notPaths; - - if (static::IGNORE_VCS_FILES === (static::IGNORE_VCS_FILES & $this->ignore)) { - $exclude = array_merge($exclude, self::$vcsPatterns); - } - - if (static::IGNORE_DOT_FILES === (static::IGNORE_DOT_FILES & $this->ignore)) { - $notPaths[] = '#(^|/)\..+(/|$)#'; - } - - $minDepth = 0; - $maxDepth = PHP_INT_MAX; - - foreach ($this->depths as $comparator) { - switch ($comparator->getOperator()) { - case '>': - $minDepth = $comparator->getTarget() + 1; - break; - case '>=': - $minDepth = $comparator->getTarget(); - break; - case '<': - $maxDepth = $comparator->getTarget() - 1; - break; - case '<=': - $maxDepth = $comparator->getTarget(); - break; - default: - $minDepth = $maxDepth = $comparator->getTarget(); - } - } - - $flags = \RecursiveDirectoryIterator::SKIP_DOTS; - - if ($this->followLinks) { - $flags |= \RecursiveDirectoryIterator::FOLLOW_SYMLINKS; - } - - $iterator = new Iterator\RecursiveDirectoryIterator($dir, $flags, $this->ignoreUnreadableDirs); - - if ($exclude) { - $iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $exclude); - } - - $iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::SELF_FIRST); - - if ($minDepth > 0 || $maxDepth < PHP_INT_MAX) { - $iterator = new Iterator\DepthRangeFilterIterator($iterator, $minDepth, $maxDepth); - } - - if ($this->mode) { - $iterator = new Iterator\FileTypeFilterIterator($iterator, $this->mode); - } - - if ($this->names || $this->notNames) { - $iterator = new Iterator\FilenameFilterIterator($iterator, $this->names, $this->notNames); - } - - if ($this->contains || $this->notContains) { - $iterator = new Iterator\FilecontentFilterIterator($iterator, $this->contains, $this->notContains); - } - - if ($this->sizes) { - $iterator = new Iterator\SizeRangeFilterIterator($iterator, $this->sizes); - } - - if ($this->dates) { - $iterator = new Iterator\DateRangeFilterIterator($iterator, $this->dates); - } - - if ($this->filters) { - $iterator = new Iterator\CustomFilterIterator($iterator, $this->filters); - } - - if ($this->paths || $notPaths) { - $iterator = new Iterator\PathFilterIterator($iterator, $this->paths, $notPaths); - } - - if ($this->sort) { - $iteratorAggregate = new Iterator\SortableIterator($iterator, $this->sort); - $iterator = $iteratorAggregate->getIterator(); - } - - return $iterator; - } - - /** - * Normalizes given directory names by removing trailing slashes. - * - * Excluding: (s)ftp:// or ssh2.(s)ftp:// wrapper - * - * @param string $dir - * - * @return string - */ - private function normalizeDir($dir) - { - if ('/' === $dir) { - return $dir; - } - - $dir = rtrim($dir, '/'.\DIRECTORY_SEPARATOR); - - if (preg_match('#^(ssh2\.)?s?ftp://#', $dir)) { - $dir .= '/'; - } - - return $dir; - } -} diff --git a/vendor/symfony/finder/Glob.php b/vendor/symfony/finder/Glob.php deleted file mode 100644 index ea76d51..0000000 --- a/vendor/symfony/finder/Glob.php +++ /dev/null @@ -1,116 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Finder; - -/** - * Glob matches globbing patterns against text. - * - * if match_glob("foo.*", "foo.bar") echo "matched\n"; - * - * // prints foo.bar and foo.baz - * $regex = glob_to_regex("foo.*"); - * for (['foo.bar', 'foo.baz', 'foo', 'bar'] as $t) - * { - * if (/$regex/) echo "matched: $car\n"; - * } - * - * Glob implements glob(3) style matching that can be used to match - * against text, rather than fetching names from a filesystem. - * - * Based on the Perl Text::Glob module. - * - * @author Fabien Potencier PHP port - * @author Richard Clamp Perl version - * @copyright 2004-2005 Fabien Potencier - * @copyright 2002 Richard Clamp - */ -class Glob -{ - /** - * Returns a regexp which is the equivalent of the glob pattern. - * - * @param string $glob The glob pattern - * @param bool $strictLeadingDot - * @param bool $strictWildcardSlash - * @param string $delimiter Optional delimiter - * - * @return string regex The regexp - */ - public static function toRegex($glob, $strictLeadingDot = true, $strictWildcardSlash = true, $delimiter = '#') - { - $firstByte = true; - $escaping = false; - $inCurlies = 0; - $regex = ''; - $sizeGlob = \strlen($glob); - for ($i = 0; $i < $sizeGlob; ++$i) { - $car = $glob[$i]; - if ($firstByte && $strictLeadingDot && '.' !== $car) { - $regex .= '(?=[^\.])'; - } - - $firstByte = '/' === $car; - - if ($firstByte && $strictWildcardSlash && isset($glob[$i + 2]) && '**' === $glob[$i + 1].$glob[$i + 2] && (!isset($glob[$i + 3]) || '/' === $glob[$i + 3])) { - $car = '[^/]++/'; - if (!isset($glob[$i + 3])) { - $car .= '?'; - } - - if ($strictLeadingDot) { - $car = '(?=[^\.])'.$car; - } - - $car = '/(?:'.$car.')*'; - $i += 2 + isset($glob[$i + 3]); - - if ('/' === $delimiter) { - $car = str_replace('/', '\\/', $car); - } - } - - if ($delimiter === $car || '.' === $car || '(' === $car || ')' === $car || '|' === $car || '+' === $car || '^' === $car || '$' === $car) { - $regex .= "\\$car"; - } elseif ('*' === $car) { - $regex .= $escaping ? '\\*' : ($strictWildcardSlash ? '[^/]*' : '.*'); - } elseif ('?' === $car) { - $regex .= $escaping ? '\\?' : ($strictWildcardSlash ? '[^/]' : '.'); - } elseif ('{' === $car) { - $regex .= $escaping ? '\\{' : '('; - if (!$escaping) { - ++$inCurlies; - } - } elseif ('}' === $car && $inCurlies) { - $regex .= $escaping ? '}' : ')'; - if (!$escaping) { - --$inCurlies; - } - } elseif (',' === $car && $inCurlies) { - $regex .= $escaping ? ',' : '|'; - } elseif ('\\' === $car) { - if ($escaping) { - $regex .= '\\\\'; - $escaping = false; - } else { - $escaping = true; - } - - continue; - } else { - $regex .= $car; - } - $escaping = false; - } - - return $delimiter.'^'.$regex.'$'.$delimiter; - } -} diff --git a/vendor/symfony/finder/Iterator/CustomFilterIterator.php b/vendor/symfony/finder/Iterator/CustomFilterIterator.php deleted file mode 100644 index 896f7e9..0000000 --- a/vendor/symfony/finder/Iterator/CustomFilterIterator.php +++ /dev/null @@ -1,61 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Finder\Iterator; - -/** - * CustomFilterIterator filters files by applying anonymous functions. - * - * The anonymous function receives a \SplFileInfo and must return false - * to remove files. - * - * @author Fabien Potencier - */ -class CustomFilterIterator extends FilterIterator -{ - private $filters = []; - - /** - * @param \Iterator $iterator The Iterator to filter - * @param callable[] $filters An array of PHP callbacks - * - * @throws \InvalidArgumentException - */ - public function __construct(\Iterator $iterator, array $filters) - { - foreach ($filters as $filter) { - if (!\is_callable($filter)) { - throw new \InvalidArgumentException('Invalid PHP callback.'); - } - } - $this->filters = $filters; - - parent::__construct($iterator); - } - - /** - * Filters the iterator values. - * - * @return bool true if the value should be kept, false otherwise - */ - public function accept() - { - $fileinfo = $this->current(); - - foreach ($this->filters as $filter) { - if (false === \call_user_func($filter, $fileinfo)) { - return false; - } - } - - return true; - } -} diff --git a/vendor/symfony/finder/Iterator/DateRangeFilterIterator.php b/vendor/symfony/finder/Iterator/DateRangeFilterIterator.php deleted file mode 100644 index 8a47321..0000000 --- a/vendor/symfony/finder/Iterator/DateRangeFilterIterator.php +++ /dev/null @@ -1,58 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Finder\Iterator; - -use Symfony\Component\Finder\Comparator\DateComparator; - -/** - * DateRangeFilterIterator filters out files that are not in the given date range (last modified dates). - * - * @author Fabien Potencier - */ -class DateRangeFilterIterator extends FilterIterator -{ - private $comparators = []; - - /** - * @param \Iterator $iterator The Iterator to filter - * @param DateComparator[] $comparators An array of DateComparator instances - */ - public function __construct(\Iterator $iterator, array $comparators) - { - $this->comparators = $comparators; - - parent::__construct($iterator); - } - - /** - * Filters the iterator values. - * - * @return bool true if the value should be kept, false otherwise - */ - public function accept() - { - $fileinfo = $this->current(); - - if (!file_exists($fileinfo->getPathname())) { - return false; - } - - $filedate = $fileinfo->getMTime(); - foreach ($this->comparators as $compare) { - if (!$compare->test($filedate)) { - return false; - } - } - - return true; - } -} diff --git a/vendor/symfony/finder/Iterator/DepthRangeFilterIterator.php b/vendor/symfony/finder/Iterator/DepthRangeFilterIterator.php deleted file mode 100644 index ce9d3aa..0000000 --- a/vendor/symfony/finder/Iterator/DepthRangeFilterIterator.php +++ /dev/null @@ -1,45 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Finder\Iterator; - -/** - * DepthRangeFilterIterator limits the directory depth. - * - * @author Fabien Potencier - */ -class DepthRangeFilterIterator extends FilterIterator -{ - private $minDepth = 0; - - /** - * @param \RecursiveIteratorIterator $iterator The Iterator to filter - * @param int $minDepth The min depth - * @param int $maxDepth The max depth - */ - public function __construct(\RecursiveIteratorIterator $iterator, $minDepth = 0, $maxDepth = PHP_INT_MAX) - { - $this->minDepth = $minDepth; - $iterator->setMaxDepth(PHP_INT_MAX === $maxDepth ? -1 : $maxDepth); - - parent::__construct($iterator); - } - - /** - * Filters the iterator values. - * - * @return bool true if the value should be kept, false otherwise - */ - public function accept() - { - return $this->getInnerIterator()->getDepth() >= $this->minDepth; - } -} diff --git a/vendor/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php b/vendor/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php deleted file mode 100644 index 60bc4e8..0000000 --- a/vendor/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php +++ /dev/null @@ -1,84 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Finder\Iterator; - -/** - * ExcludeDirectoryFilterIterator filters out directories. - * - * @author Fabien Potencier - */ -class ExcludeDirectoryFilterIterator extends FilterIterator implements \RecursiveIterator -{ - private $iterator; - private $isRecursive; - private $excludedDirs = []; - private $excludedPattern; - - /** - * @param \Iterator $iterator The Iterator to filter - * @param string[] $directories An array of directories to exclude - */ - public function __construct(\Iterator $iterator, array $directories) - { - $this->iterator = $iterator; - $this->isRecursive = $iterator instanceof \RecursiveIterator; - $patterns = []; - foreach ($directories as $directory) { - $directory = rtrim($directory, '/'); - if (!$this->isRecursive || false !== strpos($directory, '/')) { - $patterns[] = preg_quote($directory, '#'); - } else { - $this->excludedDirs[$directory] = true; - } - } - if ($patterns) { - $this->excludedPattern = '#(?:^|/)(?:'.implode('|', $patterns).')(?:/|$)#'; - } - - parent::__construct($iterator); - } - - /** - * Filters the iterator values. - * - * @return bool True if the value should be kept, false otherwise - */ - public function accept() - { - if ($this->isRecursive && isset($this->excludedDirs[$this->getFilename()]) && $this->isDir()) { - return false; - } - - if ($this->excludedPattern) { - $path = $this->isDir() ? $this->current()->getRelativePathname() : $this->current()->getRelativePath(); - $path = str_replace('\\', '/', $path); - - return !preg_match($this->excludedPattern, $path); - } - - return true; - } - - public function hasChildren() - { - return $this->isRecursive && $this->iterator->hasChildren(); - } - - public function getChildren() - { - $children = new self($this->iterator->getChildren(), []); - $children->excludedDirs = $this->excludedDirs; - $children->excludedPattern = $this->excludedPattern; - - return $children; - } -} diff --git a/vendor/symfony/finder/Iterator/FileTypeFilterIterator.php b/vendor/symfony/finder/Iterator/FileTypeFilterIterator.php deleted file mode 100644 index e9811d4..0000000 --- a/vendor/symfony/finder/Iterator/FileTypeFilterIterator.php +++ /dev/null @@ -1,53 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Finder\Iterator; - -/** - * FileTypeFilterIterator only keeps files, directories, or both. - * - * @author Fabien Potencier - */ -class FileTypeFilterIterator extends FilterIterator -{ - const ONLY_FILES = 1; - const ONLY_DIRECTORIES = 2; - - private $mode; - - /** - * @param \Iterator $iterator The Iterator to filter - * @param int $mode The mode (self::ONLY_FILES or self::ONLY_DIRECTORIES) - */ - public function __construct(\Iterator $iterator, $mode) - { - $this->mode = $mode; - - parent::__construct($iterator); - } - - /** - * Filters the iterator values. - * - * @return bool true if the value should be kept, false otherwise - */ - public function accept() - { - $fileinfo = $this->current(); - if (self::ONLY_DIRECTORIES === (self::ONLY_DIRECTORIES & $this->mode) && $fileinfo->isFile()) { - return false; - } elseif (self::ONLY_FILES === (self::ONLY_FILES & $this->mode) && $fileinfo->isDir()) { - return false; - } - - return true; - } -} diff --git a/vendor/symfony/finder/Iterator/FilecontentFilterIterator.php b/vendor/symfony/finder/Iterator/FilecontentFilterIterator.php deleted file mode 100644 index 81594b8..0000000 --- a/vendor/symfony/finder/Iterator/FilecontentFilterIterator.php +++ /dev/null @@ -1,58 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Finder\Iterator; - -/** - * FilecontentFilterIterator filters files by their contents using patterns (regexps or strings). - * - * @author Fabien Potencier - * @author Włodzimierz Gajda - */ -class FilecontentFilterIterator extends MultiplePcreFilterIterator -{ - /** - * Filters the iterator values. - * - * @return bool true if the value should be kept, false otherwise - */ - public function accept() - { - if (!$this->matchRegexps && !$this->noMatchRegexps) { - return true; - } - - $fileinfo = $this->current(); - - if ($fileinfo->isDir() || !$fileinfo->isReadable()) { - return false; - } - - $content = $fileinfo->getContents(); - if (!$content) { - return false; - } - - return $this->isAccepted($content); - } - - /** - * Converts string to regexp if necessary. - * - * @param string $str Pattern: string or regexp - * - * @return string regexp corresponding to a given string or regexp - */ - protected function toRegex($str) - { - return $this->isRegex($str) ? $str : '/'.preg_quote($str, '/').'/'; - } -} diff --git a/vendor/symfony/finder/Iterator/FilenameFilterIterator.php b/vendor/symfony/finder/Iterator/FilenameFilterIterator.php deleted file mode 100644 index e168cd8..0000000 --- a/vendor/symfony/finder/Iterator/FilenameFilterIterator.php +++ /dev/null @@ -1,47 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Finder\Iterator; - -use Symfony\Component\Finder\Glob; - -/** - * FilenameFilterIterator filters files by patterns (a regexp, a glob, or a string). - * - * @author Fabien Potencier - */ -class FilenameFilterIterator extends MultiplePcreFilterIterator -{ - /** - * Filters the iterator values. - * - * @return bool true if the value should be kept, false otherwise - */ - public function accept() - { - return $this->isAccepted($this->current()->getFilename()); - } - - /** - * Converts glob to regexp. - * - * PCRE patterns are left unchanged. - * Glob strings are transformed with Glob::toRegex(). - * - * @param string $str Pattern: glob or regexp - * - * @return string regexp corresponding to a given glob or regexp - */ - protected function toRegex($str) - { - return $this->isRegex($str) ? $str : Glob::toRegex($str); - } -} diff --git a/vendor/symfony/finder/Iterator/FilterIterator.php b/vendor/symfony/finder/Iterator/FilterIterator.php deleted file mode 100644 index c16dd8f..0000000 --- a/vendor/symfony/finder/Iterator/FilterIterator.php +++ /dev/null @@ -1,60 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Finder\Iterator; - -/** - * This iterator just overrides the rewind method in order to correct a PHP bug, - * which existed before version 5.5.23/5.6.7. - * - * @see https://bugs.php.net/68557 - * - * @author Alex Bogomazov - * - * @deprecated since 3.4, to be removed in 4.0. - */ -abstract class FilterIterator extends \FilterIterator -{ - /** - * This is a workaround for the problem with \FilterIterator leaving inner \FilesystemIterator in wrong state after - * rewind in some cases. - * - * @see FilterIterator::rewind() - */ - public function rewind() - { - if (\PHP_VERSION_ID > 50607 || (\PHP_VERSION_ID > 50523 && \PHP_VERSION_ID < 50600)) { - parent::rewind(); - - return; - } - - $iterator = $this; - while ($iterator instanceof \OuterIterator) { - $innerIterator = $iterator->getInnerIterator(); - - if ($innerIterator instanceof RecursiveDirectoryIterator) { - // this condition is necessary for iterators to work properly with non-local filesystems like ftp - if ($innerIterator->isRewindable()) { - $innerIterator->next(); - $innerIterator->rewind(); - } - } elseif ($innerIterator instanceof \FilesystemIterator) { - $innerIterator->next(); - $innerIterator->rewind(); - } - - $iterator = $innerIterator; - } - - parent::rewind(); - } -} diff --git a/vendor/symfony/finder/Iterator/MultiplePcreFilterIterator.php b/vendor/symfony/finder/Iterator/MultiplePcreFilterIterator.php deleted file mode 100644 index ee365a5..0000000 --- a/vendor/symfony/finder/Iterator/MultiplePcreFilterIterator.php +++ /dev/null @@ -1,112 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Finder\Iterator; - -/** - * MultiplePcreFilterIterator filters files using patterns (regexps, globs or strings). - * - * @author Fabien Potencier - */ -abstract class MultiplePcreFilterIterator extends FilterIterator -{ - protected $matchRegexps = []; - protected $noMatchRegexps = []; - - /** - * @param \Iterator $iterator The Iterator to filter - * @param array $matchPatterns An array of patterns that need to match - * @param array $noMatchPatterns An array of patterns that need to not match - */ - public function __construct(\Iterator $iterator, array $matchPatterns, array $noMatchPatterns) - { - foreach ($matchPatterns as $pattern) { - $this->matchRegexps[] = $this->toRegex($pattern); - } - - foreach ($noMatchPatterns as $pattern) { - $this->noMatchRegexps[] = $this->toRegex($pattern); - } - - parent::__construct($iterator); - } - - /** - * Checks whether the string is accepted by the regex filters. - * - * If there is no regexps defined in the class, this method will accept the string. - * Such case can be handled by child classes before calling the method if they want to - * apply a different behavior. - * - * @param string $string The string to be matched against filters - * - * @return bool - */ - protected function isAccepted($string) - { - // should at least not match one rule to exclude - foreach ($this->noMatchRegexps as $regex) { - if (preg_match($regex, $string)) { - return false; - } - } - - // should at least match one rule - if ($this->matchRegexps) { - foreach ($this->matchRegexps as $regex) { - if (preg_match($regex, $string)) { - return true; - } - } - - return false; - } - - // If there is no match rules, the file is accepted - return true; - } - - /** - * Checks whether the string is a regex. - * - * @param string $str - * - * @return bool Whether the given string is a regex - */ - protected function isRegex($str) - { - if (preg_match('/^(.{3,}?)[imsxuADU]*$/', $str, $m)) { - $start = substr($m[1], 0, 1); - $end = substr($m[1], -1); - - if ($start === $end) { - return !preg_match('/[*?[:alnum:] \\\\]/', $start); - } - - foreach ([['{', '}'], ['(', ')'], ['[', ']'], ['<', '>']] as $delimiters) { - if ($start === $delimiters[0] && $end === $delimiters[1]) { - return true; - } - } - } - - return false; - } - - /** - * Converts string into regexp. - * - * @param string $str Pattern - * - * @return string regexp corresponding to a given string - */ - abstract protected function toRegex($str); -} diff --git a/vendor/symfony/finder/Iterator/PathFilterIterator.php b/vendor/symfony/finder/Iterator/PathFilterIterator.php deleted file mode 100644 index 3fda557..0000000 --- a/vendor/symfony/finder/Iterator/PathFilterIterator.php +++ /dev/null @@ -1,56 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Finder\Iterator; - -/** - * PathFilterIterator filters files by path patterns (e.g. some/special/dir). - * - * @author Fabien Potencier - * @author Włodzimierz Gajda - */ -class PathFilterIterator extends MultiplePcreFilterIterator -{ - /** - * Filters the iterator values. - * - * @return bool true if the value should be kept, false otherwise - */ - public function accept() - { - $filename = $this->current()->getRelativePathname(); - - if ('\\' === \DIRECTORY_SEPARATOR) { - $filename = str_replace('\\', '/', $filename); - } - - return $this->isAccepted($filename); - } - - /** - * Converts strings to regexp. - * - * PCRE patterns are left unchanged. - * - * Default conversion: - * 'lorem/ipsum/dolor' ==> 'lorem\/ipsum\/dolor/' - * - * Use only / as directory separator (on Windows also). - * - * @param string $str Pattern: regexp or dirname - * - * @return string regexp corresponding to a given string or regexp - */ - protected function toRegex($str) - { - return $this->isRegex($str) ? $str : '/'.preg_quote($str, '/').'/'; - } -} diff --git a/vendor/symfony/finder/Iterator/RecursiveDirectoryIterator.php b/vendor/symfony/finder/Iterator/RecursiveDirectoryIterator.php deleted file mode 100644 index 63764d4..0000000 --- a/vendor/symfony/finder/Iterator/RecursiveDirectoryIterator.php +++ /dev/null @@ -1,158 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Finder\Iterator; - -use Symfony\Component\Finder\Exception\AccessDeniedException; -use Symfony\Component\Finder\SplFileInfo; - -/** - * Extends the \RecursiveDirectoryIterator to support relative paths. - * - * @author Victor Berchet - */ -class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator -{ - /** - * @var bool - */ - private $ignoreUnreadableDirs; - - /** - * @var bool - */ - private $rewindable; - - // these 3 properties take part of the performance optimization to avoid redoing the same work in all iterations - private $rootPath; - private $subPath; - private $directorySeparator = '/'; - - /** - * @param string $path - * @param int $flags - * @param bool $ignoreUnreadableDirs - * - * @throws \RuntimeException - */ - public function __construct($path, $flags, $ignoreUnreadableDirs = false) - { - if ($flags & (self::CURRENT_AS_PATHNAME | self::CURRENT_AS_SELF)) { - throw new \RuntimeException('This iterator only support returning current as fileinfo.'); - } - - parent::__construct($path, $flags); - $this->ignoreUnreadableDirs = $ignoreUnreadableDirs; - $this->rootPath = $path; - if ('/' !== \DIRECTORY_SEPARATOR && !($flags & self::UNIX_PATHS)) { - $this->directorySeparator = \DIRECTORY_SEPARATOR; - } - } - - /** - * Return an instance of SplFileInfo with support for relative paths. - * - * @return SplFileInfo File information - */ - public function current() - { - // the logic here avoids redoing the same work in all iterations - - if (null === $subPathname = $this->subPath) { - $subPathname = $this->subPath = (string) $this->getSubPath(); - } - if ('' !== $subPathname) { - $subPathname .= $this->directorySeparator; - } - $subPathname .= $this->getFilename(); - - if ('/' !== $basePath = $this->rootPath) { - $basePath .= $this->directorySeparator; - } - - return new SplFileInfo($basePath.$subPathname, $this->subPath, $subPathname); - } - - /** - * @return \RecursiveIterator - * - * @throws AccessDeniedException - */ - public function getChildren() - { - try { - $children = parent::getChildren(); - - if ($children instanceof self) { - // parent method will call the constructor with default arguments, so unreadable dirs won't be ignored anymore - $children->ignoreUnreadableDirs = $this->ignoreUnreadableDirs; - - // performance optimization to avoid redoing the same work in all children - $children->rewindable = &$this->rewindable; - $children->rootPath = $this->rootPath; - } - - return $children; - } catch (\UnexpectedValueException $e) { - if ($this->ignoreUnreadableDirs) { - // If directory is unreadable and finder is set to ignore it, a fake empty content is returned. - return new \RecursiveArrayIterator([]); - } else { - throw new AccessDeniedException($e->getMessage(), $e->getCode(), $e); - } - } - } - - /** - * Do nothing for non rewindable stream. - */ - public function rewind() - { - if (false === $this->isRewindable()) { - return; - } - - // @see https://bugs.php.net/68557 - if (\PHP_VERSION_ID < 50523 || \PHP_VERSION_ID >= 50600 && \PHP_VERSION_ID < 50607) { - parent::next(); - } - - parent::rewind(); - } - - /** - * Checks if the stream is rewindable. - * - * @return bool true when the stream is rewindable, false otherwise - */ - public function isRewindable() - { - if (null !== $this->rewindable) { - return $this->rewindable; - } - - // workaround for an HHVM bug, should be removed when https://github.com/facebook/hhvm/issues/7281 is fixed - if ('' === $this->getPath()) { - return $this->rewindable = false; - } - - if (false !== $stream = @opendir($this->getPath())) { - $infos = stream_get_meta_data($stream); - closedir($stream); - - if ($infos['seekable']) { - return $this->rewindable = true; - } - } - - return $this->rewindable = false; - } -} diff --git a/vendor/symfony/finder/Iterator/SizeRangeFilterIterator.php b/vendor/symfony/finder/Iterator/SizeRangeFilterIterator.php deleted file mode 100644 index 4e521c8..0000000 --- a/vendor/symfony/finder/Iterator/SizeRangeFilterIterator.php +++ /dev/null @@ -1,57 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Finder\Iterator; - -use Symfony\Component\Finder\Comparator\NumberComparator; - -/** - * SizeRangeFilterIterator filters out files that are not in the given size range. - * - * @author Fabien Potencier - */ -class SizeRangeFilterIterator extends FilterIterator -{ - private $comparators = []; - - /** - * @param \Iterator $iterator The Iterator to filter - * @param NumberComparator[] $comparators An array of NumberComparator instances - */ - public function __construct(\Iterator $iterator, array $comparators) - { - $this->comparators = $comparators; - - parent::__construct($iterator); - } - - /** - * Filters the iterator values. - * - * @return bool true if the value should be kept, false otherwise - */ - public function accept() - { - $fileinfo = $this->current(); - if (!$fileinfo->isFile()) { - return true; - } - - $filesize = $fileinfo->getSize(); - foreach ($this->comparators as $compare) { - if (!$compare->test($filesize)) { - return false; - } - } - - return true; - } -} diff --git a/vendor/symfony/finder/Iterator/SortableIterator.php b/vendor/symfony/finder/Iterator/SortableIterator.php deleted file mode 100644 index e67997d..0000000 --- a/vendor/symfony/finder/Iterator/SortableIterator.php +++ /dev/null @@ -1,80 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Finder\Iterator; - -/** - * SortableIterator applies a sort on a given Iterator. - * - * @author Fabien Potencier - */ -class SortableIterator implements \IteratorAggregate -{ - const SORT_BY_NAME = 1; - const SORT_BY_TYPE = 2; - const SORT_BY_ACCESSED_TIME = 3; - const SORT_BY_CHANGED_TIME = 4; - const SORT_BY_MODIFIED_TIME = 5; - - private $iterator; - private $sort; - - /** - * @param \Traversable $iterator The Iterator to filter - * @param int|callable $sort The sort type (SORT_BY_NAME, SORT_BY_TYPE, or a PHP callback) - * - * @throws \InvalidArgumentException - */ - public function __construct(\Traversable $iterator, $sort) - { - $this->iterator = $iterator; - - if (self::SORT_BY_NAME === $sort) { - $this->sort = static function ($a, $b) { - return strcmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname()); - }; - } elseif (self::SORT_BY_TYPE === $sort) { - $this->sort = static function ($a, $b) { - if ($a->isDir() && $b->isFile()) { - return -1; - } elseif ($a->isFile() && $b->isDir()) { - return 1; - } - - return strcmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname()); - }; - } elseif (self::SORT_BY_ACCESSED_TIME === $sort) { - $this->sort = static function ($a, $b) { - return $a->getATime() - $b->getATime(); - }; - } elseif (self::SORT_BY_CHANGED_TIME === $sort) { - $this->sort = static function ($a, $b) { - return $a->getCTime() - $b->getCTime(); - }; - } elseif (self::SORT_BY_MODIFIED_TIME === $sort) { - $this->sort = static function ($a, $b) { - return $a->getMTime() - $b->getMTime(); - }; - } elseif (\is_callable($sort)) { - $this->sort = $sort; - } else { - throw new \InvalidArgumentException('The SortableIterator takes a PHP callable or a valid built-in sort algorithm as an argument.'); - } - } - - public function getIterator() - { - $array = iterator_to_array($this->iterator, true); - uasort($array, $this->sort); - - return new \ArrayIterator($array); - } -} diff --git a/vendor/symfony/finder/Iterator/index.php b/vendor/symfony/finder/Iterator/index.php deleted file mode 100644 index df24d3e..0000000 --- a/vendor/symfony/finder/Iterator/index.php +++ /dev/null @@ -1,35 +0,0 @@ - - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA - */ - -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); - -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); - -header("Location: ../"); -exit; diff --git a/vendor/symfony/finder/LICENSE b/vendor/symfony/finder/LICENSE deleted file mode 100644 index 9e936ec..0000000 --- a/vendor/symfony/finder/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2004-2020 Fabien Potencier - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is furnished -to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/vendor/symfony/finder/README.md b/vendor/symfony/finder/README.md deleted file mode 100644 index 0b19c75..0000000 --- a/vendor/symfony/finder/README.md +++ /dev/null @@ -1,14 +0,0 @@ -Finder Component -================ - -The Finder component finds files and directories via an intuitive fluent -interface. - -Resources ---------- - - * [Documentation](https://symfony.com/doc/current/components/finder.html) - * [Contributing](https://symfony.com/doc/current/contributing/index.html) - * [Report issues](https://github.com/symfony/symfony/issues) and - [send Pull Requests](https://github.com/symfony/symfony/pulls) - in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/vendor/symfony/finder/SplFileInfo.php b/vendor/symfony/finder/SplFileInfo.php deleted file mode 100644 index 0f4e025..0000000 --- a/vendor/symfony/finder/SplFileInfo.php +++ /dev/null @@ -1,78 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Finder; - -/** - * Extends \SplFileInfo to support relative paths. - * - * @author Fabien Potencier - */ -class SplFileInfo extends \SplFileInfo -{ - private $relativePath; - private $relativePathname; - - /** - * @param string $file The file name - * @param string $relativePath The relative path - * @param string $relativePathname The relative path name - */ - public function __construct($file, $relativePath, $relativePathname) - { - parent::__construct($file); - $this->relativePath = $relativePath; - $this->relativePathname = $relativePathname; - } - - /** - * Returns the relative path. - * - * This path does not contain the file name. - * - * @return string the relative path - */ - public function getRelativePath() - { - return $this->relativePath; - } - - /** - * Returns the relative path name. - * - * This path contains the file name. - * - * @return string the relative path name - */ - public function getRelativePathname() - { - return $this->relativePathname; - } - - /** - * Returns the contents of the file. - * - * @return string the contents of the file - * - * @throws \RuntimeException - */ - public function getContents() - { - set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; }); - $content = file_get_contents($this->getPathname()); - restore_error_handler(); - if (false === $content) { - throw new \RuntimeException($error); - } - - return $content; - } -} diff --git a/vendor/symfony/finder/composer.json b/vendor/symfony/finder/composer.json deleted file mode 100644 index de19826..0000000 --- a/vendor/symfony/finder/composer.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "symfony/finder", - "type": "library", - "description": "Symfony Finder Component", - "keywords": [], - "homepage": "https://symfony.com", - "license": "MIT", - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "require": { - "php": "^5.5.9|>=7.0.8" - }, - "autoload": { - "psr-4": { "Symfony\\Component\\Finder\\": "" }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "minimum-stability": "dev", - "extra": { - "branch-alias": { - "dev-master": "3.4-dev" - } - } -} diff --git a/vendor/symfony/finder/index.php b/vendor/symfony/finder/index.php deleted file mode 100644 index df24d3e..0000000 --- a/vendor/symfony/finder/index.php +++ /dev/null @@ -1,35 +0,0 @@ - - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA - */ - -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); - -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); - -header("Location: ../"); -exit; diff --git a/vendor/symfony/index.php b/vendor/symfony/index.php deleted file mode 100644 index df24d3e..0000000 --- a/vendor/symfony/index.php +++ /dev/null @@ -1,35 +0,0 @@ - - * @copyright 2007-2020 PrestaShop SA - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * International Registered Trademark & Property of PrestaShop SA - */ - -header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); -header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); - -header("Cache-Control: no-store, no-cache, must-revalidate"); -header("Cache-Control: post-check=0, pre-check=0", false); -header("Pragma: no-cache"); - -header("Location: ../"); -exit; diff --git a/views/css/disable-contact-form.css b/views/css/disable-contact-form.css new file mode 100644 index 0000000..ee0fb7b --- /dev/null +++ b/views/css/disable-contact-form.css @@ -0,0 +1,12 @@ +/** + * This file is part of the securitypro package. + * + * @author Mathias Reker + * @copyright Mathias Reker + * @license Commercial Software License + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#contact-link,#contact-page,#link-static-page-contact-2{display:none!important} diff --git a/views/css/index.php b/views/css/index.php index f002f69..fa24a5a 100644 --- a/views/css/index.php +++ b/views/css/index.php @@ -1,16 +1,13 @@ e.preventDefault()); +$(document).on("contextmenu","img",function(e){"INPUT"!=e.target.nodeName&&"TEXTAREA"!=e.target.nodeName&&e.preventDefault()}); diff --git a/views/js/contextmenu.js b/views/js/contextmenu.js index 40b1d90..e746afa 100644 --- a/views/js/contextmenu.js +++ b/views/js/contextmenu.js @@ -1,15 +1,12 @@ /** - * 2020 Mathias R. + * This file is part of the securitypro package. * - * NOTICE OF LICENSE + * @author Mathias Reker + * @copyright Mathias Reker + * @license Commercial Software License * - * This file is licensed under the Software License Agreement - * With the purchase or the installation of the software in your application - * you accept the license agreement. - * - * @author Mathias R. - * @copyright Mathias R. - * @license Commercial license (You can not resell or redistribute this software.) + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. */ -document.oncontextmenu=function(){return!1}; +$(document).on("contextmenu",function(e){"INPUT"!=e.target.nodeName&&"TEXTAREA"!=e.target.nodeName&&e.preventDefault()}); diff --git a/views/js/index.php b/views/js/index.php index f002f69..fa24a5a 100644 --- a/views/js/index.php +++ b/views/js/index.php @@ -1,16 +1,13 @@ .active"),s=n&&t.support.transition&&i.hasClass("fade");function o(){i.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),a.addClass("active"),s?(a[0].offsetWidth,a.addClass("in")):a.removeClass("fade"),a.parent(".dropdown-menu")&&a.closest("li.dropdown").addClass("active"),n&&n()}s?i.one(t.support.transition.end,o):o(),i.removeClass("in"),scroll(0,0)}};var e=t.fn.tab;t.fn.tab=function(e){return this.each(function(){var n=t(this),i=n.data("tab");i||n.data("tab",i=new a(this)),"string"==typeof e&&i[e]()})},t.fn.tab.Constructor=a,t.fn.tab.noConflict=function(){return t.fn.tab=e,this},t(document).on("click.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(a){a.preventDefault(),t(this).tab("show")})}(window.jQuery),function(t){t.createTabs=function(){t("#content").find('form [id^="fieldset"]').length&&(blockTab='
',t.each(t("#content").find('form [id^="fieldset"]'),function(){heading=t(this).find(".panel-heading, legend"),blockTab+=''+heading.html()+"",t(this).addClass("tab-pane")}),blockTab+="
",t("#content").find("form").wrap("
").before(blockTab).addClass("col-lg-10 tab-content"),t("#content").find("form > br").remove(),t("#content").find("#module-tabs a:first").tab("show").addClass("active"),t("#content").find(".list-group-item").on("click",function(){var a=t(this).parent().closest(".list-group").children(".active");a.hasClass("active")&&a.removeClass("active"),t(this).addClass("active")}))}}(jQuery),$(document).ready(function(){$.createTabs(),$('a[data-toggle="tab"]').on("shown",function(t){localStorage.setItem("lastTab",$(t.target).attr("id"))});var t=localStorage.getItem("lastTab");t&&($("#"+t).tab("show"),$("#fieldset_0_securitylite").removeClass("active"),$("#"+t).addClass("active"))}); diff --git a/views/js/secure-random-password.min.js b/views/js/secure-random-password.js similarity index 94% rename from views/js/secure-random-password.min.js rename to views/js/secure-random-password.js index 47b6404..176ff77 100644 --- a/views/js/secure-random-password.min.js +++ b/views/js/secure-random-password.js @@ -1,15 +1,12 @@ -/** - * 2020 Mathias R. - * - * NOTICE OF LICENSE - * - * This file is licensed under the Software License Agreement - * With the purchase or the installation of the software in your application - * you accept the license agreement. - * - * @author Mathias R. - * @copyright Mathias R. - * @license Commercial license (You can not resell or redistribute this software.) - */ - -!function(r){var t={};function n(e){if(t[e])return t[e].exports;var o=t[e]={i:e,l:!1,exports:{}};return r[e].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=r,n.c=t,n.d=function(r,t,e){n.o(r,t)||Object.defineProperty(r,t,{configurable:!1,enumerable:!0,get:e})},n.n=function(r){var t=r&&r.__esModule?function(){return r.default}:function(){return r};return n.d(t,"a",t),t},n.o=function(r,t){return Object.prototype.hasOwnProperty.call(r,t)},n.p="",n(n.s=2)}([function(r,t){r.exports={}},function(r,t,n){"use strict";function e(r){return Array.apply(null,Array(r)).map(function(r,t){return t})}function o(r){return Array.prototype.slice.call(r)}t.assign=function(){var r=o(arguments),t=r[0];return r.slice(1).filter(function(r){return!!r}).forEach(function(r){Object.keys(r).forEach(function(n){t[n]=r[n]})}),t},t.intersection=function(r,t){r=o(r),t=o(t);var n={};r.forEach(function(r){n[r]=!0});var e={};return t.forEach(function(r){e[r]=!0}),Object.keys(n).filter(function(r){return e.hasOwnProperty(r)})},t.isInteger=function(r){return"number"==typeof r&&isFinite(r)&&Math.floor(r)===r},t.isString=function(r){return"string"==typeof r||r instanceof String},t.range=e,t.repeat=function(r,t){return e(t).map(function(){return r})},t.toArray=o},function(r,t,n){window.secureRandomPassword=n(3)},function(r,t,n){"use strict";var e=n(4).default,o=n(7),u=n(1);Object.keys(o).forEach(function(r){t[r]=o[r]});var a=["Il1|","O0"];function c(r){var t={avoidAmbiguous:!0,characters:[o.lower,{characters:o.upper,exactly:1},{characters:o.symbols,exactly:1}],length:12,predicate:function(){return!0},random:e},n=function(r){if(!r.characters)return[];var t=Array.isArray(r.characters)?r.characters:[r.characters];t=t.map(function(r){return u.isString(r)?{characters:r}:r});var n=!0===r.avoidAmbiguous?a:r.avoidAmbiguous||[];return function(r,t){var n=r.map(function(r){return r.characters}).join(""),e=t.filter(function(r){return u.intersection(r,n).length>1}).join("");r.forEach(function(r){r.characters=u.toArray(r.characters).filter(function(r){return e.indexOf(r)<0}).join("")})}(t,n),t}(r=u.assign({},t,r));if(!u.isInteger(r.length))throw new Error("length must be an integer");if(r.length<1)throw new Error("length must be > 0");if(r.length= # of character sets passed");if(n.some(function(r){return!r.characters}))throw new Error("No character set may be empty");if(0===n.length)throw new Error("Must pass one or more character sets");if("function"!=typeof r.predicate)throw new Error("predicate must be a function");var c,s=n.map(function(r){return r.exactly||1}).reduce(function(r,t){return r+t},0);if(r.length=0;e--)t+=r[e]*n,n*=256;return t}u.prototype.choose=function(r){if(!r||!r.length)throw new Error("Must pass 1 or more choices");return r[this._getInt(r.length)]},u.prototype.getInt=function(r){if(void 0===r)throw new Error("Must pass an upper bound");if(!o.isInteger(r))throw new Error("Upper bound must be a number");if(r<1)throw new Error("Upper bound must be > 0");return this._getInt(r)},u.prototype._getInt=function(r){if(1===r)return 0;var t,n=Math.ceil(Math.log(r)/Math.log(256)),e=Math.pow(2,8*n)-Math.pow(2,8*n)%r;do{t=a(this._randomSource(n))}while(t>=e);return t%r},u.prototype.shuffle=function(r){r=Array.prototype.slice.call(r||[]);for(var t=[];r.length;)t.push(r.splice(this._getInt(r.length),1)[0]);return t},t.Random=u,t.default=new u(e)},function(r,t,n){(function(e,o){var u;!function(a){"use strict";function c(r,t){if(t=t||{type:"Array"},void 0!==e&&"number"==typeof e.pid)return function(r,t){var e=n(6).randomBytes(r);switch(t.type){case"Array":return[].slice.call(e);case"Buffer":return e;case"Uint8Array":for(var o=new Uint8Array(r),u=0;u?@[\\]^_`{|}~",t.copyableSymbols="_"}]); +/** + * This file is part of the securitypro package. + * + * @author Mathias Reker + * @copyright Mathias Reker + * @license Commercial Software License + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +!function(r){var t={};function n(e){if(t[e])return t[e].exports;var o=t[e]={i:e,l:!1,exports:{}};return r[e].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=r,n.c=t,n.d=function(r,t,e){n.o(r,t)||Object.defineProperty(r,t,{configurable:!1,enumerable:!0,get:e})},n.n=function(r){var t=r&&r.__esModule?function(){return r.default}:function(){return r};return n.d(t,"a",t),t},n.o=function(r,t){return Object.prototype.hasOwnProperty.call(r,t)},n.p="",n(n.s=2)}([function(r,t){r.exports={}},function(r,t,n){"use strict";function e(r){return Array.apply(null,Array(r)).map(function(r,t){return t})}function o(r){return Array.prototype.slice.call(r)}t.assign=function(){var r=o(arguments),t=r[0];return r.slice(1).filter(function(r){return!!r}).forEach(function(r){Object.keys(r).forEach(function(n){t[n]=r[n]})}),t},t.intersection=function(r,t){r=o(r),t=o(t);var n={};r.forEach(function(r){n[r]=!0});var e={};return t.forEach(function(r){e[r]=!0}),Object.keys(n).filter(function(r){return e.hasOwnProperty(r)})},t.isInteger=function(r){return"number"==typeof r&&isFinite(r)&&Math.floor(r)===r},t.isString=function(r){return"string"==typeof r||r instanceof String},t.range=e,t.repeat=function(r,t){return e(t).map(function(){return r})},t.toArray=o},function(r,t,n){window.secureRandomPassword=n(3)},function(r,t,n){"use strict";var e=n(4).default,o=n(7),u=n(1);Object.keys(o).forEach(function(r){t[r]=o[r]});var a=["Il1|","O0"];function c(r){var t={avoidAmbiguous:!0,characters:[o.lower,{characters:o.upper,exactly:1},{characters:o.symbols,exactly:1}],length:12,predicate:function(){return!0},random:e},n=function(r){if(!r.characters)return[];var t=Array.isArray(r.characters)?r.characters:[r.characters];t=t.map(function(r){return u.isString(r)?{characters:r}:r});var n=!0===r.avoidAmbiguous?a:r.avoidAmbiguous||[];return function(r,t){var n=r.map(function(r){return r.characters}).join(""),e=t.filter(function(r){return u.intersection(r,n).length>1}).join("");r.forEach(function(r){r.characters=u.toArray(r.characters).filter(function(r){return e.indexOf(r)<0}).join("")})}(t,n),t}(r=u.assign({},t,r));if(!u.isInteger(r.length))throw new Error("length must be an integer");if(r.length<1)throw new Error("length must be > 0");if(r.length= # of character sets passed");if(n.some(function(r){return!r.characters}))throw new Error("No character set may be empty");if(0===n.length)throw new Error("Must pass one or more character sets");if("function"!=typeof r.predicate)throw new Error("predicate must be a function");var c,s=n.map(function(r){return r.exactly||1}).reduce(function(r,t){return r+t},0);if(r.length=0;e--)t+=r[e]*n,n*=256;return t}u.prototype.choose=function(r){if(!r||!r.length)throw new Error("Must pass 1 or more choices");return r[this._getInt(r.length)]},u.prototype.getInt=function(r){if(void 0===r)throw new Error("Must pass an upper bound");if(!o.isInteger(r))throw new Error("Upper bound must be a number");if(r<1)throw new Error("Upper bound must be > 0");return this._getInt(r)},u.prototype._getInt=function(r){if(1===r)return 0;var t,n=Math.ceil(Math.log(r)/Math.log(256)),e=Math.pow(2,8*n)-Math.pow(2,8*n)%r;do{t=a(this._randomSource(n))}while(t>=e);return t%r},u.prototype.shuffle=function(r){r=Array.prototype.slice.call(r||[]);for(var t=[];r.length;)t.push(r.splice(this._getInt(r.length),1)[0]);return t},t.Random=u,t.default=new u(e)},function(r,t,n){(function(e,o){var u;!function(a){"use strict";function c(r,t){if(t=t||{type:"Array"},void 0!==e&&"number"==typeof e.pid)return function(r,t){var e=n(6).randomBytes(r);switch(t.type){case"Array":return[].slice.call(e);case"Buffer":return e;case"Uint8Array":for(var o=new Uint8Array(r),u=0;u?@[\\]^_`{|}~",t.copyableSymbols="_"}]); diff --git a/views/templates/admin/contact.tpl b/views/templates/admin/contact.tpl deleted file mode 100644 index 85c17b5..0000000 --- a/views/templates/admin/contact.tpl +++ /dev/null @@ -1,39 +0,0 @@ -{* - * 2020 Mathias R. - * - * NOTICE OF LICENSE - * - * This file is licensed under the Software License Agreement - * With the purchase or the installation of the software in your application - * you accept the license agreement. - * - * @author Mathias R. - * @copyright Mathias R. - * @license Commercial license (You can not resell or redistribute this software.) -*} - -
-

{l s='Contact developer' mod='securitylite'}

-
-

{l s='Want to upgrade to Security Pro? Only 69,99€ excl. tax as an onetime fee! Free support!' mod='securitylite'}

- {l s='Upgrade now' mod='securitylite'} {l s='Read more' mod='securitylite'} -
-
-
-

{l s='Questions?' mod='securitylite'}

- {l s='Contact module developer' mod='securitylite'} -
-
-
-

{l s='Would you like to translate this module into your language or improve the wording?' mod='securitylite'}

-
    -
  • {l s='Click on "Translate" (flag icon) in the upper right corner' mod='securitylite'}
  • -
  • {l s='Choose a language' mod='securitylite'}
  • -
  • {l s='Make your changes and save' mod='securitylite'}
  • -
-

{l s='If you do any improvements to the wording, please export your translation and send it to the module developer, so your improvements can be merged into the next release. Your contribution is appreciated!' mod='securitylite'}

-
- -
-
-
diff --git a/views/templates/admin/index.php b/views/templates/admin/index.php deleted file mode 100644 index f002f69..0000000 --- a/views/templates/admin/index.php +++ /dev/null @@ -1,25 +0,0 @@ - -

{l s='Scripts' mod='securitylite'}

-
-

{l s='Run this script to quickly find open ports on your network. If you have unused open ports you should consider to close them.' mod='securitylite'} {l s='Running this script might take 1-2 minutes. Please be patient.' mod='securitylite'}

-
- -
-
-

{l s='Change file permissions to 644 and directory permissions to 755. This is highly recommended!' mod='securitylite'} {l s='Running this script might take 1-2 minutes. Please be patient.' mod='securitylite'}

-
- -
-
-

{l s='Fix directory traversal (observing) security vulnerability. This script adds missing index.php files to theme- and module directories. This is highly recommended!' mod='securitylite'} {l s='Running this script might take 1-2 minutes. Please be patient.' mod='securitylite'}

-
- -
- {if $show eq '1'} -
-

{l s='It is highly recommended to remove following files/directories:' mod='securitylite'}

-
    - {foreach from=$elements item=element} -
  • {$element|escape:'htmlall':'UTF-8'}
  • - {/foreach} -
-
- -
- {/if} -
- - - diff --git a/views/templates/admin/ssl.tpl b/views/templates/admin/ssl.tpl deleted file mode 100644 index 25a6a1f..0000000 --- a/views/templates/admin/ssl.tpl +++ /dev/null @@ -1,38 +0,0 @@ -{* - * 2020 Mathias R. - * - * NOTICE OF LICENSE - * - * This file is licensed under the Software License Agreement - * With the purchase or the installation of the software in your application - * you accept the license agreement. - * - * @author Mathias R. - * @copyright Mathias R. - * @license Commercial license (You can not resell or redistribute this software.) -*} - -
-

{l s='Analyze SSL / TLS' mod='securitylite'}

-
- {if $sslEnabled} -

{l s='Certificate' mod='securitylite'}: {$getIssuer|escape:'htmlall':'UTF-8'}

-

{l s='Verified by' mod='securitylite'}: {$getVarified|escape:'htmlall':'UTF-8'}

-

{l s='Expiration date' mod='securitylite'}: {$expirationDate|escape:'htmlall':'UTF-8'}

-

{l s='Expire in' mod='securitylite'}: {$diffInDays|escape:'htmlall':'UTF-8'} days

-

{l s='Signature algorithm' mod='securitylite'}: {$getSignatureAlgorithm|escape:'htmlall':'UTF-8'}

-

{l s='Version' mod='securitylite'}: {$getTlsVersion|escape:'htmlall':'UTF-8'}

-
-

{l s='Mixed content occurs when initial HTML is loaded over a secure HTTPS connection, but other resources (such as images, videos, stylesheets, scripts) are loaded over an insecure HTTP connection. This is called mixed content because both HTTP and HTTPS content are being loaded to display the same page, and the initial request was secure over HTTPS. Modern browsers display warnings about this type of content to indicate to the user that this page contains insecure resources.' mod='securitylite'}

- {l s='Scan your website for mixed content' mod='securitylite'} - {else} -

{l s='You must enable SSL to see this block.' mod='securitylite'}

- {/if} -
-
- - diff --git a/views/templates/front/index.php b/views/templates/front/index.php deleted file mode 100644 index f002f69..0000000 --- a/views/templates/front/index.php +++ /dev/null @@ -1,25 +0,0 @@ -