helper.php 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. <?php
  2. /**
  3. * ownCloud
  4. *
  5. * @author Florin Peter
  6. * @copyright 2013 Florin Peter <owncloud@florin-peter.de>
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
  10. * License as published by the Free Software Foundation; either
  11. * version 3 of the License, or any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
  17. *
  18. * You should have received a copy of the GNU Affero General Public
  19. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  20. *
  21. */
  22. namespace OCA\Encryption;
  23. /**
  24. * @brief Class to manage registration of hooks an various helper methods
  25. * @package OCA\Encryption
  26. */
  27. class Helper {
  28. /**
  29. * @brief register share related hooks
  30. *
  31. */
  32. public static function registerShareHooks() {
  33. \OCP\Util::connectHook('OCP\Share', 'pre_shared', 'OCA\Encryption\Hooks', 'preShared');
  34. \OCP\Util::connectHook('OCP\Share', 'post_shared', 'OCA\Encryption\Hooks', 'postShared');
  35. \OCP\Util::connectHook('OCP\Share', 'post_unshare', 'OCA\Encryption\Hooks', 'postUnshare');
  36. }
  37. /**
  38. * @brief register user related hooks
  39. *
  40. */
  41. public static function registerUserHooks() {
  42. \OCP\Util::connectHook('OC_User', 'post_login', 'OCA\Encryption\Hooks', 'login');
  43. \OCP\Util::connectHook('OC_User', 'post_setPassword', 'OCA\Encryption\Hooks', 'setPassphrase');
  44. \OCP\Util::connectHook('OC_User', 'pre_setPassword', 'OCA\Encryption\Hooks', 'preSetPassphrase');
  45. \OCP\Util::connectHook('OC_User', 'post_createUser', 'OCA\Encryption\Hooks', 'postCreateUser');
  46. \OCP\Util::connectHook('OC_User', 'post_deleteUser', 'OCA\Encryption\Hooks', 'postDeleteUser');
  47. }
  48. /**
  49. * @brief register filesystem related hooks
  50. *
  51. */
  52. public static function registerFilesystemHooks() {
  53. \OCP\Util::connectHook('OC_Filesystem', 'post_rename', 'OCA\Encryption\Hooks', 'postRename');
  54. }
  55. /**
  56. * @brief register app management related hooks
  57. *
  58. */
  59. public static function registerAppHooks() {
  60. \OCP\Util::connectHook('OC_App', 'pre_disable', 'OCA\Encryption\Hooks', 'preDisable');
  61. }
  62. /**
  63. * @brief setup user for files_encryption
  64. *
  65. * @param Util $util
  66. * @param string $password
  67. * @return bool
  68. */
  69. public static function setupUser($util, $password) {
  70. // Check files_encryption infrastructure is ready for action
  71. if (!$util->ready()) {
  72. \OCP\Util::writeLog('Encryption library', 'User account "' . $util->getUserId()
  73. . '" is not ready for encryption; configuration started', \OCP\Util::DEBUG);
  74. if (!$util->setupServerSide($password)) {
  75. return false;
  76. }
  77. }
  78. return true;
  79. }
  80. /**
  81. * @brief enable recovery
  82. *
  83. * @param $recoveryKeyId
  84. * @param $recoveryPassword
  85. * @internal param \OCA\Encryption\Util $util
  86. * @internal param string $password
  87. * @return bool
  88. */
  89. public static function adminEnableRecovery($recoveryKeyId, $recoveryPassword) {
  90. $view = new \OC\Files\View('/');
  91. if ($recoveryKeyId === null) {
  92. $recoveryKeyId = 'recovery_' . substr(md5(time()), 0, 8);
  93. \OC_Appconfig::setValue('files_encryption', 'recoveryKeyId', $recoveryKeyId);
  94. }
  95. if (!$view->is_dir('/owncloud_private_key')) {
  96. $view->mkdir('/owncloud_private_key');
  97. }
  98. if (
  99. (!$view->file_exists("/public-keys/" . $recoveryKeyId . ".public.key")
  100. || !$view->file_exists("/owncloud_private_key/" . $recoveryKeyId . ".private.key"))
  101. ) {
  102. $keypair = \OCA\Encryption\Crypt::createKeypair();
  103. \OC_FileProxy::$enabled = false;
  104. // Save public key
  105. if (!$view->is_dir('/public-keys')) {
  106. $view->mkdir('/public-keys');
  107. }
  108. $view->file_put_contents('/public-keys/' . $recoveryKeyId . '.public.key', $keypair['publicKey']);
  109. // Encrypt private key empty passphrase
  110. $encryptedPrivateKey = \OCA\Encryption\Crypt::symmetricEncryptFileContent($keypair['privateKey'], $recoveryPassword);
  111. // Save private key
  112. $view->file_put_contents('/owncloud_private_key/' . $recoveryKeyId . '.private.key', $encryptedPrivateKey);
  113. \OC_FileProxy::$enabled = true;
  114. // Set recoveryAdmin as enabled
  115. \OC_Appconfig::setValue('files_encryption', 'recoveryAdminEnabled', 1);
  116. $return = true;
  117. } else { // get recovery key and check the password
  118. $util = new \OCA\Encryption\Util(new \OC_FilesystemView('/'), \OCP\User::getUser());
  119. $return = $util->checkRecoveryPassword($recoveryPassword);
  120. if ($return) {
  121. \OC_Appconfig::setValue('files_encryption', 'recoveryAdminEnabled', 1);
  122. }
  123. }
  124. return $return;
  125. }
  126. /**
  127. * @brief disable recovery
  128. *
  129. * @param $recoveryPassword
  130. * @return bool
  131. */
  132. public static function adminDisableRecovery($recoveryPassword) {
  133. $util = new Util(new \OC_FilesystemView('/'), \OCP\User::getUser());
  134. $return = $util->checkRecoveryPassword($recoveryPassword);
  135. if ($return) {
  136. // Set recoveryAdmin as disabled
  137. \OC_Appconfig::setValue('files_encryption', 'recoveryAdminEnabled', 0);
  138. }
  139. return $return;
  140. }
  141. /**
  142. * @brief checks if access is public/anonymous user
  143. * @return bool
  144. */
  145. public static function isPublicAccess() {
  146. if (\OCP\USER::getUser() === false
  147. || (isset($_GET['service']) && $_GET['service'] == 'files'
  148. && isset($_GET['t']))
  149. ) {
  150. return true;
  151. } else {
  152. return false;
  153. }
  154. }
  155. /**
  156. * @brief Format a path to be relative to the /user/files/ directory
  157. * @param string $path the absolute path
  158. * @return string e.g. turns '/admin/files/test.txt' into 'test.txt'
  159. */
  160. public static function stripUserFilesPath($path) {
  161. $trimmed = ltrim($path, '/');
  162. $split = explode('/', $trimmed);
  163. // it is not a file relative to data/user/files
  164. if (count($split) < 3 || $split[1] !== 'files') {
  165. return false;
  166. }
  167. $sliced = array_slice($split, 2);
  168. $relPath = implode('/', $sliced);
  169. return $relPath;
  170. }
  171. /**
  172. * @brief get path to the correspondig file in data/user/files
  173. * @param string $path path to a version or a file in the trash
  174. * @return string path to correspondig file relative to data/user/files
  175. */
  176. public static function getPathToRealFile($path) {
  177. $trimmed = ltrim($path, '/');
  178. $split = explode('/', $trimmed);
  179. if (count($split) < 3 || $split[1] !== "files_versions") {
  180. return false;
  181. }
  182. $sliced = array_slice($split, 2);
  183. $realPath = implode('/', $sliced);
  184. //remove the last .v
  185. $realPath = substr($realPath, 0, strrpos($realPath, '.v'));
  186. return $realPath;
  187. }
  188. /**
  189. * @brief redirect to a error page
  190. */
  191. public static function redirectToErrorPage() {
  192. $location = \OC_Helper::linkToAbsolute('apps/files_encryption/files', 'error.php');
  193. $post = 0;
  194. if(count($_POST) > 0) {
  195. $post = 1;
  196. }
  197. header('Location: ' . $location . '?p=' . $post);
  198. exit();
  199. }
  200. /**
  201. * check requirements for encryption app.
  202. * @return bool true if requirements are met
  203. */
  204. public static function checkRequirements() {
  205. $result = true;
  206. //openssl extension needs to be loaded
  207. $result &= extension_loaded("openssl");
  208. // we need php >= 5.3.3
  209. $result &= version_compare(phpversion(), '5.3.3', '>=');
  210. return (bool) $result;
  211. }
  212. /**
  213. * check some common errors if the server isn't configured properly for encryption
  214. * @return bool true if configuration seems to be OK
  215. */
  216. public static function checkConfiguration() {
  217. if(openssl_pkey_new(array('private_key_bits' => 4096))) {
  218. return true;
  219. } else {
  220. while ($msg = openssl_error_string()) {
  221. \OCP\Util::writeLog('Encryption library', 'openssl_pkey_new() fails: ' . $msg, \OCP\Util::ERROR);
  222. }
  223. return false;
  224. }
  225. }
  226. /**
  227. * @brief glob uses different pattern than regular expressions, escape glob pattern only
  228. * @param unescaped path
  229. * @return escaped path
  230. */
  231. public static function escapeGlobPattern($path) {
  232. return preg_replace('/(\*|\?|\[)/', '[$1]', $path);
  233. }
  234. }