Merge branch 'master' into encryption_initial_enc_indicator
This commit is contained in:
commit
1065c33543
|
@ -108,7 +108,6 @@ if ($needUpgrade) {
|
|||
// if the encryption app is disabled, than everything is fine (INIT_SUCCESSFUL status code)
|
||||
$encryptionInitStatus = 2;
|
||||
if (OC_App::isEnabled('files_encryption')) {
|
||||
$publicUploadEnabled = 'no';
|
||||
$session = new \OCA\Encryption\Session(new \OC\Files\View('/'));
|
||||
$encryptionInitStatus = $session->getInitialized();
|
||||
}
|
||||
|
|
|
@ -225,10 +225,7 @@ class Helper {
|
|||
* @return bool
|
||||
*/
|
||||
public static function isPublicAccess() {
|
||||
if (\OCP\USER::getUser() === false
|
||||
|| (isset($_GET['service']) && $_GET['service'] == 'files'
|
||||
&& isset($_GET['t']))
|
||||
) {
|
||||
if (\OCP\User::getUser() === false) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
@ -256,10 +253,45 @@ class Helper {
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief get path to the correspondig file in data/user/files if path points
|
||||
* @brief try to get the user from the path if no user is logged in
|
||||
* @param string $path
|
||||
* @return mixed user or false if we couldn't determine a user
|
||||
*/
|
||||
public static function getUser($path) {
|
||||
|
||||
$user = \OCP\User::getUser();
|
||||
|
||||
|
||||
// if we are logged in, then we return the userid
|
||||
if ($user) {
|
||||
return $user;
|
||||
}
|
||||
|
||||
// if no user is logged in we try to access a publicly shared files.
|
||||
// In this case we need to try to get the user from the path
|
||||
|
||||
$trimmed = ltrim($path, '/');
|
||||
$split = explode('/', $trimmed);
|
||||
|
||||
// it is not a file relative to data/user/files
|
||||
if (count($split) < 2 || $split[1] !== 'files') {
|
||||
return false;
|
||||
}
|
||||
|
||||
$user = $split[0];
|
||||
|
||||
if (\OCP\User::userExists($user)) {
|
||||
return $user;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get path to the corresponding file in data/user/files if path points
|
||||
* to a version or to a file in cache
|
||||
* @param string $path path to a version or a file in the trash
|
||||
* @return string path to correspondig file relative to data/user/files
|
||||
* @return string path to corresponding file relative to data/user/files
|
||||
*/
|
||||
public static function getPathToRealFile($path) {
|
||||
$trimmed = ltrim($path, '/');
|
||||
|
|
|
@ -112,21 +112,18 @@ class Keymanager {
|
|||
* @brief store file encryption key
|
||||
*
|
||||
* @param \OC_FilesystemView $view
|
||||
* @param \OCA\Encryption\Util $util
|
||||
* @param string $path relative path of the file, including filename
|
||||
* @param $userId
|
||||
* @param $catfile
|
||||
* @internal param string $key
|
||||
* @param string $catfile keyfile content
|
||||
* @return bool true/false
|
||||
* @note The keyfile is not encrypted here. Client code must
|
||||
* asymmetrically encrypt the keyfile before passing it to this method
|
||||
*/
|
||||
public static function setFileKey(\OC_FilesystemView $view, $path, $userId, $catfile) {
|
||||
public static function setFileKey(\OC_FilesystemView $view, $util, $path, $catfile) {
|
||||
|
||||
$proxyStatus = \OC_FileProxy::$enabled;
|
||||
\OC_FileProxy::$enabled = false;
|
||||
|
||||
//here we need the currently logged in user, while userId can be a different user
|
||||
$util = new Util($view, \OCP\User::getUser());
|
||||
list($owner, $filename) = $util->getUidAndFilename($path);
|
||||
|
||||
// in case of system wide mount points the keys are stored directly in the data directory
|
||||
|
@ -172,15 +169,15 @@ class Keymanager {
|
|||
/**
|
||||
* @brief retrieve keyfile for an encrypted file
|
||||
* @param \OC_FilesystemView $view
|
||||
* @param \OCA\Encryption\Util $util
|
||||
* @param $filePath
|
||||
* @internal param \OCA\Encryption\file $string name
|
||||
* @return string file key or false
|
||||
* @note The keyfile returned is asymmetrically encrypted. Decryption
|
||||
* of the keyfile must be performed by client code
|
||||
*/
|
||||
public static function getFileKey(\OC_FilesystemView $view, $filePath) {
|
||||
public static function getFileKey($view, $util, $filePath) {
|
||||
|
||||
$util = new Util($view, \OCP\User::getUser());
|
||||
|
||||
list($owner, $filename) = $util->getUidAndFilename($filePath);
|
||||
$filename = Helper::stripPartialFileExtension($filename);
|
||||
|
@ -216,17 +213,17 @@ class Keymanager {
|
|||
* @brief Delete a keyfile
|
||||
*
|
||||
* @param \OC_FilesystemView $view
|
||||
* @param string $userId username
|
||||
* @param string $path path of the file the key belongs to
|
||||
* @return bool Outcome of unlink operation
|
||||
* @note $path must be relative to data/user/files. e.g. mydoc.txt NOT
|
||||
* /data/admin/files/mydoc.txt
|
||||
*/
|
||||
public static function deleteFileKey(\OC_FilesystemView $view, $userId, $path) {
|
||||
public static function deleteFileKey(\OC_FilesystemView $view, $path) {
|
||||
|
||||
$trimmed = ltrim($path, '/');
|
||||
|
||||
$util = new Util($view, \OCP\User::getUser());
|
||||
$userId = Helper::getUser($path);
|
||||
$util = new Util($view, $userId);
|
||||
|
||||
if($util->isSystemWideMountPoint($path)) {
|
||||
$keyPath = '/files_encryption/keyfiles/' . $trimmed;
|
||||
|
@ -315,16 +312,15 @@ class Keymanager {
|
|||
/**
|
||||
* @brief store multiple share keys for a single file
|
||||
* @param \OC_FilesystemView $view
|
||||
* @param $path
|
||||
* @param \OCA\Encryption\Util $util
|
||||
* @param string $path
|
||||
* @param array $shareKeys
|
||||
* @return bool
|
||||
*/
|
||||
public static function setShareKeys(\OC_FilesystemView $view, $path, array $shareKeys) {
|
||||
public static function setShareKeys(\OC_FilesystemView $view, $util, $path, array $shareKeys) {
|
||||
|
||||
// $shareKeys must be an array with the following format:
|
||||
// [userId] => [encrypted key]
|
||||
// Here we need the currently logged in user, while userId can be a different user
|
||||
$util = new Util($view, \OCP\User::getUser());
|
||||
|
||||
list($owner, $filename) = $util->getUidAndFilename($path);
|
||||
|
||||
|
@ -363,21 +359,18 @@ class Keymanager {
|
|||
* @brief retrieve shareKey for an encrypted file
|
||||
* @param \OC_FilesystemView $view
|
||||
* @param string $userId
|
||||
* @param \OCA\Encryption\Util $util
|
||||
* @param string $filePath
|
||||
* @internal param \OCA\Encryption\file $string name
|
||||
* @return string file key or false
|
||||
* @note The sharekey returned is encrypted. Decryption
|
||||
* of the keyfile must be performed by client code
|
||||
*/
|
||||
public static function getShareKey(\OC_FilesystemView $view, $userId, $filePath) {
|
||||
public static function getShareKey(\OC_FilesystemView $view, $userId, $util, $filePath) {
|
||||
|
||||
// try reusing key file if part file
|
||||
$proxyStatus = \OC_FileProxy::$enabled;
|
||||
\OC_FileProxy::$enabled = false;
|
||||
|
||||
//here we need the currently logged in user, while userId can be a different user
|
||||
$util = new Util($view, \OCP\User::getUser());
|
||||
|
||||
list($owner, $filename) = $util->getUidAndFilename($filePath);
|
||||
$filename = Helper::stripPartialFileExtension($filename);
|
||||
// in case of system wide mount points the keys are stored directly in the data directory
|
||||
|
@ -444,8 +437,9 @@ class Keymanager {
|
|||
$proxyStatus = \OC_FileProxy::$enabled;
|
||||
\OC_FileProxy::$enabled = false;
|
||||
|
||||
//here we need the currently logged in user, while userId can be a different user
|
||||
$util = new Util($view, \OCP\User::getUser());
|
||||
$userId = Helper::getUser($filePath);
|
||||
|
||||
$util = new Util($view, $userId);
|
||||
|
||||
list($owner, $filename) = $util->getUidAndFilename($filePath);
|
||||
|
||||
|
|
|
@ -47,8 +47,10 @@ class Proxy extends \OC_FileProxy {
|
|||
*/
|
||||
private static function shouldEncrypt($path) {
|
||||
|
||||
$userId = Helper::getUser($path);
|
||||
|
||||
if (\OCP\App::isEnabled('files_encryption') === false || Crypt::mode() !== 'server' ||
|
||||
strpos($path, '/' . \OCP\User::getUser() . '/files') !== 0) {
|
||||
strpos($path, '/' . $userId . '/files') !== 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -201,7 +203,7 @@ class Proxy extends \OC_FileProxy {
|
|||
list($owner, $ownerPath) = $util->getUidAndFilename($relativePath);
|
||||
|
||||
// Delete keyfile & shareKey so it isn't orphaned
|
||||
if (!Keymanager::deleteFileKey($view, $owner, $ownerPath)) {
|
||||
if (!Keymanager::deleteFileKey($view, $ownerPath)) {
|
||||
\OCP\Util::writeLog('Encryption library',
|
||||
'Keyfile or shareKey could not be deleted for file "' . $ownerPath . '"', \OCP\Util::ERROR);
|
||||
}
|
||||
|
@ -244,9 +246,6 @@ class Proxy extends \OC_FileProxy {
|
|||
// split the path parts
|
||||
$pathParts = explode('/', $path);
|
||||
|
||||
// get relative path
|
||||
$relativePath = \OCA\Encryption\Helper::stripUserFilesPath($path);
|
||||
|
||||
// FIXME: handling for /userId/cache used by webdav for chunking. The cache chunks are NOT encrypted
|
||||
if (isset($pathParts[2]) && $pathParts[2] === 'cache') {
|
||||
return $result;
|
||||
|
@ -260,7 +259,8 @@ class Proxy extends \OC_FileProxy {
|
|||
|
||||
$view = new \OC_FilesystemView('');
|
||||
|
||||
$util = new Util($view, \OCP\USER::getUser());
|
||||
$userId = Helper::getUser($path);
|
||||
$util = new Util($view, $userId);
|
||||
|
||||
// If file is already encrypted, decrypt using crypto protocol
|
||||
if (
|
||||
|
@ -323,7 +323,7 @@ class Proxy extends \OC_FileProxy {
|
|||
|
||||
$view = new \OC_FilesystemView('/');
|
||||
|
||||
$userId = \OCP\User::getUser();
|
||||
$userId = Helper::getUser($path);
|
||||
$util = new Util($view, $userId);
|
||||
|
||||
// if encryption is no longer enabled or if the files aren't migrated yet
|
||||
|
@ -401,7 +401,7 @@ class Proxy extends \OC_FileProxy {
|
|||
|
||||
$view = new \OC_FilesystemView('/');
|
||||
$session = new \OCA\Encryption\Session($view);
|
||||
$userId = \OCP\User::getUser();
|
||||
$userId = Helper::getUser($path);
|
||||
$util = new Util($view, $userId);
|
||||
|
||||
// split the path parts
|
||||
|
|
|
@ -55,6 +55,7 @@ class Stream {
|
|||
private $rawPath; // The raw path relative to the data dir
|
||||
private $relPath; // rel path to users file dir
|
||||
private $userId;
|
||||
private $keyId;
|
||||
private $handle; // Resource returned by fopen
|
||||
private $meta = array(); // Header / meta for source stream
|
||||
private $writeCache;
|
||||
|
@ -90,17 +91,22 @@ class Stream {
|
|||
$this->rootView = new \OC_FilesystemView('/');
|
||||
}
|
||||
|
||||
|
||||
$this->session = new \OCA\Encryption\Session($this->rootView);
|
||||
|
||||
$this->privateKey = $this->session->getPrivateKey($this->userId);
|
||||
|
||||
$util = new Util($this->rootView, \OCP\USER::getUser());
|
||||
|
||||
$this->userId = $util->getUserId();
|
||||
$this->privateKey = $this->session->getPrivateKey();
|
||||
|
||||
// rawPath is relative to the data directory
|
||||
$this->rawPath = \OC\Files\Filesystem::normalizePath(str_replace('crypt://', '', $path));
|
||||
|
||||
$this->userId = Helper::getUser($this->rawPath);
|
||||
|
||||
$util = new Util($this->rootView, $this->userId);
|
||||
|
||||
// get the key ID which we want to use, can be the users key or the
|
||||
// public share key
|
||||
$this->keyId = $util->getKeyId();
|
||||
|
||||
// Strip identifier text from path, this gives us the path relative to data/<user>/files
|
||||
$this->relPath = Helper::stripUserFilesPath($this->rawPath);
|
||||
// if raw path doesn't point to a real file, check if it is a version or a file in the trash bin
|
||||
|
@ -250,12 +256,13 @@ class Stream {
|
|||
|
||||
// Fetch and decrypt keyfile
|
||||
// Fetch existing keyfile
|
||||
$this->encKeyfile = Keymanager::getFileKey($this->rootView, $this->relPath);
|
||||
$util = new \OCA\Encryption\Util($this->rootView, $this->userId);
|
||||
$this->encKeyfile = Keymanager::getFileKey($this->rootView, $util, $this->relPath);
|
||||
|
||||
// If a keyfile already exists
|
||||
if ($this->encKeyfile) {
|
||||
|
||||
$shareKey = Keymanager::getShareKey($this->rootView, $this->userId, $this->relPath);
|
||||
$shareKey = Keymanager::getShareKey($this->rootView, $this->keyId, $util, $this->relPath);
|
||||
|
||||
// if there is no valid private key return false
|
||||
if ($this->privateKey === false) {
|
||||
|
@ -503,7 +510,7 @@ class Stream {
|
|||
\OC_FileProxy::$enabled = false;
|
||||
|
||||
// Fetch user's public key
|
||||
$this->publicKey = Keymanager::getPublicKey($this->rootView, $this->userId);
|
||||
$this->publicKey = Keymanager::getPublicKey($this->rootView, $this->keyId);
|
||||
|
||||
// Check if OC sharing api is enabled
|
||||
$sharingEnabled = \OCP\Share::isEnabled();
|
||||
|
@ -521,10 +528,10 @@ class Stream {
|
|||
$this->encKeyfiles = Crypt::multiKeyEncrypt($this->plainKey, $publicKeys);
|
||||
|
||||
// Save the new encrypted file key
|
||||
Keymanager::setFileKey($this->rootView, $this->relPath, $this->userId, $this->encKeyfiles['data']);
|
||||
Keymanager::setFileKey($this->rootView, $util, $this->relPath, $this->encKeyfiles['data']);
|
||||
|
||||
// Save the sharekeys
|
||||
Keymanager::setShareKeys($this->rootView, $this->relPath, $this->encKeyfiles['keys']);
|
||||
Keymanager::setShareKeys($this->rootView, $util, $this->relPath, $this->encKeyfiles['keys']);
|
||||
|
||||
// Re-enable proxy - our work is done
|
||||
\OC_FileProxy::$enabled = $proxyStatus;
|
||||
|
|
|
@ -38,7 +38,8 @@ class Util {
|
|||
const MIGRATION_OPEN = 0; // user still needs to be migrated
|
||||
|
||||
private $view; // OC_FilesystemView object for filesystem operations
|
||||
private $userId; // ID of the currently logged-in user
|
||||
private $userId; // ID of the user we use to encrypt/decrypt files
|
||||
private $keyId; // ID of the key we want to manipulate
|
||||
private $client; // Client side encryption mode flag
|
||||
private $publicKeyDir; // Dir containing all public user keys
|
||||
private $encryptionDir; // Dir containing user's files_encryption
|
||||
|
@ -58,41 +59,16 @@ class Util {
|
|||
public function __construct(\OC_FilesystemView $view, $userId, $client = false) {
|
||||
|
||||
$this->view = $view;
|
||||
$this->userId = $userId;
|
||||
$this->client = $client;
|
||||
$this->isPublic = false;
|
||||
$this->userId = $userId;
|
||||
|
||||
$this->publicShareKeyId = \OC_Appconfig::getValue('files_encryption', 'publicShareKeyId');
|
||||
$this->recoveryKeyId = \OC_Appconfig::getValue('files_encryption', 'recoveryKeyId');
|
||||
|
||||
// if we are anonymous/public
|
||||
if (\OCA\Encryption\Helper::isPublicAccess()) {
|
||||
$this->userId = $this->publicShareKeyId;
|
||||
|
||||
// only handle for files_sharing app
|
||||
if (isset($GLOBALS['app']) && $GLOBALS['app'] === 'files_sharing') {
|
||||
$this->userDir = '/' . $GLOBALS['fileOwner'];
|
||||
$this->fileFolderName = 'files';
|
||||
$this->userFilesDir = '/' . $GLOBALS['fileOwner'] . '/'
|
||||
. $this->fileFolderName; // TODO: Does this need to be user configurable?
|
||||
$this->publicKeyDir = '/' . 'public-keys';
|
||||
$this->encryptionDir = '/' . $GLOBALS['fileOwner'] . '/' . 'files_encryption';
|
||||
$this->keyfilesPath = $this->encryptionDir . '/' . 'keyfiles';
|
||||
$this->shareKeysPath = $this->encryptionDir . '/' . 'share-keys';
|
||||
$this->publicKeyPath =
|
||||
$this->publicKeyDir . '/' . $this->userId . '.public.key'; // e.g. data/public-keys/admin.public.key
|
||||
$this->privateKeyPath =
|
||||
'/owncloud_private_key/' . $this->userId . '.private.key'; // e.g. data/admin/admin.private.key
|
||||
$this->isPublic = true;
|
||||
// make sure that the owners home is mounted
|
||||
\OC\Files\Filesystem::initMountPoints($GLOBALS['fileOwner']);
|
||||
}
|
||||
|
||||
} else {
|
||||
$this->userDir = '/' . $this->userId;
|
||||
$this->fileFolderName = 'files';
|
||||
$this->userFilesDir =
|
||||
'/' . $this->userId . '/' . $this->fileFolderName; // TODO: Does this need to be user configurable?
|
||||
'/' . $userId . '/' . $this->fileFolderName; // TODO: Does this need to be user configurable?
|
||||
$this->publicKeyDir = '/' . 'public-keys';
|
||||
$this->encryptionDir = '/' . $this->userId . '/' . 'files_encryption';
|
||||
$this->keyfilesPath = $this->encryptionDir . '/' . 'keyfiles';
|
||||
|
@ -102,7 +78,14 @@ class Util {
|
|||
$this->privateKeyPath =
|
||||
$this->encryptionDir . '/' . $this->userId . '.private.key'; // e.g. data/admin/admin.private.key
|
||||
// make sure that the owners home is mounted
|
||||
\OC\Files\Filesystem::initMountPoints($this->userId);
|
||||
\OC\Files\Filesystem::initMountPoints($userId);
|
||||
|
||||
if (\OCA\Encryption\Helper::isPublicAccess()) {
|
||||
$this->keyId = $this->publicShareKeyId;
|
||||
$this->isPublic = true;
|
||||
} else {
|
||||
$this->keyId = $this->userId;
|
||||
$this->isPublic = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -188,13 +171,13 @@ class Util {
|
|||
// check if public-key exists but private-key is missing
|
||||
if ($this->view->file_exists($this->publicKeyPath) && !$this->view->file_exists($this->privateKeyPath)) {
|
||||
\OCP\Util::writeLog('Encryption library',
|
||||
'public key exists but private key is missing for "' . $this->userId . '"', \OCP\Util::FATAL);
|
||||
'public key exists but private key is missing for "' . $this->keyId . '"', \OCP\Util::FATAL);
|
||||
return false;
|
||||
} else {
|
||||
if (!$this->view->file_exists($this->publicKeyPath) && $this->view->file_exists($this->privateKeyPath)
|
||||
) {
|
||||
\OCP\Util::writeLog('Encryption library',
|
||||
'private key exists but public key is missing for "' . $this->userId . '"', \OCP\Util::FATAL);
|
||||
'private key exists but public key is missing for "' . $this->keyId . '"', \OCP\Util::FATAL);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -367,7 +350,7 @@ class Util {
|
|||
// scanning every file like this
|
||||
// will eat server resources :(
|
||||
if (
|
||||
Keymanager::getFileKey($this->view, $relPath)
|
||||
Keymanager::getFileKey($this->view, $this, $relPath)
|
||||
&& $isEncryptedPath
|
||||
) {
|
||||
|
||||
|
@ -478,7 +461,7 @@ class Util {
|
|||
$relPath = Helper::stripUserFilesPath($path);
|
||||
}
|
||||
|
||||
$fileKey = Keymanager::getFileKey($this->view, $relPath);
|
||||
$fileKey = Keymanager::getFileKey($this->view, $this, $relPath);
|
||||
|
||||
if ($fileKey === false) {
|
||||
return false;
|
||||
|
@ -1056,10 +1039,10 @@ class Util {
|
|||
private function decryptKeyfile($filePath, $privateKey) {
|
||||
|
||||
// Get the encrypted keyfile
|
||||
$encKeyfile = Keymanager::getFileKey($this->view, $filePath);
|
||||
$encKeyfile = Keymanager::getFileKey($this->view, $this, $filePath);
|
||||
|
||||
// The file has a shareKey and must use it for decryption
|
||||
$shareKey = Keymanager::getShareKey($this->view, $this->userId, $filePath);
|
||||
$shareKey = Keymanager::getShareKey($this->view, $this->keyId, $this, $filePath);
|
||||
|
||||
$plainKeyfile = Crypt::multiKeyDecrypt($encKeyfile, $shareKey, $privateKey);
|
||||
|
||||
|
@ -1110,8 +1093,8 @@ class Util {
|
|||
// Save the recrypted key to it's owner's keyfiles directory
|
||||
// Save new sharekeys to all necessary user directory
|
||||
if (
|
||||
!Keymanager::setFileKey($this->view, $filePath, $fileOwner, $multiEncKey['data'])
|
||||
|| !Keymanager::setShareKeys($this->view, $filePath, $multiEncKey['keys'])
|
||||
!Keymanager::setFileKey($this->view, $this, $filePath, $multiEncKey['data'])
|
||||
|| !Keymanager::setShareKeys($this->view, $this, $filePath, $multiEncKey['keys'])
|
||||
) {
|
||||
|
||||
\OCP\Util::writeLog('Encryption library',
|
||||
|
@ -1337,7 +1320,7 @@ class Util {
|
|||
// handle public access
|
||||
if ($this->isPublic) {
|
||||
$filename = $path;
|
||||
$fileOwnerUid = $GLOBALS['fileOwner'];
|
||||
$fileOwnerUid = $this->userId;
|
||||
|
||||
return array(
|
||||
$fileOwnerUid,
|
||||
|
@ -1562,6 +1545,13 @@ class Util {
|
|||
return $this->userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getKeyId() {
|
||||
return $this->keyId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
|
|
|
@ -157,6 +157,8 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
|||
|
||||
$filename = 'tmp-' . time() . '.test';
|
||||
|
||||
$util = new Encryption\Util(new \OC_FilesystemView(), $this->userId);
|
||||
|
||||
$cryptedFile = file_put_contents('crypt:///' . $this->userId . '/files/'. $filename, $this->dataShort);
|
||||
|
||||
// Test that data was successfully written
|
||||
|
@ -176,10 +178,10 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
|||
$this->assertNotEquals($this->dataShort, $retreivedCryptedFile);
|
||||
|
||||
// Get the encrypted keyfile
|
||||
$encKeyfile = Encryption\Keymanager::getFileKey($this->view, $filename);
|
||||
$encKeyfile = Encryption\Keymanager::getFileKey($this->view, $util, $filename);
|
||||
|
||||
// Attempt to fetch the user's shareKey
|
||||
$shareKey = Encryption\Keymanager::getShareKey($this->view, $this->userId, $filename);
|
||||
$shareKey = Encryption\Keymanager::getShareKey($this->view, $this->userId, $util, $filename);
|
||||
|
||||
// get session
|
||||
$session = new \OCA\Encryption\Session($this->view);
|
||||
|
@ -199,7 +201,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
|||
// Teardown
|
||||
$this->view->unlink($this->userId . '/files/' . $filename);
|
||||
|
||||
Encryption\Keymanager::deleteFileKey($this->view, $this->userId, $filename);
|
||||
Encryption\Keymanager::deleteFileKey($this->view, $filename);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -214,6 +216,8 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
|||
// Generate a a random filename
|
||||
$filename = 'tmp-' . time() . '.test';
|
||||
|
||||
$util = new Encryption\Util(new \OC_FilesystemView(), $this->userId);
|
||||
|
||||
// Save long data as encrypted file using stream wrapper
|
||||
$cryptedFile = file_put_contents('crypt:///' . $this->userId . '/files/' . $filename, $this->dataLong . $this->dataLong);
|
||||
|
||||
|
@ -250,10 +254,10 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
|||
//print_r($e);
|
||||
|
||||
// Get the encrypted keyfile
|
||||
$encKeyfile = Encryption\Keymanager::getFileKey($this->view, $filename);
|
||||
$encKeyfile = Encryption\Keymanager::getFileKey($this->view, $util, $filename);
|
||||
|
||||
// Attempt to fetch the user's shareKey
|
||||
$shareKey = Encryption\Keymanager::getShareKey($this->view, $this->userId, $filename);
|
||||
$shareKey = Encryption\Keymanager::getShareKey($this->view, $this->userId, $util, $filename);
|
||||
|
||||
// get session
|
||||
$session = new \OCA\Encryption\Session($this->view);
|
||||
|
@ -283,7 +287,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
|
|||
|
||||
$this->view->unlink($this->userId . '/files/' . $filename);
|
||||
|
||||
Encryption\Keymanager::deleteFileKey($this->view, $this->userId, $filename);
|
||||
Encryption\Keymanager::deleteFileKey($this->view, $filename);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -145,13 +145,15 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase {
|
|||
|
||||
$file = 'unittest-' . time() . '.txt';
|
||||
|
||||
$util = new Encryption\Util($this->view, $this->userId);
|
||||
|
||||
// Disable encryption proxy to prevent recursive calls
|
||||
$proxyStatus = \OC_FileProxy::$enabled;
|
||||
\OC_FileProxy::$enabled = false;
|
||||
|
||||
$this->view->file_put_contents($this->userId . '/files/' . $file, $this->dataShort);
|
||||
|
||||
Encryption\Keymanager::setFileKey($this->view, $file, $this->userId, $key);
|
||||
Encryption\Keymanager::setFileKey($this->view, $util, $file, $key);
|
||||
|
||||
$this->assertTrue($this->view->file_exists('/' . $this->userId . '/files_encryption/keyfiles/' . $file . '.key'));
|
||||
|
||||
|
|
|
@ -152,9 +152,6 @@ if (isset($path)) {
|
|||
$tmpl->assign('sharingToken', $token);
|
||||
$tmpl->assign('disableSharing', true);
|
||||
$allowPublicUploadEnabled = (bool) ($linkItem['permissions'] & OCP\PERMISSION_CREATE);
|
||||
if (\OCP\App::isEnabled('files_encryption')) {
|
||||
$allowPublicUploadEnabled = false;
|
||||
}
|
||||
if (OC_Appconfig::getValue('core', 'shareapi_allow_public_upload', 'yes') === 'no') {
|
||||
$allowPublicUploadEnabled = false;
|
||||
}
|
||||
|
|
|
@ -53,8 +53,11 @@ switch($action) {
|
|||
case 'determineGroupsForGroups':
|
||||
case 'determineAttributes':
|
||||
case 'getUserListFilter':
|
||||
case 'getLoginFilterMode':
|
||||
case 'getUserLoginFilter':
|
||||
case 'getUserFilterMode':
|
||||
case 'getGroupFilter':
|
||||
case 'getGroupFilterMode':
|
||||
case 'countUsers':
|
||||
case 'countGroups':
|
||||
try {
|
||||
|
@ -87,6 +90,9 @@ switch($action) {
|
|||
exit;
|
||||
}
|
||||
$configuration->saveConfiguration();
|
||||
//clear the cache on save
|
||||
$connection = new \OCA\user_ldap\lib\Connection($ldapWrapper, $prefix);
|
||||
$connection->clearCache();
|
||||
OCP\JSON::success();
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -67,16 +67,17 @@ class Group_Proxy extends lib\Proxy implements \OCP\GroupInterface {
|
|||
* @param $gid string, the gid connected to the request
|
||||
* @param $method string, the method of the group backend that shall be called
|
||||
* @param $parameters an array of parameters to be passed
|
||||
* @param $passOnWhen the result matches this variable
|
||||
* @return mixed, the result of the method or false
|
||||
*/
|
||||
protected function callOnLastSeenOn($gid, $method, $parameters) {
|
||||
protected function callOnLastSeenOn($gid, $method, $parameters, $passOnWhen) {
|
||||
$cacheKey = $this->getGroupCacheKey($gid);;
|
||||
$prefix = $this->getFromCache($cacheKey);
|
||||
//in case the uid has been found in the past, try this stored connection first
|
||||
if(!is_null($prefix)) {
|
||||
if(isset($this->backends[$prefix])) {
|
||||
$result = call_user_func_array(array($this->backends[$prefix], $method), $parameters);
|
||||
if(!$result) {
|
||||
if($result === $passOnWhen) {
|
||||
//not found here, reset cache to null if group vanished
|
||||
//because sometimes methods return false with a reason
|
||||
$groupExists = call_user_func_array(
|
||||
|
|
|
@ -120,7 +120,7 @@ var LdapConfiguration = {
|
|||
clearMappings: function(mappingSubject) {
|
||||
$.post(
|
||||
OC.filePath('user_ldap','ajax','clearMappings.php'),
|
||||
'ldap_clear_mapping='+mappingSubject,
|
||||
'ldap_clear_mapping='+encodeURIComponent(mappingSubject),
|
||||
function(result) {
|
||||
if(result.status == 'success') {
|
||||
OC.dialogs.info(
|
||||
|
@ -143,6 +143,8 @@ var LdapWizard = {
|
|||
saveBlacklist: {},
|
||||
userFilterGroupSelectState: 'enable',
|
||||
spinner: '<img class="wizSpinner" src="'+ OC.imagePath('core', 'loading.gif') +'">',
|
||||
filterModeAssisted: 0,
|
||||
filterModeRaw: 1,
|
||||
|
||||
ajax: function(param, fnOnSuccess, fnOnError) {
|
||||
$.post(
|
||||
|
@ -160,10 +162,7 @@ var LdapWizard = {
|
|||
|
||||
applyChanges: function (result) {
|
||||
for (id in result.changes) {
|
||||
if(!$.isArray(result.changes[id])) {
|
||||
//no need to blacklist multiselect
|
||||
LdapWizard.saveBlacklist[id] = true;
|
||||
}
|
||||
LdapWizard.blacklistAdd(id);
|
||||
if(id.indexOf('count') > 0) {
|
||||
$('#'+id).text(result.changes[id]);
|
||||
} else {
|
||||
|
@ -195,6 +194,25 @@ var LdapWizard = {
|
|||
}
|
||||
},
|
||||
|
||||
|
||||
blacklistAdd: function(id) {
|
||||
obj = $('#'+id);
|
||||
if(!(obj[0].hasOwnProperty('multiple') && obj[0]['multiple'] == true)) {
|
||||
//no need to blacklist multiselect
|
||||
LdapWizard.saveBlacklist[id] = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
blacklistRemove: function(id) {
|
||||
if(LdapWizard.saveBlacklist.hasOwnProperty(id)) {
|
||||
delete LdapWizard.saveBlacklist[id];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
checkBaseDN: function() {
|
||||
host = $('#ldap_host').val();
|
||||
port = $('#ldap_port').val();
|
||||
|
@ -204,7 +222,8 @@ var LdapWizard = {
|
|||
//FIXME: determine base dn with anonymous access
|
||||
if(host && port && user && pass) {
|
||||
param = 'action=guessBaseDN'+
|
||||
'&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val();
|
||||
'&ldap_serverconfig_chooser='+
|
||||
encodeURIComponent($('#ldap_serverconfig_chooser').val());
|
||||
|
||||
LdapWizard.showSpinner('#ldap_base');
|
||||
$('#ldap_base').prop('disabled', 'disabled');
|
||||
|
@ -232,7 +251,8 @@ var LdapWizard = {
|
|||
|
||||
if(host && !port) {
|
||||
param = 'action=guessPortAndTLS'+
|
||||
'&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val();
|
||||
'&ldap_serverconfig_chooser='+
|
||||
encodeURIComponent($('#ldap_serverconfig_chooser').val());
|
||||
|
||||
LdapWizard.showSpinner('#ldap_port');
|
||||
$('#ldap_port').prop('disabled', 'disabled');
|
||||
|
@ -256,6 +276,12 @@ var LdapWizard = {
|
|||
},
|
||||
|
||||
composeFilter: function(type) {
|
||||
subject = type.charAt(0).toUpperCase() + type.substr(1);
|
||||
if(!$('#raw'+subject+'FilterContainer').hasClass('invisible')) {
|
||||
//Raw filter editing, i.e. user defined filter, don't compose
|
||||
return;
|
||||
}
|
||||
|
||||
if(type == 'user') {
|
||||
action = 'getUserListFilter';
|
||||
} else if(type == 'login') {
|
||||
|
@ -265,7 +291,8 @@ var LdapWizard = {
|
|||
}
|
||||
|
||||
param = 'action='+action+
|
||||
'&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val();
|
||||
'&ldap_serverconfig_chooser='+
|
||||
encodeURIComponent($('#ldap_serverconfig_chooser').val());
|
||||
|
||||
LdapWizard.ajax(param,
|
||||
function(result) {
|
||||
|
@ -323,7 +350,8 @@ var LdapWizard = {
|
|||
|
||||
_countThings: function(method) {
|
||||
param = 'action='+method+
|
||||
'&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val();
|
||||
'&ldap_serverconfig_chooser='+
|
||||
encodeURIComponent($('#ldap_serverconfig_chooser').val());
|
||||
|
||||
LdapWizard.ajax(param,
|
||||
function(result) {
|
||||
|
@ -345,7 +373,8 @@ var LdapWizard = {
|
|||
|
||||
detectGroupMemberAssoc: function() {
|
||||
param = 'action=determineGroupMemberAssoc'+
|
||||
'&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val();
|
||||
'&ldap_serverconfig_chooser='+
|
||||
encodeURIComponent($('#ldap_serverconfig_chooser').val());
|
||||
|
||||
LdapWizard.ajax(param,
|
||||
function(result) {
|
||||
|
@ -359,7 +388,8 @@ var LdapWizard = {
|
|||
|
||||
findAttributes: function() {
|
||||
param = 'action=determineAttributes'+
|
||||
'&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val();
|
||||
'&ldap_serverconfig_chooser='+
|
||||
encodeURIComponent($('#ldap_serverconfig_chooser').val());
|
||||
|
||||
LdapWizard.showSpinner('#ldap_loginfilter_attributes');
|
||||
LdapWizard.ajax(param,
|
||||
|
@ -374,7 +404,9 @@ var LdapWizard = {
|
|||
LdapWizard.hideSpinner('#ldap_loginfilter_attributes');
|
||||
LdapWizard.applyChanges(result);
|
||||
$('#ldap_loginfilter_attributes').multiselect('refresh');
|
||||
if($('#rawLoginFilterContainer').hasClass('invisible')) {
|
||||
$('#ldap_loginfilter_attributes').multiselect('enable');
|
||||
}
|
||||
},
|
||||
function (result) {
|
||||
//deactivate if no attributes found
|
||||
|
@ -390,8 +422,9 @@ var LdapWizard = {
|
|||
if(type != 'Users' && type != 'Groups') {
|
||||
return false;
|
||||
}
|
||||
param = 'action=determineGroupsFor'+type+
|
||||
'&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val();
|
||||
param = 'action=determineGroupsFor'+encodeURIComponent(type)+
|
||||
'&ldap_serverconfig_chooser='+
|
||||
encodeURIComponent($('#ldap_serverconfig_chooser').val());
|
||||
|
||||
LdapWizard.showSpinner('#'+multisel);
|
||||
LdapWizard.ajax(param,
|
||||
|
@ -405,7 +438,11 @@ var LdapWizard = {
|
|||
LdapWizard.hideSpinner('#'+multisel);
|
||||
LdapWizard.applyChanges(result);
|
||||
$('#'+multisel).multiselect('refresh');
|
||||
part = type.slice(0, -1);
|
||||
if($('#raw' + part + 'FilterContainer').hasClass('invisible')) {
|
||||
//enable only when raw filter editing is not turned on
|
||||
$('#'+multisel).multiselect('enable');
|
||||
}
|
||||
},
|
||||
function (result) {
|
||||
LdapWizard.hideSpinner('#'+multisel);
|
||||
|
@ -418,8 +455,9 @@ var LdapWizard = {
|
|||
if(type != 'User' && type != 'Group') {
|
||||
return false;
|
||||
}
|
||||
param = 'action=determine'+type+'ObjectClasses'+
|
||||
'&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val();
|
||||
param = 'action=determine'+encodeURIComponent(type)+'ObjectClasses'+
|
||||
'&ldap_serverconfig_chooser='+
|
||||
encodeURIComponent($('#ldap_serverconfig_chooser').val());
|
||||
|
||||
LdapWizard.showSpinner('#'+multisel);
|
||||
LdapWizard.ajax(param,
|
||||
|
@ -485,15 +523,15 @@ var LdapWizard = {
|
|||
},
|
||||
|
||||
initGroupFilter: function() {
|
||||
LdapWizard.regardFilterMode('Group');
|
||||
LdapWizard.findObjectClasses('ldap_groupfilter_objectclass', 'Group');
|
||||
LdapWizard.findAvailableGroups('ldap_groupfilter_groups', 'Groups');
|
||||
LdapWizard.composeFilter('group');
|
||||
LdapWizard.countGroups();
|
||||
},
|
||||
|
||||
initLoginFilter: function() {
|
||||
LdapWizard.regardFilterMode('Login');
|
||||
LdapWizard.findAttributes();
|
||||
LdapWizard.composeFilter('login');
|
||||
},
|
||||
|
||||
initMultiSelect: function(object, id, caption) {
|
||||
|
@ -509,9 +547,9 @@ var LdapWizard = {
|
|||
},
|
||||
|
||||
initUserFilter: function() {
|
||||
LdapWizard.regardFilterMode('User');
|
||||
LdapWizard.findObjectClasses('ldap_userfilter_objectclass', 'User');
|
||||
LdapWizard.findAvailableGroups('ldap_userfilter_groups', 'Users');
|
||||
LdapWizard.composeFilter('user');
|
||||
LdapWizard.countUsers();
|
||||
},
|
||||
|
||||
|
@ -566,9 +604,36 @@ var LdapWizard = {
|
|||
}
|
||||
},
|
||||
|
||||
regardFilterMode: function(subject) {
|
||||
param = 'action=get'+encodeURIComponent(subject)+'FilterMode'+
|
||||
'&ldap_serverconfig_chooser='+
|
||||
encodeURIComponent($('#ldap_serverconfig_chooser').val());
|
||||
|
||||
LdapWizard.ajax(param,
|
||||
function(result) {
|
||||
property = 'ldap' + subject + 'FilterMode';
|
||||
mode = result.changes[property];
|
||||
if(mode == LdapWizard.filterModeRaw
|
||||
&& $('#raw'+subject+'FilterContainer').hasClass('invisible')) {
|
||||
LdapWizard['toggleRaw'+subject+'Filter']();
|
||||
} else if(mode == LdapWizard.filterModeAssisted
|
||||
&& !$('#raw'+subject+'FilterContainer').hasClass('invisible')) {
|
||||
LdapWizard['toggleRaw'+subject+'Filter']();
|
||||
} else {
|
||||
c = $('#raw'+subject+'FilterContainer').hasClass('invisible');
|
||||
}
|
||||
},
|
||||
function (result) {
|
||||
//on error case get back to default i.e. Assisted
|
||||
if(!$('#raw'+subject+'FilterContainer').hasClass('invisible')) {
|
||||
LdapWizard['toggleRaw'+subject+'Filter']();
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
save: function(inputObj) {
|
||||
if(LdapWizard.saveBlacklist.hasOwnProperty(inputObj.id)) {
|
||||
delete LdapWizard.saveBlacklist[inputObj.id];
|
||||
if(LdapWizard.blacklistRemove(inputObj.id)) {
|
||||
return;
|
||||
}
|
||||
if($(inputObj).is('input[type=checkbox]')
|
||||
|
@ -601,8 +666,8 @@ var LdapWizard = {
|
|||
},
|
||||
|
||||
_save: function(object, value) {
|
||||
param = 'cfgkey='+object.id+
|
||||
'&cfgval='+value+
|
||||
param = 'cfgkey='+encodeURIComponent(object.id)+
|
||||
'&cfgval='+encodeURIComponent(value)+
|
||||
'&action=save'+
|
||||
'&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val();
|
||||
|
||||
|
@ -632,7 +697,9 @@ var LdapWizard = {
|
|||
}
|
||||
},
|
||||
|
||||
toggleRawFilter: function(container, moc, mg, stateVar) {
|
||||
toggleRawFilter: function(container, moc, mg, stateVar, modeKey) {
|
||||
//moc = multiselect objectclass
|
||||
//mg = mutliselect groups
|
||||
if($(container).hasClass('invisible')) {
|
||||
$(container).removeClass('invisible');
|
||||
$(moc).multiselect('disable');
|
||||
|
@ -642,26 +709,62 @@ var LdapWizard = {
|
|||
LdapWizard[stateVar] = 'enable';
|
||||
}
|
||||
$(mg).multiselect('disable');
|
||||
LdapWizard._save({ id: modeKey }, LdapWizard.filterModeRaw);
|
||||
} else {
|
||||
$(container).addClass('invisible');
|
||||
$(mg).multiselect(LdapWizard[stateVar]);
|
||||
$(moc).multiselect('enable');
|
||||
LdapWizard._save({ id: modeKey }, LdapWizard.filterModeAssisted);
|
||||
if(moc.indexOf('user') >= 0) {
|
||||
LdapWizard.blacklistRemove('ldap_userlist_filter');
|
||||
LdapWizard.composeFilter('user');
|
||||
} else {
|
||||
LdapWizard.blacklistRemove('ldap_group_filter');
|
||||
LdapWizard.composeFilter('group');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toggleRawGroupFilter: function() {
|
||||
LdapWizard.blacklistRemove('ldap_group_filter');
|
||||
LdapWizard.toggleRawFilter('#rawGroupFilterContainer',
|
||||
'#ldap_groupfilter_objectclass',
|
||||
'#ldap_groupfilter_groups',
|
||||
'groupFilterGroupSelectState'
|
||||
'groupFilterGroupSelectState',
|
||||
'ldapGroupFilterMode'
|
||||
);
|
||||
},
|
||||
|
||||
toggleRawLoginFilter: function() {
|
||||
LdapWizard.blacklistRemove('ldap_login_filter');
|
||||
container = '#rawLoginFilterContainer';
|
||||
if($(container).hasClass('invisible')) {
|
||||
$(container).removeClass('invisible');
|
||||
action = 'disable';
|
||||
property = 'disabled';
|
||||
mode = LdapWizard.filterModeRaw;
|
||||
} else {
|
||||
$(container).addClass('invisible');
|
||||
action = 'enable';
|
||||
property = false;
|
||||
mode = LdapWizard.filterModeAssisted;
|
||||
}
|
||||
$('#ldap_loginfilter_attributes').multiselect(action);
|
||||
$('#ldap_loginfilter_email').prop('disabled', property);
|
||||
$('#ldap_loginfilter_username').prop('disabled', property);
|
||||
LdapWizard._save({ id: 'ldapLoginFilterMode' }, mode);
|
||||
if(action == 'enable') {
|
||||
LdapWizard.composeFilter('login');
|
||||
}
|
||||
},
|
||||
|
||||
toggleRawUserFilter: function() {
|
||||
LdapWizard.blacklistRemove('ldap_userlist_filter');
|
||||
LdapWizard.toggleRawFilter('#rawUserFilterContainer',
|
||||
'#ldap_userfilter_objectclass',
|
||||
'#ldap_userfilter_groups',
|
||||
'userFilterGroupSelectState'
|
||||
'userFilterGroupSelectState',
|
||||
'ldapUserFilterMode'
|
||||
);
|
||||
},
|
||||
|
||||
|
@ -722,6 +825,7 @@ $(document).ready(function() {
|
|||
$('.lwautosave').change(function() { LdapWizard.save(this); });
|
||||
$('#toggleRawUserFilter').click(LdapWizard.toggleRawUserFilter);
|
||||
$('#toggleRawGroupFilter').click(LdapWizard.toggleRawGroupFilter);
|
||||
$('#toggleRawLoginFilter').click(LdapWizard.toggleRawLoginFilter);
|
||||
LdapConfiguration.refreshConfig();
|
||||
$('.ldap_action_continue').click(function(event) {
|
||||
event.preventDefault();
|
||||
|
|
|
@ -199,7 +199,9 @@ class Access extends LDAPUtility {
|
|||
*/
|
||||
public function username2dn($name) {
|
||||
$dn = $this->ocname2dn($name, true);
|
||||
if($dn) {
|
||||
//Check whether the DN belongs to the Base, to avoid issues on multi-
|
||||
//server setups
|
||||
if($dn && $this->isDNPartOfBase($dn, $this->connection->ldapBaseUsers)) {
|
||||
return $dn;
|
||||
}
|
||||
|
||||
|
|
|
@ -47,12 +47,15 @@ class Configuration {
|
|||
'ldapUserFilterObjectclass' => null,
|
||||
'ldapUserFilterGroups' => null,
|
||||
'ldapUserFilter' => null,
|
||||
'ldapUserFilterMode' => null,
|
||||
'ldapGroupFilter' => null,
|
||||
'ldapGroupFilterMode' => null,
|
||||
'ldapGroupFilterObjectclass' => null,
|
||||
'ldapGroupFilterGroups' => null,
|
||||
'ldapGroupDisplayName' => null,
|
||||
'ldapGroupMemberAssocAttr' => null,
|
||||
'ldapLoginFilter' => null,
|
||||
'ldapLoginFilterMode' => null,
|
||||
'ldapLoginFilterEmail' => null,
|
||||
'ldapLoginFilterUsername' => null,
|
||||
'ldapLoginFilterAttributes' => null,
|
||||
|
@ -72,6 +75,7 @@ class Configuration {
|
|||
'ldapExpertUsernameAttr' => null,
|
||||
'ldapExpertUUIDUserAttr' => null,
|
||||
'ldapExpertUUIDGroupAttr' => null,
|
||||
'lastJpegPhotoLookup' => null,
|
||||
);
|
||||
|
||||
public function __construct($configPrefix, $autoread = true) {
|
||||
|
@ -301,13 +305,16 @@ class Configuration {
|
|||
'ldap_base_users' => '',
|
||||
'ldap_base_groups' => '',
|
||||
'ldap_userlist_filter' => '',
|
||||
'ldap_user_filter_mode' => 0,
|
||||
'ldap_userfilter_objectclass' => '',
|
||||
'ldap_userfilter_groups' => '',
|
||||
'ldap_login_filter' => 'uid=%uid',
|
||||
'ldap_login_filter_mode' => 0,
|
||||
'ldap_loginfilter_email' => 0,
|
||||
'ldap_loginfilter_username' => 1,
|
||||
'ldap_loginfilter_attributes' => '',
|
||||
'ldap_group_filter' => '',
|
||||
'ldap_group_filter_mode' => 0,
|
||||
'ldap_groupfilter_objectclass' => '',
|
||||
'ldap_groupfilter_groups' => '',
|
||||
'ldap_display_name' => 'displayName',
|
||||
|
@ -330,6 +337,7 @@ class Configuration {
|
|||
'ldap_expert_uuid_user_attr' => '',
|
||||
'ldap_expert_uuid_group_attr' => '',
|
||||
'has_memberof_filter_support' => 0,
|
||||
'last_jpegPhoto_lookup' => 0,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -352,11 +360,14 @@ class Configuration {
|
|||
'ldap_userfilter_objectclass' => 'ldapUserFilterObjectclass',
|
||||
'ldap_userfilter_groups' => 'ldapUserFilterGroups',
|
||||
'ldap_userlist_filter' => 'ldapUserFilter',
|
||||
'ldap_user_filter_mode' => 'ldapUserFilterMode',
|
||||
'ldap_login_filter' => 'ldapLoginFilter',
|
||||
'ldap_login_filter_mode' => 'ldapLoginFilterMode',
|
||||
'ldap_loginfilter_email' => 'ldapLoginFilterEmail',
|
||||
'ldap_loginfilter_username' => 'ldapLoginFilterUsername',
|
||||
'ldap_loginfilter_attributes' => 'ldapLoginFilterAttributes',
|
||||
'ldap_group_filter' => 'ldapGroupFilter',
|
||||
'ldap_group_filter_mode' => 'ldapGroupFilterMode',
|
||||
'ldap_groupfilter_objectclass' => 'ldapGroupFilterObjectclass',
|
||||
'ldap_groupfilter_groups' => 'ldapGroupFilterGroups',
|
||||
'ldap_display_name' => 'ldapUserDisplayName',
|
||||
|
@ -377,6 +388,7 @@ class Configuration {
|
|||
'ldap_expert_uuid_user_attr' => 'ldapExpertUUIDUserAttr',
|
||||
'ldap_expert_uuid_group_attr' => 'ldapExpertUUIDGroupAttr',
|
||||
'has_memberof_filter_support' => 'hasMemberOfFilterSupport',
|
||||
'last_jpegPhoto_lookup' => 'lastJpegPhotoLookup',
|
||||
);
|
||||
return $array;
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ abstract class Proxy {
|
|||
return 'group-'.$gid.'-lastSeenOn';
|
||||
}
|
||||
|
||||
abstract protected function callOnLastSeenOn($id, $method, $parameters);
|
||||
abstract protected function callOnLastSeenOn($id, $method, $parameters, $passOnWhen);
|
||||
abstract protected function walkBackends($id, $method, $parameters);
|
||||
|
||||
/**
|
||||
|
@ -64,8 +64,9 @@ abstract class Proxy {
|
|||
* @param $parameters an array of parameters to be passed
|
||||
* @return mixed, the result of the specified method
|
||||
*/
|
||||
protected function handleRequest($id, $method, $parameters) {
|
||||
if(!$result = $this->callOnLastSeenOn($id, $method, $parameters)) {
|
||||
protected function handleRequest($id, $method, $parameters, $passOnWhen = false) {
|
||||
$result = $this->callOnLastSeenOn($id, $method, $parameters, $passOnWhen);
|
||||
if($result === $passOnWhen) {
|
||||
$result = $this->walkBackends($id, $method, $parameters);
|
||||
}
|
||||
return $result;
|
||||
|
|
|
@ -38,6 +38,9 @@ class Wizard extends LDAPUtility {
|
|||
const LFILTER_USER_LIST = 3;
|
||||
const LFILTER_GROUP_LIST = 4;
|
||||
|
||||
const LFILTER_MODE_ASSISTED = 2;
|
||||
const LFILTER_MODE_RAW = 1;
|
||||
|
||||
const LDAP_NW_TIMEOUT = 4;
|
||||
|
||||
/**
|
||||
|
@ -147,6 +150,42 @@ class Wizard extends LDAPUtility {
|
|||
return $this->result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief return the state of the Group Filter Mode
|
||||
*/
|
||||
public function getGroupFilterMode() {
|
||||
$this->getFilterMode('ldapGroupFilterMode');
|
||||
return $this->result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief return the state of the Login Filter Mode
|
||||
*/
|
||||
public function getLoginFilterMode() {
|
||||
$this->getFilterMode('ldapLoginFilterMode');
|
||||
return $this->result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief return the state of the User Filter Mode
|
||||
*/
|
||||
public function getUserFilterMode() {
|
||||
$this->getFilterMode('ldapUserFilterMode');
|
||||
return $this->result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief return the state of the mode of the specified filter
|
||||
* @param $confkey string, contains the access key of the Configuration
|
||||
*/
|
||||
private function getFilterMode($confkey) {
|
||||
$mode = $this->configuration->$confkey;
|
||||
if(is_null($mode)) {
|
||||
$mode = $this->LFILTER_MODE_ASSISTED;
|
||||
}
|
||||
$this->result->addChange($confkey, $mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief detects the available LDAP attributes
|
||||
* @returns the instance's WizardResult instance
|
||||
|
|
|
@ -28,6 +28,16 @@
|
|||
name="ldap_loginfilter_attributes">
|
||||
</select>
|
||||
</p>
|
||||
<p>
|
||||
<label><a id='toggleRawLoginFilter'>↓ <?php p($l->t('Edit raw filter instead'));?></a></label>
|
||||
</p>
|
||||
<p id="rawLoginFilterContainer" class="invisible">
|
||||
<input type="text" id="ldap_login_filter" name="ldap_login_filter"
|
||||
class="lwautosave"
|
||||
placeholder="<?php p($l->t('Raw LDAP filter'));?>"
|
||||
title="<?php p($l->t('Defines the filter to apply, when login is attempted. %%uid replaces the username in the login action. Example: "uid=%%uid"'));?>"
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<div class="ldapWizardInfo invisible"> </div>
|
||||
</p>
|
||||
|
|
|
@ -20,9 +20,6 @@
|
|||
<h3><?php p($l->t('Connection Settings'));?></h3>
|
||||
<div>
|
||||
<p><label for="ldap_configuration_active"><?php p($l->t('Configuration Active'));?></label><input type="checkbox" id="ldap_configuration_active" name="ldap_configuration_active" value="1" data-default="<?php p($_['ldap_configuration_active_default']); ?>" title="<?php p($l->t('When unchecked, this configuration will be skipped.'));?>" /></p>
|
||||
<p><label for="ldap_login_filter"><?php p($l->t('User Login Filter'));?></label><input type="text" id="ldap_login_filter" name="ldap_login_filter"
|
||||
data-default="<?php p($_['ldap_login_filter_default']); ?>"
|
||||
title="<?php p($l->t('Defines the filter to apply, when login is attempted. %%uid replaces the username in the login action. Example: "uid=%%uid"'));?>" /></p>
|
||||
<p><label for="ldap_backup_host"><?php p($l->t('Backup (Replica) Host'));?></label><input type="text" id="ldap_backup_host" name="ldap_backup_host" data-default="<?php p($_['ldap_backup_host_default']); ?>" title="<?php p($l->t('Give an optional backup host. It must be a replica of the main LDAP/AD server.'));?>"></p>
|
||||
<p><label for="ldap_backup_port"><?php p($l->t('Backup (Replica) Port'));?></label><input type="number" id="ldap_backup_port" name="ldap_backup_port" data-default="<?php p($_['ldap_backup_port_default']); ?>" /></p>
|
||||
<p><label for="ldap_override_main_server"><?php p($l->t('Disable Main Server'));?></label><input type="checkbox" id="ldap_override_main_server" name="ldap_override_main_server" value="1" data-default="<?php p($_['ldap_override_main_server_default']); ?>" title="<?php p($l->t('Only connect to the replica server.'));?>" /></p>
|
||||
|
|
|
@ -69,6 +69,74 @@ class USER_LDAP extends BackendUtility implements \OCP\UserInterface {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief reads jpegPhoto and set is as avatar if available
|
||||
* @param $uid string ownCloud user name
|
||||
* @param $dn string the user's LDAP DN
|
||||
* @return void
|
||||
*/
|
||||
private function updateAvatar($uid, $dn) {
|
||||
$hasLoggedIn = \OCP\Config::getUserValue($uid, 'user_ldap',
|
||||
'firstLoginAccomplished', 0);
|
||||
$lastChecked = \OCP\Config::getUserValue($uid, 'user_ldap',
|
||||
'lastJpegPhotoLookup', 0);
|
||||
if(($hasLoggedIn !== '1') || (time() - intval($lastChecked)) < 86400 ) {
|
||||
//update only once a day
|
||||
return;
|
||||
}
|
||||
|
||||
$jpegPhoto = $this->access->readAttribute($dn, 'jpegPhoto');
|
||||
\OCP\Config::setUserValue($uid, 'user_ldap', 'lastJpegPhotoLookup', time());
|
||||
if(!$jpegPhoto || !is_array($jpegPhoto) || !isset($jpegPhoto[0])) {
|
||||
//not set, nothing left to do;
|
||||
return;
|
||||
}
|
||||
|
||||
$image = new \OCP\Image();
|
||||
$image->loadFromBase64(base64_encode($jpegPhoto[0]));
|
||||
|
||||
if(!$image->valid()) {
|
||||
\OCP\Util::writeLog('user_ldap', 'jpegPhoto data invalid for '.$dn,
|
||||
\OCP\Util::ERROR);
|
||||
return;
|
||||
}
|
||||
//make sure it is a square and not bigger than 128x128
|
||||
$size = min(array($image->width(), $image->height(), 128));
|
||||
if(!$image->centerCrop($size)) {
|
||||
\OCP\Util::writeLog('user_ldap',
|
||||
'croping image for avatar failed for '.$dn,
|
||||
\OCP\Util::ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!\OC\Files\Filesystem::$loaded) {
|
||||
\OC_Util::setupFS($uid);
|
||||
}
|
||||
|
||||
$avatarManager = \OC::$server->getAvatarManager();
|
||||
$avatar = $avatarManager->getAvatar($uid);
|
||||
$avatar->set($image);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief checks whether the user is allowed to change his avatar in ownCloud
|
||||
* @param $uid string the ownCloud user name
|
||||
* @return boolean either the user can or cannot
|
||||
*/
|
||||
public function canChangeAvatar($uid) {
|
||||
$dn = $this->access->username2dn($uid);
|
||||
if(!$dn) {
|
||||
return false;
|
||||
}
|
||||
$jpegPhoto = $this->access->readAttribute($dn, 'jpegPhoto');
|
||||
if(!$jpegPhoto || !is_array($jpegPhoto) || !isset($jpegPhoto[0])) {
|
||||
//The user is allowed to change his avatar in ownCloud only if no
|
||||
//avatar is provided by LDAP
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if the password is correct
|
||||
* @param $uid The username
|
||||
|
@ -100,6 +168,10 @@ class USER_LDAP extends BackendUtility implements \OCP\UserInterface {
|
|||
return false;
|
||||
}
|
||||
|
||||
\OCP\Config::setUserValue($ocname, 'user_ldap',
|
||||
'firstLoginAccomplished', 1);
|
||||
|
||||
$this->updateAvatar($ocname, $dn);
|
||||
//give back the display name
|
||||
return $ocname;
|
||||
}
|
||||
|
@ -173,6 +245,7 @@ class USER_LDAP extends BackendUtility implements \OCP\UserInterface {
|
|||
|
||||
$this->access->connection->writeToCache('userExists'.$uid, true);
|
||||
$this->updateQuota($dn);
|
||||
$this->updateAvatar($uid, $dn);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -289,7 +362,8 @@ class USER_LDAP extends BackendUtility implements \OCP\UserInterface {
|
|||
public function implementsActions($actions) {
|
||||
return (bool)((OC_USER_BACKEND_CHECK_PASSWORD
|
||||
| OC_USER_BACKEND_GET_HOME
|
||||
| OC_USER_BACKEND_GET_DISPLAYNAME)
|
||||
| OC_USER_BACKEND_GET_DISPLAYNAME
|
||||
| OC_USER_BACKEND_PROVIDE_AVATAR)
|
||||
& $actions);
|
||||
}
|
||||
|
||||
|
|
|
@ -54,6 +54,7 @@ class User_Proxy extends lib\Proxy implements \OCP\UserInterface {
|
|||
protected function walkBackends($uid, $method, $parameters) {
|
||||
$cacheKey = $this->getUserCacheKey($uid);
|
||||
foreach($this->backends as $configPrefix => $backend) {
|
||||
// print("walkBackend '$configPrefix'<br/>");
|
||||
if($result = call_user_func_array(array($backend, $method), $parameters)) {
|
||||
$this->writeToCache($cacheKey, $configPrefix);
|
||||
return $result;
|
||||
|
@ -67,16 +68,17 @@ class User_Proxy extends lib\Proxy implements \OCP\UserInterface {
|
|||
* @param $uid string, the uid connected to the request
|
||||
* @param $method string, the method of the user backend that shall be called
|
||||
* @param $parameters an array of parameters to be passed
|
||||
* @param $passOnWhen the result matches this variable
|
||||
* @return mixed, the result of the method or false
|
||||
*/
|
||||
protected function callOnLastSeenOn($uid, $method, $parameters) {
|
||||
protected function callOnLastSeenOn($uid, $method, $parameters, $passOnWhen) {
|
||||
$cacheKey = $this->getUserCacheKey($uid);
|
||||
$prefix = $this->getFromCache($cacheKey);
|
||||
//in case the uid has been found in the past, try this stored connection first
|
||||
if(!is_null($prefix)) {
|
||||
if(isset($this->backends[$prefix])) {
|
||||
$result = call_user_func_array(array($this->backends[$prefix], $method), $parameters);
|
||||
if(!$result) {
|
||||
if($result === $passOnWhen) {
|
||||
//not found here, reset cache to null if user vanished
|
||||
//because sometimes methods return false with a reason
|
||||
$userExists = call_user_func_array(
|
||||
|
@ -163,6 +165,15 @@ class User_Proxy extends lib\Proxy implements \OCP\UserInterface {
|
|||
return $this->handleRequest($uid, 'getDisplayName', array($uid));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief checks whether the user is allowed to change his avatar in ownCloud
|
||||
* @param $uid string the ownCloud user name
|
||||
* @return boolean either the user can or cannot
|
||||
*/
|
||||
public function canChangeAvatar($uid) {
|
||||
return $this->handleRequest($uid, 'canChangeAvatar', array($uid), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a list of all display names
|
||||
* @returns array with all displayNames (value) and the corresponding uids (key)
|
||||
|
|
107
db_structure.xml
107
db_structure.xml
|
@ -9,6 +9,11 @@
|
|||
|
||||
<table>
|
||||
|
||||
<!--
|
||||
Namespaced Key-Value Store for Application Configuration.
|
||||
- Keys are namespaced per appid.
|
||||
- E.g. (core, global_cache_gc_lastrun) -> 1385463286
|
||||
-->
|
||||
<name>*dbprefix*appconfig</name>
|
||||
|
||||
<declaration>
|
||||
|
@ -62,6 +67,13 @@
|
|||
|
||||
<table>
|
||||
|
||||
<!--
|
||||
Bidirectional Map for Storage Names and Storage Ids.
|
||||
- Assigns each storage name a unique storage id integer.
|
||||
- Long storage names are hashed.
|
||||
- E.g. local::/tmp/ <-> 2
|
||||
- E.g. b5db994aa8c6625100e418406c798269 <-> 27
|
||||
-->
|
||||
<name>*dbprefix*storages</name>
|
||||
|
||||
<declaration>
|
||||
|
@ -159,6 +171,12 @@
|
|||
|
||||
<table>
|
||||
|
||||
<!--
|
||||
Bidirectional Map for Mimetypes and Mimetype Id
|
||||
- Assigns each mimetype (and supertype) a unique mimetype id integer.
|
||||
- E.g. application <-> 5
|
||||
- E.g. application/pdf <-> 6
|
||||
-->
|
||||
<name>*dbprefix*mimetypes</name>
|
||||
|
||||
<declaration>
|
||||
|
@ -195,6 +213,16 @@
|
|||
|
||||
<table>
|
||||
|
||||
<!--
|
||||
Main file table containing one row for each directory and file.
|
||||
- Assigns a unique integer fileid to each file (and directory)
|
||||
- Assigns an etag to each file (and directory)
|
||||
- Caches various file/dir properties such as:
|
||||
- path (filename, e.g. files/combinatoricslib-2.0_doc.zip)
|
||||
- path_hash = md5(path)
|
||||
- name (basename, e.g. combinatoricslib-2.0_doc.zip)
|
||||
- size (for directories this is the sum of all contained file sizes)
|
||||
-->
|
||||
<name>*dbprefix*filecache</name>
|
||||
|
||||
<declaration>
|
||||
|
@ -208,6 +236,7 @@
|
|||
<length>4</length>
|
||||
</field>
|
||||
|
||||
<!-- Foreign Key storages::numeric_id -->
|
||||
<field>
|
||||
<name>storage</name>
|
||||
<type>integer</type>
|
||||
|
@ -232,6 +261,7 @@
|
|||
<length>32</length>
|
||||
</field>
|
||||
|
||||
<!-- Foreign Key filecache::fileid -->
|
||||
<field>
|
||||
<name>parent</name>
|
||||
<type>integer</type>
|
||||
|
@ -248,6 +278,7 @@
|
|||
<length>250</length>
|
||||
</field>
|
||||
|
||||
<!-- Foreign Key mimetypes::id -->
|
||||
<field>
|
||||
<name>mimetype</name>
|
||||
<type>integer</type>
|
||||
|
@ -256,6 +287,7 @@
|
|||
<length>4</length>
|
||||
</field>
|
||||
|
||||
<!-- Foreign Key mimetypes::id -->
|
||||
<field>
|
||||
<name>mimepart</name>
|
||||
<type>integer</type>
|
||||
|
@ -367,10 +399,15 @@
|
|||
|
||||
<table>
|
||||
|
||||
<!--
|
||||
Maps (fileid, user) to an integer which is a permission bitfield.
|
||||
- E.g. (4, admin) -> 27
|
||||
-->
|
||||
<name>*dbprefix*permissions</name>
|
||||
|
||||
<declaration>
|
||||
|
||||
<!-- Foreign Key filecache::fileid -->
|
||||
<field>
|
||||
<name>fileid</name>
|
||||
<type>integer</type>
|
||||
|
@ -379,6 +416,7 @@
|
|||
<length>4</length>
|
||||
</field>
|
||||
|
||||
<!-- Foreign Key users::uid -->
|
||||
<field>
|
||||
<name>user</name>
|
||||
<type>text</type>
|
||||
|
@ -413,10 +451,16 @@
|
|||
|
||||
<table>
|
||||
|
||||
<!--
|
||||
Stores which groups have which users as members in an n:m relationship.
|
||||
- Maps group id (gid) to a set of users (uid)
|
||||
- Maps user id (uid) to a set of groups (gid) (but without index)
|
||||
-->
|
||||
<name>*dbprefix*group_user</name>
|
||||
|
||||
<declaration>
|
||||
|
||||
<!-- Foreign Key groups::gid -->
|
||||
<field>
|
||||
<name>gid</name>
|
||||
<type>text</type>
|
||||
|
@ -425,6 +469,7 @@
|
|||
<length>64</length>
|
||||
</field>
|
||||
|
||||
<!-- Foreign Key users::uid -->
|
||||
<field>
|
||||
<name>uid</name>
|
||||
<type>text</type>
|
||||
|
@ -453,10 +498,19 @@
|
|||
|
||||
<table>
|
||||
|
||||
<!--
|
||||
Stores which groups have which users as admins in an n:m relationship.
|
||||
- Maps group id (gid) to a set of users (uid)
|
||||
- Maps user id (uid) to a set of groups (gid)
|
||||
|
||||
NOTE: This could (very likely) be reduced to a single bit in group_user
|
||||
instead of repeating varchars gid and uid here
|
||||
-->
|
||||
<name>*dbprefix*group_admin</name>
|
||||
|
||||
<declaration>
|
||||
|
||||
<!-- Foreign Key groups::gid -->
|
||||
<field>
|
||||
<name>gid</name>
|
||||
<type>text</type>
|
||||
|
@ -465,6 +519,7 @@
|
|||
<length>64</length>
|
||||
</field>
|
||||
|
||||
<!-- Foreign Key users::uid -->
|
||||
<field>
|
||||
<name>uid</name>
|
||||
<type>text</type>
|
||||
|
@ -500,6 +555,9 @@
|
|||
|
||||
<table>
|
||||
|
||||
<!--
|
||||
A simple list of groups.
|
||||
-->
|
||||
<name>*dbprefix*groups</name>
|
||||
|
||||
<declaration>
|
||||
|
@ -527,6 +585,9 @@
|
|||
|
||||
<table>
|
||||
|
||||
<!--
|
||||
Locks held by WebDAV clients via OC_Connector_Sabre_Locks.
|
||||
-->
|
||||
<name>*dbprefix*locks</name>
|
||||
|
||||
<declaration>
|
||||
|
@ -541,6 +602,7 @@
|
|||
<length>4</length>
|
||||
</field>
|
||||
|
||||
<!-- Foreign Key users::uid -->
|
||||
<field>
|
||||
<name>userid</name>
|
||||
<type>text</type>
|
||||
|
@ -606,10 +668,16 @@
|
|||
|
||||
<table>
|
||||
|
||||
<!--
|
||||
Namespaced Key-Value Store for User Preferences
|
||||
- Keys are namespaced per userid and appid.
|
||||
- E.g. (admin, files, cache_version) -> 5
|
||||
-->
|
||||
<name>*dbprefix*preferences</name>
|
||||
|
||||
<declaration>
|
||||
|
||||
<!-- Foreign Key users::uid -->
|
||||
<field>
|
||||
<name>userid</name>
|
||||
<type>text</type>
|
||||
|
@ -664,6 +732,9 @@
|
|||
|
||||
<table>
|
||||
|
||||
<!--
|
||||
WebDAV properties.
|
||||
-->
|
||||
<name>*dbprefix*properties</name>
|
||||
|
||||
<declaration>
|
||||
|
@ -677,6 +748,7 @@
|
|||
<length>4</length>
|
||||
</field>
|
||||
|
||||
<!-- Foreign Key users::uid -->
|
||||
<field>
|
||||
<name>userid</name>
|
||||
<type>text</type>
|
||||
|
@ -722,6 +794,9 @@
|
|||
|
||||
<table>
|
||||
|
||||
<!--
|
||||
Shares of all types (user-to-user, external-via-link, etc.)
|
||||
-->
|
||||
<name>*dbprefix*share</name>
|
||||
|
||||
<declaration>
|
||||
|
@ -735,6 +810,7 @@
|
|||
<length>4</length>
|
||||
</field>
|
||||
|
||||
<!-- Constant OCP\Share::SHARE_TYPE_* -->
|
||||
<field>
|
||||
<name>share_type</name>
|
||||
<type>integer</type>
|
||||
|
@ -743,6 +819,7 @@
|
|||
<length>1</length>
|
||||
</field>
|
||||
|
||||
<!-- Foreign Key users::uid or NULL -->
|
||||
<field>
|
||||
<name>share_with</name>
|
||||
<type>text</type>
|
||||
|
@ -751,6 +828,7 @@
|
|||
<length>255</length>
|
||||
</field>
|
||||
|
||||
<!-- Foreign Key users::uid -->
|
||||
<field>
|
||||
<name>uid_owner</name>
|
||||
<type>text</type>
|
||||
|
@ -759,6 +837,7 @@
|
|||
<length>255</length>
|
||||
</field>
|
||||
|
||||
<!-- Foreign Key share::id or NULL -->
|
||||
<field>
|
||||
<name>parent</name>
|
||||
<type>integer</type>
|
||||
|
@ -766,6 +845,7 @@
|
|||
<length>4</length>
|
||||
</field>
|
||||
|
||||
<!-- E.g. file or folder -->
|
||||
<field>
|
||||
<name>item_type</name>
|
||||
<type>text</type>
|
||||
|
@ -774,6 +854,7 @@
|
|||
<length>64</length>
|
||||
</field>
|
||||
|
||||
<!-- Foreign Key filecache::fileid -->
|
||||
<field>
|
||||
<name>item_source</name>
|
||||
<type>text</type>
|
||||
|
@ -790,6 +871,7 @@
|
|||
<length>255</length>
|
||||
</field>
|
||||
|
||||
<!-- Foreign Key filecache::fileid -->
|
||||
<field>
|
||||
<name>file_source</name>
|
||||
<type>integer</type>
|
||||
|
@ -805,6 +887,7 @@
|
|||
<length>512</length>
|
||||
</field>
|
||||
|
||||
<!-- Permission bitfield -->
|
||||
<field>
|
||||
<name>permissions</name>
|
||||
<type>integer</type>
|
||||
|
@ -813,6 +896,7 @@
|
|||
<length>1</length>
|
||||
</field>
|
||||
|
||||
<!-- Time of share creation -->
|
||||
<field>
|
||||
<name>stime</name>
|
||||
<type>integer</type>
|
||||
|
@ -821,6 +905,7 @@
|
|||
<length>8</length>
|
||||
</field>
|
||||
|
||||
<!-- Whether the receiver accepted the share, if share_with is set. -->
|
||||
<field>
|
||||
<name>accepted</name>
|
||||
<type>integer</type>
|
||||
|
@ -829,6 +914,7 @@
|
|||
<length>1</length>
|
||||
</field>
|
||||
|
||||
<!-- Time of share expiration -->
|
||||
<field>
|
||||
<name>expiration</name>
|
||||
<type>timestamp</type>
|
||||
|
@ -883,6 +969,10 @@
|
|||
|
||||
<table>
|
||||
|
||||
<!--
|
||||
Scheduled background jobs.
|
||||
See OC\BackgroundJob\JobList.
|
||||
-->
|
||||
<name>*dbprefix*jobs</name>
|
||||
|
||||
<declaration>
|
||||
|
@ -934,6 +1024,9 @@
|
|||
|
||||
<table>
|
||||
|
||||
<!--
|
||||
List of usernames, their display name and login password.
|
||||
-->
|
||||
<name>*dbprefix*users</name>
|
||||
|
||||
<declaration>
|
||||
|
@ -976,6 +1069,9 @@
|
|||
|
||||
<table>
|
||||
|
||||
<!--
|
||||
List of tags (category) + a unique tag id (id) per user (uid) and type.
|
||||
-->
|
||||
<name>*dbprefix*vcategory</name>
|
||||
|
||||
<declaration>
|
||||
|
@ -990,6 +1086,7 @@
|
|||
<length>4</length>
|
||||
</field>
|
||||
|
||||
<!-- Foreign Key users::uid -->
|
||||
<field>
|
||||
<name>uid</name>
|
||||
<type>text</type>
|
||||
|
@ -1043,6 +1140,9 @@
|
|||
|
||||
<table>
|
||||
|
||||
<!--
|
||||
Object-Tag associations per tag type.
|
||||
-->
|
||||
<name>*dbprefix*vcategory_to_object</name>
|
||||
|
||||
<declaration>
|
||||
|
@ -1056,6 +1156,7 @@
|
|||
<length>4</length>
|
||||
</field>
|
||||
|
||||
<!-- Foreign Key vcategory::id -->
|
||||
<field>
|
||||
<name>categoryid</name>
|
||||
<type>integer</type>
|
||||
|
@ -1109,6 +1210,11 @@
|
|||
|
||||
<table>
|
||||
|
||||
<!--
|
||||
Namespaced Key-Value Store for arbitrary data.
|
||||
- Keys are namespaced per userid and appid.
|
||||
- E.g. (admin, files, foo) -> bar
|
||||
-->
|
||||
<name>*dbprefix*privatedata</name>
|
||||
|
||||
<declaration>
|
||||
|
@ -1123,6 +1229,7 @@
|
|||
<autoincrement>1</autoincrement>
|
||||
</field>
|
||||
|
||||
<!-- Foreign Key users::uid -->
|
||||
<field>
|
||||
<name>user</name>
|
||||
<type>text</type>
|
||||
|
|
|
@ -43,8 +43,12 @@ class App {
|
|||
* stored in the DI container
|
||||
* @param string $methodName the method that you want to call
|
||||
* @param DIContainer $container an instance of a pimple container.
|
||||
* @param array $urlParams list of URL parameters (optional)
|
||||
*/
|
||||
public static function main($controllerName, $methodName, IAppContainer $container) {
|
||||
public static function main($controllerName, $methodName, DIContainer $container, array $urlParams = null) {
|
||||
if (!is_null($urlParams)) {
|
||||
$container['urlParams'] = $urlParams;
|
||||
}
|
||||
$controller = $container[$controllerName];
|
||||
|
||||
// initialize the dispatcher and run all the middleware before the controller
|
||||
|
|
|
@ -37,6 +37,6 @@ class RouteActionHandler {
|
|||
}
|
||||
|
||||
public function __invoke($params) {
|
||||
App::main($this->controllerName, $this->actionName, $params, $this->container);
|
||||
App::main($this->controllerName, $this->actionName, $this->container, $params);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,15 +44,19 @@ class OC_Avatar implements \OCP\IAvatar {
|
|||
|
||||
/**
|
||||
* @brief sets the users avatar
|
||||
* @param $data mixed imagedata or path to set a new avatar
|
||||
* @param $data mixed OC_Image, imagedata or path to set a new avatar
|
||||
* @throws Exception if the provided file is not a jpg or png image
|
||||
* @throws Exception if the provided image is not valid
|
||||
* @throws \OC\NotSquareException if the image is not square
|
||||
* @return void
|
||||
*/
|
||||
public function set ($data) {
|
||||
|
||||
if($data instanceOf OC_Image) {
|
||||
$img = $data;
|
||||
$data = $img->data();
|
||||
} else {
|
||||
$img = new OC_Image($data);
|
||||
}
|
||||
$type = substr($img->mimeType(), -3);
|
||||
if ($type === 'peg') {
|
||||
$type = 'jpg';
|
||||
|
|
|
@ -424,6 +424,22 @@ class OC_User {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check whether user can change his avatar
|
||||
* @param string $uid The username
|
||||
* @return bool
|
||||
*
|
||||
* Check whether a specified user can change his avatar
|
||||
*/
|
||||
public static function canUserChangeAvatar($uid) {
|
||||
$user = self::getManager()->get($uid);
|
||||
if ($user) {
|
||||
return $user->canChangeAvatar();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check whether user can change his password
|
||||
* @param string $uid The username
|
||||
|
|
|
@ -31,13 +31,13 @@ define('OC_USER_BACKEND_NOT_IMPLEMENTED', -501);
|
|||
/**
|
||||
* actions that user backends can define
|
||||
*/
|
||||
define('OC_USER_BACKEND_CREATE_USER', 0x000001);
|
||||
define('OC_USER_BACKEND_SET_PASSWORD', 0x000010);
|
||||
define('OC_USER_BACKEND_CHECK_PASSWORD', 0x000100);
|
||||
define('OC_USER_BACKEND_GET_HOME', 0x001000);
|
||||
define('OC_USER_BACKEND_GET_DISPLAYNAME', 0x010000);
|
||||
define('OC_USER_BACKEND_SET_DISPLAYNAME', 0x100000);
|
||||
|
||||
define('OC_USER_BACKEND_CREATE_USER', 0x0000001);
|
||||
define('OC_USER_BACKEND_SET_PASSWORD', 0x0000010);
|
||||
define('OC_USER_BACKEND_CHECK_PASSWORD', 0x0000100);
|
||||
define('OC_USER_BACKEND_GET_HOME', 0x0001000);
|
||||
define('OC_USER_BACKEND_GET_DISPLAYNAME', 0x0010000);
|
||||
define('OC_USER_BACKEND_SET_DISPLAYNAME', 0x0100000);
|
||||
define('OC_USER_BACKEND_PROVIDE_AVATAR', 0x1000000);
|
||||
|
||||
/**
|
||||
* Abstract base class for user management. Provides methods for querying backend
|
||||
|
@ -54,6 +54,7 @@ abstract class OC_User_Backend implements OC_User_Interface {
|
|||
OC_USER_BACKEND_GET_HOME => 'getHome',
|
||||
OC_USER_BACKEND_GET_DISPLAYNAME => 'getDisplayName',
|
||||
OC_USER_BACKEND_SET_DISPLAYNAME => 'setDisplayName',
|
||||
OC_USER_BACKEND_PROVIDE_AVATAR => 'canChangeAvatar',
|
||||
);
|
||||
|
||||
/**
|
||||
|
|
|
@ -139,6 +139,18 @@ class User {
|
|||
return \OC_Config::getValue("datadirectory", \OC::$SERVERROOT . "/data") . '/' . $this->uid; //TODO switch to Config object once implemented
|
||||
}
|
||||
|
||||
/**
|
||||
* check if the backend allows the user to change his avatar on Personal page
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canChangeAvatar() {
|
||||
if($this->backend->implementsActions(\OC_USER_BACKEND_PROVIDE_AVATAR)) {
|
||||
return $this->backend->canChangeAvatar($this->uid);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* check if the backend supports changing passwords
|
||||
*
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
*/
|
||||
|
||||
namespace OCP\AppFramework;
|
||||
use OC\AppFramework\routing\RouteConfig;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -52,6 +53,28 @@ class App {
|
|||
return $this->container;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is to be called to create single routes and restful routes based on the given $routes array.
|
||||
*
|
||||
* Example code in routes.php of tasks app (it will register two restful resources):
|
||||
* $routes = array(
|
||||
* 'resources' => array(
|
||||
* 'lists' => array('url' => '/tasklists'),
|
||||
* 'tasks' => array('url' => '/tasklists/{listId}/tasks')
|
||||
* )
|
||||
* );
|
||||
*
|
||||
* $a = new TasksApp();
|
||||
* $a->registerRoutes($this, $routes);
|
||||
*
|
||||
* @param \OC_Router $router
|
||||
* @param array $routes
|
||||
*/
|
||||
public function registerRoutes($router, $routes) {
|
||||
$routeConfig = new RouteConfig($this->container, $router, $routes);
|
||||
$routeConfig->register();
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called by the routing component to fire up the frameworks dispatch mechanism.
|
||||
*
|
||||
|
|
|
@ -90,6 +90,7 @@ $tmpl->assign('displayNameChangeSupported', OC_User::canUserChangeDisplayName(OC
|
|||
$tmpl->assign('displayName', OC_User::getDisplayName());
|
||||
$tmpl->assign('enableDecryptAll' , $enableDecryptAll);
|
||||
$tmpl->assign('enableAvatars', \OC_Config::getValue('enable_avatars', true));
|
||||
$tmpl->assign('avatarChangeSupported', OC_User::canUserChangeAvatar(OC_User::getUser()));
|
||||
|
||||
$forms=OC_App::getForms('personal');
|
||||
$tmpl->assign('forms', array());
|
||||
|
|
|
@ -15,6 +15,20 @@ $levelLabels = array(
|
|||
|
||||
<?php
|
||||
|
||||
// is ssl working ?
|
||||
if (!$_['isConnectedViaHTTPS']) {
|
||||
?>
|
||||
<fieldset class="personalblock">
|
||||
<h2><?php p($l->t('Security Warning'));?></h2>
|
||||
|
||||
<span class="securitywarning">
|
||||
<?php p($l->t('You are accessing %s via HTTP. We strongly suggest you configure your server to require using HTTPS instead.', $theme->getTitle())); ?>
|
||||
</span>
|
||||
|
||||
</fieldset>
|
||||
<?php
|
||||
}
|
||||
|
||||
// is htaccess working ?
|
||||
if (!$_['htaccessworking']) {
|
||||
?>
|
||||
|
|
|
@ -87,11 +87,15 @@ if($_['passwordChangeSupported']) {
|
|||
<div id="displayavatar">
|
||||
<div class="avatardiv"></div><br>
|
||||
<div class="warning hidden"></div>
|
||||
<?php if ($_['avatarChangeSupported']): ?>
|
||||
<div class="inlineblock button" id="uploadavatarbutton"><?php p($l->t('Upload new')); ?></div>
|
||||
<input type="file" class="hidden" name="files[]" id="uploadavatar">
|
||||
<div class="inlineblock button" id="selectavatar"><?php p($l->t('Select new from Files')); ?></div>
|
||||
<div class="inlineblock button" id="removeavatar"><?php p($l->t('Remove image')); ?></div><br>
|
||||
<?php p($l->t('Either png or jpg. Ideally square but you will be able to crop it.')); ?>
|
||||
<?php else: ?>
|
||||
<?php p($l->t('Your avatar is provided by your original account.')); ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div id="cropper" class="hidden">
|
||||
<div class="inlineblock button" id="abortcropperbutton"><?php p($l->t('Abort')); ?></div>
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Arthur Schiwon
|
||||
* @copyright 2013 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
class Avatar_User_Dummy extends \OC_User_Dummy {
|
||||
public function canChangeAvatar($uid) {
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -87,6 +87,75 @@ class User extends \PHPUnit_Framework_TestCase {
|
|||
$this->assertFalse($user->setPassword('bar',''));
|
||||
}
|
||||
|
||||
public function testChangeAvatarSupportedYes() {
|
||||
/**
|
||||
* @var \OC_User_Backend | \PHPUnit_Framework_MockObject_MockObject $backend
|
||||
*/
|
||||
require_once 'avataruserdummy.php';
|
||||
$backend = $this->getMock('Avatar_User_Dummy');
|
||||
$backend->expects($this->once())
|
||||
->method('canChangeAvatar')
|
||||
->with($this->equalTo('foo'))
|
||||
->will($this->returnValue(true));
|
||||
|
||||
$backend->expects($this->any())
|
||||
->method('implementsActions')
|
||||
->will($this->returnCallback(function ($actions) {
|
||||
if ($actions === \OC_USER_BACKEND_PROVIDE_AVATAR) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
|
||||
$user = new \OC\User\User('foo', $backend);
|
||||
$this->assertTrue($user->canChangeAvatar());
|
||||
}
|
||||
|
||||
public function testChangeAvatarSupportedNo() {
|
||||
/**
|
||||
* @var \OC_User_Backend | \PHPUnit_Framework_MockObject_MockObject $backend
|
||||
*/
|
||||
require_once 'avataruserdummy.php';
|
||||
$backend = $this->getMock('Avatar_User_Dummy');
|
||||
$backend->expects($this->once())
|
||||
->method('canChangeAvatar')
|
||||
->with($this->equalTo('foo'))
|
||||
->will($this->returnValue(false));
|
||||
|
||||
$backend->expects($this->any())
|
||||
->method('implementsActions')
|
||||
->will($this->returnCallback(function ($actions) {
|
||||
if ($actions === \OC_USER_BACKEND_PROVIDE_AVATAR) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
|
||||
$user = new \OC\User\User('foo', $backend);
|
||||
$this->assertFalse($user->canChangeAvatar());
|
||||
}
|
||||
|
||||
public function testChangeAvatarNotSupported() {
|
||||
/**
|
||||
* @var \OC_User_Backend | \PHPUnit_Framework_MockObject_MockObject $backend
|
||||
*/
|
||||
require_once 'avataruserdummy.php';
|
||||
$backend = $this->getMock('Avatar_User_Dummy');
|
||||
$backend->expects($this->never())
|
||||
->method('canChangeAvatar');
|
||||
|
||||
$backend->expects($this->any())
|
||||
->method('implementsActions')
|
||||
->will($this->returnCallback(function ($actions) {
|
||||
return false;
|
||||
}));
|
||||
|
||||
$user = new \OC\User\User('foo', $backend);
|
||||
$this->assertTrue($user->canChangeAvatar());
|
||||
}
|
||||
|
||||
public function testDelete() {
|
||||
/**
|
||||
* @var \OC_User_Backend | \PHPUnit_Framework_MockObject_MockObject $backend
|
||||
|
|
Loading…
Reference in New Issue