mirror of
https://github.com/LibreSign/libresign.git
synced 2025-12-18 05:20:45 +01:00
fix: restrict access to validation endpoints
- Created the attribute PrivateValidation to restrict access to public endpoints when this is enabled at administration settings. - Added the attribute PrivateValidation to all endpoints that have /validation/ at path. Signed-off-by: Vitor Mattos <vitor@php.rio>
This commit is contained in:
parent
85e3bd2e97
commit
b4c12293ce
5 changed files with 73 additions and 33 deletions
|
|
@ -16,6 +16,7 @@ use OCA\Libresign\Db\SignRequestMapper;
|
|||
use OCA\Libresign\Exception\LibresignException;
|
||||
use OCA\Libresign\Helper\JSActions;
|
||||
use OCA\Libresign\Helper\ValidateHelper;
|
||||
use OCA\Libresign\Middleware\Attribute\PrivateValidation;
|
||||
use OCA\Libresign\Middleware\Attribute\RequireManager;
|
||||
use OCA\Libresign\ResponseDefinitions;
|
||||
use OCA\Libresign\Service\AccountService;
|
||||
|
|
@ -85,6 +86,7 @@ class FileController extends AEnvironmentAwareController {
|
|||
* 404: Request failed
|
||||
* 422: Request failed
|
||||
*/
|
||||
#[PrivateValidation]
|
||||
#[NoAdminRequired]
|
||||
#[NoCSRFRequired]
|
||||
#[PublicPage]
|
||||
|
|
@ -105,6 +107,7 @@ class FileController extends AEnvironmentAwareController {
|
|||
* 404: Request failed
|
||||
* 422: Request failed
|
||||
*/
|
||||
#[PrivateValidation]
|
||||
#[NoAdminRequired]
|
||||
#[NoCSRFRequired]
|
||||
#[PublicPage]
|
||||
|
|
@ -125,6 +128,7 @@ class FileController extends AEnvironmentAwareController {
|
|||
* 404: Request failed
|
||||
* 400: Request failed
|
||||
*/
|
||||
#[PrivateValidation]
|
||||
#[NoAdminRequired]
|
||||
#[NoCSRFRequired]
|
||||
#[PublicPage]
|
||||
|
|
@ -174,6 +178,7 @@ class FileController extends AEnvironmentAwareController {
|
|||
* 404: Request failed
|
||||
* 422: Request failed
|
||||
*/
|
||||
#[PrivateValidation]
|
||||
#[NoAdminRequired]
|
||||
#[NoCSRFRequired]
|
||||
#[PublicPage]
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ use OCA\Libresign\AppInfo\Application;
|
|||
use OCA\Libresign\Exception\LibresignException;
|
||||
use OCA\Libresign\Helper\JSActions;
|
||||
use OCA\Libresign\Helper\ValidateHelper;
|
||||
use OCA\Libresign\Middleware\Attribute\PrivateValidation;
|
||||
use OCA\Libresign\Middleware\Attribute\RequireSetupOk;
|
||||
use OCA\Libresign\Middleware\Attribute\RequireSignRequestUuid;
|
||||
use OCA\Libresign\Service\AccountService;
|
||||
|
|
@ -273,6 +274,7 @@ class PageController extends AEnvironmentPageAwareController {
|
|||
*
|
||||
* 200: OK
|
||||
*/
|
||||
#[PrivateValidation]
|
||||
#[NoAdminRequired]
|
||||
#[NoCSRFRequired]
|
||||
#[RequireSetupOk]
|
||||
|
|
@ -280,7 +282,6 @@ class PageController extends AEnvironmentPageAwareController {
|
|||
#[RequireSignRequestUuid]
|
||||
#[FrontpageRoute(verb: 'GET', url: '/p/sign/{uuid}')]
|
||||
public function sign(string $uuid): TemplateResponse {
|
||||
$this->throwIfValidationPageNotAccessible();
|
||||
$this->initialState->provideInitialState('action', JSActions::ACTION_SIGN);
|
||||
$this->initialState->provideInitialState('config',
|
||||
$this->accountService->getConfig($this->userSession->getUser())
|
||||
|
|
@ -407,6 +408,7 @@ class PageController extends AEnvironmentPageAwareController {
|
|||
* 401: Validation page not accessible if unauthenticated
|
||||
* 404: File not found
|
||||
*/
|
||||
#[PrivateValidation]
|
||||
#[NoAdminRequired]
|
||||
#[NoCSRFRequired]
|
||||
#[RequireSetupOk]
|
||||
|
|
@ -414,7 +416,6 @@ class PageController extends AEnvironmentPageAwareController {
|
|||
#[AnonRateLimit(limit: 30, period: 60)]
|
||||
#[FrontpageRoute(verb: 'GET', url: '/p/pdf/{uuid}')]
|
||||
public function getPdf($uuid) {
|
||||
$this->throwIfValidationPageNotAccessible();
|
||||
try {
|
||||
$file = $this->accountService->getPdfByUuid($uuid);
|
||||
} catch (DoesNotExistException $th) {
|
||||
|
|
@ -433,6 +434,7 @@ class PageController extends AEnvironmentPageAwareController {
|
|||
* 200: OK
|
||||
* 401: Validation page not accessible if unauthenticated
|
||||
*/
|
||||
#[PrivateValidation]
|
||||
#[NoAdminRequired]
|
||||
#[NoCSRFRequired]
|
||||
#[RequireSignRequestUuid]
|
||||
|
|
@ -441,7 +443,6 @@ class PageController extends AEnvironmentPageAwareController {
|
|||
#[AnonRateLimit(limit: 30, period: 60)]
|
||||
#[FrontpageRoute(verb: 'GET', url: '/pdf/{uuid}')]
|
||||
public function getPdfFile($uuid): FileDisplayResponse {
|
||||
$this->throwIfValidationPageNotAccessible();
|
||||
$file = $this->getNextcloudFile();
|
||||
return new FileDisplayResponse($file, Http::STATUS_OK, ['Content-Type' => $file->getMimeType()]);
|
||||
}
|
||||
|
|
@ -454,6 +455,7 @@ class PageController extends AEnvironmentPageAwareController {
|
|||
* 200: OK
|
||||
* 401: Validation page not accessible if unauthenticated
|
||||
*/
|
||||
#[PrivateValidation]
|
||||
#[NoAdminRequired]
|
||||
#[NoCSRFRequired]
|
||||
#[RequireSetupOk(template: 'validation')]
|
||||
|
|
@ -461,7 +463,6 @@ class PageController extends AEnvironmentPageAwareController {
|
|||
#[AnonRateLimit(limit: 30, period: 60)]
|
||||
#[FrontpageRoute(verb: 'GET', url: '/p/validation')]
|
||||
public function validation(): TemplateResponse {
|
||||
$this->throwIfValidationPageNotAccessible();
|
||||
if ($this->getFileEntity()) {
|
||||
$this->initialState->provideInitialState('config',
|
||||
$this->accountService->getConfig($this->userSession->getUser())
|
||||
|
|
@ -500,6 +501,7 @@ class PageController extends AEnvironmentPageAwareController {
|
|||
* 303: Redirected to validation page
|
||||
* 401: Validation page not accessible if unauthenticated
|
||||
*/
|
||||
#[PrivateValidation]
|
||||
#[NoAdminRequired]
|
||||
#[NoCSRFRequired]
|
||||
#[RequireSetupOk]
|
||||
|
|
@ -507,7 +509,6 @@ class PageController extends AEnvironmentPageAwareController {
|
|||
#[AnonRateLimit(limit: 30, period: 60)]
|
||||
#[FrontpageRoute(verb: 'GET', url: '/validation/{uuid}')]
|
||||
public function validationFileWithShortUrl(): TemplateResponse {
|
||||
$this->throwIfValidationPageNotAccessible();
|
||||
return $this->validationFilePublic($this->request->getParam('uuid'));
|
||||
}
|
||||
|
||||
|
|
@ -545,6 +546,7 @@ class PageController extends AEnvironmentPageAwareController {
|
|||
* 200: OK
|
||||
* 401: Validation page not accessible if unauthenticated
|
||||
*/
|
||||
#[PrivateValidation]
|
||||
#[NoAdminRequired]
|
||||
#[NoCSRFRequired]
|
||||
#[RequireSetupOk(template: 'validation')]
|
||||
|
|
@ -552,7 +554,6 @@ class PageController extends AEnvironmentPageAwareController {
|
|||
#[AnonRateLimit(limit: 30, period: 60)]
|
||||
#[FrontpageRoute(verb: 'GET', url: '/p/validation/{uuid}')]
|
||||
public function validationFilePublic(string $uuid): TemplateResponse {
|
||||
$this->throwIfValidationPageNotAccessible();
|
||||
try {
|
||||
$this->signFileService->getFileByUuid($uuid);
|
||||
$this->fileService->setFileByType('uuid', $uuid);
|
||||
|
|
@ -599,31 +600,4 @@ class PageController extends AEnvironmentPageAwareController {
|
|||
|
||||
return $response;
|
||||
}
|
||||
|
||||
private function throwIfValidationPageNotAccessible(): void {
|
||||
$isValidationUrlPrivate = (bool)$this->appConfig->getValueBool(Application::APP_ID, 'make_validation_url_private', false);
|
||||
if ($this->userSession->isLoggedIn()) {
|
||||
return;
|
||||
}
|
||||
if ($isValidationUrlPrivate) {
|
||||
if ($uuid = $this->request->getParam('uuid')) {
|
||||
$redirectUrl = $this->urlGenerator->linkToRoute(
|
||||
'libresign.page.validationFilePublic',
|
||||
['uuid' => $uuid]
|
||||
);
|
||||
} else {
|
||||
$redirectUrl = $this->urlGenerator->linkToRoute(
|
||||
'libresign.page.validation',
|
||||
);
|
||||
}
|
||||
|
||||
throw new LibresignException(json_encode([
|
||||
'action' => JSActions::ACTION_REDIRECT,
|
||||
'errors' => [$this->l10n->t('You are not logged in. Please log in.')],
|
||||
'redirect' => $this->urlGenerator->linkToRoute('core.login.showLoginForm', [
|
||||
'redirect_url' => $redirectUrl,
|
||||
]),
|
||||
]), Http::STATUS_UNAUTHORIZED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
15
lib/Middleware/Attribute/PrivateValidation.php
Normal file
15
lib/Middleware/Attribute/PrivateValidation.php
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2025 LibreCode coop and contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace OCA\Libresign\Middleware\Attribute;
|
||||
|
||||
use Attribute;
|
||||
|
||||
#[Attribute]
|
||||
class PrivateValidation {
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@ use OCA\Libresign\Handler\CertificateEngine\Handler as CertificateEngineHandler;
|
|||
use OCA\Libresign\Helper\JSActions;
|
||||
use OCA\Libresign\Helper\ValidateHelper;
|
||||
use OCA\Libresign\Middleware\Attribute\CanSignRequestUuid;
|
||||
use OCA\Libresign\Middleware\Attribute\PrivateValidation;
|
||||
use OCA\Libresign\Middleware\Attribute\RequireManager;
|
||||
use OCA\Libresign\Middleware\Attribute\RequireSetupOk;
|
||||
use OCA\Libresign\Middleware\Attribute\RequireSigner;
|
||||
|
|
@ -35,9 +36,11 @@ use OCP\AppFramework\Http\Response;
|
|||
use OCP\AppFramework\Http\TemplateResponse;
|
||||
use OCP\AppFramework\Middleware;
|
||||
use OCP\AppFramework\Services\IInitialState;
|
||||
use OCP\IAppConfig;
|
||||
use OCP\IL10N;
|
||||
use OCP\IRequest;
|
||||
use OCP\ISession;
|
||||
use OCP\IURLGenerator;
|
||||
use OCP\IUser;
|
||||
use OCP\IUserSession;
|
||||
use OCP\Util;
|
||||
|
|
@ -56,6 +59,8 @@ class InjectionMiddleware extends Middleware {
|
|||
private IInitialState $initialState,
|
||||
private SignFileService $signFileService,
|
||||
private IL10N $l10n,
|
||||
private IAppConfig $appConfig,
|
||||
private IURLGenerator $urlGenerator,
|
||||
?string $userId,
|
||||
) {
|
||||
$this->request = $request;
|
||||
|
|
@ -87,6 +92,39 @@ class InjectionMiddleware extends Middleware {
|
|||
$this->requireSetupOk($reflectionMethod);
|
||||
|
||||
$this->handleUuid($controller, $reflectionMethod);
|
||||
|
||||
$this->privateValidation($reflectionMethod);
|
||||
}
|
||||
|
||||
private function privateValidation(\ReflectionMethod $reflectionMethod): void {
|
||||
if (empty($reflectionMethod->getAttributes(PrivateValidation::class))) {
|
||||
return;
|
||||
}
|
||||
if ($this->userSession->isLoggedIn()) {
|
||||
return;
|
||||
}
|
||||
$isValidationUrlPrivate = (bool)$this->appConfig->getValueBool(Application::APP_ID, 'make_validation_url_private', false);
|
||||
if (!$isValidationUrlPrivate) {
|
||||
return;
|
||||
}
|
||||
if ($uuid = $this->request->getParam('uuid')) {
|
||||
$redirectUrl = $this->urlGenerator->linkToRoute(
|
||||
'libresign.page.validationFilePublic',
|
||||
['uuid' => $uuid]
|
||||
);
|
||||
} else {
|
||||
$redirectUrl = $this->urlGenerator->linkToRoute(
|
||||
'libresign.page.validation',
|
||||
);
|
||||
}
|
||||
|
||||
throw new LibresignException(json_encode([
|
||||
'action' => JSActions::ACTION_REDIRECT,
|
||||
'errors' => [$this->l10n->t('You are not logged in. Please log in.')],
|
||||
'redirect' => $this->urlGenerator->linkToRoute('core.login.showLoginForm', [
|
||||
'redirect_url' => $redirectUrl,
|
||||
]),
|
||||
]), Http::STATUS_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
private function handleUuid(Controller $controller, \ReflectionMethod $reflectionMethod): void {
|
||||
|
|
|
|||
|
|
@ -18,10 +18,12 @@ use OCP\AppFramework\Http\JSONResponse;
|
|||
use OCP\AppFramework\Http\RedirectResponse;
|
||||
use OCP\AppFramework\Http\TemplateResponse;
|
||||
use OCP\AppFramework\Services\IInitialState;
|
||||
use OCP\IAppConfig;
|
||||
use OCP\IL10N;
|
||||
use OCP\IRequest;
|
||||
use OCP\IServerContainer;
|
||||
use OCP\ISession;
|
||||
use OCP\IURLGenerator;
|
||||
use OCP\IUserSession;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
|
@ -42,6 +44,8 @@ final class InjectionMiddlewareTest extends \OCA\Libresign\Tests\Unit\TestCase {
|
|||
private IInitialState $initialState;
|
||||
private SignFileService&MockObject $signFileService;
|
||||
private IL10N&MockObject $l10n;
|
||||
private IappConfig&MockObject $appConfig;
|
||||
private IurlGenerator&MockObject $urlGenerator;
|
||||
private ?string $userId;
|
||||
|
||||
private InitialStateService $initialStateService;
|
||||
|
|
@ -54,6 +58,8 @@ final class InjectionMiddlewareTest extends \OCA\Libresign\Tests\Unit\TestCase {
|
|||
$this->signRequestMapper = $this->createMock(SignRequestMapper::class);
|
||||
$this->certificateEngineHandler = $this->createMock(CertificateEngineHandler::class);
|
||||
$this->fileMapper = $this->createMock(FileMapper::class);
|
||||
$this->appConfig = $this->createMock(IAppConfig::class);
|
||||
$this->urlGenerator = $this->createMock(IURLGenerator::class);
|
||||
|
||||
$this->initialStateService = new InitialStateService(
|
||||
$this->createMock(LoggerInterface::class),
|
||||
|
|
@ -78,6 +84,8 @@ final class InjectionMiddlewareTest extends \OCA\Libresign\Tests\Unit\TestCase {
|
|||
$this->initialState,
|
||||
$this->signFileService,
|
||||
$this->l10n,
|
||||
$this->appConfig,
|
||||
$this->urlGenerator,
|
||||
$this->userId,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue