Compare commits
352 Commits
checkValid
...
v8.1.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aca9fce93f | ||
|
|
f7f34dbeb4 | ||
|
|
8e0cddbe01 | ||
|
|
3bad2ac1e5 | ||
|
|
9f3ea9116e | ||
|
|
3387d05ca9 | ||
|
|
74871b1676 | ||
|
|
352d695c95 | ||
|
|
cc9d5e44b1 | ||
|
|
643cba065a | ||
|
|
c5b28e0795 | ||
|
|
5062007000 | ||
|
|
9daf3e7410 | ||
|
|
8f6774fc4c | ||
|
|
371f4bf472 | ||
|
|
49879b868b | ||
|
|
1cf61baa41 | ||
|
|
e3642f2f3d | ||
|
|
bb973c2d76 | ||
|
|
cde21db620 | ||
|
|
f9be35c931 | ||
|
|
ba13cecb76 | ||
|
|
5412899665 | ||
|
|
6ccc5a6cd3 | ||
|
|
7ccd52db25 | ||
|
|
a05ead505d | ||
|
|
0a9904963d | ||
|
|
c1953f9676 | ||
|
|
5e8f0a893d | ||
|
|
c16a847163 | ||
|
|
c2ded337e6 | ||
|
|
df4348674b | ||
|
|
f3392f9e59 | ||
|
|
923e6ca1bf | ||
|
|
64fb704c4e | ||
|
|
4ba4fb5ffb | ||
|
|
e1d2ab83cc | ||
|
|
6fd2f18b85 | ||
|
|
a2810f6207 | ||
|
|
4d92aa551d | ||
|
|
5ed1744a6f | ||
|
|
371061ac6d | ||
|
|
85c8af596d | ||
|
|
2f2d94f801 | ||
|
|
9ece45ca28 | ||
|
|
e9a17fbee5 | ||
|
|
37747016f2 | ||
|
|
07f903a1e3 | ||
|
|
4c13a648bb | ||
|
|
c3ec3b0fe0 | ||
|
|
045c491be8 | ||
|
|
56fcef3d56 | ||
|
|
db909277f1 | ||
|
|
30c149deeb | ||
|
|
87f27d0ba1 | ||
|
|
48ec118af6 | ||
|
|
b21912aa41 | ||
|
|
f83f80ac71 | ||
|
|
c7d9936d67 | ||
|
|
ffb8819125 | ||
|
|
b5f8f94341 | ||
|
|
a77f679779 | ||
|
|
c2ca7fc91d | ||
|
|
29a4d1b512 | ||
|
|
c589244b40 | ||
|
|
4a1246fa29 | ||
|
|
dc128295c6 | ||
|
|
788831f139 | ||
|
|
9a81eca7ba | ||
|
|
b9e0e6a573 | ||
|
|
32c6fdf098 | ||
|
|
643b6c11c3 | ||
|
|
9e5f538897 | ||
|
|
ab68469e61 | ||
|
|
b70e7f4d0a | ||
|
|
623ce418ce | ||
|
|
6c2f95ff9f | ||
|
|
2764aa1b99 | ||
|
|
1a167dd5ac | ||
|
|
f934a6fae6 | ||
|
|
50a8ba6062 | ||
|
|
427f7d5a5c | ||
|
|
655eb4ce40 | ||
|
|
9bd37d2acd | ||
|
|
1d2803ec9a | ||
|
|
d6994b2da6 | ||
|
|
c4667d5213 | ||
|
|
310762a118 | ||
|
|
7b5218ed30 | ||
|
|
00447f32f6 | ||
|
|
876266f0ce | ||
|
|
dc1755ab52 | ||
|
|
c48a61a975 | ||
|
|
42c454e8d0 | ||
|
|
aaa1249075 | ||
|
|
380971c76d | ||
|
|
1efcbca9dc | ||
|
|
1f7b231b9a | ||
|
|
0b279f9a13 | ||
|
|
aa12a9983a | ||
|
|
bf149b1529 | ||
|
|
c736f5dcc4 | ||
|
|
63e07b0525 | ||
|
|
690a4597e3 | ||
|
|
709f289beb | ||
|
|
fd259db588 | ||
|
|
5500cb9b4e | ||
|
|
15a054f127 | ||
|
|
015323c1cb | ||
|
|
4d1b898bc5 | ||
|
|
8d800e9635 | ||
|
|
bef8dd4171 | ||
|
|
2f851201db | ||
|
|
cbcbbd9423 | ||
|
|
5d433da1ae | ||
|
|
349c650535 | ||
|
|
3ceee5408a | ||
|
|
3b30dd4394 | ||
|
|
f3b8b90191 | ||
|
|
76399dc6b0 | ||
|
|
a2d456c195 | ||
|
|
9c289b71c6 | ||
|
|
4676f39855 | ||
|
|
7b510f2510 | ||
|
|
b823bbbc28 | ||
|
|
0dfa839582 | ||
|
|
01fc0b53f6 | ||
|
|
04bed337ee | ||
|
|
0e4bdfbef3 | ||
|
|
3233b9c4ee | ||
|
|
1850476916 | ||
|
|
bcc79b0e40 | ||
|
|
1d8b5ac909 | ||
|
|
540ad35f3b | ||
|
|
d2c81fd3c5 | ||
|
|
c3468c7b29 | ||
|
|
a1706f61aa | ||
|
|
7d436579cb | ||
|
|
b2adf17433 | ||
|
|
76306dd5a1 | ||
|
|
727cb3b2a3 | ||
|
|
227e338542 | ||
|
|
6dffa0fc95 | ||
|
|
bf1096602b | ||
|
|
d6bc77599e | ||
|
|
21c9dd284b | ||
|
|
174c4e3113 | ||
|
|
373d1b67b2 | ||
|
|
31eb4f06f7 | ||
|
|
b9e5809869 | ||
|
|
8c145541f6 | ||
|
|
880ba38e2c | ||
|
|
47ec44da3b | ||
|
|
60cd118371 | ||
|
|
2c81ac1cf7 | ||
|
|
3ea3fc7b62 | ||
|
|
dc012be598 | ||
|
|
94f2b2ba8c | ||
|
|
116ec56e8c | ||
|
|
444d5d27de | ||
|
|
dcda1e1e61 | ||
|
|
6bcf2b9e77 | ||
|
|
dbc03b68ae | ||
|
|
94eb5f645a | ||
|
|
c31e2464c8 | ||
|
|
9e42d3ed43 | ||
|
|
d3266f5459 | ||
|
|
dcd9154f04 | ||
|
|
c8e1359c9d | ||
|
|
6c8689072c | ||
|
|
e272ec0c3e | ||
|
|
327f96f29b | ||
|
|
1add97feae | ||
|
|
e9a1a8cf75 | ||
|
|
69970f83f9 | ||
|
|
82bffa0df2 | ||
|
|
7c58985ca1 | ||
|
|
18ec257ab2 | ||
|
|
04b409fb09 | ||
|
|
571b7f0c2c | ||
|
|
e94d8bbf24 | ||
|
|
ac04692eac | ||
|
|
f7cb36a706 | ||
|
|
c9132190ab | ||
|
|
677bb62edf | ||
|
|
087acc550c | ||
|
|
ca66a705ec | ||
|
|
89ccdcf134 | ||
|
|
1436baaff7 | ||
|
|
30b3b075ba | ||
|
|
6e1e70439b | ||
|
|
e0a330315d | ||
|
|
b91f002baf | ||
|
|
cb791c7fe2 | ||
|
|
1a1e19f929 | ||
|
|
6534202573 | ||
|
|
a430e75425 | ||
|
|
78a46dcac1 | ||
|
|
8c9b8f4fe9 | ||
|
|
a0ab86bb91 | ||
|
|
ab16bea5c7 | ||
|
|
2e8f47dfb6 | ||
|
|
a79a15e6c5 | ||
|
|
cf4f43363c | ||
|
|
ef2eeae852 | ||
|
|
f7360795f8 | ||
|
|
c61b23561b | ||
|
|
4409aed581 | ||
|
|
a9524e250a | ||
|
|
42ca905d62 | ||
|
|
4d6dcec751 | ||
|
|
9bfbed5e0d | ||
|
|
c411dcd30a | ||
|
|
2c83115a3d | ||
|
|
73da1ca71d | ||
|
|
7f5f7711ad | ||
|
|
891a4d2ccd | ||
|
|
e0b5bea50f | ||
|
|
3133949418 | ||
|
|
dcd5666601 | ||
|
|
fc467da7d3 | ||
|
|
a949f6c576 | ||
|
|
e8cbfd16a2 | ||
|
|
e25a116aa6 | ||
|
|
036ba93ded | ||
|
|
b8561bda9c | ||
|
|
c4ddf08b79 | ||
|
|
ef65e519ae | ||
|
|
4b41021fc3 | ||
|
|
0ef06afc75 | ||
|
|
6dedef7967 | ||
|
|
1c7d737124 | ||
|
|
4ee61f3c7a | ||
|
|
c910ac1f47 | ||
|
|
95e44bfc4e | ||
|
|
ee18718099 | ||
|
|
6782c6d22e | ||
|
|
cef2680c0d | ||
|
|
e29158c892 | ||
|
|
a53b7e3240 | ||
|
|
74e0b6f1e5 | ||
|
|
b8e8e3fdaf | ||
|
|
965fd990fc | ||
|
|
3fdd5d9012 | ||
|
|
b4bef0214e | ||
|
|
ee85d1fd37 | ||
|
|
77a37e076f | ||
|
|
a07675e513 | ||
|
|
2b63903942 | ||
|
|
2bc2e974b2 | ||
|
|
2ecba9e5a5 | ||
|
|
dd5b347672 | ||
|
|
8be59bf7e0 | ||
|
|
e92d427dde | ||
|
|
897e99ac58 | ||
|
|
dc6cc57e11 | ||
|
|
f1df6cd4ff | ||
|
|
ff8e63c991 | ||
|
|
d4cc4019fd | ||
|
|
6383bd3744 | ||
|
|
738e116c00 | ||
|
|
777964ff2b | ||
|
|
00a044f885 | ||
|
|
335372064e | ||
|
|
17d7a2893e | ||
|
|
1b8eb668de | ||
|
|
a3172008c6 | ||
|
|
b2db982768 | ||
|
|
001dd400a1 | ||
|
|
5bfbfca266 | ||
|
|
fc6420c290 | ||
|
|
015d4e3ba3 | ||
|
|
deeacacfae | ||
|
|
d199fb4e8d | ||
|
|
289fd99333 | ||
|
|
579bee03bd | ||
|
|
816910baf1 | ||
|
|
fb452486d7 | ||
|
|
ae1332e9c9 | ||
|
|
9d9ab82a17 | ||
|
|
edb15bd493 | ||
|
|
4c6b26d056 | ||
|
|
8e1fca7402 | ||
|
|
db5a574faf | ||
|
|
8e0294d0fd | ||
|
|
256c57c01e | ||
|
|
db21b0964c | ||
|
|
cc45b49de7 | ||
|
|
90104fc5d8 | ||
|
|
8f2ce01553 | ||
|
|
3ade5f5111 | ||
|
|
60939ebd2c | ||
|
|
c73f938ff4 | ||
|
|
06d7480fa2 | ||
|
|
48b2a4e034 | ||
|
|
824df7e22d | ||
|
|
ab308d246a | ||
|
|
dc9454ea3c | ||
|
|
f920923dd6 | ||
|
|
698e2ebc90 | ||
|
|
1548d69762 | ||
|
|
8466d9d235 | ||
|
|
48b1e9e2a6 | ||
|
|
f21eb35431 | ||
|
|
509725fad9 | ||
|
|
447c60c4e4 | ||
|
|
eb055b0d78 | ||
|
|
d48d59661a | ||
|
|
312d82fe71 | ||
|
|
96b97d1567 | ||
|
|
97e49e422f | ||
|
|
5d3d44eeb9 | ||
|
|
51978aa296 | ||
|
|
3823713c7c | ||
|
|
3854dead08 | ||
|
|
ce0f391ecd | ||
|
|
388409290a | ||
|
|
fb85fc619d | ||
|
|
d5e90e7239 | ||
|
|
c04beb0bad | ||
|
|
9def2fcf71 | ||
|
|
1427a79643 | ||
|
|
06ec916b11 | ||
|
|
7d94d963e9 | ||
|
|
c051c180ab | ||
|
|
9cba7c1793 | ||
|
|
16514762bf | ||
|
|
2727d9797d | ||
|
|
a95b5c3b3e | ||
|
|
1902101923 | ||
|
|
8a3f54c225 | ||
|
|
478fe752e7 | ||
|
|
ea731c5c66 | ||
|
|
caa3210a59 | ||
|
|
8fe5d4b268 | ||
|
|
85fc84e3d3 | ||
|
|
6008bf975d | ||
|
|
4abec8b5b9 | ||
|
|
d6cbf8be71 | ||
|
|
2d92b5a64e | ||
|
|
d6b24c7bbc | ||
|
|
4aa2eff94c | ||
|
|
4fff832fa6 | ||
|
|
39e391fd1a | ||
|
|
e48afaf334 | ||
|
|
18e4fe7add | ||
|
|
c7bc669e00 | ||
|
|
09038697cd | ||
|
|
eb2e8d99cc | ||
|
|
82493e9789 | ||
|
|
526a45be18 | ||
|
|
283f8e7e69 |
@@ -1,4 +1,4 @@
|
||||
# Version: 8.1.0
|
||||
# Version: 8.1.4
|
||||
<IfModule mod_headers.c>
|
||||
<IfModule mod_fcgid.c>
|
||||
<IfModule mod_setenvif.c>
|
||||
|
||||
2
3rdparty
2
3rdparty
Submodule 3rdparty updated: a79a7ee86b...8939064aa9
@@ -17,7 +17,7 @@ Depencencies:
|
||||
[](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/
|
||||
[](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
|
||||
|
||||
@@ -81,6 +81,7 @@ class Application extends \OCP\AppFramework\App {
|
||||
|
||||
$hookManager->registerHook([
|
||||
new UserHooks($container->query('KeyManager'),
|
||||
$server->getUserManager(),
|
||||
$server->getLogger(),
|
||||
$container->query('UserSetup'),
|
||||
$server->getUserSession(),
|
||||
@@ -195,7 +196,8 @@ class Application extends \OCP\AppFramework\App {
|
||||
$server->getUserSession(),
|
||||
$c->query('KeyManager'),
|
||||
$c->query('Crypt'),
|
||||
$c->query('Session')
|
||||
$c->query('Session'),
|
||||
$server->getSession()
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ use OCP\AppFramework\Http;
|
||||
use OCP\AppFramework\Http\DataResponse;
|
||||
use OCP\IL10N;
|
||||
use OCP\IRequest;
|
||||
use OCP\ISession;
|
||||
use OCP\IUserManager;
|
||||
use OCP\IUserSession;
|
||||
|
||||
@@ -54,6 +55,9 @@ class SettingsController extends Controller {
|
||||
/** @var Session */
|
||||
private $session;
|
||||
|
||||
/** @var ISession */
|
||||
private $ocSession;
|
||||
|
||||
/**
|
||||
* @param string $AppName
|
||||
* @param IRequest $request
|
||||
@@ -63,6 +67,7 @@ class SettingsController extends Controller {
|
||||
* @param KeyManager $keyManager
|
||||
* @param Crypt $crypt
|
||||
* @param Session $session
|
||||
* @param ISession $ocSession
|
||||
*/
|
||||
public function __construct($AppName,
|
||||
IRequest $request,
|
||||
@@ -71,7 +76,8 @@ class SettingsController extends Controller {
|
||||
IUserSession $userSession,
|
||||
KeyManager $keyManager,
|
||||
Crypt $crypt,
|
||||
Session $session) {
|
||||
Session $session,
|
||||
ISession $ocSession) {
|
||||
parent::__construct($AppName, $request);
|
||||
$this->l = $l10n;
|
||||
$this->userSession = $userSession;
|
||||
@@ -79,6 +85,7 @@ class SettingsController extends Controller {
|
||||
$this->keyManager = $keyManager;
|
||||
$this->crypt = $crypt;
|
||||
$this->session = $session;
|
||||
$this->ocSession = $ocSession;
|
||||
}
|
||||
|
||||
|
||||
@@ -97,6 +104,13 @@ class SettingsController extends Controller {
|
||||
|
||||
//check if password is correct
|
||||
$passwordCorrect = $this->userManager->checkPassword($uid, $newPassword);
|
||||
if ($passwordCorrect === false) {
|
||||
// if check with uid fails we need to check the password with the login name
|
||||
// e.g. in the ldap case. For local user we need to check the password with
|
||||
// the uid because in this case the login name is case insensitive
|
||||
$loginName = $this->ocSession->get('loginname');
|
||||
$passwordCorrect = $this->userManager->checkPassword($loginName, $newPassword);
|
||||
}
|
||||
|
||||
if ($passwordCorrect !== false) {
|
||||
$encryptedKey = $this->keyManager->getPrivateKey($uid);
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
namespace OCA\Encryption\Hooks;
|
||||
|
||||
|
||||
use OCP\IUserManager;
|
||||
use OCP\Util as OCUtil;
|
||||
use OCA\Encryption\Hooks\Contracts\IHook;
|
||||
use OCA\Encryption\KeyManager;
|
||||
@@ -41,6 +42,10 @@ class UserHooks implements IHook {
|
||||
* @var KeyManager
|
||||
*/
|
||||
private $keyManager;
|
||||
/**
|
||||
* @var IUserManager
|
||||
*/
|
||||
private $userManager;
|
||||
/**
|
||||
* @var ILogger
|
||||
*/
|
||||
@@ -74,6 +79,7 @@ class UserHooks implements IHook {
|
||||
* UserHooks constructor.
|
||||
*
|
||||
* @param KeyManager $keyManager
|
||||
* @param IUserManager $userManager
|
||||
* @param ILogger $logger
|
||||
* @param Setup $userSetup
|
||||
* @param IUserSession $user
|
||||
@@ -83,6 +89,7 @@ class UserHooks implements IHook {
|
||||
* @param Recovery $recovery
|
||||
*/
|
||||
public function __construct(KeyManager $keyManager,
|
||||
IUserManager $userManager,
|
||||
ILogger $logger,
|
||||
Setup $userSetup,
|
||||
IUserSession $user,
|
||||
@@ -92,6 +99,7 @@ class UserHooks implements IHook {
|
||||
Recovery $recovery) {
|
||||
|
||||
$this->keyManager = $keyManager;
|
||||
$this->userManager = $userManager;
|
||||
$this->logger = $logger;
|
||||
$this->userSetup = $userSetup;
|
||||
$this->user = $user;
|
||||
@@ -196,7 +204,7 @@ class UserHooks implements IHook {
|
||||
public function preSetPassphrase($params) {
|
||||
if (App::isEnabled('encryption')) {
|
||||
|
||||
$user = $this->user->getUser();
|
||||
$user = $this->userManager->get($params['uid']);
|
||||
|
||||
if ($user && !$user->canChangePassword()) {
|
||||
$this->setPassphrase($params);
|
||||
|
||||
@@ -49,7 +49,7 @@ class Crypt {
|
||||
*/
|
||||
private $logger;
|
||||
/**
|
||||
* @var IUser
|
||||
* @var string
|
||||
*/
|
||||
private $user;
|
||||
/**
|
||||
@@ -64,7 +64,7 @@ class Crypt {
|
||||
*/
|
||||
public function __construct(ILogger $logger, IUserSession $userSession, IConfig $config) {
|
||||
$this->logger = $logger;
|
||||
$this->user = $userSession && $userSession->isLoggedIn() ? $userSession->getUser() : false;
|
||||
$this->user = $userSession && $userSession->isLoggedIn() ? $userSession->getUser()->getUID() : '"no user given"';
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ class Crypt {
|
||||
$res = $this->getOpenSSLPKey();
|
||||
|
||||
if (!$res) {
|
||||
$log->error("Encryption Library couldn't generate users key-pair for {$this->user->getUID()}",
|
||||
$log->error("Encryption Library couldn't generate users key-pair for {$this->user}",
|
||||
['app' => 'encryption']);
|
||||
|
||||
if (openssl_error_string()) {
|
||||
@@ -98,7 +98,7 @@ class Crypt {
|
||||
'privateKey' => $privateKey
|
||||
];
|
||||
}
|
||||
$log->error('Encryption library couldn\'t export users private key, please check your servers OpenSSL configuration.' . $this->user->getUID(),
|
||||
$log->error('Encryption library couldn\'t export users private key, please check your servers OpenSSL configuration.' . $this->user,
|
||||
['app' => 'encryption']);
|
||||
if (openssl_error_string()) {
|
||||
$log->error('Encryption Library:' . openssl_error_string(),
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace OCA\Encryption;
|
||||
use OC\DB\Connection;
|
||||
use OC\Files\View;
|
||||
use OCP\IConfig;
|
||||
use OCP\ILogger;
|
||||
|
||||
class Migration {
|
||||
|
||||
@@ -36,21 +37,28 @@ class Migration {
|
||||
private $connection;
|
||||
/** @var IConfig */
|
||||
private $config;
|
||||
/** @var ILogger */
|
||||
private $logger;
|
||||
/** @var string*/
|
||||
protected $installedVersion;
|
||||
|
||||
/**
|
||||
* @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;
|
||||
$this->installedVersion = $this->config->getAppValue('files_encryption', 'installed_version', '-1');
|
||||
}
|
||||
|
||||
public function __destruct() {
|
||||
public function finalCleanUp() {
|
||||
$this->view->deleteAll('files_encryption/public_keys');
|
||||
$this->updateFileCache();
|
||||
$this->config->deleteAppValue('files_encryption', 'installed_version');
|
||||
@@ -60,12 +68,16 @@ class Migration {
|
||||
* update file cache, copy unencrypted_size to the 'size' column
|
||||
*/
|
||||
private function updateFileCache() {
|
||||
$query = $this->connection->createQueryBuilder();
|
||||
$query->update('`*PREFIX*filecache`')
|
||||
->set('`size`', '`unencrypted_size`')
|
||||
->where($query->expr()->eq('`encrypted`', ':encrypted'))
|
||||
->setParameter('encrypted', 1);
|
||||
$query->execute();
|
||||
// make sure that we don't update the file cache multiple times
|
||||
// only update during the first run
|
||||
if ($this->installedVersion !== '-1') {
|
||||
$query = $this->connection->createQueryBuilder();
|
||||
$query->update('`*PREFIX*filecache`')
|
||||
->set('`size`', '`unencrypted_size`')
|
||||
->where($query->expr()->eq('`encrypted`', ':encrypted'))
|
||||
->setParameter('encrypted', 1);
|
||||
$query->execute();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,27 +150,43 @@ class Migration {
|
||||
*/
|
||||
public function updateDB() {
|
||||
|
||||
// make sure that we don't update the file cache multiple times
|
||||
// only update during the first run
|
||||
if ($this->installedVersion === '-1') {
|
||||
return;
|
||||
}
|
||||
|
||||
// delete left-over from old encryption which is no longer needed
|
||||
$this->config->deleteAppValue('files_encryption', 'ocsid');
|
||||
$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 +252,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 +266,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 +281,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 +295,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 +311,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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -54,6 +54,9 @@ class SettingsControllerTest extends TestCase {
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject */
|
||||
private $sessionMock;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject */
|
||||
private $ocSessionMock;
|
||||
|
||||
protected function setUp() {
|
||||
|
||||
parent::setUp();
|
||||
@@ -91,9 +94,11 @@ class SettingsControllerTest extends TestCase {
|
||||
])
|
||||
->getMock();
|
||||
|
||||
$this->ocSessionMock = $this->getMockBuilder('\OCP\ISession')->disableOriginalConstructor()->getMock();
|
||||
|
||||
$this->userSessionMock->expects($this->any())
|
||||
->method('getUID')
|
||||
->willReturn('testUser');
|
||||
->willReturn('testUserUid');
|
||||
|
||||
$this->userSessionMock->expects($this->any())
|
||||
->method($this->anything())
|
||||
@@ -110,7 +115,8 @@ class SettingsControllerTest extends TestCase {
|
||||
$this->userSessionMock,
|
||||
$this->keyManagerMock,
|
||||
$this->cryptMock,
|
||||
$this->sessionMock
|
||||
$this->sessionMock,
|
||||
$this->ocSessionMock
|
||||
);
|
||||
}
|
||||
|
||||
@@ -122,8 +128,10 @@ class SettingsControllerTest extends TestCase {
|
||||
$oldPassword = 'old';
|
||||
$newPassword = 'new';
|
||||
|
||||
$this->userSessionMock->expects($this->once())->method('getUID')->willReturn('uid');
|
||||
|
||||
$this->userManagerMock
|
||||
->expects($this->once())
|
||||
->expects($this->exactly(2))
|
||||
->method('checkPassword')
|
||||
->willReturn(false);
|
||||
|
||||
@@ -171,16 +179,22 @@ class SettingsControllerTest extends TestCase {
|
||||
$oldPassword = 'old';
|
||||
$newPassword = 'new';
|
||||
|
||||
$this->userSessionMock
|
||||
->expects($this->once())
|
||||
->method('getUID')
|
||||
->willReturn('testUser');
|
||||
$this->ocSessionMock->expects($this->once())
|
||||
->method('get')->with('loginname')->willReturn('testUser');
|
||||
|
||||
$this->userManagerMock
|
||||
->expects($this->once())
|
||||
->expects($this->at(0))
|
||||
->method('checkPassword')
|
||||
->with('testUserUid', 'new')
|
||||
->willReturn(false);
|
||||
$this->userManagerMock
|
||||
->expects($this->at(1))
|
||||
->method('checkPassword')
|
||||
->with('testUser', 'new')
|
||||
->willReturn(true);
|
||||
|
||||
|
||||
|
||||
$this->cryptMock
|
||||
->expects($this->once())
|
||||
->method('decryptPrivateKey')
|
||||
@@ -200,7 +214,7 @@ class SettingsControllerTest extends TestCase {
|
||||
$this->keyManagerMock
|
||||
->expects($this->once())
|
||||
->method('setPrivateKey')
|
||||
->with($this->equalTo('testUser'), $this->equalTo('header.encryptedKey'));
|
||||
->with($this->equalTo('testUserUid'), $this->equalTo('header.encryptedKey'));
|
||||
|
||||
$this->sessionMock
|
||||
->expects($this->once())
|
||||
|
||||
@@ -47,6 +47,11 @@ class UserHooksTest extends TestCase {
|
||||
* @var \PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
private $keyManagerMock;
|
||||
/**
|
||||
* @var \PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
private $userManagerMock;
|
||||
|
||||
/**
|
||||
* @var \PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
@@ -101,11 +106,58 @@ class UserHooksTest extends TestCase {
|
||||
$this->assertNull($this->instance->postDeleteUser($this->params));
|
||||
}
|
||||
|
||||
public function testPreSetPassphrase() {
|
||||
$this->userSessionMock->expects($this->once())
|
||||
->method('canChangePassword');
|
||||
/**
|
||||
* @dataProvider dataTestPreSetPassphrase
|
||||
*/
|
||||
public function testPreSetPassphrase($canChange) {
|
||||
|
||||
$this->assertNull($this->instance->preSetPassphrase($this->params));
|
||||
/** @var UserHooks | \PHPUnit_Framework_MockObject_MockObject $instance */
|
||||
$instance = $this->getMockBuilder('OCA\Encryption\Hooks\UserHooks')
|
||||
->setConstructorArgs(
|
||||
[
|
||||
$this->keyManagerMock,
|
||||
$this->userManagerMock,
|
||||
$this->loggerMock,
|
||||
$this->userSetupMock,
|
||||
$this->userSessionMock,
|
||||
$this->utilMock,
|
||||
$this->sessionMock,
|
||||
$this->cryptMock,
|
||||
$this->recoveryMock
|
||||
]
|
||||
)
|
||||
->setMethods(['setPassphrase'])
|
||||
->getMock();
|
||||
|
||||
$userMock = $this->getMock('OCP\IUser');
|
||||
|
||||
$this->userManagerMock->expects($this->once())
|
||||
->method('get')
|
||||
->with($this->params['uid'])
|
||||
->willReturn($userMock);
|
||||
$userMock->expects($this->once())
|
||||
->method('canChangePassword')
|
||||
->willReturn($canChange);
|
||||
|
||||
if ($canChange) {
|
||||
// in this case the password will be changed in the post hook
|
||||
$instance->expects($this->never())->method('setPassphrase');
|
||||
} else {
|
||||
// if user can't change the password we update the encryption
|
||||
// key password already in the pre hook
|
||||
$instance->expects($this->once())
|
||||
->method('setPassphrase')
|
||||
->with($this->params);
|
||||
}
|
||||
|
||||
$instance->preSetPassphrase($this->params);
|
||||
}
|
||||
|
||||
public function dataTestPreSetPassphrase() {
|
||||
return [
|
||||
[true],
|
||||
[false]
|
||||
];
|
||||
}
|
||||
|
||||
public function testSetPassphrase() {
|
||||
@@ -186,6 +238,7 @@ class UserHooksTest extends TestCase {
|
||||
->willReturn(false);
|
||||
|
||||
$userHooks = new UserHooks($this->keyManagerMock,
|
||||
$this->userManagerMock,
|
||||
$this->loggerMock,
|
||||
$this->userSetupMock,
|
||||
$userSessionMock,
|
||||
@@ -216,6 +269,9 @@ class UserHooksTest extends TestCase {
|
||||
$this->keyManagerMock = $this->getMockBuilder('OCA\Encryption\KeyManager')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->userManagerMock = $this->getMockBuilder('OCP\IUserManager')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->userSetupMock = $this->getMockBuilder('OCA\Encryption\Users\Setup')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
@@ -258,6 +314,7 @@ class UserHooksTest extends TestCase {
|
||||
$this->recoveryMock = $recoveryMock;
|
||||
$this->utilMock = $utilMock;
|
||||
$this->instance = new UserHooks($this->keyManagerMock,
|
||||
$this->userManagerMock,
|
||||
$this->loggerMock,
|
||||
$this->userSetupMock,
|
||||
$this->userSessionMock,
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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,8 @@ 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);
|
||||
$this->invokePrivate($m, 'installedVersion', ['0.7']);
|
||||
$m->updateDB();
|
||||
|
||||
$this->verifyDB('`*PREFIX*appconfig`', 'files_encryption', 0);
|
||||
@@ -271,6 +316,59 @@ 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);
|
||||
$this->invokePrivate($m, 'installedVersion', ['0.7']);
|
||||
$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 +389,8 @@ 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);
|
||||
$this->invokePrivate($m, 'installedVersion', ['0.7']);
|
||||
self::invokePrivate($m, 'updateFileCache');
|
||||
|
||||
// check results
|
||||
@@ -353,4 +452,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
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ if ($maxUploadFileSize >= 0 and $totalSize > $maxUploadFileSize) {
|
||||
}
|
||||
|
||||
$result = array();
|
||||
if (strpos($dir, '..') === false) {
|
||||
if (\OC\Files\Filesystem::isValidPath($dir) === true) {
|
||||
$fileCount = count($files['name']);
|
||||
for ($i = 0; $i < $fileCount; $i++) {
|
||||
|
||||
|
||||
@@ -45,12 +45,12 @@ $server->setBaseUri($baseuri);
|
||||
|
||||
// Load plugins
|
||||
$defaults = new OC_Defaults();
|
||||
$server->addPlugin(new \OC\Connector\Sabre\MaintenancePlugin(\OC::$server->getConfig()));
|
||||
$server->addPlugin(new \OC\Connector\Sabre\BlockLegacyClientPlugin(\OC::$server->getConfig()));
|
||||
$server->addPlugin(new \Sabre\DAV\Auth\Plugin($authBackend, $defaults->getName()));
|
||||
// FIXME: The following line is a workaround for legacy components relying on being able to send a GET to /
|
||||
$server->addPlugin(new \OC\Connector\Sabre\DummyGetResponsePlugin());
|
||||
$server->addPlugin(new \OC\Connector\Sabre\FilesPlugin($objectTree));
|
||||
$server->addPlugin(new \OC\Connector\Sabre\MaintenancePlugin(\OC::$server->getConfig()));
|
||||
$server->addPlugin(new \OC\Connector\Sabre\ExceptionLoggerPlugin('webdav', \OC::$server->getLogger()));
|
||||
|
||||
// wait with registering these until auth is handled and the filesystem is setup
|
||||
|
||||
96
apps/files/appinfo/update.php
Normal file
96
apps/files/appinfo/update.php
Normal file
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Björn Schießle <schiessle@owncloud.com>
|
||||
* @author Joas Schilling <nickvergessen@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/>
|
||||
*
|
||||
*/
|
||||
$installedVersion = \OC::$server->getConfig()->getAppValue('files', 'installed_version');
|
||||
$ocVersion = explode('.', \OC::$server->getSystemConfig()->getValue('version'));
|
||||
|
||||
/**
|
||||
* In case encryption was not enabled, we accidently set encrypted = 1 for
|
||||
* files inside mount points, since 8.1.0. This breaks opening the files in
|
||||
* 8.1.1 because we fixed the code that checks if a file is encrypted.
|
||||
* In order to fix the file, we need to reset the flag of the file. However,
|
||||
* the flag might be set because the file is in fact encrypted because it was
|
||||
* uploaded at a time where encryption was enabled.
|
||||
*
|
||||
* So we can only do this when:
|
||||
* - Current version of ownCloud before the update is 8.1.0 or 8.2.0.(0-2)
|
||||
* - Encryption is disabled
|
||||
* - files_encryption is not known in the app config
|
||||
*
|
||||
* If the first two are not the case, we are save. However, if files_encryption
|
||||
* values exist in the config, we might have a false negative here.
|
||||
* Now if there is no file with unencrypted size greater 0, that means there are
|
||||
* no files that are still encrypted with "files_encryption" encryption. So we
|
||||
* can also safely reset the flag here.
|
||||
*
|
||||
* If this is not the case, we go with "better save then sorry" and don't change
|
||||
* the flag but write a message to the ownCloud log file.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param \OCP\IDBConnection $conn
|
||||
*/
|
||||
function owncloud_reset_encrypted_flag(\OCP\IDBConnection $conn) {
|
||||
$conn->executeUpdate('UPDATE `*PREFIX*filecache` SET `encrypted` = 0 WHERE `encrypted` = 1');
|
||||
}
|
||||
|
||||
// Current version of ownCloud before the update is 8.1.0 or 8.2.0.(0-2)
|
||||
if ($installedVersion === '1.1.9' && (
|
||||
// 8.1.0.x
|
||||
(((int) $ocVersion[0]) === 8 && ((int) $ocVersion[1]) === 1 && ((int) $ocVersion[2]) === 0)
|
||||
||
|
||||
// < 8.1.1.1
|
||||
(((int) $ocVersion[0]) === 8 && ((int) $ocVersion[1]) === 1 && ((int) $ocVersion[2]) === 1 && ((int) $ocVersion[3]) < 1)
|
||||
)) {
|
||||
|
||||
// Encryption is not enabled
|
||||
if (!\OC::$server->getEncryptionManager()->isEnabled()) {
|
||||
$conn = \OC::$server->getDatabaseConnection();
|
||||
|
||||
// Old encryption is not known in app config
|
||||
$oldEncryption = \OC::$server->getConfig()->getAppKeys('files_encryption');
|
||||
if (empty($oldEncryption)) {
|
||||
owncloud_reset_encrypted_flag($conn);
|
||||
} else {
|
||||
$query = $conn->prepare('SELECT * FROM `*PREFIX*filecache` WHERE `encrypted` = 1 AND `unencrypted_size` > 0', 1);
|
||||
$query->execute();
|
||||
$empty = $query->fetch();
|
||||
|
||||
if (empty($empty)) {
|
||||
owncloud_reset_encrypted_flag($conn);
|
||||
} else {
|
||||
/**
|
||||
* Sorry in case you are a false positive, but we are not 100% that
|
||||
* you don't have any encrypted files anymore, so we can not reset
|
||||
* the value safely
|
||||
*/
|
||||
\OC::$server->getLogger()->warning(
|
||||
'If you have a problem with files not being accessible and '
|
||||
. 'you are not using encryption, please have a look at the following'
|
||||
. 'issue: {issue}',
|
||||
[
|
||||
'issue' => 'https://github.com/owncloud/core/issues/17846',
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
1.1.9
|
||||
1.1.10
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -1659,6 +1659,7 @@
|
||||
}
|
||||
|
||||
this.$table.addClass('hidden');
|
||||
this.$el.find('#emptycontent').addClass('hidden');
|
||||
|
||||
$mask = $('<div class="mask transparent"></div>');
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@
|
||||
ownerDisplayName = $('#ownerDisplayName').val();
|
||||
if (usedSpacePercent > 98) {
|
||||
if (owner !== oc_current_user) {
|
||||
OC.Notification.show(t('files', 'Storage of {owner} is full, files can not be updated or synced anymore!',
|
||||
OC.Notification.showTemporary(t('files', 'Storage of {owner} is full, files can not be updated or synced anymore!',
|
||||
{ owner: ownerDisplayName }));
|
||||
return;
|
||||
}
|
||||
@@ -125,7 +125,7 @@
|
||||
}
|
||||
if (usedSpacePercent > 90) {
|
||||
if (owner !== oc_current_user) {
|
||||
OC.Notification.show(t('files', 'Storage of {owner} is almost full ({usedSpacePercent}%)',
|
||||
OC.Notification.showTemporary(t('files', 'Storage of {owner} is almost full ({usedSpacePercent}%)',
|
||||
{ usedSpacePercent: usedSpacePercent, owner: ownerDisplayName }));
|
||||
return;
|
||||
}
|
||||
@@ -239,7 +239,6 @@
|
||||
|
||||
// display storage warnings
|
||||
setTimeout(Files.displayStorageWarnings, 100);
|
||||
OC.Notification.setDefault(Files.displayStorageWarnings);
|
||||
|
||||
// only possible at the moment if user is logged in or the files app is loaded
|
||||
if (OC.currentUser && OCA.Files.App) {
|
||||
|
||||
@@ -136,25 +136,26 @@ class Activity implements IExtension {
|
||||
return false;
|
||||
}
|
||||
|
||||
$l = $this->getL10N($languageCode);
|
||||
switch ($text) {
|
||||
case 'created_self':
|
||||
return (string) $this->l->t('You created %1$s', $params);
|
||||
return (string) $l->t('You created %1$s', $params);
|
||||
case 'created_by':
|
||||
return (string) $this->l->t('%2$s created %1$s', $params);
|
||||
return (string) $l->t('%2$s created %1$s', $params);
|
||||
case 'created_public':
|
||||
return (string) $this->l->t('%1$s was created in a public folder', $params);
|
||||
return (string) $l->t('%1$s was created in a public folder', $params);
|
||||
case 'changed_self':
|
||||
return (string) $this->l->t('You changed %1$s', $params);
|
||||
return (string) $l->t('You changed %1$s', $params);
|
||||
case 'changed_by':
|
||||
return (string) $this->l->t('%2$s changed %1$s', $params);
|
||||
return (string) $l->t('%2$s changed %1$s', $params);
|
||||
case 'deleted_self':
|
||||
return (string) $this->l->t('You deleted %1$s', $params);
|
||||
return (string) $l->t('You deleted %1$s', $params);
|
||||
case 'deleted_by':
|
||||
return (string) $this->l->t('%2$s deleted %1$s', $params);
|
||||
return (string) $l->t('%2$s deleted %1$s', $params);
|
||||
case 'restored_self':
|
||||
return (string) $this->l->t('You restored %1$s', $params);
|
||||
return (string) $l->t('You restored %1$s', $params);
|
||||
case 'restored_by':
|
||||
return (string) $this->l->t('%2$s restored %1$s', $params);
|
||||
return (string) $l->t('%2$s restored %1$s', $params);
|
||||
|
||||
default:
|
||||
return false;
|
||||
|
||||
@@ -42,6 +42,9 @@ class ActivityTest extends TestCase {
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject */
|
||||
protected $activityHelper;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject */
|
||||
protected $l10nFactory;
|
||||
|
||||
/** @var \OCA\Files\Activity */
|
||||
protected $activityExtension;
|
||||
|
||||
@@ -67,8 +70,28 @@ class ActivityTest extends TestCase {
|
||||
$this->config
|
||||
);
|
||||
|
||||
$this->l10nFactory = $this->getMockBuilder('OC\L10N\Factory')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$deL10n = $this->getMockBuilder('OC_L10N')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$deL10n->expects($this->any())
|
||||
->method('t')
|
||||
->willReturnCallback(function ($argument) {
|
||||
return 'translate(' . $argument . ')';
|
||||
});
|
||||
|
||||
$this->l10nFactory->expects($this->any())
|
||||
->method('get')
|
||||
->willReturnMap([
|
||||
['files', null, new \OC_L10N('files', 'en')],
|
||||
['files', 'en', new \OC_L10N('files', 'en')],
|
||||
['files', 'de', $deL10n],
|
||||
]);
|
||||
|
||||
$this->activityExtension = $activityExtension = new Activity(
|
||||
new \OC\L10N\Factory(),
|
||||
$this->l10nFactory,
|
||||
$this->getMockBuilder('OCP\IURLGenerator')->disableOriginalConstructor()->getMock(),
|
||||
$this->activityManager,
|
||||
$this->activityHelper,
|
||||
@@ -111,6 +134,26 @@ class ActivityTest extends TestCase {
|
||||
$this->activityExtension->translate('files_sharing', '', [], false, false, 'en'),
|
||||
'Asserting that no translations are set for files_sharing'
|
||||
);
|
||||
|
||||
// Test english
|
||||
$this->assertNotFalse(
|
||||
$this->activityExtension->translate('files', 'deleted_self', ['file'], false, false, 'en'),
|
||||
'Asserting that translations are set for files.deleted_self'
|
||||
);
|
||||
$this->assertStringStartsWith(
|
||||
'You deleted ',
|
||||
$this->activityExtension->translate('files', 'deleted_self', ['file'], false, false, 'en')
|
||||
);
|
||||
|
||||
// Test translation
|
||||
$this->assertNotFalse(
|
||||
$this->activityExtension->translate('files', 'deleted_self', ['file'], false, false, 'de'),
|
||||
'Asserting that translations are set for files.deleted_self'
|
||||
);
|
||||
$this->assertStringStartsWith(
|
||||
'translate(You deleted ',
|
||||
$this->activityExtension->translate('files', 'deleted_self', ['file'], false, false, 'de')
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetSpecialParameterList() {
|
||||
|
||||
3
apps/files_external/3rdparty/.gitignore
vendored
3
apps/files_external/3rdparty/.gitignore
vendored
@@ -1 +1,4 @@
|
||||
example.php
|
||||
icewind/smb/tests
|
||||
icewind/smb/install_libsmbclient.sh
|
||||
icewind/smb/.travis.yml
|
||||
|
||||
2
apps/files_external/3rdparty/composer.json
vendored
2
apps/files_external/3rdparty/composer.json
vendored
@@ -6,7 +6,7 @@
|
||||
"vendor-dir": "."
|
||||
},
|
||||
"require": {
|
||||
"icewind/smb": "1.0.1",
|
||||
"icewind/smb": "1.0.4",
|
||||
"icewind/streams": "0.2"
|
||||
}
|
||||
}
|
||||
|
||||
14
apps/files_external/3rdparty/composer.lock
generated
vendored
14
apps/files_external/3rdparty/composer.lock
generated
vendored
@@ -1,23 +1,23 @@
|
||||
{
|
||||
"_readme": [
|
||||
"This file locks the dependencies of your project to a known state",
|
||||
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"hash": "7b46d64e33feb600c5f0ec830b211e6f",
|
||||
"hash": "5c612406bc1235075305b09a5d6996a9",
|
||||
"packages": [
|
||||
{
|
||||
"name": "icewind/smb",
|
||||
"version": "v1.0.1",
|
||||
"version": "v1.0.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/icewind1991/SMB.git",
|
||||
"reference": "8041bc1960bf2da94e60b88b34e5c78300eac476"
|
||||
"reference": "9277bd20262a01b38a33cc7356e98055f2262d32"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/icewind1991/SMB/zipball/8041bc1960bf2da94e60b88b34e5c78300eac476",
|
||||
"reference": "8041bc1960bf2da94e60b88b34e5c78300eac476",
|
||||
"url": "https://api.github.com/repos/icewind1991/SMB/zipball/9277bd20262a01b38a33cc7356e98055f2262d32",
|
||||
"reference": "9277bd20262a01b38a33cc7356e98055f2262d32",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -45,7 +45,7 @@
|
||||
}
|
||||
],
|
||||
"description": "php wrapper for smbclient and libsmbclient-php",
|
||||
"time": "2015-04-20 11:16:24"
|
||||
"time": "2015-08-17 14:20:38"
|
||||
},
|
||||
{
|
||||
"name": "icewind/streams",
|
||||
|
||||
@@ -43,17 +43,17 @@
|
||||
},
|
||||
{
|
||||
"name": "icewind/smb",
|
||||
"version": "v1.0.1",
|
||||
"version_normalized": "1.0.1.0",
|
||||
"version": "v1.0.4",
|
||||
"version_normalized": "1.0.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/icewind1991/SMB.git",
|
||||
"reference": "8041bc1960bf2da94e60b88b34e5c78300eac476"
|
||||
"reference": "9277bd20262a01b38a33cc7356e98055f2262d32"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/icewind1991/SMB/zipball/8041bc1960bf2da94e60b88b34e5c78300eac476",
|
||||
"reference": "8041bc1960bf2da94e60b88b34e5c78300eac476",
|
||||
"url": "https://api.github.com/repos/icewind1991/SMB/zipball/9277bd20262a01b38a33cc7356e98055f2262d32",
|
||||
"reference": "9277bd20262a01b38a33cc7356e98055f2262d32",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -63,7 +63,7 @@
|
||||
"require-dev": {
|
||||
"satooshi/php-coveralls": "dev-master"
|
||||
},
|
||||
"time": "2015-04-20 11:16:24",
|
||||
"time": "2015-08-17 14:20:38",
|
||||
"type": "library",
|
||||
"installation-source": "source",
|
||||
"autoload": {
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
language: php
|
||||
php:
|
||||
- 5.3
|
||||
- 5.4
|
||||
- 5.5
|
||||
|
||||
env:
|
||||
global:
|
||||
- CURRENT_DIR=`pwd`
|
||||
|
||||
before_install:
|
||||
- pass=$(perl -e 'print crypt("test", "password")')
|
||||
- sudo useradd -m -p $pass test
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install samba smbclient libsmbclient-dev libsmbclient
|
||||
- wget -O /tmp/libsmbclient-php.zip https://github.com/eduardok/libsmbclient-php/archive/master.zip
|
||||
- unzip /tmp/libsmbclient-php.zip -d /tmp
|
||||
- cd /tmp/libsmbclient-php-master
|
||||
- phpize && ./configure && make && sudo make install
|
||||
- echo 'extension="libsmbclient.so"' >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
|
||||
- cd $CURRENT_DIR
|
||||
- chmod go+w $HOME
|
||||
- printf "%s\n%s\n" test test|sudo smbpasswd -s test
|
||||
- sudo mkdir /home/test/test
|
||||
- sudo chown test /home/test/test
|
||||
- |
|
||||
echo "[test]
|
||||
comment = test
|
||||
path = /home/test
|
||||
guest ok = yes
|
||||
writeable = yes
|
||||
map archive = yes
|
||||
map system = yes
|
||||
map hidden = yes
|
||||
create mask = 0777
|
||||
inherit permissions = yes" | sudo tee -a /etc/samba/smb.conf
|
||||
- sudo service smbd restart
|
||||
- testparm -s
|
||||
|
||||
install:
|
||||
- composer install --dev --no-interaction
|
||||
|
||||
script:
|
||||
- mkdir -p build/logs
|
||||
- cd tests
|
||||
- phpunit --coverage-clover ../build/logs/clover.xml --configuration phpunit.xml
|
||||
|
||||
after_script:
|
||||
- cd $CURRENT_DIR
|
||||
- php vendor/bin/coveralls -v
|
||||
26
apps/files_external/3rdparty/icewind/smb/src/AbstractShare.php
vendored
Normal file
26
apps/files_external/3rdparty/icewind/smb/src/AbstractShare.php
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (c) 2015 Robin Appelman <icewind@owncloud.com>
|
||||
* This file is licensed under the Licensed under the MIT license:
|
||||
* http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
namespace Icewind\SMB;
|
||||
|
||||
use Icewind\SMB\Exception\InvalidPathException;
|
||||
|
||||
abstract class AbstractShare implements IShare {
|
||||
private $forbiddenCharacters;
|
||||
|
||||
public function __construct() {
|
||||
$this->forbiddenCharacters = array('?', '<', '>', ':', '*', '|', '"', chr(0), "\n", "\r");
|
||||
}
|
||||
|
||||
protected function verifyPath($path) {
|
||||
foreach ($this->forbiddenCharacters as $char) {
|
||||
if (strpos($path, $char) !== false) {
|
||||
throw new InvalidPathException('Invalid path, "' . $char . '" is not allowed');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,8 +8,10 @@
|
||||
namespace Icewind\SMB;
|
||||
|
||||
use Icewind\SMB\Exception\AuthenticationException;
|
||||
use Icewind\SMB\Exception\ConnectException;
|
||||
use Icewind\SMB\Exception\ConnectionException;
|
||||
use Icewind\SMB\Exception\InvalidHostException;
|
||||
use Icewind\SMB\Exception\NoLoginServerException;
|
||||
|
||||
class Connection extends RawConnection {
|
||||
const DELIMITER = 'smb:';
|
||||
@@ -26,18 +28,25 @@ class Connection extends RawConnection {
|
||||
/**
|
||||
* get all unprocessed output from smbclient until the next prompt
|
||||
*
|
||||
* @throws ConnectionException
|
||||
* @return string
|
||||
* @throws AuthenticationException
|
||||
* @throws ConnectException
|
||||
* @throws ConnectionException
|
||||
* @throws InvalidHostException
|
||||
* @throws NoLoginServerException
|
||||
*/
|
||||
public function read() {
|
||||
if (!$this->isValid()) {
|
||||
throw new ConnectionException();
|
||||
throw new ConnectionException('Connection not valid');
|
||||
}
|
||||
$line = $this->readLine(); //first line is prompt
|
||||
$this->checkConnectionError($line);
|
||||
|
||||
$output = array();
|
||||
$line = $this->readLine();
|
||||
if ($line === false) {
|
||||
throw new ConnectException('Unknown error');
|
||||
}
|
||||
$length = mb_strlen(self::DELIMITER);
|
||||
while (mb_substr($line, 0, $length) !== self::DELIMITER) { //next prompt functions as delimiter
|
||||
$output[] .= $line;
|
||||
@@ -52,20 +61,24 @@ class Connection extends RawConnection {
|
||||
* @param $line
|
||||
* @throws AuthenticationException
|
||||
* @throws InvalidHostException
|
||||
* @throws NoLoginServerException
|
||||
*/
|
||||
private function checkConnectionError($line) {
|
||||
$line = rtrim($line, ')');
|
||||
if (substr($line, -23) === ErrorCodes::LogonFailure) {
|
||||
throw new AuthenticationException();
|
||||
throw new AuthenticationException('Invalid login');
|
||||
}
|
||||
if (substr($line, -26) === ErrorCodes::BadHostName) {
|
||||
throw new InvalidHostException();
|
||||
throw new InvalidHostException('Invalid hostname');
|
||||
}
|
||||
if (substr($line, -22) === ErrorCodes::Unsuccessful) {
|
||||
throw new InvalidHostException();
|
||||
throw new InvalidHostException('Connection unsuccessful');
|
||||
}
|
||||
if (substr($line, -28) === ErrorCodes::ConnectionRefused) {
|
||||
throw new InvalidHostException();
|
||||
throw new InvalidHostException('Connection refused');
|
||||
}
|
||||
if (substr($line, -26) === ErrorCodes::NoLogonServers) {
|
||||
throw new NoLoginServerException('No login server');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ class ErrorCodes {
|
||||
const BadHostName = 'NT_STATUS_BAD_NETWORK_NAME';
|
||||
const Unsuccessful = 'NT_STATUS_UNSUCCESSFUL';
|
||||
const ConnectionRefused = 'NT_STATUS_CONNECTION_REFUSED';
|
||||
const NoLogonServers = 'NT_STATUS_NO_LOGON_SERVERS';
|
||||
|
||||
const PathNotFound = 'NT_STATUS_OBJECT_PATH_NOT_FOUND';
|
||||
const NoSuchFile = 'NT_STATUS_NO_SUCH_FILE';
|
||||
|
||||
10
apps/files_external/3rdparty/icewind/smb/src/Exception/InvalidPathException.php
vendored
Normal file
10
apps/files_external/3rdparty/icewind/smb/src/Exception/InvalidPathException.php
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
|
||||
* This file is licensed under the Licensed under the MIT license:
|
||||
* http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
namespace Icewind\SMB\Exception;
|
||||
|
||||
class InvalidPathException extends InvalidRequestException {}
|
||||
@@ -5,5 +5,6 @@
|
||||
* http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
date_default_timezone_set('UTC');
|
||||
require_once __DIR__.'/../vendor/autoload.php';
|
||||
namespace Icewind\SMB\Exception;
|
||||
|
||||
class NoLoginServerException extends ConnectException {}
|
||||
@@ -24,12 +24,7 @@ class NativeServer extends Server {
|
||||
}
|
||||
|
||||
protected function connect() {
|
||||
$user = $this->getUser();
|
||||
$workgroup = null;
|
||||
if (strpos($user, '/')) {
|
||||
list($workgroup, $user) = explode($user, '/');
|
||||
}
|
||||
$this->state->init($workgroup, $user, $this->getPassword());
|
||||
$this->state->init($this->getWorkgroup(), $this->getUser(), $this->getPassword());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
namespace Icewind\SMB;
|
||||
|
||||
class NativeShare implements IShare {
|
||||
class NativeShare extends AbstractShare {
|
||||
/**
|
||||
* @var Server $server
|
||||
*/
|
||||
@@ -28,6 +28,7 @@ class NativeShare implements IShare {
|
||||
* @param string $name
|
||||
*/
|
||||
public function __construct($server, $name) {
|
||||
parent::__construct();
|
||||
$this->server = $server;
|
||||
$this->name = $name;
|
||||
$this->state = new NativeState();
|
||||
@@ -43,15 +44,7 @@ class NativeShare implements IShare {
|
||||
return;
|
||||
}
|
||||
|
||||
$user = $this->server->getUser();
|
||||
if (strpos($user, '/')) {
|
||||
list($workgroup, $user) = explode('/', $user);
|
||||
} elseif (strpos($user, '\\')) {
|
||||
list($workgroup, $user) = explode('\\', $user);
|
||||
} else {
|
||||
$workgroup = null;
|
||||
}
|
||||
$this->state->init($workgroup, $user, $this->server->getPassword());
|
||||
$this->state->init($this->server->getWorkgroup(), $this->server->getUser(), $this->server->getPassword());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,6 +57,7 @@ class NativeShare implements IShare {
|
||||
}
|
||||
|
||||
private function buildUrl($path) {
|
||||
$this->verifyPath($path);
|
||||
$url = sprintf('smb://%s/%s', $this->server->getHost(), $this->name);
|
||||
if ($path) {
|
||||
$path = trim($path, '/');
|
||||
@@ -149,6 +143,7 @@ class NativeShare implements IShare {
|
||||
* @throws \Icewind\SMB\Exception\InvalidTypeException
|
||||
*/
|
||||
public function del($path) {
|
||||
$this->connect();
|
||||
return $this->state->unlink($this->buildUrl($path));
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,11 @@ class Server {
|
||||
*/
|
||||
protected $password;
|
||||
|
||||
/**
|
||||
* @var string $workgroup
|
||||
*/
|
||||
protected $workgroup;
|
||||
|
||||
/**
|
||||
* Check if the smbclient php extension is available
|
||||
*
|
||||
@@ -45,10 +50,28 @@ class Server {
|
||||
*/
|
||||
public function __construct($host, $user, $password) {
|
||||
$this->host = $host;
|
||||
list($workgroup, $user) = $this->splitUser($user);
|
||||
$this->user = $user;
|
||||
$this->workgroup = $workgroup;
|
||||
$this->password = $password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Split workgroup from username
|
||||
*
|
||||
* @param $user
|
||||
* @return string[] [$workgroup, $user]
|
||||
*/
|
||||
public function splitUser($user) {
|
||||
if (strpos($user, '/')) {
|
||||
return explode('/', $user, 2);
|
||||
} elseif (strpos($user, '\\')) {
|
||||
return explode('\\', $user);
|
||||
} else {
|
||||
return array(null, $user);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
@@ -77,6 +100,13 @@ class Server {
|
||||
return $this->host;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getWorkgroup() {
|
||||
return $this->workgroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Icewind\SMB\IShare[]
|
||||
*
|
||||
@@ -84,7 +114,8 @@ class Server {
|
||||
* @throws \Icewind\SMB\Exception\InvalidHostException
|
||||
*/
|
||||
public function listShares() {
|
||||
$command = Server::CLIENT . ' --authentication-file=/proc/self/fd/3' .
|
||||
$workgroupArgument = ($this->workgroup) ? ' -W ' . escapeshellarg($this->workgroup) : '';
|
||||
$command = Server::CLIENT . $workgroupArgument . ' --authentication-file=/proc/self/fd/3' .
|
||||
' -gL ' . escapeshellarg($this->getHost());
|
||||
$connection = new RawConnection($command);
|
||||
$connection->writeAuthentication($this->getUser(), $this->getPassword());
|
||||
|
||||
@@ -7,17 +7,13 @@
|
||||
|
||||
namespace Icewind\SMB;
|
||||
|
||||
use Icewind\SMB\Exception\AccessDeniedException;
|
||||
use Icewind\SMB\Exception\AlreadyExistsException;
|
||||
use Icewind\SMB\Exception\ConnectionException;
|
||||
use Icewind\SMB\Exception\Exception;
|
||||
use Icewind\SMB\Exception\FileInUseException;
|
||||
use Icewind\SMB\Exception\InvalidTypeException;
|
||||
use Icewind\SMB\Exception\NotEmptyException;
|
||||
use Icewind\SMB\Exception\NotFoundException;
|
||||
use Icewind\Streams\CallbackWrapper;
|
||||
|
||||
class Share implements IShare {
|
||||
class Share extends AbstractShare {
|
||||
/**
|
||||
* @var Server $server
|
||||
*/
|
||||
@@ -43,6 +39,7 @@ class Share implements IShare {
|
||||
* @param string $name
|
||||
*/
|
||||
public function __construct($server, $name) {
|
||||
parent::__construct();
|
||||
$this->server = $server;
|
||||
$this->name = $name;
|
||||
$this->parser = new Parser(new TimeZoneProvider($this->server->getHost()));
|
||||
@@ -57,10 +54,11 @@ class Share implements IShare {
|
||||
if ($this->connection and $this->connection->isValid()) {
|
||||
return;
|
||||
}
|
||||
$command = sprintf('%s --authentication-file=/proc/self/fd/3 //%s/%s',
|
||||
$workgroupArgument = ($this->server->getWorkgroup()) ? ' -W ' . escapeshellarg($this->server->getWorkgroup()) : '';
|
||||
$command = sprintf('%s %s --authentication-file=/proc/self/fd/3 %s',
|
||||
Server::CLIENT,
|
||||
$this->server->getHost(),
|
||||
$this->name
|
||||
$workgroupArgument,
|
||||
escapeshellarg('//' . $this->server->getHost() . '/' . $this->name)
|
||||
);
|
||||
$this->connection = new Connection($command);
|
||||
$this->connection->writeAuthentication($this->server->getUser(), $this->server->getPassword());
|
||||
@@ -256,18 +254,18 @@ class Share implements IShare {
|
||||
*/
|
||||
public function read($source) {
|
||||
$source = $this->escapePath($source);
|
||||
// close the single quote, open a double quote where we put the single quote...
|
||||
$source = str_replace('\'', '\'"\'"\'', $source);
|
||||
// since returned stream is closed by the caller we need to create a new instance
|
||||
// since we can't re-use the same file descriptor over multiple calls
|
||||
$command = sprintf('%s --authentication-file=/proc/self/fd/3 //%s/%s -c \'get %s /proc/self/fd/5\'',
|
||||
$workgroupArgument = ($this->server->getWorkgroup()) ? ' -W ' . escapeshellarg($this->server->getWorkgroup()) : '';
|
||||
$command = sprintf('%s %s --authentication-file=/proc/self/fd/3 %s',
|
||||
Server::CLIENT,
|
||||
$this->server->getHost(),
|
||||
$this->name,
|
||||
$source
|
||||
$workgroupArgument,
|
||||
escapeshellarg('//' . $this->server->getHost() . '/' . $this->name)
|
||||
);
|
||||
$connection = new Connection($command);
|
||||
$connection->writeAuthentication($this->server->getUser(), $this->server->getPassword());
|
||||
$connection->write('get ' . $source . ' /proc/self/fd/5');
|
||||
$connection->write('exit');
|
||||
$fh = $connection->getFileOutputStream();
|
||||
stream_context_set_option($fh, 'file', 'connection', $connection);
|
||||
return $fh;
|
||||
@@ -284,23 +282,24 @@ class Share implements IShare {
|
||||
*/
|
||||
public function write($target) {
|
||||
$target = $this->escapePath($target);
|
||||
// close the single quote, open a double quote where we put the single quote...
|
||||
$target = str_replace('\'', '\'"\'"\'', $target);
|
||||
// since returned stream is closed by the caller we need to create a new instance
|
||||
// since we can't re-use the same file descriptor over multiple calls
|
||||
$command = sprintf('%s --authentication-file=/proc/self/fd/3 //%s/%s -c \'put /proc/self/fd/4 %s\'',
|
||||
$workgroupArgument = ($this->server->getWorkgroup()) ? ' -W ' . escapeshellarg($this->server->getWorkgroup()) : '';
|
||||
$command = sprintf('%s %s --authentication-file=/proc/self/fd/3 %s',
|
||||
Server::CLIENT,
|
||||
$this->server->getHost(),
|
||||
$this->name,
|
||||
$target
|
||||
$workgroupArgument,
|
||||
escapeshellarg('//' . $this->server->getHost() . '/' . $this->name)
|
||||
);
|
||||
$connection = new RawConnection($command);
|
||||
$connection = new Connection($command);
|
||||
$connection->writeAuthentication($this->server->getUser(), $this->server->getPassword());
|
||||
$fh = $connection->getFileInputStream();
|
||||
|
||||
$connection->write('put /proc/self/fd/4 ' . $target);
|
||||
$connection->write('exit');
|
||||
|
||||
// use a close callback to ensure the upload is finished before continuing
|
||||
// this also serves as a way to keep the connection in scope
|
||||
return CallbackWrapper::wrap($fh, null, null, function () use ($connection) {
|
||||
return CallbackWrapper::wrap($fh, null, null, function () use ($connection, $target) {
|
||||
$connection->close(false); // dont terminate, give the upload some time
|
||||
});
|
||||
}
|
||||
@@ -378,6 +377,7 @@ class Share implements IShare {
|
||||
* @return string
|
||||
*/
|
||||
protected function escapePath($path) {
|
||||
$this->verifyPath($path);
|
||||
if ($path === '/') {
|
||||
$path = '';
|
||||
}
|
||||
|
||||
@@ -1,539 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
|
||||
* This file is licensed under the Licensed under the MIT license:
|
||||
* http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
namespace Icewind\SMB\Test;
|
||||
|
||||
use Icewind\SMB\FileInfo;
|
||||
|
||||
abstract class AbstractShare extends \PHPUnit_Framework_TestCase {
|
||||
/**
|
||||
* @var \Icewind\SMB\Server $server
|
||||
*/
|
||||
protected $server;
|
||||
|
||||
/**
|
||||
* @var \Icewind\SMB\IShare $share
|
||||
*/
|
||||
protected $share;
|
||||
|
||||
/**
|
||||
* @var string $root
|
||||
*/
|
||||
protected $root;
|
||||
|
||||
protected $config;
|
||||
|
||||
public function tearDown() {
|
||||
try {
|
||||
if ($this->share) {
|
||||
$this->cleanDir($this->root);
|
||||
}
|
||||
unset($this->share);
|
||||
} catch (\Exception $e) {
|
||||
unset($this->share);
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
public function nameProvider() {
|
||||
// / ? < > \ : * | " are illegal characters in path on windows
|
||||
return array(
|
||||
array('simple'),
|
||||
array('with spaces_and-underscores'),
|
||||
array("single'quote'"),
|
||||
array('日本語'),
|
||||
array('url %2F +encode'),
|
||||
array('a somewhat longer filename than the other with more charaters as the all the other filenames'),
|
||||
array('$as#d€££Ö€ßœĚęĘĞĜΣΥΦΩΫ')
|
||||
);
|
||||
}
|
||||
|
||||
public function fileDataProvider() {
|
||||
return array(
|
||||
array('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua'),
|
||||
array('Mixed language, 日本語 が わからか and Various _/* characters \\|” €')
|
||||
);
|
||||
}
|
||||
|
||||
public function nameAndDataProvider() {
|
||||
$names = $this->nameProvider();
|
||||
$data = $this->fileDataProvider();
|
||||
$result = array();
|
||||
foreach ($names as $name) {
|
||||
foreach ($data as $text) {
|
||||
$result[] = array($name[0], $text[0]);
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function cleanDir($dir) {
|
||||
$content = $this->share->dir($dir);
|
||||
foreach ($content as $metadata) {
|
||||
if ($metadata->isDirectory()) {
|
||||
$this->cleanDir($metadata->getPath());
|
||||
} else {
|
||||
$this->share->del($metadata->getPath());
|
||||
}
|
||||
}
|
||||
$this->share->rmdir($dir);
|
||||
}
|
||||
|
||||
private function getTextFile($text = '') {
|
||||
if (!$text) {
|
||||
$text = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua';
|
||||
}
|
||||
$file = tempnam('/tmp', 'smb_test_');
|
||||
file_put_contents($file, $text);
|
||||
return $file;
|
||||
}
|
||||
|
||||
public function testListShares() {
|
||||
$shares = $this->server->listShares();
|
||||
foreach ($shares as $share) {
|
||||
if ($share->getName() === $this->config->share) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
$this->fail('Share "' . $this->config->share . '" not found');
|
||||
}
|
||||
|
||||
public function testRootStartsEmpty() {
|
||||
$this->assertEquals(array(), $this->share->dir($this->root));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider nameProvider
|
||||
*/
|
||||
public function testMkdir($name) {
|
||||
$this->share->mkdir($this->root . '/' . $name);
|
||||
$dirs = $this->share->dir($this->root);
|
||||
$this->assertCount(1, $dirs);
|
||||
$this->assertEquals($name, $dirs[0]->getName());
|
||||
$this->assertTrue($dirs[0]->isDirectory());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider nameProvider
|
||||
*/
|
||||
public function testRenameDirectory($name) {
|
||||
$this->share->mkdir($this->root . '/' . $name);
|
||||
$this->share->rename($this->root . '/' . $name, $this->root . '/' . $name . '_rename');
|
||||
$dirs = $this->share->dir($this->root);
|
||||
$this->assertEquals(1, count($dirs));
|
||||
$this->assertEquals($name . '_rename', $dirs[0]->getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider nameProvider
|
||||
*/
|
||||
public function testRmdir($name) {
|
||||
$this->share->mkdir($this->root . '/' . $name);
|
||||
$this->share->rmdir($this->root . '/' . $name);
|
||||
$this->assertCount(0, $this->share->dir($this->root));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider nameAndDataProvider
|
||||
*/
|
||||
public function testPut($name, $text) {
|
||||
$tmpFile = $this->getTextFile($text);
|
||||
$size = filesize($tmpFile);
|
||||
|
||||
$this->share->put($tmpFile, $this->root . '/' . $name);
|
||||
unlink($tmpFile);
|
||||
|
||||
$files = $this->share->dir($this->root);
|
||||
$this->assertCount(1, $files);
|
||||
$this->assertEquals($name, $files[0]->getName());
|
||||
$this->assertEquals($size, $files[0]->getSize());
|
||||
$this->assertFalse($files[0]->isDirectory());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider nameProvider
|
||||
*/
|
||||
public function testRenameFile($name) {
|
||||
$tmpFile = $this->getTextFile();
|
||||
|
||||
$this->share->put($tmpFile, $this->root . '/' . $name);
|
||||
unlink($tmpFile);
|
||||
|
||||
$this->share->rename($this->root . '/' . $name, $this->root . '/' . $name . '_renamed');
|
||||
|
||||
$files = $this->share->dir($this->root);
|
||||
$this->assertEquals(1, count($files));
|
||||
$this->assertEquals($name . '_renamed', $files[0]->getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider nameAndDataProvider
|
||||
*/
|
||||
public function testGet($name, $text) {
|
||||
$tmpFile = $this->getTextFile($text);
|
||||
|
||||
$this->share->put($tmpFile, $this->root . '/' . $name);
|
||||
unlink($tmpFile);
|
||||
|
||||
$targetFile = tempnam('/tmp', 'smb_test_');
|
||||
$this->share->get($this->root . '/' . $name, $targetFile);
|
||||
|
||||
$this->assertEquals($text, file_get_contents($targetFile));
|
||||
unlink($targetFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider nameProvider
|
||||
*/
|
||||
public function testDel($name) {
|
||||
$tmpFile = $this->getTextFile();
|
||||
|
||||
$this->share->put($tmpFile, $this->root . '/' . $name);
|
||||
unlink($tmpFile);
|
||||
|
||||
$this->share->del($this->root . '/' . $name);
|
||||
$this->assertCount(0, $this->share->dir($this->root));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Icewind\SMB\Exception\NotFoundException
|
||||
*/
|
||||
public function testCreateFolderInNonExistingFolder() {
|
||||
$this->share->mkdir($this->root . '/foo/bar');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Icewind\SMB\Exception\NotFoundException
|
||||
*/
|
||||
public function testRemoveFolderInNonExistingFolder() {
|
||||
$this->share->rmdir($this->root . '/foo/bar');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Icewind\SMB\Exception\NotFoundException
|
||||
*/
|
||||
public function testRemoveNonExistingFolder() {
|
||||
$this->share->rmdir($this->root . '/foo');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Icewind\SMB\Exception\AlreadyExistsException
|
||||
*/
|
||||
public function testCreateExistingFolder() {
|
||||
$this->share->mkdir($this->root . '/bar');
|
||||
$this->share->mkdir($this->root . '/bar');
|
||||
$this->share->rmdir($this->root . '/bar');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Icewind\SMB\Exception\InvalidTypeException
|
||||
*/
|
||||
public function testCreateFileExistingFolder() {
|
||||
$this->share->mkdir($this->root . '/bar');
|
||||
$this->share->put($this->getTextFile(), $this->root . '/bar');
|
||||
$this->share->rmdir($this->root . '/bar');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Icewind\SMB\Exception\NotFoundException
|
||||
*/
|
||||
public function testCreateFileInNonExistingFolder() {
|
||||
$this->share->put($this->getTextFile(), $this->root . '/foo/bar');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Icewind\SMB\Exception\NotFoundException
|
||||
*/
|
||||
public function testTestRemoveNonExistingFile() {
|
||||
$this->share->del($this->root . '/foo');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Icewind\SMB\Exception\NotFoundException
|
||||
*/
|
||||
public function testDownloadNonExistingFile() {
|
||||
$this->share->get($this->root . '/foo', '/dev/null');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Icewind\SMB\Exception\InvalidTypeException
|
||||
*/
|
||||
public function testDownloadFolder() {
|
||||
$this->share->mkdir($this->root . '/foobar');
|
||||
$this->share->get($this->root . '/foobar', '/dev/null');
|
||||
$this->share->rmdir($this->root . '/foobar');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Icewind\SMB\Exception\InvalidTypeException
|
||||
*/
|
||||
public function testDelFolder() {
|
||||
$this->share->mkdir($this->root . '/foobar');
|
||||
$this->share->del($this->root . '/foobar');
|
||||
$this->share->rmdir($this->root . '/foobar');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Icewind\SMB\Exception\InvalidTypeException
|
||||
*/
|
||||
public function testRmdirFile() {
|
||||
$this->share->put($this->getTextFile(), $this->root . '/foobar');
|
||||
$this->share->rmdir($this->root . '/foobar');
|
||||
$this->share->del($this->root . '/foobar');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Icewind\SMB\Exception\NotEmptyException
|
||||
*/
|
||||
public function testRmdirNotEmpty() {
|
||||
$this->share->mkdir($this->root . '/foobar');
|
||||
$this->share->put($this->getTextFile(), $this->root . '/foobar/asd');
|
||||
$this->share->rmdir($this->root . '/foobar');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Icewind\SMB\Exception\NotFoundException
|
||||
*/
|
||||
public function testDirNonExisting() {
|
||||
$this->share->dir('/foobar/asd');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Icewind\SMB\Exception\NotFoundException
|
||||
*/
|
||||
public function testRmDirNonExisting() {
|
||||
$this->share->rmdir('/foobar/asd');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Icewind\SMB\Exception\NotFoundException
|
||||
*/
|
||||
public function testRenameNonExisting() {
|
||||
$this->share->rename('/foobar/asd', '/foobar/bar');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Icewind\SMB\Exception\NotFoundException
|
||||
*/
|
||||
public function testRenameTargetNonExisting() {
|
||||
$txt = $this->getTextFile();
|
||||
$this->share->put($txt, $this->root . '/foo.txt');
|
||||
unlink($txt);
|
||||
$this->share->rename($this->root . '/foo.txt', $this->root . '/bar/foo.txt');
|
||||
}
|
||||
|
||||
public function testModifiedDate() {
|
||||
$now = time();
|
||||
$this->share->put($this->getTextFile(), $this->root . '/foo.txt');
|
||||
$dir = $this->share->dir($this->root);
|
||||
$mtime = $dir[0]->getMTime();
|
||||
$this->assertTrue(abs($now - $mtime) <= 2, 'Modified time differs by ' . abs($now - $mtime) . ' seconds');
|
||||
$this->share->del($this->root . '/foo.txt');
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider nameAndDataProvider
|
||||
*/
|
||||
public function testReadStream($name, $text) {
|
||||
$sourceFile = $this->getTextFile($text);
|
||||
$this->share->put($sourceFile, $this->root . '/' . $name);
|
||||
$fh = $this->share->read($this->root . '/' . $name);
|
||||
$content = stream_get_contents($fh);
|
||||
fclose($fh);
|
||||
$this->share->del($this->root . '/' . $name);
|
||||
|
||||
$this->assertEquals(file_get_contents($sourceFile), $content);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider nameAndDataProvider
|
||||
*/
|
||||
public function testWriteStream($name, $text) {
|
||||
$fh = $this->share->write($this->root . '/' . $name);
|
||||
fwrite($fh, $text);
|
||||
fclose($fh);
|
||||
|
||||
$tmpFile1 = tempnam('/tmp', 'smb_test_');
|
||||
$this->share->get($this->root . '/' . $name, $tmpFile1);
|
||||
$this->assertEquals($text, file_get_contents($tmpFile1));
|
||||
$this->share->del($this->root . '/' . $name);
|
||||
unlink($tmpFile1);
|
||||
}
|
||||
|
||||
public function testDir() {
|
||||
$txtFile = $this->getTextFile();
|
||||
|
||||
$this->share->mkdir($this->root . '/dir');
|
||||
$this->share->put($txtFile, $this->root . '/file.txt');
|
||||
unlink($txtFile);
|
||||
|
||||
$dir = $this->share->dir($this->root);
|
||||
if ($dir[0]->getName() === 'dir') {
|
||||
$dirEntry = $dir[0];
|
||||
} else {
|
||||
$dirEntry = $dir[1];
|
||||
}
|
||||
$this->assertTrue($dirEntry->isDirectory());
|
||||
$this->assertFalse($dirEntry->isReadOnly());
|
||||
$this->assertFalse($dirEntry->isReadOnly());
|
||||
|
||||
if ($dir[0]->getName() === 'file.txt') {
|
||||
$fileEntry = $dir[0];
|
||||
} else {
|
||||
$fileEntry = $dir[1];
|
||||
}
|
||||
$this->assertFalse($fileEntry->isDirectory());
|
||||
$this->assertFalse($fileEntry->isReadOnly());
|
||||
$this->assertFalse($fileEntry->isReadOnly());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider nameProvider
|
||||
*/
|
||||
public function testStat($name) {
|
||||
$txtFile = $this->getTextFile();
|
||||
$size = filesize($txtFile);
|
||||
|
||||
$this->share->put($txtFile, $this->root . '/' . $name);
|
||||
unlink($txtFile);
|
||||
|
||||
$info = $this->share->stat($this->root . '/' . $name);
|
||||
$this->assertEquals($size, $info->getSize());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Icewind\SMB\Exception\NotFoundException
|
||||
*/
|
||||
public function testStatNonExisting() {
|
||||
$this->share->stat($this->root . '/fo.txt');
|
||||
}
|
||||
|
||||
/**
|
||||
* note setting archive and system bit is not supported
|
||||
*
|
||||
* @dataProvider nameProvider
|
||||
*/
|
||||
public function testSetMode($name) {
|
||||
$txtFile = $this->getTextFile();
|
||||
|
||||
$this->share->put($txtFile, $this->root . '/' . $name);
|
||||
|
||||
$this->share->setMode($this->root . '/' . $name, FileInfo::MODE_NORMAL);
|
||||
$info = $this->share->stat($this->root . '/' . $name);
|
||||
$this->assertFalse($info->isReadOnly());
|
||||
$this->assertFalse($info->isArchived());
|
||||
$this->assertFalse($info->isSystem());
|
||||
$this->assertFalse($info->isHidden());
|
||||
|
||||
$this->share->setMode($this->root . '/' . $name, FileInfo::MODE_READONLY);
|
||||
$info = $this->share->stat($this->root . '/' . $name);
|
||||
$this->assertTrue($info->isReadOnly());
|
||||
$this->assertFalse($info->isArchived());
|
||||
$this->assertFalse($info->isSystem());
|
||||
$this->assertFalse($info->isHidden());
|
||||
|
||||
$this->share->setMode($this->root . '/' . $name, FileInfo::MODE_ARCHIVE);
|
||||
$info = $this->share->stat($this->root . '/' . $name);
|
||||
$this->assertFalse($info->isReadOnly());
|
||||
$this->assertTrue($info->isArchived());
|
||||
$this->assertFalse($info->isSystem());
|
||||
$this->assertFalse($info->isHidden());
|
||||
|
||||
$this->share->setMode($this->root . '/' . $name, FileInfo::MODE_READONLY | FileInfo::MODE_ARCHIVE);
|
||||
$info = $this->share->stat($this->root . '/' . $name);
|
||||
$this->assertTrue($info->isReadOnly());
|
||||
$this->assertTrue($info->isArchived());
|
||||
$this->assertFalse($info->isSystem());
|
||||
$this->assertFalse($info->isHidden());
|
||||
|
||||
$this->share->setMode($this->root . '/' . $name, FileInfo::MODE_HIDDEN);
|
||||
$info = $this->share->stat($this->root . '/' . $name);
|
||||
$this->assertFalse($info->isReadOnly());
|
||||
$this->assertFalse($info->isArchived());
|
||||
$this->assertFalse($info->isSystem());
|
||||
$this->assertTrue($info->isHidden());
|
||||
|
||||
$this->share->setMode($this->root . '/' . $name, FileInfo::MODE_SYSTEM);
|
||||
$info = $this->share->stat($this->root . '/' . $name);
|
||||
$this->assertFalse($info->isReadOnly());
|
||||
$this->assertFalse($info->isArchived());
|
||||
$this->assertTrue($info->isSystem());
|
||||
$this->assertFalse($info->isHidden());
|
||||
|
||||
$this->share->setMode($this->root . '/' . $name, FileInfo::MODE_NORMAL);
|
||||
$info = $this->share->stat($this->root . '/' . $name);
|
||||
$this->assertFalse($info->isReadOnly());
|
||||
$this->assertFalse($info->isArchived());
|
||||
$this->assertFalse($info->isSystem());
|
||||
$this->assertFalse($info->isHidden());
|
||||
}
|
||||
|
||||
public function pathProvider() {
|
||||
// / ? < > \ : * | " are illegal characters in path on windows
|
||||
return array(
|
||||
array('dir/sub/foo.txt'),
|
||||
array('bar.txt'),
|
||||
array("single'quote'/sub/foo.txt"),
|
||||
array('日本語/url %2F +encode/asd.txt'),
|
||||
array(
|
||||
'a somewhat longer folder than the other with more charaters as the all the other filenames/' .
|
||||
'followed by a somewhat long file name after that.txt'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider pathProvider
|
||||
*/
|
||||
public function testSubDirs($path) {
|
||||
$dirs = explode('/', $path);
|
||||
$name = array_pop($dirs);
|
||||
$fullPath = '';
|
||||
foreach ($dirs as $dir) {
|
||||
$fullPath .= '/' . $dir;
|
||||
$this->share->mkdir($this->root . $fullPath);
|
||||
}
|
||||
$txtFile = $this->getTextFile();
|
||||
$size = filesize($txtFile);
|
||||
$this->share->put($txtFile, $this->root . $fullPath . '/' . $name);
|
||||
unlink($txtFile);
|
||||
$info = $this->share->stat($this->root . $fullPath . '/' . $name);
|
||||
$this->assertEquals($size, $info->getSize());
|
||||
$this->assertFalse($info->isHidden());
|
||||
}
|
||||
|
||||
public function testDelAfterStat() {
|
||||
$name = 'foo.txt';
|
||||
$txtFile = $this->getTextFile();
|
||||
|
||||
$this->share->put($txtFile, $this->root . '/' . $name);
|
||||
unlink($txtFile);
|
||||
|
||||
$this->share->stat($this->root . '/' . $name);
|
||||
$this->share->del($this->root . '/foo.txt');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @dataProvider nameProvider
|
||||
*/
|
||||
public function testDirPaths($name) {
|
||||
$txtFile = $this->getTextFile();
|
||||
$this->share->mkdir($this->root . '/' . $name);
|
||||
$this->share->put($txtFile, $this->root . '/' . $name . '/' . $name);
|
||||
unlink($txtFile);
|
||||
|
||||
$content = $this->share->dir($this->root . '/' . $name);
|
||||
$this->assertCount(1, $content);
|
||||
$this->assertEquals($name, $content[0]->getName());
|
||||
}
|
||||
|
||||
public function testStatRoot() {
|
||||
$info = $this->share->stat('/');
|
||||
$this->assertInstanceOf('\Icewind\SMB\IFileInfo', $info);
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
|
||||
* This file is licensed under the Licensed under the MIT license:
|
||||
* http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
namespace Icewind\SMB\Test;
|
||||
|
||||
use Icewind\SMB\NativeServer;
|
||||
|
||||
class NativeShare extends AbstractShare {
|
||||
public function setUp() {
|
||||
if (!function_exists('smbclient_state_new')) {
|
||||
$this->markTestSkipped('libsmbclient php extension not installed');
|
||||
}
|
||||
$this->config = json_decode(file_get_contents(__DIR__ . '/config.json'));
|
||||
$this->server = new NativeServer($this->config->host, $this->config->user, $this->config->password);
|
||||
$this->share = $this->server->getShare($this->config->share);
|
||||
if ($this->config->root) {
|
||||
$this->root = '/' . $this->config->root . '/' . uniqid();
|
||||
} else {
|
||||
$this->root = '/' . uniqid();
|
||||
}
|
||||
$this->share->mkdir($this->root);
|
||||
}
|
||||
}
|
||||
@@ -1,143 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
|
||||
* This file is licensed under the Licensed under the MIT license:
|
||||
* http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
namespace Icewind\SMB\Test;
|
||||
|
||||
use Icewind\SMB\NativeServer;
|
||||
|
||||
class NativeStream extends \PHPUnit_Framework_TestCase {
|
||||
/**
|
||||
* @var \Icewind\SMB\Server $server
|
||||
*/
|
||||
protected $server;
|
||||
|
||||
/**
|
||||
* @var \Icewind\SMB\NativeShare $share
|
||||
*/
|
||||
protected $share;
|
||||
|
||||
/**
|
||||
* @var string $root
|
||||
*/
|
||||
protected $root;
|
||||
|
||||
protected $config;
|
||||
|
||||
public function setUp() {
|
||||
if (!function_exists('smbclient_state_new')) {
|
||||
$this->markTestSkipped('libsmbclient php extension not installed');
|
||||
}
|
||||
$this->config = json_decode(file_get_contents(__DIR__ . '/config.json'));
|
||||
$this->server = new NativeServer($this->config->host, $this->config->user, $this->config->password);
|
||||
$this->share = $this->server->getShare($this->config->share);
|
||||
if ($this->config->root) {
|
||||
$this->root = '/' . $this->config->root . '/' . uniqid();
|
||||
} else {
|
||||
$this->root = '/' . uniqid();
|
||||
}
|
||||
$this->share->mkdir($this->root);
|
||||
}
|
||||
|
||||
private function getTextFile() {
|
||||
$text = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua';
|
||||
$file = tempnam('/tmp', 'smb_test_');
|
||||
file_put_contents($file, $text);
|
||||
return $file;
|
||||
}
|
||||
|
||||
public function testSeekTell() {
|
||||
$sourceFile = $this->getTextFile();
|
||||
$this->share->put($sourceFile, $this->root . '/foobar');
|
||||
$fh = $this->share->read($this->root . '/foobar');
|
||||
$content = fread($fh, 3);
|
||||
$this->assertEquals('Lor', $content);
|
||||
|
||||
fseek($fh, -2, SEEK_CUR);
|
||||
|
||||
$content = fread($fh, 3);
|
||||
$this->assertEquals('ore', $content);
|
||||
|
||||
fseek($fh, 3, SEEK_SET);
|
||||
|
||||
$content = fread($fh, 3);
|
||||
$this->assertEquals('em ', $content);
|
||||
|
||||
fseek($fh, -3, SEEK_END);
|
||||
|
||||
$content = fread($fh, 3);
|
||||
$this->assertEquals('qua', $content);
|
||||
|
||||
fseek($fh, -3, SEEK_END);
|
||||
$this->assertEquals(120, ftell($fh));
|
||||
}
|
||||
|
||||
public function testStat() {
|
||||
$sourceFile = $this->getTextFile();
|
||||
$this->share->put($sourceFile, $this->root . '/foobar');
|
||||
$fh = $this->share->read($this->root . '/foobar');
|
||||
$stat = fstat($fh);
|
||||
$this->assertEquals(filesize($sourceFile), $stat['size']);
|
||||
unlink($sourceFile);
|
||||
}
|
||||
|
||||
public function testTruncate() {
|
||||
if (version_compare(phpversion(), '5.4.0', '<')) {
|
||||
$this->markTestSkipped('php <5.4 doesn\'t support truncate for stream wrappers');
|
||||
}
|
||||
$fh = $this->share->write($this->root . '/foobar');
|
||||
fwrite($fh, 'foobar');
|
||||
ftruncate($fh, 3);
|
||||
fclose($fh);
|
||||
|
||||
$fh = $this->share->read($this->root . '/foobar');
|
||||
$this->assertEquals('foo', stream_get_contents($fh));
|
||||
}
|
||||
|
||||
public function testEOF() {
|
||||
if (version_compare(phpversion(), '5.4.0', '<')) {
|
||||
$this->markTestSkipped('php <5.4 doesn\'t support truncate for stream wrappers');
|
||||
}
|
||||
$fh = $this->share->write($this->root . '/foobar');
|
||||
fwrite($fh, 'foobar');
|
||||
fclose($fh);
|
||||
|
||||
$fh = $this->share->read($this->root . '/foobar');
|
||||
fread($fh, 3);
|
||||
$this->assertFalse(feof($fh));
|
||||
fread($fh, 5);
|
||||
$this->assertTrue(feof($fh));
|
||||
}
|
||||
|
||||
public function testLockUnsupported() {
|
||||
$fh = $this->share->write($this->root . '/foobar');
|
||||
$this->assertFalse(flock($fh, LOCK_SH));
|
||||
}
|
||||
|
||||
public function testSetOptionUnsupported() {
|
||||
$fh = $this->share->write($this->root . '/foobar');
|
||||
$this->assertFalse(stream_set_blocking($fh, false));
|
||||
}
|
||||
|
||||
public function tearDown() {
|
||||
if ($this->share) {
|
||||
$this->cleanDir($this->root);
|
||||
}
|
||||
unset($this->share);
|
||||
}
|
||||
|
||||
public function cleanDir($dir) {
|
||||
$content = $this->share->dir($dir);
|
||||
foreach ($content as $metadata) {
|
||||
if ($metadata->isDirectory()) {
|
||||
$this->cleanDir($metadata->getPath());
|
||||
} else {
|
||||
$this->share->del($metadata->getPath());
|
||||
}
|
||||
}
|
||||
$this->share->rmdir($dir);
|
||||
}
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
|
||||
* This file is licensed under the Licensed under the MIT license:
|
||||
* http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
namespace Icewind\SMB\Test;
|
||||
|
||||
|
||||
use Icewind\SMB\FileInfo;
|
||||
|
||||
class Parser extends \PHPUnit_Framework_TestCase {
|
||||
public function modeProvider() {
|
||||
return array(
|
||||
array('D', FileInfo::MODE_DIRECTORY),
|
||||
array('A', FileInfo::MODE_ARCHIVE),
|
||||
array('S', FileInfo::MODE_SYSTEM),
|
||||
array('H', FileInfo::MODE_HIDDEN),
|
||||
array('R', FileInfo::MODE_READONLY),
|
||||
array('N', FileInfo::MODE_NORMAL),
|
||||
array('RA', FileInfo::MODE_READONLY | FileInfo::MODE_ARCHIVE),
|
||||
array('RAH', FileInfo::MODE_READONLY | FileInfo::MODE_ARCHIVE | FileInfo::MODE_HIDDEN)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $timeZone
|
||||
* @return \Icewind\SMB\TimeZoneProvider
|
||||
*/
|
||||
private function getTimeZoneProvider($timeZone) {
|
||||
$mock = $this->getMockBuilder('\Icewind\SMB\TimeZoneProvider')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$mock->expects($this->any())
|
||||
->method('get')
|
||||
->will($this->returnValue($timeZone));
|
||||
return $mock;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider modeProvider
|
||||
*/
|
||||
public function testParseMode($string, $mode) {
|
||||
$parser = new \Icewind\SMB\Parser($this->getTimeZoneProvider('UTC'));
|
||||
$this->assertEquals($mode, $parser->parseMode($string), 'Failed parsing ' . $string);
|
||||
}
|
||||
|
||||
public function statProvider() {
|
||||
return array(
|
||||
array(
|
||||
array(
|
||||
'altname: test.txt',
|
||||
'create_time: Sat Oct 12 07:05:58 PM 2013 CEST',
|
||||
'access_time: Tue Oct 15 02:58:48 PM 2013 CEST',
|
||||
'write_time: Sat Oct 12 07:05:58 PM 2013 CEST',
|
||||
'change_time: Sat Oct 12 07:05:58 PM 2013 CEST',
|
||||
'attributes: (80)',
|
||||
'stream: [::$DATA], 29634 bytes'
|
||||
),
|
||||
array(
|
||||
'mtime' => strtotime('12 Oct 2013 19:05:58 CEST'),
|
||||
'mode' => FileInfo::MODE_NORMAL,
|
||||
'size' => 29634
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider statProvider
|
||||
*/
|
||||
public function testStat($output, $stat) {
|
||||
$parser = new \Icewind\SMB\Parser($this->getTimeZoneProvider('UTC'));
|
||||
$this->assertEquals($stat, $parser->parseStat($output));
|
||||
}
|
||||
|
||||
public function dirProvider() {
|
||||
return array(
|
||||
array(
|
||||
array(
|
||||
' . D 0 Tue Aug 26 19:11:56 2014',
|
||||
' .. DR 0 Sun Oct 28 15:24:02 2012',
|
||||
' c.pdf N 29634 Sat Oct 12 19:05:58 2013',
|
||||
'',
|
||||
' 62536 blocks of size 8388608. 57113 blocks available'
|
||||
),
|
||||
array(
|
||||
new FileInfo('/c.pdf', 'c.pdf', 29634, strtotime('12 Oct 2013 19:05:58 CEST'),
|
||||
FileInfo::MODE_NORMAL)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dirProvider
|
||||
*/
|
||||
public function testDir($output, $dir) {
|
||||
$parser = new \Icewind\SMB\Parser($this->getTimeZoneProvider('CEST'));
|
||||
$this->assertEquals($dir, $parser->parseDir($output, ''));
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
|
||||
* This file is licensed under the Licensed under the MIT license:
|
||||
* http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
namespace Icewind\SMB\Test;
|
||||
|
||||
class Server extends \PHPUnit_Framework_TestCase {
|
||||
/**
|
||||
* @var \Icewind\SMB\Server $server
|
||||
*/
|
||||
private $server;
|
||||
|
||||
private $config;
|
||||
|
||||
public function setUp() {
|
||||
$this->config = json_decode(file_get_contents(__DIR__ . '/config.json'));
|
||||
$this->server = new \Icewind\SMB\Server($this->config->host, $this->config->user, $this->config->password);
|
||||
}
|
||||
|
||||
public function testListShares() {
|
||||
$shares = $this->server->listShares();
|
||||
foreach ($shares as $share) {
|
||||
if ($share->getName() === $this->config->share) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
$this->fail('Share "' . $this->config->share . '" not found');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Icewind\SMB\Exception\AuthenticationException
|
||||
*/
|
||||
public function testWrongUserName() {
|
||||
$this->markTestSkipped('This fails for no reason on travis');
|
||||
$server = new \Icewind\SMB\Server($this->config->host, uniqid(), uniqid());
|
||||
$server->listShares();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Icewind\SMB\Exception\AuthenticationException
|
||||
*/
|
||||
public function testWrongPassword() {
|
||||
$server = new \Icewind\SMB\Server($this->config->host, $this->config->user, uniqid());
|
||||
$server->listShares();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Icewind\SMB\Exception\InvalidHostException
|
||||
*/
|
||||
public function testWrongHost() {
|
||||
$server = new \Icewind\SMB\Server(uniqid(), $this->config->user, $this->config->password);
|
||||
$server->listShares();
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
|
||||
* This file is licensed under the Licensed under the MIT license:
|
||||
* http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
namespace Icewind\SMB\Test;
|
||||
|
||||
use Icewind\SMB\Server as NormalServer;
|
||||
|
||||
class Share extends AbstractShare {
|
||||
public function setUp() {
|
||||
$this->config = json_decode(file_get_contents(__DIR__ . '/config.json'));
|
||||
$this->server = new NormalServer($this->config->host, $this->config->user, $this->config->password);
|
||||
$this->share = $this->server->getShare($this->config->share);
|
||||
if ($this->config->root) {
|
||||
$this->root = '/' . $this->config->root . '/' . uniqid();
|
||||
} else {
|
||||
$this->root = '/' . uniqid();
|
||||
}
|
||||
$this->share->mkdir($this->root);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"host": "localhost",
|
||||
"user": "test",
|
||||
"password": "test",
|
||||
"share": "test",
|
||||
"root": "test"
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<phpunit bootstrap="bootstrap.php">
|
||||
<testsuite name='SMB'>
|
||||
<directory suffix='.php'>./</directory>
|
||||
</testsuite>
|
||||
</phpunit>
|
||||
@@ -90,6 +90,15 @@ abstract class StoragesController extends Controller {
|
||||
}
|
||||
|
||||
// TODO: validate that other attrs are set
|
||||
if ($storage->getBackendOption('objectstore')) {
|
||||
// objectstore must not be sent from client side
|
||||
return new DataResponse(
|
||||
array(
|
||||
'message' => (string)$this->l10n->t('Objectstore forbidden')
|
||||
),
|
||||
Http::STATUS_UNPROCESSABLE_ENTITY
|
||||
);
|
||||
}
|
||||
|
||||
$backends = \OC_Mount_Config::getBackends();
|
||||
if (!isset($backends[$storage->getBackendClass()])) {
|
||||
|
||||
@@ -121,7 +121,7 @@ class AmazonS3 extends \OC\Files\Storage\Common {
|
||||
$params['region'] = empty($params['region']) ? 'eu-west-1' : $params['region'];
|
||||
$params['hostname'] = empty($params['hostname']) ? 's3.amazonaws.com' : $params['hostname'];
|
||||
if (!isset($params['port']) || $params['port'] === '') {
|
||||
$params['port'] = ($params['use_ssl'] === 'false') ? 80 : 443;
|
||||
$params['port'] = ($params['use_ssl'] === false || $params['use_ssl'] === 'false') ? 80 : 443;
|
||||
}
|
||||
$this->params = $params;
|
||||
}
|
||||
@@ -586,7 +586,7 @@ class AmazonS3 extends \OC\Files\Storage\Common {
|
||||
return $this->connection;
|
||||
}
|
||||
|
||||
$scheme = ($this->params['use_ssl'] === 'false') ? 'http' : 'https';
|
||||
$scheme = ($this->params['use_ssl'] === false || $this->params['use_ssl'] === 'false') ? 'http' : 'https';
|
||||
$base_url = $scheme . '://' . $this->params['hostname'] . ':' . $this->params['port'] . '/';
|
||||
|
||||
$this->connection = S3Client::factory(array(
|
||||
|
||||
@@ -297,7 +297,9 @@ class OC_Mount_Config {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$input = str_replace('$user', $user, $input);
|
||||
if (is_string($input)) {
|
||||
$input = str_replace('$user', $user, $input);
|
||||
}
|
||||
}
|
||||
return $input;
|
||||
}
|
||||
|
||||
@@ -78,7 +78,10 @@ class SMB extends Common {
|
||||
* @return string
|
||||
*/
|
||||
public function getId() {
|
||||
return 'smb::' . $this->server->getUser() . '@' . $this->server->getHost() . '/' . $this->share->getName() . '/' . $this->root;
|
||||
// FIXME: double slash to keep compatible with the old storage ids,
|
||||
// failure to do so will lead to creation of a new storage id and
|
||||
// loss of shares from the storage
|
||||
return 'smb::' . $this->server->getUser() . '@' . $this->server->getHost() . '//' . $this->share->getName() . '/' . $this->root;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -39,7 +39,7 @@ class SMB_OC extends SMB {
|
||||
public function __construct($params) {
|
||||
if (isset($params['host'])) {
|
||||
$host = $params['host'];
|
||||
$this->username_as_share = ($params['username_as_share'] === 'true');
|
||||
$this->username_as_share = ($params['username_as_share'] === true);
|
||||
|
||||
// dummy credentials, unused, to satisfy constructor
|
||||
$user = 'foo';
|
||||
|
||||
@@ -173,6 +173,25 @@ class StorageConfig implements \JsonSerializable {
|
||||
$this->backendOptions = $backendOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $option
|
||||
* @return mixed
|
||||
*/
|
||||
public function getBackendOption($key) {
|
||||
if (isset($this->backendOptions[$key])) {
|
||||
return $this->backendOptions[$key];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $option
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function setBackendOption($key, $value) {
|
||||
$this->backendOptions[$key] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mount priority
|
||||
*
|
||||
|
||||
@@ -40,8 +40,11 @@ abstract class StreamWrapper extends Common {
|
||||
}
|
||||
|
||||
public function rmdir($path) {
|
||||
if ($this->file_exists($path) && $this->isDeletable($path)) {
|
||||
if ($this->is_dir($path) && $this->isDeletable($path)) {
|
||||
$dh = $this->opendir($path);
|
||||
if (!is_resource($dh)) {
|
||||
return false;
|
||||
}
|
||||
while (($file = readdir($dh)) !== false) {
|
||||
if ($this->is_dir($path . '/' . $file)) {
|
||||
$this->rmdir($path . '/' . $file);
|
||||
|
||||
@@ -352,10 +352,14 @@ abstract class StoragesService {
|
||||
if (!isset($allStorages[$id])) {
|
||||
throw new NotFoundException('Storage with id "' . $id . '" not found');
|
||||
}
|
||||
|
||||
$oldStorage = $allStorages[$id];
|
||||
$allStorages[$id] = $updatedStorage;
|
||||
|
||||
// ensure objectstore is persistent
|
||||
if ($objectstore = $oldStorage->getBackendOption('objectstore')) {
|
||||
$updatedStorage->setBackendOption('objectstore', $objectstore);
|
||||
}
|
||||
|
||||
$allStorages[$id] = $updatedStorage;
|
||||
$this->writeConfig($allStorages);
|
||||
|
||||
$this->triggerChangeHooks($oldStorage, $updatedStorage);
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
<?php elseif (strpos($placeholder, '!') === 0): ?>
|
||||
<label><input type="checkbox"
|
||||
data-parameter="<?php p($parameter); ?>"
|
||||
<?php if ($value == 'true'): ?> checked="checked"<?php endif; ?>
|
||||
<?php if ($value === true || $value === 'true'): ?> checked="checked"<?php endif; ?>
|
||||
/><?php p(substr($placeholder, 1)); ?></label>
|
||||
<?php elseif (strpos($placeholder, '#') === 0): ?>
|
||||
<input type="hidden"
|
||||
|
||||
@@ -61,4 +61,16 @@ class SMB extends Storage {
|
||||
$this->assertTrue($result);
|
||||
$this->assertTrue($this->instance->is_dir('foo bar'));
|
||||
}
|
||||
|
||||
public function testStorageId() {
|
||||
$this->instance = new \OC\Files\Storage\SMB([
|
||||
'host' => 'testhost',
|
||||
'user' => 'testuser',
|
||||
'password' => 'somepass',
|
||||
'share' => 'someshare',
|
||||
'root' => 'someroot',
|
||||
]);
|
||||
$this->assertEquals('smb::testuser@testhost//someshare//someroot/', $this->instance->getId());
|
||||
$this->instance = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -39,9 +39,6 @@ $l = \OC::$server->getL10N('files_sharing');
|
||||
\OC::$CLASSPATH['OCA\Files\Share\Maintainer'] = 'files_sharing/lib/maintainer.php';
|
||||
\OC::$CLASSPATH['OCA\Files\Share\Proxy'] = 'files_sharing/lib/proxy.php';
|
||||
|
||||
// Exceptions
|
||||
\OC::$CLASSPATH['OCA\Files_Sharing\Exceptions\BrokenPath'] = 'files_sharing/lib/exceptions.php';
|
||||
|
||||
$application = new Application();
|
||||
$application->registerMountProviders();
|
||||
$application->setupPropagation();
|
||||
@@ -57,10 +54,6 @@ $application->setupPropagation();
|
||||
\OCP\Util::addScript('files_sharing', 'share');
|
||||
\OCP\Util::addScript('files_sharing', 'external');
|
||||
|
||||
// FIXME: registering a job here will cause additional useless SQL queries
|
||||
// when the route is not cron.php, needs a better way
|
||||
\OC::$server->getJobList()->add('OCA\Files_sharing\Lib\DeleteOrphanedSharesJob');
|
||||
|
||||
\OC::$server->getActivityManager()->registerExtension(function() {
|
||||
return new \OCA\Files_Sharing\Activity(
|
||||
\OC::$server->query('L10NFactory'),
|
||||
|
||||
@@ -59,7 +59,6 @@ class Application extends App {
|
||||
return new ExternalSharesController(
|
||||
$c->query('AppName'),
|
||||
$c->query('Request'),
|
||||
$c->query('IsIncomingShareEnabled'),
|
||||
$c->query('ExternalManager')
|
||||
);
|
||||
});
|
||||
@@ -76,9 +75,6 @@ class Application extends App {
|
||||
$container->registerService('UserManager', function (SimpleContainer $c) use ($server) {
|
||||
return $server->getUserManager();
|
||||
});
|
||||
$container->registerService('IsIncomingShareEnabled', function (SimpleContainer $c) {
|
||||
return Helper::isIncomingServer2serverShareEnabled();
|
||||
});
|
||||
$container->registerService('ExternalManager', function (SimpleContainer $c) use ($server) {
|
||||
$user = $server->getUserSession()->getUser();
|
||||
$uid = $user ? $user->getUID() : null;
|
||||
@@ -98,7 +94,8 @@ class Application extends App {
|
||||
return new SharingCheckMiddleware(
|
||||
$c->query('AppName'),
|
||||
$server->getConfig(),
|
||||
$server->getAppManager()
|
||||
$server->getAppManager(),
|
||||
$c['ControllerMethodReflector']
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
22
apps/files_sharing/appinfo/install.php
Normal file
22
apps/files_sharing/appinfo/install.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Joas Schilling <nickvergessen@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/>
|
||||
*
|
||||
*/
|
||||
|
||||
\OC::$server->getJobList()->add('OCA\Files_sharing\Lib\DeleteOrphanedSharesJob');
|
||||
@@ -28,3 +28,4 @@ if (version_compare($installedVersion, '0.6.0', '<')) {
|
||||
$m->addAcceptRow();
|
||||
}
|
||||
|
||||
\OC::$server->getJobList()->add('OCA\Files_sharing\Lib\DeleteOrphanedSharesJob');
|
||||
|
||||
@@ -1 +1 @@
|
||||
0.6.1
|
||||
0.6.3
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -158,9 +158,18 @@ OCA.Sharing.PublicApp = {
|
||||
};
|
||||
|
||||
this.fileList.generatePreviewUrl = function (urlSpec) {
|
||||
urlSpec = urlSpec || {};
|
||||
if (!urlSpec.x) {
|
||||
urlSpec.x = 36;
|
||||
}
|
||||
if (!urlSpec.y) {
|
||||
urlSpec.y = 36;
|
||||
}
|
||||
urlSpec.x *= window.devicePixelRatio;
|
||||
urlSpec.y *= window.devicePixelRatio;
|
||||
urlSpec.x = Math.floor(urlSpec.x);
|
||||
urlSpec.y = Math.floor(urlSpec.y);
|
||||
urlSpec.t = $('#dirToken').val();
|
||||
urlSpec.y = Math.floor(36 * window.devicePixelRatio);
|
||||
urlSpec.x = Math.floor(36 * window.devicePixelRatio);
|
||||
return OC.generateUrl('/apps/files_sharing/ajax/publicpreview.php?') + $.param(urlSpec);
|
||||
};
|
||||
|
||||
@@ -292,15 +301,8 @@ $(document).ready(function () {
|
||||
|
||||
if (window.Files) {
|
||||
// HACK: for oc-dialogs previews that depends on Files:
|
||||
Files.lazyLoadPreview = function (path, mime, ready, width, height, etag) {
|
||||
return App.fileList.lazyLoadPreview({
|
||||
path: path,
|
||||
mime: mime,
|
||||
callback: ready,
|
||||
width: width,
|
||||
height: height,
|
||||
etag: etag
|
||||
});
|
||||
Files.generatePreviewUrl = function (urlSpec) {
|
||||
return App.fileList.generatePreviewUrl(urlSpec);
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
@@ -25,6 +25,10 @@
|
||||
* @param {OCA.Files.FileList} fileList file list to be extended
|
||||
*/
|
||||
attach: function(fileList) {
|
||||
// core sharing is disabled/not loaded
|
||||
if (!OC.Share) {
|
||||
return;
|
||||
}
|
||||
if (fileList.id === 'trashbin' || fileList.id === 'files.public') {
|
||||
return;
|
||||
}
|
||||
@@ -151,7 +155,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.
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
|
||||
namespace OC\Files\Cache;
|
||||
|
||||
use OC\User\NoUserException;
|
||||
use OCP\Share_Backend_Collection;
|
||||
|
||||
/**
|
||||
@@ -60,9 +61,14 @@ class Shared_Cache extends Cache {
|
||||
if ($target === false || $target === $this->storage->getMountPoint()) {
|
||||
$target = '';
|
||||
}
|
||||
$source = \OC_Share_Backend_File::getSource($target, $this->storage->getMountPoint(), $this->storage->getItemType());
|
||||
$source = \OC_Share_Backend_File::getSource($target, $this->storage->getShare());
|
||||
if (isset($source['path']) && isset($source['fileOwner'])) {
|
||||
\OC\Files\Filesystem::initMountPoints($source['fileOwner']);
|
||||
try {
|
||||
\OC\Files\Filesystem::initMountPoints($source['fileOwner']);
|
||||
} catch(NoUserException $e) {
|
||||
\OC::$server->getLogger()->logException($e, ['app' => 'files_sharing']);
|
||||
return false;
|
||||
}
|
||||
$mounts = \OC\Files\Filesystem::getMountByNumericId($source['storage']);
|
||||
if (is_array($mounts) and !empty($mounts)) {
|
||||
$fullPath = $mounts[0]->getMountPoint() . $source['path'];
|
||||
@@ -242,7 +248,7 @@ class Shared_Cache extends Cache {
|
||||
*/
|
||||
protected function getMoveInfo($path) {
|
||||
$cache = $this->getSourceCache($path);
|
||||
$file = \OC_Share_Backend_File::getSource($path, $this->storage->getMountPoint(), $this->storage->getItemType());
|
||||
$file = \OC_Share_Backend_File::getSource($path, $this->storage->getShare());
|
||||
return [$cache->getNumericStorageId(), $file['path']];
|
||||
}
|
||||
|
||||
|
||||
@@ -59,20 +59,20 @@ class Capabilities {
|
||||
$public['enabled'] = $this->config->getAppValue('core', 'shareapi_allow_links', 'yes') === 'yes';
|
||||
if ($public['enabled']) {
|
||||
$public['password'] = [];
|
||||
$public['password']['enforced'] = ($this->config->getAppValue('core', 'shareapi_enforce_links_password', 'yes') === 'yes');
|
||||
$public['password']['enforced'] = ($this->config->getAppValue('core', 'shareapi_enforce_links_password', 'no') === 'yes');
|
||||
|
||||
$public['expire_date'] = [];
|
||||
$public['expire_date']['enabled'] = $this->config->getAppValue('core', 'shareapi_default_expire_date', 'yes') === 'yes';
|
||||
$public['expire_date']['enabled'] = $this->config->getAppValue('core', 'shareapi_default_expire_date', 'no') === 'yes';
|
||||
if ($public['expire_date']['enabled']) {
|
||||
$public['expire_date']['days'] = $this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7');
|
||||
$public['expire_date']['enforced'] = $this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'yes') === 'yes';
|
||||
$public['expire_date']['enforced'] = $this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no') === 'yes';
|
||||
}
|
||||
|
||||
$public['send_mail'] = $this->config->getAppValue('core', 'shareapi_allow_public_notification', 'yes') === 'yes';
|
||||
$public['send_mail'] = $this->config->getAppValue('core', 'shareapi_allow_public_notification', 'no') === 'yes';
|
||||
}
|
||||
$res["public"] = $public;
|
||||
|
||||
$res['user']['send_mail'] = $this->config->getAppValue('core', 'shareapi_allow_mail_notification', 'yes') === 'yes';
|
||||
$res['user']['send_mail'] = $this->config->getAppValue('core', 'shareapi_allow_mail_notification', 'no') === 'yes';
|
||||
|
||||
$res['resharing'] = $this->config->getAppValue('core', 'shareapi_allow_resharing', 'yes') === 'yes';
|
||||
|
||||
|
||||
@@ -82,10 +82,13 @@ class PublicAuth extends \Sabre\DAV\Auth\Backend\AbstractBasic {
|
||||
|
||||
}
|
||||
return true;
|
||||
} else if (\OC::$server->getSession()->exists('public_link_authenticated')
|
||||
&& \OC::$server->getSession()->get('public_link_authenticated') === $linkItem['id']) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} elseif ($linkItem['share_type'] == \OCP\Share::SHARE_TYPE_REMOTE) {
|
||||
} else if ($linkItem['share_type'] == \OCP\Share::SHARE_TYPE_REMOTE) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
||||
@@ -36,8 +36,6 @@ use OCP\AppFramework\Http\JSONResponse;
|
||||
*/
|
||||
class ExternalSharesController extends Controller {
|
||||
|
||||
/** @var bool */
|
||||
private $incomingShareEnabled;
|
||||
/** @var \OCA\Files_Sharing\External\Manager */
|
||||
private $externalManager;
|
||||
|
||||
@@ -49,52 +47,42 @@ class ExternalSharesController extends Controller {
|
||||
*/
|
||||
public function __construct($appName,
|
||||
IRequest $request,
|
||||
$incomingShareEnabled,
|
||||
\OCA\Files_Sharing\External\Manager $externalManager) {
|
||||
parent::__construct($appName, $request);
|
||||
$this->incomingShareEnabled = $incomingShareEnabled;
|
||||
$this->externalManager = $externalManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
* @NoOutgoingFederatedSharingRequired
|
||||
*
|
||||
* @return JSONResponse
|
||||
*/
|
||||
public function index() {
|
||||
$shares = [];
|
||||
if ($this->incomingShareEnabled) {
|
||||
$shares = $this->externalManager->getOpenShares();
|
||||
}
|
||||
return new JSONResponse($shares);
|
||||
return new JSONResponse($this->externalManager->getOpenShares());
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
* @NoOutgoingFederatedSharingRequired
|
||||
*
|
||||
* @param int $id
|
||||
* @return JSONResponse
|
||||
*/
|
||||
public function create($id) {
|
||||
if ($this->incomingShareEnabled) {
|
||||
$this->externalManager->acceptShare($id);
|
||||
}
|
||||
|
||||
$this->externalManager->acceptShare($id);
|
||||
return new JSONResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
* @NoOutgoingFederatedSharingRequired
|
||||
*
|
||||
* @param $id
|
||||
* @return JSONResponse
|
||||
*/
|
||||
public function destroy($id) {
|
||||
if ($this->incomingShareEnabled) {
|
||||
$this->externalManager->declineShare($id);
|
||||
}
|
||||
|
||||
$this->externalManager->declineShare($id);
|
||||
return new JSONResponse();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ use OCA\Files_Sharing\Helper;
|
||||
use OCP\User;
|
||||
use OCP\Util;
|
||||
use OCA\Files_Sharing\Activity;
|
||||
use \OCP\Files\NotFoundException;
|
||||
|
||||
/**
|
||||
* Class ShareController
|
||||
@@ -148,6 +149,7 @@ class ShareController extends Controller {
|
||||
* @param string $token
|
||||
* @param string $path
|
||||
* @return TemplateResponse|RedirectResponse
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function showShare($token, $path = '') {
|
||||
\OC_User::setIncognitoMode(true);
|
||||
@@ -171,7 +173,7 @@ class ShareController extends Controller {
|
||||
$getPath = Filesystem::normalizePath($path);
|
||||
$originalSharePath .= $path;
|
||||
} else {
|
||||
throw new OCP\Files\NotFoundException();
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
$file = basename($originalSharePath);
|
||||
@@ -303,7 +305,7 @@ class ShareController extends Controller {
|
||||
/**
|
||||
* @param string $token
|
||||
* @return string Resolved file path of the token
|
||||
* @throws \Exception In case share could not get properly resolved
|
||||
* @throws NotFoundException In case share could not get properly resolved
|
||||
*/
|
||||
private function getPath($token) {
|
||||
$linkItem = Share::getShareByToken($token, false);
|
||||
@@ -312,7 +314,7 @@ class ShareController extends Controller {
|
||||
$rootLinkItem = Share::resolveReShare($linkItem);
|
||||
if (isset($rootLinkItem['uid_owner'])) {
|
||||
if(!$this->userManager->userExists($rootLinkItem['uid_owner'])) {
|
||||
throw new \Exception('Owner of the share does not exist anymore');
|
||||
throw new NotFoundException('Owner of the share does not exist anymore');
|
||||
}
|
||||
OC_Util::tearDownFS();
|
||||
OC_Util::setupFS($rootLinkItem['uid_owner']);
|
||||
@@ -324,6 +326,6 @@ class ShareController extends Controller {
|
||||
}
|
||||
}
|
||||
|
||||
throw new \Exception('No file found belonging to file.');
|
||||
throw new NotFoundException('No file found belonging to file.');
|
||||
}
|
||||
}
|
||||
|
||||
26
apps/files_sharing/lib/exceptions/s2sexception.php
Normal file
26
apps/files_sharing/lib/exceptions/s2sexception.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
/**
|
||||
* @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\Exceptions;
|
||||
|
||||
/**
|
||||
* S2S sharing not allowed
|
||||
*/
|
||||
class S2SException extends \Exception {
|
||||
}
|
||||
3
apps/files_sharing/lib/external/scanner.php
vendored
3
apps/files_sharing/lib/external/scanner.php
vendored
@@ -48,9 +48,10 @@ class Scanner extends \OC\Files\Cache\Scanner {
|
||||
* @param int $reuseExisting
|
||||
* @param int $parentId
|
||||
* @param array | null $cacheData existing data in the cache for the file to be scanned
|
||||
* @param bool $lock set to false to disable getting an additional read lock during scanning
|
||||
* @return array an array of metadata of the scanned file
|
||||
*/
|
||||
public function scanFile($file, $reuseExisting = 0, $parentId = -1, $cacheData = null) {
|
||||
public function scanFile($file, $reuseExisting = 0, $parentId = -1, $cacheData = null, $lock = true) {
|
||||
try {
|
||||
return parent::scanFile($file, $reuseExisting);
|
||||
} catch (ForbiddenException $e) {
|
||||
|
||||
20
apps/files_sharing/lib/external/storage.php
vendored
20
apps/files_sharing/lib/external/storage.php
vendored
@@ -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);
|
||||
|
||||
@@ -27,7 +27,11 @@ use OCP\App\IAppManager;
|
||||
use OCP\AppFramework\Http\NotFoundResponse;
|
||||
use OCP\AppFramework\Middleware;
|
||||
use OCP\AppFramework\Http\TemplateResponse;
|
||||
use OCP\Files\NotFoundException;
|
||||
use OCP\IConfig;
|
||||
use OCP\AppFramework\Utility\IControllerMethodReflector;
|
||||
use OCA\Files_Sharing\Exceptions\S2SException;
|
||||
use OCP\AppFramework\Http\JSONResponse;
|
||||
|
||||
/**
|
||||
* Checks whether the "sharing check" is enabled
|
||||
@@ -42,6 +46,8 @@ class SharingCheckMiddleware extends Middleware {
|
||||
protected $config;
|
||||
/** @var IAppManager */
|
||||
protected $appManager;
|
||||
/** @var IControllerMethodReflector */
|
||||
protected $reflector;
|
||||
|
||||
/***
|
||||
* @param string $appName
|
||||
@@ -50,30 +56,74 @@ class SharingCheckMiddleware extends Middleware {
|
||||
*/
|
||||
public function __construct($appName,
|
||||
IConfig $config,
|
||||
IAppManager $appManager) {
|
||||
IAppManager $appManager,
|
||||
IControllerMethodReflector $reflector
|
||||
) {
|
||||
$this->appName = $appName;
|
||||
$this->config = $config;
|
||||
$this->appManager = $appManager;
|
||||
$this->reflector = $reflector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if sharing is enabled before the controllers is executed
|
||||
*
|
||||
* @param \OCP\AppFramework\Controller $controller
|
||||
* @param string $methodName
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function beforeController($controller, $methodName) {
|
||||
if(!$this->isSharingEnabled()) {
|
||||
throw new \Exception('Sharing is disabled.');
|
||||
throw new NotFoundException('Sharing is disabled.');
|
||||
}
|
||||
|
||||
if ($controller instanceof \OCA\Files_Sharing\Controllers\ExternalSharesController &&
|
||||
!$this->externalSharesChecks()) {
|
||||
throw new S2SException('Federated sharing not allowed');
|
||||
} else if ($controller instanceof \OCA\Files_Sharing\Controllers\ShareController &&
|
||||
!$this->isLinkSharingEnabled()) {
|
||||
throw new NotFoundException('Link sharing is disabled');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return 404 page in case of an exception
|
||||
* Return 404 page in case of a not found exception
|
||||
*
|
||||
* @param \OCP\AppFramework\Controller $controller
|
||||
* @param string $methodName
|
||||
* @param \Exception $exception
|
||||
* @return TemplateResponse
|
||||
* @return NotFoundResponse
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function afterException($controller, $methodName, \Exception $exception){
|
||||
return new NotFoundResponse();
|
||||
public function afterException($controller, $methodName, \Exception $exception) {
|
||||
if(is_a($exception, '\OCP\Files\NotFoundException')) {
|
||||
return new NotFoundResponse();
|
||||
}
|
||||
|
||||
if (is_a($exception, '\OCA\Files_Sharing\Exceptions\S2SException')) {
|
||||
return new JSONResponse($exception->getMessage(), 405);
|
||||
}
|
||||
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for externalshares controller
|
||||
* @return bool
|
||||
*/
|
||||
private function externalSharesChecks() {
|
||||
|
||||
if (!$this->reflector->hasAnnotation('NoIncomingFederatedSharingRequired') &&
|
||||
$this->config->getAppValue('files_sharing', 'incoming_server2server_share_enabled', 'yes') !== 'yes') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->reflector->hasAnnotation('NoOutgoingFederatedSharingRequired') &&
|
||||
$this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') !== 'yes') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -87,6 +137,19 @@ class SharingCheckMiddleware extends Middleware {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if link sharing is allowed
|
||||
* @return bool
|
||||
*/
|
||||
private function isLinkSharingEnabled() {
|
||||
// Check if the shareAPI is enabled
|
||||
if ($this->config->getAppValue('core', 'shareapi_enabled', 'yes') !== 'yes') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check whether public sharing is enabled
|
||||
if($this->config->getAppValue('core', 'shareapi_allow_links', 'yes') !== 'yes') {
|
||||
return false;
|
||||
|
||||
@@ -66,12 +66,6 @@ class MountProvider implements IMountProvider {
|
||||
return $share['permissions'] > 0;
|
||||
});
|
||||
$shares = array_map(function ($share) use ($user, $storageFactory) {
|
||||
try {
|
||||
Filesystem::initMountPoints($share['uid_owner']);
|
||||
} catch(NoUserException $e) {
|
||||
\OC::$server->getLogger()->warning('The user \'' . $share['uid_owner'] . '\' of share with ID \'' . $share['id'] . '\' can\'t be retrieved.', array('app' => 'files_sharing'));
|
||||
return null;
|
||||
}
|
||||
// for updating etags for the share owner when we make changes to this share.
|
||||
$ownerPropagator = $this->propagationManager->getChangePropagator($share['uid_owner']);
|
||||
|
||||
|
||||
@@ -126,20 +126,28 @@ class RecipientPropagator {
|
||||
});
|
||||
}
|
||||
|
||||
protected $propagatingIds = [];
|
||||
|
||||
public function propagateById($id) {
|
||||
if (isset($this->propagatingIds[$id])) {
|
||||
return;
|
||||
}
|
||||
$this->propagatingIds[$id] = true;
|
||||
$shares = Share::getAllSharesForFileId($id);
|
||||
foreach ($shares as $share) {
|
||||
// propagate down the share tree
|
||||
$this->markDirty($share, microtime(true));
|
||||
|
||||
// propagate up the share tree
|
||||
$user = $share['uid_owner'];
|
||||
if($user !== $this->userId) {
|
||||
if ($share['share_with'] === $this->userId) {
|
||||
$user = $share['uid_owner'];
|
||||
$view = new View('/' . $user . '/files');
|
||||
$path = $view->getPath($share['file_source']);
|
||||
$watcher = new ChangeWatcher($view, $this->manager->getSharePropagator($user));
|
||||
$watcher->writeHook(['path' => $path]);
|
||||
}
|
||||
}
|
||||
|
||||
unset($this->propagatingIds[$id]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,27 +206,15 @@ class OC_Share_Backend_File implements OCP\Share_Backend_File_Dependent {
|
||||
|
||||
/**
|
||||
* @param string $target
|
||||
* @param string $mountPoint
|
||||
* @param string $itemType
|
||||
* @param array $share
|
||||
* @return array|false source item
|
||||
*/
|
||||
public static function getSource($target, $mountPoint, $itemType) {
|
||||
if ($itemType === 'folder') {
|
||||
$source = \OCP\Share::getItemSharedWith('folder', $mountPoint, \OC_Share_Backend_File::FORMAT_SHARED_STORAGE);
|
||||
if ($source && $target !== '') {
|
||||
// note: in case of ext storage mount points the path might be empty
|
||||
// which would cause a leading slash to appear
|
||||
$source['path'] = ltrim($source['path'] . '/' . $target, '/');
|
||||
}
|
||||
} else {
|
||||
$source = \OCP\Share::getItemSharedWith('file', $mountPoint, \OC_Share_Backend_File::FORMAT_SHARED_STORAGE);
|
||||
public static function getSource($target, $share) {
|
||||
if ($share['item_type'] === 'folder' && $target !== '') {
|
||||
// note: in case of ext storage mount points the path might be empty
|
||||
// which would cause a leading slash to appear
|
||||
$share['path'] = ltrim($share['path'] . '/' . $target, '/');
|
||||
}
|
||||
if ($source) {
|
||||
return self::resolveReshares($source);
|
||||
}
|
||||
|
||||
\OCP\Util::writeLog('files_sharing', 'File source not found for: '.$target, \OCP\Util::DEBUG);
|
||||
return false;
|
||||
return self::resolveReshares($share);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -41,35 +41,47 @@ class SharedMount extends MountPoint implements MoveableMount {
|
||||
*/
|
||||
protected $ownerPropagator;
|
||||
|
||||
/**
|
||||
* @var \OC\Files\View
|
||||
*/
|
||||
private $recipientView;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $user;
|
||||
|
||||
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']);
|
||||
$absMountPoint = '/' . $arguments['user'] . '/files' . $newMountPoint;
|
||||
$this->user = $arguments['user'];
|
||||
$this->recipientView = new View('/' . $this->user . '/files');
|
||||
$newMountPoint = $this->verifyMountPoint($arguments['share']);
|
||||
$absMountPoint = '/' . $this->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']) {
|
||||
self::updateFileTarget($newMountPoint, $share);
|
||||
if ($newMountPoint !== $share['file_target']) {
|
||||
$this->updateFileTarget($newMountPoint, $share);
|
||||
$share['file_target'] = $newMountPoint;
|
||||
$share['unique_name'] = true;
|
||||
}
|
||||
@@ -79,11 +91,12 @@ 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
|
||||
*/
|
||||
private static function updateFileTarget($newPath, &$share) {
|
||||
private function updateFileTarget($newPath, &$share) {
|
||||
// if the user renames a mount point from a group share we need to create a new db entry
|
||||
// for the unique name
|
||||
if ($share['share_type'] === \OCP\Share::SHARE_TYPE_GROUP && empty($share['unique_name'])) {
|
||||
@@ -91,7 +104,7 @@ class SharedMount extends MountPoint implements MoveableMount {
|
||||
.' `share_type`, `share_with`, `uid_owner`, `permissions`, `stime`, `file_source`,'
|
||||
.' `file_target`, `token`, `parent`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)');
|
||||
$arguments = array($share['item_type'], $share['item_source'], $share['item_target'],
|
||||
2, \OCP\User::getUser(), $share['uid_owner'], $share['permissions'], $share['stime'], $share['file_source'],
|
||||
2, $this->user, $share['uid_owner'], $share['permissions'], $share['stime'], $share['file_source'],
|
||||
$newPath, $share['token'], $share['id']);
|
||||
} else {
|
||||
// rename mount point
|
||||
@@ -99,7 +112,7 @@ class SharedMount extends MountPoint implements MoveableMount {
|
||||
'Update `*PREFIX*share`
|
||||
SET `file_target` = ?
|
||||
WHERE `id` = ?'
|
||||
);
|
||||
);
|
||||
$arguments = array($newPath, $share['id']);
|
||||
}
|
||||
|
||||
|
||||
@@ -45,8 +45,18 @@ 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'];
|
||||
}
|
||||
|
||||
private function init() {
|
||||
Filesystem::initMountPoints($this->share['uid_owner']);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,17 +84,18 @@ class Shared extends \OC\Files\Storage\Common implements ISharedStorage {
|
||||
* @return array Returns array with the keys path, permissions, and owner or false if not found
|
||||
*/
|
||||
public function getFile($target) {
|
||||
$this->init();
|
||||
if (!isset($this->files[$target])) {
|
||||
// Check for partial files
|
||||
if (pathinfo($target, PATHINFO_EXTENSION) === 'part') {
|
||||
$source = \OC_Share_Backend_File::getSource(substr($target, 0, -5), $this->getMountPoint(), $this->getItemType());
|
||||
$source = \OC_Share_Backend_File::getSource(substr($target, 0, -5), $this->getShare());
|
||||
if ($source) {
|
||||
$source['path'] .= '.part';
|
||||
// All partial files have delete permission
|
||||
$source['permissions'] |= \OCP\Constants::PERMISSION_DELETE;
|
||||
}
|
||||
} else {
|
||||
$source = \OC_Share_Backend_File::getSource($target, $this->getMountPoint(), $this->getItemType());
|
||||
$source = \OC_Share_Backend_File::getSource($target, $this->getShare());
|
||||
}
|
||||
$this->files[$target] = $source;
|
||||
}
|
||||
@@ -313,7 +324,7 @@ class Shared extends \OC\Files\Storage\Common implements ISharedStorage {
|
||||
}
|
||||
|
||||
public function rename($path1, $path2) {
|
||||
|
||||
$this->init();
|
||||
// we need the paths relative to data/user/files
|
||||
$relPath1 = $this->getMountPoint() . '/' . $path1;
|
||||
$relPath2 = $this->getMountPoint() . '/' . $path2;
|
||||
@@ -623,6 +634,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 +650,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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,6 +25,12 @@
|
||||
|
||||
$l = \OC::$server->getL10N('files_sharing');
|
||||
|
||||
$isIE8 = false;
|
||||
preg_match('/MSIE (.*?);/', $_SERVER['HTTP_USER_AGENT'], $matches);
|
||||
if (count($matches) > 0 && $matches[1] <= 9) {
|
||||
$isIE8 = true;
|
||||
}
|
||||
|
||||
$uid = \OC::$server->getUserSession()->getUser()->getUID();
|
||||
$server = \OC::$server->getURLGenerator()->getAbsoluteURL('/');
|
||||
$cloudID = $uid . '@' . rtrim(\OCA\Files_Sharing\Helper::removeProtocolFromUrl($server), '/');
|
||||
@@ -38,5 +44,6 @@ $tmpl->assign('message_without_URL', $l->t('Share with me through my #ownCloud F
|
||||
$tmpl->assign('owncloud_logo_path', $ownCloudLogoPath);
|
||||
$tmpl->assign('reference', $url);
|
||||
$tmpl->assign('cloudId', $cloudID);
|
||||
$tmpl->assign('showShareIT', !$isIE8);
|
||||
|
||||
return $tmpl->fetchPage();
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -3,8 +3,10 @@
|
||||
/** @var array $_ */
|
||||
script('files_sharing', 'settings-personal');
|
||||
style('files_sharing', 'settings-personal');
|
||||
script('files_sharing', '3rdparty/gs-share/gs-share');
|
||||
style('files_sharing', '3rdparty/gs-share/style');
|
||||
if ($_['showShareIT']) {
|
||||
script('files_sharing', '3rdparty/gs-share/gs-share');
|
||||
style('files_sharing', '3rdparty/gs-share/style');
|
||||
}
|
||||
?>
|
||||
|
||||
<?php if ($_['outgoingServer2serverShareEnabled']): ?>
|
||||
@@ -18,6 +20,7 @@ style('files_sharing', '3rdparty/gs-share/style');
|
||||
|
||||
<br>
|
||||
|
||||
<?php if ($_['showShareIT']) {?>
|
||||
<p>
|
||||
<?php p($l->t('Share it:')); ?>
|
||||
<div class="gs-share">
|
||||
@@ -68,6 +71,7 @@ style('files_sharing', '3rdparty/gs-share/style');
|
||||
|
||||
</a></xmp>
|
||||
</p>
|
||||
<?php } ?>
|
||||
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
@@ -78,7 +78,7 @@ class FilesSharingCapabilitiesTest extends \Test\TestCase {
|
||||
public function testLinkPassword() {
|
||||
$map = [
|
||||
['core', 'shareapi_allow_links', 'yes', 'yes'],
|
||||
['core', 'shareapi_enforce_links_password', 'yes', 'yes'],
|
||||
['core', 'shareapi_enforce_links_password', 'no', 'yes'],
|
||||
];
|
||||
$result = $this->getResults($map);
|
||||
$this->assertArrayHasKey('password', $result['public']);
|
||||
@@ -89,7 +89,7 @@ class FilesSharingCapabilitiesTest extends \Test\TestCase {
|
||||
public function testLinkNoPassword() {
|
||||
$map = [
|
||||
['core', 'shareapi_allow_links', 'yes', 'yes'],
|
||||
['core', 'shareapi_enforce_links_password', 'yes', 'no'],
|
||||
['core', 'shareapi_enforce_links_password', 'no', 'no'],
|
||||
];
|
||||
$result = $this->getResults($map);
|
||||
$this->assertArrayHasKey('password', $result['public']);
|
||||
@@ -100,7 +100,7 @@ class FilesSharingCapabilitiesTest extends \Test\TestCase {
|
||||
public function testLinkNoExpireDate() {
|
||||
$map = [
|
||||
['core', 'shareapi_allow_links', 'yes', 'yes'],
|
||||
['core', 'shareapi_default_expire_date', 'yes', 'no'],
|
||||
['core', 'shareapi_default_expire_date', 'no', 'no'],
|
||||
];
|
||||
$result = $this->getResults($map);
|
||||
$this->assertArrayHasKey('expire_date', $result['public']);
|
||||
@@ -111,9 +111,9 @@ class FilesSharingCapabilitiesTest extends \Test\TestCase {
|
||||
public function testLinkExpireDate() {
|
||||
$map = [
|
||||
['core', 'shareapi_allow_links', 'yes', 'yes'],
|
||||
['core', 'shareapi_default_expire_date', 'yes', 'yes'],
|
||||
['core', 'shareapi_default_expire_date', 'no', 'yes'],
|
||||
['core', 'shareapi_expire_after_n_days', '7', '7'],
|
||||
['core', 'shareapi_enforce_expire_date', 'yes', 'no'],
|
||||
['core', 'shareapi_enforce_expire_date', 'no', 'no'],
|
||||
];
|
||||
$result = $this->getResults($map);
|
||||
$this->assertArrayHasKey('expire_date', $result['public']);
|
||||
@@ -126,8 +126,8 @@ class FilesSharingCapabilitiesTest extends \Test\TestCase {
|
||||
public function testLinkExpireDateEnforced() {
|
||||
$map = [
|
||||
['core', 'shareapi_allow_links', 'yes', 'yes'],
|
||||
['core', 'shareapi_default_expire_date', 'yes', 'yes'],
|
||||
['core', 'shareapi_enforce_expire_date', 'yes', 'yes'],
|
||||
['core', 'shareapi_default_expire_date', 'no', 'yes'],
|
||||
['core', 'shareapi_enforce_expire_date', 'no', 'yes'],
|
||||
];
|
||||
$result = $this->getResults($map);
|
||||
$this->assertArrayHasKey('expire_date', $result['public']);
|
||||
@@ -138,7 +138,7 @@ class FilesSharingCapabilitiesTest extends \Test\TestCase {
|
||||
public function testLinkSendMail() {
|
||||
$map = [
|
||||
['core', 'shareapi_allow_links', 'yes', 'yes'],
|
||||
['core', 'shareapi_allow_public_notification', 'yes', 'yes'],
|
||||
['core', 'shareapi_allow_public_notification', 'no', 'yes'],
|
||||
];
|
||||
$result = $this->getResults($map);
|
||||
$this->assertTrue($result['public']['send_mail']);
|
||||
@@ -147,7 +147,7 @@ class FilesSharingCapabilitiesTest extends \Test\TestCase {
|
||||
public function testLinkNoSendMail() {
|
||||
$map = [
|
||||
['core', 'shareapi_allow_links', 'yes', 'yes'],
|
||||
['core', 'shareapi_allow_public_notification', 'yes', 'no'],
|
||||
['core', 'shareapi_allow_public_notification', 'no', 'no'],
|
||||
];
|
||||
$result = $this->getResults($map);
|
||||
$this->assertFalse($result['public']['send_mail']);
|
||||
@@ -155,7 +155,7 @@ class FilesSharingCapabilitiesTest extends \Test\TestCase {
|
||||
|
||||
public function testUserSendMail() {
|
||||
$map = [
|
||||
['core', 'shareapi_allow_mail_notification', 'yes', 'yes'],
|
||||
['core', 'shareapi_allow_mail_notification', 'no', 'yes'],
|
||||
];
|
||||
$result = $this->getResults($map);
|
||||
$this->assertTrue($result['user']['send_mail']);
|
||||
@@ -163,7 +163,7 @@ class FilesSharingCapabilitiesTest extends \Test\TestCase {
|
||||
|
||||
public function testUserNoSendMail() {
|
||||
$map = [
|
||||
['core', 'shareapi_allow_mail_notification', 'yes', 'no'],
|
||||
['core', 'shareapi_allow_mail_notification', 'no', 'no'],
|
||||
];
|
||||
$result = $this->getResults($map);
|
||||
$this->assertFalse($result['user']['send_mail']);
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Lukas Reschke <lukas@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\Controllers;
|
||||
|
||||
use OCP\AppFramework\Http\DataResponse;
|
||||
use OCP\AppFramework\Http\JSONResponse;
|
||||
use OCP\Http\Client\IClientService;
|
||||
use OCP\IRequest;
|
||||
|
||||
/**
|
||||
* Class ExternalShareControllerTest
|
||||
*
|
||||
* @package OCA\Files_Sharing\Controllers
|
||||
*/
|
||||
class ExternalShareControllerTest extends \Test\TestCase {
|
||||
/** @var IRequest */
|
||||
private $request;
|
||||
/** @var \OCA\Files_Sharing\External\Manager */
|
||||
private $externalManager;
|
||||
/** @var IClientService */
|
||||
private $clientService;
|
||||
|
||||
public function setUp() {
|
||||
$this->request = $this->getMockBuilder('\\OCP\\IRequest')
|
||||
->disableOriginalConstructor()->getMock();
|
||||
$this->externalManager = $this->getMockBuilder('\\OCA\\Files_Sharing\\External\\Manager')
|
||||
->disableOriginalConstructor()->getMock();
|
||||
$this->clientService = $this->getMockBuilder('\\OCP\Http\\Client\\IClientService')
|
||||
->disableOriginalConstructor()->getMock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ExternalSharesController
|
||||
*/
|
||||
public function getExternalShareController() {
|
||||
return new ExternalSharesController(
|
||||
'files_sharing',
|
||||
$this->request,
|
||||
$this->externalManager,
|
||||
$this->clientService
|
||||
);
|
||||
}
|
||||
|
||||
public function testIndex() {
|
||||
$this->externalManager
|
||||
->expects($this->once())
|
||||
->method('getOpenShares')
|
||||
->will($this->returnValue(['MyDummyArray']));
|
||||
|
||||
$this->assertEquals(new JSONResponse(['MyDummyArray']), $this->getExternalShareController()->index());
|
||||
}
|
||||
|
||||
public function testCreate() {
|
||||
$this->externalManager
|
||||
->expects($this->once())
|
||||
->method('acceptShare')
|
||||
->with(4);
|
||||
|
||||
$this->assertEquals(new JSONResponse(), $this->getExternalShareController()->create(4));
|
||||
}
|
||||
|
||||
public function testDestroy() {
|
||||
$this->externalManager
|
||||
->expects($this->once())
|
||||
->method('declineShare')
|
||||
->with(4);
|
||||
|
||||
$this->assertEquals(new JSONResponse(), $this->getExternalShareController()->destroy(4));
|
||||
}
|
||||
}
|
||||
@@ -266,15 +266,15 @@ class EtagPropagation extends TestCase {
|
||||
\OCP\Share::unshare(
|
||||
'folder',
|
||||
$folderId,
|
||||
\OCP\Share::SHARE_TYPE_USER,
|
||||
\OCP\Share::SHARE_TYPE_USER,
|
||||
self::TEST_FILES_SHARING_API_USER2
|
||||
)
|
||||
);
|
||||
$this->assertEtagsForFoldersChanged([
|
||||
// direct recipient affected
|
||||
self::TEST_FILES_SHARING_API_USER2,
|
||||
self::TEST_FILES_SHARING_API_USER2,
|
||||
// reshare recipient affected
|
||||
self::TEST_FILES_SHARING_API_USER4,
|
||||
self::TEST_FILES_SHARING_API_USER4,
|
||||
]);
|
||||
|
||||
$this->assertAllUnchaged();
|
||||
@@ -287,9 +287,9 @@ class EtagPropagation extends TestCase {
|
||||
);
|
||||
$this->assertEtagsForFoldersChanged([
|
||||
// direct recipient affected
|
||||
self::TEST_FILES_SHARING_API_USER2,
|
||||
self::TEST_FILES_SHARING_API_USER2,
|
||||
// reshare recipient affected
|
||||
self::TEST_FILES_SHARING_API_USER4,
|
||||
self::TEST_FILES_SHARING_API_USER4,
|
||||
]);
|
||||
|
||||
$this->assertAllUnchaged();
|
||||
@@ -398,4 +398,13 @@ class EtagPropagation extends TestCase {
|
||||
|
||||
$this->assertAllUnchaged();
|
||||
}
|
||||
|
||||
public function testRecipientUploadInDirectReshare() {
|
||||
$this->loginAsUser(self::TEST_FILES_SHARING_API_USER2);
|
||||
Filesystem::file_put_contents('/directReshare/test.txt', 'sad');
|
||||
$this->assertEtagsNotChanged([self::TEST_FILES_SHARING_API_USER3]);
|
||||
$this->assertEtagsChanged([self::TEST_FILES_SHARING_API_USER1, self::TEST_FILES_SHARING_API_USER2, self::TEST_FILES_SHARING_API_USER4]);
|
||||
|
||||
$this->assertAllUnchaged();
|
||||
}
|
||||
}
|
||||
|
||||
82
apps/files_sharing/tests/external/scannertest.php
vendored
Normal file
82
apps/files_sharing/tests/external/scannertest.php
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Joas Schilling <nickvergessen@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\External;
|
||||
|
||||
use OCA\Files_Sharing\External\Scanner;
|
||||
use Test\TestCase;
|
||||
|
||||
class ScannerTest extends TestCase {
|
||||
/** @var \OCA\Files_Sharing\External\Scanner */
|
||||
protected $scanner;
|
||||
/** @var \OCA\Files_Sharing\External\Storage|\PHPUnit_Framework_MockObject_MockObject */
|
||||
protected $storage;
|
||||
/** @var \OC\Files\Cache\Cache|\PHPUnit_Framework_MockObject_MockObject */
|
||||
protected $cache;
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->storage = $this->getMockBuilder('\OCA\Files_Sharing\External\Storage')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->cache = $this->getMockBuilder('\OC\Files\Cache\Cache')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->storage->expects($this->any())
|
||||
->method('getCache')
|
||||
->willReturn($this->cache);
|
||||
|
||||
$this->scanner = new Scanner($this->storage);
|
||||
}
|
||||
|
||||
public function testScanAll() {
|
||||
$this->storage->expects($this->any())
|
||||
->method('getShareInfo')
|
||||
->willReturn(['status' => 'success', 'data' => []]);
|
||||
|
||||
// FIXME add real tests, we are currently only checking for
|
||||
// Declaration of OCA\Files_Sharing\External\Scanner::*() should be
|
||||
// compatible with OC\Files\Cache\Scanner::*()
|
||||
$this->scanner->scanAll();
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
|
||||
public function testScan() {
|
||||
$this->storage->expects($this->any())
|
||||
->method('getShareInfo')
|
||||
->willReturn(['status' => 'success', 'data' => []]);
|
||||
|
||||
// FIXME add real tests, we are currently only checking for
|
||||
// Declaration of OCA\Files_Sharing\External\Scanner::*() should be
|
||||
// compatible with OC\Files\Cache\Scanner::*()
|
||||
$this->scanner->scan('test', Scanner::SCAN_RECURSIVE);
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
|
||||
public function testScanFile() {
|
||||
// FIXME add real tests, we are currently only checking for
|
||||
// Declaration of OCA\Files_Sharing\External\Scanner::*() should be
|
||||
// compatible with OC\Files\Cache\Scanner::*()
|
||||
$this->scanner->scanFile('test', Scanner::SCAN_RECURSIVE);
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
}
|
||||
@@ -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
apps/files_sharing/tests/locking.php
Normal file
101
apps/files_sharing/tests/locking.php
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,11 @@
|
||||
*/
|
||||
|
||||
namespace OCA\Files_Sharing\Middleware;
|
||||
|
||||
use OCP\AppFramework\Http\NotFoundResponse;
|
||||
use OCP\Files\NotFoundException;
|
||||
use OCP\AppFramework\Utility\IControllerMethodReflector;
|
||||
use OCA\Files_Sharing\Exceptions\S2SException;
|
||||
use OCP\AppFramework\Http\JSONResponse;
|
||||
|
||||
/**
|
||||
* @package OCA\Files_Sharing\Middleware\SharingCheckMiddleware
|
||||
@@ -36,29 +40,35 @@ class SharingCheckMiddlewareTest extends \Test\TestCase {
|
||||
private $appManager;
|
||||
/** @var SharingCheckMiddleware */
|
||||
private $sharingCheckMiddleware;
|
||||
/** @var \OCP\AppFramework\Controller */
|
||||
private $controllerMock;
|
||||
/** @var IControllerMethodReflector */
|
||||
private $reflector;
|
||||
|
||||
protected function setUp() {
|
||||
$this->config = $this->getMockBuilder('\OCP\IConfig')
|
||||
->disableOriginalConstructor()->getMock();
|
||||
$this->appManager = $this->getMockBuilder('\OCP\App\IAppManager')
|
||||
->disableOriginalConstructor()->getMock();
|
||||
$this->controllerMock = $this->getMockBuilder('\OCP\AppFramework\Controller')
|
||||
->disableOriginalConstructor()->getMock();
|
||||
$this->reflector = $this->getMockBuilder('\OCP\AppFramework\Utility\IControllerMethodReflector')
|
||||
->disableOriginalConstructor()->getMock();
|
||||
|
||||
$this->sharingCheckMiddleware = new SharingCheckMiddleware('files_sharing', $this->config, $this->appManager);
|
||||
$this->sharingCheckMiddleware = new SharingCheckMiddleware(
|
||||
'files_sharing',
|
||||
$this->config,
|
||||
$this->appManager,
|
||||
$this->reflector);
|
||||
}
|
||||
|
||||
public function testIsSharingEnabledWithEverythingEnabled() {
|
||||
public function testIsSharingEnabledWithAppEnabled() {
|
||||
$this->appManager
|
||||
->expects($this->once())
|
||||
->method('isEnabledForUser')
|
||||
->with('files_sharing')
|
||||
->will($this->returnValue(true));
|
||||
|
||||
$this->config
|
||||
->expects($this->once())
|
||||
->method('getAppValue')
|
||||
->with('core', 'shareapi_allow_links', 'yes')
|
||||
->will($this->returnValue('yes'));
|
||||
|
||||
$this->assertTrue(self::invokePrivate($this->sharingCheckMiddleware, 'isSharingEnabled'));
|
||||
}
|
||||
|
||||
@@ -72,7 +82,136 @@ class SharingCheckMiddlewareTest extends \Test\TestCase {
|
||||
$this->assertFalse(self::invokePrivate($this->sharingCheckMiddleware, 'isSharingEnabled'));
|
||||
}
|
||||
|
||||
public function testIsSharingEnabledWithSharingDisabled() {
|
||||
public function testIsLinkSharingEnabledWithEverythinEnabled() {
|
||||
$this->config
|
||||
->expects($this->at(0))
|
||||
->method('getAppValue')
|
||||
->with('core', 'shareapi_enabled', 'yes')
|
||||
->will($this->returnValue('yes'));
|
||||
|
||||
$this->config
|
||||
->expects($this->at(1))
|
||||
->method('getAppValue')
|
||||
->with('core', 'shareapi_allow_links', 'yes')
|
||||
->will($this->returnValue('yes'));
|
||||
|
||||
$this->assertTrue(self::invokePrivate($this->sharingCheckMiddleware, 'isLinkSharingEnabled'));
|
||||
}
|
||||
|
||||
|
||||
public function testIsLinkSharingEnabledWithLinkSharingDisabled() {
|
||||
$this->config
|
||||
->expects($this->at(0))
|
||||
->method('getAppValue')
|
||||
->with('core', 'shareapi_enabled', 'yes')
|
||||
->will($this->returnValue('yes'));
|
||||
|
||||
$this->config
|
||||
->expects($this->at(1))
|
||||
->method('getAppValue')
|
||||
->with('core', 'shareapi_allow_links', 'yes')
|
||||
->will($this->returnValue('no'));
|
||||
|
||||
$this->assertFalse(self::invokePrivate($this->sharingCheckMiddleware, 'isLinkSharingEnabled'));
|
||||
}
|
||||
|
||||
public function testIsLinkSharingEnabledWithSharingAPIDisabled() {
|
||||
$this->config
|
||||
->expects($this->once())
|
||||
->method('getAppValue')
|
||||
->with('core', 'shareapi_enabled', 'yes')
|
||||
->will($this->returnValue('no'));
|
||||
|
||||
$this->assertFalse(self::invokePrivate($this->sharingCheckMiddleware, 'isLinkSharingEnabled'));
|
||||
}
|
||||
|
||||
public function externalSharesChecksDataProvider() {
|
||||
|
||||
$data = [];
|
||||
|
||||
foreach ([false, true] as $annIn) {
|
||||
foreach ([false, true] as $annOut) {
|
||||
foreach ([false, true] as $confIn) {
|
||||
foreach ([false, true] as $confOut) {
|
||||
|
||||
$res = true;
|
||||
if (!$annIn && !$confIn) {
|
||||
$res = false;
|
||||
} elseif (!$annOut && !$confOut) {
|
||||
$res = false;
|
||||
}
|
||||
|
||||
$d = [
|
||||
[
|
||||
['NoIncomingFederatedSharingRequired', $annIn],
|
||||
['NoOutgoingFederatedSharingRequired', $annOut],
|
||||
],
|
||||
[
|
||||
['files_sharing', 'incoming_server2server_share_enabled', 'yes', $confIn ? 'yes' : 'no'],
|
||||
['files_sharing', 'outgoing_server2server_share_enabled', 'yes', $confOut ? 'yes' : 'no'],
|
||||
],
|
||||
$res
|
||||
];
|
||||
|
||||
$data[] = $d;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider externalSharesChecksDataProvider
|
||||
*/
|
||||
public function testExternalSharesChecks($annotations, $config, $expectedResult) {
|
||||
$this->reflector
|
||||
->expects($this->atLeastOnce())
|
||||
->method('hasAnnotation')
|
||||
->will($this->returnValueMap($annotations));
|
||||
|
||||
$this->config
|
||||
->method('getAppValue')
|
||||
->will($this->returnValueMap($config));
|
||||
|
||||
$this->assertEquals($expectedResult, self::invokePrivate($this->sharingCheckMiddleware, 'externalSharesChecks'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider externalSharesChecksDataProvider
|
||||
*/
|
||||
public function testBeforeControllerWithExternalShareControllerWithSharingEnabled($annotations, $config, $noException) {
|
||||
$this->appManager
|
||||
->expects($this->once())
|
||||
->method('isEnabledForUser')
|
||||
->with('files_sharing')
|
||||
->will($this->returnValue(true));
|
||||
|
||||
$this->reflector
|
||||
->expects($this->atLeastOnce())
|
||||
->method('hasAnnotation')
|
||||
->will($this->returnValueMap($annotations));
|
||||
|
||||
$this->config
|
||||
->method('getAppValue')
|
||||
->will($this->returnValueMap($config));
|
||||
|
||||
$controller = $this->getMockBuilder('\OCA\Files_Sharing\Controllers\ExternalSharesController')
|
||||
->disableOriginalConstructor()->getMock();
|
||||
|
||||
$exceptionThrown = false;
|
||||
|
||||
try {
|
||||
$this->sharingCheckMiddleware->beforeController($controller, 'myMethod');
|
||||
} catch (\OCA\Files_Sharing\Exceptions\S2SException $exception) {
|
||||
$exceptionThrown = true;
|
||||
}
|
||||
|
||||
$this->assertNotEquals($noException, $exceptionThrown);
|
||||
}
|
||||
|
||||
public function testBeforeControllerWithShareControllerWithSharingEnabled() {
|
||||
$this->appManager
|
||||
->expects($this->once())
|
||||
->method('isEnabledForUser')
|
||||
@@ -80,11 +219,69 @@ class SharingCheckMiddlewareTest extends \Test\TestCase {
|
||||
->will($this->returnValue(true));
|
||||
|
||||
$this->config
|
||||
->expects($this->once())
|
||||
->expects($this->at(0))
|
||||
->method('getAppValue')
|
||||
->with('core', 'shareapi_enabled', 'yes')
|
||||
->will($this->returnValue('yes'));
|
||||
|
||||
$this->config
|
||||
->expects($this->at(1))
|
||||
->method('getAppValue')
|
||||
->with('core', 'shareapi_allow_links', 'yes')
|
||||
->will($this->returnValue('no'));
|
||||
->will($this->returnValue('yes'));
|
||||
|
||||
$this->assertFalse(self::invokePrivate($this->sharingCheckMiddleware, 'isSharingEnabled'));
|
||||
$controller = $this->getMockBuilder('\OCA\Files_Sharing\Controllers\ShareController')
|
||||
->disableOriginalConstructor()->getMock();
|
||||
|
||||
$this->sharingCheckMiddleware->beforeController($controller, 'myMethod');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \OCP\Files\NotFoundException
|
||||
* @expectedExceptionMessage Link sharing is disabled
|
||||
*/
|
||||
public function testBeforeControllerWithShareControllerWithSharingEnabledAPIDisabled() {
|
||||
$this->appManager
|
||||
->expects($this->once())
|
||||
->method('isEnabledForUser')
|
||||
->with('files_sharing')
|
||||
->will($this->returnValue(true));
|
||||
|
||||
$controller = $this->getMockBuilder('\OCA\Files_Sharing\Controllers\ShareController')
|
||||
->disableOriginalConstructor()->getMock();
|
||||
|
||||
$this->sharingCheckMiddleware->beforeController($controller, 'myMethod');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \OCP\Files\NotFoundException
|
||||
* @expectedExceptionMessage Sharing is disabled.
|
||||
*/
|
||||
public function testBeforeControllerWithSharingDisabled() {
|
||||
$this->appManager
|
||||
->expects($this->once())
|
||||
->method('isEnabledForUser')
|
||||
->with('files_sharing')
|
||||
->will($this->returnValue(false));
|
||||
|
||||
$this->sharingCheckMiddleware->beforeController($this->controllerMock, 'myMethod');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Exception
|
||||
* @expectedExceptionMessage My Exception message
|
||||
*/
|
||||
public function testAfterExceptionWithRegularException() {
|
||||
$this->sharingCheckMiddleware->afterException($this->controllerMock, 'myMethod', new \Exception('My Exception message'));
|
||||
}
|
||||
|
||||
public function testAfterExceptionWithNotFoundException() {
|
||||
$this->assertEquals(new NotFoundResponse(), $this->sharingCheckMiddleware->afterException($this->controllerMock, 'myMethod', new NotFoundException('My Exception message')));
|
||||
}
|
||||
|
||||
public function testAfterExceptionWithS2SException() {
|
||||
$this->assertEquals(new JSONResponse('My Exception message', 405), $this->sharingCheckMiddleware->afterException($this->controllerMock, 'myMethod', new S2SException('My Exception message')));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -441,4 +441,43 @@ class Test_Files_Sharing_Storage extends OCA\Files_sharing\Tests\TestCase {
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
|
||||
$this->view->unlink($this->folder);
|
||||
}
|
||||
|
||||
public function testNameConflict() {
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
|
||||
$view1 = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER1 . '/files');
|
||||
$view1->mkdir('foo');
|
||||
$folderInfo1 = $view1->getFileInfo('foo');
|
||||
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER3);
|
||||
$view3 = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER3 . '/files');
|
||||
$view3->mkdir('foo');
|
||||
$folderInfo2 = $view3->getFileInfo('foo');
|
||||
|
||||
// share a folder with the same name from two different users to the same user
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
|
||||
|
||||
\OCP\Share::shareItem('folder', $folderInfo1['fileid'], \OCP\Share::SHARE_TYPE_GROUP,
|
||||
self::TEST_FILES_SHARING_API_GROUP1, 31);
|
||||
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
|
||||
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER3);
|
||||
|
||||
\OCP\Share::shareItem('folder', $folderInfo2['fileid'], \OCP\Share::SHARE_TYPE_GROUP,
|
||||
self::TEST_FILES_SHARING_API_GROUP1, 31);
|
||||
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
|
||||
$view2 = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files');
|
||||
|
||||
$this->assertTrue($view2->file_exists('/foo'));
|
||||
$this->assertTrue($view2->file_exists('/foo (2)'));
|
||||
|
||||
$mount = $view2->getMount('/foo');
|
||||
$this->assertInstanceOf('\OCA\Files_Sharing\SharedMount', $mount);
|
||||
/** @var \OC\Files\Storage\Shared $storage */
|
||||
$storage = $mount->getStorage();
|
||||
|
||||
$source = $storage->getFile('');
|
||||
$this->assertEquals(self::TEST_FILES_SHARING_API_USER1, $source['uid_owner']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 @@
|
||||
0.6.2
|
||||
0.6.3
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user