Manager.php 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  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\IConfig;
  35. use OCP\IL10N;
  36. use Psr\Log\LoggerInterface;
  37. class Manager implements IManager {
  38. /** @var array */
  39. protected $encryptionModules;
  40. /** @var IConfig */
  41. protected $config;
  42. protected LoggerInterface $logger;
  43. /** @var Il10n */
  44. protected $l;
  45. /** @var View */
  46. protected $rootView;
  47. /** @var Util */
  48. protected $util;
  49. /** @var ArrayCache */
  50. protected $arrayCache;
  51. public function __construct(IConfig $config, LoggerInterface $logger, IL10N $l10n, View $rootView, Util $util, ArrayCache $arrayCache) {
  52. $this->encryptionModules = [];
  53. $this->config = $config;
  54. $this->logger = $logger;
  55. $this->l = $l10n;
  56. $this->rootView = $rootView;
  57. $this->util = $util;
  58. $this->arrayCache = $arrayCache;
  59. }
  60. /**
  61. * Check if encryption is enabled
  62. *
  63. * @return bool true if enabled, false if not
  64. */
  65. public function isEnabled() {
  66. $installed = $this->config->getSystemValue('installed', false);
  67. if (!$installed) {
  68. return false;
  69. }
  70. $enabled = $this->config->getAppValue('core', 'encryption_enabled', 'no');
  71. return $enabled === 'yes';
  72. }
  73. /**
  74. * check if new encryption is ready
  75. *
  76. * @return bool
  77. * @throws ServiceUnavailableException
  78. */
  79. public function isReady() {
  80. if ($this->isKeyStorageReady() === false) {
  81. throw new ServiceUnavailableException('Key Storage is not ready');
  82. }
  83. return true;
  84. }
  85. /**
  86. * @param string $user
  87. */
  88. public function isReadyForUser($user) {
  89. if (!$this->isReady()) {
  90. return false;
  91. }
  92. foreach ($this->getEncryptionModules() as $module) {
  93. /** @var IEncryptionModule $m */
  94. $m = call_user_func($module['callback']);
  95. if (!$m->isReadyForUser($user)) {
  96. return false;
  97. }
  98. }
  99. return true;
  100. }
  101. /**
  102. * Registers an callback function which must return an encryption module instance
  103. *
  104. * @param string $id
  105. * @param string $displayName
  106. * @param callable $callback
  107. * @throws Exceptions\ModuleAlreadyExistsException
  108. */
  109. public function registerEncryptionModule($id, $displayName, callable $callback) {
  110. if (isset($this->encryptionModules[$id])) {
  111. throw new Exceptions\ModuleAlreadyExistsException($id, $displayName);
  112. }
  113. $this->encryptionModules[$id] = [
  114. 'id' => $id,
  115. 'displayName' => $displayName,
  116. 'callback' => $callback,
  117. ];
  118. $defaultEncryptionModuleId = $this->getDefaultEncryptionModuleId();
  119. if (empty($defaultEncryptionModuleId)) {
  120. $this->setDefaultEncryptionModule($id);
  121. }
  122. }
  123. /**
  124. * Unregisters an encryption module
  125. *
  126. * @param string $moduleId
  127. */
  128. public function unregisterEncryptionModule($moduleId) {
  129. unset($this->encryptionModules[$moduleId]);
  130. }
  131. /**
  132. * get a list of all encryption modules
  133. *
  134. * @return array [id => ['id' => $id, 'displayName' => $displayName, 'callback' => callback]]
  135. */
  136. public function getEncryptionModules() {
  137. return $this->encryptionModules;
  138. }
  139. /**
  140. * get a specific encryption module
  141. *
  142. * @param string $moduleId
  143. * @return IEncryptionModule
  144. * @throws Exceptions\ModuleDoesNotExistsException
  145. */
  146. public function getEncryptionModule($moduleId = '') {
  147. if (empty($moduleId)) {
  148. return $this->getDefaultEncryptionModule();
  149. }
  150. if (isset($this->encryptionModules[$moduleId])) {
  151. return call_user_func($this->encryptionModules[$moduleId]['callback']);
  152. }
  153. $message = "Module with ID: $moduleId does not exist.";
  154. $hint = $this->l->t('Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator.', [$moduleId]);
  155. throw new Exceptions\ModuleDoesNotExistsException($message, $hint);
  156. }
  157. /**
  158. * get default encryption module
  159. *
  160. * @return \OCP\Encryption\IEncryptionModule
  161. * @throws Exceptions\ModuleDoesNotExistsException
  162. */
  163. protected function getDefaultEncryptionModule() {
  164. $defaultModuleId = $this->getDefaultEncryptionModuleId();
  165. if (empty($defaultModuleId)) {
  166. $message = 'No default encryption module defined';
  167. throw new Exceptions\ModuleDoesNotExistsException($message);
  168. }
  169. if (isset($this->encryptionModules[$defaultModuleId])) {
  170. return call_user_func($this->encryptionModules[$defaultModuleId]['callback']);
  171. }
  172. $message = 'Default encryption module not loaded';
  173. throw new Exceptions\ModuleDoesNotExistsException($message);
  174. }
  175. /**
  176. * set default encryption module Id
  177. *
  178. * @param string $moduleId
  179. * @return bool
  180. */
  181. public function setDefaultEncryptionModule($moduleId) {
  182. try {
  183. $this->getEncryptionModule($moduleId);
  184. } catch (\Exception $e) {
  185. return false;
  186. }
  187. $this->config->setAppValue('core', 'default_encryption_module', $moduleId);
  188. return true;
  189. }
  190. /**
  191. * get default encryption module Id
  192. *
  193. * @return string
  194. */
  195. public function getDefaultEncryptionModuleId() {
  196. return $this->config->getAppValue('core', 'default_encryption_module');
  197. }
  198. /**
  199. * Add storage wrapper
  200. */
  201. public function setupStorage() {
  202. // If encryption is disabled and there are no loaded modules it makes no sense to load the wrapper
  203. if (!empty($this->encryptionModules) || $this->isEnabled()) {
  204. $encryptionWrapper = new EncryptionWrapper($this->arrayCache, $this, $this->logger);
  205. Filesystem::addStorageWrapper('oc_encryption', [$encryptionWrapper, 'wrapStorage'], 2);
  206. }
  207. }
  208. /**
  209. * check if key storage is ready
  210. *
  211. * @return bool
  212. */
  213. protected function isKeyStorageReady() {
  214. $rootDir = $this->util->getKeyStorageRoot();
  215. // the default root is always valid
  216. if ($rootDir === '') {
  217. return true;
  218. }
  219. // check if key storage is mounted correctly
  220. if ($this->rootView->file_exists($rootDir . '/' . Storage::KEY_STORAGE_MARKER)) {
  221. return true;
  222. }
  223. return false;
  224. }
  225. }