File Manager

Current Directory: /home/astoriaah/www/plugins/system/gdpr
Viewing File: /home/astoriaah/www/plugins/system/gdpr/gdpr.php
<?php /** * @author Joomla! Extensions Store * @package GDPR::plugins::system * @copyright (C) 2018 - Joomla! Extensions Store * @license GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html */ defined ( '_JEXEC' ) or die ( 'Restricted access' ); jimport ( 'joomla.plugin.plugin' ); /** * Observer class notified on events * * @author Joomla! Extensions Store * @package GDPR::plugins::system * * @since 1.0 */ class plgSystemGdpr extends JPlugin { /** * Parameters object for component and plugin * * @access private * @var Object */ private $cParams; /** * App instance * * @access private * @var Object */ private $app; /** * Init state * * @access private * @var bool */ private $hasCookieCategory; /** * Init state * * @access private * @var bool */ private $unsetCategoriesCookies = array(); /** * Store the language sef string for the query parameter if the website is multilanguage * * @access private * @var string */ private $languageQueryStringParam = null; /** * Load manifest file for this type of data source * @access private * @return mixed */ private function loadManifest($option) { // Load configuration manifest file $fileName = JPATH_ROOT . '/components/com_gdpr/manifests/' . $option . '.json'; // Check if file exists and is valid manifest if(!file_exists($fileName)) { return false; } // Load the manifest serialized file and assign to local variable $manifest = file_get_contents($fileName); $manifestConfiguration = json_decode($manifest); return $manifestConfiguration; } /** * Force a first top head append of the configuration script * @access private * @return void */ private function addConfigToHead() { static $headAdded; if(!$headAdded && isset($this->configurationOptionsScript)) { $body = $this->app->getBody (); // Replace buffered main view contents at the body end $body = preg_replace ( '/<head>/i', '<head>' . '<script>'. $this->configurationOptionsScript . '</script>', $body, 1 ); // Set the new JResponse contents $this->app->setBody ( $body ); $headAdded = true; } } /** * Function to kill al external resources to prevent loading of third party cookies * * @access private * @param string $categoryDomains * @param int $categoryIndex * @param bool $isIndividual * @return void */ private function killExternalResources ($categoryDomains = null, $categoryIndex = null, $isIndividual = false) { // Support for custom component forms $domainsToKill = array(); $domainsExcluded = array(); $advancedKillResourceMethod = false; // Check if the preserve locked cats is enabled if($this->cParams->get('preserve_locked_categories', 0)) { /** * Check if the $categoryCookie is requested, in this case skip not disabled cats if the deny all state is active */ if($categoryDomains && $this->cParams->get('cookie_category' . $categoryIndex . '_locked', 0)) { $cookieConsentStatus = $this->app->input->cookie->get('cookieconsent_status'); // Deny all state by the user 'Decline' toolbar button if(!$cookieConsentStatus || $cookieConsentStatus == 'deny') { $session = $this->app->getSession(); if(!$session->get('gdpr_cookie_category_disabled_' . $categoryIndex, 0)) { // Return without blocking domains of this category return; } } } /** * Check if the preserve locked cats is enabled and if the $categoryCookie is NOT requested AKA global kill, * in this case if the deny all state is active skip all domains in locked and not disabled categories */ if(!$categoryDomains) { $cookieConsentStatus = $this->app->input->cookie->get('cookieconsent_status'); // Deny all state by the user 'Decline' toolbar button if(!$cookieConsentStatus || $cookieConsentStatus == 'deny') { $session = $this->app->getSession(); // If a category is not disabled and it's locked for($catIndex = 1, $max = 4; $catIndex <= $max; $catIndex ++) { if(!$session->get('gdpr_cookie_category_disabled_' . $catIndex, 0) && $this->cParams->get('cookie_category' . $catIndex . '_locked', 0)) { // Add cookies in this category to $excludedLocalCookies $domainsInThisCategory = explode(PHP_EOL, $this->cParams->get('domains_category' . $catIndex . '_list', '')); foreach ($domainsInThisCategory as &$singleDomainInThisCategory) { $singleDomainInThisCategory = trim($singleDomainInThisCategory); if($singleDomainInThisCategory) { $domainsExcluded[] = $singleDomainInThisCategory; } } } } } } } if($this->cParams->get('external_blocking_mode', 'simple') == 'advanced') { static $simpleHtmlDomInstance, $domElements; if(!$simpleHtmlDomInstance) { require_once (JPATH_ROOT . '/plugins/system/gdpr/simplehtmldom.php'); $killResourceSelector = trim($this->cParams->get('external_advanced_blocking_mode_tags', 'iframe,script,img,source,link'), ','); $simpleHtmlDomInstance = new GdprSimpleHtmlDom(); $simpleHtmlDomInstance->load( $this->app->getBody () ); $domElements = $simpleHtmlDomInstance->find( $killResourceSelector ); } $advancedKillResourceMethod = true; } // Kill all domains if(!$categoryDomains) { $defaultDomains = 'googletagmanager.com' . PHP_EOL . 'google-analytics.com' . PHP_EOL . 'adsbygoogle.js' . PHP_EOL . 'googleadservices.com' . PHP_EOL . 'googlesyndication.com' . PHP_EOL . 'paypal.com' . PHP_EOL . 'facebook.com' . PHP_EOL . 'facebook.net' . PHP_EOL . 'facebook.it'. PHP_EOL . 'google.com' . PHP_EOL . 'google.it' . PHP_EOL . 'googlecode.com' . PHP_EOL . 'googleapis.com' . PHP_EOL . 'doubleclick.net' . PHP_EOL . 'twitter.com' . PHP_EOL . 'twitterfeed.com' . PHP_EOL . 'youtube.com' . PHP_EOL . 'youtube-nocookie.com' . PHP_EOL . 'vimeo.com' . PHP_EOL . 'linkedin.com' . PHP_EOL . 'pinterest.com' . PHP_EOL . 'digg.com' . PHP_EOL . 'instagram.com' . PHP_EOL . 'addthis.com' . PHP_EOL . 'eventbrite.it' . PHP_EOL . 'eventbrite.com' . PHP_EOL . 'addtoany.com' . PHP_EOL . 'mixpanel.com' . PHP_EOL . 'adform.net' . PHP_EOL . 'performgroup.com'; $domainsParameter = trim($this->cParams->get('external_cookies_domains', $defaultDomains)); } else { $domainsParameter = $categoryDomains; } if($domainsParameter) { $domainsToKill = explode(PHP_EOL, $domainsParameter); if(!empty($domainsToKill)) { $sameBaseDomain = JUri::base(false); $customAttribute = trim($this->cParams->get('external_advanced_blocking_mode_custom_attribute', '')); $blockingMode = $this->cParams->get('external_blocking_mode', 'simple'); // Exclude its same GDPR user view from being blocked if($this->app->input->get('option') == 'com_gdpr' && $this->app->input->get('view') == 'user' && $blockingMode == 'simple') { $blockingMode = 'simplebytag'; } $killResourceSelectorPReg = JString::str_ireplace(',', '|<', trim($this->cParams->get('external_advanced_blocking_mode_tags', 'iframe,script,img,source,link'), ',')); $body = $this->app->getBody (); foreach ($domainsToKill as &$domainToKill) { $domainToKill = trim($domainToKill); // Skip empty strings if(!$domainToKill) { continue; } // Ensure to never kill local resources!!! if(stripos($sameBaseDomain, $domainToKill) !== false) { continue; } // Skip if it's an excluded domain if(in_array($domainToKill, $domainsExcluded)) { continue; } if(!$advancedKillResourceMethod) { // Replace buffered main view contents at the body end if($blockingMode == 'simple') { $body = JString::str_ireplace( $domainToKill, md5($domainToKill) . '-gdprlock', $body ); } elseif($blockingMode == 'simplebytag') { $body = preg_replace('/(<' . $killResourceSelectorPReg . ')(?!\s+class=".*gdpr_cookie_switcher.*")([^<]*)(' . preg_quote($domainToKill, '/') . ')/iU', '$1$2gdprlock', $body); } } else { // Advanced DOM mode foreach ( $domElements as $element ) { // Match valid resources with a custom attribute if($customAttribute && $element->hasAttribute( $customAttribute )) { $elementSrc = $element->getAttribute($customAttribute); if(stripos($elementSrc, $domainToKill) !== false) { $element->removeAttribute($customAttribute); $element->setAttribute('data-source', 'gdprlock'); continue; } } // Skip invalid resources without the src attribute $hasSrc = $element->hasAttribute( 'src' ); $hasHref = $element->hasAttribute( 'href' ); if(!$hasSrc && !$hasHref) { // If it's an no-src inline script tag, ensure that there are no matched domain in the text node if($element->tag == 'script') { $nodeText = $element->text(true); $nodeText = JString::str_ireplace( $domainToKill, '', $nodeText ); $element->innertext = $nodeText; } continue; } // Tags with src attribute if($hasSrc) { $elementSrc = $element->getAttribute('src'); if(stripos($elementSrc, $domainToKill) !== false) { // If there is an on page load feature enabled for iframes, add the original attribute here if($this->cParams->get('placeholder_onpage_unlock', 0)) { $elementSrc = $element->getAttribute('src'); if($element->tag == 'iframe' && is_string($elementSrc) && JString::strpos($elementSrc, 'about') === false) { $element->setAttribute('data-original-src', $elementSrc); } } // If there is an on page unlock feature enabled for scripts, add the original attribute here if($this->cParams->get('scripts_onpage_unlock', 0)) { $elementSrc = $element->getAttribute('src'); if($element->tag == 'script' && is_string($elementSrc)) { $element->setAttribute('data-gdprlock-original-script-src', $elementSrc); } } $element->removeAttribute('src'); $element->setAttribute('data-source', 'gdprlock'); if($isIndividual && $element->tag == 'iframe') { $element->setAttribute('data-gdpr-domain', $domainToKill); } } } // Tags with href attribute if($hasHref) { $elementHref = $element->getAttribute('href'); if(stripos($elementHref, $domainToKill) !== false) { $element->removeAttribute('href'); $element->setAttribute('data-source', 'gdprlock'); } } } } } // Set the new JResponse contents if($advancedKillResourceMethod) { $body = $simpleHtmlDomInstance->save(); } // Final assignment $this->app->setBody ( $body ); } } } /** * Must even local resources be killed PHP server side? * * @access private * @param string $categoryCookie * @param int $categoryIndex * @return void */ private function killLocalCookies($categoryCookie = null, $categoryIndex = null) { $excludedLocalCookies = explode(',', trim($this->cParams->get('allow_local_cookies', ''))); // Do not block Joomla session cookie if there are categories or if there are not categories + the opt-out is enabled + block local cookies on server is enabled + users choose deny all if(!$this->cParams->get('block_joomla_session_cookie', 1) || $this->hasCookieCategory || (!$this->hasCookieCategory && $this->cParams->get('compliance_type', 'opt-in') == 'opt-out')) { $excludedLocalCookies[] = $this->app->getSession()->getName(); $excludedLocalCookies[] = md5(JApplicationHelper::getHash('administrator')); } // Check if the preserve locked cats is enabled if($this->cParams->get('preserve_locked_categories', 0)) { /** * Check if the $categoryCookie is requested, in this case skip not disabled cats if the deny all state is active */ if($categoryCookie && $this->cParams->get('cookie_category' . $categoryIndex . '_locked', 0)) { $cookieConsentStatus = $this->app->input->cookie->get('cookieconsent_status'); // Deny all state by the user 'Decline' toolbar button if(!$cookieConsentStatus || $cookieConsentStatus == 'deny') { $session = $this->app->getSession(); if(!$session->get('gdpr_cookie_category_disabled_' . $categoryIndex, 0)) { // Return without blocking cookies of this category return; } } } /** * Check if the preserve locked cats is enabled and if the $categoryCookie is NOT requested AKA global kill, * in this case if the deny all state is active skip all cookies in locked and not disabled categories */ if(!$categoryCookie) { $cookieConsentStatus = $this->app->input->cookie->get('cookieconsent_status'); // Deny all state by the user 'Decline' toolbar button if(!$cookieConsentStatus || $cookieConsentStatus == 'deny') { $session = $this->app->getSession(); // If a category is not disabled and it's locked for($catIndex = 1, $max = 4; $catIndex <= $max; $catIndex ++) { if(!$session->get('gdpr_cookie_category_disabled_' . $catIndex, 0) && $this->cParams->get('cookie_category' . $catIndex . '_locked', 0)) { // Add cookies in this category to $excludedLocalCookies $cookiesInThisCategory = explode(PHP_EOL, $this->cParams->get('cookie_category' . $catIndex . '_list', '')); foreach ($cookiesInThisCategory as &$singleCookieInThisCategory) { $singleCookieInThisCategory = trim($singleCookieInThisCategory); $excludedLocalCookies[] = $singleCookieInThisCategory; } } } } } } $cookies = $this->app->input->cookie->getArray(); if(!empty($cookies)) { // Block all cookies if(!$categoryCookie) { foreach ($cookies as $cookieName=>$cookieValue) { if(!in_array($cookieName, $excludedLocalCookies)) { $this->app->input->cookie->set($cookieName, '', -1, '/'); } } } else { // Block only cookies in the not accepted category $categoryCookieArray = explode(PHP_EOL, $categoryCookie); foreach ($categoryCookieArray as &$singleCookieInCategory) { $singleCookieInCategory = trim($singleCookieInCategory); } $cookiesBlockingMode = $this->cParams->get('categories_cookies_blocking_mode', 'sent'); if($cookiesBlockingMode == 'sent') { // Mode 1, block all cookies sent cookies included in a category foreach ($cookies as $cookieName=>$cookieValue) { if(in_array($cookieName, $categoryCookieArray) && !in_array($cookieName, $excludedLocalCookies)) { $this->app->input->cookie->set($cookieName, '', -1, '/'); $this->unsetCategoriesCookies[] = $cookieName; } } } elseif ($cookiesBlockingMode == 'listed') { // Mode 2, block all cookies that are included in a category despite if it's sent or not foreach ($categoryCookieArray as $cookieName) { if(!in_array($cookieName, $excludedLocalCookies)) { $this->app->input->cookie->set(rawurlencode($cookieName), '', -1, '/'); $this->unsetCategoriesCookies[] = $cookieName; } } } } } else { if($this->cParams->get('block_joomla_session_cookie', 1) && !$this->hasCookieCategory) { $this->app->input->cookie->set($this->app->getSession()->getName(), '', -1, '/'); } } } /** * Check for the valid filtered execution of the plugin based on option and view selected * * @param string $feature * @access private * @return bool */ private function validateExecution($feature) { static $isBot, $menuExcluded; // Get the dispatched option, view and id $option = $this->app->input->get('option'); $view = $this->app->input->get('view'); $excludedExtensions = $this->cParams->get($feature, array('0')); // Is this the same com_gdpr user view? Always include the plugin and avoid exclusions $document = JFactory::getDocument(); if($option == 'com_gdpr' && $view == 'user' && $document->getType() === 'html') { return true; } // An invalid execution detected for this component? if(in_array($option, $excludedExtensions, true)) { return false; } // Add invalid execution check for menu page exclusions if(!isset($menuExcluded)) { $menu = $this->app->getMenu ()->getActive (); if (is_object ( $menu )) { $menuItemid = $menu->id; $menuExclusions = $this->cParams->get ( 'menu_exclusions' ); if (is_array ( $menuExclusions ) && ! in_array ( 0, $menuExclusions, false ) && in_array ( $menuItemid, $menuExclusions )) { $menuExcluded = true; } else { $menuExcluded = false; } } } if($menuExcluded) { return false; } // Check for user agent exclusion if (isset ( $_SERVER ['HTTP_USER_AGENT'] )) { if(!isset($isBot)) { $lightHouseExclude = $this->cParams->get('exclude_lighthouse', 0) ? 'Lighthouse|' : ''; $user_agent = $_SERVER ['HTTP_USER_AGENT']; $botRegexPattern = "(" . $lightHouseExclude . "Googlebot\/|Googlebot\-Mobile|Googlebot\-Image|Googlebot\-Video|Google favicon|JSitemapbot|Mediapartners\-Google|bingbot|slurp|java|wget|curl|Commons\-HttpClient|Python\-urllib|libwww|httpunit|nutch|phpcrawl|msnbot|jyxobot|FAST\-WebCrawler|FAST Enterprise Crawler|biglotron|teoma|convera|seekbot|gigablast|exabot|ngbot|ia_archiver|GingerCrawler|webmon |httrack|webcrawler|grub\.org|UsineNouvelleCrawler|antibot|netresearchserver|speedy|fluffy|bibnum\.bnf|findlink|msrbot|panscient|yacybot|AISearchBot|IOI|ips\-agent|tagoobot|MJ12bot|dotbot|woriobot|yanga|buzzbot|mlbot|yandexbot|purebot|Linguee Bot|Voyager|CyberPatrol|voilabot|baiduspider|citeseerxbot|spbot|twengabot|postrank|turnitinbot|scribdbot|page2rss|sitebot|linkdex|Adidxbot|blekkobot|ezooms|dotbot|Mail\.RU_Bot|discobot|heritrix|findthatfile|europarchive\.org|NerdByNature\.Bot|sistrix crawler|ahrefsbot|Aboundex|domaincrawler|wbsearchbot|summify|ccbot|edisterbot|seznambot|ec2linkfinder|gslfbot|aihitbot|intelium_bot|facebookexternalhit|yeti|RetrevoPageAnalyzer|lb\-spider|sogou|lssbot|careerbot|wotbox|wocbot|ichiro|DuckDuckBot|lssrocketcrawler|drupact|webcompanycrawler|acoonbot|openindexspider|gnam gnam spider|web\-archive\-net\.com\.bot|backlinkcrawler|coccoc|integromedb|content crawler spider|toplistbot|seokicks\-robot|it2media\-domain\-crawler|ip\-web\-crawler\.com|siteexplorer\.info|elisabot|proximic|changedetection|blexbot|arabot|WeSEE:Search|niki\-bot|CrystalSemanticsBot|rogerbot|360Spider|psbot|InterfaxScanBot|Lipperhey SEO Service|CC Metadata Scaper|g00g1e\.net|GrapeshotCrawler|urlappendbot|brainobot|fr\-crawler|binlar|SimpleCrawler|Livelapbot|Twitterbot|cXensebot|smtbot|bnf\.fr_bot|A6\-Indexer|ADmantX|Facebot|Twitterbot|OrangeBot|memorybot|AdvBot|MegaIndex|SemanticScholarBot|ltx71|nerdybot|xovibot|BUbiNG|Qwantify|archive\.org_bot|Applebot|TweetmemeBot|crawler4j|findxbot|SemrushBot|yoozBot|lipperhey|y!j\-asr|Domain Re\-Animator Bot|AddThis)"; $isBot = preg_match("/{$botRegexPattern}/i", $user_agent); } if($isBot) { return false; } } return true; } /** * Check a specific feature exclusion by group * * @param string $feature * @access private * @return bool */ private function checkExclusionPermissions($feature) { static $userGroups; $isExcluded = false; if(!$userGroups) { $user = JFactory::getUser(); $userGroups = $user->getAuthorisedGroups(); } $featureExcludedGroups = $this->cParams->get($feature, array(0)); if(is_array($featureExcludedGroups) && !in_array(0, $featureExcludedGroups, false)) { $intersectResult = array_intersect($userGroups, $featureExcludedGroups); $isExcluded = (int)(count($intersectResult)); } return $isExcluded; } /** * Load the main component frontend language strings * * @param string * @access private * @return void */ private function loadComponentLanguage() { static $languageLoaded = false; // Manage partial language translations if(!$languageLoaded) { $jLang = JFactory::getLanguage(); $jLang->load('com_gdpr', JPATH_SITE . '/components/com_gdpr', 'en-GB', true, true); if($jLang->getTag() != 'en-GB') { $jLang->load('com_gdpr', JPATH_SITE, null, true, false); $jLang->load('com_gdpr', JPATH_SITE . '/components/com_gdpr', null, true, false); } } $languageLoaded = true; } /** * Fix relative links into Joomla editor fields, img->src and a->href * * @param string $buffer * @access private * @return string */ private function fixRelativeLinks($buffer) { // Replace src links. $base = JUri::base ( true ) . '/'; // Check for all unknown protocols (a protocol must contain at least one alphanumeric character followed by a ":"). $protocols = '[a-zA-Z0-9\-]+:'; $attributes = array ( 'href=', 'src=' ); foreach ( $attributes as $attribute ) { if (strpos ( $buffer, $attribute ) !== false) { $regex = '#\s' . $attribute . '\\\"(?!/|' . $protocols . '|\#|\')([^"]*)\\\"#m'; $buffer = preg_replace ( $regex, ' ' . $attribute . '\"' . $base . '$1\"', $buffer ); } } return $buffer; } /** * Method to be called after the app initialise to kill the page caching preventing third party cookies refresh * * @return void */ public function onAfterInitialise () { // Avoid operations if plugin is executed in backend if ( $this->app->isAdmin ()) { return; } // Only if page caching plugin is enabled if(!JPluginHelper::isEnabled('system', 'cache') && !JPluginHelper::isEnabled('system', 'jotcache')) { return; } // Avoid for logged in users, no page cache for them if(JFactory::getUser()->id) { return; } // Output JS APP nel Document if(stripos($_SERVER['REQUEST_URI'], '/rss/')) { return; } // Fix for sh404sef RSS routing issue // Disable auto caching management if($this->cParams->get('auto_manage_caching', 1) != 1) { return; } $document = JFactory::getDocument(); if($document->getType() !== 'html' || $this->app->input->getCmd ( 'tmpl' ) === 'component') { return; } // Reset document JFactory::$document = null; // Not enabled feature if(!$this->cParams->get('enable_cookie_consent', 1)) { return; } // Validate execution for this component if(!$this->validateExecution('exclude_cookie_consent')) { return; } // Check permissions exclusions if($this->checkExclusionPermissions('disallow_cookie')) { return; } // If the cookie is already set and the revocable mode is not enabled just skip if($this->app->input->cookie->get('cookieconsent_status') && !$this->cParams->get('revokable', 1)) { return; } $cookieCategories = false; if( $this->cParams->get('compliance_type', 'opt-in') != 'info' && ((int)$this->cParams->get('cookie_category1_enable', 0) || (int)$this->cParams->get('cookie_category2_enable', 0) || (int)$this->cParams->get('cookie_category3_enable', 0) || (int)$this->cParams->get('cookie_category4_enable', 0))) { $cookieCategories = true; } if($this->cParams->get('block_external_cookies_domains', 0) || $cookieCategories) { if($this->cParams->get('compliance_type', 'opt-in') == 'opt-in' || $this->cParams->get('compliance_type', 'opt-in') == 'opt-out') { $dispatcher = JEventDispatcher::getInstance(); // Kill the Joomla page cache $pluginClassName = 'PlgSystemCache'; // Manage plugins exclusions at a early stage in the Joomla CMS app execution lifecycle if(class_exists($pluginClassName)) { // Get plugin observer object based on type/name $plugin = JPluginHelper::getPlugin('system', 'cache'); // Instantiate the observer object and inject the subject for the attach $pluginInstanceToExclude = new $pluginClassName($dispatcher, (array) $plugin); // Now search and detach it $dispatcher->detach($pluginInstanceToExclude); } // Kill the JotCache $pluginClassName = 'plgSystemJotCache'; // Manage plugins exclusions at a early stage in the Joomla CMS app execution lifecycle if(class_exists($pluginClassName)) { // Get plugin observer object based on type/name $plugin = JPluginHelper::getPlugin('system', 'jotcache'); // Instantiate the observer object and inject the subject for the attach $pluginInstanceToExclude = new $pluginClassName($dispatcher, (array) $plugin); // Now search and detach it $dispatcher->detach($pluginInstanceToExclude); } } } } /** * Method to be called everytime a head section has to be compiled and manipulated * * @return void */ public function onBeforeCompileHead() { // Avoid operations if plugin is executed in backend if ( $this->app->isAdmin ()) { return; } // Output JS APP nel Document $document = JFactory::getDocument(); $tmplComponent = $this->app->input->getCmd ( 'tmpl' ) === 'component'; if($document->getType() !== 'html' || $tmplComponent) { if($document->getType() !== 'html') { return; } elseif($tmplComponent) { if($this->cParams->get('custom_css_styles_into_popup', 0)) { // Add custom styles if any if($customCssStyles = trim($this->cParams->get('custom_css_styles', ''))) { $document->addStyleDeclaration($customCssStyles); } } if($this->cParams->get('include_cookie_toolbar_tmpl_component', 0) && $this->app->input->getCmd('option') != 'com_gdpr') { // Go on } else { return; } } } // Scripts loading $jQueryInclusion = $this->cParams->get ( 'jquery_include', true ); if ($jQueryInclusion) { if (version_compare ( JVERSION, '3.0', '>=' )) { JHtml::_ ( 'jquery.framework' ); } else { $document->addScript ( JUri::root ( true ) . '/plugins/system/gdpr/assets/js/jquery.js' ); } } if ($this->cParams->get ( 'jquery_noconflict', 0 )) { $document->addScript ( JUri::root ( true ) . '/plugins/system/gdpr/assets/js/jquery.noconflict.js' ); } // Not enabled feature if(!$this->cParams->get('enable_cookie_consent', 1)) { return; } // Validate execution for this component if(!$this->validateExecution('exclude_cookie_consent')) { return; } // Check permissions exclusions if($this->checkExclusionPermissions('disallow_cookie')) { return; } // Ensure that the website is not offline, otherwise allows the app and document rendering by Joomla to complete if ($this->app->get('offline') && !JFactory::getUser()->authorise('core.login.offline')) { return false; } // Special container selector override for the modal center position, always outside the body + blurred modal if blocked status if($this->cParams->get('position', 'bottom') == 'center' && $this->cParams->get('open_always_declined', 1)) { $this->cParams->set('container_selector', 'html'); $blurredEffectPercentage = $this->cParams->get('position_center_blur_effect_percentage', 50); // Switch the blur effect type if($this->cParams->get('position_center_blur_effect_type', 'modal1') == 'modal1') { $blurredEffect = 'body,body.gdpr-backdrop-effect{filter:brightness(' . $blurredEffectPercentage . '%) blur(5px);pointer-events:none;}div.fancybox-container.fancybox-is-open{z-index:99999999}'; } else { $blurredEffect = 'body,body.gdpr-backdrop-effect{filter:brightness(' . $blurredEffectPercentage . '%);pointer-events:none;}div.fancybox-container.fancybox-is-open{z-index:99999999}'; } if($this->cParams->get('compliance_type', 'opt-in') == 'opt-in' ) { $cookieConsentComplianceCookie = $this->app->input->cookie->get('cookieconsent_status'); if(!$cookieConsentComplianceCookie || $cookieConsentComplianceCookie == 'deny') { if($this->cParams->get('position_center_blur_effect', '0')) { $document->addStyleDeclaration($blurredEffect); } } } if($this->cParams->get('compliance_type', 'opt-in') == 'opt-out') { $cookieConsentComplianceCookie = $this->app->input->cookie->get('cookieconsent_status'); if($cookieConsentComplianceCookie == 'deny') { if($this->cParams->get('position_center_blur_effect', '0')) { $document->addStyleDeclaration($blurredEffect); } } } } // Override the toolbar styles $boxbarMaxwidth = $this->cParams->get('boxbar_maxwidth', 'auto'); if($boxbarMaxwidth == 'auto') { if($this->cParams->get('allowall_showbutton', 0)) { $boxbarMaxwidth = 32; } else { $boxbarMaxwidth = 24; } } else { $boxbarMaxwidth = (int)$boxbarMaxwidth; } $document->addStyleDeclaration('div.cc-window.cc-floating{max-width:' . $boxbarMaxwidth . 'em}@media(max-width: 639px){div.cc-window.cc-floating:not(.cc-center){max-width: none}}'); $document->addStyleDeclaration('div.cc-window, span.cc-cookie-settings-toggler{font-size:' . $this->cParams->get('popup_fontsize', 16) . 'px}'); $document->addStyleDeclaration('div.cc-revoke{font-size:' . $this->cParams->get('revocable_button_fontsize', 16) . 'px}'); $document->addStyleDeclaration('div.cc-settings-label,span.cc-cookie-settings-toggle{font-size:' . intval($this->cParams->get('popup_fontsize', 16) - 2) . 'px}'); $document->addStyleDeclaration('div.cc-window.cc-banner{padding:' . $this->cParams->get('popup_padding', '1') . 'em 1.8em}'); $document->addStyleDeclaration('div.cc-window.cc-floating{padding:' . floatval($this->cParams->get('popup_padding', '1') * 2) . 'em 1.8em}'); $document->addStyleDeclaration('input.cc-cookie-checkbox+span:before, input.cc-cookie-checkbox+span:after{border-radius:' . $this->cParams->get('categories_border_radius', 1) . 'px}'); $document->addStyleDeclaration('div.cc-center,div.cc-floating,div.cc-checkbox-container,div.gdpr-fancybox-container div.fancybox-content,ul.cc-cookie-category-list li,fieldset.cc-service-list-title legend{border-radius:' . intval($this->cParams->get('popup_border_radius', 0)) . 'px}'); $document->addStyleDeclaration('div.cc-window a.cc-btn{border-radius:' . intval($this->cParams->get('popup_border_radius', 0) / 2) . 'px}'); $document->addStyleSheet(JUri::root(true) . '/plugins/system/gdpr/assets/css/cookieconsent.min.css'); // Add a separate CSS stylesheet for the center extended theme $cookieCategoriesDescriptions = 'cookieCategoriesDescriptions: {},'; if($this->cParams->get('position', 'bottom') == 'center' && $this->cParams->get('center_theme', 'compact') == 'extended') { $document->addStyleSheet(JUri::root(true) . '/plugins/system/gdpr/assets/css/cookieconsent.xtd.min.css'); $cookieCategoriesDescriptions = "cookieCategoriesDescriptions: {" . "categoryReadMore: '" . JText::_($this->cParams->get('category_read_more', 'Open category settings'), true) . "'," . "cat1:'" . JString::str_ireplace(array("\r\n", "\n", "\r"), ' ', JText::_($this->cParams->get('cookie_category1_description', 'Necessary cookies help make a website usable by enabling basic functions like page navigation and access to secure areas of the website. The website cannot function properly without these cookies.'), true)) . "'," . "cat2:'" . JString::str_ireplace(array("\r\n", "\n", "\r"), ' ', JText::_($this->cParams->get('cookie_category2_description', 'Preference cookies enable a website to remember information that changes the way the website behaves or looks, like your preferred language or the region that you are in.'), true)) . "'," . "cat3:'" . JString::str_ireplace(array("\r\n", "\n", "\r"), ' ', JText::_($this->cParams->get('cookie_category3_description', 'Statistic cookies help website owners to understand how visitors interact with websites by collecting and reporting information anonymously.'), true)) . "'," . "cat4:'" . JString::str_ireplace(array("\r\n", "\n", "\r"), ' ', JText::_($this->cParams->get('cookie_category4_description', 'Marketing cookies are used to track visitors across websites. The intention is to display ads that are relevant and engaging for the individual user and thereby more valuable for publishers and third party advertisers.'), true)) . "'},"; } $ccpaStatesArray = $this->cParams->get('usa_ccpa', array('0')); $ccpaStatesJson = in_array('0', $ccpaStatesArray, true) ? 'null' : json_encode($ccpaStatesArray); $this->configurationOptionsScript = "var gdprConfigurationOptions = { complianceType: '" . $this->cParams->get('compliance_type', 'opt-in') . "', cookieConsentLifetime: " . $this->cParams->get('cookie_consent_lifetime', 365) . ", cookieConsentSamesitePolicy: '" . $this->cParams->get('cookie_consent_samesite_policy', '') . "', cookieConsentSecure: " . $this->cParams->get('cookie_consent_secure', 0) . ", disableFirstReload: " . $this->cParams->get('disable_first_reload', 0) . ", blockJoomlaSessionCookie: " . $this->cParams->get('block_joomla_session_cookie', 1) . ", blockExternalCookiesDomains: " . $this->cParams->get('block_external_cookies_domains', 0) . ", externalAdvancedBlockingModeCustomAttribute: '" . addcslashes(trim($this->cParams->get('external_advanced_blocking_mode_custom_attribute', '')), "'") . "', allowedCookies: '" . addcslashes($this->cParams->get('allow_local_cookies', ''), "'") . "', blockCookieDefine: " . $this->cParams->get('block_cookie_define', 1) . ", autoAcceptOnNextPage: " . $this->cParams->get('auto_accept_on_next_page', 0) . ", revokable: " . $this->cParams->get('revokable', 1) . ", lawByCountry: " . $this->cParams->get('lawbycountry', 0) . ", checkboxLawByCountry: " . $this->cParams->get('checkboxlawbycountry', 0) . ", blockPrivacyPolicy: " . $this->cParams->get('block_privacypolicy', 0) . ", cacheGeolocationCountry: " . $this->cParams->get('cache_geolocation_country', 1) . ", countryAcceptReloadTimeout: " . $this->cParams->get('country_accept_reload_timeout', 1000) . ", usaCCPARegions: " . $ccpaStatesJson . ", dismissOnScroll: " . (int)$this->cParams->get('dismiss_onscroll', 0) . ", dismissOnTimeout: " . (int)$this->cParams->get('dismiss_ontimeout', 0) . ", containerSelector: '" . addcslashes($this->cParams->get('container_selector', 'body'), "'") . "', hideOnMobileDevices: " . (int)$this->cParams->get('hide_on_mobile_devices', 0) . ", autoFloatingOnMobile: " . (int)$this->cParams->get('auto_floating_on_mobile', 0) . ", autoFloatingOnMobileThreshold: " . (int)$this->cParams->get('auto_floating_on_mobile_threshold', 1024) . ", autoRedirectOnDecline: " . (int)$this->cParams->get('auto_redirect_on_decline', 0) . ", autoRedirectOnDeclineLink: '" . JText::_($this->cParams->get('auto_redirect_on_decline_link', ''), true) . "', showReloadMsg: " . (int)$this->cParams->get('show_reload_message', 0) . ", showReloadMsgText: '" . JText::_($this->cParams->get('show_reload_message_text', ''), true) . "', defaultClosedToolbar: " . (int)$this->cParams->get('default_closed_toolbar', 0) . ", toolbarLayout: '" . $this->cParams->get('layout', 'basic') . "', toolbarTheme: '" . $this->cParams->get('theme', 'block') . "', toolbarButtonsTheme: '" . $this->cParams->get('buttons_theme', 'decline_first') . "', revocableToolbarTheme: '" . $this->cParams->get('revocabletheme', 'basic') . "', toolbarPosition: '" . $this->cParams->get('position', 'bottom') . "', toolbarCenterTheme: '" . $this->cParams->get('center_theme', 'compact') . "', revokePosition: '" . $this->cParams->get('revokeposition', 'revoke-top') . "', toolbarPositionmentType: " . $this->cParams->get('positionment_type', 1) . ", positionCenterSimpleBackdrop: " . $this->cParams->get('position_center_simple_backdrop', 0) . ", positionCenterBlurEffect: " . $this->cParams->get('position_center_blur_effect', 0) . ", preventPageScrolling: " . $this->cParams->get('prevent_page_scrolling', 0) . ", popupEffect: '" . $this->cParams->get('popup_effect', 'fade') . "', popupBackground: '" . $this->cParams->get('popup_background', '#000000') . "', popupText: '" . $this->cParams->get('popup_text', '#FFFFFF') . "', popupLink: '" . $this->cParams->get('popup_link', '#FFFFFF') . "', buttonBackground: '" . $this->cParams->get('button_background', '#FFFFFF') . "', buttonBorder: '" . $this->cParams->get('button_border', '#FFFFFF') . "', buttonText: '" . $this->cParams->get('button_text', '#000000') . "', highlightOpacity: '" . $this->cParams->get('popup_background_opacity', '100') . "', highlightBackground: '" . $this->cParams->get('highlight_background', '#333333') . "', highlightBorder: '" . $this->cParams->get('highlight_border', '#FFFFFF') . "', highlightText: '" . $this->cParams->get('highlight_text', '#FFFFFF') . "', highlightDismissBackground: '" . $this->cParams->get('highlight_dismiss_background', '#333333') . "', highlightDismissBorder: '" . $this->cParams->get('highlight_dismiss_border', '#FFFFFF') . "', highlightDismissText: '" . $this->cParams->get('highlight_dismiss_text', '#FFFFFF') . "', hideRevokableButton: " . $this->cParams->get('hide_revokable_button', 0) . ", hideRevokableButtonOnscroll: " . $this->cParams->get('hide_revokable_button_onscroll', 0) . ", customRevokableButton: " . $this->cParams->get('custom_revokable_button', 0) . ", customRevokableButtonAction: " . $this->cParams->get('custom_revokable_button_action', 0) . ", headerText: '" . JString::str_ireplace(array("\r\n", "\n", "\r"), ' ', $this->fixRelativeLinks(JText::_($this->cParams->get('header', 'Cookies used on the website!'), true))) . "', messageText: '" . trim(JString::str_ireplace(array("\r\n", "\n", "\r", "<p>", "</p>"), ' ', $this->fixRelativeLinks(JText::_($this->cParams->get('message', 'This website uses cookies to ensure you get the best experience on our website.'), true)))) . "', denyMessageEnabled: " . $this->cParams->get('deny_message_enabled', 0) . ", denyMessage: '" . trim(JString::str_ireplace(array("\r\n", "\n", "\r", "<p>", "</p>"), ' ', $this->fixRelativeLinks(JText::_($this->cParams->get('deny_message', 'You have declined cookies, to ensure the best experience on this website please consent the cookie usage.'), true)))) . "', placeholderBlockedResources: " . $this->cParams->get('placeholder_blocked_resources', 0) . ", placeholderBlockedResourcesAction: '" . $this->cParams->get('placeholder_blocked_resources_action', '') . "', placeholderBlockedResourcesText: '" . JText::_($this->cParams->get('placeholder_blocked_resources_text', 'You must accept cookies and reload the page to view this content'), true) . "', placeholderIndividualBlockedResourcesText: '" . JText::_($this->cParams->get('placeholder_invididual_blocked_resources_text', 'You must accept cookies from {domain} and reload the page to view this content'), true) . "', placeholderIndividualBlockedResourcesAction: " . $this->cParams->get('placeholder_individual_blocked_resources_action', 0) . ", placeholderOnpageUnlock: " . $this->cParams->get('placeholder_onpage_unlock', 0) . ", scriptsOnpageUnlock: " . $this->cParams->get('scripts_onpage_unlock', 0) . ", dismissText: '" . JText::_($this->cParams->get('dismiss_text', 'Got it!'), true) . "', allowText: '" . JText::_($this->cParams->get('allow_text', 'Allow cookies'), true) . "', denyText: '" . JText::_($this->cParams->get('deny_text', 'Decline'), true) . "', cookiePolicyLinkText: '" . JText::_($this->cParams->get('cookie_policy_link_text', ''), true) . "', cookiePolicyLink: '" . JText::_($this->cParams->get('cookie_policy_link', 'javascript:void(0)'), true) . "', cookiePolicyRevocableTabText: '" . JText::_($this->cParams->get('cookie_policy_revocable_tab_text', 'Cookie policy'), true) . "', privacyPolicyLinkText: '" . JText::_($this->cParams->get('privacy_policy_link_text', ''), true) . "', privacyPolicyLink: '" . JText::_($this->cParams->get('privacy_policy_link', 'javascript:void(0)'), true) . "', enableGdprBulkConsent: " . (int)$this->cParams->get('enable_gdpr_bulk_consent', 0) . ", enableCustomScriptExecGeneric: " . (int)$this->cParams->get('enable_custom_script_exec_generic', 0) . ", customScriptExecGeneric: '" . JString::str_ireplace(array("\r\n", "\n", "\r"), '', addcslashes($this->cParams->get('custom_script_exec_generic', ''), "'")) . "', categoriesCheckboxTemplate: '" . $this->cParams->get('categories_checkbox_template', 'cc-checkboxes-light') . "', toggleCookieSettings: " . (int)$this->cParams->get('toggle_cookie_settings', 0) . ", toggleCookieSettingsLinkedView: " . (int)$this->cParams->get('toggle_cookie_settings_linked_view', 0) . ", toggleCookieSettingsLinkedViewSefLink: '" . JRoute::_('index.php?option=com_gdpr&view=user') . "', toggleCookieSettingsText: '<span class=\"cc-cookie-settings-toggle\">" . JText::_($this->cParams->get('toggle_cookie_settings_text', 'Settings'), true) . " <span class=\"cc-cookie-settings-toggler\">&#x25EE;</span></span>', toggleCookieSettingsButtonBackground: '" . $this->cParams->get('toggle_cookie_settings_button_background', '#333333') . "', toggleCookieSettingsButtonBorder: '" . $this->cParams->get('toggle_cookie_settings_button_border', '#FFFFFF') . "', toggleCookieSettingsButtonText: '" . $this->cParams->get('toggle_cookie_settings_button_text', '#FFFFFF') . "', showLinks: " . (int)$this->cParams->get('show_links', 1) . ", blankLinks: '" . $this->cParams->get('blank_links', '_blank') . "', autoOpenPrivacyPolicy: " . (int)$this->cParams->get('auto_open_privacy_policy', 0) . ", openAlwaysDeclined: " . (int)$this->cParams->get('open_always_declined', 1) . ", cookieSettingsLabel: '" . JText::_($this->cParams->get('cookie_settings_label', 'Cookie settings:'), true) . "', cookieSettingsDesc: '" . JText::_($this->cParams->get('cookie_settings_desc', 'Choose which kind of cookies you want to disable by clicking on the checkboxes. Click on a category name for more informations about used cookies.'), true) . "', cookieCategory1Enable: " . (int)$this->cParams->get('cookie_category1_enable', 0) . ", cookieCategory1Name: '" . JText::_($this->cParams->get('cookie_category1_name', 'Necessary'), true) . "', cookieCategory1Locked: " . (int)$this->cParams->get('cookie_category1_locked', 0) . ", cookieCategory2Enable: " . (int)$this->cParams->get('cookie_category2_enable', 0) . ", cookieCategory2Name: '" . JText::_($this->cParams->get('cookie_category2_name', 'Preferences'), true) . "', cookieCategory2Locked: " . (int)$this->cParams->get('cookie_category2_locked', 0) . ", cookieCategory3Enable: " . (int)$this->cParams->get('cookie_category3_enable', 0) . ", cookieCategory3Name: '" . JText::_($this->cParams->get('cookie_category3_name', 'Statistics'), true) . "', cookieCategory3Locked: " . (int)$this->cParams->get('cookie_category3_locked', 0) . ", cookieCategory4Enable: " . (int)$this->cParams->get('cookie_category4_enable', 0) . ", cookieCategory4Name: '" . JText::_($this->cParams->get('cookie_category4_name', 'Marketing'), true) . "', cookieCategory4Locked: " . (int)$this->cParams->get('cookie_category4_locked', 0) . ", $cookieCategoriesDescriptions alwaysReloadAfterCategoriesChange: " . (int)$this->cParams->get('always_reload_after_categories_change', 0) . ", preserveLockedCategories: " . (int)$this->cParams->get('preserve_locked_categories', 0) . ", reloadOnfirstDeclineall: " . (int)$this->cParams->get('reload_onfirst_declineall', 0) . ", trackExistingCheckboxSelectors: '" . addcslashes(trim($this->cParams->get('track_existing_checkbox_selectors', '')), "'") . "', trackExistingCheckboxConsentLogsFormfields: '" . addcslashes(trim($this->cParams->get('consent_logs_formfields', 'name,email,subject,message'), ','), "'") . "', allowallShowbutton: " . (int)$this->cParams->get('allowall_showbutton', 0) . ", allowallText: '" . JText::_($this->cParams->get('allowall_text', 'Allow all cookies'), true) . "', allowallButtonBackground: '" . $this->cParams->get('allowall_button_background', '#FFFFFF') . "', allowallButtonBorder: '" . $this->cParams->get('allowall_button_border', '#FFFFFF') . "', allowallButtonText: '" . $this->cParams->get('allowall_button_text', '#000000') . "', allowallButtonTimingAjax: '" . $this->cParams->get('allowall_button_timing_ajax', 'fast') . "', includeAcceptButton: " . (int)$this->cParams->get('include_accept_button', 0) . ", trackConsentDate: " . (int)$this->cParams->get('track_consent_date', 0) . ", optoutIndividualResources: " . (int)$this->cParams->get('optout_individual_resources', 0) . ", blockIndividualResourcesServerside: " . (int)$this->cParams->get('block_individual_resources_serverside', 0) . ", disableSwitchersOptoutCategory: " . (int)$this->cParams->get('disable_switchers_optout_category', 0) . ", allowallIndividualResources: " . (int)$this->cParams->get('allowall_individual_resources', 1) . ", blockLocalStorage: " . (int)$this->cParams->get('block_local_storage', 0) . ", blockSessionStorage: " . (int)$this->cParams->get('block_session_storage', 0) . ", externalAdvancedBlockingModeTags: '" . addcslashes(trim($this->cParams->get('external_advanced_blocking_mode_tags', 'iframe,script,img,source,link'), ','), "'") . "', enableCustomScriptExecCategory1: " . (int)$this->cParams->get('enable_custom_script_exec_category1', 0) . ", customScriptExecCategory1: '" . JString::str_ireplace(array("\r\n", "\n", "\r"), '', addcslashes($this->cParams->get('custom_script_exec_category1', ''), "'")) . "', enableCustomScriptExecCategory2: " . (int)$this->cParams->get('enable_custom_script_exec_category2', 0) . ", customScriptExecCategory2: '" . JString::str_ireplace(array("\r\n", "\n", "\r"), '', addcslashes($this->cParams->get('custom_script_exec_category2', ''), "'")) . "', enableCustomScriptExecCategory3: " . (int)$this->cParams->get('enable_custom_script_exec_category3', 0) . ", customScriptExecCategory3: '" . JString::str_ireplace(array("\r\n", "\n", "\r"), '', addcslashes($this->cParams->get('custom_script_exec_category3', ''), "'")) . "', enableCustomScriptExecCategory4: " . (int)$this->cParams->get('enable_custom_script_exec_category4', 0) . ", customScriptExecCategory4: '" . JString::str_ireplace(array("\r\n", "\n", "\r"), '', addcslashes($this->cParams->get('custom_script_exec_category4', ''), "'")) . "', debugMode: " . (int)$this->cParams->get('debug', 0) . " };"; $document->addScriptDeclaration($this->configurationOptionsScript); $document->addScriptDeclaration("var gdpr_ajax_livesite='" . JUri::base() . "';"); $document->addScriptDeclaration("var gdpr_enable_log_cookie_consent=" . (int)$this->cParams->get('enable_log_cookie_consent', 1) . ";"); // Load ajax endpoint for cookie categories $cookieCategories = false; if( $this->cParams->get('compliance_type', 'opt-in') != 'info' && ((int)$this->cParams->get('cookie_category1_enable', 0) || (int)$this->cParams->get('cookie_category2_enable', 0) || (int)$this->cParams->get('cookie_category3_enable', 0) || (int)$this->cParams->get('cookie_category4_enable', 0))) { $document->addScriptDeclaration("var gdprUseCookieCategories=1;"); $document->addScriptDeclaration("var gdpr_ajaxendpoint_cookie_category_desc='" . JUri::base() . "index.php?option=com_gdpr&task=user.getCookieCategoryDescription&format=raw" . $this->languageQueryStringParam . "';"); $cookieConsentComplianceCookie = true; $cookieCategories = true; $this->hasCookieCategory = true; $session = $this->app->getSession(); if($session->get('gdpr_cookie_category_disabled_1', 0) == 1 || (!$session->get('gdpr_cookie_category_disabled_1', 0) && !$this->cParams->get('cookie_category1_checked', 1))) { $document->addScriptDeclaration("var gdprCookieCategoryDisabled1=1;"); if(!$session->get('gdpr_cookie_category_disabled_1', 0) && !$this->cParams->get('cookie_category1_checked', 1)) { $session->set('gdpr_cookie_category_disabled_1', 1); } } if($session->get('gdpr_cookie_category_disabled_2', 0) == 1 || (!$session->get('gdpr_cookie_category_disabled_2', 0) && !$this->cParams->get('cookie_category2_checked', 0))) { $document->addScriptDeclaration("var gdprCookieCategoryDisabled2=1;"); if(!$session->get('gdpr_cookie_category_disabled_2', 0) && !$this->cParams->get('cookie_category2_checked', 0)) { $session->set('gdpr_cookie_category_disabled_2', 1); } } if($session->get('gdpr_cookie_category_disabled_3', 0) == 1 || (!$session->get('gdpr_cookie_category_disabled_3', 0) && !$this->cParams->get('cookie_category3_checked', 0))) { $document->addScriptDeclaration("var gdprCookieCategoryDisabled3=1;"); if(!$session->get('gdpr_cookie_category_disabled_3', 0) && !$this->cParams->get('cookie_category3_checked', 0)) { $session->set('gdpr_cookie_category_disabled_3', 1); } } if($session->get('gdpr_cookie_category_disabled_4', 0) == 1 || (!$session->get('gdpr_cookie_category_disabled_4', 0) && !$this->cParams->get('cookie_category4_checked', 0))) { $document->addScriptDeclaration("var gdprCookieCategoryDisabled4=1;"); if(!$session->get('gdpr_cookie_category_disabled_4', 0) && !$this->cParams->get('cookie_category4_checked', 0)) { $session->set('gdpr_cookie_category_disabled_4', 1); } } if($this->hasCookieCategory) { $document->addScriptDeclaration("var gdprJSessCook='" . $this->app->getSession()->getName() . "';"); $document->addScriptDeclaration("var gdprJSessVal='" . $this->app->getSession()->getId() . "';"); $document->addScriptDeclaration("var gdprJAdminSessCook='" . md5(JApplicationHelper::getHash('administrator')) . "';"); $document->addScriptDeclaration("var gdprPropagateCategoriesSession=" . (int)$this->cParams->get('propagate_categories_session', 1) . ";"); $document->addScriptDeclaration("var gdprAlwaysPropagateCategoriesSession=" . (int)$this->cParams->get('always_propagate_categories_session', 1) . ";"); } } if($this->cParams->get('use_fancybox_links', 0) || $cookieCategories) { $this->loadComponentLanguage(); if($this->cParams->get('use_gdpr_fancybox', 1)) { $document->addStyleSheet(JUri::root(true) . '/plugins/system/gdpr/assets/css/jquery.fancybox.min.css'); $document->addScript(JUri::root(true) . '/plugins/system/gdpr/assets/js/jquery.fancybox.min.js', 'text/javascript', true); } $document->addScriptDeclaration("var gdprFancyboxWidth=" . (int)$this->cParams->get('fancybox_width', 700) . ";"); $document->addScriptDeclaration("var gdprFancyboxHeight=" . (int)$this->cParams->get('fancybox_height', 800) . ";"); $document->addScriptDeclaration("var gdprCloseText='" . JText::_('COM_GDPR_CLOSE_POPUP_TEXT', true) . "';"); } // Load popup if($this->cParams->get('use_fancybox_links', 0)) { $formatPopup = $this->cParams->get('popup_format_template', 1) ? 'tmpl=component' : 'format=raw'; $document->addScriptDeclaration("var gdprUseFancyboxLinks=1;"); if($this->cParams->get('use_cookie_policy_contents', 0)) { $document->addScriptDeclaration("var gdpr_ajaxendpoint_cookie_policy='" . JUri::base() . "index.php?option=com_gdpr&task=user.getCookiePolicy&$formatPopup" . $this->languageQueryStringParam . "';"); } if($this->cParams->get('use_privacy_policy_contents', 0)) { $document->addScriptDeclaration("var gdpr_ajaxendpoint_privacy_policy='" . JUri::base() . "index.php?option=com_gdpr&task=user.getPrivacyPolicy&$formatPopup" . $this->languageQueryStringParam . "';"); } } // Hide the decline button if required to opt-in once only if($this->cParams->get('remove_decline_button', 0)) { $document->addStyleDeclaration('a.cc-btn.cc-deny{display:none}'); } // Hide the dismiss button if($this->cParams->get('remove_dismiss_button', 0)) { $document->addStyleDeclaration('a.cc-btn.cc-dismiss{display:none}'); } // Custom rounded styles for switchers if($this->cParams->get('switcher_style', 'square') == 'rounded' && $this->cParams->get('position', 'bottom') == 'center' && $this->cParams->get('center_theme', 'compact') == 'compact') { $document->addStyleDeclaration('fieldset.cc-cookie-list-title .gdpr_onoffswitch-label,fieldset.cc-cookie-list-title .gdpr_cookie_switcher span.gdpr_onoffswitch-switch,div.gdpr-component-view span.cc-checkboxes-placeholder,div.gdpr-component-view div.cc-checkboxes-container input.cc-cookie-checkbox+span::before{border-radius:10px}div.gdpr-component-view div.cc-checkboxes-container input.cc-cookie-checkbox+span::before{height: 14px;bottom: 2px;left:3px}div.gdpr-component-view div.cc-checkboxes-container input.cc-cookie-checkbox:checked+span::before{transform:translateX(22px)}'); } if($this->cParams->get('switcher_style', 'square') == 'rounded' && $this->cParams->get('position', 'bottom') == 'center' && $this->cParams->get('center_theme', 'compact') == 'extended') { $document->addStyleDeclaration('div.cc-checkboxes-container input.cc-cookie-checkbox+span,fieldset.cc-cookie-list-title .gdpr_cookie_switcher label.gdpr_onoffswitch-label{border-radius:15px}div.cc-checkboxes-container input.cc-cookie-checkbox+span::before{border-radius:10px;height:14px;bottom: 2px;width:14px}fieldset.cc-cookie-list-title .gdpr_cookie_switcher span.gdpr_onoffswitch-switch{border-radius:10px;height:14px;top:2px;right:3px}fieldset.cc-cookie-list-title .gdpr_onoffswitchcookie.gdpr_cookie_switcher.disabled .gdpr_onoffswitch-switch{right:25px}div.cc-checkboxes-container input.cc-cookie-checkbox:checked+span::before{left:8px}div.cc-checkboxes-container input.cc-cookie-checkbox+span::before{left:3px}div.gdpr-component-view span.cc-checkboxes-placeholder,div.gdpr-component-view div.cc-checkboxes-container input.cc-cookie-checkbox+span::before{border-radius:10px}div.gdpr-component-view div.cc-checkboxes-container input.cc-cookie-checkbox+span::before{height: 14px;bottom: 2px;left:3px}div.gdpr-component-view div.cc-checkboxes-container input.cc-cookie-checkbox:checked+span::before{transform:translateX(22px)}'); } // Add custom styles if any if($customCssStyles = trim($this->cParams->get('custom_css_styles', ''))) { $document->addStyleDeclaration($customCssStyles); } if($this->cParams->get('privacy_policy_checkbox_consent_date', 0) || $this->cParams->get('privacy_policy_dynamic_checkbox_consent_date', 0)) { if($this->cParams->get('privacy_policy_checkbox_consent_date_style', 'newline') == 'newline') { $document->addStyleDeclaration('label.gdpr_privacy_policy_consent_date{display:block;margin:5px 0;font-size:12px;color:#6c757d;cursor:auto}'); } else { $document->addStyleDeclaration('label.gdpr_privacy_policy_consent_date{display:inline-block;margin:0 5px;font-size:12px;color:#6c757d;cursor:auto}'); } } // Evaluate the bulk consent for other linked domains if($this->cParams->get('enable_gdpr_bulk_consent', 0)) { // Check if this client has already a valid local consent, in such case it does not need a bulk consent check $cookieConsentComplianceCookie = $this->app->input->cookie->get('cookieconsent_status'); $db = JFactory::getDbo(); $currentUser = JFactory::getUser(); $currentUserIdQuery = $currentUser->id > 0 ? " OR " . $db->quoteName('user_id') . " = " . $db->quote($currentUser->id) : null; $ipaddress = $_SERVER['REMOTE_ADDR']; $consentLifeTime = $this->cParams->get('cookie_consent_lifetime', 365); $dateStartingValidConsent = $db->quote(date('Y-m-d', strtotime("-" . $consentLifeTime . " days", time()))); $query = $db->getQuery(true) ->select($db->quoteName('id')) ->from($db->quoteName('#__gdpr_cookie_consent_registry')) ->where($db->quoteName('ipaddress') . " = " . $db->quote($ipaddress)) ->where($db->quoteName('consent_date') . " > " . $dateStartingValidConsent) ->where("(" . $db->quoteName('session_id') . " = " . $db->quote(session_id()) . $currentUserIdQuery . ")"); $db->setQuery($query); $localCookieConsent = $db->loadResult(); $linkedDomains = explode(PHP_EOL, trim($this->cParams->get('bulk_consent_domains', ''))); if(!$localCookieConsent && !$cookieConsentComplianceCookie && $linkedDomains && $ipaddress) { // Auto loader setup // Register autoloader prefix require_once JPATH_ROOT . '/administrator/components/com_gdpr/framework/loader.php'; GdprLoader::setup(); GdprLoader::registerPrefix('Gdpr', JPATH_ROOT . '/administrator/components/com_gdpr/framework'); // Select the HTTP connector transport $httpTransport = $this->cParams->get ( 'bulk_consent_api_transport', 'curl' ) == 'socket' ? new GdprHttpTransportSocket() : new GdprHttpTransportCurl (); $httpTransport->forceFollowRedirect = true; $httpConnector = new GdprHttp($httpTransport); $localDomain = JUri::base(); foreach ($linkedDomains as &$singleLinkedDomain) { if($singleLinkedDomain) { $singleLinkedDomain = rtrim(trim($singleLinkedDomain), '/') . '/'; if($singleLinkedDomain != $localDomain) { $apiURL = $singleLinkedDomain . 'index.php?option=com_gdpr&task=user.checkBulkConsent&format=json&client_ipaddress=' . $ipaddress . '&key=' . md5($ipaddress); try { $response = $httpConnector->get($apiURL); } catch (Exception $e) { // No error handling go on with the process for other domains continue; } if($response->code == 200 && $response->body) { $document->addScriptDeclaration("var gdprBulkConsent=1;"); $document->addScriptDeclaration("var gdprBulkConsents='" . $response->body . "';"); break; } } } } } } // Load cookieconsent $document->addScript(JUri::root(true) . '/plugins/system/gdpr/assets/js/cookieconsent.min.js', 'text/javascript', true); $document->addScript(JUri::root(true) . '/plugins/system/gdpr/assets/js/init.js', 'text/javascript', true); } /** * Application event after rendering * Here is the place to manipulate the Joomla output and remove external resources * Keep in mind that the ordering of execution of system plugins matters * * @access public */ public function onAfterRender() { // Avoid operations if plugin is executed in backend if ( $this->app->isAdmin ()) { return; } // Output JS APP nel Document if(!$this->cParams->get('kill_cookies_ajax_requests', 0)) { $document = JFactory::getDocument(); if($document->getType() !== 'html' || $this->app->input->getCmd ( 'tmpl' ) === 'component') { return; } } else { // Ensure we are not applying and auto killing com_gdpr popup domains if($this->app->input->get('option') == 'com_gdpr' && $this->app->input->get('fancybox') == 'true') { return; } } // Not enabled feature if(!$this->cParams->get('enable_cookie_consent', 1)) { return; } // Validate execution for this component if(!$this->validateExecution('exclude_cookie_consent')) { return; } // Check permissions exclusions if($this->checkExclusionPermissions('disallow_cookie')) { return; } // Block external cookies by domain if($this->cParams->get('block_external_cookies_domains', 0)) { if($this->cParams->get('compliance_type', 'opt-in') == 'opt-in' ) { $cookieConsentComplianceCookie = $this->app->input->cookie->get('cookieconsent_status'); if(!$cookieConsentComplianceCookie || $cookieConsentComplianceCookie == 'deny') { $this->killExternalResources(); } } if($this->cParams->get('compliance_type', 'opt-in') == 'opt-out') { $session = $this->app->getSession(); $cookieConsentComplianceCookie = $this->app->input->cookie->get('cookieconsent_status'); if($cookieConsentComplianceCookie == 'deny' || $session->get('gdpr_generic_cookie_consent_denyall', 0)) { $this->killExternalResources(); } } } // Block local cookies by name if($this->cParams->get('block_local_cookies_server_side', 0)) { if($this->cParams->get('compliance_type', 'opt-in') == 'opt-in' ) { $cookieConsentComplianceCookie = $this->app->input->cookie->get('cookieconsent_status'); if(!$cookieConsentComplianceCookie || $cookieConsentComplianceCookie == 'deny') { $this->killLocalCookies(); } } if($this->cParams->get('compliance_type', 'opt-in') == 'opt-out') { $session = $this->app->getSession(); $cookieConsentComplianceCookie = $this->app->input->cookie->get('cookieconsent_status'); if($cookieConsentComplianceCookie == 'deny' || $session->get('gdpr_generic_cookie_consent_denyall', 0)) { $this->killLocalCookies(); } } } // Block cookies by category if blocking compliance type and there is a 'deny all', an explicit category disable or an implicit category disabled $cookieConsentStatus = $this->app->input->cookie->get('cookieconsent_status'); $complianceType = $this->cParams->get('compliance_type', 'opt-in'); if($complianceType != 'info') { $session = $this->app->getSession(); $blockCheckedCategoriesByDefault = (int)$this->cParams->get('block_checked_categories_by_default', 0) && !$this->app->input->cookie->get('cookieconsent_status'); if( (int)$this->cParams->get('cookie_category1_enable', 0) && ($cookieConsentStatus == 'deny' || $session->get('gdpr_generic_cookie_consent_denyall', 0) || $session->get('gdpr_cookie_category_disabled_1', 0) == 1 || (!$session->get('gdpr_cookie_category_disabled_1', 0) && (!$this->cParams->get('cookie_category1_checked', 1) || $blockCheckedCategoriesByDefault)))) { // Check for services cookies/domains translation in this category $servicesCategory1 = $this->cParams->get('services_category1_list', array()); $cookieCategory1List = trim($this->cParams->get('cookie_category1_list', '')); if(!empty($servicesCategory1)) { foreach ($servicesCategory1 as $serviceCategory1Array) { if($serviceCategory1Array->cookies) { $lineFeed = $cookieCategory1List ? PHP_EOL : null; $cookieCategory1List .= $lineFeed . trim($serviceCategory1Array->cookies); } } } if($cookieCategory1List) { $this->killLocalCookies($cookieCategory1List, 1); } $domainsCategory1List = trim($this->cParams->get('domains_category1_list', '')); if(!empty($servicesCategory1)) { foreach ($servicesCategory1 as $serviceCategory1Array) { if($serviceCategory1Array->domains) { $lineFeed = $domainsCategory1List ? PHP_EOL : null; $domainsCategory1List .= $lineFeed . trim($serviceCategory1Array->domains); } } } if($domainsCategory1List) { $this->killExternalResources($domainsCategory1List, 1); } } if( (int)$this->cParams->get('cookie_category2_enable', 0) && ($cookieConsentStatus == 'deny' || $session->get('gdpr_generic_cookie_consent_denyall', 0) || $session->get('gdpr_cookie_category_disabled_2', 0) == 1 || (!$session->get('gdpr_cookie_category_disabled_2', 0) && (!$this->cParams->get('cookie_category2_checked', 0) || $blockCheckedCategoriesByDefault)))) { // Check for services cookies/domains translation in this category $servicesCategory2 = $this->cParams->get('services_category2_list', array()); $cookieCategory2List = trim($this->cParams->get('cookie_category2_list', '')); if(!empty($servicesCategory2)) { foreach ($servicesCategory2 as $serviceCategory2Array) { if($serviceCategory2Array->cookies) { $lineFeed = $cookieCategory2List ? PHP_EOL : null; $cookieCategory2List .= $lineFeed . trim($serviceCategory2Array->cookies); } } } if($cookieCategory2List) { $this->killLocalCookies($cookieCategory2List, 2); } $domainsCategory2List = trim($this->cParams->get('domains_category2_list', '')); if(!empty($servicesCategory2)) { foreach ($servicesCategory2 as $serviceCategory2Array) { if($serviceCategory2Array->domains) { $lineFeed = $domainsCategory2List ? PHP_EOL : null; $domainsCategory2List .= $lineFeed . trim($serviceCategory2Array->domains); } } } if($domainsCategory2List) { $this->killExternalResources($domainsCategory2List, 2); } } if( (int)$this->cParams->get('cookie_category3_enable', 0) && ($cookieConsentStatus == 'deny' || $session->get('gdpr_generic_cookie_consent_denyall', 0) || $session->get('gdpr_cookie_category_disabled_3', 0) == 1 || (!$session->get('gdpr_cookie_category_disabled_3', 0) && (!$this->cParams->get('cookie_category3_checked', 0) || $blockCheckedCategoriesByDefault)))) { // Check for services cookies/domains translation in this category $servicesCategory3 = $this->cParams->get('services_category3_list', array()); $cookieCategory3List = trim($this->cParams->get('cookie_category3_list', '')); if(!empty($servicesCategory3)) { foreach ($servicesCategory3 as $serviceCategory3Array) { if($serviceCategory3Array->cookies) { $lineFeed = $cookieCategory3List ? PHP_EOL : null; $cookieCategory3List .= $lineFeed . trim($serviceCategory3Array->cookies); } } } if($cookieCategory3List) { $this->killLocalCookies($cookieCategory3List, 3); } $domainsCategory3List = trim($this->cParams->get('domains_category3_list', '')); if(!empty($servicesCategory3)) { foreach ($servicesCategory3 as $serviceCategory3Array) { if($serviceCategory3Array->domains) { $lineFeed = $domainsCategory3List ? PHP_EOL : null; $domainsCategory3List .= $lineFeed . trim($serviceCategory3Array->domains); } } } if($domainsCategory3List) { $this->killExternalResources($domainsCategory3List, 3); } } if( (int)$this->cParams->get('cookie_category4_enable', 0) && ($cookieConsentStatus == 'deny' || $session->get('gdpr_generic_cookie_consent_denyall', 0) || $session->get('gdpr_cookie_category_disabled_4', 0) == 1 || (!$session->get('gdpr_cookie_category_disabled_4', 0) && (!$this->cParams->get('cookie_category4_checked', 0) || $blockCheckedCategoriesByDefault)))) { // Check for services cookies/domains translation in this category $servicesCategory4 = $this->cParams->get('services_category4_list', array()); $cookieCategory4List = trim($this->cParams->get('cookie_category4_list', '')); if(!empty($servicesCategory4)) { foreach ($servicesCategory4 as $serviceCategory4Array) { if($serviceCategory4Array->cookies) { $lineFeed = $cookieCategory4List ? PHP_EOL : null; $cookieCategory4List .= $lineFeed . trim($serviceCategory4Array->cookies); } } } if($cookieCategory4List) { $this->killLocalCookies($cookieCategory4List, 4); } $domainsCategory4List = trim($this->cParams->get('domains_category4_list', '')); if(!empty($servicesCategory4)) { foreach ($servicesCategory4 as $serviceCategory4Array) { if($serviceCategory4Array->domains) { $lineFeed = $domainsCategory4List ? PHP_EOL : null; $domainsCategory4List .= $lineFeed . trim($serviceCategory4Array->domains); } } } if($domainsCategory4List) { $this->killExternalResources($domainsCategory4List, 4); } } // Evaluate if there are any gdprCookiesChoices into the session for single resources block if($this->cParams->get('block_individual_resources_serverside', 0)) { $cookiesChoicesString = $session->get('cookieschoices', '{}'); $cookiesChoicesArray = json_decode($cookiesChoicesString, true); if(!empty($cookiesChoicesArray)) { $cookiesStringed = null; $domainsStringed = null; foreach ($cookiesChoicesArray as $cookieOrDomain=>$type) { // True? cookie if($type) { $cookiesStringed .= $cookieOrDomain . PHP_EOL; } // False? Domain if(!$type) { $domainsStringed .= $cookieOrDomain . PHP_EOL; } } // Found cookies to block? if($cookiesStringed) { $cookiesStringed = rtrim($cookiesStringed, PHP_EOL); $this->killLocalCookies($cookiesStringed); } // Found domains to block? if($domainsStringed) { $domainsStringed = rtrim($domainsStringed, PHP_EOL); $this->killExternalResources($domainsStringed, null, true); } } } // Add JS var domain for unset categories cookies if($this->cParams->get('block_local_cookies_server_side', 0) && count($this->unsetCategoriesCookies)) { $body = $this->app->getBody (); // Replace buffered main view contents at the body end $body = preg_replace ( "/<\/head>/i", "<script>var gdpr_unset_categories_cookies=" . json_encode($this->unsetCategoriesCookies) . ";</script></head>", $body, 1 ); // Set the new JResponse contents $this->app->setBody ( $body ); } } // If JCHOptimize detected and enable noconflict JCH enabled if ($this->cParams->get('jch_noconflict', 1) && $jchPlugin = JPluginHelper::getPlugin('system', 'jch_optimize')) { $jchParams = json_decode($jchPlugin->params); if($jchParams->combine_files_enable){ $this->addConfigToHead(); } } // If scripts no conflict mode is enabled if ($this->cParams->get('scripts_noconflict', 0)) { $this->addConfigToHead(); } } /** Add supports for custom component views, custom manifest and forms not triggering onContentPrepareForm event * * @access public * @return void */ public function onAfterRoute() { // Avoid operations if plugin is executed in backend if ( $this->app->isAdmin ()) { // Kill com_joomlaupdate informations about extensions missing updater info, leave only main one $doc = JFactory::getDocument(); if(version_compare(JVERSION, '3.10', '>=') && version_compare(JVERSION, '4.0', '<') && !$this->app->get('jextstore_joomlaupdate_script') && $this->app->input->get('option') == 'com_joomlaupdate' && !$this->app->input->get('view') && !$this->app->input->get('task')) { $doc->addScriptDeclaration (" window.addEventListener('DOMContentLoaded', function(e) { if(document.querySelector('#pre-update-check')) { var jextensionsIntervalCount = 0; var jextensionsIntervalTimer = setInterval(function() { [].slice.call(document.querySelectorAll('#compatibilitytype1 tbody tr td.exname, #preupdatecheckheadings tbody tr[id^=plg_] td:first-child')).forEach(function(td) { let txt = td.innerText; if (txt && txt.toLowerCase().match(/jsitemap|gdpr|responsivizer|jchatsocial|jcomment|jrealtime|jspeed|jredirects|vsutility|visualstyles|visual\sstyles|instant\sfacebook\slogin|instantpaypal|screen\sreader|jspeed|jamp/i)) { td.parentElement.style.display = 'none'; td.parentElement.classList.remove('error'); td.parentElement.classList.add('jextcompatible'); } }); [].slice.call(document.querySelectorAll('#compatibilitytype2 tbody tr td.exname')).forEach(function(td) { let txt = td.innerText; if (txt && txt.toLowerCase().match(/jsitemap|gdpr|responsivizer|jchatsocial|jcomment|jrealtime|jspeed|jredirects|vsutility|visualstyles|visual\sstyles|instant\sfacebook\slogin|instantpaypal|screen\sreader|jspeed|jamp/i)) { td.parentElement.classList.remove('error'); td.parentElement.classList.add('jextcompatible'); let smallLabels = td.querySelectorAll(':scope span.label'); [].slice.call(smallLabels).forEach(function(element) { element.style.display = 'none'; }); } }); if (document.querySelectorAll('#compatibilitytype0 tbody tr').length == 0 && document.querySelectorAll('#compatibilitytype1 tbody tr:not(.jextcompatible)').length == 0 && document.querySelectorAll('#compatibilitytype2 tbody tr:not(.jextcompatible)').length == 0) { [].slice.call(document.querySelectorAll('#preupdatecheckbox, #preupdateCheckCompleteProblems')).forEach(function(element) { element.style.display = 'none'; }); if(document.querySelector('#noncoreplugins')) { document.querySelector('#noncoreplugins').checked = true; } if(document.querySelector('button.submitupdate')) { document.querySelector('button.submitupdate').disabled = false; document.querySelector('button.submitupdate').classList.remove('disabled'); } }; if (document.querySelectorAll('#compatibilitytype0 tbody tr').length == 0 && document.querySelectorAll('#preupdatecheckheadings tbody tr:not(.jextcompatible)').length == 0) { [].slice.call(document.querySelectorAll('#preupdatecheckheadings, #preupdateconfirmation')).forEach(function(element) { element.style.display = 'none'; }); }; if (document.querySelectorAll('#compatibilitytype0 tbody tr').length == 0) { if(document.querySelectorAll('#compatibilitytype1 tbody tr:not(.jextcompatible)').length == 0) { let compatibilityTable1 = document.querySelector('#compatibilitytype1'); if(compatibilityTable1) { compatibilityTable1.style.display = 'none'; } } clearInterval(jextensionsIntervalTimer); } jextensionsIntervalCount++; }, 1000); }; });"); $this->app->set('jextstore_joomlaupdate_script', true); } return; } $document = JFactory::getDocument(); if($document->getType() !== 'html') { return; } // Initialize the multilanguage status if($this->app->getLanguageFilter()) { $knownLangs = JLanguageHelper::getLanguages(); $defaultLanguageCode = JFactory::getLanguage()->getTag(); foreach ($knownLangs as $knownLang) { if($knownLang->lang_code == $defaultLanguageCode) { $this->languageQueryStringParam = '&lang=' . $knownLang->sef; break; } } } // Manage the session cookie destroy if cookie consent is not accepted/enabled and the Joomla! session cookie is blocked if($this->validateExecution('exclude_cookie_consent') && !$this->checkExclusionPermissions('disallow_cookie') && !$this->app->get('offline')) { // Check if the Joomla! session cookie block option is enabled if($this->cParams->get('block_joomla_session_cookie', 1)) { $option = $this->app->input->get('option'); $task = $this->app->input->get('task'); $op2 = $this->app->input->get('op2'); if($this->cParams->get('compliance_type', 'opt-in') == 'opt-in' ) { $cookieConsentComplianceCookie = $this->app->input->cookie->get('cookieconsent_status'); if(!$cookieConsentComplianceCookie || $cookieConsentComplianceCookie == 'deny') { if(( $option == 'com_users' && $task == 'user.login') || ($option == 'com_easysocial' && $task == 'login') || ($option == 'com_comprofiler' && $op2 == 'login') || ($option == 'com_kunena' && $task == 'login')) { $session = $this->app->getSession(); $session->destroy(); $this->app->redirect ( JRoute::_('index.php?gdprcookielogin=1') ); } } } if($this->cParams->get('compliance_type', 'opt-in') == 'opt-out') { $cookieConsentComplianceCookie = $this->app->input->cookie->get('cookieconsent_status'); if($cookieConsentComplianceCookie == 'deny') { if(( $option == 'com_users' && $task == 'user.login') || ($option == 'com_easysocial' && $task == 'login') || ($option == 'com_comprofiler' && $op2 == 'login') || ($option == 'com_kunena' && $task == 'login')) { $session = $this->app->getSession(); $session->destroy(); $this->app->redirect ( JRoute::_('index.php?gdprcookielogin=1') ); } } } } } // Trigger simulate the onContentPrepareForm for third parties extensions not using JForm // Get the dispatched option and view $option = $this->app->input->get('option'); $view = $this->app->input->get('view'); // Fallback for old extension using a task mapping if(!$view && $this->app->input->get('task')) { $view = $this->app->input->get('task'); } // Fallback for old extension using a func mapping if(!$view && $this->app->input->get('func')) { $view = $this->app->input->get('func'); } // Fallback for old extension using a ctrl mapping if(!$view && $this->app->input->get('ctrl')) { $view = $this->app->input->get('ctrl'); } // Fallback to the whole component if(!$view) { $view = '*'; } $dispatchedFirm = $option . '.' . $view; // If debug mode is enabled show the form name for configuration purpouse if($this->cParams->get('debug', 0) && $document->getType() === 'html') { echo '<label style="font-size:14px;background-color:#8d0000;color:#FFF;border-radius:5px;padding:10px;display:inline-block;margin:2px"><span style="font-size:16px;font-weight:bold">Component.View: </span>' . $dispatchedFirm . '</label>'; } // Support for custom component forms $customComponentsUserprofileButtonsArray = array(); if($customComponentsViewUserprofileButtons = trim($this->cParams->get('custom_components_view_userprofile_buttons', ''))) { $customComponentsUserprofileButtons = trim($this->cParams->get('custom_components_userprofile_buttons', '')); $customComponentsUserprofileButtons .= PHP_EOL . $customComponentsViewUserprofileButtons; $this->cParams->set('custom_components_userprofile_buttons', $customComponentsUserprofileButtons); $customComponentsUserprofileButtonsArray = explode(PHP_EOL, trim($this->cParams->get('custom_components_userprofile_buttons', ''))); if(!empty($customComponentsUserprofileButtonsArray)) { foreach ($customComponentsUserprofileButtonsArray as &$customComponentUserprofileButtonsArray) { $customComponentUserprofileButtonsArray = trim($customComponentUserprofileButtonsArray); } } } $customComponentsFormCheckboxArray = array(); if($customComponentsViewFormCheckbox = trim($this->cParams->get('custom_components_view_form_checkbox', ''))) { $customComponentsFormCheckbox = trim($this->cParams->get('custom_components_form_checkbox', '')); $customComponentsFormCheckbox .= PHP_EOL . $customComponentsViewFormCheckbox; $this->cParams->set('custom_components_form_checkbox', $customComponentsFormCheckbox); $customComponentsFormCheckboxArray = explode(PHP_EOL, trim($this->cParams->get('custom_components_form_checkbox', ''))); if(!empty($customComponentsFormCheckboxArray)) { foreach ($customComponentsFormCheckboxArray as &$customComponentFormCheckboxArray) { $customComponentFormCheckboxArray = trim($customComponentFormCheckboxArray); } } } // Check for custom third parties integrations manifest if($tpdIntegrations = $this->cParams->get('3pdintegration', array())) { foreach ($tpdIntegrations as $integratedExtension) { $manifest = $this->loadManifest($integratedExtension); if($manifest && is_object($manifest)) { // Inject the custom component view name for user profile buttons if(isset($manifest->custom_components_userprofile_buttons)) { if(is_array($manifest->custom_components_userprofile_buttons)) { $customComponentsUserprofileButtonsArray = array_merge ($customComponentsUserprofileButtonsArray, $manifest->custom_components_userprofile_buttons); } else { $customComponentsUserprofileButtonsArray[] = trim($manifest->custom_components_userprofile_buttons); } } // Inject the custom component form selector for user profile buttons if(isset($manifest->custom_components_view_userprofile_buttons_selector)) { $customComponentsViewUserprofileButtonsSelector = trim($this->cParams->get('custom_components_view_userprofile_buttons_selector', '')); if($customComponentsViewUserprofileButtonsSelector) { $customComponentsViewUserprofileButtonsSelector .= ',' . $manifest->custom_components_view_userprofile_buttons_selector; } else { $customComponentsViewUserprofileButtonsSelector = $manifest->custom_components_view_userprofile_buttons_selector; } $this->cParams->set('custom_components_view_userprofile_buttons_selector', $customComponentsViewUserprofileButtonsSelector); } // Inject the custom component view name for privacy checkbox if(isset($manifest->custom_components_form_checkbox)) { if(is_array($manifest->custom_components_form_checkbox)) { $customComponentsFormCheckboxArray = array_merge ($customComponentsFormCheckboxArray, $manifest->custom_components_form_checkbox); } else { $customComponentsFormCheckboxArray[] = trim($manifest->custom_components_form_checkbox); } } // Inject the custom component form selector or privacy checkbox if(isset($manifest->custom_components_view_form_checkbox_selector)) { $customComponentsViewFormCheckboxSelector = trim($this->cParams->get('custom_components_view_form_checkbox_selector', '')); if($customComponentsViewFormCheckboxSelector) { $customComponentsViewFormCheckboxSelector .= ',' . $manifest->custom_components_view_form_checkbox_selector; } else { $customComponentsViewFormCheckboxSelector = $manifest->custom_components_view_form_checkbox_selector; } $this->cParams->set('custom_components_view_form_checkbox_selector', $customComponentsViewFormCheckboxSelector); } } } } if(in_array($dispatchedFirm, $customComponentsUserprofileButtonsArray) || in_array($dispatchedFirm, $customComponentsFormCheckboxArray)) { $dummyForm = new JForm($dispatchedFirm); $dummyForm->load('<config><params></params></config>'); $currentCustomComponentsFormCheckbox = $this->cParams->get('custom_components_form_checkbox', null); $currentCustomComponentsFormCheckbox .= PHP_EOL . $dispatchedFirm; $this->cParams->set('custom_components_form_checkbox', $currentCustomComponentsFormCheckbox); $this->onContentPrepareForm($dummyForm, array()); } /** * Set the users component in order to allow the username to be editable */ if($this->cParams->get('override_change_login_name', 1)) { $userCParams = JComponentHelper::getParams('com_users'); $userCParams->set('change_login_name', 1); } /** * Evaluate if the user has revoked the privacy policy, in such case force a redirect to the user edit screen * 1- The user must me logged in * 2- The parameter must be enabled * 3- The user profile value must be 0 = revoked */ $userId = JFactory::getUser()->id; if($this->cParams->get('block_privacypolicy', 0) && $this->cParams->get('privacy_policy_checkbox', 1) && $this->app->input->get('option') != 'com_users' && $this->app->input->get('option') != 'com_comprofiler' && $this->app->input->get('option') != 'com_gdpr' && !$this->app->input->get('tmpl') == 'component' && (int)$userId > 0 && $this->validateExecution('exclude_privacycheckbox') && !$this->checkExclusionPermissions('disallow_privacypolicy')) { $db = JFactory::getDbo(); $query = $db->getQuery(true) ->select($db->quoteName('profile_value')) ->from($db->quoteName('#__user_profiles')) ->where($db->quoteName('user_id') . ' = ' . (int) $userId) ->where($db->quoteName('profile_key') . ' = ' . $db->quote('gdpr_consent_status')); $db->setQuery($query); $privacyPolicyConsent = $db->loadResult(); if ((int)$privacyPolicyConsent == 0) { $this->loadComponentLanguage(); $this->app->enqueueMessage(JText::_('COM_GDPR_REQUIRED_TOACCEPT_PRIVACY_POLICY'), 'notice'); $query = $db->getQuery(true) ->select($db->quoteName('requireReset')) ->from($db->quoteName('#__users')) ->where($db->quoteName('id') . ' = ' . (int) $userId); $db->setQuery($query); $requirePasswordReset = $db->loadResult(); if($requirePasswordReset) { $this->app->enqueueMessage(JText::_('JGLOBAL_PASSWORD_RESET_REQUIRED'), 'notice'); } // Core component or integration with CB if(in_array('cbuilder', $this->cParams->get('3pdintegration', array()))) { $this->app->redirect(JRoute::_('index.php?option=com_comprofiler&task=userDetails&gdprprivacyrequest=1', false)); } else { $this->app->redirect(JRoute::_('index.php?option=com_users&view=profile&layout=edit&gdprprivacyrequest=1', false)); } } } // Add a message for the user failed login because of cookies declined if($this->app->input->get('gdprcookielogin', 0) && !$userId) { $this->loadComponentLanguage(); $this->app->enqueueMessage(JText::_('COM_GDPR_REQUIRED_TOACCEPT_COOKIES_TOLOGIN'), 'notice'); } } /** * onAfterInitialise handler * Check if some dynamic checkbox are enabled and the app must be injected and started * * @access public * @return null */ public function onAfterDispatch() { // Avoid operations if plugin is executed in backend if ( $this->app->isAdmin ()) { return; } // Output JS APP nel Document $document = JFactory::getDocument(); if($document->getType() !== 'html') { return; } if($this->app->input->get('fancybox')) { return; } if($this->cParams->get('disable_dynamic_checkbox', 0)) { return; } // Check if any of the dynamic checkbox is enabled, if so inject script and start JS app $db = JFactory::getDbo(); $query = $db->getQuery(true); $query->select('id'); $query->select('placeholder'); $query->from($db->quoteName('#__gdpr_checkbox')); $results = $db->setQuery($query)->loadObjectList('placeholder'); // Found active dynamic checkbox if(count($results)) { $this->loadComponentLanguage(); //load the translation require_once JPATH_ROOT . '/administrator/components/com_gdpr/framework/helpers/language.php'; $gdprLanguage = GdprHelpersLanguage::getInstance(); $translations = array( 'COM_GDPR_DYNAMIC_PRIVACY_POLICY_ACCEPT', 'COM_GDPR_DYNAMIC_PRIVACY_POLICY_NOACCEPT' ); $gdprLanguage->injectJsTranslations($translations, $document); if($this->cParams->get('use_gdpr_fancybox', 1)) { $document->addStyleSheet(JUri::root(true) . '/plugins/system/gdpr/assets/css/jquery.fancybox.min.css'); $document->addScript(JUri::root(true) . '/plugins/system/gdpr/assets/js/jquery.fancybox.min.js', 'text/javascript', true); } $document->addScriptDeclaration("var gdpr_livesite='" . JUri::base() . "';"); $document->addScriptDeclaration("var gdprDynamicFancyboxWidth=" . (int)$this->cParams->get('fancybox_checkbox_width', 700) . ";"); $document->addScriptDeclaration("var gdprDynamicFancyboxHeight=" . (int)$this->cParams->get('fancybox_checkbox_height', 800) . ";"); $document->addScriptDeclaration("var gdprDynamicFancyboxCloseText='" . JText::_('COM_GDPR_CLOSE_POPUP_TEXT', true) . "';"); $document->addScriptDeclaration("var gdprDynamicCheckboxRequiredText='" . JText::_('COM_GDPR_PRIVACY_POLICY_REQUIRED', true) . "';"); $document->addScriptDeclaration("var gdprDynamicCheckboxArray='" . json_encode(array_keys($results)) . "';"); $document->addScriptDeclaration("var gdprDynamicCheckboxOrder = '" . $this->cParams->get('privacy_policy_checkbox_order', 'right') . "';"); $document->addScriptDeclaration("var gdprPrivacyPolicyDynamicCheckboxContainerTemplate = '" . addcslashes(JString::str_ireplace(array("\r\n", "\n", "\r"), ' ', $this->cParams->get('checkbox_template_container', "<div class='control-group'>{field}</div>")), "'") . "';"); $document->addScriptDeclaration("var gdprPrivacyPolicyDynamicCheckboxLabelTemplate = '" . addcslashes(JString::str_ireplace(array("\r\n", "\n", "\r"), ' ', $this->cParams->get('checkbox_template_label', "<div class='control-label' style='display:inline-block'>{label}</div>")), "'") . "';"); $document->addScriptDeclaration("var gdprPrivacyPolicyDynamicCheckboxCheckboxTemplate = '" . addcslashes(JString::str_ireplace(array("\r\n", "\n", "\r"), ' ', $this->cParams->get('checkbox_template_controls', "<div class='controls' style='display:inline-block;margin-left:20px'>{checkbox}</div>")), "'") . "';"); $document->addScriptDeclaration("var gdprDynamicCheckboxRemoveAttributes = " . (int)$this->cParams->get('remove_attributes', 1) . ";"); $document->addScriptDeclaration("var gdprDynamicForceSubmitButton = " . (int)$this->cParams->get('force_submit_button', 0) . ";"); $document->addScriptDeclaration("var gdprDynamicRemoveSubmitButtonEvents = " . (int)$this->cParams->get('remove_submit_button_events', 0) . ";"); $document->addScriptDeclaration("var gdprDynamicCheckboxCustomSubmissionMethodSelector = '" . addcslashes($this->cParams->get('custom_submission_method_selectors', 'input[type=submit],button[type=submit],button[type=button]'), "'") . "';"); $document->addScriptDeclaration("var gdprPrivacyPolicyDynamicControl = " . (int)$this->cParams->get('use_dynamic_checkbox', 1) . ";"); $document->addScriptDeclaration("var gdprDynamicCheckboxControlsClass = " . (int)$this->cParams->get('checkbox_controls_class', 0) . ";"); $document->addScriptDeclaration("var gdprDynamicCheckboxControlsClassList = '" . addcslashes(trim($this->cParams->get('checkbox_controls_class_list', 'required'), ' '), "'") . "';"); $document->addScriptDeclaration("var gdprDynamicCheckboxPopupFormatTemplate = '" . $this->cParams->get('dynamic_checkbox_popup_format_template', 'ajaxraw') . "';"); $document->addScriptDeclaration("var gdprCurrentSefLanguage='" . $this->languageQueryStringParam . "';"); $document->addScriptDeclaration("var gdprPrivacyPolicyDynamicCheckboxConsentDate = " . (int)$this->cParams->get('privacy_policy_dynamic_checkbox_consent_date', 0) . ";"); $document->addScript(JUri::root(true) . '/plugins/system/gdpr/assets/js/checkbox.js', 'text/javascript', true); } } /** * Log for user changes, optionally validating privacy policy checkbox server side * * @param array $user Holds the new user data. * @param boolean $isnew True if a new user is stored. * @param boolean $success True if user was successfully stored in the database. * @param string $msg Message. * * @return void * * @since 1.6 */ public function onUserBeforeSave($oldUser, $isnew, $newUser) { // Load component language $this->loadComponentLanguage(); // Skip always a new user creation if($isnew) { if($this->app->isSite() && $this->cParams->get('privacypolicy_serverside_validation', 0)) { // Check if the privacy policy field is in the request and is not checked $privacyPolicy = $this->app->input->getInt('gdpr_privacy_policy_checkbox'); // Exclusions only for checkbox - $this->cParams->set('privacy_policy_checkbox', 0) if(!$privacyPolicy && $this->cParams->get('privacy_policy_checkbox', 1) && $this->validateExecution('exclude_privacycheckbox') && !$this->checkExclusionPermissions('disallow_privacypolicy')) { throw new InvalidArgumentException(JText::_('COM_GDPR_PRIVACY_POLICY_NOT_ACCEPTED')); } } return; } // Manage the revokable privacy policy status here $privacyPolicy = 1; if(!$isnew) { if($this->app->isSite() && !in_array($this->app->input->get('task'), array('activate', 'confirm', 'login')) && !$this->app->input->get('fblogin') && ($this->cParams->get('revokable_privacypolicy', 0) || $this->app->input->get('gdprprivacyrequest', 0) || isset($newUser['privacyconsent']))) { // Exclusions only for checkbox - $this->cParams->set('privacy_policy_checkbox', 0) if(($this->cParams->get('privacy_policy_checkbox', 1) || isset($newUser['privacyconsent'])) && in_array($this->app->input->get('option'), array('com_users', 'com_comprofiler')) && $this->validateExecution('exclude_privacycheckbox') && !$this->checkExclusionPermissions('disallow_privacypolicy')) { // Check if the privacy policy field is in the request and is not checked. Missing = no more accepted and to flag 0 $privacyPolicy = $this->app->input->getInt('gdpr_privacy_policy_checkbox', 0); if(!isset($_REQUEST['gdpr_privacy_policy_checkbox']) && !$this->cParams->get('revokable_privacypolicy', 0) && isset($newUser['privacyconsent'])) { $privacyPolicy = $newUser['privacyconsent']['privacy']; } $db = JFactory::getDbo(); $query = "UPDATE " . $db->quotename('#__user_profiles') . "\n SET " . $db->quotename('profile_value') . " = " . (int)$privacyPolicy . "\n WHERE " . $db->quotename('profile_key') . " = " . $db->quote('gdpr_consent_status') . "\n AND " . $db->quotename('user_id') . " = " . (int)$newUser['id']; try { $db->setQuery($query)->execute(); } catch(Exception $e) { // No errors during the create log record phase } // UPDATE the content of the already generated user note if any if($this->cParams->get('log_usernote_privacypolicy', 1)) { $noteBody = $privacyPolicy ? JText::sprintf('COM_GDPR_PRIVACY_UPDATED_BODY', $newUser['name'], $newUser['email'], JDate::getInstance()->toSql()) : JText::sprintf('COM_GDPR_PRIVACY_REVOKED_BODY', $newUser['name'], $newUser['email'], JDate::getInstance()->toSql()); $query = "UPDATE " . $db->quotename('#__user_notes') . "\n SET " . $db->quotename('body') . " = " . $db->quote($noteBody) . "\n WHERE " . $db->quotename('user_id') . " = " . (int)$newUser['id'] . "\n AND " . $db->quotename('catid') . " = " .(int) $this->cParams->get('log_usernote_privacypolicy_category', 0) . "\n AND " . $db->quotename('subject') . " = " . $db->quote(JText::_('COM_GDPR_PRIVACY_ACCEPTED_SUBJECT')); try { $db->setQuery($query)->execute(); } catch(Exception $e) { // No errors during the create log record phase } } // Integration with Joomla 3.9+ Privacy tool suite if(version_compare(JVERSION, '3.9', '>=') && $this->cParams->get('log_userconsent_privacypolicy', 1)) { $privacyConsentBody = $privacyPolicy ? JText::sprintf('COM_GDPR_PRIVACY_GDPR_UPDATED_BODY', $newUser['name'], $newUser['email'], JDate::getInstance()->toSql()) : JText::sprintf('COM_GDPR_PRIVACY_GDPR_REVOKED_BODY', $newUser['name'], $newUser['email'], JDate::getInstance()->toSql()); // If log IP address if($this->cParams->get('log_user_ipaddress', 0)) { $privacyConsentBody .= JText::sprintf('COM_GDPR_PRIVACY_GDPR_BODY_IP_ADDRESS', $_SERVER['REMOTE_ADDR']); } $query = "UPDATE " . $db->quotename('#__privacy_consents') . "\n SET " . $db->quotename('body') . " = " . $db->quote($privacyConsentBody) . "\n WHERE " . $db->quotename('user_id') . " = " . (int)$newUser['id'] . "\n AND " . $db->quotename('subject') . " = " . $db->quote('COM_GDPR_PRIVACY_GDPR_ACCEPTED_SUBJECT') . "\n AND " . $db->quotename('state') . " = 1"; try { $db->setQuery($query)->execute(); } catch(Exception $e) { // No errors during the create log record phase } } /** * Special handling for old users having never inserted records */ if($this->app->input->get('gdprprivacyrequest', 0) || isset($newUser['privacyconsent'])) { //Check if the user_profiles status exists $query = $db->getQuery(true) ->select('1') ->from($db->quoteName('#__user_profiles')) ->where($db->quoteName('user_id') . ' = ' . (int) $newUser['id']) ->where($db->quoteName('profile_key') . ' = ' . $db->quote('gdpr_consent_status')); $db->setQuery($query); $consent = $db->loadObjectList(); if (!count($consent)) { // Add a profile key for the consent confirmation status $userProfileKey = (object) array( 'user_id' => (int) $newUser['id'], 'profile_key' => 'gdpr_consent_status', 'profile_value' => (int)$privacyPolicy ); try { $db->insertObject('#__user_profiles', $userProfileKey); } catch (Exception $e) { // No errors during the create log record phase } } //Check if the user_note exists if($this->cParams->get('log_usernote_privacypolicy', 1)) { $query = $db->getQuery(true) ->select('1') ->from($db->quoteName('#__user_notes')) ->where($db->quoteName('user_id') . ' = ' . (int) $newUser['id']) ->where($db->quoteName('catid') . ' = ' . (int)$this->cParams->get('log_usernote_privacypolicy_category', 0)) ->where($db->quoteName('subject') . ' = ' . $db->quote(JText::_('COM_GDPR_PRIVACY_ACCEPTED_SUBJECT'))); $db->setQuery($query); $userConsentNote = $db->loadObjectList(); if (!count($userConsentNote)) { $userNote = (object) array( 'user_id' => (int) $newUser['id'], 'catid' => $this->cParams->get('log_usernote_privacypolicy_category', 0), 'subject' => JText::_('COM_GDPR_PRIVACY_ACCEPTED_SUBJECT'), 'body' => $noteBody, 'state' => 1, 'created_user_id' => (int) $newUser['id'], 'modified_user_id' => (int) $newUser['id'], 'created_time' => JDate::getInstance()->toSql() ); try { $db->insertObject('#__user_notes', $userNote); } catch(Exception $e) { // No errors during the create log record phase } } } // Integration with Joomla 3.9+ Privacy tool suite if(version_compare(JVERSION, '3.9', '>=') && $this->cParams->get('log_userconsent_privacypolicy', 1)) { // Check and insert new record for never consented users on first login $userConsentRecord = array(); $query = $db->getQuery(true) ->select('1') ->from($db->quoteName('#__privacy_consents')) ->where($db->quoteName('user_id') . ' = ' . (int) $newUser['id']) ->where($db->quoteName('subject') . ' = ' . $db->quote('COM_GDPR_PRIVACY_GDPR_ACCEPTED_SUBJECT')) ->where($db->quoteName('state') . ' = 1'); try { $db->setQuery($query); $userConsentRecord = $db->loadObjectList(); } catch (Exception $e) { // No errors during the create log record phase } if (!count($userConsentRecord)) { // Create the user note $userPrivacyConsent = (object) array( 'user_id' => (int) $newUser['id'], 'subject' => 'COM_GDPR_PRIVACY_GDPR_ACCEPTED_SUBJECT', 'body' => $privacyConsentBody, 'created' => JDate::getInstance()->toSql(), 'state' => 1 ); try { $db->insertObject('#__privacy_consents', $userPrivacyConsent); } catch(Exception $e) { // No errors during the create log record phase } } } } } } } // Validate execution for this component if(!$this->validateExecution('exclude_logs')) { return; } // Check permissions exclusions if($this->checkExclusionPermissions('disallow_logs')) { return; } // Comparisons to find changes applied to this user $somethingChanged = false; $changes = array(); $db = JFactory::getDbo(); $editorUser = JFactory::getUser(); // Check for change_name rule $changeName = 0; if($oldUser['name'] != $newUser['name']) { $changes['change_name'] = array('oldvalue' => $oldUser['name'], 'newvalue' => $newUser['name']); $changeName = 1; $somethingChanged = true; } // Check for change_username rule $changeUsername = 0; if($oldUser['username'] != $newUser['username']) { $changes['change_username'] = array('oldvalue' => $oldUser['username'], 'newvalue' => $newUser['username']); $changeUsername = 1; $somethingChanged = true; } // Check for change_password rule $changePassword = 0; if($newUser['password'] && $oldUser['password'] != $newUser['password']) { $changePassword = 1; $somethingChanged = true; } // Check for change_email rule $changeEmail = 0; if($oldUser['email'] != $newUser['email']) { $changes['change_email'] = array('oldvalue' => $oldUser['email'], 'newvalue' => $newUser['email']); $changeEmail = 1; $somethingChanged = true; } // Check for change_email rule $changeParams = 0; if($oldUser['params'] != $newUser['params']) { // Decode oldParams $oldUserParams = json_decode($oldUser['params'], true); $newUserParams = json_decode($newUser['params'], true); $changedOldParams = array(); $changedNewParams = array(); foreach ($newUserParams as $paramName => $newParamValue) { if(!isset($oldUserParams[$paramName]) && $newParamValue) { $changedOldParams[$paramName] = null; $changedNewParams[$paramName] = $newParamValue; } else { if(isset($oldUserParams[$paramName])) { $oldParamValue = $oldUserParams[$paramName]; if($oldParamValue != $newParamValue) { $changedOldParams[$paramName] = $oldParamValue; $changedNewParams[$paramName] = $newParamValue; } } } } if(count($changedNewParams)) { $changes['change_params'] = array('oldvalue' => $changedOldParams, 'newvalue' => $changedNewParams); $changeParams = 1; $somethingChanged = true; } } // Add support for actionlogs fields if(isset($newUser['actionlogs'])) { $currentExtensionsLogsNotify = $newUser['actionlogs']['actionlogsNotify']; $currentExtensionsLogs = $newUser['actionlogs']['actionlogsExtensions']; // Found an extended user profile, go on and load old values to compare $query = "SELECT " . $db->quotename('notify') . ',' . $db->quotename('extensions') . "\n FROM " . $db->quotename('#__action_logs_users') . "\n WHERE " . $db->quotename('user_id') . " = " . (int) $newUser['id']; try { $oldExtensionsLogsSettings = $db->setQuery($query)->loadObject(); // Initialize empty object array if(!isset($oldExtensionsLogsSettings->extensions)) { $oldExtensionsLogsSettings = new stdClass(); $oldExtensionsLogsSettings->extensions = '[]'; } if($oldExtensionsLogsSettings->extensions) { // Decode oldParams $oldExtensionsLogs = json_decode($oldExtensionsLogsSettings->extensions); // Change differences $changedNewActionlogs = array_diff($currentExtensionsLogs, $oldExtensionsLogs); $changedOldActionlogs = array_diff($oldExtensionsLogs, $currentExtensionsLogs); if(count($changedNewActionlogs) || count($changedOldActionlogs)) { // Already exists a change in standard params? if(isset($changes['change_params'])) { $changes['change_params']['oldvalue'] = array_merge($changes['change_params']['oldvalue'], $oldExtensionsLogs); $changes['change_params']['newvalue'] = array_merge($changes['change_params']['newvalue'], $currentExtensionsLogs); } else { $changes['change_params'] = array('oldvalue' => $oldExtensionsLogs, 'newvalue' => $currentExtensionsLogs); } $changeParams = 1; $somethingChanged = true; } } // Initialize empty object value if(!isset($oldExtensionsLogsSettings->notify)) { $oldExtensionsLogsSettings->notify = 0; } if($oldExtensionsLogsSettings->notify != $currentExtensionsLogsNotify) { // Already exists a change in standard params? if(isset($changes['change_params'])) { $changes['change_params']['oldvalue']['actionlogsNotify'] = $oldExtensionsLogsSettings->notify; $changes['change_params']['newvalue']['actionlogsNotify'] = $currentExtensionsLogsNotify; } else { $changes['change_params'] = array('oldvalue' => array('actionlogsNotify'=>$oldExtensionsLogsSettings->notify), 'newvalue' => array('actionlogsNotify'=>$currentExtensionsLogsNotify)); } $changeParams = 1; $somethingChanged = true; } } catch(Exception $e) { // No errors during the create log record phase } } // Check for change_requirereset rule $changeRequirereset = 0; if($oldUser['requireReset'] != $newUser['requireReset']) { $changes['change_requirereset'] = array('oldvalue' => $oldUser['requireReset'], 'newvalue' => $newUser['requireReset']); $changeRequirereset = 1; $somethingChanged = true; } // Check for change_block rule $changeBlock = 0; if($oldUser['block'] != $newUser['block']) { $changes['change_block'] = array('oldvalue' => $oldUser['block'], 'newvalue' => $newUser['block']); $changeBlock = 1; $somethingChanged = true; } // Check for change_sendemail rule $changeSendemail = 0; if($oldUser['sendEmail'] != $newUser['sendEmail']) { $changes['change_sendemail'] = array('oldvalue' => $oldUser['sendEmail'], 'newvalue' => $newUser['sendEmail']); $changeSendemail = 1; $somethingChanged = true; } // Check for change_usergroups rule $changeUsergroups = 0; $groupsChanged = !(array_diff($oldUser['groups'], $newUser['groups']) === array_diff($newUser['groups'], $oldUser['groups'])); if($groupsChanged) { try { // Get old usergroups names $query = "SELECT " . $db->quoteName('title') . "\n FROM " . $db->quoteName('#__usergroups') . "\n WHERE " . $db->quoteName('id') . " IN(" . implode(',', $oldUser['groups']) . ")"; $oldUsergroupsName = $db->setQuery($query)->loadColumn(); // Get new usergroups names $query = "SELECT " . $db->quoteName('title') . "\n FROM " . $db->quoteName('#__usergroups') . "\n WHERE " . $db->quoteName('id') . " IN(" . implode(',', $newUser['groups']) . ")"; $newUsergroupsName = $db->setQuery($query)->loadColumn(); } catch(Exception $e) { // No errors during the create log record phase } $changes['change_usergroups'] = array('oldvalue' => $oldUsergroupsName, 'newvalue' => $newUsergroupsName); $changeUsergroups = 1; $somethingChanged = true; } // Check for change_requirereset rule change empty activation to something more useful $changeActivation = 0; if($oldUser['activation'] != $newUser['activation']) { $changes['change_activation'] = array('oldvalue' => $oldUser['activation'], 'newvalue' => $newUser['activation']); $changeActivation = 1; $somethingChanged = true; } // Check if $newUser has the profile array, in such case load old profile values for this user from #__user_profiles and compare them if(isset($newUser['profile'])) { // Found an extended user profile, go on and load old values to compare $query = "SELECT " . $db->quotename('profile_key') . " AS " . $db->quote('key') . ", " . $db->quotename('profile_value') . " AS " . $db->quote('value') . "\n FROM " . $db->quotename('#__user_profiles') . "\n WHERE " . $db->quotename('profile_key') . " != " . $db->quote('gdpr_consent_status') . "\n AND " . $db->quotename('profile_key') . " != " . $db->quote('profile.tos') . "\n AND " . $db->quotename('user_id') . " = " . (int) $newUser['id']; try { $oldProfileValues = $db->setQuery($query)->loadAssocList('key'); if(count($newUser['profile'])) { // Decode oldParams $oldUserProfileValues = $oldProfileValues; $newUserProfileValues = $newUser['profile']; $changedOldProfile = array(); $changedNewProfile = array(); foreach ($newUserProfileValues as $paramName => $newParamValue) { if(!isset($oldUserProfileValues['profile.'.$paramName]) && $newParamValue) { $changedOldProfile[$paramName] = null; $changedNewProfile[$paramName] = $newParamValue; } else { if(isset($oldUserProfileValues['profile.'.$paramName])) { // The value is json_encoded into the database rows by the user profile plugin $oldParamValue = json_decode($oldUserProfileValues['profile.'.$paramName]['value']); if($oldParamValue != $newParamValue) { $changedOldProfile[$paramName] = $oldParamValue; $changedNewProfile[$paramName] = $newParamValue; } } } } if(count($changedNewProfile)) { // Already exists a change in standard params? if(isset($changes['change_params'])) { $changes['change_params']['oldvalue'] = array_merge($changes['change_params']['oldvalue'], $changedOldProfile); $changes['change_params']['newvalue'] = array_merge($changes['change_params']['newvalue'], $changedNewProfile); } else { $changes['change_params'] = array('oldvalue' => $changedOldProfile, 'newvalue' => $changedNewProfile); } $changeParams = 1; $somethingChanged = true; } } } catch(Exception $e) { // No errors during the create log record phase } } // Add support for custom fields if(isset($newUser['com_fields'])) { // Found an extended user profile by custom fields, go on and load old values to compare $postedCustomFields = array_keys($newUser['com_fields']); foreach ($postedCustomFields as &$postedCustomField) { $postedCustomField = $db->quote($postedCustomField); } $postedCustomFields = implode(',', $postedCustomFields); $query = "SELECT " . $db->quotename('name') . " AS " . $db->quote('key') . ", " . $db->quotename('value') . " AS " . $db->quote('value') . "\n FROM " . $db->quotename('#__fields') . " AS " . $db->quotename('fieldstable') . "\n JOIN " . $db->quotename('#__fields_values') . " AS " . $db->quotename('fieldsvalues') . "\n ON fieldstable.id = fieldsvalues.field_id " . "\n WHERE fieldsvalues.item_id = " . (int) $newUser['id'] . "\n AND fieldstable.state = 1" . "\n AND fieldstable.name IN(" . $postedCustomFields .")"; try { $oldProfileFieldsValues = $db->setQuery($query)->loadAssocList('key'); if(count($newUser['com_fields'])) { // Decode oldParams $oldUserProfileFieldsValues = $oldProfileFieldsValues; $newUserProfileFieldsValues = $newUser['com_fields']; $changedFieldsOldProfile = array(); $changedFieldsNewProfile = array(); foreach ($newUserProfileFieldsValues as $paramName => $newParamValue) { if(!isset($oldUserProfileFieldsValues[$paramName]) && $newParamValue) { $changedFieldsOldProfile[$paramName] = null; $changedFieldsNewProfile[$paramName] = $newParamValue; } else { if(isset($oldUserProfileFieldsValues[$paramName])) { // The value is json_encoded into the database rows by the user profile plugin $oldParamValue = $oldUserProfileFieldsValues[$paramName]['value']; if($oldParamValue != $newParamValue && $newParamValue !== false) { $changedFieldsOldProfile[$paramName] = $oldParamValue; $changedFieldsNewProfile[$paramName] = $newParamValue; } } } } if(count($changedFieldsNewProfile)) { // Already exists a change in standard params? if(isset($changes['change_params'])) { $changes['change_params']['oldvalue'] = array_merge($changes['change_params']['oldvalue'], $changedFieldsOldProfile); $changes['change_params']['newvalue'] = array_merge($changes['change_params']['newvalue'], $changedFieldsNewProfile); } else { $changes['change_params'] = array('oldvalue' => $changedFieldsOldProfile, 'newvalue' => $changedFieldsNewProfile); } $changeParams = 1; $somethingChanged = true; } } } catch(Exception $e) { // No errors during the create log record phase } } // Won't log if no changes and empty savings are not enabled if(!$this->cParams->get('log_empty_save', 1) && !$somethingChanged) { return; } // Track created users into component db table JTable::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_gdpr/tables'); $logsTable = JTable::getInstance('Logs', 'Table'); $logsTable->user_id = $newUser['id']; $logsTable->name = $newUser['name']; $logsTable->username = $newUser['username']; $logsTable->email = $newUser['email']; $logsTable->change_name = $changeName; $logsTable->change_username = $changeUsername; $logsTable->change_password = $changePassword; $logsTable->change_email = $changeEmail; $logsTable->change_params = $changeParams; $logsTable->change_requirereset = $changeRequirereset; $logsTable->change_block = $changeBlock; $logsTable->change_sendemail = $changeSendemail; $logsTable->change_usergroups = $changeUsergroups; $logsTable->change_activation = $changeActivation; $logsTable->editor_user_id = $editorUser->id; $logsTable->editor_name = $editorUser->name; $logsTable->editor_username = $editorUser->username; $logsTable->change_date = JDate::getInstance()->toSql(); $logsTable->changes_structure = array('changes'=>$changes); $logsTable->created_user = 0; $logsTable->deleted_user = 0; $logsTable->privacy_policy = $privacyPolicy; // If log IP address if($this->cParams->get('log_user_ipaddress', 0)) { $logsTable->ipaddress = $_SERVER['REMOTE_ADDR']; } // Integration with Joomla 3.9+ Privacy tool suite if(version_compare(JVERSION, '3.9', '>=')) { if($this->app->input->get('option') == 'com_privacy' && $this->app->input->get('task') == 'remove' && $this->app->input->get('id')) { $logsTable->deleted_user = 1; // Pseudonymise the GDPR user note and GDPR privacy consent try { $queryNotes = "UPDATE " . $db->quotename('#__user_notes') . "\n SET " . $db->quotename('body') . " = " . $db->quote($logsTable->username) . "\n WHERE " . $db->quotename('user_id') . " = " . $logsTable->user_id . "\n AND " . $db->quotename('catid') . " = " . (int) $this->cParams->get('log_usernote_privacypolicy_category', 0) . "\n AND " . $db->quotename('subject') . " = " . $db->quote(JText::_('COM_GDPR_PRIVACY_ACCEPTED_SUBJECT')); $db->setQuery($queryNotes); $db->execute(); $queryConsents = "UPDATE " . $db->quotename('#__privacy_consents') . "\n SET " . $db->quotename('body') . " = " . $db->quote($logsTable->username) . "\n WHERE " . $db->quotename('user_id') . " = " . $logsTable->user_id . "\n AND " . $db->quotename('subject') . " = " . $db->quote('COM_GDPR_PRIVACY_GDPR_ACCEPTED_SUBJECT'); $db->setQuery($queryConsents); $db->execute(); } catch(Exception $e) { // No errors during the create log record phase } } } // Store without any user error visible exception try { $logsTable->store(); } catch(Exception $e) { // No errors during the create log record phase } } /** * Log for new user creation, optionally creates a user note for the agreement to the privacy policy * * @param array $user Holds the new user data. * @param boolean $isnew True if a new user is stored. * @param boolean $success True if user was successfully stored in the database. * @param string $msg Message. * * @return void * * @since 1.6 */ public function onUserAfterSave($newUser, $isnew, $success, $msg) { // Validate execution for this component if(!$this->validateExecution('exclude_logs')) { return; } // Check permissions exclusions if($this->checkExclusionPermissions('disallow_logs')) { return; } // Comparisons to find changes applied to this user $somethingChanged = false; $changes = array(); $originalUser = JFactory::getUser(); $editorUser = clone $originalUser; // Frontend self new registration, swap editor with himself if(!$editorUser->id) { $editorUser->id = $newUser['id']; $editorUser->name = $newUser['name']; $editorUser->username = $newUser['username']; } // Evaluate an accept of the Joomla 3.9+ Privacy tool suite, act the same as the GDPR one $privacyToolAccepted = false; if(version_compare(JVERSION, '3.9', '>=') && isset($newUser['privacyconsent'])) { if(isset($newUser['privacyconsent']['privacy']) == 1) { $privacyToolAccepted = true; } } // Log a user creation if($isnew && $this->cParams->get('log_user_create', 1)) { // Add a record in the log table about the deletion of this user $changes = array(); JTable::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_gdpr/tables'); $logsTable = JTable::getInstance('Logs', 'Table'); $logsTable->user_id = $newUser['id']; $logsTable->name = $newUser['name']; $logsTable->username = $newUser['username']; $logsTable->email = $newUser['email']; $logsTable->change_name = 0; $logsTable->change_username = 0; $logsTable->change_password = 0; $logsTable->change_email = 0; $logsTable->change_params = 0; $logsTable->change_requirereset = 0; $logsTable->change_block = 0; $logsTable->change_sendemail = 0; $logsTable->change_usergroups = 0; $logsTable->editor_user_id = $editorUser->id; $logsTable->editor_name = $editorUser->name; $logsTable->editor_username = $editorUser->username; $logsTable->change_date = JDate::getInstance()->toSql(); $logsTable->changes_structure = array('changes'=>$changes); $logsTable->created_user = 1; $logsTable->deleted_user = 0; if($this->app->input->getInt('gdpr_privacy_policy_checkbox') != 1 && !$privacyToolAccepted) { $logsTable->privacy_policy = 0; } // If log IP address if($this->cParams->get('log_user_ipaddress', 0)) { $logsTable->ipaddress = $_SERVER['REMOTE_ADDR']; } // Store without any user error visible exception try { $logsTable->store(); } catch(Exception $e) { // No errors during the create log record phase } } // Create a user note for privacy policy checkbox accepted if($isnew && ($this->app->input->getInt('gdpr_privacy_policy_checkbox') == 1 || $privacyToolAccepted)) { // Load component language $this->loadComponentLanguage(); $db = JFactory::getDbo(); if($this->cParams->get('log_usernote_privacypolicy', 1)) { $userNote = (object) array( 'user_id' => $logsTable->user_id, 'catid' => $this->cParams->get('log_usernote_privacypolicy_category', 0), 'subject' => JText::_('COM_GDPR_PRIVACY_ACCEPTED_SUBJECT'), 'body' => JText::sprintf('COM_GDPR_PRIVACY_ACCEPTED_BODY', $logsTable->name, $logsTable->email, $logsTable->change_date), 'state' => 1, 'created_user_id' => $logsTable->user_id, 'created_time' => $logsTable->change_date, 'modified_user_id' => $logsTable->user_id, 'modified_time' => $logsTable->change_date ); try { $db->insertObject('#__user_notes', $userNote); } catch(Exception $e) { // No errors during the create log record phase } } // Integration with Joomla 3.9+ Privacy tool suite if(version_compare(JVERSION, '3.9', '>=') && $this->cParams->get('log_userconsent_privacypolicy', 1)) { $privacyConsentBody = JText::sprintf('COM_GDPR_PRIVACY_GDPR_ACCEPTED_BODY', $logsTable->name, $logsTable->email, $logsTable->change_date); // If log IP address if($this->cParams->get('log_user_ipaddress', 0)) { $privacyConsentBody .= JText::sprintf('COM_GDPR_PRIVACY_GDPR_BODY_IP_ADDRESS', $_SERVER['REMOTE_ADDR']); } // Create the user consent $userPrivacyConsent = (object) array( 'user_id' => $logsTable->user_id, 'subject' => 'COM_GDPR_PRIVACY_GDPR_ACCEPTED_SUBJECT', 'body' => $privacyConsentBody, 'created' => $userNote->created_time, 'state' => 1 ); try { $db->insertObject('#__privacy_consents', $userPrivacyConsent); } catch (Exception $e) { // Do nothing if the save fails } } // Add a profile key for the consent confirmation status $userProfileKey = (object) array( 'user_id' => $logsTable->user_id, 'profile_key' => 'gdpr_consent_status', 'profile_value' => 1 ); try { $db->insertObject('#__user_profiles', $userProfileKey); } catch (Exception $e) { // No errors during the create log record phase } } } /** * Log user deletion, optionally notifying an admin about it * * Method is called after user data is deleted from the database * * @param array $user Holds the user data * @param boolean $success True if user was successfully stored in the database * @param string $msg Message * * @return boolean * * @since 1.6 */ public function onUserAfterDelete($user, $success, $msg) { // Validate execution for this component if(!$this->validateExecution('exclude_logs')) { return; } // Check permissions exclusions if($this->checkExclusionPermissions('disallow_logs')) { return; } // Log a user deletion if($this->cParams->get('log_user_delete', 1)) { // Add a record in the log table about the deletion of this user $changes = array(); $editorUser = JFactory::getUser(); JTable::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_gdpr/tables'); $logsTable = JTable::getInstance('Logs', 'Table'); $logsTable->user_id = $user['id']; $logsTable->name = $user['name']; $logsTable->username = $user['username']; $logsTable->email = $user['email']; $logsTable->change_name = 0; $logsTable->change_username = 0; $logsTable->change_password = 0; $logsTable->change_email = 0; $logsTable->change_params = 0; $logsTable->change_requirereset = 0; $logsTable->change_block = 0; $logsTable->change_sendemail = 0; $logsTable->change_usergroups = 0; $logsTable->editor_user_id = $editorUser->id; $logsTable->editor_name = $editorUser->name; $logsTable->editor_username = $editorUser->username; $logsTable->change_date = JDate::getInstance()->toSql(); $logsTable->changes_structure = array('changes'=>$changes); $logsTable->created_user = 0; $logsTable->deleted_user = 1; $logsTable->privacy_policy = 1; // If log IP address if($this->cParams->get('log_user_ipaddress', 0)) { $logsTable->ipaddress = $_SERVER['REMOTE_ADDR']; } // Store without any user error visible exception try { $logsTable->store(); } catch(Exception $e) { // No errors during the create log record phase } } // Optionally notifies an administrator about the user deletion by email // Notify a user deletion: notify ONLY own/itself user deletion $currentUser = JFactory::getUser (); if($this->cParams->get('notify_user_self_delete', 0) && $this->app->isSite() && $currentUser->id == $user['id']) { // Load component language $this->loadComponentLanguage(); // Joomla global configuration $jConfig = JFactory::getConfig(); // Check for notify email addresses $validEmailAddresses = array(); $emailAddresses = $this->cParams->get('logs_emails', ''); $emailAddresses = explode(',', $emailAddresses); if(!empty($emailAddresses)) { foreach ($emailAddresses as $validEmail) { if(filter_var(trim($validEmail), FILTER_VALIDATE_EMAIL)) { $validEmailAddresses[] = trim($validEmail); } } } if(!empty($validEmailAddresses)) { // Build the email subject and message $sitename = $jConfig->get('sitename'); $subject = JText::sprintf('COM_GDPR_USER_DELETED_OWN_PROFILE_SUBJECT', $sitename); $msg = JText::sprintf('COM_GDPR_USER_DELETED_OWN_PROFILE_MSG', $user['name'], $sitename, $user['name'], $user['username'], $user['email'], $logsTable->change_date); // Send the email $mailer = JFactory::getMailer(); $mailer->isHtml(true); $mailer->addReplyTo($user['email'], $user['name']); $mailer->setSender(array($this->cParams->get('logs_mailfrom', $jConfig->get('mailfrom')), $this->cParams->get('logs_fromname', $jConfig->get('fromname')))); $mailer->addRecipient($validEmailAddresses); $mailer->setSubject($subject); $mailer->setBody($msg); // The Send method will raise an error via JError on a failure, we do not need to check it ourselves here $mailer->Send(); } } return true; } /** * Extends forms by adding custom features: * - Privacy policy * - Delete profile btn * - Export profile btn * * @param Object $form * @param array $data * * @return boolean * * @since 1.6 */ function onContentPrepareForm($form, $data) { static $injectedGdprApp = false; // Avoid operations if plugin is executed in backend if ( $this->app->isAdmin ()) { // Check if the component language files must be loaded in the com_privacy component if($this->app->input->getCmd('option') == 'com_privacy' && $this->app->input->getCmd('view') == 'consents') { $this->loadComponentLanguage(); } return; } // Validate execution for this component if(!$this->validateExecution('exclude_userprofile')) { return; } // Exclusions only for checkbox - $this->cParams->set('privacy_policy_checkbox', 0) if(!$this->validateExecution('exclude_privacycheckbox')) { $this->cParams->set('privacy_policy_checkbox', 0); } // Only works on JForms if (!($form instanceof JForm)) return false; $document = JFactory::getDocument(); if($document->getType() !== 'html') { return; } // which belong to the following components $components_list = array( "com_users.profile", // Delete/Export btns "com_users.registration", // Checkbox "com_contact.contact" // Checkbox ); // Support for custom component forms $customComponentsUserprofileButtons = array(); if(trim($this->cParams->get('custom_components_userprofile_buttons', ''))) { $customComponentsUserprofileButtons = explode(PHP_EOL, trim($this->cParams->get('custom_components_userprofile_buttons', ''))); if(!empty($customComponentsUserprofileButtons)) { foreach ($customComponentsUserprofileButtons as &$customComponentsUserprofileButton) { $customComponentsUserprofileButton = trim($customComponentsUserprofileButton); } $components_list = array_merge($components_list, $customComponentsUserprofileButtons); } } $customComponentsFormCheckbox = array(); if(trim($this->cParams->get('custom_components_form_checkbox', ''))) { $customComponentsFormCheckbox = explode(PHP_EOL, trim($this->cParams->get('custom_components_form_checkbox', ''))); if(!empty($customComponentsFormCheckbox)) { foreach ($customComponentsFormCheckbox as &$customComponentFormCheckbox) { $customComponentFormCheckbox = trim($customComponentFormCheckbox); } $components_list = array_merge($components_list, $customComponentsFormCheckbox); } } // Grab the form name $formName = $form->getName(); // If debug mode is enabled show the form name for configuration purpouse if($debugMode = $this->cParams->get('debug', 0)) { echo '<label style="font-size:14px;background-color:#005e8d;color:#FFF;border-radius:5px;padding:10px;display:inline-block;margin:2px"><span style="font-size:16px;font-weight:bold">Form name: </span>' . $formName . '</label>'; } if (in_array($formName, $components_list) && !$injectedGdprApp) { $currentUser = JFactory::getUser(); $document->addScript(JUri::root(true) . '/plugins/system/gdpr/assets/js/user.js', 'text/javascript', true); if($debugMode) { echo '<label style="font-size:14px;border:3px solid #005e8d;color:#000;border-radius:5px;padding:10px;display:inline-block;margin:2px"><span style="font-size:16px;font-weight:bold">USER.JS Script Included</span></label>'; } // Load component language $this->loadComponentLanguage(); //load the translation require_once JPATH_ROOT . '/administrator/components/com_gdpr/framework/helpers/language.php'; $gdprLanguage = GdprHelpersLanguage::getInstance(); $translations = array( 'COM_GDPR_DELETE_PROFILE', 'COM_GDPR_EXPORT_CSV_PROFILE', 'COM_GDPR_EXPORT_XLS_PROFILE', 'COM_GDPR_EXPORT_PROFILE_REQUEST', 'COM_GDPR_PRIVACY_POLICY_REQUIRED', 'COM_GDPR_DELETE_PROFILE_CONFIRMATION', 'COM_GDPR_PRIVACY_POLICY_ACCEPT', 'COM_GDPR_PRIVACY_POLICY_NOACCEPT' ); $gdprLanguage->injectJsTranslations($translations, $document); $document->addScriptDeclaration("var gdpr_livesite='" . JUri::base() . "';"); $document->addScriptDeclaration("var gdprCurrentOption = '" . $this->app->input->getCmd('option') . "';"); $document->addScriptDeclaration("var gdprCurrentView = '" . $this->app->input->getCmd('view') . "';"); $document->addScriptDeclaration("var gdprCurrentTask = '" . $this->app->input->getCmd('task') . "';"); $document->addScriptDeclaration("var gdprCurrentLayout = '" . $this->app->input->getCmd('layout') . "';"); $document->addScriptDeclaration("var gdprCurrentUserId = " . (int)$currentUser->id . ";"); $document->addScriptDeclaration("var gdprDebugMode = " . (int)$debugMode . ";"); $document->addScriptDeclaration("var gdprDeleteButton = " . (int)$this->cParams->get('userprofile_buttons_delete', 1) . ";"); $document->addScriptDeclaration("var gdprExportButton = " . (int)$this->cParams->get('userprofile_buttons_export', 1) . ";"); $document->addScriptDeclaration("var gdprPrivacyPolicyCheckbox = " . (int)$this->cParams->get('privacy_policy_checkbox', 1) . ";"); $document->addScriptDeclaration("var gdprPrivacyPolicyCheckboxLinkText = '" .JText::_($this->cParams->get('privacy_policy_checkbox_link_text', 'Privacy policy'), true) . "';"); $document->addScriptDeclaration("var gdprPrivacyPolicyCheckboxLink = '" . JText::_($this->cParams->get('privacy_policy_checkbox_link', 'javascript:void(0)'), true) . "';"); $document->addScriptDeclaration("var gdprPrivacyPolicyCheckboxLinkTitle = '" .JText::_($this->cParams->get('privacy_policy_checkbox_link_title', 'Please agree to our privacy policy, otherwise you will not be able to register.'), true) . "';"); $document->addScriptDeclaration("var gdprPrivacyPolicyCheckboxOrder = '" . $this->cParams->get('privacy_policy_checkbox_order', 'right') . "';"); $document->addScriptDeclaration("var gdprRemoveAttributes = " . (int)$this->cParams->get('remove_attributes', 1) . ";"); $document->addScriptDeclaration("var gdprForceSubmitButton = " . (int)$this->cParams->get('force_submit_button', 0) . ";"); $document->addScriptDeclaration("var gdprRemoveSubmitButtonEvents = " . (int)$this->cParams->get('remove_submit_button_events', 0) . ";"); $document->addScriptDeclaration("var gdprPrivacyPolicyContainerTemplate = '" . addcslashes(JString::str_ireplace(array("\r\n", "\n", "\r"), ' ', $this->cParams->get('checkbox_template_container', "<div class='control-group'>{field}</div>")), "'") . "';"); $document->addScriptDeclaration("var gdprPrivacyPolicyLabelTemplate = '" . addcslashes(JString::str_ireplace(array("\r\n", "\n", "\r"), ' ', $this->cParams->get('checkbox_template_label', "<div class='control-label' style='display:inline-block'>{label}</div>")), "'") . "';"); $document->addScriptDeclaration("var gdprPrivacyPolicyCheckboxTemplate = '" . addcslashes(JString::str_ireplace(array("\r\n", "\n", "\r"), ' ', $this->cParams->get('checkbox_template_controls', "<div class='controls' style='display:inline-block;margin-left:20px'>{checkbox}</div>")), "'") . "';"); $document->addScriptDeclaration("var gdprPrivacyPolicyControl = " . (int)$this->cParams->get('use_checkbox', 1) . ";"); $document->addScriptDeclaration("var gdprFormSubmissionMethod = '" . $this->cParams->get('checkbox_submission_method', 'form') . "';"); $document->addScriptDeclaration("var gdprFormActionWorkingmode = '" . $this->cParams->get('userprofile_form_action_workingmode', 'base') . "';"); $document->addScriptDeclaration("var gdprCustomSubmissionMethodSelector = '" . addcslashes($this->cParams->get('custom_submission_method_selectors', 'input[type=submit],button[type=submit],button[type=button]'), "'") . "';"); $document->addScriptDeclaration("var gdprConsentLogsFormfields = '" . addcslashes(trim($this->cParams->get('consent_logs_formfields', 'name,email,subject,message'), ','), "'") . "';"); $document->addScriptDeclaration("var gdprConsentRegistryTrackPreviousConsent = " . (int)$this->cParams->get('consent_registry_track_previous_consent', 1) . ";"); $document->addScriptDeclaration("var gdprCustomAppendMethod = " . (int)$this->cParams->get('custom_append_method', 0) . ";"); $document->addScriptDeclaration("var gdprCustomAppendMethodSelector = '" . addcslashes($this->cParams->get('custom_append_method_selectors', 'input[type=submit],button[type=submit]'), "'") . "';"); $document->addScriptDeclaration("var gdprCustomAppendMethodTargetElement = '" . $this->cParams->get('custom_append_method_target_element', 'parent') . "';"); $document->addScriptDeclaration("var gdprCheckboxControlsClass = " . (int)$this->cParams->get('checkbox_controls_class', 0) . ";"); $document->addScriptDeclaration("var gdprCheckboxControlsClassList = '" . addcslashes(trim($this->cParams->get('checkbox_controls_class_list', 'required'), ' '), "'") . "';"); $document->addScriptDeclaration("var gdprPrivacyPolicyCheckboxConsentDate = " . (int)$this->cParams->get('privacy_policy_checkbox_consent_date', 0) . ";"); $document->addScriptDeclaration("var gdprUserprofileButtonsWorkingmode = " . (int)$this->cParams->get('userprofile_buttons_workingmode', 0) . ";"); if($customComponentsViewFormCheckboxSelector = trim($this->cParams->get('custom_components_view_form_checkbox_selector', ''))) { $document->addScriptDeclaration("var gdprCustomComponentsViewFormCheckboxSelector = '" . addcslashes($customComponentsViewFormCheckboxSelector, "'") . "';"); } if($customComponentsViewUserprofileButtonsSelector = trim($this->cParams->get('custom_components_view_userprofile_buttons_selector', ''))) { $document->addScriptDeclaration("var gdprCustomComponentsViewUserprofileButtonsSelector = '" . addcslashes($customComponentsViewUserprofileButtonsSelector, "'") . "';"); } // Inject permissions exclusions $disallowPrivacyPolicy = $this->checkExclusionPermissions('disallow_privacypolicy'); $document->addScriptDeclaration("var gdprDisallowPrivacyPolicy = " . ($disallowPrivacyPolicy ? 1 : 0) . ";"); $disallowDeleteProfile = $this->checkExclusionPermissions('disallow_deleteprofile'); $document->addScriptDeclaration("var gdprDisallowDeleteProfile = " . ($disallowDeleteProfile ? 1 : 0) . ";"); $disallowExportProfile = $this->checkExclusionPermissions('disallow_exportprofile'); $document->addScriptDeclaration("var gdprDisallowExportProfile = " . ($disallowExportProfile ? 1 : 0) . ";"); // Add later/revokable support for Joomla! profile form if($this->app->input->get('gdprprivacyrequest', 0)) { // Force the revokable mode on $this->cParams->set('revokable_privacypolicy', 1); $document->addScriptDeclaration("var gdprPropagateGdprPrivacyRequest = 1;"); } if((($formName == 'com_users.profile' && $this->app->input->getCmd('option') == 'com_users') || ($formName == 'com_comprofiler.userdetails' && $this->app->input->getCmd('option') == 'com_comprofiler')) && $currentUser->id && $this->cParams->get('revokable_privacypolicy', 0)) { $db = JFactory::getDbo(); $query = "SELECT " . $db->quotename('profile_value') . "\n FROM " . $db->quotename('#__user_profiles') . "\n WHERE " . $db->quotename('profile_key') . " = " . $db->quote('gdpr_consent_status') . "\n AND " . $db->quotename('user_id') . " = " . (int)$currentUser->id; try { $currentPrivacyConsentStatus = $db->setQuery($query)->loadResult(); $document->addScriptDeclaration("var gdprCurrentPrivacyConsentStatus = " . (int)$currentPrivacyConsentStatus . ";"); if($this->cParams->get('revokable_privacypolicy_always_mandatory', 0)) { $document->addScriptDeclaration("var gdprRevokablePrivacyPolicyAlwaysMandatory = 1;"); } } catch(Exception $e) { // No errors during the create log record phase } // Recover the date of the consent if($this->cParams->get('privacy_policy_checkbox_consent_date', 0)) { $query = "SELECT" . "\n logs.change_date ," . "\n logs.privacy_policy" . "\n FROM " . $db->quotename('#__gdpr_logs') . " AS logs" . "\n JOIN " . $db->quotename('#__user_profiles') . " AS profiles ON logs.user_id = profiles.user_id" . "\n WHERE logs.changes_structure = " . $db->quote('{"changes":[]}') . "\n AND logs.user_id = " . (int)$currentUser->id . "\n AND profiles.profile_key = " . $db->quote('gdpr_consent_status') . "\n AND profiles.profile_value = 1" . "\n ORDER BY logs.id DESC"; try { $currentPrivacyPolicyConsentDate = $db->setQuery($query)->loadObject(); if($currentPrivacyPolicyConsentDate && $currentPrivacyPolicyConsentDate->privacy_policy == 1) { $document->addScriptDeclaration("var gdprCurrentPrivacyPolicyConsentDate = '" . JText::sprintf('COM_GDPR_CONSENT_ACCEPTED_DATE', JHtml::_('date', $currentPrivacyPolicyConsentDate->change_date, JText::_('DATE_FORMAT_LC2')), array('jsSafe'=>true)) . "';"); } } catch(Exception $e) { // No errors during the create log record phase } } } // Support for custom component tasks $customFormsUserprofileButtons = array(); if(trim($this->cParams->get('custom_forms_userprofile_buttons', ''))) { $customFormsUserprofileButtons = explode(PHP_EOL, trim($this->cParams->get('custom_forms_userprofile_buttons', ''))); if(!empty($customFormsUserprofileButtons)) { foreach ($customFormsUserprofileButtons as &$customFormsUserprofileButton) { $customFormsUserprofileButton = trim($customFormsUserprofileButton); } $document->addScriptDeclaration("var gdprCustomFormsUserprofileButtons = " . json_encode($customFormsUserprofileButtons). ";"); } } $customFormsTaskCheckbox = array(); if(trim($this->cParams->get('custom_forms_task_checkbox', ''))) { $customFormsTaskCheckbox = explode(PHP_EOL, trim($this->cParams->get('custom_forms_task_checkbox', ''))); if(!empty($customFormsTaskCheckbox)) { foreach ($customFormsTaskCheckbox as &$customFormTaskCheckbox) { $customFormTaskCheckbox = trim($customFormTaskCheckbox); } $document->addScriptDeclaration("var gdprCustomFormsTaskCheckbox = " . json_encode($customFormsTaskCheckbox). ";"); } } // Load popup if($this->cParams->get('use_fancybox_checkbox', 0)) { if($this->cParams->get('use_gdpr_fancybox', 1)) { $document->addStyleSheet(JUri::root(true) . '/plugins/system/gdpr/assets/css/jquery.fancybox.min.css'); $document->addScript(JUri::root(true) . '/plugins/system/gdpr/assets/js/jquery.fancybox.min.js', 'text/javascript', true); } $document->addScriptDeclaration("var gdprUseFancyboxCheckbox=1;"); $document->addScriptDeclaration("var gdprFancyboxCheckboxWidth=" . (int)$this->cParams->get('fancybox_checkbox_width', 700) . ";"); $document->addScriptDeclaration("var gdprFancyboxCheckboxHeight=" . (int)$this->cParams->get('fancybox_checkbox_height', 800) . ";"); $document->addScriptDeclaration("var gdprCheckboxCloseText='" . JText::_('COM_GDPR_CLOSE_POPUP_TEXT', true) . "';"); if($this->cParams->get('use_checkbox_contents', 0)) { $formatPopup = $this->cParams->get('popup_format_template', 1) ? 'tmpl=component' : 'format=raw'; $document->addScriptDeclaration("var gdpr_ajaxendpoint_checkbox_policy='" . JUri::base() . "index.php?option=com_gdpr&task=user.getCheckboxPolicy&$formatPopup" . $this->languageQueryStringParam . "';"); } } $injectedGdprApp = true; } return true; } /** * Reports the privacy related capabilities for this plugin to site administrators. * * @return array */ public function onPrivacyCollectAdminCapabilities() { // Manage partial language translations $jLang = JFactory::getLanguage(); $jLang->load('com_gdpr', JPATH_ROOT . '/administrator/components/com_gdpr', 'en-GB', true, true); if($jLang->getTag() != 'en-GB') { $jLang->load('com_gdpr', JPATH_ROOT . '/administrator', null, true, false); $jLang->load('com_gdpr', JPATH_ROOT . '/administrator/components/com_gdpr', null, true, false); } return array( JText::_('COM_GDPR_PRIVACY_CAPABILITIES_TITLE') => array( JText::_('COM_GDPR_PRIVACY_CAPABILITIES_LOGS_USER_PROFILE'), JText::_('COM_GDPR_PRIVACY_CAPABILITIES_LOGS_USER_CONSENTS'), JText::_('COM_GDPR_PRIVACY_CAPABILITIES_COOKIE_MANAGEMENT'), JText::_('COM_GDPR_PRIVACY_CAPABILITIES_LOGS_COOKIE_CONSENTS'), JText::_('COM_GDPR_PRIVACY_CAPABILITIES_CONSENTS_REGISTRY'), JText::_('COM_GDPR_PRIVACY_CAPABILITIES_DATA_BREACH'), JText::_('COM_GDPR_PRIVACY_CAPABILITIES_RECORD_PROCESSING_ACTIVITIES'), JText::_('COM_GDPR_PRIVACY_CAPABILITIES_PROFILE_EXPORT_DELETION'), JText::_('COM_GDPR_PRIVACY_CAPABILITIES_REVOCABLE_CONSENT') ) ); } /** * Processes an export request by the Joomla! Privacy component * * This event will collect data for the following GDPR tables: * * - #__gdpr_consent_registry * - #__gdpr_cookie_consent_registry * - #__gdpr_logs * * @param PrivacyTableRequest Table object $request The request record being processed * * @return PrivacyExportDomain[] */ public function onPrivacyExportRequest($request) { if (!$request->email) { return array(); } if(!$this->cParams->get('integrate_comprivacy', 1)) { return array(); } // Check if the component language files must be loaded in the com_privacy component $this->loadComponentLanguage(); $db = JFactory::getDbo(); $userIdQuery = "SELECT " . $db->quoteName('id') . "\n FROM " . $db->quoteName('#__users') . "\n WHERE " . $db->quoteName('email') . " = " . $db->quote($request->email); $request->user_id = $db->setQuery($userIdQuery)->loadResult(); if (!$request->user_id) { return array(); } // Ensure to have class loading for the com_privacy helpers classes JLoader::register('PrivacyExportDomain', JPATH_ROOT . '/administrator/components/com_privacy/helpers/export/domain.php'); JLoader::register('PrivacyExportField', JPATH_ROOT . '/administrator/components/com_privacy/helpers/export/field.php'); JLoader::register('PrivacyExportItem', JPATH_ROOT . '/administrator/components/com_privacy/helpers/export/item.php'); // Init domains tables $domains = array(); // Initialize a domains assoc array $domainsToLoad = array ( 'gdpr_consent_registry' => array ( 'name' => JText::_('COM_GDPR_EXPORT_CONSENT'), 'description' => JText::_('COM_GDPR_EXPORT_CONSENT_DESC') ), 'gdpr_cookie_consent_registry' => array ( 'name' => JText::_('COM_GDPR_EXPORT_COOKIE_CONSENT'), 'description' => JText::_('COM_GDPR_EXPORT_COOKIE_CONSENT_DESC') ), 'gdpr_logs' => array ( 'name' => JText::_('COM_GDPR_EXPORT_LOGS'), 'description' => JText::_('COM_GDPR_EXPORT_LOGS_DESC') ) ); // Excluded if not enabled $cookieCategoriesArray = array('category1','category2','category3','category4'); foreach ($domainsToLoad as $domainName => $domainInformations) { $domain = new PrivacyExportDomain; $domain->name = $domainInformations['name']; $domain->description = $domainInformations['description']; // Load all consents for this user $query = "SELECT * FROM " . $db->quoteName('#__' . $domainName) . "\n WHERE " . $db->quoteName('user_id') . " = " . (int) $request->user_id; $db->setQuery($query); try { $dataItems = $db->loadObjectList(); } catch (Exception $e) { // No error handling go on with the process for other domains } foreach ($dataItems as $dataItem) { $item = new PrivacyExportItem; $item->id = $dataItem->id; foreach ($dataItem as $key => $value) { if (is_object($value)) { $value = (array) $value; } if (is_array($value)) { $value = print_r($value, true); } if(in_array($key, $cookieCategoriesArray)) { if(!$this->cParams->get('cookie_' . $key . '_enable', null)) { continue; } } $field = new PrivacyExportField; $field->name = $key; $field->value = $value; $item->addField($field); } $domain->addItem($item); } // Assign this domain $domains[] = $domain; } return $domains; } /** * Event to specify whether a privacy policy has been published. * * @param array &$policy The privacy policy status data, passed by reference, with keys "published" and "editLink" * * @return void */ public function onPrivacyCheckPrivacyPolicyPublished(&$policy) { // If another plugin has already indicated a policy is published, we won't change anything here if ($policy['published']) { return; } $privacyPolicyLink = $this->cParams->get('privacy_policy_link'); $privacyPolicyCheckboxLink = $this->cParams->get('privacy_policy_checkbox_link'); $privacyPolicyContents = $this->cParams->get('privacy_policy_contents', ''); $checkboxContents = $this->cParams->get('checkbox_contents', ''); if (!$privacyPolicyLink && !$privacyPolicyCheckboxLink && !$privacyPolicyContents && !$checkboxContents) { return; } $policy['articlePublished'] = true; $policy['published'] = true; $policy['editLink'] = JRoute::_('index.php?option=com_gdpr&task=config.display#_cookieconsent'); } /** * Provide a hash for the default page cache plugin's key based on parameters, session vars and input vars * * @return string $hash Calculated hash */ public function onPageCacheGetKey() { // If the cache mode is set to 'Advanced' go on to create a hash based on variables if($this->cParams->get('auto_manage_caching', 1) == 2) { // Retrieve the session $session = $this->app->getSession(); // Initialize the hash parts $gdprCookieCategoryDisabledHash = null; $gdprCookieCategoryChecked = null; $gdprCookieCategoryLockedHash = null; $gdprCookieCategoryEnable = null; $gdprExternalBlockingMode = $this->cParams->get('external_blocking_mode', 'simple'); $gdprBlockedtags = trim($this->cParams->get('external_advanced_blocking_mode_tags', 'iframe,script,img,source,link'), ','); $cookieConsentStatus = $this->app->input->cookie->get('cookieconsent_status'); $cookiedConsentDenyAll = $session->get('gdpr_generic_cookie_consent_denyall', 0); for($catIndex = 1, $max = 4; $catIndex <= $max; $catIndex ++) { $gdprCookieCategoryDisabledHash .= $session->get('gdpr_cookie_category_disabled_' . $catIndex); $gdprCookieCategoryChecked .= $this->cParams->get('cookie_category' . $catIndex .'_checked'); $gdprCookieCategoryLockedHash .= $this->cParams->get('cookie_category' . $catIndex . '_locked'); $gdprCookieCategoryEnable .= $this->cParams->get('cookie_category' . $catIndex .'_enable'); } return md5($gdprCookieCategoryDisabledHash . $gdprCookieCategoryLockedHash . $gdprCookieCategoryEnable . $gdprExternalBlockingMode . $gdprBlockedtags . $cookieConsentStatus . $cookiedConsentDenyAll); } return null; } /** Manage the Joomla updater based on the user license * * @access public * @return void */ public function onInstallerBeforePackageDownload(&$url, &$headers) { $uri = JUri::getInstance($url); $parts = explode('/', $uri->getPath()); $app = JFactory::getApplication(); if ($uri->getHost() == 'storejextensions.org' && in_array('com_gdpr.zip', $parts)) { // Init as false unless the license is valid $validUpdate = false; // Load component language $jLang = JFactory::getLanguage(); $jLang->load('com_gdpr', JPATH_BASE . '/components/com_gdpr', 'en-GB', true, true); if($jLang->getTag() != 'en-GB') { $jLang->load('com_gdpr', JPATH_BASE, null, true, false); $jLang->load('com_gdpr', JPATH_BASE . '/components/com_gdpr', null, true, false); } // Email license validation API call and &$url building construction override $cParams = JComponentHelper::getParams('com_gdpr'); $registrationEmail = $cParams->get('registration_email', null); // License if($registrationEmail) { $prodCode = 'gdpr'; $cdFuncUsed = 'str_' . 'ro' . 't' . '13'; // Retrieve license informations from the remote REST API $apiResponse = null; $apiEndpoint = $cdFuncUsed('uggc' . '://' . 'fgberwrkgrafvbaf' . '.bet') . "/option,com_easycommerce/action,licenseCode/email,$registrationEmail/productcode,$prodCode"; if (function_exists('curl_init')){ $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $apiEndpoint); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $apiResponse = curl_exec($ch); curl_close($ch); } $objectApiResponse = json_decode($apiResponse); if(!is_object($objectApiResponse)) { // Message user about error retrieving license informations $app->enqueueMessage(JText::_('COM_GDPR_ERROR_RETRIEVING_LICENSE_INFO')); } else { if(!$objectApiResponse->success) { switch ($objectApiResponse->reason) { // Message user about the reason the license is not valid case 'nomatchingcode': $app->enqueueMessage(JText::_('COM_GDPR_LICENSE_NOMATCHING')); break; case 'expired': // Message user about license expired on $objectApiResponse->expireon $app->enqueueMessage(JText::sprintf('COM_GDPR_LICENSE_EXPIRED', $objectApiResponse->expireon)); break; } } // Valid license found, builds the URL update link and message user about the license expiration validity if($objectApiResponse->success) { $url = $cdFuncUsed('uggc' . '://' . 'fgberwrkgrafvbaf' . '.bet' . '/TQCE1306VSPQxtve1433712323njnlv35td1tena3386i.ugzy'); $validUpdate = true; $app->enqueueMessage(JText::sprintf('COM_GDPR_EXTENSION_UPDATED_SUCCESS', $objectApiResponse->expireon)); } } } else { // Message user about missing email license code $app->enqueueMessage(JText::sprintf('COM_GDPR_MISSING_REGISTRATION_EMAIL_ADDRESS', JFilterOutput::ampReplace('index.php?option=com_gdpr&task=config.display#_licensepreferences'))); } if(!$validUpdate) { $app->enqueueMessage(JText::_('COM_GDPR_UPDATER_STANDARD_ADVISE'), 'notice'); } } } /** * Override registers Listeners to the Dispatcher * It allows to stop a plugin execution based on the registered listeners * * @override * @return void */ public function registerListeners() { // Ensure compatibility excluding Joomla 4 if(version_compare(JVERSION, '4', '>=')) { return; } elseif (method_exists(get_parent_class($this), 'registerListeners')) { parent::registerListeners(); } } /** * Plugin class constructor * * @param Object $subject */ public function __construct(&$subject) { // Ensure compatibility excluding Joomla 4 if(version_compare(JVERSION, '4', '>=')) { return false; } $this->app = JFactory::getApplication(); try { $this->cParams = JComponentHelper::getParams ( 'com_gdpr' ); } catch (Exception $e) { return false; } parent::__construct ( $subject ); } }