* @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Plugin\System\Webauthn\Extension; use Joomla\CMS\Application\CMSApplication; use Joomla\CMS\Application\CMSApplicationInterface; use Joomla\CMS\Event\CoreEventAware; use Joomla\CMS\Factory; use Joomla\CMS\Log\Log; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\Database\DatabaseAwareInterface; use Joomla\Database\DatabaseAwareTrait; use Joomla\Database\DatabaseDriver; use Joomla\Event\DispatcherInterface; use Joomla\Event\SubscriberInterface; use Joomla\Plugin\System\Webauthn\Authentication; use Joomla\Plugin\System\Webauthn\PluginTraits\AdditionalLoginButtons; use Joomla\Plugin\System\Webauthn\PluginTraits\AjaxHandler; use Joomla\Plugin\System\Webauthn\PluginTraits\AjaxHandlerChallenge; use Joomla\Plugin\System\Webauthn\PluginTraits\AjaxHandlerCreate; use Joomla\Plugin\System\Webauthn\PluginTraits\AjaxHandlerDelete; use Joomla\Plugin\System\Webauthn\PluginTraits\AjaxHandlerInitCreate; use Joomla\Plugin\System\Webauthn\PluginTraits\AjaxHandlerLogin; use Joomla\Plugin\System\Webauthn\PluginTraits\AjaxHandlerSaveLabel; use Joomla\Plugin\System\Webauthn\PluginTraits\EventReturnAware; use Joomla\Plugin\System\Webauthn\PluginTraits\UserDeletion; use Joomla\Plugin\System\Webauthn\PluginTraits\UserProfileFields; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * WebAuthn Passwordless Login plugin * * The plugin features are broken down into Traits for the sole purpose of making an otherwise * supermassive class somewhat manageable. You can find the Traits inside the Webauthn/PluginTraits * folder. * * @since 4.0.0 */ final class Webauthn extends CMSPlugin implements SubscriberInterface { // Add WebAuthn buttons use AdditionalLoginButtons; // AJAX request handlers use AjaxHandler; use AjaxHandlerInitCreate; use AjaxHandlerCreate; use AjaxHandlerSaveLabel; use AjaxHandlerDelete; use AjaxHandlerChallenge; use AjaxHandlerLogin; // Utility methods for setting the events' return values use EventReturnAware; use CoreEventAware; // Custom user profile fields use UserProfileFields; // Handle user profile deletion use UserDeletion; /** * Autoload the language files * * @var boolean * @since 4.2.0 */ protected $autoloadLanguage = true; /** * Should I try to detect and register legacy event listeners? * * @var boolean * @since 4.2.0 * * @deprecated */ protected $allowLegacyListeners = false; /** * The WebAuthn authentication helper object * * @var Authentication * @since 4.2.0 */ protected $authenticationHelper; /** * Constructor. Loads the language files as well. * * @param DispatcherInterface $subject 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). * @param Authentication|null $authHelper The WebAuthn helper object * * @since 4.0.0 */ public function __construct(&$subject, array $config = [], Authentication $authHelper = null) { parent::__construct($subject, $config); /** * Note: Do NOT try to load the language in the constructor. This is called before Joomla initializes the * application language. Therefore the temporary Joomla language object and all loaded strings in it will be * destroyed on application initialization. As a result we need to call loadLanguage() in each method * individually, even though all methods make use of language strings. */ // Register a debug log file writer $logLevels = Log::ERROR | Log::CRITICAL | Log::ALERT | Log::EMERGENCY; if (\defined('JDEBUG') && JDEBUG) { $logLevels = Log::ALL; } Log::addLogger([ 'text_file' => "webauthn_system.php", 'text_entry_format' => '{DATETIME} {PRIORITY} {CLIENTIP} {MESSAGE}', ], $logLevels, ["webauthn.system"]); $this->authenticationHelper = $authHelper ?? (new Authentication()); $this->authenticationHelper->setAttestationSupport($this->params->get('attestationSupport', 0) == 1); } /** * Returns the Authentication helper object * * @return Authentication * * @since 4.2.0 */ public function getAuthenticationHelper(): Authentication { return $this->authenticationHelper; } /** * Returns an array of events this subscriber will listen to. * * @return array * * @since 4.2.0 */ public static function getSubscribedEvents(): array { try { $app = Factory::getApplication(); } catch (\Exception $e) { return []; } if (!$app->isClient('site') && !$app->isClient('administrator')) { return []; } return [ 'onAjaxWebauthn' => 'onAjaxWebauthn', 'onAjaxWebauthnChallenge' => 'onAjaxWebauthnChallenge', 'onAjaxWebauthnCreate' => 'onAjaxWebauthnCreate', 'onAjaxWebauthnDelete' => 'onAjaxWebauthnDelete', 'onAjaxWebauthnInitcreate' => 'onAjaxWebauthnInitcreate', 'onAjaxWebauthnLogin' => 'onAjaxWebauthnLogin', 'onAjaxWebauthnSavelabel' => 'onAjaxWebauthnSavelabel', 'onUserAfterDelete' => 'onUserAfterDelete', 'onUserLoginButtons' => 'onUserLoginButtons', 'onContentPrepareForm' => 'onContentPrepareForm', 'onContentPrepareData' => 'onContentPrepareData', ]; } }