Compare commits
631 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 927cae7efc | |||
| b04d510053 | |||
| b4741cfa96 | |||
| 55a122a9fe | |||
| 5014d2c60c | |||
| 8a39256092 | |||
| ae850d76ea | |||
| 765526ec4c | |||
| 87052be76f | |||
| 02ef384064 | |||
| cf05d50654 | |||
| f5a597b259 | |||
| 2c656b0e4c | |||
| 9c44e7bfb8 | |||
| 0418b330d5 | |||
| 780530ec83 | |||
| 67c862c286 | |||
| 88006222a9 | |||
| d01bfe3587 | |||
| 38644cffd4 | |||
| 2c10e31c8f | |||
| e37f9c8351 | |||
| 79187fcb10 | |||
| e72cd711ad | |||
| 598f798c04 | |||
| 919241cdda | |||
| f7db588e62 | |||
| a2cc658f37 | |||
| f830150acc | |||
| 77a601c3fe | |||
| 24037218dd | |||
| caae0e6f47 | |||
| 07988cf77c | |||
| f3bd266787 | |||
| 03c9657607 | |||
| e6c2382a19 | |||
| 43b2f3c2dc | |||
| 1ae73f0e99 | |||
| 3f23ae4a16 | |||
| a4c0f259a5 | |||
| 6ebe04f8d4 | |||
| 1c5a86a115 | |||
| 57d6c49a62 | |||
| 423311c7e8 | |||
| 0cdeeec82b | |||
| 32bd2d15e3 | |||
| ef1ddfc5db | |||
| 529d45c5b2 | |||
| 0c72c99f04 | |||
| 2bb6a920e3 | |||
| 1325649b4b | |||
| bf7e2c756f | |||
| 467da3c519 | |||
| df2f85ee01 | |||
| 9e52b174b1 | |||
| 03ca380815 | |||
| db763760f1 | |||
| 0ca1500330 | |||
| 92cbeefa34 | |||
| b62d20f2ee | |||
| 4f9c750a0a | |||
| a529b2bf86 | |||
| 27ec925132 | |||
| c716776a90 | |||
| b588692ef4 | |||
| 5544509283 | |||
| 39492eb020 | |||
| 24eb2bcab5 | |||
| 8b83580af7 | |||
| 02757ad08e | |||
| 3bf505b566 | |||
| 1dea188fea | |||
| 86e4177914 | |||
| ec71e0b4e6 | |||
| 51017e43a0 | |||
| eb778eb2b0 | |||
| 45ad072c62 | |||
| 3ac33c865b | |||
| 431638742c | |||
| 7b432cbbf7 | |||
| 01cede4511 | |||
| 73954c44c6 | |||
| e345ae7b53 | |||
| 9fd53ef84f | |||
| 6a46ede8b7 | |||
| 3e5a1ad76b | |||
| a45c606b96 | |||
| fcad7252bd | |||
| c11edb9138 | |||
| 61852536fe | |||
| d9d7774cc1 | |||
| 63e5282c41 | |||
| 0c3204c7a6 | |||
| c2a72ce6b0 | |||
| cbf8dd439c | |||
| c658ec658a | |||
| 9db5323a92 | |||
| c58501ee87 | |||
| 3e9d8cce10 | |||
| 6897be7a93 | |||
| f0b0e462ea | |||
| 2b83afdd7e | |||
| a81b4c54d8 | |||
| 7975b74816 | |||
| 361b70e4d7 | |||
| 8305ae6b09 | |||
| 91fc933432 | |||
| ed60bdeac9 | |||
| bd14af5806 | |||
| 234f33e01e | |||
| 441f807bce | |||
| 80560e70b7 | |||
| 56c51d481c | |||
| 2d2e024cfa | |||
| 491c714f54 | |||
| 8459b9f6fb | |||
| 153ff1b766 | |||
| 11efe732f9 | |||
| f03a1868ab | |||
| 1c000b799b | |||
| 18d46dfdeb | |||
| 9d761fcaee | |||
| 5f70ed188b | |||
| 616fd4b54a | |||
| 6d87922cea | |||
| 0753514e5b | |||
| 7ef006e1c9 | |||
| 5a58d142e5 | |||
| db51d9aacb | |||
| d534f262aa | |||
| 0f04bfc319 | |||
| 4d42485bf5 | |||
| 713f2b3a52 | |||
| 0d39a63b05 | |||
| bd1bf9e9ac | |||
| 6552fec113 | |||
| d5190b5481 | |||
| 06bc987bd9 | |||
| 344606b2c8 | |||
| a5574e885c | |||
| bf1f9df590 | |||
| 2fd2b182e7 | |||
| 8778af681c | |||
| fb63e75743 | |||
| 4c0af1b2a2 | |||
| 9c38baac9e | |||
| dd18f963d4 | |||
| 5d46dfd2b4 | |||
| 1d54735d5d | |||
| cb5f9d2164 | |||
| a26ddb33a2 | |||
| dd8ba68e07 | |||
| bfe4ee6e47 | |||
| a429fa74d9 | |||
| f0a0e44d2e | |||
| 533e8e14b6 | |||
| 60099b91c4 | |||
| 5fd1d54607 | |||
| 0eb3496ab6 | |||
| bd06b4cf42 | |||
| 72c0cc2267 | |||
| 43b6676d0e | |||
| 36e7d3b7da | |||
| 7a60651037 | |||
| 50705cfaf8 | |||
| 3720ba9318 | |||
| a05fc9dc73 | |||
| cf0a12f999 | |||
| 5fcc3401e2 | |||
| 60b2dd6ab4 | |||
| ed96f8c628 | |||
| 77bcc5b2f3 | |||
| 1b1951a64f | |||
| a33dcd359a | |||
| 55ebf024a7 | |||
| 21f467dd36 | |||
| 26e504e096 | |||
| 5d56eba398 | |||
| 0b80c5e18e | |||
| be26cccd8a | |||
| 71bd33da98 | |||
| 3c673717b0 | |||
| 01a176f2a3 | |||
| af1c47d1e8 | |||
| 913ad8634f | |||
| 79711c32b7 | |||
| ddd832c2dc | |||
| d30059d76c | |||
| 5fe7781452 | |||
| 8fc4f67f14 | |||
| f5d9513957 | |||
| 3917383cef | |||
| 46a4af1dc2 | |||
| 2954169512 | |||
| b122b285c9 | |||
| 85b7ee349b | |||
| 7484c2f0d8 | |||
| 2944f952dc | |||
| 9b414d81d8 | |||
| 5ac96c0a87 | |||
| a60e113fa8 | |||
| 392e36d4e4 | |||
| 8b3728ed9b | |||
| b96b601017 | |||
| cdf37a061b | |||
| b1f838814d | |||
| 161e58b1a2 | |||
| d815638f7b | |||
| 384d1892aa | |||
| 32a90911b0 | |||
| 6967512c5f | |||
| 8ea0187ecd | |||
| abc7f143da | |||
| d7779f9209 | |||
| 4c5aa43079 | |||
| 11ca5588ea | |||
| 3ff1f879e0 | |||
| 74b68e10e4 | |||
| ec853da5ad | |||
| c494887d98 | |||
| f64c6c9c9c | |||
| 56fabf8adf | |||
| 42ada6cb15 | |||
| 54607a2142 | |||
| 6a6b645b83 | |||
| 2f1270278d | |||
| f235e8b803 | |||
| baf8d8433f | |||
| f5bd8e4947 | |||
| d49e3d0ceb | |||
| bc76998cd2 | |||
| f371f14fc2 | |||
| 4e1799759c | |||
| 122f3ff594 | |||
| a19fd8880d | |||
| e3a9a19d95 | |||
| 75e8d2ad6e | |||
| 2dc688dcdf | |||
| ce79974888 | |||
| 060a40ad43 | |||
| ce3e5a8538 | |||
| 9384fa65b5 | |||
| e6e0573756 | |||
| fcde4c70a2 | |||
| b7cf8fac34 | |||
| 0271e7539d | |||
| 3acd98f331 | |||
| 74a625155d | |||
| 643835e2b3 | |||
| a843129a06 | |||
| 0ab77083c6 | |||
| 32401b42f1 | |||
| 4fbd6023f0 | |||
| b35a5b5a85 | |||
| 135479cae2 | |||
| 29fd95967b | |||
| c8a48272c5 | |||
| 2b3b4272f8 | |||
| 786007c78c | |||
| 1e5a39ea6c | |||
| d859d1b6c7 | |||
| 778efcb054 | |||
| f52662ab26 | |||
| fea444b941 | |||
| 27c29c0c58 | |||
| afc4224aff | |||
| 042bfabf64 | |||
| e9ebbcb47e | |||
| 35a71cc9a5 | |||
| ddccbb9530 | |||
| 5ef6c4e03d | |||
| b6c868ec88 | |||
| 32625aff30 | |||
| 2fb1ed84f2 | |||
| 9255da9856 | |||
| 2db69a5328 | |||
| 4c46a2f162 | |||
| 6d7a5bf943 | |||
| 8d87a2c4a6 | |||
| 42197e2ce3 | |||
| 61c802935b | |||
| b6334a2da5 | |||
| acc547c5ff | |||
| b509fdb30f | |||
| 3f35822e24 | |||
| d5316623dc | |||
| 8339aeab9a | |||
| f718e88aa1 | |||
| 38783b1ca3 | |||
| 56fade9a04 | |||
| 70e68280b8 | |||
| 840f5487aa | |||
| 920e991c82 | |||
| 67c3ab92cf | |||
| 3bc748d43f | |||
| aeb9e172a9 | |||
| 1025c30885 | |||
| 4aae60a375 | |||
| 05a15a9669 | |||
| 43e01439d6 | |||
| 2261db62f5 | |||
| 496b62f2eb | |||
| b5ab3d7fc0 | |||
| 321a631d92 | |||
| a1ded6e9d7 | |||
| 68dd41a4c9 | |||
| 0d02aa7910 | |||
| 77a533a29d | |||
| 84e942f121 | |||
| 96c092ce14 | |||
| ec3f92e102 | |||
| 15e357fa94 | |||
| 3ba1441c2d | |||
| 9c24dbbac7 | |||
| 9b908c3d05 | |||
| dbfe5ef28a | |||
| a3c33585e1 | |||
| 6a8c41754f | |||
| 3399930355 | |||
| 09d80ac9fc | |||
| 6995b96589 | |||
| 5624968d1e | |||
| a5d6e6eb28 | |||
| 098b4e9e81 | |||
| d0b3fe2414 | |||
| 3e02e79154 | |||
| 841998bdcb | |||
| ff93c5859b | |||
| 7ffe80cf25 | |||
| 86daab2800 | |||
| 174ab07a4b | |||
| 9998861402 | |||
| 5b6ba39734 | |||
| fb9c2b5362 | |||
| a93e424738 | |||
| d27db8cc61 | |||
| 0c6a58a883 | |||
| d2b766ddee | |||
| da10518278 | |||
| 9ed35a377f | |||
| c8c182b36e | |||
| f2dadc7104 | |||
| ada93bab0c | |||
| b3acb2a1e7 | |||
| af72528570 | |||
| 5f69b2095a | |||
| 6e3a7ea140 | |||
| 38c817c7dd | |||
| 61873e4e21 | |||
| 6d4d5400d7 | |||
| 92d069ab6c | |||
| d0101668ce | |||
| 73a5e3810f | |||
| 6d81789a66 | |||
| e1e501b17f | |||
| f53ecea372 | |||
| 15b39a6566 | |||
| 508ef23486 | |||
| ff8d755702 | |||
| 9159598d32 | |||
| 361d6892c9 | |||
| 149b55f8ae | |||
| e7a46ed9e7 | |||
| ad06cd4b1f | |||
| f03142f3d6 | |||
| 0497136d29 | |||
| c7f26fa969 | |||
| ad6e281586 | |||
| 595d43ab35 | |||
| 45738b6b7a | |||
| ba33fd6a07 | |||
| 19585f9c3b | |||
| da150afcc5 | |||
| 496b68e2ad | |||
| d6a380613f | |||
| c38454a5b2 | |||
| e4fa642e54 | |||
| 697f461ded | |||
| 48a1e69f5e | |||
| d71fae51f8 | |||
| 372676ee17 | |||
| 686a43ccf3 | |||
| 3ce828b4b7 | |||
| b297ddf349 | |||
| ecc7161611 | |||
| f4c91f0e82 | |||
| 5a37703b3f | |||
| 088879c4ec | |||
| 7097201eab | |||
| b089b85753 | |||
| 34c1760e9f | |||
| 140f3a7aa9 | |||
| f1a99ebb6d | |||
| bd205c58c7 | |||
| a036cc56c4 | |||
| 1203580848 | |||
| f534574b30 | |||
| a11a75faba | |||
| 0d8d5cb3e6 | |||
| 4858b5e94a | |||
| 3d68d172af | |||
| fe652258be | |||
| 24dbdd2b8e | |||
| f8675f60e8 | |||
| d6ee378564 | |||
| 335ad56ff8 | |||
| 7479a6ebf9 | |||
| f0c4347330 | |||
| d222d2b73f | |||
| 5b6f866756 | |||
| cdeb7cb9b3 | |||
| a7398bcfa8 | |||
| f4e1e5f414 | |||
| c9875e3959 | |||
| a3c6b7a662 | |||
| 063d2032a7 | |||
| 47c05e048f | |||
| c83a17e6c8 | |||
| 3e7bc72281 | |||
| 251e4d78b8 | |||
| 6b89f4b44d | |||
| a766f5b633 | |||
| 7ee3ad411c | |||
| bdfd3ca2bf | |||
| 4dcd1ed34f | |||
| a045f8cd3a | |||
| 4e74983676 | |||
| aedd64b5a6 | |||
| b6e81b517f | |||
| 77b5e2e661 | |||
| 9411a6ea53 | |||
| e0d1fa554f | |||
| 532f65116a | |||
| 30398370b8 | |||
| 413bd5406c | |||
| 056b97834d | |||
| 1f5f278501 | |||
| 2b91e628f5 | |||
| c8dab5829c | |||
| 8089e0f9b8 | |||
| 7fd925e96d | |||
| 3a4ac2caa1 | |||
| 67b9edeeb7 | |||
| 25d003a52d | |||
| a47f965b87 | |||
| 0484939fe0 | |||
| 69296befa6 | |||
| bc5c608e4e | |||
| 02374e595a | |||
| f788dffce8 | |||
| d102cb4ffa | |||
| 83a06950f4 | |||
| 6c09c0e082 | |||
| 2376d69115 | |||
| 7eb0d6866c | |||
| 5ddacaed7f | |||
| bd74ab2886 | |||
| 424cc31fd6 | |||
| d388ef5c0a | |||
| 7d389b26f9 | |||
| 9254073786 | |||
| bb703006da | |||
| 1371fecf26 | |||
| 1e5c786392 | |||
| 6d85cf2a0b | |||
| 3b1715c3fc | |||
| 6d747e9721 | |||
| c5db1ef3cc | |||
| 27a630b0bc | |||
| e25593db4e | |||
| 7edf912ef8 | |||
| aab44694ad | |||
| 98268078c0 | |||
| df97d8299a | |||
| 97dba2e022 | |||
| b52154b306 | |||
| 64a9315b4a | |||
| 3fb55d9d2e | |||
| 094f5bcc78 | |||
| 79f5346105 | |||
| 5c0139fdff | |||
| c1c70b306e | |||
| 4d261d9e15 | |||
| 257dbe61e2 | |||
| d660aab116 | |||
| e37f44e56a | |||
| bdc26c6749 | |||
| 6d8fdcd7d2 | |||
| 0044c3bb6b | |||
| 1ec756d125 | |||
| c31990e936 | |||
| 4e850128e6 | |||
| 00bb0e122f | |||
| 2013404e0a | |||
| 734112a5c1 | |||
| fbcd80ac08 | |||
| 435b9c3028 | |||
| 838c849a5a | |||
| 85d7492398 | |||
| a6eb638380 | |||
| cb3bc5ad31 | |||
| d9384cd959 | |||
| bd7f6c9e18 | |||
| bb69eebde4 | |||
| cb39c55073 | |||
| 33737f9526 | |||
| b3ddd39438 | |||
| 2b297567b5 | |||
| d6276beac0 | |||
| 03bb3d2bdc | |||
| 44c7562c7b | |||
| e556698db7 | |||
| 2bdf5a8b1a | |||
| dfc6bfe131 | |||
| c0d1b6bfb2 | |||
| 387638e317 | |||
| 2d3ea08e19 | |||
| 3ebd0b8983 | |||
| 984b6a28ac | |||
| 744b20bc0d | |||
| 8905e77d60 | |||
| c16c680e32 | |||
| 13cee302f7 | |||
| 2aaad09062 | |||
| 996c68aa2e | |||
| 7f030eedde | |||
| 2e93300313 | |||
| a385a367b0 | |||
| 97b83b9098 | |||
| ce69e83b33 | |||
| a2e9056832 | |||
| 260229b027 | |||
| 0c014409e6 | |||
| 2068eaf16b | |||
| 645e7a0c9e | |||
| 0afd79a22c | |||
| 6946962609 | |||
| f8ecef2917 | |||
| 6c544b95e8 | |||
| 5637a581d2 | |||
| 83b9a89569 | |||
| 8580e2a697 | |||
| 7f45226b8e | |||
| 37632e428d | |||
| 7930440b31 | |||
| 749c519759 | |||
| 35cb14c95f | |||
| 28f462095d | |||
| 19a7aa081e | |||
| 82ccb04182 | |||
| ebbd40385a | |||
| 03f9b14a23 | |||
| 8ed1762dfb | |||
| 76ff7ab007 | |||
| 9bf1a18512 | |||
| 86400ea4c8 | |||
| ff6deb809a | |||
| 7f1416e62a | |||
| a23396452f | |||
| 1981d220c5 | |||
| 572720fb7a | |||
| 0732131cd9 | |||
| 2ffcff228c | |||
| bec08955b2 | |||
| f040529e6d | |||
| 5ac620cb04 | |||
| e26a5ff715 | |||
| b7c7ec26c7 | |||
| 7f1e32764d | |||
| 3f5cefb07f | |||
| 463ad5a50d | |||
| ec9517f98b | |||
| 36680a5a81 | |||
| 04597aedcb | |||
| 1a9e08ae4d | |||
| dedb47390b | |||
| 95eb9bf8ae | |||
| cc0a855103 | |||
| 19dd866c7e | |||
| 8e89c51e87 | |||
| 2a859f84a8 | |||
| 8869dcf1af | |||
| ca121d8438 | |||
| f5bac5fb2d | |||
| c52f66cc73 | |||
| 5e5d9e0a80 | |||
| b98c22d39b | |||
| b609d36e3c | |||
| a7968604d8 | |||
| 9b99c81a9d | |||
| 96bb1f7f45 | |||
| 85cde16feb | |||
| 1e4431ba01 | |||
| 994f36e498 | |||
| 640abbe099 | |||
| 1f2550e3da | |||
| cfca88f20e | |||
| 8e77ca6201 | |||
| 41d8157937 | |||
| 6534304196 | |||
| 7bd4f6cac5 | |||
| 69cc2044f0 | |||
| eb682a3022 | |||
| e638a9a444 | |||
| f268eee86c | |||
| 28e1480d1c | |||
| 81c4043d61 | |||
| bd5796a0d1 | |||
| 919d19c906 | |||
| 459c78106d | |||
| 444e21ab15 | |||
| b59d58fdc1 | |||
| b26dd3c76b | |||
| 3d35c7edcc | |||
| 6eb1f7a474 | |||
| f3f1d1ee73 | |||
| 11b2835cc3 | |||
| 8b86df308b | |||
| 98ac45fa78 | |||
| 617636d5a7 | |||
| 4d9fd199ef | |||
| cc820eb824 | |||
| 135d40203c | |||
| 30cc4b9293 | |||
| 04e14ab5a6 | |||
| a133833fb9 | |||
| 2b001adce0 | |||
| 5a8db83c48 | |||
| af17de9467 | |||
| 992bd6dbf2 | |||
| f74bf923ca |
+1
-1
Submodule 3rdparty updated: b958a1e609...4a46bb61a2
@@ -27,7 +27,9 @@ $success = true;
|
||||
//Now delete
|
||||
foreach ($files as $file) {
|
||||
if (\OC\Files\Filesystem::file_exists($dir . '/' . $file) &&
|
||||
!\OC\Files\Filesystem::unlink($dir . '/' . $file)) {
|
||||
!(\OC\Files\Filesystem::isDeletable($dir . '/' . $file) &&
|
||||
\OC\Files\Filesystem::unlink($dir . '/' . $file))
|
||||
) {
|
||||
$filesWithError .= $file . "\n";
|
||||
$success = false;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ try {
|
||||
|
||||
OCP\JSON::success(array('data' => $data));
|
||||
} catch (\OCP\Files\StorageNotAvailableException $e) {
|
||||
\OCP\Util::logException('files', $e);
|
||||
OCP\JSON::error(array(
|
||||
'data' => array(
|
||||
'exception' => '\OCP\Files\StorageNotAvailableException',
|
||||
@@ -39,6 +40,7 @@ try {
|
||||
)
|
||||
));
|
||||
} catch (\OCP\Files\StorageInvalidException $e) {
|
||||
\OCP\Util::logException('files', $e);
|
||||
OCP\JSON::error(array(
|
||||
'data' => array(
|
||||
'exception' => '\OCP\Files\StorageInvalidException',
|
||||
@@ -46,6 +48,7 @@ try {
|
||||
)
|
||||
));
|
||||
} catch (\Exception $e) {
|
||||
\OCP\Util::logException('files', $e);
|
||||
OCP\JSON::error(array(
|
||||
'data' => array(
|
||||
'exception' => '\Exception',
|
||||
|
||||
@@ -19,10 +19,16 @@ if(\OC\Files\Filesystem::file_exists($target . '/' . $file)) {
|
||||
if ($target != '' || strtolower($file) != 'shared') {
|
||||
$targetFile = \OC\Files\Filesystem::normalizePath($target . '/' . $file);
|
||||
$sourceFile = \OC\Files\Filesystem::normalizePath($dir . '/' . $file);
|
||||
if(\OC\Files\Filesystem::rename($sourceFile, $targetFile)) {
|
||||
OCP\JSON::success(array("data" => array( "dir" => $dir, "files" => $file )));
|
||||
} else {
|
||||
OCP\JSON::error(array("data" => array( "message" => $l->t("Could not move %s", array($file)) )));
|
||||
try {
|
||||
if(\OC\Files\Filesystem::rename($sourceFile, $targetFile)) {
|
||||
OCP\JSON::success(array("data" => array( "dir" => $dir, "files" => $file )));
|
||||
} else {
|
||||
OCP\JSON::error(array("data" => array( "message" => $l->t("Could not move %s", array($file)) )));
|
||||
}
|
||||
} catch (\OCP\Files\NotPermittedException $e) {
|
||||
OCP\JSON::error(array("data" => array( "message" => $l->t("Permission denied") )));
|
||||
} catch (\Exception $e) {
|
||||
OCP\JSON::error(array("data" => array( "message" => $e->getMessage())));
|
||||
}
|
||||
}else{
|
||||
OCP\JSON::error(array("data" => array( "message" => $l->t("Could not move %s", array($file)) )));
|
||||
|
||||
@@ -93,7 +93,8 @@ if (\OC\Files\Filesystem::file_exists($target)) {
|
||||
}
|
||||
|
||||
if($source) {
|
||||
if(substr($source, 0, 8)!='https://' and substr($source, 0, 7)!='http://') {
|
||||
$httpHelper = \OC::$server->getHTTPHelper();
|
||||
if(!$httpHelper->isHTTPURL($source)) {
|
||||
OCP\JSON::error(array('data' => array('message' => $l10n->t('Not a valid source'))));
|
||||
exit();
|
||||
}
|
||||
@@ -104,7 +105,10 @@ if($source) {
|
||||
exit();
|
||||
}
|
||||
|
||||
$ctx = stream_context_create(null, array('notification' =>'progress'));
|
||||
$source = $httpHelper->getFinalLocationOfURL($source);
|
||||
|
||||
$ctx = stream_context_create(\OC::$server->getHTTPHelper()->getDefaultContextArray(), array('notification' =>'progress'));
|
||||
|
||||
$sourceStream=@fopen($source, 'rb', false, $ctx);
|
||||
$result = 0;
|
||||
if (is_resource($sourceStream)) {
|
||||
@@ -115,6 +119,9 @@ if($source) {
|
||||
$freeSpace = $storageStats['freeSpace'];
|
||||
|
||||
foreach($meta['wrapper_data'] as $header) {
|
||||
if (strpos($header, ':') === false){
|
||||
continue;
|
||||
}
|
||||
list($name, $value) = explode(':', $header);
|
||||
if ('content-length' === strtolower(trim($name))) {
|
||||
$length = (int) trim($value);
|
||||
|
||||
@@ -17,4 +17,7 @@
|
||||
<webdav>appinfo/remote.php</webdav>
|
||||
<filesync>appinfo/filesync.php</filesync>
|
||||
</remote>
|
||||
<documentation>
|
||||
<user>user-files</user>
|
||||
</documentation>
|
||||
</info>
|
||||
|
||||
@@ -38,7 +38,7 @@ $server->setBaseUri($baseuri);
|
||||
$defaults = new OC_Defaults();
|
||||
$server->addPlugin(new \Sabre\DAV\Auth\Plugin($authBackend, $defaults->getName()));
|
||||
$server->addPlugin(new \Sabre\DAV\Locks\Plugin($lockBackend));
|
||||
$server->addPlugin(new \Sabre\DAV\Browser\Plugin(false)); // Show something in the Browser, but no upload
|
||||
$server->addPlugin(new \Sabre\DAV\Browser\Plugin(false, false)); // Show something in the Browser, but no upload
|
||||
$server->addPlugin(new OC_Connector_Sabre_FilesPlugin());
|
||||
$server->addPlugin(new OC_Connector_Sabre_MaintenancePlugin());
|
||||
$server->addPlugin(new OC_Connector_Sabre_ExceptionLoggerPlugin('webdav'));
|
||||
|
||||
@@ -77,7 +77,11 @@ class Scan extends Command {
|
||||
if (is_object($user)) {
|
||||
$user = $user->getUID();
|
||||
}
|
||||
$this->scanFiles($user, $output);
|
||||
if ($this->userManager->userExists($user)) {
|
||||
$this->scanFiles($user, $output);
|
||||
} else {
|
||||
$output->writeln("<error>Unknown user $user</error>");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,19 +153,23 @@ table th .columntitle.name {
|
||||
margin-left: 50px;
|
||||
}
|
||||
|
||||
.sort-indicator.hidden { visibility: hidden; }
|
||||
table th .sort-indicator {
|
||||
width: 10px;
|
||||
height: 8px;
|
||||
margin-left: 10px;
|
||||
margin-left: 5px;
|
||||
display: inline-block;
|
||||
vertical-align: text-bottom;
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=30)";
|
||||
filter: alpha(opacity=30);
|
||||
opacity: .3;
|
||||
}
|
||||
.sort-indicator.hidden {
|
||||
visibility: hidden;
|
||||
}
|
||||
table th:hover .sort-indicator.hidden {
|
||||
width: 10px;
|
||||
height: 8px;
|
||||
margin-left: 10px;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
table th, table td { border-bottom:1px solid #ddd; text-align:left; font-weight:normal; }
|
||||
table td {
|
||||
padding: 0 15px;
|
||||
@@ -235,8 +239,8 @@ table td.filename a.name {
|
||||
table tr[data-type="dir"] td.filename a.name span.nametext {font-weight:bold; }
|
||||
table td.filename input.filename {
|
||||
width: 70%;
|
||||
margin-top: 1px;
|
||||
margin-left: 48px;
|
||||
margin-top: 6px;
|
||||
margin-left: 7px;
|
||||
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:3px 8px 8px 3px; }
|
||||
@@ -475,7 +479,7 @@ a.action>img {
|
||||
|
||||
.summary td {
|
||||
padding-top: 20px;
|
||||
padding-bottom: 250px;
|
||||
padding-bottom: 150px;
|
||||
border-bottom: none;
|
||||
}
|
||||
.summary .info {
|
||||
|
||||
@@ -137,3 +137,27 @@
|
||||
.oc-dialog .oc-dialog-buttonrow .cancel {
|
||||
float:left;
|
||||
}
|
||||
|
||||
.highlightUploaded {
|
||||
-webkit-animation: highlightAnimation 2s 1;
|
||||
-moz-animation: highlightAnimation 2s 1;
|
||||
-o-animation: highlightAnimation 2s 1;
|
||||
animation: highlightAnimation 2s 1;
|
||||
}
|
||||
|
||||
@-webkit-keyframes highlightAnimation {
|
||||
0% { background-color: rgba(255, 255, 140, 1); }
|
||||
100% { background-color: rgba(0, 0, 0, 0); }
|
||||
}
|
||||
@-moz-keyframes highlightAnimation {
|
||||
0% { background-color: rgba(255, 255, 140, 1); }
|
||||
100% { background-color: rgba(0, 0, 0, 0); }
|
||||
}
|
||||
@-o-keyframes highlightAnimation {
|
||||
0% { background-color: rgba(255, 255, 140, 1); }
|
||||
100% { background-color: rgba(0, 0, 0, 0); }
|
||||
}
|
||||
@keyframes highlightAnimation {
|
||||
0% { background-color: rgba(255, 255, 140, 1); }
|
||||
100% { background-color: rgba(0, 0, 0, 0); }
|
||||
}
|
||||
|
||||
@@ -34,12 +34,12 @@ if(!\OC\Files\Filesystem::file_exists($filename)) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$ftype=\OC\Files\Filesystem::getMimeType( $filename );
|
||||
$ftype=\OC_Helper::getSecureMimeType(\OC\Files\Filesystem::getMimeType( $filename ));
|
||||
|
||||
header('Content-Type:'.$ftype);
|
||||
OCP\Response::setContentDispositionHeader(basename($filename), 'attachment');
|
||||
OCP\Response::disableCaching();
|
||||
header('Content-Length: '.\OC\Files\Filesystem::filesize($filename));
|
||||
OCP\Response::setContentLengthHeader(\OC\Files\Filesystem::filesize($filename));
|
||||
|
||||
OC_Util::obEnd();
|
||||
\OC\Files\Filesystem::readfile( $filename );
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
initialize: function() {
|
||||
this.navigation = new OCA.Files.Navigation($('#app-navigation'));
|
||||
|
||||
var urlParams = OC.Util.History.parseUrlQuery();
|
||||
var fileActions = new OCA.Files.FileActions();
|
||||
// default actions
|
||||
fileActions.registerDefaultActions();
|
||||
@@ -47,7 +48,8 @@
|
||||
dragOptions: dragOptions,
|
||||
folderDropOptions: folderDropOptions,
|
||||
fileActions: fileActions,
|
||||
allowLegacyActions: true
|
||||
allowLegacyActions: true,
|
||||
scrollTo: urlParams.scrollto
|
||||
}
|
||||
);
|
||||
this.files.initialize();
|
||||
@@ -58,7 +60,7 @@
|
||||
|
||||
this._setupEvents();
|
||||
// trigger URL change event handlers
|
||||
this._onPopState(OC.Util.History.parseUrlQuery());
|
||||
this._onPopState(urlParams);
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -427,6 +427,14 @@ OC.Upload = {
|
||||
data.textStatus = 'servererror';
|
||||
data.errorThrown = result[0].data.message; // error message has been translated on server
|
||||
fu._trigger('fail', e, data);
|
||||
} else { // Successful upload
|
||||
// Checking that the uploaded file is the last one and contained in the current directory
|
||||
if (data.files[0] === data.originalFiles[data.originalFiles.length - 1] &&
|
||||
result[0].directory === FileList.getCurrentDirectory()) {
|
||||
// Scroll to the last uploaded file and highlight all of them
|
||||
var fileList = _.pluck(data.originalFiles, 'name');
|
||||
FileList.highlightFiles(fileList);
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
@@ -482,6 +490,21 @@ OC.Upload = {
|
||||
}
|
||||
});
|
||||
|
||||
} else {
|
||||
// for all browsers that don't support the progress bar
|
||||
// IE 8 & 9
|
||||
|
||||
// show a spinner
|
||||
fileupload.on('fileuploadstart', function() {
|
||||
$('#upload').addClass('icon-loading');
|
||||
$('#upload .icon-upload').hide();
|
||||
});
|
||||
|
||||
// hide a spinner
|
||||
fileupload.on('fileuploadstop fileuploadfail', function() {
|
||||
$('#upload').removeClass('icon-loading');
|
||||
$('#upload .icon-upload').show();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -621,7 +644,7 @@ OC.Upload = {
|
||||
},
|
||||
function(result) {
|
||||
if (result.status === 'success') {
|
||||
FileList.add(result.data, {hidden: hidden, animate: true});
|
||||
FileList.add(result.data, {hidden: hidden, animate: true, scrollTo: true});
|
||||
} else {
|
||||
OC.dialogs.alert(result.data.message, t('core', 'Could not create file'));
|
||||
}
|
||||
@@ -637,7 +660,7 @@ OC.Upload = {
|
||||
},
|
||||
function(result) {
|
||||
if (result.status === 'success') {
|
||||
FileList.add(result.data, {hidden: hidden, animate: true});
|
||||
FileList.add(result.data, {hidden: hidden, animate: true, scrollTo: true});
|
||||
} else {
|
||||
OC.dialogs.alert(result.data.message, t('core', 'Could not create folder'));
|
||||
}
|
||||
|
||||
+125
-21
@@ -49,8 +49,10 @@
|
||||
fileSummary: null,
|
||||
initialized: false,
|
||||
|
||||
// number of files per page
|
||||
pageSize: 20,
|
||||
// number of files per page, calculated dynamically
|
||||
pageSize: function() {
|
||||
return Math.ceil(this.$container.height() / 50);
|
||||
},
|
||||
|
||||
/**
|
||||
* Array of files in the current folder.
|
||||
@@ -103,9 +105,10 @@
|
||||
* @param $el container element with existing markup for the #controls
|
||||
* and a table
|
||||
* @param options map of options, see other parameters
|
||||
* @param scrollContainer scrollable container, defaults to $(window)
|
||||
* @param dragOptions drag options, disabled by default
|
||||
* @param folderDropOptions folder drop options, disabled by default
|
||||
* @param options.scrollContainer scrollable container, defaults to $(window)
|
||||
* @param options.dragOptions drag options, disabled by default
|
||||
* @param options.folderDropOptions folder drop options, disabled by default
|
||||
* @param options.scrollTo name of file to scroll to after the first load
|
||||
*/
|
||||
initialize: function($el, options) {
|
||||
var self = this;
|
||||
@@ -165,6 +168,12 @@
|
||||
this.setupUploadEvents();
|
||||
|
||||
this.$container.on('scroll', _.bind(this._onScroll, this));
|
||||
|
||||
if (options.scrollTo) {
|
||||
this.$fileList.one('updated', function() {
|
||||
self.scrollTo(options.scrollTo);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -472,7 +481,8 @@
|
||||
mimetype: $el.attr('data-mime'),
|
||||
type: $el.attr('data-type'),
|
||||
size: parseInt($el.attr('data-size'), 10),
|
||||
etag: $el.attr('data-etag')
|
||||
etag: $el.attr('data-etag'),
|
||||
permissions: parseInt($el.attr('data-permissions'), 10)
|
||||
};
|
||||
},
|
||||
|
||||
@@ -483,7 +493,7 @@
|
||||
*/
|
||||
_nextPage: function(animate) {
|
||||
var index = this.$fileList.children().length,
|
||||
count = this.pageSize,
|
||||
count = this.pageSize(),
|
||||
tr,
|
||||
fileData,
|
||||
newTrs = [],
|
||||
@@ -709,9 +719,10 @@
|
||||
*
|
||||
* @param fileData map of file attributes
|
||||
* @param options map of attributes:
|
||||
* - "updateSummary": true to update the summary after adding (default), false otherwise
|
||||
* - "silent": true to prevent firing events like "fileActionsReady"
|
||||
* - "animate": true to animate preview loading (defaults to true here)
|
||||
* @param options.updateSummary true to update the summary after adding (default), false otherwise
|
||||
* @param options.silent true to prevent firing events like "fileActionsReady"
|
||||
* @param options.animate true to animate preview loading (defaults to true here)
|
||||
* @param options.scrollTo true to automatically scroll to the file's location
|
||||
* @return new tr element (not appended to the table)
|
||||
*/
|
||||
add: function(fileData, options) {
|
||||
@@ -760,6 +771,10 @@
|
||||
});
|
||||
}
|
||||
|
||||
if (options.scrollTo) {
|
||||
this.scrollTo(fileData.name);
|
||||
}
|
||||
|
||||
// defaults to true if not defined
|
||||
if (typeof(options.updateSummary) === 'undefined' || !!options.updateSummary) {
|
||||
this.fileSummary.add(fileData, true);
|
||||
@@ -1155,7 +1170,7 @@
|
||||
// if there are less elements visible than one page
|
||||
// but there are still pending elements in the array,
|
||||
// then directly append the next page
|
||||
if (lastIndex < this.files.length && lastIndex < this.pageSize) {
|
||||
if (lastIndex < this.files.length && lastIndex < this.pageSize()) {
|
||||
this._nextPage(true);
|
||||
}
|
||||
|
||||
@@ -1507,16 +1522,15 @@
|
||||
this.$table.removeClass('hidden');
|
||||
},
|
||||
scrollTo:function(file) {
|
||||
//scroll to and highlight preselected file
|
||||
var $scrollToRow = this.findFileEl(file);
|
||||
if ($scrollToRow.exists()) {
|
||||
$scrollToRow.addClass('searchresult');
|
||||
$(window).scrollTop($scrollToRow.position().top);
|
||||
//remove highlight when hovered over
|
||||
$scrollToRow.one('hover', function() {
|
||||
$scrollToRow.removeClass('searchresult');
|
||||
});
|
||||
if (!_.isArray(file)) {
|
||||
file = [file];
|
||||
}
|
||||
this.highlightFiles(file, function($tr) {
|
||||
$tr.addClass('searchresult');
|
||||
$tr.one('hover', function() {
|
||||
$tr.removeClass('searchresult');
|
||||
});
|
||||
});
|
||||
},
|
||||
filter:function(query) {
|
||||
this.$fileList.find('tr').each(function(i,e) {
|
||||
@@ -1551,7 +1565,7 @@
|
||||
this.$el.find('.selectedActions').addClass('hidden');
|
||||
}
|
||||
else {
|
||||
canDelete = (this.getDirectoryPermissions() & OC.PERMISSION_DELETE);
|
||||
canDelete = (this.getDirectoryPermissions() & OC.PERMISSION_DELETE) && this.isSelectedDeletable();
|
||||
this.$el.find('.selectedActions').removeClass('hidden');
|
||||
this.$el.find('#headerSize a>span:first').text(OC.Util.humanFileSize(summary.totalSize));
|
||||
var selection = '';
|
||||
@@ -1571,6 +1585,15 @@
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Check whether all selected files are deletable
|
||||
*/
|
||||
isSelectedDeletable: function() {
|
||||
return _.reduce(this.getSelectedFiles(), function(deletable, file) {
|
||||
return deletable && (file.permissions & OC.PERMISSION_DELETE);
|
||||
}, true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns whether all files are selected
|
||||
* @return true if all files are selected, false otherwise
|
||||
@@ -1615,6 +1638,18 @@
|
||||
return name;
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows a "permission denied" notification
|
||||
*/
|
||||
_showPermissionDeniedNotification: function() {
|
||||
var message = t('core', 'You don’t have permission to upload or create files here');
|
||||
OC.Notification.show(message);
|
||||
//hide notification after 10 sec
|
||||
setTimeout(function() {
|
||||
OC.Notification.hide();
|
||||
}, 5000);
|
||||
},
|
||||
|
||||
/**
|
||||
* Setup file upload events related to the file-upload plugin
|
||||
*/
|
||||
@@ -1646,6 +1681,12 @@
|
||||
// remember as context
|
||||
data.context = dropTarget;
|
||||
|
||||
// if permissions are specified, only allow if create permission is there
|
||||
var permissions = dropTarget.data('permissions');
|
||||
if (!_.isUndefined(permissions) && (permissions & OC.PERMISSION_CREATE) === 0) {
|
||||
self._showPermissionDeniedNotification();
|
||||
return false;
|
||||
}
|
||||
var dir = dropTarget.data('file');
|
||||
// if from file list, need to prepend parent dir
|
||||
if (dir) {
|
||||
@@ -1670,6 +1711,7 @@
|
||||
// cancel uploads to current dir if no permission
|
||||
var isCreatable = (self.getDirectoryPermissions() & OC.PERMISSION_CREATE) !== 0;
|
||||
if (!isCreatable) {
|
||||
self._showPermissionDeniedNotification();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1840,6 +1882,68 @@
|
||||
self.updateStorageStatistics();
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Scroll to the last file of the given list
|
||||
* Highlight the list of files
|
||||
* @param files array of filenames,
|
||||
* @param {Function} [highlightFunction] optional function
|
||||
* to be called after the scrolling is finished
|
||||
*/
|
||||
highlightFiles: function(files, highlightFunction) {
|
||||
// Detection of the uploaded element
|
||||
var filename = files[files.length - 1];
|
||||
var $fileRow = this.findFileEl(filename);
|
||||
|
||||
while(!$fileRow.exists() && this._nextPage(false) !== false) { // Checking element existence
|
||||
$fileRow = this.findFileEl(filename);
|
||||
}
|
||||
|
||||
if (!$fileRow.exists()) { // Element not present in the file list
|
||||
return;
|
||||
}
|
||||
|
||||
var currentOffset = this.$container.scrollTop();
|
||||
var additionalOffset = this.$el.find("#controls").height()+this.$el.find("#controls").offset().top;
|
||||
|
||||
// Animation
|
||||
var _this = this;
|
||||
var $scrollContainer = this.$container;
|
||||
if ($scrollContainer[0] === window) {
|
||||
// need to use "body" to animate scrolling
|
||||
// when the scroll container is the window
|
||||
$scrollContainer = $('body');
|
||||
}
|
||||
$scrollContainer.animate({
|
||||
// Scrolling to the top of the new element
|
||||
scrollTop: currentOffset + $fileRow.offset().top - $fileRow.height() * 2 - additionalOffset
|
||||
}, {
|
||||
duration: 500,
|
||||
complete: function() {
|
||||
// Highlighting function
|
||||
var highlightRow = highlightFunction;
|
||||
|
||||
if (!highlightRow) {
|
||||
highlightRow = function($fileRow) {
|
||||
$fileRow.addClass("highlightUploaded");
|
||||
setTimeout(function() {
|
||||
$fileRow.removeClass("highlightUploaded");
|
||||
}, 2500);
|
||||
};
|
||||
}
|
||||
|
||||
// Loop over uploaded files
|
||||
for(var i=0; i<files.length; i++) {
|
||||
var $fileRow = _this.findFileEl(files[i]);
|
||||
|
||||
if($fileRow.length !== 0) { // Checking element existence
|
||||
highlightRow($fileRow);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -350,7 +350,7 @@ var createDragShadow = function(event) {
|
||||
}
|
||||
|
||||
// do not show drag shadow for too many files
|
||||
var selectedFiles = _.first(FileList.getSelectedFiles(), FileList.pageSize);
|
||||
var selectedFiles = _.first(FileList.getSelectedFiles(), FileList.pageSize());
|
||||
selectedFiles = _.sortBy(selectedFiles, FileList._fileInfoCompare);
|
||||
|
||||
if (!isDragSelected && selectedFiles.length === 1) {
|
||||
@@ -433,7 +433,12 @@ var folderDropOptions = {
|
||||
return false;
|
||||
}
|
||||
|
||||
var targetPath = FileList.getCurrentDirectory() + '/' + $(this).closest('tr').data('file');
|
||||
var $tr = $(this).closest('tr');
|
||||
if (($tr.data('permissions') & OC.PERMISSION_CREATE) === 0) {
|
||||
FileList._showPermissionDeniedNotification();
|
||||
return false;
|
||||
}
|
||||
var targetPath = FileList.getCurrentDirectory() + '/' + $tr.data('file');
|
||||
|
||||
var files = FileList.getSelectedFiles();
|
||||
if (files.length === 0) {
|
||||
|
||||
@@ -17,7 +17,7 @@ $TRANSLATIONS = array(
|
||||
"Invalid Token" => "Jeton non valide",
|
||||
"No file was uploaded. Unknown error" => "Aucun fichier n'a été envoyé. Erreur inconnue",
|
||||
"There is no error, the file uploaded with success" => "Aucune erreur, le fichier a été envoyé avec succès.",
|
||||
"The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "Le fichier envoyé dépasse l'instruction upload_max_filesize située dans le fichier php.ini:",
|
||||
"The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "Le fichier envoyé dépasse l'instruction upload_max_filesize située dans le fichier php.ini :",
|
||||
"The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Le fichier envoyé dépasse l'instruction MAX_FILE_SIZE qui est spécifiée dans le formulaire HTML.",
|
||||
"The uploaded file was only partially uploaded" => "Le fichier n'a été que partiellement envoyé.",
|
||||
"No file was uploaded" => "Pas de fichier envoyé.",
|
||||
@@ -62,7 +62,7 @@ $TRANSLATIONS = array(
|
||||
"Your storage is almost full ({usedSpacePercent}%)" => "Votre espace de stockage est presque plein ({usedSpacePercent}%)",
|
||||
"Encryption App is enabled but your keys are not initialized, please log-out and log-in again" => "L'application de chiffrement est activée mais vos clés ne sont pas initialisées, veuillez vous déconnecter et ensuite vous reconnecter.",
|
||||
"Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." => "Votre clef privée pour l'application de chiffrement est invalide ! Veuillez mettre à jour le mot de passe de votre clef privée dans vos paramètres personnels pour récupérer l'accès à vos fichiers chiffrés.",
|
||||
"Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Le chiffrement était désactivé mais vos fichiers sont toujours chiffrés. Veuillez vous rendre sur vos Paramètres personnels pour déchiffrer vos fichiers.",
|
||||
"Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Le chiffrement a été désactivé mais vos fichiers sont toujours chiffrés. Veuillez vous rendre sur vos paramètres personnels pour déchiffrer vos fichiers.",
|
||||
"{dirs} and {files}" => "{dirs} et {files}",
|
||||
"%s could not be renamed" => "%s ne peut être renommé",
|
||||
"Upload (max. %s)" => "Envoi (max. %s)",
|
||||
@@ -77,13 +77,13 @@ $TRANSLATIONS = array(
|
||||
"Text file" => "Fichier texte",
|
||||
"New folder" => "Nouveau dossier",
|
||||
"Folder" => "Dossier",
|
||||
"From link" => "Depuis le lien",
|
||||
"From link" => "Depuis un lien",
|
||||
"You don’t have permission to upload or create files here" => "Vous n'avez pas la permission de téléverser ou de créer des fichiers ici",
|
||||
"Nothing in here. Upload something!" => "Il n'y a rien ici ! Envoyez donc quelque chose :)",
|
||||
"Download" => "Télécharger",
|
||||
"Upload too large" => "Téléversement trop volumineux",
|
||||
"The files you are trying to upload exceed the maximum size for file uploads on this server." => "Les fichiers que vous essayez d'envoyer dépassent la taille maximale permise par ce serveur.",
|
||||
"Files are being scanned, please wait." => "Les fichiers sont en cours d'analyse, veuillez patienter.",
|
||||
"Currently scanning" => "Analyse en cours de traitement"
|
||||
"Currently scanning" => "Analyse en cours",
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=2; plural=(n > 1);";
|
||||
|
||||
@@ -93,7 +93,7 @@ class Helper
|
||||
public static function compareSize($a, $b) {
|
||||
$aSize = $a->getSize();
|
||||
$bSize = $b->getSize();
|
||||
return $aSize - $bSize;
|
||||
return ($aSize < $bSize) ? -1 : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -34,7 +34,14 @@ class Test_OC_Files_App_Rename extends \PHPUnit_Framework_TestCase {
|
||||
*/
|
||||
private $files;
|
||||
|
||||
function setUp() {
|
||||
/** @var \OC\Files\Storage\Storage */
|
||||
private $originalStorage;
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->originalStorage = \OC\Files\Filesystem::getStorage('/');
|
||||
|
||||
// mock OC_L10n
|
||||
if (!self::$user) {
|
||||
self::$user = uniqid();
|
||||
@@ -59,10 +66,13 @@ class Test_OC_Files_App_Rename extends \PHPUnit_Framework_TestCase {
|
||||
$this->files = new \OCA\Files\App($viewMock, $l10nMock);
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
protected function tearDown() {
|
||||
$result = \OC_User::deleteUser(self::$user);
|
||||
$this->assertTrue($result);
|
||||
\OC\Files\Filesystem::tearDown();
|
||||
\OC\Files\Filesystem::mount($this->originalStorage, array(), '/');
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
*/
|
||||
|
||||
describe('OCA.Files.FileList tests', function() {
|
||||
var testFiles, alertStub, notificationStub, fileList;
|
||||
var testFiles, alertStub, notificationStub, fileList, pageSizeStub;
|
||||
var bcResizeStub;
|
||||
|
||||
/**
|
||||
@@ -97,7 +97,8 @@ describe('OCA.Files.FileList tests', function() {
|
||||
name: 'One.txt',
|
||||
mimetype: 'text/plain',
|
||||
size: 12,
|
||||
etag: 'abc'
|
||||
etag: 'abc',
|
||||
permissions: OC.PERMISSION_ALL
|
||||
}, {
|
||||
id: 2,
|
||||
type: 'file',
|
||||
@@ -105,6 +106,7 @@ describe('OCA.Files.FileList tests', function() {
|
||||
mimetype: 'image/jpeg',
|
||||
size: 12049,
|
||||
etag: 'def',
|
||||
permissions: OC.PERMISSION_ALL
|
||||
}, {
|
||||
id: 3,
|
||||
type: 'file',
|
||||
@@ -112,15 +114,17 @@ describe('OCA.Files.FileList tests', function() {
|
||||
mimetype: 'application/pdf',
|
||||
size: 58009,
|
||||
etag: '123',
|
||||
permissions: OC.PERMISSION_ALL
|
||||
}, {
|
||||
id: 4,
|
||||
type: 'dir',
|
||||
name: 'somedir',
|
||||
mimetype: 'httpd/unix-directory',
|
||||
size: 250,
|
||||
etag: '456'
|
||||
etag: '456',
|
||||
permissions: OC.PERMISSION_ALL
|
||||
}];
|
||||
|
||||
pageSizeStub = sinon.stub(OCA.Files.FileList.prototype, 'pageSize').returns(20);
|
||||
fileList = new OCA.Files.FileList($('#app-content-files'));
|
||||
});
|
||||
afterEach(function() {
|
||||
@@ -130,6 +134,7 @@ describe('OCA.Files.FileList tests', function() {
|
||||
notificationStub.restore();
|
||||
alertStub.restore();
|
||||
bcResizeStub.restore();
|
||||
pageSizeStub.restore();
|
||||
});
|
||||
describe('Getters', function() {
|
||||
it('Returns the current directory', function() {
|
||||
@@ -218,13 +223,13 @@ describe('OCA.Files.FileList tests', function() {
|
||||
|
||||
expect($tr).toBeDefined();
|
||||
expect($tr[0].tagName.toLowerCase()).toEqual('tr');
|
||||
expect($tr.attr('data-id')).toEqual(null);
|
||||
expect($tr.attr('data-id')).toBeUndefined();
|
||||
expect($tr.attr('data-type')).toEqual('file');
|
||||
expect($tr.attr('data-file')).toEqual('testFile.txt');
|
||||
expect($tr.attr('data-size')).toEqual(null);
|
||||
expect($tr.attr('data-etag')).toEqual(null);
|
||||
expect($tr.attr('data-size')).toBeUndefined();
|
||||
expect($tr.attr('data-etag')).toBeUndefined();
|
||||
expect($tr.attr('data-permissions')).toEqual('31');
|
||||
expect($tr.attr('data-mime')).toEqual(null);
|
||||
expect($tr.attr('data-mime')).toBeUndefined();
|
||||
expect($tr.attr('data-mtime')).toEqual('123456');
|
||||
|
||||
expect($tr.find('.filesize').text()).toEqual('Pending');
|
||||
@@ -239,11 +244,11 @@ describe('OCA.Files.FileList tests', function() {
|
||||
|
||||
expect($tr).toBeDefined();
|
||||
expect($tr[0].tagName.toLowerCase()).toEqual('tr');
|
||||
expect($tr.attr('data-id')).toEqual(null);
|
||||
expect($tr.attr('data-id')).toBeUndefined();
|
||||
expect($tr.attr('data-type')).toEqual('dir');
|
||||
expect($tr.attr('data-file')).toEqual('testFolder');
|
||||
expect($tr.attr('data-size')).toEqual(null);
|
||||
expect($tr.attr('data-etag')).toEqual(null);
|
||||
expect($tr.attr('data-size')).toBeUndefined();
|
||||
expect($tr.attr('data-etag')).toBeUndefined();
|
||||
expect($tr.attr('data-permissions')).toEqual('31');
|
||||
expect($tr.attr('data-mime')).toEqual('httpd/unix-directory');
|
||||
expect($tr.attr('data-mtime')).toEqual('123456');
|
||||
@@ -814,7 +819,7 @@ describe('OCA.Files.FileList tests', function() {
|
||||
fileList.$fileList.on('fileActionsReady', handler);
|
||||
fileList._nextPage();
|
||||
expect(handler.calledOnce).toEqual(true);
|
||||
expect(handler.getCall(0).args[0].$files.length).toEqual(fileList.pageSize);
|
||||
expect(handler.getCall(0).args[0].$files.length).toEqual(fileList.pageSize());
|
||||
});
|
||||
it('does not trigger "fileActionsReady" event after single add with silent argument', function() {
|
||||
var handler = sinon.stub();
|
||||
@@ -1478,6 +1483,17 @@ describe('OCA.Files.FileList tests', function() {
|
||||
$('.select-all').click();
|
||||
expect(fileList.$el.find('.delete-selected').hasClass('hidden')).toEqual(true);
|
||||
});
|
||||
it('show doesnt show the delete action if one or more files are not deletable', function () {
|
||||
fileList.setFiles(testFiles);
|
||||
$('#permissions').val(OC.PERMISSION_READ | OC.PERMISSION_DELETE);
|
||||
$('.select-all').click();
|
||||
expect(fileList.$el.find('.delete-selected').hasClass('hidden')).toEqual(false);
|
||||
testFiles[0].permissions = OC.PERMISSION_READ;
|
||||
$('.select-all').click();
|
||||
fileList.setFiles(testFiles);
|
||||
$('.select-all').click();
|
||||
expect(fileList.$el.find('.delete-selected').hasClass('hidden')).toEqual(true);
|
||||
});
|
||||
});
|
||||
describe('Actions', function() {
|
||||
beforeEach(function() {
|
||||
@@ -1494,7 +1510,8 @@ describe('OCA.Files.FileList tests', function() {
|
||||
mimetype: 'text/plain',
|
||||
type: 'file',
|
||||
size: 12,
|
||||
etag: 'abc'
|
||||
etag: 'abc',
|
||||
permissions: OC.PERMISSION_ALL
|
||||
});
|
||||
expect(files[1]).toEqual({
|
||||
id: 3,
|
||||
@@ -1502,7 +1519,8 @@ describe('OCA.Files.FileList tests', function() {
|
||||
name: 'Three.pdf',
|
||||
mimetype: 'application/pdf',
|
||||
size: 58009,
|
||||
etag: '123'
|
||||
etag: '123',
|
||||
permissions: OC.PERMISSION_ALL
|
||||
});
|
||||
expect(files[2]).toEqual({
|
||||
id: 4,
|
||||
@@ -1510,7 +1528,8 @@ describe('OCA.Files.FileList tests', function() {
|
||||
name: 'somedir',
|
||||
mimetype: 'httpd/unix-directory',
|
||||
size: 250,
|
||||
etag: '456'
|
||||
etag: '456',
|
||||
permissions: OC.PERMISSION_ALL
|
||||
});
|
||||
});
|
||||
it('Removing a file removes it from the selection', function() {
|
||||
@@ -1523,7 +1542,8 @@ describe('OCA.Files.FileList tests', function() {
|
||||
mimetype: 'text/plain',
|
||||
type: 'file',
|
||||
size: 12,
|
||||
etag: 'abc'
|
||||
etag: 'abc',
|
||||
permissions: OC.PERMISSION_ALL
|
||||
});
|
||||
expect(files[1]).toEqual({
|
||||
id: 4,
|
||||
@@ -1531,7 +1551,8 @@ describe('OCA.Files.FileList tests', function() {
|
||||
name: 'somedir',
|
||||
mimetype: 'httpd/unix-directory',
|
||||
size: 250,
|
||||
etag: '456'
|
||||
etag: '456',
|
||||
permissions: OC.PERMISSION_ALL
|
||||
});
|
||||
});
|
||||
describe('Download', function() {
|
||||
@@ -1835,7 +1856,6 @@ describe('OCA.Files.FileList tests', function() {
|
||||
// but it makes it possible to simulate the event triggering to
|
||||
// test the response of the handlers
|
||||
$uploader = $('#file_upload_start');
|
||||
fileList.setupUploadEvents();
|
||||
fileList.setFiles(testFiles);
|
||||
});
|
||||
|
||||
@@ -1912,6 +1932,16 @@ describe('OCA.Files.FileList tests', function() {
|
||||
ev = dropOn(fileList.$fileList.find('th:first'));
|
||||
|
||||
expect(ev.result).toEqual(false);
|
||||
expect(notificationStub.calledOnce).toEqual(true);
|
||||
});
|
||||
it('drop on an folder does not trigger upload if no upload permission on that folder', function() {
|
||||
var $tr = fileList.findFileEl('somedir');
|
||||
var ev;
|
||||
$tr.data('permissions', OC.PERMISSION_READ);
|
||||
ev = dropOn($tr);
|
||||
|
||||
expect(ev.result).toEqual(false);
|
||||
expect(notificationStub.calledOnce).toEqual(true);
|
||||
});
|
||||
it('drop on a file row inside the table triggers upload to current folder', function() {
|
||||
var ev;
|
||||
|
||||
@@ -16,8 +16,28 @@ use OCA\Encryption;
|
||||
$l = OC_L10N::get('files_encryption');
|
||||
|
||||
$return = false;
|
||||
// Enable recoveryAdmin
|
||||
$errorMessage = $l->t("Unknown error");
|
||||
|
||||
//check if both passwords are the same
|
||||
if (empty($_POST['recoveryPassword'])) {
|
||||
$errorMessage = $l->t('Missing recovery key password');
|
||||
\OCP\JSON::error(array('data' => array('message' => $errorMessage)));
|
||||
exit();
|
||||
}
|
||||
|
||||
if (empty($_POST['confirmPassword'])) {
|
||||
$errorMessage = $l->t('Please repeat the recovery key password');
|
||||
\OCP\JSON::error(array('data' => array('message' => $errorMessage)));
|
||||
exit();
|
||||
}
|
||||
|
||||
if ($_POST['recoveryPassword'] !== $_POST['confirmPassword']) {
|
||||
$errorMessage = $l->t('Repeated recovery key password does not match the provided recovery key password');
|
||||
\OCP\JSON::error(array('data' => array('message' => $errorMessage)));
|
||||
exit();
|
||||
}
|
||||
|
||||
// Enable recoveryAdmin
|
||||
$recoveryKeyId = \OC::$server->getAppConfig()->getValue('files_encryption', 'recoveryKeyId');
|
||||
|
||||
if (isset($_POST['adminEnableRecovery']) && $_POST['adminEnableRecovery'] === '1') {
|
||||
@@ -26,14 +46,9 @@ if (isset($_POST['adminEnableRecovery']) && $_POST['adminEnableRecovery'] === '1
|
||||
|
||||
// Return success or failure
|
||||
if ($return) {
|
||||
\OCP\JSON::success(array('data' => array('message' => $l->t('Recovery key successfully enabled'))));
|
||||
$successMessage = $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!')
|
||||
)
|
||||
));
|
||||
$errorMessage = $l->t('Could not disable recovery key. Please check your recovery key password!');
|
||||
}
|
||||
|
||||
// Disable recoveryAdmin
|
||||
@@ -43,17 +58,16 @@ if (isset($_POST['adminEnableRecovery']) && $_POST['adminEnableRecovery'] === '1
|
||||
) {
|
||||
$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'))));
|
||||
$successMessage = $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!')
|
||||
)
|
||||
));
|
||||
$errorMessage = $l->t('Could not disable recovery key. Please check your recovery key password!');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Return success or failure
|
||||
if ($return) {
|
||||
\OCP\JSON::success(array('data' => array('message' => $successMessage)));
|
||||
} else {
|
||||
\OCP\JSON::error(array('data' => array('message' => $errorMessage)));
|
||||
}
|
||||
|
||||
@@ -21,6 +21,32 @@ $return = false;
|
||||
|
||||
$oldPassword = $_POST['oldPassword'];
|
||||
$newPassword = $_POST['newPassword'];
|
||||
$confirmPassword = $_POST['confirmPassword'];
|
||||
|
||||
//check if both passwords are the same
|
||||
if (empty($_POST['oldPassword'])) {
|
||||
$errorMessage = $l->t('Please provide the old recovery password');
|
||||
\OCP\JSON::error(array('data' => array('message' => $errorMessage)));
|
||||
exit();
|
||||
}
|
||||
|
||||
if (empty($_POST['newPassword'])) {
|
||||
$errorMessage = $l->t('Please provide a new recovery password');
|
||||
\OCP\JSON::error(array('data' => array('message' => $errorMessage)));
|
||||
exit();
|
||||
}
|
||||
|
||||
if (empty($_POST['confirmPassword'])) {
|
||||
$errorMessage = $l->t('Please repeat the new recovery password');
|
||||
\OCP\JSON::error(array('data' => array('message' => $errorMessage)));
|
||||
exit();
|
||||
}
|
||||
|
||||
if ($_POST['newPassword'] !== $_POST['confirmPassword']) {
|
||||
$errorMessage = $l->t('Repeated recovery key password does not match the provided recovery key password');
|
||||
\OCP\JSON::error(array('data' => array('message' => $errorMessage)));
|
||||
exit();
|
||||
}
|
||||
|
||||
$view = new \OC\Files\View('/');
|
||||
$util = new \OCA\Encryption\Util(new \OC\Files\View('/'), \OCP\User::getUser());
|
||||
|
||||
@@ -18,6 +18,7 @@ use OCA\Encryption;
|
||||
$l = OC_L10N::get('core');
|
||||
|
||||
$return = false;
|
||||
$errorMessage = $l->t('Could not update the private key password.');
|
||||
|
||||
$oldPassword = $_POST['oldPassword'];
|
||||
$newPassword = $_POST['newPassword'];
|
||||
@@ -25,31 +26,45 @@ $newPassword = $_POST['newPassword'];
|
||||
$view = new \OC\Files\View('/');
|
||||
$session = new \OCA\Encryption\Session($view);
|
||||
$user = \OCP\User::getUser();
|
||||
$loginName = \OC::$server->getUserSession()->getLoginName();
|
||||
|
||||
$proxyStatus = \OC_FileProxy::$enabled;
|
||||
\OC_FileProxy::$enabled = false;
|
||||
// check new password
|
||||
$passwordCorrect = \OCP\User::checkPassword($loginName, $newPassword);
|
||||
|
||||
$keyPath = '/' . $user . '/files_encryption/' . $user . '.private.key';
|
||||
if ($passwordCorrect !== false) {
|
||||
|
||||
$encryptedKey = $view->file_get_contents($keyPath);
|
||||
$decryptedKey = \OCA\Encryption\Crypt::decryptPrivateKey($encryptedKey, $oldPassword);
|
||||
$proxyStatus = \OC_FileProxy::$enabled;
|
||||
\OC_FileProxy::$enabled = false;
|
||||
|
||||
if ($decryptedKey) {
|
||||
$cipher = \OCA\Encryption\Helper::getCipher();
|
||||
$encryptedKey = \OCA\Encryption\Crypt::symmetricEncryptFileContent($decryptedKey, $newPassword, $cipher);
|
||||
if ($encryptedKey) {
|
||||
\OCA\Encryption\Keymanager::setPrivateKey($encryptedKey, $user);
|
||||
$session->setPrivateKey($decryptedKey);
|
||||
$return = true;
|
||||
$keyPath = '/' . $user . '/files_encryption/' . $user . '.private.key';
|
||||
|
||||
$encryptedKey = $view->file_get_contents($keyPath);
|
||||
$decryptedKey = \OCA\Encryption\Crypt::decryptPrivateKey($encryptedKey, $oldPassword);
|
||||
|
||||
if ($decryptedKey) {
|
||||
$cipher = \OCA\Encryption\Helper::getCipher();
|
||||
$encryptedKey = \OCA\Encryption\Crypt::symmetricEncryptFileContent($decryptedKey, $newPassword, $cipher);
|
||||
if ($encryptedKey) {
|
||||
\OCA\Encryption\Keymanager::setPrivateKey($encryptedKey, $user);
|
||||
$session->setPrivateKey($decryptedKey);
|
||||
$return = true;
|
||||
}
|
||||
} else {
|
||||
$result = false;
|
||||
$errorMessage = $l->t('The old password was not correct, please try again.');
|
||||
}
|
||||
}
|
||||
|
||||
\OC_FileProxy::$enabled = $proxyStatus;
|
||||
\OC_FileProxy::$enabled = $proxyStatus;
|
||||
|
||||
} else {
|
||||
$result = false;
|
||||
$errorMessage = $l->t('The current log-in password was not correct, please try again.');
|
||||
}
|
||||
|
||||
// success or failure
|
||||
if ($return) {
|
||||
$session->setInitialized(\OCA\Encryption\Session::INIT_SUCCESSFUL);
|
||||
\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.'))));
|
||||
\OCP\JSON::error(array('data' => array('message' => $errorMessage)));
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ use OCA\Encryption;
|
||||
\OCP\JSON::checkAppEnabled('files_encryption');
|
||||
\OCP\JSON::callCheck();
|
||||
|
||||
$l = \OC::$server->getL10N('files_encryption');
|
||||
|
||||
if (
|
||||
isset($_POST['userEnableRecovery'])
|
||||
&& (0 == $_POST['userEnableRecovery'] || '1' === $_POST['userEnableRecovery'])
|
||||
@@ -38,4 +40,8 @@ if (
|
||||
}
|
||||
|
||||
// Return success or failure
|
||||
($return) ? \OCP\JSON::success() : \OCP\JSON::error();
|
||||
if ($return) {
|
||||
\OCP\JSON::success(array('data' => array('message' => $l->t('File recovery settings updated'))));
|
||||
} else {
|
||||
\OCP\JSON::error(array('data' => array('message' => $l->t('Could not update file recovery'))));
|
||||
}
|
||||
|
||||
@@ -35,22 +35,6 @@ if (!OC_Config::getValue('maintenance', false)) {
|
||||
if(!in_array('crypt', stream_get_wrappers())) {
|
||||
stream_wrapper_register('crypt', 'OCA\Encryption\Stream');
|
||||
}
|
||||
|
||||
// check if we are logged in
|
||||
if (OCP\User::isLoggedIn()) {
|
||||
|
||||
// ensure filesystem is loaded
|
||||
if (!\OC\Files\Filesystem::$loaded) {
|
||||
\OC_Util::setupFS();
|
||||
}
|
||||
|
||||
$view = new OC\Files\View('/');
|
||||
|
||||
$sessionReady = OCA\Encryption\Helper::checkRequirements();
|
||||
if($sessionReady) {
|
||||
$session = new \OCA\Encryption\Session($view);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// logout user if we are in maintenance to force re-login
|
||||
OCP\User::logout();
|
||||
|
||||
@@ -2,14 +2,18 @@
|
||||
<info>
|
||||
<id>files_encryption</id>
|
||||
<name>Encryption</name>
|
||||
<description>The ownCloud files encryption system provides server side-encryption. After the app is enabled you need to re-login to initialize your encryption keys. Please note that server side encryption requires that the ownCloud server admin can be trusted. The main purpose of this app is the encryption of files that are stored on externally mounted storages.</description>
|
||||
<description>
|
||||
This application encrypts all files accessed by ownCloud at rest, wherever they are stored. As an example, with this application enabled, external cloud based Amazon S3 storage will be encrypted, protecting this data on storage outside of the control of the Admin. When this application is enabled for the first time, all files are encrypted as users log in and are prompted for their password. The recommended recovery key option enables recovery of files in case the key is lost.
|
||||
Note that this app encrypts all files that are touched by ownCloud, so external storage providers and applications such as SharePoint will see new files encrypted when they are accessed. Encryption is based on AES 128 or 256 bit keys. More information is available in the Encryption documentation.
|
||||
|
||||
</description>
|
||||
<licence>AGPL</licence>
|
||||
<author>Sam Tuke, Bjoern Schiessle, Florin Peter</author>
|
||||
<requiremin>4</requiremin>
|
||||
<shipped>true</shipped>
|
||||
<documentation>
|
||||
<user>http://doc.owncloud.org/server/6.0/user_manual/files/encryption.html</user>
|
||||
<admin>http://doc.owncloud.org/server/6.0/admin_manual/configuration/configuration_encryption.html</admin>
|
||||
<user>user-encryption</user>
|
||||
<admin>admin-encryption</admin>
|
||||
</documentation>
|
||||
<rememberlogin>false</rememberlogin>
|
||||
<types>
|
||||
|
||||
@@ -6,6 +6,9 @@ if (!isset($_)) { //also provide standalone error page
|
||||
|
||||
$l = OC_L10N::get('files_encryption');
|
||||
|
||||
OC_JSON::checkAppEnabled('files_encryption');
|
||||
OC_App::loadApp('files_encryption');
|
||||
|
||||
if (isset($_GET['errorCode'])) {
|
||||
$errorCode = $_GET['errorCode'];
|
||||
switch ($errorCode) {
|
||||
|
||||
@@ -205,13 +205,12 @@ class Hooks {
|
||||
if (Crypt::mode() === 'server') {
|
||||
|
||||
$view = new \OC\Files\View('/');
|
||||
$session = new \OCA\Encryption\Session($view);
|
||||
|
||||
if ($params['uid'] === \OCP\User::getUser()) {
|
||||
// Get existing decrypted private key
|
||||
$privateKey = $session->getPrivateKey();
|
||||
|
||||
$session = new \OCA\Encryption\Session($view);
|
||||
|
||||
// Get existing decrypted private key
|
||||
$privateKey = $session->getPrivateKey();
|
||||
if ($params['uid'] === \OCP\User::getUser() && $privateKey) {
|
||||
|
||||
// Encrypt private key with new user pwd as passphrase
|
||||
$encryptedPrivateKey = Crypt::symmetricEncryptFileContent($privateKey, $params['password'], Helper::getCipher());
|
||||
@@ -242,6 +241,9 @@ class Hooks {
|
||||
|| !$util->userKeysExists()
|
||||
|| !$view->file_exists($user . '/files')) {
|
||||
|
||||
// backup old keys
|
||||
$util->backupAllKeys('recovery');
|
||||
|
||||
$newUserPassword = $params['password'];
|
||||
|
||||
// make sure that the users home is mounted
|
||||
@@ -421,34 +423,18 @@ class Hooks {
|
||||
* @param array $params with the old path and the new path
|
||||
*/
|
||||
public static function preRename($params) {
|
||||
$user = \OCP\User::getUser();
|
||||
$view = new \OC\Files\View('/');
|
||||
$util = new Util($view, $user);
|
||||
list($ownerOld, $pathOld) = $util->getUidAndFilename($params['oldpath']);
|
||||
|
||||
// we only need to rename the keys if the rename happens on the same mountpoint
|
||||
// otherwise we perform a stream copy, so we get a new set of keys
|
||||
$mp1 = $view->getMountPoint('/' . $user . '/files/' . $params['oldpath']);
|
||||
$mp2 = $view->getMountPoint('/' . $user . '/files/' . $params['newpath']);
|
||||
|
||||
$type = $view->is_dir('/' . $user . '/files/' . $params['oldpath']) ? 'folder' : 'file';
|
||||
|
||||
if ($mp1 === $mp2) {
|
||||
self::$renamedFiles[$params['oldpath']] = array(
|
||||
'uid' => $ownerOld,
|
||||
'path' => $pathOld,
|
||||
'type' => $type,
|
||||
'operation' => 'rename',
|
||||
);
|
||||
|
||||
}
|
||||
self::preRenameOrCopy($params, 'rename');
|
||||
}
|
||||
|
||||
/**
|
||||
* mark file as renamed so that we know the original source after the file was renamed
|
||||
* mark file as copied so that we know the original source after the file was copied
|
||||
* @param array $params with the old path and the new path
|
||||
*/
|
||||
public static function preCopy($params) {
|
||||
self::preRenameOrCopy($params, 'copy');
|
||||
}
|
||||
|
||||
private static function preRenameOrCopy($params, $operation) {
|
||||
$user = \OCP\User::getUser();
|
||||
$view = new \OC\Files\View('/');
|
||||
$util = new Util($view, $user);
|
||||
@@ -462,11 +448,27 @@ class Hooks {
|
||||
$type = $view->is_dir('/' . $user . '/files/' . $params['oldpath']) ? 'folder' : 'file';
|
||||
|
||||
if ($mp1 === $mp2) {
|
||||
if ($util->isSystemWideMountPoint($pathOld)) {
|
||||
$oldShareKeyPath = 'files_encryption/share-keys/' . $pathOld;
|
||||
} else {
|
||||
$oldShareKeyPath = $ownerOld . '/' . 'files_encryption/share-keys/' . $pathOld;
|
||||
}
|
||||
// gather share keys here because in postRename() the file will be moved already
|
||||
$oldShareKeys = Helper::findShareKeys($pathOld, $oldShareKeyPath, $view);
|
||||
if (count($oldShareKeys) === 0) {
|
||||
\OC_Log::write(
|
||||
'Encryption library', 'No share keys found for "' . $pathOld . '"',
|
||||
\OC_Log::WARN
|
||||
);
|
||||
}
|
||||
self::$renamedFiles[$params['oldpath']] = array(
|
||||
'uid' => $ownerOld,
|
||||
'path' => $pathOld,
|
||||
'type' => $type,
|
||||
'operation' => 'copy');
|
||||
'operation' => $operation,
|
||||
'sharekeys' => $oldShareKeys
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -488,6 +490,7 @@ class Hooks {
|
||||
$view = new \OC\Files\View('/');
|
||||
$userId = \OCP\User::getUser();
|
||||
$util = new Util($view, $userId);
|
||||
$oldShareKeys = null;
|
||||
|
||||
if (isset(self::$renamedFiles[$params['oldpath']]['uid']) &&
|
||||
isset(self::$renamedFiles[$params['oldpath']]['path'])) {
|
||||
@@ -495,9 +498,11 @@ class Hooks {
|
||||
$pathOld = self::$renamedFiles[$params['oldpath']]['path'];
|
||||
$type = self::$renamedFiles[$params['oldpath']]['type'];
|
||||
$operation = self::$renamedFiles[$params['oldpath']]['operation'];
|
||||
$oldShareKeys = self::$renamedFiles[$params['oldpath']]['sharekeys'];
|
||||
unset(self::$renamedFiles[$params['oldpath']]);
|
||||
} else {
|
||||
\OCP\Util::writeLog('Encryption library', "can't get path and owner from the file before it was renamed", \OCP\Util::DEBUG);
|
||||
\OC_FileProxy::$enabled = $proxyStatus;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -533,9 +538,7 @@ class Hooks {
|
||||
$oldKeyfilePath .= '.key';
|
||||
$newKeyfilePath .= '.key';
|
||||
|
||||
// handle share-keys
|
||||
$matches = Helper::findShareKeys($oldShareKeyPath, $view);
|
||||
foreach ($matches as $src) {
|
||||
foreach ($oldShareKeys as $src) {
|
||||
$dst = \OC\Files\Filesystem::normalizePath(str_replace($pathOld, $pathNew, $src));
|
||||
$view->$operation($src, $dst);
|
||||
}
|
||||
|
||||
@@ -9,32 +9,21 @@
|
||||
|
||||
$(document).ready(function(){
|
||||
|
||||
$('input:password[name="encryptionRecoveryPassword"]').keyup(function(event) {
|
||||
var recoveryPassword = $( '#encryptionRecoveryPassword' ).val();
|
||||
var recoveryPasswordRepeated = $( '#repeatEncryptionRecoveryPassword' ).val();
|
||||
var checkedButton = $('input:radio[name="adminEnableRecovery"]:checked').val();
|
||||
var uncheckedValue = (1+parseInt(checkedButton)) % 2;
|
||||
if (recoveryPassword !== '' && recoveryPassword === recoveryPasswordRepeated) {
|
||||
$('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 = $( '#encryptionRecoveryPassword' ).val();
|
||||
var confirmPassword = $( '#repeatEncryptionRecoveryPassword' ).val();
|
||||
OC.msg.startSaving('#encryptionSetRecoveryKey .msg');
|
||||
$.post(
|
||||
OC.filePath( 'files_encryption', 'ajax', 'adminrecovery.php' )
|
||||
, { adminEnableRecovery: recoveryStatus, recoveryPassword: recoveryPassword }
|
||||
, { adminEnableRecovery: recoveryStatus, recoveryPassword: recoveryPassword, confirmPassword: confirmPassword }
|
||||
, function( result ) {
|
||||
OC.msg.finishedSaving('#encryptionSetRecoveryKey .msg', 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") {
|
||||
$('p[name="changeRecoveryPasswordBlock"]').addClass("hidden");
|
||||
} else {
|
||||
@@ -49,33 +38,17 @@ $(document).ready(function(){
|
||||
|
||||
// change recovery password
|
||||
|
||||
$('input:password[name="changeRecoveryPassword"]').keyup(function(event) {
|
||||
var oldRecoveryPassword = $('#oldEncryptionRecoveryPassword').val();
|
||||
var newRecoveryPassword = $('#newEncryptionRecoveryPassword').val();
|
||||
var newRecoveryPasswordRepeated = $('#repeatedNewEncryptionRecoveryPassword').val();
|
||||
|
||||
if (newRecoveryPassword !== '' && oldRecoveryPassword !== '' && newRecoveryPassword === newRecoveryPasswordRepeated) {
|
||||
$('button:button[name="submitChangeRecoveryKey"]').removeAttr("disabled");
|
||||
} else {
|
||||
$('button:button[name="submitChangeRecoveryKey"]').attr("disabled", "true");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
$('button:button[name="submitChangeRecoveryKey"]').click(function() {
|
||||
var oldRecoveryPassword = $('#oldEncryptionRecoveryPassword').val();
|
||||
var newRecoveryPassword = $('#newEncryptionRecoveryPassword').val();
|
||||
OC.msg.startSaving('#encryption .msg');
|
||||
var confirmNewPassword = $('#repeatedNewEncryptionRecoveryPassword').val();
|
||||
OC.msg.startSaving('#encryptionChangeRecoveryKey .msg');
|
||||
$.post(
|
||||
OC.filePath( 'files_encryption', 'ajax', 'changeRecoveryPassword.php' )
|
||||
, { oldPassword: oldRecoveryPassword, newPassword: newRecoveryPassword }
|
||||
, { oldPassword: oldRecoveryPassword, newPassword: newRecoveryPassword, confirmPassword: confirmNewPassword }
|
||||
, function( data ) {
|
||||
if (data.status == "error") {
|
||||
OC.msg.finishedSaving('#encryption .msg', data);
|
||||
} else {
|
||||
OC.msg.finishedSaving('#encryption .msg', data);
|
||||
OC.msg.finishedSaving('#encryptionChangeRecoveryKey .msg', data);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -26,36 +26,27 @@ $(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();
|
||||
|
||||
OC.msg.startAction('#userEnableRecovery .msg', 'Updating recovery keys. This can take some time...');
|
||||
$.post(
|
||||
OC.filePath( 'files_encryption', 'ajax', 'userrecovery.php' )
|
||||
, { userEnableRecovery: recoveryStatus }
|
||||
, function( data ) {
|
||||
if ( data.status == "success" ) {
|
||||
$('#recoveryEnabledSuccess').show();
|
||||
} else {
|
||||
$('#recoveryEnabledError').show();
|
||||
}
|
||||
OC.msg.finishedAction('#userEnableRecovery .msg', data);
|
||||
}
|
||||
);
|
||||
// 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();
|
||||
|
||||
@@ -73,7 +64,7 @@ $(document).ready(function(){
|
||||
// Ensure page is not reloaded on form submit
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
);
|
||||
|
||||
// update private key password
|
||||
|
||||
@@ -4,8 +4,8 @@ $TRANSLATIONS = array(
|
||||
"Could not enable recovery key. Please check your recovery key password!" => "Impossible d'activer la clé de récupération. Veuillez vérifier votre mot de passe de clé de récupération !",
|
||||
"Recovery key successfully disabled" => "Clé de récupération désactivée avec succès",
|
||||
"Could not disable recovery key. Please check your recovery key password!" => "Impossible de désactiver la clé de récupération. Veuillez vérifier votre mot de passe de clé de récupération !",
|
||||
"Password successfully changed." => "Mot de passe changé avec succès ",
|
||||
"Could not change the password. Maybe the old password was not correct." => "Ne peut pas changer le mot de passe. L'ancien mot de passe est peut-être incorrect.",
|
||||
"Password successfully changed." => "Mot de passe changé avec succès.",
|
||||
"Could not change the password. Maybe the old password was not correct." => "Erreur lors du changement de mot de passe. L'ancien mot de passe est peut-être incorrect.",
|
||||
"Private key password successfully updated." => "Mot de passe de la clé privé mis à jour avec succès.",
|
||||
"Could not update the private key password. Maybe the old password was not correct." => "Impossible de mettre à jour le mot de passe de la clé privé. Peut-être que l'ancien mot de passe n'était pas correcte.",
|
||||
"Encryption app not initialized! Maybe the encryption app was re-enabled during your session. Please try to log out and log back in to initialize the encryption app." => "L'application de chiffrement n'est pas initialisée ! Peut-être que cette application a été réactivée pendant votre session. Veuillez essayer de vous déconnecter et ensuite de vous reconnecter pour initialiser l'application de chiffrement.",
|
||||
@@ -22,8 +22,8 @@ $TRANSLATIONS = array(
|
||||
"Enable recovery key (allow to recover users files in case of password loss):" => "Activer la clef de récupération (permet de récupérer les fichiers des utilisateurs en cas de perte de mot de passe).",
|
||||
"Recovery key password" => "Mot de passe de la clef de récupération",
|
||||
"Repeat Recovery key password" => "Répétez le mot de passe de la clé de récupération",
|
||||
"Enabled" => "Activer",
|
||||
"Disabled" => "Désactiver",
|
||||
"Enabled" => "Activé",
|
||||
"Disabled" => "Désactivé",
|
||||
"Change recovery key password:" => "Modifier le mot de passe de la clef de récupération :",
|
||||
"Old Recovery key password" => "Ancien mot de passe de la clef de récupération",
|
||||
"New Recovery key password" => "Nouveau mot de passe de la clef de récupération",
|
||||
|
||||
Executable → Regular
+4
-3
@@ -24,6 +24,7 @@
|
||||
*/
|
||||
|
||||
namespace OCA\Encryption;
|
||||
use OCA\Encryption\Exceptions\EncryptionException;
|
||||
|
||||
require_once __DIR__ . '/../3rdparty/Crypt_Blowfish/Blowfish.php';
|
||||
|
||||
@@ -321,9 +322,9 @@ class Crypt {
|
||||
$padded = self::addPadding($catfile);
|
||||
|
||||
return $padded;
|
||||
} catch (OCA\Encryption\Exceptions\EncryptionException $e) {
|
||||
$message = 'Could not encrypt file content (code: ' . $e->getCode . '): ';
|
||||
\OCP\Util::writeLog('files_encryption', $message . $e->getMessage, \OCP\Util::ERROR);
|
||||
} catch (EncryptionException $e) {
|
||||
$message = 'Could not encrypt file content (code: ' . $e->getCode() . '): ';
|
||||
\OCP\Util::writeLog('files_encryption', $message . $e->getMessage(), \OCP\Util::ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Executable → Regular
+30
-14
@@ -431,24 +431,40 @@ class Helper {
|
||||
|
||||
/**
|
||||
* find all share keys for a given file
|
||||
* @param string $path to the file
|
||||
* @param \OC\Files\View $view view, relative to data/
|
||||
* @return array list of files, path relative to data/
|
||||
*
|
||||
* @param string $filePath path to the file name relative to the user's files dir
|
||||
* for example "subdir/filename.txt"
|
||||
* @param string $shareKeyPath share key prefix path relative to the user's data dir
|
||||
* for example "user1/files_encryption/share-keys/subdir/filename.txt"
|
||||
* @param \OC\Files\View $rootView root view, relative to data/
|
||||
* @return array list of share key files, path relative to data/$user
|
||||
*/
|
||||
public static function findShareKeys($path, $view) {
|
||||
public static function findShareKeys($filePath, $shareKeyPath, $rootView) {
|
||||
$result = array();
|
||||
$pathinfo = pathinfo($path);
|
||||
$dirContent = $view->opendir($pathinfo['dirname']);
|
||||
|
||||
if (is_resource($dirContent)) {
|
||||
while (($file = readdir($dirContent)) !== false) {
|
||||
if (!\OC\Files\Filesystem::isIgnoredDir($file)) {
|
||||
if (preg_match("/" . $pathinfo['filename'] . ".(.*).shareKey/", $file)) {
|
||||
$result[] = $pathinfo['dirname'] . '/' . $file;
|
||||
}
|
||||
}
|
||||
$user = \OCP\User::getUser();
|
||||
$util = new Util($rootView, $user);
|
||||
// get current sharing state
|
||||
$sharingEnabled = \OCP\Share::isEnabled();
|
||||
|
||||
// get users sharing this file
|
||||
$usersSharing = $util->getSharingUsersArray($sharingEnabled, $filePath);
|
||||
|
||||
$pathinfo = pathinfo($shareKeyPath);
|
||||
|
||||
$baseDir = $pathinfo['dirname'] . '/';
|
||||
$fileName = $pathinfo['basename'];
|
||||
foreach ($usersSharing as $user) {
|
||||
$keyName = $fileName . '.' . $user . '.shareKey';
|
||||
if ($rootView->file_exists($baseDir . $keyName)) {
|
||||
$result[] = $baseDir . $keyName;
|
||||
} else {
|
||||
\OC_Log::write(
|
||||
'Encryption library',
|
||||
'No share key found for user "' . $user . '" for file "' . $fileName . '"',
|
||||
\OC_Log::WARN
|
||||
);
|
||||
}
|
||||
closedir($dirContent);
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
||||
Executable → Regular
+32
-22
@@ -459,13 +459,17 @@ class Keymanager {
|
||||
\OCP\Util::writeLog('files_encryption', 'delAllShareKeys: delete share keys: ' . $baseDir . $filePath, \OCP\Util::DEBUG);
|
||||
$result = $view->unlink($baseDir . $filePath);
|
||||
} else {
|
||||
$parentDir = dirname($baseDir . $filePath);
|
||||
$filename = pathinfo($filePath, PATHINFO_BASENAME);
|
||||
foreach($view->getDirectoryContent($parentDir) as $content) {
|
||||
$path = $content['path'];
|
||||
if (self::getFilenameFromShareKey($content['name']) === $filename) {
|
||||
\OCP\Util::writeLog('files_encryption', 'dellAllShareKeys: delete share keys: ' . '/' . $userId . '/' . $path, \OCP\Util::DEBUG);
|
||||
$result &= $view->unlink('/' . $userId . '/' . $path);
|
||||
$sharingEnabled = \OCP\Share::isEnabled();
|
||||
$users = $util->getSharingUsersArray($sharingEnabled, $filePath);
|
||||
foreach($users as $user) {
|
||||
$keyName = $baseDir . $filePath . '.' . $user . '.shareKey';
|
||||
if ($view->file_exists($keyName)) {
|
||||
\OCP\Util::writeLog(
|
||||
'files_encryption',
|
||||
'dellAllShareKeys: delete share keys: "' . $keyName . '"',
|
||||
\OCP\Util::DEBUG
|
||||
);
|
||||
$result &= $view->unlink($keyName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -539,17 +543,20 @@ class Keymanager {
|
||||
if ($view->is_dir($dir . '/' . $file)) {
|
||||
self::recursiveDelShareKeys($dir . '/' . $file, $userIds, $owner, $view);
|
||||
} else {
|
||||
$realFile = $realFileDir . self::getFilenameFromShareKey($file);
|
||||
foreach ($userIds as $userId) {
|
||||
if (preg_match("/(.*)." . $userId . ".shareKey/", $file)) {
|
||||
if ($userId === $owner &&
|
||||
$view->file_exists($realFile)) {
|
||||
\OCP\Util::writeLog('files_encryption', 'original file still exists, keep owners share key!', \OCP\Util::ERROR);
|
||||
continue;
|
||||
}
|
||||
\OCP\Util::writeLog('files_encryption', 'recursiveDelShareKey: delete share key: ' . $file, \OCP\Util::DEBUG);
|
||||
$view->unlink($dir . '/' . $file);
|
||||
$fileNameFromShareKey = self::getFilenameFromShareKey($file, $userId);
|
||||
if (!$fileNameFromShareKey) {
|
||||
continue;
|
||||
}
|
||||
$realFile = $realFileDir . $fileNameFromShareKey;
|
||||
|
||||
if ($userId === $owner &&
|
||||
$view->file_exists($realFile)) {
|
||||
\OCP\Util::writeLog('files_encryption', 'original file still exists, keep owners share key!', \OCP\Util::ERROR);
|
||||
continue;
|
||||
}
|
||||
\OCP\Util::writeLog('files_encryption', 'recursiveDelShareKey: delete share key: ' . $file, \OCP\Util::DEBUG);
|
||||
$view->unlink($dir . '/' . $file);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -591,16 +598,19 @@ class Keymanager {
|
||||
/**
|
||||
* extract filename from share key name
|
||||
* @param string $shareKey (filename.userid.sharekey)
|
||||
* @param string $userId
|
||||
* @return string|false filename or false
|
||||
*/
|
||||
protected static function getFilenameFromShareKey($shareKey) {
|
||||
$parts = explode('.', $shareKey);
|
||||
protected static function getFilenameFromShareKey($shareKey, $userId) {
|
||||
$expectedSuffix = '.' . $userId . '.' . 'shareKey';
|
||||
$suffixLen = strlen($expectedSuffix);
|
||||
|
||||
$filename = false;
|
||||
if(count($parts) > 2) {
|
||||
$filename = implode('.', array_slice($parts, 0, count($parts)-2));
|
||||
$suffix = substr($shareKey, -$suffixLen);
|
||||
|
||||
if ($suffix !== $expectedSuffix) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $filename;
|
||||
return substr($shareKey, 0, -$suffixLen);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,12 +49,17 @@ class Proxy extends \OC_FileProxy {
|
||||
* @param string $uid user
|
||||
* @return boolean
|
||||
*/
|
||||
private function isExcludedPath($path, $uid) {
|
||||
protected function isExcludedPath($path, $uid) {
|
||||
|
||||
$view = new \OC\Files\View();
|
||||
|
||||
// files outside of the files-folder are excluded
|
||||
if(strpos($path, '/' . $uid . '/files') !== 0) {
|
||||
$path = \OC\Files\Filesystem::normalizePath($path);
|
||||
|
||||
// we only encrypt/decrypt files in the files and files_versions folder
|
||||
if(
|
||||
strpos($path, '/' . $uid . '/files/') !== 0 &&
|
||||
strpos($path, '/' . $uid . '/files_versions/') !== 0) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -157,8 +162,8 @@ class Proxy extends \OC_FileProxy {
|
||||
// store new unenecrypted size so that it can be updated
|
||||
// in the post proxy
|
||||
$tmpFileInfo = $view->getFileInfo($tmpPath);
|
||||
if ( isset($tmpFileInfo['size']) ) {
|
||||
self::$unencryptedSizes[\OC\Files\Filesystem::normalizePath($path)] = $tmpFileInfo['size'];
|
||||
if ( isset($tmpFileInfo['unencrypted_size']) ) {
|
||||
self::$unencryptedSizes[\OC\Files\Filesystem::normalizePath($path)] = $tmpFileInfo['unencrypted_size'];
|
||||
}
|
||||
|
||||
// remove our temp file
|
||||
@@ -262,7 +267,7 @@ class Proxy extends \OC_FileProxy {
|
||||
* @param resource $result
|
||||
* @return resource
|
||||
*/
|
||||
public function postFopen($path, &$result) {
|
||||
public function postFopen($path, $result) {
|
||||
|
||||
$path = \OC\Files\Filesystem::normalizePath($path);
|
||||
|
||||
|
||||
@@ -573,6 +573,7 @@ class Stream {
|
||||
\OC_FileProxy::$enabled = false;
|
||||
|
||||
if ($this->rootView->file_exists($this->rawPath) && $this->size === 0) {
|
||||
fclose($this->handle);
|
||||
$this->rootView->unlink($this->rawPath);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
namespace OCA\Encryption;
|
||||
use OC\User\NoUserException;
|
||||
|
||||
/**
|
||||
* Class for utilities relating to encrypted file storage system
|
||||
@@ -888,6 +889,31 @@ class Util {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given user is ready for encryption.
|
||||
* Also returns true if the given user is the public user
|
||||
* or the recovery key user.
|
||||
*
|
||||
* @param string $user user to check
|
||||
*
|
||||
* @return boolean true if the user is ready, false otherwise
|
||||
*/
|
||||
private function isUserReady($user) {
|
||||
if ($user === $this->publicShareKeyId
|
||||
|| $user === $this->recoveryKeyId
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
$util = new Util($this->view, $user);
|
||||
return $util->ready();
|
||||
} catch (NoUserException $e) {
|
||||
\OCP\Util::writeLog('Encryption library',
|
||||
'No User object for '.$user, \OCP\Util::DEBUG);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter an array of UIDs to return only ones ready for sharing
|
||||
* @param array $unfilteredUsers users to be checked for sharing readiness
|
||||
@@ -900,16 +926,9 @@ class Util {
|
||||
|
||||
// Loop through users and create array of UIDs that need new keyfiles
|
||||
foreach ($unfilteredUsers as $user) {
|
||||
|
||||
$util = new Util($this->view, $user);
|
||||
|
||||
// Check that the user is encryption capable, or is the
|
||||
// public system user 'ownCloud' (for public shares)
|
||||
if (
|
||||
$user === $this->publicShareKeyId
|
||||
or $user === $this->recoveryKeyId
|
||||
or $util->ready()
|
||||
) {
|
||||
// public system user (for public shares)
|
||||
if ($this->isUserReady($user)) {
|
||||
|
||||
// Construct array of ready UIDs for Keymanager{}
|
||||
$readyIds[] = $user;
|
||||
@@ -1525,6 +1544,22 @@ class Util {
|
||||
$this->recoverAllFiles('/', $privateKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* create a backup of all keys from the user
|
||||
*
|
||||
* @param string $purpose (optional) define the purpose of the backup, will be part of the backup folder
|
||||
*/
|
||||
public function backupAllKeys($purpose = '') {
|
||||
$this->userId;
|
||||
$backupDir = $this->encryptionDir . '/backup.';
|
||||
$backupDir .= ($purpose === '') ? date("Y-m-d_H-i-s") . '/' : $purpose . '.' . date("Y-m-d_H-i-s") . '/';
|
||||
$this->view->mkdir($backupDir);
|
||||
$this->view->copy($this->shareKeysPath, $backupDir . 'share-keys/');
|
||||
$this->view->copy($this->keyfilesPath, $backupDir . 'keyfiles/');
|
||||
$this->view->copy($this->privateKeyPath, $backupDir . $this->userId . '.private.key');
|
||||
$this->view->copy($this->publicKeyPath, $backupDir . $this->userId . '.public.key');
|
||||
}
|
||||
|
||||
/**
|
||||
* check if the file is stored on a system wide mount point
|
||||
* @param string $path relative to /data/user with leading '/'
|
||||
|
||||
@@ -28,7 +28,6 @@ $result = false;
|
||||
if ($recoveryAdminEnabled || !$privateKeySet) {
|
||||
|
||||
\OCP\Util::addscript('files_encryption', 'settings-personal');
|
||||
\OCP\Util::addScript('settings', 'personal');
|
||||
|
||||
$tmpl->assign('recoveryEnabled', $recoveryAdminEnabled);
|
||||
$tmpl->assign('recoveryEnabledForUser', $recoveryEnabledForUser);
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
<?php if($_["initStatus"] === \OCA\Encryption\Session::NOT_INITIALIZED): ?>
|
||||
<?php p($l->t("Encryption App is enabled but your keys are not initialized, please log-out and log-in again")); ?>
|
||||
<?php else: ?>
|
||||
<p>
|
||||
<p id="encryptionSetRecoveryKey">
|
||||
<?php p($l->t("Enable recovery key (allow to recover users files in case of password loss):")); ?>
|
||||
<span class="msg"></span>
|
||||
<br/>
|
||||
<br/>
|
||||
<input type="password" name="encryptionRecoveryPassword" id="encryptionRecoveryPassword"/>
|
||||
@@ -18,7 +19,7 @@
|
||||
type='radio'
|
||||
name='adminEnableRecovery'
|
||||
value='1'
|
||||
<?php echo($_["recoveryEnabled"] === '1' ? 'checked="checked"' : 'disabled'); ?> />
|
||||
<?php echo($_["recoveryEnabled"] === '1' ? 'checked="checked"' : ''); ?> />
|
||||
<?php p($l->t("Enabled")); ?>
|
||||
<br/>
|
||||
|
||||
@@ -26,13 +27,14 @@
|
||||
type='radio'
|
||||
name='adminEnableRecovery'
|
||||
value='0'
|
||||
<?php echo($_["recoveryEnabled"] === '0' ? 'checked="checked"' : 'disabled'); ?> />
|
||||
<?php echo($_["recoveryEnabled"] === '0' ? 'checked="checked"' : ''); ?> />
|
||||
<?php p($l->t("Disabled")); ?>
|
||||
</p>
|
||||
<br/><br/>
|
||||
|
||||
<p name="changeRecoveryPasswordBlock" <?php if ($_['recoveryEnabled'] === '0') print_unescaped('class="hidden"');?>>
|
||||
<p name="changeRecoveryPasswordBlock" id="encryptionChangeRecoveryKey" <?php if ($_['recoveryEnabled'] === '0') print_unescaped('class="hidden"');?>>
|
||||
<strong><?php p($l->t("Change recovery key password:")); ?></strong>
|
||||
<span class="msg"></span>
|
||||
<br/><br/>
|
||||
<input
|
||||
type="password"
|
||||
@@ -55,10 +57,9 @@
|
||||
<br/>
|
||||
<button
|
||||
type="button"
|
||||
name="submitChangeRecoveryKey"
|
||||
disabled><?php p($l->t("Change Password")); ?>
|
||||
name="submitChangeRecoveryKey">
|
||||
<?php p($l->t("Change Password")); ?>
|
||||
</button>
|
||||
<span class="msg"></span>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
</form>
|
||||
|
||||
@@ -39,8 +39,9 @@
|
||||
|
||||
<?php elseif ( $_["recoveryEnabled"] && $_["privateKeySet"] && $_["initialized"] === \OCA\Encryption\Session::INIT_SUCCESSFUL ): ?>
|
||||
<br />
|
||||
<p>
|
||||
<p id="userEnableRecovery">
|
||||
<label for="userEnableRecovery"><?php p( $l->t( "Enable password recovery:" ) ); ?></label>
|
||||
<span class="msg"></span>
|
||||
<br />
|
||||
<em><?php p( $l->t( "Enabling this option will allow you to reobtain access to your encrypted files in case of password loss" ) ); ?></em>
|
||||
<br />
|
||||
@@ -58,8 +59,6 @@
|
||||
value='0'
|
||||
<?php echo ( $_["recoveryEnabledForUser"] === false ? 'checked="checked"' : '' ); ?> />
|
||||
<?php p( $l->t( "Disabled" ) ); ?>
|
||||
<div id="recoveryEnabledSuccess"><?php p( $l->t( 'File recovery settings updated' ) ); ?></div>
|
||||
<div id="recoveryEnabledError"><?php p( $l->t( 'Could not update file recovery' ) ); ?></div>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
</form>
|
||||
|
||||
@@ -23,7 +23,7 @@ use OCA\Encryption;
|
||||
/**
|
||||
* Class Test_Encryption_Crypt
|
||||
*/
|
||||
class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
class Test_Encryption_Crypt extends \OCA\Files_Encryption\Tests\TestCase {
|
||||
|
||||
const TEST_ENCRYPTION_CRYPT_USER1 = "test-crypt-user1";
|
||||
|
||||
@@ -42,6 +42,8 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
public $genPublicKey;
|
||||
|
||||
public static function setUpBeforeClass() {
|
||||
parent::setUpBeforeClass();
|
||||
|
||||
// reset backend
|
||||
\OC_User::clearBackends();
|
||||
\OC_User::useBackend('database');
|
||||
@@ -57,10 +59,12 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
\OC_FileProxy::register(new OCA\Encryption\Proxy());
|
||||
|
||||
// create test user
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Crypt::TEST_ENCRYPTION_CRYPT_USER1, true);
|
||||
self::loginHelper(\Test_Encryption_Crypt::TEST_ENCRYPTION_CRYPT_USER1, true);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// set user id
|
||||
\OC_User::setUserId(\Test_Encryption_Crypt::TEST_ENCRYPTION_CRYPT_USER1);
|
||||
$this->userId = \Test_Encryption_Crypt::TEST_ENCRYPTION_CRYPT_USER1;
|
||||
@@ -88,7 +92,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
\OC_App::disable('files_trashbin');
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
protected function tearDown() {
|
||||
// reset app files_trashbin
|
||||
if ($this->stateFilesTrashbin) {
|
||||
OC_App::enable('files_trashbin');
|
||||
@@ -98,17 +102,29 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
$this->assertTrue(\OC_FileProxy::$enabled);
|
||||
\OCP\Config::deleteSystemValue('cipher');
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
public static function tearDownAfterClass() {
|
||||
// cleanup test user
|
||||
\OC_User::deleteUser(\Test_Encryption_Crypt::TEST_ENCRYPTION_CRYPT_USER1);
|
||||
|
||||
\OC_Hook::clear();
|
||||
\OC_FileProxy::clearProxies();
|
||||
|
||||
// Delete keys in /data/
|
||||
$view = new \OC\Files\View('/');
|
||||
$view->rmdir('public-keys');
|
||||
$view->rmdir('owncloud_private_key');
|
||||
|
||||
parent::tearDownAfterClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* @medium
|
||||
*/
|
||||
function testGenerateKey() {
|
||||
public function testGenerateKey() {
|
||||
|
||||
# TODO: use more accurate (larger) string length for test confirmation
|
||||
|
||||
@@ -118,7 +134,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
}
|
||||
|
||||
function testDecryptPrivateKey() {
|
||||
public function testDecryptPrivateKey() {
|
||||
|
||||
// test successful decrypt
|
||||
$crypted = Encryption\Crypt::symmetricEncryptFileContent($this->genPrivateKey, 'hat');
|
||||
@@ -140,7 +156,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
/**
|
||||
* @medium
|
||||
*/
|
||||
function testSymmetricEncryptFileContent() {
|
||||
public function testSymmetricEncryptFileContent() {
|
||||
|
||||
# TODO: search in keyfile for actual content as IV will ensure this test always passes
|
||||
|
||||
@@ -158,7 +174,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
/**
|
||||
* @medium
|
||||
*/
|
||||
function testSymmetricEncryptFileContentAes128() {
|
||||
public function testSymmetricEncryptFileContentAes128() {
|
||||
|
||||
# TODO: search in keyfile for actual content as IV will ensure this test always passes
|
||||
|
||||
@@ -176,9 +192,9 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
/**
|
||||
* @medium
|
||||
*/
|
||||
function testSymmetricStreamEncryptShortFileContent() {
|
||||
public function testSymmetricStreamEncryptShortFileContent() {
|
||||
|
||||
$filename = 'tmp-' . uniqid() . '.test';
|
||||
$filename = 'tmp-' . $this->getUniqueID() . '.test';
|
||||
|
||||
$cryptedFile = file_put_contents('crypt:///' . $this->userId . '/files/'. $filename, $this->dataShort);
|
||||
|
||||
@@ -213,9 +229,9 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
/**
|
||||
* @medium
|
||||
*/
|
||||
function testSymmetricStreamEncryptShortFileContentAes128() {
|
||||
public function testSymmetricStreamEncryptShortFileContentAes128() {
|
||||
|
||||
$filename = 'tmp-' . uniqid() . '.test';
|
||||
$filename = 'tmp-' . $this->getUniqueID() . '.test';
|
||||
|
||||
\OCP\Config::setSystemValue('cipher', 'AES-128-CFB');
|
||||
|
||||
@@ -258,10 +274,10 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
* @note If this test fails with truncate content, check that enough array slices are being rejoined to form $e, as the crypt.php file may have gotten longer and broken the manual
|
||||
* reassembly of its data
|
||||
*/
|
||||
function testSymmetricStreamEncryptLongFileContent() {
|
||||
public function testSymmetricStreamEncryptLongFileContent() {
|
||||
|
||||
// Generate a a random filename
|
||||
$filename = 'tmp-' . uniqid() . '.test';
|
||||
$filename = 'tmp-' . $this->getUniqueID() . '.test';
|
||||
|
||||
// Save long data as encrypted file using stream wrapper
|
||||
$cryptedFile = file_put_contents('crypt:///' . $this->userId . '/files/' . $filename, $this->dataLong . $this->dataLong);
|
||||
@@ -302,10 +318,10 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
* @note If this test fails with truncate content, check that enough array slices are being rejoined to form $e, as the crypt.php file may have gotten longer and broken the manual
|
||||
* reassembly of its data
|
||||
*/
|
||||
function testSymmetricStreamEncryptLongFileContentAes128() {
|
||||
public function testSymmetricStreamEncryptLongFileContentAes128() {
|
||||
|
||||
// Generate a a random filename
|
||||
$filename = 'tmp-' . uniqid() . '.test';
|
||||
$filename = 'tmp-' . $this->getUniqueID() . '.test';
|
||||
|
||||
\OCP\Config::setSystemValue('cipher', 'AES-128-CFB');
|
||||
|
||||
@@ -350,10 +366,10 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
* @note If this test fails with truncate content, check that enough array slices are being rejoined to form $e, as the crypt.php file may have gotten longer and broken the manual
|
||||
* reassembly of its data
|
||||
*/
|
||||
function testStreamDecryptLongFileContentWithoutHeader() {
|
||||
public function testStreamDecryptLongFileContentWithoutHeader() {
|
||||
|
||||
// Generate a a random filename
|
||||
$filename = 'tmp-' . uniqid() . '.test';
|
||||
$filename = 'tmp-' . $this->getUniqueID() . '.test';
|
||||
|
||||
\OCP\Config::setSystemValue('cipher', 'AES-128-CFB');
|
||||
|
||||
@@ -398,7 +414,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
/**
|
||||
* @medium
|
||||
*/
|
||||
function testIsEncryptedContent() {
|
||||
public function testIsEncryptedContent() {
|
||||
|
||||
$this->assertFalse(Encryption\Crypt::isCatfileContent($this->dataUrl));
|
||||
|
||||
@@ -413,7 +429,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
/**
|
||||
* @large
|
||||
*/
|
||||
function testMultiKeyEncrypt() {
|
||||
public function testMultiKeyEncrypt() {
|
||||
|
||||
# TODO: search in keyfile for actual content as IV will ensure this test always passes
|
||||
|
||||
@@ -467,9 +483,9 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
/**
|
||||
* @medium
|
||||
*/
|
||||
function testRenameFile() {
|
||||
public function testRenameFile() {
|
||||
|
||||
$filename = 'tmp-' . uniqid();
|
||||
$filename = 'tmp-' . $this->getUniqueID();
|
||||
|
||||
// Save long data as encrypted file using stream wrapper
|
||||
$cryptedFile = file_put_contents('crypt:///' . $this->userId . '/files/' . $filename, $this->dataLong);
|
||||
@@ -482,7 +498,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
$this->assertEquals($this->dataLong, $decrypt);
|
||||
|
||||
$newFilename = 'tmp-new-' . uniqid();
|
||||
$newFilename = 'tmp-new-' . $this->getUniqueID();
|
||||
$view = new \OC\Files\View('/' . $this->userId . '/files');
|
||||
$view->rename($filename, $newFilename);
|
||||
|
||||
@@ -498,9 +514,9 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
/**
|
||||
* @medium
|
||||
*/
|
||||
function testMoveFileIntoFolder() {
|
||||
public function testMoveFileIntoFolder() {
|
||||
|
||||
$filename = 'tmp-' . uniqid();
|
||||
$filename = 'tmp-' . $this->getUniqueID();
|
||||
|
||||
// Save long data as encrypted file using stream wrapper
|
||||
$cryptedFile = file_put_contents('crypt:///' . $this->userId . '/files/' . $filename, $this->dataLong);
|
||||
@@ -513,8 +529,8 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
$this->assertEquals($this->dataLong, $decrypt);
|
||||
|
||||
$newFolder = '/newfolder' . uniqid();
|
||||
$newFilename = 'tmp-new-' . uniqid();
|
||||
$newFolder = '/newfolder' . $this->getUniqueID();
|
||||
$newFilename = 'tmp-new-' . $this->getUniqueID();
|
||||
$view = new \OC\Files\View('/' . $this->userId . '/files');
|
||||
$view->mkdir($newFolder);
|
||||
$view->rename($filename, $newFolder . '/' . $newFilename);
|
||||
@@ -531,12 +547,12 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
/**
|
||||
* @medium
|
||||
*/
|
||||
function testMoveFolder() {
|
||||
public function testMoveFolder() {
|
||||
|
||||
$view = new \OC\Files\View('/' . $this->userId . '/files');
|
||||
|
||||
$filename = '/tmp-' . uniqid();
|
||||
$folder = '/folder' . uniqid();
|
||||
$filename = '/tmp-' . $this->getUniqueID();
|
||||
$folder = '/folder' . $this->getUniqueID();
|
||||
|
||||
$view->mkdir($folder);
|
||||
|
||||
@@ -551,7 +567,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
$this->assertEquals($this->dataLong, $decrypt);
|
||||
|
||||
$newFolder = '/newfolder/subfolder' . uniqid();
|
||||
$newFolder = '/newfolder/subfolder' . $this->getUniqueID();
|
||||
$view->mkdir('/newfolder');
|
||||
|
||||
$view->rename($folder, $newFolder);
|
||||
@@ -569,8 +585,8 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
/**
|
||||
* @medium
|
||||
*/
|
||||
function testChangePassphrase() {
|
||||
$filename = 'tmp-' . uniqid();
|
||||
public function testChangePassphrase() {
|
||||
$filename = 'tmp-' . $this->getUniqueID();
|
||||
|
||||
// Save long data as encrypted file using stream wrapper
|
||||
$cryptedFile = file_put_contents('crypt:///' . $this->userId . '/files/' . $filename, $this->dataLong);
|
||||
@@ -606,9 +622,9 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
/**
|
||||
* @medium
|
||||
*/
|
||||
function testViewFilePutAndGetContents() {
|
||||
public function testViewFilePutAndGetContents() {
|
||||
|
||||
$filename = '/tmp-' . uniqid();
|
||||
$filename = '/tmp-' . $this->getUniqueID();
|
||||
$view = new \OC\Files\View('/' . $this->userId . '/files');
|
||||
|
||||
// Save short data as encrypted file using stream wrapper
|
||||
@@ -640,8 +656,8 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
/**
|
||||
* @large
|
||||
*/
|
||||
function testTouchExistingFile() {
|
||||
$filename = '/tmp-' . uniqid();
|
||||
public function testTouchExistingFile() {
|
||||
$filename = '/tmp-' . $this->getUniqueID();
|
||||
$view = new \OC\Files\View('/' . $this->userId . '/files');
|
||||
|
||||
// Save short data as encrypted file using stream wrapper
|
||||
@@ -664,8 +680,8 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
/**
|
||||
* @medium
|
||||
*/
|
||||
function testTouchFile() {
|
||||
$filename = '/tmp-' . uniqid();
|
||||
public function testTouchFile() {
|
||||
$filename = '/tmp-' . $this->getUniqueID();
|
||||
$view = new \OC\Files\View('/' . $this->userId . '/files');
|
||||
|
||||
$view->touch($filename);
|
||||
@@ -688,8 +704,8 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
/**
|
||||
* @medium
|
||||
*/
|
||||
function testFopenFile() {
|
||||
$filename = '/tmp-' . uniqid();
|
||||
public function testFopenFile() {
|
||||
$filename = '/tmp-' . $this->getUniqueID();
|
||||
$view = new \OC\Files\View('/' . $this->userId . '/files');
|
||||
|
||||
// Save short data as encrypted file using stream wrapper
|
||||
@@ -706,6 +722,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
$this->assertEquals($this->dataShort, $decrypt);
|
||||
|
||||
// tear down
|
||||
fclose($handle);
|
||||
$view->unlink($filename);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,33 +5,49 @@
|
||||
* later.
|
||||
* See the COPYING-README file.
|
||||
*/
|
||||
|
||||
|
||||
require_once __DIR__ . '/../lib/helper.php';
|
||||
require_once __DIR__ . '/util.php';
|
||||
|
||||
use OCA\Encryption;
|
||||
|
||||
/**
|
||||
* Class Test_Encryption_Helper
|
||||
*/
|
||||
class Test_Encryption_Helper extends \PHPUnit_Framework_TestCase {
|
||||
class Test_Encryption_Helper extends \OCA\Files_Encryption\Tests\TestCase {
|
||||
|
||||
const TEST_ENCRYPTION_HELPER_USER1 = "test-helper-user1";
|
||||
const TEST_ENCRYPTION_HELPER_USER2 = "test-helper-user2";
|
||||
|
||||
public static function setUpBeforeClass() {
|
||||
protected function setUpUsers() {
|
||||
// create test user
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Helper::TEST_ENCRYPTION_HELPER_USER2, true);
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Helper::TEST_ENCRYPTION_HELPER_USER1, true);
|
||||
self::loginHelper(\Test_Encryption_Helper::TEST_ENCRYPTION_HELPER_USER2, true);
|
||||
self::loginHelper(\Test_Encryption_Helper::TEST_ENCRYPTION_HELPER_USER1, true);
|
||||
}
|
||||
|
||||
public static function tearDownAfterClass() {
|
||||
protected function cleanUpUsers() {
|
||||
// cleanup test user
|
||||
\OC_User::deleteUser(\Test_Encryption_Helper::TEST_ENCRYPTION_HELPER_USER1);
|
||||
\OC_User::deleteUser(\Test_Encryption_Helper::TEST_ENCRYPTION_HELPER_USER2);
|
||||
}
|
||||
|
||||
public static function setupHooks() {
|
||||
// Filesystem related hooks
|
||||
\OCA\Encryption\Helper::registerFilesystemHooks();
|
||||
|
||||
// clear and register hooks
|
||||
\OC_FileProxy::clearProxies();
|
||||
\OC_FileProxy::register(new OCA\Encryption\Proxy());
|
||||
}
|
||||
|
||||
public static function tearDownAfterClass() {
|
||||
\OC_Hook::clear();
|
||||
\OC_FileProxy::clearProxies();
|
||||
|
||||
// Delete keys in /data/
|
||||
$view = new \OC\Files\View('/');
|
||||
$view->rmdir('public-keys');
|
||||
$view->rmdir('owncloud_private_key');
|
||||
|
||||
parent::tearDownAfterClass();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,19 +99,20 @@ class Test_Encryption_Helper extends \PHPUnit_Framework_TestCase {
|
||||
}
|
||||
|
||||
function testGetUser() {
|
||||
self::setUpUsers();
|
||||
|
||||
$path1 = "/" . self::TEST_ENCRYPTION_HELPER_USER1 . "/files/foo/bar.txt";
|
||||
$path2 = "/" . self::TEST_ENCRYPTION_HELPER_USER1 . "/cache/foo/bar.txt";
|
||||
$path3 = "/" . self::TEST_ENCRYPTION_HELPER_USER2 . "/thumbnails/foo";
|
||||
$path4 ="/" . "/" . self::TEST_ENCRYPTION_HELPER_USER1;
|
||||
|
||||
\Test_Encryption_Util::loginHelper(self::TEST_ENCRYPTION_HELPER_USER1);
|
||||
self::loginHelper(self::TEST_ENCRYPTION_HELPER_USER1);
|
||||
|
||||
// if we are logged-in every path should return the currently logged-in user
|
||||
$this->assertEquals(self::TEST_ENCRYPTION_HELPER_USER1, Encryption\Helper::getUser($path3));
|
||||
|
||||
// now log out
|
||||
\Test_Encryption_Util::logoutHelper();
|
||||
self::logoutHelper();
|
||||
|
||||
// now we should only get the user from /user/files and user/cache paths
|
||||
$this->assertEquals(self::TEST_ENCRYPTION_HELPER_USER1, Encryption\Helper::getUser($path1));
|
||||
@@ -105,7 +122,60 @@ class Test_Encryption_Helper extends \PHPUnit_Framework_TestCase {
|
||||
$this->assertFalse(Encryption\Helper::getUser($path4));
|
||||
|
||||
// Log-in again
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Helper::TEST_ENCRYPTION_HELPER_USER1);
|
||||
self::loginHelper(\Test_Encryption_Helper::TEST_ENCRYPTION_HELPER_USER1);
|
||||
self::cleanUpUsers();
|
||||
}
|
||||
|
||||
function userNamesProvider() {
|
||||
return array(
|
||||
array('testuser' . $this->getUniqueID()),
|
||||
array('user.name.with.dots'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether share keys can be found
|
||||
*
|
||||
* @dataProvider userNamesProvider
|
||||
*/
|
||||
function testFindShareKeys($userName) {
|
||||
self::setUpUsers();
|
||||
// note: not using dataProvider as we want to make
|
||||
// sure that the correct keys are match and not any
|
||||
// other ones that might happen to have similar names
|
||||
self::setupHooks();
|
||||
self::loginHelper($userName, true);
|
||||
$testDir = 'testFindShareKeys' . $this->getUniqueID() . '/';
|
||||
$baseDir = $userName . '/files/' . $testDir;
|
||||
$fileList = array(
|
||||
't est.txt',
|
||||
't est_.txt',
|
||||
't est.doc.txt',
|
||||
't est(.*).txt', // make sure the regexp is escaped
|
||||
'multiple.dots.can.happen.too.txt',
|
||||
't est.' . $userName . '.txt',
|
||||
't est_.' . $userName . '.shareKey.txt',
|
||||
'who would upload their.shareKey',
|
||||
'user ones file.txt',
|
||||
'user ones file.txt.backup',
|
||||
'.t est.txt'
|
||||
);
|
||||
|
||||
$rootView = new \OC\Files\View('/');
|
||||
$rootView->mkdir($baseDir);
|
||||
foreach ($fileList as $fileName) {
|
||||
$rootView->file_put_contents($baseDir . $fileName, 'dummy');
|
||||
}
|
||||
|
||||
$shareKeysDir = $userName . '/files_encryption/share-keys/' . $testDir;
|
||||
foreach ($fileList as $fileName) {
|
||||
// make sure that every file only gets its correct respective keys
|
||||
$result = Encryption\Helper::findShareKeys($baseDir . $fileName, $shareKeysDir . $fileName, $rootView);
|
||||
$this->assertEquals(
|
||||
array($shareKeysDir . $fileName . '.' . $userName . '.shareKey'),
|
||||
$result
|
||||
);
|
||||
}
|
||||
self::cleanUpUsers();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ require_once __DIR__ . '/../lib/keymanager.php';
|
||||
require_once __DIR__ . '/../lib/stream.php';
|
||||
require_once __DIR__ . '/../lib/util.php';
|
||||
require_once __DIR__ . '/../appinfo/app.php';
|
||||
require_once __DIR__ . '/util.php';
|
||||
|
||||
use OCA\Encryption;
|
||||
|
||||
@@ -34,22 +33,44 @@ use OCA\Encryption;
|
||||
* Class Test_Encryption_Hooks
|
||||
* this class provide basic hook app tests
|
||||
*/
|
||||
class Test_Encryption_Hooks extends \PHPUnit_Framework_TestCase {
|
||||
class Test_Encryption_Hooks extends \OCA\Files_Encryption\Tests\TestCase {
|
||||
|
||||
const TEST_ENCRYPTION_HOOKS_USER1 = "test-encryption-hooks-user1";
|
||||
const TEST_ENCRYPTION_HOOKS_USER2 = "test-encryption-hooks-user2";
|
||||
const TEST_ENCRYPTION_HOOKS_USER1 = "test-encryption-hooks-user1.dot";
|
||||
const TEST_ENCRYPTION_HOOKS_USER2 = "test-encryption-hooks-user2.dot";
|
||||
const TEST_ENCRYPTION_HOOKS_USER3 = "test-encryption-hooks-user3.dot";
|
||||
|
||||
/**
|
||||
* @var \OC\Files\View
|
||||
*/
|
||||
/** @var \OC\Files\View */
|
||||
public $user1View; // view on /data/user1/files
|
||||
/** @var \OC\Files\View */
|
||||
public $user2View; // view on /data/user2/files
|
||||
/** @var \OC\Files\View */
|
||||
public $rootView; // view on /data/user
|
||||
public $data;
|
||||
public $filename;
|
||||
public $folder;
|
||||
|
||||
private static $testFiles;
|
||||
|
||||
public static function setUpBeforeClass() {
|
||||
parent::setUpBeforeClass();
|
||||
|
||||
// note: not using a data provider because these
|
||||
// files all need to coexist to make sure the
|
||||
// share keys are found properly (pattern matching)
|
||||
self::$testFiles = array(
|
||||
't est.txt',
|
||||
't est_.txt',
|
||||
't est.doc.txt',
|
||||
't est(.*).txt', // make sure the regexp is escaped
|
||||
'multiple.dots.can.happen.too.txt',
|
||||
't est.' . self::TEST_ENCRYPTION_HOOKS_USER1 . '.txt',
|
||||
't est_.' . self::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey.txt',
|
||||
'who would upload their.shareKey',
|
||||
'user ones file.txt',
|
||||
'user ones file.txt.backup',
|
||||
'.t est.txt'
|
||||
);
|
||||
|
||||
// reset backend
|
||||
\OC_User::clearBackends();
|
||||
\OC_User::useBackend('database');
|
||||
@@ -73,13 +94,15 @@ class Test_Encryption_Hooks extends \PHPUnit_Framework_TestCase {
|
||||
\OC_FileProxy::register(new OCA\Encryption\Proxy());
|
||||
|
||||
// create test user
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1, true);
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2, true);
|
||||
self::loginHelper(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1, true);
|
||||
self::loginHelper(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2, true);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// set user id
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1);
|
||||
self::loginHelper(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1);
|
||||
\OC_User::setUserId(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1);
|
||||
|
||||
// init filesystem view
|
||||
@@ -89,8 +112,8 @@ class Test_Encryption_Hooks extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
// init short data
|
||||
$this->data = 'hats';
|
||||
$this->filename = 'enc_hooks_tests-' . uniqid() . '.txt';
|
||||
$this->folder = 'enc_hooks_tests_folder-' . uniqid();
|
||||
$this->filename = 'enc_hooks_tests-' . $this->getUniqueID() . '.txt';
|
||||
$this->folder = 'enc_hooks_tests_folder-' . $this->getUniqueID();
|
||||
|
||||
}
|
||||
|
||||
@@ -98,6 +121,17 @@ class Test_Encryption_Hooks extends \PHPUnit_Framework_TestCase {
|
||||
// cleanup test user
|
||||
\OC_User::deleteUser(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1);
|
||||
\OC_User::deleteUser(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2);
|
||||
\OC_User::deleteUser(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER3);
|
||||
|
||||
\OC_Hook::clear();
|
||||
\OC_FileProxy::clearProxies();
|
||||
|
||||
// Delete keys in /data/
|
||||
$view = new \OC\Files\View('/');
|
||||
$view->rmdir('public-keys');
|
||||
$view->rmdir('owncloud_private_key');
|
||||
|
||||
parent::tearDownAfterClass();
|
||||
}
|
||||
|
||||
function testDisableHook() {
|
||||
@@ -119,7 +153,7 @@ class Test_Encryption_Hooks extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
// relogin user to initialize the encryption again
|
||||
$user = \OCP\User::getUser();
|
||||
\Test_Encryption_Util::loginHelper($user);
|
||||
self::loginHelper($user);
|
||||
|
||||
}
|
||||
|
||||
@@ -144,8 +178,8 @@ class Test_Encryption_Hooks extends \PHPUnit_Framework_TestCase {
|
||||
self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/keyfiles/' . $this->filename . '.key'));
|
||||
|
||||
|
||||
\Test_Encryption_Util::logoutHelper();
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2);
|
||||
self::logoutHelper();
|
||||
self::loginHelper(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2);
|
||||
\OC_User::setUserId(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2);
|
||||
|
||||
|
||||
@@ -202,8 +236,8 @@ class Test_Encryption_Hooks extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
function testDeleteHooksForSharedFiles() {
|
||||
|
||||
\Test_Encryption_Util::logoutHelper();
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1);
|
||||
self::logoutHelper();
|
||||
self::loginHelper(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1);
|
||||
\OC_User::setUserId(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1);
|
||||
|
||||
// remember files_trashbin state
|
||||
@@ -238,8 +272,8 @@ class Test_Encryption_Hooks extends \PHPUnit_Framework_TestCase {
|
||||
self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/'
|
||||
. $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2 . '.shareKey'));
|
||||
|
||||
\Test_Encryption_Util::logoutHelper();
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2);
|
||||
self::logoutHelper();
|
||||
self::loginHelper(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2);
|
||||
\OC_User::setUserId(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2);
|
||||
|
||||
// user2 update the shared file
|
||||
@@ -269,8 +303,8 @@ class Test_Encryption_Hooks extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
// cleanup
|
||||
|
||||
\Test_Encryption_Util::logoutHelper();
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1);
|
||||
self::logoutHelper();
|
||||
self::loginHelper(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1);
|
||||
\OC_User::setUserId(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1);
|
||||
|
||||
if ($stateFilesTrashbin) {
|
||||
@@ -281,25 +315,33 @@ class Test_Encryption_Hooks extends \PHPUnit_Framework_TestCase {
|
||||
}
|
||||
}
|
||||
|
||||
function testRenameHook() {
|
||||
// create all files to make sure all keys can coexist properly
|
||||
foreach (self::$testFiles as $file) {
|
||||
// save file with content
|
||||
$cryptedFile = file_put_contents('crypt:///' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $file, $this->data);
|
||||
|
||||
// test that data was successfully written
|
||||
$this->assertTrue(is_int($cryptedFile));
|
||||
}
|
||||
|
||||
foreach (self::$testFiles as $file) {
|
||||
$this->doTestRenameHook($file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* test rename operation
|
||||
*/
|
||||
function testRenameHook() {
|
||||
|
||||
// save file with content
|
||||
$cryptedFile = file_put_contents('crypt:///' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $this->filename, $this->data);
|
||||
|
||||
// test that data was successfully written
|
||||
$this->assertTrue(is_int($cryptedFile));
|
||||
|
||||
function doTestRenameHook($filename) {
|
||||
// check if keys exists
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
'/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/'
|
||||
. $this->filename . '.' . self::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey'));
|
||||
. $filename . '.' . self::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey'));
|
||||
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
'/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/keyfiles/'
|
||||
. $this->filename . '.key'));
|
||||
. $filename . '.key'));
|
||||
|
||||
// make subfolder and sub-subfolder
|
||||
$this->rootView->mkdir('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $this->folder);
|
||||
@@ -310,50 +352,58 @@ class Test_Encryption_Hooks extends \PHPUnit_Framework_TestCase {
|
||||
// move the file to the sub-subfolder
|
||||
$root = $this->rootView->getRoot();
|
||||
$this->rootView->chroot('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/');
|
||||
$this->rootView->rename($this->filename, '/' . $this->folder . '/' . $this->folder . '/' . $this->filename);
|
||||
$this->rootView->rename($filename, '/' . $this->folder . '/' . $this->folder . '/' . $filename);
|
||||
$this->rootView->chroot($root);
|
||||
|
||||
$this->assertFalse($this->rootView->file_exists('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $this->filename));
|
||||
$this->assertTrue($this->rootView->file_exists('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $this->folder . '/' . $this->folder . '/' . $this->filename));
|
||||
$this->assertFalse($this->rootView->file_exists('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $filename));
|
||||
$this->assertTrue($this->rootView->file_exists('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $this->folder . '/' . $this->folder . '/' . $filename));
|
||||
|
||||
// keys should be renamed too
|
||||
$this->assertFalse($this->rootView->file_exists(
|
||||
'/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/'
|
||||
. $this->filename . '.' . self::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey'));
|
||||
. $filename . '.' . self::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey'));
|
||||
$this->assertFalse($this->rootView->file_exists(
|
||||
'/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/keyfiles/'
|
||||
. $this->filename . '.key'));
|
||||
. $filename . '.key'));
|
||||
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
'/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/' . $this->folder . '/' . $this->folder . '/'
|
||||
. $this->filename . '.' . self::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey'));
|
||||
. $filename . '.' . self::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey'));
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
'/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/keyfiles/' . $this->folder . '/' . $this->folder . '/'
|
||||
. $this->filename . '.key'));
|
||||
. $filename . '.key'));
|
||||
|
||||
// cleanup
|
||||
$this->rootView->unlink('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $this->folder);
|
||||
}
|
||||
|
||||
function testCopyHook() {
|
||||
// create all files to make sure all keys can coexist properly
|
||||
foreach (self::$testFiles as $file) {
|
||||
// save file with content
|
||||
$cryptedFile = file_put_contents('crypt:///' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $file, $this->data);
|
||||
|
||||
// test that data was successfully written
|
||||
$this->assertTrue(is_int($cryptedFile));
|
||||
}
|
||||
|
||||
foreach (self::$testFiles as $file) {
|
||||
$this->doTestCopyHook($file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* test rename operation
|
||||
*/
|
||||
function testCopyHook() {
|
||||
|
||||
// save file with content
|
||||
$cryptedFile = file_put_contents('crypt:///' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $this->filename, $this->data);
|
||||
|
||||
// test that data was successfully written
|
||||
$this->assertTrue(is_int($cryptedFile));
|
||||
|
||||
function doTestCopyHook($filename) {
|
||||
// check if keys exists
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
'/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/'
|
||||
. $this->filename . '.' . self::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey'));
|
||||
. $filename . '.' . self::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey'));
|
||||
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
'/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/keyfiles/'
|
||||
. $this->filename . '.key'));
|
||||
. $filename . '.key'));
|
||||
|
||||
// make subfolder and sub-subfolder
|
||||
$this->rootView->mkdir('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $this->folder);
|
||||
@@ -362,29 +412,29 @@ class Test_Encryption_Hooks extends \PHPUnit_Framework_TestCase {
|
||||
$this->assertTrue($this->rootView->is_dir('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $this->folder . '/' . $this->folder));
|
||||
|
||||
// copy the file to the sub-subfolder
|
||||
\OC\Files\Filesystem::copy($this->filename, '/' . $this->folder . '/' . $this->folder . '/' . $this->filename);
|
||||
\OC\Files\Filesystem::copy($filename, '/' . $this->folder . '/' . $this->folder . '/' . $filename);
|
||||
|
||||
$this->assertTrue($this->rootView->file_exists('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $this->filename));
|
||||
$this->assertTrue($this->rootView->file_exists('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $this->folder . '/' . $this->folder . '/' . $this->filename));
|
||||
$this->assertTrue($this->rootView->file_exists('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $filename));
|
||||
$this->assertTrue($this->rootView->file_exists('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $this->folder . '/' . $this->folder . '/' . $filename));
|
||||
|
||||
// keys should be copied too
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
'/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/'
|
||||
. $this->filename . '.' . self::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey'));
|
||||
. $filename . '.' . self::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey'));
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
'/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/keyfiles/'
|
||||
. $this->filename . '.key'));
|
||||
. $filename . '.key'));
|
||||
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
'/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/' . $this->folder . '/' . $this->folder . '/'
|
||||
. $this->filename . '.' . self::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey'));
|
||||
. $filename . '.' . self::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey'));
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
'/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/keyfiles/' . $this->folder . '/' . $this->folder . '/'
|
||||
. $this->filename . '.key'));
|
||||
. $filename . '.key'));
|
||||
|
||||
// cleanup
|
||||
$this->rootView->unlink('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $this->folder);
|
||||
$this->rootView->unlink('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $this->filename);
|
||||
$this->rootView->unlink('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $filename);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -396,31 +446,35 @@ class Test_Encryption_Hooks extends \PHPUnit_Framework_TestCase {
|
||||
$view = new \OC\Files\View();
|
||||
|
||||
// set user password for the first time
|
||||
\OCA\Encryption\Hooks::postCreateUser(array('uid' => 'newUser', 'password' => 'newUserPassword'));
|
||||
\OC_User::createUser(self::TEST_ENCRYPTION_HOOKS_USER3, 'newUserPassword');
|
||||
\OCA\Encryption\Hooks::postCreateUser(array(
|
||||
'uid' => self::TEST_ENCRYPTION_HOOKS_USER3,
|
||||
'password' => 'newUserPassword')
|
||||
);
|
||||
|
||||
$this->assertTrue($view->file_exists('public-keys/newUser.public.key'));
|
||||
$this->assertTrue($view->file_exists('newUser/files_encryption/newUser.private.key'));
|
||||
$this->assertTrue($view->file_exists('public-keys/'.self::TEST_ENCRYPTION_HOOKS_USER3.'.public.key'));
|
||||
$this->assertTrue($view->file_exists(self::TEST_ENCRYPTION_HOOKS_USER3.'/files_encryption/'.self::TEST_ENCRYPTION_HOOKS_USER3.'.private.key'));
|
||||
|
||||
// check if we are able to decrypt the private key
|
||||
$encryptedKey = \OCA\Encryption\Keymanager::getPrivateKey($view, 'newUser');
|
||||
$encryptedKey = \OCA\Encryption\Keymanager::getPrivateKey($view, self::TEST_ENCRYPTION_HOOKS_USER3);
|
||||
$privateKey = \OCA\Encryption\Crypt::decryptPrivateKey($encryptedKey, 'newUserPassword');
|
||||
$this->assertTrue(is_string($privateKey));
|
||||
|
||||
// change the password before the user logged-in for the first time,
|
||||
// we can replace the encryption keys
|
||||
\OCA\Encryption\Hooks::setPassphrase(array('uid' => 'newUser', 'password' => 'passwordChanged'));
|
||||
\OCA\Encryption\Hooks::setPassphrase(array('uid' => self::TEST_ENCRYPTION_HOOKS_USER3, 'password' => 'passwordChanged'));
|
||||
|
||||
$encryptedKey = \OCA\Encryption\Keymanager::getPrivateKey($view, 'newUser');
|
||||
$encryptedKey = \OCA\Encryption\Keymanager::getPrivateKey($view, self::TEST_ENCRYPTION_HOOKS_USER3);
|
||||
$privateKey = \OCA\Encryption\Crypt::decryptPrivateKey($encryptedKey, 'passwordChanged');
|
||||
$this->assertTrue(is_string($privateKey));
|
||||
|
||||
// now create a files folder to simulate a already used account
|
||||
$view->mkdir('/newUser/files');
|
||||
$view->mkdir('/'.self::TEST_ENCRYPTION_HOOKS_USER3.'/files');
|
||||
|
||||
// change the password after the user logged in, now the password should not change
|
||||
\OCA\Encryption\Hooks::setPassphrase(array('uid' => 'newUser', 'password' => 'passwordChanged2'));
|
||||
\OCA\Encryption\Hooks::setPassphrase(array('uid' => self::TEST_ENCRYPTION_HOOKS_USER3, 'password' => 'passwordChanged2'));
|
||||
|
||||
$encryptedKey = \OCA\Encryption\Keymanager::getPrivateKey($view, 'newUser');
|
||||
$encryptedKey = \OCA\Encryption\Keymanager::getPrivateKey($view, self::TEST_ENCRYPTION_HOOKS_USER3);
|
||||
$privateKey = \OCA\Encryption\Crypt::decryptPrivateKey($encryptedKey, 'passwordChanged2');
|
||||
$this->assertFalse($privateKey);
|
||||
|
||||
|
||||
@@ -14,16 +14,15 @@ require_once __DIR__ . '/../lib/stream.php';
|
||||
require_once __DIR__ . '/../lib/util.php';
|
||||
require_once __DIR__ . '/../lib/helper.php';
|
||||
require_once __DIR__ . '/../appinfo/app.php';
|
||||
require_once __DIR__ . '/util.php';
|
||||
|
||||
use OCA\Encryption;
|
||||
|
||||
/**
|
||||
* Class Test_Encryption_Keymanager
|
||||
*/
|
||||
class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase {
|
||||
class Test_Encryption_Keymanager extends \OCA\Files_Encryption\Tests\TestCase {
|
||||
|
||||
const TEST_USER = "test-keymanager-user";
|
||||
const TEST_USER = "test-keymanager-user.dot";
|
||||
|
||||
public $userId;
|
||||
public $pass;
|
||||
@@ -36,6 +35,8 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase {
|
||||
public $dataShort;
|
||||
|
||||
public static function setUpBeforeClass() {
|
||||
parent::setUpBeforeClass();
|
||||
|
||||
// reset backend
|
||||
\OC_User::clearBackends();
|
||||
\OC_User::useBackend('database');
|
||||
@@ -58,10 +59,11 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
// create test user
|
||||
\OC_User::deleteUser(\Test_Encryption_Keymanager::TEST_USER);
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Keymanager::TEST_USER, true);
|
||||
parent::loginHelper(\Test_Encryption_Keymanager::TEST_USER, true);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
// set content for encrypting / decrypting in tests
|
||||
$this->dataLong = file_get_contents(__DIR__ . '/../lib/crypt.php');
|
||||
$this->dataShort = 'hats';
|
||||
@@ -76,7 +78,7 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
$this->view = new \OC\Files\View('/');
|
||||
|
||||
\Test_Encryption_Util::loginHelper(Test_Encryption_Keymanager::TEST_USER);
|
||||
self::loginHelper(Test_Encryption_Keymanager::TEST_USER);
|
||||
$this->userId = \Test_Encryption_Keymanager::TEST_USER;
|
||||
$this->pass = \Test_Encryption_Keymanager::TEST_USER;
|
||||
|
||||
@@ -87,6 +89,8 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase {
|
||||
function tearDown() {
|
||||
$this->view->deleteAll('/'.Test_Encryption_Keymanager::TEST_USER.'/files_encryption/share-keys');
|
||||
$this->view->deleteAll('/'.Test_Encryption_Keymanager::TEST_USER.'/files_encryption/keyfiles');
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
public static function tearDownAfterClass() {
|
||||
@@ -98,6 +102,16 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase {
|
||||
if (self::$stateFilesTrashbin) {
|
||||
OC_App::enable('files_trashbin');
|
||||
}
|
||||
|
||||
\OC_Hook::clear();
|
||||
\OC_FileProxy::clearProxies();
|
||||
|
||||
// Delete keys in /data/
|
||||
$view = new \OC\Files\View('/');
|
||||
$view->rmdir('public-keys');
|
||||
$view->rmdir('owncloud_private_key');
|
||||
|
||||
parent::tearDownAfterClass();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -135,15 +149,25 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase {
|
||||
$this->assertArrayHasKey('key', $sslInfo);
|
||||
}
|
||||
|
||||
function fileNameFromShareKeyProvider() {
|
||||
return array(
|
||||
array('file.user.shareKey', 'user', 'file'),
|
||||
array('file.name.with.dots.user.shareKey', 'user', 'file.name.with.dots'),
|
||||
array('file.name.user.with.dots.shareKey', 'user.with.dots', 'file.name'),
|
||||
array('file.txt', 'user', false),
|
||||
array('user.shareKey', 'user', false),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @small
|
||||
*
|
||||
* @dataProvider fileNameFromShareKeyProvider
|
||||
*/
|
||||
function testGetFilenameFromShareKey() {
|
||||
$this->assertEquals("file",
|
||||
\TestProtectedKeymanagerMethods::testGetFilenameFromShareKey("file.user.shareKey"));
|
||||
$this->assertEquals("file.name.with.dots",
|
||||
\TestProtectedKeymanagerMethods::testGetFilenameFromShareKey("file.name.with.dots.user.shareKey"));
|
||||
$this->assertFalse(\TestProtectedKeymanagerMethods::testGetFilenameFromShareKey("file.txt"));
|
||||
function testGetFilenameFromShareKey($fileName, $user, $expectedFileName) {
|
||||
$this->assertEquals($expectedFileName,
|
||||
\TestProtectedKeymanagerMethods::testGetFilenameFromShareKey($fileName, $user)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -153,7 +177,7 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
$key = $this->randomKey;
|
||||
|
||||
$file = 'unittest-' . uniqid() . '.txt';
|
||||
$file = 'unittest-' . $this->getUniqueID() . '.txt';
|
||||
|
||||
$util = new Encryption\Util($this->view, $this->userId);
|
||||
|
||||
@@ -249,6 +273,12 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase {
|
||||
$this->view->file_put_contents('/'.Test_Encryption_Keymanager::TEST_USER.'/files_encryption/share-keys/folder1/existingFile.txt.user1.shareKey', 'data');
|
||||
$this->view->file_put_contents('/'.Test_Encryption_Keymanager::TEST_USER.'/files_encryption/share-keys/folder1/existingFile.txt.' . Test_Encryption_Keymanager::TEST_USER . '.shareKey', 'data');
|
||||
$this->view->file_put_contents('/'.Test_Encryption_Keymanager::TEST_USER.'/files_encryption/share-keys/folder1/file1.user1.shareKey', 'data');
|
||||
$this->view->file_put_contents('/'.Test_Encryption_Keymanager::TEST_USER.'/files_encryption/share-keys/folder1/file1.user1.test.shareKey', 'data');
|
||||
$this->view->file_put_contents('/'.Test_Encryption_Keymanager::TEST_USER.'/files_encryption/share-keys/folder1/file1.test-keymanager-userxdot.shareKey', 'data');
|
||||
$this->view->file_put_contents('/'.Test_Encryption_Keymanager::TEST_USER.'/files_encryption/share-keys/folder1/file1.userx.' . Test_Encryption_Keymanager::TEST_USER . '.shareKey', 'data');
|
||||
$this->view->file_put_contents('/'.Test_Encryption_Keymanager::TEST_USER.'/files_encryption/share-keys/folder1/file1.' . Test_Encryption_Keymanager::TEST_USER . '.userx.shareKey', 'data');
|
||||
$this->view->file_put_contents('/'.Test_Encryption_Keymanager::TEST_USER.'/files_encryption/share-keys/folder1/file1.user1.' . Test_Encryption_Keymanager::TEST_USER . '.shareKey', 'data');
|
||||
$this->view->file_put_contents('/'.Test_Encryption_Keymanager::TEST_USER.'/files_encryption/share-keys/folder1/file1.' . Test_Encryption_Keymanager::TEST_USER . '.user1.shareKey', 'data');
|
||||
$this->view->file_put_contents('/'.Test_Encryption_Keymanager::TEST_USER.'/files_encryption/share-keys/folder1/file2.user2.shareKey', 'data');
|
||||
$this->view->file_put_contents('/'.Test_Encryption_Keymanager::TEST_USER.'/files_encryption/share-keys/folder1/file2.user3.shareKey', 'data');
|
||||
$this->view->file_put_contents('/'.Test_Encryption_Keymanager::TEST_USER.'/files_encryption/share-keys/folder1/subfolder/file2.user3.shareKey', 'data');
|
||||
@@ -279,6 +309,23 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase {
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/'.Test_Encryption_Keymanager::TEST_USER.'/files_encryption/share-keys/folder1/subfolder/file2.user3.shareKey'));
|
||||
|
||||
// check if share keys for user or file with similar name
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/'.Test_Encryption_Keymanager::TEST_USER.'/files_encryption/share-keys/folder1/file1.user1.test.shareKey'));
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/'.Test_Encryption_Keymanager::TEST_USER.'/files_encryption/share-keys/folder1/file1.test-keymanager-userxdot.shareKey'));
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/'.Test_Encryption_Keymanager::TEST_USER.'/files_encryption/share-keys/folder1/file1.' . Test_Encryption_Keymanager::TEST_USER . '.userx.shareKey'));
|
||||
// FIXME: this case currently cannot be distinguished, needs further fixing
|
||||
/*
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/'.Test_Encryption_Keymanager::TEST_USER.'/files_encryption/share-keys/folder1/file1.userx.' . Test_Encryption_Keymanager::TEST_USER . '.shareKey'));
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/'.Test_Encryption_Keymanager::TEST_USER.'/files_encryption/share-keys/folder1/file1.user1.' . Test_Encryption_Keymanager::TEST_USER . '.shareKey'));
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/'.Test_Encryption_Keymanager::TEST_USER.'/files_encryption/share-keys/folder1/file1.' . Test_Encryption_Keymanager::TEST_USER . '.user1.shareKey'));
|
||||
*/
|
||||
|
||||
// owner key from existing file should still exists because the file is still there
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/'.Test_Encryption_Keymanager::TEST_USER.'/files_encryption/share-keys/folder1/existingFile.txt.' . Test_Encryption_Keymanager::TEST_USER . '.shareKey'));
|
||||
@@ -432,18 +479,19 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase {
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/'.Test_Encryption_Keymanager::TEST_USER.'/files_encryption/share-keys/folder1/existingFile.txt.user3.shareKey'));
|
||||
|
||||
// try to del all share keys froma file, should fail because the file still exists
|
||||
// try to del all share keys from file, should succeed because the does not exist any more
|
||||
$result2 = Encryption\Keymanager::delAllShareKeys($this->view, Test_Encryption_Keymanager::TEST_USER, 'folder1/nonexistingFile.txt');
|
||||
$this->assertTrue($result2);
|
||||
|
||||
// check if share keys are really gone
|
||||
$this->assertFalse($this->view->file_exists(
|
||||
'/'.Test_Encryption_Keymanager::TEST_USER.'/files_encryption/share-keys/folder1/nonexistingFile.txt.' . Test_Encryption_Keymanager::TEST_USER . '.shareKey'));
|
||||
$this->assertFalse($this->view->file_exists(
|
||||
// check that it only deleted keys or users who had access, others remain
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/'.Test_Encryption_Keymanager::TEST_USER.'/files_encryption/share-keys/folder1/nonexistingFile.txt.user1.shareKey'));
|
||||
$this->assertFalse($this->view->file_exists(
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/'.Test_Encryption_Keymanager::TEST_USER.'/files_encryption/share-keys/folder1/nonexistingFile.txt.user2.shareKey'));
|
||||
$this->assertFalse($this->view->file_exists(
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/'.Test_Encryption_Keymanager::TEST_USER.'/files_encryption/share-keys/folder1/nonexistingFile.txt.user3.shareKey'));
|
||||
|
||||
// cleanup
|
||||
@@ -479,8 +527,8 @@ class TestProtectedKeymanagerMethods extends \OCA\Encryption\Keymanager {
|
||||
/**
|
||||
* @param string $sharekey
|
||||
*/
|
||||
public static function testGetFilenameFromShareKey($sharekey) {
|
||||
return self::getFilenameFromShareKey($sharekey);
|
||||
public static function testGetFilenameFromShareKey($sharekey, $user) {
|
||||
return self::getFilenameFromShareKey($sharekey, $user);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,7 +27,6 @@ require_once __DIR__ . '/../lib/proxy.php';
|
||||
require_once __DIR__ . '/../lib/stream.php';
|
||||
require_once __DIR__ . '/../lib/util.php';
|
||||
require_once __DIR__ . '/../appinfo/app.php';
|
||||
require_once __DIR__ . '/util.php';
|
||||
|
||||
use OCA\Encryption;
|
||||
|
||||
@@ -35,7 +34,7 @@ use OCA\Encryption;
|
||||
* Class Test_Encryption_Proxy
|
||||
* this class provide basic proxy app tests
|
||||
*/
|
||||
class Test_Encryption_Proxy extends \PHPUnit_Framework_TestCase {
|
||||
class Test_Encryption_Proxy extends \OCA\Files_Encryption\Tests\TestCase {
|
||||
|
||||
const TEST_ENCRYPTION_PROXY_USER1 = "test-proxy-user1";
|
||||
|
||||
@@ -47,9 +46,12 @@ class Test_Encryption_Proxy extends \PHPUnit_Framework_TestCase {
|
||||
public $view; // view in /data/user/files
|
||||
public $rootView; // view on /data/user
|
||||
public $data;
|
||||
public $dataLong;
|
||||
public $filename;
|
||||
|
||||
public static function setUpBeforeClass() {
|
||||
parent::setUpBeforeClass();
|
||||
|
||||
// reset backend
|
||||
\OC_User::clearBackends();
|
||||
\OC_User::useBackend('database');
|
||||
@@ -65,10 +67,12 @@ class Test_Encryption_Proxy extends \PHPUnit_Framework_TestCase {
|
||||
\OC_FileProxy::register(new OCA\Encryption\Proxy());
|
||||
|
||||
// create test user
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Proxy::TEST_ENCRYPTION_PROXY_USER1, true);
|
||||
self::loginHelper(\Test_Encryption_Proxy::TEST_ENCRYPTION_PROXY_USER1, true);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// set user id
|
||||
\OC_User::setUserId(\Test_Encryption_Proxy::TEST_ENCRYPTION_PROXY_USER1);
|
||||
$this->userId = \Test_Encryption_Proxy::TEST_ENCRYPTION_PROXY_USER1;
|
||||
@@ -80,13 +84,24 @@ class Test_Encryption_Proxy extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
// init short data
|
||||
$this->data = 'hats';
|
||||
$this->filename = 'enc_proxy_tests-' . uniqid() . '.txt';
|
||||
$this->dataLong = file_get_contents(__DIR__ . '/../lib/crypt.php');
|
||||
$this->filename = 'enc_proxy_tests-' . $this->getUniqueID() . '.txt';
|
||||
|
||||
}
|
||||
|
||||
public static function tearDownAfterClass() {
|
||||
// cleanup test user
|
||||
\OC_User::deleteUser(\Test_Encryption_Proxy::TEST_ENCRYPTION_PROXY_USER1);
|
||||
|
||||
\OC_Hook::clear();
|
||||
\OC_FileProxy::clearProxies();
|
||||
|
||||
// Delete keys in /data/
|
||||
$view = new \OC\Files\View('/');
|
||||
$view->rmdir('public-keys');
|
||||
$view->rmdir('owncloud_private_key');
|
||||
|
||||
parent::tearDownAfterClass();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,17 +110,19 @@ class Test_Encryption_Proxy extends \PHPUnit_Framework_TestCase {
|
||||
*/
|
||||
function testPostFileSize() {
|
||||
|
||||
$this->view->file_put_contents($this->filename, $this->data);
|
||||
$this->view->file_put_contents($this->filename, $this->dataLong);
|
||||
$size = strlen($this->dataLong);
|
||||
|
||||
\OC_FileProxy::$enabled = false;
|
||||
|
||||
$unencryptedSize = $this->view->filesize($this->filename);
|
||||
$encryptedSize = $this->view->filesize($this->filename);
|
||||
|
||||
\OC_FileProxy::$enabled = true;
|
||||
|
||||
$encryptedSize = $this->view->filesize($this->filename);
|
||||
$unencryptedSize = $this->view->filesize($this->filename);
|
||||
|
||||
$this->assertTrue($encryptedSize !== $unencryptedSize);
|
||||
$this->assertTrue($encryptedSize > $unencryptedSize);
|
||||
$this->assertSame($size, $unencryptedSize);
|
||||
|
||||
// cleanup
|
||||
$this->view->unlink($this->filename);
|
||||
@@ -132,4 +149,42 @@ class Test_Encryption_Proxy extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider isExcludedPathProvider
|
||||
*/
|
||||
function testIsExcludedPath($path, $expected) {
|
||||
$this->view->mkdir(dirname($path));
|
||||
$this->view->file_put_contents($path, "test");
|
||||
|
||||
$testClass = new DummyProxy();
|
||||
|
||||
$result = $testClass->isExcludedPathTesting($path, $this->userId);
|
||||
$this->assertSame($expected, $result);
|
||||
|
||||
$this->view->deleteAll(dirname($path));
|
||||
|
||||
}
|
||||
|
||||
public function isExcludedPathProvider() {
|
||||
return array(
|
||||
array ('/' . \Test_Encryption_Proxy::TEST_ENCRYPTION_PROXY_USER1 . '/files/test.txt', false),
|
||||
array (\Test_Encryption_Proxy::TEST_ENCRYPTION_PROXY_USER1 . '/files/test.txt', false),
|
||||
array ('/files/test.txt', true),
|
||||
array ('/' . \Test_Encryption_Proxy::TEST_ENCRYPTION_PROXY_USER1 . '/files/versions/test.txt', false),
|
||||
array ('/' . \Test_Encryption_Proxy::TEST_ENCRYPTION_PROXY_USER1 . '/files_versions/test.txt', false),
|
||||
array ('/' . \Test_Encryption_Proxy::TEST_ENCRYPTION_PROXY_USER1 . '/files_trashbin/test.txt', true),
|
||||
array ('/' . \Test_Encryption_Proxy::TEST_ENCRYPTION_PROXY_USER1 . '/file/test.txt', true),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Dummy class to make protected methods available for testing
|
||||
*/
|
||||
class DummyProxy extends \OCA\Encryption\Proxy {
|
||||
public function isExcludedPathTesting($path, $uid) {
|
||||
return $this->isExcludedPath($path, $uid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,14 +29,13 @@ require_once __DIR__ . '/../lib/stream.php';
|
||||
require_once __DIR__ . '/../lib/util.php';
|
||||
require_once __DIR__ . '/../lib/helper.php';
|
||||
require_once __DIR__ . '/../appinfo/app.php';
|
||||
require_once __DIR__ . '/util.php';
|
||||
|
||||
use OCA\Encryption;
|
||||
|
||||
/**
|
||||
* Class Test_Encryption_Share
|
||||
*/
|
||||
class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
class Test_Encryption_Share extends \OCA\Files_Encryption\Tests\TestCase {
|
||||
|
||||
const TEST_ENCRYPTION_SHARE_USER1 = "test-share-user1";
|
||||
const TEST_ENCRYPTION_SHARE_USER2 = "test-share-user2";
|
||||
@@ -56,6 +55,8 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
public $subsubfolder;
|
||||
|
||||
public static function setUpBeforeClass() {
|
||||
parent::setUpBeforeClass();
|
||||
|
||||
// reset backend
|
||||
\OC_User::clearBackends();
|
||||
\OC_User::useBackend('database');
|
||||
@@ -65,8 +66,10 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
// clear share hooks
|
||||
\OC_Hook::clear('OCP\\Share');
|
||||
|
||||
// register share hooks
|
||||
\OC::registerShareHooks();
|
||||
\OCP\Util::connectHook('OC_Filesystem', 'setup', '\OC\Files\Storage\Shared', 'setup');
|
||||
\OCA\Files_Sharing\Helper::registerHooks();
|
||||
|
||||
// Sharing related hooks
|
||||
\OCA\Encryption\Helper::registerShareHooks();
|
||||
@@ -76,13 +79,14 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
// clear and register hooks
|
||||
\OC_FileProxy::clearProxies();
|
||||
\OC_FileProxy::register(new OCA\Files\Share\Proxy());
|
||||
\OC_FileProxy::register(new OCA\Encryption\Proxy());
|
||||
|
||||
// create users
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1, true);
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2, true);
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3, true);
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER4, true);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1, true);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2, true);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3, true);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER4, true);
|
||||
|
||||
// create group and assign users
|
||||
\OC_Group::createGroup(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_GROUP1);
|
||||
@@ -90,7 +94,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
\OC_Group::addToGroup(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER4, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_GROUP1);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->dataShort = 'hats';
|
||||
$this->view = new \OC\Files\View('/');
|
||||
|
||||
@@ -105,15 +111,20 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
// we don't want to tests with app files_trashbin enabled
|
||||
\OC_App::disable('files_trashbin');
|
||||
|
||||
// login as first user
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
protected function tearDown() {
|
||||
// reset app files_trashbin
|
||||
if ($this->stateFilesTrashbin) {
|
||||
OC_App::enable('files_trashbin');
|
||||
} else {
|
||||
OC_App::disable('files_trashbin');
|
||||
}
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
public static function tearDownAfterClass() {
|
||||
@@ -125,6 +136,16 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
\OC_User::deleteUser(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
|
||||
\OC_User::deleteUser(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3);
|
||||
\OC_User::deleteUser(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER4);
|
||||
|
||||
\OC_Hook::clear();
|
||||
\OC_FileProxy::clearProxies();
|
||||
|
||||
// Delete keys in /data/
|
||||
$view = new \OC\Files\View('/');
|
||||
$view->rmdir('public-keys');
|
||||
$view->rmdir('owncloud_private_key');
|
||||
|
||||
parent::tearDownAfterClass();
|
||||
}
|
||||
|
||||
|
||||
@@ -134,7 +155,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
*/
|
||||
function testShareFile($withTeardown = true) {
|
||||
// login as admin
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
|
||||
// save file with content
|
||||
$cryptedFile = file_put_contents('crypt:///' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename, $this->dataShort);
|
||||
@@ -163,7 +184,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
\OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2, OCP\PERMISSION_ALL);
|
||||
|
||||
// login as admin
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
|
||||
// check if share key for user1 exists
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
@@ -171,7 +192,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
. $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey'));
|
||||
|
||||
// login as user1
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
|
||||
|
||||
// get file contents
|
||||
$retrievedCryptedFile = $this->view->file_get_contents(
|
||||
@@ -184,7 +205,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
if ($withTeardown) {
|
||||
|
||||
// login as admin
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
|
||||
// unshare the file
|
||||
\OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
|
||||
@@ -214,7 +235,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
$this->testShareFile(false);
|
||||
|
||||
// login as user2
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
|
||||
|
||||
// get the file info
|
||||
$fileInfo = $this->view->getFileInfo(
|
||||
@@ -224,7 +245,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
\OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3, OCP\PERMISSION_ALL);
|
||||
|
||||
// login as admin
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
|
||||
// check if share key for user2 exists
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
@@ -232,7 +253,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
. $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3 . '.shareKey'));
|
||||
|
||||
// login as user2
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3);
|
||||
|
||||
// get file contents
|
||||
$retrievedCryptedFile = $this->view->file_get_contents(
|
||||
@@ -245,13 +266,13 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
if ($withTeardown) {
|
||||
|
||||
// login as user1
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
|
||||
|
||||
// unshare the file with user2
|
||||
\OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3);
|
||||
|
||||
// login as admin
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
|
||||
// check if share key not exists
|
||||
$this->assertFalse($this->view->file_exists(
|
||||
@@ -285,7 +306,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
*/
|
||||
function testShareFolder($withTeardown = true) {
|
||||
// login as admin
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
|
||||
// create folder structure
|
||||
$this->view->mkdir('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files' . $this->folder1);
|
||||
@@ -320,7 +341,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
\OCP\Share::shareItem('folder', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2, OCP\PERMISSION_ALL);
|
||||
|
||||
// login as admin
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
|
||||
// check if share key for user1 exists
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
@@ -329,7 +350,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
. $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey'));
|
||||
|
||||
// login as user1
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
|
||||
|
||||
// get file contents
|
||||
$retrievedCryptedFile = $this->view->file_get_contents(
|
||||
@@ -343,7 +364,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
if ($withTeardown) {
|
||||
|
||||
// login as admin
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
|
||||
// unshare the folder with user1
|
||||
\OCP\Share::unshare('folder', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
|
||||
@@ -377,7 +398,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
$fileInfoFolder1 = $this->testShareFolder(false);
|
||||
|
||||
// login as user2
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
|
||||
|
||||
// disable encryption proxy to prevent recursive calls
|
||||
$proxyStatus = \OC_FileProxy::$enabled;
|
||||
@@ -398,7 +419,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
\OCP\Share::shareItem('folder', $fileInfoSubFolder['fileid'], \OCP\Share::SHARE_TYPE_USER, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3, OCP\PERMISSION_ALL);
|
||||
|
||||
// login as admin
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
|
||||
// check if share key for user3 exists
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
@@ -407,7 +428,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
. $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3 . '.shareKey'));
|
||||
|
||||
// login as user3
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3);
|
||||
|
||||
// get file contents
|
||||
$retrievedCryptedFile = $this->view->file_get_contents(
|
||||
@@ -429,7 +450,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
\OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER4, OCP\PERMISSION_ALL);
|
||||
|
||||
// login as admin
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
|
||||
// check if share key for user3 exists
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
@@ -438,7 +459,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
. $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER4 . '.shareKey'));
|
||||
|
||||
// login as user3
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER4);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER4);
|
||||
|
||||
// get file contents
|
||||
$retrievedCryptedFile = $this->view->file_get_contents(
|
||||
@@ -451,7 +472,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
if ($withTeardown) {
|
||||
|
||||
// login as user2
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3);
|
||||
|
||||
// unshare the file with user3
|
||||
\OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER4);
|
||||
@@ -463,7 +484,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
. $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER4 . '.shareKey'));
|
||||
|
||||
// login as user1
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
|
||||
|
||||
// unshare the folder with user2
|
||||
\OCP\Share::unshare('folder', $fileInfoSubFolder['fileid'], \OCP\Share::SHARE_TYPE_USER, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3);
|
||||
@@ -475,7 +496,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
. $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3 . '.shareKey'));
|
||||
|
||||
// login as admin
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
|
||||
// unshare the folder1 with user1
|
||||
\OCP\Share::unshare('folder', $fileInfoFolder1['fileid'], \OCP\Share::SHARE_TYPE_USER, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
|
||||
@@ -502,7 +523,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
function testPublicShareFile() {
|
||||
// login as admin
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
|
||||
// save file with content
|
||||
$cryptedFile = file_put_contents('crypt:///' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename, $this->dataShort);
|
||||
@@ -531,7 +552,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
\OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, false, OCP\PERMISSION_ALL);
|
||||
|
||||
// login as admin
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
|
||||
$publicShareKeyId = \OC::$server->getAppConfig()->getValue('files_encryption', 'publicShareKeyId');
|
||||
|
||||
@@ -543,7 +564,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
// some hacking to simulate public link
|
||||
//$GLOBALS['app'] = 'files_sharing';
|
||||
//$GLOBALS['fileOwner'] = \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1;
|
||||
\Test_Encryption_Util::logoutHelper();
|
||||
self::logoutHelper();
|
||||
|
||||
// get file contents
|
||||
$retrievedCryptedFile = file_get_contents('crypt:///' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename);
|
||||
@@ -554,7 +575,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
// tear down
|
||||
|
||||
// login as admin
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
|
||||
// unshare the file
|
||||
\OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, null);
|
||||
@@ -580,7 +601,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
*/
|
||||
function testShareFileWithGroup() {
|
||||
// login as admin
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
|
||||
// save file with content
|
||||
$cryptedFile = file_put_contents('crypt:///' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename, $this->dataShort);
|
||||
@@ -609,7 +630,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
\OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_GROUP1, OCP\PERMISSION_ALL);
|
||||
|
||||
// login as admin
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
|
||||
// check if share key for user2 and user3 exists
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
@@ -620,7 +641,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
. $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER4 . '.shareKey'));
|
||||
|
||||
// login as user1
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3);
|
||||
|
||||
// get file contents
|
||||
$retrievedCryptedFile = $this->view->file_get_contents(
|
||||
@@ -630,7 +651,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
$this->assertEquals($this->dataShort, $retrievedCryptedFile);
|
||||
|
||||
// login as admin
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
|
||||
// unshare the file
|
||||
\OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_GROUP1);
|
||||
@@ -661,13 +682,13 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
function testRecoveryFile() {
|
||||
|
||||
// login as admin
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
|
||||
\OCA\Encryption\Helper::adminEnableRecovery(null, 'test123');
|
||||
$recoveryKeyId = \OC::$server->getAppConfig()->getValue('files_encryption', 'recoveryKeyId');
|
||||
|
||||
// login as admin
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
|
||||
$util = new \OCA\Encryption\Util(new \OC\Files\View('/'), \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
|
||||
@@ -767,7 +788,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
function testRecoveryForUser() {
|
||||
|
||||
// login as admin
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
|
||||
$result = \OCA\Encryption\Helper::adminEnableRecovery(null, 'test123');
|
||||
$this->assertTrue($result);
|
||||
@@ -775,7 +796,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
$recoveryKeyId = \OC::$server->getAppConfig()->getValue('files_encryption', 'recoveryKeyId');
|
||||
|
||||
// login as user2
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
|
||||
|
||||
$util = new \OCA\Encryption\Util(new \OC\Files\View('/'), \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
|
||||
|
||||
@@ -819,7 +840,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
. $this->filename . '.' . $recoveryKeyId . '.shareKey'));
|
||||
|
||||
// login as admin
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
|
||||
// change password
|
||||
\OC_User::setPassword(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2, 'test', 'test123');
|
||||
@@ -829,7 +850,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
\OCA\Encryption\Hooks::setPassphrase($params);
|
||||
|
||||
// login as user2
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2, false, 'test');
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2, false, 'test');
|
||||
|
||||
// get file contents
|
||||
$retrievedCryptedFile1 = file_get_contents('crypt:///' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/' . $this->filename);
|
||||
@@ -881,7 +902,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
*/
|
||||
function testFailShareFile() {
|
||||
// login as admin
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
|
||||
// save file with content
|
||||
$cryptedFile = file_put_contents('crypt:///' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename, $this->dataShort);
|
||||
@@ -919,7 +940,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
|
||||
// login as admin
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
|
||||
// check if share key for user1 not exists
|
||||
$this->assertFalse($this->view->file_exists(
|
||||
@@ -964,7 +985,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
function testRename() {
|
||||
|
||||
// login as admin
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
|
||||
// save file with content
|
||||
$cryptedFile = file_put_contents('crypt:///' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename, $this->dataShort);
|
||||
@@ -989,7 +1010,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
|
||||
// login as user2
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
|
||||
|
||||
$this->assertTrue($this->view->file_exists('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/' . $this->filename));
|
||||
|
||||
@@ -1012,7 +1033,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
$this->assertEquals($this->dataShort, $retrievedRenamedFile);
|
||||
|
||||
// cleanup
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
$this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename);
|
||||
}
|
||||
|
||||
@@ -1024,8 +1045,8 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
$view = new \OC\Files\View('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
|
||||
$filename = '/tmp-' . uniqid();
|
||||
$folder = '/folder' . uniqid();
|
||||
$filename = '/tmp-' . $this->getUniqueID();
|
||||
$folder = '/folder' . $this->getUniqueID();
|
||||
|
||||
\OC\Files\Filesystem::mkdir($folder);
|
||||
|
||||
@@ -1040,7 +1061,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
$this->assertEquals($this->dataShort, $decrypt);
|
||||
|
||||
$newFolder = '/newfolder/subfolder' . uniqid();
|
||||
$newFolder = '/newfolder/subfolder' . $this->getUniqueID();
|
||||
\OC\Files\Filesystem::mkdir('/newfolder');
|
||||
|
||||
// get the file info from previous created file
|
||||
@@ -1059,9 +1080,79 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
// check if additional share key for user2 exists
|
||||
$this->assertTrue($view->file_exists('files_encryption/share-keys' . $newFolder . '/' . $filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey'));
|
||||
|
||||
// check that old keys were removed/moved properly
|
||||
$this->assertFalse($view->file_exists('files_encryption/share-keys' . $folder . '/' . $filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey'));
|
||||
|
||||
// tear down
|
||||
\OC\Files\Filesystem::unlink($newFolder);
|
||||
\OC\Files\Filesystem::unlink('/newfolder');
|
||||
}
|
||||
|
||||
function usersProvider() {
|
||||
return array(
|
||||
// test as owner
|
||||
array(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1),
|
||||
// test as share receiver
|
||||
array(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider usersProvider
|
||||
*/
|
||||
function testMoveFileToFolder($userId) {
|
||||
$view = new \OC\Files\View('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
|
||||
$filename = '/tmp-' . $this->getUniqueID();
|
||||
$folder = '/folder' . $this->getUniqueID();
|
||||
|
||||
\OC\Files\Filesystem::mkdir($folder);
|
||||
|
||||
// Save long data as encrypted file using stream wrapper
|
||||
$cryptedFile = \OC\Files\Filesystem::file_put_contents($folder . $filename, $this->dataShort);
|
||||
|
||||
// Test that data was successfully written
|
||||
$this->assertTrue(is_int($cryptedFile));
|
||||
|
||||
// Get file decrypted contents
|
||||
$decrypt = \OC\Files\Filesystem::file_get_contents($folder . $filename);
|
||||
|
||||
$this->assertEquals($this->dataShort, $decrypt);
|
||||
|
||||
$subFolder = $folder . '/subfolder' . $this->getUniqueID();
|
||||
\OC\Files\Filesystem::mkdir($subFolder);
|
||||
|
||||
// get the file info from previous created file
|
||||
$fileInfo = \OC\Files\Filesystem::getFileInfo($folder);
|
||||
$this->assertTrue($fileInfo instanceof \OC\Files\FileInfo);
|
||||
|
||||
// share the folder
|
||||
\OCP\Share::shareItem('folder', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2, OCP\PERMISSION_ALL);
|
||||
|
||||
// check that the share keys exist
|
||||
$this->assertTrue($view->file_exists('files_encryption/share-keys' . $folder . '/' . $filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '.shareKey'));
|
||||
$this->assertTrue($view->file_exists('files_encryption/share-keys' . $folder . '/' . $filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey'));
|
||||
|
||||
// move the file into the subfolder as the test user
|
||||
self::loginHelper($userId);
|
||||
\OC\Files\Filesystem::rename($folder . $filename, $subFolder . $filename);
|
||||
self::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
|
||||
// Get file decrypted contents
|
||||
$newDecrypt = \OC\Files\Filesystem::file_get_contents($subFolder . $filename);
|
||||
$this->assertEquals($this->dataShort, $newDecrypt);
|
||||
|
||||
// check if additional share key for user2 exists
|
||||
$this->assertTrue($view->file_exists('files_encryption/share-keys' . $subFolder . '/' . $filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '.shareKey'));
|
||||
$this->assertTrue($view->file_exists('files_encryption/share-keys' . $subFolder . '/' . $filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey'));
|
||||
|
||||
// check that old keys were removed/moved properly
|
||||
$this->assertFalse($view->file_exists('files_encryption/share-keys' . $folder . '/' . $filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '.shareKey'));
|
||||
$this->assertFalse($view->file_exists('files_encryption/share-keys' . $folder . '/' . $filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey'));
|
||||
|
||||
// tear down
|
||||
\OC\Files\Filesystem::unlink($subFolder);
|
||||
\OC\Files\Filesystem::unlink($folder);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ require_once __DIR__ . '/../lib/proxy.php';
|
||||
require_once __DIR__ . '/../lib/stream.php';
|
||||
require_once __DIR__ . '/../lib/util.php';
|
||||
require_once __DIR__ . '/../appinfo/app.php';
|
||||
require_once __DIR__ . '/util.php';
|
||||
|
||||
use OCA\Encryption;
|
||||
|
||||
@@ -35,7 +34,7 @@ use OCA\Encryption;
|
||||
* Class Test_Encryption_Stream
|
||||
* this class provide basic stream tests
|
||||
*/
|
||||
class Test_Encryption_Stream extends \PHPUnit_Framework_TestCase {
|
||||
class Test_Encryption_Stream extends \OCA\Files_Encryption\Tests\TestCase {
|
||||
|
||||
const TEST_ENCRYPTION_STREAM_USER1 = "test-stream-user1";
|
||||
|
||||
@@ -49,6 +48,8 @@ class Test_Encryption_Stream extends \PHPUnit_Framework_TestCase {
|
||||
public $stateFilesTrashbin;
|
||||
|
||||
public static function setUpBeforeClass() {
|
||||
parent::setUpBeforeClass();
|
||||
|
||||
// reset backend
|
||||
\OC_User::clearBackends();
|
||||
\OC_User::useBackend('database');
|
||||
@@ -61,10 +62,12 @@ class Test_Encryption_Stream extends \PHPUnit_Framework_TestCase {
|
||||
\OC_FileProxy::register(new OCA\Encryption\Proxy());
|
||||
|
||||
// create test user
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Stream::TEST_ENCRYPTION_STREAM_USER1, true);
|
||||
self::loginHelper(\Test_Encryption_Stream::TEST_ENCRYPTION_STREAM_USER1, true);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// set user id
|
||||
\OC_User::setUserId(\Test_Encryption_Stream::TEST_ENCRYPTION_STREAM_USER1);
|
||||
$this->userId = \Test_Encryption_Stream::TEST_ENCRYPTION_STREAM_USER1;
|
||||
@@ -83,7 +86,7 @@ class Test_Encryption_Stream extends \PHPUnit_Framework_TestCase {
|
||||
\OC_App::disable('files_trashbin');
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
protected function tearDown() {
|
||||
// reset app files_trashbin
|
||||
if ($this->stateFilesTrashbin) {
|
||||
OC_App::enable('files_trashbin');
|
||||
@@ -91,15 +94,27 @@ class Test_Encryption_Stream extends \PHPUnit_Framework_TestCase {
|
||||
else {
|
||||
OC_App::disable('files_trashbin');
|
||||
}
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
public static function tearDownAfterClass() {
|
||||
// cleanup test user
|
||||
\OC_User::deleteUser(\Test_Encryption_Stream::TEST_ENCRYPTION_STREAM_USER1);
|
||||
|
||||
\OC_Hook::clear();
|
||||
\OC_FileProxy::clearProxies();
|
||||
|
||||
// Delete keys in /data/
|
||||
$view = new \OC\Files\View('/');
|
||||
$view->rmdir('public-keys');
|
||||
$view->rmdir('owncloud_private_key');
|
||||
|
||||
parent::tearDownAfterClass();
|
||||
}
|
||||
|
||||
function testStreamOptions() {
|
||||
$filename = '/tmp-' . uniqid();
|
||||
$filename = '/tmp-' . $this->getUniqueID();
|
||||
$view = new \OC\Files\View('/' . $this->userId . '/files');
|
||||
|
||||
// Save short data as encrypted file using stream wrapper
|
||||
@@ -117,12 +132,14 @@ class Test_Encryption_Stream extends \PHPUnit_Framework_TestCase {
|
||||
$this->assertTrue(flock($handle, LOCK_SH));
|
||||
$this->assertTrue(flock($handle, LOCK_UN));
|
||||
|
||||
fclose($handle);
|
||||
|
||||
// tear down
|
||||
$view->unlink($filename);
|
||||
}
|
||||
|
||||
function testStreamSetBlocking() {
|
||||
$filename = '/tmp-' . uniqid();
|
||||
$filename = '/tmp-' . $this->getUniqueID();
|
||||
$view = new \OC\Files\View('/' . $this->userId . '/files');
|
||||
|
||||
// Save short data as encrypted file using stream wrapper
|
||||
@@ -133,6 +150,13 @@ class Test_Encryption_Stream extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
$handle = $view->fopen($filename, 'r');
|
||||
|
||||
|
||||
if (\OC_Util::runningOnWindows()) {
|
||||
fclose($handle);
|
||||
$view->unlink($filename);
|
||||
$this->markTestSkipped('[Windows] stream_set_blocking() does not work as expected on Windows.');
|
||||
}
|
||||
|
||||
// set stream options
|
||||
$this->assertTrue(stream_set_blocking($handle, 1));
|
||||
|
||||
@@ -146,7 +170,7 @@ class Test_Encryption_Stream extends \PHPUnit_Framework_TestCase {
|
||||
* @medium
|
||||
*/
|
||||
function testStreamSetTimeout() {
|
||||
$filename = '/tmp-' . uniqid();
|
||||
$filename = '/tmp-' . $this->getUniqueID();
|
||||
$view = new \OC\Files\View('/' . $this->userId . '/files');
|
||||
|
||||
// Save short data as encrypted file using stream wrapper
|
||||
@@ -167,7 +191,7 @@ class Test_Encryption_Stream extends \PHPUnit_Framework_TestCase {
|
||||
}
|
||||
|
||||
function testStreamSetWriteBuffer() {
|
||||
$filename = '/tmp-' . uniqid();
|
||||
$filename = '/tmp-' . $this->getUniqueID();
|
||||
$view = new \OC\Files\View('/' . $this->userId . '/files');
|
||||
|
||||
// Save short data as encrypted file using stream wrapper
|
||||
@@ -193,9 +217,9 @@ class Test_Encryption_Stream extends \PHPUnit_Framework_TestCase {
|
||||
*/
|
||||
function testStreamFromLocalFile() {
|
||||
|
||||
$filename = '/' . $this->userId . '/files/' . 'tmp-' . uniqid().'.txt';
|
||||
$filename = '/' . $this->userId . '/files/' . 'tmp-' . $this->getUniqueID().'.txt';
|
||||
|
||||
$tmpFilename = "/tmp/" . uniqid() . ".txt";
|
||||
$tmpFilename = "/tmp/" . $this->getUniqueID() . ".txt";
|
||||
|
||||
// write an encrypted file
|
||||
$cryptedFile = $this->view->file_put_contents($filename, $this->dataShort);
|
||||
@@ -220,6 +244,8 @@ class Test_Encryption_Stream extends \PHPUnit_Framework_TestCase {
|
||||
// check if it was successful
|
||||
$this->assertEquals($this->dataShort, $contentFromTmpFile);
|
||||
|
||||
fclose($handle);
|
||||
|
||||
// clean up
|
||||
unlink($tmpFilename);
|
||||
$this->view->unlink($filename);
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (c) 2012 Sam Tuke <samtuke@owncloud.com>
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later.
|
||||
* See the COPYING-README file.
|
||||
*/
|
||||
|
||||
namespace OCA\Files_Encryption\Tests;
|
||||
|
||||
use OCA\Encryption;
|
||||
|
||||
/**
|
||||
* Class Test_Encryption_TestCase
|
||||
*/
|
||||
abstract class TestCase extends \Test\TestCase {
|
||||
/**
|
||||
* @param string $user
|
||||
* @param bool $create
|
||||
* @param bool $password
|
||||
*/
|
||||
public static function loginHelper($user, $create = false, $password = false, $loadEncryption = true) {
|
||||
if ($create) {
|
||||
try {
|
||||
\OC_User::createUser($user, $user);
|
||||
} catch (\Exception $e) {
|
||||
// catch username is already being used from previous aborted runs
|
||||
}
|
||||
}
|
||||
|
||||
if ($password === false) {
|
||||
$password = $user;
|
||||
}
|
||||
|
||||
\OC_Util::tearDownFS();
|
||||
\OC_User::setUserId('');
|
||||
\OC\Files\Filesystem::tearDown();
|
||||
\OC_User::setUserId($user);
|
||||
\OC_Util::setupFS($user);
|
||||
|
||||
if ($loadEncryption) {
|
||||
$params['uid'] = $user;
|
||||
$params['password'] = $password;
|
||||
\OCA\Encryption\Hooks::login($params);
|
||||
}
|
||||
}
|
||||
|
||||
public static function logoutHelper() {
|
||||
\OC_Util::tearDownFS();
|
||||
\OC_User::setUserId(false);
|
||||
\OC\Files\Filesystem::tearDown();
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,6 @@ require_once __DIR__ . '/../lib/stream.php';
|
||||
require_once __DIR__ . '/../lib/util.php';
|
||||
require_once __DIR__ . '/../appinfo/app.php';
|
||||
require_once __DIR__ . '/../../files_trashbin/appinfo/app.php';
|
||||
require_once __DIR__ . '/util.php';
|
||||
|
||||
use OCA\Encryption;
|
||||
|
||||
@@ -36,9 +35,10 @@ use OCA\Encryption;
|
||||
* Class Test_Encryption_Trashbin
|
||||
* this class provide basic trashbin app tests
|
||||
*/
|
||||
class Test_Encryption_Trashbin extends \PHPUnit_Framework_TestCase {
|
||||
class Test_Encryption_Trashbin extends \OCA\Files_Encryption\Tests\TestCase {
|
||||
|
||||
const TEST_ENCRYPTION_TRASHBIN_USER1 = "test-trashbin-user1";
|
||||
const TEST_ENCRYPTION_TRASHBIN_USER2 = "test-trashbin-user2";
|
||||
|
||||
public $userId;
|
||||
public $pass;
|
||||
@@ -53,12 +53,15 @@ class Test_Encryption_Trashbin extends \PHPUnit_Framework_TestCase {
|
||||
public $subsubfolder;
|
||||
|
||||
public static function setUpBeforeClass() {
|
||||
parent::setUpBeforeClass();
|
||||
|
||||
// reset backend
|
||||
\OC_User::clearBackends();
|
||||
\OC_User::useBackend('database');
|
||||
|
||||
\OC_Hook::clear('OC_Filesystem');
|
||||
\OC_Hook::clear('OC_User');
|
||||
\OC_Hook::clear('OCP\\Share');
|
||||
|
||||
// trashbin hooks
|
||||
\OCA\Files_Trashbin\Trashbin::registerHooks();
|
||||
@@ -66,19 +69,34 @@ class Test_Encryption_Trashbin extends \PHPUnit_Framework_TestCase {
|
||||
// Filesystem related hooks
|
||||
\OCA\Encryption\Helper::registerFilesystemHooks();
|
||||
|
||||
|
||||
// register share hooks
|
||||
\OC::registerShareHooks();
|
||||
\OCA\Files_Sharing\Helper::registerHooks();
|
||||
|
||||
// Sharing related hooks
|
||||
\OCA\Encryption\Helper::registerShareHooks();
|
||||
|
||||
// Filesystem related hooks
|
||||
\OCA\Encryption\Helper::registerFilesystemHooks();
|
||||
|
||||
// clear and register hooks
|
||||
\OC_FileProxy::clearProxies();
|
||||
\OC_FileProxy::register(new OCA\Files\Share\Proxy());
|
||||
\OC_FileProxy::register(new OCA\Encryption\Proxy());
|
||||
|
||||
// create test user
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1, true);
|
||||
self::loginHelper(self::TEST_ENCRYPTION_TRASHBIN_USER2, true);
|
||||
self::loginHelper(self::TEST_ENCRYPTION_TRASHBIN_USER1, true);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// set user id
|
||||
\OC_User::setUserId(\Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1);
|
||||
$this->userId = \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1;
|
||||
$this->pass = \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1;
|
||||
\OC_User::setUserId(self::TEST_ENCRYPTION_TRASHBIN_USER1);
|
||||
$this->userId = self::TEST_ENCRYPTION_TRASHBIN_USER1;
|
||||
$this->pass = self::TEST_ENCRYPTION_TRASHBIN_USER1;
|
||||
|
||||
// init filesystem view
|
||||
$this->view = new \OC\Files\View('/');
|
||||
@@ -93,11 +111,14 @@ class Test_Encryption_Trashbin extends \PHPUnit_Framework_TestCase {
|
||||
// remember files_trashbin state
|
||||
$this->stateFilesTrashbin = OC_App::isEnabled('files_trashbin');
|
||||
|
||||
$this->view->deleteAll('/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_trashbin');
|
||||
$this->view->deleteAll('/' . self::TEST_ENCRYPTION_TRASHBIN_USER2 . '/files_trashbin');
|
||||
|
||||
// we want to tests with app files_trashbin enabled
|
||||
\OC_App::enable('files_trashbin');
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
protected function tearDown() {
|
||||
// reset app files_trashbin
|
||||
if ($this->stateFilesTrashbin) {
|
||||
OC_App::enable('files_trashbin');
|
||||
@@ -105,11 +126,23 @@ class Test_Encryption_Trashbin extends \PHPUnit_Framework_TestCase {
|
||||
else {
|
||||
OC_App::disable('files_trashbin');
|
||||
}
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
public static function tearDownAfterClass() {
|
||||
// cleanup test user
|
||||
\OC_User::deleteUser(\Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1);
|
||||
\OC_User::deleteUser(self::TEST_ENCRYPTION_TRASHBIN_USER1);
|
||||
|
||||
\OC_Hook::clear();
|
||||
\OC_FileProxy::clearProxies();
|
||||
|
||||
// Delete keys in /data/
|
||||
$view = new \OC\Files\View('/');
|
||||
$view->rmdir('public-keys');
|
||||
$view->rmdir('owncloud_private_key');
|
||||
|
||||
parent::tearDownAfterClass();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -119,49 +152,72 @@ class Test_Encryption_Trashbin extends \PHPUnit_Framework_TestCase {
|
||||
function testDeleteFile() {
|
||||
|
||||
// generate filename
|
||||
$filename = 'tmp-' . uniqid() . '.txt';
|
||||
$filename = 'tmp-' . $this->getUniqueID() . '.txt';
|
||||
$filename2 = $filename . '.backup'; // a second file with similar name
|
||||
|
||||
// save file with content
|
||||
$cryptedFile = file_put_contents('crypt:///' .\Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1. '/files/'. $filename, $this->dataShort);
|
||||
$cryptedFile = file_put_contents('crypt:///' .self::TEST_ENCRYPTION_TRASHBIN_USER1. '/files/'. $filename, $this->dataShort);
|
||||
$cryptedFile2 = file_put_contents('crypt:///' .self::TEST_ENCRYPTION_TRASHBIN_USER1. '/files/'. $filename2, $this->dataShort);
|
||||
|
||||
// test that data was successfully written
|
||||
$this->assertTrue(is_int($cryptedFile));
|
||||
$this->assertTrue(is_int($cryptedFile2));
|
||||
|
||||
// check if key for admin exists
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/keyfiles/' . $filename
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/keyfiles/' . $filename
|
||||
. '.key'));
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/keyfiles/' . $filename2
|
||||
. '.key'));
|
||||
|
||||
// check if share key for admin exists
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/share-keys/'
|
||||
. $filename . '.' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '.shareKey'));
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/share-keys/'
|
||||
. $filename . '.' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '.shareKey'));
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/share-keys/'
|
||||
. $filename2 . '.' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '.shareKey'));
|
||||
|
||||
// delete file
|
||||
// delete first file
|
||||
\OC\FIles\Filesystem::unlink($filename);
|
||||
|
||||
// check if file not exists
|
||||
$this->assertFalse($this->view->file_exists(
|
||||
'/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files/' . $filename));
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files/' . $filename));
|
||||
|
||||
// check if key for admin not exists
|
||||
$this->assertFalse($this->view->file_exists(
|
||||
'/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/keyfiles/' . $filename
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/keyfiles/' . $filename
|
||||
. '.key'));
|
||||
|
||||
// check if share key for admin not exists
|
||||
$this->assertFalse($this->view->file_exists(
|
||||
'/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/share-keys/'
|
||||
. $filename . '.' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '.shareKey'));
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/share-keys/'
|
||||
. $filename . '.' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '.shareKey'));
|
||||
|
||||
// check that second file still exists
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files/' . $filename2));
|
||||
|
||||
// check that key for second file still exists
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/keyfiles/' . $filename2
|
||||
. '.key'));
|
||||
|
||||
// check that share key for second file still exists
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/share-keys/'
|
||||
. $filename2 . '.' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '.shareKey'));
|
||||
|
||||
// get files
|
||||
$trashFiles = $this->view->getDirectoryContent(
|
||||
'/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_trashbin/files/');
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_trashbin/files/');
|
||||
|
||||
$trashFileSuffix = null;
|
||||
// find created file with timestamp
|
||||
foreach ($trashFiles as $file) {
|
||||
if (strncmp($file['path'], $filename, strlen($filename))) {
|
||||
if (strpos($file['path'], $filename . '.d') !== false) {
|
||||
$path_parts = pathinfo($file['name']);
|
||||
$trashFileSuffix = $path_parts['extension'];
|
||||
}
|
||||
@@ -172,48 +228,77 @@ class Test_Encryption_Trashbin extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
// check if key for admin not exists
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_trashbin/keyfiles/' . $filename
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_trashbin/keyfiles/' . $filename
|
||||
. '.key.' . $trashFileSuffix));
|
||||
|
||||
// check if share key for admin not exists
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_trashbin/share-keys/' . $filename
|
||||
. '.' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '.shareKey.' . $trashFileSuffix));
|
||||
|
||||
// return filename for next test
|
||||
return $filename . '.' . $trashFileSuffix;
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_trashbin/share-keys/' . $filename
|
||||
. '.' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '.shareKey.' . $trashFileSuffix));
|
||||
}
|
||||
|
||||
/**
|
||||
* @medium
|
||||
* test restore file
|
||||
*
|
||||
* @depends testDeleteFile
|
||||
*/
|
||||
function testRestoreFile($filename) {
|
||||
function testRestoreFile() {
|
||||
// generate filename
|
||||
$filename = 'tmp-' . $this->getUniqueID() . '.txt';
|
||||
$filename2 = $filename . '.backup'; // a second file with similar name
|
||||
|
||||
// save file with content
|
||||
$cryptedFile = file_put_contents('crypt:///' . self::TEST_ENCRYPTION_TRASHBIN_USER1. '/files/'. $filename, $this->dataShort);
|
||||
$cryptedFile2 = file_put_contents('crypt:///' . self::TEST_ENCRYPTION_TRASHBIN_USER1. '/files/'. $filename2, $this->dataShort);
|
||||
|
||||
// delete both files
|
||||
\OC\Files\Filesystem::unlink($filename);
|
||||
\OC\Files\Filesystem::unlink($filename2);
|
||||
|
||||
$trashFiles = $this->view->getDirectoryContent('/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_trashbin/files/');
|
||||
|
||||
$trashFileSuffix = null;
|
||||
$trashFileSuffix2 = null;
|
||||
// find created file with timestamp
|
||||
foreach ($trashFiles as $file) {
|
||||
if (strpos($file['path'], $filename . '.d') !== false) {
|
||||
$path_parts = pathinfo($file['name']);
|
||||
$trashFileSuffix = $path_parts['extension'];
|
||||
}
|
||||
}
|
||||
|
||||
// prepare file information
|
||||
$path_parts = pathinfo($filename);
|
||||
$trashFileSuffix = $path_parts['extension'];
|
||||
$timestamp = str_replace('d', '', $trashFileSuffix);
|
||||
$fileNameWithoutSuffix = str_replace('.' . $trashFileSuffix, '', $filename);
|
||||
|
||||
// restore file
|
||||
$this->assertTrue(\OCA\Files_Trashbin\Trashbin::restore($filename, $fileNameWithoutSuffix, $timestamp));
|
||||
// restore first file
|
||||
$this->assertTrue(\OCA\Files_Trashbin\Trashbin::restore($filename . '.' . $trashFileSuffix, $filename, $timestamp));
|
||||
|
||||
// check if file exists
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files/' . $fileNameWithoutSuffix));
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files/' . $filename));
|
||||
|
||||
// check if key for admin exists
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/keyfiles/'
|
||||
. $fileNameWithoutSuffix . '.key'));
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/keyfiles/'
|
||||
. $filename . '.key'));
|
||||
|
||||
// check if share key for admin exists
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/share-keys/'
|
||||
. $fileNameWithoutSuffix . '.' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '.shareKey'));
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/share-keys/'
|
||||
. $filename . '.' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '.shareKey'));
|
||||
|
||||
// check that second file was NOT restored
|
||||
$this->assertFalse($this->view->file_exists(
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files/' . $filename2));
|
||||
|
||||
// check if key for admin exists
|
||||
$this->assertFalse($this->view->file_exists(
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/keyfiles/'
|
||||
. $filename2 . '.key'));
|
||||
|
||||
// check if share key for admin exists
|
||||
$this->assertFalse($this->view->file_exists(
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/share-keys/'
|
||||
. $filename2 . '.' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '.shareKey'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -223,7 +308,7 @@ class Test_Encryption_Trashbin extends \PHPUnit_Framework_TestCase {
|
||||
function testPermanentDeleteFile() {
|
||||
|
||||
// generate filename
|
||||
$filename = 'tmp-' . uniqid() . '.txt';
|
||||
$filename = 'tmp-' . $this->getUniqueID() . '.txt';
|
||||
|
||||
// save file with content
|
||||
$cryptedFile = file_put_contents('crypt:///' .$this->userId. '/files/' . $filename, $this->dataShort);
|
||||
@@ -233,30 +318,30 @@ class Test_Encryption_Trashbin extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
// check if key for admin exists
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/keyfiles/' . $filename
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/keyfiles/' . $filename
|
||||
. '.key'));
|
||||
|
||||
// check if share key for admin exists
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/share-keys/'
|
||||
. $filename . '.' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '.shareKey'));
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/share-keys/'
|
||||
. $filename . '.' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '.shareKey'));
|
||||
|
||||
// delete file
|
||||
\OC\FIles\Filesystem::unlink($filename);
|
||||
\OC\Files\Filesystem::unlink($filename);
|
||||
|
||||
// check if file not exists
|
||||
$this->assertFalse($this->view->file_exists(
|
||||
'/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files/' . $filename));
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files/' . $filename));
|
||||
|
||||
// check if key for admin not exists
|
||||
$this->assertFalse($this->view->file_exists(
|
||||
'/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/keyfiles/' . $filename
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/keyfiles/' . $filename
|
||||
. '.key'));
|
||||
|
||||
// check if share key for admin not exists
|
||||
$this->assertFalse($this->view->file_exists(
|
||||
'/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/share-keys/'
|
||||
. $filename . '.' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '.shareKey'));
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_encryption/share-keys/'
|
||||
. $filename . '.' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '.shareKey'));
|
||||
|
||||
// find created file with timestamp
|
||||
$query = \OC_DB::prepare('SELECT `timestamp`,`type` FROM `*PREFIX*files_trash`'
|
||||
@@ -270,13 +355,13 @@ class Test_Encryption_Trashbin extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
// check if key for admin exists
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_trashbin/keyfiles/' . $filename
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_trashbin/keyfiles/' . $filename
|
||||
. '.key.' . $trashFileSuffix));
|
||||
|
||||
// check if share key for admin exists
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_trashbin/share-keys/' . $filename
|
||||
. '.' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '.shareKey.' . $trashFileSuffix));
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_trashbin/share-keys/' . $filename
|
||||
. '.' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '.shareKey.' . $trashFileSuffix));
|
||||
|
||||
// get timestamp from file
|
||||
$timestamp = str_replace('d', '', $trashFileSuffix);
|
||||
@@ -286,18 +371,72 @@ class Test_Encryption_Trashbin extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
// check if key for admin not exists
|
||||
$this->assertFalse($this->view->file_exists(
|
||||
'/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_trashbin/files/' . $filename . '.'
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_trashbin/files/' . $filename . '.'
|
||||
. $trashFileSuffix));
|
||||
|
||||
// check if key for admin not exists
|
||||
$this->assertFalse($this->view->file_exists(
|
||||
'/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_trashbin/keyfiles/' . $filename
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_trashbin/keyfiles/' . $filename
|
||||
. '.key.' . $trashFileSuffix));
|
||||
|
||||
// check if share key for admin not exists
|
||||
$this->assertFalse($this->view->file_exists(
|
||||
'/' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_trashbin/share-keys/' . $filename
|
||||
. '.' . \Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1 . '.shareKey.' . $trashFileSuffix));
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_trashbin/share-keys/' . $filename
|
||||
. '.' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '.shareKey.' . $trashFileSuffix));
|
||||
}
|
||||
|
||||
|
||||
function testDeleteSharedFile() {
|
||||
|
||||
// generate filename
|
||||
$filename = 'tmp-' . $this->getUniqueID() . '.txt';
|
||||
|
||||
// save file with content
|
||||
$cryptedFile = file_put_contents('crypt:///' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files/' . $filename, $this->dataShort);
|
||||
// test that data was successfully written
|
||||
$this->assertTrue(is_int($cryptedFile));
|
||||
|
||||
// get the file info from previous created file
|
||||
$fileInfo = $this->view->getFileInfo(
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files/' . $filename);
|
||||
|
||||
// check if we have a valid file info
|
||||
$this->assertTrue($fileInfo instanceof \OC\Files\FileInfo);
|
||||
|
||||
// share the file
|
||||
$this->assertTrue(
|
||||
\OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, self::TEST_ENCRYPTION_TRASHBIN_USER2, OCP\PERMISSION_ALL)
|
||||
);
|
||||
|
||||
self::loginHelper(self::TEST_ENCRYPTION_TRASHBIN_USER2);
|
||||
|
||||
$this->assertTrue(\OC\Files\Filesystem::file_exists($filename));
|
||||
|
||||
\OCA\Files_Trashbin\Trashbin::move2trash($filename);
|
||||
|
||||
$query = \OC_DB::prepare('SELECT `timestamp` FROM `*PREFIX*files_trash`'
|
||||
. ' WHERE `id`=?');
|
||||
$result = $query->execute(array($filename))->fetchRow();
|
||||
|
||||
$this->assertNotEmpty($result);
|
||||
|
||||
$timestamp = $result['timestamp'];
|
||||
|
||||
// check if key for both users exists
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_trashbin/keyfiles/' . $filename
|
||||
. '.key.d'. $timestamp));
|
||||
// check if key for admin exists
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER2 . '/files_trashbin/keyfiles/' . $filename
|
||||
. '.key.d' . $timestamp));
|
||||
|
||||
// check if share key for both users exists
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_trashbin/share-keys/'
|
||||
. $filename . '.' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '.shareKey.d' . $timestamp));
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER2 . '/files_trashbin/share-keys/'
|
||||
. $filename . '.' . self::TEST_ENCRYPTION_TRASHBIN_USER2 . '.shareKey.d' . $timestamp));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ use OCA\Encryption;
|
||||
/**
|
||||
* Class Test_Encryption_Util
|
||||
*/
|
||||
class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
|
||||
class Test_Encryption_Util extends \OCA\Files_Encryption\Tests\TestCase {
|
||||
|
||||
const TEST_ENCRYPTION_UTIL_USER1 = "test-util-user1";
|
||||
const TEST_ENCRYPTION_UTIL_USER2 = "test-util-user2";
|
||||
@@ -49,21 +49,18 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
|
||||
public $stateFilesTrashbin;
|
||||
|
||||
public static function setUpBeforeClass() {
|
||||
parent::setUpBeforeClass();
|
||||
|
||||
// reset backend
|
||||
\OC_User::clearBackends();
|
||||
\OC_User::useBackend('database');
|
||||
|
||||
// Filesystem related hooks
|
||||
\OCA\Encryption\Helper::registerFilesystemHooks();
|
||||
|
||||
// clear and register hooks
|
||||
\OC_FileProxy::clearProxies();
|
||||
\OC_FileProxy::register(new OCA\Encryption\Proxy());
|
||||
self::setupHooks();
|
||||
|
||||
// create test user
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1, true);
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER2, true);
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER, true);
|
||||
self::loginHelper(self::TEST_ENCRYPTION_UTIL_USER1, true);
|
||||
self::loginHelper(self::TEST_ENCRYPTION_UTIL_USER2, true);
|
||||
self::loginHelper(self::TEST_ENCRYPTION_UTIL_LEGACY_USER, true);
|
||||
|
||||
// create groups
|
||||
\OC_Group::createGroup(self::TEST_ENCRYPTION_UTIL_GROUP1);
|
||||
@@ -73,13 +70,14 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
|
||||
\OC_Group::addToGroup(self::TEST_ENCRYPTION_UTIL_USER1, self::TEST_ENCRYPTION_UTIL_GROUP1);
|
||||
}
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
function setUp() {
|
||||
// login user
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1);
|
||||
\OC_User::setUserId(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1);
|
||||
$this->userId = \Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1;
|
||||
$this->pass = \Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1;
|
||||
self::loginHelper(self::TEST_ENCRYPTION_UTIL_USER1);
|
||||
\OC_User::setUserId(self::TEST_ENCRYPTION_UTIL_USER1);
|
||||
$this->userId = self::TEST_ENCRYPTION_UTIL_USER1;
|
||||
$this->pass = self::TEST_ENCRYPTION_UTIL_USER1;
|
||||
|
||||
// set content for encrypting / decrypting in tests
|
||||
$this->dataUrl = __DIR__ . '/../lib/crypt.php';
|
||||
@@ -114,7 +112,7 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
|
||||
\OC_App::disable('files_trashbin');
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
protected function tearDown() {
|
||||
// reset app files_trashbin
|
||||
if ($this->stateFilesTrashbin) {
|
||||
OC_App::enable('files_trashbin');
|
||||
@@ -122,16 +120,38 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
|
||||
else {
|
||||
OC_App::disable('files_trashbin');
|
||||
}
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
public static function tearDownAfterClass() {
|
||||
// cleanup test user
|
||||
\OC_User::deleteUser(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1);
|
||||
\OC_User::deleteUser(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER2);
|
||||
\OC_User::deleteUser(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_LEGACY_USER);
|
||||
\OC_User::deleteUser(self::TEST_ENCRYPTION_UTIL_USER1);
|
||||
\OC_User::deleteUser(self::TEST_ENCRYPTION_UTIL_USER2);
|
||||
\OC_User::deleteUser(self::TEST_ENCRYPTION_UTIL_LEGACY_USER);
|
||||
|
||||
//cleanup groups
|
||||
\OC_Group::deleteGroup(self::TEST_ENCRYPTION_UTIL_GROUP1);
|
||||
\OC_Group::deleteGroup(self::TEST_ENCRYPTION_UTIL_GROUP2);
|
||||
|
||||
\OC_Hook::clear();
|
||||
\OC_FileProxy::clearProxies();
|
||||
|
||||
// Delete keys in /data/
|
||||
$view = new \OC\Files\View('/');
|
||||
$view->rmdir('public-keys');
|
||||
$view->rmdir('owncloud_private_key');
|
||||
|
||||
parent::tearDownAfterClass();
|
||||
}
|
||||
|
||||
public static function setupHooks() {
|
||||
// Filesystem related hooks
|
||||
\OCA\Encryption\Helper::registerFilesystemHooks();
|
||||
|
||||
// clear and register hooks
|
||||
\OC_FileProxy::clearProxies();
|
||||
\OC_FileProxy::register(new OCA\Encryption\Proxy());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -159,8 +179,8 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
self::loginHelper($this->userId);
|
||||
|
||||
$unencryptedFile = '/tmpUnencrypted-' . uniqid() . '.txt';
|
||||
$encryptedFile = '/tmpEncrypted-' . uniqid() . '.txt';
|
||||
$unencryptedFile = '/tmpUnencrypted-' . $this->getUniqueID() . '.txt';
|
||||
$encryptedFile = '/tmpEncrypted-' . $this->getUniqueID() . '.txt';
|
||||
|
||||
// Disable encryption proxy to write a unencrypted file
|
||||
$proxyStatus = \OC_FileProxy::$enabled;
|
||||
@@ -267,9 +287,9 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
|
||||
*/
|
||||
function testGetUidAndFilename() {
|
||||
|
||||
\OC_User::setUserId(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1);
|
||||
\OC_User::setUserId(self::TEST_ENCRYPTION_UTIL_USER1);
|
||||
|
||||
$filename = '/tmp-' . uniqid() . '.test';
|
||||
$filename = '/tmp-' . $this->getUniqueID() . '.test';
|
||||
|
||||
// Disable encryption proxy to prevent recursive calls
|
||||
$proxyStatus = \OC_FileProxy::$enabled;
|
||||
@@ -284,7 +304,7 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
list($fileOwnerUid, $file) = $util->getUidAndFilename($filename);
|
||||
|
||||
$this->assertEquals(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1, $fileOwnerUid);
|
||||
$this->assertEquals(self::TEST_ENCRYPTION_UTIL_USER1, $fileOwnerUid);
|
||||
|
||||
$this->assertEquals($file, $filename);
|
||||
|
||||
@@ -295,9 +315,9 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
|
||||
< * Test that data that is read by the crypto stream wrapper
|
||||
*/
|
||||
function testGetFileSize() {
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1);
|
||||
self::loginHelper(self::TEST_ENCRYPTION_UTIL_USER1);
|
||||
|
||||
$filename = 'tmp-' . uniqid();
|
||||
$filename = 'tmp-' . $this->getUniqueID();
|
||||
$externalFilename = '/' . $this->userId . '/files/' . $filename;
|
||||
|
||||
// Test for 0 byte files
|
||||
@@ -321,7 +341,7 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
function testEncryptAll() {
|
||||
|
||||
$filename = "/encryptAll" . uniqid() . ".txt";
|
||||
$filename = "/encryptAll" . $this->getUniqueID() . ".txt";
|
||||
$util = new Encryption\Util($this->view, $this->userId);
|
||||
|
||||
// disable encryption to upload a unencrypted file
|
||||
@@ -352,7 +372,7 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
function testDecryptAll() {
|
||||
|
||||
$filename = "/decryptAll" . uniqid() . ".txt";
|
||||
$filename = "/decryptAll" . $this->getUniqueID() . ".txt";
|
||||
$datadir = \OC_Config::getValue('datadirectory', \OC::$SERVERROOT . '/data/');
|
||||
$userdir = $datadir . '/' . $this->userId . '/files/';
|
||||
|
||||
@@ -426,11 +446,53 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* test if all keys get moved to the backup folder correctly
|
||||
*/
|
||||
function testBackupAllKeys() {
|
||||
self::loginHelper(self::TEST_ENCRYPTION_UTIL_USER1);
|
||||
|
||||
// create some dummy key files
|
||||
$encPath = '/' . self::TEST_ENCRYPTION_UTIL_USER1 . '/files_encryption';
|
||||
$this->view->file_put_contents($encPath . '/keyfiles/foo.key', 'key');
|
||||
$this->view->file_put_contents($encPath . '/share-keys/foo.user1.shareKey', 'share key');
|
||||
|
||||
$util = new \OCA\Encryption\Util($this->view, self::TEST_ENCRYPTION_UTIL_USER1);
|
||||
|
||||
$util->backupAllKeys('testing');
|
||||
|
||||
$encFolderContent = $this->view->getDirectoryContent($encPath);
|
||||
|
||||
$backupPath = '';
|
||||
foreach ($encFolderContent as $c) {
|
||||
$name = $c['name'];
|
||||
if (substr($name, 0, strlen('backup')) === 'backup') {
|
||||
$backupPath = $encPath . '/'. $c['name'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$this->assertTrue($backupPath !== '');
|
||||
|
||||
// check backupDir Content
|
||||
$this->assertTrue($this->view->is_dir($backupPath . '/keyfiles'));
|
||||
$this->assertTrue($this->view->is_dir($backupPath . '/share-keys'));
|
||||
$this->assertTrue($this->view->file_exists($backupPath . '/keyfiles/foo.key'));
|
||||
$this->assertTrue($this->view->file_exists($backupPath . '/share-keys/foo.user1.shareKey'));
|
||||
$this->assertTrue($this->view->file_exists($backupPath . '/' . self::TEST_ENCRYPTION_UTIL_USER1 . '.private.key'));
|
||||
$this->assertTrue($this->view->file_exists($backupPath . '/' . self::TEST_ENCRYPTION_UTIL_USER1 . '.public.key'));
|
||||
|
||||
//cleanup
|
||||
$this->view->deleteAll($backupPath);
|
||||
$this->view->unlink($encPath . '/keyfiles/foo.key', 'key');
|
||||
$this->view->unlink($encPath . '/share-keys/foo.user1.shareKey', 'share key');
|
||||
}
|
||||
|
||||
|
||||
function testDescryptAllWithBrokenFiles() {
|
||||
|
||||
$file1 = "/decryptAll1" . uniqid() . ".txt";
|
||||
$file2 = "/decryptAll2" . uniqid() . ".txt";
|
||||
$file1 = "/decryptAll1" . $this->getUniqueID() . ".txt";
|
||||
$file2 = "/decryptAll2" . $this->getUniqueID() . ".txt";
|
||||
|
||||
$util = new Encryption\Util($this->view, $this->userId);
|
||||
|
||||
@@ -575,6 +637,43 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that filterShareReadyUsers() returns the correct list of
|
||||
* users that are ready or not ready for encryption
|
||||
*/
|
||||
public function testFilterShareReadyUsers() {
|
||||
$appConfig = \OC::$server->getAppConfig();
|
||||
|
||||
$publicShareKeyId = $appConfig->getValue('files_encryption', 'publicShareKeyId');
|
||||
$recoveryKeyId = $appConfig->getValue('files_encryption', 'recoveryKeyId');
|
||||
|
||||
$usersToTest = array(
|
||||
'readyUser',
|
||||
'notReadyUser',
|
||||
'nonExistingUser',
|
||||
$publicShareKeyId,
|
||||
$recoveryKeyId,
|
||||
);
|
||||
\Test_Encryption_Util::loginHelper('readyUser', true);
|
||||
\Test_Encryption_Util::loginHelper('notReadyUser', true);
|
||||
// delete encryption dir to make it not ready
|
||||
$this->view->unlink('notReadyUser/files_encryption/');
|
||||
|
||||
// login as user1
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1);
|
||||
|
||||
$result = $this->util->filterShareReadyUsers($usersToTest);
|
||||
$this->assertEquals(
|
||||
array('readyUser', $publicShareKeyId, $recoveryKeyId),
|
||||
$result['ready']
|
||||
);
|
||||
$this->assertEquals(
|
||||
array('notReadyUser', 'nonExistingUser'),
|
||||
$result['unready']
|
||||
);
|
||||
\OC_User::deleteUser('readyUser');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $user
|
||||
* @param bool $create
|
||||
|
||||
@@ -27,7 +27,6 @@ require_once __DIR__ . '/../lib/proxy.php';
|
||||
require_once __DIR__ . '/../lib/stream.php';
|
||||
require_once __DIR__ . '/../lib/util.php';
|
||||
require_once __DIR__ . '/../appinfo/app.php';
|
||||
require_once __DIR__ . '/util.php';
|
||||
|
||||
use OCA\Encryption;
|
||||
|
||||
@@ -36,7 +35,7 @@ use OCA\Encryption;
|
||||
*
|
||||
* this class provide basic webdav tests for PUT,GET and DELETE
|
||||
*/
|
||||
class Test_Encryption_Webdav extends \PHPUnit_Framework_TestCase {
|
||||
class Test_Encryption_Webdav extends \OCA\Files_Encryption\Tests\TestCase {
|
||||
|
||||
const TEST_ENCRYPTION_WEBDAV_USER1 = "test-webdav-user1";
|
||||
|
||||
@@ -52,6 +51,8 @@ class Test_Encryption_Webdav extends \PHPUnit_Framework_TestCase {
|
||||
private $storage;
|
||||
|
||||
public static function setUpBeforeClass() {
|
||||
parent::setUpBeforeClass();
|
||||
|
||||
// reset backend
|
||||
\OC_User::clearBackends();
|
||||
\OC_User::useBackend('database');
|
||||
@@ -67,11 +68,13 @@ class Test_Encryption_Webdav extends \PHPUnit_Framework_TestCase {
|
||||
\OC_FileProxy::register(new OCA\Encryption\Proxy());
|
||||
|
||||
// create test user
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Webdav::TEST_ENCRYPTION_WEBDAV_USER1, true);
|
||||
self::loginHelper(\Test_Encryption_Webdav::TEST_ENCRYPTION_WEBDAV_USER1, true);
|
||||
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// reset backend
|
||||
\OC_User::useBackend('database');
|
||||
|
||||
@@ -93,21 +96,33 @@ class Test_Encryption_Webdav extends \PHPUnit_Framework_TestCase {
|
||||
\OC_App::disable('files_trashbin');
|
||||
|
||||
// create test user
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Webdav::TEST_ENCRYPTION_WEBDAV_USER1);
|
||||
self::loginHelper(\Test_Encryption_Webdav::TEST_ENCRYPTION_WEBDAV_USER1);
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
protected function tearDown() {
|
||||
// reset app files_trashbin
|
||||
if ($this->stateFilesTrashbin) {
|
||||
OC_App::enable('files_trashbin');
|
||||
} else {
|
||||
OC_App::disable('files_trashbin');
|
||||
}
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
public static function tearDownAfterClass() {
|
||||
// cleanup test user
|
||||
\OC_User::deleteUser(\Test_Encryption_Webdav::TEST_ENCRYPTION_WEBDAV_USER1);
|
||||
|
||||
\OC_Hook::clear();
|
||||
\OC_FileProxy::clearProxies();
|
||||
|
||||
// Delete keys in /data/
|
||||
$view = new \OC\Files\View('/');
|
||||
$view->rmdir('public-keys');
|
||||
$view->rmdir('owncloud_private_key');
|
||||
|
||||
parent::tearDownAfterClass();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -116,7 +131,7 @@ class Test_Encryption_Webdav extends \PHPUnit_Framework_TestCase {
|
||||
function testWebdavPUT() {
|
||||
|
||||
// generate filename
|
||||
$filename = '/tmp-' . uniqid() . '.txt';
|
||||
$filename = '/tmp-' . $this->getUniqueID() . '.txt';
|
||||
|
||||
// set server vars
|
||||
$_SERVER['REQUEST_METHOD'] = 'OPTIONS';
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
OCP\JSON::checkAppEnabled('files_external');
|
||||
OCP\JSON::callCheck();
|
||||
|
||||
OCP\JSON::checkAdminUser();
|
||||
|
||||
$pattern = '';
|
||||
$limit = null;
|
||||
$offset = null;
|
||||
if (isset($_GET['pattern'])) {
|
||||
$pattern = $_GET['pattern'];
|
||||
}
|
||||
if (isset($_GET['limit'])) {
|
||||
$limit = $_GET['limit'];
|
||||
}
|
||||
if (isset($_GET['offset'])) {
|
||||
$offset = $_GET['offset'];
|
||||
}
|
||||
|
||||
$groups = \OC_Group::getGroups($pattern, $limit, $offset);
|
||||
$users = \OCP\User::getDisplayNames($pattern, $limit, $offset);
|
||||
|
||||
$results = array('groups' => $groups, 'users' => $users);
|
||||
|
||||
\OCP\JSON::success($results);
|
||||
@@ -2,11 +2,18 @@
|
||||
<info>
|
||||
<id>files_external</id>
|
||||
<name>External storage support</name>
|
||||
<description>Mount external storage sources</description>
|
||||
<description>
|
||||
This application enables administrators to configure connections to external storage providers, such as FTP servers, S3 or SWIFT object stores, Google Drive, Dropbox, other ownCloud servers, WebDAV servers and more. Administrators can choose in the GUI which type of storage to enable, and can mount these storage locations for a user, a group, or the entire system. Users will see a new folder appear in their root ownCloud directory, and then can then access and use it like any other ownCloud folder. External Storage also allows users to share files stored in these external location. In these cases, the credentials for the owner of the file are used then the recipient requests the file from external storage, thereby ensuring that the recipient can get at the file that was shared.
|
||||
In addition to the GUI, it is possible to configure external storage manually at the command line. This option provides the advanced user with more flexibility for configuring bulk external storage mounts, as well as setting mount priorities. More information is available in the External Storage GUI documentation and the External Storage Configuration File documentation.
|
||||
|
||||
</description>
|
||||
<licence>AGPL</licence>
|
||||
<author>Robin Appelman, Michael Gapczynski, Vincent Petry</author>
|
||||
<requiremin>4.93</requiremin>
|
||||
<shipped>true</shipped>
|
||||
<documentation>
|
||||
<admin>admin-external-storage</admin>
|
||||
</documentation>
|
||||
<types>
|
||||
<filesystem/>
|
||||
</types>
|
||||
|
||||
@@ -20,8 +20,10 @@
|
||||
*
|
||||
*/
|
||||
|
||||
OC_API::register('get',
|
||||
'/apps/files_external/api/v1/mounts',
|
||||
array('\OCA\Files\External\Api', 'getUserMounts'),
|
||||
'files_external');
|
||||
$this->create('files_external_list_applicable', '/applicable')->actionInclude('files_external/ajax/applicable.php');
|
||||
|
||||
OC_API::register('get',
|
||||
'/apps/files_external/api/v1/mounts',
|
||||
array('\OCA\Files\External\Api', 'getUserMounts'),
|
||||
'files_external');
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
0.2.1
|
||||
0.2.2
|
||||
@@ -42,3 +42,19 @@ tr:hover>td.remove>img { visibility:visible; cursor:pointer; }
|
||||
#userMountingBackends {
|
||||
padding-left: 25px;
|
||||
}
|
||||
|
||||
#body-settings .select2-results .select2-result-label {
|
||||
height: 32px;
|
||||
padding: 3px;
|
||||
}
|
||||
.select2-results .select2-result-label .avatardiv {
|
||||
display:inline-block;
|
||||
}
|
||||
.select2-results .select2-result-label .avatardiv + span {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.select2-results .select2-result-label .avatardiv[data-type="group"] + span {
|
||||
vertical-align: top;
|
||||
top: 6px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,14 @@ function updateStatus(statusEl, result){
|
||||
}
|
||||
}
|
||||
|
||||
function getSelection($row) {
|
||||
var values = $row.find('.applicableUsers').select2('val');
|
||||
if (!values || values.length === 0) {
|
||||
values = ['all'];
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
OC.MountConfig={
|
||||
saveStorage:function(tr, callback) {
|
||||
var mountPoint = $(tr).find('.mountPoint input').val();
|
||||
@@ -42,10 +50,7 @@ OC.MountConfig={
|
||||
}
|
||||
});
|
||||
if ($('#externalStorage').data('admin') === true) {
|
||||
var multiselect = $(tr).find('.chzn-select').val();
|
||||
if (multiselect == null) {
|
||||
return false;
|
||||
}
|
||||
var multiselect = getSelection($(tr));
|
||||
}
|
||||
if (addMountPoint) {
|
||||
var status = false;
|
||||
@@ -166,8 +171,122 @@ OC.MountConfig={
|
||||
};
|
||||
|
||||
$(document).ready(function() {
|
||||
$('.chzn-select').chosen();
|
||||
//initialize hidden input field with list of users and groups
|
||||
$('#externalStorage').find('tr:not(#addMountPoint)').each(function(i,tr) {
|
||||
var applicable = $(tr).find('.applicable');
|
||||
if (applicable.length > 0) {
|
||||
var groups = applicable.data('applicable-groups');
|
||||
var groupsId = [];
|
||||
$.each(groups, function () {
|
||||
groupsId.push(this+"(group)");
|
||||
});
|
||||
var users = applicable.data('applicable-users');
|
||||
if (users.indexOf('all') > -1) {
|
||||
$(tr).find('.applicableUsers').val('');
|
||||
} else {
|
||||
$(tr).find('.applicableUsers').val(groupsId.concat(users).join(','));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var userListLimit = 30;
|
||||
function addSelect2 ($elements) {
|
||||
if ($elements.length > 0) {
|
||||
$elements.select2({
|
||||
placeholder: t('files_external', 'All users. Type to select user or group.'),
|
||||
allowClear: true,
|
||||
multiple: true,
|
||||
//minimumInputLength: 1,
|
||||
ajax: {
|
||||
url: OC.generateUrl('apps/files_external/applicable'),
|
||||
dataType: 'json',
|
||||
quietMillis: 100,
|
||||
data: function (term, page) { // page is the one-based page number tracked by Select2
|
||||
return {
|
||||
pattern: term, //search term
|
||||
limit: userListLimit, // page size
|
||||
offset: userListLimit*(page-1) // page number starts with 0
|
||||
};
|
||||
},
|
||||
results: function (data, page) {
|
||||
if (data.status === "success") {
|
||||
|
||||
var results = [];
|
||||
var userCount = 0; // users is an object
|
||||
|
||||
// add groups
|
||||
$.each(data.groups, function(i, group) {
|
||||
results.push({name:group+'(group)', displayname:group, type:'group' });
|
||||
});
|
||||
// add users
|
||||
$.each(data.users, function(id, user) {
|
||||
userCount++;
|
||||
results.push({name:id, displayname:user, type:'user' });
|
||||
});
|
||||
|
||||
|
||||
var more = (userCount >= userListLimit) || (data.groups.length >= userListLimit);
|
||||
return {results: results, more: more};
|
||||
} else {
|
||||
//FIXME add error handling
|
||||
}
|
||||
}
|
||||
},
|
||||
initSelection: function(element, callback) {
|
||||
$.ajax(OC.generateUrl('displaynames'), {
|
||||
data: {
|
||||
users: element.val().split(",")
|
||||
},
|
||||
dataType: "json"
|
||||
}).done(function(data) {
|
||||
var results = [];
|
||||
if (data.status === "success") {
|
||||
$.each(data.users, function(user, displayname) {
|
||||
if (displayname !== false) {
|
||||
results.push({name:user, displayname:displayname, type:'user'});
|
||||
}
|
||||
});
|
||||
callback(results);
|
||||
} else {
|
||||
//FIXME add error handling
|
||||
}
|
||||
});
|
||||
},
|
||||
id: function(element) {
|
||||
return element.name;
|
||||
},
|
||||
formatResult: function (element) {
|
||||
var $result = $('<span><div class="avatardiv"/><span>'+escapeHTML(element.displayname)+'</span></span>');
|
||||
var $div = $result.find('.avatardiv')
|
||||
.attr('data-type', element.type)
|
||||
.attr('data-name', element.name)
|
||||
.attr('data-displayname', element.displayname);
|
||||
if (element.type === 'group') {
|
||||
var url = OC.imagePath('core','places/contacts-dark'); // TODO better group icon
|
||||
$div.html('<img width="32" height="32" src="'+url+'">');
|
||||
}
|
||||
return $result.get(0).outerHTML;
|
||||
},
|
||||
formatSelection: function (element) {
|
||||
if (element.type === 'group') {
|
||||
return '<span title="'+escapeHTML(element.name)+'" class="group">'+escapeHTML(element.displayname+' '+t('files_external', '(group)'))+'</span>';
|
||||
} else {
|
||||
return '<span title="'+escapeHTML(element.name)+'" class="user">'+escapeHTML(element.displayname)+'</span>';
|
||||
}
|
||||
},
|
||||
escapeMarkup: function (m) { return m; } // we escape the markup in formatResult and formatSelection
|
||||
}).on("select2-loaded", function() {
|
||||
$.each($(".avatardiv"), function(i, div) {
|
||||
$div = $(div);
|
||||
if ($div.data('type') === 'user') {
|
||||
$div.avatar($div.data('name'),32);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
addSelect2($('tr:not(#addMountPoint) .applicableUsers'));
|
||||
|
||||
$('#externalStorage').on('change', '#selectBackend', function() {
|
||||
var tr = $(this).parent().parent();
|
||||
$('#externalStorage tbody').append($(tr).clone());
|
||||
@@ -209,15 +328,11 @@ $(document).ready(function() {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
// Reset chosen
|
||||
var chosen = $(tr).find('.applicable select');
|
||||
chosen.parent().find('div').remove();
|
||||
chosen.removeAttr('id').removeClass('chzn-done').css({display:'inline-block'});
|
||||
chosen.chosen();
|
||||
$(tr).find('td').last().attr('class', 'remove');
|
||||
$(tr).find('td').last().removeAttr('style');
|
||||
$(tr).removeAttr('id');
|
||||
$(this).remove();
|
||||
addSelect2(tr.find('.applicableUsers'));
|
||||
});
|
||||
|
||||
function suggestMountPoint(defaultMountPoint) {
|
||||
@@ -270,8 +385,8 @@ $(document).ready(function() {
|
||||
OC.MountConfig.saveStorage($(this).parent().parent().parent());
|
||||
});
|
||||
|
||||
$('#externalStorage').on('change', '.applicable .chzn-select', function() {
|
||||
OC.MountConfig.saveStorage($(this).parent().parent());
|
||||
$('#externalStorage').on('change', '.applicable', function() {
|
||||
OC.MountConfig.saveStorage($(this).parent());
|
||||
});
|
||||
|
||||
$('#sslCertificate').on('click', 'td.remove>img', function() {
|
||||
@@ -288,20 +403,18 @@ $(document).ready(function() {
|
||||
|
||||
if ($('#externalStorage').data('admin') === true) {
|
||||
var isPersonal = false;
|
||||
var multiselect = $(tr).find('.chzn-select').val();
|
||||
if (multiselect != null) {
|
||||
$.each(multiselect, function(index, value) {
|
||||
var pos = value.indexOf('(group)');
|
||||
if (pos != -1) {
|
||||
var mountType = 'group';
|
||||
var applicable = value.substr(0, pos);
|
||||
} else {
|
||||
var mountType = 'user';
|
||||
var applicable = value;
|
||||
}
|
||||
$.post(OC.filePath('files_external', 'ajax', 'removeMountPoint.php'), { mountPoint: mountPoint, mountType: mountType, applicable: applicable, isPersonal: isPersonal });
|
||||
});
|
||||
}
|
||||
var multiselect = getSelection($(tr));
|
||||
$.each(multiselect, function(index, value) {
|
||||
var pos = value.indexOf('(group)');
|
||||
if (pos != -1) {
|
||||
var mountType = 'group';
|
||||
var applicable = value.substr(0, pos);
|
||||
} else {
|
||||
var mountType = 'user';
|
||||
var applicable = value;
|
||||
}
|
||||
$.post(OC.filePath('files_external', 'ajax', 'removeMountPoint.php'), { mountPoint: mountPoint, mountType: mountType, applicable: applicable, isPersonal: isPersonal });
|
||||
});
|
||||
} else {
|
||||
var mountType = 'user';
|
||||
var applicable = OC.currentUser;
|
||||
@@ -322,14 +435,14 @@ $(document).ready(function() {
|
||||
OC.AppConfig.setValue('files_external', 'allow_user_mounting', 'no');
|
||||
$('#userMountingBackends').addClass('hidden');
|
||||
}
|
||||
OC.msg.finishedSaving('#userMountingMsg', {status: 'success', data: {message: t('settings', 'Saved')}});
|
||||
OC.msg.finishedSaving('#userMountingMsg', {status: 'success', data: {message: t('files_external', 'Saved')}});
|
||||
});
|
||||
|
||||
$('input[name="allowUserMountingBackends\\[\\]"]').bind('change', function() {
|
||||
OC.msg.startSaving('#userMountingMsg');
|
||||
var userMountingBackends = $('input[name="allowUserMountingBackends\\[\\]"]:checked').map(function(){return $(this).val();}).get();
|
||||
OC.AppConfig.setValue('files_external', 'user_mounting_backends', userMountingBackends.join());
|
||||
OC.msg.finishedSaving('#userMountingMsg', {status: 'success', data: {message: t('settings', 'Saved')}});
|
||||
OC.msg.finishedSaving('#userMountingMsg', {status: 'success', data: {message: t('files_external', 'Saved')}});
|
||||
|
||||
// disable allowUserMounting
|
||||
if(userMountingBackends.length === 0) {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<?php
|
||||
$TRANSLATIONS = array(
|
||||
"Fetching request tokens failed. Verify that your Dropbox app key and secret are correct." => "La requête de récupération des jetons d’authentification a échoué. Veuillez vérifier votre App-Key Dropbox ainsi que le mot de passe.",
|
||||
"Fetching request tokens failed. Verify that your Dropbox app key and secret are correct." => "La récupération des jetons d’authentification a échoué. Veuillez vérifier votre clé d'application Dropbox ainsi que le mot de passe.",
|
||||
"Fetching access tokens failed. Verify that your Dropbox app key and secret are correct." => "La requête d’accès aux jetons d’authentification a échoué. Veuillez vérifier votre App-Key Dropbox ainsi que le mot de passe.",
|
||||
"Please provide a valid Dropbox app key and secret." => "Veuillez fournir une clé d'application (app key) ainsi qu'un mot de passe valides.",
|
||||
"Step 1 failed. Exception: %s" => "L’étape 1 a échoué. Erreur: %s",
|
||||
"Step 2 failed. Exception: %s" => "L’étape 2 a échoué. Erreur: %s",
|
||||
"Step 1 failed. Exception: %s" => "L’étape 1 a échoué. Erreur : %s",
|
||||
"Step 2 failed. Exception: %s" => "L’étape 2 a échoué. Erreur : %s",
|
||||
"External storage" => "Stockage externe",
|
||||
"Local" => "Local",
|
||||
"Location" => "Emplacement",
|
||||
@@ -26,7 +26,7 @@ $TRANSLATIONS = array(
|
||||
"Username" => "Nom d'utilisateur",
|
||||
"Password" => "Mot de passe",
|
||||
"Root" => "Root",
|
||||
"Secure ftps://" => "Sécuriser via ftps://",
|
||||
"Secure ftps://" => "Sécurisation ftps://",
|
||||
"Client ID" => "ID Client",
|
||||
"Client secret" => "Secret client",
|
||||
"OpenStack Object Storage" => "Object de Stockage OpenStack",
|
||||
@@ -40,7 +40,7 @@ $TRANSLATIONS = array(
|
||||
"URL of identity endpoint (required for OpenStack Object Storage)" => "URL du point d'accès d'identité (requis pour le stockage OpenStack)",
|
||||
"Timeout of HTTP requests in seconds (optional)" => "Temps maximal de requête HTTP en seconde (facultatif)",
|
||||
"Share" => "Partager",
|
||||
"SMB / CIFS using OC login" => "SMB / CIFS utilise le nom d'utilisateur OC",
|
||||
"SMB / CIFS using OC login" => "SMB / CIFS en utilisant les identifiants OC",
|
||||
"Username as share" => "Nom d'utilisateur du partage",
|
||||
"URL" => "URL",
|
||||
"Secure https://" => "Sécurisation https://",
|
||||
@@ -54,8 +54,8 @@ $TRANSLATIONS = array(
|
||||
"Saved" => "Sauvegarder",
|
||||
"<b>Note:</b> " => "<b>Attention :</b>",
|
||||
" and " => "et",
|
||||
"<b>Note:</b> The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "<b>Attention :</b> Le support de cURL de PHP n'est pas activé ou installé. Le montage de %s n'est pas possible. Contactez votre administrateur système pour l'installer.",
|
||||
"<b>Note:</b> The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "<b>Attention : </b> Le support FTP de PHP n'est pas activé ou installé. Le montage de %s n'est pas possible. Contactez votre administrateur système pour l'installer.",
|
||||
"<b>Note:</b> The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "<b>Attention :</b> La prise en charge de cURL par PHP n'est pas activée ou installée. Le montage de %s n'est pas possible. Contactez votre administrateur système pour l'installer.",
|
||||
"<b>Note:</b> The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "<b>Attention : </b> La prise en charge du FTP par PHP n'est pas activée ou installée. Le montage de %s n'est pas possible. Contactez votre administrateur système pour l'installer.",
|
||||
"<b>Note:</b> \"%s\" is not installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "<b>Attention : </b> \"%s\" n'est pas installé. Le montage de %s n'est pas possible. Contactez votre administrateur système pour l'installer.",
|
||||
"You don't have any external storages" => "Vous n'avez pas de support de stockage externe",
|
||||
"Name" => "Nom",
|
||||
@@ -72,7 +72,7 @@ $TRANSLATIONS = array(
|
||||
"Groups" => "Groupes",
|
||||
"Users" => "Utilisateurs",
|
||||
"Delete" => "Supprimer",
|
||||
"Enable User External Storage" => "Activer le stockage externe pour les utilisateurs",
|
||||
"Enable User External Storage" => "Autoriser les utilisateurs à ajouter des stockages externes",
|
||||
"Allow users to mount the following external storage" => "Autorise les utilisateurs à monter les stockage externes suivants",
|
||||
"SSL root certificates" => "Certificats racine SSL",
|
||||
"Import Root Certificate" => "Importer un certificat racine"
|
||||
|
||||
@@ -45,6 +45,10 @@ class AmazonS3 extends \OC\Files\Storage\Common {
|
||||
* @var array
|
||||
*/
|
||||
private static $tmpFiles = array();
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $params;
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
@@ -53,6 +57,10 @@ class AmazonS3 extends \OC\Files\Storage\Common {
|
||||
* @var int
|
||||
*/
|
||||
private $timeout = 15;
|
||||
/**
|
||||
* @var int in seconds
|
||||
*/
|
||||
private $rescanDelay = 10;
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
@@ -68,72 +76,92 @@ class AmazonS3 extends \OC\Files\Storage\Common {
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* when running the tests wait to let the buckets catch up
|
||||
*/
|
||||
private function testTimeout() {
|
||||
if ($this->test) {
|
||||
sleep($this->timeout);
|
||||
}
|
||||
}
|
||||
|
||||
private function isRoot($path) {
|
||||
return $path === '.';
|
||||
}
|
||||
|
||||
private function cleanKey($path) {
|
||||
if ($path === '.') {
|
||||
if ($this->isRoot($path)) {
|
||||
return '/';
|
||||
}
|
||||
return $path;
|
||||
}
|
||||
|
||||
public function __construct($params) {
|
||||
if (!isset($params['key']) || !isset($params['secret']) || !isset($params['bucket'])) {
|
||||
if (empty($params['key']) || empty($params['secret']) || empty($params['bucket'])) {
|
||||
throw new \Exception("Access Key, Secret and Bucket have to be configured.");
|
||||
}
|
||||
|
||||
$this->id = 'amazon::' . $params['key'] . md5($params['secret']);
|
||||
$this->id = 'amazon::' . $params['bucket'];
|
||||
$this->updateLegacyId($params);
|
||||
|
||||
$this->bucket = $params['bucket'];
|
||||
$scheme = ($params['use_ssl'] === 'false') ? 'http' : 'https';
|
||||
$this->test = isset($params['test']);
|
||||
$this->timeout = ( ! isset($params['timeout'])) ? 15 : $params['timeout'];
|
||||
$params['region'] = ( ! isset($params['region']) || $params['region'] === '' ) ? 'eu-west-1' : $params['region'];
|
||||
$params['hostname'] = ( !isset($params['hostname']) || $params['hostname'] === '' ) ? 's3.amazonaws.com' : $params['hostname'];
|
||||
$this->timeout = (!isset($params['timeout'])) ? 15 : $params['timeout'];
|
||||
$this->rescanDelay = (!isset($params['rescanDelay'])) ? 10 : $params['rescanDelay'];
|
||||
$params['region'] = empty($params['region']) ? 'eu-west-1' : $params['region'];
|
||||
$params['hostname'] = empty($params['hostname']) ? 's3.amazonaws.com' : $params['hostname'];
|
||||
if (!isset($params['port']) || $params['port'] === '') {
|
||||
$params['port'] = ($params['use_ssl'] === 'false') ? 80 : 443;
|
||||
}
|
||||
$base_url = $scheme.'://'.$params['hostname'].':'.$params['port'].'/';
|
||||
$this->params = $params;
|
||||
}
|
||||
|
||||
$this->connection = S3Client::factory(array(
|
||||
'key' => $params['key'],
|
||||
'secret' => $params['secret'],
|
||||
'base_url' => $base_url,
|
||||
'region' => $params['region']
|
||||
));
|
||||
/**
|
||||
* Updates old storage ids (v0.2.1 and older) that are based on key and secret to new ones based on the bucket name.
|
||||
* TODO Do this in an update.php. requires iterating over all users and loading the mount.json from their home
|
||||
*
|
||||
* @param array $params
|
||||
*/
|
||||
public function updateLegacyId (array $params) {
|
||||
$oldId = 'amazon::' . $params['key'] . md5($params['secret']);
|
||||
|
||||
if (!$this->connection->isValidBucketName($this->bucket)) {
|
||||
throw new \Exception("The configured bucket name is invalid.");
|
||||
// find by old id or bucket
|
||||
$stmt = \OC::$server->getDatabaseConnection()->prepare(
|
||||
'SELECT `numeric_id`, `id` FROM `*PREFIX*storages` WHERE `id` IN (?, ?)'
|
||||
);
|
||||
$stmt->execute(array($oldId, $this->id));
|
||||
while ($row = $stmt->fetch()) {
|
||||
$storages[$row['id']] = $row['numeric_id'];
|
||||
}
|
||||
|
||||
if (!$this->connection->doesBucketExist($this->bucket)) {
|
||||
try {
|
||||
$result = $this->connection->createBucket(array(
|
||||
'Bucket' => $this->bucket
|
||||
));
|
||||
$this->connection->waitUntilBucketExists(array(
|
||||
'Bucket' => $this->bucket,
|
||||
'waiter.interval' => 1,
|
||||
'waiter.max_attempts' => 15
|
||||
));
|
||||
$this->testTimeout();
|
||||
} catch (S3Exception $e) {
|
||||
\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
|
||||
throw new \Exception("Creation of bucket failed.");
|
||||
}
|
||||
if (isset($storages[$this->id]) && isset($storages[$oldId])) {
|
||||
// if both ids exist, delete the old storage and corresponding filecache entries
|
||||
\OC\Files\Cache\Storage::remove($oldId);
|
||||
} else if (isset($storages[$oldId])) {
|
||||
// if only the old id exists do an update
|
||||
$stmt = \OC::$server->getDatabaseConnection()->prepare(
|
||||
'UPDATE `*PREFIX*storages` SET `id` = ? WHERE `id` = ?'
|
||||
);
|
||||
$stmt->execute(array($this->id, $oldId));
|
||||
}
|
||||
if (!$this->file_exists('.')) {
|
||||
$result = $this->connection->putObject(array(
|
||||
'Bucket' => $this->bucket,
|
||||
'Key' => $this->cleanKey('.'),
|
||||
'Body' => '',
|
||||
'ContentType' => 'httpd/unix-directory',
|
||||
'ContentLength' => 0
|
||||
));
|
||||
$this->testTimeout();
|
||||
// only the bucket based id may exist, do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a file or folder
|
||||
*
|
||||
* @param string $path
|
||||
* @return bool
|
||||
*/
|
||||
protected function remove($path) {
|
||||
// remember fileType to reduce http calls
|
||||
$fileType = $this->filetype($path);
|
||||
if ($fileType === 'dir') {
|
||||
return $this->rmdir($path);
|
||||
} else if ($fileType === 'file') {
|
||||
return $this->unlink($path);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,16 +173,14 @@ class AmazonS3 extends \OC\Files\Storage\Common {
|
||||
}
|
||||
|
||||
try {
|
||||
$result = $this->connection->putObject(array(
|
||||
$this->getConnection()->putObject(array(
|
||||
'Bucket' => $this->bucket,
|
||||
'Key' => $path . '/',
|
||||
'Body' => '',
|
||||
'ContentType' => 'httpd/unix-directory',
|
||||
'ContentLength' => 0
|
||||
'Key' => $path . '/',
|
||||
'ContentType' => 'httpd/unix-directory'
|
||||
));
|
||||
$this->testTimeout();
|
||||
} catch (S3Exception $e) {
|
||||
\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
|
||||
\OCP\Util::logException('files_external', $e);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -162,77 +188,75 @@ class AmazonS3 extends \OC\Files\Storage\Common {
|
||||
}
|
||||
|
||||
public function file_exists($path) {
|
||||
$path = $this->normalizePath($path);
|
||||
|
||||
if (!$path) {
|
||||
$path = '.';
|
||||
} else if ($path != '.' && $this->is_dir($path)) {
|
||||
$path .= '/';
|
||||
}
|
||||
|
||||
try {
|
||||
$result = $this->connection->doesObjectExist(
|
||||
$this->bucket,
|
||||
$this->cleanKey($path)
|
||||
);
|
||||
} catch (S3Exception $e) {
|
||||
\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
return $result;
|
||||
return $this->filetype($path) !== false;
|
||||
}
|
||||
|
||||
|
||||
public function rmdir($path) {
|
||||
$path = $this->normalizePath($path);
|
||||
|
||||
if ($this->isRoot($path)) {
|
||||
return $this->clearBucket();
|
||||
}
|
||||
|
||||
if (!$this->file_exists($path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$dh = $this->opendir($path);
|
||||
|
||||
if(is_resource($dh)) {
|
||||
while (($file = readdir($dh)) !== false) {
|
||||
if ($file === '.' || $file === '..') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->is_dir($path . '/' . $file)) {
|
||||
$this->rmdir($path . '/' . $file);
|
||||
} else {
|
||||
$this->unlink($path . '/' . $file);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $this->batchDelete($path);
|
||||
}
|
||||
|
||||
protected function clearBucket() {
|
||||
try {
|
||||
$result = $this->connection->deleteObject(array(
|
||||
'Bucket' => $this->bucket,
|
||||
'Key' => $path . '/'
|
||||
));
|
||||
$this->testTimeout();
|
||||
$this->getConnection()->clearBucket($this->bucket);
|
||||
return true;
|
||||
// clearBucket() is not working with Ceph, so if it fails we try the slower approach
|
||||
} catch (\Exception $e) {
|
||||
return $this->batchDelete();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private function batchDelete ($path = null) {
|
||||
$params = array(
|
||||
'Bucket' => $this->bucket
|
||||
);
|
||||
if ($path !== null) {
|
||||
$params['Prefix'] = $path . '/';
|
||||
}
|
||||
try {
|
||||
// Since there are no real directories on S3, we need
|
||||
// to delete all objects prefixed with the path.
|
||||
do {
|
||||
// instead of the iterator, manually loop over the list ...
|
||||
$objects = $this->getConnection()->listObjects($params);
|
||||
// ... so we can delete the files in batches
|
||||
$this->getConnection()->deleteObjects(array(
|
||||
'Bucket' => $this->bucket,
|
||||
'Objects' => $objects['Contents']
|
||||
));
|
||||
$this->testTimeout();
|
||||
// we reached the end when the list is no longer truncated
|
||||
} while ($objects['IsTruncated']);
|
||||
} catch (S3Exception $e) {
|
||||
\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
|
||||
\OCP\Util::logException('files_external', $e);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function opendir($path) {
|
||||
$path = $this->normalizePath($path);
|
||||
|
||||
if ($path === '.') {
|
||||
if ($this->isRoot($path)) {
|
||||
$path = '';
|
||||
} else if ($path) {
|
||||
} else {
|
||||
$path .= '/';
|
||||
}
|
||||
|
||||
try {
|
||||
$files = array();
|
||||
$result = $this->connection->getIterator('ListObjects', array(
|
||||
$result = $this->getConnection()->getIterator('ListObjects', array(
|
||||
'Bucket' => $this->bucket,
|
||||
'Delimiter' => '/',
|
||||
'Prefix' => $path
|
||||
@@ -242,17 +266,14 @@ class AmazonS3 extends \OC\Files\Storage\Common {
|
||||
$file = basename(
|
||||
isset($object['Key']) ? $object['Key'] : $object['Prefix']
|
||||
);
|
||||
|
||||
if ($file != basename($path)) {
|
||||
$files[] = $file;
|
||||
}
|
||||
$files[] = $file;
|
||||
}
|
||||
|
||||
\OC\Files\Stream\Dir::register('amazons3' . $path, $files);
|
||||
|
||||
return opendir('fakedir://amazons3' . $path);
|
||||
} catch (S3Exception $e) {
|
||||
\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
|
||||
\OCP\Util::logException('files_external', $e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -261,27 +282,29 @@ class AmazonS3 extends \OC\Files\Storage\Common {
|
||||
$path = $this->normalizePath($path);
|
||||
|
||||
try {
|
||||
if ($this->is_dir($path) && $path != '.') {
|
||||
$path .= '/';
|
||||
}
|
||||
|
||||
$result = $this->connection->headObject(array(
|
||||
'Bucket' => $this->bucket,
|
||||
'Key' => $this->cleanKey($path)
|
||||
));
|
||||
|
||||
$stat = array();
|
||||
$stat['size'] = $result['ContentLength'] ? $result['ContentLength'] : 0;
|
||||
if ($result['Metadata']['lastmodified']) {
|
||||
$stat['mtime'] = strtotime($result['Metadata']['lastmodified']);
|
||||
if ($this->is_dir($path)) {
|
||||
//folders don't really exist
|
||||
$stat['size'] = -1; //unknown
|
||||
$stat['mtime'] = time() - $this->rescanDelay * 1000;
|
||||
} else {
|
||||
$stat['mtime'] = strtotime($result['LastModified']);
|
||||
$result = $this->getConnection()->headObject(array(
|
||||
'Bucket' => $this->bucket,
|
||||
'Key' => $path
|
||||
));
|
||||
|
||||
$stat['size'] = $result['ContentLength'] ? $result['ContentLength'] : 0;
|
||||
if ($result['Metadata']['lastmodified']) {
|
||||
$stat['mtime'] = strtotime($result['Metadata']['lastmodified']);
|
||||
} else {
|
||||
$stat['mtime'] = strtotime($result['LastModified']);
|
||||
}
|
||||
}
|
||||
$stat['atime'] = time();
|
||||
|
||||
return $stat;
|
||||
} catch(S3Exception $e) {
|
||||
\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
|
||||
\OCP\Util::logException('files_external', $e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -289,19 +312,19 @@ class AmazonS3 extends \OC\Files\Storage\Common {
|
||||
public function filetype($path) {
|
||||
$path = $this->normalizePath($path);
|
||||
|
||||
if ($this->isRoot($path)) {
|
||||
return 'dir';
|
||||
}
|
||||
|
||||
try {
|
||||
if ($path != '.' && $this->connection->doesObjectExist($this->bucket, $path)) {
|
||||
if ($this->getConnection()->doesObjectExist($this->bucket, $path)) {
|
||||
return 'file';
|
||||
}
|
||||
|
||||
if ($path != '.') {
|
||||
$path .= '/';
|
||||
}
|
||||
if ($this->connection->doesObjectExist($this->bucket, $this->cleanKey($path))) {
|
||||
if ($this->getConnection()->doesObjectExist($this->bucket, $path.'/')) {
|
||||
return 'dir';
|
||||
}
|
||||
} catch (S3Exception $e) {
|
||||
\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
|
||||
\OCP\Util::logException('files_external', $e);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -311,14 +334,18 @@ class AmazonS3 extends \OC\Files\Storage\Common {
|
||||
public function unlink($path) {
|
||||
$path = $this->normalizePath($path);
|
||||
|
||||
if ($this->is_dir($path)) {
|
||||
return $this->rmdir($path);
|
||||
}
|
||||
|
||||
try {
|
||||
$result = $this->connection->deleteObject(array(
|
||||
$this->getConnection()->deleteObject(array(
|
||||
'Bucket' => $this->bucket,
|
||||
'Key' => $this->cleanKey($path)
|
||||
'Key' => $path
|
||||
));
|
||||
$this->testTimeout();
|
||||
} catch (S3Exception $e) {
|
||||
\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
|
||||
\OCP\Util::logException('files_external', $e);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -335,13 +362,13 @@ class AmazonS3 extends \OC\Files\Storage\Common {
|
||||
self::$tmpFiles[$tmpFile] = $path;
|
||||
|
||||
try {
|
||||
$result = $this->connection->getObject(array(
|
||||
$this->getConnection()->getObject(array(
|
||||
'Bucket' => $this->bucket,
|
||||
'Key' => $this->cleanKey($path),
|
||||
'Key' => $path,
|
||||
'SaveAs' => $tmpFile
|
||||
));
|
||||
} catch (S3Exception $e) {
|
||||
\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
|
||||
\OCP\Util::logException('files_external', $e);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -383,12 +410,12 @@ class AmazonS3 extends \OC\Files\Storage\Common {
|
||||
return 'httpd/unix-directory';
|
||||
} else if ($this->file_exists($path)) {
|
||||
try {
|
||||
$result = $this->connection->headObject(array(
|
||||
$result = $this->getConnection()->headObject(array(
|
||||
'Bucket' => $this->bucket,
|
||||
'Key' => $this->cleanKey($path)
|
||||
'Key' => $path
|
||||
));
|
||||
} catch (S3Exception $e) {
|
||||
\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
|
||||
\OCP\Util::logException('files_external', $e);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -405,12 +432,13 @@ class AmazonS3 extends \OC\Files\Storage\Common {
|
||||
$metadata = array('lastmodified' => $mtime);
|
||||
}
|
||||
|
||||
$fileType = $this->filetype($path);
|
||||
try {
|
||||
if ($this->file_exists($path)) {
|
||||
if ($this->is_dir($path) && $path != '.') {
|
||||
if ($fileType !== false) {
|
||||
if ($fileType === 'dir' && ! $this->isRoot($path)) {
|
||||
$path .= '/';
|
||||
}
|
||||
$result = $this->connection->copyObject(array(
|
||||
$this->getConnection()->copyObject(array(
|
||||
'Bucket' => $this->bucket,
|
||||
'Key' => $this->cleanKey($path),
|
||||
'Metadata' => $metadata,
|
||||
@@ -418,15 +446,17 @@ class AmazonS3 extends \OC\Files\Storage\Common {
|
||||
));
|
||||
$this->testTimeout();
|
||||
} else {
|
||||
$result = $this->connection->putObject(array(
|
||||
$mimeType = \OC_Helper::getMimetypeDetector()->detectPath($path);
|
||||
$this->getConnection()->putObject(array(
|
||||
'Bucket' => $this->bucket,
|
||||
'Key' => $this->cleanKey($path),
|
||||
'Metadata' => $metadata
|
||||
'Metadata' => $metadata,
|
||||
'ContentType' => $mimeType
|
||||
));
|
||||
$this->testTimeout();
|
||||
}
|
||||
} catch (S3Exception $e) {
|
||||
\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
|
||||
\OCP\Util::logException('files_external', $e);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -439,35 +469,33 @@ class AmazonS3 extends \OC\Files\Storage\Common {
|
||||
|
||||
if ($this->is_file($path1)) {
|
||||
try {
|
||||
$result = $this->connection->copyObject(array(
|
||||
$this->getConnection()->copyObject(array(
|
||||
'Bucket' => $this->bucket,
|
||||
'Key' => $this->cleanKey($path2),
|
||||
'CopySource' => S3Client::encodeKey($this->bucket . '/' . $path1)
|
||||
));
|
||||
$this->testTimeout();
|
||||
} catch (S3Exception $e) {
|
||||
\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
|
||||
\OCP\Util::logException('files_external', $e);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if ($this->file_exists($path2)) {
|
||||
return false;
|
||||
}
|
||||
$this->remove($path2);
|
||||
|
||||
try {
|
||||
$result = $this->connection->copyObject(array(
|
||||
$this->getConnection()->copyObject(array(
|
||||
'Bucket' => $this->bucket,
|
||||
'Key' => $path2 . '/',
|
||||
'CopySource' => S3Client::encodeKey($this->bucket . '/' . $path1 . '/')
|
||||
));
|
||||
$this->testTimeout();
|
||||
} catch (S3Exception $e) {
|
||||
\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
|
||||
\OCP\Util::logException('files_external', $e);
|
||||
return false;
|
||||
}
|
||||
|
||||
$dh = $this->opendir($path1);
|
||||
if(is_resource($dh)) {
|
||||
if (is_resource($dh)) {
|
||||
while (($file = readdir($dh)) !== false) {
|
||||
if ($file === '.' || $file === '..') {
|
||||
continue;
|
||||
@@ -488,6 +516,7 @@ class AmazonS3 extends \OC\Files\Storage\Common {
|
||||
$path2 = $this->normalizePath($path2);
|
||||
|
||||
if ($this->is_file($path1)) {
|
||||
|
||||
if ($this->copy($path1, $path2) === false) {
|
||||
return false;
|
||||
}
|
||||
@@ -497,9 +526,6 @@ class AmazonS3 extends \OC\Files\Storage\Common {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if ($this->file_exists($path2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->copy($path1, $path2) === false) {
|
||||
return false;
|
||||
@@ -515,7 +541,7 @@ class AmazonS3 extends \OC\Files\Storage\Common {
|
||||
}
|
||||
|
||||
public function test() {
|
||||
$test = $this->connection->getBucketAcl(array(
|
||||
$test = $this->getConnection()->getBucketAcl(array(
|
||||
'Bucket' => $this->bucket,
|
||||
));
|
||||
if (isset($test) && !is_null($test->getPath('Owner/ID'))) {
|
||||
@@ -528,7 +554,48 @@ class AmazonS3 extends \OC\Files\Storage\Common {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the connection
|
||||
*
|
||||
* @return S3Client connected client
|
||||
* @throws \Exception if connection could not be made
|
||||
*/
|
||||
public function getConnection() {
|
||||
if (!is_null($this->connection)) {
|
||||
return $this->connection;
|
||||
}
|
||||
|
||||
$scheme = ($this->params['use_ssl'] === 'false') ? 'http' : 'https';
|
||||
$base_url = $scheme . '://' . $this->params['hostname'] . ':' . $this->params['port'] . '/';
|
||||
|
||||
$this->connection = S3Client::factory(array(
|
||||
'key' => $this->params['key'],
|
||||
'secret' => $this->params['secret'],
|
||||
'base_url' => $base_url,
|
||||
'region' => $this->params['region']
|
||||
));
|
||||
|
||||
if (!$this->connection->isValidBucketName($this->bucket)) {
|
||||
throw new \Exception("The configured bucket name is invalid.");
|
||||
}
|
||||
|
||||
if (!$this->connection->doesBucketExist($this->bucket)) {
|
||||
try {
|
||||
$this->connection->createBucket(array(
|
||||
'Bucket' => $this->bucket
|
||||
));
|
||||
$this->connection->waitUntilBucketExists(array(
|
||||
'Bucket' => $this->bucket,
|
||||
'waiter.interval' => 1,
|
||||
'waiter.max_attempts' => 15
|
||||
));
|
||||
$this->testTimeout();
|
||||
} catch (S3Exception $e) {
|
||||
\OCP\Util::logException('files_external', $e);
|
||||
throw new \Exception('Creation of bucket failed. '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return $this->connection;
|
||||
}
|
||||
|
||||
@@ -538,7 +605,7 @@ class AmazonS3 extends \OC\Files\Storage\Common {
|
||||
}
|
||||
|
||||
try {
|
||||
$result= $this->connection->putObject(array(
|
||||
$this->getConnection()->putObject(array(
|
||||
'Bucket' => $this->bucket,
|
||||
'Key' => $this->cleanKey(self::$tmpFiles[$tmpFile]),
|
||||
'SourceFile' => $tmpFile,
|
||||
@@ -549,7 +616,7 @@ class AmazonS3 extends \OC\Files\Storage\Common {
|
||||
|
||||
unlink($tmpFile);
|
||||
} catch (S3Exception $e) {
|
||||
\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
|
||||
\OCP\Util::logException('files_external', $e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Executable → Regular
+53
-1
@@ -118,6 +118,30 @@ class OC_Mount_Config {
|
||||
}
|
||||
$manager->addMount($mount);
|
||||
}
|
||||
|
||||
if ($data['user']) {
|
||||
$user = \OC::$server->getUserManager()->get($data['user']);
|
||||
if (!$user) {
|
||||
\OC_Log::write(
|
||||
'files_external',
|
||||
'Cannot init external mount points for non-existant user "' . $data['user'] . '".',
|
||||
\OC_Log::WARN
|
||||
);
|
||||
return;
|
||||
}
|
||||
$userView = new \OC\Files\View('/' . $user->getUID() . '/files');
|
||||
$changePropagator = new \OC\Files\Cache\ChangePropagator($userView);
|
||||
$etagPropagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, \OC::$server->getConfig());
|
||||
$etagPropagator->propagateDirtyMountPoints();
|
||||
\OCP\Util::connectHook(
|
||||
\OC\Files\Filesystem::CLASSNAME,
|
||||
\OC\Files\Filesystem::signal_create_mount,
|
||||
$etagPropagator, 'updateHook');
|
||||
\OCP\Util::connectHook(
|
||||
\OC\Files\Filesystem::CLASSNAME,
|
||||
\OC\Files\Filesystem::signal_delete_mount,
|
||||
$etagPropagator, 'updateHook');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -169,6 +193,7 @@ class OC_Mount_Config {
|
||||
foreach ($options as &$option) {
|
||||
$option = self::setUserVars($user, $option);
|
||||
}
|
||||
$options['personal'] = false;
|
||||
$options['options'] = self::decryptPasswords($options['options']);
|
||||
if (!isset($options['priority'])) {
|
||||
$options['priority'] = $backends[$options['class']]['priority'];
|
||||
@@ -458,6 +483,7 @@ class OC_Mount_Config {
|
||||
$priority = null) {
|
||||
$backends = self::getBackends();
|
||||
$mountPoint = OC\Files\Filesystem::normalizePath($mountPoint);
|
||||
$relMountPoint = $mountPoint;
|
||||
if ($mountPoint === '' || $mountPoint === '/') {
|
||||
// can't mount at root folder
|
||||
return false;
|
||||
@@ -490,6 +516,10 @@ class OC_Mount_Config {
|
||||
}
|
||||
|
||||
$mountPoints = self::readData($isPersonal ? OCP\User::getUser() : NULL);
|
||||
// who else loves multi-dimensional array ?
|
||||
$isNew = !isset($mountPoints[$mountType]) ||
|
||||
!isset($mountPoints[$mountType][$applicable]) ||
|
||||
!isset($mountPoints[$mountType][$applicable][$mountPoint]);
|
||||
$mountPoints = self::mergeMountPoints($mountPoints, $mount, $mountType);
|
||||
|
||||
// Set default priority if none set
|
||||
@@ -505,7 +535,19 @@ class OC_Mount_Config {
|
||||
|
||||
self::writeData($isPersonal ? OCP\User::getUser() : NULL, $mountPoints);
|
||||
|
||||
return self::getBackendStatus($class, $classOptions, $isPersonal);
|
||||
$result = self::getBackendStatus($class, $classOptions, $isPersonal);
|
||||
if ($result && $isNew) {
|
||||
\OC_Hook::emit(
|
||||
\OC\Files\Filesystem::CLASSNAME,
|
||||
\OC\Files\Filesystem::signal_create_mount,
|
||||
array(
|
||||
\OC\Files\Filesystem::signal_param_path => $relMountPoint,
|
||||
\OC\Files\Filesystem::signal_param_mount_type => $mountType,
|
||||
\OC\Files\Filesystem::signal_param_users => $applicable,
|
||||
)
|
||||
);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -518,6 +560,7 @@ class OC_Mount_Config {
|
||||
*/
|
||||
public static function removeMountPoint($mountPoint, $mountType, $applicable, $isPersonal = false) {
|
||||
// Verify that the mount point applies for the current user
|
||||
$relMountPoints = $mountPoint;
|
||||
if ($isPersonal) {
|
||||
if ($applicable != OCP\User::getUser()) {
|
||||
return false;
|
||||
@@ -538,6 +581,15 @@ class OC_Mount_Config {
|
||||
}
|
||||
}
|
||||
self::writeData($isPersonal ? OCP\User::getUser() : NULL, $mountPoints);
|
||||
\OC_Hook::emit(
|
||||
\OC\Files\Filesystem::CLASSNAME,
|
||||
\OC\Files\Filesystem::signal_delete_mount,
|
||||
array(
|
||||
\OC\Files\Filesystem::signal_param_path => $relMountPoints,
|
||||
\OC\Files\Filesystem::signal_param_mount_type => $mountType,
|
||||
\OC\Files\Filesystem::signal_param_users => $applicable,
|
||||
)
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Executable → Regular
+1
@@ -44,6 +44,7 @@ class Dropbox extends \OC\Files\Storage\Common {
|
||||
$this->id = 'dropbox::'.$params['app_key'] . $params['token']. '/' . $this->root;
|
||||
$oauth = new \Dropbox_OAuth_Curl($params['app_key'], $params['app_secret']);
|
||||
$oauth->setToken($params['token'], $params['token_secret']);
|
||||
// note: Dropbox_API connection is lazy
|
||||
$this->dropbox = new \Dropbox_API($oauth, 'auto');
|
||||
} else {
|
||||
throw new \Exception('Creating \OC\Files\Storage\Dropbox storage failed');
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later.
|
||||
* See the COPYING-README file.
|
||||
*/
|
||||
|
||||
namespace OCA\Files_External;
|
||||
|
||||
use OC\Files\Filesystem;
|
||||
|
||||
/**
|
||||
* Updates the etag of parent folders whenever a new external storage mount
|
||||
* point has been created or deleted. Updates need to be triggered using
|
||||
* the updateHook() method.
|
||||
*
|
||||
* There are two modes of operation:
|
||||
* - for personal mount points, the etag is propagated directly
|
||||
* - for system mount points, a dirty flag is saved in the configuration and
|
||||
* the etag will be updated the next time propagateDirtyMountPoints() is called
|
||||
*/
|
||||
class EtagPropagator {
|
||||
/**
|
||||
* @var \OCP\IUser
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* @var \OC\Files\Cache\ChangePropagator
|
||||
*/
|
||||
protected $changePropagator;
|
||||
|
||||
/**
|
||||
* @var \OCP\IConfig
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* @param \OCP\IUser $user current user, must match the propagator's
|
||||
* user
|
||||
* @param \OC\Files\Cache\ChangePropagator $changePropagator change propagator
|
||||
* initialized with a view for $user
|
||||
* @param \OCP\IConfig $config
|
||||
*/
|
||||
public function __construct($user, $changePropagator, $config) {
|
||||
$this->user = $user;
|
||||
$this->changePropagator = $changePropagator;
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Propagate the etag changes for all mountpoints marked as dirty and mark the mountpoints as clean
|
||||
*
|
||||
* @param int $time
|
||||
*/
|
||||
public function propagateDirtyMountPoints($time = null) {
|
||||
if ($time === null) {
|
||||
$time = time();
|
||||
}
|
||||
$mountPoints = $this->getDirtyMountPoints();
|
||||
foreach ($mountPoints as $mountPoint) {
|
||||
$this->changePropagator->addChange($mountPoint);
|
||||
$this->config->setUserValue($this->user->getUID(), 'files_external', $mountPoint, $time);
|
||||
}
|
||||
if (count($mountPoints)) {
|
||||
$this->changePropagator->propagateChanges($time);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all mountpoints we need to update the etag for
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
protected function getDirtyMountPoints() {
|
||||
$dirty = array();
|
||||
$mountPoints = $this->config->getAppKeys('files_external');
|
||||
foreach ($mountPoints as $mountPoint) {
|
||||
if (substr($mountPoint, 0, 1) === '/') {
|
||||
$updateTime = $this->config->getAppValue('files_external', $mountPoint);
|
||||
$userTime = $this->config->getUserValue($this->user->getUID(), 'files_external', $mountPoint);
|
||||
if ($updateTime > $userTime) {
|
||||
$dirty[] = $mountPoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $dirty;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $mountPoint
|
||||
* @param int $time
|
||||
*/
|
||||
protected function markDirty($mountPoint, $time = null) {
|
||||
if ($time === null) {
|
||||
$time = time();
|
||||
}
|
||||
$this->config->setAppValue('files_external', $mountPoint, $time);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update etags for mount points for known user
|
||||
* For global or group mount points, updating the etag for every user is not feasible
|
||||
* instead we mark the mount point as dirty and update the etag when the filesystem is loaded for the user
|
||||
* For personal mount points, the change is propagated directly
|
||||
*
|
||||
* @param array $params hook parameters
|
||||
* @param int $time update time to use when marking a mount point as dirty
|
||||
*/
|
||||
public function updateHook($params, $time = null) {
|
||||
if ($time === null) {
|
||||
$time = time();
|
||||
}
|
||||
$users = $params[Filesystem::signal_param_users];
|
||||
$type = $params[Filesystem::signal_param_mount_type];
|
||||
$mountPoint = $params[Filesystem::signal_param_path];
|
||||
$mountPoint = Filesystem::normalizePath($mountPoint);
|
||||
if ($type === \OC_Mount_Config::MOUNT_TYPE_GROUP or $users === 'all') {
|
||||
$this->markDirty($mountPoint, $time);
|
||||
} else {
|
||||
$this->changePropagator->addChange($mountPoint);
|
||||
$this->changePropagator->propagateChanges($time);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,7 +39,7 @@ class FTP extends \OC\Files\Storage\StreamWrapper{
|
||||
$this->root .= '/';
|
||||
}
|
||||
} else {
|
||||
throw new \Exception();
|
||||
throw new \Exception('Creating \OC\Files\Storage\FTP storage failed');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@ class Google extends \OC\Files\Storage\Common {
|
||||
$client->setScopes(array('https://www.googleapis.com/auth/drive'));
|
||||
$client->setUseObjects(true);
|
||||
$client->setAccessToken($params['token']);
|
||||
// note: API connection is lazy
|
||||
$this->service = new \Google_DriveService($client);
|
||||
$token = json_decode($params['token'], true);
|
||||
$this->id = 'google::'.substr($params['client_id'], 0, 30).$token['created'];
|
||||
|
||||
@@ -22,6 +22,14 @@ class OwnCloud extends \OC\Files\Storage\DAV{
|
||||
// extract context path from host if specified
|
||||
// (owncloud install path on host)
|
||||
$host = $params['host'];
|
||||
// strip protocol
|
||||
if (substr($host, 0, 8) == "https://") {
|
||||
$host = substr($host, 8);
|
||||
$params['secure'] = true;
|
||||
} else if (substr($host, 0, 7) == "http://") {
|
||||
$host = substr($host, 7);
|
||||
$params['secure'] = false;
|
||||
}
|
||||
$contextPath = '';
|
||||
$hostSlashPos = strpos($host, '/');
|
||||
if ($hostSlashPos !== false){
|
||||
@@ -29,13 +37,13 @@ class OwnCloud extends \OC\Files\Storage\DAV{
|
||||
$host = substr($host, 0, $hostSlashPos);
|
||||
}
|
||||
|
||||
if (substr($contextPath , 1) !== '/'){
|
||||
if (substr($contextPath, -1) !== '/'){
|
||||
$contextPath .= '/';
|
||||
}
|
||||
|
||||
if (isset($params['root'])){
|
||||
$root = $params['root'];
|
||||
if (substr($root, 1) !== '/'){
|
||||
if (substr($root, 0, 1) !== '/'){
|
||||
$root = '/' . $root;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,18 @@ class SFTP extends \OC\Files\Storage\Common {
|
||||
if (substr($this->root, -1, 1) != '/') {
|
||||
$this->root .= '/';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the connection.
|
||||
*
|
||||
* @return \Net_SFTP connected client instance
|
||||
* @throws \Exception when the connection failed
|
||||
*/
|
||||
public function getConnection() {
|
||||
if (!is_null($this->client)) {
|
||||
return $this->client;
|
||||
}
|
||||
|
||||
$hostKeys = $this->readHostKeys();
|
||||
$this->client = new \Net_SFTP($this->host);
|
||||
@@ -71,6 +83,7 @@ class SFTP extends \OC\Files\Storage\Common {
|
||||
if (!$this->client->login($this->user, $this->password)) {
|
||||
throw new \Exception('Login failed');
|
||||
}
|
||||
return $this->client;
|
||||
}
|
||||
|
||||
public function test() {
|
||||
@@ -81,7 +94,7 @@ class SFTP extends \OC\Files\Storage\Common {
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return $this->client->nlist() !== false;
|
||||
return $this->getConnection()->nlist() !== false;
|
||||
}
|
||||
|
||||
public function getId(){
|
||||
@@ -149,7 +162,7 @@ class SFTP extends \OC\Files\Storage\Common {
|
||||
|
||||
public function mkdir($path) {
|
||||
try {
|
||||
return $this->client->mkdir($this->absPath($path));
|
||||
return $this->getConnection()->mkdir($this->absPath($path));
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
@@ -157,7 +170,7 @@ class SFTP extends \OC\Files\Storage\Common {
|
||||
|
||||
public function rmdir($path) {
|
||||
try {
|
||||
return $this->client->delete($this->absPath($path), true);
|
||||
return $this->getConnection()->delete($this->absPath($path), true);
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
@@ -165,7 +178,7 @@ class SFTP extends \OC\Files\Storage\Common {
|
||||
|
||||
public function opendir($path) {
|
||||
try {
|
||||
$list = $this->client->nlist($this->absPath($path));
|
||||
$list = $this->getConnection()->nlist($this->absPath($path));
|
||||
|
||||
$id = md5('sftp:' . $path);
|
||||
$dirStream = array();
|
||||
@@ -183,7 +196,7 @@ class SFTP extends \OC\Files\Storage\Common {
|
||||
|
||||
public function filetype($path) {
|
||||
try {
|
||||
$stat = $this->client->stat($this->absPath($path));
|
||||
$stat = $this->getConnection()->stat($this->absPath($path));
|
||||
if ($stat['type'] == NET_SFTP_TYPE_REGULAR) {
|
||||
return 'file';
|
||||
}
|
||||
@@ -199,7 +212,7 @@ class SFTP extends \OC\Files\Storage\Common {
|
||||
|
||||
public function file_exists($path) {
|
||||
try {
|
||||
return $this->client->stat($this->absPath($path)) !== false;
|
||||
return $this->getConnection()->stat($this->absPath($path)) !== false;
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
@@ -207,7 +220,7 @@ class SFTP extends \OC\Files\Storage\Common {
|
||||
|
||||
public function unlink($path) {
|
||||
try {
|
||||
return $this->client->delete($this->absPath($path), true);
|
||||
return $this->getConnection()->delete($this->absPath($path), true);
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
@@ -234,7 +247,7 @@ class SFTP extends \OC\Files\Storage\Common {
|
||||
case 'x+':
|
||||
case 'c':
|
||||
case 'c+':
|
||||
$context = stream_context_create(array('sftp' => array('session' => $this->client)));
|
||||
$context = stream_context_create(array('sftp' => array('session' => $this->getConnection())));
|
||||
return fopen($this->constructUrl($path), $mode, false, $context);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
@@ -248,7 +261,7 @@ class SFTP extends \OC\Files\Storage\Common {
|
||||
return false;
|
||||
}
|
||||
if (!$this->file_exists($path)) {
|
||||
$this->client->put($this->absPath($path), '');
|
||||
$this->getConnection()->put($this->absPath($path), '');
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@@ -259,11 +272,11 @@ class SFTP extends \OC\Files\Storage\Common {
|
||||
}
|
||||
|
||||
public function getFile($path, $target) {
|
||||
$this->client->get($path, $target);
|
||||
$this->getConnection()->get($path, $target);
|
||||
}
|
||||
|
||||
public function uploadFile($path, $target) {
|
||||
$this->client->put($target, $path, NET_SFTP_LOCAL_FILE);
|
||||
$this->getConnection()->put($target, $path, NET_SFTP_LOCAL_FILE);
|
||||
}
|
||||
|
||||
public function rename($source, $target) {
|
||||
@@ -271,7 +284,7 @@ class SFTP extends \OC\Files\Storage\Common {
|
||||
if (!$this->is_dir($target) && $this->file_exists($target)) {
|
||||
$this->unlink($target);
|
||||
}
|
||||
return $this->client->rename(
|
||||
return $this->getConnection()->rename(
|
||||
$this->absPath($source),
|
||||
$this->absPath($target)
|
||||
);
|
||||
@@ -282,7 +295,7 @@ class SFTP extends \OC\Files\Storage\Common {
|
||||
|
||||
public function stat($path) {
|
||||
try {
|
||||
$stat = $this->client->stat($this->absPath($path));
|
||||
$stat = $this->getConnection()->stat($this->absPath($path));
|
||||
|
||||
$mtime = $stat ? $stat['mtime'] : -1;
|
||||
$size = $stat ? $stat['size'] : 0;
|
||||
|
||||
@@ -13,14 +13,24 @@ require_once __DIR__ . '/../3rdparty/smb4php/smb.php';
|
||||
class SMB_OC extends \OC\Files\Storage\SMB {
|
||||
private $username_as_share;
|
||||
|
||||
/**
|
||||
* @param array $params
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct($params) {
|
||||
if (isset($params['host']) && \OC::$session->exists('smb-credentials')) {
|
||||
if (isset($params['host'])) {
|
||||
$host=$params['host'];
|
||||
$this->username_as_share = ($params['username_as_share'] === 'true');
|
||||
|
||||
$params_auth = \OC::$session->get('smb-credentials');
|
||||
$user = \OC::$session->get('loginname');
|
||||
$password = $params_auth['password'];
|
||||
$user = 'foo';
|
||||
$password = 'bar';
|
||||
if (\OC::$session->exists('smb-credentials')) {
|
||||
$params_auth = json_decode(\OC::$server->getCrypto()->decrypt(\OC::$session->get('smb-credentials')), true);
|
||||
$user = \OC::$session->get('loginname');
|
||||
$password = $params_auth['password'];
|
||||
} else {
|
||||
// assume we are testing from the admin section
|
||||
}
|
||||
|
||||
$root=isset($params['root'])?$params['root']:'/';
|
||||
$share = '';
|
||||
@@ -44,14 +54,34 @@ class SMB_OC extends \OC\Files\Storage\SMB {
|
||||
}
|
||||
}
|
||||
|
||||
public static function login( $params ) {
|
||||
\OC::$session->set('smb-credentials', $params);
|
||||
/**
|
||||
* Intercepts the user credentials on login and stores them
|
||||
* encrypted inside the session if SMB_OC storage is enabled.
|
||||
* @param array $params
|
||||
*/
|
||||
public static function login($params) {
|
||||
$mountpoints = \OC_Mount_Config::getAbsoluteMountPoints($params['uid']);
|
||||
$mountpointClasses = array();
|
||||
foreach($mountpoints as $mountpoint) {
|
||||
$mountpointClasses[$mountpoint['class']] = true;
|
||||
}
|
||||
if(isset($mountpointClasses['\OC\Files\Storage\SMB_OC'])) {
|
||||
\OC::$session->set('smb-credentials', \OC::$server->getCrypto()->encrypt(json_encode($params)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @return boolean
|
||||
*/
|
||||
public function isSharable($path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $isPersonal
|
||||
* @return bool
|
||||
*/
|
||||
public function test($isPersonal = true) {
|
||||
if ($isPersonal) {
|
||||
if ($this->stat('')) {
|
||||
|
||||
@@ -47,6 +47,12 @@ class Swift extends \OC\Files\Storage\Common {
|
||||
* @var string
|
||||
*/
|
||||
private $bucket;
|
||||
/**
|
||||
* Connection parameters
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $params;
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
@@ -84,7 +90,7 @@ class Swift extends \OC\Files\Storage\Common {
|
||||
*/
|
||||
private function doesObjectExist($path) {
|
||||
try {
|
||||
$this->container->getPartialObject($path);
|
||||
$this->getContainer()->getPartialObject($path);
|
||||
return true;
|
||||
} catch (ClientErrorResponseException $e) {
|
||||
\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
|
||||
@@ -110,37 +116,7 @@ class Swift extends \OC\Files\Storage\Common {
|
||||
$params['service_name'] = 'cloudFiles';
|
||||
}
|
||||
|
||||
$settings = array(
|
||||
'username' => $params['user'],
|
||||
);
|
||||
|
||||
if (isset($params['password'])) {
|
||||
$settings['password'] = $params['password'];
|
||||
} else if (isset($params['key'])) {
|
||||
$settings['apiKey'] = $params['key'];
|
||||
}
|
||||
|
||||
if (isset($params['tenant'])) {
|
||||
$settings['tenantName'] = $params['tenant'];
|
||||
}
|
||||
|
||||
if (isset($params['timeout'])) {
|
||||
$settings['timeout'] = $params['timeout'];
|
||||
}
|
||||
|
||||
$this->anchor = new OpenStack($params['url'], $settings);
|
||||
|
||||
$this->connection = $this->anchor->objectStoreService($params['service_name'], $params['region']);
|
||||
|
||||
try {
|
||||
$this->container = $this->connection->getContainer($this->bucket);
|
||||
} catch (ClientErrorResponseException $e) {
|
||||
$this->container = $this->connection->createContainer($this->bucket);
|
||||
}
|
||||
|
||||
if (!$this->file_exists('.')) {
|
||||
$this->mkdir('.');
|
||||
}
|
||||
$this->params = $params;
|
||||
}
|
||||
|
||||
public function mkdir($path) {
|
||||
@@ -158,7 +134,7 @@ class Swift extends \OC\Files\Storage\Common {
|
||||
$customHeaders = array('content-type' => 'httpd/unix-directory');
|
||||
$metadataHeaders = DataObject::stockHeaders(array());
|
||||
$allHeaders = $customHeaders + $metadataHeaders;
|
||||
$this->container->uploadObject($path, '', $allHeaders);
|
||||
$this->getContainer()->uploadObject($path, '', $allHeaders);
|
||||
} catch (Exceptions\CreateUpdateError $e) {
|
||||
\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
|
||||
return false;
|
||||
@@ -198,7 +174,7 @@ class Swift extends \OC\Files\Storage\Common {
|
||||
}
|
||||
|
||||
try {
|
||||
$this->container->dataObject()->setName($path . '/')->delete();
|
||||
$this->getContainer()->dataObject()->setName($path . '/')->delete();
|
||||
} catch (Exceptions\DeleteError $e) {
|
||||
\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
|
||||
return false;
|
||||
@@ -221,7 +197,7 @@ class Swift extends \OC\Files\Storage\Common {
|
||||
try {
|
||||
$files = array();
|
||||
/** @var OpenCloud\Common\Collection $objects */
|
||||
$objects = $this->container->objectList(array(
|
||||
$objects = $this->getContainer()->objectList(array(
|
||||
'prefix' => $path,
|
||||
'delimiter' => '/'
|
||||
));
|
||||
@@ -251,7 +227,7 @@ class Swift extends \OC\Files\Storage\Common {
|
||||
}
|
||||
|
||||
try {
|
||||
$object = $this->container->getPartialObject($path);
|
||||
$object = $this->getContainer()->getPartialObject($path);
|
||||
} catch (ClientErrorResponseException $e) {
|
||||
\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
|
||||
return false;
|
||||
@@ -304,7 +280,7 @@ class Swift extends \OC\Files\Storage\Common {
|
||||
}
|
||||
|
||||
try {
|
||||
$this->container->dataObject()->setName($path)->delete();
|
||||
$this->getContainer()->dataObject()->setName($path)->delete();
|
||||
} catch (ClientErrorResponseException $e) {
|
||||
\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
|
||||
return false;
|
||||
@@ -322,7 +298,7 @@ class Swift extends \OC\Files\Storage\Common {
|
||||
$tmpFile = \OC_Helper::tmpFile();
|
||||
self::$tmpFiles[$tmpFile] = $path;
|
||||
try {
|
||||
$object = $this->container->getObject($path);
|
||||
$object = $this->getContainer()->getObject($path);
|
||||
} catch (ClientErrorResponseException $e) {
|
||||
\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
|
||||
return false;
|
||||
@@ -375,7 +351,7 @@ class Swift extends \OC\Files\Storage\Common {
|
||||
if ($this->is_dir($path)) {
|
||||
return 'httpd/unix-directory';
|
||||
} else if ($this->file_exists($path)) {
|
||||
$object = $this->container->getPartialObject($path);
|
||||
$object = $this->getContainer()->getPartialObject($path);
|
||||
return $object->getContentType();
|
||||
}
|
||||
return false;
|
||||
@@ -392,14 +368,15 @@ class Swift extends \OC\Files\Storage\Common {
|
||||
$path .= '/';
|
||||
}
|
||||
|
||||
$object = $this->container->getPartialObject($path);
|
||||
$object = $this->getContainer()->getPartialObject($path);
|
||||
$object->saveMetadata($metadata);
|
||||
return true;
|
||||
} else {
|
||||
$customHeaders = array('content-type' => 'text/plain');
|
||||
$mimeType = \OC_Helper::getMimetypeDetector()->detectPath($path);
|
||||
$customHeaders = array('content-type' => $mimeType);
|
||||
$metadataHeaders = DataObject::stockHeaders($metadata);
|
||||
$allHeaders = $customHeaders + $metadataHeaders;
|
||||
$this->container->uploadObject($path, '', $allHeaders);
|
||||
$this->getContainer()->uploadObject($path, '', $allHeaders);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -415,7 +392,7 @@ class Swift extends \OC\Files\Storage\Common {
|
||||
$this->unlink($path2);
|
||||
|
||||
try {
|
||||
$source = $this->container->getPartialObject($path1);
|
||||
$source = $this->getContainer()->getPartialObject($path1);
|
||||
$source->copy($this->bucket.'/'.$path2);
|
||||
} catch (ClientErrorResponseException $e) {
|
||||
\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
|
||||
@@ -428,7 +405,7 @@ class Swift extends \OC\Files\Storage\Common {
|
||||
$this->unlink($path2);
|
||||
|
||||
try {
|
||||
$source = $this->container->getPartialObject($path1 . '/');
|
||||
$source = $this->getContainer()->getPartialObject($path1 . '/');
|
||||
$source->copy($this->bucket.'/'.$path2 . '/');
|
||||
} catch (ClientErrorResponseException $e) {
|
||||
\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
|
||||
@@ -486,16 +463,71 @@ class Swift extends \OC\Files\Storage\Common {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the connection
|
||||
*
|
||||
* @return OpenCloud\ObjectStore\Service connected client
|
||||
* @throws \Exception if connection could not be made
|
||||
*/
|
||||
public function getConnection() {
|
||||
if (!is_null($this->connection)) {
|
||||
return $this->connection;
|
||||
}
|
||||
|
||||
$settings = array(
|
||||
'username' => $this->params['user'],
|
||||
);
|
||||
|
||||
if (!empty($this->params['password'])) {
|
||||
$settings['password'] = $this->params['password'];
|
||||
} else if (!empty($this->params['key'])) {
|
||||
$settings['apiKey'] = $this->params['key'];
|
||||
}
|
||||
|
||||
if (!empty($this->params['tenant'])) {
|
||||
$settings['tenantName'] = $this->params['tenant'];
|
||||
}
|
||||
|
||||
if (!empty($this->params['timeout'])) {
|
||||
$settings['timeout'] = $this->params['timeout'];
|
||||
}
|
||||
|
||||
$this->anchor = new OpenStack($this->params['url'], $settings);
|
||||
|
||||
$this->connection = $this->anchor->objectStoreService($this->params['service_name'], $this->params['region']);
|
||||
|
||||
return $this->connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the initialized object store container.
|
||||
*
|
||||
* @return OpenCloud\ObjectStore\Resource\Container
|
||||
*/
|
||||
public function getContainer() {
|
||||
if (!is_null($this->container)) {
|
||||
return $this->container;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->container = $this->getConnection()->getContainer($this->bucket);
|
||||
} catch (ClientErrorResponseException $e) {
|
||||
$this->container = $this->getConnection()->createContainer($this->bucket);
|
||||
}
|
||||
|
||||
if (!$this->file_exists('.')) {
|
||||
$this->mkdir('.');
|
||||
}
|
||||
|
||||
return $this->container;
|
||||
}
|
||||
|
||||
public function writeBack($tmpFile) {
|
||||
if (!isset(self::$tmpFiles[$tmpFile])) {
|
||||
return false;
|
||||
}
|
||||
$fileData = fopen($tmpFile, 'r');
|
||||
$this->container->uploadObject(self::$tmpFiles[$tmpFile], $fileData);
|
||||
$this->getContainer()->uploadObject(self::$tmpFiles[$tmpFile], $fileData);
|
||||
unlink($tmpFile);
|
||||
}
|
||||
|
||||
|
||||
Executable → Regular
@@ -23,9 +23,10 @@
|
||||
OC_Util::checkAdminUser();
|
||||
|
||||
OCP\Util::addScript('files_external', 'settings');
|
||||
OCP\Util::addscript('3rdparty', 'chosen/chosen.jquery.min');
|
||||
OCP\Util::addStyle('files_external', 'settings');
|
||||
OCP\Util::addStyle('3rdparty', 'chosen/chosen');
|
||||
|
||||
OCP\Util::addScript('core', 'select2/select2');
|
||||
OCP\Util::addStyle('core', 'select2/select2');
|
||||
|
||||
$backends = OC_Mount_Config::getBackends();
|
||||
$personal_backends = array();
|
||||
@@ -46,9 +47,6 @@ $tmpl->assign('isAdminPage', true);
|
||||
$tmpl->assign('mounts', OC_Mount_Config::getSystemMountPoints());
|
||||
$tmpl->assign('backends', $backends);
|
||||
$tmpl->assign('personal_backends', $personal_backends);
|
||||
$tmpl->assign('groups', OC_Group::getGroups());
|
||||
$tmpl->assign('users', OCP\User::getUsers());
|
||||
$tmpl->assign('userDisplayNames', OC_User::getDisplayNames());
|
||||
$tmpl->assign('dependencies', OC_Mount_Config::checkDependencies());
|
||||
$tmpl->assign('allowUserMounting', OCP\Config::getAppValue('files_external', 'allow_user_mounting', 'yes'));
|
||||
return $tmpl->fetchPage();
|
||||
|
||||
@@ -88,31 +88,8 @@
|
||||
print_unescaped(json_encode($mount['applicable']['groups'])); ?>'
|
||||
data-applicable-users='<?php if (isset($mount['applicable']['users']))
|
||||
print_unescaped(json_encode($mount['applicable']['users'])); ?>'>
|
||||
<select class="chzn-select"
|
||||
multiple style="width:20em;"
|
||||
data-placeholder="<?php p($l->t('No user or group')); ?>">
|
||||
<option value="all"
|
||||
<?php if (empty($mount['class']) || (isset($mount['applicable']['users']) && in_array('all', $mount['applicable']['users']))) print_unescaped('selected="selected"');?> >
|
||||
<?php p($l->t('All Users')); ?>
|
||||
</option>
|
||||
<optgroup label="<?php p($l->t('Groups')); ?>">
|
||||
<?php foreach ($_['groups'] as $group): ?>
|
||||
<option value="<?php p($group); ?>(group)"
|
||||
<?php if (isset($mount['applicable']['groups']) && in_array($group, $mount['applicable']['groups'])): ?>
|
||||
selected="selected"
|
||||
<?php endif; ?>><?php p($group); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</optgroup>
|
||||
<optgroup label="<?php p($l->t('Users')); ?>">
|
||||
<?php foreach ($_['users'] as $user): ?>
|
||||
<option value="<?php p($user); ?>"
|
||||
<?php if (isset($mount['applicable']['users']) && in_array($user, $mount['applicable']['users'])): ?>
|
||||
selected="selected"
|
||||
<?php endif; ?>><?php p($_['userDisplayNames'][$user]); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</optgroup>
|
||||
</select>
|
||||
</td>
|
||||
<input type="hidden" class="applicableUsers" style="width:20em;" value=""/>
|
||||
</td>
|
||||
<?php endif; ?>
|
||||
<td <?php if (isset($mount['mountpoint'])): ?>class="remove"
|
||||
<?php else: ?>style="visibility:hidden;"
|
||||
|
||||
@@ -38,29 +38,11 @@ class AmazonS3 extends Storage {
|
||||
|
||||
public function tearDown() {
|
||||
if ($this->instance) {
|
||||
$connection = $this->instance->getConnection();
|
||||
|
||||
try {
|
||||
// NOTE(berendt): clearBucket() is not working with Ceph
|
||||
$iterator = $connection->getIterator('ListObjects', array(
|
||||
'Bucket' => $this->config['amazons3']['bucket']
|
||||
));
|
||||
|
||||
foreach ($iterator as $object) {
|
||||
$connection->deleteObject(array(
|
||||
'Bucket' => $this->config['amazons3']['bucket'],
|
||||
'Key' => $object['Key']
|
||||
));
|
||||
}
|
||||
} catch (S3Exception $e) {
|
||||
}
|
||||
|
||||
$connection->deleteBucket(array(
|
||||
'Bucket' => $this->config['amazons3']['bucket']
|
||||
));
|
||||
|
||||
//wait some seconds for completing the replication
|
||||
sleep(30);
|
||||
$this->instance->rmdir('');
|
||||
}
|
||||
}
|
||||
|
||||
public function testStat() {
|
||||
$this->markTestSkipped('S3 doesn\'t update the parents folder mtime');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Jörn Friedrich Dreyer
|
||||
* @copyright 2012 Jörn Friedrich Dreyer jfd@owncloud.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
namespace Test\Files\Storage;
|
||||
|
||||
class AmazonS3Migration extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
/**
|
||||
* @var \OC\Files\Storage\Storage instance
|
||||
*/
|
||||
protected $instance;
|
||||
|
||||
public function setUp () {
|
||||
$uuid = uniqid();
|
||||
|
||||
$this->params['key'] = 'key'.$uuid;
|
||||
$this->params['secret'] = 'secret'.$uuid;
|
||||
$this->params['bucket'] = 'bucket'.$uuid;
|
||||
|
||||
$this->oldId = 'amazon::' . $this->params['key'] . md5($this->params['secret']);
|
||||
$this->newId = 'amazon::' . $this->params['bucket'];
|
||||
}
|
||||
|
||||
public function tearDown () {
|
||||
$this->deleteStorage($this->oldId);
|
||||
$this->deleteStorage($this->newId);
|
||||
}
|
||||
|
||||
public function testUpdateLegacyOnlyId () {
|
||||
// add storage ids
|
||||
$oldCache = new \OC\Files\Cache\Cache($this->oldId);
|
||||
|
||||
// add file to old cache
|
||||
$fileId = $oldCache->put('/', array('size' => 0, 'mtime' => time(), 'mimetype' => 'httpd/directory'));
|
||||
|
||||
try {
|
||||
$this->instance = new \OC\Files\Storage\AmazonS3($this->params);
|
||||
} catch (\Exception $e) {
|
||||
//ignore
|
||||
}
|
||||
$storages = $this->getStorages();
|
||||
|
||||
$this->assertTrue(isset($storages[$this->newId]));
|
||||
$this->assertFalse(isset($storages[$this->oldId]));
|
||||
$this->assertSame((int)$oldCache->getNumericStorageId(), (int)$storages[$this->newId]);
|
||||
|
||||
list($storageId, $path) = \OC\Files\Cache\Cache::getById($fileId);
|
||||
|
||||
$this->assertSame($this->newId, $storageId);
|
||||
$this->assertSame('/', $path);
|
||||
}
|
||||
|
||||
public function testUpdateLegacyAndNewId () {
|
||||
// add storage ids
|
||||
|
||||
$oldCache = new \OC\Files\Cache\Cache($this->oldId);
|
||||
new \OC\Files\Cache\Cache($this->newId);
|
||||
|
||||
// add file to old cache
|
||||
$fileId = $oldCache->put('/', array('size' => 0, 'mtime' => time(), 'mimetype' => 'httpd/directory'));
|
||||
|
||||
try {
|
||||
$this->instance = new \OC\Files\Storage\AmazonS3($this->params);
|
||||
} catch (\Exception $e) {
|
||||
//ignore
|
||||
}
|
||||
$storages = $this->getStorages();
|
||||
|
||||
$this->assertTrue(isset($storages[$this->newId]));
|
||||
$this->assertFalse(isset($storages[$this->oldId]));
|
||||
|
||||
$this->assertNull(\OC\Files\Cache\Cache::getById($fileId), 'old filecache has not been cleared');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $storages
|
||||
* @return array
|
||||
*/
|
||||
public function getStorages() {
|
||||
$storages = array();
|
||||
$stmt = \OC::$server->getDatabaseConnection()->prepare(
|
||||
'SELECT `numeric_id`, `id` FROM `*PREFIX*storages` WHERE `id` IN (?, ?)'
|
||||
);
|
||||
$stmt->execute(array($this->oldId, $this->newId));
|
||||
while ($row = $stmt->fetch()) {
|
||||
$storages[$row['id']] = $row['numeric_id'];
|
||||
}
|
||||
return $storages;
|
||||
}
|
||||
|
||||
public function deleteStorage($id) {
|
||||
$stmt = \OC::$server->getDatabaseConnection()->prepare(
|
||||
'DELETE FROM `*PREFIX*storages` WHERE `id` = ?'
|
||||
);
|
||||
$stmt->execute(array($id));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,328 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later.
|
||||
* See the COPYING-README file.
|
||||
*/
|
||||
|
||||
namespace Tests\Files_External;
|
||||
|
||||
use OC\Files\Filesystem;
|
||||
use OC\User\User;
|
||||
|
||||
class EtagPropagator extends \PHPUnit_Framework_TestCase {
|
||||
protected function getUser() {
|
||||
return new User(uniqid(), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \PHPUnit_Framework_MockObject_MockObject | \OC\Files\Cache\ChangePropagator
|
||||
*/
|
||||
protected function getChangePropagator() {
|
||||
return $this->getMockBuilder('\OC\Files\Cache\ChangePropagator')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \PHPUnit_Framework_MockObject_MockObject | \OCP\IConfig
|
||||
*/
|
||||
protected function getConfig() {
|
||||
$appConfig = array();
|
||||
$userConfig = array();
|
||||
$mock = $this->getMockBuilder('\OCP\IConfig')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$mock->expects($this->any())
|
||||
->method('getAppValue')
|
||||
->will($this->returnCallback(function ($appId, $key, $default = null) use (&$appConfig) {
|
||||
if (isset($appConfig[$appId]) and isset($appConfig[$appId][$key])) {
|
||||
return $appConfig[$appId][$key];
|
||||
} else {
|
||||
return $default;
|
||||
}
|
||||
}));
|
||||
$mock->expects($this->any())
|
||||
->method('setAppValue')
|
||||
->will($this->returnCallback(function ($appId, $key, $value) use (&$appConfig) {
|
||||
if (!isset($appConfig[$appId])) {
|
||||
$appConfig[$appId] = array();
|
||||
}
|
||||
$appConfig[$appId][$key] = $value;
|
||||
}));
|
||||
$mock->expects($this->any())
|
||||
->method('getAppKeys')
|
||||
->will($this->returnCallback(function ($appId) use (&$appConfig) {
|
||||
if (!isset($appConfig[$appId])) {
|
||||
$appConfig[$appId] = array();
|
||||
}
|
||||
return array_keys($appConfig[$appId]);
|
||||
}));
|
||||
|
||||
$mock->expects($this->any())
|
||||
->method('getUserValue')
|
||||
->will($this->returnCallback(function ($userId, $appId, $key, $default = null) use (&$userConfig) {
|
||||
if (isset($userConfig[$userId]) and isset($userConfig[$userId][$appId]) and isset($userConfig[$userId][$appId][$key])) {
|
||||
return $userConfig[$userId][$appId][$key];
|
||||
} else {
|
||||
return $default;
|
||||
}
|
||||
}));
|
||||
$mock->expects($this->any())
|
||||
->method('setUserValue')
|
||||
->will($this->returnCallback(function ($userId, $appId, $key, $value) use (&$userConfig) {
|
||||
if (!isset($userConfig[$userId])) {
|
||||
$userConfig[$userId] = array();
|
||||
}
|
||||
if (!isset($userConfig[$userId][$appId])) {
|
||||
$userConfig[$userId][$appId] = array();
|
||||
}
|
||||
$userConfig[$userId][$appId][$key] = $value;
|
||||
}));
|
||||
|
||||
return $mock;
|
||||
}
|
||||
|
||||
public function testSingleUserMount() {
|
||||
$time = time();
|
||||
$user = $this->getUser();
|
||||
$config = $this->getConfig();
|
||||
$changePropagator = $this->getChangePropagator();
|
||||
$propagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, $config);
|
||||
|
||||
$changePropagator->expects($this->once())
|
||||
->method('addChange')
|
||||
->with('/test');
|
||||
$changePropagator->expects($this->once())
|
||||
->method('propagateChanges')
|
||||
->with($time);
|
||||
|
||||
$propagator->updateHook(array(
|
||||
Filesystem::signal_param_path => '/test',
|
||||
Filesystem::signal_param_mount_type => \OC_Mount_Config::MOUNT_TYPE_USER,
|
||||
Filesystem::signal_param_users => $user->getUID(),
|
||||
), $time);
|
||||
}
|
||||
|
||||
public function testGlobalMountNoDirectUpdate() {
|
||||
$time = time();
|
||||
$user = $this->getUser();
|
||||
$config = $this->getConfig();
|
||||
$changePropagator = $this->getChangePropagator();
|
||||
$propagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, $config);
|
||||
|
||||
// not updated directly
|
||||
$changePropagator->expects($this->never())
|
||||
->method('addChange');
|
||||
$changePropagator->expects($this->never())
|
||||
->method('propagateChanges');
|
||||
|
||||
$propagator->updateHook(array(
|
||||
Filesystem::signal_param_path => '/test',
|
||||
Filesystem::signal_param_mount_type => \OC_Mount_Config::MOUNT_TYPE_USER,
|
||||
Filesystem::signal_param_users => 'all',
|
||||
), $time);
|
||||
|
||||
// mount point marked as dirty
|
||||
$this->assertEquals(array('/test'), $config->getAppKeys('files_external'));
|
||||
$this->assertEquals($time, $config->getAppValue('files_external', '/test'));
|
||||
}
|
||||
|
||||
public function testGroupMountNoDirectUpdate() {
|
||||
$time = time();
|
||||
$user = $this->getUser();
|
||||
$config = $this->getConfig();
|
||||
$changePropagator = $this->getChangePropagator();
|
||||
$propagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, $config);
|
||||
|
||||
// not updated directly
|
||||
$changePropagator->expects($this->never())
|
||||
->method('addChange');
|
||||
$changePropagator->expects($this->never())
|
||||
->method('propagateChanges');
|
||||
|
||||
$propagator->updateHook(array(
|
||||
Filesystem::signal_param_path => '/test',
|
||||
Filesystem::signal_param_mount_type => \OC_Mount_Config::MOUNT_TYPE_GROUP,
|
||||
Filesystem::signal_param_users => 'test',
|
||||
), $time);
|
||||
|
||||
// mount point marked as dirty
|
||||
$this->assertEquals(array('/test'), $config->getAppKeys('files_external'));
|
||||
$this->assertEquals($time, $config->getAppValue('files_external', '/test'));
|
||||
}
|
||||
|
||||
public function testGlobalMountNoDirtyMountPoint() {
|
||||
$time = time();
|
||||
$user = $this->getUser();
|
||||
$config = $this->getConfig();
|
||||
$changePropagator = $this->getChangePropagator();
|
||||
$propagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, $config);
|
||||
|
||||
$changePropagator->expects($this->never())
|
||||
->method('addChange');
|
||||
$changePropagator->expects($this->never())
|
||||
->method('propagateChanges');
|
||||
|
||||
$propagator->propagateDirtyMountPoints($time);
|
||||
|
||||
$this->assertEquals(0, $config->getUserValue($user->getUID(), 'files_external', '/test', 0));
|
||||
}
|
||||
|
||||
public function testGlobalMountDirtyMountPointFirstTime() {
|
||||
$time = time();
|
||||
$user = $this->getUser();
|
||||
$config = $this->getConfig();
|
||||
$changePropagator = $this->getChangePropagator();
|
||||
$propagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, $config);
|
||||
|
||||
$config->setAppValue('files_external', '/test', $time - 10);
|
||||
|
||||
$changePropagator->expects($this->once())
|
||||
->method('addChange')
|
||||
->with('/test');
|
||||
$changePropagator->expects($this->once())
|
||||
->method('propagateChanges')
|
||||
->with($time);
|
||||
|
||||
$propagator->propagateDirtyMountPoints($time);
|
||||
|
||||
$this->assertEquals($time, $config->getUserValue($user->getUID(), 'files_external', '/test'));
|
||||
}
|
||||
|
||||
public function testGlobalMountNonDirtyMountPoint() {
|
||||
$time = time();
|
||||
$user = $this->getUser();
|
||||
$config = $this->getConfig();
|
||||
$changePropagator = $this->getChangePropagator();
|
||||
$propagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, $config);
|
||||
|
||||
$config->setAppValue('files_external', '/test', $time - 10);
|
||||
$config->setUserValue($user->getUID(), 'files_external', '/test', $time - 10);
|
||||
|
||||
$changePropagator->expects($this->never())
|
||||
->method('addChange');
|
||||
$changePropagator->expects($this->never())
|
||||
->method('propagateChanges');
|
||||
|
||||
$propagator->propagateDirtyMountPoints($time);
|
||||
|
||||
$this->assertEquals($time - 10, $config->getUserValue($user->getUID(), 'files_external', '/test'));
|
||||
}
|
||||
|
||||
public function testGlobalMountNonDirtyMountPointOtherUser() {
|
||||
$time = time();
|
||||
$user = $this->getUser();
|
||||
$user2 = $this->getUser();
|
||||
$config = $this->getConfig();
|
||||
$changePropagator = $this->getChangePropagator();
|
||||
$propagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, $config);
|
||||
|
||||
$config->setAppValue('files_external', '/test', $time - 10);
|
||||
$config->setUserValue($user2->getUID(), 'files_external', '/test', $time - 10);
|
||||
|
||||
$changePropagator->expects($this->once())
|
||||
->method('addChange')
|
||||
->with('/test');
|
||||
$changePropagator->expects($this->once())
|
||||
->method('propagateChanges')
|
||||
->with($time);
|
||||
|
||||
$propagator->propagateDirtyMountPoints($time);
|
||||
|
||||
$this->assertEquals($time, $config->getUserValue($user->getUID(), 'files_external', '/test'));
|
||||
}
|
||||
|
||||
public function testGlobalMountDirtyMountPointSecondTime() {
|
||||
$time = time();
|
||||
$user = $this->getUser();
|
||||
$config = $this->getConfig();
|
||||
$changePropagator = $this->getChangePropagator();
|
||||
$propagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, $config);
|
||||
|
||||
$config->setAppValue('files_external', '/test', $time - 10);
|
||||
$config->setUserValue($user->getUID(), 'files_external', '/test', $time - 20);
|
||||
|
||||
$changePropagator->expects($this->once())
|
||||
->method('addChange')
|
||||
->with('/test');
|
||||
$changePropagator->expects($this->once())
|
||||
->method('propagateChanges')
|
||||
->with($time);
|
||||
|
||||
$propagator->propagateDirtyMountPoints($time);
|
||||
|
||||
$this->assertEquals($time, $config->getUserValue($user->getUID(), 'files_external', '/test'));
|
||||
}
|
||||
|
||||
public function testGlobalMountMultipleUsers() {
|
||||
$time = time();
|
||||
$config = $this->getConfig();
|
||||
$user1 = $this->getUser();
|
||||
$user2 = $this->getUser();
|
||||
$user3 = $this->getUser();
|
||||
$changePropagator1 = $this->getChangePropagator();
|
||||
$changePropagator2 = $this->getChangePropagator();
|
||||
$changePropagator3 = $this->getChangePropagator();
|
||||
$propagator1 = new \OCA\Files_External\EtagPropagator($user1, $changePropagator1, $config);
|
||||
$propagator2 = new \OCA\Files_External\EtagPropagator($user2, $changePropagator2, $config);
|
||||
$propagator3 = new \OCA\Files_External\EtagPropagator($user3, $changePropagator3, $config);
|
||||
|
||||
$config->setAppValue('files_external', '/test', $time - 10);
|
||||
|
||||
$changePropagator1->expects($this->once())
|
||||
->method('addChange')
|
||||
->with('/test');
|
||||
$changePropagator1->expects($this->once())
|
||||
->method('propagateChanges')
|
||||
->with($time);
|
||||
|
||||
$propagator1->propagateDirtyMountPoints($time);
|
||||
|
||||
$this->assertEquals($time, $config->getUserValue($user1->getUID(), 'files_external', '/test'));
|
||||
$this->assertEquals(0, $config->getUserValue($user2->getUID(), 'files_external', '/test', 0));
|
||||
$this->assertEquals(0, $config->getUserValue($user3->getUID(), 'files_external', '/test', 0));
|
||||
|
||||
$changePropagator2->expects($this->once())
|
||||
->method('addChange')
|
||||
->with('/test');
|
||||
$changePropagator2->expects($this->once())
|
||||
->method('propagateChanges')
|
||||
->with($time);
|
||||
|
||||
$propagator2->propagateDirtyMountPoints($time);
|
||||
|
||||
$this->assertEquals($time, $config->getUserValue($user1->getUID(), 'files_external', '/test'));
|
||||
$this->assertEquals($time, $config->getUserValue($user2->getUID(), 'files_external', '/test', 0));
|
||||
$this->assertEquals(0, $config->getUserValue($user3->getUID(), 'files_external', '/test', 0));
|
||||
}
|
||||
|
||||
public function testGlobalMountMultipleDirtyMountPoints() {
|
||||
$time = time();
|
||||
$user = $this->getUser();
|
||||
$config = $this->getConfig();
|
||||
$changePropagator = $this->getChangePropagator();
|
||||
$propagator = new \OCA\Files_External\EtagPropagator($user, $changePropagator, $config);
|
||||
|
||||
$config->setAppValue('files_external', '/test', $time - 10);
|
||||
$config->setAppValue('files_external', '/foo', $time - 50);
|
||||
$config->setAppValue('files_external', '/bar', $time - 70);
|
||||
|
||||
$config->setUserValue($user->getUID(), 'files_external', '/foo', $time - 70);
|
||||
$config->setUserValue($user->getUID(), 'files_external', '/bar', $time - 70);
|
||||
|
||||
$changePropagator->expects($this->exactly(2))
|
||||
->method('addChange');
|
||||
$changePropagator->expects($this->once())
|
||||
->method('propagateChanges')
|
||||
->with($time);
|
||||
|
||||
$propagator->propagateDirtyMountPoints($time);
|
||||
|
||||
$this->assertEquals($time, $config->getUserValue($user->getUID(), 'files_external', '/test'));
|
||||
$this->assertEquals($time, $config->getUserValue($user->getUID(), 'files_external', '/foo'));
|
||||
$this->assertEquals($time - 70, $config->getUserValue($user->getUID(), 'files_external', '/bar'));
|
||||
}
|
||||
}
|
||||
@@ -20,14 +20,48 @@
|
||||
*
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/../../../lib/base.php';
|
||||
|
||||
class Test_Mount_Config_Dummy_Storage {
|
||||
public function test() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class Test_Mount_Config_Hook_Test {
|
||||
static $signal;
|
||||
static $params;
|
||||
|
||||
public static function setUpHooks() {
|
||||
self::clear();
|
||||
\OCP\Util::connectHook(
|
||||
\OC\Files\Filesystem::CLASSNAME,
|
||||
\OC\Files\Filesystem::signal_create_mount,
|
||||
'\Test_Mount_Config_Hook_Test', 'createHookCallback');
|
||||
\OCP\Util::connectHook(
|
||||
\OC\Files\Filesystem::CLASSNAME,
|
||||
\OC\Files\Filesystem::signal_delete_mount,
|
||||
'\Test_Mount_Config_Hook_Test', 'deleteHookCallback');
|
||||
}
|
||||
|
||||
public static function clear() {
|
||||
self::$signal = null;
|
||||
self::$params = null;
|
||||
}
|
||||
|
||||
public static function createHookCallback($params) {
|
||||
self::$signal = \OC\Files\Filesystem::signal_create_mount;
|
||||
self::$params = $params;
|
||||
}
|
||||
|
||||
public static function deleteHookCallback($params) {
|
||||
self::$signal = \OC\Files\Filesystem::signal_delete_mount;
|
||||
self::$params = $params;
|
||||
}
|
||||
|
||||
public static function getLastCall() {
|
||||
return array(self::$signal, self::$params);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Test_Mount_Config
|
||||
*/
|
||||
@@ -79,9 +113,11 @@ class Test_Mount_Config extends \PHPUnit_Framework_TestCase {
|
||||
);
|
||||
|
||||
OC_Mount_Config::$skipTest = true;
|
||||
Test_Mount_Config_Hook_Test::setupHooks();
|
||||
}
|
||||
|
||||
public function tearDown() {
|
||||
Test_Mount_Config_Hook_Test::clear();
|
||||
OC_Mount_Config::$skipTest = false;
|
||||
|
||||
\OC_User::deleteUser(self::TEST_USER2);
|
||||
@@ -329,6 +365,102 @@ class Test_Mount_Config extends \PHPUnit_Framework_TestCase {
|
||||
$this->assertEquals(array_keys($options), array_keys($savedOptions));
|
||||
}
|
||||
|
||||
public function testHooks() {
|
||||
$mountPoint = '/test';
|
||||
$mountType = 'user';
|
||||
$applicable = 'all';
|
||||
$isPersonal = false;
|
||||
|
||||
$mountConfig = array(
|
||||
'host' => 'smbhost',
|
||||
'user' => 'smbuser',
|
||||
'password' => 'smbpassword',
|
||||
'share' => 'smbshare',
|
||||
'root' => 'smbroot'
|
||||
);
|
||||
|
||||
// write config
|
||||
$this->assertTrue(
|
||||
OC_Mount_Config::addMountPoint(
|
||||
$mountPoint,
|
||||
'\OC\Files\Storage\SMB',
|
||||
$mountConfig,
|
||||
$mountType,
|
||||
$applicable,
|
||||
$isPersonal
|
||||
)
|
||||
);
|
||||
|
||||
list($hookName, $params) = Test_Mount_Config_Hook_Test::getLastCall();
|
||||
$this->assertEquals(
|
||||
\OC\Files\Filesystem::signal_create_mount,
|
||||
$hookName
|
||||
);
|
||||
$this->assertEquals(
|
||||
$mountPoint,
|
||||
$params[\OC\Files\Filesystem::signal_param_path]
|
||||
);
|
||||
$this->assertEquals(
|
||||
$mountType,
|
||||
$params[\OC\Files\Filesystem::signal_param_mount_type]
|
||||
);
|
||||
$this->assertEquals(
|
||||
$applicable,
|
||||
$params[\OC\Files\Filesystem::signal_param_users]
|
||||
);
|
||||
|
||||
Test_Mount_Config_Hook_Test::clear();
|
||||
|
||||
// edit
|
||||
$mountConfig['host'] = 'anothersmbhost';
|
||||
$this->assertTrue(
|
||||
OC_Mount_Config::addMountPoint(
|
||||
$mountPoint,
|
||||
'\OC\Files\Storage\SMB',
|
||||
$mountConfig,
|
||||
$mountType,
|
||||
$applicable,
|
||||
$isPersonal
|
||||
)
|
||||
);
|
||||
|
||||
// hook must not be called on edit
|
||||
list($hookName, $params) = Test_Mount_Config_Hook_Test::getLastCall();
|
||||
$this->assertEquals(
|
||||
null,
|
||||
$hookName
|
||||
);
|
||||
|
||||
Test_Mount_Config_Hook_Test::clear();
|
||||
|
||||
$this->assertTrue(
|
||||
OC_Mount_Config::removeMountPoint(
|
||||
$mountPoint,
|
||||
$mountType,
|
||||
$applicable,
|
||||
$isPersonal
|
||||
)
|
||||
);
|
||||
|
||||
list($hookName, $params) = Test_Mount_Config_Hook_Test::getLastCall();
|
||||
$this->assertEquals(
|
||||
\OC\Files\Filesystem::signal_delete_mount,
|
||||
$hookName
|
||||
);
|
||||
$this->assertEquals(
|
||||
$mountPoint,
|
||||
$params[\OC\Files\Filesystem::signal_param_path]
|
||||
);
|
||||
$this->assertEquals(
|
||||
$mountType,
|
||||
$params[\OC\Files\Filesystem::signal_param_mount_type]
|
||||
);
|
||||
$this->assertEquals(
|
||||
$applicable,
|
||||
$params[\OC\Files\Filesystem::signal_param_users]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test password obfuscation
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (c) 2014 Vincent Petry <pvince81@owncloud.com>
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later.
|
||||
* See the COPYING-README file.
|
||||
*/
|
||||
|
||||
namespace Test\Files\Storage;
|
||||
|
||||
class OwnCloudFunctions extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
function configUrlProvider() {
|
||||
return array(
|
||||
array(
|
||||
array(
|
||||
'host' => 'testhost',
|
||||
'root' => 'testroot',
|
||||
'secure' => false
|
||||
),
|
||||
'http://testhost/remote.php/webdav/testroot/',
|
||||
),
|
||||
array(
|
||||
array(
|
||||
'host' => 'testhost',
|
||||
'root' => 'testroot',
|
||||
'secure' => true
|
||||
),
|
||||
'https://testhost/remote.php/webdav/testroot/',
|
||||
),
|
||||
array(
|
||||
array(
|
||||
'host' => 'http://testhost',
|
||||
'root' => 'testroot',
|
||||
'secure' => false
|
||||
),
|
||||
'http://testhost/remote.php/webdav/testroot/',
|
||||
),
|
||||
array(
|
||||
array(
|
||||
'host' => 'https://testhost',
|
||||
'root' => 'testroot',
|
||||
'secure' => false
|
||||
),
|
||||
'https://testhost/remote.php/webdav/testroot/',
|
||||
),
|
||||
array(
|
||||
array(
|
||||
'host' => 'https://testhost/testroot',
|
||||
'root' => '',
|
||||
'secure' => false
|
||||
),
|
||||
'https://testhost/testroot/remote.php/webdav/',
|
||||
),
|
||||
array(
|
||||
array(
|
||||
'host' => 'https://testhost/testroot',
|
||||
'root' => 'subdir',
|
||||
'secure' => false
|
||||
),
|
||||
'https://testhost/testroot/remote.php/webdav/subdir/',
|
||||
),
|
||||
array(
|
||||
array(
|
||||
'host' => 'http://testhost/testroot',
|
||||
'root' => 'subdir',
|
||||
'secure' => true
|
||||
),
|
||||
'http://testhost/testroot/remote.php/webdav/subdir/',
|
||||
),
|
||||
array(
|
||||
array(
|
||||
'host' => 'http://testhost/testroot/',
|
||||
'root' => '/subdir',
|
||||
'secure' => false
|
||||
),
|
||||
'http://testhost/testroot/remote.php/webdav/subdir/',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider configUrlProvider
|
||||
*/
|
||||
public function testConfig($config, $expectedUri) {
|
||||
$config['user'] = 'someuser';
|
||||
$config['password'] = 'somepassword';
|
||||
$instance = new \OC\Files\Storage\OwnCloud($config);
|
||||
$this->assertEquals($expectedUri, $instance->createBaseUri());
|
||||
}
|
||||
}
|
||||
@@ -24,25 +24,39 @@ $owner = $_POST['owner'];
|
||||
$name = $_POST['name'];
|
||||
$password = $_POST['password'];
|
||||
|
||||
// Check for invalid name
|
||||
if(!\OCP\Util::isValidFileName($name)) {
|
||||
\OCP\JSON::error(array('data' => array('message' => $l->t('The mountpoint name contains invalid characters.'))));
|
||||
exit();
|
||||
}
|
||||
|
||||
$user = \OC::$server->getUserSession()->getUser();
|
||||
$uid = ($user) ? $user->getUID() : null;
|
||||
$externalManager = new \OCA\Files_Sharing\External\Manager(
|
||||
\OC::$server->getDatabaseConnection(),
|
||||
\OC\Files\Filesystem::getMountManager(),
|
||||
\OC\Files\Filesystem::getLoader(),
|
||||
\OC::$server->getUserSession()
|
||||
$uid
|
||||
);
|
||||
|
||||
$name = OCP\Files::buildNotExistingFileName('/', $name);
|
||||
|
||||
$mount = $externalManager->addShare($remote, $token, $password, $name, $owner);
|
||||
/**
|
||||
* @var \OCA\Files_Sharing\External\Storage $storage
|
||||
*/
|
||||
$storage = $mount->getStorage();
|
||||
$result = $storage->file_exists('');
|
||||
if($result){
|
||||
$storage->getScanner()->scanAll();
|
||||
\OCP\JSON::success();
|
||||
// check for ssl cert
|
||||
if (substr($remote, 0, 5) === 'https' and !OC_Util::getUrlContent($remote)) {
|
||||
\OCP\JSON::error(array('data' => array('message' => $l->t("Invalid or untrusted ssl certificate"))));
|
||||
exit;
|
||||
} else {
|
||||
$externalManager->removeShare($mount->getMountPoint());
|
||||
\OCP\JSON::error(array('data' => array('message' => $l->t("Couldn't add remote share"))));
|
||||
$mount = $externalManager->addShare($remote, $token, $password, $name, $owner);
|
||||
/**
|
||||
* @var \OCA\Files_Sharing\External\Storage $storage
|
||||
*/
|
||||
$storage = $mount->getStorage();
|
||||
$result = $storage->file_exists('');
|
||||
if ($result) {
|
||||
$storage->getScanner()->scanAll();
|
||||
\OCP\JSON::success();
|
||||
} else {
|
||||
$externalManager->removeShare($mount->getMountPoint());
|
||||
\OCP\JSON::error(array('data' => array('message' => $l->t("Couldn't add remote share"))));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,8 @@ function testUrl($url) {
|
||||
try {
|
||||
$result = file_get_contents($url);
|
||||
$data = json_decode($result);
|
||||
return is_object($data) and !empty($data->version);
|
||||
// public link mount is only supported in ownCloud 7+
|
||||
return is_object($data) and !empty($data->version) and version_compare($data->version, '7.0.0', '>=');
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ $l = OC_L10N::get('files_sharing');
|
||||
OC::$CLASSPATH['OC_Share_Backend_File'] = 'files_sharing/lib/share/file.php';
|
||||
OC::$CLASSPATH['OC_Share_Backend_Folder'] = 'files_sharing/lib/share/folder.php';
|
||||
OC::$CLASSPATH['OC\Files\Storage\Shared'] = 'files_sharing/lib/sharedstorage.php';
|
||||
OC::$CLASSPATH['OC\Files\Cache\SharedScanner'] = 'files_sharing/lib/scanner.php';
|
||||
OC::$CLASSPATH['OC\Files\Cache\Shared_Cache'] = 'files_sharing/lib/cache.php';
|
||||
OC::$CLASSPATH['OC\Files\Cache\Shared_Permissions'] = 'files_sharing/lib/permissions.php';
|
||||
OC::$CLASSPATH['OC\Files\Cache\Shared_Updater'] = 'files_sharing/lib/updater.php';
|
||||
@@ -12,6 +13,9 @@ OC::$CLASSPATH['OCA\Files\Share\Api'] = 'files_sharing/lib/api.php';
|
||||
OC::$CLASSPATH['OCA\Files\Share\Maintainer'] = 'files_sharing/lib/maintainer.php';
|
||||
OC::$CLASSPATH['OCA\Files\Share\Proxy'] = 'files_sharing/lib/proxy.php';
|
||||
|
||||
// Exceptions
|
||||
OC::$CLASSPATH['OCA\Files_Sharing\Exceptions\BrokenPath'] = 'files_sharing/lib/exceptions.php';
|
||||
|
||||
\OCP\App::registerAdmin('files_sharing', 'settings-admin');
|
||||
|
||||
\OCA\Files_Sharing\Helper::registerHooks();
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
<field>
|
||||
<name>password</name>
|
||||
<type>text</type>
|
||||
<notnull>true</notnull>
|
||||
<notnull>false</notnull>
|
||||
<length>64</length>
|
||||
<comments>Optional password for the public share</comments>
|
||||
</field>
|
||||
|
||||
@@ -2,7 +2,11 @@
|
||||
<info>
|
||||
<id>files_sharing</id>
|
||||
<name>Share Files</name>
|
||||
<description>File sharing between users</description>
|
||||
<description>
|
||||
This application enables users to share files within ownCloud. If enabled, the admin can choose which groups can share files. The applicable users can then share files and folders with other users and groups within ownCloud. In addition, if the admin enables the share link feature, an external link can be used to share files with other users outside of ownCloud. Admins can also enforce passwords, expirations dates, and enable server to server sharing via share links, as well as sharing from mobile devices.
|
||||
Turning the feature off removes shared files and folders on the server for all share recipients, and also on the sync clients and mobile apps. More information is available in the ownCloud Documentation.
|
||||
|
||||
</description>
|
||||
<licence>AGPL</licence>
|
||||
<author>Michael Gapczynski, Bjoern Schiessle</author>
|
||||
<requiremin>4.93</requiremin>
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
// hack the buttons
|
||||
$dialog.find('.ui-icon').remove();
|
||||
$buttons.eq(0).text(t('core', 'Cancel'));
|
||||
$buttons.eq(1).text(t('core', 'Add remote share'));
|
||||
$buttons.eq(1).text(t('files_sharing', 'Add remote share'));
|
||||
};
|
||||
})();
|
||||
|
||||
|
||||
@@ -56,6 +56,11 @@ OCA.Sharing.PublicApp = {
|
||||
}
|
||||
|
||||
var mimetype = $('#mimetype').val();
|
||||
var mimetypeIcon = $('#mimetypeIcon').val();
|
||||
mimetypeIcon = mimetypeIcon.substring(0, mimetypeIcon.length - 3);
|
||||
mimetypeIcon = mimetypeIcon + 'svg';
|
||||
|
||||
var previewSupported = $('#previewSupported').val();
|
||||
|
||||
if (typeof FileActions !== 'undefined') {
|
||||
// Show file preview if previewer is available, images are already handled by the template
|
||||
@@ -68,21 +73,25 @@ OCA.Sharing.PublicApp = {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// dynamically load image previews
|
||||
if (mimetype.substr(0, mimetype.indexOf('/')) === 'image') {
|
||||
var params = {
|
||||
x: $(document).width() * window.devicePixelRatio,
|
||||
y: $(document).height() * window.devicePixelRatio,
|
||||
a: 'true',
|
||||
file: encodeURIComponent(this.initialDir + $('#filename').val()),
|
||||
t: $('#sharingToken').val(),
|
||||
scalingup: 0
|
||||
};
|
||||
|
||||
var params = {
|
||||
x: $(document).width() * window.devicePixelRatio,
|
||||
y: $(document).height() * window.devicePixelRatio,
|
||||
a: 'true',
|
||||
file: encodeURIComponent(this.initialDir + $('#filename').val()),
|
||||
t: $('#sharingToken').val(),
|
||||
scalingup: 0
|
||||
};
|
||||
|
||||
var img = $('<img class="publicpreview">');
|
||||
var img = $('<img class="publicpreview">');
|
||||
if (previewSupported === 'true' || mimetype.substr(0, mimetype.indexOf('/')) === 'image' && mimetype !== 'image/svg+xml') {
|
||||
img.attr('src', OC.filePath('files_sharing', 'ajax', 'publicpreview.php') + '?' + OC.buildQueryString(params));
|
||||
img.appendTo('#imgframe');
|
||||
} else if (mimetype.substr(0, mimetype.indexOf('/')) !== 'video') {
|
||||
img.attr('src', OC.Util.replaceSVGIcon(mimetypeIcon));
|
||||
img.attr('width', 128);
|
||||
img.appendTo('#imgframe');
|
||||
}
|
||||
|
||||
if (this.fileList) {
|
||||
@@ -201,7 +210,7 @@ OCA.Sharing.PublicApp = {
|
||||
// this check needs to happen on the server due to the Content Security Policy directive
|
||||
$.get(OC.generateUrl('apps/files_sharing/testremote'), {remote: remote}).then(function (protocol) {
|
||||
if (protocol !== 'http' && protocol !== 'https') {
|
||||
OC.dialogs.alert(t('files_sharing', 'No ownCloud installation found at {remote}', {remote: remote}),
|
||||
OC.dialogs.alert(t('files_sharing', 'No ownCloud installation (7 or higher) found at {remote}', {remote: remote}),
|
||||
t('files_sharing', 'Invalid ownCloud url'));
|
||||
} else {
|
||||
OC.redirect(protocol + '://' + url);
|
||||
|
||||
@@ -30,6 +30,10 @@ $TRANSLATIONS = array(
|
||||
"Direct link" => "Enllaz direutu",
|
||||
"Remote Shares" => "Comparticiones remotes",
|
||||
"Allow other instances to mount public links shared from this server" => "Permitir a otres instancies montar enllaces compartíos públicos d'esti sirvidor",
|
||||
"Allow users to mount public link shares" => "Permitir a los usuarios montar enllaces compartíos públicos"
|
||||
"Allow users to mount public link shares" => "Permitir a los usuarios montar enllaces compartíos públicos",
|
||||
"Remote share" => "Compartición remota",
|
||||
"Remote share password" => "Contraseña de compartición remota",
|
||||
"Do you want to add the remote share {name} from {owner}@{remote}?" => "Quies amestar compartición remota {name} de {owner}@{remote}?",
|
||||
"Add remote share" => "Amestar compartición remota",
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=2; plural=(n != 1);";
|
||||
|
||||
@@ -4,6 +4,12 @@ $TRANSLATIONS = array(
|
||||
"Shared by" => "Споделено от",
|
||||
"Name" => "Име",
|
||||
"Save" => "Запис",
|
||||
"Download" => "Изтегляне"
|
||||
"Download" => "Изтегляне",
|
||||
"Remote share" => "Прикачена Папка",
|
||||
"Remote share password" => "Парола за прикачена папка",
|
||||
"Do you want to add the remote share {name} from {owner}@{remote}?" => "Желаеш ли да добавиш като прикачената папка {name} от {owner}@{remote}?",
|
||||
"Couldn't add remote share" => "Неуспешно добавяне на отдалечена споделена директория.",
|
||||
"Add remote share" => "Добави прикачена папка",
|
||||
"Remote Shares" => "Прикачени Папки",
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=2; plural=(n != 1);";
|
||||
|
||||
@@ -3,6 +3,9 @@ $TRANSLATIONS = array(
|
||||
"Password" => "কূটশব্দ",
|
||||
"Name" => "রাম",
|
||||
"Save" => "সংরক্ষণ",
|
||||
"Download" => "ডাউনলোড"
|
||||
"Download" => "ডাউনলোড",
|
||||
"Remote share" => "দুরবর্তী ভাগাভাগি",
|
||||
"Couldn't add remote share" => "দুরবর্তী ভাগাভাগি যোগ করা গেলনা",
|
||||
"Remote Shares" => "দুরবর্তী ভাগাভাগি",
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=2; plural=(n != 1);";
|
||||
|
||||
@@ -31,6 +31,10 @@ $TRANSLATIONS = array(
|
||||
"Direct link" => "Enllaç directe",
|
||||
"Remote Shares" => "Compartició remota",
|
||||
"Allow other instances to mount public links shared from this server" => "Permet que altres instàncies muntin enllaços públics compartits des d'aqeust servidor",
|
||||
"Allow users to mount public link shares" => "Permet que usuaris muntin compartits amb enllaços públics"
|
||||
"Allow users to mount public link shares" => "Permet que usuaris muntin compartits amb enllaços públics",
|
||||
"Remote share" => "Compartició remota",
|
||||
"Remote share password" => "Contrasenya de compartició remota",
|
||||
"Do you want to add the remote share {name} from {owner}@{remote}?" => "Voleu afegir la compartició remota {nom} des de {owner}@{remote}?",
|
||||
"Add remote share" => "Afegeix compartició remota",
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=2; plural=(n != 1);";
|
||||
|
||||
@@ -31,6 +31,10 @@ $TRANSLATIONS = array(
|
||||
"Direct link" => "Přímý odkaz",
|
||||
"Remote Shares" => "Vzdálená úložiště",
|
||||
"Allow other instances to mount public links shared from this server" => "Povolit připojování veřejně sdílených odkazů z tohoto serveru",
|
||||
"Allow users to mount public link shares" => "Povolit uživatelům připojovat veřejně sdílené odkazy"
|
||||
"Allow users to mount public link shares" => "Povolit uživatelům připojovat veřejně sdílené odkazy",
|
||||
"Remote share" => "Vzdálené úložiště",
|
||||
"Remote share password" => "Heslo ke vzdálenému úložišti",
|
||||
"Do you want to add the remote share {name} from {owner}@{remote}?" => "Chcete přidat vzdálené úložiště {name} uživatele {owner}@{remote}?",
|
||||
"Add remote share" => "Přidat vzdálené úložiště",
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;";
|
||||
|
||||
@@ -22,6 +22,12 @@ $TRANSLATIONS = array(
|
||||
"Save" => "Gem",
|
||||
"Download" => "Download",
|
||||
"Download %s" => "Download %s",
|
||||
"Direct link" => "Direkte link"
|
||||
"Direct link" => "Direkte link",
|
||||
"Remote share" => "Ekstern deling",
|
||||
"Remote share password" => "Adgangskode for ekstern deling",
|
||||
"Do you want to add the remote share {name} from {owner}@{remote}?" => "Vil du tilføje den eksterne deling {name} fra {owner}@{remote}?",
|
||||
"Couldn't add remote share" => "Kunne ikke tliføje den delte ekstern ressource",
|
||||
"Add remote share" => "Tilføj ekstern deling",
|
||||
"Remote Shares" => "Eksterne delinger",
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=2; plural=(n != 1);";
|
||||
|
||||
@@ -31,6 +31,10 @@ $TRANSLATIONS = array(
|
||||
"Direct link" => "Direkter Link",
|
||||
"Remote Shares" => "Entfernte Freigaben",
|
||||
"Allow other instances to mount public links shared from this server" => "Andere Instanzen zum Hinzufügen von öffentlichen Links, die über diesen Server Freigegeben werden, erlauben",
|
||||
"Allow users to mount public link shares" => "Erlaube Nutzern das Hinzufügen von freigegebenen öffentlichen Links"
|
||||
"Allow users to mount public link shares" => "Erlaube Nutzern das Hinzufügen von freigegebenen öffentlichen Links",
|
||||
"Remote share" => "Entfernte Freigabe",
|
||||
"Remote share password" => "Passwort für die entfernte Freigabe",
|
||||
"Do you want to add the remote share {name} from {owner}@{remote}?" => "Möchtest Du die entfernte Freigabe {name} von {owner}@{remote} hinzufügen?",
|
||||
"Add remote share" => "Entfernte Freigabe hinzufügen",
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=2; plural=(n != 1);";
|
||||
|
||||
@@ -31,6 +31,10 @@ $TRANSLATIONS = array(
|
||||
"Direct link" => "Direkte Verlinkung",
|
||||
"Remote Shares" => "Entfernte Freigaben",
|
||||
"Allow other instances to mount public links shared from this server" => "Andere Instanzen zum Hinzufügen von öffentlichen Links, die über diesen Server Freigegeben werden, erlauben",
|
||||
"Allow users to mount public link shares" => "Erlaube Nutzern das Hinzufügen von freigegebenen öffentlichen Links"
|
||||
"Allow users to mount public link shares" => "Erlaube Nutzern das Hinzufügen von freigegebenen öffentlichen Links",
|
||||
"Remote share" => "Entfernte Freigabe",
|
||||
"Remote share password" => "Passwort für die entfernte Freigabe",
|
||||
"Do you want to add the remote share {name} from {owner}@{remote}?" => "Möchten Sie die entfernte Freigabe {name} von {owner}@{remote} hinzufügen?",
|
||||
"Add remote share" => "Entfernte Freigabe hinzufügen",
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=2; plural=(n != 1);";
|
||||
|
||||
@@ -31,6 +31,10 @@ $TRANSLATIONS = array(
|
||||
"Direct link" => "Άμεσος σύνδεσμος",
|
||||
"Remote Shares" => "Απομακρυσμένοι Κοινόχρηστοι Φάκελοι",
|
||||
"Allow other instances to mount public links shared from this server" => "Να επιτρέπεται σε άλλες εγκαταστάσεις να επιθέτουν δημόσιους συνδέσμους που έχουν διαμοιραστεί από αυτόν το διακομιστή",
|
||||
"Allow users to mount public link shares" => "Να επιτρέπεται στους χρήστες να επιθέτουν κοινόχρηστους φακέλους με δημόσιους συνδέσμους"
|
||||
"Allow users to mount public link shares" => "Να επιτρέπεται στους χρήστες να επιθέτουν κοινόχρηστους φακέλους με δημόσιους συνδέσμους",
|
||||
"Remote share" => "Απομακρυσμένος κοινόχρηστος φάκελος",
|
||||
"Remote share password" => "Κωδικός πρόσβασης απομακρυσμένου κοινόχρηστου φακέλου",
|
||||
"Do you want to add the remote share {name} from {owner}@{remote}?" => "Θέλετε να προσθέσουμε τον απομακρυσμένο κοινόχρηστο φάκελο {name} από {owner}@{remote}?",
|
||||
"Add remote share" => "Προσθήκη απομακρυσμένου κοινόχρηστου φακέλου",
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=2; plural=(n != 1);";
|
||||
|
||||
@@ -31,6 +31,10 @@ $TRANSLATIONS = array(
|
||||
"Direct link" => "Direct link",
|
||||
"Remote Shares" => "Remote Shares",
|
||||
"Allow other instances to mount public links shared from this server" => "Allow other instances to mount public links shared from this server",
|
||||
"Allow users to mount public link shares" => "Allow users to mount public link shares"
|
||||
"Allow users to mount public link shares" => "Allow users to mount public link shares",
|
||||
"Remote share" => "Remote share",
|
||||
"Remote share password" => "Remote share password",
|
||||
"Do you want to add the remote share {name} from {owner}@{remote}?" => "Do you want to add the remote share {name} from {owner}@{remote}?",
|
||||
"Add remote share" => "Add remote share",
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=2; plural=(n != 1);";
|
||||
|
||||
@@ -31,6 +31,10 @@ $TRANSLATIONS = array(
|
||||
"Direct link" => "Enlace directo",
|
||||
"Remote Shares" => "Almacenamiento compartido remoto",
|
||||
"Allow other instances to mount public links shared from this server" => "Permitir a otros montar enlaces publicos compartidos de este servidor",
|
||||
"Allow users to mount public link shares" => "Permitir a los usuarios montar enlaces publicos compartidos"
|
||||
"Allow users to mount public link shares" => "Permitir a los usuarios montar enlaces publicos compartidos",
|
||||
"Remote share" => "Recurso compartido remoto",
|
||||
"Remote share password" => "Contraseña del compartido remoto",
|
||||
"Do you want to add the remote share {name} from {owner}@{remote}?" => "¿Desea añadir el recurso compartido remoto {name} de {owner}@{remote}?",
|
||||
"Add remote share" => "Añadir recurso compartido remoto",
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=2; plural=(n != 1);";
|
||||
|
||||
@@ -30,6 +30,10 @@ $TRANSLATIONS = array(
|
||||
"Direct link" => "Otsene link",
|
||||
"Remote Shares" => "Eemalolevad jagamised",
|
||||
"Allow other instances to mount public links shared from this server" => "Luba teistel instantsidel ühendada sellest serverist jagatud avalikke linke",
|
||||
"Allow users to mount public link shares" => "Luba kasutajatel ühendada jagatud avalikke linke"
|
||||
"Allow users to mount public link shares" => "Luba kasutajatel ühendada jagatud avalikke linke",
|
||||
"Remote share" => "Kaugjagamine",
|
||||
"Remote share password" => "Kaugjagamise parool",
|
||||
"Do you want to add the remote share {name} from {owner}@{remote}?" => "Soovid lisata kaugjagamise {name} asukohast {owner}@{remote}?",
|
||||
"Add remote share" => "Lisa kaugjagamine",
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=2; plural=(n != 1);";
|
||||
|
||||
@@ -31,6 +31,10 @@ $TRANSLATIONS = array(
|
||||
"Direct link" => "Lotura zuzena",
|
||||
"Remote Shares" => "Hurruneko Elkarbanaketak",
|
||||
"Allow other instances to mount public links shared from this server" => "Baimendu beste instantziak zerbitzari honetatik elkarbanatutako lotura publikoak kargatzen",
|
||||
"Allow users to mount public link shares" => "Baimendu erabiltzaileak lotura publiko bidezko elkarbanaketak kargatzen"
|
||||
"Allow users to mount public link shares" => "Baimendu erabiltzaileak lotura publiko bidezko elkarbanaketak kargatzen",
|
||||
"Remote share" => "Urrutiko parte hartzea",
|
||||
"Remote share password" => "Urrutiko parte hartzeen pasahitza",
|
||||
"Do you want to add the remote share {name} from {owner}@{remote}?" => "Nahi duzu gehitzea {name} urrutiko partekatzea honengandik {owner}@{remote}?",
|
||||
"Add remote share" => "Gehitu urrutiko parte hartzea",
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=2; plural=(n != 1);";
|
||||
|
||||
@@ -15,6 +15,12 @@ $TRANSLATIONS = array(
|
||||
"Save" => "ذخیره",
|
||||
"Download" => "دانلود",
|
||||
"Download %s" => "دانلود %s",
|
||||
"Direct link" => "پیوند مستقیم"
|
||||
"Direct link" => "پیوند مستقیم",
|
||||
"Remote share" => "اشتراک از راه دور",
|
||||
"Remote share password" => "رمز عبور اشتراک از راه دور",
|
||||
"Do you want to add the remote share {name} from {owner}@{remote}?" => "آیا مایل به افزودن اشتراک از راه دور {name} از {owner}@{remote} هستید.",
|
||||
"Couldn't add remote share" => "امکان افزودن اشتراک گذاری از راه دور وجود ندارد",
|
||||
"Add remote share" => "افزودن اشتراک از راه دور",
|
||||
"Remote Shares" => "اشتراک های از راه دور",
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=1; plural=0;";
|
||||
|
||||
@@ -31,6 +31,10 @@ $TRANSLATIONS = array(
|
||||
"Direct link" => "Suora linkki",
|
||||
"Remote Shares" => "Etäjaot",
|
||||
"Allow other instances to mount public links shared from this server" => "Salli muiden instanssien liittää tältä palvelimelta jaettuja julkisia linkkejä",
|
||||
"Allow users to mount public link shares" => "Salli käyttäjien liittää julkisia linkkijakoja"
|
||||
"Allow users to mount public link shares" => "Salli käyttäjien liittää julkisia linkkijakoja",
|
||||
"Remote share" => "Etäjako",
|
||||
"Remote share password" => "Etäjaon salasana",
|
||||
"Do you want to add the remote share {name} from {owner}@{remote}?" => "Haluatko lisätä etäjaon {name} kohteesta {owner}@{remote}?",
|
||||
"Add remote share" => "Lisää etäjako",
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=2; plural=(n != 1);";
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
$TRANSLATIONS = array(
|
||||
"Server to server sharing is not enabled on this server" => "Le partage de serveur à serveur n'est pas activé sur ce serveur",
|
||||
"Couldn't add remote share" => "Impossible d'ajouter un partage distant",
|
||||
"Shared with you" => "Partagé avec vous",
|
||||
"Shared with others" => "Partagé avec d'autres",
|
||||
"Shared by link" => "Partagé par lien",
|
||||
"No files have been shared with you yet." => "Aucun fichier n'est partagé avec vous pour l'instant",
|
||||
"You haven't shared any files yet." => "Vous ne partagez pas de fichier pour l'instant",
|
||||
"You haven't shared any files by link yet." => "Vous ne partagez aucun de fichier par lien pour l'instant.",
|
||||
"Shared with you" => "Partagés avec vous",
|
||||
"Shared with others" => "Partagés avec d'autres",
|
||||
"Shared by link" => "Partagés par lien",
|
||||
"No files have been shared with you yet." => "Aucun fichier n'est partagé avec vous pour l'instant.",
|
||||
"You haven't shared any files yet." => "Vous ne partagez pas de fichier pour l'instant.",
|
||||
"You haven't shared any files by link yet." => "Vous ne partagez pas de fichier par lien pour l'instant.",
|
||||
"Add {name} from {owner}@{remote}" => "Ajouter {name} de {owner}@{remote}",
|
||||
"Add Share" => "Ajouter un partage",
|
||||
"Password" => "Mot de passe",
|
||||
@@ -31,6 +31,10 @@ $TRANSLATIONS = array(
|
||||
"Direct link" => "Lien direct",
|
||||
"Remote Shares" => "Partages Distants",
|
||||
"Allow other instances to mount public links shared from this server" => "Autorise d'autres instances à monter des liens publiques partagés depuis ce serveur",
|
||||
"Allow users to mount public link shares" => "Autorise les utilisateurs à monter des liens de partages publiques"
|
||||
"Allow users to mount public link shares" => "Autorise les utilisateurs à monter des liens de partages publiques",
|
||||
"Remote share" => "Partage distant",
|
||||
"Remote share password" => "Mot de passe du partage distant",
|
||||
"Do you want to add the remote share {name} from {owner}@{remote}?" => "Voulez-vous ajouter le partage distant {name} de {owner}@{remote} ?",
|
||||
"Add remote share" => "Ajouter un partage distant",
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=2; plural=(n > 1);";
|
||||
|
||||
@@ -31,6 +31,10 @@ $TRANSLATIONS = array(
|
||||
"Direct link" => "Ligazón directa",
|
||||
"Remote Shares" => "Comparticións remotas",
|
||||
"Allow other instances to mount public links shared from this server" => "Permitir que outras instancias monten ligazóns públicas compartidas desde este servidor",
|
||||
"Allow users to mount public link shares" => "Permitirlle aos usuarios montar ligazóns públicas compartidas"
|
||||
"Allow users to mount public link shares" => "Permitirlle aos usuarios montar ligazóns públicas compartidas",
|
||||
"Remote share" => "Compartición remota",
|
||||
"Remote share password" => "Contrasinal da compartición remota",
|
||||
"Do you want to add the remote share {name} from {owner}@{remote}?" => "Quere engadir a compartición remota {name} desde {owner}@{remote}?",
|
||||
"Add remote share" => "Engadir unha compartición remota",
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=2; plural=(n != 1);";
|
||||
|
||||
@@ -3,6 +3,12 @@ $TRANSLATIONS = array(
|
||||
"Password" => "Lozinka",
|
||||
"Name" => "Ime",
|
||||
"Save" => "Snimi",
|
||||
"Download" => "Preuzimanje"
|
||||
"Download" => "Preuzimanje",
|
||||
"Remote share" => "Udaljeni zajednički resurs (za raspodjelu)",
|
||||
"Remote share password" => "Lozinka za udaljeni zajednički resurs",
|
||||
"Do you want to add the remote share {name} from {owner}@{remote}?" => "Želite li dodati udaljeni zajednički resurs {name} od {owner}@{remote}?",
|
||||
"Couldn't add remote share" => "Udaljeni zajednički resurs nije moguće dodati",
|
||||
"Add remote share" => "Dodajte udaljeni zajednički resurs",
|
||||
"Remote Shares" => "Udaljeni zajednički resursi (za raspodjelu)",
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;";
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user