aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/encryption/appinfo/application.php3
-rw-r--r--apps/encryption/lib/crypto/encryption.php40
-rw-r--r--apps/encryption/lib/util.php31
-rw-r--r--apps/encryption/settings/settings-personal.php3
-rw-r--r--apps/encryption/tests/lib/UtilTest.php18
-rw-r--r--apps/files_sharing/lib/sharedstorage.php8
-rw-r--r--core/js/share.js41
-rw-r--r--core/js/tests/specs/shareSpec.js133
-rw-r--r--lib/private/connector/sabre/dummygetresponseplugin.php18
-rw-r--r--lib/private/encryption/exceptions/decryptionfailedexception.php11
-rw-r--r--lib/private/files.php88
-rw-r--r--lib/private/files/storage/wrapper/encryption.php24
-rw-r--r--lib/public/encryption/exceptions/genericencryptionexception.php11
-rw-r--r--lib/public/encryption/iencryptionmodule.php12
-rw-r--r--lib/public/lock/ilockingprovider.php2
-rw-r--r--settings/changepassword/controller.php3
-rw-r--r--tests/lib/connector/sabre/DummyGetResponsePluginTest.php65
-rw-r--r--tests/lib/files/storage/wrapper/encryption.php9
-rw-r--r--tests/lib/files/stream/encryption.php3
19 files changed, 453 insertions, 70 deletions
diff --git a/apps/encryption/appinfo/application.php b/apps/encryption/appinfo/application.php
index 0d6f57f46e9..79b2ad3abaf 100644
--- a/apps/encryption/appinfo/application.php
+++ b/apps/encryption/appinfo/application.php
@@ -209,7 +209,8 @@ class Application extends \OCP\AppFramework\App {
$c->query('Crypt'),
$server->getLogger(),
$server->getUserSession(),
- $server->getConfig());
+ $server->getConfig(),
+ $server->getUserManager());
});
}
diff --git a/apps/encryption/lib/crypto/encryption.php b/apps/encryption/lib/crypto/encryption.php
index f19638da7ca..c060bb04e53 100644
--- a/apps/encryption/lib/crypto/encryption.php
+++ b/apps/encryption/lib/crypto/encryption.php
@@ -270,6 +270,15 @@ class Encryption implements IEncryptionModule {
* @return mixed decrypted data
*/
public function decrypt($data) {
+ if (empty($this->fileKey)) {
+ $msg = $this->l->t('Can not decrypt this file, probably this is a shared file. Please ask the file owner to reshare the file with you.');
+ $this->logger->error('Can not decrypt this file,
+ probably this is a shared file.
+ Please ask the file owner to reshare the file with you.');
+
+ throw new DecryptionFailedException($msg);
+ }
+
$result = '';
if (!empty($data)) {
$result = $this->crypt->symmetricDecryptFileContent($data, $this->fileKey, $this->cipher);
@@ -349,6 +358,36 @@ class Encryption implements IEncryptionModule {
}
/**
+ * check if the encryption module is able to read the file,
+ * e.g. if all encryption keys exists
+ *
+ * @param string $path
+ * @param string $uid user for whom we want to check if he can read the file
+ * @return bool
+ * @throws DecryptionFailedException
+ */
+ public function isReadable($path, $uid) {
+ $fileKey = $this->keyManager->getFileKey($path, $uid);
+ if (empty($fileKey)) {
+ $owner = $this->util->getOwner($path);
+ if ($owner !== $uid) {
+ // if it is a shared file we throw a exception with a useful
+ // error message because in this case it means that the file was
+ // shared with the user at a point where the user didn't had a
+ // valid private/public key
+ $msg = 'Encryption module "' . $this->getDisplayName() .
+ '" is not able to read ' . $path;
+ $hint = $this->l->t('Can not read this file, probably this is a shared file. Please ask the file owner to reshare the file with you.');
+ $this->logger->warning($msg);
+ throw new DecryptionFailedException($msg, 0, null, $hint);
+ }
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
* @param string $path
* @return string
*/
@@ -363,4 +402,5 @@ class Encryption implements IEncryptionModule {
return $realPath;
}
+
}
diff --git a/apps/encryption/lib/util.php b/apps/encryption/lib/util.php
index 51d5241122f..afed96aaa38 100644
--- a/apps/encryption/lib/util.php
+++ b/apps/encryption/lib/util.php
@@ -29,6 +29,7 @@ use OCA\Encryption\Crypto\Crypt;
use OCP\IConfig;
use OCP\ILogger;
use OCP\IUser;
+use OCP\IUserManager;
use OCP\IUserSession;
use OCP\PreConditionNotMetException;
@@ -53,6 +54,10 @@ class Util {
* @var IConfig
*/
private $config;
+ /**
+ * @var IUserManager
+ */
+ private $userManager;
/**
* Util constructor.
@@ -62,18 +67,21 @@ class Util {
* @param ILogger $logger
* @param IUserSession $userSession
* @param IConfig $config
+ * @param IUserManager $userManager
*/
public function __construct(View $files,
Crypt $crypt,
ILogger $logger,
IUserSession $userSession,
- IConfig $config
+ IConfig $config,
+ IUserManager $userManager
) {
$this->files = $files;
$this->crypt = $crypt;
$this->logger = $logger;
$this->user = $userSession && $userSession->isLoggedIn() ? $userSession->getUser() : false;
$this->config = $config;
+ $this->userManager = $userManager;
}
/**
@@ -117,5 +125,26 @@ class Util {
return $this->files->file_exists($uid . '/files');
}
+ /**
+ * get owner from give path, path relative to data/ expected
+ *
+ * @param string $path relative to data/
+ * @return string
+ * @throws \BadMethodCallException
+ */
+ public function getOwner($path) {
+ $owner = '';
+ $parts = explode('/', $path, 3);
+ if (count($parts) > 1) {
+ $owner = $parts[1];
+ if ($this->userManager->userExists($owner) === false) {
+ throw new \BadMethodCallException('Unknown user: ' .
+ 'method expects path to a user folder relative to the data folder');
+ }
+
+ }
+
+ return $owner;
+ }
}
diff --git a/apps/encryption/settings/settings-personal.php b/apps/encryption/settings/settings-personal.php
index 003a27da71d..3815626ee64 100644
--- a/apps/encryption/settings/settings-personal.php
+++ b/apps/encryption/settings/settings-personal.php
@@ -35,7 +35,8 @@ $util = new \OCA\Encryption\Util(
$crypt,
\OC::$server->getLogger(),
$userSession,
- \OC::$server->getConfig());
+ \OC::$server->getConfig(),
+ \OC::$server->getUserManager());
$keyManager = new \OCA\Encryption\KeyManager(
\OC::$server->getEncryptionKeyStorage(),
diff --git a/apps/encryption/tests/lib/UtilTest.php b/apps/encryption/tests/lib/UtilTest.php
index eab912b82d4..18cf0386793 100644
--- a/apps/encryption/tests/lib/UtilTest.php
+++ b/apps/encryption/tests/lib/UtilTest.php
@@ -28,11 +28,17 @@ use Test\TestCase;
class UtilTest extends TestCase {
private static $tempStorage = [];
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject */
private $configMock;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject */
private $filesMock;
- /**
- * @var Util
- */
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject */
+ private $userManagerMock;
+
+ /** @var Util */
private $instance;
public function testSetRecoveryForUser() {
@@ -40,9 +46,6 @@ class UtilTest extends TestCase {
$this->assertArrayHasKey('recoveryEnabled', self::$tempStorage);
}
- /**
- *
- */
public function testIsRecoveryEnabledForUser() {
$this->assertTrue($this->instance->isRecoveryEnabledForUser('admin'));
@@ -62,6 +65,7 @@ class UtilTest extends TestCase {
protected function setUp() {
parent::setUp();
$this->filesMock = $this->getMock('OC\Files\View');
+ $this->userManagerMock = $this->getMock('\OCP\IUserManager');
$cryptMock = $this->getMockBuilder('OCA\Encryption\Crypto\Crypt')
->disableOriginalConstructor()
@@ -98,7 +102,7 @@ class UtilTest extends TestCase {
->method('setUserValue')
->will($this->returnCallback([$this, 'setValueTester']));
- $this->instance = new Util($this->filesMock, $cryptMock, $loggerMock, $userSessionMock, $configMock);
+ $this->instance = new Util($this->filesMock, $cryptMock, $loggerMock, $userSessionMock, $configMock, $this->userManagerMock);
}
/**
diff --git a/apps/files_sharing/lib/sharedstorage.php b/apps/files_sharing/lib/sharedstorage.php
index 33b7f887e19..10a37c7dae9 100644
--- a/apps/files_sharing/lib/sharedstorage.php
+++ b/apps/files_sharing/lib/sharedstorage.php
@@ -217,7 +217,13 @@ class Shared extends \OC\Files\Storage\Common implements ISharedStorage {
}
public function isReadable($path) {
- return $this->file_exists($path);
+ $isReadable = false;
+ if ($source = $this->getSourcePath($path)) {
+ list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
+ $isReadable = $storage->isReadable($internalPath);
+ }
+
+ return $isReadable && $this->file_exists($path);
}
public function isUpdatable($path) {
diff --git a/core/js/share.js b/core/js/share.js
index 6723b829ca5..121ee97d17f 100644
--- a/core/js/share.js
+++ b/core/js/share.js
@@ -839,6 +839,24 @@ OC.Share={
$('#defaultExpireMessage').slideDown(OC.menuSpeed);
}
$.datepicker.setDefaults(datePickerOptions);
+ },
+ /**
+ * Get the default Expire date
+ *
+ * @return {String} The expire date
+ */
+ getDefaultExpirationDate:function() {
+ var expireDateString = '';
+ if (oc_appconfig.core.defaultExpireDateEnabled) {
+ var date = new Date().getTime();
+ var expireAfterMs = oc_appconfig.core.defaultExpireDate * 24 * 60 * 60 * 1000;
+ var expireDate = new Date(date + expireAfterMs);
+ var month = expireDate.getMonth() + 1;
+ var year = expireDate.getFullYear();
+ var day = expireDate.getDate();
+ expireDateString = year + "-" + month + '-' + day + ' 00:00:00';
+ }
+ return expireDateString;
}
};
@@ -986,18 +1004,15 @@ $(document).ready(function() {
$('#linkPassText').attr('placeholder', t('core', 'Choose a password for the public link'));
// Reset link
$('#linkText').val('');
+ $('#showPassword').prop('checked', false);
+ $('#linkPass').hide();
+ $('#sharingDialogAllowPublicUpload').prop('checked', false);
+ $('#expirationCheckbox').prop('checked', false);
+ $('#expirationDate').hide();
var expireDateString = '';
- if (oc_appconfig.core.defaultExpireDateEnabled) {
- var date = new Date().getTime();
- var expireAfterMs = oc_appconfig.core.defaultExpireDate * 24 * 60 * 60 * 1000;
- var expireDate = new Date(date + expireAfterMs);
- var month = expireDate.getMonth() + 1;
- var year = expireDate.getFullYear();
- var day = expireDate.getDate();
- expireDateString = year + "-" + month + '-' + day + ' 00:00:00';
- }
// Create a link
if (oc_appconfig.core.enforcePasswordForPublicLink === false) {
+ expireDateString = OC.Share.getDefaultExpirationDate();
$loading.removeClass('hidden');
$button.addClass('hidden');
$button.prop('disabled', true);
@@ -1135,8 +1150,10 @@ $(document).ready(function() {
permissions = OC.PERMISSION_READ;
}
+ var expireDateString = OC.Share.getDefaultExpirationDate();
+
$loading.removeClass('hidden');
- OC.Share.share(itemType, itemSource, OC.Share.SHARE_TYPE_LINK, $('#linkPassText').val(), permissions, itemSourceName, function(data) {
+ OC.Share.share(itemType, itemSource, OC.Share.SHARE_TYPE_LINK, $('#linkPassText').val(), permissions, itemSourceName, expireDateString, function(data) {
$loading.addClass('hidden');
linkPassText.val('');
linkPassText.attr('placeholder', t('core', 'Password protected'));
@@ -1145,8 +1162,12 @@ $(document).ready(function() {
OC.Share.showLink(data.token, "password set", itemSource);
OC.Share.updateIcon(itemType, itemSource);
}
+ $('#dropdown').trigger(new $.Event('sharesChanged', {shares: OC.Share.currentShares}));
});
+ if (expireDateString !== '') {
+ OC.Share.showExpirationDate(expireDateString);
+ }
}
});
diff --git a/core/js/tests/specs/shareSpec.js b/core/js/tests/specs/shareSpec.js
index 3e9a0b247d7..c075351b9f5 100644
--- a/core/js/tests/specs/shareSpec.js
+++ b/core/js/tests/specs/shareSpec.js
@@ -228,6 +228,112 @@ describe('OC.Share tests', function() {
oc_appconfig.core.enforcePasswordForPublicLink = old;
});
+ it('reset password on toggle of share', function() {
+ $('#allowShareWithLink').val('yes');
+ OC.Share.showDropDown(
+ 'file',
+ 123,
+ $container,
+ true,
+ 31,
+ 'shared_file_name.txt'
+ );
+ $('#dropdown [name=linkCheckbox]').click();
+ fakeServer.requests[0].respond(
+ 200,
+ { 'Content-Type': 'application/json' },
+ JSON.stringify({data: {token: 'xyz'}, status: 'success'})
+ );
+
+ //Password protection should be unchecked and password field not visible
+ expect($('#dropdown [name=showPassword]').prop('checked')).toEqual(false);
+ expect($('#dropdown #linkPass').is(":visible")).toEqual(false);
+
+ // Toggle and set password
+ $('#dropdown [name=showPassword]').click();
+ $('#dropdown #linkPassText').val('foo');
+ $('#dropdown #linkPassText').trigger(new $.Event('keyup', {keyCode: 13}));
+ fakeServer.requests[1].respond(
+ 200,
+ { 'Content-Type': 'application/json' },
+ JSON.stringify({data: {token: 'xyz2'}, status: 'success'})
+ );
+
+ // Unshare
+ $('#dropdown [name=linkCheckbox]').click();
+ fakeServer.requests[2].respond(
+ 200,
+ { 'Content-Type': 'application/json' },
+ JSON.stringify({status: 'success'})
+ );
+
+ // Toggle share again
+ $('#dropdown [name=linkCheckbox]').click();
+ fakeServer.requests[3].respond(
+ 200,
+ { 'Content-Type': 'application/json' },
+ JSON.stringify({data: {token: 'xyz3'}, status: 'success'})
+ );
+
+
+ // Password checkbox should be unchecked
+ expect($('#dropdown [name=showPassword]').prop('checked')).toEqual(false);
+ expect($('#dropdown #linkPass').is(":visible")).toEqual(false);
+ });
+ it('reset expiration on toggle of share', function() {
+ $('#allowShareWithLink').val('yes');
+ OC.Share.showDropDown(
+ 'file',
+ 123,
+ $container,
+ true,
+ 31,
+ 'shared_file_name.txt'
+ );
+ $('#dropdown [name=linkCheckbox]').click();
+ fakeServer.requests[0].respond(
+ 200,
+ { 'Content-Type': 'application/json' },
+ JSON.stringify({data: {token: 'xyz'}, status: 'success'})
+ );
+
+ //Expiration should be unchecked and expiration field not visible
+ expect($('#dropdown [name=expirationCheckbox]').prop('checked')).toEqual(false);
+ expect($('#dropdown #expirationDate').is(":visible")).toEqual(false);
+
+ // Toggle and set password
+ $('#dropdown [name=expirationCheckbox]').click();
+ d = new Date();
+ d.setDate(d.getDate() + 1);
+ date=d.getDate() + '-' + (d.getMonth()+1) + '-' + d.getFullYear();
+ $('#dropdown #expirationDate').val(date);
+ $('#dropdown #expirationDate').change();
+ fakeServer.requests[1].respond(
+ 200,
+ { 'Content-Type': 'application/json' },
+ JSON.stringify({data: {token: 'xyz2'}, status: 'success'})
+ );
+
+ // Unshare
+ $('#dropdown [name=linkCheckbox]').click();
+ fakeServer.requests[2].respond(
+ 200,
+ { 'Content-Type': 'application/json' },
+ JSON.stringify({status: 'success'})
+ );
+
+ // Toggle share again
+ $('#dropdown [name=linkCheckbox]').click();
+ fakeServer.requests[3].respond(
+ 200,
+ { 'Content-Type': 'application/json' },
+ JSON.stringify({data: {token: 'xyz3'}, status: 'success'})
+ );
+
+ // Recheck expire visibility
+ expect($('#dropdown [name=expirationCheckbox]').prop('checked')).toEqual(false);
+ expect($('#dropdown #expirationDate').is(":visible")).toEqual(false);
+ });
it('shows populated link share when a link share exists', function() {
loadItemStub.returns({
reshare: [],
@@ -419,6 +525,7 @@ describe('OC.Share tests', function() {
};
loadItemStub.returns(shareData);
oc_appconfig.core.defaultExpireDate = 7;
+ oc_appconfig.core.enforcePasswordForPublicLink = false;
oc_appconfig.core.defaultExpireDateEnabled = false;
oc_appconfig.core.defaultExpireDateEnforced = false;
});
@@ -474,6 +581,32 @@ describe('OC.Share tests', function() {
$('#dropdown [name=expirationCheckbox]').click();
expect($('#dropdown [name=expirationCheckbox]').prop('checked')).toEqual(true);
});
+ it('enforces default date when enforced date setting is enabled and password is enforced', function() {
+ /* jshint camelcase:false */
+ oc_appconfig.core.enforcePasswordForPublicLink = true;
+ oc_appconfig.core.defaultExpireDateEnabled = true;
+ oc_appconfig.core.defaultExpireDateEnforced = true;
+ showDropDown();
+ $('#dropdown [name=linkCheckbox]').click();
+
+ //Enter password
+ $('#dropdown #linkPassText').val('foo');
+ $('#dropdown #linkPassText').trigger(new $.Event('keyup', {keyCode: 13}));
+ fakeServer.requests[0].respond(
+ 200,
+ { 'Content-Type': 'application/json' },
+ JSON.stringify({data: {token: 'xyz'}, status: 'success'})
+ );
+
+ expect($('#dropdown [name=expirationCheckbox]').prop('checked')).toEqual(true);
+ // TODO: those zeros must go...
+ expect($('#dropdown #expirationDate').val()).toEqual('2014-1-27 00:00:00');
+
+ // disabling is not allowed
+ expect($('#dropdown [name=expirationCheckbox]').prop('disabled')).toEqual(true);
+ $('#dropdown [name=expirationCheckbox]').click();
+ expect($('#dropdown [name=expirationCheckbox]').prop('checked')).toEqual(true);
+ });
it('displayes email form when sending emails is enabled', function() {
$('input[name=mailPublicNotificationEnabled]').val('yes');
showDropDown();
diff --git a/lib/private/connector/sabre/dummygetresponseplugin.php b/lib/private/connector/sabre/dummygetresponseplugin.php
index 7d57f6021fa..6057236b635 100644
--- a/lib/private/connector/sabre/dummygetresponseplugin.php
+++ b/lib/private/connector/sabre/dummygetresponseplugin.php
@@ -20,6 +20,8 @@
*/
namespace OC\Connector\Sabre;
+use Sabre\HTTP\ResponseInterface;
+use Sabre\HTTP\RequestInterface;
/**
* Class DummyGetResponsePlugin is a plugin used to not show a "Not implemented"
@@ -42,15 +44,25 @@ class DummyGetResponsePlugin extends \Sabre\DAV\ServerPlugin {
* @param \Sabre\DAV\Server $server
* @return void
*/
- function initialize(\Sabre\DAV\Server $server) {
+ function initialize(\Sabre\DAV\Server $server) {
$this->server = $server;
- $this->server->on('method:GET', [$this,'httpGet'], 200);
+ $this->server->on('method:GET', [$this, 'httpGet'], 200);
}
/**
+ * @param RequestInterface $request
+ * @param ResponseInterface $response
* @return false
*/
- function httpGet() {
+ function httpGet(RequestInterface $request, ResponseInterface $response) {
+ $string = 'This is the WebDAV interface. It can only be accessed by ' .
+ 'WebDAV clients such as the ownCloud desktop sync client.';
+ $stream = fopen('php://memory','r+');
+ fwrite($stream, $string);
+ rewind($stream);
+
+ $response->setBody($stream);
+
return false;
}
}
diff --git a/lib/private/encryption/exceptions/decryptionfailedexception.php b/lib/private/encryption/exceptions/decryptionfailedexception.php
index 406ae12968e..7e9fa21eaef 100644
--- a/lib/private/encryption/exceptions/decryptionfailedexception.php
+++ b/lib/private/encryption/exceptions/decryptionfailedexception.php
@@ -27,4 +27,15 @@ use OCP\Encryption\Exceptions\GenericEncryptionException;
class DecryptionFailedException extends GenericEncryptionException {
+ /**
+ * @param string $message
+ * @param int $code
+ * @param \Exception $previous
+ * @param string $hint
+ */
+ public function __construct($message = '', $code = 0, \Exception $previous = null, $hint = '') {
+ parent::__construct($message, $code, $previous, $hint);
+
+}
+
}
diff --git a/lib/private/files.php b/lib/private/files.php
index 97f9d8163b1..6a739fc844c 100644
--- a/lib/private/files.php
+++ b/lib/private/files.php
@@ -129,52 +129,60 @@ class OC_Files {
$zip = new ZipStreamer(false);
}
OC_Util::obEnd();
- if ($zip or \OC\Files\Filesystem::isReadable($filename)) {
- self::sendHeaders($filename, $name, $zip);
- } elseif (!\OC\Files\Filesystem::file_exists($filename)) {
- header("HTTP/1.0 404 Not Found");
- $tmpl = new OC_Template('', '404', 'guest');
- $tmpl->printPage();
- } else {
- header("HTTP/1.0 403 Forbidden");
- die('403 Forbidden');
- }
- if($only_header) {
- return ;
- }
- if ($zip) {
- $executionTime = intval(ini_get('max_execution_time'));
- set_time_limit(0);
- if ($get_type === self::ZIP_FILES) {
- foreach ($files as $file) {
- $file = $dir . '/' . $file;
- if (\OC\Files\Filesystem::is_file($file)) {
- $fh = \OC\Files\Filesystem::fopen($file, 'r');
- $zip->addFileFromStream($fh, basename($file));
- fclose($fh);
- } elseif (\OC\Files\Filesystem::is_dir($file)) {
- self::zipAddDir($file, $zip);
+
+ try {
+
+ if ($zip or \OC\Files\Filesystem::isReadable($filename)) {
+ self::sendHeaders($filename, $name, $zip);
+ } elseif (!\OC\Files\Filesystem::file_exists($filename)) {
+ header("HTTP/1.0 404 Not Found");
+ $tmpl = new OC_Template('', '404', 'guest');
+ $tmpl->printPage();
+ } else {
+ header("HTTP/1.0 403 Forbidden");
+ die('403 Forbidden');
+ }
+ if ($only_header) {
+ return;
+ }
+ if ($zip) {
+ $executionTime = intval(ini_get('max_execution_time'));
+ set_time_limit(0);
+ if ($get_type === self::ZIP_FILES) {
+ foreach ($files as $file) {
+ $file = $dir . '/' . $file;
+ if (\OC\Files\Filesystem::is_file($file)) {
+ $fh = \OC\Files\Filesystem::fopen($file, 'r');
+ $zip->addFileFromStream($fh, basename($file));
+ fclose($fh);
+ } elseif (\OC\Files\Filesystem::is_dir($file)) {
+ self::zipAddDir($file, $zip);
+ }
}
+ } elseif ($get_type === self::ZIP_DIR) {
+ $file = $dir . '/' . $files;
+ self::zipAddDir($file, $zip);
}
- } elseif ($get_type === self::ZIP_DIR) {
- $file = $dir . '/' . $files;
- self::zipAddDir($file, $zip);
- }
- $zip->finalize();
- set_time_limit($executionTime);
- } else {
- if ($xsendfile) {
- $view = \OC\Files\Filesystem::getView();
- /** @var $storage \OC\Files\Storage\Storage */
- list($storage) = $view->resolvePath($filename);
- if ($storage->isLocal()) {
- self::addSendfileHeader($filename);
+ $zip->finalize();
+ set_time_limit($executionTime);
+ } else {
+ if ($xsendfile) {
+ $view = \OC\Files\Filesystem::getView();
+ /** @var $storage \OC\Files\Storage\Storage */
+ list($storage) = $view->resolvePath($filename);
+ if ($storage->isLocal()) {
+ self::addSendfileHeader($filename);
+ } else {
+ \OC\Files\Filesystem::readfile($filename);
+ }
} else {
\OC\Files\Filesystem::readfile($filename);
}
- } else {
- \OC\Files\Filesystem::readfile($filename);
}
+ } catch (\Exception $ex) {
+ $l = \OC::$server->getL10N('core');
+ $hint = method_exists($ex, 'getHint') ? $ex->getHint() : '';
+ \OC_Template::printErrorPage($l->t('Can\'t read file'), $hint);
}
}
diff --git a/lib/private/files/storage/wrapper/encryption.php b/lib/private/files/storage/wrapper/encryption.php
index f7759d91497..1683ff1350f 100644
--- a/lib/private/files/storage/wrapper/encryption.php
+++ b/lib/private/files/storage/wrapper/encryption.php
@@ -253,6 +253,30 @@ class Encryption extends Wrapper {
}
/**
+ * check if a file can be read
+ *
+ * @param string $path
+ * @return bool
+ */
+ public function isReadable($path) {
+
+ $isReadable = true;
+
+ $metaData = $this->getMetaData($path);
+ if (
+ !$this->is_dir($path) &&
+ isset($metaData['encrypted']) &&
+ $metaData['encrypted'] === true
+ ) {
+ $fullPath = $this->getFullPath($path);
+ $module = $this->getEncryptionModule($path);
+ $isReadable = $module->isReadable($fullPath, $this->uid);
+ }
+
+ return $this->storage->isReadable($path) && $isReadable;
+ }
+
+ /**
* see http://php.net/manual/en/function.copy.php
*
* @param string $path1
diff --git a/lib/public/encryption/exceptions/genericencryptionexception.php b/lib/public/encryption/exceptions/genericencryptionexception.php
index be96450d431..e97f00c88bf 100644
--- a/lib/public/encryption/exceptions/genericencryptionexception.php
+++ b/lib/public/encryption/exceptions/genericencryptionexception.php
@@ -30,17 +30,26 @@ namespace OCP\Encryption\Exceptions;
*/
class GenericEncryptionException extends \Exception {
+ /** @var string */
+ protected $hint;
+
/**
* @param string $message
* @param int $code
* @param \Exception $previous
* @since 8.1.0
*/
- public function __construct($message = '', $code = 0, \Exception $previous = null) {
+ public function __construct($message = '', $code = 0, \Exception $previous = null, $hint = '') {
if (empty($message)) {
$message = 'Unspecified encryption exception';
}
parent::__construct($message, $code, $previous);
+
+ $this->hint = $hint;
+ }
+
+ public function getHint() {
+ return $this->hint;
}
}
diff --git a/lib/public/encryption/iencryptionmodule.php b/lib/public/encryption/iencryptionmodule.php
index 0dda042d759..975e57744e9 100644
--- a/lib/public/encryption/iencryptionmodule.php
+++ b/lib/public/encryption/iencryptionmodule.php
@@ -119,4 +119,16 @@ interface IEncryptionModule {
* @since 8.1.0
*/
public function getUnencryptedBlockSize();
+
+ /**
+ * check if the encryption module is able to read the file,
+ * e.g. if all encryption keys exists
+ *
+ * @param string $path
+ * @param string $uid user for whom we want to check if he can read the file
+ * @return boolean
+ * @since 8.1.0
+ */
+ public function isReadable($path, $uid);
+
}
diff --git a/lib/public/lock/ilockingprovider.php b/lib/public/lock/ilockingprovider.php
index a584ec02ef6..0b17580faac 100644
--- a/lib/public/lock/ilockingprovider.php
+++ b/lib/public/lock/ilockingprovider.php
@@ -35,7 +35,7 @@ interface ILockingProvider {
/**
* @param string $path
* @param int $type self::LOCK_SHARED or self::LOCK_EXCLUSIVE
- * @throws \OCP\Files\Lock\LockedException
+ * @throws \OCP\Lock\LockedException
*/
public function acquireLock($path, $type);
diff --git a/settings/changepassword/controller.php b/settings/changepassword/controller.php
index 94323fc2fcc..69b7ca710a9 100644
--- a/settings/changepassword/controller.php
+++ b/settings/changepassword/controller.php
@@ -89,7 +89,8 @@ class Controller {
$crypt,
\OC::$server->getLogger(),
\OC::$server->getUserSession(),
- \OC::$server->getConfig());
+ \OC::$server->getConfig(),
+ \OC::$server->getUserManager());
$keyManager = new \OCA\Encryption\KeyManager(
$keyStorage,
$crypt,
diff --git a/tests/lib/connector/sabre/DummyGetResponsePluginTest.php b/tests/lib/connector/sabre/DummyGetResponsePluginTest.php
new file mode 100644
index 00000000000..fa8f0694625
--- /dev/null
+++ b/tests/lib/connector/sabre/DummyGetResponsePluginTest.php
@@ -0,0 +1,65 @@
+<?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 Test\Connector\Sabre;
+
+use OC\Connector\Sabre\DummyGetResponsePlugin;
+use Test\TestCase;
+
+/**
+ * Class DummyGetResponsePluginTest
+ *
+ * @package Test\Connector\Sabre
+ */
+class DummyGetResponsePluginTest extends TestCase {
+ /** @var DummyGetResponsePlugin */
+ private $dummyGetResponsePlugin;
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->dummyGetResponsePlugin = new DummyGetResponsePlugin();
+ }
+
+ public function testInitialize() {
+ /** @var \Sabre\DAV\Server $server */
+ $server = $this->getMock('\Sabre\DAV\Server');
+ $server
+ ->expects($this->once())
+ ->method('on')
+ ->with('method:GET', [$this->dummyGetResponsePlugin, 'httpGet'], 200);
+
+ $this->dummyGetResponsePlugin->initialize($server);
+ }
+
+
+ public function testHttpGet() {
+ /** @var \Sabre\HTTP\RequestInterface $request */
+ $request = $this->getMock('\Sabre\HTTP\RequestInterface');
+ /** @var \Sabre\HTTP\ResponseInterface $response */
+ $response = $server = $this->getMock('\Sabre\HTTP\ResponseInterface');
+ $response
+ ->expects($this->once())
+ ->method('setBody');
+
+ $this->assertSame(false, $this->dummyGetResponsePlugin->httpGet($request, $response));
+ }
+}
diff --git a/tests/lib/files/storage/wrapper/encryption.php b/tests/lib/files/storage/wrapper/encryption.php
index 97810c9c5dd..361592f6ca1 100644
--- a/tests/lib/files/storage/wrapper/encryption.php
+++ b/tests/lib/files/storage/wrapper/encryption.php
@@ -117,7 +117,7 @@ class Encryption extends \Test\Files\Storage\Storage {
$this->encryptionManager, $this->util, $logger, $file, null, $this->keyStore, $this->update
]
)
- ->setMethods(['getMetaData', 'getCache'])
+ ->setMethods(['getMetaData', 'getCache', 'getEncryptionModule'])
->getMock();
$this->instance->expects($this->any())
@@ -127,6 +127,10 @@ class Encryption extends \Test\Files\Storage\Storage {
$this->instance->expects($this->any())
->method('getCache')
->willReturn($this->cache);
+
+ $this->instance->expects($this->any())
+ ->method('getEncryptionModule')
+ ->willReturn($mockModule);
}
/**
@@ -135,7 +139,7 @@ class Encryption extends \Test\Files\Storage\Storage {
protected function buildMockModule() {
$this->encryptionModule = $this->getMockBuilder('\OCP\Encryption\IEncryptionModule')
->disableOriginalConstructor()
- ->setMethods(['getId', 'getDisplayName', 'begin', 'end', 'encrypt', 'decrypt', 'update', 'shouldEncrypt', 'getUnencryptedBlockSize'])
+ ->setMethods(['getId', 'getDisplayName', 'begin', 'end', 'encrypt', 'decrypt', 'update', 'shouldEncrypt', 'getUnencryptedBlockSize', 'isReadable'])
->getMock();
$this->encryptionModule->expects($this->any())->method('getId')->willReturn('UNIT_TEST_MODULE');
@@ -147,6 +151,7 @@ class Encryption extends \Test\Files\Storage\Storage {
$this->encryptionModule->expects($this->any())->method('update')->willReturn(true);
$this->encryptionModule->expects($this->any())->method('shouldEncrypt')->willReturn(true);
$this->encryptionModule->expects($this->any())->method('getUnencryptedBlockSize')->willReturn(8192);
+ $this->encryptionModule->expects($this->any())->method('isReadable')->willReturn(true);
return $this->encryptionModule;
}
diff --git a/tests/lib/files/stream/encryption.php b/tests/lib/files/stream/encryption.php
index 892491cbc32..113cd14ada7 100644
--- a/tests/lib/files/stream/encryption.php
+++ b/tests/lib/files/stream/encryption.php
@@ -253,13 +253,14 @@ class Encryption extends \Test\TestCase {
protected function buildMockModule() {
$encryptionModule = $this->getMockBuilder('\OCP\Encryption\IEncryptionModule')
->disableOriginalConstructor()
- ->setMethods(['getId', 'getDisplayName', 'begin', 'end', 'encrypt', 'decrypt', 'update', 'shouldEncrypt', 'getUnencryptedBlockSize'])
+ ->setMethods(['getId', 'getDisplayName', 'begin', 'end', 'encrypt', 'decrypt', 'update', 'shouldEncrypt', 'getUnencryptedBlockSize', 'isReadable'])
->getMock();
$encryptionModule->expects($this->any())->method('getId')->willReturn('UNIT_TEST_MODULE');
$encryptionModule->expects($this->any())->method('getDisplayName')->willReturn('Unit test module');
$encryptionModule->expects($this->any())->method('begin')->willReturn([]);
$encryptionModule->expects($this->any())->method('end')->willReturn('');
+ $encryptionModule->expects($this->any())->method('isReadable')->willReturn(true);
$encryptionModule->expects($this->any())->method('encrypt')->willReturnCallback(function($data) {
// simulate different block size by adding some padding to the data
if (isset($data[6125])) {