Manager.php 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2016, ownCloud, Inc.
  4. *
  5. * @author Björn Schießle <bjoern@schiessle.org>
  6. * @author Christoph Wurst <christoph@winzerhof-wurst.at>
  7. * @author Joas Schilling <coding@schilljs.com>
  8. * @author Roeland Jago Douma <roeland@famdouma.nl>
  9. * @author Thomas Müller <thomas.mueller@tmit.eu>
  10. *
  11. * @license AGPL-3.0
  12. *
  13. * This code is free software: you can redistribute it and/or modify
  14. * it under the terms of the GNU Affero General Public License, version 3,
  15. * as published by the Free Software Foundation.
  16. *
  17. * This program is distributed in the hope that it will be useful,
  18. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. * GNU Affero General Public License for more details.
  21. *
  22. * You should have received a copy of the GNU Affero General Public License, version 3,
  23. * along with this program. If not, see <http://www.gnu.org/licenses/>
  24. *
  25. */
  26. namespace OC\Encryption;
  27. use OC\Encryption\Keys\Storage;
  28. use OC\Files\Filesystem;
  29. use OC\Files\View;
  30. use OC\Memcache\ArrayCache;
  31. use OC\ServiceUnavailableException;
  32. use OCP\Encryption\IEncryptionModule;
  33. use OCP\Encryption\IManager;
  34. use OCP\Files\Mount\IMountPoint;
  35. use OCP\Files\Storage\IStorage;
  36. use OCP\IConfig;
  37. use OCP\IL10N;
  38. use Psr\Log\LoggerInterface;
  39. class Manager implements IManager {
  40. protected array $encryptionModules;
  41. public function __construct(
  42. protected IConfig $config,
  43. protected LoggerInterface $logger,
  44. protected IL10N $l,
  45. protected View $rootView,
  46. protected Util $util,
  47. protected ArrayCache $arrayCache,
  48. ) {
  49. $this->encryptionModules = [];
  50. }
  51. /**
  52. * Check if encryption is enabled
  53. *
  54. * @return bool true if enabled, false if not
  55. */
  56. public function isEnabled() {
  57. $installed = $this->config->getSystemValueBool('installed', false);
  58. if (!$installed) {
  59. return false;
  60. }
  61. $enabled = $this->config->getAppValue('core', 'encryption_enabled', 'no');
  62. return $enabled === 'yes';
  63. }
  64. /**
  65. * check if new encryption is ready
  66. *
  67. * @return bool
  68. * @throws ServiceUnavailableException
  69. */
  70. public function isReady() {
  71. if ($this->isKeyStorageReady() === false) {
  72. throw new ServiceUnavailableException('Key Storage is not ready');
  73. }
  74. return true;
  75. }
  76. /**
  77. * @param string $user
  78. */
  79. public function isReadyForUser($user) {
  80. if (!$this->isReady()) {
  81. return false;
  82. }
  83. foreach ($this->getEncryptionModules() as $module) {
  84. /** @var IEncryptionModule $m */
  85. $m = call_user_func($module['callback']);
  86. if (!$m->isReadyForUser($user)) {
  87. return false;
  88. }
  89. }
  90. return true;
  91. }
  92. /**
  93. * Registers an callback function which must return an encryption module instance
  94. *
  95. * @param string $id
  96. * @param string $displayName
  97. * @param callable $callback
  98. * @throws Exceptions\ModuleAlreadyExistsException
  99. */
  100. public function registerEncryptionModule($id, $displayName, callable $callback) {
  101. if (isset($this->encryptionModules[$id])) {
  102. throw new Exceptions\ModuleAlreadyExistsException($id, $displayName);
  103. }
  104. $this->encryptionModules[$id] = [
  105. 'id' => $id,
  106. 'displayName' => $displayName,
  107. 'callback' => $callback,
  108. ];
  109. $defaultEncryptionModuleId = $this->getDefaultEncryptionModuleId();
  110. if (empty($defaultEncryptionModuleId)) {
  111. $this->setDefaultEncryptionModule($id);
  112. }
  113. }
  114. /**
  115. * Unregisters an encryption module
  116. *
  117. * @param string $moduleId
  118. */
  119. public function unregisterEncryptionModule($moduleId) {
  120. unset($this->encryptionModules[$moduleId]);
  121. }
  122. /**
  123. * get a list of all encryption modules
  124. *
  125. * @return array [id => ['id' => $id, 'displayName' => $displayName, 'callback' => callback]]
  126. */
  127. public function getEncryptionModules() {
  128. return $this->encryptionModules;
  129. }
  130. /**
  131. * get a specific encryption module
  132. *
  133. * @param string $moduleId
  134. * @return IEncryptionModule
  135. * @throws Exceptions\ModuleDoesNotExistsException
  136. */
  137. public function getEncryptionModule($moduleId = '') {
  138. if (empty($moduleId)) {
  139. return $this->getDefaultEncryptionModule();
  140. }
  141. if (isset($this->encryptionModules[$moduleId])) {
  142. return call_user_func($this->encryptionModules[$moduleId]['callback']);
  143. }
  144. $message = "Module with ID: $moduleId does not exist.";
  145. $hint = $this->l->t('Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator.', [$moduleId]);
  146. throw new Exceptions\ModuleDoesNotExistsException($message, $hint);
  147. }
  148. /**
  149. * get default encryption module
  150. *
  151. * @return \OCP\Encryption\IEncryptionModule
  152. * @throws Exceptions\ModuleDoesNotExistsException
  153. */
  154. protected function getDefaultEncryptionModule() {
  155. $defaultModuleId = $this->getDefaultEncryptionModuleId();
  156. if (empty($defaultModuleId)) {
  157. $message = 'No default encryption module defined';
  158. throw new Exceptions\ModuleDoesNotExistsException($message);
  159. }
  160. if (isset($this->encryptionModules[$defaultModuleId])) {
  161. return call_user_func($this->encryptionModules[$defaultModuleId]['callback']);
  162. }
  163. $message = 'Default encryption module not loaded';
  164. throw new Exceptions\ModuleDoesNotExistsException($message);
  165. }
  166. /**
  167. * set default encryption module Id
  168. *
  169. * @param string $moduleId
  170. * @return bool
  171. */
  172. public function setDefaultEncryptionModule($moduleId) {
  173. try {
  174. $this->getEncryptionModule($moduleId);
  175. } catch (\Exception $e) {
  176. return false;
  177. }
  178. $this->config->setAppValue('core', 'default_encryption_module', $moduleId);
  179. return true;
  180. }
  181. /**
  182. * get default encryption module Id
  183. *
  184. * @return string
  185. */
  186. public function getDefaultEncryptionModuleId() {
  187. return $this->config->getAppValue('core', 'default_encryption_module');
  188. }
  189. /**
  190. * Add storage wrapper
  191. */
  192. public function setupStorage() {
  193. // If encryption is disabled and there are no loaded modules it makes no sense to load the wrapper
  194. if (!empty($this->encryptionModules) || $this->isEnabled()) {
  195. $encryptionWrapper = new EncryptionWrapper($this->arrayCache, $this, $this->logger);
  196. Filesystem::addStorageWrapper('oc_encryption', [$encryptionWrapper, 'wrapStorage'], 2);
  197. }
  198. }
  199. public function forceWrapStorage(IMountPoint $mountPoint, IStorage $storage) {
  200. $encryptionWrapper = new EncryptionWrapper($this->arrayCache, $this, $this->logger);
  201. return $encryptionWrapper->wrapStorage($mountPoint->getMountPoint(), $storage, $mountPoint, true);
  202. }
  203. /**
  204. * check if key storage is ready
  205. *
  206. * @return bool
  207. */
  208. protected function isKeyStorageReady() {
  209. $rootDir = $this->util->getKeyStorageRoot();
  210. // the default root is always valid
  211. if ($rootDir === '') {
  212. return true;
  213. }
  214. // check if key storage is mounted correctly
  215. if ($this->rootView->file_exists($rootDir . '/' . Storage::KEY_STORAGE_MARKER)) {
  216. return true;
  217. }
  218. return false;
  219. }
  220. }