Merge pull request #25 from nextcloud/downstream-160608

Downstream 2016-06-08
This commit is contained in:
Morris Jobke 2016-06-09 15:01:57 +02:00
commit fc3ad7d5f7
57 changed files with 748 additions and 176 deletions

View File

@ -196,6 +196,8 @@ class Directory extends \OCA\DAV\Connector\Sabre\Node
throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage());
} catch (\OCP\Files\InvalidPathException $ex) {
throw new InvalidPath($ex->getMessage());
} catch (ForbiddenException $e) {
throw new \Sabre\DAV\Exception\Forbidden();
}
}

View File

@ -168,20 +168,19 @@ class FilesPlugin extends ServerPlugin {
*/
function checkMove($source, $destination) {
$sourceNode = $this->tree->getNodeForPath($source);
if ($sourceNode instanceof FutureFile) {
if (!$sourceNode instanceof Node) {
return;
}
list($sourceDir,) = \Sabre\HTTP\URLUtil::splitPath($source);
list($destinationDir,) = \Sabre\HTTP\URLUtil::splitPath($destination);
if ($sourceDir !== $destinationDir) {
$sourceFileInfo = $this->fileView->getFileInfo($source);
if ($sourceFileInfo === false) {
$sourceNodeFileInfo = $sourceNode->getFileInfo();
if (is_null($sourceNodeFileInfo)) {
throw new NotFound($source . ' does not exist');
}
if (!$sourceFileInfo->isDeletable()) {
if (!$sourceNodeFileInfo->isDeletable()) {
throw new Forbidden($source . " cannot be deleted");
}
}

View File

@ -347,4 +347,8 @@ abstract class Node implements \Sabre\DAV\INode {
public function changeLock($type) {
$this->fileView->changeLock($this->path, $type);
}
public function getFileInfo() {
return $this->info;
}
}

View File

@ -161,6 +161,8 @@ class ObjectTree extends \Sabre\DAV\Tree {
throw new \Sabre\DAV\Exception\NotFound('Storage ' . $path . ' is invalid');
} catch (LockedException $e) {
throw new \Sabre\DAV\Exception\Locked();
} catch (ForbiddenException $e) {
throw new \Sabre\DAV\Exception\Forbidden();
}
}

View File

@ -24,6 +24,7 @@
*/
namespace OCA\DAV\Tests\unit\Connector\Sabre;
use OCA\DAV\Connector\Sabre\FilesPlugin;
use OCP\Files\StorageNotAvailableException;
use Sabre\DAV\PropFind;
use Sabre\DAV\PropPatch;
@ -36,16 +37,16 @@ use Test\TestCase;
* See the COPYING-README file.
*/
class FilesPluginTest extends TestCase {
const GETETAG_PROPERTYNAME = \OCA\DAV\Connector\Sabre\FilesPlugin::GETETAG_PROPERTYNAME;
const FILEID_PROPERTYNAME = \OCA\DAV\Connector\Sabre\FilesPlugin::FILEID_PROPERTYNAME;
const INTERNAL_FILEID_PROPERTYNAME = \OCA\DAV\Connector\Sabre\FilesPlugin::INTERNAL_FILEID_PROPERTYNAME;
const SIZE_PROPERTYNAME = \OCA\DAV\Connector\Sabre\FilesPlugin::SIZE_PROPERTYNAME;
const PERMISSIONS_PROPERTYNAME = \OCA\DAV\Connector\Sabre\FilesPlugin::PERMISSIONS_PROPERTYNAME;
const LASTMODIFIED_PROPERTYNAME = \OCA\DAV\Connector\Sabre\FilesPlugin::LASTMODIFIED_PROPERTYNAME;
const DOWNLOADURL_PROPERTYNAME = \OCA\DAV\Connector\Sabre\FilesPlugin::DOWNLOADURL_PROPERTYNAME;
const OWNER_ID_PROPERTYNAME = \OCA\DAV\Connector\Sabre\FilesPlugin::OWNER_ID_PROPERTYNAME;
const OWNER_DISPLAY_NAME_PROPERTYNAME = \OCA\DAV\Connector\Sabre\FilesPlugin::OWNER_DISPLAY_NAME_PROPERTYNAME;
const DATA_FINGERPRINT_PROPERTYNAME = \OCA\DAV\Connector\Sabre\FilesPlugin::DATA_FINGERPRINT_PROPERTYNAME;
const GETETAG_PROPERTYNAME = FilesPlugin::GETETAG_PROPERTYNAME;
const FILEID_PROPERTYNAME = FilesPlugin::FILEID_PROPERTYNAME;
const INTERNAL_FILEID_PROPERTYNAME = FilesPlugin::INTERNAL_FILEID_PROPERTYNAME;
const SIZE_PROPERTYNAME = FilesPlugin::SIZE_PROPERTYNAME;
const PERMISSIONS_PROPERTYNAME = FilesPlugin::PERMISSIONS_PROPERTYNAME;
const LASTMODIFIED_PROPERTYNAME = FilesPlugin::LASTMODIFIED_PROPERTYNAME;
const DOWNLOADURL_PROPERTYNAME = FilesPlugin::DOWNLOADURL_PROPERTYNAME;
const OWNER_ID_PROPERTYNAME = FilesPlugin::OWNER_ID_PROPERTYNAME;
const OWNER_DISPLAY_NAME_PROPERTYNAME = FilesPlugin::OWNER_DISPLAY_NAME_PROPERTYNAME;
const DATA_FINGERPRINT_PROPERTYNAME = FilesPlugin::DATA_FINGERPRINT_PROPERTYNAME;
/**
* @var \Sabre\DAV\Server | \PHPUnit_Framework_MockObject_MockObject
@ -58,7 +59,7 @@ class FilesPluginTest extends TestCase {
private $tree;
/**
* @var \OCA\DAV\Connector\Sabre\FilesPlugin
* @var FilesPlugin
*/
private $plugin;
@ -84,11 +85,11 @@ class FilesPluginTest extends TestCase {
->disableOriginalConstructor()
->getMock();
$this->config = $this->getMock('\OCP\IConfig');
$this->config->method('getSystemValue')
$this->config->expects($this->any())->method('getSystemValue')
->with($this->equalTo('data-fingerprint'), $this->equalTo(''))
->willReturn('my_fingerprint');
$this->plugin = new \OCA\DAV\Connector\Sabre\FilesPlugin(
$this->plugin = new FilesPlugin(
$this->tree,
$this->view,
$this->config
@ -263,7 +264,7 @@ class FilesPluginTest extends TestCase {
}
public function testGetPublicPermissions() {
$this->plugin = new \OCA\DAV\Connector\Sabre\FilesPlugin(
$this->plugin = new FilesPlugin(
$this->tree,
$this->view,
$this->config,
@ -331,7 +332,7 @@ class FilesPluginTest extends TestCase {
$node = $this->getMockBuilder('\OCA\DAV\Connector\Sabre\Directory')
->disableOriginalConstructor()
->getMock();
$node->method('getPath')->willReturn('/');
$node->expects($this->any())->method('getPath')->willReturn('/');
$propFind = new PropFind(
'/',
@ -432,11 +433,16 @@ class FilesPluginTest extends TestCase {
->method('isDeletable')
->willReturn(false);
$this->view->expects($this->once())
$node = $this->getMockBuilder('\OCA\DAV\Connector\Sabre\Node')
->disableOriginalConstructor()
->getMock();
$node->expects($this->once())
->method('getFileInfo')
->with('FolderA/test.txt')
->willReturn($fileInfoFolderATestTXT);
$this->tree->expects($this->once())->method('getNodeForPath')
->willReturn($node);
$this->plugin->checkMove('FolderA/test.txt', 'test.txt');
}
@ -448,11 +454,16 @@ class FilesPluginTest extends TestCase {
->method('isDeletable')
->willReturn(true);
$this->view->expects($this->once())
$node = $this->getMockBuilder('\OCA\DAV\Connector\Sabre\Node')
->disableOriginalConstructor()
->getMock();
$node->expects($this->once())
->method('getFileInfo')
->with('FolderA/test.txt')
->willReturn($fileInfoFolderATestTXT);
$this->tree->expects($this->once())->method('getNodeForPath')
->willReturn($node);
$this->plugin->checkMove('FolderA/test.txt', 'test.txt');
}
@ -461,10 +472,15 @@ class FilesPluginTest extends TestCase {
* @expectedExceptionMessage FolderA/test.txt does not exist
*/
public function testMoveSrcNotExist() {
$this->view->expects($this->once())
$node = $this->getMockBuilder('\OCA\DAV\Connector\Sabre\Node')
->disableOriginalConstructor()
->getMock();
$node->expects($this->once())
->method('getFileInfo')
->with('FolderA/test.txt')
->willReturn(false);
->willReturn(null);
$this->tree->expects($this->once())->method('getNodeForPath')
->willReturn($node);
$this->plugin->checkMove('FolderA/test.txt', 'test.txt');
}

View File

@ -0,0 +1,59 @@
<?php
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
* @author Robin Appelman <icewind@owncloud.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
* @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OCA\DAV\Tests\unit\Connector\Sabre\RequestTest;
use OC\Connector\Sabre\Exception\FileLocked;
use OCP\AppFramework\Http;
use OCP\Lock\ILockingProvider;
/**
* Class DeleteTest
*
* @group DB
*
* @package OCA\DAV\Tests\unit\Connector\Sabre\RequestTest
*/
class DeleteTest extends RequestTest {
public function testBasicUpload() {
$user = $this->getUniqueID();
$view = $this->setupUser($user, 'pass');
$view->file_put_contents('foo.txt', 'asd');
$mount = $view->getMount('foo.txt');
$internalPath = $view->getAbsolutePath();
// create a ghost file
$mount->getStorage()->unlink($mount->getInternalPath($internalPath));
// cache entry still exists
$this->assertInstanceOf('\OCP\Files\FileInfo', $view->getFileInfo('foo.txt'));
$response = $this->request($view, $user, 'pass', 'DELETE', '/foo.txt');
$this->assertEquals(Http::STATUS_NO_CONTENT, $response->getStatus());
// no longer in the cache
$this->assertFalse($view->getFileInfo('foo.txt'));
}
}

View File

@ -0,0 +1,6 @@
OC.L10N.register(
"federatedfilesharing",
{
"Invalid Federated Cloud ID" : "معرّف السحابة المتحدة غير صالح"
},
"nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;");

View File

@ -0,0 +1,4 @@
{ "translations": {
"Invalid Federated Cloud ID" : "معرّف السحابة المتحدة غير صالح"
},"pluralForm" :"nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;"
}

View File

@ -53,6 +53,9 @@
this.$showHiddenFiles = $('input#showhiddenfilesToggle');
var showHidden = $('#showHiddenFiles').val() === "1";
this.$showHiddenFiles.prop('checked', showHidden);
if ($('#fileNotFound').val() === "1") {
OC.Notification.showTemporary(t('files', 'File could not be found'));
}
this._filesConfig = new OC.Backbone.Model({
showhidden: showHidden

View File

@ -32,6 +32,8 @@ OC.L10N.register(
"Could not get result from server." : "Kunne ikke hente resultat fra server.",
"Uploading..." : "Uploader...",
"..." : "...",
"Any moment now..." : "Når som helst...",
"Soon..." : "Snart...",
"File upload is in progress. Leaving the page now will cancel the upload." : "Fil upload kører. Hvis du forlader siden nu, vil uploadet blive annuleret.",
"Actions" : "Handlinger",
"Download" : "Download",
@ -47,6 +49,8 @@ OC.L10N.register(
"This directory is unavailable, please check the logs or contact the administrator" : "Denne mappe er utilgængelig, tjek venligst loggene eller kontakt administratoren",
"Could not move \"{file}\", target exists" : "Kunne ikke flytte \"{file}\" - der findes allerede en fil med dette navn",
"Could not move \"{file}\"" : "Kunne ikke flytte \"{file}\"",
"{newName} already exists" : "{newName} eksistere allerede",
"Error deleting file \"{fileName}\"." : "Fejl under sletning af filen \"{fileName}\"",
"No entries in this folder match '{filter}'" : "Der er ingen poster i denne mappe, der matcher '{filter}'",
"Name" : "Navn",
"Size" : "Størrelse",
@ -68,6 +72,7 @@ OC.L10N.register(
"_%n byte_::_%n bytes_" : ["%n byte","%n bytes"],
"Favorited" : "Gjort til foretrukken",
"Favorite" : "Foretrukken",
"Local link" : "Lokalt link",
"Folder" : "Mappe",
"New folder" : "Ny Mappe",
"{newname} already exists" : "{newname} eksistere allerede",
@ -97,6 +102,7 @@ OC.L10N.register(
"Save" : "Gem",
"Missing permissions to edit from here." : "Rettighed mangler til at redigere på dette sted",
"Settings" : "Indstillinger",
"Show hidden files" : "Vis skjulte filer",
"WebDAV" : "WebDAV",
"No files in here" : "Her er ingen filer",
"Upload some content or sync with your devices!" : "Overfør indhold eller synkronisér med dine enheder!",

View File

@ -30,6 +30,8 @@
"Could not get result from server." : "Kunne ikke hente resultat fra server.",
"Uploading..." : "Uploader...",
"..." : "...",
"Any moment now..." : "Når som helst...",
"Soon..." : "Snart...",
"File upload is in progress. Leaving the page now will cancel the upload." : "Fil upload kører. Hvis du forlader siden nu, vil uploadet blive annuleret.",
"Actions" : "Handlinger",
"Download" : "Download",
@ -45,6 +47,8 @@
"This directory is unavailable, please check the logs or contact the administrator" : "Denne mappe er utilgængelig, tjek venligst loggene eller kontakt administratoren",
"Could not move \"{file}\", target exists" : "Kunne ikke flytte \"{file}\" - der findes allerede en fil med dette navn",
"Could not move \"{file}\"" : "Kunne ikke flytte \"{file}\"",
"{newName} already exists" : "{newName} eksistere allerede",
"Error deleting file \"{fileName}\"." : "Fejl under sletning af filen \"{fileName}\"",
"No entries in this folder match '{filter}'" : "Der er ingen poster i denne mappe, der matcher '{filter}'",
"Name" : "Navn",
"Size" : "Størrelse",
@ -66,6 +70,7 @@
"_%n byte_::_%n bytes_" : ["%n byte","%n bytes"],
"Favorited" : "Gjort til foretrukken",
"Favorite" : "Foretrukken",
"Local link" : "Lokalt link",
"Folder" : "Mappe",
"New folder" : "Ny Mappe",
"{newname} already exists" : "{newname} eksistere allerede",
@ -95,6 +100,7 @@
"Save" : "Gem",
"Missing permissions to edit from here." : "Rettighed mangler til at redigere på dette sted",
"Settings" : "Indstillinger",
"Show hidden files" : "Vis skjulte filer",
"WebDAV" : "WebDAV",
"No files in here" : "Her er ingen filer",
"Upload some content or sync with your devices!" : "Overfør indhold eller synkronisér med dine enheder!",

View File

@ -27,9 +27,9 @@ namespace OCA\Files\Controller;
use OC\AppFramework\Http\Request;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\ContentSecurityPolicy;
use OCP\AppFramework\Http\Response;
use OCP\AppFramework\Http\RedirectResponse;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\Files\NotFoundException;
use OCP\IConfig;
use OCP\IL10N;
use OCP\INavigationManager;
@ -37,7 +37,6 @@ use OCP\IRequest;
use OCP\IURLGenerator;
use OCP\IUserSession;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use OCP\AppFramework\Http\NotFoundResponse;
use OCP\Files\Folder;
use OCP\App\IAppManager;
@ -142,11 +141,15 @@ class ViewController extends Controller {
* @param string $view
* @param string $fileid
* @return TemplateResponse
* @throws \OCP\Files\NotFoundException
*/
public function index($dir = '', $view = '', $fileid = null) {
$fileNotFound = false;
if ($fileid !== null) {
return $this->showFile($fileid);
try {
return $this->showFile($fileid);
} catch (NotFoundException $e) {
$fileNotFound = true;
}
}
$nav = new \OCP\Template('files', 'appnavigation', '');
@ -245,6 +248,7 @@ class ViewController extends Controller {
$params['defaultFileSortingDirection'] = $this->config->getUserValue($user, 'files', 'file_sorting_direction', 'asc');
$showHidden = (bool) $this->config->getUserValue($this->userSession->getUser()->getUID(), 'files', 'show_hidden', false);
$params['showHiddenFiles'] = $showHidden ? 1 : 0;
$params['fileNotFound'] = $fileNotFound ? 1 : 0;
$params['appNavigation'] = $nav;
$params['appContents'] = $contentItems;
$this->navigationManager->setActiveEntry('files_index');
@ -265,40 +269,37 @@ class ViewController extends Controller {
* Redirects to the file list and highlight the given file id
*
* @param string $fileId file id to show
* @return Response redirect response or not found response
* @return RedirectResponse redirect response or not found response
* @throws \OCP\Files\NotFoundException
*
* @NoCSRFRequired
* @NoAdminRequired
*/
public function showFile($fileId) {
try {
$uid = $this->userSession->getUser()->getUID();
$baseFolder = $this->rootFolder->get($uid . '/files/');
$uid = $this->userSession->getUser()->getUID();
$baseFolder = $this->rootFolder->get($uid . '/files/');
$files = $baseFolder->getById($fileId);
$params = [];
if (empty($files) && $this->appManager->isEnabledForUser('files_trashbin')) {
$baseFolder = $this->rootFolder->get($uid . '/files_trashbin/files/');
$files = $baseFolder->getById($fileId);
$params = [];
if (empty($files) && $this->appManager->isEnabledForUser('files_trashbin')) {
$baseFolder = $this->rootFolder->get($uid . '/files_trashbin/files/');
$files = $baseFolder->getById($fileId);
$params['view'] = 'trashbin';
}
if (!empty($files)) {
$file = current($files);
if ($file instanceof Folder) {
// set the full path to enter the folder
$params['dir'] = $baseFolder->getRelativePath($file->getPath());
} else {
// set parent path as dir
$params['dir'] = $baseFolder->getRelativePath($file->getParent()->getPath());
// and scroll to the entry
$params['scrollto'] = $file->getName();
}
return new RedirectResponse($this->urlGenerator->linkToRoute('files.view.index', $params));
}
} catch (\OCP\Files\NotFoundException $e) {
return new NotFoundResponse();
$params['view'] = 'trashbin';
}
return new NotFoundResponse();
if (!empty($files)) {
$file = current($files);
if ($file instanceof Folder) {
// set the full path to enter the folder
$params['dir'] = $baseFolder->getRelativePath($file->getPath());
} else {
// set parent path as dir
$params['dir'] = $baseFolder->getRelativePath($file->getParent()->getPath());
// and scroll to the entry
$params['scrollto'] = $file->getName();
}
return new RedirectResponse($this->urlGenerator->linkToRoute('files.view.index', $params));
}
throw new \OCP\Files\NotFoundException();
}
}

View File

@ -14,6 +14,7 @@
<input type="hidden" name="usedSpacePercent" id="usedSpacePercent" value="<?php p($_['usedSpacePercent']); ?>" />
<input type="hidden" name="owner" id="owner" value="<?php p($_['owner']); ?>" />
<input type="hidden" name="ownerDisplayName" id="ownerDisplayName" value="<?php p($_['ownerDisplayName']); ?>" />
<input type="hidden" name="fileNotFound" id="fileNotFound" value="<?php p($_['fileNotFound']); ?>"" />
<?php if (!$_['isPublic']) :?>
<input type="hidden" name="mailNotificationEnabled" id="mailNotificationEnabled" value="<?php p($_['mailNotificationEnabled']) ?>" />
<input type="hidden" name="mailPublicNotificationEnabled" id="mailPublicNotificationEnabled" value="<?php p($_['mailPublicNotificationEnabled']) ?>" />

View File

@ -26,6 +26,7 @@ namespace OCA\Files\Tests\Controller;
use OCA\Files\Controller\ViewController;
use OCP\AppFramework\Http;
use OCP\Files\NotFoundException;
use OCP\IUser;
use OCP\Template;
use Test\TestCase;
@ -259,7 +260,8 @@ class ViewControllerTest extends TestCase {
'isPublic' => false,
'defaultFileSorting' => 'name',
'defaultFileSortingDirection' => 'asc',
'showHiddenFiles' => false,
'showHiddenFiles' => 0,
'fileNotFound' => 0,
'mailNotificationEnabled' => 'no',
'mailPublicNotificationEnabled' => 'no',
'allowShareWithLink' => 'yes',
@ -410,11 +412,14 @@ class ViewControllerTest extends TestCase {
->with(123)
->will($this->returnValue([]));
$expected = new Http\NotFoundResponse();
if ($useShowFile) {
$this->assertEquals($expected, $this->viewController->showFile(123));
$this->setExpectedException('OCP\Files\NotFoundException');
$this->viewController->showFile(123);
} else {
$this->assertEquals($expected, $this->viewController->index('/whatever', '', '123'));
$response = $this->viewController->index('MyDir', 'MyView', '123');
$this->assertInstanceOf('OCP\AppFramework\Http\TemplateResponse', $response);
$params = $response->getParams();
$this->assertEquals(1, $params['fileNotFound']);
}
}

View File

@ -7,13 +7,13 @@ OC.L10N.register(
"Step 1 failed. Exception: %s" : "Passo 1 falhou. Exceção: %s",
"Step 2 failed. Exception: %s" : "Passo 2 falhou. Exceção: %s",
"External storage" : "Armazenamento Externo",
"Dropbox App Configuration" : "Configuração da app Dropbox",
"Google Drive App Configuration" : "Configuração da app Google Drive",
"Dropbox App Configuration" : "Configuração da aplicação Dropbox",
"Google Drive App Configuration" : "Configuração da aplicação Google Drive",
"Personal" : "Pessoal",
"System" : "Sistema",
"Grant access" : "Conceder acesso",
"Error configuring OAuth1" : "Erro de configuração OAuth1",
"Error configuring OAuth2" : "Erro de configuração OAuth2",
"Error configuring OAuth1" : "Erro ao configurar OAuth1",
"Error configuring OAuth2" : "Erro ao configurar OAuth2",
"Generate keys" : "Gerar chaves",
"Error generating key pair" : "Erro ao gerar chave par",
"All users. Type to select user or group." : "Todos os utilizadores. Digite para selecionar o utilizador ou grupo.",
@ -27,14 +27,14 @@ OC.L10N.register(
"Couldn't get the list of external mount points: {type}" : "Não foi possível conseguir a lista de pontos de montagem externos: {type}",
"There was an error with message: " : "Houve um erro com a mensagem:",
"External mount error" : "Erro de montagem externa",
"external-storage" : "Armazenamento Externo",
"external-storage" : "armazenamento externo",
"Couldn't get the list of Windows network drive mount points: empty response from the server" : "Não foi possível conseguir a lista de pontos de montagem Windows na rede: resposta vazia do servidor",
"Some of the configured external mount points are not connected. Please click on the red row(s) for more information" : "Alguns dos pontos de montagem externos configurados não estão conectados. Por favor, clique na fila vermelha para mais informação",
"Please enter the credentials for the {mount} mount" : "Por favor, introduza as credenciais para {mount}",
"Username" : "Nome de utilizador",
"Password" : "Palavra-passe",
"Credentials saved" : "Credenciais guardadas",
"Credentials saving failed" : "Falha ao salvar credenciais",
"Credentials saving failed" : "Falha ao guardar as credenciais",
"Credentials required" : "Credenciais necessárias",
"Save" : "Guardar",
"Storage with id \"%i\" not found" : "Não foi encontrado o armazenamento com a id. \"%i\"",
@ -49,7 +49,7 @@ OC.L10N.register(
"Insufficient data: %s" : "Dados insuficientes: %s",
"%s" : "%s",
"Storage with id \"%i\" is not user editable" : "Armazenamento com id \"%i\" não é editável pelo utilizador",
"Access key" : "Código de acesso",
"Access key" : "Chave de acesso",
"Secret key" : "Código secreto",
"Builtin" : "Integrado",
"None" : "Nenhum",

View File

@ -5,13 +5,13 @@
"Step 1 failed. Exception: %s" : "Passo 1 falhou. Exceção: %s",
"Step 2 failed. Exception: %s" : "Passo 2 falhou. Exceção: %s",
"External storage" : "Armazenamento Externo",
"Dropbox App Configuration" : "Configuração da app Dropbox",
"Google Drive App Configuration" : "Configuração da app Google Drive",
"Dropbox App Configuration" : "Configuração da aplicação Dropbox",
"Google Drive App Configuration" : "Configuração da aplicação Google Drive",
"Personal" : "Pessoal",
"System" : "Sistema",
"Grant access" : "Conceder acesso",
"Error configuring OAuth1" : "Erro de configuração OAuth1",
"Error configuring OAuth2" : "Erro de configuração OAuth2",
"Error configuring OAuth1" : "Erro ao configurar OAuth1",
"Error configuring OAuth2" : "Erro ao configurar OAuth2",
"Generate keys" : "Gerar chaves",
"Error generating key pair" : "Erro ao gerar chave par",
"All users. Type to select user or group." : "Todos os utilizadores. Digite para selecionar o utilizador ou grupo.",
@ -25,14 +25,14 @@
"Couldn't get the list of external mount points: {type}" : "Não foi possível conseguir a lista de pontos de montagem externos: {type}",
"There was an error with message: " : "Houve um erro com a mensagem:",
"External mount error" : "Erro de montagem externa",
"external-storage" : "Armazenamento Externo",
"external-storage" : "armazenamento externo",
"Couldn't get the list of Windows network drive mount points: empty response from the server" : "Não foi possível conseguir a lista de pontos de montagem Windows na rede: resposta vazia do servidor",
"Some of the configured external mount points are not connected. Please click on the red row(s) for more information" : "Alguns dos pontos de montagem externos configurados não estão conectados. Por favor, clique na fila vermelha para mais informação",
"Please enter the credentials for the {mount} mount" : "Por favor, introduza as credenciais para {mount}",
"Username" : "Nome de utilizador",
"Password" : "Palavra-passe",
"Credentials saved" : "Credenciais guardadas",
"Credentials saving failed" : "Falha ao salvar credenciais",
"Credentials saving failed" : "Falha ao guardar as credenciais",
"Credentials required" : "Credenciais necessárias",
"Save" : "Guardar",
"Storage with id \"%i\" not found" : "Não foi encontrado o armazenamento com a id. \"%i\"",
@ -47,7 +47,7 @@
"Insufficient data: %s" : "Dados insuficientes: %s",
"%s" : "%s",
"Storage with id \"%i\" is not user editable" : "Armazenamento com id \"%i\" não é editável pelo utilizador",
"Access key" : "Código de acesso",
"Access key" : "Chave de acesso",
"Secret key" : "Código secreto",
"Builtin" : "Integrado",
"None" : "Nenhum",

View File

@ -97,6 +97,9 @@ class Google extends \OC\Files\Storage\Common {
private function getDriveFile($path) {
// Remove leading and trailing slashes
$path = trim($path, '/');
if ($path === '.') {
$path = '';
}
if (isset($this->driveFiles[$path])) {
return $this->driveFiles[$path];
} else if ($path === '') {
@ -138,7 +141,7 @@ class Google extends \OC\Files\Storage\Common {
if ($pos !== false) {
$pathWithoutExt = substr($path, 0, $pos);
$file = $this->getDriveFile($pathWithoutExt);
if ($file) {
if ($file && $this->isGoogleDocFile($file)) {
// Switch cached Google_Service_Drive_DriveFile to the correct index
unset($this->driveFiles[$pathWithoutExt]);
$this->driveFiles[$path] = $file;
@ -208,6 +211,17 @@ class Google extends \OC\Files\Storage\Common {
}
}
/**
* Returns whether the given drive file is a Google Doc file
*
* @param \Google_Service_Drive_DriveFile
*
* @return true if the file is a Google Doc file, false otherwise
*/
private function isGoogleDocFile($file) {
return $this->getGoogleDocExtension($file->getMimeType()) !== '';
}
public function mkdir($path) {
if (!$this->is_dir($path)) {
$parentFolder = $this->getDriveFile(dirname($path));

View File

@ -60,4 +60,13 @@ class GoogleTest extends \Test\Files\Storage\Storage {
parent::tearDown();
}
public function testSameNameAsFolderWithExtension() {
$this->assertTrue($this->instance->mkdir('testsamename'));
$this->assertEquals(13, $this->instance->file_put_contents('testsamename.txt', 'some contents'));
$this->assertEquals('some contents', $this->instance->file_get_contents('testsamename.txt'));
$this->assertTrue($this->instance->is_dir('testsamename'));
$this->assertTrue($this->instance->unlink('testsamename.txt'));
$this->assertTrue($this->instance->rmdir('testsamename'));
}
}

View File

@ -81,7 +81,7 @@ class Cache extends CacheJail {
}
protected function formatCacheEntry($entry) {
$path = $entry['path'];
$path = isset($entry['path']) ? $entry['path'] : '';
$entry = parent::formatCacheEntry($entry);
$sharePermissions = $this->storage->getPermissions($path);
if (isset($entry['permissions'])) {

View File

@ -415,4 +415,22 @@ class Shared extends \OC\Files\Storage\Wrapper\Jail implements ISharedStorage {
return $this->sourceStorage;
}
public function file_get_contents($path) {
$info = [
'target' => $this->getMountPoint() . '/' . $path,
'source' => $this->getSourcePath($path),
];
\OCP\Util::emitHook('\OC\Files\Storage\Shared', 'file_get_contents', $info);
return parent::file_get_contents($path);
}
public function file_put_contents($path, $data) {
$info = [
'target' => $this->getMountPoint() . '/' . $path,
'source' => $this->getSourcePath($path),
];
\OCP\Util::emitHook('\OC\Files\Storage\Shared', 'file_put_contents', $info);
return parent::file_put_contents($path, $data);
}
}

View File

@ -7,20 +7,20 @@ OC.L10N.register(
"Please select tags to filter by" : "Veuillez sélectionner les étiquettes par lesquelles filtrer",
"No files found for the selected tags" : "Aucun fichier pour les étiquettes sélectionnées",
"<strong>System tags</strong> for a file have been modified" : "<strong>Les étiquettes systèmes</strong> pour un fichier ont été modifiées",
"You assigned system tag %3$s" : "Vous avez attribué l'étiquette système %3$s",
"You assigned system tag %3$s" : "Vous avez attribué l'étiquette collaborative %3$s",
"%1$s assigned system tag %3$s" : "%1$s a attribué l'étiquette système %3$s",
"You unassigned system tag %3$s" : "Vous avez retiré l'étiquette système %3$s",
"You unassigned system tag %3$s" : "Vous avez retiré l'étiquette collaborative %3$s",
"%1$s unassigned system tag %3$s" : "%1$s a retiré l'étiquette système %3$s",
"You created system tag %2$s" : "Vous avez créé l'étiquette système %2$s",
"You created system tag %2$s" : "Vous avez créé l'étiquette collaborative %2$s",
"%1$s created system tag %2$s" : "%1$s a créé l'étiquette système %2$s",
"You deleted system tag %2$s" : "Vous avez supprimé l'étiquette système %2$s",
"%1$s deleted system tag %2$s" : "%1$s a supprimé l'étiquette système %2$s",
"You updated system tag %3$s to %2$s" : "Vous avez renommé l'étiquette système %3$s en %2$s",
"%1$s updated system tag %3$s to %2$s" : "%1$s a renommé l'étiquette système %3$s en %2$s",
"You assigned system tag %3$s to %2$s" : "Vous avez attribué l'étiquette système %3$s à %2$s",
"%1$s assigned system tag %3$s to %2$s" : "%1$s a attribué l'étiquette système %3$s à %2$s",
"You unassigned system tag %3$s from %2$s" : "Vous avez retiré l'étiquette système %3$s de %2$s",
"%1$s unassigned system tag %3$s from %2$s" : "%1$s a retiré l'étiquette système %3$s à %2$s",
"You deleted system tag %2$s" : "Vous avez supprimé l'étiquette collaborative %2$s",
"%1$s deleted system tag %2$s" : "%1$s a supprimé l'étiquette collaborative %2$s",
"You updated system tag %3$s to %2$s" : "Vous avez renommé l'étiquette collaborative %3$s en %2$s",
"%1$s updated system tag %3$s to %2$s" : "%1$s a renommé l'étiquette collaborative %3$s en %2$s",
"You assigned system tag %3$s to %2$s" : "Vous avez attribué l'étiquette collaborative %3$s à %2$s",
"%1$s assigned system tag %3$s to %2$s" : "%1$s a attribué l'étiquette collaborative %3$s à %2$s",
"You unassigned system tag %3$s from %2$s" : "Vous avez retiré l'étiquette collaborative %3$s à %2$s",
"%1$s unassigned system tag %3$s from %2$s" : "%1$s a retiré l'étiquette collaborative %3$s à %2$s",
"%s (restricted)" : "%s (restreint)",
"%s (invisible)" : "%s (invisible)",
"No files in here" : "Aucun fichier",

View File

@ -5,20 +5,20 @@
"Please select tags to filter by" : "Veuillez sélectionner les étiquettes par lesquelles filtrer",
"No files found for the selected tags" : "Aucun fichier pour les étiquettes sélectionnées",
"<strong>System tags</strong> for a file have been modified" : "<strong>Les étiquettes systèmes</strong> pour un fichier ont été modifiées",
"You assigned system tag %3$s" : "Vous avez attribué l'étiquette système %3$s",
"You assigned system tag %3$s" : "Vous avez attribué l'étiquette collaborative %3$s",
"%1$s assigned system tag %3$s" : "%1$s a attribué l'étiquette système %3$s",
"You unassigned system tag %3$s" : "Vous avez retiré l'étiquette système %3$s",
"You unassigned system tag %3$s" : "Vous avez retiré l'étiquette collaborative %3$s",
"%1$s unassigned system tag %3$s" : "%1$s a retiré l'étiquette système %3$s",
"You created system tag %2$s" : "Vous avez créé l'étiquette système %2$s",
"You created system tag %2$s" : "Vous avez créé l'étiquette collaborative %2$s",
"%1$s created system tag %2$s" : "%1$s a créé l'étiquette système %2$s",
"You deleted system tag %2$s" : "Vous avez supprimé l'étiquette système %2$s",
"%1$s deleted system tag %2$s" : "%1$s a supprimé l'étiquette système %2$s",
"You updated system tag %3$s to %2$s" : "Vous avez renommé l'étiquette système %3$s en %2$s",
"%1$s updated system tag %3$s to %2$s" : "%1$s a renommé l'étiquette système %3$s en %2$s",
"You assigned system tag %3$s to %2$s" : "Vous avez attribué l'étiquette système %3$s à %2$s",
"%1$s assigned system tag %3$s to %2$s" : "%1$s a attribué l'étiquette système %3$s à %2$s",
"You unassigned system tag %3$s from %2$s" : "Vous avez retiré l'étiquette système %3$s de %2$s",
"%1$s unassigned system tag %3$s from %2$s" : "%1$s a retiré l'étiquette système %3$s à %2$s",
"You deleted system tag %2$s" : "Vous avez supprimé l'étiquette collaborative %2$s",
"%1$s deleted system tag %2$s" : "%1$s a supprimé l'étiquette collaborative %2$s",
"You updated system tag %3$s to %2$s" : "Vous avez renommé l'étiquette collaborative %3$s en %2$s",
"%1$s updated system tag %3$s to %2$s" : "%1$s a renommé l'étiquette collaborative %3$s en %2$s",
"You assigned system tag %3$s to %2$s" : "Vous avez attribué l'étiquette collaborative %3$s à %2$s",
"%1$s assigned system tag %3$s to %2$s" : "%1$s a attribué l'étiquette collaborative %3$s à %2$s",
"You unassigned system tag %3$s from %2$s" : "Vous avez retiré l'étiquette collaborative %3$s à %2$s",
"%1$s unassigned system tag %3$s from %2$s" : "%1$s a retiré l'étiquette collaborative %3$s à %2$s",
"%s (restricted)" : "%s (restreint)",
"%s (invisible)" : "%s (invisible)",
"No files in here" : "Aucun fichier",

View File

@ -260,6 +260,17 @@ trait BasicStructure {
}
}
/**
* @Given User :user modifies text of :filename with text :text
* @param string $user
* @param string $filename
* @param string $text
*/
public function modifyTextOfFile($user, $filename, $text) {
self::removeFile("../../data/$user/files", "$filename");
file_put_contents("../../data/$user/files" . "$filename", "$text");
}
/**
* @BeforeSuite
*/

View File

@ -12,7 +12,7 @@ require __DIR__ . '/../../vendor/autoload.php';
*/
class FederationContext implements Context, SnippetAcceptingContext {
use Sharing;
use WebDav;
/**
* @Given /^User "([^"]*)" from server "(LOCAL|REMOTE)" shares "([^"]*)" with user "([^"]*)" from server "(LOCAL|REMOTE)"$/

View File

@ -120,6 +120,67 @@ Feature: federated
| share_with | user2 |
| share_with_displayname | user2 |
Scenario: Overwrite a federated shared file as recipient
Given Using server "REMOTE"
And user "user1" exists
And user "user2" exists
And Using server "LOCAL"
And user "user0" exists
And User "user0" from server "LOCAL" shares "/textfile0.txt" with user "user1" from server "REMOTE"
And User "user1" from server "REMOTE" accepts last pending share
And Using server "REMOTE"
And As an "user1"
And User "user1" modifies text of "/textfile0.txt" with text "BLABLABLA"
When User "user1" uploads file "../../data/user1/files/textfile0.txt" to "/textfile0 (2).txt"
And Downloading file "/textfile0 (2).txt" with range "bytes=0-8"
Then Downloaded content should be "BLABLABLA"
Scenario: Overwrite a federated shared folder as recipient
Given Using server "REMOTE"
And user "user1" exists
And user "user2" exists
And Using server "LOCAL"
And user "user0" exists
And User "user0" from server "LOCAL" shares "/PARENT" with user "user1" from server "REMOTE"
And User "user1" from server "REMOTE" accepts last pending share
And Using server "REMOTE"
And As an "user1"
And User "user1" modifies text of "/textfile0.txt" with text "BLABLABLA"
When User "user1" uploads file "../../data/user1/files/textfile0.txt" to "/PARENT (2)/textfile0.txt"
And Downloading file "/PARENT (2)/textfile0.txt" with range "bytes=0-8"
Then Downloaded content should be "BLABLABLA"
Scenario: Overwrite a federated shared file as recipient using old chunking
Given Using server "REMOTE"
And user "user1" exists
And user "user2" exists
And Using server "LOCAL"
And user "user0" exists
And User "user0" from server "LOCAL" shares "/textfile0.txt" with user "user1" from server "REMOTE"
And User "user1" from server "REMOTE" accepts last pending share
And Using server "REMOTE"
And As an "user1"
And user "user1" uploads chunk file "1" of "3" with "AAAAA" to "/textfile0 (2).txt"
And user "user1" uploads chunk file "2" of "3" with "BBBBB" to "/textfile0 (2).txt"
And user "user1" uploads chunk file "3" of "3" with "CCCCC" to "/textfile0 (2).txt"
When Downloading file "/textfile0 (2).txt" with range "bytes=0-4"
Then Downloaded content should be "AAAAA"
Scenario: Overwrite a federated shared folder as recipient using old chunking
Given Using server "REMOTE"
And user "user1" exists
And user "user2" exists
And Using server "LOCAL"
And user "user0" exists
And User "user0" from server "LOCAL" shares "/PARENT" with user "user1" from server "REMOTE"
And User "user1" from server "REMOTE" accepts last pending share
And Using server "REMOTE"
And As an "user1"
And user "user1" uploads chunk file "1" of "3" with "AAAAA" to "/PARENT (2)/textfile0.txt"
And user "user1" uploads chunk file "2" of "3" with "BBBBB" to "/PARENT (2)/textfile0.txt"
And user "user1" uploads chunk file "3" of "3" with "CCCCC" to "/PARENT (2)/textfile0.txt"
When Downloading file "/PARENT (2)/textfile0.txt" with range "bytes=3-13"
Then Downloaded content should be "AABBBBBCCCC"

View File

@ -120,7 +120,8 @@ class Application extends App {
$c->query('AppName'),
$c->query('Request'),
$c->query('UserManager'),
$c->query('OC\Authentication\Token\DefaultTokenProvider'),
$c->query('ServerContainer')->query('OC\Authentication\Token\IProvider'),
$c->query('TwoFactorAuthManager'),
$c->query('SecureRandom')
);
});

View File

@ -111,7 +111,8 @@ class DecryptAll extends Command {
$this->addArgument(
'user',
InputArgument::OPTIONAL,
'user for which you want to decrypt all files (optional)'
'user for which you want to decrypt all files (optional)',
''
);
}
@ -127,8 +128,16 @@ class DecryptAll extends Command {
return;
}
$uid = $input->getArgument('user');
//FIXME WHEN https://github.com/owncloud/core/issues/24994 is fixed
if ($uid === null) {
$message = 'your ownCloud';
} else {
$message = "$uid's account";
}
$output->writeln("\n");
$output->writeln('You are about to start to decrypt all files stored in your ownCloud.');
$output->writeln("You are about to start to decrypt all files stored in $message.");
$output->writeln('It will depend on the encryption module and your setup if this is possible.');
$output->writeln('Depending on the number and size of your files this can take some time');
$output->writeln('Please make sure that no user access his files during this process!');
@ -140,6 +149,7 @@ class DecryptAll extends Command {
$result = $this->decryptAll->decryptAll($input, $output, $user);
if ($result === false) {
$output->writeln(' aborted.');
$output->writeln('Server side encryption remains enabled');
$this->config->setAppValue('core', 'encryption_enabled', 'yes');
}
$this->resetSingleUserAndTrashbin();

View File

@ -1,4 +1,5 @@
<?php
/**
* @author Christoph Wurst <christoph@owncloud.com>
*
@ -23,22 +24,27 @@ namespace OC\Core\Controller;
use OC\AppFramework\Http;
use OC\Authentication\Token\DefaultTokenProvider;
use OC\Authentication\Token\IProvider;
use OC\Authentication\Token\IToken;
use OC\User\Manager;
use OC\Authentication\TwoFactorAuth\Manager as TwoFactorAuthManager;
use OC\User\Manager as UserManager;
use OCA\User_LDAP\User\Manager;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\JSONResponse;
use OCP\AppFramework\Http\Response;
use OCP\IRequest;
use OCP\Security\ISecureRandom;
class TokenController extends Controller {
/** @var Manager */
/** @var UserManager */
private $userManager;
/** @var DefaultTokenProvider */
/** @var IProvider */
private $tokenProvider;
/** @var TwoFactorAuthManager */
private $twoFactorAuthManager;
/** @var ISecureRandom */
private $secureRandom;
@ -49,12 +55,12 @@ class TokenController extends Controller {
* @param DefaultTokenProvider $tokenProvider
* @param ISecureRandom $secureRandom
*/
public function __construct($appName, IRequest $request, Manager $userManager, DefaultTokenProvider $tokenProvider,
ISecureRandom $secureRandom) {
public function __construct($appName, IRequest $request, UserManager $userManager, IProvider $tokenProvider, TwoFactorAuthManager $twoFactorAuthManager, ISecureRandom $secureRandom) {
parent::__construct($appName, $request);
$this->userManager = $userManager;
$this->tokenProvider = $tokenProvider;
$this->secureRandom = $secureRandom;
$this->twoFactorAuthManager = $twoFactorAuthManager;
}
/**
@ -70,18 +76,26 @@ class TokenController extends Controller {
*/
public function generateToken($user, $password, $name = 'unknown client') {
if (is_null($user) || is_null($password)) {
$response = new Response();
$response = new JSONResponse();
$response->setStatus(Http::STATUS_UNPROCESSABLE_ENTITY);
return $response;
}
$loginResult = $this->userManager->checkPassword($user, $password);
if ($loginResult === false) {
$response = new Response();
$loginName = $user;
$user = $this->userManager->checkPassword($loginName, $password);
if ($user === false) {
$response = new JSONResponse();
$response->setStatus(Http::STATUS_UNAUTHORIZED);
return $response;
}
if ($this->twoFactorAuthManager->isTwoFactorAuthenticated($user)) {
$resp = new JSONResponse();
$resp->setStatus(Http::STATUS_UNAUTHORIZED);
return $resp;
}
$token = $this->secureRandom->generate(128);
$this->tokenProvider->generateToken($token, $loginResult->getUID(), $user, $password, $name, IToken::PERMANENT_TOKEN);
$this->tokenProvider->generateToken($token, $user->getUID(), $loginName, $password, $name, IToken::PERMANENT_TOKEN);
return [
'token' => $token,
];

View File

@ -61,6 +61,13 @@ class TwoFactorChallengeController extends Controller {
$this->urlGenerator = $urlGenerator;
}
/**
* @return string
*/
protected function getLogoutAttribute() {
return \OC_User::getLogoutAttribute();
}
/**
* @NoAdminRequired
* @NoCSRFRequired
@ -75,6 +82,7 @@ class TwoFactorChallengeController extends Controller {
$data = [
'providers' => $providers,
'redirect_url' => $redirect_url,
'logout_attribute' => $this->getLogoutAttribute(),
];
return new TemplateResponse($this->appName, 'twofactorselectchallenge', $data, 'guest');
}
@ -106,6 +114,7 @@ class TwoFactorChallengeController extends Controller {
$data = [
'error' => $error,
'provider' => $provider,
'logout_attribute' => $this->getLogoutAttribute(),
'template' => $tmpl->fetchPage(),
];
return new TemplateResponse($this->appName, 'twofactorshowchallenge', $data, 'guest');

View File

@ -82,6 +82,11 @@ class TwoFactorMiddleware extends Middleware {
return;
}
if ($controller instanceof \OC\Core\Controller\LoginController && $methodName === 'logout') {
// Don't block the logout page, to allow canceling the 2FA
return;
}
if ($this->userSession->isLoggedIn()) {
$user = $this->userSession->getUser();

View File

@ -38,6 +38,10 @@ body {
display: inline-block;
}
a.two-factor-cancel {
color: #fff;
}
.float-spinner {
height: 32px;
display: none;

View File

@ -18,4 +18,5 @@
</li>
<?php endforeach; ?>
</ul>
</fieldset>
</fieldset>
<a class="two-factor-cancel" <?php print_unescaped($_['logout_attribute']); ?>><?php p($l->t('Cancel login')) ?></a>

View File

@ -17,3 +17,4 @@ $template = $_['template'];
<span class="warning"><?php p($l->t('An error occured while verifying the token')); ?></span>
<?php endif; ?>
<?php print_unescaped($template); ?>
<a class="two-factor-cancel" <?php print_unescaped($_['logout_attribute']); ?>><?php p($l->t('Cancel login')) ?></a>

View File

@ -1,18 +1,46 @@
OC.L10N.register(
"lib",
{
"Cannot write into \"config\" directory!" : "الكتابة في مجلد \"config\" غير ممكنة!",
"This can usually be fixed by giving the webserver write access to the config directory" : "يمكن حل هذا عادة بإعطاء خادم الوب صلاحية الكتابة في مجلد config",
"See %s" : "أنظر %s",
"Sample configuration detected" : "تم اكتشاف إعدادات عيّنة",
"PHP %s or higher is required." : "إصدار PHP %s أو أحدث منه مطلوب.",
"PHP with a version lower than %s is required." : "PHP الإصدار %s أو أقل مطلوب.",
"%sbit or higher PHP required." : "مكتبات PHP ذات %s بت أو أعلى مطلوبة.",
"Following databases are supported: %s" : "قواعد البيانات التالية مدعومة: %s",
"The command line tool %s could not be found" : "لم يتم العثور على أداة سطر الأوامر %s",
"The library %s is not available." : "مكتبة %s غير متوفرة.",
"Unknown filetype" : "نوع الملف غير معروف",
"Invalid image" : "الصورة غير صالحة",
"today" : "اليوم",
"yesterday" : "يوم أمس",
"_%n day ago_::_%n days ago_" : ["قبل ساعات","قبل يوم","قبل يومين","قبل %n يوماً","قبل %n يوماً","قبل %n يوماً"],
"last month" : "الشهر الماضي",
"_%n month ago_::_%n months ago_" : ["قبل عدة أيام","قبل شهر","قبل شهرين","قبل %n شهراً","قبل %n شهراً","قبل %n شهراً"],
"last year" : "السنةالماضية",
"seconds ago" : "منذ ثواني",
"Empty filename is not allowed" : "لا يسمح بأسماء فارغة للملفات",
"4-byte characters are not supported in file names" : "المحارف ذات 4 بايت غير مسموح بها في أسماء الملفات",
"File name is a reserved word" : "اسم الملف كلمة محجوزة",
"File name contains at least one invalid character" : "اسم الملف به ، على الأقل ، حرف غير صالح",
"File name is too long" : "اسم الملف طويل جداً",
"App directory already exists" : "مجلد التطبيق موجود مسبقا",
"Can't create app folder. Please fix permissions. %s" : "لا يمكن إنشاء مجلد التطبيق. يرجى تعديل الصلاحيات. %s",
"Archive does not contain a directory named %s" : "الأرشيف لا يحتوي مجلداً اسمه %s",
"No source specified when installing app" : "لم يتم تحديد المصدر عن تثبيت البرنامج",
"No href specified when installing app from http" : "لم يتم تحديد href عند تثبيت التطبيق من http",
"No path specified when installing app from local file" : "لم يتم تحديد مسار عند تثبيت التطبيق من ملف محلّي",
"Archives of type %s are not supported" : "الأرشيفات من نوع %s غير مدعومة",
"Failed to open archive when installing app" : "فشل فتح الأرشيف أثناء تثبيت التطبيق",
"App does not provide an info.xml file" : "التطبيق لا يتوفر على ملف info.xml",
"App cannot be installed because appinfo file cannot be read." : "لا يمكن تثبيت التطبيق لأن ملف appinfo غير ممكنة قراءته.",
"Signature could not get checked. Please contact the app developer and check your admin screen." : "لم يتم التحقق من التوقيع. فضلاً اتصل بمطوّر التطبيق و تحقق من شاشة الإدارة في حسابك.",
"App can't be installed because of not allowed code in the App" : "لم يتم تثبيت التطبيق لوجود شفرة غير مسموح بها في التطبيق",
"App can't be installed because it is not compatible with this version of ownCloud" : "لم يتم تثبيت التطبيق لأنه غير متوافق مع هذا الإصدار من ownCloud",
"App can't be installed because it contains the <shipped>true</shipped> tag which is not allowed for non shipped apps" : "لم يتم تثبيت التطبيق لأن به علامة <shipped>true</shipped> التي لايسمح بها في التطبيقات غير المشحونة",
"App can't be installed because the version in info.xml is not the same as the version reported from the app store" : "لم يتم تثبيت التطبيق لأن الإصدار في info.xml مختلف عن الإصدار المذكور في متجر التطبيقات",
"%s enter the database username and name." : "%s أدخِل اسم قاعدة البيانات واسم مستخدمها.",
"%s enter the database username." : "%s ادخل اسم المستخدم الخاص بقاعدة البيانات.",
"%s enter the database name." : "%s ادخل اسم فاعدة البيانات",
"%s you may not use dots in the database name" : "%s لا يسمح لك باستخدام نقطه (.) في اسم قاعدة البيانات",
@ -23,9 +51,20 @@ OC.L10N.register(
"You need to enter either an existing account or the administrator." : "انت بحاجة لكتابة اسم مستخدم موجود أو حساب المدير.",
"Offending command was: \"%s\", name: %s, password: %s" : "الأمر المخالف كان : \"%s\", اسم المستخدم : %s, كلمة المرور: %s",
"PostgreSQL username and/or password not valid" : "اسم المستخدم / أو كلمة المرور الخاصة بـPostgreSQL غير صحيحة",
"Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "نظام ماك الإصدار X غير مدعوم و %s لن يعمل بشكل صحيح على هذه المنصة. استخدمه على مسؤوليتك!",
"For the best results, please consider using a GNU/Linux server instead." : "فضلاً ضع في الاعتبار استخدام نظام GNU/Linux بدل الأنظمة الأخرى للحصول على أفضل النتائج.",
"Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "فضلاً إحذف إعداد open_basedir من ملف php.ini لديك أو حوّل إلى PHP إصدار 64 بت.",
"Set an admin username." : "اعداد اسم مستخدم للمدير",
"Set an admin password." : "اعداد كلمة مرور للمدير",
"Can't create or write into the data directory %s" : "لا يمكن الإنشاء أو الكتابة في مجلد البيانات %s",
"Invalid Federated Cloud ID" : "معرّف سحابة الاتحاد غير صالح",
"%s shared »%s« with you" : "%s شارك »%s« معك",
"%s via %s" : "%s عبر %s",
"Sharing %s failed, because the file does not exist" : "فشلت مشاركة %s فالملف غير موجود",
"You are not allowed to share %s" : "أنت غير مسموح لك أن تشارك %s",
"Sharing %s failed, because you can not share with yourself" : "فشلت مشاركة %s لأنك لايمكنك المشاركة مع نفسك",
"Sharing %s failed, because the user %s does not exist" : "فشلت مشاركة %s لأن المستخدم %s غير موجود",
"Share type %s is not valid for %s" : "مشاركة النوع %s غير صالحة لـ %s",
"Could not find category \"%s\"" : "تعذر العثور على المجلد \"%s\"",
"Apps" : "التطبيقات",
"A valid username must be provided" : "يجب ادخال اسم مستخدم صحيح",

View File

@ -1,16 +1,44 @@
{ "translations": {
"Cannot write into \"config\" directory!" : "الكتابة في مجلد \"config\" غير ممكنة!",
"This can usually be fixed by giving the webserver write access to the config directory" : "يمكن حل هذا عادة بإعطاء خادم الوب صلاحية الكتابة في مجلد config",
"See %s" : "أنظر %s",
"Sample configuration detected" : "تم اكتشاف إعدادات عيّنة",
"PHP %s or higher is required." : "إصدار PHP %s أو أحدث منه مطلوب.",
"PHP with a version lower than %s is required." : "PHP الإصدار %s أو أقل مطلوب.",
"%sbit or higher PHP required." : "مكتبات PHP ذات %s بت أو أعلى مطلوبة.",
"Following databases are supported: %s" : "قواعد البيانات التالية مدعومة: %s",
"The command line tool %s could not be found" : "لم يتم العثور على أداة سطر الأوامر %s",
"The library %s is not available." : "مكتبة %s غير متوفرة.",
"Unknown filetype" : "نوع الملف غير معروف",
"Invalid image" : "الصورة غير صالحة",
"today" : "اليوم",
"yesterday" : "يوم أمس",
"_%n day ago_::_%n days ago_" : ["قبل ساعات","قبل يوم","قبل يومين","قبل %n يوماً","قبل %n يوماً","قبل %n يوماً"],
"last month" : "الشهر الماضي",
"_%n month ago_::_%n months ago_" : ["قبل عدة أيام","قبل شهر","قبل شهرين","قبل %n شهراً","قبل %n شهراً","قبل %n شهراً"],
"last year" : "السنةالماضية",
"seconds ago" : "منذ ثواني",
"Empty filename is not allowed" : "لا يسمح بأسماء فارغة للملفات",
"4-byte characters are not supported in file names" : "المحارف ذات 4 بايت غير مسموح بها في أسماء الملفات",
"File name is a reserved word" : "اسم الملف كلمة محجوزة",
"File name contains at least one invalid character" : "اسم الملف به ، على الأقل ، حرف غير صالح",
"File name is too long" : "اسم الملف طويل جداً",
"App directory already exists" : "مجلد التطبيق موجود مسبقا",
"Can't create app folder. Please fix permissions. %s" : "لا يمكن إنشاء مجلد التطبيق. يرجى تعديل الصلاحيات. %s",
"Archive does not contain a directory named %s" : "الأرشيف لا يحتوي مجلداً اسمه %s",
"No source specified when installing app" : "لم يتم تحديد المصدر عن تثبيت البرنامج",
"No href specified when installing app from http" : "لم يتم تحديد href عند تثبيت التطبيق من http",
"No path specified when installing app from local file" : "لم يتم تحديد مسار عند تثبيت التطبيق من ملف محلّي",
"Archives of type %s are not supported" : "الأرشيفات من نوع %s غير مدعومة",
"Failed to open archive when installing app" : "فشل فتح الأرشيف أثناء تثبيت التطبيق",
"App does not provide an info.xml file" : "التطبيق لا يتوفر على ملف info.xml",
"App cannot be installed because appinfo file cannot be read." : "لا يمكن تثبيت التطبيق لأن ملف appinfo غير ممكنة قراءته.",
"Signature could not get checked. Please contact the app developer and check your admin screen." : "لم يتم التحقق من التوقيع. فضلاً اتصل بمطوّر التطبيق و تحقق من شاشة الإدارة في حسابك.",
"App can't be installed because of not allowed code in the App" : "لم يتم تثبيت التطبيق لوجود شفرة غير مسموح بها في التطبيق",
"App can't be installed because it is not compatible with this version of ownCloud" : "لم يتم تثبيت التطبيق لأنه غير متوافق مع هذا الإصدار من ownCloud",
"App can't be installed because it contains the <shipped>true</shipped> tag which is not allowed for non shipped apps" : "لم يتم تثبيت التطبيق لأن به علامة <shipped>true</shipped> التي لايسمح بها في التطبيقات غير المشحونة",
"App can't be installed because the version in info.xml is not the same as the version reported from the app store" : "لم يتم تثبيت التطبيق لأن الإصدار في info.xml مختلف عن الإصدار المذكور في متجر التطبيقات",
"%s enter the database username and name." : "%s أدخِل اسم قاعدة البيانات واسم مستخدمها.",
"%s enter the database username." : "%s ادخل اسم المستخدم الخاص بقاعدة البيانات.",
"%s enter the database name." : "%s ادخل اسم فاعدة البيانات",
"%s you may not use dots in the database name" : "%s لا يسمح لك باستخدام نقطه (.) في اسم قاعدة البيانات",
@ -21,9 +49,20 @@
"You need to enter either an existing account or the administrator." : "انت بحاجة لكتابة اسم مستخدم موجود أو حساب المدير.",
"Offending command was: \"%s\", name: %s, password: %s" : "الأمر المخالف كان : \"%s\", اسم المستخدم : %s, كلمة المرور: %s",
"PostgreSQL username and/or password not valid" : "اسم المستخدم / أو كلمة المرور الخاصة بـPostgreSQL غير صحيحة",
"Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "نظام ماك الإصدار X غير مدعوم و %s لن يعمل بشكل صحيح على هذه المنصة. استخدمه على مسؤوليتك!",
"For the best results, please consider using a GNU/Linux server instead." : "فضلاً ضع في الاعتبار استخدام نظام GNU/Linux بدل الأنظمة الأخرى للحصول على أفضل النتائج.",
"Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "فضلاً إحذف إعداد open_basedir من ملف php.ini لديك أو حوّل إلى PHP إصدار 64 بت.",
"Set an admin username." : "اعداد اسم مستخدم للمدير",
"Set an admin password." : "اعداد كلمة مرور للمدير",
"Can't create or write into the data directory %s" : "لا يمكن الإنشاء أو الكتابة في مجلد البيانات %s",
"Invalid Federated Cloud ID" : "معرّف سحابة الاتحاد غير صالح",
"%s shared »%s« with you" : "%s شارك »%s« معك",
"%s via %s" : "%s عبر %s",
"Sharing %s failed, because the file does not exist" : "فشلت مشاركة %s فالملف غير موجود",
"You are not allowed to share %s" : "أنت غير مسموح لك أن تشارك %s",
"Sharing %s failed, because you can not share with yourself" : "فشلت مشاركة %s لأنك لايمكنك المشاركة مع نفسك",
"Sharing %s failed, because the user %s does not exist" : "فشلت مشاركة %s لأن المستخدم %s غير موجود",
"Share type %s is not valid for %s" : "مشاركة النوع %s غير صالحة لـ %s",
"Could not find category \"%s\"" : "تعذر العثور على المجلد \"%s\"",
"Apps" : "التطبيقات",
"A valid username must be provided" : "يجب ادخال اسم مستخدم صحيح",

View File

@ -29,6 +29,7 @@ OC.L10N.register(
"Module with id: %s does not exist. Please enable it in your apps settings or contact your administrator." : "Modulul cu id-ul %s nu există. Activează-l în setările tale de aplicație sau contactează-ți administratorul.",
"Empty filename is not allowed" : "Nu este permis fișier fără nume",
"Dot files are not allowed" : "Fișierele care încep cu caracterul punct nu sunt permise",
"4-byte characters are not supported in file names" : "Caracterele stocate în 4 octeți nu sunt suportate în denumirile fișierelor",
"File name is a reserved word" : "Numele fișierului este un cuvânt rezervat",
"File name contains at least one invalid character" : "Numele fișierului conține măcar un caracter invalid",
"File name is too long" : "Numele fișierului este prea lung",
@ -36,6 +37,8 @@ OC.L10N.register(
"Can't create app folder. Please fix permissions. %s" : "Nu se poate crea directorul de aplicație. Repară permisiunile. %s",
"Archive does not contain a directory named %s" : "Arhiva nu conține vreun director cu numele %s",
"No source specified when installing app" : "Nu a fost specificată vreo sursă la instalarea aplicației",
"No href specified when installing app from http" : "Nu s-a specificat adresa la instalarea aplicației dintr-o sursă de pe Internet",
"No path specified when installing app from local file" : "Nu s-a specificat vreo cale la instalarea aplicației de pe un fișier local",
"Archives of type %s are not supported" : "Arhivele de tip %s nu sunt suportate",
"Failed to open archive when installing app" : "Deschiderea arhivei a eșuat în timpul instalării aplicației",
"App does not provide an info.xml file" : "Aplicația nu furnizează un fișier info.xml",
@ -51,10 +54,12 @@ OC.L10N.register(
"DB Error: \"%s\"" : "Eroare Bază de Date: \"%s\"",
"Offending command was: \"%s\"" : "Comanda cauză a fost: \"%s\"",
"PostgreSQL username and/or password not valid" : "Nume utilizator și/sau parolă PostgreSQL greșită",
"For the best results, please consider using a GNU/Linux server instead." : "Pentru cele mai bune rezultate, ia în calcul folosirea unui server care rulează un sistem de operare GNU/Linux.",
"Set an admin username." : "Setează un nume de administrator.",
"Set an admin password." : "Setează o parolă de administrator.",
"Invalid Federated Cloud ID" : "ID invalid cloud federalizat",
"%s shared »%s« with you" : "%s Partajat »%s« cu tine de",
"%s via %s" : "%s via %s",
"You are not allowed to share %s" : "Nu există permisiunea de partajare %s",
"Sharing %s failed, because this item is already shared with %s" : "Partajarea %s a eșuat deoarece acest element este deja partajat cu %s",
"Not allowed to create a federated share with the same user" : "Nu este permisă crearea unei partajări federalizate cu acelaşi utilizator",

View File

@ -27,6 +27,7 @@
"Module with id: %s does not exist. Please enable it in your apps settings or contact your administrator." : "Modulul cu id-ul %s nu există. Activează-l în setările tale de aplicație sau contactează-ți administratorul.",
"Empty filename is not allowed" : "Nu este permis fișier fără nume",
"Dot files are not allowed" : "Fișierele care încep cu caracterul punct nu sunt permise",
"4-byte characters are not supported in file names" : "Caracterele stocate în 4 octeți nu sunt suportate în denumirile fișierelor",
"File name is a reserved word" : "Numele fișierului este un cuvânt rezervat",
"File name contains at least one invalid character" : "Numele fișierului conține măcar un caracter invalid",
"File name is too long" : "Numele fișierului este prea lung",
@ -34,6 +35,8 @@
"Can't create app folder. Please fix permissions. %s" : "Nu se poate crea directorul de aplicație. Repară permisiunile. %s",
"Archive does not contain a directory named %s" : "Arhiva nu conține vreun director cu numele %s",
"No source specified when installing app" : "Nu a fost specificată vreo sursă la instalarea aplicației",
"No href specified when installing app from http" : "Nu s-a specificat adresa la instalarea aplicației dintr-o sursă de pe Internet",
"No path specified when installing app from local file" : "Nu s-a specificat vreo cale la instalarea aplicației de pe un fișier local",
"Archives of type %s are not supported" : "Arhivele de tip %s nu sunt suportate",
"Failed to open archive when installing app" : "Deschiderea arhivei a eșuat în timpul instalării aplicației",
"App does not provide an info.xml file" : "Aplicația nu furnizează un fișier info.xml",
@ -49,10 +52,12 @@
"DB Error: \"%s\"" : "Eroare Bază de Date: \"%s\"",
"Offending command was: \"%s\"" : "Comanda cauză a fost: \"%s\"",
"PostgreSQL username and/or password not valid" : "Nume utilizator și/sau parolă PostgreSQL greșită",
"For the best results, please consider using a GNU/Linux server instead." : "Pentru cele mai bune rezultate, ia în calcul folosirea unui server care rulează un sistem de operare GNU/Linux.",
"Set an admin username." : "Setează un nume de administrator.",
"Set an admin password." : "Setează o parolă de administrator.",
"Invalid Federated Cloud ID" : "ID invalid cloud federalizat",
"%s shared »%s« with you" : "%s Partajat »%s« cu tine de",
"%s via %s" : "%s via %s",
"You are not allowed to share %s" : "Nu există permisiunea de partajare %s",
"Sharing %s failed, because this item is already shared with %s" : "Partajarea %s a eșuat deoarece acest element este deja partajat cu %s",
"Not allowed to create a federated share with the same user" : "Nu este permisă crearea unei partajări federalizate cu acelaşi utilizator",

View File

@ -154,7 +154,7 @@ class AllConfig implements \OCP\IConfig {
*
* @param string $appName the appName that we want to store the value under
* @param string $key the key of the value, under which will be saved
* @param string $value the value that should be stored
* @param string|float|int $value the value that should be stored
*/
public function setAppValue($appName, $key, $value) {
\OC::$server->getAppConfig()->setValue($appName, $key, $value);
@ -198,11 +198,16 @@ class AllConfig implements \OCP\IConfig {
* @param string $userId the userId of the user that we want to store the value under
* @param string $appName the appName that we want to store the value under
* @param string $key the key under which the value is being stored
* @param string $value the value that you want to store
* @param string|float|int $value the value that you want to store
* @param string $preCondition only update if the config value was previously the value passed as $preCondition
* @throws \OCP\PreConditionNotMetException if a precondition is specified and is not met
* @throws \UnexpectedValueException when trying to store an unexpected value
*/
public function setUserValue($userId, $appName, $key, $value, $preCondition = null) {
if (!is_int($value) && !is_float($value) && !is_string($value)) {
throw new \UnexpectedValueException('Only integers, floats and strings are allowed as value');
}
// TODO - FIXME
$this->fixDIInit();

View File

@ -143,7 +143,7 @@ class AppConfig implements IAppConfig {
*
* @param string $app app
* @param string $key key
* @param string $value value
* @param string|float|int $value value
* @return bool True if the value was inserted or updated, false if the value was the same
*/
public function setValue($app, $key, $value) {

View File

@ -28,6 +28,7 @@ class DefaultTokenCleanupJob extends Job {
protected function run($argument) {
/* @var $provider DefaultTokenProvider */
// TODO: add OC\Authentication\Token\IProvider::invalidateOldTokens and query interface
$provider = OC::$server->query('OC\Authentication\Token\DefaultTokenProvider');
$provider->invalidateOldTokens();
}

View File

@ -80,7 +80,7 @@ class DecryptAll {
$this->input = $input;
$this->output = $output;
if (!empty($user) && $this->userManager->userExists($user) === false) {
if ($user !== '' && $this->userManager->userExists($user) === false) {
$this->output->writeln('User "' . $user . '" does not exist. Please check the username and try again');
return false;
}
@ -141,7 +141,7 @@ class DecryptAll {
$this->output->writeln("\n");
$userList = [];
if (empty($user)) {
if ($user === '') {
$fetchUsersProgress = new ProgressBar($this->output);
$fetchUsersProgress->setFormat(" %message% \n [%bar%]");

View File

@ -38,6 +38,7 @@ use OC\Files\Filesystem;
use OC\Hooks\BasicEmitter;
use OCP\Config;
use OCP\Files\Cache\IScanner;
use OCP\Files\ForbiddenException;
use OCP\Files\Storage\ILockingStorage;
use OCP\Lock\ILockingProvider;
@ -140,7 +141,11 @@ class Scanner extends BasicEmitter implements IScanner {
}
}
$data = $this->getData($file);
try {
$data = $this->getData($file);
} catch (ForbiddenException $e) {
return null;
}
if ($data) {

View File

@ -231,7 +231,10 @@ class Updater implements IUpdater {
$parentId = $this->cache->getParentId($internalPath);
$parent = dirname($internalPath);
if ($parentId != -1) {
$this->cache->update($parentId, array('storage_mtime' => $this->storage->filemtime($parent)));
$mtime = $this->storage->filemtime($parent);
if ($mtime !== false) {
$this->cache->update($parentId, array('storage_mtime' => $mtime));
}
}
}
}

View File

@ -643,6 +643,9 @@ abstract class Common implements Storage, ILockingStorage {
$data = [];
$data['mimetype'] = $this->getMimeType($path);
$data['mtime'] = $this->filemtime($path);
if ($data['mtime'] === false) {
$data['mtime'] = time();
}
if ($data['mimetype'] == 'httpd/unix-directory') {
$data['size'] = -1; //unknown
} else {

View File

@ -33,20 +33,31 @@
*/
namespace OC\Files\Storage;
use OCP\Files\ForbiddenException;
/**
* for local filestore, we only have to map the paths
*/
class Local extends \OC\Files\Storage\Common {
protected $datadir;
protected $dataDirLength;
protected $allowSymlinks = false;
protected $realDataDir;
public function __construct($arguments) {
if (!isset($arguments['datadir']) || !is_string($arguments['datadir'])) {
throw new \InvalidArgumentException('No data directory set for local storage');
}
$this->datadir = $arguments['datadir'];
$this->realDataDir = rtrim(realpath($this->datadir), '/') . '/';
if (substr($this->datadir, -1) !== '/') {
$this->datadir .= '/';
}
$this->dataDirLength = strlen($this->realDataDir);
}
public function __destruct() {
@ -157,7 +168,7 @@ class Local extends \OC\Files\Storage\Common {
public function filemtime($path) {
clearstatcache($this->getSourcePath($path));
return filemtime($this->getSourcePath($path));
return $this->file_exists($path) ? filemtime($this->getSourcePath($path)) : false;
}
public function touch($path, $mtime = null) {
@ -188,7 +199,7 @@ class Local extends \OC\Files\Storage\Common {
return '';
}
$handle = fopen($fileName,'rb');
$handle = fopen($fileName, 'rb');
$content = fread($handle, $fileSize);
fclose($handle);
return $content;
@ -337,10 +348,27 @@ class Local extends \OC\Files\Storage\Common {
*
* @param string $path
* @return string
* @throws ForbiddenException
*/
public function getSourcePath($path) {
$fullPath = $this->datadir . $path;
return $fullPath;
if ($this->allowSymlinks || $path === '') {
return $fullPath;
}
$pathToResolve = $fullPath;
$realPath = realpath($pathToResolve);
while ($realPath === false) { // for non existing files check the parent directory
$pathToResolve = dirname($pathToResolve);
$realPath = realpath($pathToResolve);
}
if ($realPath) {
$realPath = $realPath . '/';
}
if (substr($realPath, 0, $this->dataDirLength) === $this->realDataDir) {
return $fullPath;
} else {
throw new ForbiddenException("Following symlinks is not allowed ('$fullPath' -> '$realPath' not inside '{$this->realDataDir}')", false);
}
}
/**
@ -377,7 +405,7 @@ class Local extends \OC\Files\Storage\Common {
* @return bool
*/
public function copyFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
if($sourceStorage->instanceOfStorage('\OC\Files\Storage\Local')){
if ($sourceStorage->instanceOfStorage('\OC\Files\Storage\Local')) {
/**
* @var \OC\Files\Storage\Local $sourceStorage
*/

View File

@ -337,10 +337,17 @@ class View {
return $this->removeMount($mount, $absolutePath);
}
if ($this->is_dir($path)) {
return $this->basicOperation('rmdir', $path, array('delete'));
$result = $this->basicOperation('rmdir', $path, array('delete'));
} else {
return false;
$result = false;
}
if (!$result && !$this->file_exists($path)) { //clear ghost files from the cache on delete
$storage = $mount->getStorage();
$internalPath = $mount->getInternalPath($absolutePath);
$storage->getUpdater()->remove($internalPath);
}
return $result;
}
/**
@ -429,7 +436,7 @@ class View {
/**
* @param string $path
* @param int $from
* @param int $from
* @param int $to
* @return bool|mixed
* @throws \OCP\Files\InvalidPathException
@ -441,18 +448,18 @@ class View {
$handle = $this->fopen($path, 'rb');
if ($handle) {
if (fseek($handle, $from) === 0) {
$chunkSize = 8192; // 8 kB chunks
$end = $to + 1;
while (!feof($handle) && ftell($handle) < $end) {
$len = $end-ftell($handle);
if ($len > $chunkSize) {
$len = $chunkSize;
$chunkSize = 8192; // 8 kB chunks
$end = $to + 1;
while (!feof($handle) && ftell($handle) < $end) {
$len = $end - ftell($handle);
if ($len > $chunkSize) {
$len = $chunkSize;
}
echo fread($handle, $len);
flush();
}
echo fread($handle, $len);
flush();
}
$size = ftell($handle) - $from;
return $size;
$size = ftell($handle) - $from;
return $size;
}
throw new \OCP\Files\UnseekableException('fseek error');
@ -679,7 +686,15 @@ class View {
if ($mount and $mount->getInternalPath($absolutePath) === '') {
return $this->removeMount($mount, $absolutePath);
}
return $this->basicOperation('unlink', $path, array('delete'));
$result = $this->basicOperation('unlink', $path, array('delete'));
if (!$result && !$this->file_exists($path)) { //clear ghost files from the cache on delete
$storage = $mount->getStorage();
$internalPath = $mount->getInternalPath($absolutePath);
$storage->getUpdater()->remove($internalPath);
return true;
} else {
return $result;
}
}
/**

View File

@ -206,7 +206,9 @@ class OC_Helper {
foreach ($files as $fileInfo) {
/** @var SplFileInfo $fileInfo */
if ($fileInfo->isDir()) {
if ($fileInfo->isLink()) {
unlink($fileInfo->getPathname());
} else if ($fileInfo->isDir()) {
rmdir($fileInfo->getRealPath());
} else {
unlink($fileInfo->getRealPath());

View File

@ -88,7 +88,7 @@ interface IAppConfig {
* sets a value in the appconfig
* @param string $app app
* @param string $key key
* @param string $value value
* @param string|float|int $value value
* @deprecated 8.0.0 use method setAppValue of \OCP\IConfig
*
* Sets a value. If the key did not exist before it will be created.

View File

@ -104,7 +104,7 @@ interface IConfig {
* Writes a new app wide value
*
* @param string $appName the appName that we want to store the value under
* @param string $key the key of the value, under which will be saved
* @param string|float|int $key the key of the value, under which will be saved
* @param string $value the value that should be stored
* @return void
* @since 6.0.0
@ -149,6 +149,7 @@ interface IConfig {
* @param string $value the value that you want to store
* @param string $preCondition only update if the config value was previously the value passed as $preCondition
* @throws \OCP\PreConditionNotMetException if a precondition is specified and is not met
* @throws \UnexpectedValueException when trying to store an unexpected value
* @since 6.0.0 - parameter $precondition was added in 8.0.0
*/
public function setUserValue($userId, $appName, $key, $value, $preCondition = null);

View File

@ -14,7 +14,7 @@ var UserList = {
availableGroups: [],
offset: 0,
usersToLoad: 10, //So many users will be loaded when user scrolls down
initialUsersToLoad: 250, //initial number of users to load
initialUsersToLoad: 50, //initial number of users to load
currentGid: '',
filter: '',

View File

@ -23,8 +23,9 @@
namespace Tests\Core\Controller;
use OC\AppFramework\Http;
use OC\Authentication\Token\IToken;
use OC\Core\Controller\TokenController;
use OCP\AppFramework\Http\Response;
use OCP\AppFramework\Http\JSONResponse;
use Test\TestCase;
class TokenControllerTest extends TestCase {
@ -34,6 +35,7 @@ class TokenControllerTest extends TestCase {
private $request;
private $userManager;
private $tokenProvider;
private $twoFactorAuthManager;
private $secureRandom;
protected function setUp() {
@ -43,17 +45,17 @@ class TokenControllerTest extends TestCase {
$this->userManager = $this->getMockBuilder('\OC\User\Manager')
->disableOriginalConstructor()
->getMock();
$this->tokenProvider = $this->getMockBuilder('\OC\Authentication\Token\DefaultTokenProvider')
$this->tokenProvider = $this->getMock('\OC\Authentication\Token\IProvider');
$this->twoFactorAuthManager = $this->getMockBuilder('\OC\Authentication\TwoFactorAuth\Manager')
->disableOriginalConstructor()
->getMock();
$this->secureRandom = $this->getMock('\OCP\Security\ISecureRandom');
$this->tokenController = new TokenController('core', $this->request, $this->userManager, $this->tokenProvider,
$this->secureRandom);
$this->tokenController = new TokenController('core', $this->request, $this->userManager, $this->tokenProvider, $this->twoFactorAuthManager, $this->secureRandom);
}
public function testWithoutCredentials() {
$expected = new Response();
$expected = new JSONResponse();
$expected->setStatus(Http::STATUS_UNPROCESSABLE_ENTITY);
$actual = $this->tokenController->generateToken(null, null);
@ -66,7 +68,7 @@ class TokenControllerTest extends TestCase {
->method('checkPassword')
->with('john', 'passme')
->will($this->returnValue(false));
$expected = new Response();
$expected = new JSONResponse();
$expected->setStatus(Http::STATUS_UNAUTHORIZED);
$actual = $this->tokenController->generateToken('john', 'passme');
@ -83,13 +85,17 @@ class TokenControllerTest extends TestCase {
$user->expects($this->once())
->method('getUID')
->will($this->returnValue('john'));
$this->twoFactorAuthManager->expects($this->once())
->method('isTwoFactorAuthenticated')
->with($user)
->will($this->returnValue(false));
$this->secureRandom->expects($this->once())
->method('generate')
->with(128)
->will($this->returnValue('verysecurerandomtoken'));
$this->tokenProvider->expects($this->once())
->method('generateToken')
->with('verysecurerandomtoken', 'john', 'john', '123456', 'unknown client', \OC\Authentication\Token\IToken::PERMANENT_TOKEN);
->with('verysecurerandomtoken', 'john', 'john', '123456', 'unknown client', IToken::PERMANENT_TOKEN);
$expected = [
'token' => 'verysecurerandomtoken'
];
@ -99,4 +105,24 @@ class TokenControllerTest extends TestCase {
$this->assertEquals($expected, $actual);
}
public function testWithValidCredentialsBut2faEnabled() {
$user = $this->getMock('\OCP\IUser');
$this->userManager->expects($this->once())
->method('checkPassword')
->with('john', '123456')
->will($this->returnValue($user));
$this->twoFactorAuthManager->expects($this->once())
->method('isTwoFactorAuthenticated')
->with($user)
->will($this->returnValue(true));
$this->secureRandom->expects($this->never())
->method('generate');
$expected = new JSONResponse();
$expected->setStatus(Http::STATUS_UNAUTHORIZED);
$actual = $this->tokenController->generateToken('john', '123456');
$this->assertEquals($expected, $actual);
}
}

View File

@ -33,7 +33,7 @@ class TwoFactorChallengeControllerTest extends TestCase {
private $session;
private $urlGenerator;
/** TwoFactorChallengeController */
/** @var TwoFactorChallengeController|\PHPUnit_Framework_MockObject_MockObject */
private $controller;
protected function setUp() {
@ -47,9 +47,20 @@ class TwoFactorChallengeControllerTest extends TestCase {
$this->session = $this->getMock('\OCP\ISession');
$this->urlGenerator = $this->getMock('\OCP\IURLGenerator');
$this->controller = new TwoFactorChallengeController(
'core', $this->request, $this->twoFactorManager, $this->userSession, $this->session, $this->urlGenerator
);
$this->controller = $this->getMockBuilder('OC\Core\Controller\TwoFactorChallengeController')
->setConstructorArgs([
'core',
$this->request,
$this->twoFactorManager,
$this->userSession,
$this->session,
$this->urlGenerator,
])
->setMethods(['getLogoutAttribute'])
->getMock();
$this->controller->expects($this->any())
->method('getLogoutAttribute')
->willReturn('logoutAttribute');
}
public function testSelectChallenge() {
@ -70,6 +81,7 @@ class TwoFactorChallengeControllerTest extends TestCase {
$expected = new \OCP\AppFramework\Http\TemplateResponse('core', 'twofactorselectchallenge', [
'providers' => $providers,
'redirect_url' => '/some/url',
'logout_attribute' => 'logoutAttribute',
], 'guest');
$this->assertEquals($expected, $this->controller->selectChallenge('/some/url'));
@ -110,6 +122,7 @@ class TwoFactorChallengeControllerTest extends TestCase {
$expected = new \OCP\AppFramework\Http\TemplateResponse('core', 'twofactorshowchallenge', [
'error' => true,
'provider' => $provider,
'logout_attribute' => 'logoutAttribute',
'template' => '<html/>',
], 'guest');

View File

@ -123,6 +123,25 @@ class AllConfigTest extends \Test\TestCase {
$config->deleteUserValue('userPreCond', 'appPreCond', 'keyPreCond');
}
public function dataSetUserValueUnexpectedValue() {
return [
[true],
[false],
[null],
[new \stdClass()],
];
}
/**
* @dataProvider dataSetUserValueUnexpectedValue
* @param mixed $value
* @expectedException \UnexpectedValueException
*/
public function testSetUserValueUnexpectedValue($value) {
$config = $this->getConfig();
$config->setUserValue('userSetBool', 'appSetBool', 'keySetBool', $value);
}
/**
* @expectedException \OCP\PreConditionNotMetException
*/

View File

@ -86,13 +86,25 @@ class DecryptAllTest extends TestCase {
$this->invokePrivate($this->instance, 'output', [$this->outputInterface]);
}
/**
* @dataProvider dataTrueFalse
* @param bool $prepareResult
*/
public function testDecryptAll($prepareResult, $user) {
public function dataDecryptAll() {
return [
[true, 'user1', true],
[false, 'user1', true],
[true, '0', true],
[false, '0', true],
[true, '', false],
];
}
if (!empty($user)) {
/**
* @dataProvider dataDecryptAll
* @param bool $prepareResult
* @param string $user
* @param bool $userExistsChecked
*/
public function testDecryptAll($prepareResult, $user, $userExistsChecked) {
if ($userExistsChecked) {
$this->userManager->expects($this->once())->method('userExists')->willReturn(true);
} else {
$this->userManager->expects($this->never())->method('userExists');
@ -125,15 +137,6 @@ class DecryptAllTest extends TestCase {
$instance->decryptAll($this->inputInterface, $this->outputInterface, $user);
}
public function dataTrueFalse() {
return [
[true, 'user1'],
[false, 'user1'],
[true, ''],
[true, null]
];
}
/**
* test decrypt all call with a user who doesn't exists
*/
@ -147,8 +150,16 @@ class DecryptAllTest extends TestCase {
);
}
public function dataTrueFalse() {
return [
[true],
[false],
];
}
/**
* @dataProvider dataTrueFalse
* @param bool $success
*/
public function testPrepareEncryptionModules($success) {

View File

@ -84,5 +84,36 @@ class LocalTest extends Storage {
public function testInvalidArgumentsNoArray() {
new \OC\Files\Storage\Local(null);
}
/**
* @expectedException \OCP\Files\ForbiddenException
*/
public function testDisallowSymlinksOutsideDatadir() {
$subDir1 = $this->tmpDir . 'sub1';
$subDir2 = $this->tmpDir . 'sub2';
$sym = $this->tmpDir . 'sub1/sym';
mkdir($subDir1);
mkdir($subDir2);
symlink($subDir2, $sym);
$storage = new \OC\Files\Storage\Local(['datadir' => $subDir1]);
$storage->file_put_contents('sym/foo', 'bar');
}
public function testDisallowSymlinksInsideDatadir() {
$subDir1 = $this->tmpDir . 'sub1';
$subDir2 = $this->tmpDir . 'sub1/sub2';
$sym = $this->tmpDir . 'sub1/sym';
mkdir($subDir1);
mkdir($subDir2);
symlink($subDir2, $sym);
$storage = new \OC\Files\Storage\Local(['datadir' => $subDir1]);
$storage->file_put_contents('sym/foo', 'bar');
}
}

View File

@ -2417,7 +2417,7 @@ class ViewTest extends \Test\TestCase {
$content = $view->getDirectoryContent('', $filter);
$files = array_map(function(FileInfo $info) {
$files = array_map(function (FileInfo $info) {
return $info->getName();
}, $content);
sort($files);
@ -2444,4 +2444,53 @@ class ViewTest extends \Test\TestCase {
$data = $view->getFileInfo('.');
$this->assertEquals('', $data->getChecksum());
}
public function testDeleteGhostFile() {
$storage = new Temporary(array());
$scanner = $storage->getScanner();
$cache = $storage->getCache();
$storage->file_put_contents('foo.txt', 'bar');
\OC\Files\Filesystem::mount($storage, array(), '/test/');
$scanner->scan('');
$storage->unlink('foo.txt');
$this->assertTrue($cache->inCache('foo.txt'));
$view = new \OC\Files\View('/test');
$rootInfo = $view->getFileInfo('');
$this->assertEquals(3, $rootInfo->getSize());
$view->unlink('foo.txt');
$newInfo = $view->getFileInfo('');
$this->assertFalse($cache->inCache('foo.txt'));
$this->assertNotEquals($rootInfo->getEtag(), $newInfo->getEtag());
$this->assertEquals(0, $newInfo->getSize());
}
public function testDeleteGhostFolder() {
$storage = new Temporary(array());
$scanner = $storage->getScanner();
$cache = $storage->getCache();
$storage->mkdir('foo');
$storage->file_put_contents('foo/foo.txt', 'bar');
\OC\Files\Filesystem::mount($storage, array(), '/test/');
$scanner->scan('');
$storage->rmdir('foo');
$this->assertTrue($cache->inCache('foo'));
$this->assertTrue($cache->inCache('foo/foo.txt'));
$view = new \OC\Files\View('/test');
$rootInfo = $view->getFileInfo('');
$this->assertEquals(3, $rootInfo->getSize());
$view->rmdir('foo');
$newInfo = $view->getFileInfo('');
$this->assertFalse($cache->inCache('foo'));
$this->assertFalse($cache->inCache('foo/foo.txt'));
$this->assertNotEquals($rootInfo->getEtag(), $newInfo->getEtag());
$this->assertEquals(0, $newInfo->getSize());
}
}

View File

@ -25,10 +25,10 @@
// We only can count up. The 4. digit is only for the internal patchlevel to trigger DB upgrades
// between betas, final and RCs. This is _not_ the public version number. Reset minor/patchlevel
// when updating major/minor version number.
$OC_Version = array(9, 1, 0, 7);
$OC_Version = array(9, 1, 0, 8);
// The human readable string
$OC_VersionString = '9.1.0 beta 1';
$OC_VersionString = '9.1.0 beta 2';
$OC_VersionCanBeUpgradedFrom = array(9, 0);