Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.
   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  /**
  17   * Privacy provider.
  18   *
  19   * @package     tool_mfa
  20   * @author      Mikhail Golenkov <golenkovm@gmail.com>
  21   * @copyright   Catalyst IT
  22   * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  namespace tool_mfa\privacy;
  26  
  27  use core_privacy\local\metadata\collection;
  28  use core_privacy\local\request\contextlist;
  29  use core_privacy\local\request\approved_contextlist;
  30  use core_privacy\local\request\approved_userlist;
  31  use core_privacy\local\request\writer;
  32  use core_privacy\local\request\userlist;
  33  
  34  /**
  35   * Privacy provider
  36   *
  37   * @package tool_mfa
  38   */
  39  class provider implements
  40      \core_privacy\local\metadata\provider,
  41      \core_privacy\local\request\data_provider {
  42  
  43      /**
  44       * Returns metadata about this plugin's privacy policy.
  45       *
  46       * @param   collection $collection The initialised collection to add items to.
  47       * @return  collection     A listing of user data stored through this system.
  48       */
  49      public static function get_metadata(collection $collection): collection {
  50          $collection->add_database_table(
  51              'tool_mfa',
  52              [
  53                  'id' => 'privacy:metadata:tool_mfa:id',
  54                  'userid' => 'privacy:metadata:tool_mfa:userid',
  55                  'factor' => 'privacy:metadata:tool_mfa:factor',
  56                  'secret' => 'privacy:metadata:tool_mfa:secret',
  57                  'label' => 'privacy:metadata:tool_mfa:label',
  58                  'timecreated' => 'privacy:metadata:tool_mfa:timecreated',
  59                  'createdfromip' => 'privacy:metadata:tool_mfa:createdfromip',
  60                  'timemodified' => 'privacy:metadata:tool_mfa:timemodified',
  61                  'lastverified' => 'privacy:metadata:tool_mfa:lastverified',
  62              ],
  63              'privacy:metadata:tool_mfa'
  64          );
  65  
  66          $collection->add_database_table(
  67              'tool_mfa_secrets',
  68              [
  69                  'userid' => 'privacy:metadata:tool_mfa_secrets:userid',
  70                  'factor' => 'privacy:metadata:tool_mfa_secrets:factor',
  71                  'secret' => 'privacy:metadata:tool_mfa_secrets:secret',
  72                  'sessionid' => 'privacy:metadata:tool_mfa_secrets:sessionid',
  73              ],
  74              'privacy:metadata:tool_mfa_secrets'
  75          );
  76  
  77          $collection->add_database_table(
  78              'tool_mfa_auth',
  79              [
  80                  'userid' => 'privacy:metadata:tool_mfa_auth:userid',
  81                  'lastverified' => 'privacy:metadata:tool_mfa_auth:lastverified',
  82              ],
  83              'privacy:metadata:tool_mfa_auth'
  84          );
  85  
  86          return $collection;
  87      }
  88  
  89      /**
  90       * Get the list of contexts that contain user information for the given user.
  91       *
  92       * @param int $userid the userid to search.
  93       * @return contextlist the contexts in which data is contained.
  94       */
  95      public static function get_contexts_for_userid(int $userid): contextlist {
  96          $contextlist = new \core_privacy\local\request\contextlist();
  97          $contextlist->add_user_context($userid);
  98          $contextlist->add_system_context();
  99          return $contextlist;
 100      }
 101  
 102      /**
 103       * Gets the list of users who have data with a context. Secrets context is a subset of this table.
 104       *
 105       * @param userlist $userlist the userlist containing users who have data in this context.
 106       * @return void
 107       */
 108      public static function get_users_in_context(userlist $userlist): void {
 109          $context = $userlist->get_context();
 110          // If current context is system, all users are contained within, get all users.
 111          if ($context->contextlevel == CONTEXT_SYSTEM) {
 112              $sql = "
 113              SELECT *
 114              FROM {tool_mfa}";
 115              $userlist->add_from_sql('userid', $sql, []);
 116          }
 117      }
 118  
 119      /**
 120       * Exports all data stored in provided contexts for user. Secrets should not be exported as they are transient.
 121       *
 122       * @param approved_contextlist $contextlist the list of contexts to export for.
 123       * @return void
 124       */
 125      public static function export_user_data(approved_contextlist $contextlist): void {
 126          global $DB;
 127          $userid = $contextlist->get_user()->id;
 128          foreach ($contextlist as $context) {
 129              // If not in system context, exit loop.
 130              if ($context->contextlevel == CONTEXT_SYSTEM) {
 131                  $parentclass = [];
 132  
 133                  // Get records for user ID.
 134                  $rows = $DB->get_records('tool_mfa', ['userid' => $userid]);
 135  
 136                  if (count($rows) > 0) {
 137                      $i = 0;
 138                      foreach ($rows as $row) {
 139                          $parentclass[$i]['userid'] = $row->userid;
 140                          $timecreated = \core_privacy\local\request\transform::datetime($row->timecreated);
 141                          $parentclass[$i]['factor'] = $row->factor;
 142                          $parentclass[$i]['timecreated'] = $timecreated;
 143                          $parentclass[$i]['createdfromip'] = $row->createdfromip;
 144                          $timemodified = \core_privacy\local\request\transform::datetime($row->timemodified);
 145                          $parentclass[$i]['timemodified'] = $timemodified;
 146                          $lastverified = \core_privacy\local\request\transform::datetime($row->lastverified);
 147                          $parentclass[$i]['lastverified'] = $lastverified;
 148                          $parentclass[$i]['revoked'] = $row->revoked;
 149                          $i++;
 150                      }
 151                  }
 152  
 153                  // Also get lastverified auth time for user, and add.
 154                  $lastverifiedauth = $DB->get_field('tool_mfa_auth', 'lastverified', ['userid' => $userid]);
 155                  if (!empty($lastverifiedauth)) {
 156                      $lastverifiedauth = \core_privacy\local\request\transform::datetime($lastverifiedauth);
 157                      $parentclass['lastverifiedauth'] = $lastverifiedauth;
 158                  }
 159  
 160                  writer::with_context($context)->export_data(
 161                      [get_string('privacy:metadata:tool_mfa', 'tool_mfa')],
 162                      (object) $parentclass);
 163              }
 164          }
 165      }
 166  
 167      /**
 168       * Deletes data for all users in context.
 169       *
 170       * @param context $context The context to delete for.
 171       * @return void
 172       */
 173      public static function delete_data_for_all_users_in_context(\context $context): void {
 174          global $DB;
 175          // All data contained in system context.
 176          if ($context->contextlevel == CONTEXT_SYSTEM) {
 177              $DB->delete_records('tool_mfa', []);
 178              $DB->delete_records('tool_mfa_secrets', []);
 179              $DB->delete_records('tool_mfa_auth', []);
 180          }
 181      }
 182  
 183      /**
 184       * Deletes all data in all provided contexts for user.
 185       *
 186       * @param approved_contextlist $contextlist the list of contexts to delete for.
 187       * @return void
 188       */
 189      public static function delete_data_for_user(approved_contextlist $contextlist): void {
 190          global $DB;
 191          $userid = $contextlist->get_user()->id;
 192          foreach ($contextlist as $context) {
 193              // If not in system context, skip context.
 194              if ($context->contextlevel == CONTEXT_SYSTEM) {
 195                  $DB->delete_records('tool_mfa', ['userid' => $userid]);
 196                  $DB->delete_records('tool_mfa_secrets', ['userid' => $userid]);
 197                  $DB->delete_records('tool_mfa_auth', ['userid' => $userid]);
 198              }
 199          }
 200      }
 201  
 202      /**
 203       * Given a userlist, deletes all data in all provided contexts for the users
 204       *
 205       * @param approved_userlist $userlist the list of users to delete data for
 206       * @return void
 207       */
 208      public static function delete_data_for_users(approved_userlist $userlist): void {
 209          $users = $userlist->get_users();
 210          foreach ($users as $user) {
 211              // Create contextlist.
 212              $contextlist = new approved_contextlist($user, 'tool_mfa', [CONTEXT_SYSTEM]);
 213              // Call delete data.
 214              self::delete_data_for_user($contextlist);
 215          }
 216      }
 217  }