primo commit

This commit is contained in:
2024-12-17 17:34:10 +01:00
commit e650f8df99
16435 changed files with 2451012 additions and 0 deletions

View File

@ -0,0 +1,72 @@
<?php
/**
* @package Conditions
* @version 24.11.1459
*
* @author Peter van Westen <info@regularlabs.com>
* @link https://regularlabs.com
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
* @license GNU General Public License version 2 or later
*/
use RegularLabs\Library\ActionLogPlugin as RL_ActionLogPlugin;
use RegularLabs\Library\Document as RL_Document;
use RegularLabs\Library\Extension as RL_Extension;
use RegularLabs\Library\Language as RL_Language;
defined('_JEXEC') or die;
if ( ! is_file(JPATH_LIBRARIES . '/regularlabs/regularlabs.xml')
|| ! class_exists('RegularLabs\Library\Parameters')
|| ! class_exists('RegularLabs\Library\DownloadKey')
|| ! class_exists('RegularLabs\Library\ActionLogPlugin')
)
{
return;
}
if ( ! RL_Document::isJoomlaVersion(4))
{
RL_Extension::disable('conditions', 'plugin', 'actionlog');
return;
}
if (true)
{
class PlgActionlogConditions extends RL_ActionLogPlugin
{
public $name = 'CONDITIONS';
public $alias = 'conditions';
public function __construct(&$subject, array $config = [])
{
parent::__construct($subject, $config);
$this->addItem('com_conditions', 'item', 'CON_ITEM');
}
public function onContentAfterSave($context, $table, $isNew, $data = [])
{
if ($context !== 'com_conditions.condition')
{
return;
}
parent::onContentAfterSave($context, $table, $isNew, $data);
}
public function onConditionAfterMap($data)
{
RL_Language::load($data->extension);
$item = $this->getItem($data->extension);
$item->title = $data->item_name;
$item->id = $data->item_id;
$this->option = $data->extension;
parent::onContentAfterSave($item->context, $item, false);
$this->option = 'com_conditions';
}
}
}

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<extension version="4" type="plugin" group="actionlog" method="upgrade">
<name>PLG_ACTIONLOG_CONDITIONS</name>
<description>PLG_ACTIONLOG_CONDITIONS_DESC</description>
<version>24.11.1459</version>
<creationDate>November 2024</creationDate>
<author>Regular Labs (Peter van Westen)</author>
<authorEmail>info@regularlabs.com</authorEmail>
<authorUrl>https://regularlabs.com</authorUrl>
<copyright>Copyright © 2024 Regular Labs - All Rights Reserved</copyright>
<license>GNU General Public License version 2 or later</license>
<files>
<file plugin="conditions">conditions.php</file>
<folder>language</folder>
</files>
<config>
<fields name="params" addfieldprefix="RegularLabs\Library\Form\Field">
<fieldset name="basic">
<field name="@load_language_regularlabs" type="LoadLanguage" extension="plg_system_regularlabs"/>
<field name="@load_language" type="LoadLanguage" extension="plg_system_conditions"/>
<field name="@jcompatibility" type="JCompatibility" extension="REGULAR_LABS_LIBRARY"/>
<field name="@license" type="License" extension="CONDITIONS"/>
<field name="@version" type="Version" extension="CONDITIONS"/>
<field name="@dependency" type="Dependency" label="CON_THE_COMPONENT" file="/administrator/components/com_conditions/conditions.xml"/>
<field name="@header" type="Header" label="CONDITIONS" description="CONDITIONS_DESC"/>
<field name="@note__settings" type="Note" class="rl-alert alert alert-info rl-alert-light" text="CON_SETTINGS,&lt;a href=&quot;index.php?option=com_conditions&quot; target=&quot;_blank&quot;&gt;,&lt;/a&gt;"/>
</fieldset>
</fields>
</config>
</extension>

View File

@ -0,0 +1,21 @@
;; @package Conditions
;; @version 24.11.1459
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link https://regularlabs.com
;; @copyright Copyright © 2024 Regular Labs All Rights Reserved
;; @license GNU General Public License version 2 or later
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
PLG_ACTIONLOG_CONDITIONS="Action Log - Regular Labs - Conditions"
PLG_ACTIONLOG_CONDITIONS_DESC="Record the actions of users for Conditions"
CONDITIONS="Conditions"
CONDITIONS_DESC="With Conditions you can replace whatever you want in your entire site."
CON_SETTINGS="Please see the [[%1:start link%]]Conditions component[[%2:end link%]] for settings."
CON_THE_COMPONENT="the Conditions component"
CON_THE_SYSTEM_PLUGIN="the Conditions system plugin"
CON_ITEM="Conditions set"

View File

@ -0,0 +1,13 @@
;; @package Conditions
;; @version 24.11.1459
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link https://regularlabs.com
;; @copyright Copyright © 2024 Regular Labs All Rights Reserved
;; @license GNU General Public License version 2 or later
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
PLG_ACTIONLOG_CONDITIONS="Action Log - Regular Labs - Conditions"
PLG_ACTIONLOG_CONDITIONS_DESC="Record the actions of users for Conditions"
CONDITIONS="Conditions"

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<extension type="plugin" group="actionlog" method="upgrade">
<name>plg_actionlog_joomla</name>
<author>Joomla! Project</author>
<creationDate>2018-05</creationDate>
<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>3.9.0</version>
<description>PLG_ACTIONLOG_JOOMLA_XML_DESCRIPTION</description>
<namespace path="src">Joomla\Plugin\Actionlog\Joomla</namespace>
<files>
<folder plugin="joomla">services</folder>
<folder>src</folder>
</files>
<languages>
<language tag="en-GB">language/en-GB/plg_actionlog_joomla.ini</language>
<language tag="en-GB">language/en-GB/plg_actionlog_joomla.sys.ini</language>
</languages>
</extension>

View File

@ -0,0 +1,50 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage Actionlog.joomla
*
* @copyright (C) 2022 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
\defined('_JEXEC') or die;
use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\User\UserFactoryInterface;
use Joomla\Database\DatabaseInterface;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use Joomla\Plugin\Actionlog\Joomla\Extension\Joomla;
return new class () implements ServiceProviderInterface {
/**
* Registers the service provider with a DI container.
*
* @param Container $container The DI container.
*
* @return void
*
* @since 4.2.0
*/
public function register(Container $container)
{
$container->set(
PluginInterface::class,
function (Container $container) {
$plugin = new Joomla(
$container->get(DispatcherInterface::class),
(array) PluginHelper::getPlugin('actionlog', 'joomla')
);
$plugin->setApplication(Factory::getApplication());
$plugin->setDatabase($container->get(DatabaseInterface::class));
$plugin->setUserFactory($container->get(UserFactoryInterface::class));
return $plugin;
}
);
}
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
<html><body bgcolor="#FFFFFF"></body></html>

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<extension type="plugin" group="api-authentication" method="upgrade">
<name>plg_api-authentication_basic</name>
<author>Joomla! Project</author>
<creationDate>2005-11</creationDate>
<copyright>(C) 2019 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>4.0.0</version>
<description>PLG_API-AUTHENTICATION_BASIC_XML_DESCRIPTION</description>
<namespace path="src">Joomla\Plugin\ApiAuthentication\Basic</namespace>
<files>
<folder plugin="basic">services</folder>
<folder>src</folder>
</files>
<languages>
<language tag="en-GB">language/en-GB/plg_api-authentication_basic.ini</language>
<language tag="en-GB">language/en-GB/plg_api-authentication_basic.sys.ini</language>
</languages>
</extension>

View File

@ -0,0 +1,50 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage Apiauthentication.basic
*
* @copyright (C) 2022 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
\defined('_JEXEC') or die;
use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\User\UserFactoryInterface;
use Joomla\Database\DatabaseInterface;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use Joomla\Plugin\ApiAuthentication\Basic\Extension\Basic;
return new class () implements ServiceProviderInterface {
/**
* Registers the service provider with a DI container.
*
* @param Container $container The DI container.
*
* @return void
*
* @since 4.2.0
*/
public function register(Container $container)
{
$container->set(
PluginInterface::class,
function (Container $container) {
$plugin = new Basic(
$container->get(DispatcherInterface::class),
(array) PluginHelper::getPlugin('api-authentication', 'basic'),
);
$plugin->setApplication(Factory::getApplication());
$plugin->setDatabase($container->get(DatabaseInterface::class));
$plugin->setUserFactory($container->get(UserFactoryInterface::class));
return $plugin;
}
);
}
};

View File

@ -0,0 +1,115 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage Apiauthentication.basic
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\ApiAuthentication\Basic\Extension;
use Joomla\CMS\Authentication\Authentication;
use Joomla\CMS\Event\User\AuthenticationEvent;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\User\UserFactoryAwareTrait;
use Joomla\CMS\User\UserHelper;
use Joomla\Database\DatabaseAwareTrait;
use Joomla\Event\SubscriberInterface;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Joomla Authentication plugin
*
* @since 4.0.0
*/
final class Basic extends CMSPlugin implements SubscriberInterface
{
use DatabaseAwareTrait;
use UserFactoryAwareTrait;
/**
* Returns an array of events this subscriber will listen to.
*
* @return array
*
* @since 5.2.0
*/
public static function getSubscribedEvents(): array
{
return ['onUserAuthenticate' => 'onUserAuthenticate'];
}
/**
* This method should handle any authentication and report back to the subject
*
* @param AuthenticationEvent $event Authentication event
*
* @return void
*
* @since 4.0.0
*/
public function onUserAuthenticate(AuthenticationEvent $event): void
{
$response = $event->getAuthenticationResponse();
$response->type = 'Basic';
$username = $this->getApplication()->getInput()->server->get('PHP_AUTH_USER', '', 'USERNAME');
$password = $this->getApplication()->getInput()->server->get('PHP_AUTH_PW', '', 'RAW');
if ($password === '') {
$response->status = Authentication::STATUS_FAILURE;
$response->error_message = $this->getApplication()->getLanguage()->_('JGLOBAL_AUTH_EMPTY_PASS_NOT_ALLOWED');
return;
}
$db = $this->getDatabase();
$query = $db->getQuery(true)
->select($db->quoteName(['id', 'password']))
->from($db->quoteName('#__users'))
->where($db->quoteName('username') . ' = :username')
->bind(':username', $username);
$db->setQuery($query);
$result = $db->loadObject();
if ($result) {
$match = UserHelper::verifyPassword($password, $result->password, $result->id);
if ($match === true) {
// Bring this in line with the rest of the system
$user = $this->getUserFactory()->loadUserById($result->id);
$response->email = $user->email;
$response->fullname = $user->name;
$response->username = $username;
if ($this->getApplication()->isClient('administrator')) {
$response->language = $user->getParam('admin_language');
} else {
$response->language = $user->getParam('language');
}
$response->status = Authentication::STATUS_SUCCESS;
$response->error_message = '';
} else {
// Invalid password
$response->status = Authentication::STATUS_FAILURE;
$response->error_message = $this->getApplication()->getLanguage()->_('JGLOBAL_AUTH_INVALID_PASS');
}
} else {
// Let's hash the entered password even if we don't have a matching user for some extra response time
// By doing so, we mitigate side channel user enumeration attacks
UserHelper::hashPassword($password);
// Invalid user
$response->status = Authentication::STATUS_FAILURE;
$response->error_message = $this->getApplication()->getLanguage()->_('JGLOBAL_AUTH_NO_USER');
}
}
}

View File

@ -0,0 +1,52 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage Apiauthentication.token
*
* @copyright (C) 2022 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
\defined('_JEXEC') or die;
use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\User\UserFactoryInterface;
use Joomla\Database\DatabaseInterface;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use Joomla\Filter\InputFilter;
use Joomla\Plugin\ApiAuthentication\Token\Extension\Token;
return new class () implements ServiceProviderInterface {
/**
* Registers the service provider with a DI container.
*
* @param Container $container The DI container.
*
* @return void
*
* @since 4.2.0
*/
public function register(Container $container)
{
$container->set(
PluginInterface::class,
function (Container $container) {
$plugin = new Token(
$container->get(DispatcherInterface::class),
(array) PluginHelper::getPlugin('api-authentication', 'token'),
new InputFilter()
);
$plugin->setApplication(Factory::getApplication());
$plugin->setDatabase($container->get(DatabaseInterface::class));
$plugin->setUserFactory($container->get(UserFactoryInterface::class));
return $plugin;
}
);
}
};

View File

@ -0,0 +1,400 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage Apiauthentication.token
*
* @copyright (C) 2020 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\ApiAuthentication\Token\Extension;
use Joomla\CMS\Authentication\Authentication;
use Joomla\CMS\Crypt\Crypt;
use Joomla\CMS\Event\User\AuthenticationEvent;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\User\UserFactoryAwareTrait;
use Joomla\Database\DatabaseAwareTrait;
use Joomla\Database\ParameterType;
use Joomla\Event\DispatcherInterface;
use Joomla\Event\SubscriberInterface;
use Joomla\Filter\InputFilter;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Joomla Token Authentication plugin
*
* @since 4.0.0
*/
final class Token extends CMSPlugin implements SubscriberInterface
{
use DatabaseAwareTrait;
use UserFactoryAwareTrait;
/**
* The prefix of the user profile keys, without the dot.
*
* @var string
* @since 4.0.0
*/
private $profileKeyPrefix = 'joomlatoken';
/**
* Allowed HMAC algorithms for the token
*
* @var string[]
* @since 4.0.0
*/
private $allowedAlgos = ['sha256', 'sha512'];
/**
* The input filter
*
* @var InputFilter
* @since 4.2.0
*/
private $filter;
/**
* Returns an array of events this subscriber will listen to.
*
* @return array
*
* @since 5.0.0
*/
public static function getSubscribedEvents(): array
{
return ['onUserAuthenticate' => 'onUserAuthenticate'];
}
/**
* Constructor.
*
* @param DispatcherInterface $dispatcher The dispatcher
* @param array $config An optional associative array of configuration settings
* @param InputFilter $filter The input filter
*
* @since 4.2.0
*/
public function __construct(DispatcherInterface $dispatcher, array $config, InputFilter $filter)
{
parent::__construct($dispatcher, $config);
$this->filter = $filter;
}
/**
* This method should handle any authentication and report back to the subject
*
* @param AuthenticationEvent $event Authentication event
*
* @return void
*
* @since 4.0.0
*/
public function onUserAuthenticate(AuthenticationEvent $event): void
{
$response = $event->getAuthenticationResponse();
// Default response is authentication failure.
$response->type = 'Token';
$response->status = Authentication::STATUS_FAILURE;
$response->error_message = $this->getApplication()->getLanguage()->_('JGLOBAL_AUTH_FAIL');
/**
* First look for an HTTP Authorization header with the following format:
* Authorization: Bearer <token>
* Do keep in mind that Bearer is **case-sensitive**. Whitespace between Bearer and the
* token, as well as any whitespace following the token is discarded.
*/
$authHeader = $this->getApplication()->getInput()->server->get('HTTP_AUTHORIZATION', '', 'string');
$tokenString = '';
// Apache specific fixes. See https://github.com/symfony/symfony/issues/19693
if (
empty($authHeader) && \PHP_SAPI === 'apache2handler'
&& \function_exists('apache_request_headers') && apache_request_headers() !== false
) {
$apacheHeaders = array_change_key_case(apache_request_headers(), CASE_LOWER);
if (\array_key_exists('authorization', $apacheHeaders)) {
$authHeader = $this->filter->clean($apacheHeaders['authorization'], 'STRING');
}
}
// Another Apache specific fix. See https://github.com/symfony/symfony/issues/1813
if (empty($authHeader)) {
$authHeader = $this->getApplication()->getInput()->server->get('REDIRECT_HTTP_AUTHORIZATION', '', 'string');
}
if (substr($authHeader, 0, 7) == 'Bearer ') {
$parts = explode(' ', $authHeader, 2);
$tokenString = trim($parts[1]);
$tokenString = $this->filter->clean($tokenString, 'BASE64');
}
if (empty($tokenString)) {
$tokenString = $this->getApplication()->getInput()->server->get('HTTP_X_JOOMLA_TOKEN', '', 'string');
}
// No token: authentication failure
if (empty($tokenString)) {
return;
}
// The token is a base64 encoded string. Make sure we can decode it.
$authString = @base64_decode($tokenString);
if (empty($authString) || (strpos($authString, ':') === false)) {
return;
}
/**
* Deconstruct the decoded token string to its three discrete parts: algorithm, user ID and
* HMAC of the token string saved in the database.
*/
$parts = explode(':', $authString, 3);
if (\count($parts) != 3) {
return;
}
list($algo, $userId, $tokenHMAC) = $parts;
/**
* Verify the HMAC algorithm requested in the token string is allowed
*/
$allowedAlgo = \in_array($algo, $this->allowedAlgos);
/**
* Make sure the user ID is an integer
*/
$userId = (int) $userId;
/**
* Calculate the reference token data HMAC
*/
try {
$siteSecret = $this->getApplication()->get('secret');
} catch (\Exception $e) {
return;
}
// An empty secret! What kind of monster are you?!
if (empty($siteSecret)) {
return;
}
$referenceTokenData = $this->getTokenSeedForUser($userId);
$referenceTokenData = empty($referenceTokenData) ? '' : $referenceTokenData;
$referenceTokenData = base64_decode($referenceTokenData);
$referenceHMAC = hash_hmac($algo, $referenceTokenData, $siteSecret);
// Is the token enabled?
$enabled = $this->isTokenEnabledForUser($userId);
// Do the tokens match? Use a timing safe string comparison to prevent timing attacks.
$hashesMatch = Crypt::timingSafeCompare($referenceHMAC, $tokenHMAC);
// Is the user in the allowed user groups?
$inAllowedUserGroups = $this->isInAllowedUserGroup($userId);
/**
* Can we log in?
*
* DO NOT concatenate in a single line. Due to boolean short-circuit evaluation it might
* make timing attacks possible. Using separate lines of code with the previously calculated
* boolean value to the right hand side forces PHP to evaluate the conditions in
* approximately constant time.
*/
// We need non-empty reference token data (the user must have configured a token)
$canLogin = !empty($referenceTokenData);
// The token must be enabled
$canLogin = $enabled && $canLogin;
// The token hash must be calculated with an allowed algorithm
$canLogin = $allowedAlgo && $canLogin;
// The token HMAC hash coming into the request and our reference must match.
$canLogin = $hashesMatch && $canLogin;
// The user must belong in the allowed user groups
$canLogin = $inAllowedUserGroups && $canLogin;
/**
* DO NOT try to be smart and do an early return when either of the individual conditions
* are not met. There's a reason we only return after checking all three conditions: it
* prevents timing attacks.
*/
if (!$canLogin) {
return;
}
// Get the actual user record
$user = $this->getUserFactory()->loadUserById($userId);
// Disallow login for blocked, inactive or password reset required users
if ($user->block || !empty(trim($user->activation)) || $user->requireReset) {
$response->status = Authentication::STATUS_DENIED;
return;
}
// Update the response to indicate successful login
$response->status = Authentication::STATUS_SUCCESS;
$response->error_message = '';
$response->username = $user->username;
$response->email = $user->email;
$response->fullname = $user->name;
$response->timezone = $user->getParam('timezone', $this->getApplication()->get('offset', 'UTC'));
$response->language = $user->getParam('language', $this->getApplication()->get('language'));
// Stop event propagation when status is STATUS_SUCCESS
$event->stopPropagation();
}
/**
* Retrieve the token seed string for the given user ID.
*
* @param int $userId The numeric user ID to return the token seed string for.
*
* @return string|null Null if there is no token configured or the user doesn't exist.
* @since 4.0.0
*/
private function getTokenSeedForUser(int $userId): ?string
{
try {
$db = $this->getDatabase();
$query = $db->getQuery(true)
->select($db->quoteName('profile_value'))
->from($db->quoteName('#__user_profiles'))
->where($db->quoteName('profile_key') . ' = :profileKey')
->where($db->quoteName('user_id') . ' = :userId');
$profileKey = $this->profileKeyPrefix . '.token';
$query->bind(':profileKey', $profileKey, ParameterType::STRING);
$query->bind(':userId', $userId, ParameterType::INTEGER);
return $db->setQuery($query)->loadResult();
} catch (\Exception $e) {
return null;
}
}
/**
* Is the token enabled for a given user ID? If the user does not exist or has no token it
* returns false.
*
* @param int $userId The User ID to check whether the token is enabled on their account.
*
* @return boolean
* @since 4.0.0
*/
private function isTokenEnabledForUser(int $userId): bool
{
try {
$db = $this->getDatabase();
$query = $db->getQuery(true)
->select($db->quoteName('profile_value'))
->from($db->quoteName('#__user_profiles'))
->where($db->quoteName('profile_key') . ' = :profileKey')
->where($db->quoteName('user_id') . ' = :userId');
$profileKey = $this->profileKeyPrefix . '.enabled';
$query->bind(':profileKey', $profileKey, ParameterType::STRING);
$query->bind(':userId', $userId, ParameterType::INTEGER);
$value = $db->setQuery($query)->loadResult();
return $value == 1;
} catch (\Exception $e) {
return false;
}
}
/**
* Retrieves a configuration parameter of a different plugin than the current one.
*
* @param string $folder Plugin folder
* @param string $plugin Plugin name
* @param string $param Parameter name
* @param null $default Default value, in case the parameter is missing
*
* @return mixed
* @since 4.0.0
*/
private function getPluginParameter(string $folder, string $plugin, string $param, $default = null)
{
/** @var \Joomla\Component\Plugins\Administrator\Model\PluginModel $model */
$model = $this->getApplication()->bootComponent('plugins')
->getMVCFactory()->createModel('Plugin', 'Administrator', ['ignore_request' => true]);
$pluginObject = $model->getItem(['folder' => $folder, 'element' => $plugin]);
if (!\is_object($pluginObject) || !$pluginObject->enabled || !\array_key_exists($param, $pluginObject->params)) {
return $default;
}
return $pluginObject->params[$param];
}
/**
* Get the configured user groups which are allowed to have access to tokens.
*
* @return int[]
* @since 4.0.0
*/
private function getAllowedUserGroups(): array
{
$userGroups = $this->getPluginParameter('user', 'token', 'allowedUserGroups', [8]);
if (empty($userGroups)) {
return [];
}
if (!\is_array($userGroups)) {
$userGroups = [$userGroups];
}
return $userGroups;
}
/**
* Is the user with the given ID in the allowed User Groups with access to tokens?
*
* @param int $userId The user ID to check
*
* @return boolean False when doesn't belong to allowed user groups, user not found, or guest
* @since 4.0.0
*/
private function isInAllowedUserGroup($userId)
{
$allowedUserGroups = $this->getAllowedUserGroups();
$user = $this->getUserFactory()->loadUserById($userId);
if ($user->id != $userId) {
return false;
}
if ($user->guest) {
return false;
}
// No specifically allowed user groups: allow ALL user groups.
if (empty($allowedUserGroups)) {
return true;
}
$groups = $user->getAuthorisedGroups();
$intersection = array_intersect($groups, $allowedUserGroups);
return !empty($intersection);
}
}

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<extension type="plugin" group="api-authentication" method="upgrade">
<name>plg_api-authentication_token</name>
<author>Joomla! Project</author>
<creationDate>2019-11</creationDate>
<copyright>(C) 2020 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>4.0.0</version>
<description>PLG_API-AUTHENTICATION_TOKEN_XML_DESCRIPTION</description>
<namespace path="src">Joomla\Plugin\ApiAuthentication\Token</namespace>
<files>
<folder plugin="token">services</folder>
<folder>src</folder>
</files>
<languages>
<language tag="en-GB">language/en-GB/plg_api-authentication_token.ini</language>
<language tag="en-GB">language/en-GB/plg_api-authentication_token.sys.ini</language>
</languages>
</extension>

View File

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<extension type="plugin" group="authentication" method="upgrade">
<name>plg_authentication_cookie</name>
<author>Joomla! Project</author>
<creationDate>2013-07</creationDate>
<copyright>(C) 2013 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>3.0.0</version>
<description>PLG_AUTHENTICATION_COOKIE_XML_DESCRIPTION</description>
<namespace path="src">Joomla\Plugin\Authentication\Cookie</namespace>
<files>
<folder plugin="cookie">services</folder>
<folder>src</folder>
</files>
<languages>
<language tag="en-GB">language/en-GB/plg_authentication_cookie.ini</language>
<language tag="en-GB">language/en-GB/plg_authentication_cookie.sys.ini</language>
</languages>
<config>
<fields name="params">
<fieldset name="basic">
<field
name="cookie_lifetime"
type="number"
label="PLG_AUTHENTICATION_COOKIE_FIELD_COOKIE_LIFETIME_LABEL"
default="60"
filter="integer"
required="true"
/>
<field
name="key_length"
type="list"
label="PLG_AUTHENTICATION_COOKIE_FIELD_KEY_LENGTH_LABEL"
default="16"
filter="integer"
required="true"
validate="options"
>
<option value="8">8</option>
<option value="16">16</option>
<option value="32">32</option>
<option value="64">64</option>
</field>
</fieldset>
</fields>
</config>
</extension>

View File

@ -0,0 +1,50 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage Authentication.cookie
*
* @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
\defined('_JEXEC') or die;
use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\User\UserFactoryInterface;
use Joomla\Database\DatabaseInterface;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use Joomla\Plugin\Authentication\Cookie\Extension\Cookie;
return new class () implements ServiceProviderInterface {
/**
* Registers the service provider with a DI container.
*
* @param Container $container The DI container.
*
* @return void
*
* @since 4.3.0
*/
public function register(Container $container)
{
$container->set(
PluginInterface::class,
function (Container $container) {
$plugin = new Cookie(
$container->get(DispatcherInterface::class),
(array) PluginHelper::getPlugin('authentication', 'cookie')
);
$plugin->setApplication(Factory::getApplication());
$plugin->setDatabase($container->get(DatabaseInterface::class));
$plugin->setUserFactory($container->get(UserFactoryInterface::class));
return $plugin;
}
);
}
};

View File

@ -0,0 +1,426 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage Authentication.cookie
*
* @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\Authentication\Cookie\Extension;
use Joomla\CMS\Authentication\Authentication;
use Joomla\CMS\Event\Privacy\CollectCapabilitiesEvent;
use Joomla\CMS\Event\User\AfterLoginEvent;
use Joomla\CMS\Event\User\AfterLogoutEvent;
use Joomla\CMS\Event\User\AuthenticationEvent;
use Joomla\CMS\Filter\InputFilter;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Log\Log;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\User\UserFactoryAwareTrait;
use Joomla\CMS\User\UserHelper;
use Joomla\Database\DatabaseAwareTrait;
use Joomla\Event\SubscriberInterface;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Joomla Authentication plugin
*
* @since 3.2
* @note Code based on http://jaspan.com/improved_persistent_login_cookie_best_practice
* and http://fishbowl.pastiche.org/2004/01/19/persistent_login_cookie_best_practice/
*/
final class Cookie extends CMSPlugin implements SubscriberInterface
{
use DatabaseAwareTrait;
use UserFactoryAwareTrait;
/**
* Returns an array of events this subscriber will listen to.
*
* @return array
*
* @since 5.2.0
*/
public static function getSubscribedEvents(): array
{
return [
'onPrivacyCollectAdminCapabilities' => 'onPrivacyCollectAdminCapabilities',
'onUserAuthenticate' => 'onUserAuthenticate',
'onUserAfterLogin' => 'onUserAfterLogin',
'onUserAfterLogout' => 'onUserAfterLogout',
];
}
/**
* Reports the privacy related capabilities for this plugin to site administrators.
*
* @return void
*
* @since 3.9.0
*/
public function onPrivacyCollectAdminCapabilities(CollectCapabilitiesEvent $event): void
{
$this->loadLanguage();
$event->addResult([
$this->getApplication()->getLanguage()->_('PLG_AUTHENTICATION_COOKIE') => [
$this->getApplication()->getLanguage()->_('PLG_AUTHENTICATION_COOKIE_PRIVACY_CAPABILITY_COOKIE'),
],
]);
}
/**
* This method should handle any authentication and report back to the subject
*
* @param AuthenticationEvent $event Authentication event
*
* @return void
*
* @since 3.2
*/
public function onUserAuthenticate(AuthenticationEvent $event): void
{
$app = $this->getApplication();
// No remember me for admin
if ($app->isClient('administrator')) {
return;
}
// Get cookie
$cookieName = 'joomla_remember_me_' . UserHelper::getShortHashedUserAgent();
$cookieValue = $app->getInput()->cookie->get($cookieName);
// Try with old cookieName (pre 3.6.0) if not found
if (!$cookieValue) {
$cookieName = UserHelper::getShortHashedUserAgent();
$cookieValue = $app->getInput()->cookie->get($cookieName);
}
if (!$cookieValue) {
return;
}
$cookieArray = explode('.', $cookieValue);
// Check for valid cookie value
if (\count($cookieArray) !== 2) {
// Destroy the cookie in the browser.
$app->getInput()->cookie->set($cookieName, '', 1, $app->get('cookie_path', '/'), $app->get('cookie_domain', ''));
Log::add('Invalid cookie detected.', Log::WARNING, 'error');
return;
}
$response = $event->getAuthenticationResponse();
$response->type = 'Cookie';
// Filter series since we're going to use it in the query
$filter = new InputFilter();
$series = $filter->clean($cookieArray[1], 'ALNUM');
$now = time();
// Remove expired tokens
$db = $this->getDatabase();
$query = $db->getQuery(true)
->delete($db->quoteName('#__user_keys'))
->where($db->quoteName('time') . ' < :now')
->bind(':now', $now);
try {
$db->setQuery($query)->execute();
} catch (\RuntimeException $e) {
// We aren't concerned with errors from this query, carry on
}
// Find the matching record if it exists.
$query = $db->getQuery(true)
->select($db->quoteName(['user_id', 'token', 'series', 'time']))
->from($db->quoteName('#__user_keys'))
->where($db->quoteName('series') . ' = :series')
->where($db->quoteName('uastring') . ' = :uastring')
->order($db->quoteName('time') . ' DESC')
->bind(':series', $series)
->bind(':uastring', $cookieName);
try {
$results = $db->setQuery($query)->loadObjectList();
} catch (\RuntimeException $e) {
$response->status = Authentication::STATUS_FAILURE;
return;
}
if (\count($results) !== 1) {
// Destroy the cookie in the browser.
$app->getInput()->cookie->set($cookieName, '', 1, $app->get('cookie_path', '/'), $app->get('cookie_domain', ''));
$response->status = Authentication::STATUS_FAILURE;
return;
}
// We have a user with one cookie with a valid series and a corresponding record in the database.
if (!UserHelper::verifyPassword($cookieArray[0], $results[0]->token)) {
/*
* This is a real attack!
* Either the series was guessed correctly or a cookie was stolen and used twice (once by attacker and once by victim).
* Delete all tokens for this user!
*/
$query = $db->getQuery(true)
->delete($db->quoteName('#__user_keys'))
->where($db->quoteName('user_id') . ' = :userid')
->bind(':userid', $results[0]->user_id);
try {
$db->setQuery($query)->execute();
} catch (\RuntimeException $e) {
// Log an alert for the site admin
Log::add(
\sprintf('Failed to delete cookie token for user %s with the following error: %s', $results[0]->user_id, $e->getMessage()),
Log::WARNING,
'security'
);
}
// Destroy the cookie in the browser.
$app->getInput()->cookie->set($cookieName, '', 1, $app->get('cookie_path', '/'), $app->get('cookie_domain', ''));
// Issue warning by email to user and/or admin?
Log::add(Text::sprintf('PLG_AUTHENTICATION_COOKIE_ERROR_LOG_LOGIN_FAILED', $results[0]->user_id), Log::WARNING, 'security');
$response->status = Authentication::STATUS_FAILURE;
return;
}
// Make sure there really is a user with this name and get the data for the session.
$query = $db->getQuery(true)
->select($db->quoteName(['id', 'username', 'password']))
->from($db->quoteName('#__users'))
->where($db->quoteName('username') . ' = :userid')
->where($db->quoteName('requireReset') . ' = 0')
->bind(':userid', $results[0]->user_id);
try {
$result = $db->setQuery($query)->loadObject();
} catch (\RuntimeException $e) {
$response->status = Authentication::STATUS_FAILURE;
return;
}
if ($result) {
// Bring this in line with the rest of the system
$user = $this->getUserFactory()->loadUserById($result->id);
// Set response data.
$response->username = $result->username;
$response->email = $user->email;
$response->fullname = $user->name;
$response->password = $result->password;
$response->language = $user->getParam('language');
// Set response status.
$response->status = Authentication::STATUS_SUCCESS;
$response->error_message = '';
// Stop event propagation when status is STATUS_SUCCESS
$event->stopPropagation();
} else {
$response->status = Authentication::STATUS_FAILURE;
$response->error_message = $app->getLanguage()->_('JGLOBAL_AUTH_NO_USER');
}
}
/**
* We set the authentication cookie only after login is successfully finished.
* We set a new cookie either for a user with no cookies or one
* where the user used a cookie to authenticate.
*
* @param AfterLoginEvent $event Login event
*
* @return void
*
* @since 3.2
*/
public function onUserAfterLogin(AfterLoginEvent $event): void
{
$app = $this->getApplication();
// No remember me for admin
if ($app->isClient('administrator')) {
return;
}
$db = $this->getDatabase();
$options = $event->getOptions();
if (isset($options['responseType']) && $options['responseType'] === 'Cookie') {
// Logged in using a cookie
$cookieName = 'joomla_remember_me_' . UserHelper::getShortHashedUserAgent();
// We need the old data to get the existing series
$cookieValue = $app->getInput()->cookie->get($cookieName);
// Try with old cookieName (pre 3.6.0) if not found
if (!$cookieValue) {
$oldCookieName = UserHelper::getShortHashedUserAgent();
$cookieValue = $app->getInput()->cookie->get($oldCookieName);
// Destroy the old cookie in the browser
$app->getInput()->cookie->set($oldCookieName, '', 1, $app->get('cookie_path', '/'), $app->get('cookie_domain', ''));
}
$cookieArray = explode('.', $cookieValue);
// Filter series since we're going to use it in the query
$filter = new InputFilter();
$series = $filter->clean($cookieArray[1], 'ALNUM');
} elseif (!empty($options['remember'])) {
// Remember checkbox is set
$cookieName = 'joomla_remember_me_' . UserHelper::getShortHashedUserAgent();
// Create a unique series which will be used over the lifespan of the cookie
$unique = false;
$errorCount = 0;
do {
$series = UserHelper::genRandomPassword(20);
$query = $db->getQuery(true)
->select($db->quoteName('series'))
->from($db->quoteName('#__user_keys'))
->where($db->quoteName('series') . ' = :series')
->bind(':series', $series);
try {
$results = $db->setQuery($query)->loadResult();
if ($results === null) {
$unique = true;
}
} catch (\RuntimeException $e) {
$errorCount++;
// We'll let this query fail up to 5 times before giving up, there's probably a bigger issue at this point
if ($errorCount === 5) {
return;
}
}
} while ($unique === false);
} else {
return;
}
// Get the parameter values
$lifetime = $this->params->get('cookie_lifetime', 60) * 24 * 60 * 60;
$length = $this->params->get('key_length', 16);
// Generate new cookie
$token = UserHelper::genRandomPassword($length);
$cookieValue = $token . '.' . $series;
// Overwrite existing cookie with new value
$app->getInput()->cookie->set(
$cookieName,
$cookieValue,
time() + $lifetime,
$app->get('cookie_path', '/'),
$app->get('cookie_domain', ''),
$app->isHttpsForced(),
true
);
$query = $db->getQuery(true);
if (!empty($options['remember'])) {
$future = (time() + $lifetime);
// Create new record
$query
->insert($db->quoteName('#__user_keys'))
->set($db->quoteName('user_id') . ' = :userid')
->set($db->quoteName('series') . ' = :series')
->set($db->quoteName('uastring') . ' = :uastring')
->set($db->quoteName('time') . ' = :time')
->bind(':userid', $options['user']->username)
->bind(':series', $series)
->bind(':uastring', $cookieName)
->bind(':time', $future);
} else {
// Update existing record with new token
$query
->update($db->quoteName('#__user_keys'))
->where($db->quoteName('user_id') . ' = :userid')
->where($db->quoteName('series') . ' = :series')
->where($db->quoteName('uastring') . ' = :uastring')
->bind(':userid', $options['user']->username)
->bind(':series', $series)
->bind(':uastring', $cookieName);
}
$hashedToken = UserHelper::hashPassword($token);
$query->set($db->quoteName('token') . ' = :token')
->bind(':token', $hashedToken);
try {
$db->setQuery($query)->execute();
} catch (\RuntimeException $e) {
// We aren't concerned with errors from this query, carry on
}
}
/**
* This is where we delete any authentication cookie when a user logs out
*
* @param AfterLogoutEvent $event Logout event
*
* @return void
*
* @since 3.2
*/
public function onUserAfterLogout(AfterLogoutEvent $event): void
{
$app = $this->getApplication();
// No remember me for admin
if ($app->isClient('administrator')) {
return;
}
$cookieName = 'joomla_remember_me_' . UserHelper::getShortHashedUserAgent();
$cookieValue = $app->getInput()->cookie->get($cookieName);
// There are no cookies to delete.
if (!$cookieValue) {
return;
}
$cookieArray = explode('.', $cookieValue);
// Filter series since we're going to use it in the query
$filter = new InputFilter();
$series = $filter->clean($cookieArray[1], 'ALNUM');
// Remove the record from the database
$db = $this->getDatabase();
$query = $db->getQuery(true)
->delete($db->quoteName('#__user_keys'))
->where($db->quoteName('series') . ' = :series')
->bind(':series', $series);
try {
$db->setQuery($query)->execute();
} catch (\RuntimeException $e) {
// We aren't concerned with errors from this query, carry on
}
// Destroy the cookie
$app->getInput()->cookie->set($cookieName, '', 1, $app->get('cookie_path', '/'), $app->get('cookie_domain', ''));
}
}

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<extension type="plugin" group="authentication" method="upgrade">
<name>plg_authentication_joomla</name>
<author>Joomla! Project</author>
<creationDate>2005-11</creationDate>
<copyright>(C) 2005 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>3.0.0</version>
<description>PLG_AUTHENTICATION_JOOMLA_XML_DESCRIPTION</description>
<namespace path="src">Joomla\Plugin\Authentication\Joomla</namespace>
<files>
<folder plugin="joomla">services</folder>
<folder>src</folder>
</files>
<languages>
<language tag="en-GB">language/en-GB/plg_authentication_joomla.ini</language>
<language tag="en-GB">language/en-GB/plg_authentication_joomla.sys.ini</language>
</languages>
</extension>

View File

@ -0,0 +1,50 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage Authentication.joomla
*
* @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
\defined('_JEXEC') or die;
use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\User\UserFactoryInterface;
use Joomla\Database\DatabaseInterface;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use Joomla\Plugin\Authentication\Joomla\Extension\Joomla;
return new class () implements ServiceProviderInterface {
/**
* Registers the service provider with a DI container.
*
* @param Container $container The DI container.
*
* @return void
*
* @since 4.3.0
*/
public function register(Container $container)
{
$container->set(
PluginInterface::class,
function (Container $container) {
$plugin = new Joomla(
$container->get(DispatcherInterface::class),
(array) PluginHelper::getPlugin('authentication', 'joomla')
);
$plugin->setApplication(Factory::getApplication());
$plugin->setDatabase($container->get(DatabaseInterface::class));
$plugin->setUserFactory($container->get(UserFactoryInterface::class));
return $plugin;
}
);
}
};

View File

@ -0,0 +1,128 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage Authentication.joomla
*
* @copyright (C) 2006 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\Authentication\Joomla\Extension;
use Joomla\CMS\Authentication\Authentication;
use Joomla\CMS\Event\User\AuthenticationEvent;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\User\UserFactoryAwareTrait;
use Joomla\CMS\User\UserHelper;
use Joomla\Database\DatabaseAwareTrait;
use Joomla\Event\SubscriberInterface;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Joomla Authentication plugin
*
* @since 1.5
*/
final class Joomla extends CMSPlugin implements SubscriberInterface
{
use DatabaseAwareTrait;
use UserFactoryAwareTrait;
/**
* Returns an array of events this subscriber will listen to.
*
* @return array
*
* @since 5.0.0
*/
public static function getSubscribedEvents(): array
{
return ['onUserAuthenticate' => 'onUserAuthenticate'];
}
/**
* This method should handle any authentication and report back to the subject
*
* @param AuthenticationEvent $event Authentication event
*
* @return void
*
* @since 1.5
*/
public function onUserAuthenticate(AuthenticationEvent $event): void
{
$credentials = $event->getCredentials();
$response = $event->getAuthenticationResponse();
$response->type = 'Joomla';
// Joomla does not like blank passwords
if (empty($credentials['password'])) {
$response->status = Authentication::STATUS_FAILURE;
$response->error_message = $this->getApplication()->getLanguage()->_('JGLOBAL_AUTH_EMPTY_PASS_NOT_ALLOWED');
return;
}
$db = $this->getDatabase();
$query = $db->getQuery(true)
->select($db->quoteName(['id', 'password']))
->from($db->quoteName('#__users'))
->where($db->quoteName('username') . ' = :username')
->bind(':username', $credentials['username']);
$db->setQuery($query);
$result = $db->loadObject();
if ($result) {
$match = UserHelper::verifyPassword($credentials['password'], $result->password, $result->id);
if ($match === true) {
// Bring this in line with the rest of the system
$user = $this->getUserFactory()->loadUserById($result->id);
$response->email = $user->email;
$response->fullname = $user->name;
// Set default status response to success
$_status = Authentication::STATUS_SUCCESS;
$_errorMessage = '';
if ($this->getApplication()->isClient('administrator')) {
$response->language = $user->getParam('admin_language');
} else {
$response->language = $user->getParam('language');
if ($this->getApplication()->get('offline') && !$user->authorise('core.login.offline')) {
// User do not have access in offline mode
$_status = Authentication::STATUS_FAILURE;
$_errorMessage = $this->getApplication()->getLanguage()->_('JLIB_LOGIN_DENIED');
}
}
$response->status = $_status;
$response->error_message = $_errorMessage;
// Stop event propagation when status is STATUS_SUCCESS
if ($response->status === Authentication::STATUS_SUCCESS) {
$event->stopPropagation();
}
} else {
// Invalid password
$response->status = Authentication::STATUS_FAILURE;
$response->error_message = $this->getApplication()->getLanguage()->_('JGLOBAL_AUTH_INVALID_PASS');
}
} else {
// Let's hash the entered password even if we don't have a matching user for some extra response time
// By doing so, we mitigate side channel user enumeration attacks
UserHelper::hashPassword($credentials['password']);
// Invalid user
$response->status = Authentication::STATUS_FAILURE;
$response->error_message = $this->getApplication()->getLanguage()->_('JGLOBAL_AUTH_NO_USER');
}
}
}

View File

@ -0,0 +1,186 @@
<?xml version="1.0" encoding="UTF-8"?>
<extension type="plugin" group="authentication" method="upgrade">
<name>plg_authentication_ldap</name>
<author>Joomla! Project</author>
<creationDate>2005-11</creationDate>
<copyright>(C) 2005 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>3.0.0</version>
<description>PLG_LDAP_XML_DESCRIPTION</description>
<namespace path="src">Joomla\Plugin\Authentication\Ldap</namespace>
<files>
<folder plugin="ldap">services</folder>
<folder>src</folder>
</files>
<languages>
<language tag="en-GB">language/en-GB/plg_authentication_ldap.ini</language>
<language tag="en-GB">language/en-GB/plg_authentication_ldap.sys.ini</language>
</languages>
<config>
<fields name="params">
<fieldset name="basic">
<field
name="host"
type="text"
label="PLG_LDAP_FIELD_HOST_LABEL"
required="true"
/>
<field
name="port"
type="number"
label="PLG_LDAP_FIELD_PORT_LABEL"
min="1"
max="65535"
default="389"
hint="389"
validate="number"
filter="integer"
/>
<field
name="use_ldapV3"
type="radio"
layout="joomla.form.field.radio.switcher"
label="PLG_LDAP_FIELD_V3_LABEL"
default="1"
filter="integer"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
<field
name="encryption"
type="list"
label="PLG_LDAP_FIELD_ENCRYPTION_LABEL"
default="none"
validate="options"
>
<option value="none">PLG_LDAP_FIELD_VALUE_ENCRYPTIONNONE</option>
<option value="tls">PLG_LDAP_FIELD_VALUE_ENCRYPTIONTLS</option>
<option value="ssl">PLG_LDAP_FIELD_VALUE_ENCRYPTIONSSL</option>
</field>
<field
name="ignore_reqcert_tls"
type="radio"
label="PLG_LDAP_FIELD_IGNORE_REQCERT_TLS_LABEL"
layout="joomla.form.field.radio.switcher"
default="1"
filter="boolean"
showon="encryption!:none"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
<field
name="cacert"
type="text"
label="PLG_LDAP_FIELD_CACERT_LABEL"
description="PLG_LDAP_FIELD_CACERT_DESC"
required="false"
showon="encryption!:none[AND]ignore_reqcert_tls:0"
/>
<field
name="no_referrals"
type="radio"
label="PLG_LDAP_FIELD_REFERRALS_LABEL"
default="0"
filter="integer"
layout="joomla.form.field.radio.switcher"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
<field
name="auth_method"
type="list"
label="PLG_LDAP_FIELD_AUTHMETHOD_LABEL"
default="bind"
validate="options"
>
<option value="search">PLG_LDAP_FIELD_VALUE_BINDSEARCH</option>
<option value="bind">PLG_LDAP_FIELD_VALUE_BINDUSER</option>
</field>
<field
name="base_dn"
type="text"
label="PLG_LDAP_FIELD_BASEDN_LABEL"
required="true"
/>
<field
name="search_string"
type="text"
label="PLG_LDAP_FIELD_SEARCHSTRING_LABEL"
description="PLG_LDAP_FIELD_SEARCHSTRING_DESC"
required="true"
/>
<field
name="users_dn"
type="text"
label="PLG_LDAP_FIELD_USERSDN_LABEL"
description="PLG_LDAP_FIELD_USERSDN_DESC"
/>
<field
name="username"
type="text"
label="PLG_LDAP_FIELD_USERNAME_LABEL"
description="PLG_LDAP_FIELD_USERNAME_DESC"
/>
<field
name="password"
type="password"
label="PLG_LDAP_FIELD_PASSWORD_LABEL"
description="PLG_LDAP_FIELD_PASSWORD_DESC"
/>
<field
name="ldap_fullname"
type="text"
label="PLG_LDAP_FIELD_FULLNAME_LABEL"
description="PLG_LDAP_FIELD_FULLNAME_DESC"
default="fullName"
/>
<field
name="ldap_email"
type="text"
label="PLG_LDAP_FIELD_EMAIL_LABEL"
description="PLG_LDAP_FIELD_EMAIL_DESC"
default="mail"
/>
<field
name="ldap_uid"
type="text"
label="PLG_LDAP_FIELD_UID_LABEL"
description="PLG_LDAP_FIELD_UID_DESC"
default="uid"
/>
<field
name="ldap_debug"
type="radio"
label="PLG_LDAP_FIELD_LDAPDEBUG_LABEL"
description="PLG_LDAP_FIELD_LDAPDEBUG_DESC"
default="0"
filter="integer"
layout="joomla.form.field.radio.switcher"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
</fieldset>
</fields>
</config>
</extension>

View File

@ -0,0 +1,48 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage Authentication.ldap
*
* @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
\defined('_JEXEC') or die;
use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use Joomla\Plugin\Authentication\Ldap\Extension\Ldap;
use Joomla\Plugin\Authentication\Ldap\Factory\LdapFactory;
return new class () implements ServiceProviderInterface {
/**
* Registers the service provider with a DI container.
*
* @param Container $container The DI container.
*
* @return void
*
* @since 4.3.0
*/
public function register(Container $container)
{
$container->set(
PluginInterface::class,
function (Container $container) {
$plugin = new Ldap(
new LdapFactory(),
$container->get(DispatcherInterface::class),
(array) PluginHelper::getPlugin('authentication', 'ldap')
);
$plugin->setApplication(Factory::getApplication());
return $plugin;
}
);
}
};

View File

@ -0,0 +1,316 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage Authentication.ldap
*
* @copyright (C) 2006 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\Authentication\Ldap\Extension;
use Joomla\CMS\Authentication\Authentication;
use Joomla\CMS\Event\User\AuthenticationEvent;
use Joomla\CMS\Log\Log;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\Event\DispatcherInterface;
use Joomla\Event\SubscriberInterface;
use Joomla\Plugin\Authentication\Ldap\Factory\LdapFactoryInterface;
use Symfony\Component\Ldap\Entry;
use Symfony\Component\Ldap\Exception\ConnectionException;
use Symfony\Component\Ldap\Exception\LdapException;
use Symfony\Component\Ldap\LdapInterface;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* LDAP Authentication Plugin
*
* @since 1.5
*/
final class Ldap extends CMSPlugin implements SubscriberInterface
{
/**
* The ldap factory
*
* @var LdapFactoryInterface
* @since 4.3.0
*/
private $factory;
/**
* Constructor
*
* @param LdapFactoryInterface $factory The Ldap factory
* @param DispatcherInterface $dispatcher The object to observe
* @param array $config An optional associative array of configuration settings.
* Recognized key values include 'name', 'group', 'params', 'language'
* (this list is not meant to be comprehensive).
*
* @since 4.3.0
*/
public function __construct(LdapFactoryInterface $factory, DispatcherInterface $dispatcher, array $config = [])
{
parent::__construct($dispatcher, $config);
$this->factory = $factory;
}
/**
* Returns an array of events this subscriber will listen to.
*
* @return array
*
* @since 5.2.0
*/
public static function getSubscribedEvents(): array
{
return ['onUserAuthenticate' => 'onUserAuthenticate'];
}
/**
* This method should handle any authentication and report back to the subject
*
* @param AuthenticationEvent $event Authentication event
*
* @return void
*
* @since 1.5
*/
public function onUserAuthenticate(AuthenticationEvent $event): void
{
// If LDAP not correctly configured then bail early.
if (!$this->params->get('host', '')) {
return;
}
$credentials = $event->getCredentials();
$response = $event->getAuthenticationResponse();
// For JLog
$logcategory = 'ldap';
$response->type = $logcategory;
// Strip null bytes from the password
$credentials['password'] = str_replace(\chr(0), '', $credentials['password']);
// LDAP does not like Blank passwords (tries to Anon Bind which is bad)
if (empty($credentials['password'])) {
$response->status = Authentication::STATUS_FAILURE;
$response->error_message = $this->getApplication()->getLanguage()->_('JGLOBAL_AUTH_EMPTY_PASS_NOT_ALLOWED');
return;
}
// Load plugin params info
$ldap_email = $this->params->get('ldap_email', '');
$ldap_fullname = $this->params->get('ldap_fullname', '');
$ldap_uid = $this->params->get('ldap_uid', '');
$auth_method = $this->params->get('auth_method', '');
// Load certificate info
$ignore_reqcert_tls = (bool) $this->params->get('ignore_reqcert_tls', '1');
$cacert = $this->params->get('cacert', '');
// getting certificate file and certificate directory options (both need to be set)
if (!$ignore_reqcert_tls && !empty($cacert)) {
if (is_dir($cacert)) {
$cacertdir = $cacert;
$cacertfile = "";
} elseif (is_file($cacert)) {
$cacertfile = $cacert;
$cacertdir = \dirname($cacert);
} else {
$cacertfile = $cacert;
$cacertdir = $cacert;
Log::add(\sprintf('Certificate path for LDAP client is neither an existing file nor directory: "%s"', $cacert), Log::ERROR, $logcategory);
}
} else {
Log::add(\sprintf('Not setting any LDAP TLS CA certificate options because %s, system wide settings are used', $ignore_reqcert_tls ? "certificate is ignored" : "no certificate location is configured"), Log::DEBUG, $logcategory);
}
$options = [
'host' => $this->params->get('host', ''),
'port' => (int) $this->params->get('port', ''),
'version' => $this->params->get('use_ldapV3', '1') == '1' ? 3 : 2,
'referrals' => (bool) $this->params->get('no_referrals', '0'),
'encryption' => $this->params->get('encryption', 'none'),
'debug' => (bool) $this->params->get('ldap_debug', '0'),
'options' => [
'x_tls_require_cert' => $ignore_reqcert_tls ? LDAP_OPT_X_TLS_NEVER : LDAP_OPT_X_TLS_DEMAND,
],
];
// if these are not set, the system defaults are used
if (isset($cacertdir) && isset($cacertfile)) {
$options['options']['x_tls_cacertdir'] = $cacertdir;
$options['options']['x_tls_cacertfile'] = $cacertfile;
}
Log::add(\sprintf('Creating LDAP session with options: %s', json_encode($options)), Log::DEBUG, $logcategory);
$connection_string = \sprintf('ldap%s://%s:%s', 'ssl' === $options['encryption'] ? 's' : '', $options['host'], $options['port']);
Log::add(\sprintf('Creating LDAP session to connect to "%s" while binding', $connection_string), Log::DEBUG, $logcategory);
$ldap = $this->factory->createLdap($options);
switch ($auth_method) {
case 'search':
try {
$dn = $this->params->get('username', '');
Log::add(\sprintf('Binding to LDAP server with administrative dn "%s" and given administrative password (anonymous if user dn is blank)', $dn), Log::DEBUG, $logcategory);
$ldap->bind($dn, $this->params->get('password', ''));
} catch (ConnectionException | LdapException $exception) {
$response->status = Authentication::STATUS_FAILURE;
$response->error_message = $this->getApplication()->getLanguage()->_('JGLOBAL_AUTH_NOT_CONNECT');
Log::add($exception->getMessage(), Log::ERROR, $logcategory);
return;
}
// Search for users DN
try {
$searchstring = str_replace(
'[search]',
str_replace(';', '\3b', $ldap->escape($credentials['username'], '', LDAP_ESCAPE_FILTER)),
$this->params->get('search_string', '')
);
Log::add(\sprintf('Searching LDAP entry with filter: "%s"', $searchstring), Log::DEBUG, $logcategory);
$entry = $this->searchByString($searchstring, $ldap);
} catch (LdapException $exception) {
$response->status = Authentication::STATUS_FAILURE;
$response->error_message = $this->getApplication()->getLanguage()->_('JGLOBAL_AUTH_UNKNOWN_ACCESS_DENIED');
Log::add($exception->getMessage(), Log::ERROR, $logcategory);
return;
}
if (!$entry) {
// we did not find the login in LDAP
$response->status = Authentication::STATUS_FAILURE;
$response->error_message = $this->getApplication()->getLanguage()->_('JGLOBAL_AUTH_NO_USER');
Log::add($this->getApplication()->getLanguage()->_('JGLOBAL_AUTH_USER_NOT_FOUND'), Log::ERROR, $logcategory);
return;
}
Log::add(\sprintf('LDAP entry found at "%s"', $entry->getDn()), Log::DEBUG, $logcategory);
try {
// Verify Users Credentials
Log::add(\sprintf('Binding to LDAP server with found user dn "%s" and user entered password', $entry->getDn()), Log::DEBUG, $logcategory);
$ldap->bind($entry->getDn(), $credentials['password']);
} catch (ConnectionException $exception) {
$response->status = Authentication::STATUS_FAILURE;
$response->error_message = $this->getApplication()->getLanguage()->_('JGLOBAL_AUTH_INVALID_PASS');
Log::add($exception->getMessage(), Log::ERROR, $logcategory);
return;
}
break;
case 'bind':
// We just accept the result here
try {
if ($this->params->get('users_dn', '') == '') {
$dn = $credentials['username'];
} else {
$dn = str_replace(
'[username]',
$ldap->escape($credentials['username'], '', LDAP_ESCAPE_DN),
$this->params->get('users_dn', '')
);
}
Log::add(\sprintf('Direct binding to LDAP server with entered user dn "%s" and user entered password', $dn), Log::DEBUG, $logcategory);
$ldap->bind($dn, $credentials['password']);
} catch (ConnectionException | LdapException $exception) {
$response->status = Authentication::STATUS_FAILURE;
$response->error_message = $this->getApplication()->getLanguage()->_('JGLOBAL_AUTH_INVALID_PASS');
Log::add($exception->getMessage(), Log::ERROR, $logcategory);
return;
}
try {
$searchstring = str_replace(
'[search]',
str_replace(';', '\3b', $ldap->escape($credentials['username'], '', LDAP_ESCAPE_FILTER)),
$this->params->get('search_string', '')
);
Log::add(\sprintf('Searching LDAP entry with filter: "%s"', $searchstring), Log::DEBUG, $logcategory);
$entry = $this->searchByString($searchstring, $ldap);
} catch (LdapException $exception) {
$response->status = Authentication::STATUS_FAILURE;
$response->error_message = $this->getApplication()->getLanguage()->_('JGLOBAL_AUTH_UNKNOWN_ACCESS_DENIED');
Log::add($exception->getMessage(), Log::ERROR, $logcategory);
return;
}
if (!$entry) {
// we did not find the login in LDAP
$response->status = Authentication::STATUS_FAILURE;
$response->error_message = $this->getApplication()->getLanguage()->_('JGLOBAL_AUTH_NO_USER');
Log::add($this->getApplication()->getLanguage()->_('JGLOBAL_AUTH_USER_NOT_FOUND'), Log::ERROR, $logcategory);
return;
}
Log::add(\sprintf('LDAP entry found at "%s"', $entry->getDn()), Log::DEBUG, $logcategory);
break;
default:
// Unsupported configuration
$response->status = Authentication::STATUS_FAILURE;
$response->error_message = $this->getApplication()->getLanguage()->_('JGLOBAL_AUTH_UNKNOWN_ACCESS_DENIED');
Log::add($response->error_message, Log::ERROR, $logcategory);
return;
}
// Grab some details from LDAP and return them
$response->username = $entry->getAttribute($ldap_uid)[0] ?? false;
$response->email = $entry->getAttribute($ldap_email)[0] ?? false;
$response->fullname = $entry->getAttribute($ldap_fullname)[0] ?? $credentials['username'];
// Were good - So say so.
Log::add(\sprintf('LDAP login succeeded; username: "%s", email: "%s", fullname: "%s"', $response->username, $response->email, $response->fullname), Log::DEBUG, $logcategory);
$response->status = Authentication::STATUS_SUCCESS;
$response->error_message = '';
// Stop event propagation when status is STATUS_SUCCESS
$event->stopPropagation();
// The connection is no longer needed, destroy the object to close it
unset($ldap);
}
/**
* Shortcut method to perform a LDAP search based on a semicolon separated string
*
* Note that this method requires that semicolons which should be part of the search term to be escaped
* to correctly split the search string into separate lookups
*
* @param string $search search string of search values
* @param LdapInterface $ldap The LDAP client
*
* @return Entry|null The search result entry if a matching record was found
*
* @since 3.8.2
*/
private function searchByString(string $search, LdapInterface $ldap)
{
$dn = $this->params->get('base_dn', '');
// We return the first entry from the first search result which contains data
foreach (explode(';', $search) as $key => $result) {
$results = $ldap->query($dn, '(' . str_replace('\3b', ';', $result) . ')')->execute();
if (\count($results)) {
return $results[0];
}
}
}
}

View File

@ -0,0 +1,41 @@
<?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\Authentication\Ldap\Factory;
use Symfony\Component\Ldap\Ldap;
use Symfony\Component\Ldap\LdapInterface;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Factory to create Ldap clients.
*
* @since 4.3.0
*/
class LdapFactory implements LdapFactoryInterface
{
/**
* Method to load and return an Ldap client.
*
* @param array $config The configuration array for the ldap client
*
* @return LdapInterface
*
* @since 4.3.0
*
* @throws \Exception
*/
public function createLdap(array $config): LdapInterface
{
return Ldap::create('ext_ldap', $config);
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\Authentication\Ldap\Factory;
use Symfony\Component\Ldap\LdapInterface;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Factory to create Ldap clients.
*
* @since 4.3.0
*/
interface LdapFactoryInterface
{
/**
* Method to load and return an Ldap client.
*
* @param array $config The configuration array for the ldap client
*
* @return LdapInterface
*
* @since 4.3.0
* @throws \Exception
*/
public function createLdap(array $config): LdapInterface;
}

View File

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8"?>
<extension type="plugin" group="behaviour" method="upgrade">
<name>plg_behaviour_compat</name>
<author>Joomla! Project</author>
<creationDate>2023-09</creationDate>
<copyright>(C) 2023 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>5.0.0</version>
<description>PLG_COMPAT_XML_DESCRIPTION</description>
<namespace path="src">Joomla\Plugin\Behaviour\Compat</namespace>
<files>
<folder plugin="compat">services</folder>
<folder>src</folder>
</files>
<languages>
<language tag="en-GB">language/en-GB/plg_behaviour_compat.ini</language>
<language tag="en-GB">language/en-GB/plg_behaviour_compat.sys.ini</language>
</languages>
<config>
<fields name="params">
<fieldset name="basic">
<field
name="classes_aliases"
type="radio"
layout="joomla.form.field.radio.switcher"
label="PLG_COMPAT_FIELD_CLASSES_ALIASES_LABEL"
description="PLG_COMPAT_FIELD_CLASSES_ALIASES_DESCRIPTION"
default="1"
filter="integer"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
<field
name="es5_assets"
type="radio"
label="PLG_COMPAT_FIELD_ES5_ASSETS_LABEL"
description="PLG_COMPAT_FIELD_ES5_ASSETS_DESCRIPTION"
layout="joomla.form.field.radio.switcher"
default="1"
filter="integer"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
<field
name="removed_asset"
type="radio"
label="PLG_COMPAT_FIELD_REMOVED_ASSETS_LABEL"
description="PLG_COMPAT_FIELD_REMOVED_ASSETS_DESCRIPTION"
layout="joomla.form.field.radio.switcher"
default="1"
filter="integer"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
</fieldset>
</fields>
</config>
</extension>

View File

@ -0,0 +1,45 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage Behaviour.compat
*
* @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
\defined('_JEXEC') or die;
use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use Joomla\Plugin\Behaviour\Compat\Extension\Compat;
return new class () implements ServiceProviderInterface {
/**
* Registers the service provider with a DI container.
*
* @param Container $container The DI container.
*
* @return void
* @since 4.4.0
*/
public function register(Container $container)
{
$container->set(
PluginInterface::class,
function (Container $container) {
$plugin = PluginHelper::getPlugin('behaviour', 'compat');
$dispatcher = $container->get(DispatcherInterface::class);
$plugin = new Compat($dispatcher, (array) $plugin);
$plugin->setApplication(Factory::getApplication());
return $plugin;
}
);
}
};

View File

@ -0,0 +1,112 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage Behaviour.compat
*
* @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\Behaviour\Compat\Extension;
use Joomla\CMS\Event\Application\AfterInitialiseDocumentEvent;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\Event\DispatcherInterface;
use Joomla\Event\Priority;
use Joomla\Event\SubscriberInterface;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Joomla! Compat Plugin.
*
* @since 4.4.0
*/
final class Compat extends CMSPlugin implements SubscriberInterface
{
/**
* Returns an array of CMS events this plugin will listen to and the respective handlers.
*
* @return array
*
* @since 4.4.0
*/
public static function getSubscribedEvents(): array
{
/**
* Note that onAfterInitialise must be the first handlers to run for this
* plugin to operate as expected. These handlers load compatibility code which
* might be needed by other plugins
*/
return [
'onAfterInitialiseDocument' => ['onAfterInitialiseDocument', Priority::HIGH],
];
}
/**
* Constructor
*
* @param DispatcherInterface $dispatcher The event dispatcher
* @param array $config An optional associative array of configuration settings.
* Recognized key values include 'name', 'group', 'params', 'language'
* (this list is not meant to be comprehensive).
*
* @since 1.5
*/
public function __construct(DispatcherInterface $dispatcher, array $config = [])
{
parent::__construct($dispatcher, $config);
/**
* Normally we should never use the constructor to execute any logic which would
* affect other parts of the cms, but since we need to load class aliases as
* early as possible we load the class aliases in the constructor so behaviour and system plugins
* which depend on the JPlugin alias for example still are working
*/
/**
* Load class names which are deprecated in joomla 4.0 and which will
* likely be removed in Joomla 6.0
*/
if ($this->params->get('classes_aliases', '1')) {
require_once \dirname(__DIR__) . '/classmap/classmap.php';
}
}
/**
* We run as early as possible, this should be the first event
*
* @param AfterInitialiseDocumentEvent $event
* @return void
*
* @since 5.0.0
*/
public function onAfterInitialiseDocument(AfterInitialiseDocumentEvent $event)
{
/**
* Load the es5 assets stubs, they are needed if an extension
* directly uses a core es5 asset which has no function in Joomla 5+
* and only provides an empty asset to not throw an exception
*/
if ($this->params->get('es5_assets', '1')) {
$event->getDocument()
->getWebAssetManager()
->getRegistry()
->addRegistryFile('media/plg_behaviour_compat/es5.asset.json');
}
/**
* Load the removed assets stubs, they are needed if an extension
* directly uses a core asset from Joomla 4 which is not present in Joomla 5+
* and only provides an empty asset to not throw an exception
*/
if ($this->params->get('removed_asset', '1')) {
$event->getDocument()
->getWebAssetManager()
->getRegistry()
->addRegistryFile('media/plg_behaviour_compat/removed.asset.json');
}
}
}

View File

@ -0,0 +1,532 @@
<?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2014 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
// No direct access.
\defined('_JEXEC') or die;
require_once __DIR__ . '/extensions.classmap.php';
JLoader::registerAlias('JRegistry', '\\Joomla\\Registry\\Registry', '6.0');
JLoader::registerAlias('JRegistryFormatIni', '\\Joomla\\Registry\\Format\\Ini', '6.0');
JLoader::registerAlias('JRegistryFormatJson', '\\Joomla\\Registry\\Format\\Json', '6.0');
JLoader::registerAlias('JRegistryFormatPhp', '\\Joomla\\Registry\\Format\\Php', '6.0');
JLoader::registerAlias('JRegistryFormatXml', '\\Joomla\\Registry\\Format\\Xml', '6.0');
JLoader::registerAlias('JStringInflector', '\\Joomla\\String\\Inflector', '6.0');
JLoader::registerAlias('JStringNormalise', '\\Joomla\\String\\Normalise', '6.0');
JLoader::registerAlias('JData', '\\Joomla\\Data\\DataObject', '6.0');
JLoader::registerAlias('JDataSet', '\\Joomla\\Data\\DataSet', '6.0');
JLoader::registerAlias('JDataDumpable', '\\Joomla\\Data\\DumpableInterface', '6.0');
JLoader::registerAlias('JApplicationAdministrator', '\\Joomla\\CMS\\Application\\AdministratorApplication', '6.0');
JLoader::registerAlias('JApplicationHelper', '\\Joomla\\CMS\\Application\\ApplicationHelper', '6.0');
JLoader::registerAlias('JApplicationBase', '\\Joomla\\CMS\\Application\\BaseApplication', '6.0');
JLoader::registerAlias('JApplicationCli', '\\Joomla\\CMS\\Application\\CliApplication', '6.0');
JLoader::registerAlias('JApplicationCms', '\\Joomla\\CMS\\Application\\CMSApplication', '6.0');
JLoader::registerAlias('JApplicationDaemon', '\\Joomla\\CMS\\Application\\DaemonApplication', '6.0');
JLoader::registerAlias('JApplicationSite', '\\Joomla\\CMS\\Application\\SiteApplication', '6.0');
JLoader::registerAlias('JApplicationWeb', '\\Joomla\\CMS\\Application\\WebApplication', '6.0');
JLoader::registerAlias('JApplicationWebClient', '\\Joomla\\Application\\Web\\WebClient', '6.0');
JLoader::registerAlias('JDaemon', '\\Joomla\\CMS\\Application\\DaemonApplication', '6.0');
JLoader::registerAlias('JCli', '\\Joomla\\CMS\\Application\\CliApplication', '6.0');
JLoader::registerAlias('JWeb', '\\Joomla\\CMS\\Application\\WebApplication', '4.0');
JLoader::registerAlias('JWebClient', '\\Joomla\\Application\\Web\\WebClient', '4.0');
JLoader::registerAlias('JModelAdmin', '\\Joomla\\CMS\\MVC\\Model\\AdminModel', '6.0');
JLoader::registerAlias('JModelForm', '\\Joomla\\CMS\\MVC\\Model\\FormModel', '6.0');
JLoader::registerAlias('JModelItem', '\\Joomla\\CMS\\MVC\\Model\\ItemModel', '6.0');
JLoader::registerAlias('JModelList', '\\Joomla\\CMS\\MVC\\Model\\ListModel', '6.0');
JLoader::registerAlias('JModelLegacy', '\\Joomla\\CMS\\MVC\\Model\\BaseDatabaseModel', '6.0');
JLoader::registerAlias('JViewCategories', '\\Joomla\\CMS\\MVC\\View\\CategoriesView', '6.0');
JLoader::registerAlias('JViewCategory', '\\Joomla\\CMS\\MVC\\View\\CategoryView', '6.0');
JLoader::registerAlias('JViewCategoryfeed', '\\Joomla\\CMS\\MVC\\View\\CategoryFeedView', '6.0');
JLoader::registerAlias('JViewLegacy', '\\Joomla\\CMS\\MVC\\View\\HtmlView', '6.0');
JLoader::registerAlias('JControllerAdmin', '\\Joomla\\CMS\\MVC\\Controller\\AdminController', '6.0');
JLoader::registerAlias('JControllerLegacy', '\\Joomla\\CMS\\MVC\\Controller\\BaseController', '6.0');
JLoader::registerAlias('JControllerForm', '\\Joomla\\CMS\\MVC\\Controller\\FormController', '6.0');
JLoader::registerAlias('JTableInterface', '\\Joomla\\CMS\\Table\\TableInterface', '6.0');
JLoader::registerAlias('JTable', '\\Joomla\\CMS\\Table\\Table', '6.0');
JLoader::registerAlias('JTableNested', '\\Joomla\\CMS\\Table\\Nested', '6.0');
JLoader::registerAlias('JTableAsset', '\\Joomla\\CMS\\Table\\Asset', '6.0');
JLoader::registerAlias('JTableExtension', '\\Joomla\\CMS\\Table\\Extension', '6.0');
JLoader::registerAlias('JTableLanguage', '\\Joomla\\CMS\\Table\\Language', '6.0');
JLoader::registerAlias('JTableUpdate', '\\Joomla\\CMS\\Table\\Update', '6.0');
JLoader::registerAlias('JTableUpdatesite', '\\Joomla\\CMS\\Table\\UpdateSite', '6.0');
JLoader::registerAlias('JTableUser', '\\Joomla\\CMS\\Table\\User', '6.0');
JLoader::registerAlias('JTableUsergroup', '\\Joomla\\CMS\\Table\\Usergroup', '6.0');
JLoader::registerAlias('JTableViewlevel', '\\Joomla\\CMS\\Table\\ViewLevel', '6.0');
JLoader::registerAlias('JTableContenthistory', '\\Joomla\\CMS\\Table\\ContentHistory', '6.0');
JLoader::registerAlias('JTableContenttype', '\\Joomla\\CMS\\Table\\ContentType', '6.0');
JLoader::registerAlias('JTableCorecontent', '\\Joomla\\CMS\\Table\\CoreContent', '6.0');
JLoader::registerAlias('JTableUcm', '\\Joomla\\CMS\\Table\\Ucm', '6.0');
JLoader::registerAlias('JTableCategory', '\\Joomla\\CMS\\Table\\Category', '6.0');
JLoader::registerAlias('JTableContent', '\\Joomla\\CMS\\Table\\Content', '6.0');
JLoader::registerAlias('JTableMenu', '\\Joomla\\CMS\\Table\\Menu', '6.0');
JLoader::registerAlias('JTableMenuType', '\\Joomla\\CMS\\Table\\MenuType', '6.0');
JLoader::registerAlias('JTableModule', '\\Joomla\\CMS\\Table\\Module', '6.0');
JLoader::registerAlias('JAccess', '\\Joomla\\CMS\\Access\\Access', '6.0');
JLoader::registerAlias('JAccessRule', '\\Joomla\\CMS\\Access\\Rule', '6.0');
JLoader::registerAlias('JAccessRules', '\\Joomla\\CMS\\Access\\Rules', '6.0');
JLoader::registerAlias('JAccessExceptionNotallowed', '\\Joomla\\CMS\\Access\\Exception\\NotAllowed', '6.0');
JLoader::registerAlias('JRule', '\\Joomla\\CMS\\Access\\Rule', '6.0');
JLoader::registerAlias('JRules', '\\Joomla\\CMS\\Access\\Rules', '6.0');
JLoader::registerAlias('JHelp', '\\Joomla\\CMS\\Help\\Help', '6.0');
JLoader::registerAlias('JCaptcha', '\\Joomla\\CMS\\Captcha\\Captcha', '6.0');
JLoader::registerAlias('JLanguageAssociations', '\\Joomla\\CMS\\Language\\Associations', '6.0');
JLoader::registerAlias('JLanguage', '\\Joomla\\CMS\\Language\\Language', '6.0');
JLoader::registerAlias('JLanguageHelper', '\\Joomla\\CMS\\Language\\LanguageHelper', '6.0');
JLoader::registerAlias('JLanguageMultilang', '\\Joomla\\CMS\\Language\\Multilanguage', '6.0');
JLoader::registerAlias('JText', '\\Joomla\\CMS\\Language\\Text', '6.0');
JLoader::registerAlias('JLanguageTransliterate', '\\Joomla\\CMS\\Language\\Transliterate', '6.0');
JLoader::registerAlias('JComponentHelper', '\\Joomla\\CMS\\Component\\ComponentHelper', '6.0');
JLoader::registerAlias('JComponentRecord', '\\Joomla\\CMS\\Component\\ComponentRecord', '6.0');
JLoader::registerAlias('JComponentExceptionMissing', '\\Joomla\\CMS\\Component\\Exception\\MissingComponentException', '6.0');
JLoader::registerAlias('JComponentRouterBase', '\\Joomla\\CMS\\Component\\Router\\RouterBase', '6.0');
JLoader::registerAlias('JComponentRouterInterface', '\\Joomla\\CMS\\Component\\Router\\RouterInterface', '6.0');
JLoader::registerAlias('JComponentRouterLegacy', '\\Joomla\\CMS\\Component\\Router\\RouterLegacy', '6.0');
JLoader::registerAlias('JComponentRouterView', '\\Joomla\\CMS\\Component\\Router\\RouterView', '6.0');
JLoader::registerAlias('JComponentRouterViewconfiguration', '\\Joomla\\CMS\\Component\\Router\\RouterViewConfiguration', '6.0');
JLoader::registerAlias('JComponentRouterRulesMenu', '\\Joomla\\CMS\\Component\\Router\\Rules\\MenuRules', '6.0');
JLoader::registerAlias('JComponentRouterRulesNomenu', '\\Joomla\\CMS\\Component\\Router\\Rules\\NomenuRules', '6.0');
JLoader::registerAlias('JComponentRouterRulesInterface', '\\Joomla\\CMS\\Component\\Router\\Rules\\RulesInterface', '6.0');
JLoader::registerAlias('JComponentRouterRulesStandard', '\\Joomla\\CMS\\Component\\Router\\Rules\\StandardRules', '6.0');
JLoader::registerAlias('JEditor', '\\Joomla\\CMS\\Editor\\Editor', '6.0');
JLoader::registerAlias('JErrorPage', '\\Joomla\\CMS\\Exception\\ExceptionHandler', '6.0');
JLoader::registerAlias('JAuthenticationHelper', '\\Joomla\\CMS\\Helper\\AuthenticationHelper', '6.0');
JLoader::registerAlias('JHelper', '\\Joomla\\CMS\\Helper\\CMSHelper', '6.0');
JLoader::registerAlias('JHelperContent', '\\Joomla\\CMS\\Helper\\ContentHelper', '6.0');
JLoader::registerAlias('JLibraryHelper', '\\Joomla\\CMS\\Helper\\LibraryHelper', '6.0');
JLoader::registerAlias('JHelperMedia', '\\Joomla\\CMS\\Helper\\MediaHelper', '6.0');
JLoader::registerAlias('JModuleHelper', '\\Joomla\\CMS\\Helper\\ModuleHelper', '6.0');
JLoader::registerAlias('JHelperRoute', '\\Joomla\\CMS\\Helper\\RouteHelper', '6.0');
JLoader::registerAlias('JHelperTags', '\\Joomla\\CMS\\Helper\\TagsHelper', '6.0');
JLoader::registerAlias('JHelperUsergroups', '\\Joomla\\CMS\\Helper\\UserGroupsHelper', '6.0');
JLoader::registerAlias('JLayoutBase', '\\Joomla\\CMS\\Layout\\BaseLayout', '6.0');
JLoader::registerAlias('JLayoutFile', '\\Joomla\\CMS\\Layout\\FileLayout', '6.0');
JLoader::registerAlias('JLayoutHelper', '\\Joomla\\CMS\\Layout\\LayoutHelper', '6.0');
JLoader::registerAlias('JLayout', '\\Joomla\\CMS\\Layout\\LayoutInterface', '6.0');
JLoader::registerAlias('JResponseJson', '\\Joomla\\CMS\\Response\\JsonResponse', '6.0');
JLoader::registerAlias('JPlugin', '\\Joomla\\CMS\\Plugin\\CMSPlugin', '6.0');
JLoader::registerAlias('JPluginHelper', '\\Joomla\\CMS\\Plugin\\PluginHelper', '6.0');
JLoader::registerAlias('JMenu', '\\Joomla\\CMS\\Menu\\AbstractMenu', '6.0');
JLoader::registerAlias('JMenuAdministrator', '\\Joomla\\CMS\\Menu\\AdministratorMenu', '6.0');
JLoader::registerAlias('JMenuItem', '\\Joomla\\CMS\\Menu\\MenuItem', '6.0');
JLoader::registerAlias('JMenuSite', '\\Joomla\\CMS\\Menu\\SiteMenu', '6.0');
JLoader::registerAlias('JPagination', '\\Joomla\\CMS\\Pagination\\Pagination', '6.0');
JLoader::registerAlias('JPaginationObject', '\\Joomla\\CMS\\Pagination\\PaginationObject', '6.0');
JLoader::registerAlias('JPathway', '\\Joomla\\CMS\\Pathway\\Pathway', '6.0');
JLoader::registerAlias('JPathwaySite', '\\Joomla\\CMS\\Pathway\\SitePathway', '6.0');
JLoader::registerAlias('JSchemaChangeitem', '\\Joomla\\CMS\\Schema\\ChangeItem', '6.0');
JLoader::registerAlias('JSchemaChangeset', '\\Joomla\\CMS\\Schema\\ChangeSet', '6.0');
JLoader::registerAlias('JSchemaChangeitemMysql', '\\Joomla\\CMS\\Schema\\ChangeItem\\MysqlChangeItem', '6.0');
JLoader::registerAlias('JSchemaChangeitemPostgresql', '\\Joomla\\CMS\\Schema\\ChangeItem\\PostgresqlChangeItem', '6.0');
JLoader::registerAlias('JUcm', '\\Joomla\\CMS\\UCM\\UCM', '6.0');
JLoader::registerAlias('JUcmBase', '\\Joomla\\CMS\\UCM\\UCMBase', '6.0');
JLoader::registerAlias('JUcmContent', '\\Joomla\\CMS\\UCM\\UCMContent', '6.0');
JLoader::registerAlias('JUcmType', '\\Joomla\\CMS\\UCM\\UCMType', '6.0');
JLoader::registerAlias('JToolbar', '\\Joomla\\CMS\\Toolbar\\Toolbar', '6.0');
JLoader::registerAlias('JToolbarButton', '\\Joomla\\CMS\\Toolbar\\ToolbarButton', '6.0');
JLoader::registerAlias('JToolbarButtonConfirm', '\\Joomla\\CMS\\Toolbar\\Button\\ConfirmButton', '6.0');
JLoader::registerAlias('JToolbarButtonCustom', '\\Joomla\\CMS\\Toolbar\\Button\\CustomButton', '6.0');
JLoader::registerAlias('JToolbarButtonHelp', '\\Joomla\\CMS\\Toolbar\\Button\\HelpButton', '6.0');
JLoader::registerAlias('JToolbarButtonLink', '\\Joomla\\CMS\\Toolbar\\Button\\LinkButton', '6.0');
JLoader::registerAlias('JToolbarButtonPopup', '\\Joomla\\CMS\\Toolbar\\Button\\PopupButton', '6.0');
JLoader::registerAlias('JToolbarButtonSeparator', '\\Joomla\\CMS\\Toolbar\\Button\\SeparatorButton', '6.0');
JLoader::registerAlias('JToolbarButtonStandard', '\\Joomla\\CMS\\Toolbar\\Button\\StandardButton', '6.0');
JLoader::registerAlias('JToolbarHelper', '\\Joomla\\CMS\\Toolbar\\ToolbarHelper', '6.0');
JLoader::registerAlias('JButton', '\\Joomla\\CMS\\Toolbar\\ToolbarButton', '6.0');
JLoader::registerAlias('JVersion', '\\Joomla\\CMS\\Version', '6.0');
JLoader::registerAlias('JAuthentication', '\\Joomla\\CMS\\Authentication\\Authentication', '6.0');
JLoader::registerAlias('JAuthenticationResponse', '\\Joomla\\CMS\\Authentication\\AuthenticationResponse', '6.0');
JLoader::registerAlias('JBrowser', '\\Joomla\\CMS\\Environment\\Browser', '6.0');
JLoader::registerAlias('JAssociationExtensionInterface', '\\Joomla\\CMS\\Association\\AssociationExtensionInterface', '6.0');
JLoader::registerAlias('JAssociationExtensionHelper', '\\Joomla\\CMS\\Association\\AssociationExtensionHelper', '6.0');
JLoader::registerAlias('JDocument', '\\Joomla\\CMS\\Document\\Document', '6.0');
JLoader::registerAlias('JDocumentError', '\\Joomla\\CMS\\Document\\ErrorDocument', '6.0');
JLoader::registerAlias('JDocumentFeed', '\\Joomla\\CMS\\Document\\FeedDocument', '6.0');
JLoader::registerAlias('JDocumentHtml', '\\Joomla\\CMS\\Document\\HtmlDocument', '6.0');
JLoader::registerAlias('JDocumentImage', '\\Joomla\\CMS\\Document\\ImageDocument', '6.0');
JLoader::registerAlias('JDocumentJson', '\\Joomla\\CMS\\Document\\JsonDocument', '6.0');
JLoader::registerAlias('JDocumentOpensearch', '\\Joomla\\CMS\\Document\\OpensearchDocument', '6.0');
JLoader::registerAlias('JDocumentRaw', '\\Joomla\\CMS\\Document\\RawDocument', '6.0');
JLoader::registerAlias('JDocumentRenderer', '\\Joomla\\CMS\\Document\\DocumentRenderer', '6.0');
JLoader::registerAlias('JDocumentXml', '\\Joomla\\CMS\\Document\\XmlDocument', '6.0');
JLoader::registerAlias('JDocumentRendererFeedAtom', '\\Joomla\\CMS\\Document\\Renderer\\Feed\\AtomRenderer', '6.0');
JLoader::registerAlias('JDocumentRendererFeedRss', '\\Joomla\\CMS\\Document\\Renderer\\Feed\\RssRenderer', '6.0');
JLoader::registerAlias('JDocumentRendererHtmlComponent', '\\Joomla\\CMS\\Document\\Renderer\\Html\\ComponentRenderer', '6.0');
JLoader::registerAlias('JDocumentRendererHtmlHead', '\\Joomla\\CMS\\Document\\Renderer\\Html\\HeadRenderer', '6.0');
JLoader::registerAlias('JDocumentRendererHtmlMessage', '\\Joomla\\CMS\\Document\\Renderer\\Html\\MessageRenderer', '6.0');
JLoader::registerAlias('JDocumentRendererHtmlModule', '\\Joomla\\CMS\\Document\\Renderer\\Html\\ModuleRenderer', '6.0');
JLoader::registerAlias('JDocumentRendererHtmlModules', '\\Joomla\\CMS\\Document\\Renderer\\Html\\ModulesRenderer', '6.0');
JLoader::registerAlias('JDocumentRendererAtom', '\\Joomla\\CMS\\Document\\Renderer\\Feed\\AtomRenderer', '4.0');
JLoader::registerAlias('JDocumentRendererRSS', '\\Joomla\\CMS\\Document\\Renderer\\Feed\\RssRenderer', '4.0');
JLoader::registerAlias('JDocumentRendererComponent', '\\Joomla\\CMS\\Document\\Renderer\\Html\\ComponentRenderer', '4.0');
JLoader::registerAlias('JDocumentRendererHead', '\\Joomla\\CMS\\Document\\Renderer\\Html\\HeadRenderer', '4.0');
JLoader::registerAlias('JDocumentRendererMessage', '\\Joomla\\CMS\\Document\\Renderer\\Html\\MessageRenderer', '4.0');
JLoader::registerAlias('JDocumentRendererModule', '\\Joomla\\CMS\\Document\\Renderer\\Html\\ModuleRenderer', '4.0');
JLoader::registerAlias('JDocumentRendererModules', '\\Joomla\\CMS\\Document\\Renderer\\Html\\ModulesRenderer', '4.0');
JLoader::registerAlias('JFeedEnclosure', '\\Joomla\\CMS\\Document\\Feed\\FeedEnclosure', '6.0');
JLoader::registerAlias('JFeedImage', '\\Joomla\\CMS\\Document\\Feed\\FeedImage', '6.0');
JLoader::registerAlias('JFeedItem', '\\Joomla\\CMS\\Document\\Feed\\FeedItem', '6.0');
JLoader::registerAlias('JOpenSearchImage', '\\Joomla\\CMS\\Document\\Opensearch\\OpensearchImage', '6.0');
JLoader::registerAlias('JOpenSearchUrl', '\\Joomla\\CMS\\Document\\Opensearch\\OpensearchUrl', '6.0');
JLoader::registerAlias('JFilterInput', '\\Joomla\\CMS\\Filter\\InputFilter', '6.0');
JLoader::registerAlias('JFilterOutput', '\\Joomla\\CMS\\Filter\\OutputFilter', '6.0');
JLoader::registerAlias('JHttp', '\\Joomla\\CMS\\Http\\Http', '6.0');
JLoader::registerAlias('JHttpFactory', '\\Joomla\\CMS\\Http\\HttpFactory', '6.0');
JLoader::registerAlias('JHttpResponse', '\\Joomla\\CMS\\Http\\Response', '6.0');
JLoader::registerAlias('JHttpTransport', '\\Joomla\\CMS\\Http\\TransportInterface', '6.0');
JLoader::registerAlias('JHttpTransportCurl', '\\Joomla\\CMS\\Http\\Transport\\CurlTransport', '6.0');
JLoader::registerAlias('JHttpTransportSocket', '\\Joomla\\CMS\\Http\\Transport\\SocketTransport', '6.0');
JLoader::registerAlias('JHttpTransportStream', '\\Joomla\\CMS\\Http\\Transport\\StreamTransport', '6.0');
JLoader::registerAlias('JInstaller', '\\Joomla\\CMS\\Installer\\Installer', '6.0');
JLoader::registerAlias('JInstallerAdapter', '\\Joomla\\CMS\\Installer\\InstallerAdapter', '6.0');
JLoader::registerAlias('JInstallerExtension', '\\Joomla\\CMS\\Installer\\InstallerExtension', '6.0');
JLoader::registerAlias('JExtension', '\\Joomla\\CMS\\Installer\\InstallerExtension', '6.0');
JLoader::registerAlias('JInstallerHelper', '\\Joomla\\CMS\\Installer\\InstallerHelper', '6.0');
JLoader::registerAlias('JInstallerScript', '\\Joomla\\CMS\\Installer\\InstallerScript', '6.0');
JLoader::registerAlias('JInstallerManifest', '\\Joomla\\CMS\\Installer\\Manifest', '6.0');
JLoader::registerAlias('JInstallerAdapterComponent', '\\Joomla\\CMS\\Installer\\Adapter\\ComponentAdapter', '6.0');
JLoader::registerAlias('JInstallerComponent', '\\Joomla\\CMS\\Installer\\Adapter\\ComponentAdapter', '6.0');
JLoader::registerAlias('JInstallerAdapterFile', '\\Joomla\\CMS\\Installer\\Adapter\\FileAdapter', '6.0');
JLoader::registerAlias('JInstallerFile', '\\Joomla\\CMS\\Installer\\Adapter\\FileAdapter', '6.0');
JLoader::registerAlias('JInstallerAdapterLanguage', '\\Joomla\\CMS\\Installer\\Adapter\\LanguageAdapter', '6.0');
JLoader::registerAlias('JInstallerLanguage', '\\Joomla\\CMS\\Installer\\Adapter\\LanguageAdapter', '6.0');
JLoader::registerAlias('JInstallerAdapterLibrary', '\\Joomla\\CMS\\Installer\\Adapter\\LibraryAdapter', '6.0');
JLoader::registerAlias('JInstallerLibrary', '\\Joomla\\CMS\\Installer\\Adapter\\LibraryAdapter', '6.0');
JLoader::registerAlias('JInstallerAdapterModule', '\\Joomla\\CMS\\Installer\\Adapter\\ModuleAdapter', '6.0');
JLoader::registerAlias('JInstallerModule', '\\Joomla\\CMS\\Installer\\Adapter\\ModuleAdapter', '6.0');
JLoader::registerAlias('JInstallerAdapterPackage', '\\Joomla\\CMS\\Installer\\Adapter\\PackageAdapter', '6.0');
JLoader::registerAlias('JInstallerPackage', '\\Joomla\\CMS\\Installer\\Adapter\\PackageAdapter', '6.0');
JLoader::registerAlias('JInstallerAdapterPlugin', '\\Joomla\\CMS\\Installer\\Adapter\\PluginAdapter', '6.0');
JLoader::registerAlias('JInstallerPlugin', '\\Joomla\\CMS\\Installer\\Adapter\\PluginAdapter', '6.0');
JLoader::registerAlias('JInstallerAdapterTemplate', '\\Joomla\\CMS\\Installer\\Adapter\\TemplateAdapter', '6.0');
JLoader::registerAlias('JInstallerTemplate', '\\Joomla\\CMS\\Installer\\Adapter\\TemplateAdapter', '6.0');
JLoader::registerAlias('JInstallerManifestLibrary', '\\Joomla\\CMS\\Installer\\Manifest\\LibraryManifest', '6.0');
JLoader::registerAlias('JInstallerManifestPackage', '\\Joomla\\CMS\\Installer\\Manifest\\PackageManifest', '6.0');
JLoader::registerAlias('JRouterAdministrator', '\\Joomla\\CMS\\Router\\AdministratorRouter', '6.0');
JLoader::registerAlias('JRoute', '\\Joomla\\CMS\\Router\\Route', '6.0');
JLoader::registerAlias('JRouter', '\\Joomla\\CMS\\Router\\Router', '6.0');
JLoader::registerAlias('JRouterSite', '\\Joomla\\CMS\\Router\\SiteRouter', '6.0');
JLoader::registerAlias('JCategories', '\\Joomla\\CMS\\Categories\\Categories', '6.0');
JLoader::registerAlias('JCategoryNode', '\\Joomla\\CMS\\Categories\\CategoryNode', '6.0');
JLoader::registerAlias('JDate', '\\Joomla\\CMS\\Date\\Date', '6.0');
JLoader::registerAlias('JLog', '\\Joomla\\CMS\\Log\\Log', '6.0');
JLoader::registerAlias('JLogEntry', '\\Joomla\\CMS\\Log\\LogEntry', '6.0');
JLoader::registerAlias('JLogLogger', '\\Joomla\\CMS\\Log\\Logger', '6.0');
JLoader::registerAlias('JLogger', '\\Joomla\\CMS\\Log\\Logger', '6.0');
JLoader::registerAlias('JLogLoggerCallback', '\\Joomla\\CMS\\Log\\Logger\\CallbackLogger', '6.0');
JLoader::registerAlias('JLogLoggerDatabase', '\\Joomla\\CMS\\Log\\Logger\\DatabaseLogger', '6.0');
JLoader::registerAlias('JLogLoggerEcho', '\\Joomla\\CMS\\Log\\Logger\\EchoLogger', '6.0');
JLoader::registerAlias('JLogLoggerFormattedtext', '\\Joomla\\CMS\\Log\\Logger\\FormattedtextLogger', '6.0');
JLoader::registerAlias('JLogLoggerMessagequeue', '\\Joomla\\CMS\\Log\\Logger\\MessagequeueLogger', '6.0');
JLoader::registerAlias('JLogLoggerSyslog', '\\Joomla\\CMS\\Log\\Logger\\SyslogLogger', '6.0');
JLoader::registerAlias('JLogLoggerW3c', '\\Joomla\\CMS\\Log\\Logger\\W3cLogger', '6.0');
JLoader::registerAlias('JProfiler', '\\Joomla\\CMS\\Profiler\\Profiler', '6.0');
JLoader::registerAlias('JUri', '\\Joomla\\CMS\\Uri\\Uri', '6.0');
JLoader::registerAlias('JCache', '\\Joomla\\CMS\\Cache\\Cache', '6.0');
JLoader::registerAlias('JCacheController', '\\Joomla\\CMS\\Cache\\CacheController', '6.0');
JLoader::registerAlias('JCacheStorage', '\\Joomla\\CMS\\Cache\\CacheStorage', '6.0');
JLoader::registerAlias('JCacheControllerCallback', '\\Joomla\\CMS\\Cache\\Controller\\CallbackController', '6.0');
JLoader::registerAlias('JCacheControllerOutput', '\\Joomla\\CMS\\Cache\\Controller\\OutputController', '6.0');
JLoader::registerAlias('JCacheControllerPage', '\\Joomla\\CMS\\Cache\\Controller\\PageController', '6.0');
JLoader::registerAlias('JCacheControllerView', '\\Joomla\\CMS\\Cache\\Controller\\ViewController', '6.0');
JLoader::registerAlias('JCacheStorageApcu', '\\Joomla\\CMS\\Cache\\Storage\\ApcuStorage', '6.0');
JLoader::registerAlias('JCacheStorageHelper', '\\Joomla\\CMS\\Cache\\Storage\\CacheStorageHelper', '6.0');
JLoader::registerAlias('JCacheStorageFile', '\\Joomla\\CMS\\Cache\\Storage\\FileStorage', '6.0');
JLoader::registerAlias('JCacheStorageMemcached', '\\Joomla\\CMS\\Cache\\Storage\\MemcachedStorage', '6.0');
JLoader::registerAlias('JCacheStorageRedis', '\\Joomla\\CMS\\Cache\\Storage\\RedisStorage', '6.0');
JLoader::registerAlias('JCacheException', '\\Joomla\\CMS\\Cache\\Exception\\CacheExceptionInterface', '6.0');
JLoader::registerAlias('JCacheExceptionConnecting', '\\Joomla\\CMS\\Cache\\Exception\\CacheConnectingException', '6.0');
JLoader::registerAlias('JCacheExceptionUnsupported', '\\Joomla\\CMS\\Cache\\Exception\\UnsupportedCacheException', '6.0');
JLoader::registerAlias('JSession', '\\Joomla\\CMS\\Session\\Session', '6.0');
JLoader::registerAlias('JUser', '\\Joomla\\CMS\\User\\User', '6.0');
JLoader::registerAlias('JUserHelper', '\\Joomla\\CMS\\User\\UserHelper', '6.0');
JLoader::registerAlias('JForm', '\\Joomla\\CMS\\Form\\Form', '6.0');
JLoader::registerAlias('JFormField', '\\Joomla\\CMS\\Form\\FormField', '6.0');
JLoader::registerAlias('JFormHelper', '\\Joomla\\CMS\\Form\\FormHelper', '6.0');
JLoader::registerAlias('JFormRule', '\\Joomla\\CMS\\Form\\FormRule', '6.0');
JLoader::registerAlias('JFormFieldAccessLevel', '\\Joomla\\CMS\\Form\\Field\\AccesslevelField', '6.0');
JLoader::registerAlias('JFormFieldAliastag', '\\Joomla\\CMS\\Form\\Field\\AliastagField', '6.0');
JLoader::registerAlias('JFormFieldAuthor', '\\Joomla\\CMS\\Form\\Field\\AuthorField', '6.0');
JLoader::registerAlias('JFormFieldCacheHandler', '\\Joomla\\CMS\\Form\\Field\\CachehandlerField', '6.0');
JLoader::registerAlias('JFormFieldCalendar', '\\Joomla\\CMS\\Form\\Field\\CalendarField', '6.0');
JLoader::registerAlias('JFormFieldCaptcha', '\\Joomla\\CMS\\Form\\Field\\CaptchaField', '6.0');
JLoader::registerAlias('JFormFieldCategory', '\\Joomla\\CMS\\Form\\Field\\CategoryField', '6.0');
JLoader::registerAlias('JFormFieldCheckbox', '\\Joomla\\CMS\\Form\\Field\\CheckboxField', '6.0');
JLoader::registerAlias('JFormFieldCheckboxes', '\\Joomla\\CMS\\Form\\Field\\CheckboxesField', '6.0');
JLoader::registerAlias('JFormFieldChromeStyle', '\\Joomla\\CMS\\Form\\Field\\ChromestyleField', '6.0');
JLoader::registerAlias('JFormFieldColor', '\\Joomla\\CMS\\Form\\Field\\ColorField', '6.0');
JLoader::registerAlias('JFormFieldCombo', '\\Joomla\\CMS\\Form\\Field\\ComboField', '6.0');
JLoader::registerAlias('JFormFieldComponentlayout', '\\Joomla\\CMS\\Form\\Field\\ComponentlayoutField', '6.0');
JLoader::registerAlias('JFormFieldComponents', '\\Joomla\\CMS\\Form\\Field\\ComponentsField', '6.0');
JLoader::registerAlias('JFormFieldContenthistory', '\\Joomla\\CMS\\Form\\Field\\ContenthistoryField', '6.0');
JLoader::registerAlias('JFormFieldContentlanguage', '\\Joomla\\CMS\\Form\\Field\\ContentlanguageField', '6.0');
JLoader::registerAlias('JFormFieldContenttype', '\\Joomla\\CMS\\Form\\Field\\ContenttypeField', '6.0');
JLoader::registerAlias('JFormFieldDatabaseConnection', '\\Joomla\\CMS\\Form\\Field\\DatabaseconnectionField', '6.0');
JLoader::registerAlias('JFormFieldEditor', '\\Joomla\\CMS\\Form\\Field\\EditorField', '6.0');
JLoader::registerAlias('JFormFieldEMail', '\\Joomla\\CMS\\Form\\Field\\EmailField', '6.0');
JLoader::registerAlias('JFormFieldFile', '\\Joomla\\CMS\\Form\\Field\\FileField', '6.0');
JLoader::registerAlias('JFormFieldFileList', '\\Joomla\\CMS\\Form\\Field\\FilelistField', '6.0');
JLoader::registerAlias('JFormFieldFolderList', '\\Joomla\\CMS\\Form\\Field\\FolderlistField', '6.0');
JLoader::registerAlias('JFormFieldFrontend_Language', '\\Joomla\\CMS\\Form\\Field\\FrontendlanguageField', '6.0');
JLoader::registerAlias('JFormFieldGroupedList', '\\Joomla\\CMS\\Form\\Field\\GroupedlistField', '6.0');
JLoader::registerAlias('JFormFieldHeadertag', '\\Joomla\\CMS\\Form\\Field\\HeadertagField', '6.0');
JLoader::registerAlias('JFormFieldHidden', '\\Joomla\\CMS\\Form\\Field\\HiddenField', '6.0');
JLoader::registerAlias('JFormFieldImageList', '\\Joomla\\CMS\\Form\\Field\\ImagelistField', '6.0');
JLoader::registerAlias('JFormFieldInteger', '\\Joomla\\CMS\\Form\\Field\\IntegerField', '6.0');
JLoader::registerAlias('JFormFieldLanguage', '\\Joomla\\CMS\\Form\\Field\\LanguageField', '6.0');
JLoader::registerAlias('JFormFieldLastvisitDateRange', '\\Joomla\\CMS\\Form\\Field\\LastvisitdaterangeField', '6.0');
JLoader::registerAlias('JFormFieldLimitbox', '\\Joomla\\CMS\\Form\\Field\\LimitboxField', '6.0');
JLoader::registerAlias('JFormFieldList', '\\Joomla\\CMS\\Form\\Field\\ListField', '6.0');
JLoader::registerAlias('JFormFieldMedia', '\\Joomla\\CMS\\Form\\Field\\MediaField', '6.0');
JLoader::registerAlias('JFormFieldMenu', '\\Joomla\\CMS\\Form\\Field\\MenuField', '6.0');
JLoader::registerAlias('JFormFieldMenuitem', '\\Joomla\\CMS\\Form\\Field\\MenuitemField', '6.0');
JLoader::registerAlias('JFormFieldMeter', '\\Joomla\\CMS\\Form\\Field\\MeterField', '6.0');
JLoader::registerAlias('JFormFieldModulelayout', '\\Joomla\\CMS\\Form\\Field\\ModulelayoutField', '6.0');
JLoader::registerAlias('JFormFieldModuleOrder', '\\Joomla\\CMS\\Form\\Field\\ModuleorderField', '6.0');
JLoader::registerAlias('JFormFieldModulePosition', '\\Joomla\\CMS\\Form\\Field\\ModulepositionField', '6.0');
JLoader::registerAlias('JFormFieldModuletag', '\\Joomla\\CMS\\Form\\Field\\ModuletagField', '6.0');
JLoader::registerAlias('JFormFieldNote', '\\Joomla\\CMS\\Form\\Field\\NoteField', '6.0');
JLoader::registerAlias('JFormFieldNumber', '\\Joomla\\CMS\\Form\\Field\\NumberField', '6.0');
JLoader::registerAlias('JFormFieldOrdering', '\\Joomla\\CMS\\Form\\Field\\OrderingField', '6.0');
JLoader::registerAlias('JFormFieldPassword', '\\Joomla\\CMS\\Form\\Field\\PasswordField', '6.0');
JLoader::registerAlias('JFormFieldPlugins', '\\Joomla\\CMS\\Form\\Field\\PluginsField', '6.0');
JLoader::registerAlias('JFormFieldPlugin_Status', '\\Joomla\\CMS\\Form\\Field\\PluginstatusField', '6.0');
JLoader::registerAlias('JFormFieldPredefinedList', '\\Joomla\\CMS\\Form\\Field\\PredefinedListField', '6.0');
JLoader::registerAlias('JFormFieldRadio', '\\Joomla\\CMS\\Form\\Field\\RadioField', '6.0');
JLoader::registerAlias('JFormFieldRange', '\\Joomla\\CMS\\Form\\Field\\RangeField', '6.0');
JLoader::registerAlias('JFormFieldRedirect_Status', '\\Joomla\\CMS\\Form\\Field\\RedirectStatusField', '6.0');
JLoader::registerAlias('JFormFieldRegistrationDateRange', '\\Joomla\\CMS\\Form\\Field\\RegistrationdaterangeField', '6.0');
JLoader::registerAlias('JFormFieldRules', '\\Joomla\\CMS\\Form\\Field\\RulesField', '6.0');
JLoader::registerAlias('JFormFieldSessionHandler', '\\Joomla\\CMS\\Form\\Field\\SessionhandlerField', '6.0');
JLoader::registerAlias('JFormFieldSpacer', '\\Joomla\\CMS\\Form\\Field\\SpacerField', '6.0');
JLoader::registerAlias('JFormFieldSQL', '\\Joomla\\CMS\\Form\\Field\\SqlField', '6.0');
JLoader::registerAlias('JFormFieldStatus', '\\Joomla\\CMS\\Form\\Field\\StatusField', '6.0');
JLoader::registerAlias('JFormFieldSubform', '\\Joomla\\CMS\\Form\\Field\\SubformField', '6.0');
JLoader::registerAlias('JFormFieldTag', '\\Joomla\\CMS\\Form\\Field\\TagField', '6.0');
JLoader::registerAlias('JFormFieldTel', '\\Joomla\\CMS\\Form\\Field\\TelephoneField', '6.0');
JLoader::registerAlias('JFormFieldTemplatestyle', '\\Joomla\\CMS\\Form\\Field\\TemplatestyleField', '6.0');
JLoader::registerAlias('JFormFieldText', '\\Joomla\\CMS\\Form\\Field\\TextField', '6.0');
JLoader::registerAlias('JFormFieldTextarea', '\\Joomla\\CMS\\Form\\Field\\TextareaField', '6.0');
JLoader::registerAlias('JFormFieldTimezone', '\\Joomla\\CMS\\Form\\Field\\TimezoneField', '6.0');
JLoader::registerAlias('JFormFieldUrl', '\\Joomla\\CMS\\Form\\Field\\UrlField', '6.0');
JLoader::registerAlias('JFormFieldUserActive', '\\Joomla\\CMS\\Form\\Field\\UseractiveField', '6.0');
JLoader::registerAlias('JFormFieldUserGroupList', '\\Joomla\\CMS\\Form\\Field\\UsergrouplistField', '6.0');
JLoader::registerAlias('JFormFieldUserState', '\\Joomla\\CMS\\Form\\Field\\UserstateField', '6.0');
JLoader::registerAlias('JFormFieldUser', '\\Joomla\\CMS\\Form\\Field\\UserField', '6.0');
JLoader::registerAlias('JFormRuleBoolean', '\\Joomla\\CMS\\Form\\Rule\\BooleanRule', '6.0');
JLoader::registerAlias('JFormRuleCalendar', '\\Joomla\\CMS\\Form\\Rule\\CalendarRule', '6.0');
JLoader::registerAlias('JFormRuleCaptcha', '\\Joomla\\CMS\\Form\\Rule\\CaptchaRule', '6.0');
JLoader::registerAlias('JFormRuleColor', '\\Joomla\\CMS\\Form\\Rule\\ColorRule', '6.0');
JLoader::registerAlias('JFormRuleEmail', '\\Joomla\\CMS\\Form\\Rule\\EmailRule', '6.0');
JLoader::registerAlias('JFormRuleEquals', '\\Joomla\\CMS\\Form\\Rule\\EqualsRule', '6.0');
JLoader::registerAlias('JFormRuleNotequals', '\\Joomla\\CMS\\Form\\Rule\\NotequalsRule', '6.0');
JLoader::registerAlias('JFormRuleNumber', '\\Joomla\\CMS\\Form\\Rule\\NumberRule', '6.0');
JLoader::registerAlias('JFormRuleOptions', '\\Joomla\\CMS\\Form\\Rule\\OptionsRule', '6.0');
JLoader::registerAlias('JFormRulePassword', '\\Joomla\\CMS\\Form\\Rule\\PasswordRule', '6.0');
JLoader::registerAlias('JFormRuleRules', '\\Joomla\\CMS\\Form\\Rule\\RulesRule', '6.0');
JLoader::registerAlias('JFormRuleTel', '\\Joomla\\CMS\\Form\\Rule\\TelRule', '6.0');
JLoader::registerAlias('JFormRuleUrl', '\\Joomla\\CMS\\Form\\Rule\\UrlRule', '6.0');
JLoader::registerAlias('JFormRuleUsername', '\\Joomla\\CMS\\Form\\Rule\\UsernameRule', '6.0');
JLoader::registerAlias('JMicrodata', '\\Joomla\\CMS\\Microdata\\Microdata', '6.0');
JLoader::registerAlias('JDatabaseDriver', '\\Joomla\\Database\\DatabaseDriver', '6.0');
JLoader::registerAlias('JDatabaseExporter', '\\Joomla\\Database\\DatabaseExporter', '6.0');
JLoader::registerAlias('JDatabaseFactory', '\\Joomla\\Database\\DatabaseFactory', '6.0');
JLoader::registerAlias('JDatabaseImporter', '\\Joomla\\Database\\DatabaseImporter', '6.0');
JLoader::registerAlias('JDatabaseInterface', '\\Joomla\\Database\\DatabaseInterface', '6.0');
JLoader::registerAlias('JDatabaseIterator', '\\Joomla\\Database\\DatabaseIterator', '6.0');
JLoader::registerAlias('JDatabaseQuery', '\\Joomla\\Database\\DatabaseQuery', '6.0');
JLoader::registerAlias('JDatabaseDriverMysqli', '\\Joomla\\Database\\Mysqli\\MysqliDriver', '6.0');
JLoader::registerAlias('JDatabaseDriverPdo', '\\Joomla\\Database\\Pdo\\PdoDriver', '6.0');
JLoader::registerAlias('JDatabaseDriverPdomysql', '\\Joomla\\Database\\Mysql\\MysqlDriver', '6.0');
JLoader::registerAlias('JDatabaseDriverPgsql', '\\Joomla\\Database\\Pgsql\\PgsqlDriver', '6.0');
JLoader::registerAlias('JDatabaseDriverSqlazure', '\\Joomla\\Database\\Sqlazure\\SqlazureDriver', '6.0');
JLoader::registerAlias('JDatabaseDriverSqlite', '\\Joomla\\Database\\Sqlite\\SqliteDriver', '6.0');
JLoader::registerAlias('JDatabaseDriverSqlsrv', '\\Joomla\\Database\\Sqlsrv\\SqlsrvDriver', '6.0');
JLoader::registerAlias('JDatabaseExceptionConnecting', '\\Joomla\\Database\\Exception\\ConnectionFailureException', '6.0');
JLoader::registerAlias('JDatabaseExceptionExecuting', '\\Joomla\\Database\\Exception\\ExecutionFailureException', '6.0');
JLoader::registerAlias('JDatabaseExceptionUnsupported', '\\Joomla\\Database\\Exception\\UnsupportedAdapterException', '6.0');
JLoader::registerAlias('JDatabaseExporterMysqli', '\\Joomla\\Database\\Mysqli\\MysqliExporter', '6.0');
JLoader::registerAlias('JDatabaseExporterPdomysql', '\\Joomla\\Database\\Mysql\\MysqlExporter', '6.0');
JLoader::registerAlias('JDatabaseExporterPgsql', '\\Joomla\\Database\\Pgsql\\PgsqlExporter', '6.0');
JLoader::registerAlias('JDatabaseImporterMysqli', '\\Joomla\\Database\\Mysqli\\MysqliImporter', '6.0');
JLoader::registerAlias('JDatabaseImporterPdomysql', '\\Joomla\\Database\\Mysql\\MysqlImporter', '6.0');
JLoader::registerAlias('JDatabaseImporterPgsql', '\\Joomla\\Database\\Pgsql\\PgsqlImporter', '6.0');
JLoader::registerAlias('JDatabaseQueryElement', '\\Joomla\\Database\\Query\\QueryElement', '6.0');
JLoader::registerAlias('JDatabaseQueryLimitable', '\\Joomla\\Database\\Query\\LimitableInterface', '6.0');
JLoader::registerAlias('JDatabaseQueryPreparable', '\\Joomla\\Database\\Query\\PreparableInterface', '6.0');
JLoader::registerAlias('JDatabaseQueryMysqli', '\\Joomla\\Database\\Mysqli\\MysqliQuery', '6.0');
JLoader::registerAlias('JDatabaseQueryPdo', '\\Joomla\\Database\\Pdo\\PdoQuery', '6.0');
JLoader::registerAlias('JDatabaseQueryPdomysql', '\\Joomla\\Database\\Mysql\\MysqlQuery', '6.0');
JLoader::registerAlias('JDatabaseQueryPgsql', '\\Joomla\\Database\\Pgsql\\PgsqlQuery', '6.0');
JLoader::registerAlias('JDatabaseQuerySqlazure', '\\Joomla\\Database\\Sqlazure\\SqlazureQuery', '6.0');
JLoader::registerAlias('JDatabaseQuerySqlite', '\\Joomla\\Database\\Sqlite\\SqliteQuery', '6.0');
JLoader::registerAlias('JDatabaseQuerySqlsrv', '\\Joomla\\Database\\Sqlsrv\\SqlsrvQuery', '6.0');
JLoader::registerAlias('JFactory', '\\Joomla\\CMS\\Factory', '6.0');
JLoader::registerAlias('JMail', '\\Joomla\\CMS\\Mail\\Mail', '6.0');
JLoader::registerAlias('JMailHelper', '\\Joomla\\CMS\\Mail\\MailHelper', '6.0');
JLoader::registerAlias('JClientHelper', '\\Joomla\\CMS\\Client\\ClientHelper', '6.0');
JLoader::registerAlias('JClientFtp', '\\Joomla\\CMS\\Client\\FtpClient', '6.0');
JLoader::registerAlias('JFTP', '\\Joomla\\CMS\\Client\\FtpClient', '4.0');
JLoader::registerAlias('JUpdate', '\\Joomla\\CMS\\Updater\\Update', '6.0');
JLoader::registerAlias('JUpdateAdapter', '\\Joomla\\CMS\\Updater\\UpdateAdapter', '6.0');
JLoader::registerAlias('JUpdater', '\\Joomla\\CMS\\Updater\\Updater', '6.0');
JLoader::registerAlias('JUpdaterCollection', '\\Joomla\\CMS\\Updater\\Adapter\\CollectionAdapter', '6.0');
JLoader::registerAlias('JUpdaterExtension', '\\Joomla\\CMS\\Updater\\Adapter\\ExtensionAdapter', '6.0');
JLoader::registerAlias('JCrypt', '\\Joomla\\CMS\\Crypt\\Crypt', '6.0');
JLoader::registerAlias('JCryptCipher', '\\Joomla\\Crypt\\CipherInterface', '6.0');
JLoader::registerAlias('JCryptKey', '\\Joomla\\Crypt\\Key', '6.0');
JLoader::registerAlias('\\Joomla\\CMS\\Crypt\\CipherInterface', '\\Joomla\\Crypt\\CipherInterface', '6.0');
JLoader::registerAlias('\\Joomla\\CMS\\Crypt\\Key', '\\Joomla\\Crypt\\Key', '6.0');
JLoader::registerAlias('JCryptCipherCrypto', '\\Joomla\\CMS\\Crypt\\Cipher\\CryptoCipher', '6.0');
JLoader::registerAlias('JStringPunycode', '\\Joomla\\CMS\\String\\PunycodeHelper', '6.0');
JLoader::registerAlias('JBuffer', '\\Joomla\\CMS\\Utility\\BufferStreamHandler', '6.0');
JLoader::registerAlias('JUtility', '\\Joomla\\CMS\\Utility\\Utility', '6.0');
JLoader::registerAlias('JInputCli', '\\Joomla\\CMS\\Input\\Cli', '6.0');
JLoader::registerAlias('JInputCookie', '\\Joomla\\CMS\\Input\\Cookie', '6.0');
JLoader::registerAlias('JInputFiles', '\\Joomla\\CMS\\Input\\Files', '6.0');
JLoader::registerAlias('JInput', '\\Joomla\\CMS\\Input\\Input', '6.0');
JLoader::registerAlias('JInputJSON', '\\Joomla\\CMS\\Input\\Json', '6.0');
JLoader::registerAlias('JFeed', '\\Joomla\\CMS\\Feed\\Feed', '6.0');
JLoader::registerAlias('JFeedEntry', '\\Joomla\\CMS\\Feed\\FeedEntry', '6.0');
JLoader::registerAlias('JFeedFactory', '\\Joomla\\CMS\\Feed\\FeedFactory', '6.0');
JLoader::registerAlias('JFeedLink', '\\Joomla\\CMS\\Feed\\FeedLink', '6.0');
JLoader::registerAlias('JFeedParser', '\\Joomla\\CMS\\Feed\\FeedParser', '6.0');
JLoader::registerAlias('JFeedPerson', '\\Joomla\\CMS\\Feed\\FeedPerson', '6.0');
JLoader::registerAlias('JFeedParserAtom', '\\Joomla\\CMS\\Feed\\Parser\\AtomParser', '6.0');
JLoader::registerAlias('JFeedParserNamespace', '\\Joomla\\CMS\\Feed\\Parser\\NamespaceParserInterface', '6.0');
JLoader::registerAlias('JFeedParserRss', '\\Joomla\\CMS\\Feed\\Parser\\RssParser', '6.0');
JLoader::registerAlias('JFeedParserRssItunes', '\\Joomla\\CMS\\Feed\\Parser\\Rss\\ItunesRssParser', '6.0');
JLoader::registerAlias('JFeedParserRssMedia', '\\Joomla\\CMS\\Feed\\Parser\\Rss\\MediaRssParser', '6.0');
JLoader::registerAlias('JImage', '\\Joomla\\CMS\\Image\\Image', '6.0');
JLoader::registerAlias('JImageFilter', '\\Joomla\\CMS\\Image\\ImageFilter', '6.0');
JLoader::registerAlias('JImageFilterBackgroundfill', '\\Joomla\\CMS\\Image\\Filter\\Backgroundfill', '6.0');
JLoader::registerAlias('JImageFilterBrightness', '\\Joomla\\CMS\\Image\\Filter\\Brightness', '6.0');
JLoader::registerAlias('JImageFilterContrast', '\\Joomla\\CMS\\Image\\Filter\\Contrast', '6.0');
JLoader::registerAlias('JImageFilterEdgedetect', '\\Joomla\\CMS\\Image\\Filter\\Edgedetect', '6.0');
JLoader::registerAlias('JImageFilterEmboss', '\\Joomla\\CMS\\Image\\Filter\\Emboss', '6.0');
JLoader::registerAlias('JImageFilterNegate', '\\Joomla\\CMS\\Image\\Filter\\Negate', '6.0');
JLoader::registerAlias('JImageFilterSmooth', '\\Joomla\\CMS\\Image\\Filter\\Smooth', '6.0');
JLoader::registerAlias('JObject', '\\Joomla\\CMS\\Object\\CMSObject', '6.0');
JLoader::registerAlias('JExtensionHelper', '\\Joomla\\CMS\\Extension\\ExtensionHelper', '6.0');
JLoader::registerAlias('JHtml', '\\Joomla\\CMS\\HTML\\HTMLHelper', '6.0');
JLoader::registerAlias('\\Joomla\\Application\\Cli\\CliInput', '\\Joomla\\CMS\\Application\\CLI\\CliInput', '6.0');
JLoader::registerAlias('\\Joomla\\Application\\Cli\\CliOutput', '\\Joomla\\CMS\\Application\\CLI\\CliOutput', '6.0');
JLoader::registerAlias('\\Joomla\\Application\\Cli\\ColorStyle', '\\Joomla\\CMS\\Application\\CLI\\ColorStyle', '6.0');
JLoader::registerAlias('\\Joomla\\Application\\Cli\\Output\\Stdout', '\\Joomla\\CMS\\Application\\CLI\\Output\\Stdout', '6.0');
JLoader::registerAlias('\\Joomla\\Application\\Cli\\Output\\Xml', '\\Joomla\\CMS\\Application\\CLI\\Output\\Xml', '6.0');
JLoader::registerAlias(
'\\Joomla\\Application\\Cli\\Output\\Processor\\ColorProcessor',
'\\Joomla\\CMS\\Application\\CLI\\Output\\Processor\\ColorProcessor',
'6.0'
);
JLoader::registerAlias(
'\\Joomla\\Application\\Cli\\Output\\Processor\\ProcessorInterface',
'\\Joomla\\CMS\\Application\\CLI\\Output\\Processor\\ProcessorInterface',
'6.0'
);
JLoader::registerAlias('JFile', '\\Joomla\\CMS\\Filesystem\\File', '6.0');
JLoader::registerAlias('JFolder', '\\Joomla\\CMS\\Filesystem\\Folder', '6.0');
JLoader::registerAlias('JFilesystemHelper', '\\Joomla\\CMS\\Filesystem\\FilesystemHelper', '6.0');
JLoader::registerAlias('JFilesystemPatcher', '\\Joomla\\CMS\\Filesystem\\Patcher', '6.0');
JLoader::registerAlias('JPath', '\\Joomla\\CMS\\Filesystem\\Path', '6.0');
JLoader::registerAlias('JStream', '\\Joomla\\CMS\\Filesystem\\Stream', '6.0');
JLoader::registerAlias('JStreamString', '\\Joomla\\CMS\\Filesystem\\Streams\\StreamString', '6.0');
JLoader::registerAlias('JStringController', '\\Joomla\\CMS\\Filesystem\\Support\\StringController', '6.0');
JLoader::registerAlias('JClassLoader', '\\Joomla\\CMS\\Autoload\\ClassLoader', '6.0');
JLoader::registerAlias('JFormFilterInt_Array', '\\Joomla\\CMS\\Form\\Filter\\IntarrayFilter', '6.0');
JLoader::registerAlias('JAdapter', '\\Joomla\\CMS\\Adapter\\Adapter', '6.0');
JLoader::registerAlias('JAdapterInstance', '\\Joomla\\CMS\\Adapter\\AdapterInstance', '6.0');
JLoader::registerAlias('JHtmlAccess', '\\Joomla\\CMS\\HTML\\Helpers\\Access', '6.0');
JLoader::registerAlias('JHtmlActionsDropdown', '\\Joomla\\CMS\\HTML\\Helpers\\ActionsDropdown', '6.0');
JLoader::registerAlias('JHtmlAdminLanguage', '\\Joomla\\CMS\\HTML\\Helpers\\AdminLanguage', '6.0');
JLoader::registerAlias('JHtmlBehavior', '\\Joomla\\CMS\\HTML\\Helpers\\Behavior', '6.0');
JLoader::registerAlias('JHtmlBootstrap', '\\Joomla\\CMS\\HTML\\Helpers\\Bootstrap', '6.0');
JLoader::registerAlias('JHtmlCategory', '\\Joomla\\CMS\\HTML\\Helpers\\Category', '6.0');
JLoader::registerAlias('JHtmlContent', '\\Joomla\\CMS\\HTML\\Helpers\\Content', '6.0');
JLoader::registerAlias('JHtmlContentlanguage', '\\Joomla\\CMS\\HTML\\Helpers\\ContentLanguage', '6.0');
JLoader::registerAlias('JHtmlDate', '\\Joomla\\CMS\\HTML\\Helpers\\Date', '6.0');
JLoader::registerAlias('JHtmlDebug', '\\Joomla\\CMS\\HTML\\Helpers\\Debug', '6.0');
JLoader::registerAlias('JHtmlDraggablelist', '\\Joomla\\CMS\\HTML\\Helpers\\DraggableList', '6.0');
JLoader::registerAlias('JHtmlDropdown', '\\Joomla\\CMS\\HTML\\Helpers\\Dropdown', '6.0');
JLoader::registerAlias('JHtmlEmail', '\\Joomla\\CMS\\HTML\\Helpers\\Email', '6.0');
JLoader::registerAlias('JHtmlForm', '\\Joomla\\CMS\\HTML\\Helpers\\Form', '6.0');
JLoader::registerAlias('JHtmlFormbehavior', '\\Joomla\\CMS\\HTML\\Helpers\\FormBehavior', '6.0');
JLoader::registerAlias('JHtmlGrid', '\\Joomla\\CMS\\HTML\\Helpers\\Grid', '6.0');
JLoader::registerAlias('JHtmlIcons', '\\Joomla\\CMS\\HTML\\Helpers\\Icons', '6.0');
JLoader::registerAlias('JHtmlJGrid', '\\Joomla\\CMS\\HTML\\Helpers\\JGrid', '6.0');
JLoader::registerAlias('JHtmlJquery', '\\Joomla\\CMS\\HTML\\Helpers\\Jquery', '6.0');
JLoader::registerAlias('JHtmlLinks', '\\Joomla\\CMS\\HTML\\Helpers\\Links', '6.0');
JLoader::registerAlias('JHtmlList', '\\Joomla\\CMS\\HTML\\Helpers\\ListHelper', '6.0');
JLoader::registerAlias('JHtmlMenu', '\\Joomla\\CMS\\HTML\\Helpers\\Menu', '6.0');
JLoader::registerAlias('JHtmlNumber', '\\Joomla\\CMS\\HTML\\Helpers\\Number', '6.0');
JLoader::registerAlias('JHtmlSearchtools', '\\Joomla\\CMS\\HTML\\Helpers\\SearchTools', '6.0');
JLoader::registerAlias('JHtmlSelect', '\\Joomla\\CMS\\HTML\\Helpers\\Select', '6.0');
JLoader::registerAlias('JHtmlSidebar', '\\Joomla\\CMS\\HTML\\Helpers\\Sidebar', '6.0');
JLoader::registerAlias('JHtmlSortableList', '\\Joomla\\CMS\\HTML\\Helpers\\SortableList', '6.0');
JLoader::registerAlias('JHtmlString', '\\Joomla\\CMS\\HTML\\Helpers\\StringHelper', '6.0');
JLoader::registerAlias('JHtmlTag', '\\Joomla\\CMS\\HTML\\Helpers\\Tag', '6.0');
JLoader::registerAlias('JHtmlTel', '\\Joomla\\CMS\\HTML\\Helpers\\Telephone', '6.0');
JLoader::registerAlias('JHtmlUser', '\\Joomla\\CMS\\HTML\\Helpers\\User', '6.0');

View File

@ -0,0 +1,37 @@
<?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
// No direct access.
\defined('_JEXEC') or die;
// Class map of the core extensions
JLoader::registerAlias('ActionLogPlugin', '\\Joomla\\Component\\Actionlogs\\Administrator\\Plugin\\ActionLogPlugin', '5.0');
JLoader::registerAlias('FieldsPlugin', '\\Joomla\\Component\\Fields\\Administrator\\Plugin\\FieldsPlugin', '5.0');
JLoader::registerAlias('FieldsListPlugin', '\\Joomla\\Component\\Fields\\Administrator\\Plugin\\FieldsListPlugin', '5.0');
JLoader::registerAlias('PrivacyExportDomain', '\\Joomla\\Component\\Privacy\\Administrator\\Export\\Domain', '5.0');
JLoader::registerAlias('PrivacyExportField', '\\Joomla\\Component\\Privacy\\Administrator\\Export\\Field', '5.0');
JLoader::registerAlias('PrivacyExportItem', '\\Joomla\\Component\\Privacy\\Administrator\\Export\\Item', '5.0');
JLoader::registerAlias('PrivacyPlugin', '\\Joomla\\Component\\Privacy\\Administrator\\Plugin\\PrivacyPlugin', '5.0');
JLoader::registerAlias('PrivacyRemovalStatus', '\\Joomla\\Component\\Privacy\\Administrator\\Removal\\Status', '5.0');
JLoader::registerAlias('PrivacyTableRequest', '\\Joomla\\Component\\Privacy\\Administrator\\Table\\RequestTable', '5.0');
JLoader::registerAlias('TagsTableTag', '\\Joomla\\Component\\Tags\\Administrator\\Table\\TagTable', '5.0');
JLoader::registerAlias('ContentHelperRoute', '\\Joomla\\Component\\Content\\Site\\Helper\\RouteHelper', '5.0');
JLoader::registerAlias('FinderIndexerAdapter', '\\Joomla\\Component\\Finder\\Administrator\\Indexer\\Adapter', '5.0');
JLoader::registerAlias('FinderIndexerHelper', '\\Joomla\\Component\\Finder\\Administrator\\Indexer\\Helper', '5.0');
JLoader::registerAlias('FinderIndexer', '\\Joomla\\Component\\Finder\\Administrator\\Indexer\\Indexer', '5.0');
JLoader::registerAlias('FinderIndexerParser', '\\Joomla\\Component\\Finder\\Administrator\\Indexer\\Parser', '5.0');
JLoader::registerAlias('FinderIndexerQuery', '\\Joomla\\Component\\Finder\\Administrator\\Indexer\\Query', '5.0');
JLoader::registerAlias('FinderIndexerResult', '\\Joomla\\Component\\Finder\\Administrator\\Indexer\\Result', '5.0');
JLoader::registerAlias('FinderIndexerTaxonomy', '\\Joomla\\Component\\Finder\\Administrator\\Indexer\\Taxonomy', '5.0');
JLoader::registerAlias('FinderIndexerToken', '\\Joomla\\Component\\Finder\\Administrator\\Indexer\\Token', '5.0');

View File

@ -0,0 +1,44 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage Behaviour.taggable
*
* @copyright (C) 2022 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
\defined('_JEXEC') or die;
use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use Joomla\Plugin\Behaviour\Taggable\Extension\Taggable;
return new class () implements ServiceProviderInterface {
/**
* Registers the service provider with a DI container.
*
* @param Container $container The DI container.
*
* @return void
*
* @since 4.2.0
*/
public function register(Container $container)
{
$container->set(
PluginInterface::class,
function (Container $container) {
$plugin = new Taggable(
$container->get(DispatcherInterface::class),
(array) PluginHelper::getPlugin('behaviour', 'taggable')
);
return $plugin;
}
);
}
};

View File

@ -0,0 +1,343 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage Behaviour.taggable
*
* @copyright (C) 2016 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\Behaviour\Taggable\Extension;
use Joomla\CMS\Event\Model\BeforeBatchEvent;
use Joomla\CMS\Event\Table\AfterLoadEvent;
use Joomla\CMS\Event\Table\AfterResetEvent;
use Joomla\CMS\Event\Table\AfterStoreEvent;
use Joomla\CMS\Event\Table\BeforeDeleteEvent;
use Joomla\CMS\Event\Table\BeforeStoreEvent;
use Joomla\CMS\Event\Table\ObjectCreateEvent;
use Joomla\CMS\Event\Table\SetNewTagsEvent;
use Joomla\CMS\Helper\TagsHelper;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Table\TableInterface;
use Joomla\CMS\Tag\TaggableTableInterface;
use Joomla\Event\SubscriberInterface;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Implements the Taggable behaviour which allows extensions to automatically support tags for their content items.
*
* This plugin supersedes JHelperObserverTags.
*
* @since 4.0.0
*/
final class Taggable extends CMSPlugin implements SubscriberInterface
{
/**
* Returns an array of events this subscriber will listen to.
*
* @return array
*
* @since 4.2.0
*/
public static function getSubscribedEvents(): array
{
return [
'onTableObjectCreate' => 'onTableObjectCreate',
'onTableBeforeStore' => 'onTableBeforeStore',
'onTableAfterStore' => 'onTableAfterStore',
'onTableBeforeDelete' => 'onTableBeforeDelete',
'onTableSetNewTags' => 'onTableSetNewTags',
'onTableAfterReset' => 'onTableAfterReset',
'onTableAfterLoad' => 'onTableAfterLoad',
'onBeforeBatch' => 'onBeforeBatch',
];
}
/**
* Runs when a new table object is being created
*
* @param ObjectCreateEvent $event The event to handle
*
* @return void
*
* @since 4.0.0
*/
public function onTableObjectCreate(ObjectCreateEvent $event)
{
// Extract arguments
/** @var TableInterface $table */
$table = $event['subject'];
// If the tags table doesn't implement the interface bail
if (!($table instanceof TaggableTableInterface)) {
return;
}
// If the table already has a tags helper we have nothing to do
if (!\is_null($table->getTagsHelper())) {
return;
}
$tagsHelper = new TagsHelper();
$tagsHelper->typeAlias = $table->typeAlias;
$table->setTagsHelper($tagsHelper);
// This is required because getTagIds overrides the tags property of the Tags Helper.
$cloneHelper = clone $table->getTagsHelper();
$tagIds = $cloneHelper->getTagIds($table->getId(), $table->getTypeAlias());
if (!empty($tagIds)) {
$table->getTagsHelper()->tags = explode(',', $tagIds);
}
}
/**
* Pre-processor for $table->store($updateNulls)
*
* @param BeforeStoreEvent $event The event to handle
*
* @return void
*
* @since 4.0.0
*/
public function onTableBeforeStore(BeforeStoreEvent $event)
{
// Extract arguments
/** @var TableInterface $table */
$table = $event['subject'];
// If the tags table doesn't implement the interface bail
if (!($table instanceof TaggableTableInterface)) {
return;
}
// If the table doesn't have a tags helper we can't proceed
if (\is_null($table->getTagsHelper())) {
return;
}
/** @var TagsHelper $tagsHelper */
$tagsHelper = $table->getTagsHelper();
$tagsHelper->typeAlias = $table->getTypeAlias();
$newTags = $table->newTags ?? [];
if (empty($newTags)) {
$tagsHelper->preStoreProcess($table);
} else {
$tagsHelper->preStoreProcess($table, (array) $newTags);
}
}
/**
* Post-processor for $table->store($updateNulls)
*
* @param AfterStoreEvent $event The event to handle
*
* @return void
*
* @since 4.0.0
*/
public function onTableAfterStore(AfterStoreEvent $event)
{
// Extract arguments
/** @var TableInterface $table */
$table = $event['subject'];
$result = $event['result'];
if (!$result) {
return;
}
if (!\is_object($table) || !($table instanceof TaggableTableInterface)) {
return;
}
// If the table doesn't have a tags helper we can't proceed
if (\is_null($table->getTagsHelper())) {
return;
}
// Get the Tags helper and assign the parsed alias
/** @var TagsHelper $tagsHelper */
$tagsHelper = $table->getTagsHelper();
$tagsHelper->typeAlias = $table->getTypeAlias();
$newTags = $table->newTags ?? [];
if (empty($newTags)) {
$result = $tagsHelper->postStoreProcess($table);
} else {
if (\is_string($newTags) && (strpos($newTags, ',') !== false)) {
$newTags = explode(',', $newTags);
} elseif (!\is_array($newTags)) {
$newTags = (array) $newTags;
}
$result = $tagsHelper->postStoreProcess($table, $newTags);
}
}
/**
* Pre-processor for $table->delete($pk)
*
* @param BeforeDeleteEvent $event The event to handle
*
* @return void
*
* @since 4.0.0
*/
public function onTableBeforeDelete(BeforeDeleteEvent $event)
{
// Extract arguments
/** @var TableInterface $table */
$table = $event['subject'];
$pk = $event['pk'];
// If the tags table doesn't implement the interface bail
if (!($table instanceof TaggableTableInterface)) {
return;
}
// If the table doesn't have a tags helper we can't proceed
if (\is_null($table->getTagsHelper())) {
return;
}
// Get the Tags helper and assign the parsed alias
$table->getTagsHelper()->typeAlias = $table->getTypeAlias();
$table->getTagsHelper()->deleteTagData($table, $pk);
}
/**
* Handles the tag setting in $table->batchTag($value, $pks, $contexts)
*
* @param SetNewTagsEvent $event The event to handle
*
* @return void
*
* @since 4.0.0
*/
public function onTableSetNewTags(SetNewTagsEvent $event)
{
// Extract arguments
/** @var TableInterface $table */
$table = $event['subject'];
$newTags = $event['newTags'];
$replaceTags = $event['replaceTags'];
// If the tags table doesn't implement the interface bail
if (!($table instanceof TaggableTableInterface)) {
return;
}
// If the table doesn't have a tags helper we can't proceed
if (\is_null($table->getTagsHelper())) {
return;
}
// Get the Tags helper and assign the parsed alias
/** @var TagsHelper $tagsHelper */
$tagsHelper = $table->getTagsHelper();
$tagsHelper->typeAlias = $table->getTypeAlias();
if (!$tagsHelper->postStoreProcess($table, $newTags, $replaceTags)) {
throw new \RuntimeException($table->getError());
}
}
/**
* Runs when an existing table object is reset
*
* @param AfterResetEvent $event The event to handle
*
* @return void
*
* @since 4.0.0
*/
public function onTableAfterReset(AfterResetEvent $event)
{
// Extract arguments
/** @var TableInterface $table */
$table = $event['subject'];
// If the tags table doesn't implement the interface bail
if (!($table instanceof TaggableTableInterface)) {
return;
}
// Parse the type alias
$tagsHelper = new TagsHelper();
$tagsHelper->typeAlias = $table->getTypeAlias();
$table->setTagsHelper($tagsHelper);
}
/**
* Runs when an existing table object has been loaded
*
* @param AfterLoadEvent $event The event to handle
*
* @return void
*
* @since 4.0.0
*/
public function onTableAfterLoad(AfterLoadEvent $event)
{
// Extract arguments
/** @var TableInterface $table */
$table = $event['subject'];
// If the tags table doesn't implement the interface bail
if (!($table instanceof TaggableTableInterface)) {
return;
}
// If the table doesn't have a tags helper we can't proceed
if (\is_null($table->getTagsHelper())) {
return;
}
// This is required because getTagIds overrides the tags property of the Tags Helper.
$cloneHelper = clone $table->getTagsHelper();
$tagIds = $cloneHelper->getTagIds($table->getId(), $table->getTypeAlias());
if (!empty($tagIds)) {
$table->getTagsHelper()->tags = explode(',', $tagIds);
}
}
/**
* Runs when an existing table object has been loaded
*
* @param BeforeBatchEvent $event The event to handle
*
* @return void
*
* @since 4.0.0
*/
public function onBeforeBatch(BeforeBatchEvent $event)
{
/** @var TableInterface $sourceTable */
$sourceTable = $event['src'];
if (!($sourceTable instanceof TaggableTableInterface)) {
return;
}
if ($event['type'] === 'copy') {
$sourceTable->newTags = $sourceTable->getTagsHelper()->tags;
} else {
/**
* All other batch actions we don't want the tags to be modified so clear the helper - that way no actions
* will be performed on store
*/
$sourceTable->clearTagsHelper();
}
}
}

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<extension type="plugin" group="behaviour" method="upgrade">
<name>plg_behaviour_taggable</name>
<version>4.0.0</version>
<creationDate>2015-08</creationDate>
<author>Joomla! Project</author>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<description>PLG_BEHAVIOUR_TAGGABLE_XML_DESCRIPTION</description>
<namespace path="src">Joomla\Plugin\Behaviour\Taggable</namespace>
<files>
<folder plugin="taggable">services</folder>
<folder>src</folder>
</files>
<languages>
<language tag="en-GB">language/en-GB/plg_behaviour_taggable.ini</language>
<language tag="en-GB">language/en-GB/plg_behaviour_taggable.sys.ini</language>
</languages>
<config />
</extension>

View File

@ -0,0 +1,50 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage Behaviour.versionable
*
* @copyright (C) 2022 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
\defined('_JEXEC') or die;
use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Helper\CMSHelper;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use Joomla\Filter\InputFilter;
use Joomla\Plugin\Behaviour\Versionable\Extension\Versionable;
return new class () implements ServiceProviderInterface {
/**
* Registers the service provider with a DI container.
*
* @param Container $container The DI container.
*
* @return void
*
* @since 4.2.0
*/
public function register(Container $container)
{
$container->set(
PluginInterface::class,
function (Container $container) {
$plugin = new Versionable(
$container->get(DispatcherInterface::class),
(array) PluginHelper::getPlugin('behaviour', 'versionable'),
new InputFilter(),
new CMSHelper()
);
$plugin->setApplication(Factory::getApplication());
return $plugin;
}
);
}
};

View File

@ -0,0 +1,157 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage Behaviour.versionable
*
* @copyright (C) 2016 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\Behaviour\Versionable\Extension;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Event\Table\AfterStoreEvent;
use Joomla\CMS\Event\Table\BeforeDeleteEvent;
use Joomla\CMS\Helper\CMSHelper;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Versioning\VersionableTableInterface;
use Joomla\CMS\Versioning\Versioning;
use Joomla\Event\DispatcherInterface;
use Joomla\Event\SubscriberInterface;
use Joomla\Filter\InputFilter;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Implements the Versionable behaviour which allows extensions to automatically support content history for their content items.
*
* This plugin supersedes JTableObserverContenthistory.
*
* @since 4.0.0
*/
final class Versionable extends CMSPlugin implements SubscriberInterface
{
/**
* Returns an array of events this subscriber will listen to.
*
* @return array
*
* @since 4.2.0
*/
public static function getSubscribedEvents(): array
{
return [
'onTableAfterStore' => 'onTableAfterStore',
'onTableBeforeDelete' => 'onTableBeforeDelete',
];
}
/**
* The input filter
*
* @var InputFilter
* @since 4.2.0
*/
private $filter;
/**
* The CMS helper
*
* @var CMSHelper
* @since 4.2.0
*/
private $helper;
/**
* Constructor.
*
* @param DispatcherInterface $dispatcher The dispatcher
* @param array $config An optional associative array of configuration settings
* @param InputFilter $filter The input filter
* @param CMSHelper $helper The CMS helper
*
* @since 4.0.0
*/
public function __construct(DispatcherInterface $dispatcher, array $config, InputFilter $filter, CMSHelper $helper)
{
parent::__construct($dispatcher, $config);
$this->filter = $filter;
$this->helper = $helper;
}
/**
* Post-processor for $table->store($updateNulls)
*
* @param AfterStoreEvent $event The event to handle
*
* @return void
*
* @since 4.0.0
*/
public function onTableAfterStore(AfterStoreEvent $event)
{
// Extract arguments
/** @var VersionableTableInterface $table */
$table = $event['subject'];
$result = $event['result'];
if (!$result) {
return;
}
if (!(\is_object($table) && $table instanceof VersionableTableInterface)) {
return;
}
// Get the Tags helper and assign the parsed alias
$typeAlias = $table->getTypeAlias();
$aliasParts = explode('.', $typeAlias);
if ($aliasParts[0] === '' || !ComponentHelper::getParams($aliasParts[0])->get('save_history', 0)) {
return;
}
$id = $table->getId();
$data = $this->helper->getDataObject($table);
$input = $this->getApplication()->getInput();
$jform = $input->get('jform', [], 'array');
$versionNote = '';
if (isset($jform['version_note'])) {
$versionNote = $this->filter->clean($jform['version_note'], 'string');
}
Versioning::store($typeAlias, $id, $data, $versionNote);
}
/**
* Pre-processor for $table->delete($pk)
*
* @param BeforeDeleteEvent $event The event to handle
*
* @return void
*
* @since 4.0.0
*/
public function onTableBeforeDelete(BeforeDeleteEvent $event)
{
// Extract arguments
/** @var VersionableTableInterface $table */
$table = $event['subject'];
if (!(\is_object($table) && $table instanceof VersionableTableInterface)) {
return;
}
$typeAlias = $table->getTypeAlias();
$aliasParts = explode('.', $typeAlias);
if ($aliasParts[0] && ComponentHelper::getParams($aliasParts[0])->get('save_history', 0)) {
Versioning::delete($typeAlias, $table->getId());
}
}
}

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<extension type="plugin" group="behaviour" method="upgrade">
<name>plg_behaviour_versionable</name>
<version>4.0.0</version>
<creationDate>2015-08</creationDate>
<author>Joomla! Project</author>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<description>PLG_BEHAVIOUR_VERSIONABLE_XML_DESCRIPTION</description>
<namespace path="src">Joomla\Plugin\Behaviour\Versionable</namespace>
<files>
<folder plugin="versionable">services</folder>
<folder>src</folder>
</files>
<languages>
<language tag="en-GB">language/en-GB/plg_behaviour_versionable.ini</language>
<language tag="en-GB">language/en-GB/plg_behaviour_versionable.sys.ini</language>
</languages>
<config />
</extension>

View File

@ -0,0 +1,180 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage Captcha
*
* @author Peter Martin
* @copyright Copyright 2016-2024 Peter Martin. All rights reserved.
* @license GNU General Public License version 2 or later
* @link https://data2site.com
*/
defined('_JEXEC') or die;
use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Factory;
use Joomla\CMS\Http\HttpFactory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\Utilities\IpHelper;
/**
* hCaptcha Plugin
* Using the https://www.hcaptcha.com/ CAPTCHA service
*
* @since 1.0.0
*/
class PlgCaptchaHcaptcha extends CMSPlugin
{
/**
* Load the language file on instantiation.
*
* @var boolean
* @since 1.0.0
*/
protected $autoloadLanguage = true;
/**
* Application object.
*
* @var CMSApplication
* @since 4.0.0
*/
protected $app;
/**
* Reports the privacy related capabilities for this plugin to site administrators.
*
* @return array
*
* @since 1.0.0
*/
public function onPrivacyCollectAdminCapabilities()
{
$this->loadLanguage();
return [
Text::_('PLG_CAPTCHA_HCAPTCHA') => [
Text::_('PLG_CAPTCHA_HCAPTCHA_PRIVACY_CAPABILITY_IP_ADDRESS'),
]
];
}
/**
* Initialise the captcha
*
* @return boolean True on success, false otherwise
*
* @throws Exception
* @since 1.0.0
*/
public function onInit()
{
// If there is no Public Key set, then this plugin is no use, so exit
if ($this->params->get('publicKey', '') === '') {
throw new \RuntimeException(Text::_('PLG_CAPTCHA_HCAPTCHA_ERROR_NO_PUBLIC_KEY'));
}
// Load the JavaScript from hCaptcha
$this->app->getDocument()->getWebAssetManager()
->registerAndUseScript('plg_captcha_hcaptcha.api', 'https://hcaptcha.com/1/api.js', [], ['defer' => true]);
return true;
}
/**
* Gets the challenge HTML
*
* @param string $name The name of the field. Not Used.
* @param string $id The id of the field.
* @param string $class The class of the field.
*
* @return string The HTML to be embedded in the form.
* @throws Exception
* @since 1.0.0
*/
public function onDisplay($name = null, $id = 'hcaptcha', $class = '')
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$ele = $dom->createElement('div');
$ele->setAttribute('id', $id);
$ele->setAttribute('class', 'h-captcha required');
$ele->setAttribute('data-sitekey', $this->params->get('publicKey', ''));
$ele->setAttribute('data-theme', $this->params->get('theme', 'light'));
$ele->setAttribute('data-size', $this->params->get('size', 'normal'));
$dom->appendChild($ele);
return $dom->saveHTML($ele);
}
/**
* Calls an HTTP POST function to verify if the user's guess was correct
*
* @param string $code Answer provided by user. Not needed for the Hcaptcha implementation
*
* @return boolean
* @throws Exception
* @since 1.0.0
*/
public function onCheckAnswer($code = null)
{
$input = Factory::getApplication()->input;
$privateKey = $this->params->get('privateKey');
$remoteIp = IpHelper::getIp();
$hCaptchaResponse = $code ?? $input->get('h-captcha-response', '', 'cmd');
// Check for Private Key
if (empty($privateKey)) {
throw new \RuntimeException(Text::_('PLG_CAPTCHA_HCAPTCHA_ERROR_NO_PRIVATE_KEY'));
}
// Check for IP
if (empty($remoteIp)) {
throw new \RuntimeException(Text::_('PLG_CAPTCHA_HCAPTCHA_ERROR_NO_IP'));
}
if (empty($hCaptchaResponse)) {
throw new \RuntimeException(Text::_('PLG_CAPTCHA_HCAPTCHA_ERROR_EMPTY_SOLUTION'));
}
return $this->getResponse($privateKey, $remoteIp, $hCaptchaResponse);
}
/**
* Get the hCaptcha response.
*
* @param string $privateKey The private key for authentication.
* @param string $remoteIp The remote IP of the visitor.
* @param string $hCaptchaResponse The response received from Google.
*
* @return bool True if response is good | False if response is bad.
*
* @throws \RuntimeException
* @since 1.4.0
*/
private function getResponse(string $privateKey, string $remoteIp, string $hCaptchaResponse)
{
try {
$verifyResponse = HttpFactory::getHttp()->get(
'https://hcaptcha.com/siteverify?secret=' . $privateKey .
'&response=' . $hCaptchaResponse .
'&remoteip=' . $remoteIp
);
} catch (RuntimeException $e) {
throw new \RuntimeException(Text::_('PLG_CAPTCHA_HCAPTCHA_ERROR_CANT_CONNECT_TO_HCAPTCHA_SERVERS'));
}
if ($verifyResponse->code !== 200 || $verifyResponse->body === '') {
throw new \RuntimeException(Text::_('PLG_CAPTCHA_HCAPTCHA_ERROR_INVALID_RESPONSE'));
}
$responseData = json_decode($verifyResponse->body);
if ($responseData->success) {
return true;
}
throw new \RuntimeException(Text::_('PLG_CAPTCHA_HCAPTCHA_ERROR_INCORRECT_CAPTCHA'));
}
}

View File

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<extension version="4.0" type="plugin" group="captcha" method="upgrade">
<name>plg_captcha_hcaptcha</name>
<version>1.4.3</version>
<creationDate>January 2024</creationDate>
<author>data2site</author>
<authorEmail>support@data2site.com</authorEmail>
<authorUrl>https://data2site.com</authorUrl>
<copyright>Copyright (C) 2021-2024 by data2site.com. All rights reserved.</copyright>
<license>GNU General Public License version 2 or later</license>
<description>PLG_CAPTCHA_HCAPTCHA_XML_DESCRIPTION</description>
<files>
<filename plugin="hcaptcha">hcaptcha.php</filename>
<folder>language</folder>
</files>
<config>
<fields name="params">
<fieldset name="basic">
<field
name="publicKey"
type="text"
label="PLG_CAPTCHA_HCAPTCHA_PUBLIC_KEY"
description="PLG_CAPTCHA_HCAPTCHA_PUBLIC_KEY_DESC"
default=""
required="true"
filter="string"
size="100"
class="input-xxlarge"
/>
<field
name="privateKey"
type="text"
label="PLG_CAPTCHA_HCAPTCHA_PRIVATE_KEY"
description="PLG_CAPTCHA_HCAPTCHA_PRIVATE_KEY_DESC"
default=""
required="true"
filter="string"
size="100"
class="input-xxlarge"
/>
<field
name="theme"
type="list"
label="PLG_CAPTCHA_HCAPTCHA_THEME"
default="light"
validate="options"
>
<option value="light">PLG_CAPTCHA_HCAPTCHA_THEME_LIGHT</option>
<option value="dark">PLG_CAPTCHA_HCAPTCHA_THEME_DARK</option>
</field>
<field
name="size"
type="list"
label="PLG_CAPTCHA_HCAPTCHA_SIZE"
default="normal"
validate="options"
>
<option value="normal">PLG_CAPTCHA_HCAPTCHA_SIZE_NORMAL</option>
<option value="compact">PLG_CAPTCHA_HCAPTCHA_SIZE_COMPACT</option>
</field>
</fieldset>
</fields>
</config>
<updateservers>
<server type="extension" priority="1" name="plg_captcha_hcaptcha">https://data2site.com/updates/hcaptcha
</server>
</updateservers>
</extension>

View File

@ -0,0 +1,39 @@
; hCaptcha - CAPTCHA Plugin
; Copyright (C) Copyright 2020 - 2022 Peter Martin, https://db8.nl. All rights reserved.
; Copyright (C) Translation 2020 Tobias Zulauf (www.jah-tz.de)
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8
PLG_CAPTCHA_HCAPTCHA="CAPTCHA - hCaptcha"
PLG_CAPTCHA_HCAPTCHA_XML_DESCRIPTION="<p>Ein einfaches CAPTCHA-Plugin zum Schutz vor SPAM mit hCaptcha.com</p>
<ul>
<li>Autor: Peter Martin, <a href='https://data2site.com/' target='_blank' rel='noopener noreferrer'>https://data2site.com/</a></li>
<li>Dieses Plugin verwendet den CAPTCHA-Dienst von: <a href='https://www.hcaptcha.com/' target='_blank' rel='noopener noreferrer'>https://www.hcaptcha.com/</a></li>
<li>Fehlerberichte & Ergänzungen: <a href='https://github.com/pe7er/hcaptcha' target='_blank' rel='noopener noreferrer'>https://github.com/pe7er/hcaptcha</a></li>
</ul>"
; Params
PLG_CAPTCHA_HCAPTCHA_PUBLIC_KEY="Öffentlicher Schlüssel (Websiteschlüssel)"
PLG_CAPTCHA_HCAPTCHA_PUBLIC_KEY_DESC="Der Öffentlicher Schlüssel (Websiteschlüssel) wird zur eindeutigen Identifizierung Ihrer Website verwendet."
PLG_CAPTCHA_HCAPTCHA_PRIVATE_KEY="Privater Schlüssel (Geheimer Schlüssel)"
PLG_CAPTCHA_HCAPTCHA_PRIVATE_KEY_DESC="Der private Schlüssel (geheimer Schlüssel) wird verwendet, um Ihr hCaptcha-Konto zu verifizieren"
PLG_CAPTCHA_HCAPTCHA_THEME="Theme"
PLG_CAPTCHA_HCAPTCHA_THEME_LIGHT="Hell"
PLG_CAPTCHA_HCAPTCHA_THEME_DARK="Dunkel"
PLG_CAPTCHA_HCAPTCHA_SIZE="Größe"
PLG_CAPTCHA_HCAPTCHA_SIZE_NORMAL="Normal"
PLG_CAPTCHA_HCAPTCHA_SIZE_COMPACT="Kompakt"
; Privacy
PLG_RECAPTCHA_PRIVACY_CAPABILITY_IP_ADDRESS="Das hCaptcha-Plugin ist als Spamschutz in das hCaptcha-System von hCaptcha.com integriert. Im Rahmen dieses Dienstes wird die IP-Adresse des Nutzers, der die Captcha-Anfrage beantwortet, an hcaptcha.com übermittelt."
; Error messages
PLG_CAPTCHA_HCAPTCHA_ERROR_CANT_CONNECT_TO_HCAPTCHA_SERVERS="Verbindung zu den hcaptcha.com-Servern nicht möglich"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_PUBLIC_KEY="Öffentlicher Schlüssel (Websiteschlüssel) fehlt"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_PRIVATE_KEY="Privater Schlüssel (Geheimer Schlüssey) fehlt"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_IP="Fehler: Es konnte keine IP Adresse erkannt werden"
PLG_CAPTCHA_HCAPTCHA_ERROR_EMPTY_SOLUTION="Bitte füllen Sie das CAPTCHA aus"
PLG_CAPTCHA_HCAPTCHA_ERROR_INCORRECT_CAPTCHA="Das CAPTCHA war falsch"
PLG_CAPTCHA_HCAPTCHA_ERROR_INVALID_RESPONSE="Ungültige Antwort von hcaptcha.com"

View File

@ -0,0 +1,13 @@
; hCaptcha - CAPTCHA Plugin
; Copyright (C) Copyright 2020 - 2022 Peter Martin, https://db8.nl. All rights reserved.
; Copyright (C) Translation 2020 Tobias Zulauf (www.jah-tz.de)
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8
PLG_CAPTCHA_HCAPTCHA="CAPTCHA - hCaptcha"
PLG_CAPTCHA_HCAPTCHA_XML_DESCRIPTION="<p>Ein einfaches CAPTCHA-Plugin zum Schutz vor SPAM mit hCaptcha.com</p>
<ul>
<li>Autor: Peter Martin, <a href='https://data2site.com/' target='_blank' rel='noopener noreferrer'>https://data2site.com/</a></li>
<li>Dieses Plugin verwendet den CAPTCHA-Dienst von: <a href='https://www.hcaptcha.com/' target='_blank' rel='noopener noreferrer'>https://www.hcaptcha.com/</a></li>
<li>Fehlerberichte & Ergänzungen: <a href='https://github.com/pe7er/hcaptcha' target='_blank' rel='noopener noreferrer'>https://github.com/pe7er/hcaptcha</a></li>
</ul>"

View File

@ -0,0 +1,34 @@
; hCaptcha - CAPTCHA Plugin
; Copyright (C) Copyright 2020 - 2022 Peter Martin, https://db8.nl. All rights reserved.
; Copyright (C) Translation 2020 Tobias Zulauf (www.jah-tz.de)
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8
PLG_CAPTCHA_HCAPTCHA="CAPTCHA - hCaptcha"
PLG_CAPTCHA_HCAPTCHA_XML_DESCRIPTION="<p>Ein einfaches CAPTCHA-Plugin zum Schutz vor SPAM mit hCaptcha.com</p><ul><li>Autor: Peter Martin, <a href='https://data2site.com/' target='_blank' rel='noopener noreferrer'>https://data2site.com/</a></li><li>Dieses Plugin verwendet den CAPTCHA-Dienst von: <a href='https://www.hcaptcha.com/' target='_blank' rel='noopener noreferrer'>https://www.hcaptcha.com/</a></li><li>Fehlerberichte & Ergänzungen: <a href='https://github.com/pe7er/hcaptcha' target='_blank' rel='noopener noreferrer'>https://github.com/pe7er/hcaptcha</a></li></ul>"
; Params
PLG_CAPTCHA_HCAPTCHA_PUBLIC_KEY="Öffentlicher Schlüssel (Websiteschlüssel)"
PLG_CAPTCHA_HCAPTCHA_PUBLIC_KEY_DESC="Der Öffentlicher Schlüssel (Websiteschlüssel) wird zur eindeutigen Identifizierung Ihrer Website verwendet."
PLG_CAPTCHA_HCAPTCHA_PRIVATE_KEY="Privater Schlüssel (Geheimer Schlüssel)"
PLG_CAPTCHA_HCAPTCHA_PRIVATE_KEY_DESC="Der private Schlüssel (geheimer Schlüssel) wird verwendet, um Ihr hCaptcha-Konto zu verifizieren"
PLG_CAPTCHA_HCAPTCHA_THEME="Theme"
PLG_CAPTCHA_HCAPTCHA_THEME_LIGHT="Hell"
PLG_CAPTCHA_HCAPTCHA_THEME_DARK="Dunkel"
PLG_CAPTCHA_HCAPTCHA_SIZE="Größe"
PLG_CAPTCHA_HCAPTCHA_SIZE_NORMAL="Normal"
PLG_CAPTCHA_HCAPTCHA_SIZE_COMPACT="Kompakt"
; Privacy
PLG_RECAPTCHA_PRIVACY_CAPABILITY_IP_ADDRESS="Das hCaptcha-Plugin ist als Spamschutz in das hCaptcha-System von hCaptcha.com integriert. Im Rahmen dieses Dienstes wird die IP-Adresse des Nutzers, der die Captcha-Anfrage beantwortet, an hcaptcha.com übermittelt."
; Error messages
PLG_CAPTCHA_HCAPTCHA_ERROR_CANT_CONNECT_TO_HCAPTCHA_SERVERS="Verbindung zu den hcaptcha.com-Servern nicht möglich"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_PUBLIC_KEY="Öffentlicher Schlüssel (Websiteschlüssel) fehlt"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_PRIVATE_KEY="Privater Schlüssel (Geheimer Schlüssey) fehlt"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_IP="Fehler: Es konnte keine IP Adresse erkannt werden"
PLG_CAPTCHA_HCAPTCHA_ERROR_EMPTY_SOLUTION="Bitte füllen Sie das CAPTCHA aus"
PLG_CAPTCHA_HCAPTCHA_ERROR_INCORRECT_CAPTCHA="Das CAPTCHA war falsch"
PLG_CAPTCHA_HCAPTCHA_ERROR_INVALID_RESPONSE="Ungültige Antwort von hcaptcha.com"

View File

@ -0,0 +1,8 @@
; hCaptcha - CAPTCHA Plugin
; Copyright (C) Copyright 2020 - 2022 Peter Martin, https://db8.nl. All rights reserved.
; Copyright (C) Translation 2020 Tobias Zulauf (www.jah-tz.de)
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8
PLG_CAPTCHA_HCAPTCHA="CAPTCHA - hCaptcha"
PLG_CAPTCHA_HCAPTCHA_XML_DESCRIPTION="<p>Ein einfaches CAPTCHA-Plugin zum Schutz vor SPAM mit hCaptcha.com</p><ul><li>Autor: Peter Martin, <a href='https://data2site.com/' target='_blank' rel='noopener noreferrer'>https://data2site.com/</a></li><li>Dieses Plugin verwendet den CAPTCHA-Dienst von: <a href='https://www.hcaptcha.com/' target='_blank' rel='noopener noreferrer'>https://www.hcaptcha.com/</a></li><li>Fehlerberichte & Ergänzungen: <a href='https://github.com/pe7er/hcaptcha' target='_blank' rel='noopener noreferrer'>https://github.com/pe7er/hcaptcha</a></li></ul>"

View File

@ -0,0 +1,38 @@
; hCaptcha - CAPTCHA Plugin
; Copyright (C) Copyright 2020 - 2022 Peter Martin, https://db8.nl. All rights reserved.
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8
PLG_CAPTCHA_HCAPTCHA="CAPTCHA - hCaptcha"
PLG_CAPTCHA_HCAPTCHA_XML_DESCRIPTION="<p>A simple CAPTCHA Plugin to protect against SPAM using hCaptcha.com</p>
<ul>
<li>Author: Peter Martin, <a href="_QQ_"https://data2site.com/"_QQ_" target="_QQ_"_blank"_QQ_">https://data2site.com/</a></li>
<li>This plugin uses the CAPTCHA service of: <a href="_QQ_"https://www.hcaptcha.com/"_QQ_" target="_QQ_"_blank"_QQ_">https://www.hcaptcha.com/</a></li>
<li>Bug reports & additions: <a href="_QQ_"https://github.com/pe7er/hcaptcha"_QQ_" target="_QQ_"_blank"_QQ_">https://github.com/pe7er/hcaptcha</a></li>
</ul>"
; Params
PLG_CAPTCHA_HCAPTCHA_PUBLIC_KEY="Site Key"
PLG_CAPTCHA_HCAPTCHA_PUBLIC_KEY_DESC="Site Keys are used to uniquely identify your site"
PLG_CAPTCHA_HCAPTCHA_PRIVATE_KEY="Secret key"
PLG_CAPTCHA_HCAPTCHA_PRIVATE_KEY_DESC="A secret Key is used to verify your hCaptcha account"
PLG_CAPTCHA_HCAPTCHA_THEME="Theme"
PLG_CAPTCHA_HCAPTCHA_THEME_LIGHT="Light"
PLG_CAPTCHA_HCAPTCHA_THEME_DARK="Dark"
PLG_CAPTCHA_HCAPTCHA_SIZE="Size"
PLG_CAPTCHA_HCAPTCHA_SIZE_NORMAL="Normal"
PLG_CAPTCHA_HCAPTCHA_SIZE_COMPACT="Compact"
; Privacy
PLG_CAPTCHA_HCAPTCHA_PRIVACY_CAPABILITY_IP_ADDRESS="The hCaptcha plugin integrates with hcaptcha's CAPTCHA system as a spam protection service. As part of this service, the IP address of the user answering the captcha challenge is transmitted to hcaptcha.com."
; Error messages
PLG_CAPTCHA_HCAPTCHA_ERROR_CANT_CONNECT_TO_HCAPTCHA_SERVERS="Unable to connect to the hcaptcha.com servers"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_PUBLIC_KEY="Public Key (Site Key) is missing"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_PRIVATE_KEY="Private Key (Secret Key) is missing"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_IP="Error: No IP address"
PLG_CAPTCHA_HCAPTCHA_ERROR_EMPTY_SOLUTION="Please complete the CAPTCHA"
PLG_CAPTCHA_HCAPTCHA_ERROR_INCORRECT_CAPTCHA="The CAPTCHA was incorrect"
PLG_CAPTCHA_HCAPTCHA_ERROR_INVALID_RESPONSE="Invalid response from hcaptcha.com"

View File

@ -0,0 +1,12 @@
; hCaptcha - CAPTCHA Plugin
; Copyright (C) Copyright 2020 - 2022 Peter Martin. All rights reserved.
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8
PLG_CAPTCHA_HCAPTCHA="CAPTCHA - hCaptcha"
PLG_CAPTCHA_HCAPTCHA_XML_DESCRIPTION="<p>A simple CAPTCHA Plugin to protect against SPAM using hCaptcha.com</p>
<ul>
<li>Author: Peter Martin, <a href="_QQ_"https://data2site.com/"_QQ_" target="_QQ_"_blank"_QQ_">https://data2site.com/</a></li>
<li>This plugin uses the CAPTCHA service of: <a href="_QQ_"https://www.hcaptcha.com/"_QQ_" target="_QQ_"_blank"_QQ_">https://www.hcaptcha.com/</a></li>
<li>Bug reports & additions: <a href="_QQ_"https://github.com/pe7er/hcaptcha"_QQ_" target="_QQ_"_blank"_QQ_">https://github.com/pe7er/hcaptcha</a></li>
</ul>"

View File

@ -0,0 +1,33 @@
; hCaptcha - CAPTCHA Plugin
; Copyright (C) Copyright 2020 - 2022 Peter Martin, https://db8.nl. All rights reserved.
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8
PLG_CAPTCHA_HCAPTCHA="CAPTCHA - hCaptcha"
PLG_CAPTCHA_HCAPTCHA_XML_DESCRIPTION="<p>A simple CAPTCHA Plugin to protect against SPAM using hCaptcha.com</p><ul><li>Author: Peter Martin, <a href=\"https://data2site.com/\" target=\"_blank\">https://data2site.com/</a></li><li>This plugin uses the CAPTCHA service of: <a href=\"https://www.hcaptcha.com/\" target=\"_blank\">https://www.hcaptcha.com/</a></li><li>Bug reports & additions: <a href=\"https://github.com/pe7er/hcaptcha\" target=\"_blank\">https://github.com/pe7er/hcaptcha</a></li></ul>"
; Params
PLG_CAPTCHA_HCAPTCHA_PUBLIC_KEY="Site Key"
PLG_CAPTCHA_HCAPTCHA_PUBLIC_KEY_DESC="Site Keys are used to uniquely identify your site"
PLG_CAPTCHA_HCAPTCHA_PRIVATE_KEY="Secret key"
PLG_CAPTCHA_HCAPTCHA_PRIVATE_KEY_DESC="A secret Key is used to verify your hCaptcha account"
PLG_CAPTCHA_HCAPTCHA_THEME="Theme"
PLG_CAPTCHA_HCAPTCHA_THEME_LIGHT="Light"
PLG_CAPTCHA_HCAPTCHA_THEME_DARK="Dark"
PLG_CAPTCHA_HCAPTCHA_SIZE="Size"
PLG_CAPTCHA_HCAPTCHA_SIZE_NORMAL="Normal"
PLG_CAPTCHA_HCAPTCHA_SIZE_COMPACT="Compact"
; Privacy
PLG_CAPTCHA_HCAPTCHA_PRIVACY_CAPABILITY_IP_ADDRESS="The hCaptcha plugin integrates with hcaptcha's CAPTCHA system as a spam protection service. As part of this service, the IP address of the user answering the captcha challenge is transmitted to hcaptcha.com."
; Error messages
PLG_CAPTCHA_HCAPTCHA_ERROR_CANT_CONNECT_TO_HCAPTCHA_SERVERS="Unable to connect to the hcaptcha.com servers"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_PUBLIC_KEY="Public Key (Site Key) is missing"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_PRIVATE_KEY="Private Key (Secret Key) is missing"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_IP="Error: No IP address"
PLG_CAPTCHA_HCAPTCHA_ERROR_EMPTY_SOLUTION="Please complete the CAPTCHA"
PLG_CAPTCHA_HCAPTCHA_ERROR_INCORRECT_CAPTCHA="The CAPTCHA was incorrect"
PLG_CAPTCHA_HCAPTCHA_ERROR_INVALID_RESPONSE="Invalid response from hcaptcha.com"

View File

@ -0,0 +1,7 @@
; hCaptcha - CAPTCHA Plugin
; Copyright (C) Copyright 2020 - 2022 Peter Martin. All rights reserved.
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8
PLG_CAPTCHA_HCAPTCHA="CAPTCHA - hCaptcha"
PLG_CAPTCHA_HCAPTCHA_XML_DESCRIPTION="<p>A simple CAPTCHA Plugin to protect against SPAM using hCaptcha.com</p><ul><li>Author: Peter Martin, <a href=\"https://data2site.com/\" target=\"_blank\">https://data2site.com/</a></li><li>This plugin uses the CAPTCHA service of: <a href=\"https://www.hcaptcha.com/\" target=\"_blank\">https://www.hcaptcha.com/</a></li><li>Bug reports & additions: <a href=\"https://github.com/pe7er/hcaptcha\" target=\"_blank\">https://github.com/pe7er/hcaptcha</a></li></ul>"

View File

@ -0,0 +1,38 @@
; hCaptcha - CAPTCHA Plugin
; Copyright (C) Copyright 2020 - 2022 Peter Martin, https://db8.nl. All rights reserved.
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8
PLG_CAPTCHA_HCAPTCHA="CAPTCHA - hCaptcha"
PLG_CAPTCHA_HCAPTCHA_XML_DESCRIPTION="<p>Un simple plugin CAPTCHA para prevenir el acceso de robots de SPAM ('spammers') usando hCaptcha.com</p>
<ul>
<li>Autor: Peter Martin, <a href="_QQ_"https://data2site.com/"_QQ_" target="_QQ_"_blank"_QQ_">https://data2site.com/</a></li>
<li>Este plugin utiliza el servicio CAPTCHA de: <a href="_QQ_"https://www.hcaptcha.com/"_QQ_" target="_QQ_"_blank"_QQ_">https://www.hcaptcha.com/</a></li>
<li>Informes de errores y adiciones: <a href="_QQ_"https://github.com/pe7er/hcaptcha"_QQ_" target="_QQ_"_blank"_QQ_">https://github.com/pe7er/hcaptcha</a></li>
</ul>"
; Params
PLG_CAPTCHA_HCAPTCHA_PUBLIC_KEY="Clave pública (Site Key)"
PLG_CAPTCHA_HCAPTCHA_PUBLIC_KEY_DESC="Las claves del sitio se utilizan para identificar de manera única su sitio"
PLG_CAPTCHA_HCAPTCHA_PRIVATE_KEY="Clave privada (Secret key)"
PLG_CAPTCHA_HCAPTCHA_PRIVATE_KEY_DESC="Una clave secreta se utiliza para verificar su cuenta hCaptcha"
PLG_CAPTCHA_HCAPTCHA_THEME="Tema"
PLG_CAPTCHA_HCAPTCHA_THEME_LIGHT="Claro"
PLG_CAPTCHA_HCAPTCHA_THEME_DARK="Oscuro"
PLG_CAPTCHA_HCAPTCHA_SIZE="Tamaño"
PLG_CAPTCHA_HCAPTCHA_SIZE_NORMAL="Normal"
PLG_CAPTCHA_HCAPTCHA_SIZE_COMPACT="Compacto"
; Privacy
PLG_CAPTCHA_HCAPTCHA_PRIVACY_CAPABILITY_IP_ADDRESS="El plugin hCaptcha se integra con el sistema CAPTCHA de hcaptcha como un servicio de protección contra el spam. Como parte de este servicio, la dirección IP del usuario que responde al reto del captcha es transmitida a hcaptcha.com."
; Error messages
PLG_CAPTCHA_HCAPTCHA_ERROR_CANT_CONNECT_TO_HCAPTCHA_SERVERS="No se puede conectar a los servidores de hcaptcha.com"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_PUBLIC_KEY="Falta la llave pública (Site Key)"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_PRIVATE_KEY="La llave privada (Secret Key) ha desaparecido"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_IP="Error: No hay dirección IP"
PLG_CAPTCHA_HCAPTCHA_ERROR_EMPTY_SOLUTION="Por favor, complete el CAPTCHA"
PLG_CAPTCHA_HCAPTCHA_ERROR_INCORRECT_CAPTCHA="El CAPTCHA era incorrecto"
PLG_CAPTCHA_HCAPTCHA_ERROR_INVALID_RESPONSE="Respuesta no válida de hcaptcha.com"

View File

@ -0,0 +1,12 @@
; hCaptcha - CAPTCHA Plugin
; Copyright (C) Copyright 2020 - 2022 Peter Martin, https://db8.nl. All rights reserved.
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8
PLG_CAPTCHA_HCAPTCHA="CAPTCHA - hCaptcha"
PLG_CAPTCHA_HCAPTCHA_XML_DESCRIPTION="<p>Un simple plugin CAPTCHA para prevenir el acceso de robots de SPAM ('spammers') usando hCaptcha.com</p>
<ul>
<li>Autor: Peter Martin, <a href="_QQ_"https://data2site.com/"_QQ_" target="_QQ_"_blank"_QQ_">https://data2site.com/</a></li>
<li>Este plugin utiliza el servicio CAPTCHA de: <a href="_QQ_"https://www.hcaptcha.com/"_QQ_" target="_QQ_"_blank"_QQ_">https://www.hcaptcha.com/</a></li>
<li>Informes de errores y adiciones: <a href="_QQ_"https://github.com/pe7er/hcaptcha"_QQ_" target="_QQ_"_blank"_QQ_">https://github.com/pe7er/hcaptcha</a></li>
</ul>"

View File

@ -0,0 +1,33 @@
; hCaptcha - CAPTCHA Plugin
; Copyright (C) Copyright 2020 - 2022 Peter Martin, https://db8.nl. All rights reserved.
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8
PLG_CAPTCHA_HCAPTCHA="CAPTCHA - hCaptcha"
PLG_CAPTCHA_HCAPTCHA_XML_DESCRIPTION="<p>Un simple plugin CAPTCHA para prevenir el acceso de robots de SPAM ('spammers') usando hCaptcha.com</p><ul><li>Autor: Peter Martin, <a href=\"https://data2site.com/\" target=\"_blank\">https://data2site.com/</a></li><li>Este plugin utiliza el servicio CAPTCHA de: <a href=\"https://www.hcaptcha.com/\" target=\"_blank\">https://www.hcaptcha.com/</a></li><li>Informes de errores y adiciones: <a href=\"https://github.com/pe7er/hcaptcha\" target=\"_blank\">https://github.com/pe7er/hcaptcha</a></li></ul>"
; Params
PLG_CAPTCHA_HCAPTCHA_PUBLIC_KEY="Clave pública (Site Key)"
PLG_CAPTCHA_HCAPTCHA_PUBLIC_KEY_DESC="Las claves del sitio se utilizan para identificar de manera única su sitio"
PLG_CAPTCHA_HCAPTCHA_PRIVATE_KEY="Clave privada (Secret key)"
PLG_CAPTCHA_HCAPTCHA_PRIVATE_KEY_DESC="Una clave secreta se utiliza para verificar su cuenta hCaptcha"
PLG_CAPTCHA_HCAPTCHA_THEME="Tema"
PLG_CAPTCHA_HCAPTCHA_THEME_LIGHT="Claro"
PLG_CAPTCHA_HCAPTCHA_THEME_DARK="Oscuro"
PLG_CAPTCHA_HCAPTCHA_SIZE="Tamaño"
PLG_CAPTCHA_HCAPTCHA_SIZE_NORMAL="Normal"
PLG_CAPTCHA_HCAPTCHA_SIZE_COMPACT="Compacto"
; Privacy
PLG_CAPTCHA_HCAPTCHA_PRIVACY_CAPABILITY_IP_ADDRESS="El plugin hCaptcha se integra con el sistema CAPTCHA de hcaptcha como un servicio de protección contra el spam. Como parte de este servicio, la dirección IP del usuario que responde al reto del captcha es transmitida a hcaptcha.com."
; Error messages
PLG_CAPTCHA_HCAPTCHA_ERROR_CANT_CONNECT_TO_HCAPTCHA_SERVERS="No se puede conectar a los servidores de hcaptcha.com"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_PUBLIC_KEY="Falta la llave pública (Site Key)"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_PRIVATE_KEY="La llave privada (Secret Key) ha desaparecido"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_IP="Error: No hay dirección IP"
PLG_CAPTCHA_HCAPTCHA_ERROR_EMPTY_SOLUTION="Por favor, complete el CAPTCHA"
PLG_CAPTCHA_HCAPTCHA_ERROR_INCORRECT_CAPTCHA="El CAPTCHA era incorrecto"
PLG_CAPTCHA_HCAPTCHA_ERROR_INVALID_RESPONSE="Respuesta no válida de hcaptcha.com"

View File

@ -0,0 +1,7 @@
; hCaptcha - CAPTCHA Plugin
; Copyright (C) Copyright 2020 - 2022 Peter Martin, https://db8.nl. All rights reserved.
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8
PLG_CAPTCHA_HCAPTCHA="CAPTCHA - hCaptcha"
PLG_CAPTCHA_HCAPTCHA_XML_DESCRIPTION="<p>Un simple plugin CAPTCHA para prevenir el acceso de robots de SPAM ('spammers') usando hCaptcha.com</p><ul><li>Autor: Peter Martin, <a href=\"https://data2site.com/\" target=\"_blank\">https://data2site.com/</a></li><li>Este plugin utiliza el servicio CAPTCHA de: <a href=\"https://www.hcaptcha.com/\" target=\"_blank\">https://www.hcaptcha.com/</a></li><li>Informes de errores y adiciones: <a href=\"https://github.com/pe7er/hcaptcha\" target=\"_blank\">https://github.com/pe7er/hcaptcha</a></li></ul>"

View File

@ -0,0 +1,39 @@
; hCaptcha - CAPTCHA Plugin
; Copyright (C) Copyright 2020 - 2022 Peter Martin, https://db8.nl. All rights reserved.
; Copyright (C) Translation 2020 Yannick Berges
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8
PLG_CAPTCHA_HCAPTCHA="CAPTCHA - hCaptcha"
PLG_CAPTCHA_HCAPTCHA_XML_DESCRIPTION="<p>Un plugin simple de type CAPTCHA pour protéger votre site contre le SPAM utilise hCaptcha.com</p>
<ul>
<li>Auteur: Peter Martin, <a href="_QQ_"https://data2site.com/"_QQ_" target="_QQ_"_blank"_QQ_">https://data2site.com/</a></li>
<li>Ce plugin utilise le service de CAPTCHA: <a href="_QQ_"https://www.hcaptcha.com/"_QQ_" target="_QQ_"_blank"_QQ_">https://www.hcaptcha.com/</a></li>
<li>Rapport de bug & Ajout: <a href="_QQ_"https://github.com/pe7er/hcaptcha"_QQ_" target="_QQ_"_blank"_QQ_">https://github.com/pe7er/hcaptcha</a></li>
</ul>"
; Params
PLG_CAPTCHA_HCAPTCHA_PUBLIC_KEY="Clé site"
PLG_CAPTCHA_HCAPTCHA_PUBLIC_KEY_DESC="Les clés de site sont utilisés uniquement pour idnetifié votre site"
PLG_CAPTCHA_HCAPTCHA_PRIVATE_KEY="Clé secrète"
PLG_CAPTCHA_HCAPTCHA_PRIVATE_KEY_DESC="Cette clé secrète sera utilisée pour vérifier votre compte hCaptcha"
PLG_CAPTCHA_HCAPTCHA_THEME="Thème"
PLG_CAPTCHA_HCAPTCHA_THEME_LIGHT="Clair"
PLG_CAPTCHA_HCAPTCHA_THEME_DARK="Sombre"
PLG_CAPTCHA_HCAPTCHA_SIZE="Taille"
PLG_CAPTCHA_HCAPTCHA_SIZE_NORMAL="Normal"
PLG_CAPTCHA_HCAPTCHA_SIZE_COMPACT="Compact"
; Privacy
PLG_CAPTCHA_HCAPTCHA_PRIVACY_CAPABILITY_IP_ADDRESS="Le plugin hCaptcha s'intègre au système CAPTCHA de hcaptcha en tant que service de protection anti-spam. Dans le cadre de ce service, l'adresse IP de l'utilisateur répondant au challenge captcha est transmise à hcaptcha.com."
; Error messages
PLG_CAPTCHA_HCAPTCHA_ERROR_CANT_CONNECT_TO_HCAPTCHA_SERVERS="Impossible de se connecter aux serveurs hcaptcha.com"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_PUBLIC_KEY="La clé publique (clé du site) est manquante"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_PRIVATE_KEY="La clé privée (clé secrète) est manquante"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_IP="Erreur: pas d'adresse IP"
PLG_CAPTCHA_HCAPTCHA_ERROR_EMPTY_SOLUTION="Veuillez compléter le CAPTCHA"
PLG_CAPTCHA_HCAPTCHA_ERROR_INCORRECT_CAPTCHA="Le CAPTCHA est incorrect"
PLG_CAPTCHA_HCAPTCHA_ERROR_INVALID_RESPONSE="Réponse invalide de hcaptcha.com"

View File

@ -0,0 +1,13 @@
; hCaptcha - CAPTCHA Plugin
; Copyright (C) Copyright 2020 - 2022 Peter Martin, https://db8.nl. All rights reserved.
; Copyright (C) Translation 2020 Yannick Berges
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8
PLG_CAPTCHA_HCAPTCHA="CAPTCHA - hCaptcha"
PLG_CAPTCHA_HCAPTCHA_XML_DESCRIPTION="<p>Un plugin simple de type CAPTCHA pour protéger votre site contre le SPAM utilise hCaptcha.com</p>
<ul>
<li>Auteur: Peter Martin, <a href="_QQ_"https://data2site.com/"_QQ_" target="_QQ_"_blank"_QQ_">https://data2site.com/</a></li>
<li>Ce plugin utilise le service de CAPTCHA : <a href="_QQ_"https://www.hcaptcha.com/"_QQ_" target="_QQ_"_blank"_QQ_">https://www.hcaptcha.com/</a></li>
<li>Rapport de bug & Ajout: <a href="_QQ_"https://github.com/pe7er/hcaptcha"_QQ_" target="_QQ_"_blank"_QQ_">https://github.com/pe7er/hcaptcha</a></li>
</ul>"

View File

@ -0,0 +1,34 @@
; hCaptcha - CAPTCHA Plugin
; Copyright (C) Copyright 2020 - 2022 Peter Martin, https://db8.nl. All rights reserved.
; Copyright (C) Translation 2020 Yannick Berges
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8
PLG_CAPTCHA_HCAPTCHA="CAPTCHA - hCaptcha"
PLG_CAPTCHA_HCAPTCHA_XML_DESCRIPTION="<p>Un plugin simple de type CAPTCHA pour protéger votre site contre le SPAM utilise hCaptcha.com</p><ul><li>Auteur: Peter Martin, <a href=\"https://data2site.com/\" target=\"_blank\">https://data2site.com/</a></li><li>Ce plugin utilise le service de CAPTCHA: <a href=\"https://www.hcaptcha.com/\" target=\"_blank\">https://www.hcaptcha.com/</a></li><li>Rapport de bug & Ajout: <a href=\"https://github.com/pe7er/hcaptcha\" target=\"_blank\">https://github.com/pe7er/hcaptcha</a></li></ul>"
; Params
PLG_CAPTCHA_HCAPTCHA_PUBLIC_KEY="Clé site"
PLG_CAPTCHA_HCAPTCHA_PUBLIC_KEY_DESC="Les clés de site sont utilisés uniquement pour idnetifié votre site"
PLG_CAPTCHA_HCAPTCHA_PRIVATE_KEY="Clé secrète"
PLG_CAPTCHA_HCAPTCHA_PRIVATE_KEY_DESC="Cette clé secrète sera utilisée pour vérifier votre compte hCaptcha"
PLG_CAPTCHA_HCAPTCHA_THEME="Thème"
PLG_CAPTCHA_HCAPTCHA_THEME_LIGHT="Clair"
PLG_CAPTCHA_HCAPTCHA_THEME_DARK="Sombre"
PLG_CAPTCHA_HCAPTCHA_SIZE="Taille"
PLG_CAPTCHA_HCAPTCHA_SIZE_NORMAL="Normal"
PLG_CAPTCHA_HCAPTCHA_SIZE_COMPACT="Compact"
; Privacy
PLG_CAPTCHA_HCAPTCHA_PRIVACY_CAPABILITY_IP_ADDRESS="Le plugin hCaptcha s'intègre au système CAPTCHA de hcaptcha en tant que service de protection anti-spam. Dans le cadre de ce service, l'adresse IP de l'utilisateur répondant au challenge captcha est transmise à hcaptcha.com."
; Error messages
PLG_CAPTCHA_HCAPTCHA_ERROR_CANT_CONNECT_TO_HCAPTCHA_SERVERS="Impossible de se connecter aux serveurs hcaptcha.com"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_PUBLIC_KEY="La clé publique (clé du site) est manquante"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_PRIVATE_KEY="La clé privée (clé secrète) est manquante"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_IP="Erreur: pas d'adresse IP"
PLG_CAPTCHA_HCAPTCHA_ERROR_EMPTY_SOLUTION="Veuillez compléter le CAPTCHA"
PLG_CAPTCHA_HCAPTCHA_ERROR_INCORRECT_CAPTCHA="Le CAPTCHA est incorrect"
PLG_CAPTCHA_HCAPTCHA_ERROR_INVALID_RESPONSE="Réponse invalide de hcaptcha.com"

View File

@ -0,0 +1,8 @@
; hCaptcha - CAPTCHA Plugin
; Copyright (C) Copyright 2020 - 2022 Peter Martin, https://db8.nl. All rights reserved.
; Copyright (C) Translation 2020 Yannick Berges
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8
PLG_CAPTCHA_HCAPTCHA="CAPTCHA - hCaptcha"
PLG_CAPTCHA_HCAPTCHA_XML_DESCRIPTION="<p>Un plugin simple de type CAPTCHA pour protéger votre site contre le SPAM utilise hCaptcha.com</p><ul><li>Auteur: Peter Martin, <a href=\"https://data2site.com/\" target=\"_blank\">https://data2site.com/</a></li><li>Ce plugin utilise le service de CAPTCHA : <a href=\"https://www.hcaptcha.com/\" target=\"_blank\">https://www.hcaptcha.com/</a></li><li>Rapport de bug & Ajout: <a href=\"https://github.com/pe7er/hcaptcha\" target=\"_blank\">https://github.com/pe7er/hcaptcha</a></li></ul>"

View File

@ -0,0 +1,38 @@
; hCaptcha - CAPTCHA Plugin
; Copyright (C) Copyright 2020 - 2022 Peter Martin, https://db8.nl. All rights reserved.
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8
PLG_CAPTCHA_HCAPTCHA="CAPTCHA - hCaptcha"
PLG_CAPTCHA_HCAPTCHA_XML_DESCRIPTION="<p>Un semplice Plugin CAPTCHA per proteggersi dallo SPAM con hCaptcha.com</p>
<ul>
<li>Autore: Peter Martin, <a href="_QQ_"https://data2site.com/"_QQ_" target="_QQ_"_blank"_QQ_">https://data2site.com/</a></li>
<li>Questo plugin usa il servizio CAPTCHA di: <a href="_QQ_"https://www.hcaptcha.com/"_QQ_" target="_QQ_"_blank"_QQ_">https://www.hcaptcha.com/</a></li>
<li>Per rapporti di bug & integrazioni: <a href="_QQ_"https://github.com/pe7er/hcaptcha"_QQ_" target="_QQ_"_blank"_QQ_">https://github.com/pe7er/hcaptcha</a></li>
</ul>"
; Params
PLG_CAPTCHA_HCAPTCHA_PUBLIC_KEY="Site Key"
PLG_CAPTCHA_HCAPTCHA_PUBLIC_KEY_DESC="Le site key sono usate per identificare il tuo sito"
PLG_CAPTCHA_HCAPTCHA_PRIVATE_KEY="Secret key"
PLG_CAPTCHA_HCAPTCHA_PRIVATE_KEY_DESC="Le secret key sono usate per verificare il tuo account hCaptcha"
PLG_CAPTCHA_HCAPTCHA_THEME="Tema"
PLG_CAPTCHA_HCAPTCHA_THEME_LIGHT="Chiaro"
PLG_CAPTCHA_HCAPTCHA_THEME_DARK="Scuro"
PLG_CAPTCHA_HCAPTCHA_SIZE="Dimensione"
PLG_CAPTCHA_HCAPTCHA_SIZE_NORMAL="Normale"
PLG_CAPTCHA_HCAPTCHA_SIZE_COMPACT="Compatto"
; Privacy
PLG_CAPTCHA_HCAPTCHA_PRIVACY_CAPABILITY_IP_ADDRESS="Il plugin hCaptcha integra, assieme al sistema CAPTCHA hCaptcha, una protezione attiva dallo spam. Come parte del servizio, l'indirizzo IP dell'utente che risponde alla verifica captcha è trasmesso a hcaptcha.com."
; Error messages
PLG_CAPTCHA_HCAPTCHA_ERROR_CANT_CONNECT_TO_HCAPTCHA_SERVERS="Impossibile collegarsi ai server hcaptcha.com"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_PUBLIC_KEY="La chiave pubblica (Site Key) è mancante"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_PRIVATE_KEY="La chiave privata (Secret Key) è mancante"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_IP="Errore: Nessun indirizzo IP"
PLG_CAPTCHA_HCAPTCHA_ERROR_EMPTY_SOLUTION="Per favore completa il CAPTCHA"
PLG_CAPTCHA_HCAPTCHA_ERROR_INCORRECT_CAPTCHA="Il CAPTCHA era errato"
PLG_CAPTCHA_HCAPTCHA_ERROR_INVALID_RESPONSE="Risposta non valida da hcaptcha.com"

View File

@ -0,0 +1,12 @@
; hCaptcha - CAPTCHA Plugin
; Copyright (C) Copyright 2020 - 2022 Peter Martin. All rights reserved.
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8
PLG_CAPTCHA_HCAPTCHA="CAPTCHA - hCaptcha"
PLG_CAPTCHA_HCAPTCHA_XML_DESCRIPTION="<p>Un semplice Plugin CAPTCHA per proteggersi dallo SPAM con hCaptcha.com</p>
<ul>
<li>Autore: Peter Martin, <a href="_QQ_"https://data2site.com/"_QQ_" target="_QQ_"_blank"_QQ_">https://data2site.com/</a></li>
<li>Questo plugin usa il servizio CAPTCHA di: <a href="_QQ_"https://www.hcaptcha.com/"_QQ_" target="_QQ_"_blank"_QQ_">https://www.hcaptcha.com/</a></li>
<li>Per rapporti di bug & integrazioni: <a href="_QQ_"https://github.com/pe7er/hcaptcha"_QQ_" target="_QQ_"_blank"_QQ_">https://github.com/pe7er/hcaptcha</a></li>
</ul>"

View File

@ -0,0 +1,33 @@
; hCaptcha - CAPTCHA Plugin
; Copyright (C) Copyright 2020 - 2022 Peter Martin, https://db8.nl. All rights reserved.
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8
PLG_CAPTCHA_HCAPTCHA="CAPTCHA - hCaptcha"
PLG_CAPTCHA_HCAPTCHA_XML_DESCRIPTION="<p>Un semplice Plugin CAPTCHA per proteggersi dallo SPAM con hCaptcha.com</p><ul><li>Autore: Peter Martin, <a href=\"https://data2site.com/\" target=\"_blank\">https://data2site.com/</a></li><li>Questo plugin usa il servizio CAPTCHA di: <a href=\"https://www.hcaptcha.com/\" target=\"_blank\">https://www.hcaptcha.com/</a></li><li>Per rapporti di bug & integrazioni: <a href=\"https://github.com/pe7er/hcaptcha\" target=\"_blank\">https://github.com/pe7er/hcaptcha</a></li></ul>"
; Params
PLG_CAPTCHA_HCAPTCHA_PUBLIC_KEY="Site Key"
PLG_CAPTCHA_HCAPTCHA_PUBLIC_KEY_DESC="Le site key sono usate per identificare il tuo sito"
PLG_CAPTCHA_HCAPTCHA_PRIVATE_KEY="Secret key"
PLG_CAPTCHA_HCAPTCHA_PRIVATE_KEY_DESC="Le secret key sono usate per verificare il tuo account hCaptcha"
PLG_CAPTCHA_HCAPTCHA_THEME="Tema"
PLG_CAPTCHA_HCAPTCHA_THEME_LIGHT="Chiaro"
PLG_CAPTCHA_HCAPTCHA_THEME_DARK="Scuro"
PLG_CAPTCHA_HCAPTCHA_SIZE="Dimensione"
PLG_CAPTCHA_HCAPTCHA_SIZE_NORMAL="Normale"
PLG_CAPTCHA_HCAPTCHA_SIZE_COMPACT="Compatto"
; Privacy
PLG_CAPTCHA_HCAPTCHA_PRIVACY_CAPABILITY_IP_ADDRESS="Il plugin hCaptcha integra, assieme al sistema CAPTCHA hCaptcha, una protezione attiva dallo spam. Come parte del servizio, l'indirizzo IP dell'utente che risponde alla verifica captcha è trasmesso a hcaptcha.com."
; Error messages
PLG_CAPTCHA_HCAPTCHA_ERROR_CANT_CONNECT_TO_HCAPTCHA_SERVERS="Impossibile collegarsi ai server hcaptcha.com"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_PUBLIC_KEY="La chiave pubblica (Site Key) è mancante"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_PRIVATE_KEY="La chiave privata (Secret Key) è mancante"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_IP="Errore: Nessun indirizzo IP"
PLG_CAPTCHA_HCAPTCHA_ERROR_EMPTY_SOLUTION="Per favore completa il CAPTCHA"
PLG_CAPTCHA_HCAPTCHA_ERROR_INCORRECT_CAPTCHA="Il CAPTCHA era errato"
PLG_CAPTCHA_HCAPTCHA_ERROR_INVALID_RESPONSE="Risposta non valida da hcaptcha.com"

View File

@ -0,0 +1,7 @@
; hCaptcha - CAPTCHA Plugin
; Copyright (C) Copyright 2020 - 2022 Peter Martin. All rights reserved.
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8
PLG_CAPTCHA_HCAPTCHA="CAPTCHA - hCaptcha"
PLG_CAPTCHA_HCAPTCHA_XML_DESCRIPTION="<p>Un semplice Plugin CAPTCHA per proteggersi dallo SPAM con hCaptcha.com</p><ul><li>Autore: Peter Martin, <a href=\"https://data2site.com/\" target=\"_blank\">https://data2site.com/</a></li><li>Questo plugin usa il servizio CAPTCHA di: <a href=\"https://www.hcaptcha.com/\" target=\"_blank\">https://www.hcaptcha.com/</a></li><li>Per rapporti di bug & integrazioni: <a href=\"https://github.com/pe7er/hcaptcha\" target=\"_blank\">https://github.com/pe7er/hcaptcha</a></li></ul>"

View File

@ -0,0 +1,38 @@
; hCaptcha - CAPTCHA Plugin
; Copyright (C) Copyright 2020 - 2022 Peter Martin, https://db8.nl. All rights reserved.
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8
PLG_CAPTCHA_HCAPTCHA="CAPTCHA - hCaptcha"
PLG_CAPTCHA_HCAPTCHA_XML_DESCRIPTION="<p>Een eenvoudige CAPTCHA Plugin ter bescherming tegen SPAM met behulp van hCaptcha.com</p>
<ul>
<li>Ontwikkelaar: Peter Martin, <a href="_QQ_"https://data2site.com/"_QQ_" target="_QQ_"_blank"_QQ_">https://data2site.com/</a></li>
<li>Deze plugin maakt gebruik van de CAPTCHA service van: <a href="_QQ_"https://www.hcaptcha.com/"_QQ_" target="_QQ_"_blank"_QQ_">https://www.hcaptcha.com/</a></li>
<li>Meldt fouten & aanvullingen: <a href="_QQ_"https://github.com/pe7er/hcaptcha"_QQ_" target="_QQ_"_blank"_QQ_">https://github.com/pe7er/hcaptcha</a></li>
</ul>"
; Params
PLG_CAPTCHA_HCAPTCHA_PUBLIC_KEY="Site Key"
PLG_CAPTCHA_HCAPTCHA_PUBLIC_KEY_DESC="Een Site Key wordt gebruikt om uw site te identificeren"
PLG_CAPTCHA_HCAPTCHA_PRIVATE_KEY="Secret Key"
PLG_CAPTCHA_HCAPTCHA_PRIVATE_KEY_DESC="Een Secret Key wordt gebruikt om uw hCaptcha account te verifiëren"
PLG_CAPTCHA_HCAPTCHA_THEME="Theme"
PLG_CAPTCHA_HCAPTCHA_THEME_LIGHT="Licht"
PLG_CAPTCHA_HCAPTCHA_THEME_DARK="Donker"
PLG_CAPTCHA_HCAPTCHA_SIZE="Grootte"
PLG_CAPTCHA_HCAPTCHA_SIZE_NORMAL="Normaal"
PLG_CAPTCHA_HCAPTCHA_SIZE_COMPACT="Compact"
; Privacy
PLG_CAPTCHA_HCAPTCHA_PRIVACY_CAPABILITY_IP_ADDRESS="De hCaptcha-plug-in integreert met het CAPTCHA-systeem van hcaptcha als een spambeschermingsservice. Als onderdeel van deze service wordt het IP-adres van de gebruiker die de captcha-vraag beantwoordt, verzonden naar hcaptcha.com."
; Error messages
PLG_CAPTCHA_HCAPTCHA_ERROR_CANT_CONNECT_TO_HCAPTCHA_SERVERS="Kan geen verbinding maken met de hcaptcha.com-servers"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_PUBLIC_KEY="De publieke sleutel (Site Key) ontbreekt"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_PRIVATE_KEY="De prive sleutel (Secret Key) ontbreekt"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_IP="Fout: Geen IP-adres"
PLG_CAPTCHA_HCAPTCHA_ERROR_EMPTY_SOLUTION="Vul de CAPTCHA in"
PLG_CAPTCHA_HCAPTCHA_ERROR_INCORRECT_CAPTCHA="De CAPTCHA was onjuist"
PLG_CAPTCHA_HCAPTCHA_ERROR_INVALID_RESPONSE="Ongeldige response van hcaptcha.com"

View File

@ -0,0 +1,12 @@
; hCaptcha - CAPTCHA Plugin
; Copyright (C) Copyright 2020 - 2022 Peter Martin, https://db8.nl. All rights reserved.
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8
PLG_CAPTCHA_HCAPTCHA="CAPTCHA - hCaptcha"
PLG_CAPTCHA_HCAPTCHA_XML_DESCRIPTION="<p>Een eenvoudige CAPTCHA Plugin ter bescherming tegen SPAM met behulp van hCaptcha.com</p>
<ul>
<li>Ontwikkelaar: Peter Martin, <a href="_QQ_"https://data2site.com/"_QQ_" target="_QQ_"_blank"_QQ_">https://data2site.com/</a></li>
<li>Deze plugin maakt gebruik van de CAPTCHA service van: <a href="_QQ_"https://www.hcaptcha.com/"_QQ_" target="_QQ_"_blank"_QQ_">https://www.hcaptcha.com/</a></li>
<li>Meldt fouten & aanvullingen: <a href="_QQ_"https://github.com/pe7er/hcaptcha"_QQ_" target="_QQ_"_blank"_QQ_">https://github.com/pe7er/hcaptcha</a></li>
</ul>"

View File

@ -0,0 +1,33 @@
; hCaptcha - CAPTCHA Plugin
; Copyright (C) Copyright 2020 - 2022 Peter Martin, https://db8.nl. All rights reserved.
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8
PLG_CAPTCHA_HCAPTCHA="CAPTCHA - hCaptcha"
PLG_CAPTCHA_HCAPTCHA_XML_DESCRIPTION="<p>Een eenvoudige CAPTCHA Plugin ter bescherming tegen SPAM met behulp van hCaptcha.com</p><ul><li>Ontwikkelaar: Peter Martin, <a href=\"https://data2site.com/\" target=\"_blank\">https://data2site.com/</a></li><li>Deze plugin maakt gebruik van de CAPTCHA service van: <a href=\"https://www.hcaptcha.com/\" target=\"_blank\">https://www.hcaptcha.com/</a></li><li>Meldt fouten & aanvullingen: <a href=\"https://github.com/pe7er/hcaptcha\" target=\"_blank\">https://github.com/pe7er/hcaptcha</a></li></ul>"
; Params
PLG_CAPTCHA_HCAPTCHA_PUBLIC_KEY="Site Key"
PLG_CAPTCHA_HCAPTCHA_PUBLIC_KEY_DESC="Een Site Key wordt gebruikt om uw site te identificeren"
PLG_CAPTCHA_HCAPTCHA_PRIVATE_KEY="Secret Key"
PLG_CAPTCHA_HCAPTCHA_PRIVATE_KEY_DESC="Een Secret Key wordt gebruikt om uw hCaptcha account te verifiëren"
PLG_CAPTCHA_HCAPTCHA_THEME="Theme"
PLG_CAPTCHA_HCAPTCHA_THEME_LIGHT="Licht"
PLG_CAPTCHA_HCAPTCHA_THEME_DARK="Donker"
PLG_CAPTCHA_HCAPTCHA_SIZE="Grootte"
PLG_CAPTCHA_HCAPTCHA_SIZE_NORMAL="Normaal"
PLG_CAPTCHA_HCAPTCHA_SIZE_COMPACT="Compact"
; Privacy
PLG_CAPTCHA_HCAPTCHA_PRIVACY_CAPABILITY_IP_ADDRESS="De hCaptcha-plug-in integreert met het CAPTCHA-systeem van hcaptcha als een spambeschermingsservice. Als onderdeel van deze service wordt het IP-adres van de gebruiker die de captcha-vraag beantwoordt, verzonden naar hcaptcha.com."
; Error messages
PLG_CAPTCHA_HCAPTCHA_ERROR_CANT_CONNECT_TO_HCAPTCHA_SERVERS="Kan geen verbinding maken met de hcaptcha.com-servers"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_PUBLIC_KEY="De publieke sleutel (Site Key) ontbreekt"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_PRIVATE_KEY="De prive sleutel (Secret Key) ontbreekt"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_IP="Fout: Geen IP-adres"
PLG_CAPTCHA_HCAPTCHA_ERROR_EMPTY_SOLUTION="Vul de CAPTCHA in"
PLG_CAPTCHA_HCAPTCHA_ERROR_INCORRECT_CAPTCHA="De CAPTCHA was onjuist"
PLG_CAPTCHA_HCAPTCHA_ERROR_INVALID_RESPONSE="Ongeldige response van hcaptcha.com"

View File

@ -0,0 +1,7 @@
; hCaptcha - CAPTCHA Plugin
; Copyright (C) Copyright 2020 - 2022 Peter Martin, https://db8.nl. All rights reserved.
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8
PLG_CAPTCHA_HCAPTCHA="CAPTCHA - hCaptcha"
PLG_CAPTCHA_HCAPTCHA_XML_DESCRIPTION="<p>Een eenvoudige CAPTCHA Plugin ter bescherming tegen SPAM met behulp van hCaptcha.com</p><ul><li>Ontwikkelaar: Peter Martin, <a href=\"https://data2site.com/\" target=\"_blank\">https://data2site.com/</a></li><li>Deze plugin maakt gebruik van de CAPTCHA service van: <a href=\"https://www.hcaptcha.com/\" target=\"_blank\">https://www.hcaptcha.com/</a></li><li>Meldt fouten & aanvullingen: <a href=\"https://github.com/pe7er/hcaptcha\" target=\"_blank\">https://github.com/pe7er/hcaptcha</a></li></ul>"

View File

@ -0,0 +1,39 @@
; hCaptcha - CAPTCHA Plugin
; Copyright (C) Copyright 2020 - 2022 Peter Martin, https://db8.nl. All rights reserved.
; Copyright (C) Translation 2020 Mateusz Hajder
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8
PLG_CAPTCHA_HCAPTCHA="CAPTCHA - hCaptcha"
PLG_CAPTCHA_HCAPTCHA_XML_DESCRIPTION="<p>Prosta wtyczka CAPTCHA do ochrony przed spamem przy użyciu hCaptcha.com</p>
<ul>
<li>Autor: Peter Martin, <a href="_QQ_"https://data2site.com/"_QQ_" target="_QQ_"_blank"_QQ_">https://data2site.com/</a></li>
<li>Ta wtyczka korzysta z usługi CAPTCHA: <a href="_QQ_"https://www.hcaptcha.com/"_QQ_" target="_QQ_"_blank"_QQ_">https://www.hcaptcha.com/</a></li>
<li>Raporty o błędach & nowościach: <a href="_QQ_"https://github.com/pe7er/hcaptcha"_QQ_" target="_QQ_"_blank"_QQ_">https://github.com/pe7er/hcaptcha</a></li>
</ul>"
; Params
PLG_CAPTCHA_HCAPTCHA_PUBLIC_KEY="Klucz publiczny"
PLG_CAPTCHA_HCAPTCHA_PUBLIC_KEY_DESC="Klucz publiczny służy do identyfikacji witryny"
PLG_CAPTCHA_HCAPTCHA_PRIVATE_KEY="Klucz prywatny"
PLG_CAPTCHA_HCAPTCHA_PRIVATE_KEY_DESC="Klucz prywatny służy do weryfikacji twojego konta hCaptcha"
PLG_CAPTCHA_HCAPTCHA_THEME="Wygląd"
PLG_CAPTCHA_HCAPTCHA_THEME_LIGHT="Jasny"
PLG_CAPTCHA_HCAPTCHA_THEME_DARK="Ciemny"
PLG_CAPTCHA_HCAPTCHA_SIZE="Rozmiar"
PLG_CAPTCHA_HCAPTCHA_SIZE_NORMAL="Zwykły"
PLG_CAPTCHA_HCAPTCHA_SIZE_COMPACT="Kompaktowy"
; Privacy
PLG_CAPTCHA_HCAPTCHA_PRIVACY_CAPABILITY_IP_ADDRESS="Wtyczka hCaptcha integruje się z systemem CAPTCHA hcaptcha jako usługa ochrony przed spamem. W ramach tej usługi adres IP użytkownika biorącego udział w wyzwaniu captcha jest przesyłany do hcaptcha.com."
; Error messages
PLG_CAPTCHA_HCAPTCHA_ERROR_CANT_CONNECT_TO_HCAPTCHA_SERVERS="Nie można połączyć się z serwerami hcaptcha.com"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_PUBLIC_KEY="Brak Klucza Publicznego"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_PRIVATE_KEY="Brak Klucza Prywatnego"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_IP="Błąd: brak adresu IP"
PLG_CAPTCHA_HCAPTCHA_ERROR_EMPTY_SOLUTION="Proszę wypełnić CAPTCHA"
PLG_CAPTCHA_HCAPTCHA_ERROR_INCORRECT_CAPTCHA="CAPTCHA była niepoprawna"
PLG_CAPTCHA_HCAPTCHA_ERROR_INVALID_RESPONSE="Niepoprawna odpowiedź z hcaptcha.com"

View File

@ -0,0 +1,13 @@
; hCaptcha - CAPTCHA Plugin
; Copyright (C) Copyright 2020 - 2022 Peter Martin, https://db8.nl. All rights reserved.
; Copyright (C) Translation 2020 Mateusz Hajder
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8
PLG_CAPTCHA_HCAPTCHA="CAPTCHA - hCaptcha"
PLG_CAPTCHA_HCAPTCHA_XML_DESCRIPTION="<p>Prosta wtyczka CAPTCHA do ochrony przed spamem przy użyciu hCaptcha.com</p>
<ul>
<li>Autor: Peter Martin, <a href="_QQ_"https://data2site.com/"_QQ_" target="_QQ_"_blank"_QQ_">https://data2site.com/</a></li>
<li>Ta wtyczka korzysta z usługi CAPTCHA: <a href="_QQ_"https://www.hcaptcha.com/"_QQ_" target="_QQ_"_blank"_QQ_">https://www.hcaptcha.com/</a></li>
<li>Raporty o błędach & uzupełnienia: <a href="_QQ_"https://github.com/pe7er/hcaptcha"_QQ_" target="_QQ_"_blank"_QQ_">https://github.com/pe7er/hcaptcha</a></li>
</ul>"

View File

@ -0,0 +1,34 @@
; hCaptcha - CAPTCHA Plugin
; Copyright (C) Copyright 2020 - 2022 Peter Martin, https://db8.nl. All rights reserved.
; Copyright (C) Translation 2020 Mateusz Hajder
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8
PLG_CAPTCHA_HCAPTCHA="CAPTCHA - hCaptcha"
PLG_CAPTCHA_HCAPTCHA_XML_DESCRIPTION="<p>Prosta wtyczka CAPTCHA do ochrony przed spamem przy użyciu hCaptcha.com</p><ul><li>Autor: Peter Martin, <a href=\"https://data2site.com/\" target=\"_blank\">https://data2site.com/</a></li><li>Ta wtyczka korzysta z usługi CAPTCHA: <a href=\"https://www.hcaptcha.com/\" target=\"_blank\">https://www.hcaptcha.com/</a></li><li>Raporty o błędach & nowościach: <a href=\"https://github.com/pe7er/hcaptcha\" target=\"_blank\">https://github.com/pe7er/hcaptcha</a></li></ul>"
; Params
PLG_CAPTCHA_HCAPTCHA_PUBLIC_KEY="Klucz publiczny"
PLG_CAPTCHA_HCAPTCHA_PUBLIC_KEY_DESC="Klucz publiczny służy do identyfikacji witryny"
PLG_CAPTCHA_HCAPTCHA_PRIVATE_KEY="Klucz prywatny"
PLG_CAPTCHA_HCAPTCHA_PRIVATE_KEY_DESC="Klucz prywatny służy do weryfikacji twojego konta hCaptcha"
PLG_CAPTCHA_HCAPTCHA_THEME="Wygląd"
PLG_CAPTCHA_HCAPTCHA_THEME_LIGHT="Jasny"
PLG_CAPTCHA_HCAPTCHA_THEME_DARK="Ciemny"
PLG_CAPTCHA_HCAPTCHA_SIZE="Rozmiar"
PLG_CAPTCHA_HCAPTCHA_SIZE_NORMAL="Zwykły"
PLG_CAPTCHA_HCAPTCHA_SIZE_COMPACT="Kompaktowy"
; Privacy
PLG_CAPTCHA_HCAPTCHA_PRIVACY_CAPABILITY_IP_ADDRESS="Wtyczka hCaptcha integruje się z systemem CAPTCHA hcaptcha jako usługa ochrony przed spamem. W ramach tej usługi adres IP użytkownika biorącego udział w wyzwaniu captcha jest przesyłany do hcaptcha.com."
; Error messages
PLG_CAPTCHA_HCAPTCHA_ERROR_CANT_CONNECT_TO_HCAPTCHA_SERVERS="Nie można połączyć się z serwerami hcaptcha.com"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_PUBLIC_KEY="Brak Klucza Publicznego"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_PRIVATE_KEY="Brak Klucza Prywatnego"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_IP="Błąd: brak adresu IP"
PLG_CAPTCHA_HCAPTCHA_ERROR_EMPTY_SOLUTION="Proszę wypełnić CAPTCHA"
PLG_CAPTCHA_HCAPTCHA_ERROR_INCORRECT_CAPTCHA="CAPTCHA była niepoprawna"
PLG_CAPTCHA_HCAPTCHA_ERROR_INVALID_RESPONSE="Niepoprawna odpowiedź z hcaptcha.com"

View File

@ -0,0 +1,8 @@
; hCaptcha - CAPTCHA Plugin
; Copyright (C) Copyright 2020 - 2022 Peter Martin, https://db8.nl. All rights reserved.
; Copyright (C) Translation 2020 Mateusz Hajder
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8
PLG_CAPTCHA_HCAPTCHA="CAPTCHA - hCaptcha"
PLG_CAPTCHA_HCAPTCHA_XML_DESCRIPTION="<p>Prosta wtyczka CAPTCHA do ochrony przed spamem przy użyciu hCaptcha.com</p><ul><li>Autor: Peter Martin, <a href=\"https://data2site.com/\" target=\"_blank\">https://data2site.com/</a></li><li>Ta wtyczka korzysta z usługi CAPTCHA: <a href=\"https://www.hcaptcha.com/\" target=\"_blank\">https://www.hcaptcha.com/</a></li><li>Raporty o błędach & uzupełnienia: <a href=\"https://github.com/pe7er/hcaptcha\" target=\"_blank\">https://github.com/pe7er/hcaptcha</a></li></ul>"

View File

@ -0,0 +1,34 @@
; hCaptcha - CAPTCHA Plugin
; Copyright (C) Copyright 2020 - 2022 Peter Martin, https://db8.nl. All rights reserved.
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8
PLG_CAPTCHA_HCAPTCHA="CAPTCHA - hCaptcha"
PLG_CAPTCHA_HCAPTCHA_XML_DESCRIPTION="<p>HCaptcha.com kullanarak SPAM'a karşı koruma sağlayan basit bir CAPTCHA eklentisidir. Türkçe Çeviri: <a href="https://durualan.com" target="_blank"><b>Mehmet TAŞ</b></a></p><ul><li>Geliştiren: Peter Martin, <a href=\"https://data2site.com/\" target=\"_blank\">https://data2site.com/</a></li><li>Bu eklenti şu CAPTCHA hizmetini kullanıyor: <a href=\"https://www.hcaptcha.com/\" target=\"_blank\">https://www.hcaptcha.com/</a></li><li>Hata Raporları ve Eklemeler: <a href=\"https://github.com/pe7er/hcaptcha\" target=\"_blank\">https://github.com/pe7er/hcaptcha</a></li></ul>"
; Params
PLG_CAPTCHA_HCAPTCHA_PUBLIC_KEY="Site Anahtarı"
PLG_CAPTCHA_HCAPTCHA_PUBLIC_KEY_DESC="Site anahtarları, sitenizi benzersiz şekilde tanımlamak için kullanılır."
PLG_CAPTCHA_HCAPTCHA_PRIVATE_KEY="Gizli Anahtar"
PLG_CAPTCHA_HCAPTCHA_PRIVATE_KEY_DESC="hCaptcha hesabınızı doğrulamak için gizli bir anahtar kullanılır."
PLG_CAPTCHA_HCAPTCHA_THEME="Tema"
PLG_CAPTCHA_HCAPTCHA_THEME_LIGHT="Açık"
PLG_CAPTCHA_HCAPTCHA_THEME_DARK="Koyu"
PLG_CAPTCHA_HCAPTCHA_SIZE="Boyut"
PLG_CAPTCHA_HCAPTCHA_SIZE_DESC="Kullanmak istediğiniz şablonun boyut türünü seçin."
PLG_CAPTCHA_HCAPTCHA_SIZE_NORMAL="Normal"
PLG_CAPTCHA_HCAPTCHA_SIZE_COMPACT="Sıkışmış"
; Privacy
PLG_CAPTCHA_HCAPTCHA_PRIVACY_CAPABILITY_IP_ADDRESS="hCaptcha eklentisi, spam koruma hizmeti olarak hcaptcha'nın CAPTCHA sistemiyle tümleşiktir. Bu hizmetin bir parçası olarak, captcha sınamasını yanıtlayan kullanıcının IP adresi hcaptcha.com'a iletilir."
; Error messages
PLG_CAPTCHA_HCAPTCHA_ERROR_CANT_CONNECT_TO_HCAPTCHA_SERVERS="Hcaptcha.com sunucularına bağlanılamıyor"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_PUBLIC_KEY="Genel Anahtar (Site Anahtarı) eksik"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_PRIVATE_KEY="Özel Anahtar (Gizli Anahtar) eksik"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_IP="Hata: IP adresi yok"
PLG_CAPTCHA_HCAPTCHA_ERROR_EMPTY_SOLUTION="Lütfen CAPTCHA'yı tamamlayın"
PLG_CAPTCHA_HCAPTCHA_ERROR_INCORRECT_CAPTCHA="CAPTCHA geçersizdi"
PLG_CAPTCHA_HCAPTCHA_ERROR_INVALID_RESPONSE="Hcaptcha.com sitesinden geçersiz yanıt"

View File

@ -0,0 +1,7 @@
; hCaptcha - CAPTCHA Plugin
; Copyright (C) Copyright 2020 - 2022 Peter Martin. All rights reserved.
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8
PLG_CAPTCHA_HCAPTCHA="CAPTCHA - hCaptcha"
PLG_CAPTCHA_HCAPTCHA_XML_DESCRIPTION="<p>HCaptcha.com kullanarak SPAM'a karşı koruma sağlayan basit bir CAPTCHA eklentisidir. Türkçe Çeviri: <a href="https://durualan.com" target="_blank"><b>Mehmet TAŞ</b></a></p><ul><li>Geliştiren: Peter Martin, <a href=\"https://data2site.com/\" target=\"_blank\">https://data2site.com/</a></li><li>Bu eklenti şu CAPTCHA hizmetini kullanıyor: <a href=\"https://www.hcaptcha.com/\" target=\"_blank\">https://www.hcaptcha.com/</a></li><li>Hata Raporları ve Eklemeler: <a href=\"https://github.com/pe7er/hcaptcha\" target=\"_blank\">https://github.com/pe7er/hcaptcha</a></li></ul>"

View File

@ -0,0 +1,39 @@
; hCaptcha - CAPTCHA Plugin
; Copyright (C) Copyright 2020 - 2022 Peter Martin, https://db8.nl. All rights reserved.
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8
PLG_CAPTCHA_HCAPTCHA="CAPTCHA - hCaptcha"
PLG_CAPTCHA_HCAPTCHA_XML_DESCRIPTION="<p>HCaptcha.com kullanarak SPAM'a karşı koruma sağlayan basit bir CAPTCHA eklentisidir. Türkçe Çeviri: <a href="https://durualan.com" target="_blank"><b>Mehmet TAŞ</b></a></p>
<ul>
<li>Geliştiren: Peter Martin, <a href="_QQ_"https://data2site.com/"_QQ_" target="_QQ_"_blank"_QQ_">https://data2site.com/</a></li>
<li>Bu eklenti şu CAPTCHA hizmetini kullanıyor: <a href="_QQ_"https://www.hcaptcha.com/"_QQ_" target="_QQ_"_blank"_QQ_">https://www.hcaptcha.com/</a></li>
<li>Hata Raporları ve Eklemeler: <a href="_QQ_"https://github.com/pe7er/hcaptcha"_QQ_" target="_QQ_"_blank"_QQ_">https://github.com/pe7er/hcaptcha</a></li>
</ul>"
; Params
PLG_CAPTCHA_HCAPTCHA_PUBLIC_KEY="Site Anahtarı"
PLG_CAPTCHA_HCAPTCHA_PUBLIC_KEY_DESC="Site anahtarları, sitenizi benzersiz şekilde tanımlamak için kullanılır."
PLG_CAPTCHA_HCAPTCHA_PRIVATE_KEY="Gizli Anahtar"
PLG_CAPTCHA_HCAPTCHA_PRIVATE_KEY_DESC="hCaptcha hesabınızı doğrulamak için gizli bir anahtar kullanılır."
PLG_CAPTCHA_HCAPTCHA_THEME="Tema"
PLG_CAPTCHA_HCAPTCHA_THEME_LIGHT="Açık"
PLG_CAPTCHA_HCAPTCHA_THEME_DARK="Koyu"
PLG_CAPTCHA_HCAPTCHA_SIZE="Boyut"
PLG_CAPTCHA_HCAPTCHA_SIZE_DESC="Kullanmak istediğiniz şablonun boyut türünü seçin."
PLG_CAPTCHA_HCAPTCHA_SIZE_NORMAL="Normal"
PLG_CAPTCHA_HCAPTCHA_SIZE_COMPACT="Sıkışmış"
; Privacy
PLG_CAPTCHA_HCAPTCHA_PRIVACY_CAPABILITY_IP_ADDRESS="hCaptcha eklentisi, spam koruma hizmeti olarak hcaptcha'nın CAPTCHA sistemiyle tümleşiktir. Bu hizmetin bir parçası olarak, captcha sınamasını yanıtlayan kullanıcının IP adresi hcaptcha.com'a iletilir."
; Error messages
PLG_CAPTCHA_HCAPTCHA_ERROR_CANT_CONNECT_TO_HCAPTCHA_SERVERS="Hcaptcha.com sunucularına bağlanılamıyor"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_PUBLIC_KEY="Genel Anahtar (Site Anahtarı) eksik"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_PRIVATE_KEY="Özel Anahtar (Gizli Anahtar) eksik"
PLG_CAPTCHA_HCAPTCHA_ERROR_NO_IP="Hata: IP adresi yok"
PLG_CAPTCHA_HCAPTCHA_ERROR_EMPTY_SOLUTION="Lütfen CAPTCHA'yı tamamlayın"
PLG_CAPTCHA_HCAPTCHA_ERROR_INCORRECT_CAPTCHA="CAPTCHA geçersizdi"
PLG_CAPTCHA_HCAPTCHA_ERROR_INVALID_RESPONSE="Hcaptcha.com sitesinden geçersiz yanıt"

View File

@ -0,0 +1,12 @@
; hCaptcha - CAPTCHA Plugin
; Copyright (C) Copyright 2020 - 2022 Peter Martin. All rights reserved.
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8
PLG_CAPTCHA_HCAPTCHA="CAPTCHA - hCaptcha"
PLG_CAPTCHA_HCAPTCHA_XML_DESCRIPTION="<p>HCaptcha.com kullanarak SPAM'a karşı koruma sağlayan basit bir CAPTCHA eklentisidir. Türkçe Çeviri: <a href="https://durualan.com" target="_blank"><b>Mehmet TAŞ</b></a></p>
<ul>
<li>Geliştiren: Peter Martin, <a href="_QQ_"https://data2site.com/"_QQ_" target="_QQ_"_blank"_QQ_">https://data2site.com/</a></li>
<li>Bu eklenti şu CAPTCHA hizmetini kullanıyor: <a href="_QQ_"https://www.hcaptcha.com/"_QQ_" target="_QQ_"_blank"_QQ_">https://www.hcaptcha.com/</a></li>
<li>Hata Raporları ve Eklemeler: <a href="_QQ_"https://github.com/pe7er/hcaptcha"_QQ_" target="_QQ_"_blank"_QQ_">https://github.com/pe7er/hcaptcha</a></li>
</ul>"

View File

@ -0,0 +1 @@
<!DOCTYPE html><title></title>

View File

@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<extension type="plugin" group="captcha" method="upgrade">
<name>plg_captcha_recaptcha_invisible</name>
<version>3.8</version>
<creationDate>2017-11</creationDate>
<author>Joomla! Project</author>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<copyright>(C) 2017 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<description>PLG_CAPTCHA_RECAPTCHA_INVISIBLE_XML_DESCRIPTION</description>
<namespace path="src">Joomla\Plugin\Captcha\InvisibleReCaptcha</namespace>
<files>
<folder plugin="recaptcha_invisible">services</folder>
<folder>src</folder>
</files>
<languages>
<language tag="en-GB">language/en-GB/plg_captcha_recaptcha_invisible.ini</language>
<language tag="en-GB">language/en-GB/plg_captcha_recaptcha_invisible.sys.ini</language>
</languages>
<config>
<fields name="params">
<fieldset name="basic">
<field
name="public_key"
type="text"
label="PLG_RECAPTCHA_INVISIBLE_PUBLIC_KEY_LABEL"
description="PLG_RECAPTCHA_INVISIBLE_PUBLIC_KEY_DESC"
default=""
required="true"
filter="string"
class="input-xxlarge"
/>
<field
name="private_key"
type="text"
label="PLG_RECAPTCHA_INVISIBLE_PRIVATE_KEY_LABEL"
description="PLG_RECAPTCHA_INVISIBLE_PRIVATE_KEY_DESC"
default=""
required="true"
filter="string"
class="input-xxlarge"
/>
<field
name="badge"
type="list"
label="PLG_RECAPTCHA_INVISIBLE_BADGE_LABEL"
description="PLG_RECAPTCHA_INVISIBLE_BADGE_DESC"
default="bottomright"
validate="options"
>
<option value="bottomright">PLG_RECAPTCHA_INVISIBLE_BADGE_BOTTOMRIGHT</option>
<option value="bottomleft">PLG_RECAPTCHA_INVISIBLE_BADGE_BOTTOMLEFT</option>
<option value="inline">PLG_RECAPTCHA_INVISIBLE_BADGE_INLINE</option>
</field>
<field
name="tabindex"
type="number"
label="PLG_RECAPTCHA_INVISIBLE_TABINDEX_LABEL"
description="PLG_RECAPTCHA_INVISIBLE_TABINDEX_DESC"
default="0"
min="0"
filter="integer"
/>
<field
name="callback"
type="text"
label="PLG_RECAPTCHA_INVISIBLE_CALLBACK_LABEL"
description="PLG_RECAPTCHA_INVISIBLE_CALLBACK_DESC"
default=""
filter="string"
/>
<field
name="expired_callback"
type="text"
label="PLG_RECAPTCHA_INVISIBLE_EXPIRED_CALLBACK_LABEL"
description="PLG_RECAPTCHA_INVISIBLE_EXPIRED_CALLBACK_DESC"
default=""
filter="string"
/>
<field
name="error_callback"
type="text"
label="PLG_RECAPTCHA_INVISIBLE_ERROR_CALLBACK_LABEL"
description="PLG_RECAPTCHA_INVISIBLE_ERROR_CALLBACK_DESC"
default=""
filter="string"
/>
</fieldset>
</fields>
</config>
</extension>

View File

@ -0,0 +1,48 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage Captcha.invisible_recaptcha
*
* @copyright (C) 2022 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
use Joomla\CMS\Captcha\Google\HttpBridgePostRequestMethod;
use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use Joomla\Plugin\Captcha\InvisibleReCaptcha\Extension\InvisibleReCaptcha;
return new class () implements ServiceProviderInterface {
/**
* Registers the service provider with a DI container.
*
* @param Container $container The DI container.
*
* @return void
*
* @since 4.3.0
*/
public function register(Container $container)
{
$container->set(
PluginInterface::class,
function (Container $container) {
$plugin = new InvisibleReCaptcha(
$container->get(DispatcherInterface::class),
(array) PluginHelper::getPlugin('captcha', 'recaptcha_invisible'),
new HttpBridgePostRequestMethod()
);
$plugin->setApplication(Factory::getApplication());
return $plugin;
}
);
}
};

View File

@ -0,0 +1,227 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage Captcha.invisible_recaptcha
*
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\Captcha\InvisibleReCaptcha\Extension;
use Joomla\CMS\Application\CMSWebApplicationInterface;
use Joomla\CMS\Form\Field\CaptchaField;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\Event\DispatcherInterface;
use Joomla\Utilities\IpHelper;
use ReCaptcha\ReCaptcha;
use ReCaptcha\RequestMethod;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Invisible reCAPTCHA Plugin.
*
* @since 3.9.0
*/
final class InvisibleReCaptcha extends CMSPlugin
{
/**
* Load the language file on instantiation.
*
* @var boolean
* @since 3.9.0
*/
protected $autoloadLanguage = true;
/**
* The http request method
*
* @var RequestMethod
* @since 4.3.0
*/
private $requestMethod;
/**
* Constructor.
*
* @param DispatcherInterface $dispatcher The dispatcher
* @param array $config An optional associative array of configuration settings
* @param RequestMethod $requestMethod The http request method
*
* @since 4.3.0
*/
public function __construct(DispatcherInterface $dispatcher, array $config, RequestMethod $requestMethod)
{
parent::__construct($dispatcher, $config);
$this->requestMethod = $requestMethod;
}
/**
* Reports the privacy related capabilities for this plugin to site administrators.
*
* @return array
*
* @since 3.9.0
*/
public function onPrivacyCollectAdminCapabilities()
{
$this->loadLanguage();
return [
$this->getApplication()->getLanguage()->_('PLG_CAPTCHA_RECAPTCHA_INVISIBLE') => [
$this->getApplication()->getLanguage()->_('PLG_RECAPTCHA_INVISIBLE_PRIVACY_CAPABILITY_IP_ADDRESS'),
],
];
}
/**
* Initializes the captcha
*
* @param string $id The id of the field.
*
* @return boolean True on success, false otherwise
*
* @since 3.9.0
* @throws \RuntimeException
*/
public function onInit($id = 'dynamic_recaptcha_invisible_1')
{
$app = $this->getApplication();
if (!$app instanceof CMSWebApplicationInterface) {
return false;
}
$pubkey = $this->params->get('public_key', '');
if ($pubkey === '') {
throw new \RuntimeException($app->getLanguage()->_('PLG_RECAPTCHA_INVISIBLE_ERROR_NO_PUBLIC_KEY'));
}
$apiSrc = 'https://www.google.com/recaptcha/api.js?onload=JoomlainitReCaptchaInvisible&render=explicit&hl='
. $app->getLanguage()->getTag();
// Load assets, the callback should be first
$app->getDocument()->getWebAssetManager()
->registerAndUseScript('plg_captcha_recaptchainvisible', 'plg_captcha_recaptcha_invisible/recaptcha.min.js', [], ['defer' => true])
->registerAndUseScript('plg_captcha_recaptchainvisible.api', $apiSrc, [], ['defer' => true], ['plg_captcha_recaptchainvisible'])
->registerAndUseStyle('plg_captcha_recaptchainvisible', 'plg_captcha_recaptcha_invisible/recaptcha_invisible.css');
return true;
}
/**
* Gets the challenge HTML
*
* @param string $name The name of the field. Not Used.
* @param string $id The id of the field.
* @param string $class The class of the field.
*
* @return string The HTML to be embedded in the form.
*
* @since 3.9.0
*/
public function onDisplay($name = null, $id = 'dynamic_recaptcha_invisible_1', $class = '')
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$ele = $dom->createElement('div');
$ele->setAttribute('id', $id);
$ele->setAttribute('class', ((trim($class) == '') ? 'g-recaptcha' : ($class . ' g-recaptcha')));
$ele->setAttribute('data-sitekey', $this->params->get('public_key', ''));
$ele->setAttribute('data-badge', $this->params->get('badge', 'bottomright'));
$ele->setAttribute('data-size', 'invisible');
$ele->setAttribute('data-tabindex', $this->params->get('tabindex', '0'));
$ele->setAttribute('data-callback', $this->params->get('callback', ''));
$ele->setAttribute('data-expired-callback', $this->params->get('expired_callback', ''));
$ele->setAttribute('data-error-callback', $this->params->get('error_callback', ''));
$dom->appendChild($ele);
return $dom->saveHTML($ele);
}
/**
* Calls an HTTP POST function to verify if the user's guess was correct
*
* @param string $code Answer provided by user. Not needed for the Recaptcha implementation
*
* @return boolean True if the answer is correct, false otherwise
*
* @since 3.9.0
* @throws \RuntimeException
*/
public function onCheckAnswer($code = null)
{
$input = $this->getApplication()->getInput();
$privatekey = $this->params->get('private_key');
$remoteip = IpHelper::getIp();
$response = $input->get('g-recaptcha-response', '', 'string');
// Check for Private Key
if (empty($privatekey)) {
throw new \RuntimeException($this->getApplication()->getLanguage()->_('PLG_RECAPTCHA_INVISIBLE_ERROR_NO_PRIVATE_KEY'));
}
// Check for IP
if (empty($remoteip)) {
throw new \RuntimeException($this->getApplication()->getLanguage()->_('PLG_RECAPTCHA_INVISIBLE_ERROR_NO_IP'));
}
// Discard spam submissions
if (trim($response) == '') {
throw new \RuntimeException($this->getApplication()->getLanguage()->_('PLG_RECAPTCHA_INVISIBLE_ERROR_EMPTY_SOLUTION'));
}
return $this->getResponse($privatekey, $remoteip, $response);
}
/**
* Method to react on the setup of a captcha field. Gives the possibility
* to change the field and/or the XML element for the field.
*
* @param CaptchaField $field Captcha field instance
* @param \SimpleXMLElement $element XML form definition
*
* @return void
*
* @since 3.9.0
*/
public function onSetupField(CaptchaField $field, \SimpleXMLElement $element)
{
// Hide the label for the invisible recaptcha type
$element['hiddenLabel'] = 'true';
}
/**
* Get the reCaptcha response.
*
* @param string $privatekey The private key for authentication.
* @param string $remoteip The remote IP of the visitor.
* @param string $response The response received from Google.
*
* @return boolean True if response is good | False if response is bad.
*
* @since 3.9.0
* @throws \RuntimeException
*/
private function getResponse($privatekey, $remoteip, $response)
{
$reCaptcha = new ReCaptcha($privatekey, $this->requestMethod);
$response = $reCaptcha->verify($response, $remoteip);
if (!$response->isSuccess()) {
foreach ($response->getErrorCodes() as $error) {
throw new \RuntimeException($error);
}
return false;
}
return true;
}
}

View File

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="UTF-8"?>
<extension type="plugin" group="content" method="upgrade">
<name>plg_content_confirmconsent</name>
<author>Joomla! Project</author>
<creationDate>2018-05</creationDate>
<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>3.9.0</version>
<description>PLG_CONTENT_CONFIRMCONSENT_XML_DESCRIPTION</description>
<namespace path="src">Joomla\Plugin\Content\ConfirmConsent</namespace>
<files>
<folder plugin="confirmconsent">services</folder>
<folder>src</folder>
</files>
<languages>
<language tag="en-GB">language/en-GB/plg_content_confirmconsent.ini</language>
<language tag="en-GB">language/en-GB/plg_content_confirmconsent.sys.ini</language>
</languages>
<config>
<fields name="params">
<fieldset name="basic" addfieldprefix="Joomla\Component\Content\Administrator\Field">
<field
name="consentbox_text"
type="textarea"
label="PLG_CONTENT_CONFIRMCONSENT_FIELD_NOTE_LABEL"
description="PLG_CONTENT_CONFIRMCONSENT_FIELD_NOTE_DESC"
hint="PLG_CONTENT_CONFIRMCONSENT_FIELD_NOTE_DEFAULT"
rows="7"
cols="20"
filter="html"
/>
<field
name="privacy_type"
type="list"
label="PLG_CONTENT_CONFIRMCONSENT_FIELD_TYPE_LABEL"
default="article"
validate="options"
>
<option value="article">PLG_CONTENT_CONFIRMCONSENT_FIELD_TYPE_ARTICLE</option>
<option value="menu_item">PLG_CONTENT_CONFIRMCONSENT_FIELD_TYPE_MENU_ITEM</option>
</field>
<field
name="privacy_article"
type="modal_article"
label="PLG_CONTENT_CONFIRMCONSENT_FIELD_ARTICLE_LABEL"
description="PLG_CONTENT_CONFIRMCONSENT_FIELD_ARTICLE_DESC"
select="true"
new="true"
edit="true"
clear="true"
filter="integer"
showon="privacy_type:article"
/>
<field
addfieldprefix="Joomla\Component\Menus\Administrator\Field"
name="privacy_menu_item"
type="modal_menu"
label="PLG_CONTENT_CONFIRMCONSENT_FIELD_MENU_ITEM_LABEL"
select="true"
new="true"
edit="true"
clear="true"
filter="integer"
showon="privacy_type:menu_item"
/>
</fieldset>
</fields>
</config>
</extension>

View File

@ -0,0 +1,46 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage Content.confirmconsent
*
* @copyright (C) 2022 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
\defined('_JEXEC') or die;
use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use Joomla\Plugin\Content\ConfirmConsent\Extension\ConfirmConsent;
return new class () implements ServiceProviderInterface {
/**
* Registers the service provider with a DI container.
*
* @param Container $container The DI container.
*
* @return void
*
* @since 4.3.0
*/
public function register(Container $container)
{
$container->set(
PluginInterface::class,
function (Container $container) {
$plugin = new ConfirmConsent(
$container->get(DispatcherInterface::class),
(array) PluginHelper::getPlugin('content', 'confirmconsent')
);
$plugin->setApplication(Factory::getApplication());
return $plugin;
}
);
}
};

View File

@ -0,0 +1,92 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage Content.confirmconsent
*
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\Content\ConfirmConsent\Extension;
use Joomla\CMS\Form\Form;
use Joomla\CMS\Plugin\CMSPlugin;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The Joomla Core confirm consent plugin
*
* @since 3.9.0
*/
final class ConfirmConsent extends CMSPlugin
{
/**
* Load the language file on instantiation.
*
* @var boolean
*
* @since 3.9.0
*/
protected $autoloadLanguage = true;
/**
* The supported form contexts
*
* @var array
*
* @since 3.9.0
*/
protected $supportedContext = [
'com_contact.contact',
'com_privacy.request',
];
/**
* Add additional fields to the supported forms
*
* @param Form $form The form to be altered.
* @param mixed $data The associated data for the form.
*
* @return boolean
*
* @since 3.9.0
*/
public function onContentPrepareForm(Form $form, $data)
{
if ($this->getApplication()->isClient('administrator') || !\in_array($form->getName(), $this->supportedContext)) {
return true;
}
// Get the consent box Text & the selected privacyarticle
$consentboxText = (string) $this->params->get(
'consentbox_text',
$this->getApplication()->getLanguage()->_('PLG_CONTENT_CONFIRMCONSENT_FIELD_NOTE_DEFAULT')
);
$privacyArticle = $this->params->get('privacy_article', false);
$privacyType = $this->params->get('privacy_type', 'article');
$privacyMenuItem = $this->params->get('privacy_menu_item', false);
$form->load('
<form>
<fieldset name="default" addfieldprefix="Joomla\\Plugin\\Content\\ConfirmConsent\\Field">
<field
name="consentbox"
type="ConsentBox"
articleid="' . $privacyArticle . '"
menu_item_id="' . $privacyMenuItem . '"
privacy_type="' . $privacyType . '"
label="PLG_CONTENT_CONFIRMCONSENT_CONSENTBOX_LABEL"
required="true"
>
<option value="0">' . htmlspecialchars($consentboxText, ENT_COMPAT, 'UTF-8') . '</option>
</field>
</fieldset>
</form>');
return true;
}
}

View File

@ -0,0 +1,339 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage Content.confirmconsent
*
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\Content\ConfirmConsent\Field;
use Joomla\CMS\Factory;
use Joomla\CMS\Form\Field\CheckboxesField;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Associations;
use Joomla\CMS\Language\Multilanguage;
use Joomla\CMS\Router\Route;
use Joomla\Component\Content\Site\Helper\RouteHelper;
use Joomla\Database\Exception\ExecutionFailureException;
use Joomla\Database\ParameterType;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Consentbox Field class for the Confirm Consent Plugin.
*
* @since 3.9.1
*/
class ConsentBoxField extends CheckboxesField
{
/**
* The form field type.
*
* @var string
* @since 3.9.1
*/
protected $type = 'ConsentBox';
/**
* Flag to tell the field to always be in multiple values mode.
*
* @var boolean
* @since 3.9.1
*/
protected $forceMultiple = false;
/**
* The article ID.
*
* @var integer
* @since 3.9.1
*/
protected $articleid;
/**
* The menu item ID.
*
* @var integer
* @since 4.0.0
*/
protected $menuItemId;
/**
* Type of the privacy policy.
*
* @var string
* @since 4.0.0
*/
protected $privacyType;
/**
* Method to set certain otherwise inaccessible properties of the form field object.
*
* @param string $name The property name for which to set the value.
* @param mixed $value The value of the property.
*
* @return void
*
* @since 3.9.1
*/
public function __set($name, $value)
{
switch ($name) {
case 'articleid':
$this->articleid = (int) $value;
break;
default:
parent::__set($name, $value);
}
}
/**
* Method to get certain otherwise inaccessible properties from the form field object.
*
* @param string $name The property name for which to get the value.
*
* @return mixed The property value or null.
*
* @since 3.9.1
*/
public function __get($name)
{
if ($name == 'articleid') {
return $this->$name;
}
return parent::__get($name);
}
/**
* Method to attach a Form object to the field.
*
* @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object.
* @param mixed $value The form field value to validate.
* @param string $group The field name group control value. This acts as an array container for the field.
* For example if the field has name="foo" and the group value is set to "bar" then the
* full field name would end up being "bar[foo]".
*
* @return boolean True on success.
*
* @see \Joomla\CMS\Form\FormField::setup()
* @since 3.9.1
*/
public function setup(\SimpleXMLElement $element, $value, $group = null)
{
$return = parent::setup($element, $value, $group);
if ($return) {
$this->articleid = (int) $this->element['articleid'];
$this->menuItemId = (int) $this->element['menu_item_id'];
$this->privacyType = (string) $this->element['privacy_type'];
}
return $return;
}
/**
* Method to get the field label markup.
*
* @return string The field label markup.
*
* @since 3.9.1
*/
protected function getLabel()
{
if ($this->hidden) {
return '';
}
$data = $this->getLayoutData();
// Forcing the Alias field to display the tip below
$position = $this->element['name'] == 'alias' ? ' data-bs-placement="bottom" ' : '';
// When we have an article let's add the modal and make the title clickable
$hasLink = ($data['privacyType'] === 'article' && $data['articleid'])
|| ($data['privacyType'] === 'menu_item' && $data['menuItemId']);
if ($hasLink) {
$attribs['data-bs-toggle'] = 'modal';
$data['label'] = HTMLHelper::_(
'link',
'#modal-' . $this->id,
$data['label'],
$attribs
);
}
// Here mainly for B/C with old layouts. This can be done in the layouts directly
$extraData = [
'text' => $data['label'],
'for' => $this->id,
'classes' => explode(' ', $data['labelclass']),
'position' => $position,
];
return $this->getRenderer($this->renderLabelLayout)->render(array_merge($data, $extraData));
}
/**
* Method to get the field input markup.
*
* @return string The field input markup.
*
* @since 4.0.0
*/
protected function getInput()
{
$modalHtml = '';
$layoutData = $this->getLayoutData();
$hasLink = ($this->privacyType === 'article' && $this->articleid)
|| ($this->privacyType === 'menu_item' && $this->menuItemId);
if ($hasLink) {
$modalParams['title'] = $layoutData['label'];
$modalParams['url'] = ($this->privacyType === 'menu_item') ? $this->getAssignedMenuItemUrl() : $this->getAssignedArticleUrl();
$modalParams['height'] = '100%';
$modalParams['width'] = '100%';
$modalParams['bodyHeight'] = 70;
$modalParams['modalWidth'] = 80;
$modalHtml = HTMLHelper::_('bootstrap.renderModal', 'modal-' . $this->id, $modalParams);
}
return $modalHtml . parent::getInput();
}
/**
* Method to get the data to be passed to the layout for rendering.
*
* @return array
*
* @since 3.9.1
*/
protected function getLayoutData()
{
$data = parent::getLayoutData();
$extraData = [
'articleid' => (int) $this->articleid,
'menuItemId' => (int) $this->menuItemId,
'privacyType' => (string) $this->privacyType,
];
return array_merge($data, $extraData);
}
/**
* Return the url of the assigned article based on the current user language
*
* @return string Returns the link to the article
*
* @since 3.9.1
*/
private function getAssignedArticleUrl()
{
$db = $this->getDatabase();
// Get the info from the article
$query = $db->getQuery(true)
->select($db->quoteName(['id', 'catid', 'language']))
->from($db->quoteName('#__content'))
->where($db->quoteName('id') . ' = ' . (int) $this->articleid);
$db->setQuery($query);
try {
$article = $db->loadObject();
} catch (ExecutionFailureException $e) {
// Something at the database layer went wrong
return Route::_(
'index.php?option=com_content&view=article&id='
. $this->articleid . '&tmpl=component'
);
}
if (!\is_object($article)) {
// We have not found the article object lets show a 404 to the user
return Route::_(
'index.php?option=com_content&view=article&id='
. $this->articleid . '&tmpl=component'
);
}
if (!Associations::isEnabled()) {
return Route::_(
RouteHelper::getArticleRoute(
$article->id,
$article->catid,
$article->language
) . '&tmpl=component'
);
}
$associatedArticles = Associations::getAssociations('com_content', '#__content', 'com_content.item', $article->id);
$currentLang = Factory::getLanguage()->getTag();
if (isset($associatedArticles) && $currentLang !== $article->language && \array_key_exists($currentLang, $associatedArticles)) {
return Route::_(
RouteHelper::getArticleRoute(
$associatedArticles[$currentLang]->id,
$associatedArticles[$currentLang]->catid,
$associatedArticles[$currentLang]->language
) . '&tmpl=component'
);
}
// Association is enabled but this article is not associated
return Route::_(
'index.php?option=com_content&view=article&id='
. $article->id . '&catid=' . $article->catid
. '&tmpl=component&lang=' . $article->language
);
}
/**
* Get privacy menu item URL. If the site is a multilingual website and there is associated menu item for the
* current language, the URL of the associated menu item will be returned.
*
* @return string
*
* @since 4.0.0
*/
private function getAssignedMenuItemUrl()
{
$itemId = $this->menuItemId;
$languageSuffix = '';
if ($itemId > 0 && Associations::isEnabled()) {
$privacyAssociated = Associations::getAssociations('com_menus', '#__menu', 'com_menus.item', $itemId, 'id', '', '');
$currentLang = Factory::getLanguage()->getTag();
if (isset($privacyAssociated[$currentLang])) {
$itemId = $privacyAssociated[$currentLang]->id;
}
if (Multilanguage::isEnabled()) {
$db = $this->getDatabase();
$query = $db->getQuery(true)
->select($db->quoteName(['id', 'language']))
->from($db->quoteName('#__menu'))
->where($db->quoteName('id') . ' = :id')
->bind(':id', $itemId, ParameterType::INTEGER);
$db->setQuery($query);
$menuItem = $db->loadObject();
$languageSuffix = '&lang=' . $menuItem->language;
}
}
return Route::_(
'index.php?Itemid=' . (int) $itemId . '&tmpl=component' . $languageSuffix
);
}
}

View File

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<extension type="plugin" group="content" method="upgrade">
<name>plg_content_contact</name>
<author>Joomla! Project</author>
<creationDate>2014-01</creationDate>
<copyright>(C) 2014 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>3.2.2</version>
<description>PLG_CONTENT_CONTACT_XML_DESCRIPTION</description>
<namespace path="src">Joomla\Plugin\Content\Contact</namespace>
<files>
<folder plugin="contact">services</folder>
<folder>src</folder>
</files>
<languages>
<language tag="en-GB">language/en-GB/plg_content_contact.ini</language>
<language tag="en-GB">language/en-GB/plg_content_contact.sys.ini</language>
</languages>
<config>
<fields name="params">
<fieldset name="basic">
<field
name="url"
type="list"
label="PLG_CONTENT_CONTACT_PARAM_URL_LABEL"
description="PLG_CONTENT_CONTACT_PARAM_URL_DESCRIPTION"
default="url"
validate="options"
>
<option value="url">PLG_CONTENT_CONTACT_PARAM_URL_URL</option>
<option value="webpage">PLG_CONTENT_CONTACT_PARAM_URL_WEBPAGE</option>
<option value="email">PLG_CONTENT_CONTACT_PARAM_URL_EMAIL</option>
</field>
<field
name="link_to_alias"
type="radio"
label="PLG_CONTENT_CONTACT_PARAM_ALIAS_LABEL"
description="PLG_CONTENT_CONTACT_PARAM_ALIAS_DESCRIPTION"
default="0"
layout="joomla.form.field.radio.switcher"
filter="integer"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
</fieldset>
</fields>
</config>
</extension>

View File

@ -0,0 +1,48 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage Content.contact
*
* @copyright (C) 2022 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
\defined('_JEXEC') or die;
use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\Database\DatabaseInterface;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use Joomla\Plugin\Content\Contact\Extension\Contact;
return new class () implements ServiceProviderInterface {
/**
* Registers the service provider with a DI container.
*
* @param Container $container The DI container.
*
* @return void
*
* @since 4.3.0
*/
public function register(Container $container)
{
$container->set(
PluginInterface::class,
function (Container $container) {
$plugin = new Contact(
$container->get(DispatcherInterface::class),
(array) PluginHelper::getPlugin('content', 'contact')
);
$plugin->setApplication(Factory::getApplication());
$plugin->setDatabase($container->get(DatabaseInterface::class));
return $plugin;
}
);
}
};

View File

@ -0,0 +1,146 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage Content.contact
*
* @copyright (C) 2014 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\Content\Contact\Extension;
use Joomla\CMS\Language\Multilanguage;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Router\Route;
use Joomla\Component\Contact\Site\Helper\RouteHelper;
use Joomla\Database\DatabaseAwareTrait;
use Joomla\Database\ParameterType;
use Joomla\Registry\Registry;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Contact Plugin
*
* @since 3.2
*/
final class Contact extends CMSPlugin
{
use DatabaseAwareTrait;
/**
* Plugin that retrieves contact information for contact
*
* @param string $context The context of the content being passed to the plugin.
* @param mixed &$row An object with a "text" property
* @param mixed $params Additional parameters. See {@see PlgContentContent()}.
* @param integer $page Optional page number. Unused. Defaults to zero.
*
* @return void
*/
public function onContentPrepare($context, &$row, $params, $page = 0)
{
$allowed_contexts = ['com_content.category', 'com_content.article', 'com_content.featured'];
if (!\in_array($context, $allowed_contexts)) {
return;
}
// Return if we don't have valid params or don't link the author
if (!($params instanceof Registry) || !$params->get('link_author')) {
return;
}
// Return if an alias is used
if ((int) $this->params->get('link_to_alias', 0) === 0 && $row->created_by_alias != '') {
return;
}
// Return if we don't have a valid article id
if (!isset($row->id) || !(int) $row->id) {
return;
}
$contact = $this->getContactData($row->created_by);
if ($contact === null) {
return;
}
$row->contactid = $contact->contactid;
$row->webpage = $contact->webpage;
$row->email = $contact->email_to;
$url = $this->params->get('url', 'url');
if ($row->contactid && $url === 'url') {
$row->contact_link = Route::_(RouteHelper::getContactRoute($contact->contactid . ':' . $contact->alias, $contact->catid));
} elseif ($row->webpage && $url === 'webpage') {
$row->contact_link = $row->webpage;
} elseif ($row->email && $url === 'email') {
$row->contact_link = 'mailto:' . $row->email;
} else {
$row->contact_link = '';
}
}
/**
* Retrieve Contact
*
* @param int $userId Id of the user who created the article
*
* @return \stdClass|null Object containing contact details or null if not found
*/
private function getContactData($userId)
{
static $contacts = [];
// Note: don't use isset() because value could be null.
if (\array_key_exists($userId, $contacts)) {
return $contacts[$userId];
}
$db = $this->getDatabase();
$query = $db->getQuery(true);
$userId = (int) $userId;
$query->select($db->quoteName('contact.id', 'contactid'))
->select(
$db->quoteName(
[
'contact.alias',
'contact.catid',
'contact.webpage',
'contact.email_to',
]
)
)
->from($db->quoteName('#__contact_details', 'contact'))
->where(
[
$db->quoteName('contact.published') . ' = 1',
$db->quoteName('contact.user_id') . ' = :createdby',
]
)
->bind(':createdby', $userId, ParameterType::INTEGER);
if (Multilanguage::isEnabled() === true) {
$query->where(
'(' . $db->quoteName('contact.language') . ' IN ('
. implode(',', $query->bindArray([$this->getApplication()->getLanguage()->getTag(), '*'], ParameterType::STRING))
. ') OR ' . $db->quoteName('contact.language') . ' IS NULL)'
);
}
$query->order($db->quoteName('contact.id') . ' DESC')
->setLimit(1);
$db->setQuery($query);
$contacts[$userId] = $db->loadObject();
return $contacts[$userId];
}
}

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<extension type="plugin" group="content" method="upgrade">
<name>plg_content_emailcloak</name>
<author>Joomla! Project</author>
<creationDate>2005-11</creationDate>
<copyright>(C) 2005 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>3.0.0</version>
<description>PLG_CONTENT_EMAILCLOAK_XML_DESCRIPTION</description>
<namespace path="src">Joomla\Plugin\Content\EmailCloak</namespace>
<files>
<folder plugin="emailcloak">services</folder>
<folder>src</folder>
</files>
<languages>
<language tag="en-GB">language/en-GB/plg_content_emailcloak.ini</language>
<language tag="en-GB">language/en-GB/plg_content_emailcloak.sys.ini</language>
</languages>
<config>
<fields name="params">
<fieldset name="basic">
<field
name="mode"
type="list"
label="PLG_CONTENT_EMAILCLOAK_MODE_LABEL"
default="1"
filter="integer"
validate="options"
>
<option value="0">PLG_CONTENT_EMAILCLOAK_NONLINKABLE</option>
<option value="1">PLG_CONTENT_EMAILCLOAK_LINKABLE</option>
</field>
</fieldset>
</fields>
</config>
</extension>

View File

@ -0,0 +1,46 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage Content.emailcloak
*
* @copyright (C) 2022 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
\defined('_JEXEC') or die;
use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use Joomla\Plugin\Content\EmailCloak\Extension\EmailCloak;
return new class () implements ServiceProviderInterface {
/**
* Registers the service provider with a DI container.
*
* @param Container $container The DI container.
*
* @return void
*
* @since 4.3.0
*/
public function register(Container $container)
{
$container->set(
PluginInterface::class,
function (Container $container) {
$plugin = new EmailCloak(
$container->get(DispatcherInterface::class),
(array) PluginHelper::getPlugin('content', 'emailcloak')
);
$plugin->setApplication(Factory::getApplication());
return $plugin;
}
);
}
};

View File

@ -0,0 +1,494 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage Content.emailcloak
*
* @copyright (C) 2006 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\Content\EmailCloak\Extension;
use Joomla\CMS\Event\Content\ContentPrepareEvent;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\Event\SubscriberInterface;
use Joomla\String\StringHelper;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Email cloak plugin class.
*
* @since 1.5
*/
final class EmailCloak extends CMSPlugin implements SubscriberInterface
{
/**
* Returns an array of events this subscriber will listen to.
*
* @return array
*
* @since 5.0.0
*/
public static function getSubscribedEvents(): array
{
return ['onContentPrepare' => 'onContentPrepare'];
}
/**
* Plugin that cloaks all emails in content from spambots via Javascript.
*
* @param ContentPrepareEvent $event Event instance
*
* @return void
*/
public function onContentPrepare(ContentPrepareEvent $event)
{
// Don't run if in the API Application
// Don't run this plugin when the content is being indexed
if ($this->getApplication()->isClient('api') || $event->getContext() === 'com_finder.indexer') {
return;
}
// Get content item
$item = $event->getItem();
// If the item does not have a text property there is nothing to do
if (!isset($item->text)) {
return;
}
$text = $this->cloak($item->text);
if ($text) {
$item->text = $text;
}
}
/**
* Generate a search pattern based on link and text.
*
* @param string $link The target of an email link.
* @param string $text The text enclosed by the link.
*
* @return string A regular expression that matches a link containing the parameters.
*/
private function getPattern($link, $text)
{
$pattern = '~(?:<a ([^>]*)href\s*=\s*"mailto:' . $link . '"([^>]*))>' . $text . '</a>~i';
return $pattern;
}
/**
* Cloak all emails in text from spambots via Javascript.
*
* @param string $text The string to be cloaked.
*
* @return string
*/
private function cloak($text)
{
/*
* Check for presence of {emailcloak=off} which is explicits disables this
* bot for the item.
*/
if (StringHelper::strpos($text, '{emailcloak=off}') !== false) {
return StringHelper::str_ireplace('{emailcloak=off}', '', $text);
}
// Simple performance check to determine whether bot should process further.
if (StringHelper::strpos($text, '@') === false) {
return '';
}
$mode = (int) $this->params->def('mode', 1);
$mode = $mode === 1;
// Example: any@example.org
$searchEmail = '([\w\.\'\-\+]+\@(?:[a-z0-9\.\-]+\.)+(?:[a-zA-Z0-9\-]{2,24}))';
// Example: any@example.org?subject=anyText
$searchEmailLink = $searchEmail . '([?&][\x20-\x7f][^"<>]+)';
// Any Text
$searchText = '((?:[\x20-\x7f]|[\xA1-\xFF]|[\xC2-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF4][\x80-\xBF]{3})[^<>]+)';
// Any Image link
$searchImage = '(<img[^>]+>)';
// Any Text with <span or <strong
$searchTextSpan = '(<span[^>]+>|<span>|<strong>|<strong><span[^>]+>|<strong><span>)' . $searchText . '(</span>|</strong>|</span></strong>)';
// Any address with <span or <strong
$searchEmailSpan = '(<span[^>]+>|<span>|<strong>|<strong><span[^>]+>|<strong><span>)' . $searchEmail . '(</span>|</strong>|</span></strong>)';
/*
* Search and fix derivatives of link code <a href="http://mce_host/ourdirectory/email@example.org"
* >email@example.org</a>. This happens when inserting an email in TinyMCE, cancelling its suggestion to add
* the mailto: prefix...
*/
$pattern = $this->getPattern($searchEmail, $searchEmail);
$pattern = str_replace('"mailto:', '"([\x20-\x7f][^<>]+/)', $pattern);
while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) {
$mail = $regs[3][0];
$mailText = $regs[5][0];
$attribsBefore = $regs[1][0];
$attribsAfter = $regs[4][0];
// Check to see if mail text is different from mail addy
$replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 1, $attribsBefore, $attribsAfter);
// Replace the found address with the js cloaked email
$text = substr_replace($text, $replacement, $regs[0][1], \strlen($regs[0][0]));
}
/*
* Search and fix derivatives of link code <a href="http://mce_host/ourdirectory/email@example.org"
* >anytext</a>. This happens when inserting an email in TinyMCE, cancelling its suggestion to add
* the mailto: prefix...
*/
$pattern = $this->getPattern($searchEmail, $searchText);
$pattern = str_replace('"mailto:', '"([\x20-\x7f][^<>]+/)', $pattern);
while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) {
$mail = $regs[3][0];
$mailText = $regs[5][0];
$attribsBefore = $regs[1][0];
$attribsAfter = $regs[4][0];
// Check to see if mail text is different from mail addy
$replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 0, $attribsBefore, $attribsAfter);
// Replace the found address with the js cloaked email
$text = substr_replace($text, $replacement, $regs[0][1], \strlen($regs[0][0]));
}
/*
* Search for derivatives of link code <a href="mailto:email@example.org"
* >email@example.org</a>
*/
$pattern = $this->getPattern($searchEmail, $searchEmail);
while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) {
$mail = $regs[2][0];
$mailText = $regs[4][0];
$attribsBefore = $regs[1][0];
$attribsAfter = $regs[3][0];
// Check to see if mail text is different from mail addy
$replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 1, $attribsBefore, $attribsAfter);
// Replace the found address with the js cloaked email
$text = substr_replace($text, $replacement, $regs[0][1], \strlen($regs[0][0]));
}
/*
* Search for derivatives of link code <a href="mailto:email@amail.com"
* ><anyspan >email@amail.com</anyspan></a>
*/
$pattern = $this->getPattern($searchEmail, $searchEmailSpan);
while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) {
$mail = $regs[2][0];
$mailText = $regs[4][0] . $regs[5][0] . $regs[6][0];
$attribsBefore = $regs[1][0];
$attribsAfter = $regs[3][0];
// Check to see if mail text is different from mail addy
$replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 1, $attribsBefore, $attribsAfter);
// Replace the found address with the js cloaked email
$text = substr_replace($text, $replacement, $regs[0][1], \strlen($regs[0][0]));
}
/*
* Search for derivatives of link code <a href="mailto:email@amail.com">
* <anyspan >anytext</anyspan></a>
*/
$pattern = $this->getPattern($searchEmail, $searchTextSpan);
while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) {
$mail = $regs[2][0];
$mailText = $regs[4][0] . $regs[5][0] . $regs[6][0];
$attribsBefore = $regs[1][0];
$attribsAfter = $regs[3][0];
$replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 0, $attribsBefore, $attribsAfter);
// Replace the found address with the js cloaked email
$text = substr_replace($text, $replacement, $regs[0][1], \strlen($regs[0][0]));
}
/*
* Search for derivatives of link code <a href="mailto:email@example.org">
* anytext</a>
*/
$pattern = $this->getPattern($searchEmail, $searchText);
while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) {
$mail = $regs[2][0];
$mailText = $regs[4][0];
$attribsBefore = $regs[1][0];
$attribsAfter = $regs[3][0];
$replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 0, $attribsBefore, $attribsAfter);
// Replace the found address with the js cloaked email
$text = substr_replace($text, $replacement, $regs[0][1], \strlen($regs[0][0]));
}
/*
* Search for derivatives of link code <a href="mailto:email@example.org">
* <img anything></a>
*/
$pattern = $this->getPattern($searchEmail, $searchImage);
while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) {
$mail = $regs[2][0];
$mailText = $regs[4][0];
$attribsBefore = $regs[1][0];
$attribsAfter = $regs[3][0];
$replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 0, $attribsBefore, $attribsAfter);
// Replace the found address with the js cloaked email
$text = substr_replace($text, $replacement, $regs[0][1], \strlen($regs[0][0]));
}
/*
* Search for derivatives of link code <a href="mailto:email@example.org">
* <img anything>email@example.org</a>
*/
$pattern = $this->getPattern($searchEmail, $searchImage . $searchEmail);
while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) {
$mail = $regs[2][0];
$mailText = $regs[4][0] . $regs[5][0];
$attribsBefore = $regs[1][0];
$attribsAfter = $regs[3][0];
$replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 1, $attribsBefore, $attribsAfter);
// Replace the found address with the js cloaked email
$text = substr_replace($text, $replacement, $regs[0][1], \strlen($regs[0][0]));
}
/*
* Search for derivatives of link code <a href="mailto:email@example.org">
* <img anything>any text</a>
*/
$pattern = $this->getPattern($searchEmail, $searchImage . $searchText);
while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) {
$mail = $regs[2][0];
$mailText = $regs[4][0] . $regs[5][0];
$attribsBefore = $regs[1][0];
$attribsAfter = $regs[3][0];
$replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 0, $attribsBefore, $attribsAfter);
// Replace the found address with the js cloaked email
$text = substr_replace($text, $replacement, $regs[0][1], \strlen($regs[0][0]));
}
/*
* Search for derivatives of link code <a href="mailto:email@example.org?
* subject=Text">email@example.org</a>
*/
$pattern = $this->getPattern($searchEmailLink, $searchEmail);
while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) {
$mail = $regs[2][0] . $regs[3][0];
$mailText = $regs[5][0];
$attribsBefore = $regs[1][0];
$attribsAfter = $regs[4][0];
// Needed for handling of Body parameter
$mail = str_replace('&amp;', '&', $mail);
// Check to see if mail text is different from mail addy
$replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 1, $attribsBefore, $attribsAfter);
// Replace the found address with the js cloaked email
$text = substr_replace($text, $replacement, $regs[0][1], \strlen($regs[0][0]));
}
/*
* Search for derivatives of link code <a href="mailto:email@example.org?
* subject=Text">anytext</a>
*/
$pattern = $this->getPattern($searchEmailLink, $searchText);
while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) {
$mail = $regs[2][0] . $regs[3][0];
$mailText = $regs[5][0];
$attribsBefore = $regs[1][0];
$attribsAfter = $regs[4][0];
// Needed for handling of Body parameter
$mail = str_replace('&amp;', '&', $mail);
$replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 0, $attribsBefore, $attribsAfter);
// Replace the found address with the js cloaked email
$text = substr_replace($text, $replacement, $regs[0][1], \strlen($regs[0][0]));
}
/*
* Search for derivatives of link code <a href="mailto:email@amail.com?subject= Text"
* ><anyspan >email@amail.com</anyspan></a>
*/
$pattern = $this->getPattern($searchEmailLink, $searchEmailSpan);
while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) {
$mail = $regs[2][0] . $regs[3][0];
$mailText = $regs[5][0] . $regs[6][0] . $regs[7][0];
$attribsBefore = $regs[1][0];
$attribsAfter = $regs[4][0];
// Check to see if mail text is different from mail addy
$replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 1, $attribsBefore, $attribsAfter);
// Replace the found address with the js cloaked email
$text = substr_replace($text, $replacement, $regs[0][1], \strlen($regs[0][0]));
}
/*
* Search for derivatives of link code <a href="mailto:email@amail.com?subject= Text">
* <anyspan >anytext</anyspan></a>
*/
$pattern = $this->getPattern($searchEmailLink, $searchTextSpan);
while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) {
$mail = $regs[2][0] . $regs[3][0];
$mailText = $regs[5][0] . $regs[6][0] . $regs[7][0];
$attribsBefore = $regs[1][0];
$attribsAfter = $regs[4][0];
$replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 0, $attribsBefore, $attribsAfter);
// Replace the found address with the js cloaked email
$text = substr_replace($text, $replacement, $regs[0][1], \strlen($regs[0][0]));
}
/*
* Search for derivatives of link code
* <a href="mailto:email@amail.com?subject=Text"><img anything></a>
*/
$pattern = $this->getPattern($searchEmailLink, $searchImage);
while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) {
$mail = $regs[2][0] . $regs[3][0];
$mailText = $regs[5][0];
$attribsBefore = $regs[1][0];
$attribsAfter = $regs[4][0];
// Needed for handling of Body parameter
$mail = str_replace('&amp;', '&', $mail);
// Check to see if mail text is different from mail addy
$replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 0, $attribsBefore, $attribsAfter);
// Replace the found address with the js cloaked email
$text = substr_replace($text, $replacement, $regs[0][1], \strlen($regs[0][0]));
}
/*
* Search for derivatives of link code
* <a href="mailto:email@amail.com?subject=Text"><img anything>email@amail.com</a>
*/
$pattern = $this->getPattern($searchEmailLink, $searchImage . $searchEmail);
while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) {
$mail = $regs[2][0] . $regs[3][0];
$mailText = $regs[5][0] . $regs[6][0];
$attribsBefore = $regs[1][0];
$attribsAfter = $regs[4][0];
// Needed for handling of Body parameter
$mail = str_replace('&amp;', '&', $mail);
// Check to see if mail text is different from mail addy
$replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 1, $attribsBefore, $attribsAfter);
// Replace the found address with the js cloaked email
$text = substr_replace($text, $replacement, $regs[0][1], \strlen($regs[0][0]));
}
/*
* Search for derivatives of link code
* <a href="mailto:email@amail.com?subject=Text"><img anything>any text</a>
*/
$pattern = $this->getPattern($searchEmailLink, $searchImage . $searchText);
while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) {
$mail = $regs[2][0] . $regs[3][0];
$mailText = $regs[5][0] . $regs[6][0];
$attribsBefore = $regs[1][0];
$attribsAfter = $regs[4][0];
// Needed for handling of Body parameter
$mail = str_replace('&amp;', '&', $mail);
// Check to see if mail text is different from mail addy
$replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mailText, 0, $attribsBefore, $attribsAfter);
// Replace the found address with the js cloaked email
$text = substr_replace($text, $replacement, $regs[0][1], \strlen($regs[0][0]));
}
/*
* Search for plain text email addresses, such as email@example.org but within HTML tags:
* <img src="..." title="email@example.org"> or <input type="text" placeholder="email@example.org">
* The '<[^<]*>(*SKIP)(*F)|' trick is used to exclude this kind of occurrences
*/
$pattern = '~<[^<]*(?<!\/)>(*SKIP)(*F)|<[^>]+?(\w*=\"' . $searchEmail . '\")[^>]*\/>~i';
while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) {
$mail = $regs[0][0];
$replacement = HTMLHelper::_('email.cloak', $mail, 0, $mail);
// Replace the found address with the js cloaked email
$text = substr_replace($text, $replacement, $regs[0][1], \strlen($mail));
}
/*
* Search for plain text email addresses, such as email@example.org but within HTML attributes:
* <a title="email@example.org" href="#">email</a> or <li title="email@example.org">email</li>
*/
$pattern = '(<[^>]+?(\w*=\"' . $searchEmail . '")[^>]*>[^<]+<[^<]+>)';
while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) {
$mail = $regs[0][0];
$replacement = HTMLHelper::_('email.cloak', $mail, 0, $mail);
// Replace the found address with the js cloaked email
$text = substr_replace($text, $replacement, $regs[0][1], \strlen($mail));
}
/*
* Search for plain text email addresses, such as email@example.org but not within HTML tags:
* <p>email@example.org</p>
* The '<[^<]*>(*SKIP)(*F)|' trick is used to exclude this kind of occurrences
* The '<[^<]*(?<!\/(?:src))>(*SKIP)(*F)|' exclude image files with @ in filename
*/
$pattern = '~<[^<]*(?<!\/(?:src))>(*SKIP)(*F)|' . $searchEmail . '~i';
while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE)) {
$mail = $regs[1][0];
$replacement = HTMLHelper::_('email.cloak', $mail, $mode, $mail);
// Replace the found address with the js cloaked email
$text = substr_replace($text, $replacement, $regs[1][1], \strlen($mail));
}
return $text;
}
}

View File

@ -0,0 +1,86 @@
<?php
/**
* @version $Id: example.php 14401 2010-01-26 14:10:00Z louis $
* @package Joomla
* @subpackage Content
* @copyright Copyright (C) 2005 - 2010 Open Source Matters. All rights reserved.
* @license GNU/GPL, see LICENSE.php
* Joomla! is free software. This version may have been modified pursuant
* to the GNU General Public License, and as distributed it includes or
* is derivative of works licensed under the GNU General Public License or
* other free or open source software licenses.
* See COPYRIGHT.php for copyright notices and details.
*/
// Check to ensure this file is included in Joomla!
defined( '_JEXEC' ) or die( 'Restricted access' );
jimport( 'joomla.plugin.plugin' );
/**
* Event Calendar Content Plugin
*
* @package Joomla
* @subpackage Content
* @since 1.5
*/
function EventCalendar_replacer( &$matches ) {
$id = (int)$matches[1];
$document =& JFactory::getDocument();
$document->addScript("components/com_cpeventcalendar/DC_EventCalendar/utilities.js");
$document->addScript("components/com_cpeventcalendar/DC_EventCalendar/button.js");
$document->addScript("components/com_cpeventcalendar/DC_EventCalendar/container.js");
$document->addScript("components/com_cpeventcalendar/DC_EventCalendar/yahoo.js");
$document->addScript("components/com_cpeventcalendar/DC_EventCalendar/event.js");
$document->addScript("components/com_cpeventcalendar/DC_EventCalendar/dom.js");
$document->addScript("components/com_cpeventcalendar/DC_EventCalendar/calendar.js");
$document->addScript("components/com_cpeventcalendar/DC_EventCalendar/element.js");
$document->addScript("components/com_cpeventcalendar/DC_EventCalendar/DCEventCalendar.js");
$document->addScript("components/com_cpeventcalendar/DC_EventCalendar/intervalcalendar.js");
$document->addScript("components/com_cpeventcalendar/DC_EventCalendar/calendarcolors.js");
$document->addStyleSheet("components/com_cpeventcalendar/DC_EventCalendar/fonts-min.css");
$document->addStyleSheet("components/com_cpeventcalendar/DC_EventCalendar/button.css");
$document->addStyleSheet("components/com_cpeventcalendar/DC_EventCalendar/container.css");
$document->addStyleSheet("components/com_cpeventcalendar/DC_EventCalendar/calendar.css");
$document->addStyleSheet("components/com_cpeventcalendar/DC_EventCalendar/DCEventCalendar.css");
$container = "plg".mt_rand();
$styletext = "#".$container." .yui-calendar td.calcell {width:".(int)$matches[3]."px;height:".(int)$matches[4]."px;}";
$document->addStyleDeclaration($styletext);
$document->addScriptDeclaration("var pathCalendarCPE = \"".JURI::base(true)."/components/com_cpeventcalendar/DC_EventCalendar/\";\n".
"var pathCalendarCPEJB = \"".JURI::base(true)."/\";\n".
"initEventCalendar(\"".$id."\",\"".$container."\",".(int)$matches[5].",2,\"".$matches[2]."\",{},".(int)$matches[3].",".(int)$matches[4].");");
$str = '<div style="z-index:1000;">
<div id="'.$container.'"></div>
<div style="clear:both"></div>
</div>
';
return $str;
}
class plgContentEventcalendar extends JPlugin
{
public function __construct(& $subject, $config)
{
parent::__construct($subject, $config);
$this->loadLanguage();
}
/**
* Example prepare content method
*
* Method is called by the view
*
* @param object The article object. Note $article->text is also available
* @param object The article params
* @param int The 'page' number
*/
public function onContentPrepare($context, &$article, &$params, $limitstart)
{
// define the regular expression for the bot
$regex = "#\{eventcalendar\:(\d{1,2})\:(\S{5})\:(\d{1,3})\:(\d{1,3})\:(\d{1,2})\}#s";
$article->text = preg_replace_callback( $regex, 'EventCalendar_replacer', $article->text );
return true;
}
}

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<extension version="1.7" type="plugin" group="content">
<name>Content - Event Calendar</name>
<author>Codepeople</author>
<creationDate>Julio 2011</creationDate>
<copyright>Copyright (C) 2011 Codepeople. All rights reserved.</copyright>
<license>GNU/GPL http://www.gnu.org/copyleft/gpl.html</license>
<authorEmail>info@joomlacalendars.com</authorEmail>
<authorUrl>www.joomlacalendars.org</authorUrl>
<version>1.6.0</version>
<description>Replace Event Calendar placeholders in article contents.</description>
<files>
<filename plugin="eventcalendar">eventcalendar.php</filename>
</files>
</extension>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<extension type="plugin" group="content" method="upgrade">
<name>plg_content_fields</name>
<author>Joomla! Project</author>
<creationDate>2017-02</creationDate>
<copyright>(C) 2017 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>3.7.0</version>
<description>PLG_CONTENT_FIELDS_XML_DESCRIPTION</description>
<namespace path="src">Joomla\Plugin\Content\Fields</namespace>
<files>
<folder plugin="fields">services</folder>
<folder>src</folder>
</files>
<languages>
<language tag="en-GB">language/en-GB/plg_content_fields.ini</language>
<language tag="en-GB">language/en-GB/plg_content_fields.sys.ini</language>
</languages>
<config>
<fields name="params">
<fieldset name="basic">
</fieldset>
</fields>
</config>
</extension>

