PageRenderTime 44ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/backup/util/plan/restore_step.class.php

https://bitbucket.org/moodle/moodle
PHP | 165 lines | 72 code | 24 blank | 69 comment | 17 complexity | 1a75b4f2a6a6413b25559152ac483983 MD5 | raw file
Possible License(s): Apache-2.0, LGPL-2.1, BSD-3-Clause, MIT, GPL-3.0
  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. * @package moodlecore
  18. * @subpackage backup-plan
  19. * @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
  20. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  21. */
  22. /**
  23. * Abstract class defining the needed stuf for one restore step
  24. *
  25. * TODO: Finish phpdocs
  26. */
  27. abstract class restore_step extends base_step {
  28. /**
  29. * Constructor - instantiates one object of this class
  30. */
  31. public function __construct($name, $task = null) {
  32. if (!is_null($task) && !($task instanceof restore_task)) {
  33. throw new restore_step_exception('wrong_restore_task_specified');
  34. }
  35. parent::__construct($name, $task);
  36. }
  37. protected function get_restoreid() {
  38. if (is_null($this->task)) {
  39. throw new restore_step_exception('not_specified_restore_task');
  40. }
  41. return $this->task->get_restoreid();
  42. }
  43. /**
  44. * Apply course startdate offset based in original course startdate and course_offset_startdate setting
  45. * Note we are using one static cache here, but *by restoreid*, so it's ok for concurrence/multiple
  46. * executions in the same request
  47. *
  48. * Note: The policy is to roll date only for configurations and not for user data. see MDL-9367.
  49. *
  50. * @param int $value Time value (seconds since epoch), or empty for nothing
  51. * @return int Time value after applying the date offset, or empty for nothing
  52. */
  53. public function apply_date_offset($value) {
  54. // Empties don't offset - zeros (int and string), false and nulls return original value.
  55. if (empty($value)) {
  56. return $value;
  57. }
  58. static $cache = array();
  59. // Lookup cache.
  60. if (isset($cache[$this->get_restoreid()])) {
  61. return $value + $cache[$this->get_restoreid()];
  62. }
  63. // No cache, let's calculate the offset.
  64. $original = $this->task->get_info()->original_course_startdate;
  65. $setting = 0;
  66. if ($this->setting_exists('course_startdate')) { // Seting may not exist (MDL-25019).
  67. $settingobject = $this->task->get_setting('course_startdate');
  68. if (method_exists($settingobject, 'get_normalized_value')) {
  69. $setting = $settingobject->get_normalized_value();
  70. } else {
  71. $setting = $settingobject->get_value();
  72. }
  73. }
  74. if (empty($original) || empty($setting)) {
  75. // Original course has not startdate or setting doesn't exist, offset = 0.
  76. $cache[$this->get_restoreid()] = 0;
  77. } else {
  78. // Arrived here, let's calculate the real offset.
  79. $cache[$this->get_restoreid()] = $setting - $original;
  80. }
  81. // Return the passed value with cached offset applied.
  82. return $value + $cache[$this->get_restoreid()];
  83. }
  84. /**
  85. * Returns symmetric-key AES-256 decryption of base64 encoded contents.
  86. *
  87. * This method is used in restore operations to decrypt contents encrypted with
  88. * {@link encrypted_final_element} automatically decoding (base64) and decrypting
  89. * contents using the key stored in backup_encryptkey config.
  90. *
  91. * Requires openssl, cipher availability, and key existence (backup
  92. * automatically sets it if missing). Integrity is provided via HMAC.
  93. *
  94. * @param string $value {@link encrypted_final_element} value to decode and decrypt.
  95. * @return string|null decoded and decrypted value or null if the operation can not be performed.
  96. */
  97. public function decrypt($value) {
  98. // No openssl available, skip this field completely.
  99. if (!function_exists('openssl_encrypt')) {
  100. return null;
  101. }
  102. // No hash available, skip this field completely.
  103. if (!function_exists('hash_hmac')) {
  104. return null;
  105. }
  106. // Cypher not available, skip this field completely.
  107. if (!in_array(backup::CIPHER, openssl_get_cipher_methods())) {
  108. return null;
  109. }
  110. // Get the decrypt key. Skip if missing.
  111. $key = get_config('backup', 'backup_encryptkey');
  112. if ($key === false) {
  113. return null;
  114. }
  115. // And decode it.
  116. $key = base64_decode($key);
  117. // Arrived here, let's proceed with authentication (provides integrity).
  118. $hmaclen = 32; // SHA256 is 32 bytes.
  119. $ivlen = openssl_cipher_iv_length(backup::CIPHER);
  120. list($hmac, $iv, $text) = array_values(unpack("a{$hmaclen}hmac/a{$ivlen}iv/a*text", base64_decode($value)));
  121. // Verify HMAC matches expectations, skip if not (integrity failed).
  122. if (!hash_equals($hmac, hash_hmac('sha256', $iv . $text, $key, true))) {
  123. return null;
  124. }
  125. // Arrived here, integrity is ok, let's decrypt.
  126. $result = openssl_decrypt($text, backup::CIPHER, $key, OPENSSL_RAW_DATA, $iv);
  127. // For some reason decrypt failed (strange, HMAC check should have deteted it), skip this field completely.
  128. if ($result === false) {
  129. return null;
  130. }
  131. return $result;
  132. }
  133. }
  134. /*
  135. * Exception class used by all the @restore_step stuff
  136. */
  137. class restore_step_exception extends base_step_exception {
  138. public function __construct($errorcode, $a=NULL, $debuginfo=null) {
  139. parent::__construct($errorcode, $a, $debuginfo);
  140. }
  141. }