Skip to content

Commit feb8460

Browse files
feat(cloud_federation_api): support multi-protocol share creation
Co-authored-by: Micke Nordin <kano@sunet.se> Signed-off-by: Micke Nordin <kano@sunet.se> Signed-off-by: Enrique Pérez Arnaud <enrique@cazalla.net>
1 parent 65059fc commit feb8460

1 file changed

Lines changed: 42 additions & 5 deletions

File tree

apps/cloud_federation_api/lib/Controller/RequestHandlerController.php

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@
77

88
namespace OCA\CloudFederationAPI\Controller;
99

10+
use OC\Authentication\Token\PublicKeyTokenProvider;
1011
use OC\OCM\OCMSignatoryManager;
1112
use OCA\CloudFederationAPI\Config;
1213
use OCA\CloudFederationAPI\Db\FederatedInviteMapper;
14+
use OCA\CloudFederationAPI\Db\OcmTokenMapMapper;
1315
use OCA\CloudFederationAPI\Events\FederatedInviteAcceptedEvent;
1416
use OCA\CloudFederationAPI\ResponseDefinitions;
1517
use OCP\AppFramework\Controller;
@@ -39,6 +41,7 @@
3941
use OCP\OCM\IOCMDiscoveryService;
4042
use OCP\Security\Signature\Exceptions\IncomingRequestException;
4143
use OCP\Security\Signature\IIncomingSignedRequest;
44+
use OCP\Server;
4245
use OCP\Share\Exceptions\ShareNotFound;
4346
use OCP\Util;
4447
use Psr\Log\LoggerInterface;
@@ -85,7 +88,7 @@ public function __construct(
8588
* @param string|null $ownerDisplayName Display name of the user who shared the item
8689
* @param string|null $sharedBy Provider specific UID of the user who shared the resource
8790
* @param string|null $sharedByDisplayName Display name of the user who shared the resource
88-
* @param array{name: list<string>, options: array<string, mixed>} $protocol e,.g. ['name' => 'webdav', 'options' => ['username' => 'john', 'permissions' => 31]]
91+
* @param array{name: string, options?: array<string, mixed>, webdav?: array<string, mixed>} $protocol Old format: ['name' => 'webdav', 'options' => ['sharedSecret' => '...', 'permissions' => '...']] or New format: ['name' => 'webdav', 'webdav' => ['uri' => '...', 'sharedSecret' => '...', 'permissions' => [...]]] or Multi format: ['name' => 'multi', 'webdav' => [...]]
8992
* @param string $shareType 'group' or 'user' share
9093
* @param string $resourceType 'file', 'calendar',...
9194
*
@@ -120,9 +123,6 @@ public function addShare($shareWith, $name, $description, $providerId, $owner, $
120123
|| $shareType === null
121124
|| !is_array($protocol)
122125
|| !isset($protocol['name'])
123-
|| !isset($protocol['options'])
124-
|| !is_array($protocol['options'])
125-
|| !isset($protocol['options']['sharedSecret'])
126126
) {
127127
return new JSONResponse(
128128
[
@@ -133,6 +133,33 @@ public function addShare($shareWith, $name, $description, $providerId, $owner, $
133133
);
134134
}
135135

136+
$protocolName = $protocol['name'];
137+
$hasOldFormat = isset($protocol['options']) && is_array($protocol['options']) && isset($protocol['options']['sharedSecret']);
138+
$hasNewFormat = isset($protocol[$protocolName]) && is_array($protocol[$protocolName]) && isset($protocol[$protocolName]['sharedSecret']);
139+
140+
// For multi-protocol, we only consider webdav
141+
$hasMultiFormat = false;
142+
if ($protocolName === 'multi') {
143+
if (isset($protocol['webdav']) && is_array($protocol['webdav']) && isset($protocol['webdav']['sharedSecret'])) {
144+
$hasMultiFormat = true;
145+
$protocol = [
146+
'name' => 'webdav',
147+
'webdav' => $protocol['webdav']
148+
];
149+
$protocolName = 'webdav';
150+
}
151+
}
152+
153+
if (!$hasOldFormat && !$hasNewFormat && !$hasMultiFormat) {
154+
return new JSONResponse(
155+
[
156+
'message' => 'Missing sharedSecret in protocol',
157+
'validationErrors' => [],
158+
],
159+
Http::STATUS_BAD_REQUEST
160+
);
161+
}
162+
136163
$supportedShareTypes = $this->config->getSupportedShareTypes($resourceType);
137164
if (!in_array($shareType, $supportedShareTypes)) {
138165
return new JSONResponse(
@@ -142,6 +169,7 @@ public function addShare($shareWith, $name, $description, $providerId, $owner, $
142169
}
143170

144171
$cloudId = $this->cloudIdManager->resolveCloudId($shareWith);
172+
$shareWithCloudId = $shareWith; // preserve full cloud ID for factory capability discovery
145173
$shareWith = $cloudId->getUser();
146174

147175
if ($shareType === 'user') {
@@ -186,7 +214,10 @@ public function addShare($shareWith, $name, $description, $providerId, $owner, $
186214

187215
try {
188216
$provider = $this->cloudFederationProviderManager->getCloudFederationProvider($resourceType);
189-
$share = $this->factory->getCloudFederationShare($shareWith, $name, $description, $providerId, $owner, $ownerDisplayName, $sharedBy, $sharedByDisplayName, '', $shareType, $resourceType);
217+
// Pass the original cloud ID so the factory can discover capabilities without warning.
218+
// Then reset shareWith to the local username that shareReceived() needs for user lookup.
219+
$share = $this->factory->getCloudFederationShare($shareWithCloudId, $name, $description, $providerId, $owner, $ownerDisplayName, $sharedBy, $sharedByDisplayName, '', $shareType, $resourceType);
220+
$share->setShareWith($shareWith);
190221
$share->setProtocol($protocol);
191222
$provider->shareReceived($share);
192223
} catch (ProviderDoesNotExistsException|ProviderCouldNotAddShareException $e) {
@@ -478,6 +509,12 @@ private function confirmNotificationIdentity(
478509
$provider = $this->cloudFederationProviderManager->getCloudFederationProvider($resourceType);
479510
if ($provider instanceof ISignedCloudFederationProvider || $provider instanceof \NCU\Federation\ISignedCloudFederationProvider) {
480511
$identity = $provider->getFederationIdFromSharedSecret($sharedSecret, $notification);
512+
if ($identity === '') {
513+
$tokenProvider = Server::get(PublicKeyTokenProvider::class);
514+
$accessTokenDb = $tokenProvider->getToken($sharedSecret);
515+
$mapping = Server::get(OcmTokenMapMapper::class)->getByAccessTokenId($accessTokenDb->getId());
516+
$identity = $provider->getFederationIdFromSharedSecret($mapping->getRefreshToken(), $notification);
517+
}
481518
} else {
482519
$this->logger->debug('cloud federation provider {provider} does not implements ISignedCloudFederationProvider', ['provider' => $provider::class]);
483520
return;

0 commit comments

Comments
 (0)