View File

@ -0,0 +1,44 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage Content.fields
*
* @copyright (C) 2022 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
\defined('_JEXEC') or die;
use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use Joomla\Plugin\Content\Fields\Extension\Fields;
return new class () implements ServiceProviderInterface {
/**
* Registers the service provider with a DI container.
*
* @param Container $container The DI container.
*
* @return void
*
* @since 4.3.0
*/
public function register(Container $container)
{
$container->set(
PluginInterface::class,
function (Container $container) {
$plugin = new Fields(
$container->get(DispatcherInterface::class),
(array) PluginHelper::getPlugin('content', 'fields')
);
return $plugin;
}
);
}
};

View File

@ -0,0 +1,160 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage Content.fields
*
* @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\Content\Fields\Extension;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\Component\Fields\Administrator\Helper\FieldsHelper;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Plug-in to show a custom field in eg an article
* This uses the {fields ID} syntax
*
* @since 3.7.0
*/
final class Fields extends CMSPlugin
{
/**
* Plugin that shows a custom field
*
* @param string $context The context of the content being passed to the plugin.
* @param object &$item The item object. Note $article->text is also available
* @param object &$params The article params
* @param int $page The 'page' number
*
* @return void
*
* @since 3.7.0
*/
public function onContentPrepare($context, &$item, &$params, $page = 0)
{
// If the item has a context, overwrite the existing one
if ($context === 'com_finder.indexer' && !empty($item->context)) {
$context = $item->context;
} elseif ($context === 'com_finder.indexer') {
// Don't run this plugin when the content is being indexed and we have no real context
return;
}
// This plugin only works if $item is an object
if (!\is_object($item)) {
return;
}
// Don't run if there is no text property (in case of bad calls) or it is empty
if (!property_exists($item, 'text') || empty($item->text)) {
return;
}
// Prepare the text
if (property_exists($item, 'text') && strpos($item->text, 'field') !== false) {
$item->text = $this->prepare($item->text, $context, $item);
}
// Prepare the intro text
if (property_exists($item, 'introtext') && \is_string($item->introtext) && strpos($item->introtext, 'field') !== false) {
$item->introtext = $this->prepare($item->introtext, $context, $item);
}
// Prepare the full text
if (!empty($item->fulltext) && strpos($item->fulltext, 'field') !== false) {
$item->fulltext = $this->prepare($item->fulltext, $context, $item);
}
}
/**
* Prepares the given string by parsing {field} and {fieldgroup} groups and replacing them.
*
* @param string $string The text to prepare
* @param string $context The context of the content
* @param object $item The item object
*
* @return string
*
* @since 3.8.1
*/
private function prepare($string, $context, $item)
{
// Search for {field ID} or {fieldgroup ID} tags and put the results into $matches.
$regex = '/{(field|fieldgroup)\s+(.*?)}/i';
preg_match_all($regex, $string, $matches, PREG_SET_ORDER);
if (!$matches) {
return $string;
}
$parts = FieldsHelper::extract($context);
if (!$parts || \count($parts) < 2) {
return $string;
}
$context = $parts[0] . '.' . $parts[1];
$fields = FieldsHelper::getFields($context, $item, true);
$fieldsById = [];
$groups = [];
// Rearranging fields in arrays for easier lookup later.
foreach ($fields as $field) {
$fieldsById[$field->id] = $field;
$groups[$field->group_id][] = $field;
}
foreach ($matches as $i => $match) {
// $match[0] is the full pattern match, $match[1] is the type (field or fieldgroup) and $match[2] the ID and optional the layout
$explode = explode(',', $match[2]);
$id = (int) $explode[0];
$output = '';
if ($match[1] === 'field' && $id) {
if (isset($fieldsById[$id])) {
$layout = !empty($explode[1]) ? trim($explode[1]) : $fieldsById[$id]->params->get('layout', 'render');
$output = FieldsHelper::render(
$context,
'field.' . $layout,
[
'item' => $item,
'context' => $context,
'field' => $fieldsById[$id],
]
);
}
} else {
if ($match[2] === '*') {
$match[0] = str_replace('*', '\*', $match[0]);
$renderFields = $fields;
} else {
$renderFields = $groups[$id] ?? '';
}
if ($renderFields) {
$layout = !empty($explode[1]) ? trim($explode[1]) : 'render';
$output = FieldsHelper::render(
$context,
'fields.' . $layout,
[
'item' => $item,
'context' => $context,
'fields' => $renderFields,
]
);
}
}
$string = preg_replace("|$match[0]|", addcslashes($output, '\\$'), $string, 1);
}
return $string;
}
}

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<extension type="plugin" group="content" method="upgrade">
<name>plg_content_finder</name>
<author>Joomla! Project</author>
<creationDate>2011-12</creationDate>
<copyright>(C) 2011 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>3.0.0</version>
<description>PLG_CONTENT_FINDER_XML_DESCRIPTION</description>
<namespace path="src">Joomla\Plugin\Content\Finder</namespace>
<files>
<folder plugin="finder">services</folder>
<folder>src</folder>
</files>
<languages>
<language tag="en-GB">language/en-GB/plg_content_finder.ini</language>
<language tag="en-GB">language/en-GB/plg_content_finder.sys.ini</language>
</languages>
<config>
<fields name="params">
</fields>
</config>
</extension>

