Repair job to fix permissions for avatars
Fixes #22978 On some older installations the permissions for the userRoot and the avatars are not correct. This breaks since we now use the Node API in the avatar code. This repair job makes sure that the permissions are set correctly. * Unit tests added
This commit is contained in:
parent
a0d8702a1c
commit
1b66db72d9
|
@ -29,6 +29,7 @@
|
|||
namespace OC;
|
||||
|
||||
use OC\Repair\AssetCache;
|
||||
use OC\Repair\AvatarPermissions;
|
||||
use OC\Repair\CleanTags;
|
||||
use OC\Repair\Collation;
|
||||
use OC\Repair\DropOldJobs;
|
||||
|
@ -134,6 +135,7 @@ class Repair implements IOutput{
|
|||
new RepairInvalidShares(\OC::$server->getConfig(), \OC::$server->getDatabaseConnection()),
|
||||
new SharePropagation(\OC::$server->getConfig()),
|
||||
new RemoveOldShares(\OC::$server->getDatabaseConnection()),
|
||||
new AvatarPermissions(\OC::$server->getDatabaseConnection()),
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
<?php
|
||||
/**
|
||||
* @author Roeland Jago Douma <rullzer@owncloud.com>
|
||||
*
|
||||
* @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 OC\Repair;
|
||||
|
||||
use OCP\IDBConnection;
|
||||
use OCP\Migration\IOutput;
|
||||
use OCP\Migration\IRepairStep;
|
||||
|
||||
/**
|
||||
* Class AvatarPermissions
|
||||
*
|
||||
* @package OC\Repair
|
||||
*/
|
||||
class AvatarPermissions implements IRepairStep {
|
||||
/** @var IDBConnection */
|
||||
private $connection;
|
||||
|
||||
/**
|
||||
* AvatarPermissions constructor.
|
||||
*
|
||||
* @param IDBConnection $connection
|
||||
*/
|
||||
public function __construct(IDBConnection $connection) {
|
||||
$this->connection = $connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName() {
|
||||
return 'Fix permissions so avatars can be stored again';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param IOutput $output
|
||||
*/
|
||||
public function run(IOutput $output) {
|
||||
$output->startProgress(2);
|
||||
$this->fixUserRootPermissions();
|
||||
$output->advance();
|
||||
$this->fixAvatarPermissions();
|
||||
$output->finishProgress();
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure all user roots have permissions 23 (all but share)
|
||||
*/
|
||||
protected function fixUserRootPermissions() {
|
||||
$qb = $this->connection->getQueryBuilder();
|
||||
$qb2 = $this->connection->getQueryBuilder();
|
||||
|
||||
$qb->select('numeric_id')
|
||||
->from('storages')
|
||||
->where($qb->expr()->like('id', $qb2->createParameter('like')));
|
||||
|
||||
$qb2->update('filecache')
|
||||
->set('permissions', $qb2->createNamedParameter(23))
|
||||
->where($qb2->expr()->eq('path', $qb2->createNamedParameter('')))
|
||||
->andWhere($qb2->expr()->in('storage', $qb2->createFunction($qb->getSQL())))
|
||||
->andWhere($qb2->expr()->neq('permissions', $qb2->createNamedParameter(23)))
|
||||
->setParameter('like', 'home::%');
|
||||
|
||||
|
||||
$qb2->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure all avatar files in the user roots have permission 27
|
||||
*/
|
||||
protected function fixAvatarPermissions() {
|
||||
$qb = $this->connection->getQueryBuilder();
|
||||
$qb2 = $this->connection->getQueryBuilder();
|
||||
|
||||
$qb->select('numeric_id')
|
||||
->from('storages')
|
||||
->where($qb->expr()->like('id', $qb2->createParameter('like')));
|
||||
|
||||
$qb2->update('filecache')
|
||||
->set('permissions', $qb2->createNamedParameter(27))
|
||||
->where($qb2->expr()->like('path', $qb2->createNamedParameter('avatar.%')))
|
||||
->andWhere($qb2->expr()->in('storage', $qb2->createFunction($qb->getSQL())))
|
||||
->andWhere($qb2->expr()->neq('permissions', $qb2->createNamedParameter(27)))
|
||||
->setParameter('like', 'home::%');
|
||||
|
||||
$qb2->execute();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,180 @@
|
|||
<?php
|
||||
/**
|
||||
* @author Roeland Jago Douma <rullzer@owncloud.com>
|
||||
*
|
||||
* @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 Test\Repair;
|
||||
|
||||
/**
|
||||
* Test for fixing the userRoot and avatar permissions
|
||||
*
|
||||
* @group DB
|
||||
*
|
||||
* @see \OC\Repair\AvatarPermissionsTest
|
||||
*/
|
||||
class AvatarPermissionsTest extends \Test\TestCase {
|
||||
|
||||
/** @var \OC\Repair\AvatarPermissions */
|
||||
protected $repair;
|
||||
|
||||
/** @var \OCP\IDBConnection */
|
||||
protected $connection;
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->connection = \OC::$server->getDatabaseConnection();
|
||||
$this->repair = new \OC\Repair\AvatarPermissions($this->connection);
|
||||
$this->cleanUpTables();
|
||||
}
|
||||
|
||||
protected function tearDown() {
|
||||
$this->cleanUpTables();
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
protected function cleanUpTables() {
|
||||
$qb = $this->connection->getQueryBuilder();
|
||||
$qb->delete('filecache')->execute();
|
||||
$qb->delete('storages')->execute();
|
||||
}
|
||||
|
||||
public function dataFixUserRootPermissions() {
|
||||
return [
|
||||
['home::user', '', 0, 23],
|
||||
['home::user', 'foo', 0, 0],
|
||||
['home::user', 'avatar.jpg', 0, 0],
|
||||
['ABC::user', '', 0, 0],
|
||||
['ABC::user', 'foo', 0, 0],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataFixUserRootPermissions
|
||||
*
|
||||
* @param string $storageId
|
||||
* @param string $path
|
||||
* @param int $permissionsBefore
|
||||
* @param int $permissionsAfter
|
||||
*/
|
||||
public function testFixUserRootPermissions($storageId, $path, $permissionsBefore, $permissionsAfter) {
|
||||
$userStorage = $this->addStorage($storageId);
|
||||
$userHome = $this->addFileCacheEntry($userStorage, $path, $permissionsBefore);
|
||||
|
||||
$this->invokePrivate($this->repair, 'fixUserRootPermissions', []);
|
||||
|
||||
$this->verifyPermissions($userHome, $permissionsAfter);
|
||||
}
|
||||
|
||||
public function dataFixAvatarPermissions() {
|
||||
return [
|
||||
['home::user', '', 0, 0],
|
||||
['home::user', 'avatar.jpg', 0, 27],
|
||||
['home::user', 'avatar.png', 0, 27],
|
||||
['home::user', 'avatar.32.png', 0, 27],
|
||||
['home::user', 'mine.txt', 0, 0],
|
||||
['ABC::user', '', 0, 0],
|
||||
['ABC::user', 'avatar.jpg', 0, 0],
|
||||
['ABC::user', 'avatar.png', 0, 0],
|
||||
['ABC::user', 'avatar.32.png', 0, 0],
|
||||
['ABC::user', 'mine.txt', 0, 0],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataFixAvatarPermissions
|
||||
*
|
||||
* @param string $storageId
|
||||
* @param string $path
|
||||
* @param int $permissionsBefore
|
||||
* @param int $permissionsAfter
|
||||
*/
|
||||
public function testFixAvatarPermissions($storageId, $path, $permissionsBefore, $permissionsAfter) {
|
||||
$userStorage = $this->addStorage($storageId);
|
||||
$userHome = $this->addFileCacheEntry($userStorage, $path, $permissionsBefore);
|
||||
|
||||
$this->invokePrivate($this->repair, 'fixAvatarPermissions', []);
|
||||
|
||||
$this->verifyPermissions($userHome, $permissionsAfter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new storage
|
||||
*
|
||||
* @param string $id
|
||||
* @return int The numeric id
|
||||
*/
|
||||
protected function addStorage($id) {
|
||||
$qb = $this->connection->getQueryBuilder();
|
||||
|
||||
$qb->insert('storages')
|
||||
->values([
|
||||
'id' => $qb->createNamedParameter($id)
|
||||
]);
|
||||
|
||||
$qb->execute();
|
||||
|
||||
return $qb->getLastInsertId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a filecache entry
|
||||
*
|
||||
* @param int $storage
|
||||
* @param string $path
|
||||
* @param int $permissions
|
||||
*
|
||||
* @return int The fileid
|
||||
*/
|
||||
protected function addFileCacheEntry($storage, $path, $permissions) {
|
||||
$qb = $this->connection->getQueryBuilder();
|
||||
|
||||
$qb->insert('filecache')
|
||||
->values([
|
||||
'path' => $qb->createNamedParameter($path),
|
||||
'storage' => $qb->createNamedParameter($storage),
|
||||
'permissions' => $qb->createNamedParameter($permissions),
|
||||
]);
|
||||
|
||||
$qb->execute();
|
||||
|
||||
return $qb->getLastInsertId();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $fileId
|
||||
* @param int $permissions
|
||||
*/
|
||||
protected function verifyPermissions($fileId, $permissions) {
|
||||
$qb = $this->connection->getQueryBuilder();
|
||||
|
||||
$qb->select('permissions')
|
||||
->from('filecache')
|
||||
->where($qb->expr()->eq('fileid', $qb->createNamedParameter($fileId)));
|
||||
|
||||
$cursor = $qb->execute();
|
||||
|
||||
$data = $cursor->fetch();
|
||||
$cursor->closeCursor();
|
||||
|
||||
$this->assertSame($permissions, (int)$data['permissions']);
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue