Skip to content

Commit bd96e25

Browse files
committed
fixing and polishing
Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
1 parent df33dfa commit bd96e25

File tree

6 files changed

+195
-67
lines changed

6 files changed

+195
-67
lines changed

lib/Controller/SlaveController.php

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,11 @@
1010

1111
use OC\Authentication\Token\IToken;
1212
use OCA\GlobalSiteSelector\AppInfo\Application;
13+
use OCA\GlobalSiteSelector\Exceptions\LocalFederatedShareException;
1314
use OCA\GlobalSiteSelector\Exceptions\MasterUrlException;
15+
use OCA\GlobalSiteSelector\Exceptions\SharedFileException;
1416
use OCA\GlobalSiteSelector\GlobalSiteSelector;
17+
use OCA\GlobalSiteSelector\Model\LocalFile;
1518
use OCA\GlobalSiteSelector\Service\GlobalScaleService;
1619
use OCA\GlobalSiteSelector\Service\GlobalShareService;
1720
use OCA\GlobalSiteSelector\Service\SlaveService;
@@ -86,33 +89,25 @@ public function sharedFile(?string $jwt): DataResponse {
8689
}
8790
$key = $this->gss->getJwtKey();
8891
$decoded = (array)JWT::decode($jwt, new Key($key, Application::JWT_ALGORITHM));
92+
// JWT store data as stdClass, not array
93+
$decoded = json_decode(json_encode($decoded), true);
94+
95+
$this->logger->debug('decoded request', ['data' => $decoded]);
8996

9097
$fileId = (int)($decoded['fileId'] ?? 0);
9198
$shareId = (int)($decoded['shareId'] ?? 0);
9299
$instance = $decoded['instance'] ?? '';
93-
if ($shareId > 0) {
94-
$fileId = $this->globalShareService->getFileOwnerFromShareId($shareId)[0] ?? 0;
95-
}
96100

97-
if ($fileId === 0 || $instance === '') {
98-
return new DataResponse(['message' => 'missing argument'], Http::STATUS_NOT_FOUND);
99-
}
101+
$target = new LocalFile();
102+
$target->import($decoded['target'] ?? []);
100103

101-
// from a file id, get all parents until mount point
102-
$files = $this->globalShareService->getRelatedFiles((int)$fileId);
103-
if (empty($files)) {
104-
return new DataResponse(['message' => 'file not found'], Http::STATUS_NOT_FOUND);
105-
}
106-
107-
// based on the mount point (last element of the list, top parent folder) we know if the file is local or a federated share from another instance
108-
$remoteShare = $this->globalShareService->getFederatedShareFromTargetLocalFile(array_slice($files, -1)[0]);
109-
// In case the mount point is a remote share, we send the correct remote instance and the remote share id
110-
if ($remoteShare?->isBounce() === true) {
111-
return new DataResponse($remoteShare, Http::STATUS_MOVED_PERMANENTLY);
104+
try {
105+
return new DataResponse($this->globalShareService->getSharedFiles($fileId, $shareId, $instance, $target));
106+
} catch (SharedFileException $e) {
107+
return new DataResponse(['message' => $e->getMessage()], Http::STATUS_NOT_FOUND);
108+
} catch (LocalFederatedShareException $e) {
109+
return new DataResponse($e->getFederatedShare(), Http::STATUS_MOVED_PERMANENTLY);
112110
}
113-
114-
// mount point is local, we return the list of shares between the remote instance and the related files
115-
return new DataResponse($this->globalShareService->getFederatedSharesRelatedToRemoteInstance($files, $instance));
116111
}
117112

118113

lib/Db/FileRequest.php

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
77
* SPDX-License-Identifier: AGPL-3.0-or-later
88
*/
9+
910
namespace OCA\GlobalSiteSelector\Db;
1011

