Compare commits
551 Commits
fix/systemtags
...
v5.0.8
| Author | SHA1 | Date | |
|---|---|---|---|
| 7d7b7e6e63 | |||
| 97d1b07445 | |||
| 0916bff81d | |||
| 36491371c8 | |||
| 2a41ff9204 | |||
| 52226e6a71 | |||
| c14206e3f8 | |||
| 54a1239680 | |||
| 16a3502cf1 | |||
| b2cfa01e57 | |||
| 79558c26a0 | |||
| 2634eb33f1 | |||
| 9d2495c63f | |||
| ba11ab92c7 | |||
| 133279714b | |||
| 2fa95cdebc | |||
| 0cc1f6e70a | |||
| db51ffc553 | |||
| 5c5a8a0eba | |||
| 7bc153a87a | |||
| f535b57896 | |||
| cbe97b5df2 | |||
| c818115a4f | |||
| ec1c769da3 | |||
| 2177001152 | |||
| a46a1eed6e | |||
| 3a2603e1fe | |||
| 126ab4ee11 | |||
| b585e960e7 | |||
| c60c76d03b | |||
| 6d1e2dc8c0 | |||
| 4bf8a93fbd | |||
| fc9e3c63f6 | |||
| 87e0a1f85c | |||
| 6d70b64fab | |||
| 9d33ed376d | |||
| 07377ed431 | |||
| 24fa167898 | |||
| 804eee87c9 | |||
| d01854fd75 | |||
| 2dedc3aa57 | |||
| b722f8bba3 | |||
| 4a67257c42 | |||
| 8dd61163bc | |||
| 0d36205083 | |||
| f13ce01499 | |||
| d4c58027e0 | |||
| dbb2457d81 | |||
| 1ed103f650 | |||
| b46c7fe872 | |||
| 0fb1d3421f | |||
| 42b0fa0c9f | |||
| dc748f3ced | |||
| a902e5048a | |||
| 72e6d915d4 | |||
| 93430ec17e | |||
| 6857e87a82 | |||
| c20653cedc | |||
| 7bc3edae0a | |||
| f155826dc2 | |||
| d6f2fe6a6b | |||
| 9532859e4d | |||
| 61c569c76a | |||
| 919c0b6248 | |||
| 9a4f2f1318 | |||
| c459a5cec2 | |||
| a7b01ae74d | |||
| 102a0415d4 | |||
| 3a2f662a0f | |||
| 73ac5c68a6 | |||
| 511a806f4e | |||
| bcb85ea79b | |||
| 4dfc560419 | |||
| 66773ac96b | |||
| f7b64993b8 | |||
| fb83481936 | |||
| a987f9f4cf | |||
| 9e5983c569 | |||
| 2a0a4ad0df | |||
| a3862c43da | |||
| b9abc8002b | |||
| 0c10c4a15d | |||
| f60a74e75f | |||
| b94272b8a3 | |||
| 8f846006d3 | |||
| 5cabb73337 | |||
| c32b267a36 | |||
| ef51a42522 | |||
| c421103ed5 | |||
| 1eae41e033 | |||
| 60173be25e | |||
| 87ef930587 | |||
| 65de4a0522 | |||
| 4df9a9aa65 | |||
| 6d3349c85e | |||
| 6ae9af16f9 | |||
| 6a7efa3a47 | |||
| 49e86ed779 | |||
| f8374faa08 | |||
| 31d565131c | |||
| 498bb50597 | |||
| 26cb6ba08c | |||
| 3e3ed0784a | |||
| 07a5914dc4 | |||
| 38d702e3f8 | |||
| a1e1456bdb | |||
| b52d765dbf | |||
| 4f75a9cf1c | |||
| 4797f9d7db | |||
| 62f01a1239 | |||
| 96e42ebff1 | |||
| fee313e256 | |||
| 437a79e2f9 | |||
| 2a26336080 | |||
| 761c7e9a51 | |||
| ba7797e6a1 | |||
| 7992953f1c | |||
| 4f99dcf699 | |||
| 850cde6ed4 | |||
| 8e5bc02e92 | |||
| 433cb9f01d | |||
| 41fa7ec791 | |||
| 908c8fdc71 | |||
| fa894beb5c | |||
| b06432fef0 | |||
| a498876aa6 | |||
| 90acda6c06 | |||
| 663c30ede0 | |||
| 5e06b068ce | |||
| c72e3ca442 | |||
| 9700b84a62 | |||
| 87f70d643e | |||
| 96983c2ad0 | |||
| cf51be0fa8 | |||
| 07b1e677a6 | |||
| 592656c699 | |||
| 1fead354b2 | |||
| 52d1797b30 | |||
| 1171a5a2e0 | |||
| 112f9f055b | |||
| b6e664c445 | |||
| f5b1f598ea | |||
| 1099960e55 | |||
| d6878f5551 | |||
| be534fecf4 | |||
| 61c89874cd | |||
| fb33c01a8f | |||
| 715648e79d | |||
| 2d876c2bf5 | |||
| 3903977166 | |||
| fe2ef4bcc4 | |||
| 28d8ed9726 | |||
| d7528a9b9f | |||
| 1d956b1faf | |||
| 5efbf25c2a | |||
| d8a55da9b6 | |||
| ca7699c8bd | |||
| 5572e1dc11 | |||
| 43146a68cf | |||
| 89191a9c1f | |||
| 68229009ac | |||
| 22394d5855 | |||
| ae2615e74d | |||
| 939bc3e71c | |||
| 7e556475f8 | |||
| a74ece336d | |||
| aa16518f66 | |||
| 56a0b7a71a | |||
| af23fa9863 | |||
| ac77c2f98c | |||
| fef186e7dc | |||
| c062322d0f | |||
| 03907da05b | |||
| bea81bcc69 | |||
| 76db8c0506 | |||
| f637118008 | |||
| e65ff413e2 | |||
| 4e2ff14cda | |||
| 5d7aa761bc | |||
| 86a1a7ea53 | |||
| 380a402699 | |||
| 7a5c4fd092 | |||
| fe9a9c3264 | |||
| 30b00f4bc1 | |||
| 1d38e244fd | |||
| b3d87def99 | |||
| 1914353c49 | |||
| d45bddc035 | |||
| d33b215b21 | |||
| 64cb67c6d7 | |||
| 9620f0df98 | |||
| a7017167bc | |||
| 1fb9a5126f | |||
| 514e47f57e | |||
| 49b4d8e3f0 | |||
| 07fb6a0d57 | |||
| 301b0f1b77 | |||
| 8c07eddc65 | |||
| 1d5c9d84fd | |||
| 76bb5a4ba7 | |||
| 7252d09dd2 | |||
| 33afa9a253 | |||
| 2d5f97ef2e | |||
| 4b50145617 | |||
| 1fa76e53dc | |||
| 243b7d82d4 | |||
| ec80dd5e3a | |||
| d3a663469a | |||
| 1b39f46cc2 | |||
| 07c3f08e66 | |||
| e35303f702 | |||
| 68960db77e | |||
| 03e5982026 | |||
| 9046c65af5 | |||
| f3620b7c03 | |||
| 7b95d031a1 | |||
| 78520cdfc7 | |||
| 1ef101c439 | |||
| a1401f686a | |||
| 5eded27fa3 | |||
| 7c9b34a416 | |||
| 6e3acd3111 | |||
| aed15ef72b | |||
| 5353bcc246 | |||
| 2e5fcf4d56 | |||
| 4dac837046 | |||
| 512571c54f | |||
| 0fa0e92883 | |||
| 8e80aa3630 | |||
| 15e0fc6b7f | |||
| 6d667c02fc | |||
| 8e512bdfdf | |||
| a5b75d348f | |||
| ae2ab015d9 | |||
| a8c3d51a49 | |||
| f9c9cceb30 | |||
| acff4fc4fa | |||
| deeb1cfd50 | |||
| 955eff8d87 | |||
| 1b4d2e851d | |||
| 1c49784f7f | |||
| 9a25f7b849 | |||
| 71cdd17df4 | |||
| 3891a4cef9 | |||
| 0017753ec5 | |||
| a4ef49c2be | |||
| 621d18f77d | |||
| 0c5bd4e578 | |||
| 54768402b6 | |||
| 7316d6f850 | |||
| daf5d47821 | |||
| c872042616 | |||
| 0cf6e5693a | |||
| 9ac29cd122 | |||
| 55e4e054d6 | |||
| 3cbe6b2d8b | |||
| 087b21c913 | |||
| 09765ea27c | |||
| 189d251c6a | |||
| 07fb230cbe | |||
| faad2d0d69 | |||
| c7d8cd9679 | |||
| 6c53253ad6 | |||
| 2018e94b41 | |||
| e044260bc1 | |||
| 12f5b5ce61 | |||
| 210ae9e5f7 | |||
| f164f43590 | |||
| 9a25c39c36 | |||
| 397dc3dcde | |||
| 8c235de826 | |||
| e7734d0c46 | |||
| 1a638cd3a8 | |||
| 890b7702ef | |||
| a4018ad4d7 | |||
| c6dc7993b6 | |||
| 7b8f64d20f | |||
| cb12cf8324 | |||
| 3bd0141e6d | |||
| 89546bf90c | |||
| c960cfcd55 | |||
| a99676a73e | |||
| 8fa5f35e4f | |||
| c4b40af602 | |||
| 1c3ced26c1 | |||
| 33520c2985 | |||
| 365c77c52c | |||
| 0eb32bfc93 | |||
| ae98c50b16 | |||
| c528fbb9bb | |||
| 0e4d45a56d | |||
| a55a92752a | |||
| df39e681b5 | |||
| 2ed0d6e1dc | |||
| 34fda272d6 | |||
| 412f0962e7 | |||
| 74e475cf2d | |||
| 1291f36709 | |||
| 1284179589 | |||
| 75fd96878a | |||
| f6dac667fd | |||
| 197914480e | |||
| 3a6181620a | |||
| 41aef94c24 | |||
| 0e3e3d15a1 | |||
| 6573fdc717 | |||
| 0e2c3dc89e | |||
| 34c8fd5149 | |||
| 55332fe1bb | |||
| 57339b725e | |||
| c8d63e3c79 | |||
| 7a1992a170 | |||
| 752a316a52 | |||
| 408aed3175 | |||
| 1282c33db4 | |||
| 256e53ba68 | |||
| 2020f35c6a | |||
| cc495ed6d8 | |||
| f2911e76bc | |||
| 726350ea97 | |||
| 9a53d50e16 | |||
| bc767f1899 | |||
| 35b1f40ba4 | |||
| a23e8833c3 | |||
| 8875bae0c3 | |||
| 144977352d | |||
| 35da6f25b1 | |||
| c43ec33ecb | |||
| 08561da5b6 | |||
| d6fe8f213d | |||
| dd8c1f7759 | |||
| 7ff26af107 | |||
| 44fedae69f | |||
| ffb91cdd66 | |||
| 1dfb757593 | |||
| c0047b9079 | |||
| 0d5c82cd2a | |||
| e3c7386be4 | |||
| 5db33b47c2 | |||
| 6c26143516 | |||
| 9c605c3fd1 | |||
| 0639634782 | |||
| 7d5b8e85ac | |||
| c99b667021 | |||
| c08c22aa54 | |||
| cbd216414a | |||
| 5428086204 | |||
| b38a1adf2d | |||
| a5978ad544 | |||
| b24e6f11ba | |||
| d642480c55 | |||
| 556ea61f8e | |||
| 3bcd10a97c | |||
| 54a3038dc0 | |||
| a6ece109ba | |||
| 4c008a8f92 | |||
| 2030037301 | |||
| 794ed99927 | |||
| 65c7746504 | |||
| faa51bd002 | |||
| d9f10e2c26 | |||
| 8d92aaf3b7 | |||
| 9894145f8d | |||
| deba972093 | |||
| 41dc1fee68 | |||
| 72ea678c0e | |||
| ff49824312 | |||
| bb3d39f728 | |||
| a7f1269f92 | |||
| 7ae0e38c4f | |||
| b626e514f7 | |||
| 3e8beddfe3 | |||
| 18d515450a | |||
| 969bcb3ced | |||
| 1d255ebf70 | |||
| 9aae21db79 | |||
| 536117da2a | |||
| 29054c27c9 | |||
| 207bf4bffe | |||
| 4e11814a0c | |||
| 32667f8c38 | |||
| 1c06bec262 | |||
| a82965edf2 | |||
| 76f12567be | |||
| d7cbf45d15 | |||
| 05a2f31352 | |||
| 811d649262 | |||
| 6e32fc1db7 | |||
| e718a728c4 | |||
| a065ae5db2 | |||
| 623db8549e | |||
| 16ef7c62dc | |||
| 0978ebd195 | |||
| 1ddfefed3f | |||
| 16b62c697f | |||
| f70b1c1b0d | |||
| b400c29944 | |||
| 86d8b831f2 | |||
| 5fbb8b374d | |||
| 0a3e87c890 | |||
| 2220802cdd | |||
| 0ff7aa4436 | |||
| 5e817584db | |||
| fbcb4b2673 | |||
| edae196f34 | |||
| 11dcc29c0c | |||
| d068325bdb | |||
| 6dc66e14fb | |||
| 30d5c70180 | |||
| e9c3caeb9b | |||
| 9a0344f1d5 | |||
| 33b27362ff | |||
| 15c50017cc | |||
| c43e33cdf5 | |||
| ef1481c7bb | |||
| 892d85556b | |||
| 5fb891e20a | |||
| c241985f04 | |||
| 9a4fe09979 | |||
| e26cdc4cdd | |||
| 317b00988a | |||
| 9159d55639 | |||
| 06ab314c15 | |||
| f26a4e0b80 | |||
| 2c3d66c776 | |||
| aef66e06b3 | |||
| 67a84ad487 | |||
| 440148aa1f | |||
| b35148bbb6 | |||
| 5ef8762886 | |||
| b52666567a | |||
| 1e580bf04b | |||
| 2a5599b3e0 | |||
| f82799cf7d | |||
| e6d286b449 | |||
| dc3a7e09af | |||
| 5add001373 | |||
| 5317e7071e | |||
| f5592cc88e | |||
| 09f11c2679 | |||
| db48f5302a | |||
| 4cd4bbd489 | |||
| 7b42c20180 | |||
| 835df6c177 | |||
| 5268aadb62 | |||
| d7dccfb648 | |||
| cc204a608a | |||
| 22c8194cc8 | |||
| 8231f657d9 | |||
| 4f9f5a41b1 | |||
| 5944ee6ebe | |||
| e1b6574ce7 | |||
| c16860e648 | |||
| d4a492d321 | |||
| a004266b7c | |||
| da96d1adb0 | |||
| ed39e47c9d | |||
| b9213cf451 | |||
| f308b0e321 | |||
| eeebf21fce | |||
| 75d944f96a | |||
| 9bfdfdf071 | |||
| 2bb22d3aab | |||
| 4742d0eb94 | |||
| c901709d53 | |||
| 84bc4c175a | |||
| 4d50a21eb4 | |||
| 37971133f1 | |||
| c962f9db47 | |||
| 6333036a1a | |||
| 73758c1f78 | |||
| 7e9e94d8d7 | |||
| 07d0245336 | |||
| 0bbac66ec5 | |||
| 4411de0dbf | |||
| 871bbbba8a | |||
| 4384cf70da | |||
| e0cf61dfc8 | |||
| 2387fbd9dd | |||
| 0b6b5e807c | |||
| b2b78228d6 | |||
| 2e5829445f | |||
| e63a12a481 | |||
| 56302ff9cf | |||
| 707de3e644 | |||
| 19a65f6c3f | |||
| 011ab3a11c | |||
| ad62d89f2b | |||
| 9b84c50f15 | |||
| 01ffa519d5 | |||
| fe73b5919d | |||
| 5ad7eb080e | |||
| 2ce8329503 | |||
| 83e5383912 | |||
| 660d204cbf | |||
| d091db4bc7 | |||
| d61e820285 | |||
| 85613cc66c | |||
| 0fb9cc3c25 | |||
| 76e5ffaa92 | |||
| 9a26b1e0a6 | |||
| bfd69dc8e0 | |||
| 0d075df15e | |||
| c82f43ee55 | |||
| 0eaf141528 | |||
| ee0dab1b13 | |||
| 98ee292c93 | |||
| 4ff5658475 | |||
| 7de540b8ee | |||
| 9a41453254 | |||
| 707b319157 | |||
| f7911412e0 | |||
| 1cb3872df0 | |||
| 432fb55d91 | |||
| 98c5d10bb5 | |||
| 84a2be1aad | |||
| 9e383db75b | |||
| c12b30f7a2 | |||
| 5bf111e75f | |||
| f42d98edab | |||
| d392aa81c7 | |||
| 532e5463db | |||
| cfea3ce2d7 | |||
| 2c76ee1c8b | |||
| 9a2c1cbcc3 | |||
| e6616ed758 | |||
| b51b41468d | |||
| 6f86802a48 | |||
| 0c6c175d62 | |||
| 885b81ba23 | |||
| fc86815a2c | |||
| 6ca2abc108 | |||
| 0fe2f81a0c | |||
| 2cd52e52c8 | |||
| d06fec658c | |||
| 049329588f | |||
| 09d3b9ef26 | |||
| 92ce2bf89b | |||
| ca93f6e1de | |||
| d166471a46 | |||
| 896c56996e | |||
| 6017ca5ddd | |||
| eedc1e76db | |||
| 510cbc4ff9 | |||
| 9b9497bedf | |||
| 8846edd919 | |||
| 253f7ec932 | |||
| 8bafcd1414 | |||
| 40bb805b83 | |||
| 00030a6c24 | |||
| 2afece459a |
@@ -73,3 +73,4 @@ data-autotest
|
||||
/tests/coverage*
|
||||
/tests/autoconfig*
|
||||
/tests/autotest*
|
||||
/l10n/.tx/
|
||||
@@ -32,5 +32,8 @@ RewriteRule ^remote/(.*) remote.php [QSA,L]
|
||||
AddType image/svg+xml svg svgz
|
||||
AddEncoding gzip svgz
|
||||
</IfModule>
|
||||
<IfModule dir_module>
|
||||
DirectoryIndex index.php index.html
|
||||
</IfModule>
|
||||
AddDefaultCharset utf-8
|
||||
Options -Indexes
|
||||
|
||||
@@ -8,7 +8,7 @@ OCP\JSON::callCheck();
|
||||
|
||||
// Get data
|
||||
$dir = stripslashes($_POST["dir"]);
|
||||
$files = isset($_POST["file"]) ? stripslashes($_POST["file"]) : stripslashes($_POST["files"]);
|
||||
$files = isset($_POST["file"]) ? $_POST["file"] : $_POST["files"];
|
||||
|
||||
$files = json_decode($files);
|
||||
$filesWithError = '';
|
||||
|
||||
+29
-13
@@ -4,6 +4,16 @@ session_write_close();
|
||||
|
||||
$force = (isset($_GET['force']) and ($_GET['force'] === 'true'));
|
||||
$dir = isset($_GET['dir']) ? $_GET['dir'] : '';
|
||||
if (isset($_GET['users'])) {
|
||||
OC_JSON::checkAdminUser();
|
||||
if ($_GET['users'] === 'all') {
|
||||
$users = OC_User::getUsers();
|
||||
} else {
|
||||
$users = json_decode($_GET['users']);
|
||||
}
|
||||
} else {
|
||||
$users = array(OC_User::getUser());
|
||||
}
|
||||
|
||||
$eventSource = new OC_EventSource();
|
||||
ScanListener::$eventSource = $eventSource;
|
||||
@@ -12,21 +22,27 @@ ScanListener::$view = \OC\Files\Filesystem::getView();
|
||||
OC_Hook::connect('\OC\Files\Cache\Scanner', 'scan_folder', 'ScanListener', 'folder');
|
||||
OC_Hook::connect('\OC\Files\Cache\Scanner', 'scan_file', 'ScanListener', 'file');
|
||||
|
||||
$absolutePath = \OC\Files\Filesystem::getView()->getAbsolutePath($dir);
|
||||
foreach ($users as $user) {
|
||||
$eventSource->send('user', $user);
|
||||
OC_Util::tearDownFS();
|
||||
OC_Util::setupFS($user);
|
||||
|
||||
$mountPoints = \OC\Files\Filesystem::getMountPoints($absolutePath);
|
||||
$mountPoints[] = \OC\Files\Filesystem::getMountPoint($absolutePath);
|
||||
$mountPoints = array_reverse($mountPoints); //start with the mount point of $dir
|
||||
$absolutePath = \OC\Files\Filesystem::getView()->getAbsolutePath($dir);
|
||||
|
||||
foreach ($mountPoints as $mountPoint) {
|
||||
$storage = \OC\Files\Filesystem::getStorage($mountPoint);
|
||||
if ($storage) {
|
||||
ScanListener::$mountPoints[$storage->getId()] = $mountPoint;
|
||||
$scanner = $storage->getScanner();
|
||||
if ($force) {
|
||||
$scanner->scan('');
|
||||
} else {
|
||||
$scanner->backgroundScan();
|
||||
$mountPoints = \OC\Files\Filesystem::getMountPoints($absolutePath);
|
||||
$mountPoints[] = \OC\Files\Filesystem::getMountPoint($absolutePath);
|
||||
$mountPoints = array_reverse($mountPoints); //start with the mount point of $dir
|
||||
|
||||
foreach ($mountPoints as $mountPoint) {
|
||||
$storage = \OC\Files\Filesystem::getStorage($mountPoint);
|
||||
if ($storage) {
|
||||
ScanListener::$mountPoints[$storage->getId()] = $mountPoint;
|
||||
$scanner = $storage->getScanner();
|
||||
if ($force) {
|
||||
$scanner->scan('', \OC\Files\Cache\Scanner::SCAN_RECURSIVE, \OC\Files\Cache\Scanner::REUSE_ETAG);
|
||||
} else {
|
||||
$scanner->backgroundScan();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+54
-14
@@ -1,17 +1,56 @@
|
||||
<?php
|
||||
|
||||
// Init owncloud
|
||||
|
||||
|
||||
// Firefox and Konqueror tries to download application/json for me. --Arthur
|
||||
OCP\JSON::setContentTypeHeader('text/plain');
|
||||
|
||||
OCP\JSON::checkLoggedIn();
|
||||
OCP\JSON::callCheck();
|
||||
// If a directory token is sent along check if public upload is permitted.
|
||||
// If not, check the login.
|
||||
// If no token is sent along, rely on login only
|
||||
|
||||
$l = OC_L10N::get('files');
|
||||
if (empty($_POST['dirToken'])) {
|
||||
// The standard case, files are uploaded through logged in users :)
|
||||
OCP\JSON::checkLoggedIn();
|
||||
$dir = isset($_POST['dir']) ? $_POST['dir'] : "";
|
||||
if (!$dir || empty($dir) || $dir === false) {
|
||||
OCP\JSON::error(array('data' => array_merge(array('message' => $l->t('Unable to set upload directory.')))));
|
||||
die();
|
||||
}
|
||||
} else {
|
||||
$linkItem = OCP\Share::getShareByToken($_POST['dirToken']);
|
||||
if ($linkItem === false) {
|
||||
OCP\JSON::error(array('data' => array_merge(array('message' => $l->t('Invalid Token')))));
|
||||
die();
|
||||
}
|
||||
|
||||
if (!($linkItem['permissions'] & OCP\PERMISSION_CREATE)) {
|
||||
OCP\JSON::checkLoggedIn();
|
||||
} else {
|
||||
// resolve reshares
|
||||
$rootLinkItem = OCP\Share::resolveReShare($linkItem);
|
||||
|
||||
// Setup FS with owner
|
||||
OC_Util::setupFS($rootLinkItem['uid_owner']);
|
||||
|
||||
// The token defines the target directory (security reasons)
|
||||
$path = \OC\Files\Filesystem::getPath($linkItem['file_source']);
|
||||
$dir = sprintf(
|
||||
"/%s/%s",
|
||||
$path,
|
||||
isset($_POST['subdir']) ? $_POST['subdir'] : ''
|
||||
);
|
||||
|
||||
if (!$dir || empty($dir) || $dir === false) {
|
||||
OCP\JSON::error(array('data' => array_merge(array('message' => $l->t('Unable to set upload directory.')))));
|
||||
die();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
OCP\JSON::callCheck();
|
||||
|
||||
|
||||
$dir = $_POST['dir'];
|
||||
// get array with current storage stats (e.g. max file size)
|
||||
$storageStats = \OCA\files\lib\Helper::buildFileStorageStatistics($dir);
|
||||
|
||||
@@ -25,7 +64,7 @@ foreach ($_FILES['files']['error'] as $error) {
|
||||
$errors = array(
|
||||
UPLOAD_ERR_OK => $l->t('There is no error, the file uploaded with success'),
|
||||
UPLOAD_ERR_INI_SIZE => $l->t('The uploaded file exceeds the upload_max_filesize directive in php.ini: ')
|
||||
. ini_get('upload_max_filesize'),
|
||||
. ini_get('upload_max_filesize'),
|
||||
UPLOAD_ERR_FORM_SIZE => $l->t('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form'),
|
||||
UPLOAD_ERR_PARTIAL => $l->t('The uploaded file was only partially uploaded'),
|
||||
UPLOAD_ERR_NO_FILE => $l->t('No file was uploaded'),
|
||||
@@ -40,17 +79,17 @@ $files = $_FILES['files'];
|
||||
|
||||
$error = '';
|
||||
|
||||
$maxUploadFilesize = OCP\Util::maxUploadFilesize($dir);
|
||||
$maxHumanFilesize = OCP\Util::humanFileSize($maxUploadFilesize);
|
||||
$maxUploadFileSize = $storageStats['uploadMaxFilesize'];
|
||||
$maxHumanFileSize = OCP\Util::humanFileSize($maxUploadFileSize);
|
||||
|
||||
$totalSize = 0;
|
||||
foreach ($files['size'] as $size) {
|
||||
$totalSize += $size;
|
||||
}
|
||||
if ($totalSize > $maxUploadFilesize) {
|
||||
if ($maxUploadFileSize >= 0 and $totalSize > $maxUploadFileSize) {
|
||||
OCP\JSON::error(array('data' => array('message' => $l->t('Not enough storage available'),
|
||||
'uploadMaxFilesize' => $maxUploadFilesize,
|
||||
'maxHumanFilesize' => $maxHumanFilesize)));
|
||||
'uploadMaxFilesize' => $maxUploadFileSize,
|
||||
'maxHumanFilesize' => $maxHumanFileSize)));
|
||||
exit();
|
||||
}
|
||||
|
||||
@@ -71,8 +110,9 @@ if (strpos($dir, '..') === false) {
|
||||
'size' => $meta['size'],
|
||||
'id' => $meta['fileid'],
|
||||
'name' => basename($target),
|
||||
'uploadMaxFilesize' => $maxUploadFilesize,
|
||||
'maxHumanFilesize' => $maxHumanFilesize
|
||||
'originalname' => $files['name'][$i],
|
||||
'uploadMaxFilesize' => $maxUploadFileSize,
|
||||
'maxHumanFilesize' => $maxHumanFileSize
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,3 +12,10 @@ OCP\App::addNavigationEntry( array( "id" => "files_index",
|
||||
"name" => $l->t("Files") ));
|
||||
|
||||
OC_Search::registerProvider('OC_Search_Provider_File');
|
||||
|
||||
// cache hooks must be connected before all other apps.
|
||||
// since 'files' is always loaded first the hooks need to be connected here
|
||||
\OC_Hook::connect('OC_Filesystem', 'post_write', '\OC\Files\Cache\Updater', 'writeHook');
|
||||
\OC_Hook::connect('OC_Filesystem', 'post_touch', '\OC\Files\Cache\Updater', 'touchHook');
|
||||
\OC_Hook::connect('OC_Filesystem', 'post_delete', '\OC\Files\Cache\Updater', 'deleteHook');
|
||||
\OC_Hook::connect('OC_Filesystem', 'post_rename', '\OC\Files\Cache\Updater', 'renameHook');
|
||||
@@ -45,7 +45,11 @@
|
||||
}
|
||||
|
||||
#uploadprogresswrapper { float: right; position: relative; }
|
||||
#uploadprogresswrapper #uploadprogressbar { position:relative; display:inline-block; width:10em; height:1.5em; top:.4em; }
|
||||
#uploadprogresswrapper #uploadprogressbar {
|
||||
position:relative; float: right;
|
||||
margin-left: 12px; width:10em; height:1.5em; top:.4em;
|
||||
display:inline-block;
|
||||
}
|
||||
|
||||
/* FILE TABLE */
|
||||
|
||||
@@ -84,7 +88,7 @@ table td.filename input.filename { width:100%; cursor:text; }
|
||||
table td.filename a, table td.login, table td.logout, table td.download, table td.upload, table td.create, table td.delete { padding:.2em .5em .5em 0; }
|
||||
table td.filename .nametext, .uploadtext, .modified { float:left; padding:.3em 0; }
|
||||
/* TODO fix usability bug (accidental file/folder selection) */
|
||||
table td.filename .nametext { overflow:hidden; text-overflow:ellipsis; }
|
||||
table td.filename .nametext { overflow:hidden; text-overflow:ellipsis; max-width:800px; }
|
||||
table td.filename .uploadtext { font-weight:normal; margin-left:.5em; }
|
||||
table td.filename form { font-size:.85em; margin-left:3em; margin-right:3em; }
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ OCP\User::checkLoggedIn();
|
||||
|
||||
// Load the files we need
|
||||
OCP\Util::addStyle('files', 'files');
|
||||
OCP\Util::addscript('files', 'file-upload');
|
||||
OCP\Util::addscript('files', 'jquery.iframe-transport');
|
||||
OCP\Util::addscript('files', 'jquery.fileupload');
|
||||
OCP\Util::addscript('files', 'jquery-visibility');
|
||||
@@ -136,5 +137,6 @@ if ($needUpgrade) {
|
||||
$tmpl->assign('uploadMaxHumanFilesize', OCP\Util::humanFileSize($maxUploadFilesize));
|
||||
$tmpl->assign('allowZipDownload', intval(OCP\Config::getSystemValue('allowZipDownload', true)));
|
||||
$tmpl->assign('usedSpacePercent', (int)$storageInfo['relative']);
|
||||
$tmpl->assign('isPublic', false);
|
||||
$tmpl->printPage();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,343 @@
|
||||
$(document).ready(function() {
|
||||
|
||||
file_upload_param = {
|
||||
dropZone: $('#content'), // restrict dropZone to content div
|
||||
//singleFileUploads is on by default, so the data.files array will always have length 1
|
||||
add: function(e, data) {
|
||||
|
||||
if(data.files[0].type === '' && data.files[0].size == 4096)
|
||||
{
|
||||
data.textStatus = 'dirorzero';
|
||||
data.errorThrown = t('files','Unable to upload your file as it is a directory or has 0 bytes');
|
||||
var fu = $(this).data('blueimp-fileupload') || $(this).data('fileupload');
|
||||
fu._trigger('fail', e, data);
|
||||
return true; //don't upload this file but go on with next in queue
|
||||
}
|
||||
|
||||
var totalSize=0;
|
||||
$.each(data.originalFiles, function(i,file){
|
||||
totalSize+=file.size;
|
||||
});
|
||||
|
||||
if(totalSize>$('#max_upload').val()){
|
||||
data.textStatus = 'notenoughspace';
|
||||
data.errorThrown = t('files','Not enough space available');
|
||||
var fu = $(this).data('blueimp-fileupload') || $(this).data('fileupload');
|
||||
fu._trigger('fail', e, data);
|
||||
return false; //don't upload anything
|
||||
}
|
||||
|
||||
// start the actual file upload
|
||||
var jqXHR = data.submit();
|
||||
|
||||
// remember jqXHR to show warning to user when he navigates away but an upload is still in progress
|
||||
if (typeof data.context !== 'undefined' && data.context.data('type') === 'dir') {
|
||||
var dirName = data.context.data('file');
|
||||
if(typeof uploadingFiles[dirName] === 'undefined') {
|
||||
uploadingFiles[dirName] = {};
|
||||
}
|
||||
uploadingFiles[dirName][data.files[0].name] = jqXHR;
|
||||
} else {
|
||||
uploadingFiles[data.files[0].name] = jqXHR;
|
||||
}
|
||||
|
||||
//show cancel button
|
||||
if($('html.lte9').length === 0 && data.dataType !== 'iframe') {
|
||||
$('#uploadprogresswrapper input.stop').show();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* called after the first add, does NOT have the data param
|
||||
* @param e
|
||||
*/
|
||||
start: function(e) {
|
||||
//IE < 10 does not fire the necessary events for the progress bar.
|
||||
if($('html.lte9').length > 0) {
|
||||
return;
|
||||
}
|
||||
$('#uploadprogressbar').progressbar({value:0});
|
||||
$('#uploadprogressbar').fadeIn();
|
||||
},
|
||||
fail: function(e, data) {
|
||||
if (typeof data.textStatus !== 'undefined' && data.textStatus !== 'success' ) {
|
||||
if (data.textStatus === 'abort') {
|
||||
$('#notification').text(t('files', 'Upload cancelled.'));
|
||||
} else {
|
||||
// HTTP connection problem
|
||||
$('#notification').text(data.errorThrown);
|
||||
}
|
||||
$('#notification').fadeIn();
|
||||
//hide notification after 5 sec
|
||||
setTimeout(function() {
|
||||
$('#notification').fadeOut();
|
||||
}, 5000);
|
||||
}
|
||||
delete uploadingFiles[data.files[0].name];
|
||||
},
|
||||
progress: function(e, data) {
|
||||
// TODO: show nice progress bar in file row
|
||||
},
|
||||
progressall: function(e, data) {
|
||||
//IE < 10 does not fire the necessary events for the progress bar.
|
||||
if($('html.lte9').length > 0) {
|
||||
return;
|
||||
}
|
||||
var progress = (data.loaded/data.total)*100;
|
||||
$('#uploadprogressbar').progressbar('value',progress);
|
||||
},
|
||||
/**
|
||||
* called for every successful upload
|
||||
* @param e
|
||||
* @param data
|
||||
*/
|
||||
done:function(e, data) {
|
||||
// handle different responses (json or body from iframe for ie)
|
||||
var response;
|
||||
if (typeof data.result === 'string') {
|
||||
response = data.result;
|
||||
} else {
|
||||
//fetch response from iframe
|
||||
response = data.result[0].body.innerText;
|
||||
}
|
||||
var result=$.parseJSON(response);
|
||||
|
||||
if(typeof result[0] !== 'undefined' && result[0].status === 'success') {
|
||||
var file = result[0];
|
||||
} else {
|
||||
data.textStatus = 'servererror';
|
||||
data.errorThrown = t('files', result.data.message);
|
||||
var fu = $(this).data('blueimp-fileupload') || $(this).data('fileupload');
|
||||
fu._trigger('fail', e, data);
|
||||
}
|
||||
|
||||
var filename = result[0].originalname;
|
||||
|
||||
// delete jqXHR reference
|
||||
if (typeof data.context !== 'undefined' && data.context.data('type') === 'dir') {
|
||||
var dirName = data.context.data('file');
|
||||
delete uploadingFiles[dirName][filename];
|
||||
if ($.assocArraySize(uploadingFiles[dirName]) == 0) {
|
||||
delete uploadingFiles[dirName];
|
||||
}
|
||||
} else {
|
||||
delete uploadingFiles[filename];
|
||||
}
|
||||
|
||||
},
|
||||
/**
|
||||
* called after last upload
|
||||
* @param e
|
||||
* @param data
|
||||
*/
|
||||
stop: function(e, data) {
|
||||
if(data.dataType !== 'iframe') {
|
||||
$('#uploadprogresswrapper input.stop').hide();
|
||||
}
|
||||
|
||||
//IE < 10 does not fire the necessary events for the progress bar.
|
||||
if($('html.lte9').length > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$('#uploadprogressbar').progressbar('value',100);
|
||||
$('#uploadprogressbar').fadeOut();
|
||||
}
|
||||
}
|
||||
var file_upload_handler = function() {
|
||||
$('#file_upload_start').fileupload(file_upload_param);
|
||||
};
|
||||
|
||||
|
||||
|
||||
if ( document.getElementById('data-upload-form') ) {
|
||||
$(file_upload_handler);
|
||||
}
|
||||
$.assocArraySize = function(obj) {
|
||||
// http://stackoverflow.com/a/6700/11236
|
||||
var size = 0, key;
|
||||
for (key in obj) {
|
||||
if (obj.hasOwnProperty(key)) size++;
|
||||
}
|
||||
return size;
|
||||
};
|
||||
|
||||
// warn user not to leave the page while upload is in progress
|
||||
$(window).bind('beforeunload', function(e) {
|
||||
if ($.assocArraySize(uploadingFiles) > 0)
|
||||
return t('files','File upload is in progress. Leaving the page now will cancel the upload.');
|
||||
});
|
||||
|
||||
//add multiply file upload attribute to all browsers except konqueror (which crashes when it's used)
|
||||
if(navigator.userAgent.search(/konqueror/i)==-1){
|
||||
$('#file_upload_start').attr('multiple','multiple')
|
||||
}
|
||||
|
||||
//if the breadcrumb is to long, start by replacing foldernames with '...' except for the current folder
|
||||
var crumb=$('div.crumb').first();
|
||||
while($('div.controls').height()>40 && crumb.next('div.crumb').length>0){
|
||||
crumb.children('a').text('...');
|
||||
crumb=crumb.next('div.crumb');
|
||||
}
|
||||
//if that isn't enough, start removing items from the breacrumb except for the current folder and it's parent
|
||||
var crumb=$('div.crumb').first();
|
||||
var next=crumb.next('div.crumb');
|
||||
while($('div.controls').height()>40 && next.next('div.crumb').length>0){
|
||||
crumb.remove();
|
||||
crumb=next;
|
||||
next=crumb.next('div.crumb');
|
||||
}
|
||||
//still not enough, start shorting down the current folder name
|
||||
var crumb=$('div.crumb>a').last();
|
||||
while($('div.controls').height()>40 && crumb.text().length>6){
|
||||
var text=crumb.text()
|
||||
text=text.substr(0,text.length-6)+'...';
|
||||
crumb.text(text);
|
||||
}
|
||||
|
||||
$(document).click(function(){
|
||||
$('#new>ul').hide();
|
||||
$('#new').removeClass('active');
|
||||
$('#new li').each(function(i,element){
|
||||
if($(element).children('p').length==0){
|
||||
$(element).children('form').remove();
|
||||
$(element).append('<p>'+$(element).data('text')+'</p>');
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#new li').click(function(){
|
||||
if($(this).children('p').length==0){
|
||||
return;
|
||||
}
|
||||
|
||||
$('#new li').each(function(i,element){
|
||||
if($(element).children('p').length==0){
|
||||
$(element).children('form').remove();
|
||||
$(element).append('<p>'+$(element).data('text')+'</p>');
|
||||
}
|
||||
});
|
||||
|
||||
var type=$(this).data('type');
|
||||
var text=$(this).children('p').text();
|
||||
$(this).data('text',text);
|
||||
$(this).children('p').remove();
|
||||
var form=$('<form></form>');
|
||||
var input=$('<input>');
|
||||
form.append(input);
|
||||
$(this).append(form);
|
||||
input.focus();
|
||||
form.submit(function(event){
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
var newname=input.val();
|
||||
if(type == 'web' && newname.length == 0) {
|
||||
OC.Notification.show(t('files', 'URL cannot be empty.'));
|
||||
return false;
|
||||
} else if (type != 'web' && !Files.isFileNameValid(newname)) {
|
||||
return false;
|
||||
} else if( type == 'folder' && $('#dir').val() == '/' && newname == 'Shared') {
|
||||
OC.Notification.show(t('files','Invalid folder name. Usage of \'Shared\' is reserved by ownCloud'));
|
||||
return false;
|
||||
}
|
||||
if (FileList.lastAction) {
|
||||
FileList.lastAction();
|
||||
}
|
||||
var name = getUniqueName(newname);
|
||||
if (newname != name) {
|
||||
FileList.checkName(name, newname, true);
|
||||
var hidden = true;
|
||||
} else {
|
||||
var hidden = false;
|
||||
}
|
||||
switch(type){
|
||||
case 'file':
|
||||
$.post(
|
||||
OC.filePath('files','ajax','newfile.php'),
|
||||
{dir:$('#dir').val(),filename:name},
|
||||
function(result){
|
||||
if (result.status == 'success') {
|
||||
var date=new Date();
|
||||
FileList.addFile(name,0,date,false,hidden);
|
||||
var tr=$('tr').filterAttr('data-file',name);
|
||||
tr.attr('data-mime',result.data.mime);
|
||||
tr.attr('data-id', result.data.id);
|
||||
getMimeIcon(result.data.mime,function(path){
|
||||
tr.find('td.filename').attr('style','background-image:url('+path+')');
|
||||
});
|
||||
} else {
|
||||
OC.dialogs.alert(result.data.message, t('core', 'Error'));
|
||||
}
|
||||
}
|
||||
);
|
||||
break;
|
||||
case 'folder':
|
||||
$.post(
|
||||
OC.filePath('files','ajax','newfolder.php'),
|
||||
{dir:$('#dir').val(),foldername:name},
|
||||
function(result){
|
||||
if (result.status == 'success') {
|
||||
var date=new Date();
|
||||
FileList.addDir(name,0,date,hidden);
|
||||
var tr=$('tr').filterAttr('data-file',name);
|
||||
tr.attr('data-id', result.data.id);
|
||||
} else {
|
||||
OC.dialogs.alert(result.data.message, t('core', 'Error'));
|
||||
}
|
||||
}
|
||||
);
|
||||
break;
|
||||
case 'web':
|
||||
if(name.substr(0,8)!='https://' && name.substr(0,7)!='http://'){
|
||||
name='http://'+name;
|
||||
}
|
||||
var localName=name;
|
||||
if(localName.substr(localName.length-1,1)=='/'){//strip /
|
||||
localName=localName.substr(0,localName.length-1)
|
||||
}
|
||||
if(localName.indexOf('/')){//use last part of url
|
||||
localName=localName.split('/').pop();
|
||||
} else { //or the domain
|
||||
localName=(localName.match(/:\/\/(.[^\/]+)/)[1]).replace('www.','');
|
||||
}
|
||||
localName = getUniqueName(localName);
|
||||
//IE < 10 does not fire the necessary events for the progress bar.
|
||||
if($('html.lte9').length > 0) {
|
||||
} else {
|
||||
$('#uploadprogressbar').progressbar({value:0});
|
||||
$('#uploadprogressbar').fadeIn();
|
||||
}
|
||||
|
||||
var eventSource=new OC.EventSource(OC.filePath('files','ajax','newfile.php'),{dir:$('#dir').val(),source:name,filename:localName});
|
||||
eventSource.listen('progress',function(progress){
|
||||
//IE < 10 does not fire the necessary events for the progress bar.
|
||||
if($('html.lte9').length > 0) {
|
||||
} else {
|
||||
$('#uploadprogressbar').progressbar('value',progress);
|
||||
}
|
||||
});
|
||||
eventSource.listen('success',function(data){
|
||||
var mime=data.mime;
|
||||
var size=data.size;
|
||||
var id=data.id;
|
||||
$('#uploadprogressbar').fadeOut();
|
||||
var date=new Date();
|
||||
FileList.addFile(localName,size,date,false,hidden);
|
||||
var tr=$('tr').filterAttr('data-file',localName);
|
||||
tr.data('mime',mime).data('id',id);
|
||||
tr.attr('data-id', id);
|
||||
getMimeIcon(mime,function(path){
|
||||
tr.find('td.filename').attr('style','background-image:url('+path+')');
|
||||
});
|
||||
});
|
||||
eventSource.listen('error',function(error){
|
||||
$('#uploadprogressbar').fadeOut();
|
||||
alert(error);
|
||||
});
|
||||
break;
|
||||
}
|
||||
var li=form.parent();
|
||||
form.remove();
|
||||
li.append('<p>'+li.data('text')+'</p>');
|
||||
$('#new>a').click();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -22,18 +22,18 @@ var FileActions = {
|
||||
if (FileActions.actions.all) {
|
||||
actions = $.extend(actions, FileActions.actions.all);
|
||||
}
|
||||
if (mime) {
|
||||
if (FileActions.actions[mime]) {
|
||||
actions = $.extend(actions, FileActions.actions[mime]);
|
||||
if (type) {//type is 'dir' or 'file'
|
||||
if (FileActions.actions[type]) {
|
||||
actions = $.extend(actions, FileActions.actions[type]);
|
||||
}
|
||||
}
|
||||
if (mime) {
|
||||
var mimePart = mime.substr(0, mime.indexOf('/'));
|
||||
if (FileActions.actions[mimePart]) {
|
||||
actions = $.extend(actions, FileActions.actions[mimePart]);
|
||||
}
|
||||
}
|
||||
if (type) {//type is 'dir' or 'file'
|
||||
if (FileActions.actions[type]) {
|
||||
actions = $.extend(actions, FileActions.actions[type]);
|
||||
if (FileActions.actions[mime]) {
|
||||
actions = $.extend(actions, FileActions.actions[mime]);
|
||||
}
|
||||
}
|
||||
var filteredActions = {};
|
||||
@@ -112,7 +112,8 @@ var FileActions = {
|
||||
addAction(name, action);
|
||||
}
|
||||
});
|
||||
if(actions.Share){
|
||||
if(actions.Share && !($('#dir').val() === '/' && file === 'Shared')){
|
||||
// t('files', 'Share')
|
||||
addAction('Share', actions.Share);
|
||||
}
|
||||
|
||||
|
||||
+180
-13
@@ -71,8 +71,20 @@ var FileList={
|
||||
tr.append(td);
|
||||
return tr;
|
||||
},
|
||||
addFile:function(name,size,lastModified,loading,hidden){
|
||||
addFile:function(name,size,lastModified,loading,hidden,param){
|
||||
var imgurl;
|
||||
|
||||
if (!param) {
|
||||
param = {};
|
||||
}
|
||||
|
||||
var download_url = null;
|
||||
if (!param.download_url) {
|
||||
download_url = OC.Router.generate('download', { file: $('#dir').val()+'/'+name });
|
||||
} else {
|
||||
download_url = param.download_url;
|
||||
}
|
||||
|
||||
if (loading) {
|
||||
imgurl = OC.imagePath('core', 'loading.gif');
|
||||
} else {
|
||||
@@ -82,23 +94,23 @@ var FileList={
|
||||
'file',
|
||||
name,
|
||||
imgurl,
|
||||
OC.Router.generate('download', { file: $('#dir').val()+'/'+name }),
|
||||
download_url,
|
||||
size,
|
||||
lastModified,
|
||||
$('#permissions').val()
|
||||
);
|
||||
|
||||
FileList.insertElement(name, 'file', tr.attr('data-file',name));
|
||||
var row = $('tr').filterAttr('data-file',name);
|
||||
FileList.insertElement(name, 'file', tr);
|
||||
if(loading){
|
||||
row.data('loading',true);
|
||||
tr.data('loading',true);
|
||||
}else{
|
||||
row.find('td.filename').draggable(dragOptions);
|
||||
tr.find('td.filename').draggable(dragOptions);
|
||||
}
|
||||
if (hidden) {
|
||||
row.hide();
|
||||
tr.hide();
|
||||
}
|
||||
FileActions.display(row.find('td.filename'));
|
||||
FileActions.display(tr.find('td.filename'));
|
||||
return tr;
|
||||
},
|
||||
addDir:function(name,size,lastModified,hidden){
|
||||
|
||||
@@ -113,13 +125,14 @@ var FileList={
|
||||
);
|
||||
|
||||
FileList.insertElement(name,'dir',tr);
|
||||
var row = $('tr').filterAttr('data-file',name);
|
||||
row.find('td.filename').draggable(dragOptions);
|
||||
row.find('td.filename').droppable(folderDropOptions);
|
||||
var td = tr.find('td.filename');
|
||||
td.draggable(dragOptions);
|
||||
td.droppable(folderDropOptions);
|
||||
if (hidden) {
|
||||
row.hide();
|
||||
tr.hide();
|
||||
}
|
||||
FileActions.display(row.find('td.filename'));
|
||||
FileActions.display(tr.find('td.filename'));
|
||||
return tr;
|
||||
},
|
||||
refresh:function(data) {
|
||||
var result = jQuery.parseJSON(data.responseText);
|
||||
@@ -190,6 +203,14 @@ var FileList={
|
||||
td.children('a.name').hide();
|
||||
td.append(form);
|
||||
input.focus();
|
||||
|
||||
//preselect input
|
||||
var len = input.val().lastIndexOf('.');
|
||||
if (len === -1) {
|
||||
len = input.val().length;
|
||||
}
|
||||
input.selectRange(0,len);
|
||||
|
||||
form.submit(function(event){
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
@@ -351,6 +372,152 @@ var FileList={
|
||||
};
|
||||
|
||||
$(document).ready(function(){
|
||||
|
||||
// handle upload events
|
||||
var file_upload_start = $('#file_upload_start');
|
||||
file_upload_start.on('fileuploaddrop', function(e, data) {
|
||||
// only handle drop to dir if fileList exists
|
||||
if ($('#fileList').length > 0) {
|
||||
var dropTarget = $(e.originalEvent.target).closest('tr');
|
||||
if(dropTarget && dropTarget.data('type') === 'dir') { // drag&drop upload to folder
|
||||
var dirName = dropTarget.data('file');
|
||||
// update folder in form
|
||||
data.formData = function(form) {
|
||||
var formArray = form.serializeArray();
|
||||
// array index 0 contains the max files size
|
||||
// array index 1 contains the request token
|
||||
// array index 2 contains the directory
|
||||
var parentDir = formArray[2]['value'];
|
||||
if (parentDir === '/') {
|
||||
formArray[2]['value'] += dirName;
|
||||
} else {
|
||||
formArray[2]['value'] += '/'+dirName;
|
||||
}
|
||||
return formArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
file_upload_start.on('fileuploadadd', function(e, data) {
|
||||
// only add to fileList if it exists
|
||||
if ($('#fileList').length > 0) {
|
||||
|
||||
if(FileList.deleteFiles && FileList.deleteFiles.indexOf(data.files[0].name)!=-1){//finish delete if we are uploading a deleted file
|
||||
FileList.finishDelete(null, true); //delete file before continuing
|
||||
}
|
||||
|
||||
// add ui visualization to existing folder or as new stand-alone file?
|
||||
var dropTarget = $(e.originalEvent.target).closest('tr');
|
||||
if(dropTarget && dropTarget.data('type') === 'dir') {
|
||||
// add to existing folder
|
||||
var dirName = dropTarget.data('file');
|
||||
|
||||
// set dir context
|
||||
data.context = $('tr').filterAttr('data-type', 'dir').filterAttr('data-file', dirName);
|
||||
|
||||
// update upload counter ui
|
||||
var uploadtext = data.context.find('.uploadtext');
|
||||
var currentUploads = parseInt(uploadtext.attr('currentUploads'));
|
||||
currentUploads += 1;
|
||||
uploadtext.attr('currentUploads', currentUploads);
|
||||
if(currentUploads === 1) {
|
||||
var img = OC.imagePath('core', 'loading.gif');
|
||||
data.context.find('td.filename').attr('style','background-image:url('+img+')');
|
||||
uploadtext.text(t('files', '1 file uploading'));
|
||||
uploadtext.show();
|
||||
} else {
|
||||
uploadtext.text(currentUploads + ' ' + t('files', 'files uploading'));
|
||||
}
|
||||
} else {
|
||||
// add as stand-alone row to filelist
|
||||
var uniqueName = getUniqueName(data.files[0].name);
|
||||
var size=t('files','Pending');
|
||||
if(data.files[0].size>=0){
|
||||
size=data.files[0].size;
|
||||
}
|
||||
var date=new Date();
|
||||
var param = {};
|
||||
if ($('#publicUploadRequestToken').length) {
|
||||
param.download_url = document.location.href + '&download&path=/' + $('#dir').val() + '/' + uniqueName;
|
||||
}
|
||||
// create new file context
|
||||
data.context = FileList.addFile(uniqueName,size,date,true,false,param);
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
file_upload_start.on('fileuploaddone', function(e, data) {
|
||||
// only update the fileList if it exists
|
||||
if ($('#fileList').length > 0) {
|
||||
var response;
|
||||
if (typeof data.result === 'string') {
|
||||
response = data.result;
|
||||
} else {
|
||||
// fetch response from iframe
|
||||
response = data.result[0].body.innerText;
|
||||
}
|
||||
var result=$.parseJSON(response);
|
||||
|
||||
if(typeof result[0] !== 'undefined' && result[0].status === 'success') {
|
||||
var file = result[0];
|
||||
|
||||
if (data.context.data('type') === 'file') {
|
||||
// update file data
|
||||
data.context.attr('data-mime',file.mime).attr('data-id',file.id);
|
||||
var size = data.context.data('size');
|
||||
if(size!=file.size){
|
||||
data.context.attr('data-size', file.size);
|
||||
data.context.find('td.filesize').text(humanFileSize(file.size));
|
||||
}
|
||||
if (FileList.loadingDone) {
|
||||
FileList.loadingDone(file.name, file.id);
|
||||
}
|
||||
} else {
|
||||
// update upload counter ui
|
||||
var uploadtext = data.context.find('.uploadtext');
|
||||
var currentUploads = parseInt(uploadtext.attr('currentUploads'));
|
||||
currentUploads -= 1;
|
||||
uploadtext.attr('currentUploads', currentUploads);
|
||||
if(currentUploads === 0) {
|
||||
var img = OC.imagePath('core', 'filetypes/folder.png');
|
||||
data.context.find('td.filename').attr('style','background-image:url('+img+')');
|
||||
uploadtext.text('');
|
||||
uploadtext.hide();
|
||||
} else {
|
||||
uploadtext.text(currentUploads + ' ' + t('files', 'files uploading'));
|
||||
}
|
||||
|
||||
// update folder size
|
||||
var size = parseInt(data.context.data('size'));
|
||||
size += parseInt(file.size) ;
|
||||
data.context.attr('data-size', size);
|
||||
data.context.find('td.filesize').text(humanFileSize(size));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
file_upload_start.on('fileuploadfail', function(e, data) {
|
||||
// only update the fileList if it exists
|
||||
// cleanup files, error notification has been shown by fileupload code
|
||||
var tr = data.context;
|
||||
if (typeof tr === 'undefined') {
|
||||
tr = $('tr').filterAttr('data-file', data.files[0].name);
|
||||
}
|
||||
if (tr.attr('data-type') === 'dir') {
|
||||
//cleanup uploading to a dir
|
||||
var uploadtext = tr.find('.uploadtext');
|
||||
var img = OC.imagePath('core', 'filetypes/folder.png');
|
||||
tr.find('td.filename').attr('style','background-image:url('+img+')');
|
||||
uploadtext.text('');
|
||||
uploadtext.hide(); //TODO really hide already
|
||||
} else {
|
||||
//remove file
|
||||
tr.fadeOut();
|
||||
tr.remove();
|
||||
}
|
||||
});
|
||||
|
||||
$('#notification').hide();
|
||||
$('#notification').on('click', '.undo', function(){
|
||||
if (FileList.deleteFiles) {
|
||||
|
||||
+39
-249
@@ -115,6 +115,11 @@ $(document).ready(function() {
|
||||
return false;
|
||||
});
|
||||
|
||||
// Trigger cancelling of file upload
|
||||
$('#uploadprogresswrapper .stop').on('click', function() {
|
||||
Files.cancelUploads();
|
||||
});
|
||||
|
||||
// Show trash bin
|
||||
$('#trash a').live('click', function() {
|
||||
window.location=OC.filePath('files_trashbin', '', 'index.php');
|
||||
@@ -226,14 +231,14 @@ $(document).ready(function() {
|
||||
OC.Notification.show(t('files','Your download is being prepared. This might take some time if the files are big.'));
|
||||
// use special download URL if provided, e.g. for public shared files
|
||||
if ( (downloadURL = document.getElementById("downloadURL")) ) {
|
||||
window.location=downloadURL.value+"&download&files="+files;
|
||||
window.location=downloadURL.value+"&download&files="+encodeURIComponent(fileslist);
|
||||
} else {
|
||||
window.location=OC.filePath('files', 'ajax', 'download.php') + '?'+ $.param({ dir: dir, files: fileslist });
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.delete').click(function(event) {
|
||||
$('.delete-selected').click(function(event) {
|
||||
var files=getSelectedFiles('name');
|
||||
event.preventDefault();
|
||||
FileList.do_delete(files);
|
||||
@@ -246,243 +251,6 @@ $(document).ready(function() {
|
||||
e.preventDefault(); // prevent browser from doing anything, if file isn't dropped in dropZone
|
||||
});
|
||||
|
||||
if ( document.getElementById('data-upload-form') ) {
|
||||
$(function() {
|
||||
$('#file_upload_start').fileupload({
|
||||
dropZone: $('#content'), // restrict dropZone to content div
|
||||
add: function(e, data) {
|
||||
var files = data.files;
|
||||
var totalSize=0;
|
||||
if(files){
|
||||
if (FileList.lastAction) {
|
||||
FileList.lastAction();
|
||||
}
|
||||
for(var i=0;i<files.length;i++){
|
||||
if(files[i].size ==0 && files[i].type== '')
|
||||
{
|
||||
OC.dialogs.alert(t('files', 'Unable to upload your file as it is a directory or has 0 bytes'), t('files', 'Upload Error'));
|
||||
return;
|
||||
}
|
||||
totalSize+=files[i].size;
|
||||
}
|
||||
}
|
||||
if(totalSize>$('#max_upload').val()){
|
||||
$( '#uploadsize-message' ).dialog({
|
||||
modal: true,
|
||||
buttons: {
|
||||
Close: {
|
||||
text:t('files', 'Close'),
|
||||
click:function() {
|
||||
$( this ).dialog( 'close' );
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}else{
|
||||
var dropTarget = $(e.originalEvent.target).closest('tr');
|
||||
if(dropTarget && dropTarget.attr('data-type') === 'dir') { // drag&drop upload to folder
|
||||
var dirName = dropTarget.attr('data-file')
|
||||
}
|
||||
|
||||
var date=new Date();
|
||||
if(files){
|
||||
for(var i=0;i<files.length;i++){
|
||||
if(files[i].size>0){
|
||||
var size=files[i].size;
|
||||
}else{
|
||||
var size=t('files','Pending');
|
||||
}
|
||||
if(files && !dirName){
|
||||
var uniqueName = getUniqueName(files[i].name);
|
||||
if (uniqueName != files[i].name) {
|
||||
FileList.checkName(uniqueName, files[i].name, true);
|
||||
var hidden = true;
|
||||
} else {
|
||||
var hidden = false;
|
||||
}
|
||||
FileList.addFile(uniqueName,size,date,true,hidden);
|
||||
} else if(dirName) {
|
||||
var uploadtext = $('tr').filterAttr('data-type', 'dir').filterAttr('data-file', dirName).find('.uploadtext')
|
||||
var currentUploads = parseInt(uploadtext.attr('currentUploads'));
|
||||
currentUploads += 1;
|
||||
uploadtext.attr('currentUploads', currentUploads);
|
||||
if(currentUploads === 1) {
|
||||
var img = OC.imagePath('core', 'loading.gif');
|
||||
var tr=$('tr').filterAttr('data-file',dirName);
|
||||
tr.find('td.filename').attr('style','background-image:url('+img+')');
|
||||
uploadtext.text(t('files', '1 file uploading'));
|
||||
uploadtext.show();
|
||||
} else {
|
||||
uploadtext.text(t('files', '{count} files uploading', {count: currentUploads}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
var filename=this.value.split('\\').pop(); //ie prepends C:\fakepath\ in front of the filename
|
||||
var uniqueName = getUniqueName(filename);
|
||||
if (uniqueName != filename) {
|
||||
FileList.checkName(uniqueName, filename, true);
|
||||
var hidden = true;
|
||||
} else {
|
||||
var hidden = false;
|
||||
}
|
||||
FileList.addFile(uniqueName,'Pending',date,true,hidden);
|
||||
}
|
||||
if($.support.xhrFileUpload) {
|
||||
for(var i=0;i<files.length;i++){
|
||||
var fileName = files[i].name
|
||||
var dropTarget = $(e.originalEvent.target).closest('tr');
|
||||
if(dropTarget && dropTarget.attr('data-type') === 'dir') { // drag&drop upload to folder
|
||||
var dirName = dropTarget.attr('data-file')
|
||||
var jqXHR = $('#file_upload_start').fileupload('send', {files: files[i],
|
||||
formData: function(form) {
|
||||
var formArray = form.serializeArray();
|
||||
// array index 0 contains the max files size
|
||||
// array index 1 contains the request token
|
||||
// array index 2 contains the directory
|
||||
formArray[2]['value'] = dirName;
|
||||
return formArray;
|
||||
}}).success(function(result, textStatus, jqXHR) {
|
||||
var response;
|
||||
response=jQuery.parseJSON(result);
|
||||
if(response[0] == undefined || response[0].status != 'success') {
|
||||
OC.Notification.show(t('files', response.data.message));
|
||||
}
|
||||
Files.updateMaxUploadFilesize(response);
|
||||
var file=response[0];
|
||||
// TODO: this doesn't work if the file name has been changed server side
|
||||
delete uploadingFiles[dirName][file.name];
|
||||
if ($.assocArraySize(uploadingFiles[dirName]) == 0) {
|
||||
delete uploadingFiles[dirName];
|
||||
}
|
||||
//TODO update file upload size limit
|
||||
|
||||
var uploadtext = $('tr').filterAttr('data-type', 'dir').filterAttr('data-file', dirName).find('.uploadtext')
|
||||
var currentUploads = parseInt(uploadtext.attr('currentUploads'));
|
||||
currentUploads -= 1;
|
||||
uploadtext.attr('currentUploads', currentUploads);
|
||||
if(currentUploads === 0) {
|
||||
var img = OC.imagePath('core', 'filetypes/folder.png');
|
||||
var tr=$('tr').filterAttr('data-file',dirName);
|
||||
tr.find('td.filename').attr('style','background-image:url('+img+')');
|
||||
uploadtext.text('');
|
||||
uploadtext.hide();
|
||||
} else {
|
||||
uploadtext.text(t('files', '{count} files uploading', {count: currentUploads}));
|
||||
}
|
||||
})
|
||||
.error(function(jqXHR, textStatus, errorThrown) {
|
||||
if(errorThrown === 'abort') {
|
||||
var currentUploads = parseInt(uploadtext.attr('currentUploads'));
|
||||
currentUploads -= 1;
|
||||
uploadtext.attr('currentUploads', currentUploads);
|
||||
if(currentUploads === 0) {
|
||||
var img = OC.imagePath('core', 'filetypes/folder.png');
|
||||
var tr=$('tr').filterAttr('data-file',dirName);
|
||||
tr.find('td.filename').attr('style','background-image:url('+img+')');
|
||||
uploadtext.text('');
|
||||
uploadtext.hide();
|
||||
} else {
|
||||
uploadtext.text(t('files', '{count} files uploading', {count: currentUploads}));
|
||||
}
|
||||
delete uploadingFiles[dirName][fileName];
|
||||
OC.Notification.show(t('files', 'Upload cancelled.'));
|
||||
}
|
||||
});
|
||||
//TODO test with filenames containing slashes
|
||||
if(uploadingFiles[dirName] === undefined) {
|
||||
uploadingFiles[dirName] = {};
|
||||
}
|
||||
uploadingFiles[dirName][fileName] = jqXHR;
|
||||
} else {
|
||||
var jqXHR = $('#file_upload_start').fileupload('send', {files: files[i]})
|
||||
.success(function(result, textStatus, jqXHR) {
|
||||
var response;
|
||||
response=jQuery.parseJSON(result);
|
||||
Files.updateMaxUploadFilesize(response);
|
||||
|
||||
if(response[0] != undefined && response[0].status == 'success') {
|
||||
var file=response[0];
|
||||
delete uploadingFiles[file.name];
|
||||
$('tr').filterAttr('data-file',file.name).data('mime',file.mime).data('id',file.id);
|
||||
var size = $('tr').filterAttr('data-file',file.name).find('td.filesize').text();
|
||||
if(size==t('files','Pending')){
|
||||
$('tr').filterAttr('data-file',file.name).find('td.filesize').text(file.size);
|
||||
}
|
||||
//TODO update file upload size limit
|
||||
FileList.loadingDone(file.name, file.id);
|
||||
} else {
|
||||
Files.cancelUpload(this.files[0].name);
|
||||
OC.Notification.show(t('files', response.data.message));
|
||||
$('#fileList > tr').not('[data-mime]').fadeOut();
|
||||
$('#fileList > tr').not('[data-mime]').remove();
|
||||
}
|
||||
})
|
||||
.error(function(jqXHR, textStatus, errorThrown) {
|
||||
if(errorThrown === 'abort') {
|
||||
Files.cancelUpload(this.files[0].name);
|
||||
OC.Notification.show(t('files', 'Upload cancelled.'));
|
||||
}
|
||||
});
|
||||
uploadingFiles[uniqueName] = jqXHR;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
data.submit().success(function(data, status) {
|
||||
// in safari data is a string
|
||||
response = jQuery.parseJSON(typeof data === 'string' ? data : data[0].body.innerText);
|
||||
Files.updateMaxUploadFilesize(response);
|
||||
if(response[0] != undefined && response[0].status == 'success') {
|
||||
var file=response[0];
|
||||
delete uploadingFiles[file.name];
|
||||
$('tr').filterAttr('data-file',file.name).data('mime',file.mime).data('id',file.id);
|
||||
var size = $('tr').filterAttr('data-file',file.name).find('td.filesize').text();
|
||||
if(size==t('files','Pending')){
|
||||
$('tr').filterAttr('data-file',file.name).find('td.filesize').text(file.size);
|
||||
}
|
||||
//TODO update file upload size limit
|
||||
FileList.loadingDone(file.name, file.id);
|
||||
} else {
|
||||
//TODO Files.cancelUpload(/*where do we get the filename*/);
|
||||
OC.Notification.show(t('files', response.data.message));
|
||||
$('#fileList > tr').not('[data-mime]').fadeOut();
|
||||
$('#fileList > tr').not('[data-mime]').remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
fail: function(e, data) {
|
||||
// TODO: cancel upload & display error notification
|
||||
},
|
||||
progress: function(e, data) {
|
||||
// TODO: show nice progress bar in file row
|
||||
},
|
||||
progressall: function(e, data) {
|
||||
var progress = (data.loaded/data.total)*100;
|
||||
$('#uploadprogressbar').progressbar('value',progress);
|
||||
},
|
||||
start: function(e, data) {
|
||||
//IE < 10 does not fire the necessary events for the progress bar.
|
||||
if($.browser.msie && parseInt($.browser.version) < 10) {
|
||||
return;
|
||||
}
|
||||
$('#uploadprogressbar').progressbar({value:0});
|
||||
$('#uploadprogressbar').fadeIn();
|
||||
if(data.dataType != 'iframe ') {
|
||||
$('#upload input.stop').show();
|
||||
}
|
||||
},
|
||||
stop: function(e, data) {
|
||||
if(data.dataType != 'iframe ') {
|
||||
$('#upload input.stop').hide();
|
||||
}
|
||||
$('#uploadprogressbar').progressbar('value',100);
|
||||
$('#uploadprogressbar').fadeOut();
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
$.assocArraySize = function(obj) {
|
||||
// http://stackoverflow.com/a/6700/11236
|
||||
var size = 0, key;
|
||||
@@ -637,12 +405,20 @@ $(document).ready(function() {
|
||||
localName=(localName.match(/:\/\/(.[^/]+)/)[1]).replace('www.','');
|
||||
}
|
||||
localName = getUniqueName(localName);
|
||||
$('#uploadprogressbar').progressbar({value:0});
|
||||
$('#uploadprogressbar').fadeIn();
|
||||
//IE < 10 does not fire the necessary events for the progress bar.
|
||||
if($('html.lte9').length > 0) {
|
||||
} else {
|
||||
$('#uploadprogressbar').progressbar({value:0});
|
||||
$('#uploadprogressbar').fadeIn();
|
||||
}
|
||||
|
||||
var eventSource=new OC.EventSource(OC.filePath('files','ajax','newfile.php'),{dir:$('#dir').val(),source:name,filename:localName});
|
||||
eventSource.listen('progress',function(progress){
|
||||
$('#uploadprogressbar').progressbar('value',progress);
|
||||
//IE < 10 does not fire the necessary events for the progress bar.
|
||||
if($('html.lte9').length > 0) {
|
||||
} else {
|
||||
$('#uploadprogressbar').progressbar('value',progress);
|
||||
}
|
||||
});
|
||||
eventSource.listen('success',function(data){
|
||||
var mime=data.mime;
|
||||
@@ -772,7 +548,7 @@ $(document).ready(function() {
|
||||
}
|
||||
});
|
||||
|
||||
function scanFiles(force, dir){
|
||||
function scanFiles(force, dir, users){
|
||||
if (!OC.currentUser) {
|
||||
return;
|
||||
}
|
||||
@@ -782,7 +558,18 @@ function scanFiles(force, dir){
|
||||
}
|
||||
force = !!force; //cast to bool
|
||||
scanFiles.scanning = true;
|
||||
var scannerEventSource = new OC.EventSource(OC.filePath('files','ajax','scan.php'),{force:force,dir:dir});
|
||||
var scannerEventSource;
|
||||
if (users) {
|
||||
var usersString;
|
||||
if (users === 'all') {
|
||||
usersString = users;
|
||||
} else {
|
||||
usersString = JSON.stringify(users);
|
||||
}
|
||||
scannerEventSource = new OC.EventSource(OC.filePath('files','ajax','scan.php'),{force: force,dir: dir, users: usersString});
|
||||
} else {
|
||||
scannerEventSource = new OC.EventSource(OC.filePath('files','ajax','scan.php'),{force: force,dir: dir});
|
||||
}
|
||||
scanFiles.cancel = scannerEventSource.close.bind(scannerEventSource);
|
||||
scannerEventSource.listen('count',function(count){
|
||||
console.log(count + 'files scanned')
|
||||
@@ -794,6 +581,9 @@ function scanFiles(force, dir){
|
||||
scanFiles.scanning=false;
|
||||
console.log('done after ' + count + 'files');
|
||||
});
|
||||
scannerEventSource.listen('user',function(user){
|
||||
console.log('scanning files for ' + user);
|
||||
});
|
||||
}
|
||||
scanFiles.scanning=false;
|
||||
|
||||
@@ -839,9 +629,9 @@ var createDragShadow = function(event){
|
||||
var dir=$('#dir').val();
|
||||
|
||||
$(selectedFiles).each(function(i,elem){
|
||||
var newtr = $('<tr data-dir="'+dir+'" data-filename="'+elem.name+'">'
|
||||
+'<td class="filename">'+elem.name+'</td><td class="size">'+humanFileSize(elem.size)+'</td>'
|
||||
+'</tr>');
|
||||
var newtr = $('<tr/>').attr('data-dir', dir).attr('data-filename', elem.name);
|
||||
newtr.append($('<td/>').addClass('filename').text(elem.name));
|
||||
newtr.append($('<td/>').addClass('size').text(humanFileSize(elem.size)));
|
||||
tbody.append(newtr);
|
||||
if (elem.type === 'dir') {
|
||||
newtr.find('td.filename').attr('style','background-image:url('+OC.imagePath('core', 'filetypes/folder.png')+')');
|
||||
@@ -865,9 +655,9 @@ var dragOptions={
|
||||
}
|
||||
}
|
||||
// sane browsers support using the distance option
|
||||
if ( ! $.browser.msie) {
|
||||
if ( $('html.ie').length === 0) {
|
||||
dragOptions['distance'] = 20;
|
||||
}
|
||||
}
|
||||
|
||||
var folderDropOptions={
|
||||
drop: function( event, ui ) {
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
"No file was uploaded" => "لم يتم ترفيع أي من الملفات",
|
||||
"Missing a temporary folder" => "المجلد المؤقت غير موجود",
|
||||
"Files" => "الملفات",
|
||||
"Share" => "شارك",
|
||||
"Delete permanently" => "حذف بشكل دائم",
|
||||
"Delete" => "محذوف",
|
||||
"Close" => "إغلق",
|
||||
"Name" => "الاسم",
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"Failed to write to disk" => "Възникна проблем при запис в диска",
|
||||
"Invalid directory." => "Невалидна директория.",
|
||||
"Files" => "Файлове",
|
||||
"Share" => "Споделяне",
|
||||
"Delete permanently" => "Изтриване завинаги",
|
||||
"Delete" => "Изтриване",
|
||||
"Rename" => "Преименуване",
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
"Failed to write to disk" => "ডিস্কে লিখতে ব্যর্থ",
|
||||
"Invalid directory." => "ভুল ডিরেক্টরি",
|
||||
"Files" => "ফাইল",
|
||||
"Share" => "ভাগাভাগি কর",
|
||||
"Delete" => "মুছে ফেল",
|
||||
"Rename" => "পূনঃনামকরণ",
|
||||
"Pending" => "মুলতুবি",
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"Not enough storage available" => "No hi ha prou espai disponible",
|
||||
"Invalid directory." => "Directori no vàlid.",
|
||||
"Files" => "Fitxers",
|
||||
"Share" => "Comparteix",
|
||||
"Delete permanently" => "Esborra permanentment",
|
||||
"Delete" => "Suprimeix",
|
||||
"Rename" => "Reanomena",
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"Not enough storage available" => "Nedostatek dostupného úložného prostoru",
|
||||
"Invalid directory." => "Neplatný adresář",
|
||||
"Files" => "Soubory",
|
||||
"Share" => "Sdílet",
|
||||
"Delete permanently" => "Trvale odstranit",
|
||||
"Delete" => "Smazat",
|
||||
"Rename" => "Přejmenovat",
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php $TRANSLATIONS = array(
|
||||
"Could not move %s - File with this name already exists" => "Methwyd symud %s - Mae ffeil gyda'r enw hwn eisoes yn bodoli",
|
||||
"Could not move %s" => "Methwyd symud %s",
|
||||
"Unable to rename file" => "Methu ailenwi ffeil",
|
||||
"No file was uploaded. Unknown error" => "Ni lwythwyd ffeil i fyny. Gwall anhysbys.",
|
||||
"There is no error, the file uploaded with success" => "Does dim gwall, llwythodd y ffeil i fyny'n llwyddiannus",
|
||||
"The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "Mae'r ffeil lwythwyd i fyny'n fwy na chyfarwyddeb upload_max_filesize yn php.ini:",
|
||||
"The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Mae'r ffeil lwythwyd i fyny'n fwy na chyfarwyddeb MAX_FILE_SIZE bennwyd yn y ffurflen HTML",
|
||||
"The uploaded file was only partially uploaded" => "Dim ond yn rhannol y llwythwyd y ffeil i fyny",
|
||||
"No file was uploaded" => "Ni lwythwyd ffeil i fyny",
|
||||
"Missing a temporary folder" => "Plygell dros dro yn eisiau",
|
||||
"Failed to write to disk" => "Methwyd ysgrifennu i'r ddisg",
|
||||
"Not enough storage available" => "Dim digon o le storio ar gael",
|
||||
"Invalid directory." => "Cyfeiriadur annilys.",
|
||||
"Files" => "Ffeiliau",
|
||||
"Share" => "Rhannu",
|
||||
"Delete permanently" => "Dileu'n barhaol",
|
||||
"Delete" => "Dileu",
|
||||
"Rename" => "Ailenwi",
|
||||
"Pending" => "I ddod",
|
||||
"{new_name} already exists" => "{new_name} yn bodoli'n barod",
|
||||
"replace" => "amnewid",
|
||||
"suggest name" => "awgrymu enw",
|
||||
"cancel" => "diddymu",
|
||||
"replaced {new_name} with {old_name}" => "newidiwyd {new_name} yn lle {old_name}",
|
||||
"undo" => "dadwneud",
|
||||
"perform delete operation" => "cyflawni gweithred dileu",
|
||||
"1 file uploading" => "1 ffeil yn llwytho i fyny",
|
||||
"files uploading" => "ffeiliau'n llwytho i fyny",
|
||||
"'.' is an invalid file name." => "Mae '.' yn enw ffeil annilys.",
|
||||
"File name cannot be empty." => "Does dim hawl cael enw ffeil gwag.",
|
||||
"Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Enw annilys, ni chaniateir, '\\', '/', '<', '>', ':', '\"', '|', '?' na '*'.",
|
||||
"Your storage is full, files can not be updated or synced anymore!" => "Mae eich storfa'n llawn, ni ellir diweddaru a chydweddu ffeiliau mwyach!",
|
||||
"Your storage is almost full ({usedSpacePercent}%)" => "Mae eich storfa bron a bod yn llawn ({usedSpacePercent}%)",
|
||||
"Your download is being prepared. This might take some time if the files are big." => "Wrthi'n paratoi i lwytho i lawr. Gall gymryd peth amser os yw'r ffeiliau'n fawr.",
|
||||
"Unable to upload your file as it is a directory or has 0 bytes" => "Methu llwytho'ch ffeil i fyny gan ei fod yn gyferiadur neu'n cynnwys 0 beit",
|
||||
"Not enough space available" => "Dim digon o le ar gael",
|
||||
"Upload cancelled." => "Diddymwyd llwytho i fyny.",
|
||||
"File upload is in progress. Leaving the page now will cancel the upload." => "Mae ffeiliau'n cael eu llwytho i fyny. Bydd gadael y dudalen hon nawr yn diddymu'r broses.",
|
||||
"URL cannot be empty." => "Does dim hawl cael URL gwag.",
|
||||
"Invalid folder name. Usage of 'Shared' is reserved by Owncloud" => "Enw plygell annilys. Mae'r defnydd o 'Shared' yn cael ei gadw gan Owncloud",
|
||||
"Error" => "Gwall",
|
||||
"Name" => "Enw",
|
||||
"Size" => "Maint",
|
||||
"Modified" => "Addaswyd",
|
||||
"1 folder" => "1 blygell",
|
||||
"{count} folders" => "{count} plygell",
|
||||
"1 file" => "1 ffeil",
|
||||
"{count} files" => "{count} ffeil",
|
||||
"Upload" => "Llwytho i fyny",
|
||||
"File handling" => "Trafod ffeiliau",
|
||||
"Maximum upload size" => "Maint mwyaf llwytho i fyny",
|
||||
"max. possible: " => "mwyaf. posib:",
|
||||
"Needed for multi-file and folder downloads." => "Angen ar gyfer llwytho mwy nag un ffeil neu blygell i lawr yr un pryd.",
|
||||
"Enable ZIP-download" => "Galluogi llwytho i lawr ZIP",
|
||||
"0 is unlimited" => "0 yn ddiderfyn",
|
||||
"Maximum input size for ZIP files" => "Maint mewnbynnu mwyaf ffeiliau ZIP",
|
||||
"Save" => "Cadw",
|
||||
"New" => "Newydd",
|
||||
"Text file" => "Ffeil destun",
|
||||
"Folder" => "Plygell",
|
||||
"From link" => "Dolen o",
|
||||
"Deleted files" => "Ffeiliau ddilewyd",
|
||||
"Cancel upload" => "Diddymu llwytho i fyny",
|
||||
"You don’t have write permissions here." => "Nid oes gennych hawliau ysgrifennu fan hyn.",
|
||||
"Nothing in here. Upload something!" => "Does dim byd fan hyn. Llwythwch rhywbeth i fyny!",
|
||||
"Download" => "Llwytho i lawr",
|
||||
"Unshare" => "Dad-rannu",
|
||||
"Upload too large" => "Maint llwytho i fyny'n rhy fawr",
|
||||
"The files you are trying to upload exceed the maximum size for file uploads on this server." => "Mae'r ffeiliau rydych yn ceisio llwytho i fyny'n fwy na maint mwyaf llwytho ffeiliau i fyny ar y gweinydd hwn.",
|
||||
"Files are being scanned, please wait." => "Arhoswch, mae ffeiliau'n cael eu sganio.",
|
||||
"Current scanning" => "Sganio cyfredol",
|
||||
"Upgrading filesystem cache..." => "Uwchraddio storfa system ffeiliau..."
|
||||
);
|
||||
@@ -13,6 +13,7 @@
|
||||
"Not enough storage available" => "Der er ikke nok plads til rådlighed",
|
||||
"Invalid directory." => "Ugyldig mappe.",
|
||||
"Files" => "Filer",
|
||||
"Share" => "Del",
|
||||
"Delete permanently" => "Slet permanent",
|
||||
"Delete" => "Slet",
|
||||
"Rename" => "Omdøb",
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"Not enough storage available" => "Nicht genug Speicherplatz verfügbar",
|
||||
"Invalid directory." => "Ungültiges Verzeichnis.",
|
||||
"Files" => "Dateien",
|
||||
"Share" => "Teilen",
|
||||
"Delete permanently" => "Permanent löschen",
|
||||
"Delete" => "Löschen",
|
||||
"Rename" => "Umbenennen",
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"Not enough storage available" => "Nicht genug Speicher vorhanden.",
|
||||
"Invalid directory." => "Ungültiges Verzeichnis.",
|
||||
"Files" => "Dateien",
|
||||
"Share" => "Teilen",
|
||||
"Delete permanently" => "Entgültig löschen",
|
||||
"Delete" => "Löschen",
|
||||
"Rename" => "Umbenennen",
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"Not enough storage available" => "Μη επαρκής διαθέσιμος αποθηκευτικός χώρος",
|
||||
"Invalid directory." => "Μη έγκυρος φάκελος.",
|
||||
"Files" => "Αρχεία",
|
||||
"Share" => "Διαμοιρασμός",
|
||||
"Delete permanently" => "Μόνιμη διαγραφή",
|
||||
"Delete" => "Διαγραφή",
|
||||
"Rename" => "Μετονομασία",
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
"Failed to write to disk" => "Malsukcesis skribo al disko",
|
||||
"Invalid directory." => "Nevalida dosierujo.",
|
||||
"Files" => "Dosieroj",
|
||||
"Share" => "Kunhavigi",
|
||||
"Delete" => "Forigi",
|
||||
"Rename" => "Alinomigi",
|
||||
"Pending" => "Traktotaj",
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"Not enough storage available" => "No hay suficiente espacio disponible",
|
||||
"Invalid directory." => "Directorio invalido.",
|
||||
"Files" => "Archivos",
|
||||
"Share" => "Compartir",
|
||||
"Delete permanently" => "Eliminar permanentemente",
|
||||
"Delete" => "Eliminar",
|
||||
"Rename" => "Renombrar",
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"Not enough storage available" => "No hay suficiente capacidad de almacenamiento",
|
||||
"Invalid directory." => "Directorio invalido.",
|
||||
"Files" => "Archivos",
|
||||
"Share" => "Compartir",
|
||||
"Delete permanently" => "Borrar de manera permanente",
|
||||
"Delete" => "Borrar",
|
||||
"Rename" => "Cambiar nombre",
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"Not enough storage available" => "Saadaval pole piisavalt ruumi",
|
||||
"Invalid directory." => "Vigane kaust.",
|
||||
"Files" => "Failid",
|
||||
"Share" => "Jaga",
|
||||
"Delete permanently" => "Kustuta jäädavalt",
|
||||
"Delete" => "Kustuta",
|
||||
"Rename" => "ümber",
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"Not enough storage available" => "Ez dago behar aina leku erabilgarri,",
|
||||
"Invalid directory." => "Baliogabeko karpeta.",
|
||||
"Files" => "Fitxategiak",
|
||||
"Share" => "Elkarbanatu",
|
||||
"Delete permanently" => "Ezabatu betirako",
|
||||
"Delete" => "Ezabatu",
|
||||
"Rename" => "Berrizendatu",
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
"Failed to write to disk" => "نوشتن بر روی دیسک سخت ناموفق بود",
|
||||
"Invalid directory." => "فهرست راهنما نامعتبر می باشد.",
|
||||
"Files" => "فایل ها",
|
||||
"Share" => "اشتراکگذاری",
|
||||
"Delete permanently" => "حذف قطعی",
|
||||
"Delete" => "پاک کردن",
|
||||
"Rename" => "تغییرنام",
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
"Not enough storage available" => "Tallennustilaa ei ole riittävästi käytettävissä",
|
||||
"Invalid directory." => "Virheellinen kansio.",
|
||||
"Files" => "Tiedostot",
|
||||
"Share" => "Jaa",
|
||||
"Delete permanently" => "Poista pysyvästi",
|
||||
"Delete" => "Poista",
|
||||
"Rename" => "Nimeä uudelleen",
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"Not enough storage available" => "Plus assez d'espace de stockage disponible",
|
||||
"Invalid directory." => "Dossier invalide.",
|
||||
"Files" => "Fichiers",
|
||||
"Share" => "Partager",
|
||||
"Delete permanently" => "Supprimer de façon définitive",
|
||||
"Delete" => "Supprimer",
|
||||
"Rename" => "Renommer",
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"Not enough storage available" => "Non hai espazo de almacenamento abondo",
|
||||
"Invalid directory." => "O directorio é incorrecto.",
|
||||
"Files" => "Ficheiros",
|
||||
"Share" => "Compartir",
|
||||
"Delete permanently" => "Eliminar permanentemente",
|
||||
"Delete" => "Eliminar",
|
||||
"Rename" => "Renomear",
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
"Missing a temporary folder" => "תיקייה זמנית חסרה",
|
||||
"Failed to write to disk" => "הכתיבה לכונן נכשלה",
|
||||
"Files" => "קבצים",
|
||||
"Share" => "שתף",
|
||||
"Delete permanently" => "מחק לצמיתות",
|
||||
"Delete" => "מחיקה",
|
||||
"Rename" => "שינוי שם",
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
"Missing a temporary folder" => "Nedostaje privremena mapa",
|
||||
"Failed to write to disk" => "Neuspjelo pisanje na disk",
|
||||
"Files" => "Datoteke",
|
||||
"Share" => "Podijeli",
|
||||
"Delete" => "Briši",
|
||||
"Rename" => "Promjeni ime",
|
||||
"Pending" => "U tijeku",
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"Not enough storage available" => "Nincs elég szabad hely.",
|
||||
"Invalid directory." => "Érvénytelen mappa.",
|
||||
"Files" => "Fájlok",
|
||||
"Share" => "Megosztás",
|
||||
"Delete permanently" => "Végleges törlés",
|
||||
"Delete" => "Törlés",
|
||||
"Rename" => "Átnevezés",
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"No file was uploaded" => "Nulle file esseva incargate",
|
||||
"Missing a temporary folder" => "Manca un dossier temporari",
|
||||
"Files" => "Files",
|
||||
"Share" => "Compartir",
|
||||
"Delete" => "Deler",
|
||||
"Close" => "Clauder",
|
||||
"Name" => "Nomine",
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
"Missing a temporary folder" => "Kehilangan folder temporer",
|
||||
"Failed to write to disk" => "Gagal menulis ke disk",
|
||||
"Files" => "Berkas",
|
||||
"Share" => "Bagikan",
|
||||
"Delete permanently" => "Hapus secara permanen",
|
||||
"Delete" => "Hapus",
|
||||
"Pending" => "Menunggu",
|
||||
"replace" => "mengganti",
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
"Failed to write to disk" => "Tókst ekki að skrifa á disk",
|
||||
"Invalid directory." => "Ógild mappa.",
|
||||
"Files" => "Skrár",
|
||||
"Share" => "Deila",
|
||||
"Delete" => "Eyða",
|
||||
"Rename" => "Endurskýra",
|
||||
"Pending" => "Bíður",
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"Not enough storage available" => "Spazio di archiviazione insufficiente",
|
||||
"Invalid directory." => "Cartella non valida.",
|
||||
"Files" => "File",
|
||||
"Share" => "Condividi",
|
||||
"Delete permanently" => "Elimina definitivamente",
|
||||
"Delete" => "Elimina",
|
||||
"Rename" => "Rinomina",
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"Not enough storage available" => "ストレージに十分な空き容量がありません",
|
||||
"Invalid directory." => "無効なディレクトリです。",
|
||||
"Files" => "ファイル",
|
||||
"Share" => "共有",
|
||||
"Delete permanently" => "完全に削除する",
|
||||
"Delete" => "削除",
|
||||
"Rename" => "名前の変更",
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
"Missing a temporary folder" => "დროებითი საქაღალდე არ არსებობს",
|
||||
"Failed to write to disk" => "შეცდომა დისკზე ჩაწერისას",
|
||||
"Files" => "ფაილები",
|
||||
"Share" => "გაზიარება",
|
||||
"Delete permanently" => "სრულად წაშლა",
|
||||
"Delete" => "წაშლა",
|
||||
"Rename" => "გადარქმევა",
|
||||
"Pending" => "მოცდის რეჟიმში",
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
"Failed to write to disk" => "디스크에 쓰지 못했습니다",
|
||||
"Invalid directory." => "올바르지 않은 디렉터리입니다.",
|
||||
"Files" => "파일",
|
||||
"Share" => "공유",
|
||||
"Delete" => "삭제",
|
||||
"Rename" => "이름 바꾸기",
|
||||
"Pending" => "보류 중",
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
"Missing a temporary folder" => "Et feelt en temporären Dossier",
|
||||
"Failed to write to disk" => "Konnt net op den Disk schreiwen",
|
||||
"Files" => "Dateien",
|
||||
"Share" => "Deelen",
|
||||
"Delete" => "Läschen",
|
||||
"replace" => "ersetzen",
|
||||
"cancel" => "ofbriechen",
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
"Missing a temporary folder" => "Nėra laikinojo katalogo",
|
||||
"Failed to write to disk" => "Nepavyko įrašyti į diską",
|
||||
"Files" => "Failai",
|
||||
"Share" => "Dalintis",
|
||||
"Delete" => "Ištrinti",
|
||||
"Rename" => "Pervadinti",
|
||||
"Pending" => "Laukiantis",
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"Not enough storage available" => "Nav pietiekami daudz vietas",
|
||||
"Invalid directory." => "Nederīga direktorija.",
|
||||
"Files" => "Datnes",
|
||||
"Share" => "Dalīties",
|
||||
"Delete permanently" => "Dzēst pavisam",
|
||||
"Delete" => "Dzēst",
|
||||
"Rename" => "Pārsaukt",
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
"Missing a temporary folder" => "Не постои привремена папка",
|
||||
"Failed to write to disk" => "Неуспеав да запишам на диск",
|
||||
"Files" => "Датотеки",
|
||||
"Share" => "Сподели",
|
||||
"Delete" => "Избриши",
|
||||
"Rename" => "Преименувај",
|
||||
"Pending" => "Чека",
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"Missing a temporary folder" => "Folder sementara hilang",
|
||||
"Failed to write to disk" => "Gagal untuk disimpan",
|
||||
"Files" => "fail",
|
||||
"Share" => "Kongsi",
|
||||
"Delete" => "Padam",
|
||||
"Pending" => "Dalam proses",
|
||||
"replace" => "ganti",
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"Missing a temporary folder" => "Mangler en midlertidig mappe",
|
||||
"Failed to write to disk" => "Klarte ikke å skrive til disk",
|
||||
"Files" => "Filer",
|
||||
"Share" => "Del",
|
||||
"Delete permanently" => "Slett permanent",
|
||||
"Delete" => "Slett",
|
||||
"Rename" => "Omdøp",
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"Not enough storage available" => "Niet genoeg opslagruimte beschikbaar",
|
||||
"Invalid directory." => "Ongeldige directory.",
|
||||
"Files" => "Bestanden",
|
||||
"Share" => "Delen",
|
||||
"Delete permanently" => "Verwijder definitief",
|
||||
"Delete" => "Verwijder",
|
||||
"Rename" => "Hernoem",
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
"Missing a temporary folder" => "Un dorsièr temporari manca",
|
||||
"Failed to write to disk" => "L'escriptura sul disc a fracassat",
|
||||
"Files" => "Fichièrs",
|
||||
"Share" => "Parteja",
|
||||
"Delete" => "Escafa",
|
||||
"Rename" => "Torna nomenar",
|
||||
"Pending" => "Al esperar",
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"Not enough storage available" => "Za mało dostępnego miejsca",
|
||||
"Invalid directory." => "Zła ścieżka.",
|
||||
"Files" => "Pliki",
|
||||
"Share" => "Udostępnij",
|
||||
"Delete permanently" => "Trwale usuń",
|
||||
"Delete" => "Usuń",
|
||||
"Rename" => "Zmień nazwę",
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"Not enough storage available" => "Espaço de armazenamento insuficiente",
|
||||
"Invalid directory." => "Diretório inválido.",
|
||||
"Files" => "Arquivos",
|
||||
"Share" => "Compartilhar",
|
||||
"Delete permanently" => "Excluir permanentemente",
|
||||
"Delete" => "Excluir",
|
||||
"Rename" => "Renomear",
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"Not enough storage available" => "Não há espaço suficiente em disco",
|
||||
"Invalid directory." => "Directório Inválido",
|
||||
"Files" => "Ficheiros",
|
||||
"Share" => "Partilhar",
|
||||
"Delete permanently" => "Eliminar permanentemente",
|
||||
"Delete" => "Apagar",
|
||||
"Rename" => "Renomear",
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
"Failed to write to disk" => "Eroare la scriere pe disc",
|
||||
"Invalid directory." => "Director invalid.",
|
||||
"Files" => "Fișiere",
|
||||
"Share" => "Partajează",
|
||||
"Delete" => "Șterge",
|
||||
"Rename" => "Redenumire",
|
||||
"Pending" => "În așteptare",
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"Not enough storage available" => "Недостаточно доступного места в хранилище",
|
||||
"Invalid directory." => "Неправильный каталог.",
|
||||
"Files" => "Файлы",
|
||||
"Share" => "Открыть доступ",
|
||||
"Delete permanently" => "Удалено навсегда",
|
||||
"Delete" => "Удалить",
|
||||
"Rename" => "Переименовать",
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"Not enough storage available" => "Недостаточно места в хранилище",
|
||||
"Invalid directory." => "Неверный каталог.",
|
||||
"Files" => "Файлы",
|
||||
"Share" => "Сделать общим",
|
||||
"Delete permanently" => "Удалить навсегда",
|
||||
"Delete" => "Удалить",
|
||||
"Rename" => "Переименовать",
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"Missing a temporary folder" => "තාවකාලික ෆොල්ඩරයක් සොයාගත නොහැක",
|
||||
"Failed to write to disk" => "තැටිගත කිරීම අසාර්ථකයි",
|
||||
"Files" => "ගොනු",
|
||||
"Share" => "බෙදා හදා ගන්න",
|
||||
"Delete" => "මකන්න",
|
||||
"Rename" => "නැවත නම් කරන්න",
|
||||
"replace" => "ප්රතිස්ථාපනය කරන්න",
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"Not enough storage available" => "Nedostatok dostupného úložného priestoru",
|
||||
"Invalid directory." => "Neplatný priečinok",
|
||||
"Files" => "Súbory",
|
||||
"Share" => "Zdieľať",
|
||||
"Delete permanently" => "Zmazať trvalo",
|
||||
"Delete" => "Odstrániť",
|
||||
"Rename" => "Premenovať",
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"Not enough storage available" => "Na voljo ni dovolj prostora",
|
||||
"Invalid directory." => "Neveljavna mapa.",
|
||||
"Files" => "Datoteke",
|
||||
"Share" => "Souporaba",
|
||||
"Delete permanently" => "Izbriši trajno",
|
||||
"Delete" => "Izbriši",
|
||||
"Rename" => "Preimenuj",
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php $TRANSLATIONS = array(
|
||||
"Could not move %s - File with this name already exists" => "%s nuk u spostua - Aty ekziston një skedar me të njëjtin emër",
|
||||
"Could not move %s" => "%s nuk u spostua",
|
||||
"Unable to rename file" => "Nuk është i mundur riemërtimi i skedarit",
|
||||
"No file was uploaded. Unknown error" => "Nuk u ngarkua asnjë skedar. Veprim i gabuar i panjohur",
|
||||
"There is no error, the file uploaded with success" => "Nuk pati veprime të gabuara, skedari u ngarkua me sukses",
|
||||
"The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "Skedari i ngarkuar tejkalon udhëzimin upload_max_filesize tek php.ini:",
|
||||
"The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Skedari i ngarkuar tejkalon udhëzimin MAX_FILE_SIZE të specifikuar në formularin HTML",
|
||||
"The uploaded file was only partially uploaded" => "Skedari i ngarkuar u ngarkua vetëm pjesërisht",
|
||||
"No file was uploaded" => "Nuk u ngarkua asnjë skedar",
|
||||
"Missing a temporary folder" => "Një dosje e përkohshme nuk u gjet",
|
||||
"Failed to write to disk" => "Ruajtja në disk dështoi",
|
||||
"Not enough storage available" => "Nuk ka mbetur hapësirë memorizimi e mjaftueshme",
|
||||
"Invalid directory." => "Dosje e pavlefshme.",
|
||||
"Files" => "Skedarët",
|
||||
"Share" => "Nda",
|
||||
"Delete permanently" => "Elimino përfundimisht",
|
||||
"Delete" => "Elimino",
|
||||
"Rename" => "Riemërto",
|
||||
"Pending" => "Pezulluar",
|
||||
"{new_name} already exists" => "{new_name} ekziston",
|
||||
"replace" => "zëvëndëso",
|
||||
"suggest name" => "sugjero një emër",
|
||||
"cancel" => "anulo",
|
||||
"replaced {new_name} with {old_name}" => "U zëvëndësua {new_name} me {old_name}",
|
||||
"undo" => "anulo",
|
||||
"perform delete operation" => "ekzekuto operacionin e eliminimit",
|
||||
"1 file uploading" => "Po ngarkohet 1 skedar",
|
||||
"files uploading" => "po ngarkoj skedarët",
|
||||
"'.' is an invalid file name." => "'.' është emër i pavlefshëm.",
|
||||
"File name cannot be empty." => "Emri i skedarit nuk mund të jetë bosh.",
|
||||
"Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Emër i pavlefshëm, '\\', '/', '<', '>', ':', '\"', '|', '?' dhe '*' nuk lejohen.",
|
||||
"Your storage is full, files can not be updated or synced anymore!" => "Hapësira juaj e memorizimit është plot, nuk mund të ngarkoni apo sinkronizoni më skedarët.",
|
||||
"Your storage is almost full ({usedSpacePercent}%)" => "Hapësira juaj e memorizimit është gati plot ({usedSpacePercent}%)",
|
||||
"Your download is being prepared. This might take some time if the files are big." => "Shkarkimi juaj po përgatitet. Mund të duhet pak kohë nqse skedarët janë të mëdhenj.",
|
||||
"Unable to upload your file as it is a directory or has 0 bytes" => "Nuk është i mundur ngarkimi i skedarit tuaj sepse është dosje ose ka dimension 0 byte",
|
||||
"Not enough space available" => "Nuk ka hapësirë memorizimi e mjaftueshme",
|
||||
"Upload cancelled." => "Ngarkimi u anulua.",
|
||||
"File upload is in progress. Leaving the page now will cancel the upload." => "Ngarkimi i skedarit është në vazhdim. Nqse ndërroni faqen tani ngarkimi do të anulohet.",
|
||||
"URL cannot be empty." => "URL-i nuk mund të jetë bosh.",
|
||||
"Invalid folder name. Usage of 'Shared' is reserved by Owncloud" => "Emri i dosjes është i pavlefshëm. Përdorimi i \"Shared\" është i rezervuar nga Owncloud-i.",
|
||||
"Error" => "Veprim i gabuar",
|
||||
"Name" => "Emri",
|
||||
"Size" => "Dimensioni",
|
||||
"Modified" => "Modifikuar",
|
||||
"1 folder" => "1 dosje",
|
||||
"{count} folders" => "{count} dosje",
|
||||
"1 file" => "1 skedar",
|
||||
"{count} files" => "{count} skedarë",
|
||||
"Upload" => "Ngarko",
|
||||
"File handling" => "Trajtimi i skedarit",
|
||||
"Maximum upload size" => "Dimensioni maksimal i ngarkimit",
|
||||
"max. possible: " => "maks. i mundur:",
|
||||
"Needed for multi-file and folder downloads." => "Duhet për shkarkimin e dosjeve dhe të skedarëve",
|
||||
"Enable ZIP-download" => "Aktivizo shkarkimin e ZIP-eve",
|
||||
"0 is unlimited" => "0 është i pakufizuar",
|
||||
"Maximum input size for ZIP files" => "Dimensioni maksimal i ngarkimit të skedarëve ZIP",
|
||||
"Save" => "Ruaj",
|
||||
"New" => "I ri",
|
||||
"Text file" => "Skedar teksti",
|
||||
"Folder" => "Dosje",
|
||||
"From link" => "Nga lidhja",
|
||||
"Deleted files" => "Skedarë të eliminuar",
|
||||
"Cancel upload" => "Anulo ngarkimin",
|
||||
"You don’t have write permissions here." => "Nuk keni të drejta për të shkruar këtu.",
|
||||
"Nothing in here. Upload something!" => "Këtu nuk ka asgjë. Ngarkoni diçka!",
|
||||
"Download" => "Shkarko",
|
||||
"Unshare" => "Hiq ndarjen",
|
||||
"Upload too large" => "Ngarkimi është shumë i madh",
|
||||
"The files you are trying to upload exceed the maximum size for file uploads on this server." => "Skedarët që doni të ngarkoni tejkalojnë dimensionet maksimale për ngarkimet në këtë server.",
|
||||
"Files are being scanned, please wait." => "Skedarët po analizohen, ju lutemi pritni.",
|
||||
"Current scanning" => "Analizimi aktual",
|
||||
"Upgrading filesystem cache..." => "Po përmirësoj memorjen e filesystem-it..."
|
||||
);
|
||||
@@ -7,6 +7,8 @@
|
||||
"Missing a temporary folder" => "Недостаје привремена фасцикла",
|
||||
"Failed to write to disk" => "Не могу да пишем на диск",
|
||||
"Files" => "Датотеке",
|
||||
"Share" => "Дели",
|
||||
"Delete permanently" => "Обриши за стално",
|
||||
"Delete" => "Обриши",
|
||||
"Rename" => "Преименуј",
|
||||
"Pending" => "На чекању",
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"Not enough storage available" => "Inte tillräckligt med lagringsutrymme tillgängligt",
|
||||
"Invalid directory." => "Felaktig mapp.",
|
||||
"Files" => "Filer",
|
||||
"Share" => "Dela",
|
||||
"Delete permanently" => "Radera permanent",
|
||||
"Delete" => "Radera",
|
||||
"Rename" => "Byt namn",
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"Missing a temporary folder" => "ஒரு தற்காலிகமான கோப்புறையை காணவில்லை",
|
||||
"Failed to write to disk" => "வட்டில் எழுத முடியவில்லை",
|
||||
"Files" => "கோப்புகள்",
|
||||
"Share" => "பகிர்வு",
|
||||
"Delete" => "அழிக்க",
|
||||
"Rename" => "பெயர்மாற்றம்",
|
||||
"Pending" => "நிலுவையிலுள்ள",
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"Not enough storage available" => "เหลือพื้นที่ไม่เพียงสำหรับใช้งาน",
|
||||
"Invalid directory." => "ไดเร็กทอรี่ไม่ถูกต้อง",
|
||||
"Files" => "ไฟล์",
|
||||
"Share" => "แชร์",
|
||||
"Delete" => "ลบ",
|
||||
"Rename" => "เปลี่ยนชื่อ",
|
||||
"Pending" => "อยู่ระหว่างดำเนินการ",
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"Not enough storage available" => "Yeterli disk alanı yok",
|
||||
"Invalid directory." => "Geçersiz dizin.",
|
||||
"Files" => "Dosyalar",
|
||||
"Share" => "Paylaş",
|
||||
"Delete permanently" => "Kalıcı olarak sil",
|
||||
"Delete" => "Sil",
|
||||
"Rename" => "İsim değiştir.",
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"Not enough storage available" => "Місця більше немає",
|
||||
"Invalid directory." => "Невірний каталог.",
|
||||
"Files" => "Файли",
|
||||
"Share" => "Поділитися",
|
||||
"Delete permanently" => "Видалити назавжди",
|
||||
"Delete" => "Видалити",
|
||||
"Rename" => "Перейменувати",
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"Not enough storage available" => "Không đủ không gian lưu trữ",
|
||||
"Invalid directory." => "Thư mục không hợp lệ",
|
||||
"Files" => "Tập tin",
|
||||
"Share" => "Chia sẻ",
|
||||
"Delete permanently" => "Xóa vĩnh vễn",
|
||||
"Delete" => "Xóa",
|
||||
"Rename" => "Sửa tên",
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"Missing a temporary folder" => "丢失了一个临时文件夹",
|
||||
"Failed to write to disk" => "写磁盘失败",
|
||||
"Files" => "文件",
|
||||
"Share" => "分享",
|
||||
"Delete" => "删除",
|
||||
"Rename" => "重命名",
|
||||
"Pending" => "Pending",
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
"Failed to write to disk" => "写入磁盘失败",
|
||||
"Invalid directory." => "无效文件夹。",
|
||||
"Files" => "文件",
|
||||
"Share" => "分享",
|
||||
"Delete permanently" => "永久删除",
|
||||
"Delete" => "删除",
|
||||
"Rename" => "重命名",
|
||||
"Pending" => "操作等待中",
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php $TRANSLATIONS = array(
|
||||
"Files" => "文件",
|
||||
"Share" => "分享",
|
||||
"Delete" => "刪除",
|
||||
"Error" => "錯誤",
|
||||
"Name" => "名稱",
|
||||
"{count} folders" => "{}文件夾",
|
||||
"Upload" => "上傳",
|
||||
"Save" => "儲存",
|
||||
"Download" => "下載",
|
||||
"Unshare" => "取消分享"
|
||||
);
|
||||
@@ -13,6 +13,7 @@
|
||||
"Not enough storage available" => "儲存空間不足",
|
||||
"Invalid directory." => "無效的資料夾。",
|
||||
"Files" => "檔案",
|
||||
"Share" => "分享",
|
||||
"Delete permanently" => "永久刪除",
|
||||
"Delete" => "刪除",
|
||||
"Rename" => "重新命名",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
value="(max <?php p($_['uploadMaxHumanFilesize']); ?>)">
|
||||
<input type="hidden" name="dir" value="<?php p($_['dir']) ?>" id="dir">
|
||||
<input type="file" id="file_upload_start" name='files[]'/>
|
||||
<a href="#" class="svg" onclick="return false;"></a>
|
||||
<a href="#" class="svg"></a>
|
||||
</form>
|
||||
</div>
|
||||
<?php if ($_['trash'] ): ?>
|
||||
@@ -44,13 +44,12 @@
|
||||
<div id="uploadprogressbar"></div>
|
||||
<input type="button" class="stop" style="display:none"
|
||||
value="<?php p($l->t('Cancel upload'));?>"
|
||||
onclick="javascript:Files.cancelUploads();"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div id="file_action_panel"></div>
|
||||
<?php else:?>
|
||||
<div class="crumb last"><?php p($l->t('You don’t have write permissions here.'))?></div>
|
||||
<?php elseif( !$_['isPublic'] ):?>
|
||||
<div class="actions"><input type="button" disabled value="<?php p($l->t('You don’t have write permissions here.'))?>"></div>
|
||||
<input type="hidden" name="dir" value="<?php p($_['dir']) ?>" id="dir">
|
||||
<?php endif;?>
|
||||
<input type="hidden" name="permissions" value="<?php p($_['permissions']); ?>" id="permissions">
|
||||
@@ -82,13 +81,13 @@
|
||||
<?php if ($_['permissions'] & OCP\PERMISSION_DELETE): ?>
|
||||
<!-- NOTE: Temporary fix to allow unsharing of files in root of Shared folder -->
|
||||
<?php if ($_['dir'] == '/Shared'): ?>
|
||||
<span class="selectedActions"><a href="" class="delete">
|
||||
<span class="selectedActions"><a href="" class="delete-selected">
|
||||
<?php p($l->t('Unshare'))?>
|
||||
<img class="svg" alt="<?php p($l->t('Unshare'))?>"
|
||||
src="<?php print_unescaped(OCP\image_path("core", "actions/delete.svg")); ?>" />
|
||||
</a></span>
|
||||
<?php else: ?>
|
||||
<span class="selectedActions"><a href="" class="delete">
|
||||
<span class="selectedActions"><a href="" class="delete-selected">
|
||||
<?php p($l->t('Delete'))?>
|
||||
<img class="svg" alt="<?php p($l->t('Delete'))?>"
|
||||
src="<?php print_unescaped(OCP\image_path("core", "actions/delete.svg")); ?>" />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php if(count($_["breadcrumb"])):?>
|
||||
<div class="crumb">
|
||||
<div class="crumb" data-dir=''>
|
||||
<a href="<?php print_unescaped($_['baseURL']); ?>">
|
||||
<img src="<?php print_unescaped(OCP\image_path('core', 'places/home.svg'));?>" class="svg" />
|
||||
</a>
|
||||
|
||||
@@ -0,0 +1,317 @@
|
||||
<?php
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* Crypt_Blowfish allows for encryption and decryption on the fly using
|
||||
* the Blowfish algorithm. Crypt_Blowfish does not require the mcrypt
|
||||
* PHP extension, it uses only PHP.
|
||||
* Crypt_Blowfish support encryption/decryption with or without a secret key.
|
||||
*
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* LICENSE: This source file is subject to version 3.0 of the PHP license
|
||||
* that is available through the world-wide-web at the following URI:
|
||||
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
|
||||
* the PHP License and are unable to obtain it through the web, please
|
||||
* send a note to license@php.net so we can mail you a copy immediately.
|
||||
*
|
||||
* @category Encryption
|
||||
* @package Crypt_Blowfish
|
||||
* @author Matthew Fonda <mfonda@php.net>
|
||||
* @copyright 2005 Matthew Fonda
|
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0
|
||||
* @version CVS: $Id: Blowfish.php,v 1.81 2005/05/30 18:40:36 mfonda Exp $
|
||||
* @link http://pear.php.net/package/Crypt_Blowfish
|
||||
*/
|
||||
|
||||
|
||||
require_once 'PEAR.php';
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Example usage:
|
||||
* $bf = new Crypt_Blowfish('some secret key!');
|
||||
* $encrypted = $bf->encrypt('this is some example plain text');
|
||||
* $plaintext = $bf->decrypt($encrypted);
|
||||
* echo "plain text: $plaintext";
|
||||
*
|
||||
*
|
||||
* @category Encryption
|
||||
* @package Crypt_Blowfish
|
||||
* @author Matthew Fonda <mfonda@php.net>
|
||||
* @copyright 2005 Matthew Fonda
|
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0
|
||||
* @link http://pear.php.net/package/Crypt_Blowfish
|
||||
* @version @package_version@
|
||||
* @access public
|
||||
*/
|
||||
class Crypt_Blowfish
|
||||
{
|
||||
/**
|
||||
* P-Array contains 18 32-bit subkeys
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $_P = array();
|
||||
|
||||
|
||||
/**
|
||||
* Array of four S-Blocks each containing 256 32-bit entries
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $_S = array();
|
||||
|
||||
/**
|
||||
* Mcrypt td resource
|
||||
*
|
||||
* @var resource
|
||||
* @access private
|
||||
*/
|
||||
var $_td = null;
|
||||
|
||||
/**
|
||||
* Initialization vector
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
var $_iv = null;
|
||||
|
||||
|
||||
/**
|
||||
* Crypt_Blowfish Constructor
|
||||
* Initializes the Crypt_Blowfish object, and gives a sets
|
||||
* the secret key
|
||||
*
|
||||
* @param string $key
|
||||
* @access public
|
||||
*/
|
||||
function Crypt_Blowfish($key)
|
||||
{
|
||||
if (extension_loaded('mcrypt')) {
|
||||
$this->_td = mcrypt_module_open(MCRYPT_BLOWFISH, '', 'ecb', '');
|
||||
$this->_iv = mcrypt_create_iv(8, MCRYPT_RAND);
|
||||
}
|
||||
$this->setKey($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated isReady method
|
||||
*
|
||||
* @return bool
|
||||
* @access public
|
||||
* @deprecated
|
||||
*/
|
||||
function isReady()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated init method - init is now a private
|
||||
* method and has been replaced with _init
|
||||
*
|
||||
* @return bool
|
||||
* @access public
|
||||
* @deprecated
|
||||
* @see Crypt_Blowfish::_init()
|
||||
*/
|
||||
function init()
|
||||
{
|
||||
$this->_init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the Crypt_Blowfish object
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
function _init()
|
||||
{
|
||||
$defaults = new Crypt_Blowfish_DefaultKey();
|
||||
$this->_P = $defaults->P;
|
||||
$this->_S = $defaults->S;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enciphers a single 64 bit block
|
||||
*
|
||||
* @param int &$Xl
|
||||
* @param int &$Xr
|
||||
* @access private
|
||||
*/
|
||||
function _encipher(&$Xl, &$Xr)
|
||||
{
|
||||
for ($i = 0; $i < 16; $i++) {
|
||||
$temp = $Xl ^ $this->_P[$i];
|
||||
$Xl = ((($this->_S[0][($temp>>24) & 255] +
|
||||
$this->_S[1][($temp>>16) & 255]) ^
|
||||
$this->_S[2][($temp>>8) & 255]) +
|
||||
$this->_S[3][$temp & 255]) ^ $Xr;
|
||||
$Xr = $temp;
|
||||
}
|
||||
$Xr = $Xl ^ $this->_P[16];
|
||||
$Xl = $temp ^ $this->_P[17];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deciphers a single 64 bit block
|
||||
*
|
||||
* @param int &$Xl
|
||||
* @param int &$Xr
|
||||
* @access private
|
||||
*/
|
||||
function _decipher(&$Xl, &$Xr)
|
||||
{
|
||||
for ($i = 17; $i > 1; $i--) {
|
||||
$temp = $Xl ^ $this->_P[$i];
|
||||
$Xl = ((($this->_S[0][($temp>>24) & 255] +
|
||||
$this->_S[1][($temp>>16) & 255]) ^
|
||||
$this->_S[2][($temp>>8) & 255]) +
|
||||
$this->_S[3][$temp & 255]) ^ $Xr;
|
||||
$Xr = $temp;
|
||||
}
|
||||
$Xr = $Xl ^ $this->_P[1];
|
||||
$Xl = $temp ^ $this->_P[0];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encrypts a string
|
||||
*
|
||||
* @param string $plainText
|
||||
* @return string Returns cipher text on success, PEAR_Error on failure
|
||||
* @access public
|
||||
*/
|
||||
function encrypt($plainText)
|
||||
{
|
||||
if (!is_string($plainText)) {
|
||||
PEAR::raiseError('Plain text must be a string', 0, PEAR_ERROR_DIE);
|
||||
}
|
||||
|
||||
if (extension_loaded('mcrypt')) {
|
||||
return mcrypt_generic($this->_td, $plainText);
|
||||
}
|
||||
|
||||
$cipherText = '';
|
||||
$len = strlen($plainText);
|
||||
$plainText .= str_repeat(chr(0),(8 - ($len%8))%8);
|
||||
for ($i = 0; $i < $len; $i += 8) {
|
||||
list(,$Xl,$Xr) = unpack("N2",substr($plainText,$i,8));
|
||||
$this->_encipher($Xl, $Xr);
|
||||
$cipherText .= pack("N2", $Xl, $Xr);
|
||||
}
|
||||
return $cipherText;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Decrypts an encrypted string
|
||||
*
|
||||
* @param string $cipherText
|
||||
* @return string Returns plain text on success, PEAR_Error on failure
|
||||
* @access public
|
||||
*/
|
||||
function decrypt($cipherText)
|
||||
{
|
||||
if (!is_string($cipherText)) {
|
||||
PEAR::raiseError('Cipher text must be a string', 1, PEAR_ERROR_DIE);
|
||||
}
|
||||
|
||||
if (extension_loaded('mcrypt')) {
|
||||
return mdecrypt_generic($this->_td, $cipherText);
|
||||
}
|
||||
|
||||
$plainText = '';
|
||||
$len = strlen($cipherText);
|
||||
$cipherText .= str_repeat(chr(0),(8 - ($len%8))%8);
|
||||
for ($i = 0; $i < $len; $i += 8) {
|
||||
list(,$Xl,$Xr) = unpack("N2",substr($cipherText,$i,8));
|
||||
$this->_decipher($Xl, $Xr);
|
||||
$plainText .= pack("N2", $Xl, $Xr);
|
||||
}
|
||||
return $plainText;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the secret key
|
||||
* The key must be non-zero, and less than or equal to
|
||||
* 56 characters in length.
|
||||
*
|
||||
* @param string $key
|
||||
* @return bool Returns true on success, PEAR_Error on failure
|
||||
* @access public
|
||||
*/
|
||||
function setKey($key)
|
||||
{
|
||||
if (!is_string($key)) {
|
||||
PEAR::raiseError('Key must be a string', 2, PEAR_ERROR_DIE);
|
||||
}
|
||||
|
||||
$len = strlen($key);
|
||||
|
||||
if ($len > 56 || $len == 0) {
|
||||
PEAR::raiseError('Key must be less than 56 characters and non-zero. Supplied key length: ' . $len, 3, PEAR_ERROR_DIE);
|
||||
}
|
||||
|
||||
if (extension_loaded('mcrypt')) {
|
||||
mcrypt_generic_init($this->_td, $key, $this->_iv);
|
||||
return true;
|
||||
}
|
||||
|
||||
require_once 'Blowfish/DefaultKey.php';
|
||||
$this->_init();
|
||||
|
||||
$k = 0;
|
||||
$data = 0;
|
||||
$datal = 0;
|
||||
$datar = 0;
|
||||
|
||||
for ($i = 0; $i < 18; $i++) {
|
||||
$data = 0;
|
||||
for ($j = 4; $j > 0; $j--) {
|
||||
$data = $data << 8 | ord($key{$k});
|
||||
$k = ($k+1) % $len;
|
||||
}
|
||||
$this->_P[$i] ^= $data;
|
||||
}
|
||||
|
||||
for ($i = 0; $i <= 16; $i += 2) {
|
||||
$this->_encipher($datal, $datar);
|
||||
$this->_P[$i] = $datal;
|
||||
$this->_P[$i+1] = $datar;
|
||||
}
|
||||
for ($i = 0; $i < 256; $i += 2) {
|
||||
$this->_encipher($datal, $datar);
|
||||
$this->_S[0][$i] = $datal;
|
||||
$this->_S[0][$i+1] = $datar;
|
||||
}
|
||||
for ($i = 0; $i < 256; $i += 2) {
|
||||
$this->_encipher($datal, $datar);
|
||||
$this->_S[1][$i] = $datal;
|
||||
$this->_S[1][$i+1] = $datar;
|
||||
}
|
||||
for ($i = 0; $i < 256; $i += 2) {
|
||||
$this->_encipher($datal, $datar);
|
||||
$this->_S[2][$i] = $datal;
|
||||
$this->_S[2][$i+1] = $datar;
|
||||
}
|
||||
for ($i = 0; $i < 256; $i += 2) {
|
||||
$this->_encipher($datal, $datar);
|
||||
$this->_S[3][$i] = $datal;
|
||||
$this->_S[3][$i+1] = $datar;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,327 @@
|
||||
<?php
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* Crypt_Blowfish allows for encryption and decryption on the fly using
|
||||
* the Blowfish algorithm. Crypt_Blowfish does not require the mcrypt
|
||||
* PHP extension, it uses only PHP.
|
||||
* Crypt_Blowfish support encryption/decryption with or without a secret key.
|
||||
*
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* LICENSE: This source file is subject to version 3.0 of the PHP license
|
||||
* that is available through the world-wide-web at the following URI:
|
||||
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
|
||||
* the PHP License and are unable to obtain it through the web, please
|
||||
* send a note to license@php.net so we can mail you a copy immediately.
|
||||
*
|
||||
* @category Encryption
|
||||
* @package Crypt_Blowfish
|
||||
* @author Matthew Fonda <mfonda@php.net>
|
||||
* @copyright 2005 Matthew Fonda
|
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0
|
||||
* @version CVS: $Id: DefaultKey.php,v 1.81 2005/05/30 18:40:37 mfonda Exp $
|
||||
* @link http://pear.php.net/package/Crypt_Blowfish
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Class containing default key
|
||||
*
|
||||
* @category Encryption
|
||||
* @package Crypt_Blowfish
|
||||
* @author Matthew Fonda <mfonda@php.net>
|
||||
* @copyright 2005 Matthew Fonda
|
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0
|
||||
* @link http://pear.php.net/package/Crypt_Blowfish
|
||||
* @version @package_version@
|
||||
* @access public
|
||||
*/
|
||||
class Crypt_Blowfish_DefaultKey
|
||||
{
|
||||
var $P = array();
|
||||
|
||||
var $S = array();
|
||||
|
||||
function Crypt_Blowfish_DefaultKey()
|
||||
{
|
||||
$this->P = array(
|
||||
0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344,
|
||||
0xA4093822, 0x299F31D0, 0x082EFA98, 0xEC4E6C89,
|
||||
0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C,
|
||||
0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917,
|
||||
0x9216D5D9, 0x8979FB1B
|
||||
);
|
||||
|
||||
$this->S = array(
|
||||
array(
|
||||
0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7,
|
||||
0xB8E1AFED, 0x6A267E96, 0xBA7C9045, 0xF12C7F99,
|
||||
0x24A19947, 0xB3916CF7, 0x0801F2E2, 0x858EFC16,
|
||||
0x636920D8, 0x71574E69, 0xA458FEA3, 0xF4933D7E,
|
||||
0x0D95748F, 0x728EB658, 0x718BCD58, 0x82154AEE,
|
||||
0x7B54A41D, 0xC25A59B5, 0x9C30D539, 0x2AF26013,
|
||||
0xC5D1B023, 0x286085F0, 0xCA417918, 0xB8DB38EF,
|
||||
0x8E79DCB0, 0x603A180E, 0x6C9E0E8B, 0xB01E8A3E,
|
||||
0xD71577C1, 0xBD314B27, 0x78AF2FDA, 0x55605C60,
|
||||
0xE65525F3, 0xAA55AB94, 0x57489862, 0x63E81440,
|
||||
0x55CA396A, 0x2AAB10B6, 0xB4CC5C34, 0x1141E8CE,
|
||||
0xA15486AF, 0x7C72E993, 0xB3EE1411, 0x636FBC2A,
|
||||
0x2BA9C55D, 0x741831F6, 0xCE5C3E16, 0x9B87931E,
|
||||
0xAFD6BA33, 0x6C24CF5C, 0x7A325381, 0x28958677,
|
||||
0x3B8F4898, 0x6B4BB9AF, 0xC4BFE81B, 0x66282193,
|
||||
0x61D809CC, 0xFB21A991, 0x487CAC60, 0x5DEC8032,
|
||||
0xEF845D5D, 0xE98575B1, 0xDC262302, 0xEB651B88,
|
||||
0x23893E81, 0xD396ACC5, 0x0F6D6FF3, 0x83F44239,
|
||||
0x2E0B4482, 0xA4842004, 0x69C8F04A, 0x9E1F9B5E,
|
||||
0x21C66842, 0xF6E96C9A, 0x670C9C61, 0xABD388F0,
|
||||
0x6A51A0D2, 0xD8542F68, 0x960FA728, 0xAB5133A3,
|
||||
0x6EEF0B6C, 0x137A3BE4, 0xBA3BF050, 0x7EFB2A98,
|
||||
0xA1F1651D, 0x39AF0176, 0x66CA593E, 0x82430E88,
|
||||
0x8CEE8619, 0x456F9FB4, 0x7D84A5C3, 0x3B8B5EBE,
|
||||
0xE06F75D8, 0x85C12073, 0x401A449F, 0x56C16AA6,
|
||||
0x4ED3AA62, 0x363F7706, 0x1BFEDF72, 0x429B023D,
|
||||
0x37D0D724, 0xD00A1248, 0xDB0FEAD3, 0x49F1C09B,
|
||||
0x075372C9, 0x80991B7B, 0x25D479D8, 0xF6E8DEF7,
|
||||
0xE3FE501A, 0xB6794C3B, 0x976CE0BD, 0x04C006BA,
|
||||
0xC1A94FB6, 0x409F60C4, 0x5E5C9EC2, 0x196A2463,
|
||||
0x68FB6FAF, 0x3E6C53B5, 0x1339B2EB, 0x3B52EC6F,
|
||||
0x6DFC511F, 0x9B30952C, 0xCC814544, 0xAF5EBD09,
|
||||
0xBEE3D004, 0xDE334AFD, 0x660F2807, 0x192E4BB3,
|
||||
0xC0CBA857, 0x45C8740F, 0xD20B5F39, 0xB9D3FBDB,
|
||||
0x5579C0BD, 0x1A60320A, 0xD6A100C6, 0x402C7279,
|
||||
0x679F25FE, 0xFB1FA3CC, 0x8EA5E9F8, 0xDB3222F8,
|
||||
0x3C7516DF, 0xFD616B15, 0x2F501EC8, 0xAD0552AB,
|
||||
0x323DB5FA, 0xFD238760, 0x53317B48, 0x3E00DF82,
|
||||
0x9E5C57BB, 0xCA6F8CA0, 0x1A87562E, 0xDF1769DB,
|
||||
0xD542A8F6, 0x287EFFC3, 0xAC6732C6, 0x8C4F5573,
|
||||
0x695B27B0, 0xBBCA58C8, 0xE1FFA35D, 0xB8F011A0,
|
||||
0x10FA3D98, 0xFD2183B8, 0x4AFCB56C, 0x2DD1D35B,
|
||||
0x9A53E479, 0xB6F84565, 0xD28E49BC, 0x4BFB9790,
|
||||
0xE1DDF2DA, 0xA4CB7E33, 0x62FB1341, 0xCEE4C6E8,
|
||||
0xEF20CADA, 0x36774C01, 0xD07E9EFE, 0x2BF11FB4,
|
||||
0x95DBDA4D, 0xAE909198, 0xEAAD8E71, 0x6B93D5A0,
|
||||
0xD08ED1D0, 0xAFC725E0, 0x8E3C5B2F, 0x8E7594B7,
|
||||
0x8FF6E2FB, 0xF2122B64, 0x8888B812, 0x900DF01C,
|
||||
0x4FAD5EA0, 0x688FC31C, 0xD1CFF191, 0xB3A8C1AD,
|
||||
0x2F2F2218, 0xBE0E1777, 0xEA752DFE, 0x8B021FA1,
|
||||
0xE5A0CC0F, 0xB56F74E8, 0x18ACF3D6, 0xCE89E299,
|
||||
0xB4A84FE0, 0xFD13E0B7, 0x7CC43B81, 0xD2ADA8D9,
|
||||
0x165FA266, 0x80957705, 0x93CC7314, 0x211A1477,
|
||||
0xE6AD2065, 0x77B5FA86, 0xC75442F5, 0xFB9D35CF,
|
||||
0xEBCDAF0C, 0x7B3E89A0, 0xD6411BD3, 0xAE1E7E49,
|
||||
0x00250E2D, 0x2071B35E, 0x226800BB, 0x57B8E0AF,
|
||||
0x2464369B, 0xF009B91E, 0x5563911D, 0x59DFA6AA,
|
||||
0x78C14389, 0xD95A537F, 0x207D5BA2, 0x02E5B9C5,
|
||||
0x83260376, 0x6295CFA9, 0x11C81968, 0x4E734A41,
|
||||
0xB3472DCA, 0x7B14A94A, 0x1B510052, 0x9A532915,
|
||||
0xD60F573F, 0xBC9BC6E4, 0x2B60A476, 0x81E67400,
|
||||
0x08BA6FB5, 0x571BE91F, 0xF296EC6B, 0x2A0DD915,
|
||||
0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664,
|
||||
0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A
|
||||
),
|
||||
array(
|
||||
0x4B7A70E9, 0xB5B32944, 0xDB75092E, 0xC4192623,
|
||||
0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266,
|
||||
0xECAA8C71, 0x699A17FF, 0x5664526C, 0xC2B19EE1,
|
||||
0x193602A5, 0x75094C29, 0xA0591340, 0xE4183A3E,
|
||||
0x3F54989A, 0x5B429D65, 0x6B8FE4D6, 0x99F73FD6,
|
||||
0xA1D29C07, 0xEFE830F5, 0x4D2D38E6, 0xF0255DC1,
|
||||
0x4CDD2086, 0x8470EB26, 0x6382E9C6, 0x021ECC5E,
|
||||
0x09686B3F, 0x3EBAEFC9, 0x3C971814, 0x6B6A70A1,
|
||||
0x687F3584, 0x52A0E286, 0xB79C5305, 0xAA500737,
|
||||
0x3E07841C, 0x7FDEAE5C, 0x8E7D44EC, 0x5716F2B8,
|
||||
0xB03ADA37, 0xF0500C0D, 0xF01C1F04, 0x0200B3FF,
|
||||
0xAE0CF51A, 0x3CB574B2, 0x25837A58, 0xDC0921BD,
|
||||
0xD19113F9, 0x7CA92FF6, 0x94324773, 0x22F54701,
|
||||
0x3AE5E581, 0x37C2DADC, 0xC8B57634, 0x9AF3DDA7,
|
||||
0xA9446146, 0x0FD0030E, 0xECC8C73E, 0xA4751E41,
|
||||
0xE238CD99, 0x3BEA0E2F, 0x3280BBA1, 0x183EB331,
|
||||
0x4E548B38, 0x4F6DB908, 0x6F420D03, 0xF60A04BF,
|
||||
0x2CB81290, 0x24977C79, 0x5679B072, 0xBCAF89AF,
|
||||
0xDE9A771F, 0xD9930810, 0xB38BAE12, 0xDCCF3F2E,
|
||||
0x5512721F, 0x2E6B7124, 0x501ADDE6, 0x9F84CD87,
|
||||
0x7A584718, 0x7408DA17, 0xBC9F9ABC, 0xE94B7D8C,
|
||||
0xEC7AEC3A, 0xDB851DFA, 0x63094366, 0xC464C3D2,
|
||||
0xEF1C1847, 0x3215D908, 0xDD433B37, 0x24C2BA16,
|
||||
0x12A14D43, 0x2A65C451, 0x50940002, 0x133AE4DD,
|
||||
0x71DFF89E, 0x10314E55, 0x81AC77D6, 0x5F11199B,
|
||||
0x043556F1, 0xD7A3C76B, 0x3C11183B, 0x5924A509,
|
||||
0xF28FE6ED, 0x97F1FBFA, 0x9EBABF2C, 0x1E153C6E,
|
||||
0x86E34570, 0xEAE96FB1, 0x860E5E0A, 0x5A3E2AB3,
|
||||
0x771FE71C, 0x4E3D06FA, 0x2965DCB9, 0x99E71D0F,
|
||||
0x803E89D6, 0x5266C825, 0x2E4CC978, 0x9C10B36A,
|
||||
0xC6150EBA, 0x94E2EA78, 0xA5FC3C53, 0x1E0A2DF4,
|
||||
0xF2F74EA7, 0x361D2B3D, 0x1939260F, 0x19C27960,
|
||||
0x5223A708, 0xF71312B6, 0xEBADFE6E, 0xEAC31F66,
|
||||
0xE3BC4595, 0xA67BC883, 0xB17F37D1, 0x018CFF28,
|
||||
0xC332DDEF, 0xBE6C5AA5, 0x65582185, 0x68AB9802,
|
||||
0xEECEA50F, 0xDB2F953B, 0x2AEF7DAD, 0x5B6E2F84,
|
||||
0x1521B628, 0x29076170, 0xECDD4775, 0x619F1510,
|
||||
0x13CCA830, 0xEB61BD96, 0x0334FE1E, 0xAA0363CF,
|
||||
0xB5735C90, 0x4C70A239, 0xD59E9E0B, 0xCBAADE14,
|
||||
0xEECC86BC, 0x60622CA7, 0x9CAB5CAB, 0xB2F3846E,
|
||||
0x648B1EAF, 0x19BDF0CA, 0xA02369B9, 0x655ABB50,
|
||||
0x40685A32, 0x3C2AB4B3, 0x319EE9D5, 0xC021B8F7,
|
||||
0x9B540B19, 0x875FA099, 0x95F7997E, 0x623D7DA8,
|
||||
0xF837889A, 0x97E32D77, 0x11ED935F, 0x16681281,
|
||||
0x0E358829, 0xC7E61FD6, 0x96DEDFA1, 0x7858BA99,
|
||||
0x57F584A5, 0x1B227263, 0x9B83C3FF, 0x1AC24696,
|
||||
0xCDB30AEB, 0x532E3054, 0x8FD948E4, 0x6DBC3128,
|
||||
0x58EBF2EF, 0x34C6FFEA, 0xFE28ED61, 0xEE7C3C73,
|
||||
0x5D4A14D9, 0xE864B7E3, 0x42105D14, 0x203E13E0,
|
||||
0x45EEE2B6, 0xA3AAABEA, 0xDB6C4F15, 0xFACB4FD0,
|
||||
0xC742F442, 0xEF6ABBB5, 0x654F3B1D, 0x41CD2105,
|
||||
0xD81E799E, 0x86854DC7, 0xE44B476A, 0x3D816250,
|
||||
0xCF62A1F2, 0x5B8D2646, 0xFC8883A0, 0xC1C7B6A3,
|
||||
0x7F1524C3, 0x69CB7492, 0x47848A0B, 0x5692B285,
|
||||
0x095BBF00, 0xAD19489D, 0x1462B174, 0x23820E00,
|
||||
0x58428D2A, 0x0C55F5EA, 0x1DADF43E, 0x233F7061,
|
||||
0x3372F092, 0x8D937E41, 0xD65FECF1, 0x6C223BDB,
|
||||
0x7CDE3759, 0xCBEE7460, 0x4085F2A7, 0xCE77326E,
|
||||
0xA6078084, 0x19F8509E, 0xE8EFD855, 0x61D99735,
|
||||
0xA969A7AA, 0xC50C06C2, 0x5A04ABFC, 0x800BCADC,
|
||||
0x9E447A2E, 0xC3453484, 0xFDD56705, 0x0E1E9EC9,
|
||||
0xDB73DBD3, 0x105588CD, 0x675FDA79, 0xE3674340,
|
||||
0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20,
|
||||
0x153E21E7, 0x8FB03D4A, 0xE6E39F2B, 0xDB83ADF7
|
||||
),
|
||||
array(
|
||||
0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934,
|
||||
0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068,
|
||||
0xD4082471, 0x3320F46A, 0x43B7D4B7, 0x500061AF,
|
||||
0x1E39F62E, 0x97244546, 0x14214F74, 0xBF8B8840,
|
||||
0x4D95FC1D, 0x96B591AF, 0x70F4DDD3, 0x66A02F45,
|
||||
0xBFBC09EC, 0x03BD9785, 0x7FAC6DD0, 0x31CB8504,
|
||||
0x96EB27B3, 0x55FD3941, 0xDA2547E6, 0xABCA0A9A,
|
||||
0x28507825, 0x530429F4, 0x0A2C86DA, 0xE9B66DFB,
|
||||
0x68DC1462, 0xD7486900, 0x680EC0A4, 0x27A18DEE,
|
||||
0x4F3FFEA2, 0xE887AD8C, 0xB58CE006, 0x7AF4D6B6,
|
||||
0xAACE1E7C, 0xD3375FEC, 0xCE78A399, 0x406B2A42,
|
||||
0x20FE9E35, 0xD9F385B9, 0xEE39D7AB, 0x3B124E8B,
|
||||
0x1DC9FAF7, 0x4B6D1856, 0x26A36631, 0xEAE397B2,
|
||||
0x3A6EFA74, 0xDD5B4332, 0x6841E7F7, 0xCA7820FB,
|
||||
0xFB0AF54E, 0xD8FEB397, 0x454056AC, 0xBA489527,
|
||||
0x55533A3A, 0x20838D87, 0xFE6BA9B7, 0xD096954B,
|
||||
0x55A867BC, 0xA1159A58, 0xCCA92963, 0x99E1DB33,
|
||||
0xA62A4A56, 0x3F3125F9, 0x5EF47E1C, 0x9029317C,
|
||||
0xFDF8E802, 0x04272F70, 0x80BB155C, 0x05282CE3,
|
||||
0x95C11548, 0xE4C66D22, 0x48C1133F, 0xC70F86DC,
|
||||
0x07F9C9EE, 0x41041F0F, 0x404779A4, 0x5D886E17,
|
||||
0x325F51EB, 0xD59BC0D1, 0xF2BCC18F, 0x41113564,
|
||||
0x257B7834, 0x602A9C60, 0xDFF8E8A3, 0x1F636C1B,
|
||||
0x0E12B4C2, 0x02E1329E, 0xAF664FD1, 0xCAD18115,
|
||||
0x6B2395E0, 0x333E92E1, 0x3B240B62, 0xEEBEB922,
|
||||
0x85B2A20E, 0xE6BA0D99, 0xDE720C8C, 0x2DA2F728,
|
||||
0xD0127845, 0x95B794FD, 0x647D0862, 0xE7CCF5F0,
|
||||
0x5449A36F, 0x877D48FA, 0xC39DFD27, 0xF33E8D1E,
|
||||
0x0A476341, 0x992EFF74, 0x3A6F6EAB, 0xF4F8FD37,
|
||||
0xA812DC60, 0xA1EBDDF8, 0x991BE14C, 0xDB6E6B0D,
|
||||
0xC67B5510, 0x6D672C37, 0x2765D43B, 0xDCD0E804,
|
||||
0xF1290DC7, 0xCC00FFA3, 0xB5390F92, 0x690FED0B,
|
||||
0x667B9FFB, 0xCEDB7D9C, 0xA091CF0B, 0xD9155EA3,
|
||||
0xBB132F88, 0x515BAD24, 0x7B9479BF, 0x763BD6EB,
|
||||
0x37392EB3, 0xCC115979, 0x8026E297, 0xF42E312D,
|
||||
0x6842ADA7, 0xC66A2B3B, 0x12754CCC, 0x782EF11C,
|
||||
0x6A124237, 0xB79251E7, 0x06A1BBE6, 0x4BFB6350,
|
||||
0x1A6B1018, 0x11CAEDFA, 0x3D25BDD8, 0xE2E1C3C9,
|
||||
0x44421659, 0x0A121386, 0xD90CEC6E, 0xD5ABEA2A,
|
||||
0x64AF674E, 0xDA86A85F, 0xBEBFE988, 0x64E4C3FE,
|
||||
0x9DBC8057, 0xF0F7C086, 0x60787BF8, 0x6003604D,
|
||||
0xD1FD8346, 0xF6381FB0, 0x7745AE04, 0xD736FCCC,
|
||||
0x83426B33, 0xF01EAB71, 0xB0804187, 0x3C005E5F,
|
||||
0x77A057BE, 0xBDE8AE24, 0x55464299, 0xBF582E61,
|
||||
0x4E58F48F, 0xF2DDFDA2, 0xF474EF38, 0x8789BDC2,
|
||||
0x5366F9C3, 0xC8B38E74, 0xB475F255, 0x46FCD9B9,
|
||||
0x7AEB2661, 0x8B1DDF84, 0x846A0E79, 0x915F95E2,
|
||||
0x466E598E, 0x20B45770, 0x8CD55591, 0xC902DE4C,
|
||||
0xB90BACE1, 0xBB8205D0, 0x11A86248, 0x7574A99E,
|
||||
0xB77F19B6, 0xE0A9DC09, 0x662D09A1, 0xC4324633,
|
||||
0xE85A1F02, 0x09F0BE8C, 0x4A99A025, 0x1D6EFE10,
|
||||
0x1AB93D1D, 0x0BA5A4DF, 0xA186F20F, 0x2868F169,
|
||||
0xDCB7DA83, 0x573906FE, 0xA1E2CE9B, 0x4FCD7F52,
|
||||
0x50115E01, 0xA70683FA, 0xA002B5C4, 0x0DE6D027,
|
||||
0x9AF88C27, 0x773F8641, 0xC3604C06, 0x61A806B5,
|
||||
0xF0177A28, 0xC0F586E0, 0x006058AA, 0x30DC7D62,
|
||||
0x11E69ED7, 0x2338EA63, 0x53C2DD94, 0xC2C21634,
|
||||
0xBBCBEE56, 0x90BCB6DE, 0xEBFC7DA1, 0xCE591D76,
|
||||
0x6F05E409, 0x4B7C0188, 0x39720A3D, 0x7C927C24,
|
||||
0x86E3725F, 0x724D9DB9, 0x1AC15BB4, 0xD39EB8FC,
|
||||
0xED545578, 0x08FCA5B5, 0xD83D7CD3, 0x4DAD0FC4,
|
||||
0x1E50EF5E, 0xB161E6F8, 0xA28514D9, 0x6C51133C,
|
||||
0x6FD5C7E7, 0x56E14EC4, 0x362ABFCE, 0xDDC6C837,
|
||||
0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0
|
||||
),
|
||||
array(
|
||||
0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B,
|
||||
0x5CB0679E, 0x4FA33742, 0xD3822740, 0x99BC9BBE,
|
||||
0xD5118E9D, 0xBF0F7315, 0xD62D1C7E, 0xC700C47B,
|
||||
0xB78C1B6B, 0x21A19045, 0xB26EB1BE, 0x6A366EB4,
|
||||
0x5748AB2F, 0xBC946E79, 0xC6A376D2, 0x6549C2C8,
|
||||
0x530FF8EE, 0x468DDE7D, 0xD5730A1D, 0x4CD04DC6,
|
||||
0x2939BBDB, 0xA9BA4650, 0xAC9526E8, 0xBE5EE304,
|
||||
0xA1FAD5F0, 0x6A2D519A, 0x63EF8CE2, 0x9A86EE22,
|
||||
0xC089C2B8, 0x43242EF6, 0xA51E03AA, 0x9CF2D0A4,
|
||||
0x83C061BA, 0x9BE96A4D, 0x8FE51550, 0xBA645BD6,
|
||||
0x2826A2F9, 0xA73A3AE1, 0x4BA99586, 0xEF5562E9,
|
||||
0xC72FEFD3, 0xF752F7DA, 0x3F046F69, 0x77FA0A59,
|
||||
0x80E4A915, 0x87B08601, 0x9B09E6AD, 0x3B3EE593,
|
||||
0xE990FD5A, 0x9E34D797, 0x2CF0B7D9, 0x022B8B51,
|
||||
0x96D5AC3A, 0x017DA67D, 0xD1CF3ED6, 0x7C7D2D28,
|
||||
0x1F9F25CF, 0xADF2B89B, 0x5AD6B472, 0x5A88F54C,
|
||||
0xE029AC71, 0xE019A5E6, 0x47B0ACFD, 0xED93FA9B,
|
||||
0xE8D3C48D, 0x283B57CC, 0xF8D56629, 0x79132E28,
|
||||
0x785F0191, 0xED756055, 0xF7960E44, 0xE3D35E8C,
|
||||
0x15056DD4, 0x88F46DBA, 0x03A16125, 0x0564F0BD,
|
||||
0xC3EB9E15, 0x3C9057A2, 0x97271AEC, 0xA93A072A,
|
||||
0x1B3F6D9B, 0x1E6321F5, 0xF59C66FB, 0x26DCF319,
|
||||
0x7533D928, 0xB155FDF5, 0x03563482, 0x8ABA3CBB,
|
||||
0x28517711, 0xC20AD9F8, 0xABCC5167, 0xCCAD925F,
|
||||
0x4DE81751, 0x3830DC8E, 0x379D5862, 0x9320F991,
|
||||
0xEA7A90C2, 0xFB3E7BCE, 0x5121CE64, 0x774FBE32,
|
||||
0xA8B6E37E, 0xC3293D46, 0x48DE5369, 0x6413E680,
|
||||
0xA2AE0810, 0xDD6DB224, 0x69852DFD, 0x09072166,
|
||||
0xB39A460A, 0x6445C0DD, 0x586CDECF, 0x1C20C8AE,
|
||||
0x5BBEF7DD, 0x1B588D40, 0xCCD2017F, 0x6BB4E3BB,
|
||||
0xDDA26A7E, 0x3A59FF45, 0x3E350A44, 0xBCB4CDD5,
|
||||
0x72EACEA8, 0xFA6484BB, 0x8D6612AE, 0xBF3C6F47,
|
||||
0xD29BE463, 0x542F5D9E, 0xAEC2771B, 0xF64E6370,
|
||||
0x740E0D8D, 0xE75B1357, 0xF8721671, 0xAF537D5D,
|
||||
0x4040CB08, 0x4EB4E2CC, 0x34D2466A, 0x0115AF84,
|
||||
0xE1B00428, 0x95983A1D, 0x06B89FB4, 0xCE6EA048,
|
||||
0x6F3F3B82, 0x3520AB82, 0x011A1D4B, 0x277227F8,
|
||||
0x611560B1, 0xE7933FDC, 0xBB3A792B, 0x344525BD,
|
||||
0xA08839E1, 0x51CE794B, 0x2F32C9B7, 0xA01FBAC9,
|
||||
0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7,
|
||||
0x1A908749, 0xD44FBD9A, 0xD0DADECB, 0xD50ADA38,
|
||||
0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F,
|
||||
0xF79E59B7, 0x43F5BB3A, 0xF2D519FF, 0x27D9459C,
|
||||
0xBF97222C, 0x15E6FC2A, 0x0F91FC71, 0x9B941525,
|
||||
0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1,
|
||||
0xB6C1075E, 0xE3056A0C, 0x10D25065, 0xCB03A442,
|
||||
0xE0EC6E0E, 0x1698DB3B, 0x4C98A0BE, 0x3278E964,
|
||||
0x9F1F9532, 0xE0D392DF, 0xD3A0342B, 0x8971F21E,
|
||||
0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8,
|
||||
0xDF359F8D, 0x9B992F2E, 0xE60B6F47, 0x0FE3F11D,
|
||||
0xE54CDA54, 0x1EDAD891, 0xCE6279CF, 0xCD3E7E6F,
|
||||
0x1618B166, 0xFD2C1D05, 0x848FD2C5, 0xF6FB2299,
|
||||
0xF523F357, 0xA6327623, 0x93A83531, 0x56CCCD02,
|
||||
0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC,
|
||||
0xDE966292, 0x81B949D0, 0x4C50901B, 0x71C65614,
|
||||
0xE6C6C7BD, 0x327A140A, 0x45E1D006, 0xC3F27B9A,
|
||||
0xC9AA53FD, 0x62A80F00, 0xBB25BFE2, 0x35BDD2F6,
|
||||
0x71126905, 0xB2040222, 0xB6CBCF7C, 0xCD769C2B,
|
||||
0x53113EC0, 0x1640E3D3, 0x38ABBD60, 0x2547ADF0,
|
||||
0xBA38209C, 0xF746CE76, 0x77AFA1C5, 0x20756060,
|
||||
0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0, 0x4CF9AA7E,
|
||||
0x1948C25C, 0x02FB8A8C, 0x01C36AE4, 0xD6EBE1F9,
|
||||
0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F,
|
||||
0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright (c) 2013, Sam Tuke <samtuke@owncloud.com>
|
||||
* This file is licensed under the Affero General Public License version 3 or later.
|
||||
* See the COPYING-README file.
|
||||
*
|
||||
* @brief Script to handle admin settings for encrypted key recovery
|
||||
*/
|
||||
use OCA\Encryption;
|
||||
|
||||
\OCP\JSON::checkAdminUser();
|
||||
\OCP\JSON::checkAppEnabled('files_encryption');
|
||||
\OCP\JSON::callCheck();
|
||||
|
||||
$l = OC_L10N::get('files_encryption');
|
||||
|
||||
$return = false;
|
||||
// Enable recoveryAdmin
|
||||
|
||||
$recoveryKeyId = OC_Appconfig::getValue('files_encryption', 'recoveryKeyId');
|
||||
|
||||
if (isset($_POST['adminEnableRecovery']) && $_POST['adminEnableRecovery'] === '1') {
|
||||
|
||||
$return = \OCA\Encryption\Helper::adminEnableRecovery($recoveryKeyId, $_POST['recoveryPassword']);
|
||||
|
||||
// Return success or failure
|
||||
if ($return) {
|
||||
\OCP\JSON::success(array('data' => array('message' => $l->t('Recovery key successfully enabled'))));
|
||||
} else {
|
||||
\OCP\JSON::error(array(
|
||||
'data' => array(
|
||||
'message' => $l->t(
|
||||
'Could not enable recovery key. Please check your recovery key password!')
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
// Disable recoveryAdmin
|
||||
} elseif (
|
||||
isset($_POST['adminEnableRecovery'])
|
||||
&& '0' === $_POST['adminEnableRecovery']
|
||||
) {
|
||||
$return = \OCA\Encryption\Helper::adminDisableRecovery($_POST['recoveryPassword']);
|
||||
|
||||
// Return success or failure
|
||||
if ($return) {
|
||||
\OCP\JSON::success(array('data' => array('message' => $l->t('Recovery key successfully disabled'))));
|
||||
} else {
|
||||
\OCP\JSON::error(array(
|
||||
'data' => array(
|
||||
'message' => $l->t(
|
||||
'Could not disable recovery key. Please check your recovery key password!')
|
||||
)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright (c) 2013, Bjoern Schiessle <schiessle@owncloud.com>
|
||||
* This file is licensed under the Affero General Public License version 3 or later.
|
||||
* See the COPYING-README file.
|
||||
*
|
||||
* @brief Script to change recovery key password
|
||||
*
|
||||
*/
|
||||
|
||||
use OCA\Encryption;
|
||||
|
||||
\OCP\JSON::checkAdminUser();
|
||||
\OCP\JSON::checkAppEnabled('files_encryption');
|
||||
\OCP\JSON::callCheck();
|
||||
|
||||
$l = OC_L10N::get('core');
|
||||
|
||||
$return = false;
|
||||
|
||||
$oldPassword = $_POST['oldPassword'];
|
||||
$newPassword = $_POST['newPassword'];
|
||||
|
||||
$view = new \OC\Files\View('/');
|
||||
$util = new \OCA\Encryption\Util(new \OC_FilesystemView('/'), \OCP\User::getUser());
|
||||
|
||||
$proxyStatus = \OC_FileProxy::$enabled;
|
||||
\OC_FileProxy::$enabled = false;
|
||||
|
||||
$keyId = $util->getRecoveryKeyId();
|
||||
$keyPath = '/owncloud_private_key/' . $keyId . '.private.key';
|
||||
|
||||
$encryptedRecoveryKey = $view->file_get_contents($keyPath);
|
||||
$decryptedRecoveryKey = \OCA\Encryption\Crypt::decryptPrivateKey($encryptedRecoveryKey, $oldPassword);
|
||||
|
||||
if ($decryptedRecoveryKey) {
|
||||
|
||||
$encryptedRecoveryKey = \OCA\Encryption\Crypt::symmetricEncryptFileContent($decryptedRecoveryKey, $newPassword);
|
||||
$view->file_put_contents($keyPath, $encryptedRecoveryKey);
|
||||
|
||||
$return = true;
|
||||
}
|
||||
|
||||
\OC_FileProxy::$enabled = $proxyStatus;
|
||||
|
||||
// success or failure
|
||||
if ($return) {
|
||||
\OCP\JSON::success(array('data' => array('message' => $l->t('Password successfully changed.'))));
|
||||
} else {
|
||||
\OCP\JSON::error(array('data' => array('message' => $l->t('Could not change the password. Maybe the old password was not correct.'))));
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright (c) 2013, Bjoern Schiessle <schiessle@owncloud.com>
|
||||
* This file is licensed under the Affero General Public License version 3 or later.
|
||||
* See the COPYING-README file.
|
||||
*
|
||||
* @brief Script to change recovery key password
|
||||
*
|
||||
*/
|
||||
|
||||
use OCA\Encryption;
|
||||
|
||||
\OCP\JSON::checkLoggedIn();
|
||||
\OCP\JSON::checkAppEnabled('files_encryption');
|
||||
\OCP\JSON::callCheck();
|
||||
|
||||
$l = OC_L10N::get('core');
|
||||
|
||||
$return = false;
|
||||
|
||||
$oldPassword = $_POST['oldPassword'];
|
||||
$newPassword = $_POST['newPassword'];
|
||||
|
||||
$view = new \OC\Files\View('/');
|
||||
$session = new \OCA\Encryption\Session($view);
|
||||
$user = \OCP\User::getUser();
|
||||
|
||||
$proxyStatus = \OC_FileProxy::$enabled;
|
||||
\OC_FileProxy::$enabled = false;
|
||||
|
||||
$keyPath = '/' . $user . '/files_encryption/' . $user . '.private.key';
|
||||
|
||||
$encryptedKey = $view->file_get_contents($keyPath);
|
||||
$decryptedKey = \OCA\Encryption\Crypt::decryptPrivateKey($encryptedKey, $oldPassword);
|
||||
|
||||
if ($decryptedKey) {
|
||||
|
||||
$encryptedKey = \OCA\Encryption\Crypt::symmetricEncryptFileContent($decryptedKey, $newPassword);
|
||||
$view->file_put_contents($keyPath, $encryptedKey);
|
||||
|
||||
$session->setPrivateKey($decryptedKey);
|
||||
|
||||
$return = true;
|
||||
}
|
||||
|
||||
\OC_FileProxy::$enabled = $proxyStatus;
|
||||
|
||||
// success or failure
|
||||
if ($return) {
|
||||
\OCP\JSON::success(array('data' => array('message' => $l->t('Private key password successfully updated.'))));
|
||||
} else {
|
||||
\OCP\JSON::error(array('data' => array('message' => $l->t('Could not update the private key password. Maybe the old password was not correct.'))));
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (c) 2013, Sam Tuke <samtuke@owncloud.com>
|
||||
* This file is licensed under the Affero General Public License version 3 or later.
|
||||
* See the COPYING-README file.
|
||||
*
|
||||
* @brief Script to handle admin settings for encrypted key recovery
|
||||
*/
|
||||
|
||||
use OCA\Encryption;
|
||||
|
||||
\OCP\JSON::checkLoggedIn();
|
||||
\OCP\JSON::checkAppEnabled('files_encryption');
|
||||
\OCP\JSON::callCheck();
|
||||
|
||||
if (
|
||||
isset($_POST['userEnableRecovery'])
|
||||
&& (0 == $_POST['userEnableRecovery'] || '1' === $_POST['userEnableRecovery'])
|
||||
) {
|
||||
|
||||
$userId = \OCP\USER::getUser();
|
||||
$view = new \OC_FilesystemView('/');
|
||||
$util = new \OCA\Encryption\Util($view, $userId);
|
||||
|
||||
// Save recovery preference to DB
|
||||
$return = $util->setRecoveryForUser($_POST['userEnableRecovery']);
|
||||
|
||||
if ($_POST['userEnableRecovery'] === '1') {
|
||||
$util->addRecoveryKeys();
|
||||
} else {
|
||||
$util->removeRecoveryKeys();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
$return = false;
|
||||
|
||||
}
|
||||
|
||||
// Return success or failure
|
||||
($return) ? \OCP\JSON::success() : \OCP\JSON::error();
|
||||
@@ -8,42 +8,61 @@ OC::$CLASSPATH['OCA\Encryption\Stream'] = 'files_encryption/lib/stream.php';
|
||||
OC::$CLASSPATH['OCA\Encryption\Proxy'] = 'files_encryption/lib/proxy.php';
|
||||
OC::$CLASSPATH['OCA\Encryption\Session'] = 'files_encryption/lib/session.php';
|
||||
OC::$CLASSPATH['OCA\Encryption\Capabilities'] = 'files_encryption/lib/capabilities.php';
|
||||
OC::$CLASSPATH['OCA\Encryption\Helper'] = 'files_encryption/lib/helper.php';
|
||||
|
||||
OC_FileProxy::register( new OCA\Encryption\Proxy() );
|
||||
if (!OC_Config::getValue('maintenance', false)) {
|
||||
OC_FileProxy::register(new OCA\Encryption\Proxy());
|
||||
|
||||
// User-related hooks
|
||||
OCP\Util::connectHook( 'OC_User', 'post_login', 'OCA\Encryption\Hooks', 'login' );
|
||||
OCP\Util::connectHook( 'OC_User', 'pre_setPassword', 'OCA\Encryption\Hooks', 'setPassphrase' );
|
||||
// User related hooks
|
||||
OCA\Encryption\Helper::registerUserHooks();
|
||||
|
||||
// Sharing-related hooks
|
||||
OCP\Util::connectHook( 'OCP\Share', 'post_shared', 'OCA\Encryption\Hooks', 'postShared' );
|
||||
OCP\Util::connectHook( 'OCP\Share', 'pre_unshare', 'OCA\Encryption\Hooks', 'preUnshare' );
|
||||
OCP\Util::connectHook( 'OCP\Share', 'pre_unshareAll', 'OCA\Encryption\Hooks', 'preUnshareAll' );
|
||||
// Sharing related hooks
|
||||
OCA\Encryption\Helper::registerShareHooks();
|
||||
|
||||
// Webdav-related hooks
|
||||
OCP\Util::connectHook( 'OC_Webdav_Properties', 'update', 'OCA\Encryption\Hooks', 'updateKeyfile' );
|
||||
// Filesystem related hooks
|
||||
OCA\Encryption\Helper::registerFilesystemHooks();
|
||||
|
||||
stream_wrapper_register( 'crypt', 'OCA\Encryption\Stream' );
|
||||
// App manager related hooks
|
||||
OCA\Encryption\Helper::registerAppHooks();
|
||||
|
||||
$session = new OCA\Encryption\Session();
|
||||
stream_wrapper_register('crypt', 'OCA\Encryption\Stream');
|
||||
|
||||
if (
|
||||
! $session->getPrivateKey( \OCP\USER::getUser() )
|
||||
&& OCP\User::isLoggedIn()
|
||||
&& OCA\Encryption\Crypt::mode() == 'server'
|
||||
) {
|
||||
// check if we are logged in
|
||||
if (OCP\User::isLoggedIn()) {
|
||||
|
||||
// Force the user to log-in again if the encryption key isn't unlocked
|
||||
// (happens when a user is logged in before the encryption app is
|
||||
// enabled)
|
||||
// ensure filesystem is loaded
|
||||
if (!\OC\Files\Filesystem::$loaded) {
|
||||
\OC_Util::setupFS();
|
||||
}
|
||||
|
||||
$view = new OC_FilesystemView('/');
|
||||
|
||||
$sessionReady = OCA\Encryption\Helper::checkRequirements();
|
||||
if($sessionReady) {
|
||||
$session = new \OCA\Encryption\Session($view);
|
||||
}
|
||||
|
||||
$user = \OCP\USER::getUser();
|
||||
// check if user has a private key
|
||||
if ($sessionReady === false || (!$view->file_exists('/' . $user . '/files_encryption/' . $user . '.private.key') && OCA\Encryption\Crypt::mode() === 'server')
|
||||
) {
|
||||
|
||||
// Force the user to log-in again if the encryption key isn't unlocked
|
||||
// (happens when a user is logged in before the encryption app is
|
||||
// enabled)
|
||||
OCP\User::logout();
|
||||
|
||||
header("Location: " . OC::$WEBROOT . '/');
|
||||
|
||||
exit();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// logout user if we are in maintenance to force re-login
|
||||
OCP\User::logout();
|
||||
|
||||
header( "Location: " . OC::$WEBROOT.'/' );
|
||||
|
||||
exit();
|
||||
|
||||
}
|
||||
|
||||
// Register settings scripts
|
||||
OCP\App::registerAdmin( 'files_encryption', 'settings' );
|
||||
OCP\App::registerPersonal( 'files_encryption', 'settings-personal' );
|
||||
OCP\App::registerAdmin('files_encryption', 'settings-admin');
|
||||
OCP\App::registerPersonal('files_encryption', 'settings-personal');
|
||||
|
||||
|
||||
@@ -18,6 +18,21 @@
|
||||
<type>text</type>
|
||||
<notnull>true</notnull>
|
||||
<length>64</length>
|
||||
<comments>What client-side / server-side configuration is used</comments>
|
||||
</field>
|
||||
<field>
|
||||
<name>recovery_enabled</name>
|
||||
<type>integer</type>
|
||||
<notnull>true</notnull>
|
||||
<default>0</default>
|
||||
<comments>Whether encryption key recovery is enabled</comments>
|
||||
</field>
|
||||
<field>
|
||||
<name>migration_status</name>
|
||||
<type>integer</type>
|
||||
<notnull>true</notnull>
|
||||
<default>0</default>
|
||||
<comments>Whether encryption migration has been performed</comments>
|
||||
</field>
|
||||
</declaration>
|
||||
</table>
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
<info>
|
||||
<id>files_encryption</id>
|
||||
<name>Encryption</name>
|
||||
<description>Server side encryption of files. Warning: You will lose your data if you enable this App and forget your password. Encryption is not yet compatible with LDAP.</description>
|
||||
<description>WARNING: This is a preview release of the new ownCloud 5 encryption system. Testing and feedback is very welcome but don't use this in production yet. After the app was enabled you need to re-login to initialize your encryption keys</description>
|
||||
<licence>AGPL</licence>
|
||||
<author>Sam Tuke</author>
|
||||
<author>Sam Tuke, Bjoern Schiessle, Florin Peter</author>
|
||||
<require>4</require>
|
||||
<shipped>true</shipped>
|
||||
<types>
|
||||
|
||||
@@ -9,6 +9,57 @@ Encrypted files
|
||||
|
||||
[encrypted data string][delimiter][IV][padding]
|
||||
[anhAAjAmcGXqj1X9g==][00iv00][MSHU5N5gECP7aAg7][xx] (square braces added)
|
||||
|
||||
- Directory structure:
|
||||
- Encrypted user data (catfiles) are stored in the usual /data/user/files dir
|
||||
- Keyfiles are stored in /data/user/files_encryption/keyfiles
|
||||
- Sharekey are stored in /data/user/files_encryption/share-files
|
||||
|
||||
- File extensions:
|
||||
- Catfiles have to keep the file extension of the original file, pre-encryption
|
||||
- Keyfiles use .keyfile
|
||||
- Sharekeys have .shareKey
|
||||
|
||||
Shared files
|
||||
------------
|
||||
|
||||
Shared files have a centrally stored catfile and keyfile, and one sharekey for
|
||||
each user that shares it.
|
||||
|
||||
When sharing is used, a different encryption method is used to encrypt the
|
||||
keyfile (openssl_seal). Although shared files have a keyfile, its contents
|
||||
use a different format therefore.
|
||||
|
||||
Each time a shared file is edited or deleted, all sharekeys for users sharing
|
||||
that file must have their sharekeys changed also. The keyfile and catfile
|
||||
however need only changing in the owners files, as there is only one copy of
|
||||
these.
|
||||
|
||||
Publicly shared files (public links)
|
||||
------------------------------------
|
||||
|
||||
Files shared via public links use a separate system user account called 'ownCloud'. All public files are shared to that user's public key, and the private key is used to access the files when the public link is used in browser.
|
||||
|
||||
This means that files shared via public links are accessible only to users who know the shared URL, or to admins who know the 'ownCloud' user password.
|
||||
|
||||
Lost password recovery
|
||||
----------------------
|
||||
|
||||
In order to enable users to read their encrypted files in the event of a password loss/reset scenario, administrators can choose to enable a 'recoveryAdmin' account. This is a user that all user files will automatically be shared to of the option is enabled. This allows the recoveryAdmin user to generate new keyfiles for the user. By default the UID of the recoveryAdmin is 'recoveryAdmin'.
|
||||
|
||||
OC_FilesystemView
|
||||
-----------------
|
||||
|
||||
files_encryption deals extensively with paths and the filesystem. In order to minimise bugs, it makes calls to filesystem methods in a consistent way: OC_FilesystemView{} objects always use '/' as their root, and specify paths each time particular methods are called. e.g. do this:
|
||||
|
||||
$view->file_exists( 'path/to/file' );
|
||||
|
||||
Not:
|
||||
|
||||
$view->chroot( 'path/to' );
|
||||
$view->file_exists( 'file' );
|
||||
|
||||
Using this convention means that $view objects are more predictable and less likely to break. Problems with paths are the #1 cause of bugs in this app, and consistent $view handling is an important way to prevent them.
|
||||
|
||||
Notes
|
||||
-----
|
||||
@@ -16,4 +67,11 @@ Notes
|
||||
- The user passphrase is required in order to set up or upgrade the app. New
|
||||
keypair generation, and the re-encryption of legacy encrypted files requires
|
||||
it. Therefore an appinfo/update.php script cannot be used, and upgrade logic
|
||||
is handled in the login hook listener.
|
||||
is handled in the login hook listener. Therefore each time the user logs in
|
||||
their files are scanned to detect unencrypted and legacy encrypted files, and
|
||||
they are (re)encrypted as necessary. This may present a performance issue; we
|
||||
need to monitor this.
|
||||
- When files are saved to ownCloud via WebDAV, a .part file extension is used so
|
||||
that the file isn't cached before the upload has been completed. .part files
|
||||
are not compatible with files_encrytion's key management system however, so
|
||||
we have to always sanitise such paths manually before using them.
|
||||
@@ -1 +1 @@
|
||||
0.3
|
||||
0.4
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
/* Copyright (c) 2013, Sam Tuke, <samtuke@owncloud.com>
|
||||
This file is licensed under the Affero General Public License version 3 or later.
|
||||
See the COPYING-README file. */
|
||||
|
||||
#encryptAllError
|
||||
, #encryptAllSuccess
|
||||
, #recoveryEnabledError
|
||||
, #recoveryEnabledSuccess {
|
||||
display: none;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
if (!isset($_)) { //also provide standalone error page
|
||||
require_once '../../../lib/base.php';
|
||||
|
||||
$l = OC_L10N::get('files_encryption');
|
||||
|
||||
$errorMsg = $l->t('Your private key is not valid! Likely your password was changed outside the ownCloud system (e.g. your corporate directory). You can update your private key password in your personal settings to recover access to your encrypted files.');
|
||||
|
||||
if(isset($_GET['p']) && $_GET['p'] === '1') {
|
||||
header('HTTP/1.0 404 ' . $errorMsg);
|
||||
}
|
||||
|
||||
// check if ajax request
|
||||
if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
|
||||
\OCP\JSON::error(array('data' => array('message' => $errorMsg)));
|
||||
} else {
|
||||
header('HTTP/1.0 404 ' . $errorMsg);
|
||||
$tmpl = new OC_Template('files_encryption', 'invalid_private_key', 'guest');
|
||||
$tmpl->printPage();
|
||||
}
|
||||
|
||||
exit;
|
||||
}
|
||||
@@ -23,10 +23,11 @@
|
||||
|
||||
namespace OCA\Encryption;
|
||||
|
||||
use OC\Files\Filesystem;
|
||||
|
||||
/**
|
||||
* Class for hook specific logic
|
||||
*/
|
||||
|
||||
class Hooks {
|
||||
|
||||
// TODO: use passphrase for encrypting private key that is separate to
|
||||
@@ -36,156 +37,531 @@ class Hooks {
|
||||
* @brief Startup encryption backend upon user login
|
||||
* @note This method should never be called for users using client side encryption
|
||||
*/
|
||||
public static function login( $params ) {
|
||||
|
||||
// Manually initialise Filesystem{} singleton with correct
|
||||
// fake root path, in order to avoid fatal webdav errors
|
||||
\OC\Files\Filesystem::init( $params['uid'], $params['uid'] . '/' . 'files' . '/' );
|
||||
|
||||
$view = new \OC_FilesystemView( '/' );
|
||||
|
||||
$util = new Util( $view, $params['uid'] );
|
||||
|
||||
// Check files_encryption infrastructure is ready for action
|
||||
if ( ! $util->ready() ) {
|
||||
|
||||
\OC_Log::write( 'Encryption library', 'User account "' . $params['uid'] . '" is not ready for encryption; configuration started', \OC_Log::DEBUG );
|
||||
|
||||
return $util->setupServerSide( $params['password'] );
|
||||
|
||||
public static function login($params) {
|
||||
$l = new \OC_L10N('files_encryption');
|
||||
//check if all requirements are met
|
||||
if(!Helper::checkRequirements() ) {
|
||||
$error_msg = $l->t("Missing requirements.");
|
||||
$hint = $l->t('Please make sure that PHP 5.3.3 or newer is installed and that the OpenSSL PHP extension is enabled and configured properly. For now, the encryption app has been disabled.');
|
||||
\OC_App::disable('files_encryption');
|
||||
\OCP\Util::writeLog('Encryption library', $error_msg . ' ' . $hint, \OCP\Util::ERROR);
|
||||
\OCP\Template::printErrorPage($error_msg, $hint);
|
||||
}
|
||||
|
||||
\OC_FileProxy::$enabled = false;
|
||||
|
||||
$encryptedKey = Keymanager::getPrivateKey( $view, $params['uid'] );
|
||||
|
||||
\OC_FileProxy::$enabled = true;
|
||||
|
||||
$privateKey = Crypt::symmetricDecryptFileContent( $encryptedKey, $params['password'] );
|
||||
|
||||
$session = new Session();
|
||||
|
||||
$session->setPrivateKey( $privateKey, $params['uid'] );
|
||||
|
||||
$view1 = new \OC_FilesystemView( '/' . $params['uid'] );
|
||||
|
||||
// Set legacy encryption key if it exists, to support
|
||||
// depreciated encryption system
|
||||
if (
|
||||
$view1->file_exists( 'encryption.key' )
|
||||
&& $encLegacyKey = $view1->file_get_contents( 'encryption.key' )
|
||||
) {
|
||||
|
||||
$plainLegacyKey = Crypt::legacyDecrypt( $encLegacyKey, $params['password'] );
|
||||
|
||||
$session->setLegacyKey( $plainLegacyKey );
|
||||
|
||||
|
||||
$view = new \OC_FilesystemView('/');
|
||||
|
||||
// ensure filesystem is loaded
|
||||
if(!\OC\Files\Filesystem::$loaded) {
|
||||
\OC_Util::setupFS($params['uid']);
|
||||
}
|
||||
|
||||
$publicKey = Keymanager::getPublicKey( $view, $params['uid'] );
|
||||
|
||||
// Encrypt existing user files:
|
||||
// This serves to upgrade old versions of the encryption
|
||||
// app (see appinfo/spec.txt)
|
||||
if (
|
||||
$util->encryptAll( $publicKey, '/' . $params['uid'] . '/' . 'files', $session->getLegacyKey(), $params['password'] )
|
||||
) {
|
||||
|
||||
\OC_Log::write(
|
||||
'Encryption library', 'Encryption of existing files belonging to "' . $params['uid'] . '" started at login'
|
||||
, \OC_Log::INFO
|
||||
);
|
||||
|
||||
|
||||
$util = new Util($view, $params['uid']);
|
||||
|
||||
// setup user, if user not ready force relogin
|
||||
if (Helper::setupUser($util, $params['password']) === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$encryptedKey = Keymanager::getPrivateKey($view, $params['uid']);
|
||||
|
||||
$privateKey = Crypt::decryptPrivateKey($encryptedKey, $params['password']);
|
||||
|
||||
if ($privateKey === false) {
|
||||
\OCP\Util::writeLog('Encryption library', 'Private key for user "' . $params['uid']
|
||||
. '" is not valid! Maybe the user password was changed from outside if so please change it back to gain access', \OCP\Util::ERROR);
|
||||
}
|
||||
|
||||
$session = new \OCA\Encryption\Session($view);
|
||||
|
||||
$session->setPrivateKey($privateKey);
|
||||
|
||||
// Check if first-run file migration has already been performed
|
||||
$ready = false;
|
||||
if ($util->getMigrationStatus() === Util::MIGRATION_OPEN) {
|
||||
$ready = $util->beginMigration();
|
||||
}
|
||||
|
||||
// If migration not yet done
|
||||
if ($ready) {
|
||||
|
||||
$userView = new \OC_FilesystemView('/' . $params['uid']);
|
||||
|
||||
// Set legacy encryption key if it exists, to support
|
||||
// depreciated encryption system
|
||||
if (
|
||||
$userView->file_exists('encryption.key')
|
||||
&& $encLegacyKey = $userView->file_get_contents('encryption.key')
|
||||
) {
|
||||
|
||||
$plainLegacyKey = Crypt::legacyDecrypt($encLegacyKey, $params['password']);
|
||||
|
||||
$session->setLegacyKey($plainLegacyKey);
|
||||
|
||||
}
|
||||
|
||||
// Encrypt existing user files:
|
||||
// This serves to upgrade old versions of the encryption
|
||||
// app (see appinfo/spec.txt)
|
||||
if (
|
||||
$util->encryptAll('/' . $params['uid'] . '/' . 'files', $session->getLegacyKey(), $params['password'])
|
||||
) {
|
||||
|
||||
\OC_Log::write(
|
||||
'Encryption library', 'Encryption of existing files belonging to "' . $params['uid'] . '" completed'
|
||||
, \OC_Log::INFO
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
// Register successful migration in DB
|
||||
$util->finishMigration();
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief setup encryption backend upon user created
|
||||
* @note This method should never be called for users using client side encryption
|
||||
*/
|
||||
public static function postCreateUser($params) {
|
||||
$view = new \OC_FilesystemView('/');
|
||||
|
||||
$util = new Util($view, $params['uid']);
|
||||
|
||||
Helper::setupUser($util, $params['password']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief cleanup encryption backend upon user deleted
|
||||
* @note This method should never be called for users using client side encryption
|
||||
*/
|
||||
public static function postDeleteUser($params) {
|
||||
$view = new \OC_FilesystemView('/');
|
||||
|
||||
// cleanup public key
|
||||
$publicKey = '/public-keys/' . $params['uid'] . '.public.key';
|
||||
|
||||
// Disable encryption proxy to prevent recursive calls
|
||||
$proxyStatus = \OC_FileProxy::$enabled;
|
||||
\OC_FileProxy::$enabled = false;
|
||||
|
||||
$view->unlink($publicKey);
|
||||
|
||||
\OC_FileProxy::$enabled = $proxyStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief If the password can't be changed within ownCloud, than update the key password in advance.
|
||||
*/
|
||||
public static function preSetPassphrase($params) {
|
||||
if ( ! \OC_User::canUserChangePassword($params['uid']) ) {
|
||||
self::setPassphrase($params);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Change a user's encryption passphrase
|
||||
* @param array $params keys: uid, password
|
||||
*/
|
||||
public static function setPassphrase( $params ) {
|
||||
|
||||
public static function setPassphrase($params) {
|
||||
|
||||
// Only attempt to change passphrase if server-side encryption
|
||||
// is in use (client-side encryption does not have access to
|
||||
// is in use (client-side encryption does not have access to
|
||||
// the necessary keys)
|
||||
if ( Crypt::mode() == 'server' ) {
|
||||
|
||||
$session = new Session();
|
||||
|
||||
// Get existing decrypted private key
|
||||
$privateKey = $session->getPrivateKey();
|
||||
|
||||
// Encrypt private key with new user pwd as passphrase
|
||||
$encryptedPrivateKey = Crypt::symmetricEncryptFileContent( $privateKey, $params['password'] );
|
||||
|
||||
// Save private key
|
||||
Keymanager::setPrivateKey( $encryptedPrivateKey );
|
||||
|
||||
// NOTE: Session does not need to be updated as the
|
||||
// private key has not changed, only the passphrase
|
||||
// used to decrypt it has changed
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief update the encryption key of the file uploaded by the client
|
||||
*/
|
||||
public static function updateKeyfile( $params ) {
|
||||
|
||||
if ( Crypt::mode() == 'client' ) {
|
||||
|
||||
if ( isset( $params['properties']['key'] ) ) {
|
||||
|
||||
$view = new \OC_FilesystemView( '/' );
|
||||
$userId = \OCP\User::getUser();
|
||||
|
||||
Keymanager::setFileKey( $view, $params['path'], $userId, $params['properties']['key'] );
|
||||
|
||||
} else {
|
||||
|
||||
\OC_Log::write(
|
||||
'Encryption library', "Client side encryption is enabled but the client doesn't provide a encryption key for the file!"
|
||||
, \OC_Log::ERROR
|
||||
);
|
||||
|
||||
error_log( "Client side encryption is enabled but the client doesn't provide an encryption key for the file!" );
|
||||
|
||||
if (Crypt::mode() === 'server') {
|
||||
|
||||
if ($params['uid'] === \OCP\User::getUser()) {
|
||||
|
||||
$view = new \OC_FilesystemView('/');
|
||||
|
||||
$session = new \OCA\Encryption\Session($view);
|
||||
|
||||
// Get existing decrypted private key
|
||||
$privateKey = $session->getPrivateKey();
|
||||
|
||||
// Encrypt private key with new user pwd as passphrase
|
||||
$encryptedPrivateKey = Crypt::symmetricEncryptFileContent($privateKey, $params['password']);
|
||||
|
||||
// Save private key
|
||||
Keymanager::setPrivateKey($encryptedPrivateKey);
|
||||
|
||||
// NOTE: Session does not need to be updated as the
|
||||
// private key has not changed, only the passphrase
|
||||
// used to decrypt it has changed
|
||||
|
||||
|
||||
} else { // admin changed the password for a different user, create new keys and reencrypt file keys
|
||||
|
||||
$user = $params['uid'];
|
||||
$recoveryPassword = $params['recoveryPassword'];
|
||||
$newUserPassword = $params['password'];
|
||||
|
||||
$view = new \OC_FilesystemView('/');
|
||||
|
||||
// make sure that the users home is mounted
|
||||
\OC\Files\Filesystem::initMountPoints($user);
|
||||
|
||||
$keypair = Crypt::createKeypair();
|
||||
|
||||
// Disable encryption proxy to prevent recursive calls
|
||||
$proxyStatus = \OC_FileProxy::$enabled;
|
||||
\OC_FileProxy::$enabled = false;
|
||||
|
||||
// Save public key
|
||||
$view->file_put_contents('/public-keys/' . $user . '.public.key', $keypair['publicKey']);
|
||||
|
||||
// Encrypt private key empty passphrase
|
||||
$encryptedPrivateKey = Crypt::symmetricEncryptFileContent($keypair['privateKey'], $newUserPassword);
|
||||
|
||||
// Save private key
|
||||
$view->file_put_contents(
|
||||
'/' . $user . '/files_encryption/' . $user . '.private.key', $encryptedPrivateKey);
|
||||
|
||||
if ($recoveryPassword) { // if recovery key is set we can re-encrypt the key files
|
||||
$util = new Util($view, $user);
|
||||
$util->recoverUsersFiles($recoveryPassword);
|
||||
}
|
||||
|
||||
\OC_FileProxy::$enabled = $proxyStatus;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
|
||||
/*
|
||||
* @brief check if files can be encrypted to every user.
|
||||
*/
|
||||
public static function postShared( $params ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param $params
|
||||
*/
|
||||
public static function preUnshare( $params ) {
|
||||
|
||||
// Delete existing catfile
|
||||
|
||||
// Generate new catfile and env keys
|
||||
|
||||
// Save env keys to user folders
|
||||
public static function preShared($params) {
|
||||
|
||||
$users = array();
|
||||
$view = new \OC\Files\View('/public-keys/');
|
||||
|
||||
switch ($params['shareType']) {
|
||||
case \OCP\Share::SHARE_TYPE_USER:
|
||||
$users[] = $params['shareWith'];
|
||||
break;
|
||||
case \OCP\Share::SHARE_TYPE_GROUP:
|
||||
$users = \OC_Group::usersInGroup($params['shareWith']);
|
||||
break;
|
||||
}
|
||||
|
||||
$error = false;
|
||||
foreach ($users as $user) {
|
||||
if (!$view->file_exists($user . '.public.key')) {
|
||||
$error = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($error) // Set flag var 'run' to notify emitting
|
||||
// script that hook execution failed
|
||||
{
|
||||
$params['run']->run = false;
|
||||
}
|
||||
// TODO: Make sure files_sharing provides user
|
||||
// feedback on failed share
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @brief
|
||||
*/
|
||||
public static function preUnshareAll( $params ) {
|
||||
|
||||
trigger_error( "preUnshareAll" );
|
||||
|
||||
public static function postShared($params) {
|
||||
|
||||
// NOTE: $params has keys:
|
||||
// [itemType] => file
|
||||
// itemSource -> int, filecache file ID
|
||||
// [parent] =>
|
||||
// [itemTarget] => /13
|
||||
// shareWith -> string, uid of user being shared to
|
||||
// fileTarget -> path of file being shared
|
||||
// uidOwner -> owner of the original file being shared
|
||||
// [shareType] => 0
|
||||
// [shareWith] => test1
|
||||
// [uidOwner] => admin
|
||||
// [permissions] => 17
|
||||
// [fileSource] => 13
|
||||
// [fileTarget] => /test8
|
||||
// [id] => 10
|
||||
// [token] =>
|
||||
// [run] => whether emitting script should continue to run
|
||||
// TODO: Should other kinds of item be encrypted too?
|
||||
|
||||
if ($params['itemType'] === 'file' || $params['itemType'] === 'folder') {
|
||||
|
||||
$view = new \OC_FilesystemView('/');
|
||||
$session = new \OCA\Encryption\Session($view);
|
||||
$userId = \OCP\User::getUser();
|
||||
$util = new Util($view, $userId);
|
||||
$path = $util->fileIdToPath($params['itemSource']);
|
||||
|
||||
$share = $util->getParentFromShare($params['id']);
|
||||
//if parent is set, then this is a re-share action
|
||||
if ($share['parent'] !== null) {
|
||||
|
||||
// get the parent from current share
|
||||
$parent = $util->getShareParent($params['parent']);
|
||||
|
||||
// if parent is file the it is an 1:1 share
|
||||
if ($parent['item_type'] === 'file') {
|
||||
|
||||
// prefix path with Shared
|
||||
$path = '/Shared' . $parent['file_target'];
|
||||
} else {
|
||||
|
||||
// NOTE: parent is folder but shared was a file!
|
||||
// we try to rebuild the missing path
|
||||
// some examples we face here
|
||||
// user1 share folder1 with user2 folder1 has
|
||||
// the following structure
|
||||
// /folder1/subfolder1/subsubfolder1/somefile.txt
|
||||
// user2 re-share subfolder2 with user3
|
||||
// user3 re-share somefile.txt user4
|
||||
// so our path should be
|
||||
// /Shared/subfolder1/subsubfolder1/somefile.txt
|
||||
// while user3 is sharing
|
||||
|
||||
if ($params['itemType'] === 'file') {
|
||||
// get target path
|
||||
$targetPath = $util->fileIdToPath($params['fileSource']);
|
||||
$targetPathSplit = array_reverse(explode('/', $targetPath));
|
||||
|
||||
// init values
|
||||
$path = '';
|
||||
$sharedPart = ltrim($parent['file_target'], '/');
|
||||
|
||||
// rebuild path
|
||||
foreach ($targetPathSplit as $pathPart) {
|
||||
if ($pathPart !== $sharedPart) {
|
||||
$path = '/' . $pathPart . $path;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// prefix path with Shared
|
||||
$path = '/Shared' . $parent['file_target'] . $path;
|
||||
} else {
|
||||
// prefix path with Shared
|
||||
$path = '/Shared' . $parent['file_target'] . $params['fileTarget'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$sharingEnabled = \OCP\Share::isEnabled();
|
||||
|
||||
// get the path including mount point only if not a shared folder
|
||||
if (strncmp($path, '/Shared', strlen('/Shared') !== 0)) {
|
||||
// get path including the the storage mount point
|
||||
$path = $util->getPathWithMountPoint($params['itemSource']);
|
||||
}
|
||||
|
||||
// if a folder was shared, get a list of all (sub-)folders
|
||||
if ($params['itemType'] === 'folder') {
|
||||
$allFiles = $util->getAllFiles($path);
|
||||
} else {
|
||||
$allFiles = array($path);
|
||||
}
|
||||
|
||||
foreach ($allFiles as $path) {
|
||||
$usersSharing = $util->getSharingUsersArray($sharingEnabled, $path);
|
||||
$util->setSharedFileKeyfiles($session, $usersSharing, $path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
public static function postUnshare($params) {
|
||||
|
||||
// NOTE: $params has keys:
|
||||
// [itemType] => file
|
||||
// [itemSource] => 13
|
||||
// [shareType] => 0
|
||||
// [shareWith] => test1
|
||||
// [itemParent] =>
|
||||
|
||||
if ($params['itemType'] === 'file' || $params['itemType'] === 'folder') {
|
||||
|
||||
$view = new \OC_FilesystemView('/');
|
||||
$userId = \OCP\User::getUser();
|
||||
$util = new Util($view, $userId);
|
||||
$path = $util->fileIdToPath($params['itemSource']);
|
||||
|
||||
// check if this is a re-share
|
||||
if ($params['itemParent']) {
|
||||
|
||||
// get the parent from current share
|
||||
$parent = $util->getShareParent($params['itemParent']);
|
||||
|
||||
// get target path
|
||||
$targetPath = $util->fileIdToPath($params['itemSource']);
|
||||
$targetPathSplit = array_reverse(explode('/', $targetPath));
|
||||
|
||||
// init values
|
||||
$path = '';
|
||||
$sharedPart = ltrim($parent['file_target'], '/');
|
||||
|
||||
// rebuild path
|
||||
foreach ($targetPathSplit as $pathPart) {
|
||||
if ($pathPart !== $sharedPart) {
|
||||
$path = '/' . $pathPart . $path;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// prefix path with Shared
|
||||
$path = '/Shared' . $parent['file_target'] . $path;
|
||||
}
|
||||
|
||||
// for group shares get a list of the group members
|
||||
if ($params['shareType'] === \OCP\Share::SHARE_TYPE_GROUP) {
|
||||
$userIds = \OC_Group::usersInGroup($params['shareWith']);
|
||||
} else {
|
||||
if ($params['shareType'] === \OCP\Share::SHARE_TYPE_LINK) {
|
||||
$userIds = array($util->getPublicShareKeyId());
|
||||
} else {
|
||||
$userIds = array($params['shareWith']);
|
||||
}
|
||||
}
|
||||
|
||||
// get the path including mount point only if not a shared folder
|
||||
if (strncmp($path, '/Shared', strlen('/Shared') !== 0)) {
|
||||
// get path including the the storage mount point
|
||||
$path = $util->getPathWithMountPoint($params['itemSource']);
|
||||
}
|
||||
|
||||
// if we unshare a folder we need a list of all (sub-)files
|
||||
if ($params['itemType'] === 'folder') {
|
||||
$allFiles = $util->getAllFiles($path);
|
||||
} else {
|
||||
$allFiles = array($path);
|
||||
}
|
||||
|
||||
foreach ($allFiles as $path) {
|
||||
|
||||
// check if the user still has access to the file, otherwise delete share key
|
||||
$sharingUsers = $util->getSharingUsersArray(true, $path);
|
||||
|
||||
// Unshare every user who no longer has access to the file
|
||||
$delUsers = array_diff($userIds, $sharingUsers);
|
||||
|
||||
// delete share key
|
||||
Keymanager::delShareKey($view, $delUsers, $path);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief after a file is renamed, rename its keyfile and share-keys also fix the file size and fix also the sharing
|
||||
* @param array with oldpath and newpath
|
||||
*
|
||||
* This function is connected to the rename signal of OC_Filesystem and adjust the name and location
|
||||
* of the stored versions along the actual file
|
||||
*/
|
||||
public static function postRename($params) {
|
||||
// Disable encryption proxy to prevent recursive calls
|
||||
$proxyStatus = \OC_FileProxy::$enabled;
|
||||
\OC_FileProxy::$enabled = false;
|
||||
|
||||
$view = new \OC_FilesystemView('/');
|
||||
$session = new \OCA\Encryption\Session($view);
|
||||
$userId = \OCP\User::getUser();
|
||||
$util = new Util($view, $userId);
|
||||
|
||||
// Format paths to be relative to user files dir
|
||||
if ($util->isSystemWideMountPoint($params['oldpath'])) {
|
||||
$baseDir = 'files_encryption/';
|
||||
$oldKeyfilePath = $baseDir . 'keyfiles/' . $params['oldpath'];
|
||||
} else {
|
||||
$baseDir = $userId . '/' . 'files_encryption/';
|
||||
$oldKeyfilePath = $baseDir . 'keyfiles/' . $params['oldpath'];
|
||||
}
|
||||
|
||||
if ($util->isSystemWideMountPoint($params['newpath'])) {
|
||||
$newKeyfilePath = $baseDir . 'keyfiles/' . $params['newpath'];
|
||||
} else {
|
||||
$newKeyfilePath = $baseDir . 'keyfiles/' . $params['newpath'];
|
||||
}
|
||||
|
||||
// add key ext if this is not an folder
|
||||
if (!$view->is_dir($oldKeyfilePath)) {
|
||||
$oldKeyfilePath .= '.key';
|
||||
$newKeyfilePath .= '.key';
|
||||
|
||||
// handle share-keys
|
||||
$localKeyPath = $view->getLocalFile($baseDir . 'share-keys/' . $params['oldpath']);
|
||||
$escapedPath = Helper::escapeGlobPattern($localKeyPath);
|
||||
$matches = glob($escapedPath . '*.shareKey');
|
||||
foreach ($matches as $src) {
|
||||
$dst = \OC\Files\Filesystem::normalizePath(str_replace($params['oldpath'], $params['newpath'], $src));
|
||||
|
||||
// create destination folder if not exists
|
||||
if (!file_exists(dirname($dst))) {
|
||||
mkdir(dirname($dst), 0750, true);
|
||||
}
|
||||
|
||||
rename($src, $dst);
|
||||
}
|
||||
|
||||
} else {
|
||||
// handle share-keys folders
|
||||
$oldShareKeyfilePath = $baseDir . 'share-keys/' . $params['oldpath'];
|
||||
$newShareKeyfilePath = $baseDir . 'share-keys/' . $params['newpath'];
|
||||
|
||||
// create destination folder if not exists
|
||||
if (!$view->file_exists(dirname($newShareKeyfilePath))) {
|
||||
$view->mkdir(dirname($newShareKeyfilePath), 0750, true);
|
||||
}
|
||||
|
||||
$view->rename($oldShareKeyfilePath, $newShareKeyfilePath);
|
||||
}
|
||||
|
||||
// Rename keyfile so it isn't orphaned
|
||||
if ($view->file_exists($oldKeyfilePath)) {
|
||||
|
||||
// create destination folder if not exists
|
||||
if (!$view->file_exists(dirname($newKeyfilePath))) {
|
||||
$view->mkdir(dirname($newKeyfilePath), 0750, true);
|
||||
}
|
||||
|
||||
$view->rename($oldKeyfilePath, $newKeyfilePath);
|
||||
}
|
||||
|
||||
// build the path to the file
|
||||
$newPath = '/' . $userId . '/files' . $params['newpath'];
|
||||
$newPathRelative = $params['newpath'];
|
||||
|
||||
if ($util->fixFileSize($newPath)) {
|
||||
// get sharing app state
|
||||
$sharingEnabled = \OCP\Share::isEnabled();
|
||||
|
||||
// get users
|
||||
$usersSharing = $util->getSharingUsersArray($sharingEnabled, $newPathRelative);
|
||||
|
||||
// update sharing-keys
|
||||
$util->setSharedFileKeyfiles($session, $usersSharing, $newPathRelative);
|
||||
}
|
||||
|
||||
\OC_FileProxy::$enabled = $proxyStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* set migration status back to '0' so that all new files get encrypted
|
||||
* if the app gets enabled again
|
||||
* @param array $params contains the app ID
|
||||
*/
|
||||
public static function preDisable($params) {
|
||||
if ($params['app'] === 'files_encryption') {
|
||||
$query = \OC_DB::prepare('UPDATE `*PREFIX*encryption` SET `migration_status`=0');
|
||||
$query->execute();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* Copyright (c) 2013, Sam Tuke <samtuke@owncloud.com>, Robin Appelman
|
||||
* <icewind1991@gmail.com>
|
||||
* This file is licensed under the Affero General Public License version 3 or later.
|
||||
* See the COPYING-README file.
|
||||
*/
|
||||
|
||||
OC.msg={
|
||||
startSaving:function(selector){
|
||||
$(selector)
|
||||
.html( t('settings', 'Saving...') )
|
||||
.removeClass('success')
|
||||
.removeClass('error')
|
||||
.stop(true, true)
|
||||
.show();
|
||||
},
|
||||
finishedSaving:function(selector, data){
|
||||
if( data.status === "success" ){
|
||||
$(selector).html( data.data.message )
|
||||
.addClass('success')
|
||||
.stop(true, true)
|
||||
.delay(3000)
|
||||
.fadeOut(900);
|
||||
}else{
|
||||
$(selector).html( data.data.message ).addClass('error');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$(document).ready(function(){
|
||||
// Trigger ajax on recoveryAdmin status change
|
||||
var enabledStatus = $('#adminEnableRecovery').val();
|
||||
|
||||
$('input:password[name="recoveryPassword"]').keyup(function(event) {
|
||||
var recoveryPassword = $( '#recoveryPassword' ).val();
|
||||
var checkedButton = $('input:radio[name="adminEnableRecovery"]:checked').val();
|
||||
var uncheckedValue = (1+parseInt(checkedButton)) % 2;
|
||||
if (recoveryPassword != '' ) {
|
||||
$('input:radio[name="adminEnableRecovery"][value="'+uncheckedValue.toString()+'"]').removeAttr("disabled");
|
||||
} else {
|
||||
$('input:radio[name="adminEnableRecovery"][value="'+uncheckedValue.toString()+'"]').attr("disabled", "true");
|
||||
}
|
||||
});
|
||||
|
||||
$( 'input:radio[name="adminEnableRecovery"]' ).change(
|
||||
function() {
|
||||
var recoveryStatus = $( this ).val();
|
||||
var oldStatus = (1+parseInt(recoveryStatus)) % 2;
|
||||
var recoveryPassword = $( '#recoveryPassword' ).val();
|
||||
$.post(
|
||||
OC.filePath( 'files_encryption', 'ajax', 'adminrecovery.php' )
|
||||
, { adminEnableRecovery: recoveryStatus, recoveryPassword: recoveryPassword }
|
||||
, function( result ) {
|
||||
if (result.status === "error") {
|
||||
OC.Notification.show(t('admin', result.data.message));
|
||||
$('input:radio[name="adminEnableRecovery"][value="'+oldStatus.toString()+'"]').attr("checked", "true");
|
||||
} else {
|
||||
OC.Notification.hide();
|
||||
if (recoveryStatus === "0") {
|
||||
$('button:button[name="submitChangeRecoveryKey"]').attr("disabled", "true");
|
||||
$('input:password[name="changeRecoveryPassword"]').attr("disabled", "true");
|
||||
$('input:password[name="changeRecoveryPassword"]').val("");
|
||||
} else {
|
||||
$('input:password[name="changeRecoveryPassword"]').removeAttr("disabled");
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
// change recovery password
|
||||
|
||||
$('input:password[name="changeRecoveryPassword"]').keyup(function(event) {
|
||||
var oldRecoveryPassword = $('input:password[id="oldRecoveryPassword"]').val();
|
||||
var newRecoveryPassword = $('input:password[id="newRecoveryPassword"]').val();
|
||||
if (newRecoveryPassword != '' && oldRecoveryPassword != '' ) {
|
||||
$('button:button[name="submitChangeRecoveryKey"]').removeAttr("disabled");
|
||||
} else {
|
||||
$('button:button[name="submitChangeRecoveryKey"]').attr("disabled", "true");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
$('button:button[name="submitChangeRecoveryKey"]').click(function() {
|
||||
var oldRecoveryPassword = $('input:password[id="oldRecoveryPassword"]').val();
|
||||
var newRecoveryPassword = $('input:password[id="newRecoveryPassword"]').val();
|
||||
OC.msg.startSaving('#encryption .msg');
|
||||
$.post(
|
||||
OC.filePath( 'files_encryption', 'ajax', 'changeRecoveryPassword.php' )
|
||||
, { oldPassword: oldRecoveryPassword, newPassword: newRecoveryPassword }
|
||||
, function( data ) {
|
||||
if (data.status == "error") {
|
||||
OC.msg.finishedSaving('#encryption .msg', data);
|
||||
} else {
|
||||
OC.msg.finishedSaving('#encryption .msg', data);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* Copyright (c) 2013, Sam Tuke <samtuke@owncloud.com>
|
||||
* This file is licensed under the Affero General Public License version 3 or later.
|
||||
* See the COPYING-README file.
|
||||
*/
|
||||
|
||||
function updatePrivateKeyPasswd() {
|
||||
var oldPrivateKeyPassword = $('input:password[id="oldPrivateKeyPassword"]').val();
|
||||
var newPrivateKeyPassword = $('input:password[id="newPrivateKeyPassword"]').val();
|
||||
OC.msg.startSaving('#encryption .msg');
|
||||
$.post(
|
||||
OC.filePath( 'files_encryption', 'ajax', 'updatePrivateKeyPassword.php' )
|
||||
, { oldPassword: oldPrivateKeyPassword, newPassword: newPrivateKeyPassword }
|
||||
, function( data ) {
|
||||
if (data.status === "error") {
|
||||
OC.msg.finishedSaving('#encryption .msg', data);
|
||||
} else {
|
||||
OC.msg.finishedSaving('#encryption .msg', data);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
$(document).ready(function(){
|
||||
|
||||
// Trigger ajax on recoveryAdmin status change
|
||||
$( 'input:radio[name="userEnableRecovery"]' ).change(
|
||||
function() {
|
||||
|
||||
// Hide feedback messages in case they're already visible
|
||||
$('#recoveryEnabledSuccess').hide();
|
||||
$('#recoveryEnabledError').hide();
|
||||
|
||||
var recoveryStatus = $( this ).val();
|
||||
|
||||
$.post(
|
||||
OC.filePath( 'files_encryption', 'ajax', 'userrecovery.php' )
|
||||
, { userEnableRecovery: recoveryStatus }
|
||||
, function( data ) {
|
||||
if ( data.status == "success" ) {
|
||||
$('#recoveryEnabledSuccess').show();
|
||||
} else {
|
||||
$('#recoveryEnabledError').show();
|
||||
}
|
||||
}
|
||||
);
|
||||
// Ensure page is not reloaded on form submit
|
||||
return false;
|
||||
}
|
||||
);
|
||||
|
||||
$("#encryptAll").click(
|
||||
function(){
|
||||
|
||||
// Hide feedback messages in case they're already visible
|
||||
$('#encryptAllSuccess').hide();
|
||||
$('#encryptAllError').hide();
|
||||
|
||||
var userPassword = $( '#userPassword' ).val();
|
||||
var encryptAll = $( '#encryptAll' ).val();
|
||||
|
||||
$.post(
|
||||
OC.filePath( 'files_encryption', 'ajax', 'encryptall.php' )
|
||||
, { encryptAll: encryptAll, userPassword: userPassword }
|
||||
, function( data ) {
|
||||
if ( data.status == "success" ) {
|
||||
$('#encryptAllSuccess').show();
|
||||
} else {
|
||||
$('#encryptAllError').show();
|
||||
}
|
||||
}
|
||||
);
|
||||
// Ensure page is not reloaded on form submit
|
||||
return false;
|
||||
}
|
||||
|
||||
);
|
||||
|
||||
// update private key password
|
||||
|
||||
$('input:password[name="changePrivateKeyPassword"]').keyup(function(event) {
|
||||
var oldPrivateKeyPassword = $('input:password[id="oldPrivateKeyPassword"]').val();
|
||||
var newPrivateKeyPassword = $('input:password[id="newPrivateKeyPassword"]').val();
|
||||
if (newPrivateKeyPassword !== '' && oldPrivateKeyPassword !== '' ) {
|
||||
$('button:button[name="submitChangePrivateKeyPassword"]').removeAttr("disabled");
|
||||
if(event.which === 13) {
|
||||
updatePrivateKeyPasswd();
|
||||
}
|
||||
} else {
|
||||
$('button:button[name="submitChangePrivateKeyPassword"]').attr("disabled", "true");
|
||||
}
|
||||
});
|
||||
|
||||
$('button:button[name="submitChangePrivateKeyPassword"]').click(function() {
|
||||
updatePrivateKeyPasswd();
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,19 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2011, Robin Appelman <icewind1991@gmail.com>
|
||||
* This file is licensed under the Affero General Public License version 3 or later.
|
||||
* See the COPYING-README file.
|
||||
*/
|
||||
|
||||
|
||||
$(document).ready(function(){
|
||||
$('#encryption_blacklist').multiSelect({
|
||||
oncheck:blackListChange,
|
||||
onuncheck:blackListChange,
|
||||
createText:'...'
|
||||
});
|
||||
|
||||
function blackListChange(){
|
||||
var blackList=$('#encryption_blacklist').val().join(',');
|
||||
OC.AppConfig.setValue('files_encryption','type_blacklist',blackList);
|
||||
}
|
||||
})
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "التشفير",
|
||||
"File encryption is enabled." => "تشفير الملفات فعال.",
|
||||
"The following file types will not be encrypted:" => "الملفات الاتية لن يتم تشفيرها:",
|
||||
"Exclude the following file types from encryption:" => "إستثناء أنواع الملفات الاتية من التشفير: ",
|
||||
"None" => "لا شيء"
|
||||
);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "Encriptatge",
|
||||
"File encryption is enabled." => "L'encriptació de fitxers està activada.",
|
||||
"The following file types will not be encrypted:" => "Els tipus de fitxers següents no s'encriptaran:",
|
||||
"Exclude the following file types from encryption:" => "Exclou els tipus de fitxers següents de l'encriptatge:",
|
||||
"Encryption" => "Xifrat",
|
||||
"File encryption is enabled." => "El xifrat de fitxers està activat.",
|
||||
"The following file types will not be encrypted:" => "Els tipus de fitxers següents no es xifraran:",
|
||||
"Exclude the following file types from encryption:" => "Exclou els tipus de fitxers següents del xifratge:",
|
||||
"None" => "Cap"
|
||||
);
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "Amgryptiad",
|
||||
"File encryption is enabled." => "Galluogwyd amgryptio ffeiliau.",
|
||||
"The following file types will not be encrypted:" => "Ni fydd ffeiliau o'r math yma'n cael eu hamgryptio:",
|
||||
"Exclude the following file types from encryption:" => "Eithrio'r mathau canlynol o ffeiliau rhag cael eu hamgryptio:",
|
||||
"None" => "Dim"
|
||||
);
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "رمزگذاری",
|
||||
"File encryption is enabled." => "رمزنگاری فایلها فعال شد.",
|
||||
"The following file types will not be encrypted:" => "فایلهای زیر رمزنگاری نخواهند شد:",
|
||||
"Exclude the following file types from encryption:" => "فایلهای زیر از رمزنگاری نادیده گرفته می شوند:",
|
||||
"None" => "هیچکدام"
|
||||
);
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "ენკრიპცია",
|
||||
"File encryption is enabled." => "ფაილის ენკრიპცია ჩართულია.",
|
||||
"The following file types will not be encrypted:" => "შემდეგი ფაილური ტიპების ენკრიპცია არ მოხდება:",
|
||||
"Exclude the following file types from encryption:" => "ამოიღე შემდეგი ფაილის ტიპები ენკრიპციიდან:",
|
||||
"None" => "არა"
|
||||
);
|
||||
@@ -2,6 +2,6 @@
|
||||
"Encryption" => "Šifriranje",
|
||||
"File encryption is enabled." => "Šifriranje datotek je omogočeno.",
|
||||
"The following file types will not be encrypted:" => "Navedene vrste datotek ne bodo šifrirane:",
|
||||
"Exclude the following file types from encryption:" => "Izloči navedene vrste datotek med šifriranjem:",
|
||||
"Exclude the following file types from encryption:" => "Ne šifriraj navedenih vrst datotek:",
|
||||
"None" => "Brez"
|
||||
);
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "شىفىرلاش",
|
||||
"File encryption is enabled." => "ھۆججەت شىفىرلاش قوزغىتىلدى.",
|
||||
"The following file types will not be encrypted:" => "تۆۋەندىكى ھۆججەت تىپلىرى شىفىرلانمايدۇ:",
|
||||
"Exclude the following file types from encryption:" => "تۆۋەندىكى ھۆججەت تىپلىرى شىفىرلاشنىڭ سىرتىدا:",
|
||||
"None" => "يوق"
|
||||
);
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "加密",
|
||||
"None" => "None"
|
||||
"File encryption is enabled." => "文件加密已启用.",
|
||||
"The following file types will not be encrypted:" => "如下的文件类型将不会被加密:",
|
||||
"Exclude the following file types from encryption:" => "从加密中排除如下的文件类型:",
|
||||
"None" => "无"
|
||||
);
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "加密",
|
||||
"File encryption is enabled." => "檔案加密已開啟",
|
||||
"The following file types will not be encrypted:" => "以下文件類別將不會被加密",
|
||||
"None" => "空"
|
||||
);
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "加密",
|
||||
"File encryption is enabled." => "檔案加密已被啟用",
|
||||
"The following file types will not be encrypted:" => "以下的文件類型不會被加密:",
|
||||
"Exclude the following file types from encryption:" => "從加密中排除的檔案類型:",
|
||||
"None" => "無"
|
||||
);
|
||||
|
||||
+228
-257
@@ -25,13 +25,8 @@
|
||||
|
||||
namespace OCA\Encryption;
|
||||
|
||||
require_once 'Crypt_Blowfish/Blowfish.php';
|
||||
|
||||
// Todo:
|
||||
// - Add a setting "Don´t encrypt files larger than xx because of performance"
|
||||
// - Don't use a password directly as encryption key. but a key which is
|
||||
// stored on the server and encrypted with the user password. -> change pass
|
||||
// faster
|
||||
//require_once '../3rdparty/Crypt_Blowfish/Blowfish.php';
|
||||
require_once realpath(dirname(__FILE__) . '/../3rdparty/Crypt_Blowfish/Blowfish.php');
|
||||
|
||||
/**
|
||||
* Class for common cryptography functionality
|
||||
@@ -41,10 +36,10 @@ class Crypt {
|
||||
|
||||
/**
|
||||
* @brief return encryption mode client or server side encryption
|
||||
* @param string user name (use system wide setting if name=null)
|
||||
* @param string $user name (use system wide setting if name=null)
|
||||
* @return string 'client' or 'server'
|
||||
*/
|
||||
public static function mode( $user = null ) {
|
||||
public static function mode($user = null) {
|
||||
|
||||
return 'server';
|
||||
|
||||
@@ -56,30 +51,40 @@ class Crypt {
|
||||
*/
|
||||
public static function createKeypair() {
|
||||
|
||||
$res = openssl_pkey_new();
|
||||
$return = false;
|
||||
|
||||
// Get private key
|
||||
openssl_pkey_export( $res, $privateKey );
|
||||
$res = openssl_pkey_new(array('private_key_bits' => 4096));
|
||||
|
||||
// Get public key
|
||||
$publicKey = openssl_pkey_get_details( $res );
|
||||
if ($res === false) {
|
||||
\OCP\Util::writeLog('Encryption library', 'couldn\'t generate users key-pair for ' . \OCP\User::getUser(), \OCP\Util::ERROR);
|
||||
\OCP\Util::writeLog('Encryption library', openssl_error_string(), \OCP\Util::ERROR);
|
||||
} elseif (openssl_pkey_export($res, $privateKey)) {
|
||||
// Get public key
|
||||
$keyDetails = openssl_pkey_get_details($res);
|
||||
$publicKey = $keyDetails['key'];
|
||||
|
||||
$publicKey = $publicKey['key'];
|
||||
|
||||
return( array( 'publicKey' => $publicKey, 'privateKey' => $privateKey ) );
|
||||
$return = array(
|
||||
'publicKey' => $publicKey,
|
||||
'privateKey' => $privateKey
|
||||
);
|
||||
} else {
|
||||
\OCP\Util::writeLog('Encryption library', 'couldn\'t export users private key, please check your servers openSSL configuration.' . \OCP\User::getUser(), \OCP\Util::ERROR);
|
||||
\OCP\Util::writeLog('Encryption library', openssl_error_string(), \OCP\Util::ERROR);
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Add arbitrary padding to encrypted data
|
||||
* @param string $data data to be padded
|
||||
* @return padded data
|
||||
* @return string padded data
|
||||
* @note In order to end up with data exactly 8192 bytes long we must
|
||||
* add two letters. It is impossible to achieve exactly 8192 length
|
||||
* blocks with encryption alone, hence padding is added to achieve the
|
||||
* required length.
|
||||
*/
|
||||
public static function addPadding( $data ) {
|
||||
public static function addPadding($data) {
|
||||
|
||||
$padded = $data . 'xx';
|
||||
|
||||
@@ -90,13 +95,13 @@ class Crypt {
|
||||
/**
|
||||
* @brief Remove arbitrary padding to encrypted data
|
||||
* @param string $padded padded data to remove padding from
|
||||
* @return unpadded data on success, false on error
|
||||
* @return string unpadded data on success, false on error
|
||||
*/
|
||||
public static function removePadding( $padded ) {
|
||||
public static function removePadding($padded) {
|
||||
|
||||
if ( substr( $padded, -2 ) == 'xx' ) {
|
||||
if (substr($padded, -2) === 'xx') {
|
||||
|
||||
$data = substr( $padded, 0, -2 );
|
||||
$data = substr($padded, 0, -2);
|
||||
|
||||
return $data;
|
||||
|
||||
@@ -111,29 +116,30 @@ class Crypt {
|
||||
|
||||
/**
|
||||
* @brief Check if a file's contents contains an IV and is symmetrically encrypted
|
||||
* @return true / false
|
||||
* @param $content
|
||||
* @return boolean
|
||||
* @note see also OCA\Encryption\Util->isEncryptedPath()
|
||||
*/
|
||||
public static function isCatfile( $content ) {
|
||||
public static function isCatfileContent($content) {
|
||||
|
||||
if ( !$content ) {
|
||||
if (!$content) {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
$noPadding = self::removePadding( $content );
|
||||
$noPadding = self::removePadding($content);
|
||||
|
||||
// Fetch encryption metadata from end of file
|
||||
$meta = substr( $noPadding, -22 );
|
||||
$meta = substr($noPadding, -22);
|
||||
|
||||
// Fetch IV from end of file
|
||||
$iv = substr( $meta, -16 );
|
||||
$iv = substr($meta, -16);
|
||||
|
||||
// Fetch identifier from start of metadata
|
||||
$identifier = substr( $meta, 0, 6 );
|
||||
$identifier = substr($meta, 0, 6);
|
||||
|
||||
if ( $identifier == '00iv00') {
|
||||
if ($identifier === '00iv00') {
|
||||
|
||||
return true;
|
||||
|
||||
@@ -150,36 +156,36 @@ class Crypt {
|
||||
* @param string $path
|
||||
* @return bool
|
||||
*/
|
||||
public static function isEncryptedMeta( $path ) {
|
||||
public static function isEncryptedMeta($path) {
|
||||
|
||||
// TODO: Use DI to get \OC\Files\Filesystem out of here
|
||||
|
||||
// Fetch all file metadata from DB
|
||||
$metadata = \OC\Files\Filesystem::getFileInfo( $path, '' );
|
||||
$metadata = \OC\Files\Filesystem::getFileInfo($path);
|
||||
|
||||
// Return encryption status
|
||||
return isset( $metadata['encrypted'] ) and ( bool )$metadata['encrypted'];
|
||||
return isset($metadata['encrypted']) && ( bool )$metadata['encrypted'];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if a file is encrypted via legacy system
|
||||
* @param $data
|
||||
* @param string $relPath The path of the file, relative to user/data;
|
||||
* e.g. filename or /Docs/filename, NOT admin/files/filename
|
||||
* @return true / false
|
||||
* @return boolean
|
||||
*/
|
||||
public static function isLegacyEncryptedContent( $data, $relPath ) {
|
||||
public static function isLegacyEncryptedContent($isCatFileContent, $relPath) {
|
||||
|
||||
// Fetch all file metadata from DB
|
||||
$metadata = \OC\Files\Filesystem::getFileInfo( $relPath, '' );
|
||||
$metadata = \OC\Files\Filesystem::getFileInfo($relPath, '');
|
||||
|
||||
// If a file is flagged with encryption in DB, but isn't a
|
||||
// valid content + IV combination, it's probably using the
|
||||
// legacy encryption system
|
||||
if (
|
||||
isset( $metadata['encrypted'] )
|
||||
and $metadata['encrypted'] === true
|
||||
and ! self::isCatfile( $data )
|
||||
if (isset($metadata['encrypted'])
|
||||
&& $metadata['encrypted'] === true
|
||||
&& $isCatFileContent === false
|
||||
) {
|
||||
|
||||
return true;
|
||||
@@ -194,18 +200,18 @@ class Crypt {
|
||||
|
||||
/**
|
||||
* @brief Symmetrically encrypt a string
|
||||
* @returns encrypted file
|
||||
* @param $plainContent
|
||||
* @param $iv
|
||||
* @param string $passphrase
|
||||
* @return string encrypted file content
|
||||
*/
|
||||
public static function encrypt( $plainContent, $iv, $passphrase = '' ) {
|
||||
|
||||
if ( $encryptedContent = openssl_encrypt( $plainContent, 'AES-128-CFB', $passphrase, false, $iv ) ) {
|
||||
public static function encrypt($plainContent, $iv, $passphrase = '') {
|
||||
|
||||
if ($encryptedContent = openssl_encrypt($plainContent, 'AES-128-CFB', $passphrase, false, $iv)) {
|
||||
return $encryptedContent;
|
||||
|
||||
} else {
|
||||
|
||||
\OC_Log::write( 'Encryption library', 'Encryption (symmetric) of content failed', \OC_Log::ERROR );
|
||||
|
||||
\OCP\Util::writeLog('Encryption library', 'Encryption (symmetric) of content failed', \OCP\Util::ERROR);
|
||||
\OCP\Util::writeLog('Encryption library', openssl_error_string(), \OCP\Util::ERROR);
|
||||
return false;
|
||||
|
||||
}
|
||||
@@ -214,18 +220,21 @@ class Crypt {
|
||||
|
||||
/**
|
||||
* @brief Symmetrically decrypt a string
|
||||
* @returns decrypted file
|
||||
* @param $encryptedContent
|
||||
* @param $iv
|
||||
* @param $passphrase
|
||||
* @throws \Exception
|
||||
* @return string decrypted file content
|
||||
*/
|
||||
public static function decrypt( $encryptedContent, $iv, $passphrase ) {
|
||||
public static function decrypt($encryptedContent, $iv, $passphrase) {
|
||||
|
||||
if ( $plainContent = openssl_decrypt( $encryptedContent, 'AES-128-CFB', $passphrase, false, $iv ) ) {
|
||||
if ($plainContent = openssl_decrypt($encryptedContent, 'AES-128-CFB', $passphrase, false, $iv)) {
|
||||
|
||||
return $plainContent;
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
throw new \Exception( 'Encryption library: Decryption (symmetric) of content failed' );
|
||||
throw new \Exception('Encryption library: Decryption (symmetric) of content failed');
|
||||
|
||||
}
|
||||
|
||||
@@ -237,7 +246,7 @@ class Crypt {
|
||||
* @param string $iv IV to be concatenated
|
||||
* @returns string concatenated content
|
||||
*/
|
||||
public static function concatIv ( $content, $iv ) {
|
||||
public static function concatIv($content, $iv) {
|
||||
|
||||
$combined = $content . '00iv00' . $iv;
|
||||
|
||||
@@ -250,20 +259,20 @@ class Crypt {
|
||||
* @param string $catFile concatenated data to be split
|
||||
* @returns array keys: encrypted, iv
|
||||
*/
|
||||
public static function splitIv ( $catFile ) {
|
||||
public static function splitIv($catFile) {
|
||||
|
||||
// Fetch encryption metadata from end of file
|
||||
$meta = substr( $catFile, -22 );
|
||||
$meta = substr($catFile, -22);
|
||||
|
||||
// Fetch IV from end of file
|
||||
$iv = substr( $meta, -16 );
|
||||
$iv = substr($meta, -16);
|
||||
|
||||
// Remove IV and IV identifier text to expose encrypted content
|
||||
$encrypted = substr( $catFile, 0, -22 );
|
||||
$encrypted = substr($catFile, 0, -22);
|
||||
|
||||
$split = array(
|
||||
'encrypted' => $encrypted
|
||||
, 'iv' => $iv
|
||||
'encrypted' => $encrypted,
|
||||
'iv' => $iv
|
||||
);
|
||||
|
||||
return $split;
|
||||
@@ -272,36 +281,32 @@ class Crypt {
|
||||
|
||||
/**
|
||||
* @brief Symmetrically encrypts a string and returns keyfile content
|
||||
* @param $plainContent content to be encrypted in keyfile
|
||||
* @returns encrypted content combined with IV
|
||||
* @param string $plainContent content to be encrypted in keyfile
|
||||
* @param string $passphrase
|
||||
* @return bool|string
|
||||
* @return string encrypted content combined with IV
|
||||
* @note IV need not be specified, as it will be stored in the returned keyfile
|
||||
* and remain accessible therein.
|
||||
*/
|
||||
public static function symmetricEncryptFileContent( $plainContent, $passphrase = '' ) {
|
||||
|
||||
if ( !$plainContent ) {
|
||||
public static function symmetricEncryptFileContent($plainContent, $passphrase = '') {
|
||||
|
||||
if (!$plainContent) {
|
||||
\OCP\Util::writeLog('Encryption library', 'symmetrically encryption failed, no content given.', \OCP\Util::ERROR);
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
$iv = self::generateIv();
|
||||
|
||||
if ( $encryptedContent = self::encrypt( $plainContent, $iv, $passphrase ) ) {
|
||||
|
||||
if ($encryptedContent = self::encrypt($plainContent, $iv, $passphrase)) {
|
||||
// Combine content to encrypt with IV identifier and actual IV
|
||||
$catfile = self::concatIv( $encryptedContent, $iv );
|
||||
|
||||
$padded = self::addPadding( $catfile );
|
||||
$catfile = self::concatIv($encryptedContent, $iv);
|
||||
$padded = self::addPadding($catfile);
|
||||
|
||||
return $padded;
|
||||
|
||||
} else {
|
||||
|
||||
\OC_Log::write( 'Encryption library', 'Encryption (symmetric) of keyfile content failed', \OC_Log::ERROR );
|
||||
|
||||
\OCP\Util::writeLog('Encryption library', 'Encryption (symmetric) of keyfile content failed', \OCP\Util::ERROR);
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -309,35 +314,69 @@ class Crypt {
|
||||
|
||||
/**
|
||||
* @brief Symmetrically decrypts keyfile content
|
||||
* @param string $source
|
||||
* @param string $target
|
||||
* @param string $key the decryption key
|
||||
* @returns decrypted content
|
||||
* @param $keyfileContent
|
||||
* @param string $passphrase
|
||||
* @throws \Exception
|
||||
* @return bool|string
|
||||
* @internal param string $source
|
||||
* @internal param string $target
|
||||
* @internal param string $key the decryption key
|
||||
* @returns string decrypted content
|
||||
*
|
||||
* This function decrypts a file
|
||||
*/
|
||||
public static function symmetricDecryptFileContent( $keyfileContent, $passphrase = '' ) {
|
||||
public static function symmetricDecryptFileContent($keyfileContent, $passphrase = '') {
|
||||
|
||||
if ( !$keyfileContent ) {
|
||||
if (!$keyfileContent) {
|
||||
|
||||
throw new \Exception( 'Encryption library: no data provided for decryption' );
|
||||
throw new \Exception('Encryption library: no data provided for decryption');
|
||||
|
||||
}
|
||||
|
||||
// Remove padding
|
||||
$noPadding = self::removePadding( $keyfileContent );
|
||||
$noPadding = self::removePadding($keyfileContent);
|
||||
|
||||
// Split into enc data and catfile
|
||||
$catfile = self::splitIv( $noPadding );
|
||||
$catfile = self::splitIv($noPadding);
|
||||
|
||||
if ( $plainContent = self::decrypt( $catfile['encrypted'], $catfile['iv'], $passphrase ) ) {
|
||||
if ($plainContent = self::decrypt($catfile['encrypted'], $catfile['iv'], $passphrase)) {
|
||||
|
||||
return $plainContent;
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Decrypt private key and check if the result is a valid keyfile
|
||||
* @param string $encryptedKey encrypted keyfile
|
||||
* @param string $passphrase to decrypt keyfile
|
||||
* @returns encrypted private key or false
|
||||
*
|
||||
* This function decrypts a file
|
||||
*/
|
||||
public static function decryptPrivateKey($encryptedKey, $passphrase) {
|
||||
|
||||
$plainKey = self::symmetricDecryptFileContent($encryptedKey, $passphrase);
|
||||
|
||||
// check if this a valid private key
|
||||
$res = openssl_pkey_get_private($plainKey);
|
||||
if (is_resource($res)) {
|
||||
$sslInfo = openssl_pkey_get_details($res);
|
||||
if (!isset($sslInfo['key'])) {
|
||||
$plainKey = false;
|
||||
}
|
||||
} else {
|
||||
$plainKey = false;
|
||||
}
|
||||
|
||||
return $plainKey;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Creates symmetric keyfile content using a generated key
|
||||
* @param string $plainContent content to be encrypted
|
||||
@@ -346,15 +385,15 @@ class Crypt {
|
||||
*
|
||||
* This function decrypts a file
|
||||
*/
|
||||
public static function symmetricEncryptFileContentKeyfile( $plainContent ) {
|
||||
public static function symmetricEncryptFileContentKeyfile($plainContent) {
|
||||
|
||||
$key = self::generateKey();
|
||||
|
||||
if( $encryptedContent = self::symmetricEncryptFileContent( $plainContent, $key ) ) {
|
||||
if ($encryptedContent = self::symmetricEncryptFileContent($plainContent, $key)) {
|
||||
|
||||
return array(
|
||||
'key' => $key
|
||||
, 'encrypted' => $encryptedContent
|
||||
'key' => $key,
|
||||
'encrypted' => $encryptedContent
|
||||
);
|
||||
|
||||
} else {
|
||||
@@ -368,22 +407,41 @@ class Crypt {
|
||||
/**
|
||||
* @brief Create asymmetrically encrypted keyfile content using a generated key
|
||||
* @param string $plainContent content to be encrypted
|
||||
* @returns array keys: key, encrypted
|
||||
* @note symmetricDecryptFileContent() can be used to decrypt files created using this method
|
||||
*
|
||||
* This function decrypts a file
|
||||
* @param array $publicKeys array keys must be the userId of corresponding user
|
||||
* @returns array keys: keys (array, key = userId), data
|
||||
* @note symmetricDecryptFileContent() can decrypt files created using this method
|
||||
*/
|
||||
public static function multiKeyEncrypt( $plainContent, array $publicKeys ) {
|
||||
public static function multiKeyEncrypt($plainContent, array $publicKeys) {
|
||||
|
||||
// openssl_seal returns false without errors if $plainContent
|
||||
// is empty, so trigger our own error
|
||||
if (empty($plainContent)) {
|
||||
|
||||
throw new \Exception('Cannot mutliKeyEncrypt empty plain content');
|
||||
|
||||
}
|
||||
|
||||
// Set empty vars to be set by openssl by reference
|
||||
$sealed = '';
|
||||
$envKeys = array();
|
||||
$shareKeys = array();
|
||||
$mappedShareKeys = array();
|
||||
|
||||
if( openssl_seal( $plainContent, $sealed, $envKeys, $publicKeys ) ) {
|
||||
if (openssl_seal($plainContent, $sealed, $shareKeys, $publicKeys)) {
|
||||
|
||||
$i = 0;
|
||||
|
||||
// Ensure each shareKey is labelled with its
|
||||
// corresponding userId
|
||||
foreach ($publicKeys as $userId => $publicKey) {
|
||||
|
||||
$mappedShareKeys[$userId] = $shareKeys[$i];
|
||||
$i++;
|
||||
|
||||
}
|
||||
|
||||
return array(
|
||||
'keys' => $envKeys
|
||||
, 'encrypted' => $sealed
|
||||
'keys' => $mappedShareKeys,
|
||||
'data' => $sealed
|
||||
);
|
||||
|
||||
} else {
|
||||
@@ -396,27 +454,31 @@ class Crypt {
|
||||
|
||||
/**
|
||||
* @brief Asymmetrically encrypt a file using multiple public keys
|
||||
* @param string $plainContent content to be encrypted
|
||||
* @param $encryptedContent
|
||||
* @param $shareKey
|
||||
* @param $privateKey
|
||||
* @return bool
|
||||
* @internal param string $plainContent content to be encrypted
|
||||
* @returns string $plainContent decrypted string
|
||||
* @note symmetricDecryptFileContent() can be used to decrypt files created using this method
|
||||
*
|
||||
* This function decrypts a file
|
||||
*/
|
||||
public static function multiKeyDecrypt( $encryptedContent, $envKey, $privateKey ) {
|
||||
public static function multiKeyDecrypt($encryptedContent, $shareKey, $privateKey) {
|
||||
|
||||
if ( !$encryptedContent ) {
|
||||
if (!$encryptedContent) {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
if ( openssl_open( $encryptedContent, $plainContent, $envKey, $privateKey ) ) {
|
||||
if (openssl_open($encryptedContent, $plainContent, $shareKey, $privateKey)) {
|
||||
|
||||
return $plainContent;
|
||||
|
||||
} else {
|
||||
|
||||
\OC_Log::write( 'Encryption library', 'Decryption (asymmetric) of sealed content failed', \OC_Log::ERROR );
|
||||
\OCP\Util::writeLog('Encryption library', 'Decryption (asymmetric) of sealed content with share-key "'.$shareKey.'" failed', \OCP\Util::ERROR);
|
||||
|
||||
return false;
|
||||
|
||||
@@ -425,12 +487,14 @@ class Crypt {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Asymmetrically encrypt a string using a public key
|
||||
* @returns encrypted file
|
||||
* @brief Asymetrically encrypt a string using a public key
|
||||
* @param $plainContent
|
||||
* @param $publicKey
|
||||
* @return string encrypted file
|
||||
*/
|
||||
public static function keyEncrypt( $plainContent, $publicKey ) {
|
||||
public static function keyEncrypt($plainContent, $publicKey) {
|
||||
|
||||
openssl_public_encrypt( $plainContent, $encryptedContent, $publicKey );
|
||||
openssl_public_encrypt($plainContent, $encryptedContent, $publicKey);
|
||||
|
||||
return $encryptedContent;
|
||||
|
||||
@@ -438,110 +502,19 @@ class Crypt {
|
||||
|
||||
/**
|
||||
* @brief Asymetrically decrypt a file using a private key
|
||||
* @returns decrypted file
|
||||
* @param $encryptedContent
|
||||
* @param $privatekey
|
||||
* @return string decrypted file
|
||||
*/
|
||||
public static function keyDecrypt( $encryptedContent, $privatekey ) {
|
||||
public static function keyDecrypt($encryptedContent, $privatekey) {
|
||||
|
||||
openssl_private_decrypt( $encryptedContent, $plainContent, $privatekey );
|
||||
|
||||
return $plainContent;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Encrypts content symmetrically and generates keyfile asymmetrically
|
||||
* @returns array containing catfile and new keyfile.
|
||||
* keys: data, key
|
||||
* @note this method is a wrapper for combining other crypt class methods
|
||||
*/
|
||||
public static function keyEncryptKeyfile( $plainContent, $publicKey ) {
|
||||
|
||||
// Encrypt plain data, generate keyfile & encrypted file
|
||||
$cryptedData = self::symmetricEncryptFileContentKeyfile( $plainContent );
|
||||
|
||||
// Encrypt keyfile
|
||||
$cryptedKey = self::keyEncrypt( $cryptedData['key'], $publicKey );
|
||||
|
||||
return array( 'data' => $cryptedData['encrypted'], 'key' => $cryptedKey );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Takes catfile, keyfile, and private key, and
|
||||
* performs decryption
|
||||
* @returns decrypted content
|
||||
* @note this method is a wrapper for combining other crypt class methods
|
||||
*/
|
||||
public static function keyDecryptKeyfile( $catfile, $keyfile, $privateKey ) {
|
||||
|
||||
// Decrypt the keyfile with the user's private key
|
||||
$decryptedKeyfile = self::keyDecrypt( $keyfile, $privateKey );
|
||||
|
||||
// Decrypt the catfile symmetrically using the decrypted keyfile
|
||||
$decryptedData = self::symmetricDecryptFileContent( $catfile, $decryptedKeyfile );
|
||||
|
||||
return $decryptedData;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Symmetrically encrypt a file by combining encrypted component data blocks
|
||||
*/
|
||||
public static function symmetricBlockEncryptFileContent( $plainContent, $key ) {
|
||||
|
||||
$crypted = '';
|
||||
|
||||
$remaining = $plainContent;
|
||||
|
||||
$testarray = array();
|
||||
|
||||
while( strlen( $remaining ) ) {
|
||||
|
||||
//echo "\n\n\$block = ".substr( $remaining, 0, 6126 );
|
||||
|
||||
// Encrypt a chunk of unencrypted data and add it to the rest
|
||||
$block = self::symmetricEncryptFileContent( substr( $remaining, 0, 6126 ), $key );
|
||||
|
||||
$padded = self::addPadding( $block );
|
||||
|
||||
$crypted .= $block;
|
||||
|
||||
$testarray[] = $block;
|
||||
|
||||
// Remove the data already encrypted from remaining unencrypted data
|
||||
$remaining = substr( $remaining, 6126 );
|
||||
$result = @openssl_private_decrypt($encryptedContent, $plainContent, $privatekey);
|
||||
|
||||
if ($result) {
|
||||
return $plainContent;
|
||||
}
|
||||
|
||||
return $crypted;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Symmetrically decrypt a file by combining encrypted component data blocks
|
||||
*/
|
||||
public static function symmetricBlockDecryptFileContent( $crypted, $key ) {
|
||||
|
||||
$decrypted = '';
|
||||
|
||||
$remaining = $crypted;
|
||||
|
||||
$testarray = array();
|
||||
|
||||
while( strlen( $remaining ) ) {
|
||||
|
||||
$testarray[] = substr( $remaining, 0, 8192 );
|
||||
|
||||
// Decrypt a chunk of unencrypted data and add it to the rest
|
||||
$decrypted .= self::symmetricDecryptFileContent( $remaining, $key );
|
||||
|
||||
// Remove the data already encrypted from remaining unencrypted data
|
||||
$remaining = substr( $remaining, 8192 );
|
||||
|
||||
}
|
||||
|
||||
return $decrypted;
|
||||
return $result;
|
||||
|
||||
}
|
||||
|
||||
@@ -551,24 +524,24 @@ class Crypt {
|
||||
*/
|
||||
public static function generateIv() {
|
||||
|
||||
if ( $random = openssl_random_pseudo_bytes( 12, $strong ) ) {
|
||||
if ($random = openssl_random_pseudo_bytes(12, $strong)) {
|
||||
|
||||
if ( !$strong ) {
|
||||
if (!$strong) {
|
||||
|
||||
// If OpenSSL indicates randomness is insecure, log error
|
||||
\OC_Log::write( 'Encryption library', 'Insecure symmetric key was generated using openssl_random_pseudo_bytes()', \OC_Log::WARN );
|
||||
\OCP\Util::writeLog('Encryption library', 'Insecure symmetric key was generated using openssl_random_pseudo_bytes()', \OCP\Util::WARN);
|
||||
|
||||
}
|
||||
|
||||
// We encode the iv purely for string manipulation
|
||||
// purposes - it gets decoded before use
|
||||
$iv = base64_encode( $random );
|
||||
$iv = base64_encode($random);
|
||||
|
||||
return $iv;
|
||||
|
||||
} else {
|
||||
|
||||
throw new \Exception( 'Generating IV failed' );
|
||||
throw new \Exception('Generating IV failed');
|
||||
|
||||
}
|
||||
|
||||
@@ -581,12 +554,12 @@ class Crypt {
|
||||
public static function generateKey() {
|
||||
|
||||
// Generate key
|
||||
if ( $key = base64_encode( openssl_random_pseudo_bytes( 183, $strong ) ) ) {
|
||||
if ($key = base64_encode(openssl_random_pseudo_bytes(183, $strong))) {
|
||||
|
||||
if ( !$strong ) {
|
||||
if (!$strong) {
|
||||
|
||||
// If OpenSSL indicates randomness is insecure, log error
|
||||
throw new \Exception ( 'Encryption library, Insecure symmetric key was generated using openssl_random_pseudo_bytes()' );
|
||||
throw new \Exception('Encryption library, Insecure symmetric key was generated using openssl_random_pseudo_bytes()');
|
||||
|
||||
}
|
||||
|
||||
@@ -603,15 +576,15 @@ class Crypt {
|
||||
/**
|
||||
* @brief Get the blowfish encryption handeler for a key
|
||||
* @param $key string (optional)
|
||||
* @return Crypt_Blowfish blowfish object
|
||||
* @return \Crypt_Blowfish blowfish object
|
||||
*
|
||||
* if the key is left out, the default handeler will be used
|
||||
*/
|
||||
public static function getBlowfish( $key = '' ) {
|
||||
public static function getBlowfish($key = '') {
|
||||
|
||||
if ( $key ) {
|
||||
if ($key) {
|
||||
|
||||
return new \Crypt_Blowfish( $key );
|
||||
return new \Crypt_Blowfish($key);
|
||||
|
||||
} else {
|
||||
|
||||
@@ -621,13 +594,17 @@ class Crypt {
|
||||
|
||||
}
|
||||
|
||||
public static function legacyCreateKey( $passphrase ) {
|
||||
/**
|
||||
* @param $passphrase
|
||||
* @return mixed
|
||||
*/
|
||||
public static function legacyCreateKey($passphrase) {
|
||||
|
||||
// Generate a random integer
|
||||
$key = mt_rand( 10000, 99999 ) . mt_rand( 10000, 99999 ) . mt_rand( 10000, 99999 ) . mt_rand( 10000, 99999 );
|
||||
$key = mt_rand(10000, 99999) . mt_rand(10000, 99999) . mt_rand(10000, 99999) . mt_rand(10000, 99999);
|
||||
|
||||
// Encrypt the key with the passphrase
|
||||
$legacyEncKey = self::legacyEncrypt( $key, $passphrase );
|
||||
$legacyEncKey = self::legacyEncrypt($key, $passphrase);
|
||||
|
||||
return $legacyEncKey;
|
||||
|
||||
@@ -635,61 +612,55 @@ class Crypt {
|
||||
|
||||
/**
|
||||
* @brief encrypts content using legacy blowfish system
|
||||
* @param $content the cleartext message you want to encrypt
|
||||
* @param $key the encryption key (optional)
|
||||
* @returns encrypted content
|
||||
* @param string $content the cleartext message you want to encrypt
|
||||
* @param string $passphrase
|
||||
* @returns string encrypted content
|
||||
*
|
||||
* This function encrypts an content
|
||||
*/
|
||||
public static function legacyEncrypt( $content, $passphrase = '' ) {
|
||||
public static function legacyEncrypt($content, $passphrase = '') {
|
||||
|
||||
$bf = self::getBlowfish( $passphrase );
|
||||
$bf = self::getBlowfish($passphrase);
|
||||
|
||||
return $bf->encrypt( $content );
|
||||
return $bf->encrypt($content);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief decrypts content using legacy blowfish system
|
||||
* @param $content the cleartext message you want to decrypt
|
||||
* @param $key the encryption key (optional)
|
||||
* @returns cleartext content
|
||||
* @param string $content the cleartext message you want to decrypt
|
||||
* @param string $passphrase
|
||||
* @return string cleartext content
|
||||
*
|
||||
* This function decrypts an content
|
||||
*/
|
||||
public static function legacyDecrypt( $content, $passphrase = '' ) {
|
||||
public static function legacyDecrypt($content, $passphrase = '') {
|
||||
|
||||
$bf = self::getBlowfish( $passphrase );
|
||||
$bf = self::getBlowfish($passphrase);
|
||||
|
||||
$decrypted = $bf->decrypt( $content );
|
||||
|
||||
$trimmed = rtrim( $decrypted, "\0" );
|
||||
|
||||
return $trimmed;
|
||||
|
||||
}
|
||||
|
||||
public static function legacyKeyRecryptKeyfile( $legacyEncryptedContent, $legacyPassphrase, $publicKey, $newPassphrase ) {
|
||||
|
||||
$decrypted = self::legacyDecrypt( $legacyEncryptedContent, $legacyPassphrase );
|
||||
|
||||
$recrypted = self::keyEncryptKeyfile( $decrypted, $publicKey );
|
||||
|
||||
return $recrypted;
|
||||
$decrypted = $bf->decrypt($content);
|
||||
|
||||
return $decrypted;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Re-encryptes a legacy blowfish encrypted file using AES with integrated IV
|
||||
* @param $legacyContent the legacy encrypted content to re-encrypt
|
||||
* @returns cleartext content
|
||||
*
|
||||
* This function decrypts an content
|
||||
* @param $data
|
||||
* @param string $key
|
||||
* @param int $maxLength
|
||||
* @return string
|
||||
*/
|
||||
public static function legacyRecrypt( $legacyContent, $legacyPassphrase, $newPassphrase ) {
|
||||
|
||||
// TODO: write me
|
||||
public static function legacyBlockDecrypt($data, $key = '', $maxLength = 0) {
|
||||
|
||||
$result = '';
|
||||
while (strlen($data)) {
|
||||
$result .= self::legacyDecrypt(substr($data, 0, 8192), $key);
|
||||
$data = substr($data, 8192);
|
||||
}
|
||||
if ($maxLength > 0) {
|
||||
return substr($result, 0, $maxLength);
|
||||
} else {
|
||||
return rtrim($result, "\0");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user