Compare commits

...

107 Commits

Author SHA1 Message Date
C Montero-Luque b4bef0214e 8.1.1 beta1 2015-07-22 16:49:28 -04:00
Thomas Müller ee85d1fd37 Merge pull request #17802 from owncloud/update-sabre-dav-2.1.6
Update SabreDAV to 2.1.6
2015-07-22 21:19:35 +02:00
Björn Schießle 77a37e076f Merge pull request #17816 from owncloud/enc_improved_app_description_8.1
[8.1 backport] improved description for the default encryption module
2015-07-22 21:01:20 +02:00
Bjoern Schiessle a07675e513 improved app description and adjust it to the way the new encryption module works 2015-07-22 16:18:10 +02:00
Joas Schilling 2b63903942 Update SabreDAV to 2.1.6 2015-07-22 12:00:29 +02:00
Joas Schilling 2bc2e974b2 Merge pull request #17752 from owncloud/enc_migration_fix_mountpoint_detection_8.1
[8.1 backport] fix system wide mount point detection on migration
2015-07-21 11:06:09 +02:00
Morris Jobke 2ecba9e5a5 Merge pull request #17762 from owncloud/backport-17723-stable8.1
Backport of #17723 to stable8.1
2015-07-21 00:30:37 +02:00
Morris Jobke dd5b347672 Merge pull request #17704 from owncloud/backport-stable8.1-17255-17526
Backport stable8.1 #17255 #17526
2015-07-21 00:01:36 +02:00
Arthur Schiwon 8be59bf7e0 Backport of #17723 to stable8.1
fix runtime caching in ldap's user manager, fixes #17631

fix indentation. no code changes, whitespace only.
2015-07-20 22:50:10 +02:00
Thomas Müller e92d427dde Merge pull request #17707 from owncloud/backport-fix-closest-stable8.1
fix browser compatibility issue for element.closest
2015-07-20 21:36:22 +02:00
Bjoern Schiessle dc6cc57e11 fix mount point detection 2015-07-20 16:26:07 +02:00
Morris Jobke f1df6cd4ff Merge pull request #17736 from owncloud/backport-allow-update-of-disabled-apps
[stable8.1] Allow upgrade of not enabled apps
2015-07-20 14:24:22 +02:00
Morris Jobke ff8e63c991 Merge pull request #17711 from owncloud/fix_repeated_migration_oc8.1
[8.1 backport] Don't mix up directories if the migration runs multiple times
2015-07-20 13:58:20 +02:00
Thomas Müller d4cc4019fd Allow upgrade of not enabled apps 2015-07-19 12:16:15 +02:00
Björn Schießle 6383bd3744 Merge pull request #17702 from owncloud/enc_detect_legacy_files2_8.1
[8.1 backport] make sure that we always detect legacy files correctlly
2015-07-17 21:39:45 +02:00
Morris Jobke 738e116c00 Merge pull request #17710 from owncloud/stable8.1-s2s-catchremotelockexceptions
[Stable 8.1] s2s catchremotelockexceptions
2015-07-17 18:35:10 +02:00
Bjoern Schiessle 777964ff2b unit tests 2015-07-17 15:30:55 +02:00
Bjoern Schiessle 00a044f885 don't move keys if the key where already moved in a previous migration run 2015-07-17 15:30:43 +02:00
Vincent Petry 335372064e Throw lock exceptions if remote share returned 423 status code 2015-07-17 15:26:40 +02:00
Hendrik Leppelsack 17d7a2893e fix browser compatibility issue for element.closest 2015-07-17 15:08:45 +02:00
Morris Jobke 1b8eb668de Merge pull request #17697 from owncloud/fix-undefined-REMOTE_ADDR-stable8.1
Fixing 'Undefined index: REMOTE_ADDR' - fixes #17460
2015-07-17 14:20:57 +02:00
Arthur Schiwon a3172008c6 LDAP: when checking group for matching filter, also take base DN into consideration. Fixes #17516 2015-07-17 13:42:33 +02:00
Arthur Schiwon b2db982768 Backport of 17255 to stable8.1
ensure groups match filter when using memberOf to read users group, refs #17119

integration test

adjust unit test

tests solidity
2015-07-17 13:41:58 +02:00
Bjoern Schiessle 001dd400a1 set targetIsEncrypted to true if file cache indicates that we try to read a encrypted file 2015-07-17 13:28:58 +02:00
Bjoern Schiessle 5bfbfca266 make sure that we always detect legacy files correctly 2015-07-17 13:28:58 +02:00
Thomas Müller fc6420c290 Fixing 'Undefined index: REMOTE_ADDR' - fixes #17460 2015-07-17 12:35:00 +02:00
Thomas Müller 015d4e3ba3 Merge pull request #17690 from owncloud/stable8.1-repair-ocs-ids
[stable8.1] Add repair step for outdated OCS IDs
2015-07-17 12:02:45 +02:00
Thomas Müller deeacacfae Merge pull request #17678 from owncloud/backport-encryption_migration_improvements-stable8.1
Backport encryption migration improvements stable8.1
2015-07-17 11:58:06 +02:00
Thomas Müller d199fb4e8d Merge pull request #17679 from owncloud/backport-fix_trashbin-stable8.1
only move real files to the trash bin
2015-07-17 11:57:41 +02:00
Lukas Reschke 289fd99333 Prefer OCS Id from database
To be consistent with other logic the app id from the database needs to be prefered. Especially when it comes to be able to replace an outdated OCS id.
2015-07-17 08:33:51 +02:00
Lukas Reschke 579bee03bd Add repair step for outdated OCS IDs
There is the case where OCs IDs might become outdated such as it has been with the calendar and contacts app which refer to the old dummy entry. This means that users with the old OCS id can't update updates as well will receive invalid state flags. (e.g. "experimental" instead of "approved")

To allow instances to properly update the applications in the future we need to migrate the OCS IDs for now manually.
2015-07-16 18:52:27 +02:00
Morris Jobke 816910baf1 Merge pull request #17676 from owncloud/backport-files-scan-user-path-stable8.1
Lock scanner to the given user
2015-07-16 16:00:43 +02:00
Bjoern Schiessle fb452486d7 only move real files to the trash bin 2015-07-16 15:11:12 +02:00
Bjoern Schiessle ae1332e9c9 only create new key pair if both keys are missing 2015-07-16 14:07:26 +02:00
Bjoern Schiessle 9d9ab82a17 only cleanUp the remaining keys if the migration really finished succesfully 2015-07-16 14:07:17 +02:00
Morris Jobke edb15bd493 Merge pull request #17653 from owncloud/backport-17330-share-group-path-exception
[stable8.1] Fix the path for users which have an exception for a group share
2015-07-16 13:19:19 +02:00
Robin Appelman 4c6b26d056 Lock scanner to the given user 2015-07-16 12:14:23 +02:00
Vincent Petry 8e1fca7402 Merge pull request #17658 from owncloud/share-lock-owner-parent-stable81
[8.1] lock parent folders for the owner when locking a shared file as recipient
2015-07-16 11:59:48 +02:00
Vincent Petry db5a574faf Merge pull request #17556 from owncloud/enc_fix_migration_stable8.1
[stable8.1 backport] more secure way to update the database
2015-07-16 11:57:00 +02:00
Morris Jobke 8e0294d0fd Merge pull request #17294 from owncloud/stable8.1-s2s-catchmoreexceptiontypes
[stable8.1] Catch more error codes thrown by federated shares
2015-07-16 11:50:00 +02:00
Morris Jobke 256c57c01e Merge pull request #17337 from owncloud/stable8.1-backport-17077
[stable8.1] fix getting mount points when passing a path to the files:scan command
2015-07-15 14:51:57 +02:00
Robin Appelman db21b0964c only lock the parent folders 2015-07-15 13:43:34 +02:00
Robin Appelman cc45b49de7 lock parent folders for the owner when locking a shared file as recipient 2015-07-15 13:42:59 +02:00
Morris Jobke 90104fc5d8 Merge pull request #17643 from owncloud/stable8.1-s2s-hasupdated-catch405
[stable8.1] Throw StorageNotAvailable if propfind on root failed
2015-07-15 11:11:28 +02:00
Joas Schilling 8f2ce01553 Make sure the owner always has the right path 2015-07-15 10:12:50 +02:00
Vincent Petry 3ade5f5111 Add test case when owner renames shared folder 2015-07-15 10:12:41 +02:00
Vincent Petry 60939ebd2c Add unit test for getUsersSharingFile
This is to test if the user list and paths are correct, even when a
recipient renamed the received shared folder
2015-07-15 10:12:29 +02:00
Joas Schilling c73f938ff4 Fix the path for users which have an exception for a group share 2015-07-15 10:12:16 +02:00
Björn Schießle 06d7480fa2 Merge pull request #17642 from owncloud/stable8.1-backport-17565
[stable8.1] allow remote shares for users with email as usernames
2015-07-14 18:20:45 +02:00
Vincent Petry 48b2a4e034 Throw StorageNotAvailable if propfind on root failed
If PROPFIND fails with 404 or 405 on the remote share root, it means the
storage is not available. Throw StorageNotAvailable is such case.
2015-07-14 17:41:58 +02:00
Felix Böhm 824df7e22d allow remote shares for users with email as usernames 2015-07-14 15:33:12 +02:00
Vincent Petry ab308d246a Merge pull request #17632 from owncloud/stable8.1-backport-17606
[stable8.1] Handle returned null value in app level code
2015-07-14 11:44:06 +02:00
Morris Jobke dc9454ea3c Handle returned null value in app level code
* getApplication on OCSClient can also return null
  this is now handled properly
* fixes #17587
2015-07-14 08:58:28 +02:00
Vincent Petry f920923dd6 Throw storage not available on guzzle error
If the remote server is in maintenance mode, we must throw storage not
available exception instead of not found which might auto-remove the
share.
2015-07-13 18:55:24 +02:00
Thomas Müller 698e2ebc90 Merge pull request #17607 from owncloud/stable8.1-backport-17426
[stable8.1] [config sample] Update info about appstore
2015-07-13 17:40:54 +02:00
Morris Jobke 1548d69762 [config sample] Update info about appstore 2015-07-13 14:52:38 +02:00
Bjoern Schiessle 8466d9d235 more secure way to update the database 2015-07-10 11:49:51 +02:00
Morris Jobke 48b1e9e2a6 Merge pull request #17288 from owncloud/stable8.1-chunk-cleanupgracefulonlock
Stable8.1 chunk cleanupgracefulonlock
2015-07-09 22:31:40 +02:00
Morris Jobke f21eb35431 Merge pull request #17518 from owncloud/stable8.1-backport-config-sample
[stable8.1] backport config sample
2015-07-09 14:30:05 +02:00
Morris Jobke 509725fad9 [config sample] improve RST markup and wording 2015-07-09 10:09:11 +02:00
Morris Jobke 447c60c4e4 refine sample config text 2015-07-09 10:06:06 +02:00
Morris Jobke eb055b0d78 [config sample] merge Miscellaneous & All other options 2015-07-09 10:06:01 +02:00
Morris Jobke d48d59661a Merge pull request #17289 from owncloud/stable8.1-files-cleanuppartfileonlyonce
Stable8.1 files cleanuppartfileonlyonce
2015-07-08 10:34:55 +02:00
Morris Jobke 312d82fe71 Merge pull request #17332 from owncloud/fix-temporary-mountpoint-name-in-activities
Fix the mount point name before creating the activities
2015-07-08 10:33:15 +02:00
Morris Jobke 96b97d1567 Merge pull request #17338 from owncloud/stable8.1-backport-17252
[stable8.1] Only do the description kung-fu on strings - fixes #17028
2015-07-08 10:32:53 +02:00
Morris Jobke 97e49e422f Merge pull request #17366 from owncloud/fix_16740_8.1
[oc8.1] owner is stored as 'uid_owner', not as 'owner' in the oc_share table
2015-07-08 10:32:30 +02:00
Morris Jobke 5d3d44eeb9 Merge pull request #17370 from owncloud/stable8.1-share-onlyshowstaticownerifavailable
[stable8.1] Do not show static share owner if not available
2015-07-08 10:31:33 +02:00
Morris Jobke 51978aa296 Merge pull request #17417 from owncloud/stable8.1-backport-17159
[stable8.1] remove duplicate ID in HTML template for public shares
2015-07-08 10:31:11 +02:00
Morris Jobke 3823713c7c Merge pull request #17429 from owncloud/stable8.1-backport-17088
[stable8.1] [upgrade] add verbosity check and show repair info & steps
2015-07-08 10:29:16 +02:00
Thomas Müller 3854dead08 Merge pull request #17431 from owncloud/stable8.1-update-readme
[stable8.1] Update readme versions
2015-07-07 10:33:36 +02:00
Vincent Petry ce0f391ecd Update README version and bower 2015-07-07 10:22:36 +02:00
Morris Jobke 388409290a [Repair] add repair info for changed collation 2015-07-07 10:16:54 +02:00
Morris Jobke fb85fc619d [upgrade] add verbosity check and show repair info & steps 2015-07-07 10:16:49 +02:00
Morris Jobke d5e90e7239 remove duplicate ID in HTML template for public shares 2015-07-06 13:34:11 +02:00
Vincent Petry c04beb0bad Do not show static share owner if not available
In some corner cases, an outgoing share exists but sharing is not
allowed for the current user. This would cause the file list to break
because the static text could not be rendered as the owner was
undefined.
2015-07-03 11:54:50 +02:00
Bjoern Schiessle 9def2fcf71 call post_addToGroup als for class OC_User because sharing and LDAP are using this class. Minimal approach to fix #16740 2015-07-03 10:36:09 +02:00
Bjoern Schiessle 1427a79643 owner is stored as 'uid_owner', not as 'owner' in the oc_share table 2015-07-03 10:36:01 +02:00
C Montero-Luque 06ec916b11 8.1.0 2015-07-02 18:20:11 -04:00
Lukas Reschke 7d94d963e9 Merge pull request #17356 from owncloud/stable8.1-apps-keepgloballist
[stable8.1] Fix global app list state
2015-07-02 21:37:41 +02:00
Vincent Petry c051c180ab Fix global app list state 2015-07-02 17:31:22 +02:00
Lukas Reschke 9cba7c1793 Merge pull request #17317 from owncloud/stable81-clean-ocsid
[stable8.1] Delete OCS ID from DB if none is specified
2015-07-02 14:15:27 +02:00
Lukas Reschke 16514762bf Merge pull request #17311 from owncloud/stable81-remove-ocs-ids
[stable8.1] Remove OCS IDs
2015-07-02 14:15:19 +02:00
Thomas Müller 2727d9797d Only do the description kung-fu on strings - fixes #17028 2015-07-02 13:16:47 +02:00
Robin Appelman a95b5c3b3e handle invalid results from mount providers 2015-07-02 13:03:09 +02:00
Robin Appelman 1902101923 handle error during setup 2015-07-02 13:03:06 +02:00
Robin Appelman 8a3f54c225 add unit test 2015-07-02 13:03:03 +02:00
Robin Appelman 478fe752e7 fix getting mount points when passing a path to the files:scan command 2015-07-02 13:02:59 +02:00
Joas Schilling ea731c5c66 Use the item name when refering to the unaccepted remote share 2015-07-02 12:35:30 +02:00
Björn Schießle caa3210a59 Merge pull request #17308 from owncloud/stable8.1-backport-17293
Stable8.1 backport 17293
2015-07-02 12:17:56 +02:00
Lukas Reschke 8fe5d4b268 Bump versions 2015-07-02 09:20:25 +02:00
Lukas Reschke 85fc84e3d3 Delete OCS ID from DB if none is specified
If no OCS ID is specified in appinfo.xml and an app update is triggered and a OCS ID is stored in the DB we should clean the value.

Ref https://github.com/owncloud/activity/issues/320#issuecomment-117937748
2015-07-02 09:20:21 +02:00
Lukas Reschke 6008bf975d [stable81] Remove OCS IDs
While making the AppStore ready for 8.1 I also deleted some dummy entries which means that these IDs do not resolve anymore. We should remove them to prevent errors such as https://github.com/owncloud/core/issues/17307

Ref https://github.com/owncloud/activity/issues/320#issuecomment-117691867
2015-07-02 08:47:31 +02:00
Jan-Christoph Borchardt 4abec8b5b9 Revert "fix z-index of share-autocomplete"
This reverts commit 4edf388a38.
2015-07-02 08:24:04 +02:00
Jan-Christoph Borchardt d6cbf8be71 Revert "explicitly set z-index on app-content, fix overlap from navigation"
This reverts commit 71e5bc1803.
2015-07-02 08:23:58 +02:00
Vincent Petry 2d92b5a64e Catch more error codes thrown by federated shares
Most of the time it doesn't make sense to forward Guzzle's
RequestException, so we convert it to StorageNotAvailable instead.

This prevents unpredictable error codes to block access to unrelated
folders needlessly.
2015-07-01 16:23:57 +02:00
Thomas Müller d6b24c7bbc Merge pull request #17266 from owncloud/stable8.1-backport-17224
Stable8.1 backport 17224
2015-07-01 16:12:55 +02:00
Vincent Petry 4aa2eff94c Only delete part file on error if it is really a part file 2015-07-01 15:25:17 +02:00
Vincent Petry 4fff832fa6 Clean up part file only once, not twice on error 2015-07-01 15:25:09 +02:00
Vincent Petry 39e391fd1a Catch cache garbage collection exception on postLogin
Just log the exception instead of preventing access to OC.
2015-07-01 15:19:46 +02:00
Vincent Petry e48afaf334 Test for chunk cache garbage collection 2015-07-01 15:19:43 +02:00
Vincent Petry 18e4fe7add Do not try clearing locked files in cache folder 2015-07-01 15:19:38 +02:00
Morris Jobke c7bc669e00 Merge pull request #17267 from owncloud/stable8.1-backport-17264
Use UTF-8 mode for preg_split and preg_replace
2015-07-01 09:13:48 +02:00
Lukas Reschke 09038697cd Use UTF-8 mode for preg_split and preg_replace
Otherwise a single application with a description containing a non compliant character can break the whole ownCloud appstore. This is for example https://apps.owncloud.com/content/show.php?content=149553

