You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

273 lines
6.9 KiB

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