system/modules/pct_theme_settings/PCT/License.php line 250

Open in your IDE?
  1. <?php
  2. /**
  3.  * Contao Open Source CMS
  4.  * 
  5.  * Copyright (C) 2005-2013 Leo Feyer
  6.  * 
  7.  * @copyright    Tim Gatzky 2019
  8.  * @author        Tim Gatzky <info@tim-gatzky.de>
  9.  * @package        pct_theme_settings
  10.  * @link        http://contao.org
  11.  */
  12.  
  13.  
  14. /**
  15.  * Namespace
  16.  */
  17. namespace PCT;
  18. /**
  19.  * Imports
  20.  */
  21. use Contao\Config;
  22. use Contao\Controller;
  23. use Contao\Date;
  24. use Contao\Email;
  25. use Contao\StringUtil;
  26. use Contao\Environment;
  27. use Contao\File;
  28. use Contao\FrontendTemplate;
  29. use Contao\Input;
  30. use Contao\Message;
  31. use Contao\System;
  32. /**
  33.  * Class file
  34.  * Core
  35.  */
  36. class License
  37. {
  38.     /**
  39.      * The current domain as string
  40.      * @var string
  41.      */
  42.     protected $strDomain '';
  43.     
  44.     /**
  45.      * The license key
  46.      * @var string
  47.      */
  48.     protected $strLicense '';
  49.     
  50.     /**
  51.      * The current host
  52.      * @var string
  53.      */
  54.     protected $strHost '';
  55.     
  56.     /**
  57.      * License hash
  58.      * @var string
  59.      */
  60.     protected $strHash '';
  61.     public function __construct()
  62.     {
  63.         $host StringUtil::decodeEntitiesEnvironment::get('host') );
  64.         // dyn. host file
  65.         $objHostFile = new File('var/pct_host');
  66.         if( empty($host) === true && $objHostFile->exists() === true )
  67.         {
  68.             $host \trim$objHostFile->getContent() ?: '' );
  69.         }
  70.         $host \str_replace(array('http://','https://','www.'), ''$host);
  71.         // resolve single dot at the end 
  72.         $host \rtrim($host,'.');
  73.         
  74.         $this->strHost $host;
  75.         $this->strDomain $host;
  76.         
  77.         // localhost or host is IP
  78.         if( \in_arrayEnvironment::get('ip'), array('127.0.0.1''fe80::1''::1')) || $host == Environment::get('ip') )
  79.         {
  80.             $this->strDomain $host;
  81.         }
  82.         else
  83.         {
  84.             $arrUrl \array_map('strtolower',parse_url($host));
  85.             if( isset($arrUrl['host']) && !empty($arrUrl['host']) )
  86.             {
  87.                 $host $arrUrl['host'];
  88.             }
  89.             
  90.             // strip double domain suffixes
  91.             if( Config::get('pct_license_suffixes') !== null && empty( Config::get('pct_license_suffixes') ) === false )
  92.             {
  93.                 $arrSuffixes array_filter(array_map('trim'array_unique(explode(','Config::get('pct_license_suffixes')) ) ) );
  94.                 foreach( $arrSuffixes as $suffix )
  95.                 {
  96.                     if( \strpos($host$suffix) !== false )
  97.                     {
  98.                         $host \str_replace($suffix,'',$host).'.'// leave a dot at the end
  99.                         break;
  100.                     }
  101.                 }
  102.             }
  103.             $tmp array_reverseexplode('.',$host) );
  104.             $this->strDomain $tmp[1];
  105.             unset($tmp);
  106.         }
  107.         
  108.         // license file
  109.         $objFile = new File('var/pct_license');
  110.         if( $objFile->exists() )
  111.         {
  112.             $this->strLicense \trim$objFile->getContent() ?: '' );
  113.         }
  114.         // build license hash
  115.         $this->strHash \sha1\implode('_', array($this->strLicense,$this->strDomain,Date::parse('d-m-Y') ) ) ); 
  116.     }
  117.     /**
  118.      * Validate the theme license
  119.      * @return boolean     Returns true if license is valid, returns false if license is invalid
  120.      */
  121.     public function validate()
  122.     {
  123.         $arrParams = array
  124.         (
  125.             'domain'     => $this->strDomain,
  126.             'key'        => $this->strLicense,
  127.             'host'        => $this->strHost,
  128.         );
  129.         $strRequest \html_entity_decode('https://api.premium-contao-themes.com/license_api.php?'.\http_build_query($arrParams));
  130.         // validate the license
  131.         $curl \curl_init();
  132.         \curl_setopt($curl\CURLOPT_RETURNTRANSFER1);
  133.         \curl_setopt($curl\CURLOPT_URL$strRequest);
  134.         \curl_setopt($curl\CURLOPT_HEADER0);
  135.         \curl_setopt($curl\CURLOPT_SSL_VERIFYPEERFALSE);
  136.         \curl_setopt($curl\CURLOPT_FOLLOWLOCATIONtrue);
  137.         // get curl response
  138.         $strResponse \curl_exec($curl);
  139.         // parse response
  140.         $objLicense \json_decode($strResponse);
  141.         
  142.         // write log file
  143.         if( (boolean)Config::get('pct_license_log') === true )
  144.         {
  145.             // write log file
  146.             $objLogFile = new File('var/pct_validation_log');
  147.             $c '';
  148.             if( $objLogFile->exists())
  149.             {
  150.                 $c $objLogFile->getContent() ?? '';
  151.             }
  152.             $c .= Date::parse('d-m-Y H:i') .' | '.$strRequest ' | license status: ' .$objLicense->status .' | curl_error:'.\curl_error($curl)."\n";
  153.             $objLogFile->write($c);
  154.             $objLogFile->close();
  155.             
  156.             
  157.         }
  158.         //! curl error
  159.         if( $objLicense === null && empty( \curl_error($curl) ) === false )
  160.         {
  161.             $this->log\curl_error($curl),true );
  162.             return true;
  163.         }
  164.         //! status OK
  165.         else if( $objLicense !== null && $objLicense->status == 'OK' )
  166.         {
  167.             // license is ok, create file
  168.             $objFile = new File('var/pct_license');
  169.             if( $objFile->exists() === false )
  170.             {
  171.                 $objFile->write$objLicense->key );
  172.                 $objFile->close();
  173.             }
  174.             // log license response
  175.             if( (boolean)Config::get('pct_license_log') === true )
  176.             {
  177.                 $this->log('License is valid. Key: '.$this->strLicense.', Domain: '.$this->strDomain,'cron');
  178.             }
  179.             
  180.             return true;
  181.         }
  182.         // !status NOT OK
  183.         else if( $objLicense !== null && $objLicense->status != 'OK' )
  184.         {
  185.             // log license response
  186.             if( (boolean)Config::get('pct_license_log') === true )
  187.             {
  188.                 $this->log($objLicense->error,'error');
  189.             }
  190.             return false;
  191.         }
  192.         
  193.         // close curl
  194.         \curl_close($curl);
  195.         unset($curl);
  196.         return false;
  197.     }
  198.     /**
  199.      * Write system logs
  200.      * @var string
  201.      * @var integer
  202.      */
  203.     protected function log($strLog,$strLogger='')
  204.     {
  205.         $logger 'monolog.logger.contao.general';
  206.         $logger_fallback \TL_GENERAL;
  207.         switch($strLogger)
  208.         {
  209.             case 'cron':
  210.             case 'green':
  211.                 $logger 'monolog.logger.contao.cron';
  212.                 $logger_fallback \TL_CRON;
  213.                 break;
  214.             case 'error':
  215.             case 'red':
  216.                 $logger 'monolog.logger.contao.error';
  217.                 $logger_fallback \TL_ERROR;
  218.                 break;
  219.         }
  220.         
  221.         if( \version_compare(\VERSION'4.13''>=') )
  222.         {
  223.             System::getContainer()->get($logger)->info($strLog);
  224.         }
  225.         else
  226.         {
  227.             System::log($strLog,'License'$logger_fallback);
  228.         }
  229.     }
  230.     /**
  231.      * Check current license state
  232.      * @return void 
  233.      */
  234.     public function checkIntegrity()
  235.     {
  236.         $objValidationFile = new File('var/pct_validation');
  237.         $objLockedFile = new File('var/pct_license_locked');
  238.                 
  239.         $blnValidate false;
  240.         // validation file does not exist yet
  241.         if( $objValidationFile->exists() === false )
  242.         {
  243.             $blnValidate true;
  244.         }
  245.         else 
  246.         {
  247.             $strHash $objValidationFile->getContent();
  248.             $arrHash explode(','$strHash);
  249.             
  250.             // domain has changed
  251.             if( in_array\sha1$this->strDomain ), $arrHash) === false )
  252.             {
  253.                 if( (boolean)Config::get('pct_license_log') === true )
  254.                 {
  255.                     $this->log('Domain has changed! Revalidating license...');
  256.                 }
  257.                 $blnValidate true;
  258.             }
  259.         }
  260.         
  261.         // manually try to unlock from inside the backend
  262.         $blnSubmitted false;
  263.         if( \TL_MODE == 'BE' && Input::post('FORM_SUBMIT') == 'UNLOCK' )
  264.         {
  265.             $blnValidate true;
  266.             $blnSubmitted true;
  267.         }
  268.         // validate from license server
  269.         else if( \TL_MODE == 'FE' && Input::post('VALIDATION') !== null && empty( Input::post('VALIDATION') ) === false )
  270.         {
  271.             // secret send
  272.             if( empty( Input::post('SECRET') ) === true || Input::post('SECRET') != \sha1Date::parse('d-m-Y') ) )
  273.             {
  274.                 die( 'Missing secret' );
  275.             }
  276.             // clear pct_validataion
  277.             $objValidationFile->write('');
  278.             $objValidationFile->close();
  279.             
  280.             if( (boolean)Config::get('pct_license_log') === true )
  281.             {
  282.                 $this->log('POST Validation: Revalidating license...');
  283.             }
  284.             $blnValidate true;
  285.             $blnSubmitted true;
  286.         }
  287.         
  288.         // validate license
  289.         if( $blnValidate === true )
  290.         {
  291.             // true -> license is ok
  292.             if ( $this->validate() === true )
  293.             {
  294.                 $strHash '';
  295.                 if( $objValidationFile->exists() )
  296.                 {
  297.                     $strHash $objValidationFile->getContent();
  298.                 }
  299.                 $arrHash \explode(','$strHash);
  300.                 $arrHash[] = \sha1$this->strDomain );
  301.                 
  302.                 $objValidationFile->writeimplode(','\array_filter\array_unique($arrHash) ) ) );
  303.                 $objValidationFile->close();
  304.                 // unlock
  305.                 if( $objLockedFile->exists() )
  306.                 {
  307.                     $objLockedFile->delete();
  308.                 }
  309.                 
  310.             }
  311.             // false -> license is invalid: lock
  312.             else
  313.             {
  314.                 $objLockedFile->writetime() );
  315.                 $objLockedFile->close();
  316.             }
  317.         }
  318.         // reload to flush post
  319.         if( $blnSubmitted )
  320.         {
  321.             if( \TL_MODE == 'FE' && Input::post('VALIDATION') )
  322.             {
  323.                 $arrResponse = array
  324.                 (
  325.                     'hash' => $this->strHash,
  326.                     'locked' => static::isLocked(),
  327.                     'revalidated' => $blnValidate,
  328.                 );
  329.                 die( \json_encode($arrResponse) );
  330.             }
  331.             
  332.             Controller::reload();
  333.         }
  334.     }
  335.     /**
  336.      * Check if website license is currently locked
  337.      * @return bool 
  338.      */
  339.     public static function isLocked()
  340.     {
  341.         $objFile = new File('var/pct_license_locked');
  342.         return (boolean)$objFile->exists();
  343.     }
  344.     /**
  345.      * Show backend message when website is locked
  346.      */
  347.     public function addBackendInfo()
  348.     {
  349.         if ( \TL_MODE == 'BE' && static::isLocked() === true )
  350.         {
  351.             System::loadLanguageFile('default');
  352.             $objFramework System::getContainer()->get('contao.framework');
  353.             $objBanner = new FrontendTemplate('be_license_banner');
  354.             $objBanner->pct_license '';
  355.             $objBanner->request_token $objFramework->getAdapter\Contao\RequestToken::class)->get();
  356.             $objFile = new File('var/pct_license');
  357.             if( $objFile->exists() === true )
  358.             {
  359.                 $objBanner->pct_license $objFile->getContent();
  360.             }
  361.             // license key submitted
  362.             if( Input::post('FORM_SUBMIT') == 'PCT_LICENSE' && Input::post('license') !== null )
  363.             {
  364.                 $objFile->writetrimInput::post('license') ) );
  365.                 $objFile->close();
  366.                 // reload here
  367.                 Controller::reload();
  368.             }
  369.             
  370.             Message::addRaw$objBanner->parse() );
  371.         }
  372.     }
  373.     /**
  374.      * Reduce backend when locked
  375.      * @param array
  376.      * @return void 
  377.      */
  378.     public function checkBackend()
  379.     {
  380.         if ( \TL_MODE == 'BE' && static::isLocked() === true 
  381.         {
  382.             // hide ThemeDesigner
  383.             unset($GLOBALS['BE_MOD']['design']['pct_themedesigner']);
  384.             // hide DemoInstaller
  385.             unset($GLOBALS['BE_MOD']['design']['pct_demoinstaller']);
  386.             // hide RS
  387.             unset($GLOBALS['BE_MOD']['content']['revolutionslider']);
  388.             // hide CE
  389.             unset($GLOBALS['BE_MOD']['content']['pct_customelements']);
  390.         }
  391.     }
  392.     /**
  393.      * Clear the frontend when locked
  394.      * @param mixed $objTemplate 
  395.      * @return void 
  396.      */
  397.     public function checkFrontend($objTemplate)
  398.     {
  399.         // work on fe_page templates only
  400.         if ( \strpos($objTemplate->getName(), 'fe_page') === false || static::isLocked() === false 
  401.         {
  402.             return;
  403.         }
  404.         $objTemplate->sections = array();
  405.         foreach(array('main','left','right','footer','header','body','body_bottom') as $s)
  406.         {
  407.             $objTemplate->{$s} = '';
  408.         }
  409.         System::loadLanguageFile('default');
  410.             
  411.         $objBanner = new FrontendTemplate('fe_license_banner');
  412.         $objTemplate->main $objBanner->parse();        
  413.     }
  414.     /**
  415.      * Send admin mail when website is locked
  416.      * @param array
  417.      * @return void 
  418.      */
  419.     public function sendAdminMailWhenLocked()
  420.     {
  421.         if ( static::isLocked() === false 
  422.         {
  423.             return;
  424.         }
  425.         System::loadLanguageFile('default');
  426.         $strAdminMail Config::get('adminEmail') ?? '';
  427.         $strSubject \sprintf($GLOBALS['TL_LANG']['EXP']['license_locked']['email_subject'],$this->strHost);
  428.         $strText \sprintf($GLOBALS['TL_LANG']['EXP']['license_locked']['email_text'],$this->strHost);
  429.         $objMail = new Email();
  430.         $objMail->from $strAdminMail;
  431.         $objMail->fromName $strAdminMail;
  432.         $objMail->subject $strSubject;
  433.         $objMail->text $strText;
  434.         $objMail->priority 'highest';
  435.         $objMail->sendTo$strAdminMail );
  436.         $this->log('[License locked] Admin-Mail has been send to '.$strAdminMail);
  437.     }
  438. }