View File

@ -0,0 +1,46 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage Content.finder
*
* @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
\defined('_JEXEC') or die;
use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use Joomla\Plugin\Content\Finder\Extension\Finder;
return new class () implements ServiceProviderInterface {
/**
* Registers the service provider with a DI container.
*
* @param Container $container The DI container.
*
* @return void
*
* @since 4.4.0
*/
public function register(Container $container): void
{
$container->set(
PluginInterface::class,
function (Container $container) {
$plugin = new Finder(
$container->get(DispatcherInterface::class),
(array) PluginHelper::getPlugin('content', 'finder')
);
$plugin->setApplication(Factory::getApplication());
return $plugin;
}
);
}
};

View File

@ -0,0 +1,176 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage Content.finder
*
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\Content\Finder\Extension;
use Joomla\CMS\Event\Finder as FinderEvent;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Plugin\PluginHelper;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Smart Search Content Plugin
*
* @since 2.5
*/
final class Finder extends CMSPlugin
{
/**
* Flag to check whether finder plugins already imported.
*
* @var bool
*
* @since 5.0.0
*/
protected $pluginsImported = false;
/**
* Smart Search after save content method.
* Content is passed by reference, but after the save, so no changes will be saved.
* Method is called right after the content is saved.
*
* @param string $context The context of the content passed to the plugin (added in 1.6)
* @param object $article A \Joomla\CMS\Table\Table\ object
* @param bool $isNew If the content has just been created
*
* @return void
*
* @since 2.5
*/
public function onContentAfterSave($context, $article, $isNew): void
{
$this->importFinderPlugins();
// Trigger the onFinderAfterSave event.
$this->getDispatcher()->dispatch('onFinderAfterSave', new FinderEvent\AfterSaveEvent('onFinderAfterSave', [
'context' => $context,
'subject' => $article,
'isNew' => $isNew,
]));
}
/**
* Smart Search before save content method.
* Content is passed by reference. Method is called before the content is saved.
*
* @param string $context The context of the content passed to the plugin (added in 1.6).
* @param object $article A \Joomla\CMS\Table\Table\ object.
* @param bool $isNew If the content is just about to be created.
*
* @return void
*
* @since 2.5
*/
public function onContentBeforeSave($context, $article, $isNew)
{
$this->importFinderPlugins();
// Trigger the onFinderBeforeSave event.
$this->getDispatcher()->dispatch('onFinderBeforeSave', new FinderEvent\BeforeSaveEvent('onFinderBeforeSave', [
'context' => $context,
'subject' => $article,
'isNew' => $isNew,
]));
}
/**
* Smart Search after delete content method.
* Content is passed by reference, but after the deletion.
*
* @param string $context The context of the content passed to the plugin (added in 1.6).
* @param object $article A \Joomla\CMS\Table\Table object.
*
* @return void
*
* @since 2.5
*/
public function onContentAfterDelete($context, $article): void
{
$this->importFinderPlugins();
// Trigger the onFinderAfterDelete event.
$this->getDispatcher()->dispatch('onFinderAfterDelete', new FinderEvent\AfterDeleteEvent('onFinderAfterDelete', [
'context' => $context,
'subject' => $article,
]));
}
/**
* Smart Search content state change method.
* Method to update the link information for items that have been changed
* from outside the edit screen. This is fired when the item is published,
* unpublished, archived, or unarchived from the list view.
*
* @param string $context The context for the content passed to the plugin.
* @param array $pks A list of primary key ids of the content that has changed state.
* @param integer $value The value of the state that the content has been changed to.
*
* @return void
*
* @since 2.5
*/
public function onContentChangeState($context, $pks, $value)
{
$this->importFinderPlugins();
// Trigger the onFinderChangeState event.
$this->getDispatcher()->dispatch('onFinderChangeState', new FinderEvent\AfterChangeStateEvent('onFinderChangeState', [
'context' => $context,
'subject' => $pks,
'value' => $value,
]));
}
/**
* Smart Search change category state content method.
* Method is called when the state of the category to which the
* content item belongs is changed.
*
* @param string $extension The extension whose category has been updated.
* @param array $pks A list of primary key ids of the content that has changed state.
* @param integer $value The value of the state that the content has been changed to.
*
* @return void
*
* @since 2.5
*/
public function onCategoryChangeState($extension, $pks, $value)
{
$this->importFinderPlugins();
// Trigger the onFinderCategoryChangeState event.
$this->getDispatcher()->dispatch('onFinderCategoryChangeState', new FinderEvent\AfterCategoryChangeStateEvent('onFinderCategoryChangeState', [
'context' => $extension,
'subject' => $pks,
'value' => $value,
]));
}
/**
* A helper method to import finder plugins.
*
* @return void
*
* @since 5.0.0
*/
protected function importFinderPlugins()
{
if ($this->pluginsImported) {
return;
}
$this->pluginsImported = true;
PluginHelper::importPlugin('finder', null, true, $this->getDispatcher());
}
}