1112
use OCA\GlobalSiteSelector\Model\FederatedShare;
@@ -72,8 +73,8 @@ public function getMountFromTarget(LocalFile $target): ?LocalMount {
7273

7374
$mount = new LocalMount();
7475
$mount->setProviderClass($row['mount_provider_class'])
75-
->setMountPoint(rtrim(explode('/files', $row['mount_point'], 2)[1] ?? '', '/'))
76-
->setUserId($row['user_id']);
76+
->setMountPoint(rtrim(explode('/files', $row['mount_point'], 2)[1] ?? '', '/'))
77+
->setUserId($row['user_id']);
7778

7879
$result->closeCursor();
7980

@@ -103,11 +104,10 @@ public function getFilesFromExternalShareStorage(string $storageKey): int {
103104
return $fileId ?? 0;
104105
}
105106

106-
107107
/**
108108
* returns the storage key related to federated share from share_external
109109
*/
110-
public function getFederatedShareStorageKey(FederatedShare $federatedShare, string $instance): string {
110+
public function getFederatedShareStorageKey(FederatedShare $federatedShare, string $instance): ?string {
111111
$qb = $this->connection->getQueryBuilder();
112112
$qb->select('share_token', 'owner', 'remote')
113113
->from('share_external')
@@ -121,6 +121,9 @@ public function getFederatedShareStorageKey(FederatedShare $federatedShare, stri
121121

122122
$result = $qb->executeQuery();
123123
$row = $result->fetch();
124+
if ($row === false) {
125+
return null;
126+
}
124127
$cloudId = $this->cloudIdManager->getCloudId($row['owner'], $row['remote']);
125128
$storage = 'shared::' . md5($row['share_token'] . '@' . $cloudId->getRemote());
126129
$result->closeCursor();
@@ -131,7 +134,7 @@ public function getFederatedShareStorageKey(FederatedShare $federatedShare, stri
131134
/**
132135
* returns the storage key related to a federated share from circles_mount
133136
*/
134-
public function getTeamStorages(FederatedShare $federatedShare, string $instance): string {
137+
public function getTeamStorages(FederatedShare $federatedShare, string $instance): ?string {
135138
$qb = $this->connection->getQueryBuilder();
136139
$qb->select('token', 'remote')
137140
->from('circles_mount')
@@ -145,10 +148,38 @@ public function getTeamStorages(FederatedShare $federatedShare, string $instance
145148

146149
$result = $qb->executeQuery();
147150
$row = $result->fetch();
148-
// store md5 into circles_mount table
151+
if ($row === false) {
152+
return null;
153+
}
154+
// why not storing md5 into circles_mount ?
149155
$storage = 'shared::' . md5($row['token'] . '@https://' . $row['remote']);
150156
$result->closeCursor();
151157

152158
return $storage;
153159
}
160+
161+
public function getFederatedTeamMount(LocalMount $mount, array $teamIds): ?FederatedShare {
162+
$qb = $this->connection->getQueryBuilder();
163+
$qb->select('remote', 'remote_id')
164+
->from('circles_mount')
165+
->where(
166+
$qb->expr()->eq('mountpoint_hash', $qb->createNamedParameter(md5($mount->getMountPoint()))),
167+
$qb->expr()->in('circle_id', $qb->createNamedParameter($teamIds, IQueryBuilder::PARAM_STR_ARRAY)),
168+
);
169+
170+
$result = $qb->executeQuery();
171+
$row = $result->fetch();
172+
if ($row === false || ($row['remote'] ?? '') === '') {
173+
return null;
174+
}
175+
176+
$federatedShare = new FederatedShare();
177+
$federatedShare->setRemote($row['remote'])
178+
->setRemoteId($row['remote_id'])
179+
->setBounce(true);
180+
181+
$result->closeCursor();
182+
183+
return $federatedShare;
184+
}
154185
}

lib/Db/ShareRequest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,9 @@ public function getFederatedSharesRelatedToRemoteInstance(array $files, string $
7676
}
7777

7878
/**
79-
* return fileId and owner about a file.
79+
* return id and owner about a file.
8080
*
81-
* @return array{int, string}
81+
* @return array{int, string} [fileId, fileOwner]
8282
*/
8383
public function getFileOwnerFromShareId(int $shareId): array {
8484
$qb = $this->connection->getQueryBuilder();
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
10+
namespace OCA\GlobalSiteSelector\Exceptions;
11+
12+
use Exception;
13+
use OCA\GlobalSiteSelector\Model\FederatedShare;
14+
15+
class SharedFileException extends Exception {
16+
}

lib/Listeners/InternalLinkRequested.php

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
namespace OCA\GlobalSiteSelector\Listeners;
1111

12+
use OCA\GlobalSiteSelector\Exceptions\LocalFederatedShareException;
13+
use OCA\GlobalSiteSelector\Exceptions\SharedFileException;
1214
use OCA\GlobalSiteSelector\GlobalSiteSelector;
1315
use OCA\GlobalSiteSelector\Service\GlobalScaleService;
1416
use OCA\GlobalSiteSelector\Service\GlobalShareService;
@@ -22,8 +24,6 @@
2224
* @template-implements IEventListener<InternalLinkRequestEvent>
2325
*/
2426
class InternalLinkRequested implements IEventListener {
25-
private ?string $currentUser = null;
26-
2727
public function __construct(
2828
private readonly IUserSession $userSession,
2929
private readonly GlobalSiteSelector $gss,
@@ -50,18 +50,39 @@ public function handle(Event $event): void {
5050
return;
5151
}
5252

53+
$currentUser = $this->userSession->getUser()?->getUID();
54+
// There is no valid reason for getUser() to be null,
55+
if ($currentUser === null) {
56+
$this->logger->warning('internal link request', ['exception' => new \Exception('could not assign current user')]);
57+
return;
58+
}
59+
5360
[$token, $newFileId] = explode('.', $fileId);
5461
// if token represents the local instance, fall back to normal behavior using file id
5562
if ($this->globalScaleService->isLocalToken($token)) {
56-
$event->setNewFileId($newFileId);
57-
return;
58-
}
63+
try {
64+
$this->globalShareService->getSharedFiles((int)$newFileId);
65+
$event->setNewFileId((string)$newFileId);
66+
return;
67+
} catch (SharedFileException $e) {
68+
$event->setNewFileId('1');
69+
return;
70+
} catch (LocalFederatedShareException $e) {
71+
// must bne ignored, meaning that while link is local, file is not local
5972

60-
$this->currentUser = $this->userSession->getUser()?->getUID();
61-
// There is no valid reason for getUser() to be null,
62-
if ($this->currentUser === null) {
63-
$this->logger->warning('internal link request', ['exception' => new \Exception('could not assign current user')]);
64-
return;
73+
$federatedShare = $e->getFederatedShare();
74+
$remote = $federatedShare->getRemote();
75+
76+
// this should never be the case
77+
if (!$federatedShare->isBounce() || $this->globalScaleService->isLocalAddress($remote)) {
78+
$event->setNewFileId('1');
79+
return;
80+
}
81+
82+
$federatedShares = $this->globalShareService->requestRemoteFederatedShares($remote, ['shareId' => $federatedShare->getRemoteId(), 'target' => $federatedShare->getTarget()?->jsonSerialize() ?? []], true);
83+
$event->setNewFileId((string)$this->globalShareService->getLastFileIdFromShares($currentUser, $federatedShares, $remote));
84+
return;
85+
}
6586
}
6687

6788
// extract instance linked to token

0 commit comments

Comments
 (0)