[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/administrator/components/com_users/src/Model/ -> MethodsModel.php (source)

   1  <?php
   2  
   3  /**
   4   * @package    Joomla.Administrator
   5   * @subpackage com_users
   6   *
   7   * @copyright  (C) 2022 Open Source Matters, Inc. <https://www.joomla.org>
   8   * @license    GNU General Public License version 2 or later; see LICENSE.txt
   9   */
  10  
  11  namespace Joomla\Component\Users\Administrator\Model;
  12  
  13  use DateInterval;
  14  use DateTimeZone;
  15  use Exception;
  16  use Joomla\CMS\Date\Date;
  17  use Joomla\CMS\Factory;
  18  use Joomla\CMS\Language\Text;
  19  use Joomla\CMS\MVC\Model\BaseDatabaseModel;
  20  use Joomla\CMS\User\User;
  21  use Joomla\CMS\User\UserFactoryInterface;
  22  use Joomla\Component\Users\Administrator\Helper\Mfa as MfaHelper;
  23  use Joomla\Database\ParameterType;
  24  use RuntimeException;
  25  
  26  // phpcs:disable PSR1.Files.SideEffects
  27  \defined('_JEXEC') or die;
  28  // phpcs:enable PSR1.Files.SideEffects
  29  
  30  /**
  31   * Multi-factor Authentication Methods list page's model
  32   *
  33   * @since 4.2.0
  34   */
  35  class MethodsModel extends BaseDatabaseModel
  36  {
  37      /**
  38       * Returns a list of all available MFA methods and their currently active records for a given user.
  39       *
  40       * @param   User|null  $user  The user object. Skip to use the current user.
  41       *
  42       * @return  array
  43       * @throws  Exception
  44       *
  45       * @since 4.2.0
  46       */
  47      public function getMethods(?User $user = null): array
  48      {
  49          if (is_null($user)) {
  50              $user = Factory::getApplication()->getIdentity()
  51                  ?: Factory::getContainer()->get(UserFactoryInterface::class)->loadUserById(0);
  52          }
  53  
  54          if ($user->guest) {
  55              return [];
  56          }
  57  
  58          // Get an associative array of MFA Methods
  59          $rawMethods = MfaHelper::getMfaMethods();
  60          $methods    = [];
  61  
  62          foreach ($rawMethods as $method) {
  63              $method['active']         = [];
  64              $methods[$method['name']] = $method;
  65          }
  66  
  67          // Put the user MFA records into the Methods array
  68          $userMfaRecords = MfaHelper::getUserMfaRecords($user->id);
  69  
  70          if (!empty($userMfaRecords)) {
  71              foreach ($userMfaRecords as $record) {
  72                  if (!isset($methods[$record->method])) {
  73                      continue;
  74                  }
  75  
  76                  $methods[$record->method]->addActiveMethod($record);
  77              }
  78          }
  79  
  80          return $methods;
  81      }
  82  
  83      /**
  84       * Delete all Multi-factor Authentication Methods for the given user.
  85       *
  86       * @param   User|null  $user  The user object to reset MFA for. Null to use the current user.
  87       *
  88       * @return  void
  89       * @throws  Exception
  90       *
  91       * @since 4.2.0
  92       */
  93      public function deleteAll(?User $user = null): void
  94      {
  95          // Make sure we have a user object
  96          if (is_null($user)) {
  97              $user = Factory::getApplication()->getIdentity() ?: Factory::getUser();
  98          }
  99  
 100          // If the user object is a guest (who can't have MFA) we abort with an error
 101          if ($user->guest) {
 102              throw new RuntimeException(Text::_('JERROR_ALERTNOAUTHOR'), 403);
 103          }
 104  
 105          $db    = $this->getDatabase();
 106          $query = $db->getQuery(true)
 107              ->delete($db->quoteName('#__user_mfa'))
 108              ->where($db->quoteName('user_id') . ' = :user_id')
 109              ->bind(':user_id', $user->id, ParameterType::INTEGER);
 110          $db->setQuery($query)->execute();
 111      }
 112  
 113      /**
 114       * Format a relative timestamp. It deals with timestamps today and yesterday in a special manner. Example returns:
 115       * Yesterday, 13:12
 116       * Today, 08:33
 117       * January 1, 2015
 118       *
 119       * @param   string  $dateTimeText  The database time string to use, e.g. "2017-01-13 13:25:36"
 120       *
 121       * @return  string  The formatted, human-readable date
 122       * @throws  Exception
 123       *
 124       * @since 4.2.0
 125       */
 126      public function formatRelative(?string $dateTimeText): string
 127      {
 128          if (empty($dateTimeText)) {
 129              return Text::_('JNEVER');
 130          }
 131  
 132          // The timestamp is given in UTC. Make sure Joomla! parses it as such.
 133          $utcTimeZone = new DateTimeZone('UTC');
 134          $jDate       = new Date($dateTimeText, $utcTimeZone);
 135          $unixStamp   = $jDate->toUnix();
 136  
 137          // I'm pretty sure we didn't have MFA in Joomla back in 1970 ;)
 138          if ($unixStamp < 0) {
 139              return Text::_('JNEVER');
 140          }
 141  
 142          // I need to display the date in the user's local timezone. That's how you do it.
 143          $user   = Factory::getApplication()->getIdentity()
 144              ?: Factory::getContainer()->get(UserFactoryInterface::class)->loadUserById(0);
 145          $userTZ = $user->getParam('timezone', 'UTC');
 146          $tz     = new DateTimeZone($userTZ);
 147          $jDate->setTimezone($tz);
 148  
 149          // Default format string: way in the past, the time of the day is not important
 150          $formatString    = Text::_('COM_USERS_MFA_LBL_DATE_FORMAT_PAST');
 151          $containerString = Text::_('COM_USERS_MFA_LBL_PAST');
 152  
 153          // If the timestamp is within the last 72 hours we may need a special format
 154          if ($unixStamp > (time() - (72 * 3600))) {
 155              // Is this timestamp today?
 156              $jNow = new Date();
 157              $jNow->setTimezone($tz);
 158              $checkNow  = $jNow->format('Ymd', true);
 159              $checkDate = $jDate->format('Ymd', true);
 160  
 161              if ($checkDate == $checkNow) {
 162                  $formatString    = Text::_('COM_USERS_MFA_LBL_DATE_FORMAT_TODAY');
 163                  $containerString = Text::_('COM_USERS_MFA_LBL_TODAY');
 164              } else {
 165                  // Is this timestamp yesterday?
 166                  $jYesterday = clone $jNow;
 167                  $jYesterday->setTime(0, 0, 0);
 168                  $oneSecond = new DateInterval('PT1S');
 169                  $jYesterday->sub($oneSecond);
 170                  $checkYesterday = $jYesterday->format('Ymd', true);
 171  
 172                  if ($checkDate == $checkYesterday) {
 173                      $formatString    = Text::_('COM_USERS_MFA_LBL_DATE_FORMAT_YESTERDAY');
 174                      $containerString = Text::_('COM_USERS_MFA_LBL_YESTERDAY');
 175                  }
 176              }
 177          }
 178  
 179          return sprintf($containerString, $jDate->format($formatString, true));
 180      }
 181  
 182      /**
 183       * Set the user's "don't show this again" flag.
 184       *
 185       * @param   User  $user  The user to check
 186       * @param   bool  $flag  True to set the flag, false to unset it (it will be set to 0, actually)
 187       *
 188       * @return  void
 189       *
 190       * @since 4.2.0
 191       */
 192      public function setFlag(User $user, bool $flag = true): void
 193      {
 194          $db         = $this->getDatabase();
 195          $profileKey = 'mfa.dontshow';
 196          $query      = $db->getQuery(true)
 197              ->select($db->quoteName('profile_value'))
 198              ->from($db->quoteName('#__user_profiles'))
 199              ->where($db->quoteName('user_id') . ' = :user_id')
 200              ->where($db->quoteName('profile_key') . ' = :profileKey')
 201              ->bind(':user_id', $user->id, ParameterType::INTEGER)
 202              ->bind(':profileKey', $profileKey, ParameterType::STRING);
 203  
 204          try {
 205              $result = $db->setQuery($query)->loadResult();
 206          } catch (Exception $e) {
 207              return;
 208          }
 209  
 210          $exists = !is_null($result);
 211  
 212          $object = (object) [
 213              'user_id'       => $user->id,
 214              'profile_key'   => 'mfa.dontshow',
 215              'profile_value' => ($flag ? 1 : 0),
 216              'ordering'      => 1,
 217          ];
 218  
 219          if (!$exists) {
 220              $db->insertObject('#__user_profiles', $object);
 221          } else {
 222              $db->updateObject('#__user_profiles', $object, ['user_id', 'profile_key']);
 223          }
 224      }
 225  }


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer