Compare commits
306 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 35746e68ce | |||
| fe03f46a39 | |||
| 6518d6d0e8 | |||
| 9d5005c795 | |||
| 84b831b0fe | |||
| 392696998b | |||
| a1fecc1d09 | |||
| 40f3404d71 | |||
| 9ae57d55f0 | |||
| 5557f6835d | |||
| a76d0cdc3d | |||
| f0032bd7b5 | |||
| 5436575564 | |||
| f746100e13 | |||
| 85e068a723 | |||
| 119cd08c93 | |||
| 912e346229 | |||
| 65ba58d2a4 | |||
| 48a2e343e0 | |||
| df9b8cdd7f | |||
| cdcb6c3dc7 | |||
| 89b0a6796d | |||
| 75d4dac8ed | |||
| 7b6602e0db | |||
| fd8ddf6d27 | |||
| 754d4f68a7 | |||
| f4c7b3051d | |||
| 9d270bcc46 | |||
| 0f2ea52861 | |||
| 4b6474edf1 | |||
| a2658515b3 | |||
| bc5368f9be | |||
| cde3efb63c | |||
| 3bc4c92d76 | |||
| 0f4c90acbc | |||
| 7438c463d4 | |||
| c50a378c3b | |||
| 30303822e3 | |||
| 5849a2de8c | |||
| 0f89d4f9ef | |||
| f7e0370f32 | |||
| 9c60922311 | |||
| c67435189e | |||
| 6bcffdc889 | |||
| b05e178bbf | |||
| 3b3ce91d46 | |||
| 2ce22eeefb | |||
| b1f8c5cfac | |||
| 164865e813 | |||
| f0e62145d3 | |||
| ebe5c05764 | |||
| 1287036801 | |||
| d44a6563a7 | |||
| e8cc365310 | |||
| 3feccc9562 | |||
| 6dfb2afa29 | |||
| a1815cf275 | |||
| 5c4e6b1c3e | |||
| 374dd3cbcb | |||
| 895285ab59 | |||
| f4aa78c75f | |||
| 0dfc47c02d | |||
| fba6ac5050 | |||
| 917002f3ec | |||
| 8df392738c | |||
| 4df15bf573 | |||
| 5fadc7e3c6 | |||
| 84b1253def | |||
| 065bcf4790 | |||
| d8f88aa413 | |||
| a1da45a172 | |||
| 6170aa5cc3 | |||
| 552bcf1dcf | |||
| f29af9c23b | |||
| 4448c06f14 | |||
| f5f92447e5 | |||
| ed1565e18c | |||
| c1bed643a0 | |||
| 3c02cbe5dd | |||
| e2a9c7a911 | |||
| 81ceb00632 | |||
| e5237a2cfe | |||
| e2b486eab6 | |||
| b1fc1b2e4c | |||
| 063b8ea31d | |||
| 6fdd1d094f | |||
| e6bf1ca7b3 | |||
| 6ee4fe56db | |||
| 28ea652e19 | |||
| 8592c0efb7 | |||
| 1e0febe467 | |||
| 0766a679b4 | |||
| ff2de8439a | |||
| d48ab2b051 | |||
| f2b7eb85c8 | |||
| 1fc8afef1e | |||
| f4bc29a1e7 | |||
| 448ee4e7a9 | |||
| 07ef143fde | |||
| 4eb90cf3dc | |||
| 99d03daf65 | |||
| 532a919a0c | |||
| b0314907c0 | |||
| 7ca01a65dd | |||
| 429fb87386 | |||
| e5ff9f0b6b | |||
| fe92dd7381 | |||
| 02bffbe670 | |||
| fda8d66697 | |||
| ef16f4ba57 | |||
| 59b3c2fde3 | |||
| c72de30ccb | |||
| a88df5c6ec | |||
| 54642984b1 | |||
| 1c19fd15e0 | |||
| 9b05d22b0c | |||
| 200e9d9497 | |||
| 5fa749cd96 | |||
| a15710afad | |||
| 7071cf15c2 | |||
| 97dbd04e0a | |||
| ba93c3d18b | |||
| 927cae7efc | |||
| b04d510053 | |||
| b4741cfa96 | |||
| 6b4f1706b9 | |||
| 55a122a9fe | |||
| 5014d2c60c | |||
| 8a39256092 | |||
| ae850d76ea | |||
| 765526ec4c | |||
| 87052be76f | |||
| 02ef384064 | |||
| cf05d50654 | |||
| f5a597b259 | |||
| 2c656b0e4c | |||
| 9c44e7bfb8 | |||
| 0418b330d5 | |||
| 780530ec83 | |||
| 67c862c286 | |||
| 88006222a9 | |||
| d01bfe3587 | |||
| 38644cffd4 | |||
| 2c10e31c8f | |||
| e37f9c8351 | |||
| 79187fcb10 | |||
| e72cd711ad | |||
| 598f798c04 | |||
| 919241cdda | |||
| f7db588e62 | |||
| a2cc658f37 | |||
| f830150acc | |||
| 77a601c3fe | |||
| 24037218dd | |||
| caae0e6f47 | |||
| 07988cf77c | |||
| f3bd266787 | |||
| 03c9657607 | |||
| e6c2382a19 | |||
| 43b2f3c2dc | |||
| 1ae73f0e99 | |||
| 3f23ae4a16 | |||
| a4c0f259a5 | |||
| 6ebe04f8d4 | |||
| 1c5a86a115 | |||
| 57d6c49a62 | |||
| 423311c7e8 | |||
| 0cdeeec82b | |||
| 32bd2d15e3 | |||
| ef1ddfc5db | |||
| 529d45c5b2 | |||
| 0c72c99f04 | |||
| 2bb6a920e3 | |||
| 1325649b4b | |||
| bf7e2c756f | |||
| 467da3c519 | |||
| df2f85ee01 | |||
| 9e52b174b1 | |||
| 03ca380815 | |||
| db763760f1 | |||
| 0ca1500330 | |||
| 92cbeefa34 | |||
| b62d20f2ee | |||
| 4f9c750a0a | |||
| a529b2bf86 | |||
| 27ec925132 | |||
| c716776a90 | |||
| b588692ef4 | |||
| 5544509283 | |||
| 39492eb020 | |||
| 24eb2bcab5 | |||
| 8b83580af7 | |||
| 02757ad08e | |||
| 3bf505b566 | |||
| 1dea188fea | |||
| 86e4177914 | |||
| ec71e0b4e6 | |||
| 51017e43a0 | |||
| eb778eb2b0 | |||
| 45ad072c62 | |||
| 3ac33c865b | |||
| 431638742c | |||
| 7b432cbbf7 | |||
| 01cede4511 | |||
| 73954c44c6 | |||
| e345ae7b53 | |||
| 9fd53ef84f | |||
| 6a46ede8b7 | |||
| 3e5a1ad76b | |||
| a45c606b96 | |||
| fcad7252bd | |||
| c11edb9138 | |||
| 61852536fe | |||
| d9d7774cc1 | |||
| 63e5282c41 | |||
| 0c3204c7a6 | |||
| c2a72ce6b0 | |||
| cbf8dd439c | |||
| c658ec658a | |||
| 9db5323a92 | |||
| c58501ee87 | |||
| 3e9d8cce10 | |||
| 6897be7a93 | |||
| f0b0e462ea | |||
| 2b83afdd7e | |||
| a81b4c54d8 | |||
| 7975b74816 | |||
| 361b70e4d7 | |||
| 8305ae6b09 | |||
| 91fc933432 | |||
| ed60bdeac9 | |||
| bd14af5806 | |||
| 234f33e01e | |||
| 441f807bce | |||
| 80560e70b7 | |||
| 56c51d481c | |||
| 2d2e024cfa | |||
| 491c714f54 | |||
| 8459b9f6fb | |||
| 153ff1b766 | |||
| 11efe732f9 | |||
| f03a1868ab | |||
| 1c000b799b | |||
| 18d46dfdeb | |||
| 9d761fcaee | |||
| 5f70ed188b | |||
| 616fd4b54a | |||
| 6d87922cea | |||
| 0753514e5b | |||
| 7ef006e1c9 | |||
| 5a58d142e5 | |||
| db51d9aacb | |||
| d534f262aa | |||
| 0f04bfc319 | |||
| 4d42485bf5 | |||
| 713f2b3a52 | |||
| 0d39a63b05 | |||
| bd1bf9e9ac | |||
| 6552fec113 | |||
| d5190b5481 | |||
| 06bc987bd9 | |||
| 344606b2c8 | |||
| a5574e885c | |||
| bf1f9df590 | |||
| 2fd2b182e7 | |||
| 8778af681c | |||
| fb63e75743 | |||
| 4c0af1b2a2 | |||
| 9c38baac9e | |||
| dd18f963d4 | |||
| 5d46dfd2b4 | |||
| 1d54735d5d | |||
| cb5f9d2164 | |||
| a26ddb33a2 | |||
| dd8ba68e07 | |||
| bfe4ee6e47 | |||
| a429fa74d9 | |||
| f0a0e44d2e | |||
| 533e8e14b6 | |||
| 60099b91c4 | |||
| 5fd1d54607 | |||
| 0eb3496ab6 | |||
| bd06b4cf42 | |||
| 72c0cc2267 | |||
| 43b6676d0e | |||
| 36e7d3b7da | |||
| 7a60651037 | |||
| 50705cfaf8 | |||
| 3720ba9318 | |||
| a05fc9dc73 | |||
| cf0a12f999 | |||
| 5fcc3401e2 | |||
| 60b2dd6ab4 | |||
| ed96f8c628 | |||
| 77bcc5b2f3 | |||
| 1b1951a64f | |||
| a33dcd359a | |||
| 55ebf024a7 | |||
| 21f467dd36 | |||
| 26e504e096 | |||
| 5d56eba398 | |||
| 0b80c5e18e | |||
| be26cccd8a | |||
| 913ad8634f | |||
| 11ca5588ea | |||
| c494887d98 |
+1
-1
Submodule 3rdparty updated: c6cefcda72...f6756af613
@@ -27,7 +27,9 @@ $success = true;
|
||||
//Now delete
|
||||
foreach ($files as $file) {
|
||||
if (\OC\Files\Filesystem::file_exists($dir . '/' . $file) &&
|
||||
!\OC\Files\Filesystem::unlink($dir . '/' . $file)) {
|
||||
!(\OC\Files\Filesystem::isDeletable($dir . '/' . $file) &&
|
||||
\OC\Files\Filesystem::unlink($dir . '/' . $file))
|
||||
) {
|
||||
$filesWithError .= $file . "\n";
|
||||
$success = false;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ OCP\JSON::checkLoggedIn();
|
||||
$l = OC_L10N::get('files');
|
||||
|
||||
// Load the files
|
||||
$dir = isset($_GET['dir']) ? $_GET['dir'] : '';
|
||||
$dir = isset($_GET['dir']) ? (string)$_GET['dir'] : '';
|
||||
$dir = \OC\Files\Filesystem::normalizePath($dir);
|
||||
|
||||
try {
|
||||
|
||||
@@ -119,6 +119,9 @@ if($source) {
|
||||
$freeSpace = $storageStats['freeSpace'];
|
||||
|
||||
foreach($meta['wrapper_data'] as $header) {
|
||||
if (strpos($header, ':') === false){
|
||||
continue;
|
||||
}
|
||||
list($name, $value) = explode(':', $header);
|
||||
if ('content-length' === strtolower(trim($name))) {
|
||||
$length = (int) trim($value);
|
||||
|
||||
@@ -49,6 +49,10 @@ if (empty($_POST['dirToken'])) {
|
||||
|
||||
// The token defines the target directory (security reasons)
|
||||
$path = \OC\Files\Filesystem::getPath($linkItem['file_source']);
|
||||
if($path === null) {
|
||||
OCP\JSON::error(array('data' => array_merge(array('message' => $l->t('Unable to set upload directory.')))));
|
||||
die();
|
||||
}
|
||||
$dir = sprintf(
|
||||
"/%s/%s",
|
||||
$path,
|
||||
|
||||
@@ -39,7 +39,7 @@ $ftype=\OC_Helper::getSecureMimeType(\OC\Files\Filesystem::getMimeType( $filenam
|
||||
header('Content-Type:'.$ftype);
|
||||
OCP\Response::setContentDispositionHeader(basename($filename), 'attachment');
|
||||
OCP\Response::disableCaching();
|
||||
header('Content-Length: '.\OC\Files\Filesystem::filesize($filename));
|
||||
OCP\Response::setContentLengthHeader(\OC\Files\Filesystem::filesize($filename));
|
||||
|
||||
OC_Util::obEnd();
|
||||
\OC\Files\Filesystem::readfile( $filename );
|
||||
|
||||
@@ -490,6 +490,21 @@ OC.Upload = {
|
||||
}
|
||||
});
|
||||
|
||||
} else {
|
||||
// for all browsers that don't support the progress bar
|
||||
// IE 8 & 9
|
||||
|
||||
// show a spinner
|
||||
fileupload.on('fileuploadstart', function() {
|
||||
$('#upload').addClass('icon-loading');
|
||||
$('#upload .icon-upload').hide();
|
||||
});
|
||||
|
||||
// hide a spinner
|
||||
fileupload.on('fileuploadstop fileuploadfail', function() {
|
||||
$('#upload').removeClass('icon-loading');
|
||||
$('#upload .icon-upload').show();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,8 +49,10 @@
|
||||
fileSummary: null,
|
||||
initialized: false,
|
||||
|
||||
// number of files per page
|
||||
pageSize: 20,
|
||||
// number of files per page, calculated dynamically
|
||||
pageSize: function() {
|
||||
return Math.ceil(this.$container.height() / 50);
|
||||
},
|
||||
|
||||
/**
|
||||
* Array of files in the current folder.
|
||||
@@ -479,7 +481,8 @@
|
||||
mimetype: $el.attr('data-mime'),
|
||||
type: $el.attr('data-type'),
|
||||
size: parseInt($el.attr('data-size'), 10),
|
||||
etag: $el.attr('data-etag')
|
||||
etag: $el.attr('data-etag'),
|
||||
permissions: parseInt($el.attr('data-permissions'), 10)
|
||||
};
|
||||
},
|
||||
|
||||
@@ -490,7 +493,7 @@
|
||||
*/
|
||||
_nextPage: function(animate) {
|
||||
var index = this.$fileList.children().length,
|
||||
count = this.pageSize,
|
||||
count = this.pageSize(),
|
||||
tr,
|
||||
fileData,
|
||||
newTrs = [],
|
||||
@@ -1167,7 +1170,7 @@
|
||||
// if there are less elements visible than one page
|
||||
// but there are still pending elements in the array,
|
||||
// then directly append the next page
|
||||
if (lastIndex < this.files.length && lastIndex < this.pageSize) {
|
||||
if (lastIndex < this.files.length && lastIndex < this.pageSize()) {
|
||||
this._nextPage(true);
|
||||
}
|
||||
|
||||
@@ -1562,7 +1565,7 @@
|
||||
this.$el.find('.selectedActions').addClass('hidden');
|
||||
}
|
||||
else {
|
||||
canDelete = (this.getDirectoryPermissions() & OC.PERMISSION_DELETE);
|
||||
canDelete = (this.getDirectoryPermissions() & OC.PERMISSION_DELETE) && this.isSelectedDeletable();
|
||||
this.$el.find('.selectedActions').removeClass('hidden');
|
||||
this.$el.find('#headerSize a>span:first').text(OC.Util.humanFileSize(summary.totalSize));
|
||||
var selection = '';
|
||||
@@ -1582,6 +1585,15 @@
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Check whether all selected files are deletable
|
||||
*/
|
||||
isSelectedDeletable: function() {
|
||||
return _.reduce(this.getSelectedFiles(), function(deletable, file) {
|
||||
return deletable && (file.permissions & OC.PERMISSION_DELETE);
|
||||
}, true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns whether all files are selected
|
||||
* @return true if all files are selected, false otherwise
|
||||
|
||||
@@ -350,7 +350,7 @@ var createDragShadow = function(event) {
|
||||
}
|
||||
|
||||
// do not show drag shadow for too many files
|
||||
var selectedFiles = _.first(FileList.getSelectedFiles(), FileList.pageSize);
|
||||
var selectedFiles = _.first(FileList.getSelectedFiles(), FileList.pageSize());
|
||||
selectedFiles = _.sortBy(selectedFiles, FileList._fileInfoCompare);
|
||||
|
||||
if (!isDragSelected && selectedFiles.length === 1) {
|
||||
|
||||
@@ -17,7 +17,7 @@ $TRANSLATIONS = array(
|
||||
"Invalid Token" => "Jeton non valide",
|
||||
"No file was uploaded. Unknown error" => "Aucun fichier n'a été envoyé. Erreur inconnue",
|
||||
"There is no error, the file uploaded with success" => "Aucune erreur, le fichier a été envoyé avec succès.",
|
||||
"The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "Le fichier envoyé dépasse l'instruction upload_max_filesize située dans le fichier php.ini:",
|
||||
"The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "Le fichier envoyé dépasse l'instruction upload_max_filesize située dans le fichier php.ini :",
|
||||
"The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Le fichier envoyé dépasse l'instruction MAX_FILE_SIZE qui est spécifiée dans le formulaire HTML.",
|
||||
"The uploaded file was only partially uploaded" => "Le fichier n'a été que partiellement envoyé.",
|
||||
"No file was uploaded" => "Pas de fichier envoyé.",
|
||||
@@ -62,7 +62,7 @@ $TRANSLATIONS = array(
|
||||
"Your storage is almost full ({usedSpacePercent}%)" => "Votre espace de stockage est presque plein ({usedSpacePercent}%)",
|
||||
"Encryption App is enabled but your keys are not initialized, please log-out and log-in again" => "L'application de chiffrement est activée mais vos clés ne sont pas initialisées, veuillez vous déconnecter et ensuite vous reconnecter.",
|
||||
"Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." => "Votre clef privée pour l'application de chiffrement est invalide ! Veuillez mettre à jour le mot de passe de votre clef privée dans vos paramètres personnels pour récupérer l'accès à vos fichiers chiffrés.",
|
||||
"Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Le chiffrement était désactivé mais vos fichiers sont toujours chiffrés. Veuillez vous rendre sur vos Paramètres personnels pour déchiffrer vos fichiers.",
|
||||
"Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Le chiffrement a été désactivé mais vos fichiers sont toujours chiffrés. Veuillez vous rendre sur vos paramètres personnels pour déchiffrer vos fichiers.",
|
||||
"{dirs} and {files}" => "{dirs} et {files}",
|
||||
"%s could not be renamed" => "%s ne peut être renommé",
|
||||
"Upload (max. %s)" => "Envoi (max. %s)",
|
||||
@@ -77,13 +77,13 @@ $TRANSLATIONS = array(
|
||||
"Text file" => "Fichier texte",
|
||||
"New folder" => "Nouveau dossier",
|
||||
"Folder" => "Dossier",
|
||||
"From link" => "Depuis le lien",
|
||||
"From link" => "Depuis un lien",
|
||||
"You don’t have permission to upload or create files here" => "Vous n'avez pas la permission de téléverser ou de créer des fichiers ici",
|
||||
"Nothing in here. Upload something!" => "Il n'y a rien ici ! Envoyez donc quelque chose :)",
|
||||
"Download" => "Télécharger",
|
||||
"Upload too large" => "Téléversement trop volumineux",
|
||||
"The files you are trying to upload exceed the maximum size for file uploads on this server." => "Les fichiers que vous essayez d'envoyer dépassent la taille maximale permise par ce serveur.",
|
||||
"Files are being scanned, please wait." => "Les fichiers sont en cours d'analyse, veuillez patienter.",
|
||||
"Currently scanning" => "Analyse en cours de traitement"
|
||||
"Currently scanning" => "Analyse en cours",
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=2; plural=(n > 1);";
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
*/
|
||||
|
||||
describe('OCA.Files.FileList tests', function() {
|
||||
var testFiles, alertStub, notificationStub, fileList;
|
||||
var testFiles, alertStub, notificationStub, fileList, pageSizeStub;
|
||||
var bcResizeStub;
|
||||
|
||||
/**
|
||||
@@ -97,7 +97,8 @@ describe('OCA.Files.FileList tests', function() {
|
||||
name: 'One.txt',
|
||||
mimetype: 'text/plain',
|
||||
size: 12,
|
||||
etag: 'abc'
|
||||
etag: 'abc',
|
||||
permissions: OC.PERMISSION_ALL
|
||||
}, {
|
||||
id: 2,
|
||||
type: 'file',
|
||||
@@ -105,6 +106,7 @@ describe('OCA.Files.FileList tests', function() {
|
||||
mimetype: 'image/jpeg',
|
||||
size: 12049,
|
||||
etag: 'def',
|
||||
permissions: OC.PERMISSION_ALL
|
||||
}, {
|
||||
id: 3,
|
||||
type: 'file',
|
||||
@@ -112,15 +114,17 @@ describe('OCA.Files.FileList tests', function() {
|
||||
mimetype: 'application/pdf',
|
||||
size: 58009,
|
||||
etag: '123',
|
||||
permissions: OC.PERMISSION_ALL
|
||||
}, {
|
||||
id: 4,
|
||||
type: 'dir',
|
||||
name: 'somedir',
|
||||
mimetype: 'httpd/unix-directory',
|
||||
size: 250,
|
||||
etag: '456'
|
||||
etag: '456',
|
||||
permissions: OC.PERMISSION_ALL
|
||||
}];
|
||||
|
||||
pageSizeStub = sinon.stub(OCA.Files.FileList.prototype, 'pageSize').returns(20);
|
||||
fileList = new OCA.Files.FileList($('#app-content-files'));
|
||||
});
|
||||
afterEach(function() {
|
||||
@@ -130,6 +134,7 @@ describe('OCA.Files.FileList tests', function() {
|
||||
notificationStub.restore();
|
||||
alertStub.restore();
|
||||
bcResizeStub.restore();
|
||||
pageSizeStub.restore();
|
||||
});
|
||||
describe('Getters', function() {
|
||||
it('Returns the current directory', function() {
|
||||
@@ -814,7 +819,7 @@ describe('OCA.Files.FileList tests', function() {
|
||||
fileList.$fileList.on('fileActionsReady', handler);
|
||||
fileList._nextPage();
|
||||
expect(handler.calledOnce).toEqual(true);
|
||||
expect(handler.getCall(0).args[0].$files.length).toEqual(fileList.pageSize);
|
||||
expect(handler.getCall(0).args[0].$files.length).toEqual(fileList.pageSize());
|
||||
});
|
||||
it('does not trigger "fileActionsReady" event after single add with silent argument', function() {
|
||||
var handler = sinon.stub();
|
||||
@@ -1478,6 +1483,17 @@ describe('OCA.Files.FileList tests', function() {
|
||||
$('.select-all').click();
|
||||
expect(fileList.$el.find('.delete-selected').hasClass('hidden')).toEqual(true);
|
||||
});
|
||||
it('show doesnt show the delete action if one or more files are not deletable', function () {
|
||||
fileList.setFiles(testFiles);
|
||||
$('#permissions').val(OC.PERMISSION_READ | OC.PERMISSION_DELETE);
|
||||
$('.select-all').click();
|
||||
expect(fileList.$el.find('.delete-selected').hasClass('hidden')).toEqual(false);
|
||||
testFiles[0].permissions = OC.PERMISSION_READ;
|
||||
$('.select-all').click();
|
||||
fileList.setFiles(testFiles);
|
||||
$('.select-all').click();
|
||||
expect(fileList.$el.find('.delete-selected').hasClass('hidden')).toEqual(true);
|
||||
});
|
||||
});
|
||||
describe('Actions', function() {
|
||||
beforeEach(function() {
|
||||
@@ -1494,7 +1510,8 @@ describe('OCA.Files.FileList tests', function() {
|
||||
mimetype: 'text/plain',
|
||||
type: 'file',
|
||||
size: 12,
|
||||
etag: 'abc'
|
||||
etag: 'abc',
|
||||
permissions: OC.PERMISSION_ALL
|
||||
});
|
||||
expect(files[1]).toEqual({
|
||||
id: 3,
|
||||
@@ -1502,7 +1519,8 @@ describe('OCA.Files.FileList tests', function() {
|
||||
name: 'Three.pdf',
|
||||
mimetype: 'application/pdf',
|
||||
size: 58009,
|
||||
etag: '123'
|
||||
etag: '123',
|
||||
permissions: OC.PERMISSION_ALL
|
||||
});
|
||||
expect(files[2]).toEqual({
|
||||
id: 4,
|
||||
@@ -1510,7 +1528,8 @@ describe('OCA.Files.FileList tests', function() {
|
||||
name: 'somedir',
|
||||
mimetype: 'httpd/unix-directory',
|
||||
size: 250,
|
||||
etag: '456'
|
||||
etag: '456',
|
||||
permissions: OC.PERMISSION_ALL
|
||||
});
|
||||
});
|
||||
it('Removing a file removes it from the selection', function() {
|
||||
@@ -1523,7 +1542,8 @@ describe('OCA.Files.FileList tests', function() {
|
||||
mimetype: 'text/plain',
|
||||
type: 'file',
|
||||
size: 12,
|
||||
etag: 'abc'
|
||||
etag: 'abc',
|
||||
permissions: OC.PERMISSION_ALL
|
||||
});
|
||||
expect(files[1]).toEqual({
|
||||
id: 4,
|
||||
@@ -1531,7 +1551,8 @@ describe('OCA.Files.FileList tests', function() {
|
||||
name: 'somedir',
|
||||
mimetype: 'httpd/unix-directory',
|
||||
size: 250,
|
||||
etag: '456'
|
||||
etag: '456',
|
||||
permissions: OC.PERMISSION_ALL
|
||||
});
|
||||
});
|
||||
describe('Download', function() {
|
||||
|
||||
@@ -19,5 +19,4 @@ Note that this app encrypts all files that are touched by ownCloud, so external
|
||||
<types>
|
||||
<filesystem/>
|
||||
</types>
|
||||
<ocsid>166047</ocsid>
|
||||
</info>
|
||||
|
||||
@@ -1 +1 @@
|
||||
0.6.1
|
||||
0.6.2
|
||||
|
||||
@@ -4,8 +4,8 @@ $TRANSLATIONS = array(
|
||||
"Could not enable recovery key. Please check your recovery key password!" => "Impossible d'activer la clé de récupération. Veuillez vérifier votre mot de passe de clé de récupération !",
|
||||
"Recovery key successfully disabled" => "Clé de récupération désactivée avec succès",
|
||||
"Could not disable recovery key. Please check your recovery key password!" => "Impossible de désactiver la clé de récupération. Veuillez vérifier votre mot de passe de clé de récupération !",
|
||||
"Password successfully changed." => "Mot de passe changé avec succès ",
|
||||
"Could not change the password. Maybe the old password was not correct." => "Ne peut pas changer le mot de passe. L'ancien mot de passe est peut-être incorrect.",
|
||||
"Password successfully changed." => "Mot de passe changé avec succès.",
|
||||
"Could not change the password. Maybe the old password was not correct." => "Erreur lors du changement de mot de passe. L'ancien mot de passe est peut-être incorrect.",
|
||||
"Private key password successfully updated." => "Mot de passe de la clé privé mis à jour avec succès.",
|
||||
"Could not update the private key password. Maybe the old password was not correct." => "Impossible de mettre à jour le mot de passe de la clé privé. Peut-être que l'ancien mot de passe n'était pas correcte.",
|
||||
"Encryption app not initialized! Maybe the encryption app was re-enabled during your session. Please try to log out and log back in to initialize the encryption app." => "L'application de chiffrement n'est pas initialisée ! Peut-être que cette application a été réactivée pendant votre session. Veuillez essayer de vous déconnecter et ensuite de vous reconnecter pour initialiser l'application de chiffrement.",
|
||||
@@ -22,8 +22,8 @@ $TRANSLATIONS = array(
|
||||
"Enable recovery key (allow to recover users files in case of password loss):" => "Activer la clef de récupération (permet de récupérer les fichiers des utilisateurs en cas de perte de mot de passe).",
|
||||
"Recovery key password" => "Mot de passe de la clef de récupération",
|
||||
"Repeat Recovery key password" => "Répétez le mot de passe de la clé de récupération",
|
||||
"Enabled" => "Activer",
|
||||
"Disabled" => "Désactiver",
|
||||
"Enabled" => "Activé",
|
||||
"Disabled" => "Désactivé",
|
||||
"Change recovery key password:" => "Modifier le mot de passe de la clef de récupération :",
|
||||
"Old Recovery key password" => "Ancien mot de passe de la clef de récupération",
|
||||
"New Recovery key password" => "Nouveau mot de passe de la clef de récupération",
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
namespace OCA\Encryption;
|
||||
use OC\User\NoUserException;
|
||||
|
||||
/**
|
||||
* Class for utilities relating to encrypted file storage system
|
||||
@@ -903,8 +904,14 @@ class Util {
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
$util = new Util($this->view, $user);
|
||||
return $util->ready();
|
||||
try {
|
||||
$util = new Util($this->view, $user);
|
||||
return $util->ready();
|
||||
} catch (NoUserException $e) {
|
||||
\OCP\Util::writeLog('Encryption library',
|
||||
'No User object for '.$user, \OCP\Util::DEBUG);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -28,7 +28,6 @@ $result = false;
|
||||
if ($recoveryAdminEnabled || !$privateKeySet) {
|
||||
|
||||
\OCP\Util::addscript('files_encryption', 'settings-personal');
|
||||
\OCP\Util::addScript('settings', 'personal');
|
||||
|
||||
$tmpl->assign('recoveryEnabled', $recoveryAdminEnabled);
|
||||
$tmpl->assign('recoveryEnabledForUser', $recoveryEnabledForUser);
|
||||
|
||||
@@ -37,6 +37,7 @@ class Test_Encryption_Hooks extends \OCA\Files_Encryption\Tests\TestCase {
|
||||
|
||||
const TEST_ENCRYPTION_HOOKS_USER1 = "test-encryption-hooks-user1.dot";
|
||||
const TEST_ENCRYPTION_HOOKS_USER2 = "test-encryption-hooks-user2.dot";
|
||||
const TEST_ENCRYPTION_HOOKS_USER3 = "test-encryption-hooks-user3.dot";
|
||||
|
||||
/** @var \OC\Files\View */
|
||||
public $user1View; // view on /data/user1/files
|
||||
@@ -120,6 +121,7 @@ class Test_Encryption_Hooks extends \OCA\Files_Encryption\Tests\TestCase {
|
||||
// cleanup test user
|
||||
\OC_User::deleteUser(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1);
|
||||
\OC_User::deleteUser(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2);
|
||||
\OC_User::deleteUser(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER3);
|
||||
|
||||
\OC_Hook::clear();
|
||||
\OC_FileProxy::clearProxies();
|
||||
@@ -444,31 +446,35 @@ class Test_Encryption_Hooks extends \OCA\Files_Encryption\Tests\TestCase {
|
||||
$view = new \OC\Files\View();
|
||||
|
||||
// set user password for the first time
|
||||
\OCA\Encryption\Hooks::postCreateUser(array('uid' => 'newUser', 'password' => 'newUserPassword'));
|
||||
\OC_User::createUser(self::TEST_ENCRYPTION_HOOKS_USER3, 'newUserPassword');
|
||||
\OCA\Encryption\Hooks::postCreateUser(array(
|
||||
'uid' => self::TEST_ENCRYPTION_HOOKS_USER3,
|
||||
'password' => 'newUserPassword')
|
||||
);
|
||||
|
||||
$this->assertTrue($view->file_exists('public-keys/newUser.public.key'));
|
||||
$this->assertTrue($view->file_exists('newUser/files_encryption/newUser.private.key'));
|
||||
$this->assertTrue($view->file_exists('public-keys/'.self::TEST_ENCRYPTION_HOOKS_USER3.'.public.key'));
|
||||
$this->assertTrue($view->file_exists(self::TEST_ENCRYPTION_HOOKS_USER3.'/files_encryption/'.self::TEST_ENCRYPTION_HOOKS_USER3.'.private.key'));
|
||||
|
||||
// check if we are able to decrypt the private key
|
||||
$encryptedKey = \OCA\Encryption\Keymanager::getPrivateKey($view, 'newUser');
|
||||
$encryptedKey = \OCA\Encryption\Keymanager::getPrivateKey($view, self::TEST_ENCRYPTION_HOOKS_USER3);
|
||||
$privateKey = \OCA\Encryption\Crypt::decryptPrivateKey($encryptedKey, 'newUserPassword');
|
||||
$this->assertTrue(is_string($privateKey));
|
||||
|
||||
// change the password before the user logged-in for the first time,
|
||||
// we can replace the encryption keys
|
||||
\OCA\Encryption\Hooks::setPassphrase(array('uid' => 'newUser', 'password' => 'passwordChanged'));
|
||||
\OCA\Encryption\Hooks::setPassphrase(array('uid' => self::TEST_ENCRYPTION_HOOKS_USER3, 'password' => 'passwordChanged'));
|
||||
|
||||
$encryptedKey = \OCA\Encryption\Keymanager::getPrivateKey($view, 'newUser');
|
||||
$encryptedKey = \OCA\Encryption\Keymanager::getPrivateKey($view, self::TEST_ENCRYPTION_HOOKS_USER3);
|
||||
$privateKey = \OCA\Encryption\Crypt::decryptPrivateKey($encryptedKey, 'passwordChanged');
|
||||
$this->assertTrue(is_string($privateKey));
|
||||
|
||||
// now create a files folder to simulate a already used account
|
||||
$view->mkdir('/newUser/files');
|
||||
$view->mkdir('/'.self::TEST_ENCRYPTION_HOOKS_USER3.'/files');
|
||||
|
||||
// change the password after the user logged in, now the password should not change
|
||||
\OCA\Encryption\Hooks::setPassphrase(array('uid' => 'newUser', 'password' => 'passwordChanged2'));
|
||||
\OCA\Encryption\Hooks::setPassphrase(array('uid' => self::TEST_ENCRYPTION_HOOKS_USER3, 'password' => 'passwordChanged2'));
|
||||
|
||||
$encryptedKey = \OCA\Encryption\Keymanager::getPrivateKey($view, 'newUser');
|
||||
$encryptedKey = \OCA\Encryption\Keymanager::getPrivateKey($view, self::TEST_ENCRYPTION_HOOKS_USER3);
|
||||
$privateKey = \OCA\Encryption\Crypt::decryptPrivateKey($encryptedKey, 'passwordChanged2');
|
||||
$this->assertFalse($privateKey);
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ use OCA\Encryption;
|
||||
class Test_Encryption_Trashbin extends \OCA\Files_Encryption\Tests\TestCase {
|
||||
|
||||
const TEST_ENCRYPTION_TRASHBIN_USER1 = "test-trashbin-user1";
|
||||
const TEST_ENCRYPTION_TRASHBIN_USER2 = "test-trashbin-user2";
|
||||
|
||||
public $userId;
|
||||
public $pass;
|
||||
@@ -60,6 +61,7 @@ class Test_Encryption_Trashbin extends \OCA\Files_Encryption\Tests\TestCase {
|
||||
|
||||
\OC_Hook::clear('OC_Filesystem');
|
||||
\OC_Hook::clear('OC_User');
|
||||
\OC_Hook::clear('OCP\\Share');
|
||||
|
||||
// trashbin hooks
|
||||
\OCA\Files_Trashbin\Trashbin::registerHooks();
|
||||
@@ -67,11 +69,24 @@ class Test_Encryption_Trashbin extends \OCA\Files_Encryption\Tests\TestCase {
|
||||
// Filesystem related hooks
|
||||
\OCA\Encryption\Helper::registerFilesystemHooks();
|
||||
|
||||
|
||||
// register share hooks
|
||||
\OC::registerShareHooks();
|
||||
\OCA\Files_Sharing\Helper::registerHooks();
|
||||
|
||||
// Sharing related hooks
|
||||
\OCA\Encryption\Helper::registerShareHooks();
|
||||
|
||||
// Filesystem related hooks
|
||||
\OCA\Encryption\Helper::registerFilesystemHooks();
|
||||
|
||||
// clear and register hooks
|
||||
\OC_FileProxy::clearProxies();
|
||||
\OC_FileProxy::register(new OCA\Files\Share\Proxy());
|
||||
\OC_FileProxy::register(new OCA\Encryption\Proxy());
|
||||
|
||||
// create test user
|
||||
self::loginHelper(self::TEST_ENCRYPTION_TRASHBIN_USER2, true);
|
||||
self::loginHelper(self::TEST_ENCRYPTION_TRASHBIN_USER1, true);
|
||||
}
|
||||
|
||||
@@ -96,6 +111,9 @@ class Test_Encryption_Trashbin extends \OCA\Files_Encryption\Tests\TestCase {
|
||||
// remember files_trashbin state
|
||||
$this->stateFilesTrashbin = OC_App::isEnabled('files_trashbin');
|
||||
|
||||
$this->view->deleteAll('/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_trashbin');
|
||||
$this->view->deleteAll('/' . self::TEST_ENCRYPTION_TRASHBIN_USER2 . '/files_trashbin');
|
||||
|
||||
// we want to tests with app files_trashbin enabled
|
||||
\OC_App::enable('files_trashbin');
|
||||
}
|
||||
@@ -367,4 +385,58 @@ class Test_Encryption_Trashbin extends \OCA\Files_Encryption\Tests\TestCase {
|
||||
. '.' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '.shareKey.' . $trashFileSuffix));
|
||||
}
|
||||
|
||||
|
||||
function testDeleteSharedFile() {
|
||||
|
||||
// generate filename
|
||||
$filename = 'tmp-' . $this->getUniqueID() . '.txt';
|
||||
|
||||
// save file with content
|
||||
$cryptedFile = file_put_contents('crypt:///' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files/' . $filename, $this->dataShort);
|
||||
// test that data was successfully written
|
||||
$this->assertTrue(is_int($cryptedFile));
|
||||
|
||||
// get the file info from previous created file
|
||||
$fileInfo = $this->view->getFileInfo(
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files/' . $filename);
|
||||
|
||||
// check if we have a valid file info
|
||||
$this->assertTrue($fileInfo instanceof \OC\Files\FileInfo);
|
||||
|
||||
// share the file
|
||||
$this->assertTrue(
|
||||
\OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, self::TEST_ENCRYPTION_TRASHBIN_USER2, OCP\PERMISSION_ALL)
|
||||
);
|
||||
|
||||
self::loginHelper(self::TEST_ENCRYPTION_TRASHBIN_USER2);
|
||||
|
||||
$this->assertTrue(\OC\Files\Filesystem::file_exists($filename));
|
||||
|
||||
\OCA\Files_Trashbin\Trashbin::move2trash($filename);
|
||||
|
||||
$query = \OC_DB::prepare('SELECT `timestamp` FROM `*PREFIX*files_trash`'
|
||||
. ' WHERE `id`=?');
|
||||
$result = $query->execute(array($filename))->fetchRow();
|
||||
|
||||
$this->assertNotEmpty($result);
|
||||
|
||||
$timestamp = $result['timestamp'];
|
||||
|
||||
// check if key for both users exists
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_trashbin/keyfiles/' . $filename
|
||||
. '.key.d'. $timestamp));
|
||||
// check if key for admin exists
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER2 . '/files_trashbin/keyfiles/' . $filename
|
||||
. '.key.d' . $timestamp));
|
||||
|
||||
// check if share key for both users exists
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_trashbin/share-keys/'
|
||||
. $filename . '.' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '.shareKey.d' . $timestamp));
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER2 . '/files_trashbin/share-keys/'
|
||||
. $filename . '.' . self::TEST_ENCRYPTION_TRASHBIN_USER2 . '.shareKey.d' . $timestamp));
|
||||
}
|
||||
}
|
||||
|
||||
+10
-2
@@ -72,8 +72,16 @@ class Dropbox_OAuth_Curl extends Dropbox_OAuth {
|
||||
if (strtoupper($method) == 'POST') {
|
||||
curl_setopt($ch, CURLOPT_URL, $uri);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
// if (is_array($arguments))
|
||||
// $arguments=http_build_query($arguments);
|
||||
|
||||
//if (is_array($arguments))
|
||||
// $arguments=http_build_query($arguments);
|
||||
if(is_array($arguments)) {
|
||||
foreach ($arguments as $key => $value) {
|
||||
if ($value[0] === '@') {
|
||||
exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $arguments);
|
||||
// $httpHeaders['Content-Length']=strlen($arguments);
|
||||
} else {
|
||||
|
||||
+8
-3
@@ -112,6 +112,11 @@ class smb {
|
||||
|
||||
|
||||
function execute ($command, $purl, $regexp = NULL) {
|
||||
if (strpos($command,';') !== false) {
|
||||
trigger_error('Semicolon not supported in commands');
|
||||
exit();
|
||||
}
|
||||
|
||||
return smb::client ('-d 0 '
|
||||
. escapeshellarg ('//' . $purl['host'] . '/' . $purl['share'])
|
||||
. ' -c ' . escapeshellarg ($command), $purl, $regexp
|
||||
@@ -319,14 +324,14 @@ class smb {
|
||||
trigger_error('rename(): error in URL', E_USER_ERROR);
|
||||
}
|
||||
smb::clearstatcache ($url_from);
|
||||
$cmd = '';
|
||||
// check if target file exists
|
||||
if (smb::url_stat($url_to)) {
|
||||
// delete target file first
|
||||
$cmd = 'del "' . $to['path'] . '"; ';
|
||||
$cmd = 'del "' . $to['path'] . '"';
|
||||
smb::execute($cmd, $to);
|
||||
$replace = true;
|
||||
}
|
||||
$cmd .= 'rename "' . $from['path'] . '" "' . $to['path'] . '"';
|
||||
$cmd = 'rename "' . $from['path'] . '" "' . $to['path'] . '"';
|
||||
$result = smb::execute($cmd, $to);
|
||||
if ($replace) {
|
||||
// clear again, else the cache will return the info
|
||||
|
||||
@@ -27,6 +27,12 @@ if ($isValid == false) {
|
||||
$isValid = openssl_pkey_get_public($data);
|
||||
}
|
||||
|
||||
// If string starts with "file://" ignore the certificate
|
||||
$query = 'file://';
|
||||
if(strtolower(substr($data, 0, strlen($query))) === $query) {
|
||||
$isValid = false;
|
||||
}
|
||||
|
||||
// add the certificate if it could be verified
|
||||
if ( $isValid ) {
|
||||
// disable proxy to prevent multiple fopen calls
|
||||
|
||||
@@ -17,5 +17,4 @@ In addition to the GUI, it is possible to configure external storage manually at
|
||||
<types>
|
||||
<filesystem/>
|
||||
</types>
|
||||
<ocsid>166048</ocsid>
|
||||
</info>
|
||||
|
||||
@@ -233,41 +233,24 @@ $(document).ready(function() {
|
||||
}
|
||||
},
|
||||
initSelection: function(element, callback) {
|
||||
|
||||
var promises = [];
|
||||
|
||||
var results = [];
|
||||
|
||||
$(element.val().split(",")).each(function (i,userId) {
|
||||
var def = new $.Deferred();
|
||||
promises.push(def.promise());
|
||||
|
||||
var pos = userId.indexOf('(group)');
|
||||
if (pos !== -1) {
|
||||
//add as group
|
||||
results.push({name:userId, displayname:userId.substr(0, pos), type:'group'});
|
||||
def.resolve();
|
||||
} else {
|
||||
$.ajax(OC.generateUrl('apps/files_external/applicable'), {
|
||||
data: {
|
||||
pattern: userId
|
||||
},
|
||||
dataType: "json"
|
||||
}).done(function(data) {
|
||||
if (data.status === "success") {
|
||||
if (data.users[userId]) {
|
||||
results.push({name:userId, displayname:data.users[userId], type:'user'});
|
||||
}
|
||||
def.resolve();
|
||||
} else {
|
||||
//FIXME add error handling
|
||||
$.ajax(OC.generateUrl('displaynames'), {
|
||||
data: {
|
||||
users: element.val().split(",")
|
||||
},
|
||||
dataType: "json"
|
||||
}).done(function(data) {
|
||||
var results = [];
|
||||
if (data.status === "success") {
|
||||
$.each(data.users, function(user, displayname) {
|
||||
if (displayname !== false) {
|
||||
results.push({name:user, displayname:displayname, type:'user'});
|
||||
}
|
||||
});
|
||||
callback(results);
|
||||
} else {
|
||||
//FIXME add error handling
|
||||
}
|
||||
});
|
||||
$.when.apply(undefined, promises).then(function(){
|
||||
callback(results);
|
||||
});
|
||||
},
|
||||
id: function(element) {
|
||||
return element.name;
|
||||
@@ -452,14 +435,14 @@ $(document).ready(function() {
|
||||
OC.AppConfig.setValue('files_external', 'allow_user_mounting', 'no');
|
||||
$('#userMountingBackends').addClass('hidden');
|
||||
}
|
||||
OC.msg.finishedSaving('#userMountingMsg', {status: 'success', data: {message: t('settings', 'Saved')}});
|
||||
OC.msg.finishedSaving('#userMountingMsg', {status: 'success', data: {message: t('files_external', 'Saved')}});
|
||||
});
|
||||
|
||||
$('input[name="allowUserMountingBackends\\[\\]"]').bind('change', function() {
|
||||
OC.msg.startSaving('#userMountingMsg');
|
||||
var userMountingBackends = $('input[name="allowUserMountingBackends\\[\\]"]:checked').map(function(){return $(this).val();}).get();
|
||||
OC.AppConfig.setValue('files_external', 'user_mounting_backends', userMountingBackends.join());
|
||||
OC.msg.finishedSaving('#userMountingMsg', {status: 'success', data: {message: t('settings', 'Saved')}});
|
||||
OC.msg.finishedSaving('#userMountingMsg', {status: 'success', data: {message: t('files_external', 'Saved')}});
|
||||
|
||||
// disable allowUserMounting
|
||||
if(userMountingBackends.length === 0) {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<?php
|
||||
$TRANSLATIONS = array(
|
||||
"Fetching request tokens failed. Verify that your Dropbox app key and secret are correct." => "La requête de récupération des jetons d’authentification a échoué. Veuillez vérifier votre App-Key Dropbox ainsi que le mot de passe.",
|
||||
"Fetching request tokens failed. Verify that your Dropbox app key and secret are correct." => "La récupération des jetons d’authentification a échoué. Veuillez vérifier votre clé d'application Dropbox ainsi que le mot de passe.",
|
||||
"Fetching access tokens failed. Verify that your Dropbox app key and secret are correct." => "La requête d’accès aux jetons d’authentification a échoué. Veuillez vérifier votre App-Key Dropbox ainsi que le mot de passe.",
|
||||
"Please provide a valid Dropbox app key and secret." => "Veuillez fournir une clé d'application (app key) ainsi qu'un mot de passe valides.",
|
||||
"Step 1 failed. Exception: %s" => "L’étape 1 a échoué. Erreur: %s",
|
||||
"Step 2 failed. Exception: %s" => "L’étape 2 a échoué. Erreur: %s",
|
||||
"Step 1 failed. Exception: %s" => "L’étape 1 a échoué. Erreur : %s",
|
||||
"Step 2 failed. Exception: %s" => "L’étape 2 a échoué. Erreur : %s",
|
||||
"External storage" => "Stockage externe",
|
||||
"Local" => "Local",
|
||||
"Location" => "Emplacement",
|
||||
@@ -26,7 +26,7 @@ $TRANSLATIONS = array(
|
||||
"Username" => "Nom d'utilisateur",
|
||||
"Password" => "Mot de passe",
|
||||
"Root" => "Root",
|
||||
"Secure ftps://" => "Sécuriser via ftps://",
|
||||
"Secure ftps://" => "Sécurisation ftps://",
|
||||
"Client ID" => "ID Client",
|
||||
"Client secret" => "Secret client",
|
||||
"OpenStack Object Storage" => "Object de Stockage OpenStack",
|
||||
@@ -40,7 +40,7 @@ $TRANSLATIONS = array(
|
||||
"URL of identity endpoint (required for OpenStack Object Storage)" => "URL du point d'accès d'identité (requis pour le stockage OpenStack)",
|
||||
"Timeout of HTTP requests in seconds (optional)" => "Temps maximal de requête HTTP en seconde (facultatif)",
|
||||
"Share" => "Partager",
|
||||
"SMB / CIFS using OC login" => "SMB / CIFS utilise le nom d'utilisateur OC",
|
||||
"SMB / CIFS using OC login" => "SMB / CIFS en utilisant les identifiants OC",
|
||||
"Username as share" => "Nom d'utilisateur du partage",
|
||||
"URL" => "URL",
|
||||
"Secure https://" => "Sécurisation https://",
|
||||
@@ -54,8 +54,8 @@ $TRANSLATIONS = array(
|
||||
"Saved" => "Sauvegarder",
|
||||
"<b>Note:</b> " => "<b>Attention :</b>",
|
||||
" and " => "et",
|
||||
"<b>Note:</b> The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "<b>Attention :</b> Le support de cURL de PHP n'est pas activé ou installé. Le montage de %s n'est pas possible. Contactez votre administrateur système pour l'installer.",
|
||||
"<b>Note:</b> The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "<b>Attention : </b> Le support FTP de PHP n'est pas activé ou installé. Le montage de %s n'est pas possible. Contactez votre administrateur système pour l'installer.",
|
||||
"<b>Note:</b> The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "<b>Attention :</b> La prise en charge de cURL par PHP n'est pas activée ou installée. Le montage de %s n'est pas possible. Contactez votre administrateur système pour l'installer.",
|
||||
"<b>Note:</b> The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "<b>Attention : </b> La prise en charge du FTP par PHP n'est pas activée ou installée. Le montage de %s n'est pas possible. Contactez votre administrateur système pour l'installer.",
|
||||
"<b>Note:</b> \"%s\" is not installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "<b>Attention : </b> \"%s\" n'est pas installé. Le montage de %s n'est pas possible. Contactez votre administrateur système pour l'installer.",
|
||||
"You don't have any external storages" => "Vous n'avez pas de support de stockage externe",
|
||||
"Name" => "Nom",
|
||||
@@ -72,7 +72,7 @@ $TRANSLATIONS = array(
|
||||
"Groups" => "Groupes",
|
||||
"Users" => "Utilisateurs",
|
||||
"Delete" => "Supprimer",
|
||||
"Enable User External Storage" => "Activer le stockage externe pour les utilisateurs",
|
||||
"Enable User External Storage" => "Autoriser les utilisateurs à ajouter des stockages externes",
|
||||
"Allow users to mount the following external storage" => "Autorise les utilisateurs à monter les stockage externes suivants",
|
||||
"SSL root certificates" => "Certificats racine SSL",
|
||||
"Import Root Certificate" => "Importer un certificat racine"
|
||||
|
||||
@@ -266,10 +266,7 @@ class AmazonS3 extends \OC\Files\Storage\Common {
|
||||
$file = basename(
|
||||
isset($object['Key']) ? $object['Key'] : $object['Prefix']
|
||||
);
|
||||
|
||||
if ($file != basename($path)) {
|
||||
$files[] = $file;
|
||||
}
|
||||
$files[] = $file;
|
||||
}
|
||||
|
||||
\OC\Files\Stream\Dir::register('amazons3' . $path, $files);
|
||||
|
||||
@@ -489,6 +489,11 @@ class OC_Mount_Config {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($classOptions['objectstore'])) {
|
||||
// objectstore cannot be set by client side
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isset($backends[$class])) {
|
||||
// invalid backend
|
||||
return false;
|
||||
@@ -875,6 +880,13 @@ class OC_Mount_Config {
|
||||
$mountPoint[$applicable][$mountPath]['priority']
|
||||
= $data[$mountType][$applicable][$mountPath]['priority'];
|
||||
}
|
||||
// Persistent objectstore
|
||||
if (isset($data[$mountType][$applicable][$mountPath])
|
||||
&& isset($data[$mountType][$applicable][$mountPath]['objectstore'])
|
||||
) {
|
||||
$mountPoint[$applicable][$mountPath]['objectstore']
|
||||
= $data[$mountType][$applicable][$mountPath]['objectstore'];
|
||||
}
|
||||
$data[$mountType][$applicable]
|
||||
= array_merge($data[$mountType][$applicable], $mountPoint[$applicable]);
|
||||
} else {
|
||||
|
||||
@@ -37,13 +37,13 @@ class OwnCloud extends \OC\Files\Storage\DAV{
|
||||
$host = substr($host, 0, $hostSlashPos);
|
||||
}
|
||||
|
||||
if (substr($contextPath , 1) !== '/'){
|
||||
if (substr($contextPath, -1) !== '/'){
|
||||
$contextPath .= '/';
|
||||
}
|
||||
|
||||
if (isset($params['root'])){
|
||||
$root = $params['root'];
|
||||
if (substr($root, 1) !== '/'){
|
||||
if (substr($root, 0, 1) !== '/'){
|
||||
$root = '/' . $root;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,13 +18,19 @@ class SMB_OC extends \OC\Files\Storage\SMB {
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct($params) {
|
||||
if (isset($params['host']) && \OC::$session->exists('smb-credentials')) {
|
||||
if (isset($params['host'])) {
|
||||
$host=$params['host'];
|
||||
$this->username_as_share = ($params['username_as_share'] === 'true');
|
||||
|
||||
$params_auth = json_decode(\OC::$server->getCrypto()->decrypt(\OC::$session->get('smb-credentials')), true);
|
||||
$user = \OC::$session->get('loginname');
|
||||
$password = $params_auth['password'];
|
||||
$user = 'foo';
|
||||
$password = 'bar';
|
||||
if (\OC::$session->exists('smb-credentials')) {
|
||||
$params_auth = json_decode(\OC::$server->getCrypto()->decrypt(\OC::$session->get('smb-credentials')), true);
|
||||
$user = \OC::$session->get('loginname');
|
||||
$password = $params_auth['password'];
|
||||
} else {
|
||||
// assume we are testing from the admin section
|
||||
}
|
||||
|
||||
$root=isset($params['root'])?$params['root']:'/';
|
||||
$share = '';
|
||||
|
||||
@@ -68,6 +68,14 @@ class OwnCloudFunctions extends \PHPUnit_Framework_TestCase {
|
||||
),
|
||||
'http://testhost/testroot/remote.php/webdav/subdir/',
|
||||
),
|
||||
array(
|
||||
array(
|
||||
'host' => 'http://testhost/testroot/',
|
||||
'root' => '/subdir',
|
||||
'secure' => false
|
||||
),
|
||||
'http://testhost/testroot/remote.php/webdav/subdir/',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -30,25 +30,33 @@ if(!\OCP\Util::isValidFileName($name)) {
|
||||
exit();
|
||||
}
|
||||
|
||||
$user = \OC::$server->getUserSession()->getUser();
|
||||
$uid = ($user) ? $user->getUID() : null;
|
||||
$externalManager = new \OCA\Files_Sharing\External\Manager(
|
||||
\OC::$server->getDatabaseConnection(),
|
||||
\OC\Files\Filesystem::getMountManager(),
|
||||
\OC\Files\Filesystem::getLoader(),
|
||||
\OC::$server->getUserSession()
|
||||
$uid
|
||||
);
|
||||
|
||||
$name = OCP\Files::buildNotExistingFileName('/', $name);
|
||||
|
||||
$mount = $externalManager->addShare($remote, $token, $password, $name, $owner);
|
||||
/**
|
||||
* @var \OCA\Files_Sharing\External\Storage $storage
|
||||
*/
|
||||
$storage = $mount->getStorage();
|
||||
$result = $storage->file_exists('');
|
||||
if($result){
|
||||
$storage->getScanner()->scanAll();
|
||||
\OCP\JSON::success();
|
||||
// check for ssl cert
|
||||
if (substr($remote, 0, 5) === 'https' and !OC_Util::getUrlContent($remote)) {
|
||||
\OCP\JSON::error(array('data' => array('message' => $l->t("Invalid or untrusted ssl certificate"))));
|
||||
exit;
|
||||
} else {
|
||||
$externalManager->removeShare($mount->getMountPoint());
|
||||
\OCP\JSON::error(array('data' => array('message' => $l->t("Couldn't add remote share"))));
|
||||
$mount = $externalManager->addShare($remote, $token, $password, $name, $owner);
|
||||
/**
|
||||
* @var \OCA\Files_Sharing\External\Storage $storage
|
||||
*/
|
||||
$storage = $mount->getStorage();
|
||||
$result = $storage->file_exists('');
|
||||
if ($result) {
|
||||
$storage->getScanner()->scanAll();
|
||||
\OCP\JSON::success();
|
||||
} else {
|
||||
$externalManager->removeShare($mount->getMountPoint());
|
||||
\OCP\JSON::error(array('data' => array('message' => $l->t("Couldn't add remote share"))));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,13 @@ $view = new \OC\Files\View('/' . $userId . '/files');
|
||||
|
||||
$pathId = $linkedItem['file_source'];
|
||||
$path = $view->getPath($pathId);
|
||||
|
||||
if($path === null) {
|
||||
\OC_Response::setStatus(\OC_Response::STATUS_NOT_FOUND);
|
||||
\OC_Log::write('core-preview', 'Could not resolve file for shared item', OC_Log::WARN);
|
||||
exit;
|
||||
}
|
||||
|
||||
$pathInfo = $view->getFileInfo($path);
|
||||
$sharedFile = null;
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@ function testUrl($url) {
|
||||
try {
|
||||
$result = file_get_contents($url);
|
||||
$data = json_decode($result);
|
||||
return is_object($data) and !empty($data->version);
|
||||
// public link mount is only supported in ownCloud 7+
|
||||
return is_object($data) and !empty($data->version) and version_compare($data->version, '7.0.0', '>=');
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ $l = OC_L10N::get('files_sharing');
|
||||
OC::$CLASSPATH['OC_Share_Backend_File'] = 'files_sharing/lib/share/file.php';
|
||||
OC::$CLASSPATH['OC_Share_Backend_Folder'] = 'files_sharing/lib/share/folder.php';
|
||||
OC::$CLASSPATH['OC\Files\Storage\Shared'] = 'files_sharing/lib/sharedstorage.php';
|
||||
OC::$CLASSPATH['OC\Files\Cache\SharedScanner'] = 'files_sharing/lib/scanner.php';
|
||||
OC::$CLASSPATH['OC\Files\Cache\Shared_Cache'] = 'files_sharing/lib/cache.php';
|
||||
OC::$CLASSPATH['OC\Files\Cache\Shared_Permissions'] = 'files_sharing/lib/permissions.php';
|
||||
OC::$CLASSPATH['OC\Files\Cache\Shared_Updater'] = 'files_sharing/lib/updater.php';
|
||||
|
||||
@@ -87,8 +87,14 @@ function removeSharedFolder($mkdirs = true, $chunkSize = 99) {
|
||||
// create folder Shared for each user
|
||||
|
||||
if ($mkdirs) {
|
||||
$logger = \OC::$server->getLogger();
|
||||
foreach ($unique_users as $user) {
|
||||
\OC\Files\Filesystem::initMountPoints($user);
|
||||
try {
|
||||
\OC\Files\Filesystem::initMountPoints($user);
|
||||
} catch(\OC\User\NoUserException $e) {
|
||||
$logger->warning("Update: removeSharedFolder - user '$user' is not present anymore" , array('app' => 'files_sharing'));
|
||||
continue;
|
||||
}
|
||||
if (!$view->file_exists('/' . $user . '/files/Shared')) {
|
||||
$view->mkdir('/' . $user . '/files/Shared');
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
0.5.3
|
||||
0.5.4
|
||||
|
||||
@@ -210,7 +210,7 @@ OCA.Sharing.PublicApp = {
|
||||
// this check needs to happen on the server due to the Content Security Policy directive
|
||||
$.get(OC.generateUrl('apps/files_sharing/testremote'), {remote: remote}).then(function (protocol) {
|
||||
if (protocol !== 'http' && protocol !== 'https') {
|
||||
OC.dialogs.alert(t('files_sharing', 'No ownCloud installation found at {remote}', {remote: remote}),
|
||||
OC.dialogs.alert(t('files_sharing', 'No ownCloud installation (7 or higher) found at {remote}', {remote: remote}),
|
||||
t('files_sharing', 'Invalid ownCloud url'));
|
||||
} else {
|
||||
OC.redirect(protocol + '://' + url);
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
$TRANSLATIONS = array(
|
||||
"Server to server sharing is not enabled on this server" => "Le partage de serveur à serveur n'est pas activé sur ce serveur",
|
||||
"Couldn't add remote share" => "Impossible d'ajouter un partage distant",
|
||||
"Shared with you" => "Partagé avec vous",
|
||||
"Shared with others" => "Partagé avec d'autres",
|
||||
"Shared by link" => "Partagé par lien",
|
||||
"No files have been shared with you yet." => "Aucun fichier n'est partagé avec vous pour l'instant",
|
||||
"You haven't shared any files yet." => "Vous ne partagez pas de fichier pour l'instant",
|
||||
"You haven't shared any files by link yet." => "Vous ne partagez aucun de fichier par lien pour l'instant.",
|
||||
"Shared with you" => "Partagés avec vous",
|
||||
"Shared with others" => "Partagés avec d'autres",
|
||||
"Shared by link" => "Partagés par lien",
|
||||
"No files have been shared with you yet." => "Aucun fichier n'est partagé avec vous pour l'instant.",
|
||||
"You haven't shared any files yet." => "Vous ne partagez pas de fichier pour l'instant.",
|
||||
"You haven't shared any files by link yet." => "Vous ne partagez pas de fichier par lien pour l'instant.",
|
||||
"Add {name} from {owner}@{remote}" => "Ajouter {name} de {owner}@{remote}",
|
||||
"Add Share" => "Ajouter un partage",
|
||||
"Password" => "Mot de passe",
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
namespace OC\Files\Cache;
|
||||
|
||||
use OC\User\NoUserException;
|
||||
use OCP\Share_Backend_Collection;
|
||||
|
||||
/**
|
||||
@@ -53,7 +54,12 @@ class Shared_Cache extends Cache {
|
||||
}
|
||||
$source = \OC_Share_Backend_File::getSource($target, $this->storage->getMountPoint(), $this->storage->getItemType());
|
||||
if (isset($source['path']) && isset($source['fileOwner'])) {
|
||||
\OC\Files\Filesystem::initMountPoints($source['fileOwner']);
|
||||
try {
|
||||
\OC\Files\Filesystem::initMountPoints($source['fileOwner']);
|
||||
} catch(NoUserException $e) {
|
||||
\OC::$server->getLogger()->warning('The user \'' . $source['uid_owner'] . '\' of a share can\'t be retrieved.', array('app' => 'files_sharing'));
|
||||
return false;
|
||||
}
|
||||
$mounts = \OC\Files\Filesystem::getMountByNumericId($source['storage']);
|
||||
if (is_array($mounts) and !empty($mounts)) {
|
||||
$fullPath = $mounts[0]->getMountPoint() . $source['path'];
|
||||
@@ -345,6 +351,28 @@ class Shared_Cache extends Cache {
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* update the folder size and the size of all parent folders
|
||||
*
|
||||
* @param string|boolean $path
|
||||
* @param array $data (optional) meta data of the folder
|
||||
*/
|
||||
public function correctFolderSize($path, $data = null) {
|
||||
$this->calculateFolderSize($path, $data);
|
||||
if ($path !== '') {
|
||||
$parent = dirname($path);
|
||||
if ($parent === '.' or $parent === '/') {
|
||||
$parent = '';
|
||||
}
|
||||
$this->correctFolderSize($parent);
|
||||
} else {
|
||||
// bubble up to source cache
|
||||
$sourceCache = $this->getSourceCache($path);
|
||||
$parent = dirname($this->files[$path]);
|
||||
$sourceCache->correctFolderSize($parent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get the size of a folder and set it in the cache
|
||||
*
|
||||
|
||||
+15
-19
@@ -29,27 +29,26 @@ class Manager {
|
||||
private $storageLoader;
|
||||
|
||||
/**
|
||||
* @var \OC\User\Session
|
||||
* @var string
|
||||
*/
|
||||
private $userSession;
|
||||
private $uid;
|
||||
|
||||
/**
|
||||
* @param \OCP\IDBConnection $connection
|
||||
* @param \OC\Files\Mount\Manager $mountManager
|
||||
* @param \OC\User\Session $userSession
|
||||
* @param \OC\Files\Storage\Loader $storageLoader
|
||||
* @param string $uid
|
||||
*/
|
||||
public function __construct(\OCP\IDBConnection $connection, \OC\Files\Mount\Manager $mountManager,
|
||||
\OC\Files\Storage\Loader $storageLoader, \OC\User\Session $userSession) {
|
||||
\OC\Files\Storage\Loader $storageLoader, $uid) {
|
||||
$this->connection = $connection;
|
||||
$this->mountManager = $mountManager;
|
||||
$this->userSession = $userSession;
|
||||
$this->storageLoader = $storageLoader;
|
||||
$this->uid = $uid;
|
||||
}
|
||||
|
||||
public function addShare($remote, $token, $password, $name, $owner) {
|
||||
$user = $this->userSession->getUser();
|
||||
if ($user) {
|
||||
if ($this->uid) {
|
||||
$query = $this->connection->prepare('
|
||||
INSERT INTO `*PREFIX*share_external`
|
||||
(`remote`, `share_token`, `password`, `name`, `owner`, `user`, `mountpoint`, `mountpoint_hash`)
|
||||
@@ -57,7 +56,7 @@ class Manager {
|
||||
');
|
||||
$mountPoint = Filesystem::normalizePath('/' . $name);
|
||||
$hash = md5($mountPoint);
|
||||
$query->execute(array($remote, $token, $password, $name, $owner, $user->getUID(), $mountPoint, $hash));
|
||||
$query->execute(array($remote, $token, $password, $name, $owner, $this->uid, $mountPoint, $hash));
|
||||
|
||||
$options = array(
|
||||
'remote' => $remote,
|
||||
@@ -76,14 +75,13 @@ class Manager {
|
||||
return false;
|
||||
}
|
||||
|
||||
$user = $this->userSession->getUser();
|
||||
if ($user) {
|
||||
if ($this->uid) {
|
||||
$query = $this->connection->prepare('
|
||||
SELECT `remote`, `share_token`, `password`, `mountpoint`, `owner`
|
||||
FROM `*PREFIX*share_external`
|
||||
WHERE `user` = ?
|
||||
');
|
||||
$query->execute(array($user->getUID()));
|
||||
$query->execute(array($this->uid));
|
||||
|
||||
while ($row = $query->fetch()) {
|
||||
$row['manager'] = $this;
|
||||
@@ -93,18 +91,18 @@ class Manager {
|
||||
}
|
||||
}
|
||||
|
||||
public static function setup() {
|
||||
public static function setup($param) {
|
||||
$externalManager = new \OCA\Files_Sharing\External\Manager(
|
||||
\OC::$server->getDatabaseConnection(),
|
||||
\OC\Files\Filesystem::getMountManager(),
|
||||
\OC\Files\Filesystem::getLoader(),
|
||||
\OC::$server->getUserSession()
|
||||
$param['user']
|
||||
);
|
||||
$externalManager->setupMounts();
|
||||
}
|
||||
|
||||
protected function stripPath($path) {
|
||||
$prefix = '/' . $this->userSession->getUser()->getUID() . '/files';
|
||||
$prefix = '/' . $this->uid . '/files';
|
||||
return rtrim(substr($path, strlen($prefix)), '/');
|
||||
}
|
||||
|
||||
@@ -114,7 +112,7 @@ class Manager {
|
||||
*/
|
||||
protected function mountShare($data) {
|
||||
$data['manager'] = $this;
|
||||
$mountPoint = '/' . $this->userSession->getUser()->getUID() . '/files' . $data['mountpoint'];
|
||||
$mountPoint = '/' . $this->uid . '/files' . $data['mountpoint'];
|
||||
$data['mountpoint'] = $mountPoint;
|
||||
$mount = new Mount(self::STORAGE, $mountPoint, $data, $this, $this->storageLoader);
|
||||
$this->mountManager->addMount($mount);
|
||||
@@ -134,7 +132,6 @@ class Manager {
|
||||
* @return bool
|
||||
*/
|
||||
public function setMountPoint($source, $target) {
|
||||
$user = $this->userSession->getUser();
|
||||
$source = $this->stripPath($source);
|
||||
$target = $this->stripPath($target);
|
||||
$sourceHash = md5($source);
|
||||
@@ -146,13 +143,12 @@ class Manager {
|
||||
WHERE `mountpoint_hash` = ?
|
||||
AND `user` = ?
|
||||
');
|
||||
$result = (bool)$query->execute(array($target, $targetHash, $sourceHash, $user->getUID()));
|
||||
$result = (bool)$query->execute(array($target, $targetHash, $sourceHash, $this->uid));
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function removeShare($mountPoint) {
|
||||
$user = $this->userSession->getUser();
|
||||
$mountPoint = $this->stripPath($mountPoint);
|
||||
$hash = md5($mountPoint);
|
||||
$query = $this->connection->prepare('
|
||||
@@ -160,6 +156,6 @@ class Manager {
|
||||
WHERE `mountpoint_hash` = ?
|
||||
AND `user` = ?
|
||||
');
|
||||
return (bool)$query->execute(array($hash, $user->getUID()));
|
||||
return (bool)$query->execute(array($hash, $this->uid));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,9 +243,21 @@ class Helper {
|
||||
* @return string
|
||||
*/
|
||||
public static function getShareFolder() {
|
||||
$shareFolder = \OCP\Config::getSystemValue('share_folder', '/');
|
||||
$shareFolder = \OC::$server->getConfig()->getSystemValue('share_folder', '/');
|
||||
$shareFolder = \OC\Files\Filesystem::normalizePath($shareFolder);
|
||||
|
||||
return \OC\Files\Filesystem::normalizePath($shareFolder);
|
||||
if (!\OC\Files\Filesystem::file_exists($shareFolder)) {
|
||||
$dir = '';
|
||||
$subdirs = explode('/', $shareFolder);
|
||||
foreach ($subdirs as $subdir) {
|
||||
$dir = $dir . '/' . $subdir;
|
||||
if (!\OC\Files\Filesystem::is_dir($dir)) {
|
||||
\OC\Files\Filesystem::mkdir($dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $shareFolder;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Vincent Petry
|
||||
* @copyright 2015 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/>.
|
||||
*/
|
||||
|
||||
namespace OC\Files\Cache;
|
||||
|
||||
/**
|
||||
* Scanner for SharedStorage
|
||||
*/
|
||||
class SharedScanner extends Scanner {
|
||||
|
||||
/**
|
||||
* Returns metadata from the shared storage, but
|
||||
* with permissions from the source storage.
|
||||
*
|
||||
* @param string $path path of the file for which to retrieve metadata
|
||||
*
|
||||
* @return array an array of metadata of the file
|
||||
*/
|
||||
public function getData($path){
|
||||
$data = parent::getData($path);
|
||||
$sourcePath = $this->storage->getSourcePath($path);
|
||||
list($sourceStorage, $internalPath) = \OC\Files\Filesystem::resolvePath($sourcePath);
|
||||
$data['permissions'] = $sourceStorage->getPermissions($internalPath);
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,7 +199,9 @@ class OC_Share_Backend_File implements OCP\Share_Backend_File_Dependent {
|
||||
if ($itemType === 'folder') {
|
||||
$source = \OCP\Share::getItemSharedWith('folder', $mountPoint, \OC_Share_Backend_File::FORMAT_SHARED_STORAGE);
|
||||
if ($source && $target !== '') {
|
||||
$source['path'] = $source['path'].'/'.$target;
|
||||
// note: in case of ext storage mount points the path might be empty
|
||||
// which would cause a leading slash to appear
|
||||
$source['path'] = ltrim($source['path'] . '/' . $target, '/');
|
||||
}
|
||||
} else {
|
||||
$source = \OCP\Share::getItemSharedWith('file', $mountPoint, \OC_Share_Backend_File::FORMAT_SHARED_STORAGE);
|
||||
|
||||
@@ -35,8 +35,8 @@ class SharedMount extends Mount implements MoveableMount {
|
||||
$mountPoint = basename($share['file_target']);
|
||||
$parent = dirname($share['file_target']);
|
||||
|
||||
while (!\OC\Files\Filesystem::is_dir($parent)) {
|
||||
$parent = dirname($parent);
|
||||
if (!\OC\Files\Filesystem::is_dir($parent)) {
|
||||
$parent = Helper::getShareFolder();
|
||||
}
|
||||
|
||||
$newMountPoint = \OCA\Files_Sharing\Helper::generateUniqueTarget(
|
||||
|
||||
@@ -500,7 +500,7 @@ class Shared extends \OC\Files\Storage\Common implements ISharedStorage {
|
||||
if (!$storage) {
|
||||
$storage = $this;
|
||||
}
|
||||
return new \OC\Files\Cache\Scanner($storage);
|
||||
return new \OC\Files\Cache\SharedScanner($storage);
|
||||
}
|
||||
|
||||
public function getWatcher($path = '', $storage = null) {
|
||||
|
||||
@@ -145,10 +145,10 @@ class Shared_Updater {
|
||||
$shareType = $params['shareType'];
|
||||
|
||||
if ($shareType === \OCP\Share::SHARE_TYPE_USER) {
|
||||
self::correctUsersFolder($shareWith, '/');
|
||||
self::correctUsersFolder($shareWith, $params['fileTarget']);
|
||||
} elseif ($shareType === \OCP\Share::SHARE_TYPE_GROUP) {
|
||||
foreach (\OC_Group::usersInGroup($shareWith) as $user) {
|
||||
self::correctUsersFolder($user, '/');
|
||||
self::correctUsersFolder($user, $params['fileTarget']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,6 +136,7 @@ if (isset($path)) {
|
||||
$tmpl->assign('sharingToken', $token);
|
||||
$tmpl->assign('server2serversharing', Helper::isOutgoingServer2serverShareEnabled());
|
||||
$tmpl->assign('protected', isset($linkItem['share_with']) ? 'true' : 'false');
|
||||
$tmpl->assign('previewEnabled', \OC::$server->getConfig()->getSystemValue('enable_previews', true));
|
||||
|
||||
$urlLinkIdentifiers= (isset($token)?'&t='.$token:'')
|
||||
.(isset($_GET['dir'])?'&dir='.$_GET['dir']:'')
|
||||
|
||||
@@ -40,7 +40,8 @@ $server->addPlugin(new OC_Connector_Sabre_ExceptionLoggerPlugin('webdav'));
|
||||
// wait with registering these until auth is handled and the filesystem is setup
|
||||
$server->subscribeEvent('beforeMethod', function () use ($server, $objectTree, $authBackend) {
|
||||
$share = $authBackend->getShare();
|
||||
$owner = $share['uid_owner'];
|
||||
$rootShare = \OCP\Share::resolveReShare($share);
|
||||
$owner = $rootShare['uid_owner'];
|
||||
$isWritable = $share['permissions'] & (\OCP\PERMISSION_UPDATE | \OCP\PERMISSION_CREATE);
|
||||
$fileId = $share['file_source'];
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ $previewSupported = OC\Preview::isMimeSupported($_['mimetype']) ? 'true' : 'fals
|
||||
<?php if (isset($_['folder'])): ?>
|
||||
<?php print_unescaped($_['folder']); ?>
|
||||
<?php else: ?>
|
||||
<?php if (substr($_['mimetype'], 0, strpos($_['mimetype'], '/')) == 'video'): ?>
|
||||
<?php if ($_['previewEnabled'] && substr($_['mimetype'], 0, strpos($_['mimetype'], '/')) == 'video'): ?>
|
||||
<div id="imgframe">
|
||||
<video tabindex="0" controls="" preload="none">
|
||||
<source src="<?php p($_['downloadURL']); ?>" type="<?php p($_['mimetype']); ?>" />
|
||||
|
||||
@@ -29,9 +29,11 @@ class Test_Files_Sharing_Helper extends Test_Files_Sharing_Base {
|
||||
function testSetGetShareFolder() {
|
||||
$this->assertSame('/', \OCA\Files_Sharing\Helper::getShareFolder());
|
||||
|
||||
\OCA\Files_Sharing\Helper::setShareFolder('/Shared');
|
||||
\OCA\Files_Sharing\Helper::setShareFolder('/Shared/Folder');
|
||||
|
||||
$this->assertSame('/Shared', \OCA\Files_Sharing\Helper::getShareFolder());
|
||||
$sharedFolder = \OCA\Files_Sharing\Helper::getShareFolder();
|
||||
$this->assertSame('/Shared/Folder', \OCA\Files_Sharing\Helper::getShareFolder());
|
||||
$this->assertTrue(\OC\Files\Filesystem::is_dir($sharedFolder));
|
||||
|
||||
// cleanup
|
||||
\OCP\Config::deleteSystemValue('share_folder');
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Robin Appelman
|
||||
* @copyright 2015 Robin Appelman <icewind@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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
use OC\Files\View;
|
||||
|
||||
require_once __DIR__ . '/base.php';
|
||||
|
||||
class Test_Files_Sharing_Propagation extends Test_Files_Sharing_Base {
|
||||
|
||||
public function testSizePropagationWhenOwnerChangesFile() {
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
|
||||
$recipientView = new View('/' . self::TEST_FILES_SHARING_API_USER1 . '/files');
|
||||
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
|
||||
$ownerView = new View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files');
|
||||
$ownerView->mkdir('/sharedfolder/subfolder');
|
||||
$ownerView->file_put_contents('/sharedfolder/subfolder/foo.txt', 'bar');
|
||||
|
||||
$sharedFolderInfo = $ownerView->getFileInfo('/sharedfolder', false);
|
||||
\OCP\Share::shareItem('folder', $sharedFolderInfo->getId(), \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER1, 31);
|
||||
$ownerRootInfo = $ownerView->getFileInfo('', false);
|
||||
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
|
||||
$this->assertTrue($recipientView->file_exists('/sharedfolder/subfolder/foo.txt'));
|
||||
$recipientRootInfo = $recipientView->getFileInfo('', false);
|
||||
|
||||
// when file changed as owner
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
|
||||
$ownerView->file_put_contents('/sharedfolder/subfolder/foo.txt', 'foobar');
|
||||
|
||||
// size of recipient's root stays the same
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
|
||||
$newRecipientRootInfo = $recipientView->getFileInfo('', false);
|
||||
$this->assertEquals($recipientRootInfo->getSize(), $newRecipientRootInfo->getSize());
|
||||
|
||||
// size of owner's root increases
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
|
||||
$newOwnerRootInfo = $ownerView->getFileInfo('', false);
|
||||
$this->assertEquals($ownerRootInfo->getSize() + 3, $newOwnerRootInfo->getSize());
|
||||
}
|
||||
|
||||
public function testSizePropagationWhenRecipientChangesFile() {
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
|
||||
$recipientView = new View('/' . self::TEST_FILES_SHARING_API_USER1 . '/files');
|
||||
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
|
||||
$ownerView = new View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files');
|
||||
$ownerView->mkdir('/sharedfolder/subfolder');
|
||||
$ownerView->file_put_contents('/sharedfolder/subfolder/foo.txt', 'bar');
|
||||
|
||||
$sharedFolderInfo = $ownerView->getFileInfo('/sharedfolder', false);
|
||||
\OCP\Share::shareItem('folder', $sharedFolderInfo->getId(), \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER1, 31);
|
||||
$ownerRootInfo = $ownerView->getFileInfo('', false);
|
||||
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
|
||||
$this->assertTrue($recipientView->file_exists('/sharedfolder/subfolder/foo.txt'));
|
||||
$recipientRootInfo = $recipientView->getFileInfo('', false);
|
||||
|
||||
// when file changed as recipient
|
||||
$recipientView->file_put_contents('/sharedfolder/subfolder/foo.txt', 'foobar');
|
||||
|
||||
// size of recipient's root stays the same
|
||||
$newRecipientRootInfo = $recipientView->getFileInfo('', false);
|
||||
$this->assertEquals($recipientRootInfo->getSize(), $newRecipientRootInfo->getSize());
|
||||
|
||||
// size of owner's root increases
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
|
||||
$newOwnerRootInfo = $ownerView->getFileInfo('', false);
|
||||
$this->assertEquals($ownerRootInfo->getSize() + 3, $newOwnerRootInfo->getSize());
|
||||
}
|
||||
}
|
||||
@@ -115,14 +115,34 @@ class Test_Files_Sharing_Updater extends Test_Files_Sharing_Base {
|
||||
}
|
||||
}
|
||||
|
||||
public function shareFolderProvider() {
|
||||
return array(
|
||||
array('/'),
|
||||
array('/my_shares'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* if a file gets shared the etag for the recipients root should change
|
||||
*
|
||||
* @dataProvider shareFolderProvider
|
||||
*
|
||||
* @param string $shareFolder share folder to use
|
||||
*/
|
||||
function testShareFile() {
|
||||
public function testShareFile($shareFolder) {
|
||||
$config = \OC::$server->getConfig();
|
||||
$oldShareFolder = $config->getSystemValue('share_folder');
|
||||
$config->setSystemValue('share_folder', $shareFolder);
|
||||
|
||||
$this->loginHelper(self::TEST_FILES_SHARING_API_USER2);
|
||||
|
||||
$beforeShare = \OC\Files\Filesystem::getFileInfo('');
|
||||
$etagBeforeShare = $beforeShare->getEtag();
|
||||
$beforeShareRoot = \OC\Files\Filesystem::getFileInfo('');
|
||||
$etagBeforeShareRoot = $beforeShareRoot->getEtag();
|
||||
|
||||
\OC\Files\Filesystem::mkdir($shareFolder);
|
||||
|
||||
$beforeShareDir = \OC\Files\Filesystem::getFileInfo($shareFolder);
|
||||
$etagBeforeShareDir = $beforeShareDir->getEtag();
|
||||
|
||||
$this->loginHelper(self::TEST_FILES_SHARING_API_USER1);
|
||||
$fileinfo = \OC\Files\Filesystem::getFileInfo($this->folder);
|
||||
@@ -131,17 +151,25 @@ class Test_Files_Sharing_Updater extends Test_Files_Sharing_Base {
|
||||
|
||||
$this->loginHelper(self::TEST_FILES_SHARING_API_USER2);
|
||||
|
||||
$afterShare = \OC\Files\Filesystem::getFileInfo('');
|
||||
$etagAfterShare = $afterShare->getEtag();
|
||||
$afterShareRoot = \OC\Files\Filesystem::getFileInfo('');
|
||||
$etagAfterShareRoot = $afterShareRoot->getEtag();
|
||||
|
||||
$this->assertTrue(is_string($etagBeforeShare));
|
||||
$this->assertTrue(is_string($etagAfterShare));
|
||||
$this->assertTrue($etagBeforeShare !== $etagAfterShare);
|
||||
$afterShareDir = \OC\Files\Filesystem::getFileInfo($shareFolder);
|
||||
$etagAfterShareDir = $afterShareDir->getEtag();
|
||||
|
||||
$this->assertTrue(is_string($etagBeforeShareRoot));
|
||||
$this->assertTrue(is_string($etagBeforeShareDir));
|
||||
$this->assertTrue(is_string($etagAfterShareRoot));
|
||||
$this->assertTrue(is_string($etagAfterShareDir));
|
||||
$this->assertTrue($etagBeforeShareRoot !== $etagAfterShareRoot);
|
||||
$this->assertTrue($etagBeforeShareDir !== $etagAfterShareDir);
|
||||
|
||||
// cleanup
|
||||
$this->loginHelper(self::TEST_FILES_SHARING_API_USER1);
|
||||
$result = \OCP\Share::unshare('folder', $fileinfo->getId(), \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER2);
|
||||
$this->assertTrue($result);
|
||||
|
||||
$config->setSystemValue('share_folder', $oldShareFolder);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,5 +17,4 @@
|
||||
<documentation>
|
||||
<user>user-trashbin</user>
|
||||
</documentation>
|
||||
<ocsid>166052</ocsid>
|
||||
</info>
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
$installedVersion=OCP\Config::getAppValue('files_trashbin', 'installed_version');
|
||||
if (version_compare($installedVersion, '0.5', '<=')) {
|
||||
$connection = OC_DB::getConnection();
|
||||
$platform = $connection->getDatabasePlatform();
|
||||
if ($platform->getName() === 'oracle') {
|
||||
try {
|
||||
$connection->beginTransaction();
|
||||
$sql1 = 'ALTER TABLE `*PREFIX*files_trash` ADD `auto_id` NUMBER(10) DEFAULT NULL';
|
||||
\OC_DB::executeAudited($sql1, array());
|
||||
$sql2 = 'CREATE SEQUENCE `*PREFIX*files_trash_seq` start with 1 increment by 1 nomaxvalue';
|
||||
\OC_DB::executeAudited($sql2, array());
|
||||
$sql3 = 'UPDATE `*PREFIX*files_trash` SET `auto_id` = `*PREFIX*files_trash_seq`.nextval';
|
||||
\OC_DB::executeAudited($sql3, array());
|
||||
$connection->commit();
|
||||
} catch (\DatabaseException $e) {
|
||||
\OCP\Util::writeLog('files_trashbin', "Oracle upgrade fixup failed: " . $e->getMessage(), \OCP\Util::WARN);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
0.6.2
|
||||
0.6.3
|
||||
|
||||
@@ -255,6 +255,10 @@
|
||||
updateStorageStatistics: function() {
|
||||
// no op because the trashbin doesn't have
|
||||
// storage info like free space / used space
|
||||
},
|
||||
|
||||
isSelectedDeletable: function() {
|
||||
return true;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
$TRANSLATIONS = array(
|
||||
"Couldn't delete %s permanently" => "Impossible d'effacer %s de façon permanente",
|
||||
"Couldn't delete %s permanently" => "Impossible de supprimer %s définitivement",
|
||||
"Couldn't restore %s" => "Impossible de restaurer %s",
|
||||
"Deleted files" => "Fichiers supprimés",
|
||||
"Restore" => "Restaurer",
|
||||
|
||||
@@ -30,6 +30,13 @@ class Trashbin {
|
||||
// unit: percentage; 50% of available disk space/quota
|
||||
const DEFAULTMAXSIZE = 50;
|
||||
|
||||
/**
|
||||
* Whether versions have already be rescanned during this PHP request
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private static $scannedVersions = false;
|
||||
|
||||
public static function getUidAndFilename($filename) {
|
||||
$uid = \OC\Files\Filesystem::getOwner($filename);
|
||||
\OC\Files\Filesystem::initMountPoints($uid);
|
||||
@@ -97,6 +104,7 @@ class Trashbin {
|
||||
* move file to the trash bin
|
||||
*
|
||||
* @param string $file_path path to the deleted file/directory relative to the files root directory
|
||||
* @return bool
|
||||
*/
|
||||
public static function move2trash($file_path) {
|
||||
$user = \OCP\User::getUser();
|
||||
@@ -109,6 +117,9 @@ class Trashbin {
|
||||
}
|
||||
|
||||
self::setUpTrash($user);
|
||||
if ($owner !== $user) {
|
||||
self::setUpTrash($owner);
|
||||
}
|
||||
|
||||
$view = new \OC\Files\View('/' . $user);
|
||||
$path_parts = pathinfo($file_path);
|
||||
@@ -279,7 +290,7 @@ class Trashbin {
|
||||
$rootView->rename($sharekeys, $user . '/files_trashbin/share-keys/' . $filename . '.d' . $timestamp);
|
||||
} else {
|
||||
// handle share-keys
|
||||
$matches = \OCA\Encryption\Helper::findShareKeys($ownerPath, $sharekeys, $rootView);
|
||||
$matches = \OCA\Encryption\Helper::findShareKeys($file_path, $sharekeys, $rootView);
|
||||
foreach ($matches as $src) {
|
||||
// get source file parts
|
||||
$pathinfo = pathinfo($src);
|
||||
@@ -884,9 +895,12 @@ class Trashbin {
|
||||
$versions = array();
|
||||
|
||||
//force rescan of versions, local storage may not have updated the cache
|
||||
/** @var \OC\Files\Storage\Storage $storage */
|
||||
list($storage, ) = $view->resolvePath('/');
|
||||
$storage->getScanner()->scan('files_trashbin');
|
||||
if (!self::$scannedVersions) {
|
||||
/** @var \OC\Files\Storage\Storage $storage */
|
||||
list($storage, ) = $view->resolvePath('/');
|
||||
$storage->getScanner()->scan('files_trashbin/versions');
|
||||
self::$scannedVersions = true;
|
||||
}
|
||||
|
||||
if ($timestamp) {
|
||||
// fetch for old versions
|
||||
|
||||
@@ -31,14 +31,18 @@ if($maxX === 0 || $maxY === 0) {
|
||||
|
||||
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);
|
||||
$preview->setMaxX($maxX);
|
||||
$preview->setMaxY($maxY);
|
||||
$preview->setScalingUp($scalingUp);
|
||||
if (is_null($file)) {
|
||||
\OC_Response::setStatus(404);
|
||||
} else {
|
||||
$preview = new \OC\Preview($user, 'files_versions', $file . '.v' . $version);
|
||||
$mimetype = \OC_Helper::getFileNameMimeType($file);
|
||||
$preview->setMimetype($mimetype);
|
||||
$preview->setMaxX($maxX);
|
||||
$preview->setMaxY($maxY);
|
||||
$preview->setScalingUp($scalingUp);
|
||||
|
||||
$preview->showPreview();
|
||||
$preview->showPreview();
|
||||
}
|
||||
}catch(\Exception $e) {
|
||||
\OC_Response::setStatus(500);
|
||||
\OC_Log::write('core', $e->getmessage(), \OC_Log::DEBUG);
|
||||
|
||||
@@ -18,5 +18,4 @@ In addition to the expiry of versions, ownCloud’s versions app makes certain n
|
||||
<user>user-versions</user>
|
||||
</documentation>
|
||||
<default_enable/>
|
||||
<ocsid>166053</ocsid>
|
||||
</info>
|
||||
|
||||
@@ -1 +1 @@
|
||||
1.0.5
|
||||
1.0.6
|
||||
|
||||
@@ -38,7 +38,7 @@ $ftype = $view->getMimeType('/'.$uid.'/files/'.$filename);
|
||||
header('Content-Type:'.$ftype);
|
||||
OCP\Response::setContentDispositionHeader(basename($filename), 'attachment');
|
||||
OCP\Response::disableCaching();
|
||||
header('Content-Length: '.$view->filesize($versionName));
|
||||
OCP\Response::setContentLengthHeader($view->filesize($versionName));
|
||||
|
||||
OC_Util::obEnd();
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ $TRANSLATIONS = array(
|
||||
"Versions" => "Versions",
|
||||
"Failed to revert {file} to revision {timestamp}." => "Échec du retour du fichier {file} à la révision {timestamp}.",
|
||||
"More versions..." => "Plus de versions...",
|
||||
"No other versions available" => "Aucune autre version disponible",
|
||||
"No other versions available" => "Aucune autre version n'est disponible",
|
||||
"Restore" => "Restaurer"
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=2; plural=(n > 1);";
|
||||
|
||||
@@ -27,7 +27,8 @@ OCP\JSON::checkAppEnabled('user_ldap');
|
||||
OCP\JSON::callCheck();
|
||||
|
||||
$subject = $_POST['ldap_clear_mapping'];
|
||||
if(\OCA\user_ldap\lib\Helper::clearMapping($subject)) {
|
||||
$helper = new \OCA\user_ldap\lib\Helper();
|
||||
if($helper->clearMapping($subject)) {
|
||||
OCP\JSON::success();
|
||||
} else {
|
||||
$l=OC_L10N::get('user_ldap');
|
||||
|
||||
@@ -27,7 +27,8 @@ OCP\JSON::checkAppEnabled('user_ldap');
|
||||
OCP\JSON::callCheck();
|
||||
|
||||
$prefix = $_POST['ldap_serverconfig_chooser'];
|
||||
if(\OCA\user_ldap\lib\Helper::deleteServerConfiguration($prefix)) {
|
||||
$helper = new \OCA\user_ldap\lib\Helper();
|
||||
if($helper->deleteServerConfiguration($prefix)) {
|
||||
OCP\JSON::success();
|
||||
} else {
|
||||
$l=OC_L10N::get('user_ldap');
|
||||
|
||||
@@ -26,7 +26,8 @@ OCP\JSON::checkAdminUser();
|
||||
OCP\JSON::checkAppEnabled('user_ldap');
|
||||
OCP\JSON::callCheck();
|
||||
|
||||
$serverConnections = \OCA\user_ldap\lib\Helper::getServerConfigurationPrefixes();
|
||||
$helper = new \OCA\user_ldap\lib\Helper();
|
||||
$serverConnections = $helper->getServerConfigurationPrefixes();
|
||||
sort($serverConnections);
|
||||
$lk = array_pop($serverConnections);
|
||||
$ln = intval(str_replace('s', '', $lk));
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*
|
||||
* @author Dominik Schmidt
|
||||
* @copyright 2011 Dominik Schmidt dev@dominik-schmidt.de
|
||||
* @copyright 2014 Arthur Schiwon <blizzz@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
|
||||
@@ -23,7 +24,8 @@
|
||||
|
||||
OCP\App::registerAdmin('user_ldap', 'settings');
|
||||
|
||||
$configPrefixes = OCA\user_ldap\lib\Helper::getServerConfigurationPrefixes(true);
|
||||
$helper = new \OCA\user_ldap\lib\Helper();
|
||||
$configPrefixes = $helper->getServerConfigurationPrefixes(true);
|
||||
$ldapWrapper = new OCA\user_ldap\lib\LDAP();
|
||||
if(count($configPrefixes) === 1) {
|
||||
$ocConfig = \OC::$server->getConfig();
|
||||
@@ -47,15 +49,9 @@ if(count($configPrefixes) > 0) {
|
||||
OC_Group::useBackend($groupBackend);
|
||||
}
|
||||
|
||||
// add settings page to navigation
|
||||
$entry = array(
|
||||
'id' => 'user_ldap_settings',
|
||||
'order'=>1,
|
||||
'href' => OCP\Util::linkTo( 'user_ldap', 'settings.php' ),
|
||||
'name' => 'LDAP'
|
||||
);
|
||||
|
||||
OCP\Backgroundjob::registerJob('OCA\user_ldap\lib\Jobs');
|
||||
OCP\Backgroundjob::registerJob('\OCA\User_LDAP\Jobs\CleanUp');
|
||||
|
||||
if(OCP\App::isEnabled('user_webdavauth')) {
|
||||
OCP\Util::writeLog('user_ldap',
|
||||
'user_ldap and user_webdavauth are incompatible. You may experience unexpected behaviour',
|
||||
|
||||
@@ -16,5 +16,4 @@ A user logs into ownCloud with their LDAP or AD credentials, and is granted acce
|
||||
<documentation>
|
||||
<admin>admin-ldap</admin>
|
||||
</documentation>
|
||||
<ocsid>166061</ocsid>
|
||||
</info>
|
||||
|
||||
@@ -6,7 +6,20 @@
|
||||
* See the COPYING-README file.
|
||||
*/
|
||||
|
||||
use OCA\user_ldap\lib\Helper;
|
||||
use OCA\user_ldap\lib\LDAP;
|
||||
use OCA\user_ldap\User_Proxy;
|
||||
|
||||
$application->add(new OCA\user_ldap\Command\ShowConfig());
|
||||
$application->add(new OCA\user_ldap\Command\SetConfig());
|
||||
$application->add(new OCA\user_ldap\Command\TestConfig());
|
||||
$application->add(new OCA\user_ldap\Command\Search());
|
||||
$application->add(new OCA\user_ldap\Command\ShowRemnants());
|
||||
$helper = new OCA\user_ldap\lib\Helper();
|
||||
$uBackend = new OCA\user_ldap\User_Proxy(
|
||||
$helper->getServerConfigurationPrefixes(true),
|
||||
new OCA\user_ldap\lib\LDAP()
|
||||
);
|
||||
$application->add(new OCA\user_ldap\Command\CheckUser(
|
||||
$uBackend, $helper, \OC::$server->getConfig()
|
||||
));
|
||||
|
||||
@@ -10,7 +10,8 @@ if($state === 'unset') {
|
||||
$installedVersion = OCP\Config::getAppValue('user_ldap', 'installed_version');
|
||||
$enableRawMode = version_compare($installedVersion, '0.4.1', '<');
|
||||
|
||||
$configPrefixes = OCA\user_ldap\lib\Helper::getServerConfigurationPrefixes(true);
|
||||
$helper = new \OCA\user_ldap\lib\Helper();
|
||||
$configPrefixes = $helper->getServerConfigurationPrefixes(true);
|
||||
$ldap = new OCA\user_ldap\lib\LDAP();
|
||||
foreach($configPrefixes as $config) {
|
||||
$connection = new OCA\user_ldap\lib\Connection($ldap, $config);
|
||||
@@ -19,7 +20,7 @@ foreach($configPrefixes as $config) {
|
||||
'user_ldap', $config.'ldap_uuid_user_attribute', 'not existing');
|
||||
if($state === 'non existing') {
|
||||
$value = \OCP\Config::getAppValue(
|
||||
'user_ldap', $config.'ldap_uuid_attribute', '');
|
||||
'user_ldap', $config.'ldap_uuid_attribute', 'auto');
|
||||
\OCP\Config::setAppValue(
|
||||
'user_ldap', $config.'ldap_uuid_user_attribute', $value);
|
||||
\OCP\Config::setAppValue(
|
||||
|
||||
@@ -1 +1 @@
|
||||
0.4.4
|
||||
0.4.6
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (c) 2014 Arthur Schiwon <blizzz@owncloud.com>
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later.
|
||||
* See the COPYING-README file.
|
||||
*/
|
||||
|
||||
namespace OCA\user_ldap\Command;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
use OCA\user_ldap\lib\user\User;
|
||||
use OCA\User_LDAP\lib\user\Manager;
|
||||
use OCA\user_ldap\lib\Helper;
|
||||
use OCA\user_ldap\User_Proxy;
|
||||
|
||||
class CheckUser extends Command {
|
||||
/** @var \OCA\user_ldap\User_Proxy */
|
||||
protected $backend;
|
||||
|
||||
/** @var \OCA\User_LDAP\lib\Helper */
|
||||
protected $helper;
|
||||
|
||||
/** @var \OCP\IConfig */
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* @param OCA\user_ldap\User_Proxy $uBackend
|
||||
* @param OCA\User_LDAP\lib\Helper $helper
|
||||
* @param OCP\IConfig $config
|
||||
*/
|
||||
public function __construct(User_Proxy $uBackend, Helper $helper, \OCP\IConfig $config) {
|
||||
$this->backend = $uBackend;
|
||||
$this->helper = $helper;
|
||||
$this->config = $config;
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure() {
|
||||
$this
|
||||
->setName('ldap:check-user')
|
||||
->setDescription('checks whether a user exists on LDAP.')
|
||||
->addArgument(
|
||||
'ocName',
|
||||
InputArgument::REQUIRED,
|
||||
'the user name as used in ownCloud'
|
||||
)
|
||||
->addOption(
|
||||
'force',
|
||||
null,
|
||||
InputOption::VALUE_NONE,
|
||||
'ignores disabled LDAP configuration'
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output) {
|
||||
try {
|
||||
$uid = $input->getArgument('ocName');
|
||||
$this->isAllowed($input->getOption('force'));
|
||||
$this->confirmUserIsMapped($uid);
|
||||
$exists = $this->backend->userExistsOnLDAP($uid);
|
||||
if($exists === true) {
|
||||
$output->writeln('The user is still available on LDAP.');
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO FIXME consolidate next line in DeletedUsersIndex
|
||||
// (impractical now, because of class dependencies)
|
||||
$this->config->setUserValue($uid, 'user_ldap', 'isDeleted', '1');
|
||||
|
||||
$output->writeln('The user does not exists on LDAP anymore.');
|
||||
$output->writeln('Clean up the user\'s remnants by: ./occ user:delete "'
|
||||
. $uid . '"');
|
||||
} catch (\Exception $e) {
|
||||
$output->writeln('<error>' . $e->getMessage(). '</error>');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* checks whether a user is actually mapped
|
||||
* @param string $ocName the username as used in ownCloud
|
||||
* @throws \Exception
|
||||
* @return bool
|
||||
*/
|
||||
protected function confirmUserIsMapped($ocName) {
|
||||
//TODO FIXME this should go to Mappings in OC 8
|
||||
$db = \OC::$server->getDatabaseConnection();
|
||||
$query = $db->prepare('
|
||||
SELECT
|
||||
`ldap_dn` AS `dn`
|
||||
FROM `*PREFIX*ldap_user_mapping`
|
||||
WHERE `owncloud_name` = ?'
|
||||
);
|
||||
|
||||
$query->execute(array($ocName));
|
||||
$result = $query->fetchColumn();
|
||||
|
||||
if($result === false) {
|
||||
throw new \Exception('The given user is not a recognized LDAP user.');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* checks whether the setup allows reliable checking of LDAP user existance
|
||||
* @throws \Exception
|
||||
* @return bool
|
||||
*/
|
||||
protected function isAllowed($force) {
|
||||
if($this->helper->haveDisabledConfigurations() && !$force) {
|
||||
throw new \Exception('Cannot check user existance, because '
|
||||
. 'disabled LDAP configurations are present.');
|
||||
}
|
||||
|
||||
// we don't check ldapUserCleanupInterval from config.php because this
|
||||
// action is triggered manually, while the setting only controls the
|
||||
// background job.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -74,7 +74,8 @@ class Search extends Command {
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output) {
|
||||
$configPrefixes = Helper::getServerConfigurationPrefixes(true);
|
||||
$helper = new Helper();
|
||||
$configPrefixes = $helper->getServerConfigurationPrefixes(true);
|
||||
$ldapWrapper = new LDAP();
|
||||
|
||||
$offset = intval($input->getOption('offset'));
|
||||
|
||||
@@ -41,7 +41,8 @@ class SetConfig extends Command {
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output) {
|
||||
$availableConfigs = Helper::getServerConfigurationPrefixes();
|
||||
$helper = new Helper();
|
||||
$availableConfigs = $helper->getServerConfigurationPrefixes();
|
||||
$configID = $input->getArgument('configID');
|
||||
if(!in_array($configID, $availableConfigs)) {
|
||||
$output->writeln("Invalid configID");
|
||||
|
||||
@@ -31,7 +31,8 @@ class ShowConfig extends Command {
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output) {
|
||||
$availableConfigs = Helper::getServerConfigurationPrefixes();
|
||||
$helper = new Helper();
|
||||
$availableConfigs = $helper->getServerConfigurationPrefixes();
|
||||
$configID = $input->getArgument('configID');
|
||||
if(!is_null($configID)) {
|
||||
$configIDs[] = $configID;
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (c) 2014 Arthur Schiwon <blizzz@owncloud.com>
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later.
|
||||
* See the COPYING-README file.
|
||||
*/
|
||||
|
||||
namespace OCA\user_ldap\Command;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
use OCA\user_ldap\lib\user\DeletedUsersIndex;
|
||||
use OCA\User_LDAP\lib\Connection;
|
||||
use OCA\User_LDAP\lib\Access;
|
||||
|
||||
class ShowRemnants extends Command {
|
||||
|
||||
protected function configure() {
|
||||
$this
|
||||
->setName('ldap:show-remnants')
|
||||
->setDescription('shows which users are not available on LDAP anymore, but have remnants in ownCloud.')
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output) {
|
||||
$dui = new DeletedUsersIndex(
|
||||
new \OC\Preferences(\OC_DB::getConnection()),
|
||||
\OC::$server->getDatabaseConnection(),
|
||||
$this->getAccess()
|
||||
);
|
||||
|
||||
/** @var \Symfony\Component\Console\Helper\Table $table */
|
||||
$table = $this->getHelperSet()->get('table');
|
||||
$table->setHeaders(array(
|
||||
'ownCloud name', 'Display Name', 'LDAP UID', 'LDAP DN', 'Last Login',
|
||||
'Dir', 'Sharer'));
|
||||
$rows = array();
|
||||
$offset = 0;
|
||||
do {
|
||||
$resultSet = $dui->getUsers($offset);
|
||||
$offset += count($resultSet);
|
||||
foreach($resultSet as $user) {
|
||||
$hAS = $user->getHasActiveShares() ? 'Y' : 'N';
|
||||
$lastLogin = ($user->getLastLogin() > 0) ?
|
||||
\OCP\Util::formatDate($user->getLastLogin()) : '-';
|
||||
$rows[] = array(
|
||||
$user->getOCName(),
|
||||
$user->getDisplayName(),
|
||||
$user->getUid(),
|
||||
$user->getDN(),
|
||||
$lastLogin,
|
||||
$user->getHomePath(),
|
||||
$hAS
|
||||
);
|
||||
}
|
||||
} while (count($resultSet) === 10);
|
||||
|
||||
$table->setRows($rows);
|
||||
$table->render($output);
|
||||
}
|
||||
|
||||
protected function getAccess() {
|
||||
$ldap = new \OCA\user_ldap\lib\LDAP();
|
||||
$dummyConnection = new Connection($ldap, '', null);
|
||||
$userManager = new \OCA\user_ldap\lib\user\Manager(
|
||||
\OC::$server->getConfig(),
|
||||
new \OCA\user_ldap\lib\FilesystemHelper(),
|
||||
new \OCA\user_ldap\lib\LogWrapper(),
|
||||
\OC::$server->getAvatarManager(),
|
||||
new \OCP\Image()
|
||||
);
|
||||
$access = new Access($dummyConnection, $ldap, $userManager);
|
||||
return $access;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -31,7 +31,8 @@ class TestConfig extends Command {
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output) {
|
||||
$availableConfigs = Helper::getServerConfigurationPrefixes();
|
||||
$helper = new Helper();
|
||||
$availableConfigs = $helper->getServerConfigurationPrefixes();
|
||||
$configID = $input->getArgument('configID');
|
||||
if(!in_array($configID, $availableConfigs)) {
|
||||
$output->writeln("Invalid configID");
|
||||
|
||||
@@ -248,33 +248,77 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
|
||||
return $this->getEntryGroupID($dn, 'primaryGroupID');
|
||||
}
|
||||
|
||||
/**
|
||||
* returns a filter for a "users in primary group" search or count operation
|
||||
*
|
||||
* @param string $groupDN
|
||||
* @param string $search
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function prepareFilterForUsersInPrimaryGroup($groupDN, $search = '') {
|
||||
$groupID = $this->getGroupPrimaryGroupID($groupDN);
|
||||
if($groupID === false) {
|
||||
throw new \Exception('Not a valid group');
|
||||
}
|
||||
|
||||
$filterParts = array();
|
||||
// part for counting users (see countUsers in user backend)
|
||||
// it is consolidated in OC 8. No big changes for OC 7.
|
||||
$filterParts[] = \OCP\Util::mb_str_replace(
|
||||
'%uid', '*', $this->access->connection->ldapLoginFilter, 'UTF-8');
|
||||
if(!empty($search)) {
|
||||
$search = $this->access->escapeFilterPart($search, true);
|
||||
$filterParts[] = $this->access->getFilterPartForUserSearch($search);
|
||||
}
|
||||
$filterParts[] = 'primaryGroupID=' . $groupID;
|
||||
|
||||
$filter = $this->access->combineFilterWithAnd($filterParts);
|
||||
|
||||
return $filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns a list of users that have the given group as primary group
|
||||
*
|
||||
* @param string $groupDN
|
||||
* @param $limit
|
||||
* @param string $search
|
||||
* @param int $limit
|
||||
* @param int $offset
|
||||
* @return string[]
|
||||
*/
|
||||
public function getUsersInPrimaryGroup($groupDN, $limit = -1, $offset = 0) {
|
||||
$groupID = $this->getGroupPrimaryGroupID($groupDN);
|
||||
if($groupID === false) {
|
||||
public function getUsersInPrimaryGroup($groupDN, $search = '', $limit = -1, $offset = 0) {
|
||||
try {
|
||||
$filter = $this->prepareFilterForUsersInPrimaryGroup($groupDN, $search);
|
||||
$users = $this->access->fetchListOfUsers(
|
||||
$filter,
|
||||
array($this->access->connection->ldapUserDisplayName, 'dn'),
|
||||
$limit,
|
||||
$offset
|
||||
);
|
||||
return $this->access->ownCloudUserNames($users);
|
||||
} catch (\Exception $e) {
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
$filter = $this->access->combineFilterWithAnd(array(
|
||||
$this->access->connection->ldapUserFilter,
|
||||
'primaryGroupID=' . $groupID
|
||||
));
|
||||
|
||||
$users = $this->access->fetchListOfUsers(
|
||||
$filter,
|
||||
array($this->access->connection->ldapUserDisplayName, 'dn'),
|
||||
$limit,
|
||||
$offset
|
||||
);
|
||||
|
||||
return $users;
|
||||
/**
|
||||
* returns the number of users that have the given group as primary group
|
||||
*
|
||||
* @param string $groupDN
|
||||
* @param string $search
|
||||
* @param int $limit
|
||||
* @param int $offset
|
||||
* @return int
|
||||
*/
|
||||
public function countUsersInPrimaryGroup($groupDN, $search = '', $limit = -1, $offset = 0) {
|
||||
try {
|
||||
$filter = $this->prepareFilterForUsersInPrimaryGroup($groupDN, $search);
|
||||
$users = $this->access->countUsers($filter, array('dn'), $limit, $offset);
|
||||
return (int)$users;
|
||||
} catch (\Exception $e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -405,6 +449,7 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
|
||||
if(!$this->groupExists($gid)) {
|
||||
return array();
|
||||
}
|
||||
$search = $this->access->escapeFilterPart($search, true);
|
||||
$cacheKey = 'usersInGroup-'.$gid.'-'.$search.'-'.$limit.'-'.$offset;
|
||||
// check for cache of the exact query
|
||||
$groupUsers = $this->access->connection->getFromCache($cacheKey);
|
||||
@@ -430,8 +475,9 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
|
||||
return array();
|
||||
}
|
||||
|
||||
$primaryUsers = $this->getUsersInPrimaryGroup($groupDN, $search, $limit, $offset);
|
||||
$members = array_keys($this->_groupMembers($groupDN));
|
||||
if(!$members) {
|
||||
if(!$members && empty($primaryUsers)) {
|
||||
//in case users could not be retrieved, return empty result set
|
||||
$this->access->connection->writeToCache($cacheKey, array());
|
||||
return array();
|
||||
@@ -468,13 +514,11 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
|
||||
}
|
||||
}
|
||||
|
||||
$groupUsers = array_unique(array_merge($groupUsers, $primaryUsers));
|
||||
natsort($groupUsers);
|
||||
$this->access->connection->writeToCache('usersInGroup-'.$gid.'-'.$search, $groupUsers);
|
||||
$groupUsers = array_slice($groupUsers, $offset, $limit);
|
||||
|
||||
//and get users that have the group as primary
|
||||
$primaryUsers = $this->getUsersInPrimaryGroup($groupDN, $limit, $offset);
|
||||
$groupUsers = array_unique(array_merge($groupUsers, $primaryUsers));
|
||||
|
||||
$this->access->connection->writeToCache($cacheKey, $groupUsers);
|
||||
|
||||
@@ -505,17 +549,19 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
|
||||
}
|
||||
|
||||
$members = array_keys($this->_groupMembers($groupDN));
|
||||
if(!$members) {
|
||||
$primaryUserCount = $this->countUsersInPrimaryGroup($groupDN, '');
|
||||
if(!$members && $primaryUserCount === 0) {
|
||||
//in case users could not be retrieved, return empty result set
|
||||
$this->access->connection->writeToCache($cacheKey, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(empty($search)) {
|
||||
$groupUsers = count($members);
|
||||
$groupUsers = count($members) + $primaryUserCount;
|
||||
$this->access->connection->writeToCache($cacheKey, $groupUsers);
|
||||
return $groupUsers;
|
||||
}
|
||||
$search = $this->access->escapeFilterPart($search, true);
|
||||
$isMemberUid =
|
||||
(strtolower($this->access->connection->ldapGroupMemberAssocAttr)
|
||||
=== 'memberuid');
|
||||
@@ -557,10 +603,9 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
|
||||
}
|
||||
|
||||
//and get users that have the group as primary
|
||||
$primaryUsers = $this->getUsersInPrimaryGroup($groupDN);
|
||||
$groupUsers = array_unique(array_merge($groupUsers, $primaryUsers));
|
||||
$primaryUsers = $this->countUsersInPrimaryGroup($groupDN, $search);
|
||||
|
||||
return count($groupUsers);
|
||||
return count($groupUsers) + $primaryUsers;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -623,6 +668,7 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
|
||||
if(!$this->enabled) {
|
||||
return array();
|
||||
}
|
||||
$search = $this->access->escapeFilterPart($search, true);
|
||||
$pagingSize = $this->access->connection->ldapPagingSize;
|
||||
if ((! $this->access->connection->hasPagedResultSupport)
|
||||
|| empty($pagingSize)) {
|
||||
@@ -630,7 +676,7 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
|
||||
}
|
||||
$maxGroups = 100000; // limit max results (just for safety reasons)
|
||||
if ($limit > -1) {
|
||||
$overallLimit = min($limit, $maxGroups);
|
||||
$overallLimit = min($limit + $offset, $maxGroups);
|
||||
} else {
|
||||
$overallLimit = $maxGroups;
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ $TRANSLATIONS = array(
|
||||
"Other Attributes:" => "Autres attributs :",
|
||||
"Defines the filter to apply, when login is attempted. %%uid replaces the username in the login action. Example: \"uid=%%uid\"" => "Définit le filtre à appliquer lors d'une tentative de connexion. %%uid remplace le nom d'utilisateur lors de la connexion. Exemple : \"uid=%%uid\"",
|
||||
"1. Server" => "1. Serveur",
|
||||
"%s. Server:" => "%s. Serveur:",
|
||||
"%s. Server:" => "%s. Serveur :",
|
||||
"Add Server Configuration" => "Ajouter une configuration du serveur",
|
||||
"Delete Configuration" => "Suppression de la configuration",
|
||||
"Host" => "Hôte",
|
||||
@@ -90,19 +90,19 @@ $TRANSLATIONS = array(
|
||||
"in seconds. A change empties the cache." => "en secondes. Tout changement vide le cache.",
|
||||
"Directory Settings" => "Paramètres du répertoire",
|
||||
"User Display Name Field" => "Champ \"nom d'affichage\" de l'utilisateur",
|
||||
"The LDAP attribute to use to generate the user's display name." => "L'attribut LDAP utilisé pour générer le nom d'utilisateur affiché.",
|
||||
"The LDAP attribute to use to generate the user's display name." => "L'attribut LDAP utilisé pour générer le nom d'affichage de l'utilisateur.",
|
||||
"Base User Tree" => "DN racine de l'arbre utilisateurs",
|
||||
"One User Base DN per line" => "Un DN racine utilisateur par ligne",
|
||||
"User Search Attributes" => "Recherche des attributs utilisateur",
|
||||
"Optional; one attribute per line" => "Optionnel, un attribut par ligne",
|
||||
"Group Display Name Field" => "Champ \"nom d'affichage\" du groupe",
|
||||
"The LDAP attribute to use to generate the groups's display name." => "L'attribut LDAP utilisé pour générer le nom de groupe affiché.",
|
||||
"The LDAP attribute to use to generate the groups's display name." => "L'attribut LDAP utilisé pour générer le nom d'affichage du groupe.",
|
||||
"Base Group Tree" => "DN racine de l'arbre groupes",
|
||||
"One Group Base DN per line" => "Un DN racine groupe par ligne",
|
||||
"Group Search Attributes" => "Recherche des attributs du groupe",
|
||||
"Group-Member association" => "Association groupe-membre",
|
||||
"Nested Groups" => "Groupes imbriqués",
|
||||
"When switched on, groups that contain groups are supported. (Only works if the group member attribute contains DNs.)" => "Si activé, les groupes contenant d'autres groupes sont supportés (fonctionne uniquement si l'attribut membre du groupe contient des DNs).",
|
||||
"When switched on, groups that contain groups are supported. (Only works if the group member attribute contains DNs.)" => "Si activé, les groupes contenant d'autres groupes sont pris en charge (fonctionne uniquement si l'attribut membre du groupe contient des DNs).",
|
||||
"Paging chunksize" => "Dimensionnement des paginations",
|
||||
"Chunksize used for paged LDAP searches that may return bulky results like user or group enumeration. (Setting it 0 disables paged LDAP searches in those situations.)" => "La taille d'une part (chunksize) est utilisée pour les recherches paginées de LDAP qui peuvent retourner des résultats par lots comme une énumération d'utilisateurs ou groupes. (Configurer à 0 pour désactiver les recherches paginées de LDAP.)",
|
||||
"Special Attributes" => "Attributs spéciaux",
|
||||
@@ -113,8 +113,8 @@ $TRANSLATIONS = array(
|
||||
"User Home Folder Naming Rule" => "Convention de nommage du répertoire utilisateur",
|
||||
"Leave empty for user name (default). Otherwise, specify an LDAP/AD attribute." => "Laisser vide ",
|
||||
"Internal Username" => "Nom d'utilisateur interne",
|
||||
"By default the internal username will be created from the UUID attribute. It makes sure that the username is unique and characters do not need to be converted. The internal username has the restriction that only these characters are allowed: [ a-zA-Z0-9_.@- ]. Other characters are replaced with their ASCII correspondence or simply omitted. On collisions a number will be added/increased. The internal username is used to identify a user internally. It is also the default name for the user home folder. It is also a part of remote URLs, for instance for all *DAV services. With this setting, the default behavior can be overridden. To achieve a similar behavior as before ownCloud 5 enter the user display name attribute in the following field. Leave it empty for default behavior. Changes will have effect only on newly mapped (added) LDAP users." => "Par défaut le nom d'utilisateur interne sera créé à partir de l'attribut UUID. Ceci permet d'assurer que le nom d'utilisateur est unique et que les caractères ne nécessitent pas de conversion. Le nom d'utilisateur interne doit contenir uniquement les caractères suivants : [ a-zA-Z0-9_.@- ]. Les autres caractères sont remplacés par leur correspondance ASCII ou simplement omis. En cas de collision, un nombre est incrémenté/décrémenté. Le nom d'utilisateur interne est utilisé pour identifier l'utilisateur au sein du système. C'est aussi le nom par défaut du répertoire utilisateur dans ownCloud. C'est aussi le port d'URLs distants, par exemple pour tous les services *DAV. Le comportement par défaut peut être modifié à l'aide de ce paramètre. Pour obtenir un comportement similaire aux versions précédentes à ownCloud 5, saisir le nom d'utilisateur à afficher dans le champ suivant. Laissez à blanc pour le comportement par défaut. Les modifications prendront effet seulement pour les nouveaux (ajoutés) utilisateurs LDAP.",
|
||||
"Internal Username Attribute:" => "Nom d'utilisateur interne:",
|
||||
"By default the internal username will be created from the UUID attribute. It makes sure that the username is unique and characters do not need to be converted. The internal username has the restriction that only these characters are allowed: [ a-zA-Z0-9_.@- ]. Other characters are replaced with their ASCII correspondence or simply omitted. On collisions a number will be added/increased. The internal username is used to identify a user internally. It is also the default name for the user home folder. It is also a part of remote URLs, for instance for all *DAV services. With this setting, the default behavior can be overridden. To achieve a similar behavior as before ownCloud 5 enter the user display name attribute in the following field. Leave it empty for default behavior. Changes will have effect only on newly mapped (added) LDAP users." => "Par défaut le nom d'utilisateur interne sera créé à partir de l'attribut UUID. Ceci permet d'assurer que le nom d'utilisateur est unique et que les caractères ne nécessitent pas de conversion. Le nom d'utilisateur interne doit contenir uniquement les caractères suivants : [ a-zA-Z0-9_.@- ]. Les autres caractères sont remplacés par leur correspondance ASCII ou simplement omis. En cas de collision, un nombre est ajouté/incrémenté. Le nom d'utilisateur interne est utilisé pour identifier l'utilisateur au sein du système. C'est aussi le nom par défaut du répertoire utilisateur dans ownCloud. Il fait aussi partie de certains URL de services, par exemple pour tous les services *DAV. Le comportement par défaut peut être modifié à l'aide de ce paramètre. Pour obtenir un comportement similaire aux versions précédentes à ownCloud 5, saisir le nom d'utilisateur à afficher dans le champ suivant. Laissez à blanc pour le comportement par défaut. Les modifications prendront effet seulement pour les nouveaux (ajoutés) utilisateurs LDAP.",
|
||||
"Internal Username Attribute:" => "Nom d'utilisateur interne :",
|
||||
"Override UUID detection" => "Surcharger la détection d'UUID",
|
||||
"By default, the UUID attribute is automatically detected. The UUID attribute is used to doubtlessly identify LDAP users and groups. Also, the internal username will be created based on the UUID, if not specified otherwise above. You can override the setting and pass an attribute of your choice. You must make sure that the attribute of your choice can be fetched for both users and groups and it is unique. Leave it empty for default behavior. Changes will have effect only on newly mapped (added) LDAP users and groups." => "Par défaut, l'attribut UUID est automatiquement détecté. Cet attribut est utilisé pour identifier les utilisateurs et groupes de façon fiable. Un nom d'utilisateur interne basé sur l'UUID sera automatiquement créé, sauf s'il est spécifié autrement ci-dessus. Vous pouvez modifier ce comportement et définir l'attribut de votre choix. Vous devez alors vous assurer que l'attribut de votre choix peut être récupéré pour les utilisateurs ainsi que pour les groupes et qu'il soit unique. Laisser à blanc pour le comportement par défaut. Les modifications seront effectives uniquement pour les nouveaux (ajoutés) utilisateurs et groupes LDAP.",
|
||||
"UUID Attribute for Users:" => "Attribut UUID pour les utilisateurs :",
|
||||
|
||||
@@ -97,7 +97,11 @@ class Access extends LDAPUtility implements user\IUserTools {
|
||||
$this->abandonPagedSearch();
|
||||
// openLDAP requires that we init a new Paged Search. Not needed by AD,
|
||||
// but does not hurt either.
|
||||
$this->initPagedSearch($filter, array($dn), array($attr), 1, 0);
|
||||
$pagingSize = intval($this->connection->ldapPagingSize);
|
||||
// 0 won't result in replies, small numbers may leave out groups
|
||||
// (cf. #12306), 500 is default for paging and should work everywhere.
|
||||
$maxResults = $pagingSize > 20 ? $pagingSize : 500;
|
||||
$this->initPagedSearch($filter, array($dn), array($attr), $maxResults, 0);
|
||||
$dn = $this->DNasBaseParameter($dn);
|
||||
$rr = @$this->ldap->read($cr, $dn, $filter, array($attr));
|
||||
if(!$this->ldap->isResource($rr)) {
|
||||
@@ -285,7 +289,7 @@ class Access extends LDAPUtility implements user\IUserTools {
|
||||
* @param boolean $isUser is it a user? otherwise group
|
||||
* @return string with the LDAP DN on success, otherwise false
|
||||
*/
|
||||
private function ocname2dn($name, $isUser) {
|
||||
public function ocname2dn($name, $isUser) {
|
||||
$table = $this->getMapTable($isUser);
|
||||
|
||||
$query = \OCP\DB::prepare('
|
||||
@@ -626,38 +630,16 @@ class Access extends LDAPUtility implements user\IUserTools {
|
||||
}
|
||||
|
||||
/**
|
||||
* retrieves all known groups from the mappings table
|
||||
* @return array with the results
|
||||
*
|
||||
* retrieves all known groups from the mappings table
|
||||
* removes a user from the mappings table
|
||||
* @param string $ocName
|
||||
*/
|
||||
private function mappedGroups() {
|
||||
return $this->mappedComponents(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* retrieves all known users from the mappings table
|
||||
* @return array with the results
|
||||
*
|
||||
* retrieves all known users from the mappings table
|
||||
*/
|
||||
private function mappedUsers() {
|
||||
return $this->mappedComponents(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param boolean $isUsers
|
||||
* @return array
|
||||
*/
|
||||
private function mappedComponents($isUsers) {
|
||||
$table = $this->getMapTable($isUsers);
|
||||
|
||||
$query = \OCP\DB::prepare('
|
||||
SELECT `ldap_dn`, `owncloud_name`
|
||||
FROM `'. $table . '`'
|
||||
);
|
||||
|
||||
return $query->execute()->fetchAll();
|
||||
public function unmapUser($ocName) {
|
||||
$table = $this->getMapTable(true);
|
||||
$delete = \OCP\DB::prepare('
|
||||
DELETE FROM `' . $table . '`
|
||||
WHERE `owncloud_name` = ?
|
||||
');
|
||||
$delete->execute(array($ocName));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -705,7 +687,10 @@ class Access extends LDAPUtility implements user\IUserTools {
|
||||
if($isUser) {
|
||||
//make sure that email address is retrieved prior to login, so user
|
||||
//will be notified when something is shared with him
|
||||
$this->userManager->get($ocName)->update();
|
||||
$user = $this->userManager->get($ocName);
|
||||
if($user instanceof user\User) {
|
||||
$user->update();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -1084,12 +1069,18 @@ class Access extends LDAPUtility implements user\IUserTools {
|
||||
/**
|
||||
* escapes (user provided) parts for LDAP filter
|
||||
* @param string $input, the provided value
|
||||
* @param bool $allowAsterisk whether in * at the beginning should be preserved
|
||||
* @return string the escaped string
|
||||
*/
|
||||
public function escapeFilterPart($input) {
|
||||
public function escapeFilterPart($input, $allowAsterisk = false) {
|
||||
$asterisk = '';
|
||||
if($allowAsterisk && strlen($input) > 0 && $input[0] === '*') {
|
||||
$asterisk = '*';
|
||||
$input = mb_substr($input, 1, null, 'UTF-8');
|
||||
}
|
||||
$search = array('*', '\\', '(', ')');
|
||||
$replace = array('\\*', '\\\\', '\\(', '\\)');
|
||||
return str_replace($search, $replace, $input);
|
||||
return $asterisk . str_replace($search, $replace, $input);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1479,7 +1470,8 @@ class Access extends LDAPUtility implements user\IUserTools {
|
||||
* @return void
|
||||
*/
|
||||
private function setPagedResultCookie($base, $filter, $limit, $offset, $cookie) {
|
||||
if(!empty($cookie)) {
|
||||
// allow '0' for 389ds
|
||||
if(!empty($cookie) || $cookie === '0') {
|
||||
$cacheKey = 'lc' . crc32($base) . '-' . crc32($filter) . '-' .intval($limit) . '-' . intval($offset);
|
||||
$this->cookies[$cacheKey] = $cookie;
|
||||
$this->lastCookie = $cookie;
|
||||
@@ -1517,11 +1509,12 @@ class Access extends LDAPUtility implements user\IUserTools {
|
||||
foreach($bases as $base) {
|
||||
|
||||
$cookie = $this->getPagedResultCookie($base, $filter, $limit, $offset);
|
||||
if(empty($cookie) && ($offset > 0)) {
|
||||
if(empty($cookie) && $cookie !== "0" && ($offset > 0)) {
|
||||
// no cookie known, although the offset is not 0. Maybe cache run out. We need
|
||||
// to start all over *sigh* (btw, Dear Reader, did you know LDAP paged
|
||||
// searching was designed by MSFT?)
|
||||
// Lukas: No, but thanks to reading that source I finally know!
|
||||
// '0' is valid, because 389ds
|
||||
$reOffset = ($offset - $limit) < 0 ? 0 : $offset - $limit;
|
||||
//a bit recursive, $offset of 0 is the exit
|
||||
\OCP\Util::writeLog('user_ldap', 'Looking for cookie L/O '.$limit.'/'.$reOffset, \OCP\Util::INFO);
|
||||
@@ -1529,7 +1522,8 @@ class Access extends LDAPUtility implements user\IUserTools {
|
||||
$cookie = $this->getPagedResultCookie($base, $filter, $limit, $offset);
|
||||
//still no cookie? obviously, the server does not like us. Let's skip paging efforts.
|
||||
//TODO: remember this, probably does not change in the next request...
|
||||
if(empty($cookie)) {
|
||||
if(empty($cookie) && $cookie !== '0') {
|
||||
// '0' is valid, because 389ds
|
||||
$cookie = null;
|
||||
}
|
||||
}
|
||||
@@ -1550,6 +1544,17 @@ class Access extends LDAPUtility implements user\IUserTools {
|
||||
}
|
||||
|
||||
}
|
||||
} else if($this->connection->hasPagedResultSupport && intval($limit) === 0) {
|
||||
// a search without limit was requested. However, if we do use
|
||||
// Paged Search once, we always must do it. This requires us to
|
||||
// initialize it with the configured page size.
|
||||
$this->abandonPagedSearch();
|
||||
// in case someone set it to 0 … use 500, otherwise no results will
|
||||
// be returned.
|
||||
$pageSize = intval($this->connection->ldapPagingSize) > 0 ? intval($this->connection->ldapPagingSize) : 500;
|
||||
$pagedSearchOK = $this->ldap->controlPagedResult(
|
||||
$this->connection->getConnectionResource(), $pageSize, false, ''
|
||||
);
|
||||
}
|
||||
|
||||
return $pagedSearchOK;
|
||||
|
||||
@@ -24,12 +24,19 @@
|
||||
namespace OCA\user_ldap\lib;
|
||||
|
||||
//magic properties (incomplete)
|
||||
use OC\ServerNotAvailableException;
|
||||
|
||||
/**
|
||||
* responsible for LDAP connections in context with the provided configuration
|
||||
*
|
||||
* @property string ldapUserFilter
|
||||
* @property string ldapUserDisplayName
|
||||
* @property boolean hasPagedResultSupport
|
||||
*/
|
||||
* @property string[] ldapBaseUsers
|
||||
* @property int|string ldapPagingSize holds an integer
|
||||
* @property string ldapLoginFilter
|
||||
* @property string ldapGroupMemberAssocAttr
|
||||
*/
|
||||
class Connection extends LDAPUtility {
|
||||
private $ldapConnectionRes = null;
|
||||
private $configPrefix;
|
||||
@@ -43,7 +50,7 @@ class Connection extends LDAPUtility {
|
||||
//cache handler
|
||||
protected $cache;
|
||||
|
||||
//settings handler
|
||||
/** @var Configuration settings handler **/
|
||||
protected $configuration;
|
||||
|
||||
protected $doNotValidate = false;
|
||||
@@ -70,8 +77,9 @@ class Connection extends LDAPUtility {
|
||||
}
|
||||
$this->hasPagedResultSupport =
|
||||
$this->ldap->hasPagedResultSupport();
|
||||
$helper = new Helper();
|
||||
$this->doNotValidate = !in_array($this->configPrefix,
|
||||
Helper::getServerConfigurationPrefixes());
|
||||
$helper->getServerConfigurationPrefixes());
|
||||
}
|
||||
|
||||
public function __destruct() {
|
||||
@@ -155,7 +163,8 @@ class Connection extends LDAPUtility {
|
||||
$this->establishConnection();
|
||||
}
|
||||
if(is_null($this->ldapConnectionRes)) {
|
||||
\OCP\Util::writeLog('user_ldap', 'Connection could not be established', \OCP\Util::ERROR);
|
||||
\OCP\Util::writeLog('user_ldap', 'No LDAP Connection to server ' . $this->configuration->ldapHost, \OCP\Util::ERROR);
|
||||
throw new ServerNotAvailableException('Connection to LDAP server could not be established');
|
||||
}
|
||||
return $this->ldapConnectionRes;
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ class Helper {
|
||||
* except the default (first) server shall be connected to.
|
||||
*
|
||||
*/
|
||||
static public function getServerConfigurationPrefixes($activeConfigurations = false) {
|
||||
public function getServerConfigurationPrefixes($activeConfigurations = false) {
|
||||
$referenceConfigkey = 'ldap_configuration_active';
|
||||
|
||||
$sql = '
|
||||
@@ -83,7 +83,7 @@ class Helper {
|
||||
* @return array an array with configprefix as keys
|
||||
*
|
||||
*/
|
||||
static public function getServerConfigurationHosts() {
|
||||
public function getServerConfigurationHosts() {
|
||||
$referenceConfigkey = 'ldap_host';
|
||||
|
||||
$query = '
|
||||
@@ -110,7 +110,7 @@ class Helper {
|
||||
* @param string $prefix the configuration prefix of the config to delete
|
||||
* @return bool true on success, false otherwise
|
||||
*/
|
||||
static public function deleteServerConfiguration($prefix) {
|
||||
public function deleteServerConfiguration($prefix) {
|
||||
//just to be on the safe side
|
||||
\OCP\User::checkAdminUser();
|
||||
|
||||
@@ -144,13 +144,29 @@ class Helper {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* checks whether there is one or more disabled LDAP configurations
|
||||
* @throws \Exception
|
||||
* @return bool
|
||||
*/
|
||||
public function haveDisabledConfigurations() {
|
||||
$all = $this->getServerConfigurationPrefixes(false);
|
||||
$active = $this->getServerConfigurationPrefixes(true);
|
||||
|
||||
if(!is_array($all) || !is_array($active)) {
|
||||
throw new \Exception('Unexpected Return Value');
|
||||
}
|
||||
|
||||
return count($all) !== count($active) || count($all) === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncate's the given mapping table
|
||||
*
|
||||
* @param string $mapping either 'user' or 'group'
|
||||
* @return bool true on success, false otherwise
|
||||
*/
|
||||
static public function clearMapping($mapping) {
|
||||
public function clearMapping($mapping) {
|
||||
if($mapping === 'user') {
|
||||
$table = '`*PREFIX*ldap_user_mapping`';
|
||||
} else if ($mapping === 'group') {
|
||||
@@ -176,7 +192,7 @@ class Helper {
|
||||
* @param string $url the URL
|
||||
* @return string|false domain as string on success, false otherwise
|
||||
*/
|
||||
static public function getDomainFromURL($url) {
|
||||
public function getDomainFromURL($url) {
|
||||
$uinfo = parse_url($url);
|
||||
if(!is_array($uinfo)) {
|
||||
return false;
|
||||
|
||||
@@ -156,7 +156,8 @@ class Jobs extends \OC\BackgroundJob\TimedJob {
|
||||
if(!is_null(self::$groupBE)) {
|
||||
return self::$groupBE;
|
||||
}
|
||||
$configPrefixes = Helper::getServerConfigurationPrefixes(true);
|
||||
$helper = new Helper();
|
||||
$configPrefixes = $helper->getServerConfigurationPrefixes(true);
|
||||
$ldapWrapper = new LDAP();
|
||||
if(count($configPrefixes) === 1) {
|
||||
//avoid the proxy when there is only one LDAP server configured
|
||||
|
||||
@@ -0,0 +1,227 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (c) 2014 Arthur Schiwon <blizzz@owncloud.com>
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later.
|
||||
* See the COPYING-README file.
|
||||
*/
|
||||
|
||||
namespace OCA\User_LDAP\Jobs;
|
||||
|
||||
use \OCA\user_ldap\User_Proxy;
|
||||
use \OCA\user_ldap\lib\Helper;
|
||||
use \OCA\user_ldap\lib\LDAP;
|
||||
|
||||
/**
|
||||
* Class CleanUp
|
||||
*
|
||||
* a Background job to clean up deleted users
|
||||
*
|
||||
* @package OCA\user_ldap\lib;
|
||||
*/
|
||||
class CleanUp extends \OC\BackgroundJob\TimedJob {
|
||||
/**
|
||||
* @var int $limit amount of users that should be checked per run
|
||||
*/
|
||||
protected $limit = 50;
|
||||
|
||||
/**
|
||||
* @var \OCP\UserInterface $userBackend
|
||||
*/
|
||||
protected $userBackend;
|
||||
|
||||
/**
|
||||
* @var \OCP\IConfig $ocConfig
|
||||
*/
|
||||
protected $ocConfig;
|
||||
|
||||
/**
|
||||
* @var \OCP\IDBConnection $db
|
||||
*/
|
||||
protected $db;
|
||||
|
||||
/**
|
||||
* @var Helper $ldapHelper
|
||||
*/
|
||||
protected $ldapHelper;
|
||||
|
||||
/**
|
||||
* @var int $defaultIntervalMin default interval in minutes
|
||||
*/
|
||||
protected $defaultIntervalMin = 51;
|
||||
|
||||
public function __construct() {
|
||||
$minutes = \OC::$server->getConfig()->getSystemValue(
|
||||
'ldapUserCleanupInterval', strval($this->defaultIntervalMin));
|
||||
$this->setInterval(intval($minutes) * 60);
|
||||
}
|
||||
|
||||
/**
|
||||
* assigns the instances passed to run() to the class properties
|
||||
* @param array $arguments
|
||||
*/
|
||||
public function setArguments($arguments) {
|
||||
//Dependency Injection is not possible, because the constructor will
|
||||
//only get values that are serialized to JSON. I.e. whatever we would
|
||||
//pass in app.php we do add here, except something else is passed e.g.
|
||||
//in tests.
|
||||
|
||||
if(isset($arguments['helper'])) {
|
||||
$this->ldapHelper = $arguments['helper'];
|
||||
} else {
|
||||
$this->ldapHelper = new Helper();
|
||||
}
|
||||
|
||||
if(isset($arguments['userBackend'])) {
|
||||
$this->userBackend = $arguments['userBackend'];
|
||||
} else {
|
||||
$this->userBackend = new User_Proxy(
|
||||
$this->ldapHelper->getServerConfigurationPrefixes(true),
|
||||
new LDAP()
|
||||
);
|
||||
}
|
||||
|
||||
if(isset($arguments['ocConfig'])) {
|
||||
$this->ocConfig = $arguments['ocConfig'];
|
||||
} else {
|
||||
$this->ocConfig = \OC::$server->getConfig();
|
||||
}
|
||||
|
||||
if(isset($arguments['db'])) {
|
||||
$this->db = $arguments['db'];
|
||||
} else {
|
||||
$this->db = \OC::$server->getDatabaseConnection();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* makes the background job do its work
|
||||
* @param array $argument
|
||||
*/
|
||||
public function run($argument) {
|
||||
$this->setArguments($argument);
|
||||
|
||||
if(!$this->isCleanUpAllowed()) {
|
||||
return;
|
||||
}
|
||||
$users = $this->getMappedUsers($this->limit, $this->getOffset());
|
||||
if(!is_array($users)) {
|
||||
//something wrong? Let's start from the beginning next time and
|
||||
//abort
|
||||
$this->setOffset(true);
|
||||
return;
|
||||
}
|
||||
$resetOffset = $this->isOffsetResetNecessary(count($users));
|
||||
$this->checkUsers($users);
|
||||
$this->setOffset($resetOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* checks whether next run should start at 0 again
|
||||
* @param int $resultCount
|
||||
* @return bool
|
||||
*/
|
||||
public function isOffsetResetNecessary($resultCount) {
|
||||
return ($resultCount < $this->limit) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* checks whether cleaning up LDAP users is allowed
|
||||
* @return bool
|
||||
*/
|
||||
public function isCleanUpAllowed() {
|
||||
try {
|
||||
if($this->ldapHelper->haveDisabledConfigurations()) {
|
||||
return false;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$enabled = $this->isCleanUpEnabled();
|
||||
|
||||
return $enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* checks whether clean up is enabled by configuration
|
||||
* @return bool
|
||||
*/
|
||||
private function isCleanUpEnabled() {
|
||||
return (bool)$this->ocConfig->getSystemValue(
|
||||
'ldapUserCleanupInterval', strval($this->defaultIntervalMin));
|
||||
}
|
||||
|
||||
/**
|
||||
* checks users whether they are still existing
|
||||
* @param array $users result from getMappedUsers()
|
||||
*/
|
||||
private function checkUsers($users) {
|
||||
foreach($users as $user) {
|
||||
$this->checkUser($user);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* checks whether a user is still existing in LDAP
|
||||
* @param string[] $user
|
||||
*/
|
||||
private function checkUser($user) {
|
||||
if($this->userBackend->userExistsOnLDAP($user['name'])) {
|
||||
//still available, all good
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO FIXME consolidate next line in DeletedUsersIndex
|
||||
// (impractical now, because of class dependencies)
|
||||
$this->ocConfig->setUserValue($user['name'], 'user_ldap', 'isDeleted', '1');
|
||||
}
|
||||
|
||||
/**
|
||||
* returns a batch of users from the mappings table
|
||||
* @param int $limit
|
||||
* @param int $offset
|
||||
* @return array
|
||||
*/
|
||||
public function getMappedUsers($limit, $offset) {
|
||||
$query = $this->db->prepare('
|
||||
SELECT
|
||||
`ldap_dn` AS `dn`,
|
||||
`owncloud_name` AS `name`,
|
||||
`directory_uuid` AS `uuid`
|
||||
FROM `*PREFIX*ldap_user_mapping`',
|
||||
$limit,
|
||||
$offset
|
||||
);
|
||||
|
||||
$query->execute();
|
||||
return $query->fetchAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the offset to fetch users from the mappings table
|
||||
* @return int
|
||||
*/
|
||||
private function getOffset() {
|
||||
return $this->ocConfig->getAppValue('user_ldap', 'cleanUpJobOffset', 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the new offset for the next run
|
||||
* @param bool $reset whether the offset should be set to 0
|
||||
*/
|
||||
public function setOffset($reset = false) {
|
||||
$newOffset = $reset ? 0 :
|
||||
$this->getOffset() + $this->limit;
|
||||
$this->ocConfig->setAppValue('user_ldap', 'cleanUpJobOffset', $newOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the chunk size (limit in DB speak)
|
||||
* @return int
|
||||
*/
|
||||
public function getChunkSize() {
|
||||
return $this->limit;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -23,6 +23,8 @@
|
||||
|
||||
namespace OCA\user_ldap\lib;
|
||||
|
||||
use OC\ServerNotAvailableException;
|
||||
|
||||
class LDAP implements ILDAPWrapper {
|
||||
protected $curFunc = '';
|
||||
protected $curArgs = array();
|
||||
@@ -280,6 +282,8 @@ class LDAP implements ILDAPWrapper {
|
||||
//for now
|
||||
} else if ($errorCode === 10) {
|
||||
//referrals, we switch them off, but then there is AD :)
|
||||
} else if ($errorCode === -1) {
|
||||
throw new ServerNotAvailableException('Lost connection to LDAP server.');
|
||||
} else {
|
||||
\OCP\Util::writeLog('user_ldap',
|
||||
'LDAP error '.$errorMsg.' (' .
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* ownCloud – LDAP Helper
|
||||
*
|
||||
* @author Arthur Schiwon
|
||||
* @copyright 2014 Arthur Schiwon <blizzz@owncloud.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\user_ldap\lib\user;
|
||||
|
||||
use OCA\user_ldap\lib\user\OfflineUser;
|
||||
use OCA\user_ldap\lib\Access;
|
||||
|
||||
/**
|
||||
* Class DeletedUsersIndex
|
||||
* @package OCA\User_LDAP
|
||||
*/
|
||||
class DeletedUsersIndex {
|
||||
/**
|
||||
* @var \OC\Preferences $preferences
|
||||
*/
|
||||
protected $preferences;
|
||||
|
||||
/**
|
||||
* @var \OCP\IDBConnection $db
|
||||
*/
|
||||
protected $db;
|
||||
|
||||
/**
|
||||
* @var \OCA\user_ldap\lib\Access $access
|
||||
*/
|
||||
protected $access;
|
||||
|
||||
/**
|
||||
* @var int $limit
|
||||
*/
|
||||
protected $limit = 10;
|
||||
|
||||
/**
|
||||
* @var array $deletedUsers
|
||||
*/
|
||||
protected $deletedUsers = false;
|
||||
|
||||
public function __construct(\OC\Preferences $preferences, \OCP\IDBConnection $db, Access $access) {
|
||||
$this->preferences = $preferences;
|
||||
$this->db = $db;
|
||||
$this->access = $access;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns key to be used against $this->deletedUsers
|
||||
* @param int $limit
|
||||
* @param int $offset
|
||||
* @return string
|
||||
*/
|
||||
private function getDeletedUsersCacheKey($limit, $offset) {
|
||||
return strval($limit) . '.' . strval($offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* reads LDAP users marked as deleted from the database
|
||||
* @param int $offset
|
||||
* @return OCA\user_ldap\lib\user\OfflineUser[]
|
||||
*/
|
||||
private function fetchDeletedUsers($offset) {
|
||||
$deletedUsers = $this->preferences->getUsersForValue(
|
||||
'user_ldap', 'isDeleted', '1', $this->limit, $offset);
|
||||
$key = $this->getDeletedUsersCacheKey($this->limit, $offset);
|
||||
|
||||
$userObjects = array();
|
||||
foreach($deletedUsers as $user) {
|
||||
$userObjects[] = new OfflineUser($user, $this->preferences, $this->db, $this->access);
|
||||
}
|
||||
|
||||
$this->deletedUsers[$key] = $userObjects;
|
||||
if(count($userObjects) > 0) {
|
||||
$this->hasUsers();
|
||||
}
|
||||
return $this->deletedUsers[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* returns all LDAP users that are marked as deleted
|
||||
* @param int|null $offset
|
||||
* @return OCA\user_ldap\lib\user\OfflineUser[]
|
||||
*/
|
||||
public function getUsers($offset = null) {
|
||||
$key = $this->getDeletedUsersCacheKey($this->limit, $offset);
|
||||
if(is_array($this->deletedUsers) && isset($this->deletedUsers[$key])) {
|
||||
return $this->deletedUsers[$key];
|
||||
}
|
||||
return $this->fetchDeletedUsers($offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* whether at least one user was detected as deleted
|
||||
* @return bool
|
||||
*/
|
||||
public function hasUsers() {
|
||||
if($this->deletedUsers === false) {
|
||||
$this->fetchDeletedUsers(0);
|
||||
}
|
||||
foreach($this->deletedUsers as $batch) {
|
||||
if(count($batch) > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -39,4 +39,7 @@ interface IUserTools {
|
||||
|
||||
public function username2dn($name);
|
||||
|
||||
//temporary hack for LDAP user cleanup, will be removed in OC 8.
|
||||
public function ocname2dn($name, $isUser);
|
||||
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ use OCA\user_ldap\lib\user\IUserTools;
|
||||
use OCA\user_ldap\lib\user\User;
|
||||
use OCA\user_ldap\lib\LogWrapper;
|
||||
use OCA\user_ldap\lib\FilesystemHelper;
|
||||
use OCA\user_ldap\lib\user\OfflineUser;
|
||||
|
||||
/**
|
||||
* Manager
|
||||
@@ -60,7 +61,9 @@ class Manager {
|
||||
*/
|
||||
protected $avatarManager;
|
||||
/**
|
||||
* @var string[][]
|
||||
* array['byDN'] \OCA\user_ldap\lib\User[]
|
||||
* ['byUid'] \OCA\user_ldap\lib\User[]
|
||||
* @var array $users
|
||||
*/
|
||||
protected $users = array(
|
||||
'byDN' => array(),
|
||||
@@ -114,8 +117,8 @@ class Manager {
|
||||
$user = new User($uid, $dn, $this->access, $this->ocConfig,
|
||||
$this->ocFilesystem, clone $this->image, $this->ocLog,
|
||||
$this->avatarManager);
|
||||
$users['byDN'][$dn] = $user;
|
||||
$users['byUid'][$uid] = $user;
|
||||
$this->users['byDN'][$dn] = $user;
|
||||
$this->users['byUid'][$uid] = $user;
|
||||
return $user;
|
||||
}
|
||||
|
||||
@@ -131,9 +134,51 @@ class Manager {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief returns a User object by it's DN or ownCloud username
|
||||
* Checks whether the specified user is marked as deleted
|
||||
* @param string $id the ownCloud user name
|
||||
* @return bool
|
||||
*/
|
||||
public function isDeletedUser($id) {
|
||||
$isDeleted = $this->ocConfig->getUserValue(
|
||||
$id, 'user_ldap', 'isDeleted', 0);
|
||||
return intval($isDeleted) === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* creates and returns an instance of OfflineUser for the specified user
|
||||
* @param string $id
|
||||
* @return \OCA\user_ldap\lib\user\OfflineUser
|
||||
*/
|
||||
public function getDeletedUser($id) {
|
||||
return new OfflineUser(
|
||||
$id,
|
||||
new \OC\Preferences(\OC_DB::getConnection()),
|
||||
\OC::$server->getDatabaseConnection(),
|
||||
$this->access);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief returns a User object by it's ownCloud username
|
||||
* @param string the DN or username of the user
|
||||
* @return \OCA\user_ldap\lib\User | null
|
||||
* @return \OCA\user_ldap\lib\user\User|\OCA\user_ldap\lib\user\OfflineUser|null
|
||||
*/
|
||||
protected function createInstancyByUserName($id) {
|
||||
//most likely a uid. Check whether it is a deleted user
|
||||
if($this->isDeletedUser($id)) {
|
||||
return $this->getDeletedUser($id);
|
||||
}
|
||||
$dn = $this->access->username2dn($id);
|
||||
if($dn !== false) {
|
||||
return $this->createAndCache($dn, $id);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief returns a User object by it's DN or ownCloud username
|
||||
* @param string the username of the user
|
||||
* @return \OCA\user_ldap\lib\user\User|\OCA\user_ldap\lib\user\OfflineUser|null
|
||||
* @throws \Exception when connection could not be established
|
||||
*/
|
||||
public function get($id) {
|
||||
$this->checkAccess();
|
||||
@@ -143,25 +188,14 @@ class Manager {
|
||||
return $this->users['byUid'][$id];
|
||||
}
|
||||
|
||||
if(!$this->access->stringResemblesDN($id) ) {
|
||||
//most likely a uid
|
||||
$dn = $this->access->username2dn($id);
|
||||
if($dn !== false) {
|
||||
return $this->createAndCache($dn, $id);
|
||||
}
|
||||
} else {
|
||||
//so it's a DN
|
||||
if($this->access->stringResemblesDN($id) ) {
|
||||
$uid = $this->access->dn2username($id);
|
||||
if($uid !== false) {
|
||||
return $this->createAndCache($id, $uid);
|
||||
}
|
||||
}
|
||||
//either funny uid or invalid. Assume funny to be on the safe side.
|
||||
$dn = $this->access->username2dn($id);
|
||||
if($dn !== false) {
|
||||
return $this->createAndCache($dn, $id);
|
||||
}
|
||||
return null;
|
||||
|
||||
return $this->createInstancyByUserName($id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,217 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* ownCloud – LDAP User
|
||||
*
|
||||
* @author Arthur Schiwon
|
||||
* @copyright 2014 Arthur Schiwon blizzz@owncloud.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\user_ldap\lib\user;
|
||||
|
||||
use OCA\user_ldap\lib\Access;
|
||||
|
||||
class OfflineUser {
|
||||
/**
|
||||
* @var string $ocName
|
||||
*/
|
||||
protected $ocName;
|
||||
/**
|
||||
* @var string $dn
|
||||
*/
|
||||
protected $dn;
|
||||
/**
|
||||
* @var string $uid the UID as provided by LDAP
|
||||
*/
|
||||
protected $uid;
|
||||
/**
|
||||
* @var string $displayName
|
||||
*/
|
||||
protected $displayName;
|
||||
/**
|
||||
* @var string $homePath
|
||||
*/
|
||||
protected $homePath;
|
||||
/**
|
||||
* @var string $lastLogin the timestamp of the last login
|
||||
*/
|
||||
protected $lastLogin;
|
||||
/**
|
||||
* @var string $email
|
||||
*/
|
||||
protected $email;
|
||||
/**
|
||||
* @var bool $hasActiveShares
|
||||
*/
|
||||
protected $hasActiveShares;
|
||||
/**
|
||||
* @var \OC\Preferences $preferences
|
||||
*/
|
||||
protected $preferences;
|
||||
/**
|
||||
* @var \OCP\IDBConnection $db
|
||||
*/
|
||||
protected $db;
|
||||
/**
|
||||
* @var \OCA\user_ldap\lib\Access
|
||||
*/
|
||||
protected $access;
|
||||
|
||||
public function __construct($ocName, \OC\Preferences $preferences, \OCP\IDBConnection $db, Access $access) {
|
||||
$this->ocName = $ocName;
|
||||
$this->preferences = $preferences;
|
||||
$this->db = $db;
|
||||
$this->access = $access;
|
||||
$this->fetchDetails();
|
||||
}
|
||||
|
||||
/**
|
||||
* exports the user details in an assoc array
|
||||
* @return array
|
||||
*/
|
||||
public function export() {
|
||||
$data = array();
|
||||
$data['ocName'] = $this->getOCName();
|
||||
$data['dn'] = $this->getDN();
|
||||
$data['uid'] = $this->getUID();
|
||||
$data['displayName'] = $this->getDisplayName();
|
||||
$data['homePath'] = $this->getHomePath();
|
||||
$data['lastLogin'] = $this->getLastLogin();
|
||||
$data['email'] = $this->getEmail();
|
||||
$data['hasActiveShares'] = $this->getHasActiveShares();
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* getter for ownCloud internal name
|
||||
* @return string
|
||||
*/
|
||||
public function getOCName() {
|
||||
return $this->ocName;
|
||||
}
|
||||
|
||||
/**
|
||||
* getter for LDAP uid
|
||||
* @return string
|
||||
*/
|
||||
public function getUID() {
|
||||
return $this->uid;
|
||||
}
|
||||
|
||||
/**
|
||||
* getter for LDAP DN
|
||||
* @return string
|
||||
*/
|
||||
public function getDN() {
|
||||
return $this->dn;
|
||||
}
|
||||
|
||||
/**
|
||||
* getter for display name
|
||||
* @return string
|
||||
*/
|
||||
public function getDisplayName() {
|
||||
return $this->displayName;
|
||||
}
|
||||
|
||||
/**
|
||||
* getter for email
|
||||
* @return string
|
||||
*/
|
||||
public function getEmail() {
|
||||
return $this->email;
|
||||
}
|
||||
|
||||
/**
|
||||
* getter for home directory path
|
||||
* @return string
|
||||
*/
|
||||
public function getHomePath() {
|
||||
return $this->homePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* getter for the last login timestamp
|
||||
* @return int
|
||||
*/
|
||||
public function getLastLogin() {
|
||||
return intval($this->lastLogin);
|
||||
}
|
||||
|
||||
/**
|
||||
* getter for having active shares
|
||||
* @return bool
|
||||
*/
|
||||
public function getHasActiveShares() {
|
||||
return $this->hasActiveShares;
|
||||
}
|
||||
|
||||
/**
|
||||
* reads the user details
|
||||
*/
|
||||
protected function fetchDetails() {
|
||||
$properties = array (
|
||||
'displayName' => 'user_ldap',
|
||||
'uid' => 'user_ldap',
|
||||
'homePath' => 'user_ldap',
|
||||
'email' => 'settings',
|
||||
'lastLogin' => 'login'
|
||||
);
|
||||
foreach($properties as $property => $app) {
|
||||
$this->$property = $this->preferences->getValue($this->ocName, $app, $property, '');
|
||||
}
|
||||
|
||||
$dn = $this->access->ocname2dn($this->ocName, true);
|
||||
$this->dn = ($dn !== false) ? $dn : '';
|
||||
|
||||
$this->determineShares();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* finds out whether the user has active shares. The result is stored in
|
||||
* $this->hasActiveShares
|
||||
*/
|
||||
protected function determineShares() {
|
||||
$query = $this->db->prepare('
|
||||
SELECT COUNT(`uid_owner`)
|
||||
FROM `*PREFIX*share`
|
||||
WHERE `uid_owner` = ?
|
||||
', 1);
|
||||
$query->execute(array($this->ocName));
|
||||
$sResult = $query->fetchColumn(0);
|
||||
if(intval($sResult) === 1) {
|
||||
$this->hasActiveShares = true;
|
||||
return;
|
||||
}
|
||||
|
||||
$query = $this->db->prepare('
|
||||
SELECT COUNT(`owner`)
|
||||
FROM `*PREFIX*share_external`
|
||||
WHERE `owner` = ?
|
||||
', 1);
|
||||
$query->execute(array($this->ocName));
|
||||
$sResult = $query->fetchColumn(0);
|
||||
if(intval($sResult) === 1) {
|
||||
$this->hasActiveShares = true;
|
||||
return;
|
||||
}
|
||||
|
||||
$this->hasActiveShares = false;
|
||||
}
|
||||
}
|
||||
@@ -212,6 +212,31 @@ class User {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a key-value pair in relation to this user
|
||||
* @param string $key
|
||||
* @param string $value
|
||||
*/
|
||||
private function store($key, $value) {
|
||||
$this->config->setUserValue($this->uid, 'user_ldap', $key, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the display name in the databae
|
||||
* @param string $displayName
|
||||
*/
|
||||
public function storeDisplayName($displayName) {
|
||||
$this->store('displayName', $displayName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the LDAP Username in the Database
|
||||
* @param string $userName
|
||||
*/
|
||||
public function storeLDAPUserName($userName) {
|
||||
$this->store('uid', $userName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief checks whether an update method specified by feature was run
|
||||
* already. If not, it will marked like this, because it is expected that
|
||||
@@ -318,7 +343,13 @@ class User {
|
||||
}
|
||||
|
||||
$avatar = $this->avatarManager->getAvatar($this->uid);
|
||||
$avatar->set($this->image);
|
||||
try {
|
||||
$avatar->set($this->image);
|
||||
} catch (\Exception $e) {
|
||||
\OC::$server->getLogger()->notice(
|
||||
'Could not set avatar for ' . $this->dn . ', because: ' . $e->getMessage(),
|
||||
array('app' => 'user_ldap'));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
|
||||
namespace OCA\user_ldap\lib;
|
||||
|
||||
use OC\ServerNotAvailableException;
|
||||
|
||||
class Wizard extends LDAPUtility {
|
||||
static protected $l;
|
||||
protected $access;
|
||||
@@ -614,7 +616,8 @@ class Wizard extends LDAPUtility {
|
||||
//this did not help :(
|
||||
//Let's see whether we can parse the Host URL and convert the domain to
|
||||
//a base DN
|
||||
$domain = Helper::getDomainFromURL($this->configuration->ldapHost);
|
||||
$helper = new Helper();
|
||||
$domain = $helper->getDomainFromURL($this->configuration->ldapHost);
|
||||
if(!$domain) {
|
||||
return false;
|
||||
}
|
||||
@@ -803,13 +806,23 @@ class Wizard extends LDAPUtility {
|
||||
}
|
||||
$base = $this->configuration->ldapBase[0];
|
||||
foreach($cns as $cn) {
|
||||
$rr = $this->ldap->search($cr, $base, 'cn=' . $cn, array('dn'));
|
||||
$rr = $this->ldap->search($cr, $base, 'cn=' . $cn, array('dn', 'primaryGroupToken'));
|
||||
if(!$this->ldap->isResource($rr)) {
|
||||
continue;
|
||||
}
|
||||
$er = $this->ldap->firstEntry($cr, $rr);
|
||||
$attrs = $this->ldap->getAttributes($cr, $er);
|
||||
$dn = $this->ldap->getDN($cr, $er);
|
||||
$filter .= '(memberof=' . $dn . ')';
|
||||
if(empty($dn)) {
|
||||
continue;
|
||||
}
|
||||
$filterPart = '(memberof=' . $dn . ')';
|
||||
if(isset($attrs['primaryGroupToken'])) {
|
||||
$pgt = $attrs['primaryGroupToken'][0];
|
||||
$primaryFilterPart = '(primaryGroupID=' . $pgt .')';
|
||||
$filterPart = '(|' . $filterPart . $primaryFilterPart . ')';
|
||||
}
|
||||
$filter .= $filterPart;
|
||||
}
|
||||
$filter .= ')';
|
||||
}
|
||||
@@ -954,18 +967,27 @@ class Wizard extends LDAPUtility {
|
||||
$this->ldap->setOption($cr, LDAP_OPT_PROTOCOL_VERSION, 3);
|
||||
$this->ldap->setOption($cr, LDAP_OPT_REFERRALS, 0);
|
||||
$this->ldap->setOption($cr, LDAP_OPT_NETWORK_TIMEOUT, self::LDAP_NW_TIMEOUT);
|
||||
if($tls) {
|
||||
$isTlsWorking = @$this->ldap->startTls($cr);
|
||||
if(!$isTlsWorking) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
\OCP\Util::writeLog('user_ldap', 'Wiz: Attemping to Bind ', \OCP\Util::DEBUG);
|
||||
//interesting part: do the bind!
|
||||
$login = $this->ldap->bind($cr,
|
||||
$this->configuration->ldapAgentName,
|
||||
$this->configuration->ldapAgentPassword);
|
||||
try {
|
||||
if($tls) {
|
||||
$isTlsWorking = @$this->ldap->startTls($cr);
|
||||
if(!$isTlsWorking) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
\OCP\Util::writeLog('user_ldap', 'Wiz: Attemping to Bind ', \OCP\Util::DEBUG);
|
||||
//interesting part: do the bind!
|
||||
$login = $this->ldap->bind($cr,
|
||||
$this->configuration->ldapAgentName,
|
||||
$this->configuration->ldapAgentPassword
|
||||
);
|
||||
$errNo = $this->ldap->errno($cr);
|
||||
$error = ldap_error($cr);
|
||||
$this->ldap->unbind($cr);
|
||||
} catch(ServerNotAvailableException $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if($login === true) {
|
||||
$this->ldap->unbind($cr);
|
||||
@@ -976,9 +998,6 @@ class Wizard extends LDAPUtility {
|
||||
return true;
|
||||
}
|
||||
|
||||
$errNo = $this->ldap->errno($cr);
|
||||
$error = ldap_error($cr);
|
||||
$this->ldap->unbind($cr);
|
||||
if($errNo === -1 || ($errNo === 2 && $ncc)) {
|
||||
//host, port or TLS wrong
|
||||
return false;
|
||||
|
||||
@@ -36,8 +36,9 @@ OCP\Util::addStyle('core', 'jquery-ui-1.10.0.custom');
|
||||
// fill template
|
||||
$tmpl = new OCP\Template('user_ldap', 'settings');
|
||||
|
||||
$prefixes = \OCA\user_ldap\lib\Helper::getServerConfigurationPrefixes();
|
||||
$hosts = \OCA\user_ldap\lib\Helper::getServerConfigurationHosts();
|
||||
$helper = new \OCA\user_ldap\lib\Helper();
|
||||
$prefixes = $helper->getServerConfigurationPrefixes();
|
||||
$hosts = $helper->getServerConfigurationHosts();
|
||||
|
||||
$wizardHtml = '';
|
||||
$toc = array();
|
||||
|
||||
@@ -77,10 +77,15 @@ class Test_Group_Ldap extends \PHPUnit_Framework_TestCase {
|
||||
->method('readAttribute')
|
||||
->will($this->returnValue(array('u11', 'u22', 'u33', 'u34')));
|
||||
|
||||
// for primary groups
|
||||
$access->expects($this->once())
|
||||
->method('countUsers')
|
||||
->will($this->returnValue(2));
|
||||
|
||||
$groupBackend = new GroupLDAP($access);
|
||||
$users = $groupBackend->countUsersInGroup('group');
|
||||
|
||||
$this->assertSame(4, $users);
|
||||
$this->assertSame(6, $users);
|
||||
}
|
||||
|
||||
public function testCountWithSearchString() {
|
||||
@@ -294,4 +299,88 @@ class Test_Group_Ldap extends \PHPUnit_Framework_TestCase {
|
||||
$groupBackend->inGroup($uid, $gid);
|
||||
}
|
||||
|
||||
public function testGetGroupsWithOffset() {
|
||||
$access = $this->getAccessMock();
|
||||
$this->enableGroups($access);
|
||||
|
||||
$access->expects($this->once())
|
||||
->method('ownCloudGroupNames')
|
||||
->will($this->returnValue(array('group1', 'group2')));
|
||||
|
||||
$groupBackend = new GroupLDAP($access);
|
||||
$groups = $groupBackend->getGroups('', 2, 2);
|
||||
|
||||
$this->assertSame(2, count($groups));
|
||||
}
|
||||
|
||||
/**
|
||||
* tests that a user listing is complete, if all it's members have the group
|
||||
* as their primary.
|
||||
*/
|
||||
public function testUsersInGroupPrimaryMembersOnly() {
|
||||
$access = $this->getAccessMock();
|
||||
$this->enableGroups($access);
|
||||
|
||||
$access->connection->expects($this->any())
|
||||
->method('getFromCache')
|
||||
->will($this->returnValue(null));
|
||||
|
||||
$access->expects($this->any())
|
||||
->method('readAttribute')
|
||||
->will($this->returnCallback(function($dn, $attr) {
|
||||
if($attr === 'primaryGroupToken') {
|
||||
return array(1337);
|
||||
}
|
||||
return array();
|
||||
}));
|
||||
|
||||
$access->expects($this->any())
|
||||
->method('groupname2dn')
|
||||
->will($this->returnValue('cn=foobar,dc=foo,dc=bar'));
|
||||
|
||||
$access->expects($this->once())
|
||||
->method('ownCloudUserNames')
|
||||
->will($this->returnValue(array('lisa', 'bart', 'kira', 'brad')));
|
||||
|
||||
$groupBackend = new GroupLDAP($access);
|
||||
$users = $groupBackend->usersInGroup('foobar');
|
||||
|
||||
$this->assertSame(4, count($users));
|
||||
}
|
||||
|
||||
/**
|
||||
* tests that a user counting is complete, if all it's members have the group
|
||||
* as their primary.
|
||||
*/
|
||||
public function testCountUsersInGroupPrimaryMembersOnly() {
|
||||
$access = $this->getAccessMock();
|
||||
$this->enableGroups($access);
|
||||
|
||||
$access->connection->expects($this->any())
|
||||
->method('getFromCache')
|
||||
->will($this->returnValue(null));
|
||||
|
||||
$access->expects($this->any())
|
||||
->method('readAttribute')
|
||||
->will($this->returnCallback(function($dn, $attr) {
|
||||
if($attr === 'primaryGroupToken') {
|
||||
return array(1337);
|
||||
}
|
||||
return array();
|
||||
}));
|
||||
|
||||
$access->expects($this->any())
|
||||
->method('groupname2dn')
|
||||
->will($this->returnValue('cn=foobar,dc=foo,dc=bar'));
|
||||
|
||||
$access->expects($this->once())
|
||||
->method('countUsers')
|
||||
->will($this->returnValue(4));
|
||||
|
||||
$groupBackend = new GroupLDAP($access);
|
||||
$users = $groupBackend->countUsersInGroup('foobar');
|
||||
|
||||
$this->assertSame(4, $users);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,7 +23,8 @@ class Test_Helper extends \PHPUnit_Framework_TestCase {
|
||||
$result = $statement->execute();
|
||||
$this->assertEquals(2, $result->fetchOne());
|
||||
|
||||
Helper::clearMapping('user');
|
||||
$helper = new Helper();
|
||||
$helper->clearMapping('user');
|
||||
|
||||
$result = $statement->execute();
|
||||
$this->assertEquals(0, $result->fetchOne());
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (c) 2014 Arthur Schiwon <blizzz@owncloud.com>
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later.
|
||||
* See the COPYING-README file.
|
||||
*/
|
||||
|
||||
namespace OCA\user_ldap\tests;
|
||||
|
||||
class Test_CleanUp extends \PHPUnit_Framework_TestCase {
|
||||
public function getMocks() {
|
||||
$mocks = array();
|
||||
$mocks['userBackend'] =
|
||||
$this->getMockBuilder('\OCA\user_ldap\User_Proxy')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$mocks['ocConfig'] = $this->getMock('\OCP\IConfig');
|
||||
$mocks['db'] = $this->getMock('\OCP\IDBConnection');
|
||||
$mocks['helper'] = $this->getMock('\OCA\user_ldap\lib\Helper');
|
||||
|
||||
return $mocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* clean up job must not run when there are disabled configurations
|
||||
*/
|
||||
public function test_runNotAllowedByDisabledConfigurations() {
|
||||
$args = $this->getMocks();
|
||||
$args['helper']->expects($this->once())
|
||||
->method('haveDisabledConfigurations')
|
||||
->will($this->returnValue(true) );
|
||||
|
||||
$args['ocConfig']->expects($this->never())
|
||||
->method('getSystemValue');
|
||||
|
||||
$bgJob = new \OCA\User_LDAP\Jobs\CleanUp();
|
||||
$bgJob->setArguments($args);
|
||||
|
||||
$result = $bgJob->isCleanUpAllowed();
|
||||
$this->assertSame(false, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* clean up job must not run when LDAP Helper is broken i.e.
|
||||
* returning unexpected results
|
||||
*/
|
||||
public function test_runNotAllowedByBrokenHelper() {
|
||||
$args = $this->getMocks();
|
||||
$args['helper']->expects($this->once())
|
||||
->method('haveDisabledConfigurations')
|
||||
->will($this->throwException(new \Exception()));
|
||||
|
||||
$args['ocConfig']->expects($this->never())
|
||||
->method('getSystemValue');
|
||||
|
||||
$bgJob = new \OCA\User_LDAP\Jobs\CleanUp();
|
||||
$bgJob->setArguments($args);
|
||||
|
||||
$result = $bgJob->isCleanUpAllowed();
|
||||
$this->assertSame(false, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* clean up job must not run when it is not enabled
|
||||
*/
|
||||
public function test_runNotAllowedBySysConfig() {
|
||||
$args = $this->getMocks();
|
||||
$args['helper']->expects($this->once())
|
||||
->method('haveDisabledConfigurations')
|
||||
->will($this->returnValue(false));
|
||||
|
||||
$args['ocConfig']->expects($this->once())
|
||||
->method('getSystemValue')
|
||||
->will($this->returnValue(false));
|
||||
|
||||
$bgJob = new \OCA\User_LDAP\Jobs\CleanUp();
|
||||
$bgJob->setArguments($args);
|
||||
|
||||
$result = $bgJob->isCleanUpAllowed();
|
||||
$this->assertSame(false, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* clean up job is allowed to run
|
||||
*/
|
||||
public function test_runIsAllowed() {
|
||||
$args = $this->getMocks();
|
||||
$args['helper']->expects($this->once())
|
||||
->method('haveDisabledConfigurations')
|
||||
->will($this->returnValue(false));
|
||||
|
||||
$args['ocConfig']->expects($this->once())
|
||||
->method('getSystemValue')
|
||||
->will($this->returnValue(true));
|
||||
|
||||
$bgJob = new \OCA\User_LDAP\Jobs\CleanUp();
|
||||
$bgJob->setArguments($args);
|
||||
|
||||
$result = $bgJob->isCleanUpAllowed();
|
||||
$this->assertSame(true, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* test whether sql is OK
|
||||
*/
|
||||
public function test_getMappedUsers() {
|
||||
$args = $this->getMocks();
|
||||
|
||||
$bgJob = new \OCA\User_LDAP\Jobs\CleanUp();
|
||||
$bgJob->setArguments($args);
|
||||
|
||||
if(version_compare(\PHPUnit_Runner_Version::id(), '3.8', '<')) {
|
||||
//otherwise we run into
|
||||
//https://github.com/sebastianbergmann/phpunit-mock-objects/issues/103
|
||||
$this->markTestIncomplete();
|
||||
}
|
||||
|
||||
$stmt = $this->getMock('\Doctrine\DBAL\Driver\Statement');
|
||||
|
||||
$args['db']->expects($this->once())
|
||||
->method('prepare')
|
||||
->will($this->returnValue($stmt));
|
||||
|
||||
$bgJob->getMappedUsers(0, $bgJob->getChunkSize());
|
||||
}
|
||||
|
||||
/**
|
||||
* check whether offset will be reset when it needs to
|
||||
*/
|
||||
public function test_OffsetResetIsNecessary() {
|
||||
$args = $this->getMocks();
|
||||
|
||||
$bgJob = new \OCA\User_LDAP\Jobs\CleanUp();
|
||||
$bgJob->setArguments($args);
|
||||
|
||||
$result = $bgJob->isOffsetResetNecessary($bgJob->getChunkSize() - 1);
|
||||
$this->assertSame(true, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* make sure offset is not reset when it is not due
|
||||
*/
|
||||
public function test_OffsetResetIsNotNecessary() {
|
||||
$args = $this->getMocks();
|
||||
|
||||
$bgJob = new \OCA\User_LDAP\Jobs\CleanUp();
|
||||
$bgJob->setArguments($args);
|
||||
|
||||
$result = $bgJob->isOffsetResetNecessary($bgJob->getChunkSize());
|
||||
$this->assertSame(false, $result);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
<?php
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Arthur Schiwon
|
||||
* @copyright 2014 Arthur Schiwon blizzz@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/>.
|
||||
*
|
||||
*/
|
||||
* ownCloud
|
||||
*
|
||||
* @author Arthur Schiwon
|
||||
* @copyright 2014 Arthur Schiwon blizzz@owncloud.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\user_ldap\tests;
|
||||
|
||||
@@ -26,173 +26,177 @@ use OCA\user_ldap\lib\user\Manager;
|
||||
|
||||
class Test_User_Manager extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
private function getTestInstances() {
|
||||
$access = $this->getMock('\OCA\user_ldap\lib\user\IUserTools');
|
||||
$config = $this->getMock('\OCP\IConfig');
|
||||
$filesys = $this->getMock('\OCA\user_ldap\lib\FilesystemHelper');
|
||||
$log = $this->getMock('\OCA\user_ldap\lib\LogWrapper');
|
||||
$avaMgr = $this->getMock('\OCP\IAvatarManager');
|
||||
$image = $this->getMock('\OCP\Image');
|
||||
private function getTestInstances() {
|
||||
$access = $this->getMock('\OCA\user_ldap\lib\user\IUserTools');
|
||||
$config = $this->getMock('\OCP\IConfig');
|
||||
$filesys = $this->getMock('\OCA\user_ldap\lib\FilesystemHelper');
|
||||
$log = $this->getMock('\OCA\user_ldap\lib\LogWrapper');
|
||||
$avaMgr = $this->getMock('\OCP\IAvatarManager');
|
||||
$image = $this->getMock('\OCP\Image');
|
||||
|
||||
return array($access, $config, $filesys, $image, $log, $avaMgr);
|
||||
}
|
||||
return array($access, $config, $filesys, $image, $log, $avaMgr);
|
||||
}
|
||||
|
||||
public function testGetByDNExisting() {
|
||||
list($access, $config, $filesys, $image, $log, $avaMgr) =
|
||||
$this->getTestInstances();
|
||||
public function testGetByDNExisting() {
|
||||
list($access, $config, $filesys, $image, $log, $avaMgr) =
|
||||
$this->getTestInstances();
|
||||
|
||||
$inputDN = 'cn=foo,dc=foobar,dc=bar';
|
||||
$uid = '563418fc-423b-1033-8d1c-ad5f418ee02e';
|
||||
$inputDN = 'cn=foo,dc=foobar,dc=bar';
|
||||
$uid = '563418fc-423b-1033-8d1c-ad5f418ee02e';
|
||||
|
||||
$access->expects($this->once())
|
||||
->method('stringResemblesDN')
|
||||
->with($this->equalTo($inputDN))
|
||||
->will($this->returnValue(true));
|
||||
|
||||
$access->expects($this->once())
|
||||
->method('dn2username')
|
||||
->with($this->equalTo($inputDN))
|
||||
->will($this->returnValue($uid));
|
||||
|
||||
$access->expects($this->never())
|
||||
->method('username2dn');
|
||||
|
||||
$manager = new Manager($config, $filesys, $log, $avaMgr, $image);
|
||||
$manager->setLdapAccess($access);
|
||||
$user = $manager->get($inputDN);
|
||||
|
||||
$this->assertInstanceOf('\OCA\user_ldap\lib\user\User', $user);
|
||||
}
|
||||
|
||||
public function testGetByEDirectoryDN() {
|
||||
list($access, $config, $filesys, $image, $log, $avaMgr) =
|
||||
$this->getTestInstances();
|
||||
|
||||
$inputDN = 'uid=foo,o=foobar,c=bar';
|
||||
$uid = '563418fc-423b-1033-8d1c-ad5f418ee02e';
|
||||
->method('stringResemblesDN')
|
||||
->with($this->equalTo($inputDN))
|
||||
->will($this->returnValue(true));
|
||||
|
||||
$access->expects($this->once())
|
||||
->method('stringResemblesDN')
|
||||
->with($this->equalTo($inputDN))
|
||||
->will($this->returnValue(true));
|
||||
->method('dn2username')
|
||||
->with($this->equalTo($inputDN))
|
||||
->will($this->returnValue($uid));
|
||||
|
||||
$access->expects($this->once())
|
||||
->method('dn2username')
|
||||
->with($this->equalTo($inputDN))
|
||||
->will($this->returnValue($uid));
|
||||
$access->expects($this->never())
|
||||
->method('username2dn');
|
||||
|
||||
$access->expects($this->never())
|
||||
->method('username2dn');
|
||||
$manager = new Manager($config, $filesys, $log, $avaMgr, $image);
|
||||
$manager->setLdapAccess($access);
|
||||
$user = $manager->get($inputDN);
|
||||
|
||||
$manager = new Manager($config, $filesys, $log, $avaMgr, $image);
|
||||
$manager->setLdapAccess($access);
|
||||
$user = $manager->get($inputDN);
|
||||
// Now we fetch the user again. If this leads to a failing test,
|
||||
// runtime caching the manager is broken.
|
||||
$user = $manager->get($inputDN);
|
||||
|
||||
$this->assertInstanceOf('\OCA\user_ldap\lib\user\User', $user);
|
||||
}
|
||||
$this->assertInstanceOf('\OCA\user_ldap\lib\user\User', $user);
|
||||
}
|
||||
|
||||
public function testGetByExoticDN() {
|
||||
list($access, $config, $filesys, $image, $log, $avaMgr) =
|
||||
$this->getTestInstances();
|
||||
public function testGetByEDirectoryDN() {
|
||||
list($access, $config, $filesys, $image, $log, $avaMgr) =
|
||||
$this->getTestInstances();
|
||||
|
||||
$inputDN = 'ab=cde,f=ghei,mno=pq';
|
||||
$uid = '563418fc-423b-1033-8d1c-ad5f418ee02e';
|
||||
$inputDN = 'uid=foo,o=foobar,c=bar';
|
||||
$uid = '563418fc-423b-1033-8d1c-ad5f418ee02e';
|
||||
|
||||
$access->expects($this->once())
|
||||
->method('stringResemblesDN')
|
||||
->with($this->equalTo($inputDN))
|
||||
->will($this->returnValue(true));
|
||||
|
||||
$access->expects($this->once())
|
||||
->method('dn2username')
|
||||
->with($this->equalTo($inputDN))
|
||||
->will($this->returnValue($uid));
|
||||
|
||||
$access->expects($this->never())
|
||||
->method('username2dn');
|
||||
|
||||
$manager = new Manager($config, $filesys, $log, $avaMgr, $image);
|
||||
$manager->setLdapAccess($access);
|
||||
$user = $manager->get($inputDN);
|
||||
|
||||
$this->assertInstanceOf('\OCA\user_ldap\lib\user\User', $user);
|
||||
}
|
||||
|
||||
public function testGetByDNNotExisting() {
|
||||
list($access, $config, $filesys, $image, $log, $avaMgr) =
|
||||
$this->getTestInstances();
|
||||
|
||||
$inputDN = 'cn=gone,dc=foobar,dc=bar';
|
||||
->method('stringResemblesDN')
|
||||
->with($this->equalTo($inputDN))
|
||||
->will($this->returnValue(true));
|
||||
|
||||
$access->expects($this->once())
|
||||
->method('stringResemblesDN')
|
||||
->with($this->equalTo($inputDN))
|
||||
->will($this->returnValue(true));
|
||||
->method('dn2username')
|
||||
->with($this->equalTo($inputDN))
|
||||
->will($this->returnValue($uid));
|
||||
|
||||
$access->expects($this->once())
|
||||
->method('dn2username')
|
||||
->with($this->equalTo($inputDN))
|
||||
->will($this->returnValue(false));
|
||||
$access->expects($this->never())
|
||||
->method('username2dn');
|
||||
|
||||
$access->expects($this->once())
|
||||
->method('username2dn')
|
||||
->with($this->equalTo($inputDN))
|
||||
->will($this->returnValue(false));
|
||||
$manager = new Manager($config, $filesys, $log, $avaMgr, $image);
|
||||
$manager->setLdapAccess($access);
|
||||
$user = $manager->get($inputDN);
|
||||
|
||||
$manager = new Manager($config, $filesys, $log, $avaMgr, $image);
|
||||
$manager->setLdapAccess($access);
|
||||
$user = $manager->get($inputDN);
|
||||
$this->assertInstanceOf('\OCA\user_ldap\lib\user\User', $user);
|
||||
}
|
||||
|
||||
$this->assertNull($user);
|
||||
}
|
||||
public function testGetByExoticDN() {
|
||||
list($access, $config, $filesys, $image, $log, $avaMgr) =
|
||||
$this->getTestInstances();
|
||||
|
||||
public function testGetByUidExisting() {
|
||||
list($access, $config, $filesys, $image, $log, $avaMgr) =
|
||||
$this->getTestInstances();
|
||||
$inputDN = 'ab=cde,f=ghei,mno=pq';
|
||||
$uid = '563418fc-423b-1033-8d1c-ad5f418ee02e';
|
||||
|
||||
$dn = 'cn=foo,dc=foobar,dc=bar';
|
||||
$uid = '563418fc-423b-1033-8d1c-ad5f418ee02e';
|
||||
$access->expects($this->once())
|
||||
->method('stringResemblesDN')
|
||||
->with($this->equalTo($inputDN))
|
||||
->will($this->returnValue(true));
|
||||
|
||||
$access->expects($this->never())
|
||||
->method('dn2username');
|
||||
$access->expects($this->once())
|
||||
->method('dn2username')
|
||||
->with($this->equalTo($inputDN))
|
||||
->will($this->returnValue($uid));
|
||||
|
||||
$access->expects($this->once())
|
||||
->method('username2dn')
|
||||
->with($this->equalTo($uid))
|
||||
->will($this->returnValue($dn));
|
||||
$access->expects($this->never())
|
||||
->method('username2dn');
|
||||
|
||||
$access->expects($this->once())
|
||||
->method('stringResemblesDN')
|
||||
->with($this->equalTo($uid))
|
||||
->will($this->returnValue(false));
|
||||
$manager = new Manager($config, $filesys, $log, $avaMgr, $image);
|
||||
$manager->setLdapAccess($access);
|
||||
$user = $manager->get($inputDN);
|
||||
|
||||
$manager = new Manager($config, $filesys, $log, $avaMgr, $image);
|
||||
$manager->setLdapAccess($access);
|
||||
$user = $manager->get($uid);
|
||||
$this->assertInstanceOf('\OCA\user_ldap\lib\user\User', $user);
|
||||
}
|
||||
|
||||
$this->assertInstanceOf('\OCA\user_ldap\lib\user\User', $user);
|
||||
}
|
||||
public function testGetByDNNotExisting() {
|
||||
list($access, $config, $filesys, $image, $log, $avaMgr) =
|
||||
$this->getTestInstances();
|
||||
|
||||
public function testGetByUidNotExisting() {
|
||||
list($access, $config, $filesys, $image, $log, $avaMgr) =
|
||||
$this->getTestInstances();
|
||||
$inputDN = 'cn=gone,dc=foobar,dc=bar';
|
||||
|
||||
$dn = 'cn=foo,dc=foobar,dc=bar';
|
||||
$uid = 'gone';
|
||||
$access->expects($this->once())
|
||||
->method('stringResemblesDN')
|
||||
->with($this->equalTo($inputDN))
|
||||
->will($this->returnValue(true));
|
||||
|
||||
$access->expects($this->never())
|
||||
->method('dn2username');
|
||||
$access->expects($this->once())
|
||||
->method('dn2username')
|
||||
->with($this->equalTo($inputDN))
|
||||
->will($this->returnValue(false));
|
||||
|
||||
$access->expects($this->exactly(2))
|
||||
->method('username2dn')
|
||||
->with($this->equalTo($uid))
|
||||
->will($this->returnValue(false));
|
||||
$access->expects($this->once())
|
||||
->method('username2dn')
|
||||
->with($this->equalTo($inputDN))
|
||||
->will($this->returnValue(false));
|
||||
|
||||
$manager = new Manager($config, $filesys, $log, $avaMgr, $image);
|
||||
$manager->setLdapAccess($access);
|
||||
$user = $manager->get($uid);
|
||||
$manager = new Manager($config, $filesys, $log, $avaMgr, $image);
|
||||
$manager->setLdapAccess($access);
|
||||
$user = $manager->get($inputDN);
|
||||
}
|
||||
|
||||
$this->assertNull($user);
|
||||
}
|
||||
public function testGetByUidExisting() {
|
||||
list($access, $config, $filesys, $image, $log, $avaMgr) =
|
||||
$this->getTestInstances();
|
||||
|
||||
$dn = 'cn=foo,dc=foobar,dc=bar';
|
||||
$uid = '563418fc-423b-1033-8d1c-ad5f418ee02e';
|
||||
|
||||
$access->expects($this->never())
|
||||
->method('dn2username');
|
||||
|
||||
$access->expects($this->once())
|
||||
->method('username2dn')
|
||||
->with($this->equalTo($uid))
|
||||
->will($this->returnValue($dn));
|
||||
|
||||
$access->expects($this->once())
|
||||
->method('stringResemblesDN')
|
||||
->with($this->equalTo($uid))
|
||||
->will($this->returnValue(false));
|
||||
|
||||
$manager = new Manager($config, $filesys, $log, $avaMgr, $image);
|
||||
$manager->setLdapAccess($access);
|
||||
$user = $manager->get($uid);
|
||||
|
||||
// Now we fetch the user again. If this leads to a failing test,
|
||||
// runtime caching the manager is broken.
|
||||
$user = $manager->get($uid);
|
||||
|
||||
$this->assertInstanceOf('\OCA\user_ldap\lib\user\User', $user);
|
||||
}
|
||||
|
||||
public function testGetByUidNotExisting() {
|
||||
list($access, $config, $filesys, $image, $log, $avaMgr) =
|
||||
$this->getTestInstances();
|
||||
|
||||
$dn = 'cn=foo,dc=foobar,dc=bar';
|
||||
$uid = 'gone';
|
||||
|
||||
$access->expects($this->never())
|
||||
->method('dn2username');
|
||||
|
||||
$access->expects($this->exactly(1))
|
||||
->method('username2dn')
|
||||
->with($this->equalTo($uid))
|
||||
->will($this->returnValue(false));
|
||||
|
||||
$manager = new Manager($config, $filesys, $log, $avaMgr, $image);
|
||||
$manager->setLdapAccess($access);
|
||||
$user = $manager->get($uid);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ class Test_User_Ldap_Direct extends \PHPUnit_Framework_TestCase {
|
||||
->method('fetchListOfUsers')
|
||||
->will($this->returnCallback(function($filter) {
|
||||
if($filter === 'roland') {
|
||||
return array('dnOfRoland,dc=test');
|
||||
return array(array('dn' => 'dnOfRoland,dc=test'));
|
||||
}
|
||||
return array();
|
||||
}));
|
||||
@@ -228,6 +228,28 @@ class Test_User_Ldap_Direct extends \PHPUnit_Framework_TestCase {
|
||||
$this->assertFalse($result);
|
||||
}
|
||||
|
||||
public function testDeleteUserCancel() {
|
||||
$access = $this->getAccessMock();
|
||||
$backend = new UserLDAP($access);
|
||||
$result = $backend->deleteUser('notme');
|
||||
$this->assertFalse($result);
|
||||
}
|
||||
|
||||
public function testDeleteUserSuccess() {
|
||||
$access = $this->getAccessMock();
|
||||
$backend = new UserLDAP($access);
|
||||
|
||||
$pref = \OC::$server->getConfig();
|
||||
$pref->setUserValue('jeremy', 'user_ldap', 'isDeleted', 1);
|
||||
$pref->setUserValue('jeremy', 'user_ldap', 'homePath', '/var/vhome/jdings/');
|
||||
|
||||
$result = $backend->deleteUser('jeremy');
|
||||
$this->assertTrue($result);
|
||||
|
||||
$home = $backend->getHome('jeremy');
|
||||
$this->assertSame($home, '/var/vhome/jdings/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the Access mock for getUsers tests
|
||||
* @param \OCA\user_ldap\lib\Access $access mock
|
||||
@@ -378,21 +400,53 @@ class Test_User_Ldap_Direct extends \PHPUnit_Framework_TestCase {
|
||||
$this->prepareMockForUserExists($access);
|
||||
|
||||
$access->expects($this->any())
|
||||
->method('readAttribute')
|
||||
->will($this->returnCallback(function($dn) {
|
||||
if($dn === 'dnOfRoland,dc=test') {
|
||||
return array();
|
||||
}
|
||||
return false;
|
||||
}));
|
||||
->method('readAttribute')
|
||||
->will($this->returnCallback(function($dn) {
|
||||
if($dn === 'dnOfRoland,dc=test') {
|
||||
return array();
|
||||
}
|
||||
return false;
|
||||
}));
|
||||
|
||||
//test for existing user
|
||||
$result = $backend->userExists('gunslinger');
|
||||
$this->assertTrue($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Exception
|
||||
*/
|
||||
public function testUserExistsForDeleted() {
|
||||
$access = $this->getAccessMock();
|
||||
$backend = new UserLDAP($access);
|
||||
$this->prepareMockForUserExists($access);
|
||||
|
||||
$access->expects($this->any())
|
||||
->method('readAttribute')
|
||||
->will($this->returnCallback(function($dn) {
|
||||
if($dn === 'dnOfRoland,dc=test') {
|
||||
return array();
|
||||
}
|
||||
return false;
|
||||
}));
|
||||
|
||||
//test for deleted user
|
||||
$result = $backend->userExists('formerUser');
|
||||
$this->assertFalse($result);
|
||||
}
|
||||
|
||||
public function testUserExistsForNeverExisting() {
|
||||
$access = $this->getAccessMock();
|
||||
$backend = new UserLDAP($access);
|
||||
$this->prepareMockForUserExists($access);
|
||||
|
||||
$access->expects($this->any())
|
||||
->method('readAttribute')
|
||||
->will($this->returnCallback(function($dn) {
|
||||
if($dn === 'dnOfRoland,dc=test') {
|
||||
return array();
|
||||
}
|
||||
return false;
|
||||
}));
|
||||
|
||||
//test for never-existing user
|
||||
$result = $backend->userExists('mallory');
|
||||
@@ -406,21 +460,55 @@ class Test_User_Ldap_Direct extends \PHPUnit_Framework_TestCase {
|
||||
\OC_User::useBackend($backend);
|
||||
|
||||
$access->expects($this->any())
|
||||
->method('readAttribute')
|
||||
->will($this->returnCallback(function($dn) {
|
||||
if($dn === 'dnOfRoland,dc=test') {
|
||||
return array();
|
||||
}
|
||||
return false;
|
||||
}));
|
||||
->method('readAttribute')
|
||||
->will($this->returnCallback(function($dn) {
|
||||
if($dn === 'dnOfRoland,dc=test') {
|
||||
return array();
|
||||
}
|
||||
return false;
|
||||
}));
|
||||
|
||||
//test for existing user
|
||||
$result = \OCP\User::userExists('gunslinger');
|
||||
$this->assertTrue($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Exception
|
||||
*/
|
||||
public function testUserExistsPublicAPIForDeleted() {
|
||||
$access = $this->getAccessMock();
|
||||
$backend = new UserLDAP($access);
|
||||
$this->prepareMockForUserExists($access);
|
||||
\OC_User::useBackend($backend);
|
||||
|
||||
$access->expects($this->any())
|
||||
->method('readAttribute')
|
||||
->will($this->returnCallback(function($dn) {
|
||||
if($dn === 'dnOfRoland,dc=test') {
|
||||
return array();
|
||||
}
|
||||
return false;
|
||||
}));
|
||||
|
||||
//test for deleted user
|
||||
$result = \OCP\User::userExists('formerUser');
|
||||
$this->assertFalse($result);
|
||||
}
|
||||
|
||||
public function testUserExistsPublicAPIForNeverExisting() {
|
||||
$access = $this->getAccessMock();
|
||||
$backend = new UserLDAP($access);
|
||||
$this->prepareMockForUserExists($access);
|
||||
\OC_User::useBackend($backend);
|
||||
|
||||
$access->expects($this->any())
|
||||
->method('readAttribute')
|
||||
->will($this->returnCallback(function($dn) {
|
||||
if($dn === 'dnOfRoland,dc=test') {
|
||||
return array();
|
||||
}
|
||||
return false;
|
||||
}));
|
||||
|
||||
//test for never-existing user
|
||||
$result = \OCP\User::userExists('mallory');
|
||||
@@ -436,50 +524,100 @@ class Test_User_Ldap_Direct extends \PHPUnit_Framework_TestCase {
|
||||
$this->assertFalse($result);
|
||||
}
|
||||
|
||||
public function testGetHome() {
|
||||
public function testGetHomeAbsolutePath() {
|
||||
$access = $this->getAccessMock();
|
||||
$backend = new UserLDAP($access);
|
||||
$this->prepareMockForUserExists($access);
|
||||
|
||||
$access->connection->expects($this->any())
|
||||
->method('__get')
|
||||
->will($this->returnCallback(function($name) {
|
||||
if($name === 'homeFolderNamingRule') {
|
||||
return 'attr:testAttribute';
|
||||
}
|
||||
return null;
|
||||
}));
|
||||
->method('__get')
|
||||
->will($this->returnCallback(function($name) {
|
||||
if($name === 'homeFolderNamingRule') {
|
||||
return 'attr:testAttribute';
|
||||
}
|
||||
return null;
|
||||
}));
|
||||
|
||||
$access->expects($this->any())
|
||||
->method('readAttribute')
|
||||
->will($this->returnCallback(function($dn, $attr) {
|
||||
switch ($dn) {
|
||||
case 'dnOfRoland,dc=test':
|
||||
if($attr === 'testAttribute') {
|
||||
return array('/tmp/rolandshome/');
|
||||
}
|
||||
return array();
|
||||
break;
|
||||
case 'dnOfLadyOfShadows,dc=test':
|
||||
if($attr === 'testAttribute') {
|
||||
return array('susannah/');
|
||||
}
|
||||
return array();
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
->method('readAttribute')
|
||||
->will($this->returnCallback(function($dn, $attr) {
|
||||
switch ($dn) {
|
||||
case 'dnOfRoland,dc=test':
|
||||
if($attr === 'testAttribute') {
|
||||
return array('/tmp/rolandshome/');
|
||||
}
|
||||
return array();
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
|
||||
//absolut path
|
||||
$result = $backend->getHome('gunslinger');
|
||||
$this->assertEquals('/tmp/rolandshome/', $result);
|
||||
}
|
||||
|
||||
public function testGetHomeDatadirRelative() {
|
||||
$access = $this->getAccessMock();
|
||||
$backend = new UserLDAP($access);
|
||||
$this->prepareMockForUserExists($access);
|
||||
|
||||
$access->connection->expects($this->any())
|
||||
->method('__get')
|
||||
->will($this->returnCallback(function($name) {
|
||||
if($name === 'homeFolderNamingRule') {
|
||||
return 'attr:testAttribute';
|
||||
}
|
||||
return null;
|
||||
}));
|
||||
|
||||
$access->expects($this->any())
|
||||
->method('readAttribute')
|
||||
->will($this->returnCallback(function($dn, $attr) {
|
||||
switch ($dn) {
|
||||
case 'dnOfLadyOfShadows,dc=test':
|
||||
if($attr === 'testAttribute') {
|
||||
return array('susannah/');
|
||||
}
|
||||
return array();
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
//datadir-relativ path
|
||||
$result = $backend->getHome('ladyofshadows');
|
||||
$datadir = \OCP\Config::getSystemValue('datadirectory',
|
||||
\OC::$SERVERROOT.'/data');
|
||||
\OC::$SERVERROOT.'/data');
|
||||
$this->assertEquals($datadir.'/susannah/', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Exception
|
||||
*/
|
||||
public function testGetHomeNoPath() {
|
||||
$access = $this->getAccessMock();
|
||||
$backend = new UserLDAP($access);
|
||||
$this->prepareMockForUserExists($access);
|
||||
|
||||
$access->connection->expects($this->any())
|
||||
->method('__get')
|
||||
->will($this->returnCallback(function($name) {
|
||||
if($name === 'homeFolderNamingRule') {
|
||||
return 'attr:testAttribute';
|
||||
}
|
||||
return null;
|
||||
}));
|
||||
|
||||
$access->expects($this->any())
|
||||
->method('readAttribute')
|
||||
->will($this->returnCallback(function($dn, $attr) {
|
||||
switch ($dn) {
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
|
||||
//no path at all – triggers OC default behaviour
|
||||
$result = $backend->getHome('newyorker');
|
||||
@@ -519,6 +657,12 @@ class Test_User_Ldap_Direct extends \PHPUnit_Framework_TestCase {
|
||||
$backend = new UserLDAP($access);
|
||||
$this->prepareMockForUserExists($access);
|
||||
|
||||
$access->connection->expects($this->any())
|
||||
->method('getConnectionResource')
|
||||
->will($this->returnCallback(function() {
|
||||
return true;
|
||||
}));
|
||||
|
||||
//with displayName
|
||||
$result = $backend->getDisplayName('gunslinger');
|
||||
$this->assertEquals('Roland Deschain', $result);
|
||||
@@ -530,9 +674,36 @@ class Test_User_Ldap_Direct extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
public function testGetDisplayNamePublicAPI() {
|
||||
$access = $this->getAccessMock();
|
||||
$access->expects($this->any())
|
||||
->method('username2dn')
|
||||
->will($this->returnCallback(function($uid) {
|
||||
switch ($uid) {
|
||||
case 'gunslinger':
|
||||
return 'dnOfRoland,dc=test';
|
||||
break;
|
||||
case 'formerUser':
|
||||
return 'dnOfFormerUser,dc=test';
|
||||
break;
|
||||
case 'newyorker':
|
||||
return 'dnOfNewYorker,dc=test';
|
||||
break;
|
||||
case 'ladyofshadows':
|
||||
return 'dnOfLadyOfShadows,dc=test';
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
$this->prepareAccessForGetDisplayName($access);
|
||||
$backend = new UserLDAP($access);
|
||||
$this->prepareMockForUserExists($access);
|
||||
|
||||
$access->connection->expects($this->any())
|
||||
->method('getConnectionResource')
|
||||
->will($this->returnCallback(function() {
|
||||
return true;
|
||||
}));
|
||||
|
||||
\OC_User::useBackend($backend);
|
||||
|
||||
//with displayName
|
||||
|
||||
@@ -26,8 +26,15 @@
|
||||
namespace OCA\user_ldap;
|
||||
|
||||
use OCA\user_ldap\lib\BackendUtility;
|
||||
use OCA\user_ldap\lib\user\OfflineUser;
|
||||
use OCA\User_LDAP\lib\User\User;
|
||||
|
||||
class USER_LDAP extends BackendUtility implements \OCP\UserInterface {
|
||||
/**
|
||||
* @var string[] $homesToKill
|
||||
*/
|
||||
protected $homesToKill = array();
|
||||
|
||||
/**
|
||||
* checks whether the user is allowed to change his avatar in ownCloud
|
||||
* @param string $uid the ownCloud user name
|
||||
@@ -35,7 +42,7 @@ class USER_LDAP extends BackendUtility implements \OCP\UserInterface {
|
||||
*/
|
||||
public function canChangeAvatar($uid) {
|
||||
$user = $this->access->userManager->get($uid);
|
||||
if(is_null($user)) {
|
||||
if(!$user instanceof User) {
|
||||
return false;
|
||||
}
|
||||
if($user->getAvatarImage() === false) {
|
||||
@@ -57,15 +64,17 @@ class USER_LDAP extends BackendUtility implements \OCP\UserInterface {
|
||||
$uid = $this->access->escapeFilterPart($uid);
|
||||
|
||||
//find out dn of the user name
|
||||
$attrs = array($this->access->connection->ldapUserDisplayName, 'dn',
|
||||
'uid', 'samaccountname');
|
||||
$filter = \OCP\Util::mb_str_replace(
|
||||
'%uid', $uid, $this->access->connection->ldapLoginFilter, 'UTF-8');
|
||||
$ldap_users = $this->access->fetchListOfUsers($filter, 'dn');
|
||||
if(count($ldap_users) < 1) {
|
||||
$users = $this->access->fetchListOfUsers($filter, $attrs);
|
||||
if(count($users) < 1) {
|
||||
return false;
|
||||
}
|
||||
$dn = $ldap_users[0];
|
||||
$dn = $users[0]['dn'];
|
||||
$user = $this->access->userManager->get($dn);
|
||||
if(is_null($user)) {
|
||||
if(!$user instanceof User) {
|
||||
\OCP\Util::writeLog('user_ldap',
|
||||
'LDAP Login: Could not get user object for DN ' . $dn .
|
||||
'. Maybe the LDAP entry has no set display name attribute?',
|
||||
@@ -79,6 +88,15 @@ class USER_LDAP extends BackendUtility implements \OCP\UserInterface {
|
||||
}
|
||||
|
||||
$user->markLogin();
|
||||
if(isset($users[0][$this->access->connection->ldapUserDisplayName])) {
|
||||
$dpn = $users[0][$this->access->connection->ldapUserDisplayName];
|
||||
$user->storeDisplayName($dpn);
|
||||
}
|
||||
if(isset($users[0]['uid'])) {
|
||||
$user->storeLDAPUserName($users[0]['uid']);
|
||||
} else if(isset($users[0]['samaccountname'])) {
|
||||
$user->storeLDAPUserName($users[0]['samaccountname']);
|
||||
}
|
||||
|
||||
return $user->getUsername();
|
||||
}
|
||||
@@ -93,7 +111,7 @@ class USER_LDAP extends BackendUtility implements \OCP\UserInterface {
|
||||
* Get a list of all users.
|
||||
*/
|
||||
public function getUsers($search = '', $limit = 10, $offset = 0) {
|
||||
$search = $this->access->escapeFilterPart($search);
|
||||
$search = $this->access->escapeFilterPart($search, true);
|
||||
$cachekey = 'getUsers-'.$search.'-'.$limit.'-'.$offset;
|
||||
|
||||
//check if users are cached, if so return
|
||||
@@ -127,10 +145,38 @@ class USER_LDAP extends BackendUtility implements \OCP\UserInterface {
|
||||
return $ldap_users;
|
||||
}
|
||||
|
||||
/**
|
||||
* checks whether a user is still available on LDAP
|
||||
* @param string|\OCA\User_LDAP\lib\user\User $user either the ownCloud user
|
||||
* name or an instance of that user
|
||||
* @return bool
|
||||
*/
|
||||
public function userExistsOnLDAP($user) {
|
||||
if(is_string($user)) {
|
||||
$user = $this->access->userManager->get($user);
|
||||
}
|
||||
if(!$user instanceof User) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$dn = $user->getDN();
|
||||
//check if user really still exists by reading its entry
|
||||
if(!is_array($this->access->readAttribute($dn, ''))) {
|
||||
$lcr = $this->access->connection->getConnectionResource();
|
||||
if(is_null($lcr)) {
|
||||
throw new \Exception('No LDAP Connection to server ' . $this->access->connection->ldapHost);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* check if a user exists
|
||||
* @param string $uid the username
|
||||
* @return boolean
|
||||
* @throws \Exception when connection could not be established
|
||||
*/
|
||||
public function userExists($uid) {
|
||||
if($this->access->connection->isCached('userExists'.$uid)) {
|
||||
@@ -138,43 +184,64 @@ class USER_LDAP extends BackendUtility implements \OCP\UserInterface {
|
||||
}
|
||||
//getting dn, if false the user does not exist. If dn, he may be mapped only, requires more checking.
|
||||
$user = $this->access->userManager->get($uid);
|
||||
|
||||
if(is_null($user)) {
|
||||
\OCP\Util::writeLog('user_ldap', 'No DN found for '.$uid.' on '.
|
||||
$this->access->connection->ldapHost, \OCP\Util::DEBUG);
|
||||
$this->access->connection->writeToCache('userExists'.$uid, false);
|
||||
return false;
|
||||
}
|
||||
$dn = $user->getDN();
|
||||
//check if user really still exists by reading its entry
|
||||
if(!is_array($this->access->readAttribute($dn, ''))) {
|
||||
\OCP\Util::writeLog('user_ldap', 'LDAP says no user '.$dn.' on '.
|
||||
$this->access->connection->ldapHost, \OCP\Util::DEBUG);
|
||||
$this->access->connection->writeToCache('userExists'.$uid, false);
|
||||
return false;
|
||||
} else if($user instanceof OfflineUser) {
|
||||
//express check for users marked as deleted. Returning true is
|
||||
//necessary for cleanup
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->access->connection->writeToCache('userExists'.$uid, true);
|
||||
$user->update();
|
||||
return true;
|
||||
$result = $this->userExistsOnLDAP($user);
|
||||
$this->access->connection->writeToCache('userExists'.$uid, $result);
|
||||
if($result === true) {
|
||||
$user->update();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* delete a user
|
||||
* returns whether a user was deleted in LDAP
|
||||
*
|
||||
* @param string $uid The username of the user to delete
|
||||
* @return bool
|
||||
*
|
||||
* Deletes a user
|
||||
*/
|
||||
public function deleteUser($uid) {
|
||||
return false;
|
||||
$pref = \OC::$server->getConfig();
|
||||
$marked = $pref->getUserValue($uid, 'user_ldap', 'isDeleted', 0);
|
||||
if(intval($marked) === 0) {
|
||||
\OC::$server->getLogger()->notice(
|
||||
'User '.$uid . ' is not marked as deleted, not cleaning up.',
|
||||
array('app' => 'user_ldap'));
|
||||
return false;
|
||||
}
|
||||
\OC::$server->getLogger()->info('Cleaning up after user ' . $uid,
|
||||
array('app' => 'user_ldap'));
|
||||
|
||||
//Get Home Directory out of user preferences so we can return it later,
|
||||
//necessary for removing directories as done by OC_User.
|
||||
$home = $pref->getUserValue($uid, 'user_ldap', 'homePath', '');
|
||||
$this->homesToKill[$uid] = $home;
|
||||
$this->access->unmapUser($uid);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the user's home directory
|
||||
* @param string $uid the username
|
||||
* @return boolean
|
||||
* @return string|bool
|
||||
*/
|
||||
public function getHome($uid) {
|
||||
if(isset($this->homesToKill[$uid]) && !empty($this->homesToKill[$uid])) {
|
||||
//a deleted user who needs some clean up
|
||||
return $this->homesToKill[$uid];
|
||||
}
|
||||
|
||||
// user Exists check required as it is not done in user proxy!
|
||||
if(!$this->userExists($uid)) {
|
||||
return false;
|
||||
@@ -184,6 +251,7 @@ class USER_LDAP extends BackendUtility implements \OCP\UserInterface {
|
||||
if($this->access->connection->isCached($cacheKey)) {
|
||||
return $this->access->connection->getFromCache($cacheKey);
|
||||
}
|
||||
$pref = \OC::$server->getConfig();
|
||||
if(strpos($this->access->connection->homeFolderNamingRule, 'attr:') === 0) {
|
||||
$attr = substr($this->access->connection->homeFolderNamingRule, strlen('attr:'));
|
||||
$homedir = $this->access->readAttribute(
|
||||
@@ -203,12 +271,17 @@ class USER_LDAP extends BackendUtility implements \OCP\UserInterface {
|
||||
\OC::$SERVERROOT.'/data' ) . '/' . $homedir[0];
|
||||
}
|
||||
$this->access->connection->writeToCache($cacheKey, $homedir);
|
||||
//we need it to store it in the DB as well in case a user gets
|
||||
//deleted so we can clean up afterwards
|
||||
$pref->setUserValue($uid, 'user_ldap', 'homePath', $homedir);
|
||||
//TODO: if home directory changes, the old one needs to be removed.
|
||||
return $homedir;
|
||||
}
|
||||
}
|
||||
|
||||
//false will apply default behaviour as defined and done by OC_User
|
||||
$this->access->connection->writeToCache($cacheKey, false);
|
||||
$pref->setUserValue($uid, 'user_ldap', 'homePath', '');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
namespace OCA\user_ldap;
|
||||
|
||||
use OCA\user_ldap\lib\ILDAPWrapper;
|
||||
use OCA\User_LDAP\lib\User\User;
|
||||
|
||||
class User_Proxy extends lib\Proxy implements \OCP\UserInterface {
|
||||
private $backends = array();
|
||||
@@ -144,6 +145,17 @@ class User_Proxy extends lib\Proxy implements \OCP\UserInterface {
|
||||
return $this->handleRequest($uid, 'userExists', array($uid));
|
||||
}
|
||||
|
||||
/**
|
||||
* check if a user exists on LDAP
|
||||
* @param string|OCA\User_LDAP\lib\User\User $user either the ownCloud user
|
||||
* name or an instance of that user
|
||||
* @return boolean
|
||||
*/
|
||||
public function userExistsOnLDAP($user) {
|
||||
$id = ($user instanceof User) ? $user->getUsername() : $user;
|
||||
return $this->handleRequest($id, 'userExistsOnLDAP', array($user));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the password is correct
|
||||
* @param string $uid The username
|
||||
@@ -209,7 +221,7 @@ class User_Proxy extends lib\Proxy implements \OCP\UserInterface {
|
||||
* Deletes a user
|
||||
*/
|
||||
public function deleteUser($uid) {
|
||||
return false;
|
||||
return $this->handleRequest($uid, 'deleteUser', array($uid));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,5 +12,4 @@
|
||||
<types>
|
||||
<authentication/>
|
||||
</types>
|
||||
<ocsid>166062</ocsid>
|
||||
</info>
|
||||
|
||||
@@ -1 +1 @@
|
||||
1.1.0.1
|
||||
1.1.0.2
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user