Manager.php 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. <?php
  2. /**
  3. * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
  4. * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
  5. * SPDX-License-Identifier: AGPL-3.0-only
  6. */
  7. namespace OC\Encryption;
  8. use OC\Encryption\Keys\Storage;
  9. use OC\Files\Filesystem;
  10. use OC\Files\View;
  11. use OC\Memcache\ArrayCache;
  12. use OC\ServiceUnavailableException;
  13. use OCP\Encryption\IEncryptionModule;
  14. use OCP\Encryption\IManager;
  15. use OCP\Files\Mount\IMountPoint;
  16. use OCP\Files\Storage\IStorage;
  17. use OCP\IConfig;
  18. use OCP\IL10N;
  19. use Psr\Log\LoggerInterface;
  20. class Manager implements IManager {
  21. protected array $encryptionModules;
  22. public function __construct(
  23. protected IConfig $config,
  24. protected LoggerInterface $logger,
  25. protected IL10N $l,
  26. protected View $rootView,
  27. protected Util $util,
  28. protected ArrayCache $arrayCache,
  29. ) {
  30. $this->encryptionModules = [];
  31. }
  32. /**
  33. * Check if encryption is enabled
  34. *
  35. * @return bool true if enabled, false if not
  36. */
  37. public function isEnabled() {
  38. $installed = $this->config->getSystemValueBool('installed', false);
  39. if (!$installed) {
  40. return false;
  41. }
  42. $enabled = $this->config->getAppValue('core', 'encryption_enabled', 'no');
  43. return $enabled === 'yes';
  44. }
  45. /**
  46. * check if new encryption is ready
  47. *
  48. * @return bool
  49. * @throws ServiceUnavailableException
  50. */
  51. public function isReady() {
  52. if ($this->isKeyStorageReady() === false) {
  53. throw new ServiceUnavailableException('Key Storage is not ready');
  54. }
  55. return true;
  56. }
  57. /**
  58. * @param string $user
  59. */
  60. public function isReadyForUser($user) {
  61. if (!$this->isReady()) {
  62. return false;
  63. }
  64. foreach ($this->getEncryptionModules() as $module) {
  65. /** @var IEncryptionModule $m */
  66. $m = call_user_func($module['callback']);
  67. if (!$m->isReadyForUser($user)) {
  68. return false;
  69. }
  70. }
  71. return true;
  72. }
  73. /**
  74. * Registers an callback function which must return an encryption module instance
  75. *
  76. * @param string $id
  77. * @param string $displayName
  78. * @param callable $callback
  79. * @throws Exceptions\ModuleAlreadyExistsException
  80. */
  81. public function registerEncryptionModule($id, $displayName, callable $callback) {
  82. if (isset($this->encryptionModules[$id])) {
  83. throw new Exceptions\ModuleAlreadyExistsException($id, $displayName);
  84. }
  85. $this->encryptionModules[$id] = [
  86. 'id' => $id,
  87. 'displayName' => $displayName,
  88. 'callback' => $callback,
  89. ];
  90. $defaultEncryptionModuleId = $this->getDefaultEncryptionModuleId();
  91. if (empty($defaultEncryptionModuleId)) {
  92. $this->setDefaultEncryptionModule($id);
  93. }
  94. }
  95. /**
  96. * Unregisters an encryption module
  97. *
  98. * @param string $moduleId
  99. */
  100. public function unregisterEncryptionModule($moduleId) {
  101. unset($this->encryptionModules[$moduleId]);
  102. }
  103. /**
  104. * get a list of all encryption modules
  105. *
  106. * @return array [id => ['id' => $id, 'displayName' => $displayName, 'callback' => callback]]
  107. */
  108. public function getEncryptionModules() {
  109. return $this->encryptionModules;
  110. }
  111. /**
  112. * get a specific encryption module
  113. *
  114. * @param string $moduleId
  115. * @return IEncryptionModule
  116. * @throws Exceptions\ModuleDoesNotExistsException
  117. */
  118. public function getEncryptionModule($moduleId = '') {
  119. if (empty($moduleId)) {
  120. return $this->getDefaultEncryptionModule();
  121. }
  122. if (isset($this->encryptionModules[$moduleId])) {
  123. return call_user_func($this->encryptionModules[$moduleId]['callback']);
  124. }
  125. $message = "Module with ID: $moduleId does not exist.";
  126. $hint = $this->l->t('Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator.', [$moduleId]);
  127. throw new Exceptions\ModuleDoesNotExistsException($message, $hint);
  128. }
  129. /**
  130. * get default encryption module
  131. *
  132. * @return \OCP\Encryption\IEncryptionModule
  133. * @throws Exceptions\ModuleDoesNotExistsException
  134. */
  135. protected function getDefaultEncryptionModule() {
  136. $defaultModuleId = $this->getDefaultEncryptionModuleId();
  137. if (empty($defaultModuleId)) {
  138. $message = 'No default encryption module defined';
  139. throw new Exceptions\ModuleDoesNotExistsException($message);
  140. }
  141. if (isset($this->encryptionModules[$defaultModuleId])) {
  142. return call_user_func($this->encryptionModules[$defaultModuleId]['callback']);
  143. }
  144. $message = 'Default encryption module not loaded';
  145. throw new Exceptions\ModuleDoesNotExistsException($message);
  146. }
  147. /**
  148. * set default encryption module Id
  149. *
  150. * @param string $moduleId
  151. * @return bool
  152. */
  153. public function setDefaultEncryptionModule($moduleId) {
  154. try {
  155. $this->getEncryptionModule($moduleId);
  156. } catch (\Exception $e) {
  157. return false;
  158. }
  159. $this->config->setAppValue('core', 'default_encryption_module', $moduleId);
  160. return true;
  161. }
  162. /**
  163. * get default encryption module Id
  164. *
  165. * @return string
  166. */
  167. public function getDefaultEncryptionModuleId() {
  168. return $this->config->getAppValue('core', 'default_encryption_module');
  169. }
  170. /**
  171. * Add storage wrapper
  172. */
  173. public function setupStorage() {
  174. // If encryption is disabled and there are no loaded modules it makes no sense to load the wrapper
  175. if (!empty($this->encryptionModules) || $this->isEnabled()) {
  176. $encryptionWrapper = new EncryptionWrapper($this->arrayCache, $this, $this->logger);
  177. Filesystem::addStorageWrapper('oc_encryption', [$encryptionWrapper, 'wrapStorage'], 2);
  178. }
  179. }
  180. public function forceWrapStorage(IMountPoint $mountPoint, IStorage $storage) {
  181. $encryptionWrapper = new EncryptionWrapper($this->arrayCache, $this, $this->logger);
  182. return $encryptionWrapper->wrapStorage($mountPoint->getMountPoint(), $storage, $mountPoint, true);
  183. }
  184. /**
  185. * check if key storage is ready
  186. *
  187. * @return bool
  188. */
  189. protected function isKeyStorageReady() {
  190. $rootDir = $this->util->getKeyStorageRoot();
  191. // the default root is always valid
  192. if ($rootDir === '') {
  193. return true;
  194. }
  195. // check if key storage is mounted correctly
  196. if ($this->rootView->file_exists($rootDir . '/' . Storage::KEY_STORAGE_MARKER)) {
  197. return true;
  198. }
  199. return false;
  200. }
  201. }