View File

@ -0,0 +1 @@
<!DOCTYPE html><title></title>

View File

@ -0,0 +1,42 @@
<?php
/**
* @package JEM
* @subpackage JEM Content Plugin
* @copyright (C) 2013-2024 joomlaeventmanager.net
* @license https://www.gnu.org/licenses/gpl-3.0 GNU/GPL
*/
defined('_JEXEC') or die;
use Joomla\CMS\Plugin\CMSPlugin;
/**
* JEM Content Plugin
*
* @package JEM.Plugin
* @subpackage Content.jem
* @since 1.9.6
*/
class plgContentJem extends CMSPlugin
{
/**
* Dissolve recurrence sets where deleted event is referred to as first.
*
* @param string The context for the content passed to the plugin.
* @param object The data relating to the content that was deleted.
*
* @since 1.9.6
*/
public function onContentAfterDelete($context, $data)
{
// Skip plugin if we are deleting something other than events
if (($context != 'com_jem.event') || empty($data->id)) {
return;
}
// event maybe first of recurrence set -> dissolve complete set
JemHelper::dissolve_recurrence($data->id);
return;
}
}

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<extension version="2.5" type="plugin" group="content" method="upgrade">
<name>plg_content_jem</name>
<author>JEM Community</author>
<authorEmail>info@joomlaeventmanager.net</authorEmail>
<authorUrl>https://www.joomlaeventmanager.net</authorUrl>
<creationDate>October 2024</creationDate>
<copyright>copyright (C) 2013-2024 joomlaeventmanager.net</copyright>
<license>https://www.gnu.org/licenses/gpl-3.0 GNU/GPL</license>
<version>4.3.1</version>
<description>PLG_CONTENT_JEM_XML_DESCRIPTION</description>
<files>
<filename plugin="jem">jem.php</filename>
<filename>index.html</filename>
<folder>language</folder>
</files>
<languages>
<language tag="en-GB">language/en-GB/plg_content_jem.ini</language>
<language tag="en-GB">language/en-GB/plg_content_jem.sys.ini</language>
</languages>
</extension>

