Skip to content

Commit 9e84cae

Browse files
committed
fix(FaceRoot): Fix duplicate prevention
fixes #695 Signed-off-by: Marcel Klehr <mklehr@gmx.net>
1 parent 710132f commit 9e84cae

File tree

4 files changed

+49
-6
lines changed

4 files changed

+49
-6
lines changed

lib/Dav/Faces/FaceRoot.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
use OCA\Recognize\Db\FaceDetection;
1313
use OCA\Recognize\Db\FaceDetectionMapper;
1414
use OCP\AppFramework\Db\DoesNotExistException;
15+
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
16+
use OCP\DB\Exception;
1517
use OCP\Files\IRootFolder;
1618
use OCP\IPreview;
1719
use OCP\ITagManager;
@@ -57,10 +59,12 @@ public function getName() {
5759
*/
5860
public function setName($name) {
5961
try {
60-
$this->clusterMapper->findByUserAndTitle($this->user->getUID(), $name);
62+
$this->clusterMapper->findByUserAndTitle($this->user->getUID(), basename($name));
6163
throw new Forbidden('Not allowed to create duplicate names');
6264
} catch (DoesNotExistException $e) {
6365
// pass
66+
} catch (MultipleObjectsReturnedException|Exception $e) {
67+
throw $e;
6468
}
6569
$this->cluster->setTitle(basename($name));
6670
$this->clusterMapper->update($this->cluster);

lib/Dav/Faces/FacesHome.php

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,15 @@ public function setName($name) {
5050
}
5151

5252
public function createDirectory($name) {
53+
if ($this->childExists(basename($name))) {
54+
throw new Forbidden('Not allowed to create duplicate names');
55+
}
56+
if (preg_match('/^[0-9]+$/', basename($name), $matches) != false) {
57+
throw new Forbidden('Not allowed to use numbers as names');
58+
}
5359
$entity = new FaceCluster();
5460
$entity->setUserId($this->user->getUID());
55-
$entity->setTitle($name);
61+
$entity->setTitle(basename($name));
5662
$this->faceClusterMapper->insert($entity);
5763
}
5864

@@ -90,9 +96,9 @@ public function getChild($name) : FaceRoot {
9096
* @throws \OCP\DB\Exception
9197
*/
9298
public function getChildren(): array {
93-
$clusters = $this->faceClusterMapper->findByUserId($this->user->getUID());
94-
$clusters = array_values(array_filter($clusters, fn ($cluster) => count($this->faceDetectionMapper->findByClusterId($cluster->getId())) > 0));
9599
if (count($this->children) === 0) {
100+
$clusters = $this->faceClusterMapper->findByUserId($this->user->getUID());
101+
$clusters = array_values(array_filter($clusters, fn ($cluster) => count($this->faceDetectionMapper->findByClusterId($cluster->getId())) > 0));
96102
$this->children = array_map(function (FaceCluster $cluster) {
97103
return new FaceRoot($this->faceClusterMapper, $cluster, $this->user, $this->faceDetectionMapper, $this->rootFolder, $this->tagManager, $this->previewManager);
98104
}, $clusters);

lib/Dav/Faces/PropFindPlugin.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,22 @@
1010
use \OCA\DAV\Connector\Sabre\FilesPlugin;
1111
use \OCA\DAV\Connector\Sabre\TagsPlugin;
1212
use OCA\DAV\Connector\Sabre\File;
13+
use OCA\Recognize\Db\FaceClusterMapper;
1314
use OCA\Recognize\Db\FaceDetectionMapper;
1415
use OCA\Recognize\Db\FaceDetectionWithTitle;
16+
use OCP\AppFramework\Db\DoesNotExistException;
17+
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
18+
use OCP\DB\Exception;
1519
use OCP\Files\DavUtil;
1620
use OCP\IPreview;
21+
use OCP\IUser;
22+
use Sabre\DAV\Exception\Forbidden;
1723
use Sabre\DAV\INode;
1824
use Sabre\DAV\PropFind;
1925
use Sabre\DAV\Server;
2026
use Sabre\DAV\ServerPlugin;
27+
use Sabre\HTTP\RequestInterface;
28+
use Sabre\HTTP\ResponseInterface;
2129

2230
final class PropFindPlugin extends ServerPlugin {
2331
public const FACE_DETECTIONS_PROPERTYNAME = '{http://nextcloud.org/ns}face-detections';
@@ -31,13 +39,15 @@ final class PropFindPlugin extends ServerPlugin {
3139
public function __construct(
3240
private FaceDetectionMapper $faceDetectionMapper,
3341
private IPreview $previewManager,
42+
private FaceClusterMapper $faceClusterMapper,
3443
) {
3544
}
3645

3746
public function initialize(Server $server) {
3847
$this->server = $server;
3948

4049
$this->server->on('propFind', [$this, 'propFind']);
50+
$this->server->on('beforeMove', [$this, 'beforeMove']);
4151
}
4252

4353

@@ -87,4 +97,23 @@ public function propFind(PropFind $propFind, INode $node) {
8797
});
8898
}
8999
}
100+
101+
public function beforeMove($source, $target) {
102+
// recognize/{userId}/faces/{name}
103+
if (str_starts_with($source, 'recognize') && str_starts_with($target, 'recognize')) {
104+
$sourceParts = explode('/', $source);
105+
$targetParts = explode('/', $target);
106+
if ($sourceParts[2] === 'faces' && $targetParts[2] === 'faces' && count($sourceParts) === 4 && count($targetParts) === 4) {
107+
try {
108+
$this->faceClusterMapper->findByUserAndTitle($targetParts[1], $targetParts[3]);
109+
throw new Forbidden('The target node already exists and cannot be overwritten');
110+
} catch (DoesNotExistException $e) {
111+
return true;
112+
} catch (MultipleObjectsReturnedException|Exception $e) {
113+
throw $e;
114+
}
115+
}
116+
}
117+
return true;
118+
}
90119
}

lib/Db/FaceClusterMapper.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,18 @@ public function findByUserAndTitle(string $userId, string $title) : Entity {
5858
$qb = $this->db->getQueryBuilder();
5959
$qb->select(FaceCluster::$columns)
6060
->from('recognize_face_clusters')
61-
->where($qb->expr()->eq('user_id', $qb->createPositionalParameter($userId)))
62-
->andWhere($qb->expr()->orX(
61+
->where($qb->expr()->eq('user_id', $qb->createPositionalParameter($userId)));
62+
if (preg_match('/^[0-9]+$/', $title, $matches) != false) {
63+
$qb->andWhere($qb->expr()->orX(
6364
$qb->expr()->eq('title', $qb->createPositionalParameter($title)),
6465
$qb->expr()->andX(
6566
$qb->expr()->eq('title', $qb->createPositionalParameter('')),
6667
$qb->expr()->eq('id', $qb->createPositionalParameter((int) $title, IQueryBuilder::PARAM_INT))
6768
)
6869
));
70+
} else {
71+
$qb->andWhere($qb->expr()->eq('title', $qb->createPositionalParameter($title)));
72+
}
6973
return $this->findEntity($qb);
7074
}
7175

0 commit comments

Comments
 (0)