Merge branch 'master' into mobile-header

This commit is contained in:
Robin Appelman 2014-02-21 12:46:09 +01:00
commit 80481a1e41
47 changed files with 779 additions and 267 deletions

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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\')
');

View File

@ -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));
}
}

View File

@ -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));

View File

@ -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' => '',
);

View File

@ -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));

View File

@ -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'])) {

View File

@ -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 */

View File

@ -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;

View File

@ -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;
}

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 880 B

After

Width:  |  Height:  |  Size: 880 B

View File

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@ -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')),

View File

@ -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>

View File

@ -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">

View File

@ -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

View File

@ -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();

View File

@ -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;

View File

@ -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('');

View File

@ -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'));
}

View File

@ -15,12 +15,18 @@ 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 {

View File

@ -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',
);

View File

@ -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;

View File

@ -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)) {

View File

@ -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',
);

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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";

View File

@ -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);
}
}

View File

@ -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.'/';

View File

@ -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;");
}

View File

@ -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));

View File

@ -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');

View File

@ -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

View File

@ -35,6 +35,31 @@ class Test_OC_Connector_Sabre_File extends PHPUnit_Framework_TestCase {
$etag = $file->put('test data');
}
/**
* @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
*/

View File

@ -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)),
);
}

View File

@ -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(''));
}
}

View File

@ -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),
);
}
}