You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
nextcloud-server/apps/cloud_federation_api/lib/Controller/OCMRequestController.php

87 lines
2.9 KiB

<?php
declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCA\CloudFederationAPI\Controller;
use JsonException;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\BruteForceProtection;
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
use OCP\AppFramework\Http\Attribute\PublicPage;
use OCP\AppFramework\Http\JSONResponse;
use OCP\AppFramework\Http\Response;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IRequest;
use OCP\OCM\Events\OCMEndpointRequestEvent;
use OCP\OCM\Exceptions\OCMArgumentException;
use OCP\OCM\IOCMDiscoveryService;
use OCP\Security\Signature\Exceptions\IncomingRequestException;
use Psr\Log\LoggerInterface;
class OCMRequestController extends Controller {
public function __construct(
string $appName,
IRequest $request,
private readonly IEventDispatcher $eventDispatcher,
private readonly IOCMDiscoveryService $ocmDiscoveryService,
private readonly LoggerInterface $logger,
) {
parent::__construct($appName, $request);
}
/**
* Method will catch any request done to /ocm/[...] and will broadcast an event.
* The first parameter of the remaining subpath (post-/ocm/) is defined as
* capability and should be used by listeners to filter incoming requests.
*
* @see OCMEndpointRequestEvent
* @see OCMEndpointRequestEvent::getArgs
*
* @param string $ocmPath
* @return Response
* @throws OCMArgumentException
*/
#[NoCSRFRequired]
#[PublicPage]
#[BruteForceProtection(action: 'receiveOcmRequest')]
public function manageOCMRequests(string $ocmPath): Response {
if (!mb_check_encoding($ocmPath, 'UTF-8')) {
throw new OCMArgumentException('path is not UTF-8');
}
try {
// if request is signed and well signed, no exceptions are thrown
// if request is not signed and host is known for not supporting signed request, no exceptions are thrown
$signedRequest = $this->ocmDiscoveryService->getIncomingSignedRequest();
} catch (IncomingRequestException $e) {
$this->logger->warning('incoming ocm request exception', ['exception' => $e]);
return new JSONResponse(['message' => $e->getMessage(), 'validationErrors' => []], Http::STATUS_BAD_REQUEST);
}
// assuming that ocm request contains a json array
$payload = $signedRequest?->getBody() ?? file_get_contents('php://input');
try {
$payload = ($payload) ? json_decode($payload, true, 512, JSON_THROW_ON_ERROR) : null;
} catch (JsonException $e) {
$this->logger->debug('json decode error', ['exception' => $e]);
$payload = null;
}
$event = new OCMEndpointRequestEvent(
$this->request->getMethod(),
preg_replace('@/+@', '/', $ocmPath),
$payload,
$signedRequest?->getOrigin()
);
$this->eventDispatcher->dispatchTyped($event);
return $event->getResponse() ?? new Response(Http::STATUS_NOT_FOUND);
}
}