summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/files/ajax/newfile.php14
-rw-r--r--apps/files/ajax/newfolder.php4
-rw-r--r--apps/files_external/ajax/addRootCertificate.php2
-rwxr-xr-xapps/files_external/lib/config.php6
-rw-r--r--apps/user_ldap/lib/helper.php6
-rw-r--r--apps/user_ldap/tests/access.php71
-rw-r--r--apps/user_ldap/tests/user_ldap.php101
-rwxr-xr-xconfig/config.sample.php3
-rw-r--r--core/ajax/appconfig.php27
-rw-r--r--core/ajax/share.php112
-rw-r--r--core/css/fixes.css5
-rw-r--r--core/css/multiselect.css8
-rw-r--r--core/css/styles.css30
-rw-r--r--core/img/filetypes/application-javascript.png (renamed from core/img/filetypes/text-x-javascript.png)bin1243 -> 1243 bytes
-rw-r--r--core/img/filetypes/application-javascript.svg (renamed from core/img/filetypes/text-x-javascript.svg)0
-rw-r--r--core/img/filetypes/application-x-shockwave-flash.png (renamed from core/img/filetypes/flash.png)bin880 -> 880 bytes
-rw-r--r--core/img/filetypes/application-x-shockwave-flash.svg (renamed from core/img/filetypes/flash.svg)0
-rw-r--r--core/img/filetypes/text-calendar.png (renamed from core/img/filetypes/calendar.png)bin1226 -> 1226 bytes
-rw-r--r--core/img/filetypes/text-calendar.svg (renamed from core/img/filetypes/calendar.svg)0
-rw-r--r--core/js/config.php1
-rw-r--r--core/templates/layout.guest.php2
-rw-r--r--core/templates/layout.user.php5
-rw-r--r--lib/private/appframework/middleware/middlewaredispatcher.php1
-rw-r--r--lib/private/connector/sabre/file.php10
-rw-r--r--lib/private/connector/sabre/node.php9
-rw-r--r--lib/private/connector/sabre/objecttree.php5
-rw-r--r--lib/private/files/filesystem.php10
-rw-r--r--lib/private/files/storage/wrapper/quota.php8
-rw-r--r--lib/private/helper.php31
-rw-r--r--lib/private/image.php2
-rw-r--r--lib/private/l10n.php4
-rw-r--r--lib/private/mimetypes.list.php140
-rw-r--r--lib/private/share/mailnotifications.php160
-rw-r--r--lib/private/urlgenerator.php3
-rw-r--r--lib/private/user.php2
-rwxr-xr-xlib/private/util.php23
-rw-r--r--lib/public/constants.php3
-rw-r--r--lib/public/util.php9
-rw-r--r--remote.php6
-rw-r--r--settings/js/isadmin.php20
-rw-r--r--settings/js/users.js85
-rw-r--r--settings/routes.php2
-rw-r--r--settings/templates/users.php2
-rw-r--r--tests/lib/connector/sabre/file.php25
-rw-r--r--tests/lib/connector/sabre/objecttree.php16
-rw-r--r--tests/lib/files/storage/wrapper/quota.php25
-rw-r--r--tests/lib/util.php48
47 files changed, 779 insertions, 267 deletions
diff --git a/apps/files/ajax/newfile.php b/apps/files/ajax/newfile.php
index 1853098c507..0187b200759 100644
--- a/apps/files/ajax/newfile.php
+++ b/apps/files/ajax/newfile.php
@@ -50,16 +50,22 @@ $l10n = \OC_L10n::get('files');
$result = array(
'success' => false,
'data' => NULL
- );
+);
+$trimmedFileName = trim($filename);
-if(trim($filename) === '') {
+if($trimmedFileName === '') {
$result['data'] = array('message' => (string)$l10n->t('File name cannot be empty.'));
OCP\JSON::error($result);
exit();
}
+if($trimmedFileName === '.' || $trimmedFileName === '..') {
+ $result['data'] = array('message' => (string)$l10n->t('"%s" is an invalid file name.', $trimmedFileName));
+ OCP\JSON::error($result);
+ exit();
+}
-if(strpos($filename, '/') !== false) {
- $result['data'] = array('message' => (string)$l10n->t('File name must not contain "/". Please choose a different name.'));
+if(!OCP\Util::isValidFileName($filename)) {
+ $result['data'] = array('message' => (string)$l10n->t("Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed."));
OCP\JSON::error($result);
exit();
}
diff --git a/apps/files/ajax/newfolder.php b/apps/files/ajax/newfolder.php
index 4cfcae3090d..b2b4fb27f74 100644
--- a/apps/files/ajax/newfolder.php
+++ b/apps/files/ajax/newfolder.php
@@ -23,8 +23,8 @@ if(trim($foldername) === '') {
exit();
}
-if(strpos($foldername, '/') !== false) {
- $result['data'] = array('message' => $l10n->t('Folder name must not contain "/". Please choose a different name.'));
+if(!OCP\Util::isValidFileName($foldername)) {
+ $result['data'] = array('message' => (string)$l10n->t("Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed."));
OCP\JSON::error($result);
exit();
}
diff --git a/apps/files_external/ajax/addRootCertificate.php b/apps/files_external/ajax/addRootCertificate.php
index ae349bfcd3a..fcd3a617ada 100644
--- a/apps/files_external/ajax/addRootCertificate.php
+++ b/apps/files_external/ajax/addRootCertificate.php
@@ -4,7 +4,7 @@ OCP\JSON::checkAppEnabled('files_external');
OCP\JSON::callCheck();
if ( ! ($filename = $_FILES['rootcert_import']['name']) ) {
- header("Location: settings/personal.php");
+ header('Location:' . OCP\Util::linkToRoute( "settings_personal" ));
exit;
}
diff --git a/apps/files_external/lib/config.php b/apps/files_external/lib/config.php
index 94dc5fb7ad8..b2109e5eacd 100755
--- a/apps/files_external/lib/config.php
+++ b/apps/files_external/lib/config.php
@@ -352,9 +352,8 @@ class OC_Mount_Config {
$phpFile = OC_User::getHome(OCP\User::getUser()).'/mount.php';
$jsonFile = OC_User::getHome(OCP\User::getUser()).'/mount.json';
} else {
- $datadir = \OC_Config::getValue("datadirectory", \OC::$SERVERROOT . "/data");
$phpFile = OC::$SERVERROOT.'/config/mount.php';
- $jsonFile = $datadir . '/mount.json';
+ $jsonFile = \OC_Config::getValue("mount_file", \OC::$SERVERROOT . "/data/mount.json");
}
if (is_file($jsonFile)) {
$mountPoints = json_decode(file_get_contents($jsonFile), true);
@@ -380,8 +379,7 @@ class OC_Mount_Config {
if ($isPersonal) {
$file = OC_User::getHome(OCP\User::getUser()).'/mount.json';
} else {
- $datadir = \OC_Config::getValue("datadirectory", \OC::$SERVERROOT . "/data");
- $file = $datadir . '/mount.json';
+ $file = \OC_Config::getValue("mount_file", \OC::$SERVERROOT . "/data/mount.json");
}
$content = json_encode($data);
@file_put_contents($file, $content);
diff --git a/apps/user_ldap/lib/helper.php b/apps/user_ldap/lib/helper.php
index 9727d847d27..7de7fe8667f 100644
--- a/apps/user_ldap/lib/helper.php
+++ b/apps/user_ldap/lib/helper.php
@@ -118,10 +118,16 @@ class Helper {
return false;
}
+ $saveOtherConfigurations = '';
+ if(empty($prefix)) {
+ $saveOtherConfigurations = 'AND `Configkey` NOT LIKE \'s%\'';
+ }
+
$query = \OCP\DB::prepare('
DELETE
FROM `*PREFIX*appconfig`
WHERE `configkey` LIKE ?
+ '.$saveOtherConfigurations.'
AND `appid` = \'user_ldap\'
AND `configkey` NOT IN (\'enabled\', \'installed_version\', \'types\', \'bgjUpdateGroupsLastRun\')
');
diff --git a/apps/user_ldap/tests/access.php b/apps/user_ldap/tests/access.php
new file mode 100644
index 00000000000..9beb2b97336
--- /dev/null
+++ b/apps/user_ldap/tests/access.php
@@ -0,0 +1,71 @@
+<?php
+/**
+* ownCloud
+*
+* @author Arthur Schiwon
+* @copyright 2013 Arthur Schiwon blizzz@owncloud.com
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+* License as published by the Free Software Foundation; either
+* version 3 of the License, or any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+*
+* You should have received a copy of the GNU Affero General Public
+* License along with this library. If not, see <http://www.gnu.org/licenses/>.
+*
+*/
+
+namespace OCA\user_ldap\tests;
+
+use \OCA\user_ldap\lib\Access;
+use \OCA\user_ldap\lib\Connection;
+use \OCA\user_ldap\lib\ILDAPWrapper;
+
+class Test_Access extends \PHPUnit_Framework_TestCase {
+ private function getConnecterAndLdapMock() {
+ static $conMethods;
+ static $accMethods;
+
+ if(is_null($conMethods) || is_null($accMethods)) {
+ $conMethods = get_class_methods('\OCA\user_ldap\lib\Connection');
+ $accMethods = get_class_methods('\OCA\user_ldap\lib\Access');
+ }
+ $lw = $this->getMock('\OCA\user_ldap\lib\ILDAPWrapper');
+ $connector = $this->getMock('\OCA\user_ldap\lib\Connection',
+ $conMethods,
+ array($lw, null, null));
+
+ return array($lw, $connector);
+ }
+
+ public function testEscapeFilterPartValidChars() {
+ list($lw, $con) = $this->getConnecterAndLdapMock();
+ $access = new Access($con, $lw);
+
+ $input = 'okay';
+ $this->assertTrue($input === $access->escapeFilterPart($input));
+ }
+
+ public function testEscapeFilterPartEscapeWildcard() {
+ list($lw, $con) = $this->getConnecterAndLdapMock();
+ $access = new Access($con, $lw);
+
+ $input = '*';
+ $expected = '\\\\*';
+ $this->assertTrue($expected === $access->escapeFilterPart($input));
+ }
+
+ public function testEscapeFilterPartEscapeWildcard2() {
+ list($lw, $con) = $this->getConnecterAndLdapMock();
+ $access = new Access($con, $lw);
+
+ $input = 'foo*bar';
+ $expected = 'foo\\\\*bar';
+ $this->assertTrue($expected === $access->escapeFilterPart($input));
+ }
+} \ No newline at end of file
diff --git a/apps/user_ldap/tests/user_ldap.php b/apps/user_ldap/tests/user_ldap.php
index 9193a005ae5..8c8d85b3c33 100644
--- a/apps/user_ldap/tests/user_ldap.php
+++ b/apps/user_ldap/tests/user_ldap.php
@@ -83,6 +83,12 @@ class Test_User_Ldap_Direct extends \PHPUnit_Framework_TestCase {
* @return void
*/
private function prepareAccessForCheckPassword(&$access) {
+ $access->expects($this->once())
+ ->method('escapeFilterPart')
+ ->will($this->returnCallback(function($uid) {
+ return $uid;
+ }));
+
$access->connection->expects($this->any())
->method('__get')
->will($this->returnCallback(function($name) {
@@ -116,17 +122,34 @@ class Test_User_Ldap_Direct extends \PHPUnit_Framework_TestCase {
}));
}
- public function testCheckPassword() {
+ public function testCheckPasswordUidReturn() {
$access = $this->getAccessMock();
+
$this->prepareAccessForCheckPassword($access);
$backend = new UserLDAP($access);
\OC_User::useBackend($backend);
$result = $backend->checkPassword('roland', 'dt19');
$this->assertEquals('gunslinger', $result);
+ }
+
+ public function testCheckPasswordWrongPassword() {
+ $access = $this->getAccessMock();
+
+ $this->prepareAccessForCheckPassword($access);
+ $backend = new UserLDAP($access);
+ \OC_User::useBackend($backend);
$result = $backend->checkPassword('roland', 'wrong');
$this->assertFalse($result);
+ }
+
+ public function testCheckPasswordWrongUser() {
+ $access = $this->getAccessMock();
+
+ $this->prepareAccessForCheckPassword($access);
+ $backend = new UserLDAP($access);
+ \OC_User::useBackend($backend);
$result = $backend->checkPassword('mallory', 'evil');
$this->assertFalse($result);
@@ -140,9 +163,23 @@ class Test_User_Ldap_Direct extends \PHPUnit_Framework_TestCase {
$result = \OCP\User::checkPassword('roland', 'dt19');
$this->assertEquals('gunslinger', $result);
+ }
+
+ public function testCheckPasswordPublicAPIWrongPassword() {
+ $access = $this->getAccessMock();
+ $this->prepareAccessForCheckPassword($access);
+ $backend = new UserLDAP($access);
+ \OC_User::useBackend($backend);
$result = \OCP\User::checkPassword('roland', 'wrong');
$this->assertFalse($result);
+ }
+
+ public function testCheckPasswordPublicAPIWrongUser() {
+ $access = $this->getAccessMock();
+ $this->prepareAccessForCheckPassword($access);
+ $backend = new UserLDAP($access);
+ \OC_User::useBackend($backend);
$result = \OCP\User::checkPassword('mallory', 'evil');
$this->assertFalse($result);
@@ -154,6 +191,12 @@ class Test_User_Ldap_Direct extends \PHPUnit_Framework_TestCase {
* @return void
*/
private function prepareAccessForGetUsers(&$access) {
+ $access->expects($this->once())
+ ->method('escapeFilterPart')
+ ->will($this->returnCallback(function($search) {
+ return $search;
+ }));
+
$access->expects($this->any())
->method('getFilterPartForUserSearch')
->will($this->returnCallback(function($search) {
@@ -191,28 +234,52 @@ class Test_User_Ldap_Direct extends \PHPUnit_Framework_TestCase {
->will($this->returnArgument(0));
}
- public function testGetUsers() {
+ public function testGetUsersNoParam() {
$access = $this->getAccessMock();
$this->prepareAccessForGetUsers($access);
$backend = new UserLDAP($access);
$result = $backend->getUsers();
$this->assertEquals(3, count($result));
+ }
+
+ public function testGetUsersLimitOffset() {
+ $access = $this->getAccessMock();
+ $this->prepareAccessForGetUsers($access);
+ $backend = new UserLDAP($access);
$result = $backend->getUsers('', 1, 2);
$this->assertEquals(1, count($result));
+ }
+
+ public function testGetUsersLimitOffset2() {
+ $access = $this->getAccessMock();
+ $this->prepareAccessForGetUsers($access);
+ $backend = new UserLDAP($access);
$result = $backend->getUsers('', 2, 1);
$this->assertEquals(2, count($result));
+ }
+
+ public function testGetUsersSearchWithResult() {
+ $access = $this->getAccessMock();
+ $this->prepareAccessForGetUsers($access);
+ $backend = new UserLDAP($access);
$result = $backend->getUsers('yo');
$this->assertEquals(2, count($result));
+ }
+
+ public function testGetUsersSearchEmptyResult() {
+ $access = $this->getAccessMock();
+ $this->prepareAccessForGetUsers($access);
+ $backend = new UserLDAP($access);
$result = $backend->getUsers('nix');
$this->assertEquals(0, count($result));
}
- public function testGetUsersViaAPI() {
+ public function testGetUsersViaAPINoParam() {
$access = $this->getAccessMock();
$this->prepareAccessForGetUsers($access);
$backend = new UserLDAP($access);
@@ -220,15 +287,43 @@ class Test_User_Ldap_Direct extends \PHPUnit_Framework_TestCase {
$result = \OCP\User::getUsers();
$this->assertEquals(3, count($result));
+ }
+
+ public function testGetUsersViaAPILimitOffset() {
+ $access = $this->getAccessMock();
+ $this->prepareAccessForGetUsers($access);
+ $backend = new UserLDAP($access);
+ \OC_User::useBackend($backend);
$result = \OCP\User::getUsers('', 1, 2);
$this->assertEquals(1, count($result));
+ }
+
+ public function testGetUsersViaAPILimitOffset2() {
+ $access = $this->getAccessMock();
+ $this->prepareAccessForGetUsers($access);
+ $backend = new UserLDAP($access);
+ \OC_User::useBackend($backend);
$result = \OCP\User::getUsers('', 2, 1);
$this->assertEquals(2, count($result));
+ }
+
+ public function testGetUsersViaAPISearchWithResult() {
+ $access = $this->getAccessMock();
+ $this->prepareAccessForGetUsers($access);
+ $backend = new UserLDAP($access);
+ \OC_User::useBackend($backend);
$result = \OCP\User::getUsers('yo');
$this->assertEquals(2, count($result));
+ }
+
+ public function testGetUsersViaAPISearchEmptyResult() {
+ $access = $this->getAccessMock();
+ $this->prepareAccessForGetUsers($access);
+ $backend = new UserLDAP($access);
+ \OC_User::useBackend($backend);
$result = \OCP\User::getUsers('nix');
$this->assertEquals(0, count($result));
diff --git a/config/config.sample.php b/config/config.sample.php
index 0cd321d095d..9f47ee32940 100755
--- a/config/config.sample.php
+++ b/config/config.sample.php
@@ -263,4 +263,7 @@ $CONFIG = array(
/* whether usage of the instance should be restricted to admin users only */
'singleuser' => false,
+
+ /* where mount.json file should be stored, defaults to data/mount.json */
+ 'mount_file' => '',
);
diff --git a/core/ajax/appconfig.php b/core/ajax/appconfig.php
index 4f26dedc797..05b7572c6d7 100644
--- a/core/ajax/appconfig.php
+++ b/core/ajax/appconfig.php
@@ -9,28 +9,43 @@ OC_Util::checkAdminUser();
OCP\JSON::callCheck();
$action=isset($_POST['action'])?$_POST['action']:$_GET['action'];
+
+if(isset($_POST['app']) || isset($_GET['app'])) {
+ $app=OC_App::cleanAppId(isset($_POST['app'])?$_POST['app']:$_GET['app']);
+}
+
+// An admin should not be able to add remote and public services
+// on its own. This should only be possible programmatically.
+// This change is due the fact that an admin may not be expected
+// to execute arbitrary code in every environment.
+if($app === 'core' && isset($_POST['key']) &&(substr($_POST['key'],0,7) === 'remote_' || substr($_POST['key'],0,7) === 'public_')) {
+ OC_JSON::error(array('data' => array('message' => 'Unexpected error!')));
+ return;
+}
+
$result=false;
switch($action) {
case 'getValue':
- $result=OC_Appconfig::getValue($_GET['app'], $_GET['key'], $_GET['defaultValue']);
+ $result=OC_Appconfig::getValue($app, $_GET['key'], $_GET['defaultValue']);
break;
case 'setValue':
- $result=OC_Appconfig::setValue($_POST['app'], $_POST['key'], $_POST['value']);
+ $result=OC_Appconfig::setValue($app, $_POST['key'], $_POST['value']);
break;
case 'getApps':
$result=OC_Appconfig::getApps();
break;
case 'getKeys':
- $result=OC_Appconfig::getKeys($_GET['app']);
+ $result=OC_Appconfig::getKeys($app);
break;
case 'hasKey':
- $result=OC_Appconfig::hasKey($_GET['app'], $_GET['key']);
+ $result=OC_Appconfig::hasKey($app, $_GET['key']);
break;
case 'deleteKey':
- $result=OC_Appconfig::deleteKey($_POST['app'], $_POST['key']);
+ $result=OC_Appconfig::deleteKey($app, $_POST['key']);
break;
case 'deleteApp':
- $result=OC_Appconfig::deleteApp($_POST['app']);
+ $result=OC_Appconfig::deleteApp($app);
break;
}
OC_JSON::success(array('data'=>$result));
+
diff --git a/core/ajax/share.php b/core/ajax/share.php
index c251f8e7bae..86ee018e388 100644
--- a/core/ajax/share.php
+++ b/core/ajax/share.php
@@ -85,93 +85,32 @@ if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSo
}
break;
case 'informRecipients':
-
$l = OC_L10N::get('core');
-
$shareType = (int) $_POST['shareType'];
$itemType = $_POST['itemType'];
$itemSource = $_POST['itemSource'];
$recipient = $_POST['recipient'];
- $ownerDisplayName = \OCP\User::getDisplayName();
- $from = \OCP\Util::getDefaultEmailAddress('sharing-noreply');
-
- $noMail = array();
- $recipientList = array();
if($shareType === \OCP\Share::SHARE_TYPE_USER) {
$recipientList[] = $recipient;
} elseif ($shareType === \OCP\Share::SHARE_TYPE_GROUP) {
$recipientList = \OC_Group::usersInGroup($recipient);
}
-
// don't send a mail to the user who shared the file
$recipientList = array_diff($recipientList, array(\OCP\User::getUser()));
- // send mail to all recipients with an email address
- foreach ($recipientList as $recipient) {
- //get correct target folder name
- $email = OC_Preferences::getValue($recipient, 'settings', 'email', '');
-
- if ($email !== '') {
- $displayName = \OCP\User::getDisplayName($recipient);
- $items = \OCP\Share::getItemSharedWithUser($itemType, $itemSource, $recipient);
- $filename = trim($items[0]['file_target'], '/');
- $subject = (string)$l->t('%s shared »%s« with you', array($ownerDisplayName, $filename));
- $expiration = null;
- if (isset($items[0]['expiration'])) {
- try {
- $date = new DateTime($items[0]['expiration']);
- $expiration = $l->l('date', $date->getTimestamp());
- } catch (Exception $e) {
- \OCP\Util::writeLog('sharing', "Couldn't read date: " . $e->getMessage(), \OCP\Util::ERROR);
- }
- }
-
- if ($itemType === 'folder') {
- $foldername = "/Shared/" . $filename;
- } else {
- // if it is a file we can just link to the Shared folder,
- // that's the place where the user will find the file
- $foldername = "/Shared";
- }
-
- $link = \OCP\Util::linkToAbsolute('files', 'index.php', array("dir" => $foldername));
-
- $content = new OC_Template("core", "mail", "");
- $content->assign('link', $link);
- $content->assign('user_displayname', $ownerDisplayName);
- $content->assign('filename', $filename);
- $content->assign('expiration', $expiration);
- $text = $content->fetchPage();
-
- $content = new OC_Template("core", "altmail", "");
- $content->assign('link', $link);
- $content->assign('user_displayname', $ownerDisplayName);
- $content->assign('filename', $filename);
- $content->assign('expiration', $expiration);
- $alttext = $content->fetchPage();
-
- $default_from = OCP\Util::getDefaultEmailAddress('sharing-noreply');
- $from = OCP\Config::getUserValue(\OCP\User::getUser(), 'settings', 'email', $default_from);
-
- // send it out now
- try {
- OCP\Util::sendMail($email, $displayName, $subject, $text, $from, $ownerDisplayName, 1, $alttext);
- } catch (Exception $exception) {
- $noMail[] = \OCP\User::getDisplayName($recipient);
- }
- }
- }
+ $mailNotification = new OC\Share\MailNotifications();
+ $result = $mailNotification->sendInternalShareMail($recipientList, $itemSource, $itemType);
\OCP\Share::setSendMailStatus($itemType, $itemSource, $shareType, true);
- if (empty($noMail)) {
+ if (empty($result)) {
OCP\JSON::success();
} else {
OCP\JSON::error(array(
'data' => array(
'message' => $l->t("Couldn't send mail to following users: %s ",
- implode(', ', $noMail)
+ implode(', ', $result)
)
)
));
@@ -187,56 +126,31 @@ if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSo
break;
case 'email':
- // enable l10n support
- $l = OC_L10N::get('core');
// read post variables
- $user = OCP\USER::getUser();
- $displayName = OCP\User::getDisplayName();
- $type = $_POST['itemType'];
$link = $_POST['link'];
$file = $_POST['file'];
$to_address = $_POST['toaddress'];
+ $mailNotification = new \OC\Share\MailNotifications();
+
$expiration = null;
if (isset($_POST['expiration']) && $_POST['expiration'] !== '') {
try {
$date = new DateTime($_POST['expiration']);
- $expiration = $l->l('date', $date->getTimestamp());
+ $expiration = $date->getTimestamp();
} catch (Exception $e) {
\OCP\Util::writeLog('sharing', "Couldn't read date: " . $e->getMessage(), \OCP\Util::ERROR);
}
}
- // setup the email
- $subject = (string)$l->t('%s shared »%s« with you', array($displayName, $file));
-
- $content = new OC_Template("core", "mail", "");
- $content->assign ('link', $link);
- $content->assign ('type', $type);
- $content->assign ('user_displayname', $displayName);
- $content->assign ('filename', $file);
- $content->assign('expiration', $expiration);
- $text = $content->fetchPage();
-
- $content = new OC_Template("core", "altmail", "");
- $content->assign ('link', $link);
- $content->assign ('type', $type);
- $content->assign ('user_displayname', $displayName);
- $content->assign ('filename', $file);
- $content->assign('expiration', $expiration);
- $alttext = $content->fetchPage();
-
- $default_from = OCP\Util::getDefaultEmailAddress('sharing-noreply');
- $from_address = OCP\Config::getUserValue($user, 'settings', 'email', $default_from );
-
- // send it out now
- try {
- OCP\Util::sendMail($to_address, $to_address, $subject, $text, $from_address, $displayName, 1, $alttext);
- OCP\JSON::success();
- } catch (Exception $exception) {
- OCP\JSON::error(array('data' => array('message' => OC_Util::sanitizeHTML($exception->getMessage()))));
+ $result = $mailNotification->sendLinkShareMail($to_address, $file, $link, $expiration);
+ if($result === true) {
+ \OCP\JSON::success();
+ } else {
+ \OCP\JSON::error(array('data' => array('message' => OC_Util::sanitizeHTML($result))));
}
+
break;
}
} else if (isset($_GET['fetch'])) {
diff --git a/core/css/fixes.css b/core/css/fixes.css
index 4ee854addef..a33afd5cf77 100644
--- a/core/css/fixes.css
+++ b/core/css/fixes.css
@@ -54,11 +54,6 @@
background-color: #1B314D;
}
-/* in IE9 the nav bar on the left side is too narrow and leave a white area - original width is 80px */
-.ie9 #navigation {
- width: 100px;
-}
-
/* IE8 isn't able to display transparent background. So it is specified using a gradient */
.ie8 #nojavascript {
filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#4c320000', endColorstr='#4c320000'); /* IE */
diff --git a/core/css/multiselect.css b/core/css/multiselect.css
index 60f2f47e698..8d949e7cdb7 100644
--- a/core/css/multiselect.css
+++ b/core/css/multiselect.css
@@ -48,7 +48,7 @@ ul.multiselectoptions > li input[type='checkbox']:checked+label {
font-weight: bold;
}
-div.multiselect {
+div.multiselect, select.multiselect {
display: inline-block;
max-width: 400px;
min-width: 150px;
@@ -58,6 +58,12 @@ div.multiselect {
vertical-align: bottom;
}
+/* To make a select look like a multiselect until it's initialized */
+select.multiselect {
+ height: 30px;
+ min-width: 113px;
+}
+
div.multiselect.active {
background-color: #fff;
position: relative;
diff --git a/core/css/styles.css b/core/css/styles.css
index 1c80a3ea160..341a507ce37 100644
--- a/core/css/styles.css
+++ b/core/css/styles.css
@@ -75,6 +75,19 @@ body { background:#fefefe; font:normal .8em/1.6em "Helvetica Neue",Helvetica,Ari
color: #aaa;
}
+#header .logo {
+ background-image: url(../img/logo.svg);
+ width: 250px;
+ height: 118px;
+ margin: 0 auto;
+}
+
+#header .logo-wide {
+ background-image: url(../img/logo-wide.svg);
+ width: 147px;
+ height: 32px;
+}
+
/* INPUTS */
input[type="text"],
input[type="password"],
@@ -935,3 +948,20 @@ div.crumb:active {
opacity:.7;
}
+.appear {
+ opacity: 1;
+ transition: opacity 500ms ease 0s;
+ -moz-transition: opacity 500ms ease 0s;
+ -ms-transition: opacity 500ms ease 0s;
+ -o-transition: opacity 500ms ease 0s;
+ -webkit-transition: opacity 500ms ease 0s;
+}
+.appear.transparent {
+ opacity: 0;
+}
+
+/* for IE10 */
+@-ms-viewport {
+ width: device-width;
+}
+
diff --git a/core/img/filetypes/text-x-javascript.png b/core/img/filetypes/application-javascript.png
index 1e1d3140f63..1e1d3140f63 100644
--- a/core/img/filetypes/text-x-javascript.png
+++ b/core/img/filetypes/application-javascript.png
Binary files differ
diff --git a/core/img/filetypes/text-x-javascript.svg b/core/img/filetypes/application-javascript.svg
index 4e9819bb685..4e9819bb685 100644
--- a/core/img/filetypes/text-x-javascript.svg
+++ b/core/img/filetypes/application-javascript.svg
diff --git a/core/img/filetypes/flash.png b/core/img/filetypes/application-x-shockwave-flash.png
index 75424f81d68..75424f81d68 100644
--- a/core/img/filetypes/flash.png
+++ b/core/img/filetypes/application-x-shockwave-flash.png
Binary files differ
diff --git a/core/img/filetypes/flash.svg b/core/img/filetypes/application-x-shockwave-flash.svg
index b373fd6512d..b373fd6512d 100644
--- a/core/img/filetypes/flash.svg
+++ b/core/img/filetypes/application-x-shockwave-flash.svg
diff --git a/core/img/filetypes/calendar.png b/core/img/filetypes/text-calendar.png
index d5c666a7695..d5c666a7695 100644
--- a/core/img/filetypes/calendar.png
+++ b/core/img/filetypes/text-calendar.png
Binary files differ
diff --git a/core/img/filetypes/calendar.svg b/core/img/filetypes/text-calendar.svg
index 7d62bb8fa12..7d62bb8fa12 100644
--- a/core/img/filetypes/calendar.svg
+++ b/core/img/filetypes/text-calendar.svg
diff --git a/core/js/config.php b/core/js/config.php
index b6875fb73f9..139c3b6d485 100644
--- a/core/js/config.php
+++ b/core/js/config.php
@@ -24,6 +24,7 @@ foreach(OC_App::getEnabledApps() as $app) {
$array = array(
"oc_debug" => (defined('DEBUG') && DEBUG) ? 'true' : 'false',
+ "oc_isadmin" => OC_User::isAdminUser(OC_User::getUser()) ? 'true' : 'false',
"oc_webroot" => "\"".OC::$WEBROOT."\"",
"oc_appswebroots" => str_replace('\\/', '/', json_encode($apps_paths)), // Ugly unescape slashes waiting for better solution
"datepickerFormatDate" => json_encode($l->l('jsdate', 'jsdate')),
diff --git a/core/templates/layout.guest.php b/core/templates/layout.guest.php
index 6a96b17b100..91157b923a5 100644
--- a/core/templates/layout.guest.php
+++ b/core/templates/layout.guest.php
@@ -36,7 +36,7 @@
<body id="body-login">
<div class="wrapper"><!-- for sticky footer -->
<header><div id="header">
- <img src="<?php print_unescaped(image_path('', 'logo.svg')); ?>" class="svg" alt="<?php p($theme->getName()); ?>" />
+ <div class='logo'></div>
<div id="logo-claim" style="display:none;"><?php p($theme->getLogoClaim()); ?></div>
</div></header>
diff --git a/core/templates/layout.user.php b/core/templates/layout.user.php
index 9e1555cfe6d..3d897503480 100644
--- a/core/templates/layout.user.php
+++ b/core/templates/layout.user.php
@@ -45,8 +45,9 @@
<?php endif; ?>
</div>
<header><div id="header">
- <a href="<?php print_unescaped(link_to('', 'index.php')); ?>" title="" id="owncloud"><img class="svg"
- src="<?php print_unescaped(image_path('', 'logo-wide.svg')); ?>" alt="<?php p($theme->getName()); ?>" /></a>
+ <a href="<?php print_unescaped(link_to('', 'index.php')); ?>" title="" id="owncloud">
+ <div class='logo-wide'></div>
+ </a>
<div id="logo-claim" style="display:none;"><?php p($theme->getLogoClaim()); ?></div>
<div id="settings" class="svg">
<span id="expand" tabindex="0" role="link">
diff --git a/lib/private/appframework/middleware/middlewaredispatcher.php b/lib/private/appframework/middleware/middlewaredispatcher.php
index 2a715598fc4..598743e523f 100644
--- a/lib/private/appframework/middleware/middlewaredispatcher.php
+++ b/lib/private/appframework/middleware/middlewaredispatcher.php
@@ -26,6 +26,7 @@ namespace OC\AppFramework\Middleware;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\Response;
+use OCP\AppFramework\MiddleWare;
/**
* This class is used to store and run all the middleware in correct order
diff --git a/lib/private/connector/sabre/file.php b/lib/private/connector/sabre/file.php
index 5ef6365f657..ef6caaf22a7 100644
--- a/lib/private/connector/sabre/file.php
+++ b/lib/private/connector/sabre/file.php
@@ -58,6 +58,11 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D
throw new \Sabre_DAV_Exception_ServiceUnavailable();
}
+ $fileName = basename($this->path);
+ if (!\OCP\Util::isValidFileName($fileName)) {
+ throw new \Sabre_DAV_Exception_BadRequest();
+ }
+
// chunked handling
if (isset($_SERVER['HTTP_OC_CHUNKED'])) {
return $this->createFileChunked($data);
@@ -142,15 +147,16 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D
* @throws Sabre_DAV_Exception_Forbidden
*/
public function delete() {
+ $fs = $this->getFS();
if ($this->path === 'Shared') {
throw new \Sabre_DAV_Exception_Forbidden();
}
- if (!\OC\Files\Filesystem::isDeletable($this->path)) {
+ if (!$fs->isDeletable($this->path)) {
throw new \Sabre_DAV_Exception_Forbidden();
}
- \OC\Files\Filesystem::unlink($this->path);
+ $fs->unlink($this->path);
// remove properties
$this->removeProperties();
diff --git a/lib/private/connector/sabre/node.php b/lib/private/connector/sabre/node.php
index 05d2d2291ec..5807c5c7f71 100644
--- a/lib/private/connector/sabre/node.php
+++ b/lib/private/connector/sabre/node.php
@@ -85,19 +85,24 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr
* @return void
*/
public function setName($name) {
+ $fs = $this->getFS();
// rename is only allowed if the update privilege is granted
- if (!\OC\Files\Filesystem::isUpdatable($this->path)) {
+ if (!$fs->isUpdatable($this->path)) {
throw new \Sabre_DAV_Exception_Forbidden();
}
list($parentPath, ) = Sabre_DAV_URLUtil::splitPath($this->path);
list(, $newName) = Sabre_DAV_URLUtil::splitPath($name);
+ if (!\OCP\Util::isValidFileName($newName)) {
+ throw new \Sabre_DAV_Exception_BadRequest();
+ }
+
$newPath = $parentPath . '/' . $newName;
$oldPath = $this->path;
- \OC\Files\Filesystem::rename($this->path, $newPath);
+ $fs->rename($this->path, $newPath);
$this->path = $newPath;
diff --git a/lib/private/connector/sabre/objecttree.php b/lib/private/connector/sabre/objecttree.php
index d1e179af2ec..d2fa425b22c 100644
--- a/lib/private/connector/sabre/objecttree.php
+++ b/lib/private/connector/sabre/objecttree.php
@@ -105,6 +105,11 @@ class ObjectTree extends \Sabre_DAV_ObjectTree {
}
}
+ $fileName = basename($destinationPath);
+ if (!\OCP\Util::isValidFileName($fileName)) {
+ throw new \Sabre_DAV_Exception_BadRequest();
+ }
+
$renameOkay = $fs->rename($sourcePath, $destinationPath);
if (!$renameOkay) {
throw new \Sabre_DAV_Exception_Forbidden('');
diff --git a/lib/private/files/filesystem.php b/lib/private/files/filesystem.php
index b6102f5c245..952f9f9febf 100644
--- a/lib/private/files/filesystem.php
+++ b/lib/private/files/filesystem.php
@@ -320,16 +320,16 @@ class Filesystem {
else {
self::mount('\OC\Files\Storage\Local', array('datadir' => $root), $user);
}
- $datadir = \OC_Config::getValue("datadirectory", \OC::$SERVERROOT . "/data");
+ $mount_file = \OC_Config::getValue("mount_file", \OC::$SERVERROOT . "/data/mount.json");
//move config file to it's new position
if (is_file(\OC::$SERVERROOT . '/config/mount.json')) {
- rename(\OC::$SERVERROOT . '/config/mount.json', $datadir . '/mount.json');
+ rename(\OC::$SERVERROOT . '/config/mount.json', $mount_file);
}
// Load system mount points
- if (is_file(\OC::$SERVERROOT . '/config/mount.php') or is_file($datadir . '/mount.json')) {
- if (is_file($datadir . '/mount.json')) {
- $mountConfig = json_decode(file_get_contents($datadir . '/mount.json'), true);
+ if (is_file(\OC::$SERVERROOT . '/config/mount.php') or is_file($mount_file)) {
+ if (is_file($mount_file)) {
+ $mountConfig = json_decode(file_get_contents($mount_file), true);
} elseif (is_file(\OC::$SERVERROOT . '/config/mount.php')) {
$mountConfig = $parser->parsePHP(file_get_contents(\OC::$SERVERROOT . '/config/mount.php'));
}
diff --git a/lib/private/files/storage/wrapper/quota.php b/lib/private/files/storage/wrapper/quota.php
index 1bcdca7f47a..26c952e694a 100644
--- a/lib/private/files/storage/wrapper/quota.php
+++ b/lib/private/files/storage/wrapper/quota.php
@@ -16,11 +16,17 @@ class Quota extends Wrapper {
protected $quota;
/**
+ * @var string $sizeRoot
+ */
+ protected $sizeRoot;
+
+ /**
* @param array $parameters
*/
public function __construct($parameters) {
$this->storage = $parameters['storage'];
$this->quota = $parameters['quota'];
+ $this->sizeRoot = isset($parameters['root']) ? $parameters['root'] : '';
}
/**
@@ -46,7 +52,7 @@ class Quota extends Wrapper {
if ($this->quota < 0) {
return $this->storage->free_space($path);
} else {
- $used = $this->getSize('');
+ $used = $this->getSize($this->sizeRoot);
if ($used < 0) {
return \OC\Files\SPACE_NOT_COMPUTED;
} else {
diff --git a/lib/private/helper.php b/lib/private/helper.php
index e5d1fa9b513..1aab2f296e1 100644
--- a/lib/private/helper.php
+++ b/lib/private/helper.php
@@ -152,7 +152,32 @@ class OC_Helper {
public static function mimetypeIcon($mimetype) {
$alias = array(
'application/octet-stream' => 'file', // use file icon as fallback
- 'application/xml' => 'code/xml',
+
+ 'application/illustrator' => 'image',
+ 'application/coreldraw' => 'image',
+ 'application/x-gimp' => 'image',
+ 'application/x-photoshop' => 'image',
+
+ 'application/x-font-ttf' => 'font',
+ 'application/font-woff' => 'font',
+ 'application/vnd.ms-fontobject' => 'font',
+
+ 'application/json' => 'text/code',
+ 'application/x-perl' => 'text/code',
+ 'application/x-php' => 'text/code',
+ 'text/x-shellscript' => 'text/code',
+ 'application/xml' => 'text/html',
+ 'text/css' => 'text/code',
+ 'application/x-tex' => 'text',
+
+ 'application/x-compressed' => 'package/x-generic',
+ 'application/x-7z-compressed' => 'package/x-generic',
+ 'application/x-deb' => 'package/x-generic',
+ 'application/x-gzip' => 'package/x-generic',
+ 'application/x-rar-compressed' => 'package/x-generic',
+ 'application/x-tar' => 'package/x-generic',
+ 'application/zip' => 'package/x-generic',
+
'application/msword' => 'x-office/document',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => 'x-office/document',
'application/vnd.openxmlformats-officedocument.wordprocessingml.template' => 'x-office/document',
@@ -162,6 +187,7 @@ class OC_Helper {
'application/vnd.oasis.opendocument.text-template' => 'x-office/document',
'application/vnd.oasis.opendocument.text-web' => 'x-office/document',
'application/vnd.oasis.opendocument.text-master' => 'x-office/document',
+
'application/mspowerpoint' => 'x-office/presentation',
'application/vnd.ms-powerpoint' => 'x-office/presentation',
'application/vnd.openxmlformats-officedocument.presentationml.presentation' => 'x-office/presentation',
@@ -173,6 +199,7 @@ class OC_Helper {
'application/vnd.ms-powerpoint.slideshow.macroEnabled.12' => 'x-office/presentation',
'application/vnd.oasis.opendocument.presentation' => 'x-office/presentation',
'application/vnd.oasis.opendocument.presentation-template' => 'x-office/presentation',
+
'application/msexcel' => 'x-office/spreadsheet',
'application/vnd.ms-excel' => 'x-office/spreadsheet',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => 'x-office/spreadsheet',
@@ -183,6 +210,8 @@ class OC_Helper {
'application/vnd.ms-excel.sheet.binary.macroEnabled.12' => 'x-office/spreadsheet',
'application/vnd.oasis.opendocument.spreadsheet' => 'x-office/spreadsheet',
'application/vnd.oasis.opendocument.spreadsheet-template' => 'x-office/spreadsheet',
+ 'text/csv' => 'x-office/spreadsheet',
+
'application/msaccess' => 'database',
);
diff --git a/lib/private/image.php b/lib/private/image.php
index 42685ddab5c..17caaa012f5 100644
--- a/lib/private/image.php
+++ b/lib/private/image.php
@@ -231,7 +231,7 @@ class OC_Image {
}
/**
- * @returns Returns the image resource in any.
+ * @returns resource Returns the image resource in any.
*/
public function resource() {
return $this->resource;
diff --git a/lib/private/l10n.php b/lib/private/l10n.php
index 1ade18ea427..ad979a92870 100644
--- a/lib/private/l10n.php
+++ b/lib/private/l10n.php
@@ -118,7 +118,7 @@ class OC_L10N implements \OCP\IL10N {
return;
}
$app = OC_App::cleanAppId($this->app);
- $lang = $this->lang;
+ $lang = str_replace(array('\0', '/', '\\', '..'), '', $this->lang);
$this->app = true;
// Find the right language
if(is_null($lang) || $lang == '') {
@@ -163,7 +163,7 @@ class OC_L10N implements \OCP\IL10N {
}
}
- if(file_exists(OC::$SERVERROOT.'/core/l10n/l10n-'.$lang.'.php')) {
+ if(file_exists(OC::$SERVERROOT.'/core/l10n/l10n-'.$lang.'.php') && OC_Helper::issubdirectory(OC::$SERVERROOT.'/core/l10n/l10n-'.$lang.'.php', OC::$SERVERROOT.'/core/l10n/')) {
// Include the file, save the data from $CONFIG
include OC::$SERVERROOT.'/core/l10n/l10n-'.$lang.'.php';
if(isset($LOCALIZATIONS) && is_array($LOCALIZATIONS)) {
diff --git a/lib/private/mimetypes.list.php b/lib/private/mimetypes.list.php
index 174877d623b..9bd07b89023 100644
--- a/lib/private/mimetypes.list.php
+++ b/lib/private/mimetypes.list.php
@@ -24,11 +24,13 @@
* Array mapping file extensions to mimetypes (in alphabetical order).
*/
return array(
- 'accdb'=>'application/msaccess',
+ '7z' => 'application/x-7z-compressed',
+ 'accdb' => 'application/msaccess',
'ai' => 'application/illustrator',
- 'avi'=>'video/x-msvideo',
+ 'avi' => 'video/x-msvideo',
'bash' => 'text/x-shellscript',
- 'blend'=>'application/x-blender',
+ 'blend' => 'application/x-blender',
+ 'bin' => 'application/x-bin',
'cb7' => 'application/x-cbr',
'cba' => 'application/x-cbr',
'cbr' => 'application/x-cbr',
@@ -38,81 +40,91 @@ return array(
'cc' => 'text/x-c',
'cdr' => 'application/coreldraw',
'cpp' => 'text/x-c++src',
- 'css'=>'text/css',
+ 'css' => 'text/css',
+ 'csv' => 'text/csv',
'cvbdl' => 'application/x-cbr',
'c' => 'text/x-c',
'c++' => 'text/x-c++src',
- 'doc'=>'application/msword',
- 'docx'=>'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
- 'dot'=>'application/msword',
- 'dotx'=>'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
- 'dv'=>'video/dv',
+ 'deb' => 'application/x-deb',
+ 'doc' => 'application/msword',
+ 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+ 'dot' => 'application/msword',
+ 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
+ 'dv' => 'video/dv',
+ 'eot' => 'application/vnd.ms-fontobject',
'epub' => 'application/epub+zip',
- 'exe'=>'application/x-ms-dos-executable',
- 'flac'=>'audio/flac',
- 'gif'=>'image/gif',
- 'gz'=>'application/x-gzip',
- 'gzip'=>'application/x-gzip',
- 'html'=>'text/html',
- 'htm'=>'text/html',
- 'ical'=>'text/calendar',
- 'ics'=>'text/calendar',
+ 'exe' => 'application/x-ms-dos-executable',
+ 'flac' => 'audio/flac',
+ 'gif' => 'image/gif',
+ 'gz' => 'application/x-gzip',
+ 'gzip' => 'application/x-gzip',
+ 'html' => 'text/html',
+ 'htm' => 'text/html',
+ 'ical' => 'text/calendar',
+ 'ics' => 'text/calendar',
'impress' => 'text/impress',
- 'jpeg'=>'image/jpeg',
- 'jpg'=>'image/jpeg',
- 'js'=>'application/javascript',
- 'keynote'=>'application/x-iwork-keynote-sffkey',
- 'kra'=>'application/x-krita',
- 'm2t'=>'video/mp2t',
- 'm4v'=>'video/mp4',
+ 'jpeg' => 'image/jpeg',
+ 'jpg' => 'image/jpeg',
+ 'js' => 'application/javascript',
+ 'json' => 'application/json',
+ 'keynote' => 'application/x-iwork-keynote-sffkey',
+ 'kra' => 'application/x-krita',
+ 'm2t' => 'video/mp2t',
+ 'm4v' => 'video/mp4',
'markdown' => 'text/markdown',
'mdown' => 'text/markdown',
'md' => 'text/markdown',
- 'mdb'=>'application/msaccess',
+ 'mdb' => 'application/msaccess',
'mdwn' => 'text/markdown',
'mobi' => 'application/x-mobipocket-ebook',
- 'mov'=>'video/quicktime',
- 'mp3'=>'audio/mpeg',
- 'mp4'=>'video/mp4',
- 'mpeg'=>'video/mpeg',
- 'mpg'=>'video/mpeg',
- 'msi'=>'application/x-msi',
- 'numbers'=>'application/x-iwork-numbers-sffnumbers',
- 'odg'=>'application/vnd.oasis.opendocument.graphics',
- 'odp'=>'application/vnd.oasis.opendocument.presentation',
- 'ods'=>'application/vnd.oasis.opendocument.spreadsheet',
- 'odt'=>'application/vnd.oasis.opendocument.text',
- 'oga'=>'audio/ogg',
- 'ogg'=>'audio/ogg',
- 'ogv'=>'video/ogg',
- 'pages'=>'application/x-iwork-pages-sffpages',
- 'pdf'=>'application/pdf',
- 'php'=>'application/x-php',
- 'pl'=>'application/x-pearl',
- 'png'=>'image/png',
- 'ppt'=>'application/mspowerpoint',
- 'pptx'=>'application/vnd.openxmlformats-officedocument.presentationml.presentation',
- 'psd'=>'application/x-photoshop',
- 'py'=>'text/x-script.python',
+ 'mov' => 'video/quicktime',
+ 'mp3' => 'audio/mpeg',
+ 'mp4' => 'video/mp4',
+ 'mpeg' => 'video/mpeg',
+ 'mpg' => 'video/mpeg',
+ 'msi' => 'application/x-msi',
+ 'numbers' => 'application/x-iwork-numbers-sffnumbers',
+ 'odg' => 'application/vnd.oasis.opendocument.graphics',
+ 'odp' => 'application/vnd.oasis.opendocument.presentation',
+ 'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
+ 'odt' => 'application/vnd.oasis.opendocument.text',
+ 'oga' => 'audio/ogg',
+ 'ogg' => 'audio/ogg',
+ 'ogv' => 'video/ogg',
+ 'otf' => 'font/opentype',
+ 'pages' => 'application/x-iwork-pages-sffpages',
+ 'pdf' => 'application/pdf',
+ 'php' => 'application/x-php',
+ 'pl' => 'application/x-perl',
+ 'png' => 'image/png',
+ 'ppt' => 'application/mspowerpoint',
+ 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
+ 'psd' => 'application/x-photoshop',
+ 'py' => 'text/x-python',
+ 'rar' => 'application/x-rar-compressed',
'reveal' => 'text/reveal',
'sgf' => 'application/sgf',
'sh-lib' => 'text/x-shellscript',
'sh' => 'text/x-shellscript',
- 'svg'=>'image/svg+xml',
- 'tar'=>'application/x-tar',
- 'tar.gz'=>'application/x-compressed',
- 'tgz'=>'application/x-compressed',
- 'tiff'=>'image/tiff',
- 'tif'=>'image/tiff',
- 'txt'=>'text/plain',
+ 'svg' => 'image/svg+xml',
+ 'swf' => 'application/x-shockwave-flash',
+ 'tar' => 'application/x-tar',
+ 'tar.gz' => 'application/x-compressed',
+ 'tex' => 'application/x-tex',
+ 'tgz' => 'application/x-compressed',
+ 'tiff' => 'image/tiff',
+ 'tif' => 'image/tiff',
+ 'ttf' => 'application/x-font-ttf',
+ 'txt' => 'text/plain',
'vcard' => 'text/vcard',
'vcf' => 'text/vcard',
- 'wav'=>'audio/wav',
- 'webm'=>'video/webm',
- 'wmv'=>'video/x-ms-asf',
- 'xcf'=>'application/x-gimp',
- 'xls'=>'application/msexcel',
- 'xlsx'=>'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
- 'xml'=>'application/xml',
- 'zip'=>'application/zip',
+ 'wav' => 'audio/wav',
+ 'webm' => 'video/webm',
+ 'woff' => 'application/font-woff',
+ 'wmv' => 'video/x-ms-asf',
+ 'xcf' => 'application/x-gimp',
+ 'xls' => 'application/msexcel',
+ 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ 'xml' => 'application/xml',
+ 'zip' => 'application/zip',
);
diff --git a/lib/private/share/mailnotifications.php b/lib/private/share/mailnotifications.php
new file mode 100644
index 00000000000..360376294cc
--- /dev/null
+++ b/lib/private/share/mailnotifications.php
@@ -0,0 +1,160 @@
+<?php
+/**
+* ownCloud
+*
+* @author Bjoern Schiessle
+* @copyright 2014 Bjoern Schiessle <schiessle@owncloud.com>
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+* License as published by the Free Software Foundation; either
+* version 3 of the License, or any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+*
+* You should have received a copy of the GNU Affero General Public
+* License along with this library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+namespace OC\Share;
+
+class MailNotifications {
+
+ private $senderId; // sender userId
+ private $from; // sender email address
+ private $senderDisplayName;
+ private $l;
+
+ /**
+ *
+ * @param string $recipient user id
+ * @param string $sender user id (if nothing is set we use the currently logged-in user)
+ */
+ public function __construct($sender = null) {
+ $this->l = \OC_L10N::get('core');
+
+ $this->senderId = $sender;
+
+ $this->from = \OCP\Util::getDefaultEmailAddress('sharing-noreply');
+ if ($this->senderId) {
+ $this->from = \OCP\Config::getUserValue($this->senderId, 'settings', 'email', $this->from);
+ $this->senderDisplayName = \OCP\User::getDisplayName($this->senderId);
+ } else {
+ $this->senderDisplayName = \OCP\User::getDisplayName();
+ }
+ }
+
+ /**
+ * @brief inform users if a file was shared with them
+ *
+ * @param array $recipientList list of recipients
+ * @param type $itemSource shared item source
+ * @param type $itemType shared item type
+ * @return array list of user to whom the mail send operation failed
+ */
+ public function sendInternalShareMail($recipientList, $itemSource, $itemType) {
+
+ $noMail = array();
+
+ foreach ($recipientList as $recipient) {
+ $recipientDisplayName = \OCP\User::getDisplayName($recipient);
+ $to = \OC_Preferences::getValue($recipient, 'settings', 'email', '');
+
+ if ($to === '') {
+ $noMail[] = $recipientDisplayName;
+ continue;
+ }
+
+ $items = \OCP\Share::getItemSharedWithUser($itemType, $itemSource, $recipient);
+ $filename = trim($items[0]['file_target'], '/');
+ $subject = (string) $this->l->t('%s shared »%s« with you', array($this->senderDisplayName, $filename));
+ $expiration = null;
+ if (isset($items[0]['expiration'])) {
+ try {
+ $date = new DateTime($items[0]['expiration']);
+ $expiration = $date->getTimestamp();
+ } catch (\Exception $e) {
+ \OCP\Util::writeLog('sharing', "Couldn't read date: " . $e->getMessage(), \OCP\Util::ERROR);
+ }
+ }
+
+ if ($itemType === 'folder') {
+ $foldername = "/Shared/" . $filename;
+ } else {
+ // if it is a file we can just link to the Shared folder,
+ // that's the place where the user will find the file
+ $foldername = "/Shared";
+ }
+
+ $link = \OCP\Util::linkToAbsolute('files', 'index.php', array("dir" => $foldername));
+
+ list($htmlMail, $alttextMail) = $this->createMailBody($filename, $link, $expiration);
+
+ // send it out now
+ try {
+ \OCP\Util::sendMail($to, $recipientDisplayName, $subject, $htmlMail, $this->from, $this->senderDisplayName, 1, $alttextMail);
+ } catch (\Exception $e) {
+ \OCP\Util::writeLog('sharing', "Can't send mail to inform the user abaut an internal share: " . $e->getMessage() , \OCP\Util::ERROR);
+ $noMail[] = $recipientDisplayName;
+ }
+ }
+
+ return $noMail;
+
+ }
+
+ /**
+ * @brief inform recipient about public link share
+ *
+ * @param string recipient recipient email address
+ * @param string $filename the shared file
+ * @param string $link the public link
+ * @param int $expiration expiration date (timestamp)
+ * @return mixed $result true or error message
+ */
+ public function sendLinkShareMail($recipient, $filename, $link, $expiration) {
+ $subject = (string)$this->l->t('%s shared »%s« with you', array($this->senderDisplayName, $filename));
+ list($htmlMail, $alttextMail) = $this->createMailBody($filename, $link, $expiration);
+ try {
+ \OCP\Util::sendMail($recipient, $recipient, $subject, $htmlMail, $this->from, $this->senderDisplayName, 1, $alttextMail);
+ } catch (\Exception $e) {
+ \OCP\Util::writeLog('sharing', "Can't send mail with public link: " . $e->getMessage(), \OCP\Util::ERROR);
+ return $e->getMessage();
+ }
+
+ return true;
+ }
+
+ /**
+ * @brief create mail body for plain text and html mail
+ *
+ * @param string $filename the shared file
+ * @param string $link link to the shared file
+ * @param int $expiration expiration date (timestamp)
+ * @return array with the html mail body and the plain text mail body
+ */
+ private function createMailBody($filename, $link, $expiration) {
+
+ $formatedDate = $expiration ? $this->l->l('date', $expiration) : null;
+
+ $html = new \OC_Template("core", "mail", "");
+ $html->assign ('link', $link);
+ $html->assign ('user_displayname', $this->senderDisplayName);
+ $html->assign ('filename', $filename);
+ $html->assign('expiration', $formatedDate);
+ $htmlMail = $html->fetchPage();
+
+ $alttext = new \OC_Template("core", "altmail", "");
+ $alttext->assign ('link', $link);
+ $alttext->assign ('user_displayname', $this->senderDisplayName);
+ $alttext->assign ('filename', $filename);
+ $alttext->assign('expiration', $formatedDate);
+ $alttextMail = $alttext->fetchPage();
+
+ return array($htmlMail, $alttextMail);
+ }
+
+}
diff --git a/lib/private/urlgenerator.php b/lib/private/urlgenerator.php
index 4e3c1109000..60da34f2d6e 100644
--- a/lib/private/urlgenerator.php
+++ b/lib/private/urlgenerator.php
@@ -147,6 +147,7 @@ class URLGenerator implements IURLGenerator {
* @return string the absolute version of the url
*/
public function getAbsoluteURL($url) {
- return \OC_Request::serverProtocol() . '://' . \OC_Request::serverHost() . $url;
+ $separator = $url[0] === '/' ? '' : '/';
+ return \OC_Request::serverProtocol() . '://' . \OC_Request::serverHost() . $separator . $url;
}
}
diff --git a/lib/private/user.php b/lib/private/user.php
index 86a01f96258..a89b7286c10 100644
--- a/lib/private/user.php
+++ b/lib/private/user.php
@@ -227,6 +227,7 @@ class OC_User {
* Log in a user and regenerate a new session - if the password is ok
*/
public static function login($uid, $password) {
+ session_regenerate_id(true);
return self::getUserSession()->login($uid, $password);
}
@@ -246,7 +247,6 @@ class OC_User {
OC_Hook::emit( "OC_User", "pre_login", array( "run" => &$run, "uid" => $uid ));
if($uid) {
- session_regenerate_id(true);
self::setUserId($uid);
self::setDisplayName($uid);
self::getUserSession()->setLoginName($uid);
diff --git a/lib/private/util.php b/lib/private/util.php
index 829eedce044..d3b682daa5c 100755
--- a/lib/private/util.php
+++ b/lib/private/util.php
@@ -65,7 +65,7 @@ class OC_Util {
$user = $storage->getUser()->getUID();
$quota = OC_Util::getUserQuota($user);
if ($quota !== \OC\Files\SPACE_UNLIMITED) {
- return new \OC\Files\Storage\Wrapper\Quota(array('storage' => $storage, 'quota' => $quota));
+ return new \OC\Files\Storage\Wrapper\Quota(array('storage' => $storage, 'quota' => $quota, 'root' => 'files'));
}
}
@@ -1155,4 +1155,25 @@ class OC_Util {
}
return $version;
}
+
+ /**
+ * Returns whether the given file name is valid
+ * @param $file string file name to check
+ * @return bool true if the file name is valid, false otherwise
+ */
+ public static function isValidFileName($file) {
+ $trimmed = trim($file);
+ if ($trimmed === '') {
+ return false;
+ }
+ if ($trimmed === '.' || $trimmed === '..') {
+ return false;
+ }
+ foreach (str_split($trimmed) as $char) {
+ if (strpos(\OCP\FILENAME_INVALID_CHARS, $char) !== false) {
+ return false;
+ }
+ }
+ return true;
+ }
}
diff --git a/lib/public/constants.php b/lib/public/constants.php
index 1495c620dc9..350646a0ac0 100644
--- a/lib/public/constants.php
+++ b/lib/public/constants.php
@@ -35,3 +35,6 @@ const PERMISSION_UPDATE = 2;
const PERMISSION_DELETE = 8;
const PERMISSION_SHARE = 16;
const PERMISSION_ALL = 31;
+
+const FILENAME_INVALID_CHARS = "\\/<>:\"|?*\n";
+
diff --git a/lib/public/util.php b/lib/public/util.php
index 570283e2a8a..585c5d22634 100644
--- a/lib/public/util.php
+++ b/lib/public/util.php
@@ -486,4 +486,13 @@ class Util {
public static function uploadLimit() {
return \OC_Helper::uploadLimit();
}
+
+ /**
+ * Returns whether the given file name is valid
+ * @param $file string file name to check
+ * @return bool true if the file name is valid, false otherwise
+ */
+ public static function isValidFileName($file) {
+ return \OC_Util::isValidFileName($file);
+ }
}
diff --git a/remote.php b/remote.php
index 7884695b3a5..9e18c8f80a9 100644
--- a/remote.php
+++ b/remote.php
@@ -32,11 +32,7 @@ try {
default:
OC_Util::checkAppEnabled($app);
OC_App::loadApp($app);
- if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
- $file = OC_App::getAppPath($app) .'/'. $parts[1];
- }else{
- $file = '/' . OC_App::getAppPath($app) .'/'. $parts[1];
- }
+ $file = OC_App::getAppPath($app) .'/'. $parts[1];
break;
}
$baseuri = OC::$WEBROOT . '/remote.php/'.$service.'/';
diff --git a/settings/js/isadmin.php b/settings/js/isadmin.php
deleted file mode 100644
index 13a8ba1d312..00000000000
--- a/settings/js/isadmin.php
+++ /dev/null
@@ -1,20 +0,0 @@
-<?php
-/**
- * Copyright (c) 2013 Lukas Reschke <lukas@statuscode.ch>
- * This file is licensed under the Affero General Public License version 3 or
- * later.
- * See the COPYING-README file.
- */
-
-// Set the content type to Javascript
-header("Content-type: text/javascript");
-
-// Disallow caching
-header("Cache-Control: no-cache, must-revalidate");
-header("Expires: Sat, 26 Jul 1997 05:00:00 GMT");
-
-if (OC_User::isAdminUser(OC_User::getUser())) {
- echo("var isadmin = true;");
-} else {
- echo("var isadmin = false;");
-}
diff --git a/settings/js/users.js b/settings/js/users.js
index 6886db668b5..160d0a8d9d2 100644
--- a/settings/js/users.js
+++ b/settings/js/users.js
@@ -85,19 +85,24 @@ var UserList = {
add: function (username, displayname, groups, subadmin, quota, sort) {
var tr = $('tbody tr').first().clone();
- if (tr.find('div.avatardiv')){
+ var subadminsEl;
+ var subadminSelect;
+ var groupsSelect;
+ if (tr.find('div.avatardiv').length){
$('div.avatardiv', tr).avatar(username, 32);
}
tr.attr('data-uid', username);
tr.attr('data-displayName', displayname);
tr.find('td.name').text(username);
tr.find('td.displayName > span').text(displayname);
- var groupsSelect = $('<select multiple="multiple" class="groupsselect" data-placehoder="Groups" title="' + t('settings', 'Groups') + '"></select>')
+
+ // make them look like the multiselect buttons
+ // until they get time to really get initialized
+ groupsSelect = $('<select multiple="multiple" class="groupsselect multiselect button" data-placehoder="Groups" title="' + t('settings', 'Groups') + '"></select>')
.attr('data-username', username)
.data('user-groups', groups);
- tr.find('td.groups').empty();
if (tr.find('td.subadmins').length > 0) {
- var subadminSelect = $('<select multiple="multiple" class="subadminsselect" data-placehoder="subadmins" title="' + t('settings', 'Group Admin') + '">')
+ subadminSelect = $('<select multiple="multiple" class="subadminsselect multiselect button" data-placehoder="subadmins" title="' + t('settings', 'Group Admin') + '">')
.attr('data-username', username)
.data('user-groups', groups)
.data('subadmin', subadmin);
@@ -109,11 +114,10 @@ var UserList = {
subadminSelect.append($('<option value="' + escapeHTML(group) + '">' + escapeHTML(group) + '</option>'));
}
});
- tr.find('td.groups').append(groupsSelect);
- UserList.applyMultiplySelect(groupsSelect);
- if (tr.find('td.subadmins').length > 0) {
- tr.find('td.subadmins').append(subadminSelect);
- UserList.applyMultiplySelect(subadminSelect);
+ tr.find('td.groups').empty().append(groupsSelect);
+ subadminsEl = tr.find('td.subadmins');
+ if (subadminsEl.length > 0) {
+ subadminsEl.append(subadminSelect);
}
if (tr.find('td.remove img').length === 0 && OC.currentUser !== username) {
var rm_img = $('<img class="svg action">').attr({
@@ -139,11 +143,11 @@ var UserList = {
}
}
$(tr).appendTo('tbody');
+
if (sort) {
UserList.doSort();
}
- quotaSelect.singleSelect();
quotaSelect.on('change', function () {
var uid = $(this).parent().parent().attr('data-uid');
var quota = $(this).val();
@@ -153,6 +157,16 @@ var UserList = {
}
});
});
+
+ // defer init so the user first sees the list appear more quickly
+ window.setTimeout(function(){
+ quotaSelect.singleSelect();
+ UserList.applyMultiplySelect(groupsSelect);
+ if (subadminSelect) {
+ UserList.applyMultiplySelect(subadminSelect);
+ }
+ }, 0);
+ return tr;
},
// From http://my.opera.com/GreyWyvern/blog/show.dml/1671288
alphanum: function(a, b) {
@@ -209,28 +223,39 @@ var UserList = {
if (UserList.updating) {
return;
}
+ $('table+.loading').css('visibility', 'visible');
UserList.updating = true;
$.get(OC.Router.generate('settings_ajax_userlist', { offset: UserList.offset, limit: UserList.usersToLoad }), function (result) {
+ var loadedUsers = 0;
+ var trs = [];
if (result.status === 'success') {
//The offset does not mirror the amount of users available,
//because it is backend-dependent. For correct retrieval,
//always the limit(requested amount of users) needs to be added.
- UserList.offset += UserList.usersToLoad;
$.each(result.data, function (index, user) {
if($('tr[data-uid="' + user.name + '"]').length > 0) {
return true;
}
var tr = UserList.add(user.name, user.displayname, user.groups, user.subadmin, user.quota, false);
- if (index === 9) {
- $(tr).bind('inview', function (event, isInView, visiblePartX, visiblePartY) {
- $(this).unbind(event);
- UserList.update();
- });
- }
+ tr.addClass('appear transparent');
+ trs.push(tr);
+ loadedUsers++;
});
if (result.data.length > 0) {
UserList.doSort();
+ $('table+.loading').css('visibility', 'hidden');
}
+ else {
+ UserList.noMoreEntries = true;
+ $('table+.loading').remove();
+ }
+ UserList.offset += loadedUsers;
+ // animate
+ setTimeout(function() {
+ for (var i = 0; i < trs.length; i++) {
+ trs[i].removeClass('transparent');
+ }
+ }, 0);
}
UserList.updating = false;
});
@@ -239,7 +264,7 @@ var UserList = {
applyMultiplySelect: function (element) {
var checked = [];
var user = element.attr('data-username');
- if ($(element).attr('class') === 'groupsselect') {
+ if ($(element).hasClass('groupsselect')) {
if (element.data('userGroups')) {
checked = element.data('userGroups');
}
@@ -248,7 +273,7 @@ var UserList = {
if (user === OC.currentUser && group === 'admin') {
return false;
}
- if (!isadmin && checked.length === 1 && checked[0] === group) {
+ if (!oc_isadmin && checked.length === 1 && checked[0] === group) {
return false;
}
$.post(
@@ -280,7 +305,7 @@ var UserList = {
});
};
var label;
- if (isadmin) {
+ if (oc_isadmin) {
label = t('settings', 'add group');
} else {
label = null;
@@ -295,7 +320,7 @@ var UserList = {
minWidth: 100
});
}
- if ($(element).attr('class') === 'subadminsselect') {
+ if ($(element).hasClass('subadminsselect')) {
if (element.data('subadmin')) {
checked = element.data('subadmin');
}
@@ -330,18 +355,26 @@ var UserList = {
minWidth: 100
});
}
- }
+ },
+
+ _onScroll: function(e) {
+ if (!!UserList.noMoreEntries) {
+ return;
+ }
+ if ($(window).scrollTop() + $(window).height() > $(document).height() - 500) {
+ UserList.update(true);
+ }
+ },
};
$(document).ready(function () {
UserList.doSort();
UserList.availableGroups = $('#content table').data('groups');
- $('tbody tr:last').bind('inview', function (event, isInView, visiblePartX, visiblePartY) {
- OC.Router.registerLoadedCallback(function () {
- UserList.update();
- });
+ OC.Router.registerLoadedCallback(function() {
+ $(window).scroll(function(e) {UserList._onScroll(e);});
});
+ $('table').after($('<div class="loading" style="height: 200px; visibility: hidden;"></div>'));
$('select[multiple]').each(function (index, element) {
UserList.applyMultiplySelect($(element));
diff --git a/settings/routes.php b/settings/routes.php
index 60f9d8e1001..895a9f5ccea 100644
--- a/settings/routes.php
+++ b/settings/routes.php
@@ -72,5 +72,3 @@ $this->create('settings_ajax_setloglevel', '/settings/ajax/setloglevel.php')
->actionInclude('settings/ajax/setloglevel.php');
$this->create('settings_ajax_setsecurity', '/settings/ajax/setsecurity.php')
->actionInclude('settings/ajax/setsecurity.php');
-$this->create('isadmin', '/settings/js/isadmin.js')
- ->actionInclude('settings/js/isadmin.php');
diff --git a/settings/templates/users.php b/settings/templates/users.php
index aabda0fac2f..937b40611b0 100644
--- a/settings/templates/users.php
+++ b/settings/templates/users.php
@@ -14,8 +14,6 @@ unset($items['admin']);
$_['subadmingroups'] = array_flip($items);
?>
-<script type="text/javascript" src="<?php print_unescaped(OC_Helper::linkToRoute('isadmin'));?>"></script>
-
<div id="controls">
<form id="newuser" autocomplete="off">
<input id="newusername" type="text" placeholder="<?php p($l->t('Login Name'))?>" /> <input
diff --git a/tests/lib/connector/sabre/file.php b/tests/lib/connector/sabre/file.php
index e1fed0384c6..c2f0ffa12d4 100644
--- a/tests/lib/connector/sabre/file.php
+++ b/tests/lib/connector/sabre/file.php
@@ -36,6 +36,31 @@ class Test_OC_Connector_Sabre_File extends PHPUnit_Framework_TestCase {
}
/**
+ * @expectedException Sabre_DAV_Exception_BadRequest
+ */
+ public function testSimplePutInvalidChars() {
+ // setup
+ $file = new OC_Connector_Sabre_File('/super*star.txt');
+ $file->fileView = $this->getMock('\OC\Files\View', array('file_put_contents'), array(), '', FALSE);
+ $file->fileView->expects($this->any())->method('file_put_contents')->withAnyParameters()->will($this->returnValue(false));
+
+ // action
+ $etag = $file->put('test data');
+ }
+
+ /**
+ * Test setting name with setName() with invalid chars
+ * @expectedException Sabre_DAV_Exception_BadRequest
+ */
+ public function testSetNameInvalidChars() {
+ // setup
+ $file = new OC_Connector_Sabre_File('/test.txt');
+ $file->fileView = $this->getMock('\OC\Files\View', array('isUpdatable'), array(), '', FALSE);
+ $file->fileView->expects($this->any())->method('isUpdatable')->withAnyParameters()->will($this->returnValue(true));
+ $file->setName('/super*star.txt');
+ }
+
+ /**
* @expectedException Sabre_DAV_Exception_Forbidden
*/
public function testDeleteSharedFails() {
diff --git a/tests/lib/connector/sabre/objecttree.php b/tests/lib/connector/sabre/objecttree.php
index e32f2365f95..fb50c736edd 100644
--- a/tests/lib/connector/sabre/objecttree.php
+++ b/tests/lib/connector/sabre/objecttree.php
@@ -52,6 +52,20 @@ class ObjectTree extends PHPUnit_Framework_TestCase {
$this->assertTrue(true);
}
+ /**
+ * @dataProvider moveFailedInvalidCharsProvider
+ * @expectedException Sabre_DAV_Exception_BadRequest
+ */
+ public function testMoveFailedInvalidChars($source, $dest, $updatables, $deletables) {
+ $this->moveTest($source, $dest, $updatables, $deletables);
+ }
+
+ function moveFailedInvalidCharsProvider() {
+ return array(
+ array('a/b', 'a/c*', array('a' => false, 'a/b' => true, 'a/c*' => false), array()),
+ );
+ }
+
function moveFailedProvider() {
return array(
array('a/b', 'a/c', array('a' => false, 'a/b' => false, 'a/c' => false), array()),
@@ -66,6 +80,8 @@ class ObjectTree extends PHPUnit_Framework_TestCase {
return array(
array('a/b', 'a/c', array('a' => false, 'a/b' => true, 'a/c' => false), array()),
array('a/b', 'b/b', array('a' => true, 'a/b' => true, 'b' => true, 'b/b' => false), array('a/b' => true)),
+ // older files with special chars can still be renamed to valid names
+ array('a/b*', 'b/b', array('a' => true, 'a/b*' => true, 'b' => true, 'b/b' => false), array('a/b*' => true)),
);
}
diff --git a/tests/lib/files/storage/wrapper/quota.php b/tests/lib/files/storage/wrapper/quota.php
index e1b880255fb..43eae78415d 100644
--- a/tests/lib/files/storage/wrapper/quota.php
+++ b/tests/lib/files/storage/wrapper/quota.php
@@ -62,7 +62,7 @@ class Quota extends \Test\Files\Storage\Storage {
$this->assertEquals('foobarqwe', $instance->file_get_contents('foo'));
}
- public function testReturnFalseWhenFopenFailed(){
+ public function testReturnFalseWhenFopenFailed() {
$failStorage = $this->getMock(
'\OC\Files\Storage\Local',
array('fopen'),
@@ -76,7 +76,7 @@ class Quota extends \Test\Files\Storage\Storage {
$this->assertFalse($instance->fopen('failedfopen', 'r'));
}
- public function testReturnRegularStreamOnRead(){
+ public function testReturnRegularStreamOnRead() {
$instance = $this->getLimitedStorage(9);
// create test file first
@@ -95,11 +95,30 @@ class Quota extends \Test\Files\Storage\Storage {
fclose($stream);
}
- public function testReturnQuotaStreamOnWrite(){
+ public function testReturnQuotaStreamOnWrite() {
$instance = $this->getLimitedStorage(9);
$stream = $instance->fopen('foo', 'w+');
$meta = stream_get_meta_data($stream);
$this->assertEquals('user-space', $meta['wrapper_type']);
fclose($stream);
}
+
+ public function testSpaceRoot() {
+ $storage = $this->getMockBuilder('\OC\Files\Storage\Local')->disableOriginalConstructor()->getMock();
+ $cache = $this->getMockBuilder('\OC\Files\Cache\Cache')->disableOriginalConstructor()->getMock();
+ $storage->expects($this->once())
+ ->method('getCache')
+ ->will($this->returnValue($cache));
+ $storage->expects($this->once())
+ ->method('free_space')
+ ->will($this->returnValue(2048));
+ $cache->expects($this->once())
+ ->method('get')
+ ->with('files')
+ ->will($this->returnValue(array('size' => 50)));
+
+ $instance = new \OC\Files\Storage\Wrapper\Quota(array('storage' => $storage, 'quota' => 1024, 'root' => 'files'));
+
+ $this->assertEquals(1024 - 50, $instance->free_space(''));
+ }
}
diff --git a/tests/lib/util.php b/tests/lib/util.php
index bfe68f5f680..ee336aa1118 100644
--- a/tests/lib/util.php
+++ b/tests/lib/util.php
@@ -170,4 +170,52 @@ class Test_Util extends PHPUnit_Framework_TestCase {
array('442aa682de2a64db1e010f50e60fd9c9', 'local::C:\Users\ADMINI~1\AppData\Local\Temp\2/442aa682de2a64db1e010f50e60fd9c9/')
);
}
+
+ /**
+ * @dataProvider filenameValidationProvider
+ */
+ public function testFilenameValidation($file, $valid) {
+ // private API
+ $this->assertEquals($valid, \OC_Util::isValidFileName($file));
+ // public API
+ $this->assertEquals($valid, \OCP\Util::isValidFileName($file));
+ }
+
+ public function filenameValidationProvider() {
+ return array(
+ // valid names
+ array('boringname', true),
+ array('something.with.extension', true),
+ array('now with spaces', true),
+ array('.a', true),
+ array('..a', true),
+ array('.dotfile', true),
+ array('single\'quote', true),
+ array(' spaces before', true),
+ array('spaces after ', true),
+ array('allowed chars including the crazy ones $%&_-^@!,()[]{}=;#', true),
+ array('汉字也能用', true),
+ array('und Ümläüte sind auch willkommen', true),
+ // disallowed names
+ array('', false),
+ array(' ', false),
+ array('.', false),
+ array('..', false),
+ array('back\\slash', false),
+ array('sl/ash', false),
+ array('lt<lt', false),
+ array('gt>gt', false),
+ array('col:on', false),
+ array('double"quote', false),
+ array('pi|pe', false),
+ array('dont?ask?questions?', false),
+ array('super*star', false),
+ array('new\nline', false),
+ // better disallow these to avoid unexpected trimming to have side effects
+ array(' ..', false),
+ array('.. ', false),
+ array('. ', false),
+ array(' .', false),
+ );
+ }
}