Fixes https://github.com/owncloud/core/issues/17101#issuecomment-117365224
2015-07-01 07:52:40 +02:00
Thomas Müller eb2e8d99cc Avoid namespace clash 2015-07-01 07:48:35 +02:00
Thomas Müller 82493e9789 Fixing content type detection and handle all local printErrorPage calls 2015-07-01 07:48:31 +02:00
Thomas Müller 526a45be18 Adding request specific exception handling - now with WebDAV responses - refs #17192 2015-07-01 07:48:27 +02:00
Thomas Müller 283f8e7e69 Adding exception handling for ServerNotAvailableException - refs #17192 2015-07-01 07:48:23 +02:00
86 changed files with 2319 additions and 532 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
# Version: 8.1.0
# Version: 8.1.1
<IfModule mod_headers.c>
<IfModule mod_fcgid.c>
<IfModule mod_setenvif.c>
+2 -2
View File
@@ -17,7 +17,7 @@ Depencencies:
[![Dependency Status](https://www.versioneye.com/user/projects/54d1f76f3ca0840b190000c0/badge.svg?style=flat)](https://www.versioneye.com/user/projects/54d1f76f3ca0840b190000c0)
### Installation instructions
https://doc.owncloud.org/server/8.0/developer_manual/app/index.html
https://doc.owncloud.org/server/8.1/developer_manual/app/index.html
### Contribution Guidelines
https://owncloud.org/contribute/
@@ -35,4 +35,4 @@ https://www.transifex.com/projects/p/owncloud/
[![Transifex](https://www.transifex.com/projects/p/owncloud/resource/core/chart/image_png)](https://www.transifex.com/projects/p/owncloud/)
For more detailed information about translations:
http://doc.owncloud.org/server/8.0/developer_manual/core/translation.html
http://doc.owncloud.org/server/8.1/developer_manual/core/translation.html
+8 -13
View File
@@ -2,19 +2,14 @@
<info>
<id>encryption</id>
<description>
This application encrypts all files accessed by ownCloud at rest,
wherever they are stored. As an example, with this application
enabled, external cloud based Amazon S3 storage will be encrypted,
protecting this data on storage outside of the control of the Admin.
When this application is enabled for the first time, all files are
encrypted as users log in and are prompted for their password. The
recommended recovery key option enables recovery of files in case
the key is lost.
Note that this app encrypts all files that are touched by ownCloud,
so external storage providers and applications such as SharePoint
will see new files encrypted when they are accessed. Encryption is
based on AES 128 or 256 bit keys. More information is available in
the Encryption documentation
In order to use this encryption module you need to enable server-side
encryption in the admin settings. Once enabled this module will encrypt
all your files transparently. The encryption is based on AES 256 keys.
The module won't touch existing files, only new files will be encrypted
after server-side encryption was enabled. It is also not possible to
disable the encryption again and switch back to a unencrypted system.
Please read the documentation to know all implications before you decide
to enable server-side encryption.
</description>
<name>Default encryption module</name>
<license>AGPL</license>
+2 -1
View File
@@ -26,4 +26,5 @@ $userManager = OC::$server->getUserManager();
$view = new \OC\Files\View();
$config = \OC::$server->getConfig();
$connection = \OC::$server->getDatabaseConnection();
$application->add(new MigrateKeys($userManager, $view, $connection, $config));
$logger = \OC::$server->getLogger();
$application->add(new MigrateKeys($userManager, $view, $connection, $config, $logger));
+10 -2
View File
@@ -27,6 +27,7 @@ use OC\Files\View;
use OC\User\Manager;
use OCA\Encryption\Migration;
use OCP\IConfig;
use OCP\ILogger;
use OCP\IUserBackend;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
@@ -44,22 +45,27 @@ class MigrateKeys extends Command {
private $connection;
/** @var IConfig */
private $config;
/** @var ILogger */
private $logger;
/**
* @param Manager $userManager
* @param View $view
* @param Connection $connection
* @param IConfig $config
* @param ILogger $logger
*/
public function __construct(Manager $userManager,
View $view,
Connection $connection,
IConfig $config) {
IConfig $config,
ILogger $logger) {
$this->userManager = $userManager;
$this->view = $view;
$this->connection = $connection;
$this->config = $config;
$this->logger = $logger;
parent::__construct();
}
@@ -77,7 +83,7 @@ class MigrateKeys extends Command {
protected function execute(InputInterface $input, OutputInterface $output) {
// perform system reorganization
$migration = new Migration($this->config, $this->view, $this->connection);
$migration = new Migration($this->config, $this->view, $this->connection, $this->logger);
$users = $input->getArgument('user_id');
if (!empty($users)) {
@@ -115,5 +121,7 @@ class MigrateKeys extends Command {
}
}
$migration->finalCleanUp();
}
}
+23 -6
View File
@@ -406,19 +406,36 @@ class KeyManager {
}
/**
* @param $userId
* check if user has a private and a public key
*
* @param string $userId
* @return bool
* @throws PrivateKeyMissingException
* @throws PublicKeyMissingException
*/
public function userHasKeys($userId) {
$privateKey = $publicKey = true;
try {
$this->getPrivateKey($userId);
$this->getPublicKey($userId);
} catch (PrivateKeyMissingException $e) {
return false;
} catch (PublicKeyMissingException $e) {
return false;
$privateKey = false;
$exception = $e;
}
try {
$this->getPublicKey($userId);
} catch (PublicKeyMissingException $e) {
$publicKey = false;
$exception = $e;
}
if ($privateKey && $publicKey) {
return true;
} elseif (!$privateKey && !$publicKey) {
return false;
} else {
throw $exception;
}
return true;
}
/**
+87 -29
View File
@@ -26,6 +26,7 @@ namespace OCA\Encryption;
use OC\DB\Connection;
use OC\Files\View;
use OCP\IConfig;
use OCP\ILogger;
class Migration {
@@ -37,20 +38,25 @@ class Migration {
/** @var IConfig */
private $config;
/** @var ILogger */
private $logger;
/**
* @param IConfig $config
* @param View $view
* @param Connection $connection
* @param ILogger $logger
*/
public function __construct(IConfig $config, View $view, Connection $connection) {
public function __construct(IConfig $config, View $view, Connection $connection, ILogger $logger) {
$this->view = $view;
$this->view->getUpdater()->disable();
$this->connection = $connection;
$this->moduleId = \OCA\Encryption\Crypto\Encryption::ID;
$this->config = $config;
$this->logger = $logger;
}
public function __destruct() {
public function finalCleanUp() {
$this->view->deleteAll('files_encryption/public_keys');
$this->updateFileCache();
$this->config->deleteAppValue('files_encryption', 'installed_version');
@@ -143,22 +149,32 @@ class Migration {
$this->config->deleteAppValue('files_encryption', 'types');
$this->config->deleteAppValue('files_encryption', 'enabled');
$oldAppValues = $this->connection->createQueryBuilder();
$oldAppValues->select('*')
->from('`*PREFIX*appconfig`')
->where($oldAppValues->expr()->eq('`appid`', ':appid'))
->setParameter('appid', 'files_encryption');
$appSettings = $oldAppValues->execute();
$query = $this->connection->createQueryBuilder();
$query->update('`*PREFIX*appconfig`')
->set('`appid`', ':newappid')
->where($query->expr()->eq('`appid`', ':oldappid'))
->setParameter('oldappid', 'files_encryption')
->setParameter('newappid', 'encryption');
$query->execute();
while ($row = $appSettings->fetch()) {
// 'installed_version' gets deleted at the end of the migration process
if ($row['configkey'] !== 'installed_version' ) {
$this->config->setAppValue('encryption', $row['configkey'], $row['configvalue']);
$this->config->deleteAppValue('files_encryption', $row['configkey']);
}
}
$query = $this->connection->createQueryBuilder();
$query->update('`*PREFIX*preferences`')
->set('`appid`', ':newappid')
->where($query->expr()->eq('`appid`', ':oldappid'))
->setParameter('oldappid', 'files_encryption')
->setParameter('newappid', 'encryption');
$query->execute();
$oldPreferences = $this->connection->createQueryBuilder();
$oldPreferences->select('*')
->from('`*PREFIX*preferences`')
->where($oldPreferences->expr()->eq('`appid`', ':appid'))
->setParameter('appid', 'files_encryption');
$preferenceSettings = $oldPreferences->execute();
while ($row = $preferenceSettings->fetch()) {
$this->config->setUserValue($row['userid'], 'encryption', $row['configkey'], $row['configvalue']);
$this->config->deleteUserValue($row['userid'], 'files_encryption', $row['configkey']);
}
}
/**
@@ -224,9 +240,10 @@ class Migration {
private function renameUsersPrivateKey($user) {
$oldPrivateKey = $user . '/files_encryption/' . $user . '.privateKey';
$newPrivateKey = $user . '/files_encryption/' . $this->moduleId . '/' . $user . '.privateKey';
$this->createPathForKeys(dirname($newPrivateKey));
$this->view->rename($oldPrivateKey, $newPrivateKey);
if ($this->view->file_exists($oldPrivateKey)) {
$this->createPathForKeys(dirname($newPrivateKey));
$this->view->rename($oldPrivateKey, $newPrivateKey);
}
}
/**
@@ -237,9 +254,10 @@ class Migration {
private function renameUsersPublicKey($user) {
$oldPublicKey = '/files_encryption/public_keys/' . $user . '.publicKey';
$newPublicKey = $user . '/files_encryption/' . $this->moduleId . '/' . $user . '.publicKey';
$this->createPathForKeys(dirname($newPublicKey));
$this->view->rename($oldPublicKey, $newPublicKey);
if ($this->view->file_exists($oldPublicKey)) {
$this->createPathForKeys(dirname($newPublicKey));
$this->view->rename($oldPublicKey, $newPublicKey);
}
}
/**
@@ -251,6 +269,11 @@ class Migration {
*/
private function renameFileKeys($user, $path, $trash = false) {
if ($this->view->is_dir($user . '/' . $path) === false) {
$this->logger->info('Skip dir /' . $user . '/' . $path . ': does not exist');
return;
}
$dh = $this->view->opendir($user . '/' . $path);
if (is_resource($dh)) {
@@ -260,8 +283,15 @@ class Migration {
$this->renameFileKeys($user, $path . '/' . $file, $trash);
} else {
$target = $this->getTargetDir($user, $path, $file, $trash);
$this->createPathForKeys(dirname($target));
$this->view->rename($user . '/' . $path . '/' . $file, $target);
if ($target !== false) {
$this->createPathForKeys(dirname($target));
$this->view->rename($user . '/' . $path . '/' . $file, $target);
} else {
$this->logger->warning(
'did not move key "' . $file
. '" could not find the corresponding file in /data/' . $user . '/files.'
. 'Most likely the key was already moved in a previous migration run and is already on the right place.');
}
}
}
}
@@ -269,23 +299,51 @@ class Migration {
}
}
/**
* get system mount points
* wrap static method so that it can be mocked for testing
*
* @internal
* @return array
*/
protected function getSystemMountPoints() {
return \OC_Mount_Config::getSystemMountPoints();
}
/**
* generate target directory
*
* @param string $user
* @param string $filePath
* @param string $keyPath
* @param string $filename
* @param bool $trash
* @return string
*/
private function getTargetDir($user, $filePath, $filename, $trash) {
private function getTargetDir($user, $keyPath, $filename, $trash) {
if ($trash) {
$targetDir = $user . '/files_encryption/keys/files_trashbin/' . substr($filePath, strlen('/files_trashbin/keys/')) . '/' . $this->moduleId . '/' . $filename;
$filePath = substr($keyPath, strlen('/files_trashbin/keys/'));
$targetDir = $user . '/files_encryption/keys/files_trashbin/' . $filePath . '/' . $this->moduleId . '/' . $filename;
} else {
$targetDir = $user . '/files_encryption/keys/files/' . substr($filePath, strlen('/files_encryption/keys/')) . '/' . $this->moduleId . '/' . $filename;
$filePath = substr($keyPath, strlen('/files_encryption/keys/'));
$targetDir = $user . '/files_encryption/keys/files/' . $filePath . '/' . $this->moduleId . '/' . $filename;
}
return $targetDir;
if ($user === '') {
// for system wide mounts we need to check if the mount point really exists
$normalized = \OC\Files\Filesystem::normalizePath($filePath);
$systemMountPoints = $this->getSystemMountPoints();
foreach ($systemMountPoints as $mountPoint) {
$normalizedMountPoint = \OC\Files\Filesystem::normalizePath($mountPoint['mountpoint']) . '/';
if (strpos($normalized, $normalizedMountPoint) === 0)
return $targetDir;
}
} else if ($trash === false && $this->view->file_exists('/' . $user. '/files/' . $filePath)) {
return $targetDir;
} else if ($trash === true && $this->view->file_exists('/' . $user. '/files_trashbin/' . $filePath)) {
return $targetDir;
}
return false;
}
/**
+47 -3
View File
@@ -182,18 +182,62 @@ class KeyManagerTest extends TestCase {
);
}
public function testUserHasKeys() {
/**
* @dataProvider dataTestUserHasKeys
*/
public function testUserHasKeys($key, $expected) {
$this->keyStorageMock->expects($this->exactly(2))
->method('getUserKey')
->with($this->equalTo($this->userId), $this->anything())
->willReturn('key');
->willReturn($key);
$this->assertTrue(
$this->assertSame($expected,
$this->instance->userHasKeys($this->userId)
);
}
public function dataTestUserHasKeys() {
return [
['key', true],
['', false]
];
}
/**
* @expectedException \OCA\Encryption\Exceptions\PrivateKeyMissingException
*/
public function testUserHasKeysMissingPrivateKey() {
$this->keyStorageMock->expects($this->exactly(2))
->method('getUserKey')
->willReturnCallback(function ($uid, $keyID, $encryptionModuleId) {
if ($keyID=== 'privateKey') {
return '';
}
return 'key';
});
$this->instance->userHasKeys($this->userId);
}
/**
* @expectedException \OCA\Encryption\Exceptions\PublicKeyMissingException
*/
public function testUserHasKeysMissingPublicKey() {
$this->keyStorageMock->expects($this->exactly(2))
->method('getUserKey')
->willReturnCallback(function ($uid, $keyID, $encryptionModuleId){
if ($keyID === 'publicKey') {
return '';
}
return 'key';
});
$this->instance->userHasKeys($this->userId);
}
public function testInit() {
$this->keyStorageMock->expects($this->any())
->method('getUserKey')
+176 -4
View File
@@ -24,6 +24,7 @@
namespace OCA\Encryption\Tests;
use OCA\Encryption\Migration;
use OCP\ILogger;
class MigrationTest extends \Test\TestCase {
@@ -37,6 +38,9 @@ class MigrationTest extends \Test\TestCase {
private $recovery_key_id = 'recovery_key_id';
private $moduleId;
/** @var PHPUnit_Framework_MockObject_MockObject | ILogger */
private $logger;
public static function setUpBeforeClass() {
parent::setUpBeforeClass();
\OC_User::createUser(self::TEST_ENCRYPTION_MIGRATION_USER1, 'foo');
@@ -53,6 +57,7 @@ class MigrationTest extends \Test\TestCase {
public function setUp() {
$this->logger = $this->getMockBuilder('\OCP\ILogger')->disableOriginalConstructor()->getMock();
$this->view = new \OC\Files\View();
$this->moduleId = \OCA\Encryption\Crypto\Encryption::ID;
}
@@ -100,6 +105,17 @@ class MigrationTest extends \Test\TestCase {
$this->view->file_put_contents($uid . '/files_encryption/keys/folder2/file.2.1/fileKey' , 'data');
}
protected function createDummyFiles($uid) {
$this->view->mkdir($uid . '/files/folder1/folder2/folder3/file3');
$this->view->mkdir($uid . '/files/folder1/folder2/file2');
$this->view->mkdir($uid . '/files/folder1/file.1');
$this->view->mkdir($uid . '/files/folder2/file.2.1');
$this->view->file_put_contents($uid . '/files/folder1/folder2/folder3/file3/fileKey' , 'data');
$this->view->file_put_contents($uid . '/files/folder1/folder2/file2/fileKey' , 'data');
$this->view->file_put_contents($uid . '/files/folder1/file.1/fileKey' , 'data');
$this->view->file_put_contents($uid . '/files/folder2/file.2.1/fileKey' , 'data');
}
protected function createDummyFilesInTrash($uid) {
$this->view->mkdir($uid . '/files_trashbin/keys/file1.d5457864');
$this->view->mkdir($uid . '/files_trashbin/keys/folder1.d7437648723/file2');
@@ -109,6 +125,11 @@ class MigrationTest extends \Test\TestCase {
$this->view->file_put_contents($uid . '/files_trashbin/keys/file1.d5457864/fileKey' , 'data');
$this->view->file_put_contents($uid . '/files_trashbin/keys/folder1.d7437648723/file2/fileKey' , 'data');
// create the files itself
$this->view->mkdir($uid . '/files_trashbin/folder1.d7437648723');
$this->view->file_put_contents($uid . '/files_trashbin/file1.d5457864' , 'data');
$this->view->file_put_contents($uid . '/files_trashbin/folder1.d7437648723/file2' , 'data');
}
protected function createDummySystemWideKeys() {
@@ -118,7 +139,6 @@ class MigrationTest extends \Test\TestCase {
$this->view->file_put_contents('files_encryption/systemwide_2.privateKey', 'data');
$this->view->file_put_contents('files_encryption/public_keys/systemwide_1.publicKey', 'data');
$this->view->file_put_contents('files_encryption/public_keys/systemwide_2.publicKey', 'data');
}
public function testMigrateToNewFolderStructure() {
@@ -134,6 +154,10 @@ class MigrationTest extends \Test\TestCase {
$this->createDummyFileKeys(self::TEST_ENCRYPTION_MIGRATION_USER2);
$this->createDummyFileKeys(self::TEST_ENCRYPTION_MIGRATION_USER3);
$this->createDummyFiles(self::TEST_ENCRYPTION_MIGRATION_USER1);
$this->createDummyFiles(self::TEST_ENCRYPTION_MIGRATION_USER2);
$this->createDummyFiles(self::TEST_ENCRYPTION_MIGRATION_USER3);
$this->createDummyFilesInTrash(self::TEST_ENCRYPTION_MIGRATION_USER2);
// no user for system wide mount points
@@ -142,7 +166,21 @@ class MigrationTest extends \Test\TestCase {
$this->createDummySystemWideKeys();
$m = new Migration(\OC::$server->getConfig(), new \OC\Files\View(), \OC::$server->getDatabaseConnection());
$m = $this->getMockBuilder('OCA\Encryption\Migration')
->setConstructorArgs(
[
\OC::$server->getConfig(),
new \OC\Files\View(),
\OC::$server->getDatabaseConnection(),
$this->logger
]
)->setMethods(['getSystemMountPoints'])->getMock();
$m->expects($this->any())->method('getSystemMountPoints')
->willReturn([['mountpoint' => 'folder1'], ['mountpoint' => 'folder2']]);
$m->reorganizeFolderStructure();
// even if it runs twice folder should always move only once
$m->reorganizeFolderStructure();
$this->assertTrue(
@@ -242,6 +280,12 @@ class MigrationTest extends \Test\TestCase {
$config->setAppValue('files_encryption', 'recoveryAdminEnabled', '1');
$config->setUserValue(self::TEST_ENCRYPTION_MIGRATION_USER1, 'files_encryption', 'recoverKeyEnabled', '1');
//$this->invokePrivate($config, 'cache', [[]]);
$cache = $this->invokePrivate(\OC::$server->getAppConfig(), 'cache');
unset($cache['encryption']);
unset($cache['files_encryption']);
$this->invokePrivate(\OC::$server->getAppConfig(), 'cache', [$cache]);
// delete default values set by the encryption app during initialization
/** @var \OC\DB\Connection $connection */
@@ -261,7 +305,7 @@ class MigrationTest extends \Test\TestCase {
public function testUpdateDB() {
$this->prepareDB();
$m = new Migration(\OC::$server->getConfig(), new \OC\Files\View(), \OC::$server->getDatabaseConnection());
$m = new Migration(\OC::$server->getConfig(), new \OC\Files\View(), \OC::$server->getDatabaseConnection(), $this->logger);
$m->updateDB();
$this->verifyDB('`*PREFIX*appconfig`', 'files_encryption', 0);
@@ -271,6 +315,58 @@ class MigrationTest extends \Test\TestCase {
}
/**
* test update db if the db already contain some existing new values
*/
public function testUpdateDBExistingNewConfig() {
$this->prepareDB();
$config = \OC::$server->getConfig();
$config->setAppValue('encryption', 'publicShareKeyId', 'wrong_share_id');
$config->setUserValue(self::TEST_ENCRYPTION_MIGRATION_USER1, 'encryption', 'recoverKeyEnabled', '9');
$m = new Migration(\OC::$server->getConfig(), new \OC\Files\View(), \OC::$server->getDatabaseConnection(), $this->logger);
$m->updateDB();
$this->verifyDB('`*PREFIX*appconfig`', 'files_encryption', 0);
$this->verifyDB('`*PREFIX*preferences`', 'files_encryption', 0);
$this->verifyDB('`*PREFIX*appconfig`', 'encryption', 3);
$this->verifyDB('`*PREFIX*preferences`', 'encryption', 1);
// check if the existing values where overwritten correctly
/** @var \OC\DB\Connection $connection */
$connection = \OC::$server->getDatabaseConnection();
$query = $connection->createQueryBuilder();
$query->select('`configvalue`')
->from('`*PREFIX*appconfig`')
->where($query->expr()->andX(
$query->expr()->eq('`appid`', ':appid'),
$query->expr()->eq('`configkey`', ':configkey')
))
->setParameter('appid', 'encryption')
->setParameter('configkey', 'publicShareKeyId');
$result = $query->execute();
$value = $result->fetch();
$this->assertTrue(isset($value['configvalue']));
$this->assertSame('share_id', $value['configvalue']);
$query = $connection->createQueryBuilder();
$query->select('`configvalue`')
->from('`*PREFIX*preferences`')
->where($query->expr()->andX(
$query->expr()->eq('`appid`', ':appid'),
$query->expr()->eq('`configkey`', ':configkey'),
$query->expr()->eq('`userid`', ':userid')
))
->setParameter('appid', 'encryption')
->setParameter('configkey', 'recoverKeyEnabled')
->setParameter('userid', self::TEST_ENCRYPTION_MIGRATION_USER1);
$result = $query->execute();
$value = $result->fetch();
$this->assertTrue(isset($value['configvalue']));
$this->assertSame('1', $value['configvalue']);
}
public function verifyDB($table, $appid, $expected) {
/** @var \OC\DB\Connection $connection */
$connection = \OC::$server->getDatabaseConnection();
@@ -291,7 +387,7 @@ class MigrationTest extends \Test\TestCase {
*/
public function testUpdateFileCache() {
$this->prepareFileCache();
$m = new Migration(\OC::$server->getConfig(), new \OC\Files\View(), \OC::$server->getDatabaseConnection());
$m = new Migration(\OC::$server->getConfig(), new \OC\Files\View(), \OC::$server->getDatabaseConnection(), $this->logger);
self::invokePrivate($m, 'updateFileCache');
// check results
@@ -353,4 +449,80 @@ class MigrationTest extends \Test\TestCase {
$this->assertSame(19, count($result));
}
/**
* @dataProvider dataTestGetTargetDir
*/
public function testGetTargetDir($user, $keyPath, $filename, $trash, $systemMounts, $expected) {
$updater = $this->getMockBuilder('\OC\Files\Cache\Updater')
->disableOriginalConstructor()->getMock();
$view = $this->getMockBuilder('\OC\Files\View')
->disableOriginalConstructor()->getMock();
$view->expects($this->any())->method('file_exists')->willReturn(true);
$view->expects($this->any())->method('getUpdater')->willReturn($updater);
$m = $this->getMockBuilder('OCA\Encryption\Migration')
->setConstructorArgs(
[
\OC::$server->getConfig(),
$view,
\OC::$server->getDatabaseConnection(),
$this->logger
]
)->setMethods(['getSystemMountPoints'])->getMock();
$m->expects($this->any())->method('getSystemMountPoints')
->willReturn($systemMounts);
$this->assertSame($expected,
$this->invokePrivate($m, 'getTargetDir', [$user, $keyPath, $filename, $trash])
);
}
public function dataTestGetTargetDir() {
return [
[
'user1',
'/files_encryption/keys/foo/bar.txt',
'user1.shareKey',
false,
[],
'user1/files_encryption/keys/files/foo/bar.txt/OC_DEFAULT_MODULE/user1.shareKey'
],
[
'user1',
'/files_trashbin/keys/foo/bar.txt',
'user1.shareKey',
true,
[],
'user1/files_encryption/keys/files_trashbin/foo/bar.txt/OC_DEFAULT_MODULE/user1.shareKey'
],
[
'',
'/files_encryption/keys/foo/bar.txt',
'user1.shareKey',
false,
[['mountpoint' => 'foo']],
'/files_encryption/keys/files/foo/bar.txt/OC_DEFAULT_MODULE/user1.shareKey'
],
[
'',
'/files_encryption/keys/foo/bar.txt',
'user1.shareKey',
false,
[['mountpoint' => 'foobar']],
false
],
[
'',
'/files_encryption/keys/foobar/bar.txt',
'user1.shareKey',
false,
[['mountpoint' => 'foo']],
false
]
];
}
}
+5 -4
View File
@@ -92,10 +92,10 @@ class Scan extends Command {
}
protected function execute(InputInterface $input, OutputInterface $output) {
$path = $input->getOption('path');
if ($path) {
$path = '/'.trim($path, '/');
list (, $user, ) = explode('/', $path, 3);
$inputPath = $input->getOption('path');
if ($inputPath) {
$inputPath = '/' . trim($inputPath, '/');
list (, $user,) = explode('/', $inputPath, 3);
$users = array($user);
} else if ($input->getOption('all')) {
$users = $this->userManager->search('');
@@ -114,6 +114,7 @@ class Scan extends Command {
if (is_object($user)) {
$user = $user->getUID();
}
$path = $inputPath ? $inputPath : '/' . $user;
if ($this->userManager->userExists($user)) {
$this->scanFiles($user, $path, $quiet, $output);
} else {
+7 -1
View File
@@ -170,8 +170,14 @@ class Server2Server {
$query = \OCP\DB::prepare('DELETE FROM `*PREFIX*share_external` WHERE `remote_id` = ? AND `share_token` = ?');
$query->execute(array($id, $token));
if ($share['accepted']) {
$path = trim($mountpoint, '/');
} else {
$path = trim($share['name'], '/');
}
\OC::$server->getActivityManager()->publishActivity(
'files_sharing', \OCA\Files_Sharing\Activity::SUBJECT_REMOTE_SHARE_UNSHARED, array($owner, $mountpoint), '', array(),
'files_sharing', \OCA\Files_Sharing\Activity::SUBJECT_REMOTE_SHARE_UNSHARED, array($owner, $path), '', array(),
'', '', $user, \OCA\Files_Sharing\Activity::TYPE_REMOTE_SHARE, \OCA\Files_Sharing\Activity::PRIORITY_MEDIUM);
}
-1
View File
@@ -19,5 +19,4 @@ Turning the feature off removes shared files and folders on the server for all s
<files>public.php</files>
<webdav>publicwebdav.php</webdav>
</public>
<ocsid>166050</ocsid>
</info>
+1 -1
View File
@@ -1 +1 @@
0.6.1
0.6.2
+1 -1
View File
@@ -72,7 +72,7 @@ thead {
}
/* keep long file names in one line to not overflow download button on mobile */
.directDownload #download {
.directDownload #downloadFile {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
+1 -1
View File
@@ -151,7 +151,7 @@
var permissions = $tr.data('permissions');
var hasLink = !!(shareStatus && shareStatus.link);
OC.Share.markFileAsShared($tr, true, hasLink);
if ((permissions & OC.PERMISSION_SHARE) === 0) {
if ((permissions & OC.PERMISSION_SHARE) === 0 && $tr.attr('data-share-owner')) {
// if no share action exists because the admin disabled sharing for this user
// we create a share notification action to inform the user about files
// shared with him otherwise we just update the existing share action.
+1 -1
View File
@@ -190,12 +190,12 @@ class Activity implements IExtension {
if ($app === self::FILES_SHARING_APP) {
switch ($text) {
case self::SUBJECT_REMOTE_SHARE_RECEIVED:
case self::SUBJECT_REMOTE_SHARE_UNSHARED:
return array(
0 => '',// We can not use 'username' since the user is in a different ownCloud
);
case self::SUBJECT_REMOTE_SHARE_ACCEPTED:
case self::SUBJECT_REMOTE_SHARE_DECLINED:
case self::SUBJECT_REMOTE_SHARE_UNSHARED:
return array(
0 => '',// We can not use 'username' since the user is in a different ownCloud
1 => 'file',
+7 -13
View File
@@ -191,7 +191,7 @@ class Storage extends DAV implements ISharedStorage {
throw new StorageInvalidException();
} else {
// ownCloud instance is gone, likely to be a temporary server configuration error
throw $e;
throw new StorageNotAvailableException();
}
} catch (ForbiddenException $e) {
// auth error, remove share for now (provide a dialog in the future)
@@ -201,10 +201,7 @@ class Storage extends DAV implements ISharedStorage {
} catch (\GuzzleHttp\Exception\ConnectException $e) {
throw new StorageNotAvailableException();
} catch (\GuzzleHttp\Exception\RequestException $e) {
if ($e->getCode() === 503) {
throw new StorageNotAvailableException();
}
throw $e;
throw new StorageNotAvailableException();
} catch (\Exception $e) {
throw $e;
}
@@ -250,16 +247,13 @@ class Storage extends DAV implements ISharedStorage {
try {
$response = $client->post($url, ['body' => ['password' => $password]]);
} catch (\GuzzleHttp\Exception\RequestException $e) {
switch ($e->getCode()) {
case 401:
case 403:
if ($e->getCode() === 401 || $e->getCode() === 403) {
throw new ForbiddenException();
case 404:
throw new NotFoundException();
case 500:
throw new \Exception();
}
throw $e;
// throw this to be on the safe side: the share will still be visible
// in the UI in case the failure is intermittent, and the user will
// be able to decide whether to remove it if it's really gone
throw new StorageNotAvailableException();
}
return json_decode($response->getBody(), true);
+17 -10
View File
@@ -41,34 +41,40 @@ class SharedMount extends MountPoint implements MoveableMount {
*/
protected $ownerPropagator;
/**
* @var \OC\Files\View
*/
private $recipientView;
public function __construct($storage, $mountpoint, $arguments = null, $loader = null) {
// first update the mount point before creating the parent
$this->ownerPropagator = $arguments['propagator'];
$newMountPoint = $this->verifyMountPoint($arguments['share'], $arguments['user']);
$this->recipientView = new View('/' . $arguments['user'] . '/files');
$newMountPoint = $this->verifyMountPoint($arguments['share']);
$absMountPoint = '/' . $arguments['user'] . '/files' . $newMountPoint;
$arguments['ownerView'] = new View('/' . $arguments['share']['uid_owner'] . '/files');
parent::__construct($storage, $absMountPoint, $arguments, $loader);
}
/**
* check if the parent folder exists otherwise move the mount point up
*/
private function verifyMountPoint(&$share, $user) {
private function verifyMountPoint(&$share) {
$mountPoint = basename($share['file_target']);
$parent = dirname($share['file_target']);
$view = new View('/' . $user . '/files');
if (!$view->is_dir($parent)) {
if (!$this->recipientView->is_dir($parent)) {
$parent = Helper::getShareFolder();
}
$newMountPoint = \OCA\Files_Sharing\Helper::generateUniqueTarget(
\OC\Files\Filesystem::normalizePath($parent . '/' . $mountPoint),
array(),
new \OC\Files\View('/' . $user . '/files')
);
\OC\Files\Filesystem::normalizePath($parent . '/' . $mountPoint),
[],
$this->recipientView
);
if($newMountPoint !== $share['file_target']) {
if ($newMountPoint !== $share['file_target']) {
self::updateFileTarget($newMountPoint, $share);
$share['file_target'] = $newMountPoint;
$share['unique_name'] = true;
@@ -79,6 +85,7 @@ class SharedMount extends MountPoint implements MoveableMount {
/**
* update fileTarget in the database if the mount point changed
*
* @param string $newPath
* @param array $share reference to the share which should be modified
* @return bool
@@ -99,7 +106,7 @@ class SharedMount extends MountPoint implements MoveableMount {
'Update `*PREFIX*share`
SET `file_target` = ?
WHERE `id` = ?'
);
);
$arguments = array($newPath, $share['id']);
}
+16
View File
@@ -45,8 +45,14 @@ class Shared extends \OC\Files\Storage\Common implements ISharedStorage {
private $files = array();
private static $isInitialized = array();
/**
* @var \OC\Files\View
*/
private $ownerView;
public function __construct($arguments) {
$this->share = $arguments['share'];
$this->ownerView = $arguments['ownerView'];
}
/**
@@ -623,6 +629,11 @@ class Shared extends \OC\Files\Storage\Common implements ISharedStorage {
/** @var \OCP\Files\Storage $targetStorage */
list($targetStorage, $targetInternalPath) = $this->resolvePath($path);
$targetStorage->acquireLock($targetInternalPath, $type, $provider);
// lock the parent folders of the owner when locking the share as recipient
if ($path === '') {
$sourcePath = $this->ownerView->getPath($this->share['file_source']);
$this->ownerView->lockFile(dirname($sourcePath), ILockingProvider::LOCK_SHARED, true);
}
}
/**
@@ -634,6 +645,11 @@ class Shared extends \OC\Files\Storage\Common implements ISharedStorage {
/** @var \OCP\Files\Storage $targetStorage */
list($targetStorage, $targetInternalPath) = $this->resolvePath($path);
$targetStorage->releaseLock($targetInternalPath, $type, $provider);
// unlock the parent folders of the owner when unlocking the share as recipient
if ($path === '') {
$sourcePath = $this->ownerView->getPath($this->share['file_source']);
$this->ownerView->unlockFile(dirname($sourcePath), ILockingProvider::LOCK_SHARED, true);
}
}
/**
+1 -1
View File
@@ -100,7 +100,7 @@ $thumbSize = 1024;
<div id="imgframe"></div>
<?php endif; ?>
<div class="directDownload">
<a href="<?php p($_['downloadURL']); ?>" id="download" class="button">
<a href="<?php p($_['downloadURL']); ?>" id="downloadFile" class="button">
<img class="svg" alt="" src="<?php print_unescaped(OCP\image_path("core", "actions/download.svg")); ?>"/>
<?php p($l->t('Download %s', array($_['filename'])))?> (<?php p($_['fileSize']) ?>)
</a>
+17
View File
@@ -206,6 +206,23 @@ describe('OCA.Sharing.Util tests', function() {
expect(OC.basename(getImageUrl($tr.find('.filename .thumbnail')))).toEqual('folder-shared.svg');
expect($action.find('img').length).toEqual(1);
});
it('do not show static share text when share exists but neither permission nor owner is available', function() {
var $action, $tr;
fileList.setFiles([{
id: 1,
type: 'dir',
name: 'One',
path: '/subdir',
mimetype: 'text/plain',
size: 12,
permissions: OC.PERMISSION_CREATE,
etag: 'abc'
}]);
$tr = fileList.$el.find('tbody tr:first');
expect($tr.find('.action-share').length).toEqual(0);
$action = $tr.find('.action-share-notification');
expect($action.length).toEqual(0);
});
});
describe('Share action', function() {
var showDropDownStub;
+101
View File
@@ -0,0 +1,101 @@
<?php
/**
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
* @copyright Copyright (c) 2015, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program 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, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OCA\Files_sharing\Tests;
use OC\Files\Filesystem;
use OC\Files\View;
use OC\Lock\MemcacheLockingProvider;
use OCP\Lock\ILockingProvider;
class Locking extends TestCase {
/**
* @var \OC_User_Dummy
*/
private $userBackend;
private $ownerUid;
private $recipientUid;
public function setUp() {
parent::setUp();
$this->userBackend = new \OC_User_Dummy();
\OC::$server->getUserManager()->registerBackend($this->userBackend);
$this->ownerUid = $this->getUniqueID('owner_');
$this->recipientUid = $this->getUniqueID('recipient_');
$this->userBackend->createUser($this->ownerUid, '');
$this->userBackend->createUser($this->recipientUid, '');
$this->loginAsUser($this->ownerUid);
Filesystem::mkdir('/foo');
Filesystem::file_put_contents('/foo/bar.txt', 'asd');
$fileId = Filesystem::getFileInfo('/foo/bar.txt')->getId();
\OCP\Share::shareItem('file', $fileId, \OCP\Share::SHARE_TYPE_USER, $this->recipientUid, 31);
$this->loginAsUser($this->recipientUid);
$this->assertTrue(Filesystem::file_exists('bar.txt'));
}
public function tearDown() {
\OC::$server->getUserManager()->removeBackend($this->userBackend);
parent::tearDown();
}
/**
* @expectedException \OCP\Lock\LockedException
*/
public function testLockAsRecipient() {
$this->loginAsUser($this->ownerUid);
Filesystem::initMountPoints($this->recipientUid);
$recipientView = new View('/' . $this->recipientUid . '/files');
$recipientView->lockFile('bar.txt', ILockingProvider::LOCK_EXCLUSIVE);
Filesystem::rename('/foo', '/asd');
}
public function testUnLockAsRecipient() {
$this->loginAsUser($this->ownerUid);
Filesystem::initMountPoints($this->recipientUid);
$recipientView = new View('/' . $this->recipientUid . '/files');
$recipientView->lockFile('bar.txt', ILockingProvider::LOCK_EXCLUSIVE);
$recipientView->unlockFile('bar.txt', ILockingProvider::LOCK_EXCLUSIVE);
$this->assertTrue(Filesystem::rename('/foo', '/asd'));
}
public function testChangeLock() {
Filesystem::initMountPoints($this->recipientUid);
$recipientView = new View('/' . $this->recipientUid . '/files');
$recipientView->lockFile('bar.txt', ILockingProvider::LOCK_SHARED);
$recipientView->changeLock('bar.txt', ILockingProvider::LOCK_EXCLUSIVE);
$recipientView->unlockFile('bar.txt', ILockingProvider::LOCK_EXCLUSIVE);
$this->assertTrue(true);
}
}
+130
View File
@@ -321,4 +321,134 @@ class Test_Files_Sharing extends OCA\Files_sharing\Tests\TestCase {
);
}
/**
* @dataProvider dataProviderGetUsersSharingFile
*
* @param string $groupName name of group to share with
* @param bool $includeOwner whether to include the owner in the result
* @param bool $includePaths whether to include paths in the result
* @param array $expectedResult expected result of the API call
*/
function testGetUsersSharingFile($groupName, $includeOwner, $includePaths, $expectedResult) {
$fileinfo = $this->view->getFileInfo($this->folder);
$result = \OCP\Share::shareItem('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP,
$groupName, \OCP\Constants::PERMISSION_READ);
$this->assertTrue($result);
// public share
$result = \OCP\Share::shareItem('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_LINK,
null, \OCP\Constants::PERMISSION_READ);
$this->assertNotNull($result); // returns the token!
// owner renames after sharing
$this->view->rename($this->folder, $this->folder . '_owner_renamed');
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
$user2View = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files');
$user2View->rename($this->folder, $this->folder . '_renamed');
$ownerPath = $this->folder . '_owner_renamed';
$owner = self::TEST_FILES_SHARING_API_USER1;
$result = \OCP\Share::getUsersSharingFile($ownerPath, $owner, $includeOwner, $includePaths);
// sort users to make sure it matches
if ($includePaths) {
ksort($result);
} else {
sort($result['users']);
}
$this->assertEquals(
$expectedResult,
$result
);
}
function dataProviderGetUsersSharingFile() {
// note: "group" contains user1 (the owner), user2 and user3
// and self::TEST_FILES_SHARING_API_GROUP1 contains only user2
return [
// share with group that contains owner
[
'group',
false,
false,
[
'users' =>
[
// because user1 was in group
self::TEST_FILES_SHARING_API_USER1,
self::TEST_FILES_SHARING_API_USER2,
self::TEST_FILES_SHARING_API_USER3,
],
'public' => true,
'remote' => false,
],
],
// share with group that does not contain owner
[
self::TEST_FILES_SHARING_API_GROUP1,
false,
false,
[
'users' =>
[
self::TEST_FILES_SHARING_API_USER2,
],
'public' => true,
'remote' => false,
],
],
// share with group that does not contain owner, include owner
[
self::TEST_FILES_SHARING_API_GROUP1,
true,
false,
[
'users' =>
[
self::TEST_FILES_SHARING_API_USER1,
self::TEST_FILES_SHARING_API_USER2,
],
'public' => true,
'remote' => false,
],
],
// include paths, with owner
[
'group',
true,
true,
[
self::TEST_FILES_SHARING_API_USER1 => self::TEST_FOLDER_NAME . '_owner_renamed',
self::TEST_FILES_SHARING_API_USER2 => self::TEST_FOLDER_NAME . '_renamed',
self::TEST_FILES_SHARING_API_USER3 => self::TEST_FOLDER_NAME,
],
],
// include paths, group without owner
[
self::TEST_FILES_SHARING_API_GROUP1,
false,
true,
[
self::TEST_FILES_SHARING_API_USER2 => self::TEST_FOLDER_NAME. '_renamed',
],
],
// include paths, include owner, group without owner
[
self::TEST_FILES_SHARING_API_GROUP1,
true,
true,
[
self::TEST_FILES_SHARING_API_USER1 => self::TEST_FOLDER_NAME . '_owner_renamed',
self::TEST_FILES_SHARING_API_USER2 => self::TEST_FOLDER_NAME . '_renamed',
],
],
];
}
}
+5 -3
View File
@@ -40,7 +40,7 @@ class UnshareChildren extends TestCase {
\OCP\Util::connectHook('OC_Filesystem', 'post_delete', '\OCA\Files_Sharing\Hooks', 'unshareChildren');
$this->folder = self::TEST_FOLDER_NAME;
$this->subfolder = '/subfolder_share_api_test';
$this->subfolder = '/subfolder_share_api_test';
$this->subsubfolder = '/subsubfolder_share_api_test';
$this->filename = '/share-api-test';
@@ -49,12 +49,14 @@ class UnshareChildren extends TestCase {
$this->view->mkdir($this->folder);
$this->view->mkdir($this->folder . $this->subfolder);
$this->view->mkdir($this->folder . $this->subfolder . $this->subsubfolder);
$this->view->file_put_contents($this->folder.$this->filename, $this->data);
$this->view->file_put_contents($this->folder . $this->filename, $this->data);
$this->view->file_put_contents($this->folder . $this->subfolder . $this->filename, $this->data);
}
protected function tearDown() {
$this->view->deleteAll($this->folder);
if ($this->view) {
$this->view->deleteAll($this->folder);
}
self::$tempStorage = null;
-1
View File
@@ -18,5 +18,4 @@ To prevent a user from running out of disk space, the ownCloud Deleted files app
<documentation>
<user>user-trashbin</user>
</documentation>
<ocsid>166052</ocsid>
</info>
+1 -1
View File
@@ -1 +1 @@
0.6.2
0.6.3
+32 -2
View File
@@ -26,6 +26,7 @@ namespace OCA\Files_Trashbin;
use OC\Files\Filesystem;
use OC\Files\Storage\Wrapper\Wrapper;
use OCP\IUserManager;
class Storage extends Wrapper {
@@ -41,8 +42,12 @@ class Storage extends Wrapper {
*/
private static $disableTrash = false;
function __construct($parameters) {
/** @var IUserManager */
private $userManager;
function __construct($parameters, IUserManager $userManager = null) {
$this->mountPoint = $parameters['mountPoint'];
$this->userManager = $userManager;
parent::__construct($parameters);
}
@@ -100,6 +105,27 @@ class Storage extends Wrapper {
return $this->doDelete($path, 'rmdir');
}
/**
* check if it is a file located in data/user/files only files in the
* 'files' directory should be moved to the trash
*
* @param $path
* @return bool
*/
protected function shouldMoveToTrash($path){
$normalized = Filesystem::normalizePath($this->mountPoint . '/' . $path);
$parts = explode('/', $normalized);
if (count($parts) < 4) {
return false;
}
if ($this->userManager->userExists($parts[1]) && $parts[2] == 'files') {
return true;
}
return false;
}
/**
* Run the delete operation with the given method
*
@@ -112,6 +138,7 @@ class Storage extends Wrapper {
if (self::$disableTrash
|| !\OC_App::isEnabled('files_trashbin')
|| (pathinfo($path, PATHINFO_EXTENSION) === 'part')
|| $this->shouldMoveToTrash($path) === false
) {
return call_user_func_array([$this->storage, $method], [$path]);
}
@@ -144,7 +171,10 @@ class Storage extends Wrapper {
*/
public static function setupStorage() {
\OC\Files\Filesystem::addStorageWrapper('oc_trashbin', function ($mountPoint, $storage) {
return new \OCA\Files_Trashbin\Storage(array('storage' => $storage, 'mountPoint' => $mountPoint));
return new \OCA\Files_Trashbin\Storage(
array('storage' => $storage, 'mountPoint' => $mountPoint),
\OC::$server->getUserManager()
);
}, 1);
}
+30
View File
@@ -493,4 +493,34 @@ class Storage extends \Test\TestCase {
$results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/files/');
$this->assertEquals(0, count($results));
}
/**
* @dataProvider dataTestShouldMoveToTrash
*/
public function testShouldMoveToTrash($mountPoint, $path, $userExists, $expected) {
$tmpStorage = $this->getMockBuilder('\OC\Files\Storage\Temporary')
->disableOriginalConstructor()->getMock();
$userManager = $this->getMockBuilder('OCP\IUserManager')
->disableOriginalConstructor()->getMock();
$userManager->expects($this->any())
->method('userExists')->willReturn($userExists);
$storage = new \OCA\Files_Trashbin\Storage(
['mountPoint' => $mountPoint, 'storage' => $tmpStorage],
$userManager
);
$this->assertSame($expected,
$this->invokePrivate($storage, 'shouldMoveToTrash', [$path])
);
}
public function dataTestShouldMoveToTrash() {
return [
['/schiesbn/', '/files/test.txt', true, true],
['/schiesbn/', '/files/test.txt', false, false],
['/schiesbn/', '/test.txt', true, false],
['/schiesbn/', '/test.txt', false, false],
];
}
}
-1
View File
@@ -18,5 +18,4 @@ In addition to the expiry of versions, ownClouds versions app makes certain n
<user>user-versions</user>
</documentation>
<default_enable/>
<ocsid>166053</ocsid>
</info>
+1 -1
View File
@@ -1 +1 @@
1.0.5
1.0.6
-1
View File
@@ -17,7 +17,6 @@ A user logs into ownCloud with their LDAP or AD credentials, and is granted acce
<documentation>
<admin>admin-ldap</admin>
</documentation>
<ocsid>166061</ocsid>
<dependencies>
<lib>ldap</lib>
</dependencies>
+1 -1
View File
@@ -1 +1 @@
0.6.0
0.6.1
+8 -1
View File
@@ -378,9 +378,16 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
&& intval($this->access->connection->useMemberOfToDetectMembership) === 1
) {
$groupDNs = $this->access->readAttribute($userDN, 'memberOf');
if (is_array($groupDNs)) {
$groupDNs = $this->access->groupsMatchFilter($groupDNs);
foreach ($groupDNs as $dn) {
$groups[] = $this->access->dn2groupname($dn);;
$groupName = $this->access->dn2groupname($dn);
if(is_string($groupName)) {
// be sure to never return false if the dn could not be
// resolved to a name, for whatever reason.
$groups[] = $groupName;
}
}
}
if($primaryGroup !== false) {
+38
View File
@@ -346,6 +346,44 @@ class Access extends LDAPUtility implements user\IUserTools {
return $this->dn2ocname($fdn, $ldapName, false);
}
/**
* accepts an array of group DNs and tests whether they match the user
* filter by doing read operations against the group entries. Returns an
* array of DNs that match the filter.
*
* @param string[] $groupDNs
* @return string[]
*/
public function groupsMatchFilter($groupDNs) {
$validGroupDNs = [];
foreach($groupDNs as $dn) {
$cacheKey = 'groupsMatchFilter-'.$dn;
if($this->connection->isCached($cacheKey)) {
if($this->connection->getFromCache($cacheKey)) {
$validGroupDNs[] = $dn;
}
continue;
}
// Check the base DN first. If this is not met already, we don't
// need to ask the server at all.
if(!$this->isDNPartOfBase($dn, $this->connection->ldapBaseGroups)) {
$this->connection->writeToCache($cacheKey, false);
continue;
}
$result = $this->readAttribute($dn, 'cn', $this->connection->ldapGroupFilter);
if(is_array($result)) {
$this->connection->writeToCache($cacheKey, true);
$validGroupDNs[] = $dn;
} else {
$this->connection->writeToCache($cacheKey, false);
}
}
return $validGroupDNs;
}
/**
* returns the internal ownCloud name for the given LDAP DN of the user, false on DN outside of search DN or failure
* @param string $dn the dn of the user object
+2 -2
View File
@@ -110,8 +110,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;
}
+14
View File
@@ -0,0 +1,14 @@
# Generated by ownCloud on 2015-06-18 14:16:40
# line below if for Apache 2.4
<ifModule mod_authz_core.c>
Require all denied
</ifModule>
# line below if for Apache 2.2
<ifModule !mod_authz_core.c>
deny from all
Satisfy All
</ifModule>
# section for Apache 2.2 and 2.4
IndexIgnore *
+4
View File
@@ -404,6 +404,10 @@ class Test_Group_Ldap extends \Test\TestCase {
->method('dn2groupname')
->will($this->returnArgument(0));
$access->expects($this->once())
->method('groupsMatchFilter')
->will($this->returnArgument(0));
$groupBackend = new GroupLDAP($access);
$groups = $groupBackend->getUserGroups('userX');
@@ -0,0 +1,184 @@
<?php
/**
* Created by PhpStorm.
* User: blizzz
* Date: 26.06.15
* Time: 18:13
*/
use OCA\user_ldap\lib\LDAP;
require_once __DIR__ . '/../../../../../lib/base.php';
class IntegrationTestAccessGroupsMatchFilter {
/** @var LDAP */
protected $ldap;
/** @var \OCA\user_ldap\lib\Connection */
protected $connection;
/** @var \OCA\user_ldap\lib\Access */
protected $access;
/** @var string */
protected $base;
/** @var string[] */
protected $server;
public function __construct($host, $port, $bind, $pwd, $base) {
$this->base = $base;
$this->server = [
'host' => $host,
'port' => $port,
'dn' => $bind,
'pwd' => $pwd
];
}
/**
* prepares the LDAP environement and sets up a test configuration for
* the LDAP backend.
*/
public function init() {
require('setup-scripts/createExplicitUsers.php');
require('setup-scripts/createExplicitGroups.php');
require('setup-scripts/createExplicitGroupsDifferentOU.php');
$this->initLDAPWrapper();
$this->initConnection();
$this->initAccess();
}
/**
* runs the test cases while outputting progress and result information
*
* If a test failed, the script is exited with return code 1.
*/
public function run() {
$cases = ['case1', 'case2', 'case3'];
foreach ($cases as $case) {
print("running $case " . PHP_EOL);
if (!$this->$case()) {
print(PHP_EOL . '>>> !!! Test ' . $case . ' FAILED !!! <<<' . PHP_EOL . PHP_EOL);
exit(1);
}
}
print('Tests succeeded' . PHP_EOL);
}
/**
* tests whether the group filter works with one specific group, while the
* input is the same.
*
* @return bool
*/
private function case1() {
$this->connection->setConfiguration(['ldapGroupFilter' => 'cn=RedGroup']);
$dns = ['cn=RedGroup,ou=Groups,' . $this->base];
$result = $this->access->groupsMatchFilter($dns);
return ($dns === $result);
}
/**
* Tests whether a filter for limited groups is effective when more existing
* groups were passed for validation.
*
* @return bool
*/
private function case2() {
$this->connection->setConfiguration(['ldapGroupFilter' => '(|(cn=RedGroup)(cn=PurpleGroup))']);
$dns = [
'cn=RedGroup,ou=Groups,' . $this->base,
'cn=BlueGroup,ou=Groups,' . $this->base,
'cn=PurpleGroup,ou=Groups,' . $this->base
];
$result = $this->access->groupsMatchFilter($dns);
$status =
count($result) === 2
&& in_array('cn=RedGroup,ou=Groups,' . $this->base, $result)
&& in_array('cn=PurpleGroup,ou=Groups,' . $this->base, $result);
return $status;
}
/**
* Tests whether a filter for limited groups is effective when more existing
* groups were passed for validation.
*
* @return bool
*/
private function case3() {
$this->connection->setConfiguration(['ldapGroupFilter' => '(objectclass=groupOfNames)']);
$dns = [
'cn=RedGroup,ou=Groups,' . $this->base,
'cn=PurpleGroup,ou=Groups,' . $this->base,
'cn=SquaredCircleGroup,ou=SpecialGroups,' . $this->base
];
$result = $this->access->groupsMatchFilter($dns);
$status =
count($result) === 2
&& in_array('cn=RedGroup,ou=Groups,' . $this->base, $result)
&& in_array('cn=PurpleGroup,ou=Groups,' . $this->base, $result);
return $status;
}
/**
* initializes the Access test instance
*/
private function initAccess() {
$this->access = new \OCA\user_ldap\lib\Access($this->connection, $this->ldap, new FakeManager());
}
/**
* initializes the test LDAP wrapper
*/
private function initLDAPWrapper() {
$this->ldap = new LDAP();
}
/**
* sets up the LDAP configuration to be used for the test
*/
private function initConnection() {
$this->connection = new \OCA\user_ldap\lib\Connection($this->ldap, '', null);
$this->connection->setConfiguration([
'ldapHost' => $this->server['host'],
'ldapPort' => $this->server['port'],
'ldapBase' => $this->base,
'ldapBaseGroups' => 'ou=Groups,' . $this->base,
'ldapAgentName' => $this->server['dn'],
'ldapAgentPassword' => $this->server['pwd'],
'ldapUserFilter' => 'objectclass=inetOrgPerson',
'ldapUserDisplayName' => 'displayName',
'ldapGroupDisplayName' => 'cn',
'ldapLoginFilter' => 'uid=%uid',
'ldapCacheTTL' => 0,
'ldapConfigurationActive' => 1,
]);
}
}
/**
* Class FakeManager
*
* this is a mock of \OCA\user_ldap\lib\user\Manager which is a dependency of
* Access, that pulls plenty more things in. Because it is not needed in the
* scope of these tests, we replace it with a mock.
*/
class FakeManager extends \OCA\user_ldap\lib\user\Manager {
public function __construct() {}
}
require_once('setup-scripts/config.php');
$test = new IntegrationTestAccessGroupsMatchFilter($host, $port, $adn, $apwd, $bdn);
$test->init();
$test->run();
@@ -0,0 +1,60 @@
# Requirements #
Have (as in do copy if not already done) the following files from https://github.com/owncloud/administration/tree/master/ldap-testing copied into the directory "setup-scripts":
* start.sh
* stop.sh
* config.php
Configure config.php according to your needs, also have a look into the LDAP and network settings in start.sh and stop.sh.
# Usage #
The basic command to run a test is:
```# ./run-test.sh [phpscript]```
Yes, run it as root from within this directory.
Example:
```
$ sudo ./run-test.sh lib/IntegrationTestAccessGroupsMatchFilter.php
71cbe88a4993e67066714d71c1cecc5ef26a54911a208103cb6294f90459e574
c74dc0155db4efa7a0515d419528a8727bbc7596601cf25b0df05e348bd74895
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c74dc0155db4 osixia/phpldapadmin:0.5.1 "/sbin/my_init" 1 seconds ago Up Less than a second 80/tcp, 0.0.0.0:8443->443/tcp docker-phpldapadmin
71cbe88a4993 nickstenning/slapd:latest "/sbin/my_init" 1 seconds ago Up Less than a second 127.0.0.1:7770->389/tcp docker-slapd
LDAP server now available under 127.0.0.1:7770 (internal IP is 172.17.0.78)
phpldapadmin now available under https://127.0.0.1:8443
created user : Alice Ealic
created group : RedGroup
created group : BlueGroup
created group : GreenGroup
created group : PurpleGroup
running case1
running case2
Tests succeeded
Stopping and resetting containers
docker-slapd
docker-phpldapadmin
docker-slapd
docker-phpldapadmin
```
# How it works #
1. start.sh is executed which brings up a fresh and clean OpenLDAP in Docker.
2. The provided test script is executed. It also outputs results.
3. stop.sh is executed to shut down OpenLDAP
# Beware #
This is quick solution for basically one test case. With expension this mechanism should be improved as well.
It does not run automatically, unless you do it. No integration with any testing framework.
exceptionOnLostConnection.php is not part of this mechanism. Read its source and run it isolated. While you're at it, port it :þ
+17
View File
@@ -0,0 +1,17 @@
#!/bin/sh
if [ $1 ] ; then
TESTSCRIPT=$1
else
echo "No test file given" exit
fi
if [ ! -e "$TESTSCRIPT" ] ; then
echo "Test file does not exist"
exit
fi
# sleep is necessary, otherwise the LDAP server cannot be connected to, yet.
setup-scripts/start.sh && sleep 2 && php -f "$TESTSCRIPT"
setup-scripts/stop.sh
@@ -0,0 +1,52 @@
<?php
if(php_sapi_name() !== 'cli') {
print('Only via CLI, please.');
exit(1);
}
include __DIR__ . '/config.php';
$cr = ldap_connect($host, $port);
ldap_set_option($cr, LDAP_OPT_PROTOCOL_VERSION, 3);
$ok = ldap_bind($cr, $adn, $apwd);
if (!$ok) {
die(ldap_error($cr));
}
$ouName = 'Groups';
$ouDN = 'ou=' . $ouName . ',' . $bdn;
//creates an OU
if (true) {
$entry = [];
$entry['objectclass'][] = 'top';
$entry['objectclass'][] = 'organizationalunit';
$entry['ou'] = $ouName;
$b = ldap_add($cr, $ouDN, $entry);
if (!$b) {
die(ldap_error($cr));
}
}
$groups = ['RedGroup', 'BlueGroup', 'GreenGroup', 'PurpleGroup'];
// groupOfNames requires groups to have at least one member
// the member used is created by createExplicitUsers.php script
$omniMember = 'uid=alice,ou=Users,' . $bdn;
foreach ($groups as $cn) {
$newDN = 'cn=' . $cn . ',' . $ouDN;
$entry = [];
$entry['cn'] = $cn;
$entry['objectclass'][] = 'groupOfNames';
$entry['member'][] = $omniMember;
$ok = ldap_add($cr, $newDN, $entry);
if ($ok) {
echo('created group ' . ': ' . $entry['cn'] . PHP_EOL);
} else {
die(ldap_error($cr));
}
}
@@ -0,0 +1,52 @@
<?php
if(php_sapi_name() !== 'cli') {
print('Only via CLI, please.');
exit(1);
}
include __DIR__ . '/config.php';
$cr = ldap_connect($host, $port);
ldap_set_option($cr, LDAP_OPT_PROTOCOL_VERSION, 3);
$ok = ldap_bind($cr, $adn, $apwd);
if (!$ok) {
die(ldap_error($cr));
}
$ouName = 'SpecialGroups';
$ouDN = 'ou=' . $ouName . ',' . $bdn;
//creates an OU
if (true) {
$entry = [];
$entry['objectclass'][] = 'top';
$entry['objectclass'][] = 'organizationalunit';
$entry['ou'] = $ouName;
$b = ldap_add($cr, $ouDN, $entry);
if (!$b) {
die(ldap_error($cr));
}
}
$groups = ['SquareGroup', 'CircleGroup', 'TriangleGroup', 'SquaredCircleGroup'];
// groupOfNames requires groups to have at least one member
// the member used is created by createExplicitUsers.php script
$omniMember = 'uid=alice,ou=Users,' . $bdn;
foreach ($groups as $cn) {
$newDN = 'cn=' . $cn . ',' . $ouDN;
$entry = [];
$entry['cn'] = $cn;
$entry['objectclass'][] = 'groupOfNames';
$entry['member'][] = $omniMember;
$ok = ldap_add($cr, $newDN, $entry);
if ($ok) {
echo('created group ' . ': ' . $entry['cn'] . PHP_EOL);
} else {
die(ldap_error($cr));
}
}
@@ -0,0 +1,54 @@
<?php
if(php_sapi_name() !== 'cli') {
print('Only via CLI, please.');
exit(1);
}
include __DIR__ . '/config.php';
$cr = ldap_connect($host, $port);
ldap_set_option($cr, LDAP_OPT_PROTOCOL_VERSION, 3);
$ok = ldap_bind($cr, $adn, $apwd);
if (!$ok) {
die(ldap_error($cr));
}
$ouName = 'Users';
$ouDN = 'ou=' . $ouName . ',' . $bdn;
//creates on OU
if (true) {
$entry = [];
$entry['objectclass'][] = 'top';
$entry['objectclass'][] = 'organizationalunit';
$entry['ou'] = $ouName;
$b = ldap_add($cr, $ouDN, $entry);
if (!$b) {
die(ldap_error($cr));
}
}
$users = ['alice'];
foreach ($users as $uid) {
$newDN = 'uid=' . $uid . ',' . $ouDN;
$fn = ucfirst($uid);
$sn = ucfirst(str_shuffle($uid)); // not so explicit but it's OK.
$entry = [];
$entry['cn'] = $fn . ' ' . $sn;
$entry['objectclass'][] = 'inetOrgPerson';
$entry['objectclass'][] = 'person';
$entry['sn'] = $sn;
$entry['userPassword'] = $uid;
$entry['displayName'] = $sn . ', ' . $fn;
$ok = ldap_add($cr, $newDN, $entry);
if ($ok) {
echo('created user ' . ': ' . $entry['cn'] . PHP_EOL);
} else {
die(ldap_error($cr));
}
}
+143 -135
View File
@@ -28,174 +28,182 @@ use OCA\user_ldap\lib\user\Manager;
class Test_User_Manager extends \Test\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');
$dbc = $this->getMock('\OCP\IDBConnection');
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');
$dbc = $this->getMock('\OCP\IDBConnection');
return array($access, $config, $filesys, $image, $log, $avaMgr, $dbc);
}
return array($access, $config, $filesys, $image, $log, $avaMgr, $dbc);
}
public function testGetByDNExisting() {
list($access, $config, $filesys, $image, $log, $avaMgr, $dbc) =
$this->getTestInstances();
public function testGetByDNExisting() {
list($access, $config, $filesys, $image, $log, $avaMgr, $dbc) =
$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, $dbc);
$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, $dbc) =
$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, $dbc);
$manager->setLdapAccess($access);
$user = $manager->get($inputDN);
$manager = new Manager($config, $filesys, $log, $avaMgr, $image, $dbc);
$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, $dbc) =
$this->getTestInstances();
public function testGetByEDirectoryDN() {
list($access, $config, $filesys, $image, $log, $avaMgr, $dbc) =
$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, $dbc);
$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, $dbc) =
$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, $dbc);
$manager->setLdapAccess($access);
$user = $manager->get($inputDN);
$manager = new Manager($config, $filesys, $log, $avaMgr, $image, $dbc);
$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, $dbc) =
$this->getTestInstances();
public function testGetByUidExisting() {
list($access, $config, $filesys, $image, $log, $avaMgr, $dbc) =
$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, $dbc);
$manager->setLdapAccess($access);
$user = $manager->get($inputDN);
$manager = new Manager($config, $filesys, $log, $avaMgr, $image, $dbc);
$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, $dbc) =
$this->getTestInstances();
public function testGetByUidNotExisting() {
list($access, $config, $filesys, $image, $log, $avaMgr, $dbc) =
$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(1))
->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, $dbc);
$manager->setLdapAccess($access);
$user = $manager->get($uid);
$manager = new Manager($config, $filesys, $log, $avaMgr, $image, $dbc);
$manager->setLdapAccess($access);
$user = $manager->get($inputDN);
$this->assertNull($user);
}
$this->assertNull($user);
}
public function testGetByUidExisting() {
list($access, $config, $filesys, $image, $log, $avaMgr, $dbc) =
$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, $dbc);
$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, $dbc) =
$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, $dbc);
$manager->setLdapAccess($access);
$user = $manager->get($uid);
$this->assertNull($user);
}
}
-1
View File
@@ -12,5 +12,4 @@
<types>
<authentication/>
</types>
<ocsid>166062</ocsid>
</info>
+1 -1
View File
@@ -1 +1 @@
1.1.0.1
1.1.0.2
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "ownCloud",
"version": "8.0 pre alpha",
"version": "8.1",
"homepage": "https://www.owncloud.org",
"license": "AGPL",
"private": true,
+117 -106
View File
@@ -81,7 +81,7 @@ $CONFIG = array(
/**
* Where user files are stored; this defaults to ``data/`` in the ownCloud
* directory. The SQLite database is also stored here, when you use SQLite.
* (SQLite is available only in ownCloud Community Edition)
* (SQLite is not available in ownCloud Enterprise Edition)
*/
'datadirectory' => '/var/www/owncloud/data',
@@ -96,7 +96,7 @@ $CONFIG = array(
* ``supportedDatabases``
*
* Available:
* - sqlite (SQLite3 - Community Edition Only)
* - sqlite (SQLite3 - Not in Enterprise Edition)
* - mysql (MySQL/MariaDB)
* - pgsql (PostgreSQL)
* - oci (Oracle - Enterprise Edition Only)
@@ -587,7 +587,6 @@ $CONFIG = array(
/**
* When enabled, admins may install apps from the ownCloud app store.
* The app store is disabled by default for ownCloud Enterprise Edition
*/
'appstoreenabled' => true,
@@ -790,69 +789,38 @@ $CONFIG = array(
'config' => '/absolute/location/of/openssl.cnf',
),
/**
* Miscellaneous
*/
/**
* Blacklist a specific file or files and disallow the upload of files
* with this name. ``.htaccess`` is blocked by default.
* WARNING: USE THIS ONLY IF YOU KNOW WHAT YOU ARE DOING.
*/
'blacklisted_files' => array('.htaccess'),
/**
* Define a default folder for shared files and folders other than root.
*/
'share_folder' => '/',
/**
* If you are applying a theme to ownCloud, enter the name of the theme here.
* The default location for themes is ``owncloud/themes/``.
*/
'theme' => '',
/**
* The default cipher for encrypting files. Currently AES-128-CFB and
* AES-256-CFB are supported.
*/
'cipher' => 'AES-256-CFB',
/**
* The minimum ownCloud desktop client version that will be allowed to sync with
* this server instance. All connections made from earlier clients will be denied
* by the server. Defaults to the minimum officially supported ownCloud version at
* the time of release of this server version.
*
* When changing this, note that older unsupported versions of the ownCloud desktop
* client may not function as expected, and could lead to permanent data loss for
* clients or other unexpected results.
*/
'minimum.supported.desktop.version' => '1.7.0',
/**
* Memory caching backend configuration
*
* Available cache backends:
* - \OC\Memcache\APC Alternative PHP Cache backend
* - \OC\Memcache\APCu APC user backend
* - \OC\Memcache\ArrayCache In-memory array-based backend (not recommended)
* - \OC\Memcache\Memcached Memcached backend
* - \OC\Memcache\Redis Redis backend
* - \OC\Memcache\XCache XCache backend
*
* * ``\OC\Memcache\APC`` Alternative PHP Cache backend
* * ``\OC\Memcache\APCu`` APC user backend
* * ``\OC\Memcache\ArrayCache`` In-memory array-based backend (not recommended)
* * ``\OC\Memcache\Memcached`` Memcached backend
* * ``\OC\Memcache\Redis`` Redis backend
* * ``\OC\Memcache\XCache`` XCache backend
*
* Advice on choosing between the various backends:
*
* * APCu should be easiest to install. Almost all distributions have packages.
* Use this for single user environment for all caches.
* * Use Redis or Memcached for distributed environments.
* For the local cache (you can configure two) take APCu.
*/
/**
* Memory caching backend for locally stored data
* Used for host-specific data, e.g. file paths
*
* * Used for host-specific data, e.g. file paths
*/
'memcache.local' => '\OC\Memcache\APCu',
/**
* Memory caching backend for distributed data
* Used for installation-specific data, e.g. database caching
* If unset, defaults to the value of memcache.local
*
* * Used for installation-specific data, e.g. database caching
* * If unset, defaults to the value of memcache.local
*/
'memcache.distributed' => '\OC\Memcache\Memcached',
@@ -887,56 +855,11 @@ $CONFIG = array(
'cache_path' => '',
/**
* EXPERIMENTAL: option whether to include external storage in quota
* calculation, defaults to false.
* Using Object Store with ownCloud
*/
'quota_include_external_storage' => false,
/**
* Specifies how often the filesystem is checked for changes made outside
* ownCloud.
*
* 0 -> Never check the filesystem for outside changes, provides a performance
* increase when it's certain that no changes are made directly to the
* filesystem
*
* 1 -> Check each file or folder at most once per request, recommended for
* general use if outside changes might happen.
*
* 2 -> Check every time the filesystem is used, causes a performance hit when
* using external storages, not recommended for regular use.
*/
'filesystem_check_changes' => 1,
/**
* All css and js files will be served by the web server statically in one js
* file and one css file if this is set to ``true``.
*/
'asset-pipeline.enabled' => false,
/**
* The parent of the directory where css and js assets will be stored if
* piplelining is enabled; this defaults to the ownCloud directory. The assets
* will be stored in a subdirectory of this directory named 'assets'. The
* server *must* be configured to serve that directory as $WEBROOT/assets.
* You will only likely need to change this if the main ownCloud directory
* is not writeable by the web server in your configuration.
*/
'assetdirectory' => '/var/www/owncloud',
/**
* Where ``mount.json`` file should be stored, defaults to ``data/mount.json``
*/
'mount_file' => 'data/mount.json',
/**
* When ``true``, prevent ownCloud from changing the cache due to changes in the
* filesystem for all storage.
*/
'filesystem_cache_readonly' => false,
/**
* The example below shows how to configure ownCloud to store all files in a
* This example shows how to configure ownCloud to store all files in a
* swift object storage.
*
* It is important to note that ownCloud in object store mode will expect
@@ -980,7 +903,7 @@ $CONFIG = array(
* Database types that are supported for installation.
*
* Available:
* - sqlite (SQLite3 - Community Edition Only)
* - sqlite (SQLite3 - Not in Enterprise Edition)
* - mysql (MySQL)
* - pgsql (PostgreSQL)
* - oci (Oracle - Enterprise Edition Only)
@@ -996,6 +919,91 @@ $CONFIG = array(
* All other config options
*/
/**
* Blacklist a specific file or files and disallow the upload of files
* with this name. ``.htaccess`` is blocked by default.
* WARNING: USE THIS ONLY IF YOU KNOW WHAT YOU ARE DOING.
*/
'blacklisted_files' => array('.htaccess'),
/**
* Define a default folder for shared files and folders other than root.
*/
'share_folder' => '/',
/**
* If you are applying a theme to ownCloud, enter the name of the theme here.
* The default location for themes is ``owncloud/themes/``.
*/
'theme' => '',
/**
* The default cipher for encrypting files. Currently AES-128-CFB and
* AES-256-CFB are supported.
*/
'cipher' => 'AES-256-CFB',
/**
* The minimum ownCloud desktop client version that will be allowed to sync with
* this server instance. All connections made from earlier clients will be denied
* by the server. Defaults to the minimum officially supported ownCloud version at
* the time of release of this server version.
*
* When changing this, note that older unsupported versions of the ownCloud desktop
* client may not function as expected, and could lead to permanent data loss for
* clients or other unexpected results.
*/
'minimum.supported.desktop.version' => '1.7.0',
/**
* EXPERIMENTAL: option whether to include external storage in quota
* calculation, defaults to false.
*/
'quota_include_external_storage' => false,
/**
* Specifies how often the filesystem is checked for changes made outside
* ownCloud.
*
* 0 -> Never check the filesystem for outside changes, provides a performance
* increase when it's certain that no changes are made directly to the
* filesystem
*
* 1 -> Check each file or folder at most once per request, recommended for
* general use if outside changes might happen.
*
* 2 -> Check every time the filesystem is used, causes a performance hit when
* using external storages, not recommended for regular use.
*/
'filesystem_check_changes' => 1,
/**
* All css and js files will be served by the web server statically in one js
* file and one css file if this is set to ``true``. This improves performance.
*/
'asset-pipeline.enabled' => false,
/**
* The parent of the directory where css and js assets will be stored if
* piplelining is enabled; this defaults to the ownCloud directory. The assets
* will be stored in a subdirectory of this directory named 'assets'. The
* server *must* be configured to serve that directory as $WEBROOT/assets.
* You will only likely need to change this if the main ownCloud directory
* is not writeable by the web server in your configuration.
*/
'assetdirectory' => '/var/www/owncloud',
/**
* Where ``mount.json`` file should be stored, defaults to ``data/mount.json``
*/
'mount_file' => 'data/mount.json',
/**
* When ``true``, prevent ownCloud from changing the cache due to changes in the
* filesystem for all storage.
*/
'filesystem_cache_readonly' => false,
/**
* Secret used by ownCloud for various purposes, e.g. to encrypt data. If you
* lose this string there will be data corruption.
@@ -1017,9 +1025,8 @@ $CONFIG = array(
* max file size for animating gifs on public-sharing-site.
* If the gif is bigger, it'll show a static preview
*
* Value represents the maximum filesize in megabytes
* Default is 10
* Set to -1 for no limit
* Value represents the maximum filesize in megabytes. Default is ``10``. Set to
* ``-1`` for no limit.
*/
'max_filesize_animated_gifs_public_sharing' => 10,
@@ -1030,7 +1037,9 @@ $CONFIG = array(
*
* Prevents concurrent processes to access the same files
* at the same time. Can help prevent side effects that would
* be caused by concurrent operations.
* be caused by concurrent operations. Mainly relevant for
* very large installations with many users working with
* shared files.
*
* WARNING: BETA quality
*/
@@ -1038,7 +1047,9 @@ $CONFIG = array(
/**
* Memory caching backend for file locking
* Because most memcache backends can clean values without warning using redis is recommended
*
* Because most memcache backends can clean values without warning using redis
* is highly recommended to *avoid data loss*.
*/
'memcache.locking' => '\\OC\\Memcache\\Redis',
+1 -1
View File
@@ -353,7 +353,7 @@ if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSo
// allow user to add unknown remote addresses for server-to-server share
$backend = \OCP\Share::getBackend((string)$_GET['itemType']);
if ($backend->isShareTypeAllowed(\OCP\Share::SHARE_TYPE_REMOTE)) {
if (substr_count((string)$_GET['search'], '@') === 1) {
if (substr_count((string)$_GET['search'], '@') >= 1) {
$shareWith[] = array(
'label' => (string)$_GET['search'],
'value' => array(
+9
View File
@@ -169,6 +169,15 @@ class Upgrade extends Command {
$output->writeln("<error>$message</error>");
});
if(OutputInterface::VERBOSITY_NORMAL < $output->getVerbosity()) {
$updater->listen('\OC\Updater', 'repairInfo', function ($message) use($output) {
$output->writeln('<info>Repair info: ' . $message . '</info>');
});
$updater->listen('\OC\Updater', 'repairStep', function ($message) use($output) {
$output->writeln('<info>Repair step: ' . $message . '</info>');
});
}
$success = $updater->upgrade();
$this->postUpgradeCheck($input, $output);
+1 -1
View File
@@ -410,7 +410,6 @@
position: relative;
height: 100%;
overflow-y: auto;
z-index: 100;
}
#app-content-wrapper {
@@ -556,3 +555,4 @@ em {
z-index:500;
padding:16px;
}
-1
View File
@@ -161,7 +161,6 @@ a.showCruds:hover,a.unshare:hover {
max-height:103px;
overflow-y:auto;
overflow-x:hidden;
z-index: 101 !important;
}
.notCreatable {
+1 -1
View File
@@ -58,7 +58,7 @@
if (!area.is(':animated')) {
// button toggles the area
if (button === event.target.closest('[data-apps-slide-toggle]')) {
if ($(button).is($(event.target).closest('[data-apps-slide-toggle]'))) {
if (area.is(':visible')) {
hideArea();
} else {
+8 -2
View File
@@ -730,8 +730,14 @@ class OC {
// NOTE: This will be replaced to use OCP
$userSession = self::$server->getUserSession();
$userSession->listen('\OC\User', 'postLogin', function () {
$cache = new \OC\Cache\File();
$cache->gc();
try {
$cache = new \OC\Cache\File();
$cache->gc();
} catch (\Exception $e) {
// a GC exception should not prevent users from using OC,
// so log the exception
\OC::$server->getLogger()->warning('Exception when running cache gc: ' . $e->getMessage(), array('app' => 'core'));
}
});
}
}
+27 -16
View File
@@ -659,6 +659,12 @@ class OC_App {
if (is_array($data)) {
$data = OC_App::parseAppInfo($data);
}
if(isset($data['ocsid'])) {
$storedId = \OC::$server->getConfig()->getAppValue($appId, 'ocsid');
if($storedId !== '' && $storedId !== $data['ocsid']) {
$data['ocsid'] = $storedId;
}
}
self::$appInfo[$appId] = $data;
@@ -1162,9 +1168,7 @@ class OC_App {
OC_DB::updateDbFromStructure(self::getAppPath($appId) . '/appinfo/database.xml');
}
unset(self::$appVersion[$appId]);
if (!self::isEnabled($appId)) {
return false;
}
// run upgrade code
if (file_exists(self::getAppPath($appId) . '/appinfo/update.php')) {
self::loadApp($appId, false);
include self::getAppPath($appId) . '/appinfo/update.php';
@@ -1174,6 +1178,8 @@ class OC_App {
$appData = self::getAppInfo($appId);
if (array_key_exists('ocsid', $appData)) {
OC_Appconfig::setValue($appId, 'ocsid', $appData['ocsid']);
} elseif(OC_Appconfig::getValue($appId, 'ocsid', null) !== null) {
OC_Appconfig::deleteKey($appId, 'ocsid');
}
foreach ($appData['remote'] as $name => $path) {
OCP\CONFIG::setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
@@ -1223,22 +1229,27 @@ class OC_App {
// just modify the description if it is available
// otherwise this will create a $data element with an empty 'description'
if (isset($data['description'])) {
// sometimes the description contains line breaks and they are then also
// shown in this way in the app management which isn't wanted as HTML
// manages line breaks itself
if (is_string($data['description'])) {
// sometimes the description contains line breaks and they are then also
// shown in this way in the app management which isn't wanted as HTML
// manages line breaks itself
// first of all we split on empty lines
$paragraphs = preg_split("!\n[[:space:]]*\n!m", $data['description']);
// first of all we split on empty lines
$paragraphs = preg_split("!\n[[:space:]]*\n!mu", $data['description']);
$result = [];
foreach ($paragraphs as $value) {
// replace multiple whitespace (tabs, space, newlines) inside a paragraph
// with a single space - also trims whitespace
$result[] = trim(preg_replace('![[:space:]]+!m', ' ', $value));
$result = [];
foreach ($paragraphs as $value) {
// replace multiple whitespace (tabs, space, newlines) inside a paragraph
// with a single space - also trims whitespace
$result[] = trim(preg_replace('![[:space:]]+!mu', ' ', $value));
}
// join the single paragraphs with a empty line in between
$data['description'] = implode("\n\n", $result);
} else {
$data['description'] = '';
}
// join the single paragraphs with a empty line in between
$data['description'] = implode("\n\n", $result);
}
return $data;
+2 -1
View File
@@ -478,7 +478,8 @@ class Request implements \ArrayAccess, \Countable, IRequest {
*/
private function isOverwriteCondition($type = '') {
$regex = '/' . $this->config->getSystemValue('overwritecondaddr', '') . '/';
return $regex === '//' || preg_match($regex, $this->server['REMOTE_ADDR']) === 1
$remoteAddr = isset($this->server['REMOTE_ADDR']) ? $this->server['REMOTE_ADDR'] : '';
return $regex === '//' || preg_match($regex, $remoteAddr) === 1
|| $type !== 'protocol';
}
+10 -3
View File
@@ -177,9 +177,16 @@ class File implements ICache {
}
while (($file = readdir($dh)) !== false) {
if ($file != '.' and $file != '..') {
$mtime = $storage->filemtime('/' . $file);
if ($mtime < $now) {
$storage->unlink('/' . $file);
try {
$mtime = $storage->filemtime('/' . $file);
if ($mtime < $now) {
$storage->unlink('/' . $file);
}
} catch (\OCP\Lock\LockedException $e) {
// ignore locked chunks
\OC::$server->getLogger()->debug('Could not cleanup locked chunk "' . $file . '"', array('app' => 'core'));
} catch (\OCP\Files\LockNotAcquiredException $e) {
\OC::$server->getLogger()->debug('Could not cleanup locked chunk "' . $file . '"', array('app' => 'core'));
}
}
}
+29 -15
View File
@@ -30,7 +30,12 @@
*/
namespace OC\Connector\Sabre;
class Auth extends \Sabre\DAV\Auth\Backend\AbstractBasic {
use Exception;
use Sabre\DAV\Auth\Backend\AbstractBasic;
use Sabre\DAV\Exception\NotAuthenticated;
use Sabre\DAV\Exception\ServiceUnavailable;
class Auth extends AbstractBasic {
const DAV_AUTHENTICATED = 'AUTHENTICATED_TO_DAV_BACKEND';
/**
@@ -69,7 +74,7 @@ class Auth extends \Sabre\DAV\Auth\Backend\AbstractBasic {
} else {
\OC_Util::setUpFS(); //login hooks may need early access to the filesystem
if(\OC_User::login($username, $password)) {
// make sure we use owncloud's internal username here
// make sure we use ownCloud's internal username here
// and not the HTTP auth supplied one, see issue #14048
$ocUser = \OC_User::getUser();
\OC_Util::setUpFS($ocUser);
@@ -99,21 +104,30 @@ class Auth extends \Sabre\DAV\Auth\Backend\AbstractBasic {
}
/**
* Override function here. We want to cache authentication cookies
* in the syncing client to avoid HTTP-401 roundtrips.
* If the sync client supplies the cookies, then OC_User::isLoggedIn()
* will return true and we can see this WebDAV request as already authenticated,
* even if there are no HTTP Basic Auth headers.
* In other case, just fallback to the parent implementation.
*
* @param \Sabre\DAV\Server $server
* @param $realm
* @return bool
*/
* Override function here. We want to cache authentication cookies
* in the syncing client to avoid HTTP-401 roundtrips.
* If the sync client supplies the cookies, then OC_User::isLoggedIn()
* will return true and we can see this WebDAV request as already authenticated,
* even if there are no HTTP Basic Auth headers.
* In other case, just fallback to the parent implementation.
*
* @param \Sabre\DAV\Server $server
* @param string $realm
* @return bool
* @throws ServiceUnavailable
*/
public function authenticate(\Sabre\DAV\Server $server, $realm) {
$result = $this->auth($server, $realm);
return $result;
try {
$result = $this->auth($server, $realm);
return $result;
} catch (NotAuthenticated $e) {
throw $e;
} catch (Exception $e) {
$class = get_class($e);
$msg = $e->getMessage();
throw new ServiceUnavailable("$class: $msg");
}
}
/**
+8 -4
View File
@@ -146,7 +146,9 @@ class File extends Node implements IFile {
}
} catch (\Exception $e) {
$partStorage->unlink($internalPartPath);
if ($needsPartFile) {
$partStorage->unlink($internalPartPath);
}
$this->convertToSabreException($e);
}
@@ -176,7 +178,9 @@ class File extends Node implements IFile {
try {
$this->fileView->changeLock($this->path, ILockingProvider::LOCK_EXCLUSIVE);
} catch (LockedException $e) {
$partStorage->unlink($internalPartPath);
if ($needsPartFile) {
$partStorage->unlink($internalPartPath);
}
throw new FileLocked($e->getMessage(), $e->getCode(), $e);
}
@@ -189,7 +193,6 @@ class File extends Node implements IFile {
}
if (!$run || $renameOkay === false || $fileExists === false) {
\OC_Log::write('webdav', 'renaming part file to final file failed', \OC_Log::ERROR);
$partStorage->unlink($internalPartPath);
throw new Exception('Could not rename part file to final file');
}
} catch (\Exception $e) {
@@ -350,6 +353,7 @@ class File extends Node implements IFile {
if ($chunk_handler->isComplete()) {
list($storage,) = $this->fileView->resolvePath($path);
$needsPartFile = $this->needsPartFile($storage);
$partFile = null;
try {
$targetPath = $path . '/' . $info['name'];
@@ -388,7 +392,7 @@ class File extends Node implements IFile {
$info = $this->fileView->getFileInfo($targetPath);
return $info->getEtag();
} catch (\Exception $e) {
if ($partFile) {
if ($partFile !== null) {
$this->fileView->unlink($partFile);
}
$this->convertToSabreException($e);
-29
View File
@@ -127,35 +127,6 @@ class Util {
return $id;
}
/**
* read header into array
*
* @param string $header
* @return array
*/
public function readHeader($header) {
$result = array();
if (substr($header, 0, strlen(self::HEADER_START)) === self::HEADER_START) {
$endAt = strpos($header, self::HEADER_END);
if ($endAt !== false) {
$header = substr($header, 0, $endAt + strlen(self::HEADER_END));
// +1 to not start with an ':' which would result in empty element at the beginning
$exploded = explode(':', substr($header, strlen(self::HEADER_START)+1));
$element = array_shift($exploded);
while ($element !== self::HEADER_END) {
$result[$element] = array_shift($exploded);
$element = array_shift($exploded);
}
}
}
return $result;
}
/**
* create header for encrypted file
*
@@ -57,8 +57,14 @@ class MountProviderCollection implements IMountProviderCollection, Emitter {
*/
public function getMountsForUser(IUser $user) {
$loader = $this->loader;
return array_reduce($this->providers, function ($mounts, IMountProvider $provider) use ($user, $loader) {
return array_merge($mounts, $provider->getMountsForUser($user, $loader));
$mounts = array_map(function (IMountProvider $provider) use ($user, $loader) {
return $provider->getMountsForUser($user, $loader);
}, $this->providers);
$mounts = array_filter($mounts, function ($result) {
return is_array($result);
});
return array_reduce($mounts, function (array $mounts, array $providerMounts) {
return array_merge($mounts, $providerMounts);
}, array());
}
+32 -18
View File
@@ -219,9 +219,9 @@ class DAV extends Common {
$this->statCache->set($path, false);
return false;
}
$this->convertException($e);
$this->convertException($e, $path);
} catch (\Exception $e) {
$this->convertException($e);
$this->convertException($e, $path);
}
return false;
}
@@ -286,9 +286,9 @@ class DAV extends Common {
if ($e->getHttpStatus() === 404) {
return false;
}
$this->convertException($e);
$this->convertException($e, $path);
} catch (\Exception $e) {
$this->convertException($e);
$this->convertException($e, $path);
}
return false;
}
@@ -311,9 +311,9 @@ class DAV extends Common {
if ($e->getHttpStatus() === 404) {
return false;
}
$this->convertException($e);
$this->convertException($e, $path);
} catch (\Exception $e) {
$this->convertException($e);
$this->convertException($e, $path);
}
return false;
}
@@ -363,6 +363,9 @@ class DAV extends Common {
$statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
if ($statusCode !== 200) {
Util::writeLog("webdav client", 'curl GET ' . curl_getinfo($curl, CURLINFO_EFFECTIVE_URL) . ' returned status code ' . $statusCode, Util::ERROR);
if ($statusCode === 423) {
throw new \OCP\Lock\LockedException($path);
}
}
curl_close($curl);
rewind($fp);
@@ -446,10 +449,10 @@ class DAV extends Common {
if ($e->getHttpStatus() === 501) {
return false;
}
$this->convertException($e);
$this->convertException($e, $path);
return false;
} catch (\Exception $e) {
$this->convertException($e);
$this->convertException($e, $path);
return false;
}
} else {
@@ -502,6 +505,9 @@ class DAV extends Common {
$statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
if ($statusCode !== 200) {
Util::writeLog("webdav client", 'curl GET ' . curl_getinfo($curl, CURLINFO_EFFECTIVE_URL) . ' returned status code ' . $statusCode, Util::ERROR);
if ($statusCode === 423) {
throw new \OCP\Lock\LockedException($path);
}
}
curl_close($curl);
fclose($source);
@@ -564,9 +570,9 @@ class DAV extends Common {
if ($e->getHttpStatus() === 404) {
return array();
}
$this->convertException($e);
$this->convertException($e, $path);
} catch (\Exception $e) {
$this->convertException($e);
$this->convertException($e, $path);
}
return array();
}
@@ -591,9 +597,9 @@ class DAV extends Common {
if ($e->getHttpStatus() === 404) {
return false;
}
$this->convertException($e);
$this->convertException($e, $path);
} catch (\Exception $e) {
$this->convertException($e);
$this->convertException($e, $path);
}
return false;
}
@@ -643,9 +649,9 @@ class DAV extends Common {
return false;
}
$this->convertException($e);
$this->convertException($e, $path);
} catch (\Exception $e) {
$this->convertException($e);
$this->convertException($e, $path);
}
return false;
}
@@ -760,13 +766,17 @@ class DAV extends Common {
return $remoteMtime > $time;
}
} catch (ClientHttpException $e) {
if ($e->getHttpStatus() === 404) {
if ($e->getHttpStatus() === 404 || $e->getHttpStatus() === 405) {
if ($path === '') {
// if root is gone it means the storage is not available
throw new StorageNotAvailableException(get_class($e).': '.$e->getMessage());
}
return false;
}
$this->convertException($e);
$this->convertException($e, $path);
return false;
} catch (\Exception $e) {
$this->convertException($e);
$this->convertException($e, $path);
return false;
}
}
@@ -778,15 +788,19 @@ class DAV extends Common {
* or do nothing.
*
* @param Exception $e sabre exception
* @param string $path optional path from the operation
*
* @throws StorageInvalidException if the storage is invalid, for example
* when the authentication expired or is invalid
* @throws StorageNotAvailableException if the storage is not available,
* which might be temporary
*/
private function convertException(Exception $e) {
private function convertException(Exception $e, $path = '') {
Util::writeLog('files_external', $e->getMessage(), Util::ERROR);
if ($e instanceof ClientHttpException) {
if ($e->getHttpStatus() === 423) {
throw new \OCP\Lock\LockedException($path);
}
if ($e->getHttpStatus() === 401) {
// either password was changed or was invalid all along
throw new StorageInvalidException(get_class($e).': '.$e->getMessage());
@@ -31,6 +31,7 @@ use OC\Encryption\Util;
use OC\Files\Filesystem;
use OC\Files\Mount\Manager;
use OC\Files\Storage\LocalTempFileTrait;
use OCP\Encryption\Exceptions\GenericEncryptionException;
use OCP\Encryption\IFile;
use OCP\Encryption\IManager;
use OCP\Encryption\Keys\IStorage;
@@ -174,9 +175,8 @@ class Encryption extends Wrapper {
public function file_get_contents($path) {
$encryptionModule = $this->getEncryptionModule($path);
$info = $this->getCache()->get($path);
if ($encryptionModule || $info['encrypted'] === true) {
if ($encryptionModule) {
$handle = $this->fopen($path, "r");
if (!$handle) {
return false;
@@ -338,14 +338,15 @@ class Encryption extends Wrapper {
* @param string $path
* @param string $mode
* @return resource
* @throws GenericEncryptionException
* @throws ModuleDoesNotExistsException
*/
public function fopen($path, $mode) {
$encryptionEnabled = $this->encryptionManager->isEnabled();
$shouldEncrypt = false;
$encryptionModule = null;
$rawHeader = $this->getHeader($path);
$header = $this->util->readHeader($rawHeader);
$header = $this->getHeader($path);
$fullPath = $this->getFullPath($path);
$encryptionModuleId = $this->util->getEncryptionModuleId($header);
@@ -380,6 +381,10 @@ class Encryption extends Wrapper {
|| $mode === 'wb'
|| $mode === 'wb+'
) {
// don't overwrite encrypted files if encyption is not enabled
if ($targetIsEncrypted && $encryptionEnabled === false) {
throw new GenericEncryptionException('Tried to access encrypted file but encryption is not enabled');
}
if ($encryptionEnabled) {
// if $encryptionModuleId is empty, the default module will be used
$encryptionModule = $this->encryptionManager->getEncryptionModule($encryptionModuleId);
@@ -398,6 +403,7 @@ class Encryption extends Wrapper {
// OC_DEFAULT_MODULE to read the file
$encryptionModule = $this->encryptionManager->getEncryptionModule('OC_DEFAULT_MODULE');
$shouldEncrypt = true;
$targetIsEncrypted = true;
}
}
} catch (ModuleDoesNotExistsException $e) {
@@ -416,7 +422,7 @@ class Encryption extends Wrapper {
$source = $this->storage->fopen($path, $mode);
$handle = \OC\Files\Stream\Encryption::wrap($source, $path, $fullPath, $header,
$this->uid, $encryptionModule, $this->storage, $this, $this->util, $this->fileHelper, $mode,
$size, $unencryptedSize, strlen($rawHeader));
$size, $unencryptedSize, $this->getHeaderSize($path));
return $handle;
}
@@ -605,6 +611,72 @@ class Encryption extends Wrapper {
return Filesystem::normalizePath($this->mountPoint . '/' . $path);
}
/**
* read first block of encrypted file, typically this will contain the
* encryption header
*
* @param string $path
* @return string
*/
protected function readFirstBlock($path) {
$firstBlock = '';
if ($this->storage->file_exists($path)) {
$handle = $this->storage->fopen($path, 'r');
$firstBlock = fread($handle, $this->util->getHeaderSize());
fclose($handle);
}
return $firstBlock;
}
/**
* return header size of given file
*
* @param string $path
* @return int
*/
protected function getHeaderSize($path) {
$headerSize = 0;
$realFile = $this->util->stripPartialFileExtension($path);
if ($this->storage->file_exists($realFile)) {
$path = $realFile;
}
$firstBlock = $this->readFirstBlock($path);
if (substr($firstBlock, 0, strlen(Util::HEADER_START)) === Util::HEADER_START) {
$headerSize = strlen($firstBlock);
}
return $headerSize;
}
/**
* parse raw header to array
*
* @param string $rawHeader
* @return array
*/
protected function parseRawHeader($rawHeader) {
$result = array();
if (substr($rawHeader, 0, strlen(Util::HEADER_START)) === Util::HEADER_START) {
$header = $rawHeader;
$endAt = strpos($header, Util::HEADER_END);
if ($endAt !== false) {
$header = substr($header, 0, $endAt + strlen(Util::HEADER_END));
// +1 to not start with an ':' which would result in empty element at the beginning
$exploded = explode(':', substr($header, strlen(Util::HEADER_START)+1));
$element = array_shift($exploded);
while ($element !== Util::HEADER_END) {
$result[$element] = array_shift($exploded);
$element = array_shift($exploded);
}
}
}
return $result;
}
/**
* read header from file
*
@@ -612,21 +684,29 @@ class Encryption extends Wrapper {
* @return array
*/
protected function getHeader($path) {
$header = '';
$realFile = $this->util->stripPartialFileExtension($path);
if ($this->storage->file_exists($realFile)) {
$path = $realFile;
}
if ($this->storage->file_exists($path)) {
$handle = $this->storage->fopen($path, 'r');
$firstBlock = fread($handle, $this->util->getHeaderSize());
fclose($handle);
if (substr($firstBlock, 0, strlen(Util::HEADER_START)) === Util::HEADER_START) {
$header = $firstBlock;
$firstBlock = $this->readFirstBlock($path);
$result = $this->parseRawHeader($firstBlock);
// if the header doesn't contain a encryption module we check if it is a
// legacy file. If true, we add the default encryption module
if (!isset($result[Util::HEADER_ENCRYPTION_MODULE_KEY])) {
if (!empty($result)) {
$result[Util::HEADER_ENCRYPTION_MODULE_KEY] = 'OC_DEFAULT_MODULE';
} else {
// if the header was empty we have to check first if it is a encrypted file at all
$info = $this->getCache()->get($path);
if (isset($info['encrypted']) && $info['encrypted'] === true) {
$result[Util::HEADER_ENCRYPTION_MODULE_KEY] = 'OC_DEFAULT_MODULE';
}
}
}
return $header;
return $result;
}
/**
@@ -639,8 +719,7 @@ class Encryption extends Wrapper {
*/
protected function getEncryptionModule($path) {
$encryptionModule = null;
$rawHeader = $this->getHeader($path);
$header = $this->util->readHeader($rawHeader);
$header = $this->getHeader($path);
$encryptionModuleId = $this->util->getEncryptionModuleId($header);
if (!empty($encryptionModuleId)) {
try {
@@ -675,4 +754,5 @@ class Encryption extends Wrapper {
return false;
}
}
+2 -3
View File
@@ -76,11 +76,10 @@ class Scanner extends PublicEmitter {
//TODO: move to the node based fileapi once that's done
\OC_Util::tearDownFS();
\OC_Util::setupFS($this->user);
$absolutePath = Filesystem::getView()->getAbsolutePath($dir);
$mountManager = Filesystem::getMountManager();
$mounts = $mountManager->findIn($absolutePath);
$mounts[] = $mountManager->find($absolutePath);
$mounts = $mountManager->findIn($dir);
$mounts[] = $mountManager->find($dir);
$mounts = array_reverse($mounts); //start with the mount of $dir
return $mounts;
+4 -2
View File
@@ -42,6 +42,7 @@ use OC\Repair\RepairConfig;
use OC\Repair\RepairLegacyStorages;
use OC\Repair\RepairMimeTypes;
use OC\Repair\SearchLuceneTables;
use OC\Repair\UpdateOutdatedOcsIds;
class Repair extends BasicEmitter {
/**
@@ -100,7 +101,7 @@ class Repair extends BasicEmitter {
* @return array of RepairStep instances
*/
public static function getRepairSteps() {
return array(
return [
new RepairMimeTypes(),
new RepairLegacyStorages(\OC::$server->getConfig(), \OC_DB::getConnection()),
new RepairConfig(),
@@ -109,7 +110,8 @@ class Repair extends BasicEmitter {
new CleanTags(\OC_DB::getConnection()),
new DropOldTables(\OC_DB::getConnection()),
new DropOldJobs(\OC::$server->getJobList()),
);
new UpdateOutdatedOcsIds(\OC::$server->getConfig()),
];
}
/**
+2
View File
@@ -150,6 +150,8 @@ class Server extends SimpleContainer implements IServerContainer {
});
$groupManager->listen('\OC\Group', 'postAddUser', function (\OC\Group\Group $group, \OC\User\User $user) {
\OC_Hook::emit('OC_Group', 'post_addToGroup', array('uid' => $user->getUID(), 'gid' => $group->getGID()));
//Minimal fix to keep it backward compatible TODO: clean up all the GroupManager hooks
\OC_Hook::emit('OC_User', 'post_addToGroup', array('uid' => $user->getUID(), 'gid' => $group->getGID()));
});
return $groupManager;
});
+2 -2
View File
@@ -63,12 +63,12 @@ class Hooks extends \OC\Share\Constants {
$itemTarget = $sourceExists['item_target'];
} else {
$itemTarget = Helper::generateTarget($item['item_type'], $item['item_source'], self::SHARE_TYPE_USER, $arguments['uid'],
$item['owner'], null, $item['parent']);
$item['uid_owner'], null, $item['parent']);
// do we also need a file target
if ($item['item_type'] === 'file' || $item['item_type'] === 'folder') {
$fileTarget = Helper::generateTarget('file', $item['file_target'], self::SHARE_TYPE_USER, $arguments['uid'],
$item['owner'], null, $item['parent']);
$item['uid_owner'], null, $item['parent']);
} else {
$fileTarget = null;
}
+28 -10
View File
@@ -142,15 +142,25 @@ class Share extends Constants {
while ($source !== -1) {
// Fetch all shares with another user
$query = \OC_DB::prepare(
'SELECT `share_with`, `file_source`, `file_target`
if (!$returnUserPaths) {
$query = \OC_DB::prepare(
'SELECT `share_with`, `file_source`, `file_target`
FROM
`*PREFIX*share`
WHERE
`item_source` = ? AND `share_type` = ? AND `item_type` IN (\'file\', \'folder\')'
);
$result = $query->execute(array($source, self::SHARE_TYPE_USER));
} else {
$query = \OC_DB::prepare(
'SELECT `share_with`, `file_source`, `file_target`
FROM
`*PREFIX*share`
WHERE
`item_source` = ? AND `share_type` = ? AND `item_type` IN (\'file\', \'folder\')'
);
$result = $query->execute(array($source, self::SHARE_TYPE_USER));
`item_source` = ? AND `share_type` IN (?, ?) AND `item_type` IN (\'file\', \'folder\')'
);
$result = $query->execute(array($source, self::SHARE_TYPE_USER, self::$shareTypeGroupUserUnique));
}
if (\OCP\DB::isError($result)) {
\OCP\Util::writeLog('OCP\Share', \OC_DB::getErrorMessage(), \OC_Log::ERROR);
@@ -182,7 +192,12 @@ class Share extends Constants {
$shares = array_merge($shares, $usersInGroup);
if ($returnUserPaths) {
foreach ($usersInGroup as $user) {
$fileTargets[(int) $row['file_source']][$user] = $row;
if (!isset($fileTargets[(int) $row['file_source']][$user])) {
// When the user already has an entry for this file source
// the file is either shared directly with him as well, or
// he has an exception entry (because of naming conflict).
$fileTargets[(int) $row['file_source']][$user] = $row;
}
}
}
}
@@ -238,9 +253,6 @@ class Share extends Constants {
// Include owner in list of users, if requested
if ($includeOwner) {
$shares[] = $ownerUser;
if ($returnUserPaths) {
$sharePaths[$ownerUser] = $path;
}
}
if ($returnUserPaths) {
@@ -268,6 +280,12 @@ class Share extends Constants {
}
}
if ($includeOwner) {
$sharePaths[$ownerUser] = $path;
} else {
unset($sharePaths[$ownerUser]);
}
return $sharePaths;
}
+6
View File
@@ -239,6 +239,12 @@ class Updater extends BasicEmitter {
$repair->listen('\OC\Repair', 'error', function ($description) {
$this->emit('\OC\Updater', 'repairError', array($description));
});
$repair->listen('\OC\Repair', 'info', function ($description) {
$this->emit('\OC\Updater', 'repairInfo', array($description));
});
$repair->listen('\OC\Repair', 'step', function ($description) {
$this->emit('\OC\Updater', 'repairStep', array($description));
});
}
/**
+1
View File
@@ -60,6 +60,7 @@ class Collation extends BasicEmitter implements \OC\RepairStep {
$tables = $this->getAllNonUTF8BinTables($this->connection);
foreach ($tables as $table) {
$this->emit('\OC\Repair', 'info', array("Change collation for $table ..."));
$query = $this->connection->prepare('ALTER TABLE `' . $table . '` CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin;');
$query->execute();
}
+108
View File
@@ -0,0 +1,108 @@
<?php
/**
* @author Lukas Reschke <l8kas@owncloud.com>
*
* @copyright Copyright (c) 2015, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program 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, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OC\Repair;
use OC\Hooks\BasicEmitter;
use OC\RepairStep;
use OCP\IConfig;
/**
* Class UpdateOutdatedOcsIds is used to update invalid outdated OCS IDs, this is
* for example the case when an application has had another OCS ID in the past such
* as for contacts and calendar when apps.owncloud.com migrated to a unified identifier
* for multiple versions.
*
* @package OC\Repair
*/
class UpdateOutdatedOcsIds extends BasicEmitter implements RepairStep {
/** @var IConfig */
private $config;
/**
* @param IConfig $config
*/
public function __construct(IConfig $config) {
$this->config = $config;
}
/**
* {@inheritdoc}
*/
public function getName() {
return 'Repair outdated OCS IDs';
}
/**
* @param string $appName
* @param string $oldId
* @param string $newId
* @return bool True if updated, false otherwise
*/
public function fixOcsId($appName, $oldId, $newId) {
$existingId = $this->config->getAppValue($appName, 'ocsid');
if($existingId === $oldId) {
$this->config->setAppValue($appName, 'ocsid', $newId);
return true;
}
return false;
}
/**
* {@inheritdoc}
*/
public function run() {
$appsToUpdate = [
'contacts' => [
'old' => '166044',
'new' => '168708',
],
'calendar' => [
'old' => '166043',
'new' => '168707',
],
'bookmarks' => [
'old' => '166042',
'new' => '168710',
],
'search_lucene' => [
'old' => '166057',
'new' => '168709',
],
'documents' => [
'old' => '166045',
'new' => '168711',
]
];
foreach($appsToUpdate as $appName => $ids) {
if ($this->fixOcsId($appName, $ids['old'], $ids['new'])) {
$this->emit(
'\OC\Repair',
'info',
[sprintf('Fixed invalid %s OCS id', $appName)]
);
}
}
}
}
+57 -14
View File
@@ -25,22 +25,72 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
use OC\Connector\Sabre\ExceptionLoggerPlugin;
use Sabre\DAV\Exception\ServiceUnavailable;
use Sabre\DAV\Server;
/**
* Class RemoteException
* Dummy exception class to be use locally to identify certain conditions
*/
class RemoteException extends Exception {
}
/**
* @param Exception $e
*/
function handleException(Exception $e) {
$request = \OC::$server->getRequest();
// in case the request content type is text/xml - we assume it's a WebDAV request
$isXmlContentType = strpos($request->getHeader('Content-Type'), 'text/xml');
if ($isXmlContentType === 0) {
// fire up a simple server to properly process the exception
$server = new Server();
$server->addPlugin(new ExceptionLoggerPlugin('webdav', \OC::$server->getLogger()));
$server->on('beforeMethod', function () use ($e) {
if ($e instanceof RemoteException) {
switch ($e->getCode()) {
case OC_Response::STATUS_SERVICE_UNAVAILABLE:
throw new ServiceUnavailable($e->getMessage());
case OC_Response::STATUS_NOT_FOUND:
throw new \Sabre\DAV\Exception\NotFound($e->getMessage());
}
}
$class = get_class($e);
$msg = $e->getMessage();
throw new ServiceUnavailable("$class: $msg");
});
$server->exec();
} else {
$statusCode = OC_Response::STATUS_INTERNAL_SERVER_ERROR;
if ($e instanceof \OC\ServiceUnavailableException ) {
$statusCode = OC_Response::STATUS_SERVICE_UNAVAILABLE;
}
\OCP\Util::writeLog('remote', $e->getMessage(), \OCP\Util::FATAL);
if ($e instanceof RemoteException) {
OC_Response::setStatus($e->getCode());
OC_Template::printErrorPage($e->getMessage());
} else {
OC_Response::setStatus($statusCode);
OC_Template::printExceptionErrorPage($e);
}
}
}
try {
require_once 'lib/base.php';
if (\OCP\Util::needUpgrade()) {
// since the behavior of apps or remotes are unpredictable during
// an upgrade, return a 503 directly
OC_Response::setStatus(OC_Response::STATUS_SERVICE_UNAVAILABLE);
OC_Template::printErrorPage('Service unavailable');
exit;
throw new RemoteException('Service unavailable', OC_Response::STATUS_SERVICE_UNAVAILABLE);
}
$request = \OC::$server->getRequest();
$pathInfo = $request->getPathInfo();
if ($pathInfo === false || $pathInfo === '') {
OC_Response::setStatus(OC_Response::STATUS_NOT_FOUND);
exit;
throw new RemoteException('Path not found', OC_Response::STATUS_NOT_FOUND);
}
if (!$pos = strpos($pathInfo, '/', 1)) {
$pos = strlen($pathInfo);
@@ -50,8 +100,7 @@ try {
$file = \OC::$server->getConfig()->getAppValue('core', 'remote_' . $service);
if(is_null($file)) {
OC_Response::setStatus(OC_Response::STATUS_NOT_FOUND);
exit;
throw new RemoteException('Path not found', OC_Response::STATUS_NOT_FOUND);
}
// force language as given in the http request
@@ -82,12 +131,6 @@ try {
$baseuri = OC::$WEBROOT . '/remote.php/'.$service.'/';
require_once $file;
} catch (\OC\ServiceUnavailableException $ex) {
OC_Response::setStatus(OC_Response::STATUS_SERVICE_UNAVAILABLE);
\OCP\Util::writeLog('remote', $ex->getMessage(), \OCP\Util::FATAL);
OC_Template::printExceptionErrorPage($ex);
} catch (Exception $ex) {
OC_Response::setStatus(OC_Response::STATUS_INTERNAL_SERVER_ERROR);
\OCP\Util::writeLog('remote', $ex->getMessage(), \OCP\Util::FATAL);
OC_Template::printExceptionErrorPage($ex);
handleException($ex);
}
+2 -1
View File
@@ -79,7 +79,8 @@ class Application extends App {
$c->query('Config'),
$c->query('DatabaseConnection'),
$c->query('UserManager'),
new View()
new View(),
$c->query('Logger')
);
});
$container->registerService('AppSettingsController', function(IContainer $c) {
@@ -173,7 +173,7 @@ class AppSettingsController extends Controller {
if(!array_key_exists('level', $app) && array_key_exists('ocsid', $app)) {
$remoteAppEntry = $this->ocsClient->getApplication($app['ocsid'], \OC_Util::getVersion());
if(array_key_exists('level', $remoteAppEntry)) {
if(is_array($remoteAppEntry) && array_key_exists('level', $remoteAppEntry)) {
$apps[$key]['level'] = $remoteAppEntry['level'];
}
}
@@ -189,7 +189,7 @@ class AppSettingsController extends Controller {
if(!array_key_exists('level', $app) && array_key_exists('ocsid', $app)) {
$remoteAppEntry = $this->ocsClient->getApplication($app['ocsid'], \OC_Util::getVersion());
if(array_key_exists('level', $remoteAppEntry)) {
if(is_array($remoteAppEntry) && array_key_exists('level', $remoteAppEntry)) {
$apps[$key]['level'] = $remoteAppEntry['level'];
}
}
+10 -2
View File
@@ -25,6 +25,7 @@ use OC\Files\View;
use OCA\Encryption\Migration;
use OCP\IL10N;
use OCP\AppFramework\Controller;
use OCP\ILogger;
use OCP\IRequest;
use OCP\IConfig;
use OC\DB\Connection;
@@ -50,6 +51,9 @@ class EncryptionController extends Controller {
/** @var View */
private $view;
/** @var ILogger */
private $logger;
/**
* @param string $appName
* @param IRequest $request
@@ -58,6 +62,7 @@ class EncryptionController extends Controller {
* @param \OC\DB\Connection $connection
* @param IUserManager $userManager
* @param View $view
* @param ILogger $logger
*/
public function __construct($appName,
IRequest $request,
@@ -65,7 +70,8 @@ class EncryptionController extends Controller {
IConfig $config,
Connection $connection,
IUserManager $userManager,
View $view) {
View $view,
ILogger $logger) {
parent::__construct($appName, $request);
$this->l10n = $l10n;
$this->config = $config;
@@ -85,7 +91,7 @@ class EncryptionController extends Controller {
try {
$migration = new Migration($this->config, $this->view, $this->connection);
$migration = new Migration($this->config, $this->view, $this->connection, $this->logger);
$migration->reorganizeSystemFolderStructure();
$migration->updateDB();
@@ -102,6 +108,8 @@ class EncryptionController extends Controller {
} while (count($users) >= $limit);
}
$migration->finalCleanUp();
} catch (\Exception $e) {
return array(
'data' => array(
+3 -2
View File
@@ -86,11 +86,12 @@ OC.Settings.Apps = OC.Settings.Apps || {
}), {
type:'GET',
success: function (apps) {
var appList = _.map(_.indexBy(apps.apps, 'id'), function(app) {
var appListWithIndex = _.indexBy(apps.apps, 'id');
OC.Settings.Apps.State.apps = appListWithIndex;
var appList = _.map(appListWithIndex, function(app) {
// default values for missing fields
return _.extend({level: 0}, app);
});
OC.Settings.Apps.State.apps = appList;
var source = $("#app-template").html();
var template = Handlebars.compile(source);
+26
View File
@@ -159,6 +159,32 @@ describe('OC.Settings.Apps tests', function() {
var results = getResultsFromDom();
expect(results.length).toEqual(5);
expect(results).toEqual(['alpha', 'delta', 'zork', 'foo', 'nolevel']);
expect(OC.Settings.Apps.State.apps).toEqual({
'foo': {
id: 'foo',
name: 'Foo app',
level: 0
},
'alpha': {
id: 'alpha',
name: 'Alpha app',
level: 300
},
'nolevel': {
id: 'nolevel',
name: 'No level'
},
'zork': {
id: 'zork',
name: 'Some famous adventure game',
level: 200
},
'delta': {
id: 'delta',
name: 'Mathematical symbol',
level: 200
}
});
});
});
+12 -2
View File
@@ -502,10 +502,18 @@ class Test_App extends \Test\TestCase {
['description' => " \t This is a multiline \n test with \n \t some new lines "],
['description' => "This is a multiline test with some new lines"]
],
[
['description' => hex2bin('5065726d657420646520732761757468656e7469666965722064616e732070697769676f20646972656374656d656e74206176656320736573206964656e74696669616e7473206f776e636c6f75642073616e73206c65732072657461706572206574206d657420c3a0206a6f757273206365757820636920656e20636173206465206368616e67656d656e74206465206d6f742064652070617373652e0d0a0d')],
['description' => "Permet de s'authentifier dans piwigo directement avec ses identifiants owncloud sans les retaper et met à jours ceux ci en cas de changement de mot de passe."]
],
[
['not-a-description' => " \t This is a multiline \n test with \n \t some new lines "],
['not-a-description' => " \t This is a multiline \n test with \n \t some new lines "]
],
[
['description' => [100, 'bla']],
['description' => ""]
],
];
}
@@ -513,9 +521,11 @@ class Test_App extends \Test\TestCase {
* Test app info parser
*
* @dataProvider appDataProvider
* @param array $data
* @param array $expected
*/
public function testParseAppInfo($data, $expected) {
$this->assertEquals($expected, \OC_App::parseAppInfo($data));
public function testParseAppInfo(array $data, array $expected) {
$this->assertSame($expected, \OC_App::parseAppInfo($data));
}
}
+15 -4
View File
@@ -1023,17 +1023,27 @@ class RequestTest extends \Test\TestCase {
$this->assertSame('/test.php', $request->getRequestUri());
}
public function testGetRequestUriWithOverwrite() {
public function providesGetRequestUriWithOverwriteData() {
return [
['/scriptname.php/some/PathInfo', '/owncloud/', ''],
['/scriptname.php/some/PathInfo', '/owncloud/', '123'],
];
}
/**
* @dataProvider providesGetRequestUriWithOverwriteData
*/
public function testGetRequestUriWithOverwrite($expectedUri, $overwriteWebRoot, $overwriteCondAddr) {
$this->config
->expects($this->at(0))
->method('getSystemValue')
->with('overwritewebroot')
->will($this->returnValue('/owncloud/'));
->will($this->returnValue($overwriteWebRoot));
$this->config
->expects($this->at(1))
->method('getSystemValue')
->with('overwritecondaddr')
->will($this->returnValue(''));
->will($this->returnValue($overwriteCondAddr));
$request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
->setMethods(['getScriptName'])
@@ -1054,6 +1064,7 @@ class RequestTest extends \Test\TestCase {
->method('getScriptName')
->will($this->returnValue('/scriptname.php'));
$this->assertSame('/scriptname.php/some/PathInfo', $request->getRequestUri());
$this->assertSame($expectedUri, $request->getRequestUri());
}
}
+89 -5
View File
@@ -23,12 +23,22 @@
namespace Test\Cache;
class FileCache extends \Test_Cache {
/** @var string */
/**
* @var string
* */
private $user;
/** @var string */
/**
* @var string
* */
private $datadir;
/** @var \OC\Files\Storage\Storage */
/**
* @var \OC\Files\Storage\Storage
* */
private $storage;
/**
* @var \OC\Files\View
* */
private $rootView;
function skip() {
//$this->skipUnless(OC_User::isLoggedIn());
@@ -59,13 +69,18 @@ class FileCache extends \Test_Cache {
\OC_User::setUserId('test');
//set up the users dir
$rootView = new \OC\Files\View('');
$rootView->mkdir('/test');
$this->rootView = new \OC\Files\View('');
$this->rootView->mkdir('/test');
$this->instance=new \OC\Cache\File();
// forces creation of cache folder for subsequent tests
$this->instance->set('hack', 'hack');
}
protected function tearDown() {
$this->instance->remove('hack', 'hack');
\OC_User::setUserId($this->user);
\OC_Config::setValue('cachedirectory', $this->datadir);
@@ -75,4 +90,73 @@ class FileCache extends \Test_Cache {
parent::tearDown();
}
private function setupMockStorage() {
$mockStorage = $this->getMock(
'\OC\Files\Storage\Local',
['filemtime', 'unlink'],
[['datadir' => \OC::$server->getTempManager()->getTemporaryFolder()]]
);
\OC\Files\Filesystem::mount($mockStorage, array(), '/test/cache');
return $mockStorage;
}
public function testGarbageCollectOldKeys() {
$mockStorage = $this->setupMockStorage();
$mockStorage->expects($this->atLeastOnce())
->method('filemtime')
->will($this->returnValue(100));
$mockStorage->expects($this->once())
->method('unlink')
->with('key1')
->will($this->returnValue(true));
$this->instance->set('key1', 'value1');
$this->instance->gc();
}
public function testGarbageCollectLeaveRecentKeys() {
$mockStorage = $this->setupMockStorage();
$mockStorage->expects($this->atLeastOnce())
->method('filemtime')
->will($this->returnValue(time() + 3600));
$mockStorage->expects($this->never())
->method('unlink')
->with('key1');
$this->instance->set('key1', 'value1');
$this->instance->gc();
}
public function lockExceptionProvider() {
return [
[new \OCP\Lock\LockedException('key1')],
[new \OCP\Files\LockNotAcquiredException('key1', 1)],
];
}
/**
* @dataProvider lockExceptionProvider
*/
public function testGarbageCollectIgnoreLockedKeys($testException) {
$mockStorage = $this->setupMockStorage();
$mockStorage->expects($this->atLeastOnce())
->method('filemtime')
->will($this->returnValue(100));
$mockStorage->expects($this->atLeastOnce())
->method('unlink')
->will($this->onConsecutiveCalls(
$this->throwException($testException),
$this->returnValue(true)
));
$this->instance->set('key1', 'value1');
$this->instance->set('key2', 'value2');
$this->instance->gc();
}
}
-13
View File
@@ -72,19 +72,6 @@ class UtilTest extends TestCase {
];
}
/**
* @dataProvider providesHeaders
*/
public function testReadHeader($header, $expected, $moduleId) {
$expected['oc_encryption_module'] = $moduleId;
$result = $this->util->readHeader($header);
$this->assertSameSize($expected, $result);
foreach ($expected as $key => $value) {
$this->assertArrayHasKey($key, $result);
$this->assertSame($value, $result[$key]);
}
}
/**
* @dataProvider providesHeaders
*/
+115 -5
View File
@@ -2,11 +2,19 @@
namespace Test\Files\Storage\Wrapper;
use OC\Encryption\Util;
use OC\Files\Storage\Temporary;
use OC\Files\View;
class Encryption extends \Test\Files\Storage\Storage {
/**
* block size will always be 8192 for a PHP stream
* @see https://bugs.php.net/bug.php?id=21641
* @var integer
*/
protected $headerSize = 8192;
/**
* @var Temporary
*/
@@ -407,18 +415,26 @@ class Encryption extends \Test\Files\Storage\Storage {
$this->encryptionManager, $util, $this->logger, $this->file, null, $this->keyStore, $this->update, $this->mountManager
]
)
->setMethods(['readFirstBlock', 'parseRawHeader'])
->getMock();
$instance->expects($this->once())->method(('parseRawHeader'))
->willReturn([Util::HEADER_ENCRYPTION_MODULE_KEY => 'OC_DEFAULT_MODULE']);
if ($strippedPathExists) {
$instance->expects($this->once())->method('readFirstBlock')
->with($strippedPath)->willReturn('');
} else {
$instance->expects($this->once())->method('readFirstBlock')
->with($path)->willReturn('');
}
$util->expects($this->once())->method('stripPartialFileExtension')
->with($path)->willReturn($strippedPath);
$sourceStorage->expects($this->at(0))
$sourceStorage->expects($this->once())
->method('file_exists')
->with($strippedPath)
->willReturn($strippedPathExists);
$sourceStorage->expects($this->at(1))
->method('file_exists')
->with($strippedPathExists ? $strippedPath : $path)
->willReturn(false);
$this->invokePrivate($instance, 'getHeader', [$path]);
}
@@ -432,4 +448,98 @@ class Encryption extends \Test\Files\Storage\Storage {
array('/foo/bar.txt.ocTransferId7437493.part', true, '/foo/bar.txt'),
);
}
/**
* test if getHeader adds the default module correctly to the header for
* legacy files
*
* @dataProvider dataTestGetHeaderAddLegacyModule
*/
public function testGetHeaderAddLegacyModule($header, $isEncrypted, $expected) {
$sourceStorage = $this->getMockBuilder('\OC\Files\Storage\Storage')
->disableOriginalConstructor()->getMock();
$util = $this->getMockBuilder('\OC\Encryption\Util')
->setConstructorArgs([new View(), new \OC\User\Manager(), $this->groupManager, $this->config])
->getMock();
$cache = $this->getMockBuilder('\OC\Files\Cache\Cache')
->disableOriginalConstructor()->getMock();
$cache->expects($this->any())
->method('get')
->willReturnCallback(function($path) use ($isEncrypted) {return ['encrypted' => $isEncrypted, 'path' => $path];});
$instance = $this->getMockBuilder('\OC\Files\Storage\Wrapper\Encryption')
->setConstructorArgs(
[
[
'storage' => $sourceStorage,
'root' => 'foo',
'mountPoint' => '/',
'mount' => $this->mount
],
$this->encryptionManager, $util, $this->logger, $this->file, null, $this->keyStore, $this->update, $this->mountManager
]
)
->setMethods(['readFirstBlock', 'parseRawHeader', 'getCache'])
->getMock();
$instance->expects($this->once())->method(('parseRawHeader'))->willReturn($header);
$instance->expects($this->any())->method('getCache')->willReturn($cache);
$result = $this->invokePrivate($instance, 'getHeader', ['test.txt']);
$this->assertSameSize($expected, $result);
foreach ($result as $key => $value) {
$this->assertArrayHasKey($key, $expected);
$this->assertSame($expected[$key], $value);
}
}
public function dataTestGetHeaderAddLegacyModule() {
return [
[['cipher' => 'AES-128'], true, ['cipher' => 'AES-128', Util::HEADER_ENCRYPTION_MODULE_KEY => 'OC_DEFAULT_MODULE']],
[[], true, [Util::HEADER_ENCRYPTION_MODULE_KEY => 'OC_DEFAULT_MODULE']],
[[], false, []],
];
}
/**
* @dataProvider dataTestParseRawHeader
*/
public function testParseRawHeader($rawHeader, $expected) {
$instance = new \OC\Files\Storage\Wrapper\Encryption(
[
'storage' => $this->sourceStorage,
'root' => 'foo',
'mountPoint' => '/',
'mount' => $this->mount
],
$this->encryptionManager, $this->util, $this->logger, $this->file, null, $this->keyStore, $this->update, $this->mountManager
);
$result = $this->invokePrivate($instance, 'parseRawHeader', [$rawHeader]);
$this->assertSameSize($expected, $result);
foreach ($result as $key => $value) {
$this->assertArrayHasKey($key, $expected);
$this->assertSame($expected[$key], $value);
}
}
public function dataTestParseRawHeader() {
return [
[str_pad('HBEGIN:oc_encryption_module:0:HEND', $this->headerSize, '-', STR_PAD_RIGHT)
, [Util::HEADER_ENCRYPTION_MODULE_KEY => '0']],
[str_pad('HBEGIN:oc_encryption_module:0:custom_header:foo:HEND', $this->headerSize, '-', STR_PAD_RIGHT)
, ['custom_header' => 'foo', Util::HEADER_ENCRYPTION_MODULE_KEY => '0']],
[str_pad('HelloWorld', $this->headerSize, '-', STR_PAD_RIGHT), []],
['', []],
[str_pad('HBEGIN:oc_encryption_module:0', $this->headerSize, '-', STR_PAD_RIGHT)
, []],
[str_pad('oc_encryption_module:0:HEND', $this->headerSize, '-', STR_PAD_RIGHT)
, []],
];
}
}
+43
View File
@@ -11,6 +11,8 @@ namespace Test\Files\Utils;
use OC\Files\Filesystem;
use OC\Files\Mount\MountPoint;
use OC\Files\Storage\Temporary;
use OCP\Files\Storage\IStorageFactory;
use OCP\IUser;
class TestScanner extends \OC\Files\Utils\Scanner {
/**
@@ -39,14 +41,22 @@ class TestScanner extends \OC\Files\Utils\Scanner {
}
class Scanner extends \Test\TestCase {
/**
* @var \OC_User_Dummy
*/
private $userBackend;
protected function setUp() {
parent::setUp();
$this->userBackend = new \OC_User_Dummy();
\OC::$server->getUserManager()->registerBackend($this->userBackend);
$this->loginAsUser();
}
protected function tearDown() {
$this->logout();
\OC::$server->getUserManager()->removeBackend($this->userBackend);
parent::tearDown();
}
@@ -94,6 +104,39 @@ class Scanner extends \Test\TestCase {
$this->assertEquals($old, $new);
}
public function testScanSubMount() {
$uid = $this->getUniqueID();
$this->userBackend->createUser($uid, 'test');
$mountProvider = $this->getMock('\OCP\Files\Config\IMountProvider');
$storage = new Temporary(array());
$mount = new MountPoint($storage, '/' . $uid . '/files/foo');
$mountProvider->expects($this->any())
->method('getMountsForUser')
->will($this->returnCallback(function (IUser $user, IStorageFactory $storageFactory) use ($mount, $uid) {
if ($user->getUID() === $uid) {
return [$mount];
} else {
return [];
}
}));
\OC::$server->getMountProviderCollection()->registerProvider($mountProvider);
$cache = $storage->getCache();
$storage->mkdir('folder');
$storage->file_put_contents('foo.txt', 'qwerty');
$storage->file_put_contents('folder/bar.txt', 'qwerty');
$scanner = new \OC\Files\Utils\Scanner($uid, \OC::$server->getDatabaseConnection());
$this->assertFalse($cache->inCache('folder/bar.txt'));
$scanner->scan('/' . $uid . '/files/foo');
$this->assertTrue($cache->inCache('folder/bar.txt'));
}
public function testChangePropagator() {
/**
* @var \OC\Files\Cache\ChangePropagator $propagator
+80
View File
@@ -0,0 +1,80 @@
<?php
/**
* @author Lukas Reschke <l8kas@owncloud.com>
*
* @copyright Copyright (c) 2015, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program 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, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace Test\Repair;
use OCP\IConfig;
use Test\TestCase;
/**
* Class UpdateOutdatedOcsIds
*
* @package Test\Repair
*/
class UpdateOutdatedOcsIds extends TestCase {
/** @var IConfig */
private $config;
/** @var \OC\Repair\UpdateOutdatedOcsIds */
private $updateOutdatedOcsIds;
public function setUp() {
parent::setUp();
$this->config = $this->getMockBuilder('\\OCP\\IConfig')->getMock();
$this->updateOutdatedOcsIds = new \OC\Repair\UpdateOutdatedOcsIds($this->config);
}
public function testGetName() {
$this->assertSame('Repair outdated OCS IDs', $this->updateOutdatedOcsIds->getName());
}
public function testFixOcsIdNoOcsId() {
$this->config
->expects($this->once())
->method('getAppValue')
->with('MyNotInstalledApp', 'ocsid')
->will($this->returnValue(''));
$this->assertFalse($this->updateOutdatedOcsIds->fixOcsId('MyNotInstalledApp', '1337', '0815'));
}
public function testFixOcsIdUpdateOcsId() {
$this->config
->expects($this->at(0))
->method('getAppValue')
->with('MyInstalledApp', 'ocsid')
->will($this->returnValue('1337'));
$this->config
->expects($this->at(1))
->method('setAppValue')
->with('MyInstalledApp', 'ocsid', '0815');
$this->assertTrue($this->updateOutdatedOcsIds->fixOcsId('MyInstalledApp', '1337', '0815'));
}
public function testFixOcsIdAlreadyFixed() {
$this->config
->expects($this->once())
->method('getAppValue')
->with('MyAlreadyFixedAppId', 'ocsid')
->will($this->returnValue('0815'));
$this->assertFalse($this->updateOutdatedOcsIds->fixOcsId('MyAlreadyFixedAppId', '1337', '0815'));
}
}
+2 -2
View File
@@ -22,10 +22,10 @@
// We only can count up. The 4. digit is only for the internal patchlevel to trigger DB upgrades
// between betas, final and RCs. This is _not_ the public version number. Reset minor/patchlevel
// when updating major/minor version number.
$OC_Version=array(8, 1, 0, 7);
$OC_Version=array(8, 1, 1, 0);
// The human readable string
$OC_VersionString='8.1 RC1';
$OC_VersionString='8.1.1';
// The ownCloud channel
$OC_Channel='git';