View File

@ -0,0 +1 @@
<!DOCTYPE html><title></title>

View File

@ -0,0 +1,13 @@
; @package JEM
; @subpackage JEM Content Plugin
; @copyright (C) 2013-2024 joomlaeventmanager.net
; @copyright (C) 2005-2009 Christoph Lukes
; @license https://www.gnu.org/licenses/gpl-3.0 GNU/GPL
;
; All translations can be found at https://app.transifex.com/jemproject/
; Please join the translation team if you want to contribute your changes to the translations
;
; Note: All ini files need to be saved as UTF-8, no BOM
PLG_CONTENT_JEM = "JEM - Content Plugin"
PLG_CONTENT_JEM_XML_DESCRIPTION = "The plugin processes the events for the JEM extension."

View File

@ -0,0 +1,13 @@
; @package JEM
; @subpackage JEM Content Plugin
; @copyright (C) 2013-2024 joomlaeventmanager.net
; @copyright (C) 2005-2009 Christoph Lukes
; @license https://www.gnu.org/licenses/gpl-3.0 GNU/GPL
;
; All translations can be found at https://app.transifex.com/jemproject/
; Please join the translation team if you want to contribute your changes to the translations
;
; Note: All ini files need to be saved as UTF-8, no BOM
PLG_CONTENT_JEM = "JEM - Content Plugin"
PLG_CONTENT_JEM_XML_DESCRIPTION = "Does event processing for JEM extension."

View File

@ -0,0 +1 @@
<!DOCTYPE html><title></title>

View File

@ -0,0 +1 @@
<!DOCTYPE html><title></title>

Some files were not shown because too many files have changed in this diff Show More