Compare commits
395 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| dc0a7428bd | |||
| 7534fae9bc | |||
| 68a9ceacbb | |||
| 8a3a5a2ff1 | |||
| 8995c81103 | |||
| 095f9114dd | |||
| 470a0ad611 | |||
| 9661001af1 | |||
| 17f869b2fb | |||
| 162ba722f6 | |||
| 4756d18a14 | |||
| 4605c2cc2d | |||
| 49e567a5cc | |||
| 7580518bd8 | |||
| d93b5af265 | |||
| 9a0c78b831 | |||
| 61a37331ce | |||
| d265d290c3 | |||
| aff7594ef3 | |||
| 5e586995a8 | |||
| 1d0e45e179 | |||
| cab94eb719 | |||
| c1cc4df26e | |||
| b4f154f9b4 | |||
| ac3f1d6f61 | |||
| d27f2929d2 | |||
| 6aee04bba4 | |||
| a88b253c78 | |||
| 751c1b0418 | |||
| a0feffb2a7 | |||
| 34d17e6168 | |||
| c30377392b | |||
| 0d2482a1a9 | |||
| 149814d95b | |||
| 16e24dc4c5 | |||
| dc11b87a1d | |||
| c8d34eaf9c | |||
| 9183ade655 | |||
| 678afc4906 | |||
| 6d3b5b24fd | |||
| 4286eeb531 | |||
| 0187537a2e | |||
| 928947f1c3 | |||
| fb1ebf13c6 | |||
| ed7e9be7cd | |||
| e903c8b57b | |||
| 210832ddf1 | |||
| 96ebefc597 | |||
| 5348e2eb54 | |||
| f6e6f465f2 | |||
| ce87f933a4 | |||
| a04af7854d | |||
| 75c7fd2886 | |||
| 92b4d52079 | |||
| 91b4045791 | |||
| 0f87a0248f | |||
| 3c9421381b | |||
| 2d946d2766 | |||
| a422f19fac | |||
| ebb1a70abc | |||
| b9d013e3ce | |||
| b044ec0420 | |||
| 864f0342af | |||
| 5a2e99c975 | |||
| d07f459409 | |||
| 3d5d6b5ad1 | |||
| 80dcec773a | |||
| 43738dacfb | |||
| 78b10de7d6 | |||
| 37db8a13d4 | |||
| eb8b2210cd | |||
| 118033cac6 | |||
| b0ba69ff31 | |||
| c1241b1691 | |||
| ad813da7b1 | |||
| b4f04c18db | |||
| 23985428ea | |||
| 018fed6014 | |||
| 3be50224ff | |||
| 0213928735 | |||
| 1cf599d494 | |||
| 8a4dbdedcf | |||
| 35b316f93f | |||
| 7e451a24bc | |||
| f8620704d4 | |||
| c6687e159b | |||
| 8227bc41cd | |||
| 6f5caaa87a | |||
| e5dac9fa24 | |||
| 48bb8aeb01 | |||
| fd32501fe0 | |||
| 0a475bdab3 | |||
| 3d6ab2b53b | |||
| 5e315495c2 | |||
| b353637e45 | |||
| fb6290c87a | |||
| 76cb5a50c0 | |||
| 5c40ef090a | |||
| 9c9b161f51 | |||
| 9b257ad862 | |||
| 5edc4c95bc | |||
| f9bd4c5d24 | |||
| 88a5f7d994 | |||
| 04b4c7c042 | |||
| 87d06bae85 | |||
| c096c6edc3 | |||
| 713c5c4275 | |||
| e48c7675b9 | |||
| f824986742 | |||
| 5e788ae1fa | |||
| 78b390da31 | |||
| b3257a315d | |||
| fc1763dc6b | |||
| 7b948b0580 | |||
| 379ddd88d6 | |||
| 23c015ba52 | |||
| 0f97d9555c | |||
| 0992a77cfb | |||
| 4b1f93b61c | |||
| 916122b166 | |||
| a3b351738a | |||
| 37f8607a88 | |||
| a4895e4df1 | |||
| a9a92892be | |||
| d8770d1284 | |||
| e3d8758a32 | |||
| 5a5496f4e7 | |||
| b33cfce2fa | |||
| 025ab0dabb | |||
| 63b078b550 | |||
| fa1288c6b3 | |||
| 9f9466d001 | |||
| 249df3864b | |||
| 615f0c4a1c | |||
| a096f19bb2 | |||
| a967acee4c | |||
| 2801edc451 | |||
| acebc3f41e | |||
| 9404389d83 | |||
| 60b75b25f8 | |||
| 608fe55889 | |||
| 37d2c0a4be | |||
| 3ccbc984f4 | |||
| 8bd3ce2fe2 | |||
| ebcbf85396 | |||
| 44a6d2a98c | |||
| 8ee368ddad | |||
| 34069e00c4 | |||
| 88542819f0 | |||
| 8a66c30895 | |||
| e6579a3c0a | |||
| 9016093b4c | |||
| 301e4988a1 | |||
| e6391d84a1 | |||
| 4c305ef459 | |||
| 72e308788f | |||
| f1dc6e1441 | |||
| 33801c311e | |||
| 0cd68cfedc | |||
| e00f483238 | |||
| 5cc8df3723 | |||
| 08bf128255 | |||
| 3979508dae | |||
| a5a2fe9180 | |||
| 29d63893ff | |||
| 39354eaaf1 | |||
| 2e8418b362 | |||
| 1a93891222 | |||
| 099ccfa254 | |||
| d41b2c5401 | |||
| 5f7bc2cf4d | |||
| 6d330e8a3f | |||
| 72b680ca2d | |||
| 5e1c3732e5 | |||
| 7251c65996 | |||
| fea0ba84c5 | |||
| cdfc6ff5d5 | |||
| 50721da77b | |||
| 14cbec6d6b | |||
| ea334cfa18 | |||
| c10af30381 | |||
| 4351609df9 | |||
| c430fe6612 | |||
| 3501007074 | |||
| 603828366f | |||
| e46df97c3a | |||
| 180bb9fa9f | |||
| 81f1c04b85 | |||
| b722ce6cc3 | |||
| 65fa896bc2 | |||
| 464b31157e | |||
| a9f7764879 | |||
| 047ae7fb23 | |||
| 98db90ba70 | |||
| 0b11762b1c | |||
| 127ab3cb47 | |||
| 09cc0c5cc9 | |||
| c4c5e34110 | |||
| 89d60a2680 | |||
| 369ec65d12 | |||
| 40c2f47cd9 | |||
| bc22799160 | |||
| 4c1510b729 | |||
| d44b98d3dd | |||
| a4e842f19a | |||
| aec0f06501 | |||
| f9e4d0a5e2 | |||
| 3093c63024 | |||
| b0edbd8ebd | |||
| 5dd20db05f | |||
| 0c140d5f6e | |||
| 49969825ad | |||
| 3b21499b34 | |||
| 3fde29ead4 | |||
| afe35ca12d | |||
| a83e37c799 | |||
| 3c7541e97c | |||
| 3ec3ebb3db | |||
| 3e71827bea | |||
| 6adac6a673 | |||
| 88dc71381f | |||
| c6ca9be406 | |||
| 7dddf59942 | |||
| 8ef32821be | |||
| 1e9f0409c3 | |||
| bcec9cea78 | |||
| 87cfbb3a2b | |||
| 3b1396b538 | |||
| ce1a1996f7 | |||
| 5f2e8f7723 | |||
| 54cd174f61 | |||
| 28be8496a9 | |||
| 3ae7bfc298 | |||
| 1cbe1896e7 | |||
| ebe3872c64 | |||
| f1ea0bcafc | |||
| cf8fc2294e | |||
| 1636c6dbd8 | |||
| 59ff8388ea | |||
| 1c58d8b226 | |||
| 0f58bd02c1 | |||
| 4b4901519d | |||
| a711d4e39a | |||
| 52dc90d5fd | |||
| 9a1cbabdd6 | |||
| 596ab7552e | |||
| ea23a09c05 | |||
| 394bd17251 | |||
| 627612c9e0 | |||
| c6fa2dd8e2 | |||
| 8d38228c98 | |||
| bbba8fd09d | |||
| 5e928fc988 | |||
| 7e36763631 | |||
| 542cf79595 | |||
| 2ea3765359 | |||
| b7aaebf94f | |||
| c9cb258616 | |||
| 697ad1ca9e | |||
| 6a838718df | |||
| 6a21922854 | |||
| c81a05cbb1 | |||
| 956a4419d8 | |||
| f356ef90d7 | |||
| a8fd55d90d | |||
| 208037b56a | |||
| 62887c67ab | |||
| 9960596f4e | |||
| b5ef21b22d | |||
| 44fb817a4e | |||
| 2c54dcda89 | |||
| 0bb7202ff7 | |||
| 75eaea1dff | |||
| 93b6c83814 | |||
| d9df271113 | |||
| 13461698e4 | |||
| eaa5dd0282 | |||
| 672cbc5378 | |||
| 2f568c9766 | |||
| c4c972fd2f | |||
| 6de259e0ac | |||
| 1f93b4e842 | |||
| 4c2d2f4dc9 | |||
| 148c16bf70 | |||
| 77af1a7127 | |||
| 2f0ec8256f | |||
| 913df0c5ed | |||
| c88109a496 | |||
| 8f5dfd0920 | |||
| ae58a385b7 | |||
| 3160b23291 | |||
| 73a0b690e9 | |||
| bdb4890d04 | |||
| 9091dd7833 | |||
| a8a35f4d07 | |||
| 0d24b22485 | |||
| e8a696cff9 | |||
| 811ef19ada | |||
| db696a2dda | |||
| 3d81009347 | |||
| 0b665700b5 | |||
| 1e407482be | |||
| d343c66f85 | |||
| 0a0d89296b | |||
| fede36d515 | |||
| 527a16852e | |||
| aab7c187f2 | |||
| dd7b074dfa | |||
| 71e93c2b79 | |||
| ca161e2a96 | |||
| ab8691d84b | |||
| a48cf28e17 | |||
| cd7c974fb6 | |||
| 3b5d032dd5 | |||
| f8088ecd29 | |||
| e83ff69465 | |||
| 66af605697 | |||
| 71dc81d420 | |||
| 02c9bb76ff | |||
| 7b388eb4a8 | |||
| c770089b50 | |||
| afaac05f61 | |||
| aba8199a82 | |||
| 0134b1ebfa | |||
| 339e073399 | |||
| 4feafda822 | |||
| 5ac339b866 | |||
| 95c90ddbc4 | |||
| 2417c8a49e | |||
| 26d0adf2fe | |||
| 734fdbddea | |||
| 33144941a9 | |||
| f309920bef | |||
| e78a309111 | |||
| 46a4ad4f3c | |||
| 3842c0d766 | |||
| 8369c1f05b | |||
| cadf1c232e | |||
| 713651738c | |||
| 1475245465 | |||
| 281bbf4bd4 | |||
| a2bbbb1448 | |||
| 87a28957aa | |||
| 01de6c565a | |||
| f3e341edac | |||
| c5d6af3c5a | |||
| cc1577054d | |||
| 3e6b18b2d0 | |||
| 7eb505e6dd | |||
| 91ca1cf985 | |||
| f8a4bcdd50 | |||
| 418d401bf9 | |||
| d0afd774b7 | |||
| 0af65cae37 | |||
| 4d50fe5f12 | |||
| f24aca61a9 | |||
| d3e2226b38 | |||
| 73fa6259be | |||
| dffc2a8b1c | |||
| fd634fdec8 | |||
| 328ebaefde | |||
| 4de8c4e5db | |||
| 8dc3cb2ffb | |||
| c67ece0f6b | |||
| 6640e120b7 | |||
| 6f7b394d99 | |||
| 91f47645b0 | |||
| 18903cc8f7 | |||
| 7e467484a8 | |||
| 21bf6abd41 | |||
| 401728b2a2 | |||
| bfd0dc3314 | |||
| ad92b12559 | |||
| 4391992b8c | |||
| 728e6d735a | |||
| 66df8c3bb3 | |||
| ca08d21da0 | |||
| 7d0f458f11 | |||
| f15aeb3bbc | |||
| 9333244925 | |||
| 50f5ab8515 | |||
| 4df0d2e7e8 | |||
| f2e17a0b68 | |||
| e372971f2b | |||
| 3bf30377b8 | |||
| 67b67b6d66 | |||
| b8390f15d4 | |||
| 5ac3f9bfa5 | |||
| 02fe013d2f | |||
| 5e5e4fe3a4 | |||
| d49e4e53fd | |||
| 2d11290121 | |||
| 1a197292da | |||
| 3b59979746 | |||
| 259d619af3 |
@@ -26,7 +26,7 @@ RewriteRule ^.well-known/carddav /remote.php/carddav/ [R]
|
||||
RewriteRule ^.well-known/caldav /remote.php/caldav/ [R]
|
||||
RewriteRule ^apps/calendar/caldav.php remote.php/caldav/ [QSA,L]
|
||||
RewriteRule ^apps/contacts/carddav.php remote.php/carddav/ [QSA,L]
|
||||
RewriteRule ^apps/([^/]*)/(.*\.(css|php))$ index.php?app=$1&getfile=$2 [QSA,L]
|
||||
RewriteRule ^apps/([^/]*)/(.*\.(php))$ index.php?app=$1&getfile=$2 [QSA,L]
|
||||
RewriteRule ^remote/(.*) remote.php [QSA,L]
|
||||
</IfModule>
|
||||
<IfModule mod_mime.c>
|
||||
@@ -38,3 +38,6 @@ DirectoryIndex index.php index.html
|
||||
</IfModule>
|
||||
AddDefaultCharset utf-8
|
||||
Options -Indexes
|
||||
<IfModule pagespeed_module>
|
||||
ModPagespeed Off
|
||||
</IfModule>
|
||||
|
||||
+1
-1
Submodule 3rdparty updated: 42efd96628...2c3c7ca21f
@@ -21,6 +21,7 @@ if (empty($_POST['dirToken'])) {
|
||||
} else {
|
||||
// return only read permissions for public upload
|
||||
$allowedPermissions = OCP\PERMISSION_READ;
|
||||
$public_directory = !empty($_POST['subdir']) ? $_POST['subdir'] : '/';
|
||||
|
||||
$linkItem = OCP\Share::getShareByToken($_POST['dirToken']);
|
||||
if ($linkItem === false) {
|
||||
@@ -34,6 +35,7 @@ if (empty($_POST['dirToken'])) {
|
||||
// resolve reshares
|
||||
$rootLinkItem = OCP\Share::resolveReShare($linkItem);
|
||||
|
||||
OCP\JSON::checkUserExists($rootLinkItem['uid_owner']);
|
||||
// Setup FS with owner
|
||||
OC_Util::tearDownFS();
|
||||
OC_Util::setupFS($rootLinkItem['uid_owner']);
|
||||
@@ -43,7 +45,7 @@ if (empty($_POST['dirToken'])) {
|
||||
$dir = sprintf(
|
||||
"/%s/%s",
|
||||
$path,
|
||||
isset($_POST['subdir']) ? $_POST['subdir'] : ''
|
||||
$public_directory
|
||||
);
|
||||
|
||||
if (!$dir || empty($dir) || $dir === false) {
|
||||
@@ -110,7 +112,14 @@ if (strpos($dir, '..') === false) {
|
||||
} else {
|
||||
$target = \OC\Files\Filesystem::normalizePath(stripslashes($dir).'/'.$files['name'][$i]);
|
||||
}
|
||||
|
||||
|
||||
$directory = \OC\Files\Filesystem::normalizePath(stripslashes($dir));
|
||||
if (isset($public_directory)) {
|
||||
// If we are uploading from the public app,
|
||||
// we want to send the relative path in the ajax request.
|
||||
$directory = $public_directory;
|
||||
}
|
||||
|
||||
if ( ! \OC\Files\Filesystem::file_exists($target)
|
||||
|| (isset($_POST['resolution']) && $_POST['resolution']==='replace')
|
||||
) {
|
||||
@@ -136,7 +145,8 @@ if (strpos($dir, '..') === false) {
|
||||
'originalname' => $files['tmp_name'][$i],
|
||||
'uploadMaxFilesize' => $maxUploadFileSize,
|
||||
'maxHumanFilesize' => $maxHumanFileSize,
|
||||
'permissions' => $meta['permissions'] & $allowedPermissions
|
||||
'permissions' => $meta['permissions'] & $allowedPermissions,
|
||||
'directory' => $directory,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -163,7 +173,8 @@ if (strpos($dir, '..') === false) {
|
||||
'originalname' => $files['tmp_name'][$i],
|
||||
'uploadMaxFilesize' => $maxUploadFileSize,
|
||||
'maxHumanFilesize' => $maxHumanFileSize,
|
||||
'permissions' => $meta['permissions'] & $allowedPermissions
|
||||
'permissions' => $meta['permissions'] & $allowedPermissions,
|
||||
'directory' => $directory,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@ $server->addPlugin(new OC_Connector_Sabre_FilesPlugin());
|
||||
$server->addPlugin(new OC_Connector_Sabre_AbortedUploadDetectionPlugin());
|
||||
$server->addPlugin(new OC_Connector_Sabre_QuotaPlugin());
|
||||
$server->addPlugin(new OC_Connector_Sabre_MaintenancePlugin());
|
||||
$server->addPlugin(new OC_Connector_Sabre_ExceptionLoggerPlugin('webdav'));
|
||||
|
||||
// And off we go!
|
||||
$server->exec();
|
||||
|
||||
@@ -58,6 +58,7 @@ class Scan extends Command {
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output) {
|
||||
if ($input->getOption('all')) {
|
||||
\OC_App::loadApps('authentication');
|
||||
$users = $this->userManager->search('');
|
||||
} else {
|
||||
$users = $input->getArgument('user_id');
|
||||
|
||||
@@ -65,9 +65,14 @@
|
||||
top: 44px;
|
||||
width: 100%;
|
||||
}
|
||||
#filestable, #controls {
|
||||
min-width: 680px;
|
||||
/* make sure there's enough room for the file actions */
|
||||
#body-user #filestable {
|
||||
min-width: 750px;
|
||||
}
|
||||
#body-user #controls {
|
||||
min-width: 600px;
|
||||
}
|
||||
|
||||
#filestable tbody tr { background-color:#fff; height:2.5em; }
|
||||
#filestable tbody tr:hover, tbody tr:active {
|
||||
background-color: rgb(240,240,240);
|
||||
@@ -98,7 +103,7 @@ table td {
|
||||
}
|
||||
table th#headerName {
|
||||
position: relative;
|
||||
width: 100em; /* not really sure why this works better than 100% … table styling */
|
||||
width: 9999px; /* not really sure why this works better than 100% … table styling */
|
||||
padding: 0;
|
||||
}
|
||||
#headerName-container {
|
||||
@@ -140,7 +145,7 @@ table.multiselect thead th {
|
||||
}
|
||||
table.multiselect #headerName {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
width: 9999px; /* when we use 100%, the styling breaks on mobile … table styling */
|
||||
}
|
||||
table td.selection, table th.selection, table td.fileaction { width:2em; text-align:center; }
|
||||
table td.filename a.name {
|
||||
@@ -237,7 +242,7 @@ table td.filename form { font-size:.85em; margin-left:3em; margin-right:3em; }
|
||||
|
||||
#fileList tr td.filename a.name label {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
width: 80%;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,9 +18,6 @@
|
||||
margin: -5px -3px;
|
||||
cursor: pointer;
|
||||
z-index: 10;
|
||||
background-image: url('%webroot%/core/img/actions/upload.svg');
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
opacity: .65;
|
||||
}
|
||||
.file_upload_target { display:none; }
|
||||
@@ -119,11 +116,6 @@
|
||||
.oc-dialog .fileexists .conflict input[type='checkbox'] {
|
||||
float: left;
|
||||
}
|
||||
.oc-dialog .fileexists .toggle {
|
||||
background-image: url('%webroot%/core/img/actions/triangle-e.png');
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
.oc-dialog .fileexists #allfileslabel {
|
||||
float:right;
|
||||
}
|
||||
|
||||
@@ -37,12 +37,7 @@ if(!\OC\Files\Filesystem::file_exists($filename)) {
|
||||
$ftype=\OC\Files\Filesystem::getMimeType( $filename );
|
||||
|
||||
header('Content-Type:'.$ftype);
|
||||
if ( preg_match( "/MSIE/", $_SERVER["HTTP_USER_AGENT"] ) ) {
|
||||
header( 'Content-Disposition: attachment; filename="' . rawurlencode( basename($filename) ) . '"' );
|
||||
} else {
|
||||
header( 'Content-Disposition: attachment; filename*=UTF-8\'\'' . rawurlencode( basename($filename) )
|
||||
. '; filename="' . rawurlencode( basename($filename) ) . '"' );
|
||||
}
|
||||
OCP\Response::setContentDispositionHeader(basename($filename), 'attachment');
|
||||
OCP\Response::disableCaching();
|
||||
header('Content-Length: '.\OC\Files\Filesystem::filesize($filename));
|
||||
|
||||
|
||||
@@ -222,6 +222,14 @@ $(document).ready(function() {
|
||||
|
||||
//examine file
|
||||
var file = data.files[0];
|
||||
try {
|
||||
// FIXME: not so elegant... need to refactor that method to return a value
|
||||
Files.isFileNameValid(file.name);
|
||||
}
|
||||
catch (errorMessage) {
|
||||
data.textStatus = 'invalidcharacters';
|
||||
data.errorThrown = errorMessage;
|
||||
}
|
||||
|
||||
if (file.type === '' && file.size === 4096) {
|
||||
data.textStatus = 'dirorzero';
|
||||
@@ -605,7 +613,7 @@ $(document).ready(function() {
|
||||
if (result.status === 'success') {
|
||||
var date=new Date();
|
||||
FileList.addDir(name, 0, date, hidden);
|
||||
var tr=$('tr[data-file="'+name+'"]');
|
||||
var tr = FileList.findFileEl(name);
|
||||
tr.attr('data-id', result.data.id);
|
||||
} else {
|
||||
OC.dialogs.alert(result.data.message, t('core', 'Could not create folder'));
|
||||
@@ -647,7 +655,7 @@ $(document).ready(function() {
|
||||
$('#uploadprogressbar').fadeOut();
|
||||
var date = new Date();
|
||||
FileList.addFile(localName, size, date, false, hidden);
|
||||
var tr = $('tr[data-file="'+localName+'"]');
|
||||
var tr = FileList.findFileEl(localName);
|
||||
tr.data('mime', mime).data('id', id);
|
||||
tr.attr('data-id', id);
|
||||
var path = $('#dir').val()+'/'+localName;
|
||||
|
||||
@@ -71,7 +71,7 @@ var FileActions = {
|
||||
FileActions.currentFile = parent;
|
||||
var actions = FileActions.get(FileActions.getCurrentMimeType(), FileActions.getCurrentType(), FileActions.getCurrentPermissions());
|
||||
var file = FileActions.getCurrentFile();
|
||||
if ($('tr[data-file="'+file+'"]').data('renaming')) {
|
||||
if (FileList.findFileEl(file).data('renaming')) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -103,9 +103,9 @@ var FileActions = {
|
||||
}
|
||||
var html = '<a href="#" class="action" data-action="' + name + '">';
|
||||
if (img) {
|
||||
html += '<img class ="svg" src="' + img + '" /> ';
|
||||
html += '<img class ="svg" src="' + img + '" />';
|
||||
}
|
||||
html += t('files', name) + '</a>';
|
||||
html += '<span> ' + t('files', name) + '</span></a>';
|
||||
|
||||
var element = $(html);
|
||||
element.data('action', name);
|
||||
|
||||
+37
-21
@@ -6,6 +6,13 @@ var FileList={
|
||||
$(this).attr('data-file',decodeURIComponent($(this).attr('data-file')));
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Returns the tr element for a given file name
|
||||
*/
|
||||
findFileEl: function(fileName){
|
||||
// use filterAttr to avoid escaping issues
|
||||
return $('#fileList tr').filterAttr('data-file', fileName);
|
||||
},
|
||||
update:function(fileListHtml) {
|
||||
var $fileList = $('#fileList');
|
||||
$fileList.empty().html(fileListHtml);
|
||||
@@ -20,6 +27,8 @@ var FileList={
|
||||
Files.setupDragAndDrop();
|
||||
}
|
||||
FileList.updateFileSummary();
|
||||
procesSelection();
|
||||
|
||||
$fileList.trigger(jQuery.Event("updated"));
|
||||
},
|
||||
createRow:function(type, name, iconurl, linktarget, size, lastModified, permissions) {
|
||||
@@ -292,8 +301,12 @@ var FileList={
|
||||
$('#filestable').toggleClass('hidden', show);
|
||||
},
|
||||
remove:function(name){
|
||||
$('tr').filterAttr('data-file',name).find('td.filename').draggable('destroy');
|
||||
$('tr').filterAttr('data-file',name).remove();
|
||||
var fileEl = FileList.findFileEl(name);
|
||||
if (fileEl.data('permissions') & OC.PERMISSION_DELETE) {
|
||||
// file is only draggable when delete permissions are set
|
||||
fileEl.find('td.filename').draggable('destroy');
|
||||
}
|
||||
fileEl.remove();
|
||||
FileList.updateFileSummary();
|
||||
if ( ! $('tr[data-file]').exists() ) {
|
||||
$('#emptycontent').removeClass('hidden');
|
||||
@@ -334,7 +347,7 @@ var FileList={
|
||||
FileList.updateFileSummary();
|
||||
},
|
||||
loadingDone:function(name, id) {
|
||||
var mime, tr = $('tr[data-file="'+name+'"]');
|
||||
var mime, tr = FileList.findFileEl(name);
|
||||
tr.data('loading', false);
|
||||
mime = tr.data('mime');
|
||||
tr.attr('data-mime', mime);
|
||||
@@ -347,12 +360,12 @@ var FileList={
|
||||
}, null, null, tr.attr('data-etag'));
|
||||
tr.find('td.filename').draggable(dragOptions);
|
||||
},
|
||||
isLoading:function(name) {
|
||||
return $('tr[data-file="'+name+'"]').data('loading');
|
||||
isLoading:function(file) {
|
||||
return FileList.findFileEl(file).data('loading');
|
||||
},
|
||||
rename:function(oldname) {
|
||||
var tr, td, input, form;
|
||||
tr = $('tr[data-file="'+oldname+'"]');
|
||||
tr = FileList.findFileEl(oldname);
|
||||
tr.data('renaming',true);
|
||||
td = tr.children('td.filename');
|
||||
input = $('<input type="text" class="filename"/>').val(oldname);
|
||||
@@ -500,14 +513,16 @@ var FileList={
|
||||
form.trigger('submit');
|
||||
});
|
||||
},
|
||||
inList:function(filename) {
|
||||
return $('#fileList tr[data-file="'+filename+'"]').length;
|
||||
inList:function(file) {
|
||||
return FileList.findFileEl(file).length;
|
||||
},
|
||||
replace:function(oldName, newName, isNewFile) {
|
||||
// Finish any existing actions
|
||||
$('tr[data-file="'+oldName+'"]').hide();
|
||||
$('tr[data-file="'+newName+'"]').hide();
|
||||
var tr = $('tr[data-file="'+oldName+'"]').clone();
|
||||
var oldFileEl = FileList.findFileEl(oldName);
|
||||
var newFileEl = FileList.findFileEl(newName);
|
||||
oldFileEl.hide();
|
||||
newFileEl.hide();
|
||||
var tr = oldFileEl.clone();
|
||||
tr.attr('data-replace', 'true');
|
||||
tr.attr('data-file', newName);
|
||||
var td = tr.children('td.filename');
|
||||
@@ -559,7 +574,7 @@ var FileList={
|
||||
files=[files];
|
||||
}
|
||||
for (var i=0; i<files.length; i++) {
|
||||
var deleteAction = $('tr[data-file="'+files[i]+'"]').children("td.date").children(".action.delete");
|
||||
var deleteAction = FileList.findFileEl(files[i]).children("td.date").children(".action.delete");
|
||||
deleteAction.removeClass('delete-icon').addClass('progress-icon');
|
||||
}
|
||||
// Finish any existing actions
|
||||
@@ -573,7 +588,7 @@ var FileList={
|
||||
function(result) {
|
||||
if (result.status === 'success') {
|
||||
$.each(files,function(index,file) {
|
||||
var files = $('tr[data-file="'+file+'"]');
|
||||
var files = FileList.findFileEl(file);
|
||||
files.remove();
|
||||
files.find('input[type="checkbox"]').removeAttr('checked');
|
||||
files.removeClass('selected');
|
||||
@@ -595,7 +610,7 @@ var FileList={
|
||||
OC.Notification.hide();
|
||||
}, 10000);
|
||||
$.each(files,function(index,file) {
|
||||
var deleteAction = $('tr[data-file="' + file + '"] .action.delete');
|
||||
var deleteAction = FileList.findFileEl(file).find('.action.delete');
|
||||
deleteAction.removeClass('progress-icon').addClass('delete-icon');
|
||||
});
|
||||
}
|
||||
@@ -737,7 +752,7 @@ var FileList={
|
||||
},
|
||||
scrollTo:function(file) {
|
||||
//scroll to and highlight preselected file
|
||||
var $scrolltorow = $('tr[data-file="'+file+'"]');
|
||||
var $scrolltorow = FileList.findFileEl(file);
|
||||
if ($scrolltorow.exists()) {
|
||||
$scrolltorow.addClass('searchresult');
|
||||
$(window).scrollTop($scrolltorow.position().top);
|
||||
@@ -880,8 +895,8 @@ $(document).ready(function() {
|
||||
data.context.find('td.filesize').text(humanFileSize(size));
|
||||
|
||||
} else {
|
||||
// only append new file if dragged onto current dir's crumb (last)
|
||||
if (data.context && data.context.hasClass('crumb') && !data.context.hasClass('last')) {
|
||||
// only append new file if uploaded into the current folder
|
||||
if (file.directory !== FileList.getCurrentDirectory()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -949,7 +964,7 @@ $(document).ready(function() {
|
||||
$('#notification').on('click', '.undo', function() {
|
||||
if (FileList.deleteFiles) {
|
||||
$.each(FileList.deleteFiles,function(index,file) {
|
||||
$('tr[data-file="'+file+'"]').show();
|
||||
FileList.findFileEl(file).show();
|
||||
});
|
||||
FileList.deleteCanceled=true;
|
||||
FileList.deleteFiles=null;
|
||||
@@ -959,10 +974,10 @@ $(document).ready(function() {
|
||||
FileList.deleteCanceled = false;
|
||||
FileList.deleteFiles = [FileList.replaceOldName];
|
||||
} else {
|
||||
$('tr[data-file="'+FileList.replaceOldName+'"]').show();
|
||||
FileList.findFileEl(FileList.replaceOldName).show();
|
||||
}
|
||||
$('tr[data-replace="true"').remove();
|
||||
$('tr[data-file="'+FileList.replaceNewName+'"]').show();
|
||||
FileList.findFileEl(FileList.replaceNewName).show();
|
||||
FileList.replaceCanceled = true;
|
||||
FileList.replaceOldName = null;
|
||||
FileList.replaceNewName = null;
|
||||
@@ -977,7 +992,8 @@ $(document).ready(function() {
|
||||
});
|
||||
});
|
||||
$('#notification:first-child').on('click', '.suggest', function() {
|
||||
$('tr[data-file="'+$('#notification > span').attr('data-oldName')+'"]').show();
|
||||
var file = $('#notification > span').attr('data-oldName');
|
||||
FileList.findFileEl(file).show();
|
||||
OC.Notification.hide();
|
||||
});
|
||||
$('#notification:first-child').on('click', '.cancel', function() {
|
||||
|
||||
+11
-8
@@ -282,7 +282,7 @@ $(document).ready(function() {
|
||||
procesSelection();
|
||||
} else {
|
||||
var filename=$(this).parent().parent().attr('data-file');
|
||||
var tr=$('tr[data-file="'+filename+'"]');
|
||||
var tr = FileList.findFileEl(filename);
|
||||
var renaming=tr.data('renaming');
|
||||
if (!renaming && !FileList.isLoading(filename)) {
|
||||
FileActions.currentFile = $(this).parent();
|
||||
@@ -541,10 +541,12 @@ var folderDropOptions={
|
||||
if (result) {
|
||||
if (result.status === 'success') {
|
||||
//recalculate folder size
|
||||
var oldSize = $('#fileList tr[data-file="'+target+'"]').data('size');
|
||||
var newSize = oldSize + $('#fileList tr[data-file="'+file+'"]').data('size');
|
||||
$('#fileList tr[data-file="'+target+'"]').data('size', newSize);
|
||||
$('#fileList tr[data-file="'+target+'"]').find('td.filesize').text(humanFileSize(newSize));
|
||||
var oldFile = FileList.findFileEl(target);
|
||||
var newFile = FileList.findFileEl(file);
|
||||
var oldSize = oldFile.data('size');
|
||||
var newSize = oldSize + newFile.data('size');
|
||||
oldFile.data('size', newSize);
|
||||
oldFile.find('td.filesize').text(humanFileSize(newSize));
|
||||
|
||||
FileList.remove(file);
|
||||
procesSelection();
|
||||
@@ -610,11 +612,12 @@ function procesSelection() {
|
||||
return el.type==='dir';
|
||||
});
|
||||
if (selectedFiles.length === 0 && selectedFolders.length === 0) {
|
||||
$('#headerName>span.name').text(t('files','Name'));
|
||||
$('#headerName span.name').text(t('files','Name'));
|
||||
$('#headerSize').text(t('files','Size'));
|
||||
$('#modified').text(t('files','Modified'));
|
||||
$('table').removeClass('multiselect');
|
||||
$('.selectedActions').hide();
|
||||
$('#select_all').removeAttr('checked');
|
||||
}
|
||||
else {
|
||||
$('.selectedActions').show();
|
||||
@@ -717,7 +720,7 @@ Files.lazyLoadPreview = function(path, mime, ready, width, height, etag) {
|
||||
console.warn('Files.lazyLoadPreview(): missing etag argument');
|
||||
}
|
||||
|
||||
if ( $('#publicUploadButtonMock').length ) {
|
||||
if ( $('#isPublic').length ) {
|
||||
urlSpec.t = $('#dirToken').val();
|
||||
previewURL = OC.Router.generate('core_ajax_public_preview', urlSpec);
|
||||
} else {
|
||||
@@ -738,7 +741,7 @@ Files.lazyLoadPreview = function(path, mime, ready, width, height, etag) {
|
||||
}
|
||||
|
||||
function getUniqueName(name) {
|
||||
if ($('tr[data-file="'+name+'"]').exists()) {
|
||||
if (FileList.findFileEl(name).exists()) {
|
||||
var parts=name.split('.');
|
||||
var extension = "";
|
||||
if (parts.length > 1) {
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
<?php
|
||||
$TRANSLATIONS = array(
|
||||
"Files" => "Файлы",
|
||||
"Share" => "Сделать общим",
|
||||
"Rename" => "Переименовать",
|
||||
"_%n folder_::_%n folders_" => array("","",""),
|
||||
"_%n file_::_%n files_" => array("","",""),
|
||||
"_Uploading %n file_::_Uploading %n files_" => array("","",""),
|
||||
"Error" => "Ошибка",
|
||||
"Size" => "Размер",
|
||||
"Upload" => "Загрузка",
|
||||
"Save" => "Сохранить",
|
||||
"Cancel upload" => "Отмена загрузки",
|
||||
"Download" => "Загрузка",
|
||||
"Delete" => "Удалить"
|
||||
);
|
||||
$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);";
|
||||
@@ -1,6 +1,7 @@
|
||||
<div id="controls">
|
||||
<?php print_unescaped($_['breadcrumb']); ?>
|
||||
<div class="actions creatable <?php if (!$_['isCreatable']):?>hidden<?php endif; ?>">
|
||||
<?php if(!isset($_['dirToken'])):?>
|
||||
<div id="new" class="button">
|
||||
<a><?php p($l->t('New'));?></a>
|
||||
<ul>
|
||||
@@ -12,21 +13,26 @@
|
||||
data-type='web'><p><?php p($l->t('From link'));?></p></li>
|
||||
</ul>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
<div id="upload" class="button"
|
||||
title="<?php p($l->t('Upload') . ' max. '.$_['uploadMaxHumanFilesize']) ?>">
|
||||
<?php if($_['uploadMaxFilesize'] >= 0):?>
|
||||
<input type="hidden" name="MAX_FILE_SIZE" id="max_upload"
|
||||
value="<?php p($_['uploadMaxFilesize']) ?>">
|
||||
<?php endif;?>
|
||||
<?php if(isset($_['dirToken'])):?>
|
||||
<input type="hidden" id="publicUploadRequestToken" name="requesttoken" value="<?php p($_['requesttoken']) ?>" />
|
||||
<input type="hidden" id="dirToken" name="dirToken" value="<?php p($_['dirToken']) ?>" />
|
||||
<?php endif;?>
|
||||
<input type="hidden" class="max_human_file_size"
|
||||
value="(max <?php p($_['uploadMaxHumanFilesize']); ?>)">
|
||||
<input type="hidden" name="dir" value="<?php p($_['dir']) ?>" id="dir">
|
||||
<input type="file" id="file_upload_start" name='files[]'
|
||||
data-url="<?php print_unescaped(OCP\Util::linkTo('files', 'ajax/upload.php')); ?>" />
|
||||
<a href="#" class="svg"></a>
|
||||
<a href="#" class="svg icon icon-upload"></a>
|
||||
</div>
|
||||
<?php if ($_['trash']): ?>
|
||||
<input id="trash" type="button" value="<?php p($l->t('Deleted files'));?>" class="button" <?php $_['trashEmpty'] ? p('disabled') : '' ?>></input>
|
||||
<input id="trash" type="button" value="<?php p($l->t('Deleted files'));?>" class="button" <?php $_['trashEmpty'] ? p('disabled') : '' ?> />
|
||||
<?php endif; ?>
|
||||
<div id="uploadprogresswrapper">
|
||||
<div id="uploadprogressbar"></div>
|
||||
@@ -44,7 +50,7 @@
|
||||
|
||||
<div id="emptycontent" <?php if (!$_['emptyContent']):?>class="hidden"<?php endif; ?>><?php p($l->t('Nothing in here. Upload something!'))?></div>
|
||||
|
||||
<input type="hidden" id="disableSharing" data-status="<?php p($_['disableSharing']); ?>"></input>
|
||||
<input type="hidden" id="disableSharing" data-status="<?php p($_['disableSharing']); ?>" />
|
||||
|
||||
<table id="filestable" data-allow-public-upload="<?php p($_['publicUploadEnabled'])?>" data-preview-x="36" data-preview-y="36">
|
||||
<thead>
|
||||
@@ -69,20 +75,11 @@
|
||||
<th <?php if (!$_['fileHeader']):?>class="hidden"<?php endif; ?> id="headerDate">
|
||||
<span id="modified"><?php p($l->t( 'Modified' )); ?></span>
|
||||
<?php if ($_['permissions'] & OCP\PERMISSION_DELETE): ?>
|
||||
<!-- NOTE: Temporary fix to allow unsharing of files in root of Shared folder -->
|
||||
<?php if ($_['dir'] == '/Shared'): ?>
|
||||
<span class="selectedActions"><a href="" class="delete-selected">
|
||||
<?php p($l->t('Unshare'))?>
|
||||
<img class="svg" alt="<?php p($l->t('Unshare'))?>"
|
||||
src="<?php print_unescaped(OCP\image_path("core", "actions/delete.svg")); ?>" />
|
||||
</a></span>
|
||||
<?php else: ?>
|
||||
<span class="selectedActions"><a href="" class="delete-selected">
|
||||
<?php p($l->t('Delete'))?>
|
||||
<img class="svg" alt="<?php p($l->t('Delete'))?>"
|
||||
src="<?php print_unescaped(OCP\image_path("core", "actions/delete.svg")); ?>" />
|
||||
</a></span>
|
||||
<?php endif; ?>
|
||||
<span class="selectedActions"><a href="" class="delete-selected">
|
||||
<?php p($l->t('Delete'))?>
|
||||
<img class="svg" alt="<?php p($l->t('Delete'))?>"
|
||||
src="<?php print_unescaped(OCP\image_path("core", "actions/delete.svg")); ?>" />
|
||||
</a></span>
|
||||
<?php endif; ?>
|
||||
</th>
|
||||
</tr>
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
<?php if(count($_["breadcrumb"])):?>
|
||||
<div class="crumb" data-dir=''>
|
||||
<a href="<?php print_unescaped($_['baseURL']); ?>">
|
||||
<img src="<?php print_unescaped(OCP\image_path('core', 'places/home.svg'));?>" class="svg" />
|
||||
</a>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
<div class="crumb <?php if(!count($_["breadcrumb"])) p('last');?>" data-dir=''>
|
||||
<a href="<?php print_unescaped($_['baseURL']); ?>">
|
||||
<img src="<?php print_unescaped(OCP\image_path('core', 'places/home.svg'));?>" class="svg" />
|
||||
</a>
|
||||
</div>
|
||||
<?php for($i=0; $i<count($_["breadcrumb"]); $i++):
|
||||
$crumb = $_["breadcrumb"][$i];
|
||||
$dir = \OCP\Util::encodePath($crumb["dir"]); ?>
|
||||
|
||||
@@ -18,7 +18,7 @@ $totalsize = 0; ?>
|
||||
data-size="<?php p($file['size']);?>"
|
||||
data-etag="<?php p($file['etag']);?>"
|
||||
data-permissions="<?php p($file['permissions']); ?>">
|
||||
<?php if($file['isPreviewAvailable']): ?>
|
||||
<?php if(isset($file['isPreviewAvailable']) and $file['isPreviewAvailable']): ?>
|
||||
<td class="filename svg preview-icon"
|
||||
<?php else: ?>
|
||||
<td class="filename svg"
|
||||
|
||||
@@ -6,6 +6,7 @@ if (OC::$CLI) {
|
||||
if (count($argv) === 2) {
|
||||
$file = $argv[1];
|
||||
list(, $user) = explode('/', $file);
|
||||
OCP\JSON::checkUserExists($owner);
|
||||
OC_Util::setupFS($user);
|
||||
$view = new \OC\Files\View('');
|
||||
/**
|
||||
|
||||
@@ -13,16 +13,14 @@ use OCA\Encryption\Util;
|
||||
$loginname = isset($_POST['user']) ? $_POST['user'] : '';
|
||||
$password = isset($_POST['password']) ? $_POST['password'] : '';
|
||||
|
||||
$migrationCompleted = true;
|
||||
$migrationStatus = Util::MIGRATION_COMPLETED;
|
||||
|
||||
if ($loginname !== '' && $password !== '') {
|
||||
$username = \OCP\User::checkPassword($loginname, $password);
|
||||
if ($username) {
|
||||
$util = new Util(new \OC_FilesystemView('/'), $username);
|
||||
if ($util->getMigrationStatus() !== Util::MIGRATION_COMPLETED) {
|
||||
$migrationCompleted = false;
|
||||
}
|
||||
$migrationStatus = $util->getMigrationStatus();
|
||||
}
|
||||
}
|
||||
|
||||
\OCP\JSON::success(array('data' => array('migrationCompleted' => $migrationCompleted)));
|
||||
\OCP\JSON::success(array('data' => array('migrationStatus' => $migrationStatus)));
|
||||
|
||||
@@ -10,6 +10,7 @@ OC::$CLASSPATH['OCA\Encryption\Session'] = 'files_encryption/lib/session.php';
|
||||
OC::$CLASSPATH['OCA\Encryption\Capabilities'] = 'files_encryption/lib/capabilities.php';
|
||||
OC::$CLASSPATH['OCA\Encryption\Helper'] = 'files_encryption/lib/helper.php';
|
||||
|
||||
\OCP\Util::addscript('files_encryption', 'encryption');
|
||||
\OCP\Util::addscript('files_encryption', 'detect-migration');
|
||||
|
||||
if (!OC_Config::getValue('maintenance', false)) {
|
||||
|
||||
@@ -18,22 +18,19 @@
|
||||
<type>text</type>
|
||||
<notnull>true</notnull>
|
||||
<length>64</length>
|
||||
<comments>What client-side / server-side configuration is used</comments>
|
||||
</field>
|
||||
<field>
|
||||
<name>recovery_enabled</name>
|
||||
<type>integer</type>
|
||||
<notnull>true</notnull>
|
||||
<default>0</default>
|
||||
<comments>Whether encryption key recovery is enabled</comments>
|
||||
</field>
|
||||
<field>
|
||||
<name>migration_status</name>
|
||||
<type>integer</type>
|
||||
<notnull>true</notnull>
|
||||
<default>0</default>
|
||||
<comments>Whether encryption migration has been performed</comments>
|
||||
</field>
|
||||
</declaration>
|
||||
</table>
|
||||
</database>
|
||||
</database>
|
||||
|
||||
@@ -2,11 +2,15 @@
|
||||
<info>
|
||||
<id>files_encryption</id>
|
||||
<name>Encryption</name>
|
||||
<description>The new ownCloud 5 files encryption system. After the app was enabled you need to re-login to initialize your encryption keys.</description>
|
||||
<description>The ownCloud files encryption system provides server side-encryption. After the app was enabled you need to re-login to initialize your encryption keys.</description>
|
||||
<licence>AGPL</licence>
|
||||
<author>Sam Tuke, Bjoern Schiessle, Florin Peter</author>
|
||||
<require>4</require>
|
||||
<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>
|
||||
</documentation>
|
||||
<rememberlogin>false</rememberlogin>
|
||||
<types>
|
||||
<filesystem/>
|
||||
|
||||
@@ -30,6 +30,11 @@ use OC\Files\Filesystem;
|
||||
*/
|
||||
class Hooks {
|
||||
|
||||
// file for which we want to rename the keys after the rename operation was successful
|
||||
private static $renamedFiles = array();
|
||||
// file for which we want to delete the keys after the delete operation was successful
|
||||
private static $deleteFiles = array();
|
||||
|
||||
/**
|
||||
* @brief Startup encryption backend upon user login
|
||||
* @note This method should never be called for users using client side encryption
|
||||
@@ -75,8 +80,14 @@ class Hooks {
|
||||
|
||||
// Check if first-run file migration has already been performed
|
||||
$ready = false;
|
||||
if ($util->getMigrationStatus() === Util::MIGRATION_OPEN) {
|
||||
$migrationStatus = $util->getMigrationStatus();
|
||||
if ($migrationStatus === Util::MIGRATION_OPEN) {
|
||||
$ready = $util->beginMigration();
|
||||
} elseif ($migrationStatus === Util::MIGRATION_IN_PROGRESS) {
|
||||
// refuse login as long as the initial encryption is running
|
||||
sleep(5);
|
||||
\OCP\User::logout();
|
||||
return false;
|
||||
}
|
||||
|
||||
// If migration not yet done
|
||||
@@ -97,21 +108,27 @@ class Hooks {
|
||||
|
||||
}
|
||||
|
||||
// Encrypt existing user files:
|
||||
if (
|
||||
$util->encryptAll('/' . $params['uid'] . '/' . 'files', $session->getLegacyKey(), $params['password'])
|
||||
) {
|
||||
// Encrypt existing user files
|
||||
try {
|
||||
$result = $util->encryptAll('/' . $params['uid'] . '/' . 'files', $session->getLegacyKey(), $params['password']);
|
||||
} catch (\Exception $ex) {
|
||||
\OCP\Util::writeLog('Encryption library', 'Initial encryption failed! Error: ' . $ex->getMessage(), \OCP\Util::FATAL);
|
||||
$util->resetMigrationStatus();
|
||||
\OCP\User::logout();
|
||||
$result = false;
|
||||
}
|
||||
|
||||
if ($result) {
|
||||
|
||||
\OC_Log::write(
|
||||
'Encryption library', 'Encryption of existing files belonging to "' . $params['uid'] . '" completed'
|
||||
, \OC_Log::INFO
|
||||
);
|
||||
|
||||
// Register successful migration in DB
|
||||
$util->finishMigration();
|
||||
|
||||
}
|
||||
|
||||
// Register successful migration in DB
|
||||
$util->finishMigration();
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -179,9 +196,9 @@ class Hooks {
|
||||
// the necessary keys)
|
||||
if (Crypt::mode() === 'server') {
|
||||
|
||||
if ($params['uid'] === \OCP\User::getUser()) {
|
||||
$view = new \OC_FilesystemView('/');
|
||||
|
||||
$view = new \OC_FilesystemView('/');
|
||||
if ($params['uid'] === \OCP\User::getUser()) {
|
||||
|
||||
$session = new \OCA\Encryption\Session($view);
|
||||
|
||||
@@ -202,36 +219,41 @@ class Hooks {
|
||||
} else { // admin changed the password for a different user, create new keys and reencrypt file keys
|
||||
|
||||
$user = $params['uid'];
|
||||
$recoveryPassword = $params['recoveryPassword'];
|
||||
$newUserPassword = $params['password'];
|
||||
$util = new Util($view, $user);
|
||||
$recoveryPassword = isset($params['recoveryPassword']) ? $params['recoveryPassword'] : null;
|
||||
|
||||
$view = new \OC_FilesystemView('/');
|
||||
if (($util->recoveryEnabledForUser() && $recoveryPassword)
|
||||
|| !$util->userKeysExists()) {
|
||||
|
||||
// make sure that the users home is mounted
|
||||
\OC\Files\Filesystem::initMountPoints($user);
|
||||
$recoveryPassword = $params['recoveryPassword'];
|
||||
$newUserPassword = $params['password'];
|
||||
|
||||
$keypair = Crypt::createKeypair();
|
||||
// make sure that the users home is mounted
|
||||
\OC\Files\Filesystem::initMountPoints($user);
|
||||
|
||||
// Disable encryption proxy to prevent recursive calls
|
||||
$proxyStatus = \OC_FileProxy::$enabled;
|
||||
\OC_FileProxy::$enabled = false;
|
||||
$keypair = Crypt::createKeypair();
|
||||
|
||||
// Save public key
|
||||
$view->file_put_contents('/public-keys/' . $user . '.public.key', $keypair['publicKey']);
|
||||
// Disable encryption proxy to prevent recursive calls
|
||||
$proxyStatus = \OC_FileProxy::$enabled;
|
||||
\OC_FileProxy::$enabled = false;
|
||||
|
||||
// Encrypt private key empty passphrase
|
||||
$encryptedPrivateKey = Crypt::symmetricEncryptFileContent($keypair['privateKey'], $newUserPassword);
|
||||
// Save public key
|
||||
$view->file_put_contents('/public-keys/' . $user . '.public.key', $keypair['publicKey']);
|
||||
|
||||
// Save private key
|
||||
$view->file_put_contents(
|
||||
'/' . $user . '/files_encryption/' . $user . '.private.key', $encryptedPrivateKey);
|
||||
// Encrypt private key empty passphrase
|
||||
$encryptedPrivateKey = Crypt::symmetricEncryptFileContent($keypair['privateKey'], $newUserPassword);
|
||||
|
||||
if ($recoveryPassword) { // if recovery key is set we can re-encrypt the key files
|
||||
$util = new Util($view, $user);
|
||||
$util->recoverUsersFiles($recoveryPassword);
|
||||
// Save private key
|
||||
$view->file_put_contents(
|
||||
'/' . $user . '/files_encryption/' . $user . '.private.key', $encryptedPrivateKey);
|
||||
|
||||
if ($recoveryPassword) { // if recovery key is set we can re-encrypt the key files
|
||||
$util = new Util($view, $user);
|
||||
$util->recoverUsersFiles($recoveryPassword);
|
||||
}
|
||||
|
||||
\OC_FileProxy::$enabled = $proxyStatus;
|
||||
}
|
||||
|
||||
\OC_FileProxy::$enabled = $proxyStatus;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -474,6 +496,27 @@ class Hooks {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief mark file as renamed so that we know the original source after the file was renamed
|
||||
* @param array $params with the old path and the new path
|
||||
*/
|
||||
public static function preRename($params) {
|
||||
$user = \OCP\User::getUser();
|
||||
$view = new \OC_FilesystemView('/');
|
||||
$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']);
|
||||
if ($mp1 === $mp2) {
|
||||
self::$renamedFiles[$params['oldpath']] = array(
|
||||
'uid' => $ownerOld,
|
||||
'path' => $pathOld);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief after a file is renamed, rename its keyfile and share-keys also fix the file size and fix also the sharing
|
||||
* @param array with oldpath and newpath
|
||||
@@ -496,19 +539,32 @@ class Hooks {
|
||||
$userId = \OCP\User::getUser();
|
||||
$util = new Util($view, $userId);
|
||||
|
||||
// Format paths to be relative to user files dir
|
||||
if ($util->isSystemWideMountPoint($params['oldpath'])) {
|
||||
$baseDir = 'files_encryption/';
|
||||
$oldKeyfilePath = $baseDir . 'keyfiles/' . $params['oldpath'];
|
||||
if (isset(self::$renamedFiles[$params['oldpath']]['uid']) &&
|
||||
isset(self::$renamedFiles[$params['oldpath']]['path'])) {
|
||||
$ownerOld = self::$renamedFiles[$params['oldpath']]['uid'];
|
||||
$pathOld = self::$renamedFiles[$params['oldpath']]['path'];
|
||||
} else {
|
||||
$baseDir = $userId . '/' . 'files_encryption/';
|
||||
$oldKeyfilePath = $baseDir . 'keyfiles/' . $params['oldpath'];
|
||||
\OCP\Util::writeLog('Encryption library', "can't get path and owner from the file before it was renamed", \OCP\Util::ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($util->isSystemWideMountPoint($params['newpath'])) {
|
||||
$newKeyfilePath = $baseDir . 'keyfiles/' . $params['newpath'];
|
||||
list($ownerNew, $pathNew) = $util->getUidAndFilename($params['newpath']);
|
||||
|
||||
// Format paths to be relative to user files dir
|
||||
if ($util->isSystemWideMountPoint($pathOld)) {
|
||||
$oldKeyfilePath = 'files_encryption/keyfiles/' . $pathOld;
|
||||
$oldShareKeyPath = 'files_encryption/share-keys/' . $pathOld;
|
||||
} else {
|
||||
$newKeyfilePath = $baseDir . 'keyfiles/' . $params['newpath'];
|
||||
$oldKeyfilePath = $ownerOld . '/' . 'files_encryption/keyfiles/' . $pathOld;
|
||||
$oldShareKeyPath = $ownerOld . '/' . 'files_encryption/share-keys/' . $pathOld;
|
||||
}
|
||||
|
||||
if ($util->isSystemWideMountPoint($pathNew)) {
|
||||
$newKeyfilePath = 'files_encryption/keyfiles/' . $pathNew;
|
||||
$newShareKeyPath = 'files_encryption/share-keys/' . $pathNew;
|
||||
} else {
|
||||
$newKeyfilePath = $ownerNew . '/files_encryption/keyfiles/' . $pathNew;
|
||||
$newShareKeyPath = $ownerNew . '/files_encryption/share-keys/' . $pathNew;
|
||||
}
|
||||
|
||||
// add key ext if this is not an folder
|
||||
@@ -517,11 +573,11 @@ class Hooks {
|
||||
$newKeyfilePath .= '.key';
|
||||
|
||||
// handle share-keys
|
||||
$localKeyPath = $view->getLocalFile($baseDir . 'share-keys/' . $params['oldpath']);
|
||||
$localKeyPath = $view->getLocalFile($oldShareKeyPath);
|
||||
$escapedPath = Helper::escapeGlobPattern($localKeyPath);
|
||||
$matches = glob($escapedPath . '*.shareKey');
|
||||
foreach ($matches as $src) {
|
||||
$dst = \OC\Files\Filesystem::normalizePath(str_replace($params['oldpath'], $params['newpath'], $src));
|
||||
$dst = \OC\Files\Filesystem::normalizePath(str_replace($pathOld, $pathNew, $src));
|
||||
|
||||
// create destination folder if not exists
|
||||
if (!file_exists(dirname($dst))) {
|
||||
@@ -533,15 +589,13 @@ class Hooks {
|
||||
|
||||
} else {
|
||||
// handle share-keys folders
|
||||
$oldShareKeyfilePath = $baseDir . 'share-keys/' . $params['oldpath'];
|
||||
$newShareKeyfilePath = $baseDir . 'share-keys/' . $params['newpath'];
|
||||
|
||||
// create destination folder if not exists
|
||||
if (!$view->file_exists(dirname($newShareKeyfilePath))) {
|
||||
$view->mkdir(dirname($newShareKeyfilePath), 0750, true);
|
||||
if (!$view->file_exists(dirname($newShareKeyPath))) {
|
||||
$view->mkdir(dirname($newShareKeyPath), 0750, true);
|
||||
}
|
||||
|
||||
$view->rename($oldShareKeyfilePath, $newShareKeyfilePath);
|
||||
$view->rename($oldShareKeyPath, $newShareKeyPath);
|
||||
}
|
||||
|
||||
// Rename keyfile so it isn't orphaned
|
||||
@@ -556,18 +610,17 @@ class Hooks {
|
||||
}
|
||||
|
||||
// build the path to the file
|
||||
$newPath = '/' . $userId . '/files' . $params['newpath'];
|
||||
$newPathRelative = $params['newpath'];
|
||||
$newPath = '/' . $ownerNew . '/files' . $pathNew;
|
||||
|
||||
if ($util->fixFileSize($newPath)) {
|
||||
// get sharing app state
|
||||
$sharingEnabled = \OCP\Share::isEnabled();
|
||||
|
||||
// get users
|
||||
$usersSharing = $util->getSharingUsersArray($sharingEnabled, $newPathRelative);
|
||||
$usersSharing = $util->getSharingUsersArray($sharingEnabled, $pathNew);
|
||||
|
||||
// update sharing-keys
|
||||
$util->setSharedFileKeyfiles($session, $usersSharing, $newPathRelative);
|
||||
$util->setSharedFileKeyfiles($session, $usersSharing, $pathNew);
|
||||
}
|
||||
|
||||
\OC_FileProxy::$enabled = $proxyStatus;
|
||||
@@ -600,4 +653,66 @@ class Hooks {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief if the file was really deleted we remove the encryption keys
|
||||
* @param array $params
|
||||
* @return boolean
|
||||
*/
|
||||
public static function postDelete($params) {
|
||||
|
||||
if (!isset(self::$deleteFiles[$params[\OC\Files\Filesystem::signal_param_path]])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$deletedFile = self::$deleteFiles[$params[\OC\Files\Filesystem::signal_param_path]];
|
||||
$path = $deletedFile['path'];
|
||||
$user = $deletedFile['uid'];
|
||||
|
||||
// we don't need to remember the file any longer
|
||||
unset(self::$deleteFiles[$params[\OC\Files\Filesystem::signal_param_path]]);
|
||||
|
||||
$view = new \OC\Files\View('/');
|
||||
|
||||
// return if the file still exists and wasn't deleted correctly
|
||||
if ($view->file_exists('/' . $user . '/files/' . $path)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Disable encryption proxy to prevent recursive calls
|
||||
$proxyStatus = \OC_FileProxy::$enabled;
|
||||
\OC_FileProxy::$enabled = false;
|
||||
|
||||
// Delete keyfile & shareKey so it isn't orphaned
|
||||
if (!Keymanager::deleteFileKey($view, $path, $user)) {
|
||||
\OCP\Util::writeLog('Encryption library',
|
||||
'Keyfile or shareKey could not be deleted for file "' . $user.'/files/'.$path . '"', \OCP\Util::ERROR);
|
||||
}
|
||||
|
||||
Keymanager::delAllShareKeys($view, $user, $path);
|
||||
|
||||
\OC_FileProxy::$enabled = $proxyStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief remember the file which should be deleted and it's owner
|
||||
* @param array $params
|
||||
* @return boolean
|
||||
*/
|
||||
public static function preDelete($params) {
|
||||
$path = $params[\OC\Files\Filesystem::signal_param_path];
|
||||
|
||||
// skip this method if the trash bin is enabled or if we delete a file
|
||||
// outside of /data/user/files
|
||||
if (\OCP\App::isEnabled('files_trashbin')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$util = new Util(new \OC_FilesystemView('/'), \OCP\USER::getUser());
|
||||
list($owner, $ownerPath) = $util->getUidAndFilename($path);
|
||||
|
||||
self::$deleteFiles[$params[\OC\Files\Filesystem::signal_param_path]] = array(
|
||||
'uid' => $owner,
|
||||
'path' => $ownerPath);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,10 +17,14 @@ $(document).ready(function(){
|
||||
data: {user: user, password: password},
|
||||
async: false,
|
||||
success: function(response) {
|
||||
if (response.data.migrationCompleted === false) {
|
||||
if (response.data.migrationStatus === OC.Encryption.MIGRATION_OPEN) {
|
||||
var message = t('files_encryption', 'Initial encryption started... This can take some time. Please wait.');
|
||||
$('#messageText').text(message);
|
||||
$('#message').removeClass('hidden').addClass('update');
|
||||
} else if (response.data.migrationStatus === OC.Encryption.MIGRATION_IN_PROGRESS) {
|
||||
var message = t('files_encryption', 'Initial encryption running... Please try again later.');
|
||||
$('#messageText').text(message);
|
||||
$('#message').removeClass('hidden').addClass('update');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Copyright (c) 2014
|
||||
* Bjoern Schiessle <schiessle@owncloud.com>
|
||||
* This file is licensed under the Affero General Public License version 3 or later.
|
||||
* See the COPYING-README file.
|
||||
*/
|
||||
|
||||
OC.Encryption={
|
||||
MIGRATION_OPEN:0,
|
||||
MIGRATION_COMPLETED:1,
|
||||
MIGRATION_IN_PROGRESS:-1,
|
||||
};
|
||||
@@ -59,7 +59,10 @@ class Helper {
|
||||
*/
|
||||
public static function registerFilesystemHooks() {
|
||||
|
||||
\OCP\Util::connectHook('OC_Filesystem', 'rename', 'OCA\Encryption\Hooks', 'preRename');
|
||||
\OCP\Util::connectHook('OC_Filesystem', 'post_rename', 'OCA\Encryption\Hooks', 'postRename');
|
||||
\OCP\Util::connectHook('OC_Filesystem', 'post_delete', 'OCA\Encryption\Hooks', 'postDelete');
|
||||
\OCP\Util::connectHook('OC_Filesystem', 'delete', 'OCA\Encryption\Hooks', 'preDelete');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -274,7 +277,7 @@ class Helper {
|
||||
$split = explode('/', $trimmed);
|
||||
|
||||
// it is not a file relative to data/user/files
|
||||
if (count($split) < 2 || $split[1] !== 'files') {
|
||||
if (count($split) < 2 || ($split[1] !== 'files' && $split[1] !== 'cache')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -370,7 +373,14 @@ class Helper {
|
||||
* @return bool true if requirements are met
|
||||
*/
|
||||
public static function checkRequirements() {
|
||||
return extension_loaded('openssl');
|
||||
$result = true;
|
||||
|
||||
//openssl extension needs to be loaded
|
||||
$result &= extension_loaded("openssl");
|
||||
// we need php >= 5.3.3
|
||||
$result &= version_compare(phpversion(), '5.3.3', '>=');
|
||||
|
||||
return (bool) $result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -214,15 +214,24 @@ class Keymanager {
|
||||
*
|
||||
* @param \OC_FilesystemView $view
|
||||
* @param string $path path of the file the key belongs to
|
||||
* @param string $userId the user to whom the file belongs
|
||||
* @return bool Outcome of unlink operation
|
||||
* @note $path must be relative to data/user/files. e.g. mydoc.txt NOT
|
||||
* /data/admin/files/mydoc.txt
|
||||
*/
|
||||
public static function deleteFileKey(\OC_FilesystemView $view, $path) {
|
||||
public static function deleteFileKey($view, $path, $userId=null) {
|
||||
|
||||
$trimmed = ltrim($path, '/');
|
||||
|
||||
$userId = Helper::getUser($path);
|
||||
if ($trimmed === '') {
|
||||
\OCP\Util::writeLog('Encryption library',
|
||||
'Can\'t delete file-key empty path given!', \OCP\Util::ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($userId === null) {
|
||||
$userId = Helper::getUser($path);
|
||||
}
|
||||
$util = new Util($view, $userId);
|
||||
|
||||
if($util->isSystemWideMountPoint($path)) {
|
||||
@@ -402,7 +411,15 @@ class Keymanager {
|
||||
* @param string $userId owner of the file
|
||||
* @param string $filePath path to the file, relative to the owners file dir
|
||||
*/
|
||||
public static function delAllShareKeys(\OC_FilesystemView $view, $userId, $filePath) {
|
||||
public static function delAllShareKeys($view, $userId, $filePath) {
|
||||
|
||||
$filePath = ltrim($filePath, '/');
|
||||
|
||||
if ($filePath === '') {
|
||||
\OCP\Util::writeLog('Encryption library',
|
||||
'Can\'t delete share-keys empty path given!', \OCP\Util::ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
$util = new util($view, $userId);
|
||||
|
||||
@@ -413,17 +430,15 @@ class Keymanager {
|
||||
}
|
||||
|
||||
|
||||
if ($view->is_dir($userId . '/files/' . $filePath)) {
|
||||
if ($view->is_dir($baseDir . $filePath)) {
|
||||
$view->unlink($baseDir . $filePath);
|
||||
} else {
|
||||
$localKeyPath = $view->getLocalFile($baseDir . $filePath);
|
||||
$escapedPath = Helper::escapeGlobPattern($localKeyPath);
|
||||
$matches = glob($escapedPath . '*.shareKey');
|
||||
foreach ($matches as $ma) {
|
||||
$result = unlink($ma);
|
||||
if (!$result) {
|
||||
\OCP\Util::writeLog('Encryption library',
|
||||
'Keyfile or shareKey could not be deleted for file "' . $filePath . '"', \OCP\Util::ERROR);
|
||||
$parentDir = dirname($baseDir . $filePath);
|
||||
$filename = pathinfo($filePath, PATHINFO_BASENAME);
|
||||
foreach($view->getDirectoryContent($parentDir) as $content) {
|
||||
$path = $content['path'];
|
||||
if (self::getFilenameFromShareKey($content['name']) === $filename) {
|
||||
$view->unlink('/' . $userId . '/' . $path);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -523,4 +538,20 @@ class Keymanager {
|
||||
return $targetPath;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief extract filename from share key name
|
||||
* @param string $shareKey (filename.userid.sharekey)
|
||||
* @return mixed filename or false
|
||||
*/
|
||||
protected static function getFilenameFromShareKey($shareKey) {
|
||||
$parts = explode('.', $shareKey);
|
||||
|
||||
$filename = false;
|
||||
if(count($parts) > 2) {
|
||||
$filename = implode('.', array_slice($parts, 0, count($parts)-2));
|
||||
}
|
||||
|
||||
return $filename;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,8 @@ namespace OCA\Encryption;
|
||||
class Proxy extends \OC_FileProxy {
|
||||
|
||||
private static $blackList = null; //mimetypes blacklisted from encryption
|
||||
private static $unencryptedSizes = array(); // remember unencrypted size
|
||||
private static $fopenMode = array(); // remember the fopen mode
|
||||
|
||||
/**
|
||||
* Check if a file requires encryption
|
||||
@@ -114,6 +116,13 @@ class Proxy extends \OC_FileProxy {
|
||||
// get encrypted content
|
||||
$data = $view->file_get_contents($tmpPath);
|
||||
|
||||
// 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_Filesystem::normalizePath($path)] = $tmpFileInfo['size'];
|
||||
}
|
||||
|
||||
// remove our temp file
|
||||
$view->deleteAll('/' . \OCP\User::getUser() . '/cache/' . $cacheFolder);
|
||||
|
||||
@@ -127,6 +136,24 @@ class Proxy extends \OC_FileProxy {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief update file cache with the new unencrypted size after file was written
|
||||
* @param string $path
|
||||
* @param mixed $result
|
||||
* @return mixed
|
||||
*/
|
||||
public function postFile_put_contents($path, $result) {
|
||||
$normalizedPath = \OC_Filesystem::normalizePath($path);
|
||||
if ( isset(self::$unencryptedSizes[$normalizedPath]) ) {
|
||||
$view = new \OC_FilesystemView('/');
|
||||
$view->putFileInfo($normalizedPath,
|
||||
array('encrypted' => true, 'unencrypted_size' => self::$unencryptedSizes[$normalizedPath]));
|
||||
unset(self::$unencryptedSizes[$normalizedPath]);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path Path of file from which has been read
|
||||
* @param string $data Data that has been read from file
|
||||
@@ -177,47 +204,6 @@ class Proxy extends \OC_FileProxy {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief When a file is deleted, remove its keyfile also
|
||||
*/
|
||||
public function preUnlink($path) {
|
||||
|
||||
// let the trashbin handle this
|
||||
if (\OCP\App::isEnabled('files_trashbin')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Disable encryption proxy to prevent recursive calls
|
||||
$proxyStatus = \OC_FileProxy::$enabled;
|
||||
\OC_FileProxy::$enabled = false;
|
||||
|
||||
$view = new \OC_FilesystemView('/');
|
||||
|
||||
$userId = \OCP\USER::getUser();
|
||||
|
||||
$util = new Util($view, $userId);
|
||||
|
||||
// get relative path
|
||||
$relativePath = \OCA\Encryption\Helper::stripUserFilesPath($path);
|
||||
|
||||
list($owner, $ownerPath) = $util->getUidAndFilename($relativePath);
|
||||
|
||||
// Delete keyfile & shareKey so it isn't orphaned
|
||||
if (!Keymanager::deleteFileKey($view, $ownerPath)) {
|
||||
\OCP\Util::writeLog('Encryption library',
|
||||
'Keyfile or shareKey could not be deleted for file "' . $ownerPath . '"', \OCP\Util::ERROR);
|
||||
}
|
||||
|
||||
Keymanager::delAllShareKeys($view, $owner, $ownerPath);
|
||||
|
||||
\OC_FileProxy::$enabled = $proxyStatus;
|
||||
|
||||
// If we don't return true then file delete will fail; better
|
||||
// to leave orphaned keyfiles than to disallow file deletion
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $path
|
||||
* @return bool
|
||||
@@ -228,6 +214,16 @@ class Proxy extends \OC_FileProxy {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief remember initial fopen mode because sometimes it gets changed during the request
|
||||
* @param string $path path
|
||||
* @param string $mode type of access
|
||||
*/
|
||||
public function preFopen($path, $mode) {
|
||||
self::$fopenMode[$path] = $mode;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $path
|
||||
* @param $result
|
||||
@@ -246,8 +242,8 @@ class Proxy extends \OC_FileProxy {
|
||||
// split the path parts
|
||||
$pathParts = explode('/', $path);
|
||||
|
||||
// FIXME: handling for /userId/cache used by webdav for chunking. The cache chunks are NOT encrypted
|
||||
if (isset($pathParts[2]) && $pathParts[2] === 'cache') {
|
||||
// don't try to encrypt/decrypt cache chunks or files in the trash bin
|
||||
if (isset($pathParts[2]) && ($pathParts[2] === 'cache' || $pathParts[2] === 'files_trashbin')) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
@@ -255,7 +251,15 @@ class Proxy extends \OC_FileProxy {
|
||||
$proxyStatus = \OC_FileProxy::$enabled;
|
||||
\OC_FileProxy::$enabled = false;
|
||||
|
||||
$meta = stream_get_meta_data($result);
|
||||
// if we remember the mode from the pre proxy we re-use it
|
||||
// oterwise we fall back to stream_get_meta_data()
|
||||
if (isset(self::$fopenMode[$path])) {
|
||||
$mode = self::$fopenMode[$path];
|
||||
unset(self::$fopenMode[$path]);
|
||||
} else {
|
||||
$meta = stream_get_meta_data($result);
|
||||
$mode = $meta['mode'];
|
||||
}
|
||||
|
||||
$view = new \OC_FilesystemView('');
|
||||
|
||||
@@ -273,14 +277,14 @@ class Proxy extends \OC_FileProxy {
|
||||
|
||||
// Open the file using the crypto stream wrapper
|
||||
// protocol and let it do the decryption work instead
|
||||
$result = fopen('crypt://' . $path, $meta['mode']);
|
||||
$result = fopen('crypt://' . $path, $mode);
|
||||
|
||||
} elseif (
|
||||
self::shouldEncrypt($path)
|
||||
and $meta ['mode'] !== 'r'
|
||||
and $meta['mode'] !== 'rb'
|
||||
self::shouldEncrypt($path)
|
||||
and $mode !== 'r'
|
||||
and $mode !== 'rb'
|
||||
) {
|
||||
$result = fopen('crypt://' . $path, $meta['mode']);
|
||||
$result = fopen('crypt://' . $path, $mode);
|
||||
}
|
||||
|
||||
// Re-enable the proxy
|
||||
|
||||
@@ -132,6 +132,14 @@ class Session {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief remove encryption keys and init status from session
|
||||
*/
|
||||
public function closeSession() {
|
||||
\OC::$session->remove('encryptionInitialized');
|
||||
\OC::$session->remove('privateKey');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Gets status if we already tried to initialize the encryption app
|
||||
|
||||
@@ -155,6 +155,9 @@ class Stream {
|
||||
} else {
|
||||
|
||||
$this->meta = stream_get_meta_data($this->handle);
|
||||
// sometimes fopen changes the mode, e.g. for a url "r" convert to "r+"
|
||||
// but we need to remember the original access type
|
||||
$this->meta['mode'] = $mode;
|
||||
|
||||
}
|
||||
|
||||
|
||||
+145
-134
@@ -2,9 +2,10 @@
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Sam Tuke, Frank Karlitschek
|
||||
* @author Sam Tuke, Frank Karlitschek, Bjoern Schiessle
|
||||
* @copyright 2012 Sam Tuke <samtuke@owncloud.com>,
|
||||
* Frank Karlitschek <frank@owncloud.org>
|
||||
* Frank Karlitschek <frank@owncloud.org>,
|
||||
* Bjoern Schiessle <schiessle@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
|
||||
@@ -56,7 +57,7 @@ class Util {
|
||||
* @param $userId
|
||||
* @param bool $client
|
||||
*/
|
||||
public function __construct(\OC_FilesystemView $view, $userId, $client = false) {
|
||||
public function __construct($view, $userId, $client = false) {
|
||||
|
||||
$this->view = $view;
|
||||
$this->client = $client;
|
||||
@@ -101,15 +102,24 @@ class Util {
|
||||
or !$this->view->file_exists($this->publicKeyPath)
|
||||
or !$this->view->file_exists($this->privateKeyPath)
|
||||
) {
|
||||
|
||||
return false;
|
||||
|
||||
} else {
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief check if the users private & public key exists
|
||||
* @return boolean
|
||||
*/
|
||||
public function userKeysExists() {
|
||||
if (
|
||||
$this->view->file_exists($this->privateKeyPath) &&
|
||||
$this->view->file_exists($this->publicKeyPath)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -232,11 +242,9 @@ class Util {
|
||||
if (\OCP\DB::isError($result)) {
|
||||
\OCP\Util::writeLog('Encryption library', \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
|
||||
} else {
|
||||
if ($result->numRows() > 0) {
|
||||
$row = $result->fetchRow();
|
||||
if (isset($row['recovery_enabled'])) {
|
||||
$recoveryEnabled[] = $row['recovery_enabled'];
|
||||
}
|
||||
$row = $result->fetchRow();
|
||||
if ($row && isset($row['recovery_enabled'])) {
|
||||
$recoveryEnabled[] = $row['recovery_enabled'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,7 +288,7 @@ class Util {
|
||||
$sql = 'UPDATE `*PREFIX*encryption` SET `recovery_enabled` = ? WHERE `uid` = ?';
|
||||
|
||||
$args = array(
|
||||
$enabled,
|
||||
$enabled ? '1' : '0',
|
||||
$this->userId
|
||||
);
|
||||
|
||||
@@ -308,7 +316,8 @@ class Util {
|
||||
$found = array(
|
||||
'plain' => array(),
|
||||
'encrypted' => array(),
|
||||
'legacy' => array()
|
||||
'legacy' => array(),
|
||||
'broken' => array(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -319,10 +328,7 @@ class Util {
|
||||
if(is_resource($handle)) {
|
||||
while (false !== ($file = readdir($handle))) {
|
||||
|
||||
if (
|
||||
$file !== "."
|
||||
&& $file !== ".."
|
||||
) {
|
||||
if ($file !== "." && $file !== "..") {
|
||||
|
||||
$filePath = $directory . '/' . $this->view->getRelativePath('/' . $file);
|
||||
$relPath = \OCA\Encryption\Helper::stripUserFilesPath($filePath);
|
||||
@@ -349,15 +355,23 @@ class Util {
|
||||
// NOTE: This is inefficient;
|
||||
// scanning every file like this
|
||||
// will eat server resources :(
|
||||
if (
|
||||
Keymanager::getFileKey($this->view, $this, $relPath)
|
||||
&& $isEncryptedPath
|
||||
) {
|
||||
if ($isEncryptedPath) {
|
||||
|
||||
$found['encrypted'][] = array(
|
||||
'name' => $file,
|
||||
'path' => $filePath
|
||||
);
|
||||
$fileKey = Keymanager::getFileKey($this->view, $this, $relPath);
|
||||
$shareKey = Keymanager::getShareKey($this->view, $this->userId, $this, $relPath);
|
||||
// if file is encrypted but now file key is available, throw exception
|
||||
if ($fileKey === false || $shareKey === false) {
|
||||
\OCP\Util::writeLog('encryption library', 'No keys available to decrypt the file: ' . $filePath, \OCP\Util::ERROR);
|
||||
$found['broken'][] = array(
|
||||
'name' => $file,
|
||||
'path' => $filePath,
|
||||
);
|
||||
} else {
|
||||
$found['encrypted'][] = array(
|
||||
'name' => $file,
|
||||
'path' => $filePath,
|
||||
);
|
||||
}
|
||||
|
||||
// If the file uses old
|
||||
// encryption system
|
||||
@@ -455,20 +469,22 @@ class Util {
|
||||
*/
|
||||
public function isEncryptedPath($path) {
|
||||
|
||||
$relPath = Helper::getPathToRealFile($path);
|
||||
// Disable encryption proxy so data retrieved is in its
|
||||
// original form
|
||||
$proxyStatus = \OC_FileProxy::$enabled;
|
||||
\OC_FileProxy::$enabled = false;
|
||||
|
||||
if ($relPath === false) {
|
||||
$relPath = Helper::stripUserFilesPath($path);
|
||||
// we only need 24 byte from the last chunk
|
||||
$data = '';
|
||||
$handle = $this->view->fopen($path, 'r');
|
||||
if (is_resource($handle) && !fseek($handle, -24, SEEK_END)) {
|
||||
$data = fgets($handle);
|
||||
}
|
||||
|
||||
$fileKey = Keymanager::getFileKey($this->view, $this, $relPath);
|
||||
|
||||
if ($fileKey === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
// re-enable proxy
|
||||
\OC_FileProxy::$enabled = $proxyStatus;
|
||||
|
||||
return Crypt::isCatfileContent($data);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -761,7 +777,7 @@ class Util {
|
||||
\OC\Files\Filesystem::putFileInfo($relPath, array(
|
||||
'encrypted' => false,
|
||||
'size' => $size,
|
||||
'unencrypted_size' => $size,
|
||||
'unencrypted_size' => 0,
|
||||
'etag' => $fileInfo['etag']
|
||||
));
|
||||
|
||||
@@ -777,6 +793,12 @@ class Util {
|
||||
$successful = false;
|
||||
}
|
||||
|
||||
// if there are broken encrypted files than the complete decryption
|
||||
// was not successful
|
||||
if (!empty($found['broken'])) {
|
||||
$successful = false;
|
||||
}
|
||||
|
||||
if ($successful) {
|
||||
$this->view->deleteAll($this->keyfilesPath);
|
||||
$this->view->deleteAll($this->shareKeysPath);
|
||||
@@ -831,32 +853,35 @@ class Util {
|
||||
// Open enc file handle for binary writing, with same filename as original plain file
|
||||
$encHandle = fopen('crypt://' . $rawPath . '.part', 'wb');
|
||||
|
||||
// Move plain file to a temporary location
|
||||
$size = stream_copy_to_stream($plainHandle, $encHandle);
|
||||
if (is_resource($encHandle)) {
|
||||
// Move plain file to a temporary location
|
||||
$size = stream_copy_to_stream($plainHandle, $encHandle);
|
||||
|
||||
fclose($encHandle);
|
||||
fclose($plainHandle);
|
||||
fclose($encHandle);
|
||||
fclose($plainHandle);
|
||||
|
||||
$fakeRoot = $this->view->getRoot();
|
||||
$this->view->chroot('/' . $this->userId . '/files');
|
||||
$fakeRoot = $this->view->getRoot();
|
||||
$this->view->chroot('/' . $this->userId . '/files');
|
||||
|
||||
$this->view->rename($relPath . '.part', $relPath);
|
||||
$this->view->rename($relPath . '.part', $relPath);
|
||||
|
||||
// set timestamp
|
||||
$this->view->touch($relPath, $timestamp);
|
||||
// set timestamp
|
||||
$this->view->touch($relPath, $timestamp);
|
||||
|
||||
$this->view->chroot($fakeRoot);
|
||||
$encSize = $this->view->filesize($relPath);
|
||||
|
||||
// Add the file to the cache
|
||||
\OC\Files\Filesystem::putFileInfo($relPath, array(
|
||||
'encrypted' => true,
|
||||
'size' => $size,
|
||||
'unencrypted_size' => $size,
|
||||
'etag' => $fileInfo['etag']
|
||||
));
|
||||
$this->view->chroot($fakeRoot);
|
||||
|
||||
$encryptedFiles[] = $relPath;
|
||||
// Add the file to the cache
|
||||
\OC\Files\Filesystem::putFileInfo($relPath, array(
|
||||
'encrypted' => true,
|
||||
'size' => $encSize,
|
||||
'unencrypted_size' => $size,
|
||||
'etag' => $fileInfo['etag']
|
||||
));
|
||||
|
||||
$encryptedFiles[] = $relPath;
|
||||
}
|
||||
}
|
||||
|
||||
// Encrypt legacy encrypted files
|
||||
@@ -973,8 +998,8 @@ class Util {
|
||||
if (\OCP\DB::isError($result)) {
|
||||
\OCP\Util::writeLog('Encryption library', \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
|
||||
} else {
|
||||
if ($result->numRows() > 0) {
|
||||
$row = $result->fetchRow();
|
||||
$row = $result->fetchRow();
|
||||
if ($row) {
|
||||
$path = substr($row['path'], strlen('files'));
|
||||
}
|
||||
}
|
||||
@@ -1188,27 +1213,49 @@ class Util {
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief set migration status
|
||||
* @param int $status
|
||||
* @return boolean
|
||||
*/
|
||||
private function setMigrationStatus($status) {
|
||||
|
||||
$sql = 'UPDATE `*PREFIX*encryption` SET `migration_status` = ? WHERE `uid` = ?';
|
||||
$args = array($status, $this->userId);
|
||||
$query = \OCP\DB::prepare($sql);
|
||||
$manipulatedRows = $query->execute($args);
|
||||
|
||||
if ($manipulatedRows === 1) {
|
||||
$result = true;
|
||||
\OCP\Util::writeLog('Encryption library', "Migration status set to " . self::MIGRATION_OPEN, \OCP\Util::INFO);
|
||||
} else {
|
||||
$result = false;
|
||||
\OCP\Util::writeLog('Encryption library', "Could not set migration status to " . self::MIGRATION_OPEN, \OCP\Util::WARN);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief start migration mode to initially encrypt users data
|
||||
* @return boolean
|
||||
*/
|
||||
public function beginMigration() {
|
||||
|
||||
$return = false;
|
||||
$result = $this->setMigrationStatus(self::MIGRATION_IN_PROGRESS);
|
||||
|
||||
$sql = 'UPDATE `*PREFIX*encryption` SET `migration_status` = ? WHERE `uid` = ? and `migration_status` = ?';
|
||||
$args = array(self::MIGRATION_IN_PROGRESS, $this->userId, self::MIGRATION_OPEN);
|
||||
$query = \OCP\DB::prepare($sql);
|
||||
$manipulatedRows = $query->execute($args);
|
||||
|
||||
if ($manipulatedRows === 1) {
|
||||
$return = true;
|
||||
if ($result) {
|
||||
\OCP\Util::writeLog('Encryption library', "Start migration to encryption mode for " . $this->userId, \OCP\Util::INFO);
|
||||
} else {
|
||||
\OCP\Util::writeLog('Encryption library', "Could not activate migration mode for " . $this->userId . ". Probably another process already started the initial encryption", \OCP\Util::WARN);
|
||||
}
|
||||
|
||||
return $return;
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function resetMigrationStatus() {
|
||||
return $this->setMigrationStatus(self::MIGRATION_OPEN);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1216,22 +1263,15 @@ class Util {
|
||||
* @return boolean
|
||||
*/
|
||||
public function finishMigration() {
|
||||
$result = $this->setMigrationStatus(self::MIGRATION_COMPLETED);
|
||||
|
||||
$return = false;
|
||||
|
||||
$sql = 'UPDATE `*PREFIX*encryption` SET `migration_status` = ? WHERE `uid` = ? and `migration_status` = ?';
|
||||
$args = array(self::MIGRATION_COMPLETED, $this->userId, self::MIGRATION_IN_PROGRESS);
|
||||
$query = \OCP\DB::prepare($sql);
|
||||
$manipulatedRows = $query->execute($args);
|
||||
|
||||
if ($manipulatedRows === 1) {
|
||||
$return = true;
|
||||
if ($result) {
|
||||
\OCP\Util::writeLog('Encryption library', "Finish migration successfully for " . $this->userId, \OCP\Util::INFO);
|
||||
} else {
|
||||
\OCP\Util::writeLog('Encryption library', "Could not deactivate migration mode for " . $this->userId, \OCP\Util::WARN);
|
||||
}
|
||||
|
||||
return $return;
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1254,11 +1294,9 @@ class Util {
|
||||
if (\OCP\DB::isError($result)) {
|
||||
\OCP\Util::writeLog('Encryption library', \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
|
||||
} else {
|
||||
if ($result->numRows() > 0) {
|
||||
$row = $result->fetchRow();
|
||||
if (isset($row['migration_status'])) {
|
||||
$migrationStatus[] = $row['migration_status'];
|
||||
}
|
||||
$row = $result->fetchRow();
|
||||
if ($row && isset($row['migration_status'])) {
|
||||
$migrationStatus[] = $row['migration_status'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1366,59 +1404,32 @@ class Util {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief go recursively through a dir and collect all files and sub files.
|
||||
* @param string $dir relative to the users files folder
|
||||
* @return array with list of files relative to the users files folder
|
||||
*/
|
||||
public function getAllFiles($dir) {
|
||||
|
||||
$result = array();
|
||||
$dirList = array($dir);
|
||||
|
||||
$content = $this->view->getDirectoryContent(\OC\Files\Filesystem::normalizePath(
|
||||
$this->userFilesDir . '/' . $dir));
|
||||
|
||||
// handling for re shared folders
|
||||
$pathSplit = explode('/', $dir);
|
||||
|
||||
foreach ($content as $c) {
|
||||
|
||||
$sharedPart = $pathSplit[sizeof($pathSplit) - 1];
|
||||
$targetPathSplit = array_reverse(explode('/', $c['path']));
|
||||
|
||||
$path = '';
|
||||
|
||||
// rebuild path
|
||||
foreach ($targetPathSplit as $pathPart) {
|
||||
|
||||
if ($pathPart !== $sharedPart) {
|
||||
|
||||
$path = '/' . $pathPart . $path;
|
||||
while ($dirList) {
|
||||
$dir = array_pop($dirList);
|
||||
$content = $this->view->getDirectoryContent(\OC\Files\Filesystem::normalizePath(
|
||||
$this->userFilesDir . '/' . $dir));
|
||||
|
||||
foreach ($content as $c) {
|
||||
$usersPath = isset($c['usersPath']) ? $c['usersPath'] : $c['path'];
|
||||
if ($c['type'] === 'dir') {
|
||||
$dirList[] = substr($usersPath, strlen("files"));
|
||||
} else {
|
||||
|
||||
break;
|
||||
|
||||
$result[] = substr($usersPath, strlen("files"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$path = $dir . $path;
|
||||
|
||||
if ($c['type'] === 'dir') {
|
||||
|
||||
$result = array_merge($result, $this->getAllFiles($path));
|
||||
|
||||
} else {
|
||||
|
||||
$result[] = $path;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1438,9 +1449,7 @@ class Util {
|
||||
if (\OCP\DB::isError($result)) {
|
||||
\OCP\Util::writeLog('Encryption library', \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
|
||||
} else {
|
||||
if ($result->numRows() > 0) {
|
||||
$row = $result->fetchRow();
|
||||
}
|
||||
$row = $result->fetchRow();
|
||||
}
|
||||
|
||||
return $row;
|
||||
@@ -1464,9 +1473,7 @@ class Util {
|
||||
if (\OCP\DB::isError($result)) {
|
||||
\OCP\Util::writeLog('Encryption library', \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
|
||||
} else {
|
||||
if ($result->numRows() > 0) {
|
||||
$row = $result->fetchRow();
|
||||
}
|
||||
$row = $result->fetchRow();
|
||||
}
|
||||
|
||||
return $row;
|
||||
@@ -1485,18 +1492,16 @@ class Util {
|
||||
|
||||
$result = $query->execute(array($id));
|
||||
|
||||
$source = array();
|
||||
$source = null;
|
||||
if (\OCP\DB::isError($result)) {
|
||||
\OCP\Util::writeLog('Encryption library', \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
|
||||
} else {
|
||||
if ($result->numRows() > 0) {
|
||||
$source = $result->fetchRow();
|
||||
}
|
||||
$source = $result->fetchRow();
|
||||
}
|
||||
|
||||
$fileOwner = false;
|
||||
|
||||
if (isset($source['parent'])) {
|
||||
if ($source && isset($source['parent'])) {
|
||||
|
||||
$parent = $source['parent'];
|
||||
|
||||
@@ -1506,16 +1511,14 @@ class Util {
|
||||
|
||||
$result = $query->execute(array($parent));
|
||||
|
||||
$item = array();
|
||||
$item = null;
|
||||
if (\OCP\DB::isError($result)) {
|
||||
\OCP\Util::writeLog('Encryption library', \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
|
||||
} else {
|
||||
if ($result->numRows() > 0) {
|
||||
$item = $result->fetchRow();
|
||||
}
|
||||
$item = $result->fetchRow();
|
||||
}
|
||||
|
||||
if (isset($item['parent'])) {
|
||||
if ($item && isset($item['parent'])) {
|
||||
|
||||
$parent = $item['parent'];
|
||||
|
||||
@@ -1780,4 +1783,12 @@ class Util {
|
||||
return $session;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief remove encryption related keys from the session
|
||||
*/
|
||||
public function closeEncryptionSession() {
|
||||
$session = new \OCA\Encryption\Session($this->view);
|
||||
$session->closeSession();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<fieldset class="personalblock">
|
||||
<h2><?php p( $l->t( 'Encryption' ) ); ?></h2>
|
||||
|
||||
<?php if ( ! $_["privateKeySet"] && $_["initialized"] ): ?>
|
||||
<?php if ( $_["initialized"] === '1' ): ?>
|
||||
<p>
|
||||
<a name="changePKPasswd" />
|
||||
<label for="changePrivateKeyPasswd">
|
||||
|
||||
@@ -155,7 +155,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
*/
|
||||
function testSymmetricStreamEncryptShortFileContent() {
|
||||
|
||||
$filename = 'tmp-' . time() . '.test';
|
||||
$filename = 'tmp-' . uniqid() . '.test';
|
||||
|
||||
$util = new Encryption\Util(new \OC_FilesystemView(), $this->userId);
|
||||
|
||||
@@ -214,7 +214,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
function testSymmetricStreamEncryptLongFileContent() {
|
||||
|
||||
// Generate a a random filename
|
||||
$filename = 'tmp-' . time() . '.test';
|
||||
$filename = 'tmp-' . uniqid() . '.test';
|
||||
|
||||
$util = new Encryption\Util(new \OC_FilesystemView(), $this->userId);
|
||||
|
||||
@@ -297,7 +297,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
*/
|
||||
function testSymmetricStreamDecryptShortFileContent() {
|
||||
|
||||
$filename = 'tmp-' . time();
|
||||
$filename = 'tmp-' . uniqid();
|
||||
|
||||
// Save long data as encrypted file using stream wrapper
|
||||
$cryptedFile = file_put_contents('crypt:///'. $this->userId . '/files/' . $filename, $this->dataShort);
|
||||
@@ -327,7 +327,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
*/
|
||||
function testSymmetricStreamDecryptLongFileContent() {
|
||||
|
||||
$filename = 'tmp-' . time();
|
||||
$filename = 'tmp-' . uniqid();
|
||||
|
||||
// Save long data as encrypted file using stream wrapper
|
||||
$cryptedFile = file_put_contents('crypt:///' . $this->userId . '/files/' . $filename, $this->dataLong);
|
||||
@@ -418,7 +418,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
*/
|
||||
function testRenameFile() {
|
||||
|
||||
$filename = 'tmp-' . time();
|
||||
$filename = 'tmp-' . uniqid();
|
||||
|
||||
// Save long data as encrypted file using stream wrapper
|
||||
$cryptedFile = file_put_contents('crypt:///' . $this->userId . '/files/' . $filename, $this->dataLong);
|
||||
@@ -431,7 +431,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
$this->assertEquals($this->dataLong, $decrypt);
|
||||
|
||||
$newFilename = 'tmp-new-' . time();
|
||||
$newFilename = 'tmp-new-' . uniqid();
|
||||
$view = new \OC\Files\View('/' . $this->userId . '/files');
|
||||
$view->rename($filename, $newFilename);
|
||||
|
||||
@@ -449,7 +449,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
*/
|
||||
function testMoveFileIntoFolder() {
|
||||
|
||||
$filename = 'tmp-' . time();
|
||||
$filename = 'tmp-' . uniqid();
|
||||
|
||||
// Save long data as encrypted file using stream wrapper
|
||||
$cryptedFile = file_put_contents('crypt:///' . $this->userId . '/files/' . $filename, $this->dataLong);
|
||||
@@ -462,8 +462,8 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
$this->assertEquals($this->dataLong, $decrypt);
|
||||
|
||||
$newFolder = '/newfolder' . time();
|
||||
$newFilename = 'tmp-new-' . time();
|
||||
$newFolder = '/newfolder' . uniqid();
|
||||
$newFilename = 'tmp-new-' . uniqid();
|
||||
$view = new \OC\Files\View('/' . $this->userId . '/files');
|
||||
$view->mkdir($newFolder);
|
||||
$view->rename($filename, $newFolder . '/' . $newFilename);
|
||||
@@ -484,8 +484,8 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
$view = new \OC\Files\View('/' . $this->userId . '/files');
|
||||
|
||||
$filename = '/tmp-' . time();
|
||||
$folder = '/folder' . time();
|
||||
$filename = '/tmp-' . uniqid();
|
||||
$folder = '/folder' . uniqid();
|
||||
|
||||
$view->mkdir($folder);
|
||||
|
||||
@@ -500,7 +500,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
$this->assertEquals($this->dataLong, $decrypt);
|
||||
|
||||
$newFolder = '/newfolder/subfolder' . time();
|
||||
$newFolder = '/newfolder/subfolder' . uniqid();
|
||||
$view->mkdir('/newfolder');
|
||||
|
||||
$view->rename($folder, $newFolder);
|
||||
@@ -519,7 +519,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
* @medium
|
||||
*/
|
||||
function testChangePassphrase() {
|
||||
$filename = 'tmp-' . time();
|
||||
$filename = 'tmp-' . uniqid();
|
||||
|
||||
// Save long data as encrypted file using stream wrapper
|
||||
$cryptedFile = file_put_contents('crypt:///' . $this->userId . '/files/' . $filename, $this->dataLong);
|
||||
@@ -557,7 +557,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
*/
|
||||
function testViewFilePutAndGetContents() {
|
||||
|
||||
$filename = '/tmp-' . time();
|
||||
$filename = '/tmp-' . uniqid();
|
||||
$view = new \OC\Files\View('/' . $this->userId . '/files');
|
||||
|
||||
// Save short data as encrypted file using stream wrapper
|
||||
@@ -590,7 +590,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
* @large
|
||||
*/
|
||||
function testTouchExistingFile() {
|
||||
$filename = '/tmp-' . time();
|
||||
$filename = '/tmp-' . uniqid();
|
||||
$view = new \OC\Files\View('/' . $this->userId . '/files');
|
||||
|
||||
// Save short data as encrypted file using stream wrapper
|
||||
@@ -614,7 +614,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
* @medium
|
||||
*/
|
||||
function testTouchFile() {
|
||||
$filename = '/tmp-' . time();
|
||||
$filename = '/tmp-' . uniqid();
|
||||
$view = new \OC\Files\View('/' . $this->userId . '/files');
|
||||
|
||||
$view->touch($filename);
|
||||
@@ -638,7 +638,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
* @medium
|
||||
*/
|
||||
function testFopenFile() {
|
||||
$filename = '/tmp-' . time();
|
||||
$filename = '/tmp-' . uniqid();
|
||||
$view = new \OC\Files\View('/' . $this->userId . '/files');
|
||||
|
||||
// Save short data as encrypted file using stream wrapper
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
|
||||
require_once __DIR__ . '/../lib/helper.php';
|
||||
require_once __DIR__ . '/util.php';
|
||||
|
||||
use OCA\Encryption;
|
||||
|
||||
@@ -16,6 +17,18 @@ use OCA\Encryption;
|
||||
*/
|
||||
class Test_Encryption_Helper extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
const TEST_ENCRYPTION_HELPER_USER1 = "test-helper-user1";
|
||||
|
||||
public static function setUpBeforeClass() {
|
||||
// create test user
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Helper::TEST_ENCRYPTION_HELPER_USER1, true);
|
||||
}
|
||||
|
||||
public static function tearDownAfterClass() {
|
||||
// cleanup test user
|
||||
\OC_User::deleteUser(\Test_Encryption_Helper::TEST_ENCRYPTION_HELPER_USER1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @medium
|
||||
*/
|
||||
@@ -64,4 +77,28 @@ class Test_Encryption_Helper extends \PHPUnit_Framework_TestCase {
|
||||
$this->assertEquals($relativePath, Encryption\Helper::getPathToRealFile($cachePath));
|
||||
}
|
||||
|
||||
function testGetUser() {
|
||||
|
||||
$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_USER1 . "/thumbnails/foo";
|
||||
$path4 ="/" . "/" . 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();
|
||||
|
||||
// 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));
|
||||
$this->assertEquals(self::TEST_ENCRYPTION_HELPER_USER1, Encryption\Helper::getUser($path2));
|
||||
|
||||
$this->assertFalse(Encryption\Helper::getUser($path3));
|
||||
$this->assertFalse(Encryption\Helper::getUser($path4));
|
||||
|
||||
// Log-in again
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Helper::TEST_ENCRYPTION_HELPER_USER1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,326 @@
|
||||
<?php
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Bjoern Schiessle
|
||||
* @copyright 2014 Bjoern Schiessle <schiessle@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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/../../../lib/base.php';
|
||||
require_once __DIR__ . '/../lib/crypt.php';
|
||||
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;
|
||||
|
||||
/**
|
||||
* Class Test_Encryption_Hooks
|
||||
* @brief this class provide basic hook app tests
|
||||
*/
|
||||
class Test_Encryption_Hooks extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
const TEST_ENCRYPTION_HOOKS_USER1 = "test-encryption-hooks-user1";
|
||||
const TEST_ENCRYPTION_HOOKS_USER2 = "test-encryption-hooks-user2";
|
||||
|
||||
/**
|
||||
* @var \OC_FilesystemView
|
||||
*/
|
||||
public $user1View; // view on /data/user1/files
|
||||
public $user2View; // view on /data/user2/files
|
||||
public $rootView; // view on /data/user
|
||||
public $data;
|
||||
public $filename;
|
||||
public $folder;
|
||||
|
||||
public static function setUpBeforeClass() {
|
||||
// reset backend
|
||||
\OC_User::clearBackends();
|
||||
\OC_User::useBackend('database');
|
||||
|
||||
\OC_Hook::clear('OC_Filesystem');
|
||||
\OC_Hook::clear('OC_User');
|
||||
|
||||
// clear share hooks
|
||||
\OC_Hook::clear('OCP\\Share');
|
||||
\OC::registerShareHooks();
|
||||
\OCP\Util::connectHook('OC_Filesystem', 'setup', '\OC\Files\Storage\Shared', 'setup');
|
||||
|
||||
// Filesystem related hooks
|
||||
\OCA\Encryption\Helper::registerFilesystemHooks();
|
||||
|
||||
// Sharing related hooks
|
||||
\OCA\Encryption\Helper::registerShareHooks();
|
||||
|
||||
// clear and register proxies
|
||||
\OC_FileProxy::clearProxies();
|
||||
\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);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
// set user id
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1);
|
||||
\OC_User::setUserId(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1);
|
||||
|
||||
// init filesystem view
|
||||
$this->user1View = new \OC_FilesystemView('/'. \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1 . '/files');
|
||||
$this->user2View = new \OC_FilesystemView('/'. \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2 . '/files');
|
||||
$this->rootView = new \OC_FilesystemView('/');
|
||||
|
||||
// init short data
|
||||
$this->data = 'hats';
|
||||
$this->filename = 'enc_hooks_tests-' . uniqid() . '.txt';
|
||||
$this->folder = 'enc_hooks_tests_folder-' . uniqid();
|
||||
|
||||
}
|
||||
|
||||
public static function tearDownAfterClass() {
|
||||
// cleanup test user
|
||||
\OC_User::deleteUser(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1);
|
||||
\OC_User::deleteUser(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2);
|
||||
}
|
||||
|
||||
function testDeleteHooks() {
|
||||
|
||||
// remember files_trashbin state
|
||||
$stateFilesTrashbin = OC_App::isEnabled('files_trashbin');
|
||||
|
||||
// we want to tests with app files_trashbin disabled
|
||||
\OC_App::disable('files_trashbin');
|
||||
|
||||
// make sure that the trash bin is disabled
|
||||
$this->assertFalse(\OC_APP::isEnabled('files_trashbin'));
|
||||
|
||||
$this->user1View->file_put_contents($this->filename, $this->data);
|
||||
|
||||
// check if all keys are generated
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/'
|
||||
. $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey'));
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
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);
|
||||
\OC_User::setUserId(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2);
|
||||
|
||||
|
||||
$this->user2View->file_put_contents($this->filename, $this->data);
|
||||
|
||||
// check if all keys are generated
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/share-keys/'
|
||||
. $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2 . '.shareKey'));
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/keyfiles/' . $this->filename . '.key'));
|
||||
|
||||
|
||||
// create a dummy file that we can delete something outside of data/user/files
|
||||
// in this case no share or file keys should be deleted
|
||||
$this->rootView->file_put_contents(self::TEST_ENCRYPTION_HOOKS_USER2 . "/" . $this->filename, $this->data);
|
||||
|
||||
// delete dummy file outside of data/user/files
|
||||
$this->rootView->unlink(self::TEST_ENCRYPTION_HOOKS_USER2 . "/" . $this->filename);
|
||||
|
||||
// all keys should still exist
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/share-keys/'
|
||||
. $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2 . '.shareKey'));
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/keyfiles/' . $this->filename . '.key'));
|
||||
|
||||
|
||||
// delete the file in data/user/files
|
||||
// now the correspondig share and file keys from user2 should be deleted
|
||||
$this->user2View->unlink($this->filename);
|
||||
|
||||
// check if keys from user2 are really deleted
|
||||
$this->assertFalse($this->rootView->file_exists(
|
||||
self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/share-keys/'
|
||||
. $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2 . '.shareKey'));
|
||||
$this->assertFalse($this->rootView->file_exists(
|
||||
self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/keyfiles/' . $this->filename . '.key'));
|
||||
|
||||
// but user1 keys should still exist
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/'
|
||||
. $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey'));
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/keyfiles/' . $this->filename . '.key'));
|
||||
|
||||
if ($stateFilesTrashbin) {
|
||||
OC_App::enable('files_trashbin');
|
||||
}
|
||||
else {
|
||||
OC_App::disable('files_trashbin');
|
||||
}
|
||||
}
|
||||
|
||||
function testDeleteHooksForSharedFiles() {
|
||||
|
||||
\Test_Encryption_Util::logoutHelper();
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1);
|
||||
\OC_User::setUserId(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1);
|
||||
|
||||
// remember files_trashbin state
|
||||
$stateFilesTrashbin = OC_App::isEnabled('files_trashbin');
|
||||
|
||||
// we want to tests with app files_trashbin disabled
|
||||
\OC_App::disable('files_trashbin');
|
||||
|
||||
// make sure that the trash bin is disabled
|
||||
$this->assertFalse(\OC_APP::isEnabled('files_trashbin'));
|
||||
|
||||
$this->user1View->file_put_contents($this->filename, $this->data);
|
||||
|
||||
// check if all keys are generated
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/'
|
||||
. $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey'));
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/keyfiles/' . $this->filename . '.key'));
|
||||
|
||||
// get the file info from previous created file
|
||||
$fileInfo = $this->user1View->getFileInfo($this->filename);
|
||||
|
||||
// check if we have a valid file info
|
||||
$this->assertTrue(is_array($fileInfo));
|
||||
|
||||
// share the file with user2
|
||||
\OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, self::TEST_ENCRYPTION_HOOKS_USER2, OCP\PERMISSION_ALL);
|
||||
|
||||
// check if new share key exists
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
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);
|
||||
\OC_User::setUserId(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2);
|
||||
|
||||
// user2 has a local file with the same name
|
||||
$this->user2View->file_put_contents($this->filename, $this->data);
|
||||
|
||||
// check if all keys are generated
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/share-keys/'
|
||||
. $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2 . '.shareKey'));
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/keyfiles/' . $this->filename . '.key'));
|
||||
|
||||
// delete the Shared file from user1 in data/user2/files/Shared
|
||||
$this->user2View->unlink('/Shared/' . $this->filename);
|
||||
|
||||
// now keys from user1s home should be gone
|
||||
$this->assertFalse($this->rootView->file_exists(
|
||||
self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/'
|
||||
. $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey'));
|
||||
$this->assertFalse($this->rootView->file_exists(
|
||||
self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/'
|
||||
. $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2 . '.shareKey'));
|
||||
$this->assertFalse($this->rootView->file_exists(
|
||||
self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/keyfiles/' . $this->filename . '.key'));
|
||||
|
||||
// but user2 keys should still exist
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/share-keys/'
|
||||
. $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2 . '.shareKey'));
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/keyfiles/' . $this->filename . '.key'));
|
||||
|
||||
// cleanup
|
||||
|
||||
$this->user2View->unlink($this->filename);
|
||||
|
||||
\Test_Encryption_Util::logoutHelper();
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1);
|
||||
\OC_User::setUserId(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1);
|
||||
|
||||
// unshare the file
|
||||
\OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, self::TEST_ENCRYPTION_HOOKS_USER2);
|
||||
|
||||
$this->user1View->unlink($this->filename);
|
||||
|
||||
if ($stateFilesTrashbin) {
|
||||
OC_App::enable('files_trashbin');
|
||||
}
|
||||
else {
|
||||
OC_App::disable('files_trashbin');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 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));
|
||||
|
||||
// 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'));
|
||||
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
'/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/keyfiles/'
|
||||
. $this->filename . '.key'));
|
||||
|
||||
// make subfolder
|
||||
$this->rootView->mkdir('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $this->folder);
|
||||
|
||||
$this->assertTrue($this->rootView->is_dir('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $this->folder));
|
||||
|
||||
// move the file out of the shared folder
|
||||
$root = $this->rootView->getRoot();
|
||||
$this->rootView->chroot('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/');
|
||||
$this->rootView->rename($this->filename, '/' . $this->folder . '/' . $this->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->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'));
|
||||
$this->assertFalse($this->rootView->file_exists(
|
||||
'/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/keyfiles/'
|
||||
. $this->filename . '.key'));
|
||||
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
'/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/' . $this->folder . '/'
|
||||
. $this->filename . '.' . self::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey'));
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
'/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/keyfiles/' . $this->folder . '/'
|
||||
. $this->filename . '.key'));
|
||||
|
||||
// cleanup
|
||||
$this->rootView->unlink('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $this->folder);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -136,6 +136,17 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase {
|
||||
$this->assertArrayHasKey('key', $sslInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* @small
|
||||
*/
|
||||
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"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @medium
|
||||
*/
|
||||
@@ -143,7 +154,7 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
$key = $this->randomKey;
|
||||
|
||||
$file = 'unittest-' . time() . '.txt';
|
||||
$file = 'unittest-' . uniqid() . '.txt';
|
||||
|
||||
$util = new Encryption\Util($this->view, $this->userId);
|
||||
|
||||
@@ -196,7 +207,7 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase {
|
||||
function testRecursiveDelShareKeys() {
|
||||
|
||||
// generate filename
|
||||
$filename = '/tmp-' . time() . '.txt';
|
||||
$filename = '/tmp-' . uniqid() . '.txt';
|
||||
|
||||
// create folder structure
|
||||
$this->view->mkdir('/'.Test_Encryption_Keymanager::TEST_USER.'/files/folder1');
|
||||
@@ -234,3 +245,12 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase {
|
||||
\OC_FileProxy::$enabled = $proxyStatus;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dummy class to access protected methods of \OCA\Encryption\Keymanager for testing
|
||||
*/
|
||||
class TestProtectedKeymanagerMethods extends \OCA\Encryption\Keymanager {
|
||||
public static function testGetFilenameFromShareKey($sharekey) {
|
||||
return self::getFilenameFromShareKey($sharekey);
|
||||
}
|
||||
}
|
||||
@@ -44,8 +44,10 @@ class Test_Encryption_Proxy extends \PHPUnit_Framework_TestCase {
|
||||
/**
|
||||
* @var \OC_FilesystemView
|
||||
*/
|
||||
public $view;
|
||||
public $view; // view in /data/user/files
|
||||
public $rootView; // view on /data/user
|
||||
public $data;
|
||||
public $filename;
|
||||
|
||||
public static function setUpBeforeClass() {
|
||||
// reset backend
|
||||
@@ -74,9 +76,12 @@ class Test_Encryption_Proxy extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
// init filesystem view
|
||||
$this->view = new \OC_FilesystemView('/'. \Test_Encryption_Proxy::TEST_ENCRYPTION_PROXY_USER1 . '/files');
|
||||
$this->rootView = new \OC_FilesystemView('/'. \Test_Encryption_Proxy::TEST_ENCRYPTION_PROXY_USER1 );
|
||||
|
||||
// init short data
|
||||
$this->data = 'hats';
|
||||
$this->filename = 'enc_proxy_tests-' . uniqid() . '.txt';
|
||||
|
||||
}
|
||||
|
||||
public static function tearDownAfterClass() {
|
||||
@@ -90,21 +95,21 @@ class Test_Encryption_Proxy extends \PHPUnit_Framework_TestCase {
|
||||
*/
|
||||
function testPostFileSize() {
|
||||
|
||||
// generate filename
|
||||
$filename = 'tmp-' . time() . '.txt';
|
||||
|
||||
$this->view->file_put_contents($filename, $this->data);
|
||||
$this->view->file_put_contents($this->filename, $this->data);
|
||||
|
||||
\OC_FileProxy::$enabled = false;
|
||||
|
||||
$unencryptedSize = $this->view->filesize($filename);
|
||||
$unencryptedSize = $this->view->filesize($this->filename);
|
||||
|
||||
\OC_FileProxy::$enabled = true;
|
||||
|
||||
$encryptedSize = $this->view->filesize($filename);
|
||||
$encryptedSize = $this->view->filesize($this->filename);
|
||||
|
||||
$this->assertTrue($encryptedSize !== $unencryptedSize);
|
||||
|
||||
// cleanup
|
||||
$this->view->unlink($this->filename);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -127,6 +127,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
\OC_User::deleteUser(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER4);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @medium
|
||||
* @param bool $withTeardown
|
||||
@@ -194,8 +195,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
. $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey'));
|
||||
|
||||
// cleanup
|
||||
$this->view->unlink(
|
||||
'/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename);
|
||||
$this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/');
|
||||
$this->view->unlink($this->filename);
|
||||
$this->view->chroot('/');
|
||||
|
||||
// check if share key not exists
|
||||
$this->assertFalse($this->view->file_exists(
|
||||
@@ -265,8 +267,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
. $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey'));
|
||||
|
||||
// cleanup
|
||||
$this->view->unlink(
|
||||
'/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename);
|
||||
$this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/');
|
||||
$this->view->unlink($this->filename);
|
||||
$this->view->chroot('/');
|
||||
|
||||
// check if share key not exists
|
||||
$this->assertFalse($this->view->file_exists(
|
||||
@@ -352,7 +355,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
. $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey'));
|
||||
|
||||
// cleanup
|
||||
$this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files' . $this->folder1);
|
||||
$this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files');
|
||||
$this->view->unlink($this->folder1);
|
||||
$this->view->chroot('/');
|
||||
|
||||
// check if share key not exists
|
||||
$this->assertFalse($this->view->file_exists(
|
||||
@@ -482,9 +487,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
. $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey'));
|
||||
|
||||
// cleanup
|
||||
$this->view->unlink(
|
||||
'/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files' . $this->folder1 . $this->subfolder
|
||||
. $this->subsubfolder . '/' . $this->filename);
|
||||
$this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files');
|
||||
$this->view->unlink($this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename);
|
||||
$this->view->chroot('/');
|
||||
|
||||
// check if share key not exists
|
||||
$this->assertFalse($this->view->file_exists(
|
||||
@@ -494,6 +499,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);
|
||||
@@ -559,7 +565,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
. $this->filename . '.' . $publicShareKeyId . '.shareKey'));
|
||||
|
||||
// cleanup
|
||||
$this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename);
|
||||
$this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/');
|
||||
$this->view->unlink($this->filename);
|
||||
$this->view->chroot('/');
|
||||
|
||||
// check if share key not exists
|
||||
$this->assertFalse($this->view->file_exists(
|
||||
@@ -636,7 +644,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
. $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER4 . '.shareKey'));
|
||||
|
||||
// cleanup
|
||||
$this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename);
|
||||
$this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/');
|
||||
$this->view->unlink($this->filename);
|
||||
$this->view->chroot('/');
|
||||
|
||||
// check if share key not exists
|
||||
$this->assertFalse($this->view->file_exists(
|
||||
@@ -649,9 +659,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
* @large
|
||||
*/
|
||||
function testRecoveryFile() {
|
||||
$this->markTestIncomplete(
|
||||
'No idea what\'s wrong here, this works perfectly in real-world. removeRecoveryKeys(\'/\') L709 removes correctly the keys, but for some reasons afterwards also the top-level folder "share-keys" is gone...'
|
||||
);
|
||||
|
||||
// login as admin
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
|
||||
@@ -733,8 +741,10 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
. $this->filename . '.' . $recoveryKeyId . '.shareKey'));
|
||||
|
||||
// cleanup
|
||||
$this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename);
|
||||
$this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->folder1);
|
||||
$this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/');
|
||||
$this->view->unlink($this->filename);
|
||||
$this->view->unlink($this->folder1);
|
||||
$this->view->chroot('/');
|
||||
|
||||
// check if share key for recovery not exists
|
||||
$this->assertFalse($this->view->file_exists(
|
||||
@@ -754,13 +764,13 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
* @large
|
||||
*/
|
||||
function testRecoveryForUser() {
|
||||
$this->markTestIncomplete(
|
||||
'This test drives Jenkins crazy - "Cannot modify header information - headers already sent" - line 811'
|
||||
);
|
||||
|
||||
// login as admin
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
|
||||
\OCA\Encryption\Helper::adminEnableRecovery(null, 'test123');
|
||||
$result = \OCA\Encryption\Helper::adminEnableRecovery(null, 'test123');
|
||||
$this->assertTrue($result);
|
||||
|
||||
$recoveryKeyId = OC_Appconfig::getValue('files_encryption', 'recoveryKeyId');
|
||||
|
||||
// login as user2
|
||||
@@ -771,6 +781,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
// enable recovery for admin
|
||||
$this->assertTrue($util->setRecoveryForUser(1));
|
||||
|
||||
// add recovery keys for existing files (e.g. the auto-generated welcome.txt)
|
||||
$util->addRecoveryKeys();
|
||||
|
||||
// create folder structure
|
||||
$this->view->mkdir('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files' . $this->folder1);
|
||||
$this->view->mkdir(
|
||||
@@ -809,6 +822,10 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
// change password
|
||||
\OC_User::setPassword(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2, 'test', 'test123');
|
||||
$params = array('uid' => \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2,
|
||||
'password' => 'test',
|
||||
'recoveryPassword' => 'test123');
|
||||
\OCA\Encryption\Hooks::setPassphrase($params);
|
||||
|
||||
// login as user2
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2, false, 'test');
|
||||
@@ -823,8 +840,10 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
$this->assertEquals($this->dataShort, $retrievedCryptedFile2);
|
||||
|
||||
// cleanup
|
||||
$this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files' . $this->folder1);
|
||||
$this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files' . $this->filename);
|
||||
$this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/');
|
||||
$this->view->unlink($this->folder1);
|
||||
$this->view->unlink($this->filename);
|
||||
$this->view->chroot('/');
|
||||
|
||||
// check if share key for user and recovery exists
|
||||
$this->assertFalse($this->view->file_exists(
|
||||
@@ -842,11 +861,21 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
. $this->subfolder . $this->subsubfolder . '/'
|
||||
. $this->filename . '.' . $recoveryKeyId . '.shareKey'));
|
||||
|
||||
// enable recovery for admin
|
||||
|
||||
// disable recovery for admin
|
||||
$this->assertTrue($util->setRecoveryForUser(0));
|
||||
|
||||
\OCA\Encryption\Helper::adminDisableRecovery('test123');
|
||||
|
||||
$this->assertEquals(0, \OC_Appconfig::getValue('files_encryption', 'recoveryAdminEnabled'));
|
||||
|
||||
//clean up, reset passwords
|
||||
\OC_User::setPassword(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2, 'test123');
|
||||
$params = array('uid' => \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2,
|
||||
'password' => \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2,
|
||||
'recoveryPassword' => 'test123');
|
||||
\OCA\Encryption\Hooks::setPassphrase($params);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -889,8 +918,8 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
} catch (Exception $e) {
|
||||
$this->assertEquals(0, strpos($e->getMessage(), "Following users are not set up for encryption"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// login as admin
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
|
||||
|
||||
@@ -925,7 +954,70 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
||||
. $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3 . '.shareKey'));
|
||||
|
||||
// cleanup
|
||||
$this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename);
|
||||
$this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/');
|
||||
$this->view->unlink($this->filename);
|
||||
$this->view->chroot('/');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief test moving a shared file out of the Shared folder
|
||||
*/
|
||||
function testRename() {
|
||||
|
||||
// login as admin
|
||||
\Test_Encryption_Util::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);
|
||||
|
||||
// test that data was successfully written
|
||||
$this->assertTrue(is_int($cryptedFile));
|
||||
|
||||
// get the file info from previous created file
|
||||
$fileInfo = $this->view->getFileInfo(
|
||||
'/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename);
|
||||
|
||||
// check if we have a valid file info
|
||||
$this->assertTrue(is_array($fileInfo));
|
||||
|
||||
// share the file
|
||||
\OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2, OCP\PERMISSION_ALL);
|
||||
|
||||
// check if share key for user2exists
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys/'
|
||||
. $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey'));
|
||||
|
||||
|
||||
// login as user2
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
|
||||
|
||||
$this->assertTrue($this->view->file_exists('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/Shared/' . $this->filename));
|
||||
|
||||
// get file contents
|
||||
$retrievedCryptedFile = $this->view->file_get_contents(
|
||||
'/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/Shared/' . $this->filename);
|
||||
|
||||
// check if data is the same as we previously written
|
||||
$this->assertEquals($this->dataShort, $retrievedCryptedFile);
|
||||
|
||||
// move the file out of the shared folder
|
||||
$this->view->rename('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/Shared/' . $this->filename,
|
||||
'/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/' . $this->filename);
|
||||
|
||||
// check if we can read the moved file
|
||||
$retrievedRenamedFile = $this->view->file_get_contents(
|
||||
'/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/' . $this->filename);
|
||||
|
||||
// check if data is the same as we previously written
|
||||
$this->assertEquals($this->dataShort, $retrievedRenamedFile);
|
||||
|
||||
// the owners file should be deleted
|
||||
$this->assertFalse($this->view->file_exists('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename));
|
||||
|
||||
// cleanup
|
||||
$this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/' . $this->filename);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ class Test_Encryption_Stream extends \PHPUnit_Framework_TestCase {
|
||||
}
|
||||
|
||||
function testStreamOptions() {
|
||||
$filename = '/tmp-' . time();
|
||||
$filename = '/tmp-' . uniqid();
|
||||
$view = new \OC\Files\View('/' . $this->userId . '/files');
|
||||
|
||||
// Save short data as encrypted file using stream wrapper
|
||||
@@ -122,7 +122,7 @@ class Test_Encryption_Stream extends \PHPUnit_Framework_TestCase {
|
||||
}
|
||||
|
||||
function testStreamSetBlocking() {
|
||||
$filename = '/tmp-' . time();
|
||||
$filename = '/tmp-' . uniqid();
|
||||
$view = new \OC\Files\View('/' . $this->userId . '/files');
|
||||
|
||||
// Save short data as encrypted file using stream wrapper
|
||||
@@ -144,7 +144,7 @@ class Test_Encryption_Stream extends \PHPUnit_Framework_TestCase {
|
||||
* @medium
|
||||
*/
|
||||
function testStreamSetTimeout() {
|
||||
$filename = '/tmp-' . time();
|
||||
$filename = '/tmp-' . uniqid();
|
||||
$view = new \OC\Files\View('/' . $this->userId . '/files');
|
||||
|
||||
// Save short data as encrypted file using stream wrapper
|
||||
@@ -163,7 +163,7 @@ class Test_Encryption_Stream extends \PHPUnit_Framework_TestCase {
|
||||
}
|
||||
|
||||
function testStreamSetWriteBuffer() {
|
||||
$filename = '/tmp-' . time();
|
||||
$filename = '/tmp-' . uniqid();
|
||||
$view = new \OC\Files\View('/' . $this->userId . '/files');
|
||||
|
||||
// Save short data as encrypted file using stream wrapper
|
||||
|
||||
@@ -119,7 +119,7 @@ class Test_Encryption_Trashbin extends \PHPUnit_Framework_TestCase {
|
||||
function testDeleteFile() {
|
||||
|
||||
// generate filename
|
||||
$filename = 'tmp-' . time() . '.txt';
|
||||
$filename = 'tmp-' . uniqid() . '.txt';
|
||||
|
||||
// save file with content
|
||||
$cryptedFile = file_put_contents('crypt:///' .\Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1. '/files/'. $filename, $this->dataShort);
|
||||
@@ -223,7 +223,7 @@ class Test_Encryption_Trashbin extends \PHPUnit_Framework_TestCase {
|
||||
function testPermanentDeleteFile() {
|
||||
|
||||
// generate filename
|
||||
$filename = 'tmp-' . time() . '.txt';
|
||||
$filename = 'tmp-' . uniqid() . '.txt';
|
||||
|
||||
// save file with content
|
||||
$cryptedFile = file_put_contents('crypt:///' .$this->userId. '/files/' . $filename, $this->dataShort);
|
||||
|
||||
@@ -64,6 +64,8 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
|
||||
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;
|
||||
@@ -219,7 +221,7 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
\OC_User::setUserId(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1);
|
||||
|
||||
$filename = '/tmp-' . time() . '.test';
|
||||
$filename = '/tmp-' . uniqid() . '.test';
|
||||
|
||||
// Disable encryption proxy to prevent recursive calls
|
||||
$proxyStatus = \OC_FileProxy::$enabled;
|
||||
@@ -247,7 +249,7 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
|
||||
function testGetFileSize() {
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1);
|
||||
|
||||
$filename = 'tmp-' . time();
|
||||
$filename = 'tmp-' . uniqid();
|
||||
$externalFilename = '/' . $this->userId . '/files/' . $filename;
|
||||
|
||||
// Test for 0 byte files
|
||||
@@ -283,7 +285,7 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
function testEncryptAll() {
|
||||
|
||||
$filename = "/encryptAll" . time() . ".txt";
|
||||
$filename = "/encryptAll" . uniqid() . ".txt";
|
||||
$util = new Encryption\Util($this->view, $this->userId);
|
||||
|
||||
// disable encryption to upload a unencrypted file
|
||||
@@ -315,7 +317,7 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
function testDecryptAll() {
|
||||
|
||||
$filename = "/decryptAll" . time() . ".txt";
|
||||
$filename = "/decryptAll" . uniqid() . ".txt";
|
||||
$util = new Encryption\Util($this->view, $this->userId);
|
||||
|
||||
$this->view->file_put_contents($this->userId . '/files/' . $filename, $this->dataShort);
|
||||
@@ -323,9 +325,12 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
|
||||
$fileInfoEncrypted = $this->view->getFileInfo($this->userId . '/files/' . $filename);
|
||||
|
||||
$this->assertTrue(is_array($fileInfoEncrypted));
|
||||
$this->assertEquals($fileInfoEncrypted['encrypted'], 1);
|
||||
|
||||
// encrypt all unencrypted files
|
||||
$util->decryptAll('/' . $this->userId . '/' . 'files');
|
||||
// decrypt all encrypted files
|
||||
$result = $util->decryptAll('/' . $this->userId . '/' . 'files');
|
||||
|
||||
$this->assertTrue($result);
|
||||
|
||||
$fileInfoUnencrypted = $this->view->getFileInfo($this->userId . '/files/' . $filename);
|
||||
|
||||
@@ -334,11 +339,83 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
|
||||
// check if mtime and etags unchanged
|
||||
$this->assertEquals($fileInfoEncrypted['mtime'], $fileInfoUnencrypted['mtime']);
|
||||
$this->assertEquals($fileInfoEncrypted['etag'], $fileInfoUnencrypted['etag']);
|
||||
// file should no longer be encrypted
|
||||
$this->assertEquals(0, $fileInfoUnencrypted['encrypted']);
|
||||
|
||||
$this->view->unlink($this->userId . '/files/' . $filename);
|
||||
|
||||
}
|
||||
|
||||
function testDescryptAllWithBrokenFiles() {
|
||||
|
||||
$file1 = "/decryptAll1" . uniqid() . ".txt";
|
||||
$file2 = "/decryptAll2" . uniqid() . ".txt";
|
||||
|
||||
$util = new Encryption\Util($this->view, $this->userId);
|
||||
|
||||
$this->view->file_put_contents($this->userId . '/files/' . $file1, $this->dataShort);
|
||||
$this->view->file_put_contents($this->userId . '/files/' . $file2, $this->dataShort);
|
||||
|
||||
$fileInfoEncrypted1 = $this->view->getFileInfo($this->userId . '/files/' . $file1);
|
||||
$fileInfoEncrypted2 = $this->view->getFileInfo($this->userId . '/files/' . $file2);
|
||||
|
||||
$this->assertTrue(is_array($fileInfoEncrypted1));
|
||||
$this->assertTrue(is_array($fileInfoEncrypted2));
|
||||
$this->assertEquals($fileInfoEncrypted1['encrypted'], 1);
|
||||
$this->assertEquals($fileInfoEncrypted2['encrypted'], 1);
|
||||
|
||||
// rename keyfile for file1 so that the decryption for file1 fails
|
||||
// Expected behaviour: decryptAll() returns false, file2 gets decrypted anyway
|
||||
$this->view->rename($this->userId . '/files_encryption/keyfiles/' . $file1 . '.key',
|
||||
$this->userId . '/files_encryption/keyfiles/' . $file1 . '.key.moved');
|
||||
|
||||
// decrypt all encrypted files
|
||||
$result = $util->decryptAll('/' . $this->userId . '/' . 'files');
|
||||
|
||||
$this->assertFalse($result);
|
||||
|
||||
$fileInfoUnencrypted1 = $this->view->getFileInfo($this->userId . '/files/' . $file1);
|
||||
$fileInfoUnencrypted2 = $this->view->getFileInfo($this->userId . '/files/' . $file2);
|
||||
|
||||
$this->assertTrue(is_array($fileInfoUnencrypted1));
|
||||
$this->assertTrue(is_array($fileInfoUnencrypted2));
|
||||
|
||||
// file1 should be still encrypted; file2 should be decrypted
|
||||
$this->assertEquals(1, $fileInfoUnencrypted1['encrypted']);
|
||||
$this->assertEquals(0, $fileInfoUnencrypted2['encrypted']);
|
||||
|
||||
// keyfiles and share keys should still exist
|
||||
$this->assertTrue($this->view->is_dir($this->userId . '/files_encryption/keyfiles/'));
|
||||
$this->assertTrue($this->view->is_dir($this->userId . '/files_encryption/share-keys/'));
|
||||
|
||||
// rename the keyfile for file1 back
|
||||
$this->view->rename($this->userId . '/files_encryption/keyfiles/' . $file1 . '.key.moved',
|
||||
$this->userId . '/files_encryption/keyfiles/' . $file1 . '.key');
|
||||
|
||||
// try again to decrypt all encrypted files
|
||||
$result = $util->decryptAll('/' . $this->userId . '/' . 'files');
|
||||
|
||||
$this->assertTrue($result);
|
||||
|
||||
$fileInfoUnencrypted1 = $this->view->getFileInfo($this->userId . '/files/' . $file1);
|
||||
$fileInfoUnencrypted2 = $this->view->getFileInfo($this->userId . '/files/' . $file2);
|
||||
|
||||
$this->assertTrue(is_array($fileInfoUnencrypted1));
|
||||
$this->assertTrue(is_array($fileInfoUnencrypted2));
|
||||
|
||||
// now both files should be decrypted
|
||||
$this->assertEquals(0, $fileInfoUnencrypted1['encrypted']);
|
||||
$this->assertEquals(0, $fileInfoUnencrypted2['encrypted']);
|
||||
|
||||
// keyfiles and share keys should be deleted
|
||||
$this->assertFalse($this->view->is_dir($this->userId . '/files_encryption/keyfiles/'));
|
||||
$this->assertFalse($this->view->is_dir($this->userId . '/files_encryption/share-keys/'));
|
||||
|
||||
$this->view->unlink($this->userId . '/files/' . $file1);
|
||||
$this->view->unlink($this->userId . '/files/' . $file2);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @large
|
||||
*/
|
||||
@@ -416,6 +493,12 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
|
||||
OCA\Encryption\Hooks::login($params);
|
||||
}
|
||||
|
||||
public static function logoutHelper() {
|
||||
\OC_Util::tearDownFS();
|
||||
\OC_User::setUserId('');
|
||||
\OC\Files\Filesystem::tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* helper function to set migration status to the right value
|
||||
* to be able to test the migration path
|
||||
|
||||
@@ -113,7 +113,7 @@ class Test_Encryption_Webdav extends \PHPUnit_Framework_TestCase {
|
||||
function testWebdavPUT() {
|
||||
|
||||
// generate filename
|
||||
$filename = '/tmp-' . time() . '.txt';
|
||||
$filename = '/tmp-' . uniqid() . '.txt';
|
||||
|
||||
// set server vars
|
||||
$_SERVER['REQUEST_METHOD'] = 'OPTIONS';
|
||||
|
||||
+6
-2
@@ -19,6 +19,10 @@
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# Addition 17/12/2012 Frank Karlitschek (frank@owncloud.org)
|
||||
# On the official website http://www.phpclasses.org/smb4php the
|
||||
# license is listed as LGPL so we assume that this is
|
||||
# dual-licensed GPL/LGPL
|
||||
###################################################################
|
||||
|
||||
define ('SMB4PHP_VERSION', '0.8');
|
||||
@@ -126,7 +130,7 @@ class smb {
|
||||
// this put env is necessary to read the output of smbclient correctly
|
||||
$old_locale = getenv('LC_ALL');
|
||||
putenv('LC_ALL=en_US.UTF-8');
|
||||
$output = popen (SMB4PHP_SMBCLIENT." -N {$auth} {$options} {$port} {$options} {$params} 2>/dev/null", 'r');
|
||||
$output = popen ('TZ=UTC '.SMB4PHP_SMBCLIENT." -N {$auth} {$options} {$port} {$options} {$params} 2>/dev/null", 'r');
|
||||
$gotInfo = false;
|
||||
$info = array ();
|
||||
$info['info']= array ();
|
||||
@@ -160,7 +164,7 @@ class smb {
|
||||
$i = ($mode == 'servers') ? array ($name, "server") : array ($name, "workgroup", $master);
|
||||
break;
|
||||
case 'files':
|
||||
list ($attr, $name) = preg_match ("/^(.*)[ ]+([D|A|H|S|R]+)$/", trim ($regs[1]), $regs2)
|
||||
list ($attr, $name) = preg_match ("/^(.*)[ ]+([D|A|H|S|R|N]+)$/", trim ($regs[1]), $regs2)
|
||||
? array (trim ($regs2[2]), trim ($regs2[1]))
|
||||
: array ('', trim ($regs[1]));
|
||||
list ($his, $im) = array (
|
||||
|
||||
@@ -23,9 +23,12 @@ $(document).ready(function() {
|
||||
$(token).val(result.access_token);
|
||||
$(token_secret).val(result.access_token_secret);
|
||||
$(configured).val('true');
|
||||
OC.MountConfig.saveStorage(tr);
|
||||
$(tr).find('.configuration input').attr('disabled', 'disabled');
|
||||
$(tr).find('.configuration').append('<span id="access" style="padding-left:0.5em;">'+t('files_external', 'Access granted')+'</span>');
|
||||
OC.MountConfig.saveStorage(tr, function(status) {
|
||||
if (status) {
|
||||
$(tr).find('.configuration input').attr('disabled', 'disabled');
|
||||
$(tr).find('.configuration').append('<span id="access" style="padding-left:0.5em;">'+t('files_external', 'Access granted')+'</span>');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
OC.dialogs.alert(result.data.message, t('files_external', 'Error configuring Dropbox storage'));
|
||||
}
|
||||
@@ -77,7 +80,6 @@ $(document).ready(function() {
|
||||
var tr = $(this).parent().parent();
|
||||
var app_key = $(this).parent().find('[data-parameter="app_key"]').val();
|
||||
var app_secret = $(this).parent().find('[data-parameter="app_secret"]').val();
|
||||
var statusSpan = $(tr).find('.status span');
|
||||
if (app_key != '' && app_secret != '') {
|
||||
var tr = $(this).parent().parent();
|
||||
var configured = $(this).parent().find('[data-parameter="configured"]');
|
||||
@@ -88,10 +90,9 @@ $(document).ready(function() {
|
||||
$(configured).val('false');
|
||||
$(token).val(result.data.request_token);
|
||||
$(token_secret).val(result.data.request_token_secret);
|
||||
OC.MountConfig.saveStorage(tr);
|
||||
statusSpan.removeClass();
|
||||
statusSpan.addClass('waiting');
|
||||
window.location = result.data.url;
|
||||
OC.MountConfig.saveStorage(tr, function() {
|
||||
window.location = result.data.url;
|
||||
});
|
||||
} else {
|
||||
OC.dialogs.alert(result.data.message, t('files_external', 'Error configuring Dropbox storage'));
|
||||
}
|
||||
|
||||
@@ -32,11 +32,14 @@ $(document).ready(function() {
|
||||
if (result && result.status == 'success') {
|
||||
$(token).val(result.data.token);
|
||||
$(configured).val('true');
|
||||
OC.MountConfig.saveStorage(tr);
|
||||
$(tr).find('.configuration input').attr('disabled', 'disabled');
|
||||
$(tr).find('.configuration').append($('<span/>')
|
||||
.attr('id', 'access')
|
||||
.text(t('files_external', 'Access granted')));
|
||||
OC.MountConfig.saveStorage(tr, function(status) {
|
||||
if (status) {
|
||||
$(tr).find('.configuration input').attr('disabled', 'disabled');
|
||||
$(tr).find('.configuration').append($('<span/>')
|
||||
.attr('id', 'access')
|
||||
.text(t('files_external', 'Access granted')));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
OC.dialogs.alert(result.data.message,
|
||||
t('files_external', 'Error configuring Google Drive storage')
|
||||
@@ -99,7 +102,6 @@ $(document).ready(function() {
|
||||
var configured = $(this).parent().find('[data-parameter="configured"]');
|
||||
var client_id = $(this).parent().find('[data-parameter="client_id"]').val();
|
||||
var client_secret = $(this).parent().find('[data-parameter="client_secret"]').val();
|
||||
var statusSpan = $(tr).find('.status span');
|
||||
if (client_id != '' && client_secret != '') {
|
||||
var token = $(this).parent().find('[data-parameter="token"]');
|
||||
$.post(OC.filePath('files_external', 'ajax', 'google.php'),
|
||||
@@ -112,10 +114,9 @@ $(document).ready(function() {
|
||||
if (result && result.status == 'success') {
|
||||
$(configured).val('false');
|
||||
$(token).val('false');
|
||||
OC.MountConfig.saveStorage(tr);
|
||||
statusSpan.removeClass();
|
||||
statusSpan.addClass('waiting');
|
||||
window.location = result.data.url;
|
||||
OC.MountConfig.saveStorage(tr, function(status) {
|
||||
window.location = result.data.url;
|
||||
});
|
||||
} else {
|
||||
OC.dialogs.alert(result.data.message,
|
||||
t('files_external', 'Error configuring Google Drive storage')
|
||||
|
||||
@@ -12,7 +12,7 @@ function updateStatus(statusEl, result){
|
||||
}
|
||||
|
||||
OC.MountConfig={
|
||||
saveStorage:function(tr) {
|
||||
saveStorage:function(tr, callback) {
|
||||
var mountPoint = $(tr).find('.mountPoint input').val();
|
||||
if (mountPoint == '') {
|
||||
return false;
|
||||
@@ -84,9 +84,15 @@ OC.MountConfig={
|
||||
},
|
||||
success: function(result) {
|
||||
status = updateStatus(statusSpan, result);
|
||||
if (callback) {
|
||||
callback(status);
|
||||
}
|
||||
},
|
||||
error: function(result){
|
||||
status = updateStatus(statusSpan, result);
|
||||
if (callback) {
|
||||
callback(status);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -137,9 +143,15 @@ OC.MountConfig={
|
||||
},
|
||||
success: function(result) {
|
||||
status = updateStatus(statusSpan, result);
|
||||
if (callback) {
|
||||
callback(status);
|
||||
}
|
||||
},
|
||||
error: function(result){
|
||||
status = updateStatus(statusSpan, result);
|
||||
if (callback) {
|
||||
callback(status);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
<?php
|
||||
$TRANSLATIONS = array(
|
||||
"Options" => "Опции",
|
||||
"Delete" => "Удалить"
|
||||
);
|
||||
$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);";
|
||||
@@ -81,9 +81,9 @@ class AmazonS3 extends \OC\Files\Storage\Common {
|
||||
$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'])) ? 'eu-west-1' : $params['region'];
|
||||
$params['hostname'] = ( !isset($params['hostname'])) ? 's3.amazonaws.com' : $params['hostname'];
|
||||
if (!isset($params['port'])) {
|
||||
$params['region'] = ( ! isset($params['region']) || $params['region'] === '' ) ? 'eu-west-1' : $params['region'];
|
||||
$params['hostname'] = ( !isset($params['hostname']) || $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'].'/';
|
||||
@@ -507,8 +507,10 @@ class AmazonS3 extends \OC\Files\Storage\Common {
|
||||
}
|
||||
|
||||
public function test() {
|
||||
$test = $this->s3->get_canonical_user_id();
|
||||
if (isset($test['id']) && $test['id'] != '') {
|
||||
$test = $this->connection->getBucketAcl(array(
|
||||
'Bucket' => $this->bucket,
|
||||
));
|
||||
if (isset($test) && !is_null($test->getPath('Owner/ID'))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -50,9 +50,9 @@ class OC_Mount_Config {
|
||||
'key' => 'Access Key',
|
||||
'secret' => '*Secret Key',
|
||||
'bucket' => 'Bucket',
|
||||
'hostname' => 'Hostname (optional)',
|
||||
'port' => 'Port (optional)',
|
||||
'region' => 'Region (optional)',
|
||||
'hostname' => '&Hostname (optional)',
|
||||
'port' => '&Port (optional)',
|
||||
'region' => '&Region (optional)',
|
||||
'use_ssl' => '!Enable SSL',
|
||||
'use_path_style' => '!Enable Path Style'));
|
||||
|
||||
@@ -61,7 +61,7 @@ class OC_Mount_Config {
|
||||
'configuration' => array(
|
||||
'configured' => '#configured',
|
||||
'app_key' => 'App key',
|
||||
'app_secret' => 'App secret',
|
||||
'app_secret' => '*App secret',
|
||||
'token' => '#token',
|
||||
'token_secret' => '#token_secret'),
|
||||
'custom' => 'dropbox');
|
||||
@@ -69,7 +69,7 @@ class OC_Mount_Config {
|
||||
if(OC_Mount_Config::checkphpftp()) $backends['\OC\Files\Storage\FTP']=array(
|
||||
'backend' => 'FTP',
|
||||
'configuration' => array(
|
||||
'host' => 'URL',
|
||||
'host' => 'Hostname',
|
||||
'user' => 'Username',
|
||||
'password' => '*Password',
|
||||
'root' => '&Root',
|
||||
@@ -80,7 +80,7 @@ class OC_Mount_Config {
|
||||
'configuration' => array(
|
||||
'configured' => '#configured',
|
||||
'client_id' => 'Client ID',
|
||||
'client_secret' => 'Client secret',
|
||||
'client_secret' => '*Client secret',
|
||||
'token' => '#token'),
|
||||
'custom' => 'google');
|
||||
|
||||
@@ -244,6 +244,7 @@ class OC_Mount_Config {
|
||||
$storage = new $class($options);
|
||||
return $storage->test();
|
||||
} catch (Exception $exception) {
|
||||
\OCP\Util::logException('files_external', $exception);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -266,15 +267,21 @@ class OC_Mount_Config {
|
||||
$mountType,
|
||||
$applicable,
|
||||
$isPersonal = false) {
|
||||
$backends = self::getBackends();
|
||||
$mountPoint = OC\Files\Filesystem::normalizePath($mountPoint);
|
||||
if ($mountPoint === '' || $mountPoint === '/' || $mountPoint == '/Shared') {
|
||||
// can't mount at root or "Shared" folder
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isset($backends[$class])) {
|
||||
// invalid backend
|
||||
return false;
|
||||
}
|
||||
if ($isPersonal) {
|
||||
// Verify that the mount point applies for the current user
|
||||
// Prevent non-admin users from mounting local storage
|
||||
if ($applicable != OCP\User::getUser() || $class == '\OC\Files\Storage\Local') {
|
||||
if ($applicable !== OCP\User::getUser() || strtolower($class) === '\oc\files\storage\local') {
|
||||
return false;
|
||||
}
|
||||
$mountPoint = '/'.$applicable.'/files/'.ltrim($mountPoint, '/');
|
||||
@@ -381,8 +388,7 @@ class OC_Mount_Config {
|
||||
* @return array
|
||||
*/
|
||||
public static function getCertificates() {
|
||||
$view = \OCP\Files::getStorage('files_external');
|
||||
$path=\OCP\Config::getSystemValue('datadirectory').$view->getAbsolutePath("").'uploads/';
|
||||
$path=OC_User::getHome(OC_User::getUser()) . '/files_external/uploads/';
|
||||
\OCP\Util::writeLog('files_external', 'checking path '.$path, \OCP\Util::INFO);
|
||||
if ( ! is_dir($path)) {
|
||||
//path might not exist (e.g. non-standard OC_User::getHome() value)
|
||||
@@ -404,8 +410,7 @@ class OC_Mount_Config {
|
||||
* creates certificate bundle
|
||||
*/
|
||||
public static function createCertificateBundle() {
|
||||
$view = \OCP\Files::getStorage("files_external");
|
||||
$path = \OCP\Config::getSystemValue('datadirectory').$view->getAbsolutePath("");
|
||||
$path=OC_User::getHome(OC_User::getUser()) . '/files_external';
|
||||
|
||||
$certs = OC_Mount_Config::getCertificates();
|
||||
$fh_certs = fopen($path."/rootcerts.crt", 'w');
|
||||
|
||||
@@ -14,6 +14,7 @@ class DAV extends \OC\Files\Storage\Common{
|
||||
private $host;
|
||||
private $secure;
|
||||
private $root;
|
||||
private $certPath;
|
||||
private $ready;
|
||||
/**
|
||||
* @var \Sabre_DAV_Client
|
||||
@@ -40,6 +41,12 @@ class DAV extends \OC\Files\Storage\Common{
|
||||
} else {
|
||||
$this->secure = false;
|
||||
}
|
||||
if ($this->secure === true) {
|
||||
$certPath=\OC_User::getHome(\OC_User::getUser()) . '/files_external/rootcerts.crt';
|
||||
if (file_exists($certPath)) {
|
||||
$this->certPath=$certPath;
|
||||
}
|
||||
}
|
||||
$this->root=isset($params['root'])?$params['root']:'/';
|
||||
if ( ! $this->root || $this->root[0]!='/') {
|
||||
$this->root='/'.$this->root;
|
||||
@@ -58,20 +65,16 @@ class DAV extends \OC\Files\Storage\Common{
|
||||
}
|
||||
$this->ready = true;
|
||||
|
||||
$settings = array(
|
||||
'baseUri' => $this->createBaseUri(),
|
||||
'userName' => $this->user,
|
||||
'password' => $this->password,
|
||||
);
|
||||
$settings = array(
|
||||
'baseUri' => $this->createBaseUri(),
|
||||
'userName' => $this->user,
|
||||
'password' => $this->password,
|
||||
);
|
||||
|
||||
$this->client = new \Sabre_DAV_Client($settings);
|
||||
|
||||
$caview = \OCP\Files::getStorage('files_external');
|
||||
if ($caview) {
|
||||
$certPath=\OCP\Config::getSystemValue('datadirectory').$caview->getAbsolutePath("").'rootcerts.crt';
|
||||
if (file_exists($certPath)) {
|
||||
$this->client->addTrustedCertificates($certPath);
|
||||
}
|
||||
if ($this->secure === true && $this->certPath) {
|
||||
$this->client->addTrustedCertificates($this->certPath);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,7 +169,14 @@ class DAV extends \OC\Files\Storage\Common{
|
||||
curl_setopt($curl, CURLOPT_URL, $this->createBaseUri().str_replace(' ', '%20', $path));
|
||||
curl_setopt($curl, CURLOPT_FILE, $fp);
|
||||
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
|
||||
|
||||
if ($this->secure === true) {
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
|
||||
if($this->certPath){
|
||||
curl_setopt($curl, CURLOPT_CAINFO, $this->certPath);
|
||||
}
|
||||
}
|
||||
|
||||
curl_exec ($curl);
|
||||
curl_close ($curl);
|
||||
rewind($fp);
|
||||
@@ -214,7 +224,7 @@ class DAV extends \OC\Files\Storage\Common{
|
||||
if (isset($response['{DAV:}quota-available-bytes'])) {
|
||||
return (int)$response['{DAV:}quota-available-bytes'];
|
||||
} else {
|
||||
return 0;
|
||||
return \OC\Files\SPACE_UNKNOWN;
|
||||
}
|
||||
} catch(\Exception $e) {
|
||||
return \OC\Files\SPACE_UNKNOWN;
|
||||
@@ -254,6 +264,13 @@ class DAV extends \OC\Files\Storage\Common{
|
||||
curl_setopt($curl, CURLOPT_INFILE, $source); // file pointer
|
||||
curl_setopt($curl, CURLOPT_INFILESIZE, filesize($path));
|
||||
curl_setopt($curl, CURLOPT_PUT, true);
|
||||
if ($this->secure === true) {
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
|
||||
if($this->certPath){
|
||||
curl_setopt($curl, CURLOPT_CAINFO, $this->certPath);
|
||||
}
|
||||
}
|
||||
curl_exec ($curl);
|
||||
curl_close ($curl);
|
||||
}
|
||||
@@ -331,3 +348,4 @@ class DAV extends \OC\Files\Storage\Common{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
class="optional"
|
||||
data-parameter="<?php p($parameter); ?>"
|
||||
value="<?php p($value); ?>"
|
||||
placeholder="<?php p(substr($placeholder, 5)); ?>" />
|
||||
placeholder="<?php p(substr($placeholder, 1)); ?>" />
|
||||
<?php elseif (strpos($placeholder, '#') !== false): ?>
|
||||
<input type="hidden"
|
||||
data-parameter="<?php p($parameter); ?>"
|
||||
|
||||
@@ -48,4 +48,29 @@ class Test_Mount_Config extends \PHPUnit_Framework_TestCase {
|
||||
$this->assertEquals(false, OC_Mount_Config::addMountPoint('/Shared', $storageClass, array(), $mountType, $applicable, $isPersonal));
|
||||
|
||||
}
|
||||
|
||||
public function testAddMountPointSingleUser() {
|
||||
\OC_User::setUserId('test');
|
||||
$mountType = 'user';
|
||||
$applicable = 'test';
|
||||
$isPersonal = true;
|
||||
// local
|
||||
$this->assertEquals(false, OC_Mount_Config::addMountPoint('/ext', '\OC\Files\storage\local', array(), $mountType, $applicable, $isPersonal));
|
||||
// non-local
|
||||
// FIXME: can't test this yet as the class (write operation) is not mockable
|
||||
// $this->assertEquals(true, OC_Mount_Config::addMountPoint('/ext', '\OC\Files\Storage\SFTP', array(), $mountType, $applicable, $isPersonal));
|
||||
|
||||
}
|
||||
|
||||
public function testAddMountPointUnexistClass() {
|
||||
\OC_User::setUserId('test');
|
||||
$storageClass = 'Unexist_Storage';
|
||||
$mountType = 'user';
|
||||
$applicable = 'test';
|
||||
$isPersonal = true;
|
||||
// local
|
||||
// non-local
|
||||
$this->assertEquals(false, OC_Mount_Config::addMountPoint('/ext', $storageClass, array(), $mountType, $applicable, $isPersonal));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,10 @@ if(!isset($linkedItem['uid_owner']) || !isset($linkedItem['file_source'])) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$userId = $linkedItem['uid_owner'];
|
||||
$rootLinkItem = OCP\Share::resolveReShare($linkedItem);
|
||||
$userId = $rootLinkItem['uid_owner'];
|
||||
|
||||
OCP\JSON::checkUserExists($rootLinkItem['uid_owner']);
|
||||
\OC_Util::setupFS($userId);
|
||||
\OC\Files\Filesystem::initMountPoints($userId);
|
||||
$view = new \OC\Files\View('/' . $userId . '/files');
|
||||
@@ -86,4 +89,4 @@ try{
|
||||
} catch (\Exception $e) {
|
||||
\OC_Response::setStatus(500);
|
||||
\OC_Log::write('core', $e->getmessage(), \OC_Log::DEBUG);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ if (version_compare($installedVersion, '0.3', '<')) {
|
||||
$shareType = OCP\Share::SHARE_TYPE_USER;
|
||||
$shareWith = $row['uid_shared_with'];
|
||||
}
|
||||
OCP\JSON::checkUserExists($row['uid_owner']);
|
||||
OC_User::setUserId($row['uid_owner']);
|
||||
//we need to setup the filesystem for the user, otherwise OC_FileSystem::getRoot will fail and break
|
||||
OC_Util::setupFS($row['uid_owner']);
|
||||
|
||||
@@ -11,16 +11,13 @@
|
||||
margin: 6px;
|
||||
}
|
||||
|
||||
input[type="submit"]{
|
||||
input[type='submit'] {
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
margin: 6px;
|
||||
background-image: url('%webroot%/core/img/actions/confirm.svg');
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
#body-login input[type="submit"] {
|
||||
#body-login input[type='submit'] {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
@media only screen and (max-width: 600px) {
|
||||
|
||||
/* make header scroll up for single shares, more view of content on small screens */
|
||||
#header.share-file {
|
||||
position: absolute !important;
|
||||
}
|
||||
|
||||
/* hide size and date columns */
|
||||
table th#headerSize,
|
||||
table td.filesize,
|
||||
table th#headerDate,
|
||||
table td.date {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* restrict length of displayed filename to prevent overflow */
|
||||
table td.filename .nametext {
|
||||
max-width: 75% !important;
|
||||
}
|
||||
|
||||
/* on mobile, show single shared image at full width without margin */
|
||||
#imgframe {
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
margin-bottom: 35px;
|
||||
}
|
||||
/* some margin for the file type icon */
|
||||
#imgframe .publicpreview {
|
||||
margin-top: 32px;
|
||||
}
|
||||
|
||||
/* always show actions on mobile */
|
||||
#fileList a.action {
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=20)" !important;
|
||||
filter: alpha(opacity=20) !important;
|
||||
opacity: .2 !important;
|
||||
display: inline !important;
|
||||
}
|
||||
/* some padding for better clickability */
|
||||
#fileList a.action img {
|
||||
padding: 0 6px 0 12px;
|
||||
}
|
||||
/* hide text of the actions on mobile */
|
||||
#fileList a.action span {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
body {
|
||||
background:#ddd;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
#header {
|
||||
background: #1d2d44 url('%webroot%/core/img/noise.png') repeat;
|
||||
background-color: #1d2d44;
|
||||
height:32px;
|
||||
left:0;
|
||||
line-height:32px;
|
||||
@@ -14,47 +14,27 @@ body {
|
||||
padding:7px;
|
||||
}
|
||||
|
||||
#details {
|
||||
color:#fff;
|
||||
float: left;
|
||||
}
|
||||
|
||||
#public_upload,
|
||||
#download {
|
||||
font-weight:700;
|
||||
margin: 0 0.4em 0 0;
|
||||
padding: 0 5px;
|
||||
height: 32px;
|
||||
float: left;
|
||||
|
||||
}
|
||||
|
||||
.header-right #details {
|
||||
margin-right: 28px;
|
||||
}
|
||||
|
||||
.header-right {
|
||||
padding: 0;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
#public_upload {
|
||||
margin-left: 0.3em;
|
||||
#details {
|
||||
color:#fff;
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";
|
||||
filter: alpha(opacity=50);
|
||||
opacity: .5;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
#public_upload img,
|
||||
#download img {
|
||||
padding-left:.1em;
|
||||
padding-right:.3em;
|
||||
vertical-align:text-bottom;
|
||||
#controls {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
#preview {
|
||||
background:#eee;
|
||||
border-bottom:1px solid #f8f8f8;
|
||||
min-height:30em;
|
||||
text-align:center;
|
||||
margin:45px auto;
|
||||
background: #fff;
|
||||
text-align: center;
|
||||
margin: 45px auto 0;
|
||||
}
|
||||
|
||||
#noPreview {
|
||||
@@ -62,11 +42,15 @@ body {
|
||||
padding-top:5em;
|
||||
}
|
||||
|
||||
footer {
|
||||
margin-top: 45px;
|
||||
}
|
||||
|
||||
p.info {
|
||||
color:#777;
|
||||
text-align:center;
|
||||
width:22em;
|
||||
margin:2em auto;
|
||||
color: #777;
|
||||
text-align: center;
|
||||
margin: 0 auto;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
p.info a {
|
||||
@@ -87,9 +71,13 @@ p.info a {
|
||||
max-width:100%;
|
||||
}
|
||||
|
||||
thead{
|
||||
background-color: white;
|
||||
padding-left:0 !important; /* fixes multiselect bar offset on shared page */
|
||||
/* some margin for the file type icon */
|
||||
#imgframe .publicpreview {
|
||||
margin-top: 10%;
|
||||
}
|
||||
|
||||
thead {
|
||||
padding-left: 0 !important; /* fixes multiselect bar offset on shared page */
|
||||
}
|
||||
|
||||
#data-upload-form {
|
||||
@@ -103,41 +91,23 @@ thead{
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#file_upload_start {
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
|
||||
filter: alpha(opacity=0);
|
||||
opacity: 0;
|
||||
z-index: 20;
|
||||
position: absolute !important;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
#publicUploadButtonMock {
|
||||
position:relative;
|
||||
display:block;
|
||||
width:100%;
|
||||
height:32px;
|
||||
cursor:pointer;
|
||||
z-index:10;
|
||||
background-image:url('%webroot%/core/img/actions/upload.svg');
|
||||
background-repeat:no-repeat;
|
||||
background-position:7px 8px;
|
||||
}
|
||||
|
||||
#publicUploadButtonMock span {
|
||||
margin: 0 5px 0 28px;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.directDownload,
|
||||
.directLink {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.directLink label {
|
||||
font-weight: normal;
|
||||
}
|
||||
.directLink input {
|
||||
margin-left: 10px;
|
||||
width: 300px;
|
||||
}
|
||||
.directDownload .button img {
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
.directLink label {
|
||||
font-weight: normal;
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";
|
||||
filter: alpha(opacity=50);
|
||||
opacity: .5;
|
||||
}
|
||||
.directLink input {
|
||||
margin-left: 5px;
|
||||
width: 300px;
|
||||
}
|
||||
.public_actions {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
@@ -9,39 +9,30 @@ function fileDownloadPath(dir, file) {
|
||||
|
||||
$(document).ready(function() {
|
||||
|
||||
$('#data-upload-form').tipsy({gravity:'ne', fade:true});
|
||||
|
||||
if (typeof FileActions !== 'undefined') {
|
||||
var mimetype = $('#mimetype').val();
|
||||
// Show file preview if previewer is available, images are already handled by the template
|
||||
if (mimetype.substr(0, mimetype.indexOf('/')) != 'image' && $('.publicpreview').length === 0) {
|
||||
// Trigger default action if not download TODO
|
||||
var action = FileActions.getDefault(mimetype, 'file', OC.PERMISSION_READ);
|
||||
if (typeof action === 'undefined') {
|
||||
$('#noPreview').show();
|
||||
if (mimetype != 'httpd/unix-directory') {
|
||||
// NOTE: Remove when a better file previewer solution exists
|
||||
$('#content').remove();
|
||||
$('table').remove();
|
||||
}
|
||||
} else {
|
||||
if (typeof action !== 'undefined') {
|
||||
action($('#filename').val());
|
||||
}
|
||||
}
|
||||
FileActions.register('dir', 'Open', OC.PERMISSION_READ, '', function(filename) {
|
||||
var tr = $('tr').filterAttr('data-file', filename);
|
||||
var tr = FileList.findFileEl(filename);
|
||||
if (tr.length > 0) {
|
||||
window.location = $(tr).find('a.name').attr('href');
|
||||
}
|
||||
});
|
||||
FileActions.register('file', 'Download', OC.PERMISSION_READ, '', function(filename) {
|
||||
var tr = $('tr').filterAttr('data-file', filename);
|
||||
var tr = FileList.findFileEl(filename);
|
||||
if (tr.length > 0) {
|
||||
window.location = $(tr).find('a.name').attr('href');
|
||||
}
|
||||
});
|
||||
FileActions.register('dir', 'Download', OC.PERMISSION_READ, '', function(filename) {
|
||||
var tr = $('tr').filterAttr('data-file', filename);
|
||||
var tr = FileList.findFileEl(filename);
|
||||
if (tr.length > 0) {
|
||||
window.location = $(tr).find('a.name').attr('href')+'&download';
|
||||
}
|
||||
@@ -58,15 +49,9 @@ $(document).ready(function() {
|
||||
};
|
||||
});
|
||||
|
||||
// Add Uploadprogress Wrapper to controls bar
|
||||
$('#controls').append($('#additional_controls div#uploadprogresswrapper'));
|
||||
|
||||
// Cancel upload trigger
|
||||
$('#cancel_upload_button').click(function() {
|
||||
OC.Upload.cancelUploads();
|
||||
procesSelection();
|
||||
$(document).on('click', '#directLink', function() {
|
||||
$(this).focus();
|
||||
$(this).select();
|
||||
});
|
||||
|
||||
$('#directLink').focus();
|
||||
|
||||
});
|
||||
|
||||
@@ -22,7 +22,7 @@ $(document).ready(function() {
|
||||
} else {
|
||||
var item = $('#dir').val() + '/' + filename;
|
||||
}
|
||||
var tr = $('tr').filterAttr('data-file', filename);
|
||||
var tr = FileList.findFileEl(filename);
|
||||
if ($(tr).data('type') == 'dir') {
|
||||
var itemType = 'folder';
|
||||
} else {
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
<?php
|
||||
$TRANSLATIONS = array(
|
||||
"Password" => "Пароль",
|
||||
"Download" => "Загрузка",
|
||||
"Upload" => "Загрузка",
|
||||
"Cancel upload" => "Отмена загрузки"
|
||||
);
|
||||
$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);";
|
||||
@@ -162,7 +162,7 @@ class Api {
|
||||
$view = new \OC\Files\View('/'.\OCP\User::getUser().'/files');
|
||||
|
||||
if(!$view->is_dir($path)) {
|
||||
return new \OC_OCS_Result(null, 404, "not a directory");
|
||||
return new \OC_OCS_Result(null, 400, "not a directory");
|
||||
}
|
||||
|
||||
$content = $view->getDirectoryContent($path);
|
||||
@@ -172,14 +172,13 @@ class Api {
|
||||
// workaround because folders are named 'dir' in this context
|
||||
$itemType = $file['type'] === 'file' ? 'file' : 'folder';
|
||||
$share = \OCP\Share::getItemShared($itemType, $file['fileid']);
|
||||
$receivedFrom = \OCP\Share::getItemSharedWithBySource($itemType, $file['fileid']);
|
||||
if ($receivedFrom) {
|
||||
$share['received_from'] = $receivedFrom['uid_owner'];
|
||||
$share['received_from_displayname'] = \OCP\User::getDisplayName($receivedFrom['uid_owner']);
|
||||
}
|
||||
if ($share) {
|
||||
$share['filename'] = $file['name'];
|
||||
$result[] = $share;
|
||||
if($share) {
|
||||
$receivedFrom = \OCP\Share::getItemSharedWithBySource($itemType, $file['fileid']);
|
||||
if ($receivedFrom) {
|
||||
$share['received_from'] = $receivedFrom['uid_owner'];
|
||||
$share['received_from_displayname'] = \OCP\User::getDisplayName($receivedFrom['uid_owner']);
|
||||
}
|
||||
$result = array_merge($result, $share);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,10 +219,8 @@ class Api {
|
||||
$shareWith = isset($_POST['password']) ? $_POST['password'] : null;
|
||||
//check public link share
|
||||
$publicUploadEnabled = \OC_Appconfig::getValue('core', 'shareapi_allow_public_upload', 'yes');
|
||||
$encryptionEnabled = \OC_App::isEnabled('files_encryption');
|
||||
if(isset($_POST['publicUpload']) &&
|
||||
($encryptionEnabled || $publicUploadEnabled !== 'yes')) {
|
||||
return new \OC_OCS_Result(null, 404, "public upload disabled by the administrator");
|
||||
if(isset($_POST['publicUpload']) && $publicUploadEnabled !== 'yes') {
|
||||
return new \OC_OCS_Result(null, 403, "public upload disabled by the administrator");
|
||||
}
|
||||
$publicUpload = isset($_POST['publicUpload']) ? $_POST['publicUpload'] : 'false';
|
||||
// read, create, update (7) if public upload is enabled or
|
||||
@@ -231,7 +228,7 @@ class Api {
|
||||
$permissions = $publicUpload === 'true' ? 7 : 1;
|
||||
break;
|
||||
default:
|
||||
return new \OC_OCS_Result(null, 404, "unknown share type");
|
||||
return new \OC_OCS_Result(null, 400, "unknown share type");
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -243,7 +240,7 @@ class Api {
|
||||
$permissions
|
||||
);
|
||||
} catch (\Exception $e) {
|
||||
return new \OC_OCS_Result(null, 404, $e->getMessage());
|
||||
return new \OC_OCS_Result(null, 403, $e->getMessage());
|
||||
}
|
||||
|
||||
if ($token) {
|
||||
@@ -321,11 +318,8 @@ class Api {
|
||||
$permissions = isset($params['_put']['permissions']) ? (int)$params['_put']['permissions'] : null;
|
||||
|
||||
$publicUploadStatus = \OC_Appconfig::getValue('core', 'shareapi_allow_public_upload', 'yes');
|
||||
$encryptionEnabled = \OC_App::isEnabled('files_encryption');
|
||||
$publicUploadEnabled = false;
|
||||
if(!$encryptionEnabled && $publicUploadStatus === 'yes') {
|
||||
$publicUploadEnabled = true;
|
||||
}
|
||||
$publicUploadEnabled = ($publicUploadStatus === 'yes') ? true : false;
|
||||
|
||||
|
||||
// only change permissions for public shares if public upload is enabled
|
||||
// and we want to set permissions to 1 (read only) or 7 (allow upload)
|
||||
@@ -363,9 +357,8 @@ class Api {
|
||||
private static function updatePublicUpload($share, $params) {
|
||||
|
||||
$publicUploadEnabled = \OC_Appconfig::getValue('core', 'shareapi_allow_public_upload', 'yes');
|
||||
$encryptionEnabled = \OC_App::isEnabled('files_encryption');
|
||||
if($encryptionEnabled || $publicUploadEnabled !== 'yes') {
|
||||
return new \OC_OCS_Result(null, 404, "public upload disabled by the administrator");
|
||||
if($publicUploadEnabled !== 'yes') {
|
||||
return new \OC_OCS_Result(null, 403, "public upload disabled by the administrator");
|
||||
}
|
||||
|
||||
if ($share['item_type'] !== 'folder' ||
|
||||
|
||||
@@ -92,12 +92,11 @@ class Shared_Cache extends Cache {
|
||||
} else {
|
||||
$query = \OC_DB::prepare(
|
||||
'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`,'
|
||||
.' `size`, `mtime`, `encrypted`'
|
||||
.' `size`, `mtime`, `encrypted`, `unencrypted_size`'
|
||||
.' FROM `*PREFIX*filecache` WHERE `fileid` = ?');
|
||||
$result = $query->execute(array($file));
|
||||
$data = $result->fetchRow();
|
||||
$data['fileid'] = (int)$data['fileid'];
|
||||
$data['size'] = (int)$data['size'];
|
||||
$data['mtime'] = (int)$data['mtime'];
|
||||
$data['storage_mtime'] = (int)$data['storage_mtime'];
|
||||
$data['encrypted'] = (bool)$data['encrypted'];
|
||||
@@ -106,6 +105,12 @@ class Shared_Cache extends Cache {
|
||||
if ($data['storage_mtime'] === 0) {
|
||||
$data['storage_mtime'] = $data['mtime'];
|
||||
}
|
||||
if ($data['encrypted'] or ($data['unencrypted_size'] > 0 and $data['mimetype'] === 'httpd/unix-directory')) {
|
||||
$data['encrypted_size'] = (int)$data['size'];
|
||||
$data['size'] = (int)$data['unencrypted_size'];
|
||||
} else {
|
||||
$data['size'] = (int)$data['size'];
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
return false;
|
||||
@@ -123,11 +128,18 @@ class Shared_Cache extends Cache {
|
||||
foreach ($files as &$file) {
|
||||
$file['mimetype'] = $this->getMimetype($file['mimetype']);
|
||||
$file['mimepart'] = $this->getMimetype($file['mimepart']);
|
||||
$file['usersPath'] = 'files/Shared/' . ltrim($file['path'], '/');
|
||||
}
|
||||
return $files;
|
||||
} else {
|
||||
if ($cache = $this->getSourceCache($folder)) {
|
||||
return $cache->getFolderContents($this->files[$folder]);
|
||||
$cache = $this->getSourceCache($folder);
|
||||
if ($cache) {
|
||||
$sourceFolderContent = $cache->getFolderContents($this->files[$folder]);
|
||||
foreach ($sourceFolderContent as $key => $c) {
|
||||
$sourceFolderContent[$key]['usersPath'] = 'files/Shared/' . $folder . '/' . $c['name'];
|
||||
}
|
||||
|
||||
return $sourceFolderContent;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -248,19 +260,40 @@ class Shared_Cache extends Cache {
|
||||
* @return array
|
||||
*/
|
||||
public function searchByMime($mimetype) {
|
||||
|
||||
if (strpos($mimetype, '/')) {
|
||||
$where = '`mimetype` = ? AND ';
|
||||
} else {
|
||||
$where = '`mimepart` = ? AND ';
|
||||
$mimepart = null;
|
||||
if (strpos($mimetype, '/') === false) {
|
||||
$mimepart = $mimetype;
|
||||
$mimetype = null;
|
||||
}
|
||||
|
||||
$value = $this->getMimetypeId($mimetype);
|
||||
|
||||
return $this->searchWithWhere($where, $value);
|
||||
// note: searchWithWhere is currently broken as it doesn't
|
||||
// recurse into subdirs nor returns the correct
|
||||
// file paths, so using getFolderContents() for now
|
||||
|
||||
$result = array();
|
||||
$exploreDirs = array('');
|
||||
while (count($exploreDirs) > 0) {
|
||||
$dir = array_pop($exploreDirs);
|
||||
$files = $this->getFolderContents($dir);
|
||||
// no results?
|
||||
if (!$files) {
|
||||
continue;
|
||||
}
|
||||
foreach ($files as $file) {
|
||||
if ($file['mimetype'] === 'httpd/unix-directory') {
|
||||
$exploreDirs[] = ltrim($dir . '/' . $file['name'], '/');
|
||||
}
|
||||
else if (($mimepart && $file['mimepart'] === $mimepart) || ($mimetype && $file['mimetype'] === $mimetype)) {
|
||||
// usersPath not reliable
|
||||
//$file['path'] = $file['usersPath'];
|
||||
$file['path'] = ltrim($dir . '/' . $file['name'], '/');
|
||||
$result[] = $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The maximum number of placeholders that can be used in an SQL query.
|
||||
* Value MUST be <= 1000 for oracle:
|
||||
@@ -268,7 +301,7 @@ class Shared_Cache extends Cache {
|
||||
* FIXME we should get this from doctrine as other DBs allow a lot more placeholders
|
||||
*/
|
||||
const MAX_SQL_CHUNK_SIZE = 1000;
|
||||
|
||||
|
||||
/**
|
||||
* search for files with a custom where clause and value
|
||||
* the $wherevalue will be array_merge()d with the file id chunks
|
||||
@@ -282,16 +315,16 @@ class Shared_Cache extends Cache {
|
||||
$ids = $this->getAll();
|
||||
|
||||
$files = array();
|
||||
|
||||
|
||||
// divide into chunks
|
||||
$chunks = array_chunk($ids, $chunksize);
|
||||
|
||||
|
||||
foreach ($chunks as $chunk) {
|
||||
$placeholders = join(',', array_fill(0, count($chunk), '?'));
|
||||
$sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`,
|
||||
`encrypted`, `unencrypted_size`, `etag`
|
||||
FROM `*PREFIX*filecache` WHERE ' . $sqlwhere . ' `fileid` IN (' . $placeholders . ')';
|
||||
|
||||
|
||||
$stmt = \OC_DB::prepare($sql);
|
||||
|
||||
$result = $stmt->execute(array_merge(array($wherevalue), $chunk));
|
||||
@@ -302,6 +335,12 @@ class Shared_Cache extends Cache {
|
||||
}
|
||||
$row['mimetype'] = $this->getMimetype($row['mimetype']);
|
||||
$row['mimepart'] = $this->getMimetype($row['mimepart']);
|
||||
if ($row['encrypted'] or ($row['unencrypted_size'] > 0 and $row['mimetype'] === 'httpd/unix-directory')) {
|
||||
$row['encrypted_size'] = $row['size'];
|
||||
$row['size'] = $row['unencrypted_size'];
|
||||
} else {
|
||||
$row['size'] = $row['size'];
|
||||
}
|
||||
$files[] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,19 @@ class Shared_Permissions extends Permissions {
|
||||
}
|
||||
}
|
||||
|
||||
private function getFile($fileId, $user) {
|
||||
if ($fileId == -1) {
|
||||
return \OCP\PERMISSION_READ;
|
||||
}
|
||||
$source = \OCP\Share::getItemSharedWithBySource('file', $fileId, \OC_Share_Backend_File::FORMAT_SHARED_STORAGE,
|
||||
null, false);
|
||||
if ($source) {
|
||||
return $source['permissions'];
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set the permissions of a file
|
||||
*
|
||||
@@ -82,7 +95,7 @@ class Shared_Permissions extends Permissions {
|
||||
if ($parentId === -1) {
|
||||
return \OCP\Share::getItemsSharedWith('file', \OC_Share_Backend_File::FORMAT_PERMISSIONS);
|
||||
}
|
||||
$permissions = $this->get($parentId, $user);
|
||||
$permissions = $this->getFile($parentId, $user);
|
||||
$query = \OC_DB::prepare('SELECT `fileid` FROM `*PREFIX*filecache` WHERE `parent` = ?');
|
||||
$result = $query->execute(array($parentId));
|
||||
$filePermissions = array();
|
||||
|
||||
@@ -91,10 +91,17 @@ class OC_Share_Backend_File implements OCP\Share_Backend_File_Dependent {
|
||||
$file['name'] = basename($item['file_target']);
|
||||
$file['mimetype'] = $item['mimetype'];
|
||||
$file['mimepart'] = $item['mimepart'];
|
||||
$file['size'] = $item['size'];
|
||||
$file['mtime'] = $item['mtime'];
|
||||
$file['encrypted'] = $item['encrypted'];
|
||||
$file['etag'] = $item['etag'];
|
||||
$storage = \OC\Files\Filesystem::getStorage('/');
|
||||
$cache = $storage->getCache();
|
||||
if ($item['encrypted'] or ($item['unencrypted_size'] > 0 and $cache->getMimetype($item['mimetype']) === 'httpd/unix-directory')) {
|
||||
$file['size'] = $item['unencrypted_size'];
|
||||
$file['encrypted_size'] = $item['size'];
|
||||
} else {
|
||||
$file['size'] = $item['size'];
|
||||
}
|
||||
$files[] = $file;
|
||||
}
|
||||
return $files;
|
||||
@@ -172,7 +179,7 @@ class OC_Share_Backend_File implements OCP\Share_Backend_File_Dependent {
|
||||
$source['fileOwner'] = $fileOwner;
|
||||
return $source;
|
||||
}
|
||||
\OCP\Util::writeLog('files_sharing', 'File source not found for: '.$target, \OCP\Util::ERROR);
|
||||
\OCP\Util::writeLog('files_sharing', 'File source not found for: '.$target, \OCP\Util::DEBUG);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -279,43 +279,26 @@ class Shared extends \OC\Files\Storage\Common {
|
||||
if ($this->isDeletable($path)) {
|
||||
list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
|
||||
return $storage->unlink($internalPath);
|
||||
} else if (dirname($path) == '/' || dirname($path) == '.') {
|
||||
// Unshare the file from the user if in the root of the Shared folder
|
||||
if ($this->is_dir($path)) {
|
||||
$itemType = 'folder';
|
||||
} else {
|
||||
$itemType = 'file';
|
||||
}
|
||||
return \OCP\Share::unshareFromSelf($itemType, $path);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function rename($path1, $path2) {
|
||||
// Check for partial files
|
||||
if (pathinfo($path1, PATHINFO_EXTENSION) === 'part') {
|
||||
if ($oldSource = $this->getSourcePath($path1)) {
|
||||
// Renaming/moving is only allowed within shared folders
|
||||
$pos1 = strpos($path1, '/', 1);
|
||||
$pos2 = strpos($path2, '/', 1);
|
||||
if ($pos1 !== false && $pos2 !== false && ($oldSource = $this->getSourcePath($path1))) {
|
||||
$newSource = $this->getSourcePath(dirname($path2)) . '/' . basename($path2);
|
||||
// Within the same folder, we only need UPDATE permissions
|
||||
if (dirname($path1) == dirname($path2) and $this->isUpdatable($path1)) {
|
||||
list($storage, $oldInternalPath) = \OC\Files\Filesystem::resolvePath($oldSource);
|
||||
$newInternalPath = substr($oldInternalPath, 0, -5);
|
||||
list(, $newInternalPath) = \OC\Files\Filesystem::resolvePath($newSource);
|
||||
return $storage->rename($oldInternalPath, $newInternalPath);
|
||||
}
|
||||
} else {
|
||||
// Renaming/moving is only allowed within shared folders
|
||||
$pos1 = strpos($path1, '/', 1);
|
||||
$pos2 = strpos($path2, '/', 1);
|
||||
if ($pos1 !== false && $pos2 !== false && ($oldSource = $this->getSourcePath($path1))) {
|
||||
$newSource = $this->getSourcePath(dirname($path2)) . '/' . basename($path2);
|
||||
// Within the same folder, we only need UPDATE permissions
|
||||
if (dirname($path1) == dirname($path2) and $this->isUpdatable($path1)) {
|
||||
list($storage, $oldInternalPath) = \OC\Files\Filesystem::resolvePath($oldSource);
|
||||
list(, $newInternalPath) = \OC\Files\Filesystem::resolvePath($newSource);
|
||||
return $storage->rename($oldInternalPath, $newInternalPath);
|
||||
// otherwise DELETE and CREATE permissions required
|
||||
} elseif ($this->isDeletable($path1) && $this->isCreatable(dirname($path2))) {
|
||||
$rootView = new \OC\Files\View('');
|
||||
return $rootView->rename($oldSource, $newSource);
|
||||
}
|
||||
// otherwise DELETE and CREATE permissions required
|
||||
} elseif ($this->isDeletable($path1) && $this->isCreatable(dirname($path2))) {
|
||||
$rootView = new \OC\Files\View('');
|
||||
return $rootView->rename($oldSource, $newSource);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -112,8 +112,12 @@ class Shared_Updater {
|
||||
*/
|
||||
static public function shareHook($params) {
|
||||
if ($params['itemType'] === 'file' || $params['itemType'] === 'folder') {
|
||||
$uidOwner = \OCP\User::getUser();
|
||||
$users = \OCP\Share::getUsersItemShared($params['itemType'], $params['fileSource'], $uidOwner, true);
|
||||
if (isset($params['uidOwner'])) {
|
||||
$uidOwner = $params['uidOwner'];
|
||||
} else {
|
||||
$uidOwner = \OCP\User::getUser();
|
||||
}
|
||||
$users = \OCP\Share::getUsersItemShared($params['itemType'], $params['fileSource'], $uidOwner, true, false);
|
||||
if (!empty($users)) {
|
||||
while (!empty($users)) {
|
||||
$reshareUsers = array();
|
||||
|
||||
@@ -35,7 +35,7 @@ function determineIcon($file, $sharingRoot, $sharingToken) {
|
||||
|
||||
if (isset($_GET['t'])) {
|
||||
$token = $_GET['t'];
|
||||
$linkItem = OCP\Share::getShareByToken($token);
|
||||
$linkItem = OCP\Share::getShareByToken($token, false);
|
||||
if (is_array($linkItem) && isset($linkItem['uid_owner'])) {
|
||||
// seems to be a valid share
|
||||
$type = $linkItem['item_type'];
|
||||
@@ -43,10 +43,10 @@ if (isset($_GET['t'])) {
|
||||
$shareOwner = $linkItem['uid_owner'];
|
||||
$path = null;
|
||||
$rootLinkItem = OCP\Share::resolveReShare($linkItem);
|
||||
$fileOwner = $rootLinkItem['uid_owner'];
|
||||
if (isset($fileOwner)) {
|
||||
if (isset($rootLinkItem['uid_owner'])) {
|
||||
OCP\JSON::checkUserExists($rootLinkItem['uid_owner']);
|
||||
OC_Util::tearDownFS();
|
||||
OC_Util::setupFS($fileOwner);
|
||||
OC_Util::setupFS($rootLinkItem['uid_owner']);
|
||||
$path = \OC\Files\Filesystem::getPath($linkItem['file_source']);
|
||||
}
|
||||
}
|
||||
@@ -136,6 +136,7 @@ if (isset($path)) {
|
||||
} else {
|
||||
OCP\Util::addScript('files', 'file-upload');
|
||||
OCP\Util::addStyle('files_sharing', 'public');
|
||||
OCP\Util::addStyle('files_sharing', 'mobile');
|
||||
OCP\Util::addScript('files_sharing', 'public');
|
||||
OCP\Util::addScript('files', 'fileactions');
|
||||
OCP\Util::addScript('files', 'jquery.iframe-transport');
|
||||
@@ -158,7 +159,6 @@ if (isset($path)) {
|
||||
if ($linkItem['item_type'] !== 'folder') {
|
||||
$allowPublicUploadEnabled = false;
|
||||
}
|
||||
$tmpl->assign('allowPublicUploadEnabled', $allowPublicUploadEnabled);
|
||||
$tmpl->assign('uploadMaxFilesize', $maxUploadFilesize);
|
||||
$tmpl->assign('uploadMaxHumanFilesize', OCP\Util::humanFileSize($maxUploadFilesize));
|
||||
|
||||
@@ -188,8 +188,8 @@ if (isset($path)) {
|
||||
} else {
|
||||
$i['extension'] = '';
|
||||
}
|
||||
$i['isPreviewAvailable'] = \OC::$server->getPreviewManager()->isMimeSupported($i['mimetype']);
|
||||
}
|
||||
$i['isPreviewAvailable'] = \OC::$server->getPreviewManager()->isMimeSupported($i['mimetype']);
|
||||
$i['directory'] = $getPath;
|
||||
$i['permissions'] = OCP\PERMISSION_READ;
|
||||
$i['icon'] = determineIcon($i, $basePath, $token);
|
||||
@@ -224,7 +224,8 @@ if (isset($path)) {
|
||||
$folder->assign('fileList', $list->fetchPage());
|
||||
$folder->assign('breadcrumb', $breadcrumbNav->fetchPage());
|
||||
$folder->assign('dir', $getPath);
|
||||
$folder->assign('isCreatable', false);
|
||||
$folder->assign('isCreatable', $allowPublicUploadEnabled);
|
||||
$folder->assign('dirToken', $linkItem['token']);
|
||||
$folder->assign('permissions', OCP\PERMISSION_READ);
|
||||
$folder->assign('isPublic',true);
|
||||
$folder->assign('publicUploadEnabled', 'no');
|
||||
|
||||
@@ -8,8 +8,11 @@
|
||||
<?php endif; ?>
|
||||
<p class="infield">
|
||||
<label for="password" class="infield"><?php p($l->t('Password')); ?></label>
|
||||
<input type="password" name="password" id="password" placeholder="" value="" autofocus />
|
||||
<input type="submit" value="" class="svg" />
|
||||
<input type="password" name="password" id="password"
|
||||
placeholder="" value=""
|
||||
autocomplete="off" autocapitalize="off" autocorrect="off"
|
||||
autofocus />
|
||||
<input type="submit" value="" class="svg icon icon-confirm" />
|
||||
</p>
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
@@ -9,64 +9,14 @@
|
||||
<input type="hidden" name="sharingToken" value="<?php p($_['sharingToken']) ?>" id="sharingToken">
|
||||
<input type="hidden" name="filename" value="<?php p($_['filename']) ?>" id="filename">
|
||||
<input type="hidden" name="mimetype" value="<?php p($_['mimetype']) ?>" id="mimetype">
|
||||
<header><div id="header">
|
||||
<header><div id="header" class="icon icon-noise <?php p((isset($_['folder']) ? 'share-folder' : 'share-file')) ?>">
|
||||
<a href="<?php print_unescaped(link_to('', 'index.php')); ?>" title="" id="owncloud"><img class="svg"
|
||||
src="<?php print_unescaped(image_path('', 'logo-wide.svg')); ?>" alt="<?php p($theme->getName()); ?>" /></a>
|
||||
<div id="logo-claim" style="display:none;"><?php p($theme->getLogoClaim()); ?></div>
|
||||
<div class="header-right">
|
||||
<?php if (isset($_['folder'])): ?>
|
||||
<span id="details"><?php p($l->t('%s shared the folder %s with you',
|
||||
array($_['displayName'], $_['filename']))) ?></span>
|
||||
<?php else: ?>
|
||||
<span id="details"><?php p($l->t('%s shared the file %s with you',
|
||||
array($_['displayName'], $_['filename']))) ?></span>
|
||||
<?php endif; ?>
|
||||
|
||||
|
||||
<?php if (!isset($_['folder']) || $_['allowZipDownload']): ?>
|
||||
<a href="<?php p($_['downloadURL']); ?>" class="button" id="download"><img
|
||||
class="svg" alt="Download" src="<?php print_unescaped(OCP\image_path("core", "actions/download.svg")); ?>"
|
||||
/><span><?php p($l->t('Download'))?></span></a>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($_['allowPublicUploadEnabled']):?>
|
||||
|
||||
|
||||
<input type="hidden" id="publicUploadRequestToken" name="requesttoken" value="<?php p($_['requesttoken']) ?>" />
|
||||
<input type="hidden" id="dirToken" name="dirToken" value="<?php p($_['dirToken']) ?>" />
|
||||
<input type="hidden" id="uploadMaxFilesize" name="uploadMaxFilesize" value="<?php p($_['uploadMaxFilesize']) ?>" />
|
||||
<input type="hidden" id="uploadMaxHumanFilesize" name="uploadMaxHumanFilesize" value="<?php p($_['uploadMaxHumanFilesize']) ?>" />
|
||||
<input type="hidden" id="directory_path" name="directory_path" value="<?php p($_['directory_path']) ?>" />
|
||||
<?php if($_['uploadMaxFilesize'] >= 0):?>
|
||||
<input type="hidden" name="MAX_FILE_SIZE" id="max_upload"
|
||||
value="<?php p($_['uploadMaxFilesize']) ?>">
|
||||
<?php endif;?>
|
||||
|
||||
|
||||
<div id="data-upload-form" class="button" title="<?php p($l->t('Upload') . ' max. '.$_['uploadMaxHumanFilesize']) ?>">
|
||||
<input id="file_upload_start" type="file" name="files[]" data-url="<?php print_unescaped(OCP\Util::linkTo('files', 'ajax/upload.php')); ?>" multiple>
|
||||
<a href="#" id="publicUploadButtonMock" class="svg">
|
||||
<span><?php p($l->t('Upload'))?></span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<span id="details"><?php p($l->t('shared by %s', array($_['displayName']))) ?></span>
|
||||
</div>
|
||||
|
||||
<div id="additional_controls" style="display:none">
|
||||
<div id="uploadprogresswrapper">
|
||||
<div id="uploadprogressbar"></div>
|
||||
<input id="cancel_upload_button" type="button" class="stop" style="display:none"
|
||||
value="<?php p($l->t('Cancel upload'));?>"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<?php endif; ?>
|
||||
|
||||
</div>
|
||||
</div></header>
|
||||
</div></header>
|
||||
<div id="content">
|
||||
<div id="preview">
|
||||
<?php if (isset($_['folder'])): ?>
|
||||
@@ -82,25 +32,28 @@
|
||||
<source src="<?php p($_['downloadURL']); ?>" type="<?php p($_['mimetype']); ?>" />
|
||||
</video>
|
||||
</div>
|
||||
<?php elseif (\OC\Preview::isMimeSupported($_['mimetype'])): ?>
|
||||
<div id="imgframe">
|
||||
<img src="<?php p(OCP\Util::linkToRoute( 'core_ajax_public_preview', array('x' => 500, 'y' => 500, 'file' => urlencode($_['directory_path']), 't' => $_['dirToken']))); ?>" class="publicpreview"/>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<ul id="noPreview">
|
||||
<li class="error">
|
||||
<?php p($l->t('No preview available for').' '.$_['filename']); ?><br />
|
||||
<a href="<?php p($_['downloadURL']); ?>" id="download"><img class="svg" alt="Download"
|
||||
src="<?php print_unescaped(OCP\image_path("core", "actions/download.svg")); ?>"
|
||||
/><?php p($l->t('Download'))?></a>
|
||||
</li>
|
||||
</ul>
|
||||
<div id="imgframe">
|
||||
<?php $size = \OC\Preview::isMimeSupported($_['mimetype']) ? 500 : 128 ?>
|
||||
<img src="<?php p(OCP\Util::linkToRoute( 'core_ajax_public_preview', array('x' => $size, 'y' => $size, 'file' => urlencode($_['directory_path']), 't' => $_['dirToken']))); ?>" class="publicpreview"/>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="directLink"><label for="directLink"><?php p($l->t('Direct link')) ?></label><input id="directLink" type="text" readonly value="<?php p($_['downloadURL']); ?>"></input></div>
|
||||
<div class="directDownload">
|
||||
<a href="<?php p($_['downloadURL']); ?>" id="download" class="button">
|
||||
<img class="svg" alt="" src="<?php print_unescaped(OCP\image_path("core", "actions/download.svg")); ?>"/>
|
||||
<?php p($l->t('Download %s', array($_['filename'])))?>
|
||||
</a>
|
||||
</div>
|
||||
<div class="directLink">
|
||||
<label for="directLink"><?php p($l->t('Direct link')) ?></label>
|
||||
<input id="directLink" type="text" readonly value="<?php p($_['downloadURL']); ?>">
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<footer>
|
||||
<p class="info">
|
||||
<?php print_unescaped($theme->getLongFooter()); ?>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
<footer>
|
||||
<p class="info">
|
||||
<?php print_unescaped($theme->getLongFooter()); ?>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
@@ -33,13 +33,16 @@ class Test_Files_Sharing_Api extends Test_Files_Sharing_Base {
|
||||
parent::setUp();
|
||||
|
||||
$this->folder = '/folder_share_api_test';
|
||||
$this->subfolder = '/subfolder_share_api_test';
|
||||
|
||||
$this->filename = 'share-api-test.txt';
|
||||
|
||||
// save file with content
|
||||
$this->view->file_put_contents($this->filename, $this->data);
|
||||
$this->view->mkdir($this->folder);
|
||||
$this->view->mkdir($this->folder . '/' . $this->subfolder);
|
||||
$this->view->file_put_contents($this->folder.'/'.$this->filename, $this->data);
|
||||
$this->view->file_put_contents($this->folder.'/' . $this->subfolder . '/' .$this->filename, $this->data);
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
@@ -286,6 +289,71 @@ class Test_Files_Sharing_Api extends Test_Files_Sharing_Base {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief share a folder, than reshare a file within the shared folder and check if we construct the correct path
|
||||
* @medium
|
||||
*/
|
||||
function testGetShareFromFolderReshares() {
|
||||
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
|
||||
|
||||
$fileInfo1 = $this->view->getFileInfo($this->folder);
|
||||
$fileInfo2 = $this->view->getFileInfo($this->folder.'/'.$this->filename);
|
||||
$fileInfo3 = $this->view->getFileInfo($this->folder.'/' . $this->subfolder . '/' .$this->filename);
|
||||
|
||||
// share root folder to user2
|
||||
$result = \OCP\Share::shareItem('folder', $fileInfo1['fileid'], \OCP\Share::SHARE_TYPE_USER,
|
||||
\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2, 31);
|
||||
|
||||
// share was successful?
|
||||
$this->assertTrue($result);
|
||||
|
||||
// login as user2
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
|
||||
|
||||
// share file in root folder
|
||||
$result = \OCP\Share::shareItem('file', $fileInfo2['fileid'], \OCP\Share::SHARE_TYPE_LINK, null, 1);
|
||||
// share was successful?
|
||||
$this->assertTrue(is_string($result));
|
||||
|
||||
// share file in subfolder
|
||||
$result = \OCP\Share::shareItem('file', $fileInfo3['fileid'], \OCP\Share::SHARE_TYPE_LINK, null, 1);
|
||||
// share was successful?
|
||||
$this->assertTrue(is_string($result));
|
||||
|
||||
$testValues=array(
|
||||
array('query' => 'Shared/' . $this->folder,
|
||||
'expectedResult' => '/Shared' . $this->folder . '/' . $this->filename),
|
||||
array('query' => 'Shared/' . $this->folder . $this->subfolder,
|
||||
'expectedResult' => '/Shared' . $this->folder . $this->subfolder . '/' . $this->filename),
|
||||
);
|
||||
foreach ($testValues as $value) {
|
||||
|
||||
$_GET['path'] = $value['query'];
|
||||
$_GET['subfiles'] = 'true';
|
||||
|
||||
$result = Share\Api::getAllShares(array());
|
||||
|
||||
$this->assertTrue($result->succeeded());
|
||||
|
||||
// test should return one share within $this->folder
|
||||
$data = $result->getData();
|
||||
|
||||
$this->assertEquals($value['expectedResult'], $data[0]['path']);
|
||||
}
|
||||
|
||||
// cleanup
|
||||
|
||||
\OCP\Share::unshare('file', $fileInfo2['fileid'], \OCP\Share::SHARE_TYPE_LINK, null);
|
||||
\OCP\Share::unshare('file', $fileInfo3['fileid'], \OCP\Share::SHARE_TYPE_LINK, null);
|
||||
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
|
||||
|
||||
\OCP\Share::unshare('folder', $fileInfo1['fileid'], \OCP\Share::SHARE_TYPE_USER,
|
||||
\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @medium
|
||||
*/
|
||||
|
||||
@@ -43,6 +43,7 @@ abstract class Test_Files_Sharing_Base extends \PHPUnit_Framework_TestCase {
|
||||
*/
|
||||
public $view;
|
||||
public $folder;
|
||||
public $subfolder;
|
||||
|
||||
public static function setUpBeforeClass() {
|
||||
// reset backend
|
||||
@@ -132,8 +133,8 @@ abstract class Test_Files_Sharing_Base extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
$share = Null;
|
||||
|
||||
if ($result && $result->numRows() > 0) {
|
||||
$share = $result->fetchRow();
|
||||
if ($result) {
|
||||
$share = $result->fetchRow();
|
||||
}
|
||||
|
||||
return $share;
|
||||
|
||||
@@ -0,0 +1,249 @@
|
||||
<?php
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Vincent Petry, Bjoern Schiessle
|
||||
* @copyright 2014 Vincent Petry <pvince81@owncloud.com>
|
||||
* 2014 Bjoern Schiessle <schiessle@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/>.
|
||||
*
|
||||
*/
|
||||
require_once __DIR__ . '/base.php';
|
||||
|
||||
class Test_Files_Sharing_Cache extends Test_Files_Sharing_Base {
|
||||
|
||||
/**
|
||||
* @var OC_FilesystemView
|
||||
*/
|
||||
public $user2View;
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
|
||||
|
||||
$this->user2View = new \OC\Files\View('/'. self::TEST_FILES_SHARING_API_USER2 . '/files');
|
||||
|
||||
// prepare user1's dir structure
|
||||
$this->view->mkdir('container');
|
||||
$this->view->mkdir('container/shareddir');
|
||||
$this->view->mkdir('container/shareddir/subdir');
|
||||
$this->view->mkdir('container/shareddir/emptydir');
|
||||
|
||||
$textData = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
$this->view->file_put_contents('container/not shared.txt', $textData);
|
||||
$this->view->file_put_contents('container/shared single file.txt', $textData);
|
||||
$this->view->file_put_contents('container/shareddir/bar.txt', $textData);
|
||||
$this->view->file_put_contents('container/shareddir/subdir/another.txt', $textData);
|
||||
$this->view->file_put_contents('container/shareddir/subdir/another too.txt', $textData);
|
||||
$this->view->file_put_contents('container/shareddir/subdir/not a text file.xml', '<xml></xml>');
|
||||
|
||||
list($this->ownerStorage, $internalPath) = $this->view->resolvePath('');
|
||||
$this->ownerCache = $this->ownerStorage->getCache();
|
||||
$this->ownerStorage->getScanner()->scan('');
|
||||
|
||||
// share "shareddir" with user2
|
||||
$fileinfo = $this->view->getFileInfo('container/shareddir');
|
||||
\OCP\Share::shareItem('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
|
||||
self::TEST_FILES_SHARING_API_USER2, 31);
|
||||
|
||||
$fileinfo = $this->view->getFileInfo('container/shared single file.txt');
|
||||
\OCP\Share::shareItem('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
|
||||
self::TEST_FILES_SHARING_API_USER2, 31);
|
||||
|
||||
// login as user2
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
|
||||
|
||||
// retrieve the shared storage
|
||||
$secondView = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER2);
|
||||
list($this->sharedStorage, $internalPath) = $secondView->resolvePath('files/Shared/shareddir');
|
||||
$this->sharedCache = $this->sharedStorage->getCache();
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
$this->sharedCache->clear();
|
||||
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
|
||||
|
||||
$fileinfo = $this->view->getFileInfo('container/shareddir');
|
||||
\OCP\Share::unshare('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
|
||||
self::TEST_FILES_SHARING_API_USER2);
|
||||
|
||||
$fileinfo = $this->view->getFileInfo('container/shared single file.txt');
|
||||
\OCP\Share::unshare('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
|
||||
self::TEST_FILES_SHARING_API_USER2);
|
||||
|
||||
$this->view->deleteAll('container');
|
||||
|
||||
$this->ownerCache->clear();
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test searching by mime type
|
||||
*/
|
||||
function testSearchByMime() {
|
||||
$results = $this->sharedStorage->getCache()->searchByMime('text');
|
||||
$check = array(
|
||||
array(
|
||||
'name' => 'shared single file.txt',
|
||||
'path' => 'shared single file.txt'
|
||||
),
|
||||
array(
|
||||
'name' => 'bar.txt',
|
||||
'path' => 'shareddir/bar.txt'
|
||||
),
|
||||
array(
|
||||
'name' => 'another too.txt',
|
||||
'path' => 'shareddir/subdir/another too.txt'
|
||||
),
|
||||
array(
|
||||
'name' => 'another.txt',
|
||||
'path' => 'shareddir/subdir/another.txt'
|
||||
),
|
||||
);
|
||||
$this->verifyFiles($check, $results);
|
||||
|
||||
$results2 = $this->sharedStorage->getCache()->searchByMime('text/plain');
|
||||
|
||||
$this->verifyFiles($check, $results);
|
||||
}
|
||||
|
||||
function testGetFolderContentsInRoot() {
|
||||
$results = $this->user2View->getDirectoryContent('/Shared/');
|
||||
|
||||
$this->verifyFiles(
|
||||
array(
|
||||
array(
|
||||
'name' => 'shareddir',
|
||||
'path' => '/shareddir',
|
||||
'mimetype' => 'httpd/unix-directory',
|
||||
'usersPath' => 'files/Shared/shareddir'
|
||||
),
|
||||
array(
|
||||
'name' => 'shared single file.txt',
|
||||
'path' => '/shared single file.txt',
|
||||
'mimetype' => 'text/plain',
|
||||
'usersPath' => 'files/Shared/shared single file.txt'
|
||||
),
|
||||
),
|
||||
$results
|
||||
);
|
||||
}
|
||||
|
||||
function testGetFolderContentsInSubdir() {
|
||||
$results = $this->user2View->getDirectoryContent('/Shared/shareddir');
|
||||
|
||||
$this->verifyFiles(
|
||||
array(
|
||||
array(
|
||||
'name' => 'bar.txt',
|
||||
'path' => 'files/container/shareddir/bar.txt',
|
||||
'mimetype' => 'text/plain',
|
||||
'usersPath' => 'files/Shared/shareddir/bar.txt'
|
||||
),
|
||||
array(
|
||||
'name' => 'emptydir',
|
||||
'path' => 'files/container/shareddir/emptydir',
|
||||
'mimetype' => 'httpd/unix-directory',
|
||||
'usersPath' => 'files/Shared/shareddir/emptydir'
|
||||
),
|
||||
array(
|
||||
'name' => 'subdir',
|
||||
'path' => 'files/container/shareddir/subdir',
|
||||
'mimetype' => 'httpd/unix-directory',
|
||||
'usersPath' => 'files/Shared/shareddir/subdir'
|
||||
),
|
||||
),
|
||||
$results
|
||||
);
|
||||
}
|
||||
|
||||
function testGetFolderContentsWhenSubSubdirShared() {
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
|
||||
|
||||
$fileinfo = $this->view->getFileInfo('container/shareddir/subdir');
|
||||
\OCP\Share::shareItem('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
|
||||
self::TEST_FILES_SHARING_API_USER3, 31);
|
||||
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER3);
|
||||
|
||||
$thirdView = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER3 . '/files');
|
||||
$results = $thirdView->getDirectoryContent('/Shared/subdir');
|
||||
|
||||
$this->verifyFiles(
|
||||
array(
|
||||
array(
|
||||
'name' => 'another too.txt',
|
||||
'path' => 'files/container/shareddir/subdir/another too.txt',
|
||||
'mimetype' => 'text/plain',
|
||||
'usersPath' => 'files/Shared/subdir/another too.txt'
|
||||
),
|
||||
array(
|
||||
'name' => 'another.txt',
|
||||
'path' => 'files/container/shareddir/subdir/another.txt',
|
||||
'mimetype' => 'text/plain',
|
||||
'usersPath' => 'files/Shared/subdir/another.txt'
|
||||
),
|
||||
array(
|
||||
'name' => 'not a text file.xml',
|
||||
'path' => 'files/container/shareddir/subdir/not a text file.xml',
|
||||
'mimetype' => 'application/xml',
|
||||
'usersPath' => 'files/Shared/subdir/not a text file.xml'
|
||||
),
|
||||
),
|
||||
$results
|
||||
);
|
||||
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
|
||||
|
||||
\OCP\Share::unshare('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
|
||||
self::TEST_FILES_SHARING_API_USER3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if 'results' contains the expected 'examples' only.
|
||||
*
|
||||
* @param array $examples array of example files
|
||||
* @param array $results array of files
|
||||
*/
|
||||
private function verifyFiles($examples, $results) {
|
||||
$this->assertEquals(count($examples), count($results));
|
||||
|
||||
foreach ($examples as $example) {
|
||||
foreach ($results as $key => $result) {
|
||||
if ($result['name'] === $example['name']) {
|
||||
$this->verifyKeys($example, $result);
|
||||
unset($results[$key]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->assertTrue(empty($results));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief verify if each value from the result matches the expected result
|
||||
* @param array $example array with the expected results
|
||||
* @param array $result array with the results
|
||||
*/
|
||||
private function verifyKeys($example, $result) {
|
||||
foreach ($example as $key => $value) {
|
||||
$this->assertEquals($value, $result[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Vincent Petry
|
||||
* @copyright 2013 Vincent Petry <pvince81@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/>.
|
||||
*
|
||||
*/
|
||||
require_once __DIR__ . '/base.php';
|
||||
|
||||
class Test_Files_Sharing_Permissions extends Test_Files_Sharing_Base {
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
|
||||
|
||||
// prepare user1's dir structure
|
||||
$textData = "dummy file data\n";
|
||||
$this->view->mkdir('container');
|
||||
$this->view->mkdir('container/shareddir');
|
||||
$this->view->mkdir('container/shareddir/subdir');
|
||||
$this->view->mkdir('container/shareddirrestricted');
|
||||
$this->view->mkdir('container/shareddirrestricted/subdir');
|
||||
$this->view->file_put_contents('container/shareddir/textfile.txt', $textData);
|
||||
$this->view->file_put_contents('container/shareddirrestricted/textfile1.txt', $textData);
|
||||
|
||||
list($this->ownerStorage, $internalPath) = $this->view->resolvePath('');
|
||||
$this->ownerCache = $this->ownerStorage->getCache();
|
||||
$this->ownerStorage->getScanner()->scan('');
|
||||
|
||||
// share "shareddir" with user2
|
||||
$fileinfo = $this->view->getFileInfo('container/shareddir');
|
||||
\OCP\Share::shareItem('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
|
||||
self::TEST_FILES_SHARING_API_USER2, 31);
|
||||
$fileinfo2 = $this->view->getFileInfo('container/shareddirrestricted');
|
||||
\OCP\Share::shareItem('folder', $fileinfo2['fileid'], \OCP\Share::SHARE_TYPE_USER,
|
||||
self::TEST_FILES_SHARING_API_USER2, 7);
|
||||
|
||||
// login as user2
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
|
||||
|
||||
// retrieve the shared storage
|
||||
$this->secondView = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER2);
|
||||
list($this->sharedStorage, $internalPath) = $this->secondView->resolvePath('files/Shared/shareddir');
|
||||
$this->sharedCache = $this->sharedStorage->getCache();
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
$this->sharedCache->clear();
|
||||
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
|
||||
|
||||
$fileinfo = $this->view->getFileInfo('container/shareddir');
|
||||
\OCP\Share::unshare('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
|
||||
self::TEST_FILES_SHARING_API_USER2);
|
||||
$fileinfo2 = $this->view->getFileInfo('container/shareddirrestricted');
|
||||
\OCP\Share::unshare('folder', $fileinfo2['fileid'], \OCP\Share::SHARE_TYPE_USER,
|
||||
self::TEST_FILES_SHARING_API_USER2);
|
||||
|
||||
$this->view->deleteAll('container');
|
||||
|
||||
$this->ownerCache->clear();
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the permissions of shared directory are returned correctly
|
||||
*/
|
||||
function testGetPermissions() {
|
||||
$sharedDirPerms = $this->sharedStorage->getPermissions('shareddir');
|
||||
$this->assertEquals(31, $sharedDirPerms);
|
||||
$sharedDirPerms = $this->sharedStorage->getPermissions('shareddir/textfile.txt');
|
||||
$this->assertEquals(31, $sharedDirPerms);
|
||||
$sharedDirRestrictedPerms = $this->sharedStorage->getPermissions('shareddirrestricted');
|
||||
$this->assertEquals(7, $sharedDirRestrictedPerms);
|
||||
$sharedDirRestrictedPerms = $this->sharedStorage->getPermissions('shareddirrestricted/textfile.txt');
|
||||
$this->assertEquals(7, $sharedDirRestrictedPerms);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the permissions of shared directory are returned correctly
|
||||
*/
|
||||
function testGetDirectoryPermissions() {
|
||||
$contents = $this->secondView->getDirectoryContent('files/Shared/shareddir');
|
||||
$this->assertEquals('subdir', $contents[0]['name']);
|
||||
$this->assertEquals(31, $contents[0]['permissions']);
|
||||
$this->assertEquals('textfile.txt', $contents[1]['name']);
|
||||
$this->assertEquals(31, $contents[1]['permissions']);
|
||||
$contents = $this->secondView->getDirectoryContent('files/Shared/shareddirrestricted');
|
||||
$this->assertEquals('subdir', $contents[0]['name']);
|
||||
$this->assertEquals(7, $contents[0]['permissions']);
|
||||
$this->assertEquals('textfile1.txt', $contents[1]['name']);
|
||||
$this->assertEquals(7, $contents[1]['permissions']);
|
||||
}
|
||||
}
|
||||
@@ -4,14 +4,24 @@ OCP\JSON::checkLoggedIn();
|
||||
OCP\JSON::callCheck();
|
||||
|
||||
// "empty trash" command
|
||||
$deleteAll = false;
|
||||
if (isset($_POST['allfiles']) and $_POST['allfiles'] === 'true'){
|
||||
$user = \OCP\User::getUser();
|
||||
$list = OCA\Files_Trashbin\Helper::getTrashFiles('/');
|
||||
$deleteAll = true;
|
||||
$dirlisting = '0';
|
||||
$folder = isset($_POST['dir']) ? $_POST['dir'] : '/';
|
||||
if ($folder === '/' || $folder === '') {
|
||||
OCA\Files_Trashbin\Trashbin::deleteAll();
|
||||
$list = array();
|
||||
} else {
|
||||
$dirname = dirname($folder);
|
||||
if ( $dirname !== '/' && $dirname !== '.' ) {
|
||||
$dirlisting = '1';
|
||||
} else {
|
||||
$dirlisting = '0';
|
||||
}
|
||||
$list[] = $folder;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$deleteAll = false;
|
||||
$files = $_POST['files'];
|
||||
$dirlisting = $_POST['dirlisting'];
|
||||
$list = json_decode($files);
|
||||
@@ -19,19 +29,13 @@ else {
|
||||
$error = array();
|
||||
$success = array();
|
||||
|
||||
|
||||
$i = 0;
|
||||
foreach ($list as $file) {
|
||||
if ( $dirlisting === '0') {
|
||||
if ($deleteAll) {
|
||||
$filename = $file['name'];
|
||||
$timestamp = $file['timestamp'];
|
||||
}
|
||||
else {
|
||||
$delimiter = strrpos($file, '.d');
|
||||
$filename = substr($file, 0, $delimiter);
|
||||
$timestamp = substr($file, $delimiter+2);
|
||||
}
|
||||
$file = ltrim($file, '/');
|
||||
$delimiter = strrpos($file, '.d');
|
||||
$filename = substr($file, 0, $delimiter);
|
||||
$timestamp = substr($file, $delimiter+2);
|
||||
} else {
|
||||
$filename = $file;
|
||||
$timestamp = null;
|
||||
|
||||
@@ -34,7 +34,17 @@ try{
|
||||
if ($view->is_dir($file)) {
|
||||
$mimetype = 'httpd/unix-directory';
|
||||
} else {
|
||||
$mimetype = \OC_Helper::getFileNameMimeType(pathinfo($file, PATHINFO_FILENAME));
|
||||
$pathInfo = pathinfo($file);
|
||||
$fileName = $pathInfo['basename'];
|
||||
// if in root dir
|
||||
if ($pathInfo['dirname'] === '.') {
|
||||
// cut off the .d* suffix
|
||||
$i = strrpos($fileName, '.');
|
||||
if ($i !== false) {
|
||||
$fileName = substr($fileName, 0, $i);
|
||||
}
|
||||
}
|
||||
$mimetype = \OC_Helper::getFileNameMimeType($fileName);
|
||||
}
|
||||
$preview->setMimetype($mimetype);
|
||||
$preview->setMaxX($maxX);
|
||||
@@ -45,4 +55,4 @@ try{
|
||||
}catch(\Exception $e) {
|
||||
\OC_Response::setStatus(500);
|
||||
\OC_Log::write('core', $e->getmessage(), \OC_Log::DEBUG);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ $success = array();
|
||||
$i = 0;
|
||||
foreach ($list as $file) {
|
||||
if ( $dirlisting === '0') {
|
||||
$file = ltrim($file, '/');
|
||||
$delimiter = strrpos($file, '.d');
|
||||
$filename = substr($file, 0, $delimiter);
|
||||
$timestamp = substr($file, $delimiter+2);
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
<notnull>true</notnull>
|
||||
<length>512</length>
|
||||
</field>
|
||||
|
||||
|
||||
<field>
|
||||
<name>type</name>
|
||||
<type>text</type>
|
||||
@@ -52,15 +52,15 @@
|
||||
<notnull>true</notnull>
|
||||
<length>4</length>
|
||||
</field>
|
||||
|
||||
|
||||
<field>
|
||||
<name>mime</name>
|
||||
<type>text</type>
|
||||
<default></default>
|
||||
<notnull>true</notnull>
|
||||
<length>30</length>
|
||||
<length>255</length>
|
||||
</field>
|
||||
|
||||
|
||||
<index>
|
||||
<name>id_index</name>
|
||||
<field>
|
||||
@@ -68,7 +68,7 @@
|
||||
<sorting>ascending</sorting>
|
||||
</field>
|
||||
</index>
|
||||
|
||||
|
||||
<index>
|
||||
<name>timestamp_index</name>
|
||||
<field>
|
||||
@@ -76,7 +76,7 @@
|
||||
<sorting>ascending</sorting>
|
||||
</field>
|
||||
</index>
|
||||
|
||||
|
||||
<index>
|
||||
<name>user_index</name>
|
||||
<field>
|
||||
@@ -84,7 +84,7 @@
|
||||
<sorting>ascending</sorting>
|
||||
</field>
|
||||
</index>
|
||||
|
||||
|
||||
</declaration>
|
||||
|
||||
</table>
|
||||
@@ -110,7 +110,7 @@
|
||||
<notnull>true</notnull>
|
||||
<length>50</length>
|
||||
</field>
|
||||
|
||||
|
||||
</declaration>
|
||||
|
||||
</table>
|
||||
|
||||
@@ -1 +1 @@
|
||||
0.4
|
||||
0.5
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
#fileList td a.file, #fileList td a.file span {
|
||||
cursor: default;
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* ownCloud - trash bin
|
||||
*
|
||||
* @author Bjoern Schiessle
|
||||
* @copyright 2013 Bjoern Schiessle schiessle@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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
// Check if we are a user
|
||||
OCP\User::checkLoggedIn();
|
||||
|
||||
$filename = $_GET["file"];
|
||||
|
||||
$view = new OC_FilesystemView('/'.\OCP\User::getUser().'/files_trashbin/files');
|
||||
|
||||
if(!$view->file_exists($filename)) {
|
||||
header("HTTP/1.0 404 Not Found");
|
||||
$tmpl = new OCP\Template( '', '404', 'guest' );
|
||||
$tmpl->assign('file', $filename);
|
||||
$tmpl->printPage();
|
||||
exit;
|
||||
}
|
||||
|
||||
$ftype=$view->getMimeType( $filename );
|
||||
|
||||
header('Content-Type:'.$ftype);if ( preg_match( "/MSIE/", $_SERVER["HTTP_USER_AGENT"] ) ) {
|
||||
header( 'Content-Disposition: attachment; filename="' . rawurlencode( basename($filename) ) . '"' );
|
||||
} else {
|
||||
header( 'Content-Disposition: attachment; filename*=UTF-8\'\'' . rawurlencode( basename($filename) )
|
||||
. '; filename="' . rawurlencode( basename($filename) ) . '"' );
|
||||
}
|
||||
OCP\Response::disableCaching();
|
||||
header('Content-Length: '. $view->filesize($filename));
|
||||
|
||||
OC_Util::obEnd();
|
||||
$view->readfile( $filename );
|
||||
@@ -10,6 +10,7 @@ OCP\Util::addScript('files', 'fileactions');
|
||||
$tmpl = new OCP\Template('files_trashbin', 'index', 'user');
|
||||
|
||||
OCP\Util::addStyle('files', 'files');
|
||||
OCP\Util::addStyle('files_trashbin', 'trash');
|
||||
OCP\Util::addScript('files', 'filelist');
|
||||
// filelist overrides
|
||||
OCP\Util::addScript('files_trashbin', 'filelist');
|
||||
|
||||
@@ -3,12 +3,12 @@ $(document).ready(function() {
|
||||
|
||||
if (typeof FileActions !== 'undefined') {
|
||||
FileActions.register('all', 'Restore', OC.PERMISSION_READ, OC.imagePath('core', 'actions/history'), function(filename) {
|
||||
var tr = $('tr').filterAttr('data-file', filename);
|
||||
var deleteAction = $('tr').filterAttr('data-file', filename).children("td.date").children(".action.delete");
|
||||
var tr = FileList.findFileEl(filename);
|
||||
var deleteAction = tr.children("td.date").children(".action.delete");
|
||||
deleteAction.removeClass('delete-icon').addClass('progress-icon');
|
||||
disableActions();
|
||||
$.post(OC.filePath('files_trashbin', 'ajax', 'undelete.php'),
|
||||
{files: JSON.stringify([filename]), dirlisting: tr.attr('data-dirlisting')},
|
||||
{files: JSON.stringify([$('#dir').val() + '/' + filename]), dirlisting: tr.attr('data-dirlisting')},
|
||||
function(result) {
|
||||
for (var i = 0; i < result.data.success.length; i++) {
|
||||
var row = document.getElementById(result.data.success[i].filename);
|
||||
@@ -30,12 +30,12 @@ $(document).ready(function() {
|
||||
return OC.imagePath('core', 'actions/delete');
|
||||
}, function(filename) {
|
||||
$('.tipsy').remove();
|
||||
var tr = $('tr').filterAttr('data-file', filename);
|
||||
var deleteAction = $('tr').filterAttr('data-file', filename).children("td.date").children(".action.delete");
|
||||
var tr = FileList.findFileEl(filename);
|
||||
var deleteAction = tr.children("td.date").children(".action.delete");
|
||||
deleteAction.removeClass('delete-icon').addClass('progress-icon');
|
||||
disableActions();
|
||||
$.post(OC.filePath('files_trashbin', 'ajax', 'delete.php'),
|
||||
{files: JSON.stringify([filename]), dirlisting: tr.attr('data-dirlisting')},
|
||||
{files: JSON.stringify([$('#dir').val() + '/' +filename]), dirlisting: tr.attr('data-dirlisting')},
|
||||
function(result) {
|
||||
for (var i = 0; i < result.data.success.length; i++) {
|
||||
var row = document.getElementById(result.data.success[i].filename);
|
||||
@@ -66,41 +66,6 @@ $(document).ready(function() {
|
||||
procesSelection();
|
||||
});
|
||||
|
||||
$('#fileList').on('click', 'td.filename a', function(event) {
|
||||
if (event.shiftKey) {
|
||||
event.preventDefault();
|
||||
var last = $(lastChecked).parent().parent().prevAll().length;
|
||||
var first = $(this).parent().parent().prevAll().length;
|
||||
var start = Math.min(first, last);
|
||||
var end = Math.max(first, last);
|
||||
var rows = $(this).parent().parent().parent().children('tr');
|
||||
for (var i = start; i < end; i++) {
|
||||
$(rows).each(function(index) {
|
||||
if (index == i) {
|
||||
var checkbox = $(this).children().children('input:checkbox');
|
||||
$(checkbox).attr('checked', 'checked');
|
||||
$(checkbox).parent().parent().addClass('selected');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
var checkbox = $(this).parent().children('input:checkbox');
|
||||
lastChecked = checkbox;
|
||||
if ($(checkbox).attr('checked')) {
|
||||
$(checkbox).removeAttr('checked');
|
||||
$(checkbox).parent().parent().removeClass('selected');
|
||||
$('#select_all').removeAttr('checked');
|
||||
} else {
|
||||
$(checkbox).attr('checked', 'checked');
|
||||
$(checkbox).parent().parent().toggleClass('selected');
|
||||
var selectedCount = $('td.filename input:checkbox:checked').length;
|
||||
if (selectedCount == $('td.filename input:checkbox').length) {
|
||||
$('#select_all').attr('checked', 'checked');
|
||||
}
|
||||
}
|
||||
procesSelection();
|
||||
});
|
||||
|
||||
$('.undelete').click('click', function(event) {
|
||||
event.preventDefault();
|
||||
var files = getSelectedFiles('file');
|
||||
@@ -108,7 +73,7 @@ $(document).ready(function() {
|
||||
var dirlisting = getSelectedFiles('dirlisting')[0];
|
||||
disableActions();
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
var deleteAction = $('tr').filterAttr('data-file', files[i]).children("td.date").children(".action.delete");
|
||||
var deleteAction = FileList.findFileEl(files[i]).children("td.date").children(".action.delete");
|
||||
deleteAction.removeClass('delete-icon').addClass('progress-icon');
|
||||
}
|
||||
|
||||
@@ -136,7 +101,8 @@ $(document).ready(function() {
|
||||
var params = {};
|
||||
if (allFiles) {
|
||||
params = {
|
||||
allfiles: true
|
||||
allfiles: true,
|
||||
dir: $('#dir').val()
|
||||
};
|
||||
}
|
||||
else {
|
||||
@@ -153,7 +119,7 @@ $(document).ready(function() {
|
||||
}
|
||||
else {
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
var deleteAction = $('tr').filterAttr('data-file', files[i]).children("td.date").children(".action.delete");
|
||||
var deleteAction = FileList.findFileEl(files[i]).children("td.date").children(".action.delete");
|
||||
deleteAction.removeClass('delete-icon').addClass('progress-icon');
|
||||
}
|
||||
}
|
||||
@@ -183,13 +149,27 @@ $(document).ready(function() {
|
||||
|
||||
});
|
||||
|
||||
$('#fileList').on('click', 'td.filename input', function() {
|
||||
var checkbox = $(this).parent().children('input:checkbox');
|
||||
$(checkbox).parent().parent().toggleClass('selected');
|
||||
if ($(checkbox).is(':checked')) {
|
||||
var selectedCount = $('td.filename input:checkbox:checked').length;
|
||||
if (selectedCount === $('td.filename input:checkbox').length) {
|
||||
$('#select_all').prop('checked', true);
|
||||
}
|
||||
} else {
|
||||
$('#select_all').prop('checked',false);
|
||||
}
|
||||
procesSelection();
|
||||
});
|
||||
|
||||
$('#fileList').on('click', 'td.filename a', function(event) {
|
||||
var mime = $(this).parent().parent().data('mime');
|
||||
if (mime !== 'httpd/unix-directory') {
|
||||
event.preventDefault();
|
||||
}
|
||||
var filename = $(this).parent().parent().attr('data-file');
|
||||
var tr = $('tr').filterAttr('data-file',filename);
|
||||
var tr = FileList.findFileEl(filename);
|
||||
var renaming = tr.data('renaming');
|
||||
if(!renaming && !FileList.isLoading(filename)){
|
||||
if(mime.substr(0, 5) === 'text/'){ //no texteditor for now
|
||||
@@ -229,7 +209,7 @@ function getSelectedFiles(property){
|
||||
elements.each(function(i,element){
|
||||
var file={
|
||||
name:$(element).attr('data-filename'),
|
||||
file:$(element).attr('data-file'),
|
||||
file:$('#dir').val() + "/" + $(element).attr('data-file'),
|
||||
timestamp:$(element).attr('data-timestamp'),
|
||||
type:$(element).attr('data-type'),
|
||||
dirlisting:$(element).attr('data-dirlisting')
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
<?php
|
||||
$TRANSLATIONS = array(
|
||||
"Error" => "Ошибка",
|
||||
"Delete" => "Удалить"
|
||||
);
|
||||
$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);";
|
||||
@@ -44,8 +44,10 @@ class Helper
|
||||
}
|
||||
|
||||
$files = array();
|
||||
$id = 0;
|
||||
foreach ($result as $r) {
|
||||
$i = array();
|
||||
$i['id'] = $id++;
|
||||
$i['name'] = $r['id'];
|
||||
$i['date'] = \OCP\Util::formatDate($r['timestamp']);
|
||||
$i['timestamp'] = $r['timestamp'];
|
||||
|
||||
@@ -189,7 +189,7 @@ class Trashbin {
|
||||
if ($rootView->is_dir($owner . '/files_versions/' . $ownerPath)) {
|
||||
$size += self::calculateSize(new \OC\Files\View('/' . $owner . '/files_versions/' . $ownerPath));
|
||||
if ($owner !== $user) {
|
||||
$rootView->copy($owner . '/files_versions/' . $ownerPath, $owner . '/files_trashbin/versions/' . basename($ownerPath) . '.d' . $timestamp);
|
||||
self::copy_recursive($owner . '/files_versions/' . $ownerPath, $owner . '/files_trashbin/versions/' . basename($ownerPath) . '.d' . $timestamp, $rootView);
|
||||
}
|
||||
$rootView->rename($owner . '/files_versions/' . $ownerPath, $user . '/files_trashbin/versions/' . $filename . '.d' . $timestamp);
|
||||
} else if ($versions = \OCA\Files_Versions\Storage::getVersions($owner, $ownerPath)) {
|
||||
@@ -247,7 +247,7 @@ class Trashbin {
|
||||
if ($rootView->is_dir($keyfile)) {
|
||||
$size += self::calculateSize(new \OC\Files\View($keyfile));
|
||||
if ($owner !== $user) {
|
||||
$rootView->copy($keyfile, $owner . '/files_trashbin/keyfiles/' . basename($ownerPath) . '.d' . $timestamp);
|
||||
self::copy_recursive($keyfile, $owner . '/files_trashbin/keyfiles/' . basename($ownerPath) . '.d' . $timestamp, $rootView);
|
||||
}
|
||||
$rootView->rename($keyfile, $user . '/files_trashbin/keyfiles/' . $filename . '.d' . $timestamp);
|
||||
} else {
|
||||
@@ -265,7 +265,7 @@ class Trashbin {
|
||||
if ($rootView->is_dir($sharekeys)) {
|
||||
$size += self::calculateSize(new \OC\Files\View($sharekeys));
|
||||
if ($owner !== $user) {
|
||||
$rootView->copy($sharekeys, $owner . '/files_trashbin/share-keys/' . basename($ownerPath) . '.d' . $timestamp);
|
||||
self::copy_recursive($sharekeys, $owner . '/files_trashbin/share-keys/' . basename($ownerPath) . '.d' . $timestamp, $rootView);
|
||||
}
|
||||
$rootView->rename($sharekeys, $user . '/files_trashbin/share-keys/' . $filename . '.d' . $timestamp);
|
||||
} else {
|
||||
@@ -564,6 +564,21 @@ class Trashbin {
|
||||
return $size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief delete all files from the trash
|
||||
*/
|
||||
public static function deleteAll() {
|
||||
$user = \OCP\User::getUser();
|
||||
$view = new \OC\Files\View('/' . $user);
|
||||
$view->deleteAll('files_trashbin');
|
||||
self::setTrashbinSize($user, 0);
|
||||
$query = \OC_DB::prepare('DELETE FROM `*PREFIX*files_trash` WHERE `user`=?');
|
||||
$query->execute(array($user));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief delete file from trash bin permanently
|
||||
*
|
||||
@@ -719,7 +734,7 @@ class Trashbin {
|
||||
// calculate available space for trash bin
|
||||
// subtract size of files and current trash bin size from quota
|
||||
if ($softQuota) {
|
||||
$rootInfo = $view->getFileInfo('/files/');
|
||||
$rootInfo = $view->getFileInfo('/files/', false);
|
||||
$free = $quota - $rootInfo['size']; // remaining free space for user
|
||||
if ($free > 0) {
|
||||
$availableSpace = ($free * self::DEFAULTMAXSIZE / 100) - $trashbinSize; // how much space can be used for versions
|
||||
@@ -763,8 +778,13 @@ class Trashbin {
|
||||
*/
|
||||
private static function expire($trashbinSize, $user) {
|
||||
|
||||
// let the admin disable auto expire
|
||||
$autoExpire = \OC_Config::getValue('trashbin_auto_expire', true);
|
||||
if ($autoExpire === false) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$user = \OCP\User::getUser();
|
||||
$view = new \OC\Files\View('/' . $user);
|
||||
$availableSpace = self::calculateFreeSpace($trashbinSize);
|
||||
$size = 0;
|
||||
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
<img src="<?php print_unescaped(OCP\image_path('core', 'places/home.svg'));?>" class="svg" />
|
||||
</a>
|
||||
</div>
|
||||
<?php if(count($_["breadcrumb"])):?>
|
||||
<div class="crumb svg"
|
||||
data-dir='/'>
|
||||
<div class="crumb svg"
|
||||
data-dir='/'>
|
||||
<a href="<?php p($_['baseURL']); ?>"><?php p($l->t("Deleted Files")); ?></a>
|
||||
</div>
|
||||
</div>
|
||||
<?php if(count($_["breadcrumb"])):?>
|
||||
<?php endif;?>
|
||||
<?php for($i=0; $i<count($_["breadcrumb"]); $i++):
|
||||
$crumb = $_["breadcrumb"][$i];
|
||||
|
||||
@@ -35,18 +35,21 @@
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
>
|
||||
<?php if(!isset($_['readonly']) || !$_['readonly']): ?><input type="checkbox" /><?php endif; ?>
|
||||
<?php if(!isset($_['readonly']) || !$_['readonly']): ?>
|
||||
<input id="select-<?php p($file['id']); ?>" type="checkbox" />
|
||||
<label for="select-<?php p($file['id']); ?>"></label>
|
||||
<?php endif; ?>
|
||||
<?php if($file['type'] === 'dir'): ?>
|
||||
<?php if( $_['dirlisting'] ): ?>
|
||||
<a class="name" href="<?php p($_['baseURL'].'/'.$name); ?>" title="">
|
||||
<a class="name dir" href="<?php p($_['baseURL'].'/'.$name); ?>" title="">
|
||||
<?php else: ?>
|
||||
<a class="name" href="<?php p($_['baseURL'].'/'.$name.'.d'.$file['timestamp']); ?>" title="">
|
||||
<a class="name dir" href="<?php p($_['baseURL'].'/'.$name.'.d'.$file['timestamp']); ?>" title="">
|
||||
<?php endif; ?>
|
||||
<?php else: ?>
|
||||
<?php if( $_['dirlisting'] ): ?>
|
||||
<a class="name" href="<?php p($_['downloadURL'].'/'.$name); ?>" title="">
|
||||
<a class="name file" href="<?php p($_['downloadURL'].'/'.$name); ?>" title="">
|
||||
<?php else: ?>
|
||||
<a class="name" href="<?php p($_['downloadURL'].'/'.$name.'.d'.$file['timestamp']);?>" title="">
|
||||
<a class="name file" href="<?php p($_['downloadURL'].'/'.$name.'.d'.$file['timestamp']);?>" title="">
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
<span class="nametext">
|
||||
|
||||
@@ -5,7 +5,8 @@ $source = $_GET['source'];
|
||||
$start = $_GET['start'];
|
||||
list ($uid, $filename) = OCA\Files_Versions\Storage::getUidAndFilename($source);
|
||||
$count = 5; //show the newest revisions
|
||||
if( ($versions = OCA\Files_Versions\Storage::getVersions($uid, $filename)) ) {
|
||||
$versions = OCA\Files_Versions\Storage::getVersions($uid, $filename, $source);
|
||||
if( $versions ) {
|
||||
|
||||
$endReached = false;
|
||||
if (count($versions) <= $start+$count) {
|
||||
|
||||
@@ -12,18 +12,11 @@ if(!\OC_App::isEnabled('files_versions')){
|
||||
}
|
||||
|
||||
$file = array_key_exists('file', $_GET) ? (string) urldecode($_GET['file']) : '';
|
||||
$user = array_key_exists('user', $_GET) ? $_GET['user'] : '';
|
||||
$maxX = array_key_exists('x', $_GET) ? (int) $_GET['x'] : 44;
|
||||
$maxY = array_key_exists('y', $_GET) ? (int) $_GET['y'] : 44;
|
||||
$version = array_key_exists('version', $_GET) ? $_GET['version'] : '';
|
||||
$scalingUp = array_key_exists('scalingup', $_GET) ? (bool) $_GET['scalingup'] : true;
|
||||
|
||||
if($user === '') {
|
||||
\OC_Response::setStatus(400); //400 Bad Request
|
||||
\OC_Log::write('versions-preview', 'No user parameter was passed', \OC_Log::DEBUG);
|
||||
exit;
|
||||
}
|
||||
|
||||
if($file === '' && $version === '') {
|
||||
\OC_Response::setStatus(400); //400 Bad Request
|
||||
\OC_Log::write('versions-preview', 'No file parameter was passed', \OC_Log::DEBUG);
|
||||
@@ -36,7 +29,8 @@ if($maxX === 0 || $maxY === 0) {
|
||||
exit;
|
||||
}
|
||||
|
||||
try{
|
||||
try {
|
||||
list($user, $file) = \OCA\Files_Versions\Storage::getUidAndFilename($file);
|
||||
$preview = new \OC\Preview($user, 'files_versions', $file.'.v'.$version);
|
||||
$mimetype = \OC_Helper::getFileNameMimeType($file);
|
||||
$preview->setMimetype($mimetype);
|
||||
|
||||
@@ -36,12 +36,7 @@ $view = new OC\Files\View('/');
|
||||
$ftype = $view->getMimeType('/'.$uid.'/files/'.$filename);
|
||||
|
||||
header('Content-Type:'.$ftype);
|
||||
if ( preg_match( "/MSIE/", $_SERVER["HTTP_USER_AGENT"] ) ) {
|
||||
header( 'Content-Disposition: attachment; filename="' . rawurlencode( basename($filename) ) . '"' );
|
||||
} else {
|
||||
header( 'Content-Disposition: attachment; filename*=UTF-8\'\'' . rawurlencode( basename($filename) )
|
||||
. '; filename="' . rawurlencode( basename($filename) ) . '"' );
|
||||
}
|
||||
OCP\Response::setContentDispositionHeader(basename($filename), 'attachment');
|
||||
OCP\Response::disableCaching();
|
||||
header('Content-Length: '.$view->filesize($versionName));
|
||||
|
||||
|
||||
@@ -77,6 +77,7 @@ function goToVersionPage(url){
|
||||
function createVersionsDropdown(filename, files) {
|
||||
|
||||
var start = 0;
|
||||
var fileEl;
|
||||
|
||||
var html = '<div id="dropdown" class="drop drop-versions" data-file="'+escapeHTML(files)+'">';
|
||||
html += '<div id="private">';
|
||||
@@ -86,8 +87,9 @@ function createVersionsDropdown(filename, files) {
|
||||
html += '<input type="button" value="'+ t('files_versions', 'More versions...') + '" name="show-more-versions" id="show-more-versions" style="display: none;" />';
|
||||
|
||||
if (filename) {
|
||||
$('tr').filterAttr('data-file',filename).addClass('mouseOver');
|
||||
$(html).appendTo($('tr').filterAttr('data-file',filename).find('td.filename'));
|
||||
fileEl = FileList.findFileEl(filename);
|
||||
fileEl.addClass('mouseOver');
|
||||
$(html).appendTo(fileEl.find('td.filename'));
|
||||
} else {
|
||||
$(html).appendTo($('thead .share'));
|
||||
}
|
||||
@@ -138,7 +140,7 @@ function createVersionsDropdown(filename, files) {
|
||||
|
||||
var preview = '<img class="preview" src="'+revision.preview+'"/>';
|
||||
|
||||
var download ='<a href="' + path + "?file=" + files + '&revision=' + revision.version + '">';
|
||||
var download ='<a href="' + path + "?file=" + encodeURIComponent(files) + '&revision=' + revision.version + '">';
|
||||
download+='<img';
|
||||
download+=' src="' + OC.imagePath('core', 'actions/download') + '"';
|
||||
download+=' name="downloadVersion" />';
|
||||
@@ -146,8 +148,7 @@ function createVersionsDropdown(filename, files) {
|
||||
download+='</a>';
|
||||
|
||||
var revert='<span class="revertVersion"';
|
||||
revert+=' id="' + revision.version + '"';
|
||||
revert+=' value="' + files + '">';
|
||||
revert+=' id="' + revision.version + '">';
|
||||
revert+='<img';
|
||||
revert+=' src="' + OC.imagePath('core', 'actions/history') + '"';
|
||||
revert+=' name="revertVersion"';
|
||||
@@ -156,14 +157,13 @@ function createVersionsDropdown(filename, files) {
|
||||
var version=$('<li/>');
|
||||
version.attr('value', revision.version);
|
||||
version.html(preview + download + revert);
|
||||
// add file here for proper name escaping
|
||||
version.find('span.revertVersion').attr('value', files);
|
||||
|
||||
version.appendTo('#found_versions');
|
||||
}
|
||||
|
||||
$('tr').filterAttr('data-file',filename).addClass('mouseOver');
|
||||
$('#dropdown').show('blind');
|
||||
|
||||
|
||||
}
|
||||
|
||||
$(this).click(
|
||||
|
||||
@@ -98,7 +98,6 @@ class Storage {
|
||||
|
||||
$files_view = new \OC\Files\View('/'.$uid .'/files');
|
||||
$users_view = new \OC\Files\View('/'.$uid);
|
||||
$versions_view = new \OC\Files\View('/'.$uid.'/files_versions');
|
||||
|
||||
// check if filename is a directory
|
||||
if($files_view->is_dir($filename)) {
|
||||
@@ -132,7 +131,10 @@ class Storage {
|
||||
\OC_FileProxy::$enabled = false;
|
||||
|
||||
// store a new version of a file
|
||||
$users_view->copy('files'.$filename, 'files_versions'.$filename.'.v'.$users_view->filemtime('files'.$filename));
|
||||
$mtime = $users_view->filemtime('files'.$filename);
|
||||
$users_view->copy('files'.$filename, 'files_versions'.$filename.'.v'. $mtime);
|
||||
// call getFileInfo to enforce a file cache entry for the new version
|
||||
$users_view->getFileInfo('files_versions'.$filename.'.v'.$mtime);
|
||||
|
||||
// reset proxy state
|
||||
\OC_FileProxy::$enabled = $proxyStatus;
|
||||
@@ -259,11 +261,12 @@ class Storage {
|
||||
|
||||
/**
|
||||
* @brief get a list of all available versions of a file in descending chronological order
|
||||
* @param $uid user id from the owner of the file
|
||||
* @param $filename file to find versions of, relative to the user files dir
|
||||
* @returns array
|
||||
* @param string $uid user id from the owner of the file
|
||||
* @param string $filename file to find versions of, relative to the user files dir
|
||||
* @param string $userFullPath
|
||||
* @returns array versions newest first
|
||||
*/
|
||||
public static function getVersions($uid, $filename) {
|
||||
public static function getVersions($uid, $filename, $userFullPath = '') {
|
||||
$versions = array();
|
||||
// fetch for old versions
|
||||
$view = new \OC\Files\View('/' . $uid . '/' . self::VERSIONS_ROOT);
|
||||
@@ -284,7 +287,11 @@ class Storage {
|
||||
$versions[$key]['cur'] = 0;
|
||||
$versions[$key]['version'] = $version;
|
||||
$versions[$key]['humanReadableTimestamp'] = self::getHumanReadableTimestamp($version);
|
||||
$versions[$key]['preview'] = \OCP\Util::linkToRoute('core_ajax_versions_preview', array('file' => $filename, 'version' => $version, 'user' => $uid));
|
||||
if (empty($userFullPath)) {
|
||||
$versions[$key]['preview'] = '';
|
||||
} else {
|
||||
$versions[$key]['preview'] = \OCP\Util::linkToRoute('core_ajax_versions_preview', array('file' => $userFullPath, 'version' => $version));
|
||||
}
|
||||
$versions[$key]['path'] = $filename;
|
||||
$versions[$key]['name'] = $versionedFile;
|
||||
$versions[$key]['size'] = $file['size'];
|
||||
@@ -390,12 +397,13 @@ class Storage {
|
||||
}
|
||||
}
|
||||
|
||||
ksort($versions);
|
||||
// newest first
|
||||
krsort($versions);
|
||||
|
||||
$result = array();
|
||||
|
||||
foreach ($versions as $key => $value) {
|
||||
$size = $view->filesize($value['path']);
|
||||
$size = $view->filesize(self::VERSIONS_ROOT.'/'.$value['path'].'.v'.$value['timestamp']);
|
||||
$filename = $value['path'];
|
||||
|
||||
$result['all'][$key]['version'] = $value['timestamp'];
|
||||
@@ -443,7 +451,7 @@ class Storage {
|
||||
// subtract size of files and current versions size from quota
|
||||
if ($softQuota) {
|
||||
$files_view = new \OC\Files\View('/'.$uid.'/files');
|
||||
$rootInfo = $files_view->getFileInfo('/');
|
||||
$rootInfo = $files_view->getFileInfo('/', false);
|
||||
$free = $quota-$rootInfo['size']; // remaining free space for user
|
||||
if ( $free > 0 ) {
|
||||
$availableSpace = ($free * self::DEFAULTMAXSIZE / 100) - ($versionsSize + $offset); // how much space can be used for versions
|
||||
@@ -506,8 +514,8 @@ class Storage {
|
||||
* @brief delete old version from a given list of versions
|
||||
*
|
||||
* @param array $versionsByFile list of versions ordered by files
|
||||
* @param array $allVversions all versions accross multiple files
|
||||
* @param $versionsFileview OC\Files\View on data/user/files_versions
|
||||
* @param array $allVversions all versions across multiple files
|
||||
* @param $versionsFileview \OC\Files\View on data/user/files_versions
|
||||
* @return size of releted versions
|
||||
*/
|
||||
private static function delOldVersions($versionsByFile, &$allVersions, $versionsFileview) {
|
||||
@@ -517,7 +525,6 @@ class Storage {
|
||||
|
||||
// delete old versions for every given file
|
||||
foreach ($versionsByFile as $versions) {
|
||||
$versions = array_reverse($versions); // newest version first
|
||||
|
||||
$interval = 1;
|
||||
$step = Storage::$max_versions_per_interval[$interval]['step'];
|
||||
@@ -536,15 +543,16 @@ class Storage {
|
||||
foreach ($versions as $key => $version) {
|
||||
$newInterval = true;
|
||||
while ($newInterval) {
|
||||
if ($nextInterval == -1 || $version['version'] >= $nextInterval) {
|
||||
if ($nextInterval == -1 || $prevTimestamp > $nextInterval) {
|
||||
if ($version['version'] > $nextVersion) {
|
||||
//distance between two version too small, delete version
|
||||
$versionsFileview->unlink($version['path'] . '.v' . $version['version']);
|
||||
\OC_Hook::emit('\OCP\Versions', 'delete', array('path' => $version['path'] . '.v' . $version['version']));
|
||||
$versionsFileview->unlink($version['path'] . '.v' . $version['version']);
|
||||
$size += $version['size'];
|
||||
unset($allVersions[$key]); // update array with all versions
|
||||
} else {
|
||||
$nextVersion = $version['version'] - $step;
|
||||
$prevTimestamp = $version['version'];
|
||||
}
|
||||
$newInterval = false; // version checked so we can move to the next one
|
||||
} else { // time to move on to the next interval
|
||||
@@ -559,7 +567,6 @@ class Storage {
|
||||
$newInterval = true; // we changed the interval -> check same version with new interval
|
||||
}
|
||||
}
|
||||
$prevTimestamp = $version['version'];
|
||||
}
|
||||
}
|
||||
return $size;
|
||||
|
||||
@@ -27,6 +27,18 @@ OCP\JSON::checkAppEnabled('user_ldap');
|
||||
OCP\JSON::callCheck();
|
||||
|
||||
$prefix = $_POST['ldap_serverconfig_chooser'];
|
||||
|
||||
// Checkboxes are not submitted, when they are unchecked. Set them manually.
|
||||
// only legacy checkboxes (Advanced and Expert tab) need to be handled here,
|
||||
// the Wizard-like tabs handle it on their own
|
||||
$chkboxes = array('ldap_configuration_active', 'ldap_override_main_server',
|
||||
'ldap_nocase', 'ldap_turn_off_cert_check');
|
||||
foreach($chkboxes as $boxid) {
|
||||
if(!isset($_POST[$boxid])) {
|
||||
$_POST[$boxid] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
$ldapWrapper = new OCA\user_ldap\lib\LDAP();
|
||||
$connection = new \OCA\user_ldap\lib\Connection($ldapWrapper, $prefix);
|
||||
$connection->setConfiguration($_POST);
|
||||
|
||||
@@ -30,6 +30,8 @@ $l=OC_L10N::get('user_ldap');
|
||||
|
||||
$ldapWrapper = new OCA\user_ldap\lib\LDAP();
|
||||
$connection = new \OCA\user_ldap\lib\Connection($ldapWrapper, '', null);
|
||||
//needs to be true, otherwise it will also fail with an irritating message
|
||||
$_POST['ldap_configuration_active'] = 1;
|
||||
if($connection->setConfiguration($_POST)) {
|
||||
//Configuration is okay
|
||||
if($connection->bind()) {
|
||||
|
||||
@@ -14,4 +14,7 @@
|
||||
<types>
|
||||
<authentication/>
|
||||
</types>
|
||||
<documentation>
|
||||
<admin>http://doc.owncloud.org/server/6.0/go.php?to=admin-ldap</admin>
|
||||
</documentation>
|
||||
</info>
|
||||
|
||||
@@ -240,6 +240,7 @@ var LdapWizard = {
|
||||
LdapWizard.hideSpinner('#ldap_base');
|
||||
LdapWizard.showInfoBox('Please specify a Base DN');
|
||||
LdapWizard.showInfoBox('Could not determine Base DN');
|
||||
$('#ldap_base').prop('disabled', false);
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -407,6 +408,7 @@ var LdapWizard = {
|
||||
if($('#rawLoginFilterContainer').hasClass('invisible')) {
|
||||
$('#ldap_loginfilter_attributes').multiselect('enable');
|
||||
}
|
||||
LdapWizard.postInitLoginFilter();
|
||||
},
|
||||
function (result) {
|
||||
//deactivate if no attributes found
|
||||
@@ -443,10 +445,24 @@ var LdapWizard = {
|
||||
//enable only when raw filter editing is not turned on
|
||||
$('#'+multisel).multiselect('enable');
|
||||
}
|
||||
if(type === 'Users') {
|
||||
//required for initial save
|
||||
filter = $('#ldap_userlist_filter').val();
|
||||
if(!filter) {
|
||||
LdapWizard.saveMultiSelect(multisel,
|
||||
$('#'+multisel).multiselect("getChecked"));
|
||||
}
|
||||
LdapWizard.userFilterAvailableGroupsHasRun = true;
|
||||
LdapWizard.postInitUserFilter();
|
||||
}
|
||||
},
|
||||
function (result) {
|
||||
LdapWizard.hideSpinner('#'+multisel);
|
||||
$('#'+multisel).multiselect('disable');
|
||||
if(type == 'Users') {
|
||||
LdapWizard.userFilterAvailableGroupsHasRun = true;
|
||||
LdapWizard.postInitUserFilter();
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
@@ -471,9 +487,23 @@ var LdapWizard = {
|
||||
LdapWizard.hideSpinner('#'+multisel);
|
||||
LdapWizard.applyChanges(result);
|
||||
$('#'+multisel).multiselect('refresh');
|
||||
if(type === 'User') {
|
||||
//required for initial save
|
||||
filter = $('#ldap_userlist_filter').val();
|
||||
if(!filter) {
|
||||
LdapWizard.saveMultiSelect(multisel,
|
||||
$('#'+multisel).multiselect("getChecked"));
|
||||
}
|
||||
LdapWizard.userFilterObjectClassesHasRun = true;
|
||||
LdapWizard.postInitUserFilter();
|
||||
}
|
||||
},
|
||||
function (result) {
|
||||
LdapWizard.hideSpinner('#'+multisel);
|
||||
if(type == 'User') {
|
||||
LdapWizard.userFilterObjectClassesHasRun = true;
|
||||
LdapWizard.postInitUserFilter();
|
||||
}
|
||||
//TODO: error handling
|
||||
}
|
||||
);
|
||||
@@ -489,13 +519,17 @@ var LdapWizard = {
|
||||
loginfilter = $('#ldap_login_filter').val();
|
||||
|
||||
//FIXME: activates a manually deactivated configuration.
|
||||
if(host && port && base && userfilter && loginfilter) {
|
||||
if(host && port && base && userfilter && loginfilter) {
|
||||
LdapWizard.updateStatusIndicator(true);
|
||||
if($('#ldap_configuration_active').is(':checked')) {
|
||||
return;
|
||||
}
|
||||
$('#ldap_configuration_active').prop('checked', true);
|
||||
LdapWizard.save($('#ldap_configuration_active')[0]);
|
||||
if(!LdapWizard.isConfigurationActiveControlLocked) {
|
||||
//avoids a manually deactivated connection will be activated
|
||||
//upon opening the admin page
|
||||
$('#ldap_configuration_active').prop('checked', true);
|
||||
LdapWizard.save($('#ldap_configuration_active')[0]);
|
||||
}
|
||||
} else {
|
||||
if($('#ldap_configuration_active').is(':checked')) {
|
||||
$('#ldap_configuration_active').prop('checked', false);
|
||||
@@ -517,9 +551,12 @@ var LdapWizard = {
|
||||
$(id + " + button").css('display', 'inline');
|
||||
},
|
||||
|
||||
isConfigurationActiveControlLocked: true,
|
||||
|
||||
init: function() {
|
||||
LdapWizard.basicStatusCheck();
|
||||
LdapWizard.functionalityCheck();
|
||||
LdapWizard.isConfigurationActiveControlLocked = false;
|
||||
},
|
||||
|
||||
initGroupFilter: function() {
|
||||
@@ -529,11 +566,21 @@ var LdapWizard = {
|
||||
LdapWizard.countGroups();
|
||||
},
|
||||
|
||||
/** init login filter tab section **/
|
||||
|
||||
initLoginFilter: function() {
|
||||
LdapWizard.regardFilterMode('Login');
|
||||
LdapWizard.findAttributes();
|
||||
},
|
||||
|
||||
postInitLoginFilter: function() {
|
||||
if($('#rawLoginFilterContainer').hasClass('invisible')) {
|
||||
LdapWizard.composeFilter('login');
|
||||
}
|
||||
},
|
||||
|
||||
/** end of init user filter tab section **/
|
||||
|
||||
initMultiSelect: function(object, id, caption) {
|
||||
object.multiselect({
|
||||
header: false,
|
||||
@@ -546,13 +593,29 @@ var LdapWizard = {
|
||||
});
|
||||
},
|
||||
|
||||
/** init user filter tab section **/
|
||||
|
||||
userFilterObjectClassesHasRun: false,
|
||||
userFilterAvailableGroupsHasRun: false,
|
||||
|
||||
initUserFilter: function() {
|
||||
LdapWizard.userFilterObjectClassesHasRun = false;
|
||||
LdapWizard.userFilterAvailableGroupsHasRun = false;
|
||||
LdapWizard.regardFilterMode('User');
|
||||
LdapWizard.findObjectClasses('ldap_userfilter_objectclass', 'User');
|
||||
LdapWizard.findAvailableGroups('ldap_userfilter_groups', 'Users');
|
||||
LdapWizard.countUsers();
|
||||
},
|
||||
|
||||
postInitUserFilter: function() {
|
||||
if(LdapWizard.userFilterObjectClassesHasRun
|
||||
&& LdapWizard.userFilterAvailableGroupsHasRun) {
|
||||
LdapWizard.composeFilter('user');
|
||||
LdapWizard.countUsers();
|
||||
}
|
||||
},
|
||||
|
||||
/** end of init user filter tab section **/
|
||||
|
||||
onTabChange: function(event, ui) {
|
||||
newTabIndex = 0;
|
||||
if(ui.newTab[0].id === '#ldapWizard2') {
|
||||
@@ -619,8 +682,6 @@ var LdapWizard = {
|
||||
} else if(mode == LdapWizard.filterModeAssisted
|
||||
&& !$('#raw'+subject+'FilterContainer').hasClass('invisible')) {
|
||||
LdapWizard['toggleRaw'+subject+'Filter']();
|
||||
} else {
|
||||
c = $('#raw'+subject+'FilterContainer').hasClass('invisible');
|
||||
}
|
||||
},
|
||||
function (result) {
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
<?php
|
||||
$TRANSLATIONS = array(
|
||||
"Error" => "Ошибка",
|
||||
"Select groups" => "Выбрать группы",
|
||||
"_%s group found_::_%s groups found_" => array("","",""),
|
||||
"_%s user found_::_%s users found_" => array("","",""),
|
||||
"Save" => "Сохранить",
|
||||
"Help" => "Помощь",
|
||||
"Password" => "Пароль",
|
||||
"Back" => "Назад"
|
||||
);
|
||||
$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);";
|
||||
+130
-28
@@ -634,6 +634,10 @@ class Access extends LDAPUtility {
|
||||
return $this->search($filter, $this->connection->ldapBaseUsers, $attr, $limit, $offset);
|
||||
}
|
||||
|
||||
public function countUsers($filter, $attr = array('dn'), $limit = null, $offset = null) {
|
||||
return $this->count($filter, $this->connection->ldapBaseGroups, $attr, $limit, $offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief executes an LDAP search, optimized for Groups
|
||||
* @param $filter the LDAP filter for the search
|
||||
@@ -647,61 +651,68 @@ class Access extends LDAPUtility {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief executes an LDAP search
|
||||
* @brief prepares and executes an LDAP search operation
|
||||
* @param $filter the LDAP filter for the search
|
||||
* @param $base an array containing the LDAP subtree(s) that shall be searched
|
||||
* @param $attr optional, array, one or more attributes that shall be
|
||||
* retrieved. Results will according to the order in the array.
|
||||
* @returns array with the search result
|
||||
*
|
||||
* Executes an LDAP search
|
||||
* @param $limit optional, maximum results to be counted
|
||||
* @param $offset optional, a starting point
|
||||
* @returns array with the search result as first value and pagedSearchOK as
|
||||
* second | false if not successful
|
||||
*/
|
||||
private function search($filter, $base, $attr = null, $limit = null, $offset = null, $skipHandling = false) {
|
||||
private function executeSearch($filter, $base, &$attr = null, $limit = null, $offset = null) {
|
||||
if(!is_null($attr) && !is_array($attr)) {
|
||||
$attr = array(mb_strtolower($attr, 'UTF-8'));
|
||||
}
|
||||
|
||||
// See if we have a resource, in case not cancel with message
|
||||
$link_resource = $this->connection->getConnectionResource();
|
||||
if(!$this->ldap->isResource($link_resource)) {
|
||||
$cr = $this->connection->getConnectionResource();
|
||||
if(!$this->ldap->isResource($cr)) {
|
||||
// Seems like we didn't find any resource.
|
||||
// Return an empty array just like before.
|
||||
\OCP\Util::writeLog('user_ldap', 'Could not search, because resource is missing.', \OCP\Util::DEBUG);
|
||||
return array();
|
||||
return false;
|
||||
}
|
||||
|
||||
//check wether paged search should be attempted
|
||||
$pagedSearchOK = $this->initPagedSearch($filter, $base, $attr, $limit, $offset);
|
||||
|
||||
$linkResources = array_pad(array(), count($base), $link_resource);
|
||||
$linkResources = array_pad(array(), count($base), $cr);
|
||||
$sr = $this->ldap->search($linkResources, $base, $filter, $attr);
|
||||
$error = $this->ldap->errno($link_resource);
|
||||
$error = $this->ldap->errno($cr);
|
||||
if(!is_array($sr) || $error !== 0) {
|
||||
\OCP\Util::writeLog('user_ldap',
|
||||
'Error when searching: '.$this->ldap->error($link_resource).
|
||||
' code '.$this->ldap->errno($link_resource),
|
||||
'Error when searching: '.$this->ldap->error($cr).
|
||||
' code '.$this->ldap->errno($cr),
|
||||
\OCP\Util::ERROR);
|
||||
\OCP\Util::writeLog('user_ldap', 'Attempt for Paging? '.print_r($pagedSearchOK, true), \OCP\Util::ERROR);
|
||||
return array();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Do the server-side sorting
|
||||
foreach(array_reverse($attr) as $sortAttr){
|
||||
foreach($sr as $searchResource) {
|
||||
$this->ldap->sort($link_resource, $searchResource, $sortAttr);
|
||||
}
|
||||
}
|
||||
return array($sr, $pagedSearchOK);
|
||||
}
|
||||
|
||||
$findings = array();
|
||||
foreach($sr as $key => $res) {
|
||||
$findings = array_merge($findings, $this->ldap->getEntries($link_resource, $res ));
|
||||
}
|
||||
/**
|
||||
* @brief processes an LDAP paged search operation
|
||||
* @param $sr the array containing the LDAP search resources
|
||||
* @param $filter the LDAP filter for the search
|
||||
* @param $base an array containing the LDAP subtree(s) that shall be searched
|
||||
* @param $iFoundItems number of results in the search operation
|
||||
* @param $limit maximum results to be counted
|
||||
* @param $offset a starting point
|
||||
* @param $pagedSearchOK whether a paged search has been executed
|
||||
* @param $skipHandling required for paged search when cookies to
|
||||
* prior results need to be gained
|
||||
* @returns array with the search result as first value and pagedSearchOK as
|
||||
* second | false if not successful
|
||||
*/
|
||||
private function processPagedSearchStatus($sr, $filter, $base, $iFoundItems, $limit, $offset, $pagedSearchOK, $skipHandling) {
|
||||
if($pagedSearchOK) {
|
||||
\OCP\Util::writeLog('user_ldap', 'Paged search successful', \OCP\Util::INFO);
|
||||
$cr = $this->connection->getConnectionResource();
|
||||
foreach($sr as $key => $res) {
|
||||
$cookie = null;
|
||||
if($this->ldap->controlPagedResultResponse($link_resource, $res, $cookie)) {
|
||||
\OCP\Util::writeLog('user_ldap', 'Set paged search cookie', \OCP\Util::INFO);
|
||||
if($this->ldap->controlPagedResultResponse($cr, $res, $cookie)) {
|
||||
$this->setPagedResultCookie($base[$key], $filter, $limit, $offset, $cookie);
|
||||
}
|
||||
}
|
||||
@@ -713,14 +724,94 @@ class Access extends LDAPUtility {
|
||||
// if count is bigger, then the server does not support
|
||||
// paged search. Instead, he did a normal search. We set a
|
||||
// flag here, so the callee knows how to deal with it.
|
||||
if($findings['count'] <= $limit) {
|
||||
if($iFoundItems <= $limit) {
|
||||
$this->pagedSearchedSuccessful = true;
|
||||
}
|
||||
} else {
|
||||
if(!is_null($limit)) {
|
||||
\OCP\Util::writeLog('user_ldap', 'Paged search failed :(', \OCP\Util::INFO);
|
||||
\OCP\Util::writeLog('user_ldap', 'Paged search was not available', \OCP\Util::INFO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief executes an LDAP search, but counts the results only
|
||||
* @param $filter the LDAP filter for the search
|
||||
* @param $base an array containing the LDAP subtree(s) that shall be searched
|
||||
* @param $attr optional, array, one or more attributes that shall be
|
||||
* retrieved. Results will according to the order in the array.
|
||||
* @param $limit optional, maximum results to be counted
|
||||
* @param $offset optional, a starting point
|
||||
* @param $skipHandling indicates whether the pages search operation is
|
||||
* completed
|
||||
* @returns int | false if the search could not be initialized
|
||||
*
|
||||
*/
|
||||
private function count($filter, $base, $attr = null, $limit = null, $offset = null, $skipHandling = false) {
|
||||
\OCP\Util::writeLog('user_ldap', 'Count filter: '.print_r($filter, true), \OCP\Util::DEBUG);
|
||||
$search = $this->executeSearch($filter, $base, $attr, $limit, $offset);
|
||||
if($search === false) {
|
||||
return false;
|
||||
}
|
||||
list($sr, $pagedSearchOK) = $search;
|
||||
$cr = $this->connection->getConnectionResource();
|
||||
$counter = 0;
|
||||
foreach($sr as $key => $res) {
|
||||
$count = $this->ldap->countEntries($cr, $res);
|
||||
if($count !== false) {
|
||||
$counter += $count;
|
||||
}
|
||||
}
|
||||
|
||||
$this->processPagedSearchStatus($sr, $filter, $base, $counter, $limit,
|
||||
$offset, $pagedSearchOK, $skipHandling);
|
||||
|
||||
return $counter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief executes an LDAP search
|
||||
* @param $filter the LDAP filter for the search
|
||||
* @param $base an array containing the LDAP subtree(s) that shall be searched
|
||||
* @param $attr optional, array, one or more attributes that shall be
|
||||
* retrieved. Results will according to the order in the array.
|
||||
* @returns array with the search result
|
||||
*
|
||||
* Executes an LDAP search
|
||||
*/
|
||||
private function search($filter, $base, $attr = null, $limit = null, $offset = null, $skipHandling = false) {
|
||||
$search = $this->executeSearch($filter, $base, $attr, $limit, $offset);
|
||||
if($search === false) {
|
||||
return array();
|
||||
}
|
||||
list($sr, $pagedSearchOK) = $search;
|
||||
$cr = $this->connection->getConnectionResource();
|
||||
|
||||
if($skipHandling) {
|
||||
//i.e. result do not need to be fetched, we just need the cookie
|
||||
//thus pass 1 or any other value as $iFoundItems because it is not
|
||||
//used
|
||||
$this->processPagedSearchStatus($sr, $filter, $base, 1, $limit,
|
||||
$offset, $pagedSearchOK,
|
||||
$skipHandling);
|
||||
return;
|
||||
}
|
||||
|
||||
// Do the server-side sorting
|
||||
foreach(array_reverse($attr) as $sortAttr){
|
||||
foreach($sr as $searchResource) {
|
||||
$this->ldap->sort($cr, $searchResource, $sortAttr);
|
||||
}
|
||||
}
|
||||
|
||||
$findings = array();
|
||||
foreach($sr as $key => $res) {
|
||||
$findings = array_merge($findings, $this->ldap->getEntries($cr , $res ));
|
||||
}
|
||||
|
||||
$this->processPagedSearchStatus($sr, $filter, $base, $findings['count'],
|
||||
$limit, $offset, $pagedSearchOK,
|
||||
$skipHandling);
|
||||
|
||||
// if we're here, probably no connection resource is returned.
|
||||
// to make ownCloud behave nicely, we simply give back an empty array.
|
||||
@@ -804,6 +895,17 @@ class Access extends LDAPUtility {
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief escapes (user provided) parts for LDAP filter
|
||||
* @param String $input, the provided value
|
||||
* @returns the escaped string
|
||||
*/
|
||||
public function escapeFilterPart($input) {
|
||||
$search = array('*', '\\', '(', ')');
|
||||
$replace = array('\\*', '\\\\', '\\(', '\\)');
|
||||
return str_replace($search, $replace, $input);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief combines the input filters with AND
|
||||
* @param $filters array, the filters to connect
|
||||
|
||||
@@ -129,6 +129,7 @@ class Configuration {
|
||||
if(!empty($val) && strpos($val, 'attr:') === false) {
|
||||
$val = 'attr:'.$val;
|
||||
}
|
||||
break;
|
||||
case 'ldapBase':
|
||||
case 'ldapBaseUsers':
|
||||
case 'ldapBaseGroups':
|
||||
@@ -140,11 +141,11 @@ class Configuration {
|
||||
case 'ldapGroupFilterGroups':
|
||||
case 'ldapLoginFilterAttributes':
|
||||
$setMethod = 'setMultiLine';
|
||||
default:
|
||||
$this->$setMethod($key, $val);
|
||||
if(is_array($applied)) {
|
||||
$applied[] = $inputkey;
|
||||
}
|
||||
break;
|
||||
}
|
||||
$this->$setMethod($key, $val);
|
||||
if(is_array($applied)) {
|
||||
$applied[] = $inputkey;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,7 +309,7 @@ class Configuration {
|
||||
'ldap_user_filter_mode' => 0,
|
||||
'ldap_userfilter_objectclass' => '',
|
||||
'ldap_userfilter_groups' => '',
|
||||
'ldap_login_filter' => 'uid=%uid',
|
||||
'ldap_login_filter' => '',
|
||||
'ldap_login_filter_mode' => 0,
|
||||
'ldap_loginfilter_email' => 0,
|
||||
'ldap_loginfilter_username' => 1,
|
||||
|
||||
@@ -50,7 +50,8 @@ class Connection extends LDAPUtility {
|
||||
parent::__construct($ldap);
|
||||
$this->configPrefix = $configPrefix;
|
||||
$this->configID = $configID;
|
||||
$this->configuration = new Configuration($configPrefix);
|
||||
$this->configuration = new Configuration($configPrefix,
|
||||
!is_null($configID));
|
||||
$memcache = new \OC\Memcache\Factory();
|
||||
if($memcache->isAvailable()) {
|
||||
$this->cache = $memcache->create();
|
||||
|
||||
@@ -48,18 +48,25 @@ class Helper {
|
||||
static public function getServerConfigurationPrefixes($activeConfigurations = false) {
|
||||
$referenceConfigkey = 'ldap_configuration_active';
|
||||
|
||||
$query = '
|
||||
$sql = '
|
||||
SELECT DISTINCT `configkey`
|
||||
FROM `*PREFIX*appconfig`
|
||||
WHERE `appid` = \'user_ldap\'
|
||||
AND `configkey` LIKE ?
|
||||
';
|
||||
if($activeConfigurations) {
|
||||
$query .= ' AND `configvalue` = \'1\'';
|
||||
}
|
||||
$query = \OCP\DB::prepare($query);
|
||||
|
||||
$serverConfigs = $query->execute(array('%'.$referenceConfigkey))->fetchAll();
|
||||
if($activeConfigurations) {
|
||||
if (\OC_Config::getValue( 'dbtype', 'sqlite' ) === 'oci') {
|
||||
//FIXME oracle hack: need to explicitly cast CLOB to CHAR for comparison
|
||||
$sql .= ' AND to_char(`configvalue`)=\'1\'';
|
||||
} else {
|
||||
$sql .= ' AND `configvalue` = \'1\'';
|
||||
}
|
||||
}
|
||||
|
||||
$stmt = \OCP\DB::prepare($sql);
|
||||
|
||||
$serverConfigs = $stmt->execute(array('%'.$referenceConfigkey))->fetchAll();
|
||||
$prefixes = array();
|
||||
|
||||
foreach($serverConfigs as $serverConfig) {
|
||||
@@ -111,10 +118,16 @@ class Helper {
|
||||
return false;
|
||||
}
|
||||
|
||||
$saveOtherConfigurations = '';
|
||||
if(empty($prefix)) {
|
||||
$saveOtherConfigurations = 'AND `Configkey` NOT LIKE \'s%\'';
|
||||
}
|
||||
|
||||
$query = \OCP\DB::prepare('
|
||||
DELETE
|
||||
FROM `*PREFIX*appconfig`
|
||||
WHERE `configkey` LIKE ?
|
||||
'.$saveOtherConfigurations.'
|
||||
AND `appid` = \'user_ldap\'
|
||||
AND `configkey` NOT IN (\'enabled\', \'installed_version\', \'types\', \'bgjUpdateGroupsLastRun\')
|
||||
');
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user