• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

LibreSign / libresign / 22321707196

23 Feb 2026 07:34PM UTC coverage: 52.905%. First build
22321707196

Pull #6993

github

web-flow
Merge a2226dbcd into 973e78682
Pull Request #6993: feat: vue3 typescript migration

1 of 9 new or added lines in 4 files covered. (11.11%)

9425 of 17815 relevant lines covered (52.9%)

6.38 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/lib/Controller/PageController.php
1
<?php
2

3
declare(strict_types=1);
4
/**
5
 * SPDX-FileCopyrightText: 2020-2024 LibreCode coop and contributors
6
 * SPDX-License-Identifier: AGPL-3.0-or-later
7
 */
8

9
namespace OCA\Libresign\Controller;
10

11
use OCA\Libresign\AppInfo\Application;
12
use OCA\Libresign\Db\FileMapper;
13
use OCA\Libresign\Db\SignRequestMapper;
14
use OCA\Libresign\Exception\LibresignException;
15
use OCA\Libresign\Helper\JSActions;
16
use OCA\Libresign\Helper\ValidateHelper;
17
use OCA\Libresign\Middleware\Attribute\PrivateValidation;
18
use OCA\Libresign\Middleware\Attribute\RequireSetupOk;
19
use OCA\Libresign\Middleware\Attribute\RequireSignRequestUuid;
20
use OCA\Libresign\Service\AccountService;
21
use OCA\Libresign\Service\DocMdp\ConfigService;
22
use OCA\Libresign\Service\File\FileListService;
23
use OCA\Libresign\Service\FileService;
24
use OCA\Libresign\Service\IdentifyMethod\SignatureMethod\TokenService;
25
use OCA\Libresign\Service\IdentifyMethodService;
26
use OCA\Libresign\Service\RequestSignatureService;
27
use OCA\Libresign\Service\SessionService;
28
use OCA\Libresign\Service\SignerElementsService;
29
use OCA\Libresign\Service\SignFileService;
30
use OCA\Viewer\Event\LoadViewer;
31
use OCP\AppFramework\Db\DoesNotExistException;
32
use OCP\AppFramework\Http;
33
use OCP\AppFramework\Http\Attribute\AnonRateLimit;
34
use OCP\AppFramework\Http\Attribute\FrontpageRoute;
35
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
36
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
37
use OCP\AppFramework\Http\Attribute\PublicPage;
38
use OCP\AppFramework\Http\ContentSecurityPolicy;
39
use OCP\AppFramework\Http\DataResponse;
40
use OCP\AppFramework\Http\FileDisplayResponse;
41
use OCP\AppFramework\Http\TemplateResponse;
42
use OCP\AppFramework\Services\IInitialState;
43
use OCP\EventDispatcher\IEventDispatcher;
44
use OCP\IAppConfig;
45
use OCP\IL10N;
46
use OCP\IRequest;
47
use OCP\IURLGenerator;
48
use OCP\IUserSession;
49
use OCP\Util;
50
use Psr\Log\LoggerInterface;
51

52
class PageController extends AEnvironmentPageAwareController {
53
        public function __construct(
54
                IRequest $request,
55
                protected IUserSession $userSession,
56
                private SessionService $sessionService,
57
                private IInitialState $initialState,
58
                private AccountService $accountService,
59
                protected SignFileService $signFileService,
60
                protected RequestSignatureService $requestSignatureService,
61
                private SignerElementsService $signerElementsService,
62
                protected IL10N $l10n,
63
                private IdentifyMethodService $identifyMethodService,
64
                private IAppConfig $appConfig,
65
                private FileService $fileService,
66
                private FileListService $fileListService,
67
                private FileMapper $fileMapper,
68
                private SignRequestMapper $signRequestMapper,
69
                private LoggerInterface $logger,
70
                private ValidateHelper $validateHelper,
71
                private IEventDispatcher $eventDispatcher,
72
                private IURLGenerator $urlGenerator,
73
                private ConfigService $docMdpConfigService,
74
        ) {
75
                parent::__construct(
×
76
                        request: $request,
×
77
                        signFileService: $signFileService,
×
78
                        l10n: $l10n,
×
79
                        userSession: $userSession,
×
80
                );
×
81
        }
82

83
        /**
84
         * Index page
85
         *
86
         * @return TemplateResponse<Http::STATUS_OK, array{}>
87
         *
88
         * 200: OK
89
         */
90
        #[NoAdminRequired]
91
        #[NoCSRFRequired]
92
        #[RequireSetupOk(template: 'main')]
93
        #[FrontpageRoute(verb: 'GET', url: '/')]
94
        public function index(): TemplateResponse {
95
                $this->initialState->provideInitialState('config', $this->accountService->getConfig($this->userSession->getUser()));
×
96
                $this->initialState->provideInitialState('filters', $this->accountService->getConfigFilters($this->userSession->getUser()));
×
97
                $this->initialState->provideInitialState('sorting', $this->accountService->getConfigSorting($this->userSession->getUser()));
×
98
                $this->initialState->provideInitialState('certificate_engine', $this->accountService->getCertificateEngineName());
×
99

100
                try {
101
                        $this->validateHelper->canRequestSign($this->userSession->getUser());
×
102
                        $this->initialState->provideInitialState('can_request_sign', true);
×
103
                } catch (LibresignException) {
×
104
                        $this->initialState->provideInitialState('can_request_sign', false);
×
105
                }
106

107
                $this->provideSignerSignatues();
×
108
                $this->initialState->provideInitialState('identify_methods', $this->identifyMethodService->getIdentifyMethodsSettings());
×
109
                $this->initialState->provideInitialState('signature_flow', $this->appConfig->getValueString(Application::APP_ID, 'signature_flow', \OCA\Libresign\Enum\SignatureFlow::NONE->value));
×
110
                $this->initialState->provideInitialState('docmdp_config', $this->docMdpConfigService->getConfig());
×
111
                $this->initialState->provideInitialState('legal_information', $this->appConfig->getValueString(Application::APP_ID, 'legal_information'));
×
112

113
                Util::addScript(Application::APP_ID, 'libresign-main');
×
NEW
114
                Util::addStyle(Application::APP_ID, 'libresign-main');
×
115

116
                if (class_exists(LoadViewer::class)) {
×
117
                        $this->eventDispatcher->dispatchTyped(new LoadViewer());
×
118
                }
119

120
                $response = new TemplateResponse(Application::APP_ID, 'main');
×
121

122
                $policy = new ContentSecurityPolicy();
×
123
                $policy->allowEvalScript(true);
×
124
                $policy->addAllowedFrameDomain('\'self\'');
×
125
                $response->setContentSecurityPolicy($policy);
×
126

127
                return $response;
×
128
        }
129

130
        /**
131
         * Index page to authenticated users
132
         *
133
         * This router is used to be possible render pages with /f/, is a
134
         * workaround at frontend side to identify pages with authenticated accounts
135
         *
136
         * @return TemplateResponse<Http::STATUS_OK, array{}>
137
         *
138
         * 200: OK
139
         */
140
        #[NoAdminRequired]
141
        #[NoCSRFRequired]
142
        #[RequireSetupOk(template: 'main')]
143
        #[FrontpageRoute(verb: 'GET', url: '/f/')]
144
        public function indexF(): TemplateResponse {
145
                return $this->index();
×
146
        }
147

148
        /**
149
         * Incomplete page
150
         *
151
         * @return TemplateResponse<Http::STATUS_OK, array{}>
152
         *
153
         * 200: OK
154
         */
155
        #[NoAdminRequired]
156
        #[NoCSRFRequired]
157
        #[FrontpageRoute(verb: 'GET', url: '/f/incomplete')]
158
        public function incomplete(): TemplateResponse {
159
                Util::addScript(Application::APP_ID, 'libresign-main');
×
NEW
160
                Util::addStyle(Application::APP_ID, 'libresign-main');
×
161
                $response = new TemplateResponse(Application::APP_ID, 'main');
×
162
                return $response;
×
163
        }
164

165
        /**
166
         * Incomplete page in full screen
167
         *
168
         * @return TemplateResponse<Http::STATUS_OK, array{}>
169
         *
170
         * 200: OK
171
         */
172
        #[PublicPage]
173
        #[NoCSRFRequired]
174
        #[FrontpageRoute(verb: 'GET', url: '/p/incomplete')]
175
        public function incompleteP(): TemplateResponse {
NEW
176
                Util::addScript(Application::APP_ID, 'libresign-main');                Util::addStyle(Application::APP_ID, 'libresign-main');                $response = new TemplateResponse(Application::APP_ID, 'main', [], TemplateResponse::RENDER_AS_BASE);
×
177
                return $response;
×
178
        }
179

180
        /**
181
         * Main page to authenticated signer with a path
182
         *
183
         * The path is used only by frontend
184
         *
185
         * @param string $path The path that was sent from frontend
186
         * @return TemplateResponse<Http::STATUS_OK, array{}>
187
         *
188
         * 200: OK
189
         */
190
        #[NoAdminRequired]
191
        #[NoCSRFRequired]
192
        #[RequireSetupOk(template: 'main')]
193
        #[FrontpageRoute(verb: 'GET', url: '/f/{path}', requirements: ['path' => '.+'])]
194
        public function indexFPath(string $path): TemplateResponse {
195
                if (preg_match('/validation\/(?<uuid>[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})$/', $path, $matches)) {
×
196
                        $signRequest = null;
×
197

198
                        try {
199
                                $this->fileService->setFileByUuid($matches['uuid']);
×
200
                        } catch (LibresignException) {
×
201
                                try {
202
                                        $this->fileService->setFileBySignerUuid($matches['uuid']);
×
203
                                        $signRequest = $this->signRequestMapper->getBySignerUuidAndUserId($matches['uuid']);
×
204
                                } catch (LibresignException) {
×
205
                                        throw new LibresignException(json_encode([
×
206
                                                'action' => JSActions::ACTION_DO_NOTHING,
×
207
                                                'errors' => [['message' => $this->l10n->t('Invalid UUID')]],
×
208
                                        ]), Http::STATUS_NOT_FOUND);
×
209
                                }
210
                        }
211

212
                        if ($signRequest) {
×
213
                                $this->fileService->setSignRequest($signRequest);
×
214
                        }
215

216
                        $this->initialState->provideInitialState('file_info',
×
217
                                $this->fileService
×
218
                                        ->setIdentifyMethodId($this->sessionService->getIdentifyMethodId())
×
219
                                        ->setHost($this->request->getServerHost())
×
220
                                        ->setMe($this->userSession->getUser())
×
221
                                        ->showVisibleElements()
×
222
                                        ->showSigners()
×
223
                                        ->showSettings()
×
224
                                        ->showMessages()
×
225
                                        ->showValidateFile()
×
226
                                        ->toArray()
×
227
                        );
×
228
                } elseif (preg_match('/sign\/(?<uuid>[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})/', $path, $matches)) {
×
229
                        try {
230
                                $signRequest = $this->signFileService->getSignRequestByUuid($matches['uuid']);
×
231
                                if ($signRequest->getStatusEnum() === \OCA\Libresign\Enum\SignRequestStatus::SIGNED) {
×
232
                                        $file = $this->signFileService->getFile($signRequest->getFileId());
×
233
                                        $redirectUrl = $this->urlGenerator->linkToRouteAbsolute('libresign.page.indexFPath', [
×
234
                                                'path' => 'validation/' . $file->getUuid(),
×
235
                                        ]);
×
236
                                        throw new LibresignException(json_encode([
×
237
                                                'action' => JSActions::ACTION_REDIRECT,
×
238
                                                'redirect' => $redirectUrl,
×
239
                                        ]), Http::STATUS_SEE_OTHER);
×
240
                                }
241
                                $file = $this->fileService
×
242
                                        ->setFile($this->signFileService->getFile($signRequest->getFileId()))
×
243
                                        ->setSignRequest($signRequest)
×
244
                                        ->setMe($this->userSession->getUser())
×
245
                                        ->showSettings()
×
246
                                        ->toArray();
×
247
                                $this->initialState->provideInitialState('needIdentificationDocuments', $file['settings']['needIdentificationDocuments'] ?? false);
×
248
                                $this->initialState->provideInitialState('identificationDocumentsWaitingApproval', $file['settings']['identificationDocumentsWaitingApproval'] ?? false);
×
249
                        } catch (LibresignException $e) {
×
250
                                throw $e;
×
251
                        } catch (\Throwable $e) {
×
252
                                throw new LibresignException(json_encode([
×
253
                                        'action' => JSActions::ACTION_DO_NOTHING,
×
254
                                        'errors' => [['message' => $this->l10n->t('Invalid UUID')]],
×
255
                                ]), Http::STATUS_NOT_FOUND);
×
256
                        }
257
                }
258
                return $this->index();
×
259
        }
260

261

262
        /**
263
         * Sign page to authenticated signer
264
         *
265
         * @param string $uuid Sign request uuid
266
         * @return TemplateResponse<Http::STATUS_OK, array{}>
267
         *
268
         * 200: OK
269
         */
270
        #[NoAdminRequired]
271
        #[NoCSRFRequired]
272
        #[RequireSetupOk]
273
        #[PublicPage]
274
        #[RequireSignRequestUuid(redirectIfSignedToValidation: true, allowIdDocs: true)]
275
        #[FrontpageRoute(verb: 'GET', url: '/f/sign/{uuid}')]
276
        public function signF(string $uuid): TemplateResponse {
277
                $this->initialState->provideInitialState('action', JSActions::ACTION_SIGN_INTERNAL);
×
278
                return $this->index();
×
279
        }
280

281
        /**
282
         * Sign page to authenticated signer with the path of file
283
         *
284
         * The path is used only by frontend
285
         *
286
         * @param string $uuid Sign request uuid
287
         * @return TemplateResponse<Http::STATUS_OK, array{}>
288
         *
289
         * 200: OK
290
         */
291
        #[NoAdminRequired]
292
        #[NoCSRFRequired]
293
        #[RequireSetupOk]
294
        #[PublicPage]
295
        #[RequireSignRequestUuid(redirectIfSignedToValidation: true, allowIdDocs: true)]
296
        #[FrontpageRoute(verb: 'GET', url: '/f/sign/{uuid}/{path}', requirements: ['path' => '.+'])]
297
        public function signFPath(string $uuid): TemplateResponse {
298
                $this->initialState->provideInitialState('action', JSActions::ACTION_SIGN_INTERNAL);
×
299
                return $this->index();
×
300
        }
301

302
        /**
303
         * Sign page to unauthenticated signer
304
         *
305
         * The path is used only by frontend
306
         *
307
         * @param string $uuid Sign request uuid
308
         * @return TemplateResponse<Http::STATUS_OK, array{}>
309
         *
310
         * 200: OK
311
         */
312
        #[NoAdminRequired]
313
        #[NoCSRFRequired]
314
        #[RequireSetupOk]
315
        #[PublicPage]
316
        #[RequireSignRequestUuid(redirectIfSignedToValidation: true, allowIdDocs: true)]
317
        #[FrontpageRoute(verb: 'GET', url: '/p/sign/{uuid}/{path}', requirements: ['path' => '.+'])]
318
        public function signPPath(string $uuid): TemplateResponse {
319
                return $this->sign($uuid);
×
320
        }
321

322
        /**
323
         * Sign page to unauthenticated signer
324
         *
325
         * The path is used only by frontend
326
         *
327
         * @param string $uuid Sign request uuid
328
         * @return TemplateResponse<Http::STATUS_OK, array{}>
329
         *
330
         * 200: OK
331
         */
332
        #[PrivateValidation]
333
        #[NoAdminRequired]
334
        #[NoCSRFRequired]
335
        #[RequireSetupOk]
336
        #[PublicPage]
337
        #[RequireSignRequestUuid(redirectIfSignedToValidation: true, allowIdDocs: true)]
338
        #[FrontpageRoute(verb: 'GET', url: '/p/sign/{uuid}')]
339
        public function sign(string $uuid): TemplateResponse {
340
                $this->initialState->provideInitialState('action', JSActions::ACTION_SIGN);
×
341
                $this->initialState->provideInitialState('config',
×
342
                        $this->accountService->getConfig($this->userSession->getUser())
×
343
                );
×
344
                $this->initialState->provideInitialState('filename', $this->getFileEntity()->getName());
×
345
                $file = $this->fileService
×
346
                        ->setFile($this->getFileEntity())
×
347
                        ->setSignRequest($this->getSignRequestEntity())
×
348
                        ->setHost($this->request->getServerHost())
×
349
                        ->setMe($this->userSession->getUser())
×
350
                        ->setSignerIdentified()
×
351
                        ->setIdentifyMethodId($this->sessionService->getIdentifyMethodId())
×
352
                        ->showVisibleElements()
×
353
                        ->showSigners()
×
354
                        ->showSettings()
×
355
                        ->toArray();
×
356
                $this->initialState->provideInitialState('config', [
×
357
                        'identificationDocumentsFlow' => $file['settings']['needIdentificationDocuments'] ?? false,
×
358
                ]);
×
359
                $this->initialState->provideInitialState('id', $file['id']);
×
360
                $this->initialState->provideInitialState('nodeId', $file['nodeId']);
×
361
                $this->initialState->provideInitialState('needIdentificationDocuments', $file['settings']['needIdentificationDocuments'] ?? false);
×
362
                $this->initialState->provideInitialState('identificationDocumentsWaitingApproval', $file['settings']['identificationDocumentsWaitingApproval'] ?? false);
×
363
                $this->initialState->provideInitialState('status', $file['status']);
×
364
                $this->initialState->provideInitialState('statusText', $file['statusText']);
×
365
                $this->initialState->provideInitialState('signers', $file['signers']);
×
366
                $this->initialState->provideInitialState('visibleElements', $file['visibleElements'] ?? []);
×
367
                $this->initialState->provideInitialState('sign_request_uuid', $uuid);
×
368
                $this->provideSignerSignatues();
×
369
                $this->initialState->provideInitialState('token_length', TokenService::TOKEN_LENGTH);
×
370
                $this->initialState->provideInitialState('description', $this->getSignRequestEntity()->getDescription() ?? '');
×
371
                if ($this->getFileEntity()->getNodeType() === 'envelope') {
×
372
                        $this->initialState->provideInitialState('pdfs', []);
×
373
                        $this->initialState->provideInitialState('envelopeFiles', $this->getEnvelopeChildFiles());
×
374
                } else {
375
                        $this->initialState->provideInitialState('pdfs', $this->getPdfUrls());
×
376
                        $this->initialState->provideInitialState('envelopeFiles', []);
×
377
                }
378
                $this->initialState->provideInitialState('nodeId', $this->getFileEntity()->getNodeId());
×
379
                $this->initialState->provideInitialState('nodeType', $this->getFileEntity()->getNodeType());
×
380

381
                Util::addScript(Application::APP_ID, 'libresign-external');
×
NEW
382
                Util::addStyle(Application::APP_ID, 'libresign-external');
×
383
                if (class_exists(LoadViewer::class)) {
×
384
                        $this->eventDispatcher->dispatchTyped(new LoadViewer());
×
385
                }
386
                $response = new TemplateResponse(Application::APP_ID, 'external', [], TemplateResponse::RENDER_AS_BASE);
×
387

388
                $policy = new ContentSecurityPolicy();
×
389
                $policy->allowEvalScript(true);
×
390
                $response->setContentSecurityPolicy($policy);
×
391

392
                return $response;
×
393
        }
394

395
        private function provideSignerSignatues(): void {
396
                $signatures = [];
×
397
                if ($this->userSession->getUser()) {
×
398
                        $signatures = $this->signerElementsService->getUserElements($this->userSession->getUser()->getUID());
×
399
                } else {
400
                        $signatures = $this->signerElementsService->getElementsFromSessionAsArray();
×
401
                }
402
                $this->initialState->provideInitialState('user_signatures', $signatures);
×
403
        }
404

405
        /**
406
         * @return string[] Array of PDF URLs
407
         */
408
        private function getPdfUrls(): array {
409
                return $this->signFileService->getPdfUrlsForSigning(
×
410
                        $this->getFileEntity(),
×
411
                        $this->getSignRequestEntity()
×
412
                );
×
413
        }
414

415
        private function getEnvelopeChildFiles(): array {
416
                $parentFileId = $this->getFileEntity()->getId();
×
417
                $currentSignRequest = $this->getSignRequestEntity();
×
418
                $childFiles = $this->fileMapper->getChildrenFiles($parentFileId);
×
419
                $childSignRequests = $this->signRequestMapper->getByEnvelopeChildrenAndIdentifyMethod(
×
420
                        $parentFileId,
×
421
                        $currentSignRequest->getId()
×
422
                );
×
423

424
                $signRequestsByFileId = [];
×
425
                foreach ($childSignRequests as $childSignRequest) {
×
426
                        $signRequestsByFileId[$childSignRequest->getFileId()] = true;
×
427
                }
428

429
                foreach ($childFiles as $childFile) {
×
430
                        if (!isset($signRequestsByFileId[$childFile->getId()])) {
×
431
                                $this->logger->warning('Missing sign request for envelope child file', [
×
432
                                        'parentFileId' => $parentFileId,
×
433
                                        'childFileId' => $childFile->getId(),
×
434
                                        'signRequestId' => $currentSignRequest->getId(),
×
435
                                ]);
×
436
                        }
437
                }
438

439
                return $this->fileListService->formatEnvelopeChildFilesForSignRequest(
×
440
                        $childFiles,
×
441
                        $childSignRequests,
×
442
                        $currentSignRequest,
×
443
                );
×
444
        }
445

446
        /**
447
         * Use UUID of file to get PDF
448
         *
449
         * @param string $uuid File uuid
450
         * @return FileDisplayResponse<Http::STATUS_OK, array{Content-Type: string}>|DataResponse<Http::STATUS_NOT_FOUND, array<empty>, array{}>
451
         *
452
         * 200: OK
453
         * 401: Validation page not accessible if unauthenticated
454
         * 404: File not found
455
         */
456
        #[PrivateValidation]
457
        #[NoAdminRequired]
458
        #[NoCSRFRequired]
459
        #[RequireSetupOk]
460
        #[PublicPage]
461
        #[AnonRateLimit(limit: 300, period: 60)]
462
        #[FrontpageRoute(verb: 'GET', url: '/p/pdf/{uuid}')]
463
        public function getPdf($uuid) {
464
                try {
465
                        $file = $this->accountService->getPdfByUuid($uuid);
×
466
                } catch (DoesNotExistException) {
×
467
                        return new DataResponse([], Http::STATUS_NOT_FOUND);
×
468
                }
469

470
                return new FileDisplayResponse($file, Http::STATUS_OK, ['Content-Type' => $file->getMimeType()]);
×
471
        }
472

473
        /**
474
         * Use UUID of user to get PDF
475
         *
476
         * @param string $uuid Sign request uuid
477
         * @return FileDisplayResponse<Http::STATUS_OK, array{Content-Type: string}>
478
         *
479
         * 200: OK
480
         * 401: Validation page not accessible if unauthenticated
481
         */
482
        #[PrivateValidation]
483
        #[NoAdminRequired]
484
        #[NoCSRFRequired]
485
        #[RequireSignRequestUuid(allowIdDocs: true)]
486
        #[PublicPage]
487
        #[RequireSetupOk]
488
        #[AnonRateLimit(limit: 300, period: 60)]
489
        #[FrontpageRoute(verb: 'GET', url: '/pdf/{uuid}')]
490
        public function getPdfFile($uuid): FileDisplayResponse {
491
                $files = $this->getNextcloudFiles();
×
492
                if (empty($files)) {
×
493
                        throw new LibresignException(json_encode([
×
494
                                'action' => JSActions::ACTION_DO_NOTHING,
×
495
                                'errors' => [['message' => $this->l10n->t('File not found')]],
×
496
                        ]), Http::STATUS_NOT_FOUND);
×
497
                }
498
                $file = current($files);
×
499
                return new FileDisplayResponse($file, Http::STATUS_OK, ['Content-Type' => $file->getMimeType()]);
×
500
        }
501

502
        /**
503
         * Show validation page
504
         *
505
         * @return TemplateResponse<Http::STATUS_OK, array{}>
506
         *
507
         * 200: OK
508
         * 401: Validation page not accessible if unauthenticated
509
         */
510
        #[PrivateValidation]
511
        #[NoAdminRequired]
512
        #[NoCSRFRequired]
513
        #[RequireSetupOk(template: 'validation')]
514
        #[PublicPage]
515
        #[AnonRateLimit(limit: 30, period: 60)]
516
        #[FrontpageRoute(verb: 'GET', url: '/p/validation')]
517
        public function validation(): TemplateResponse {
518
                if ($this->getFileEntity()) {
×
519
                        $this->initialState->provideInitialState('config',
×
520
                                $this->accountService->getConfig($this->userSession->getUser())
×
521
                        );
×
522
                        $this->initialState->provideInitialState('file', [
×
523
                                'uuid' => $this->getFileEntity()?->getUuid(),
×
524
                                'description' => $this->getSignRequestEntity()?->getDescription(),
×
525
                        ]);
×
526
                        $this->initialState->provideInitialState('filename', $this->getFileEntity()?->getName());
×
527
                        $this->initialState->provideInitialState('pdfs', $this->getPdfUrls());
×
528
                        $this->initialState->provideInitialState('signer',
×
529
                                $this->signFileService->getSignerData(
×
530
                                        $this->userSession->getUser(),
×
531
                                        $this->getSignRequestEntity(),
×
532
                                )
×
533
                        );
×
534
                }
535

536
                Util::addScript(Application::APP_ID, 'libresign-validation');
×
NEW
537
                Util::addStyle(Application::APP_ID, 'libresign-validation');
×
538
                $response = new TemplateResponse(Application::APP_ID, 'validation', [], TemplateResponse::RENDER_AS_BASE);
×
539

540
                return $response;
×
541
        }
542

543
        /**
544
         * Show validation page
545
         *
546
         * The path is used only by frontend
547
         *
548
         * @param string $uuid Sign request uuid
549
         * @return TemplateResponse<Http::STATUS_OK, array{}>
550
         *
551
         * 200: OK
552
         * 303: Redirected to validation page
553
         * 401: Validation page not accessible if unauthenticated
554
         */
555
        #[PrivateValidation]
556
        #[NoAdminRequired]
557
        #[NoCSRFRequired]
558
        #[RequireSetupOk]
559
        #[PublicPage]
560
        #[AnonRateLimit(limit: 30, period: 60)]
561
        #[FrontpageRoute(verb: 'GET', url: '/validation/{uuid}')]
562
        public function validationFileWithShortUrl(): TemplateResponse {
563
                return $this->validationFilePublic($this->request->getParam('uuid'));
×
564
        }
565

566
        /**
567
         * Show validation page
568
         *
569
         * @param string $uuid Sign request uuid
570
         * @return TemplateResponse<Http::STATUS_OK, array{}>
571
         *
572
         * 200: OK
573
         */
574
        #[NoAdminRequired]
575
        #[NoCSRFRequired]
576
        #[RequireSetupOk(template: 'main')]
577
        #[PublicPage]
578
        #[RequireSignRequestUuid]
579
        #[FrontpageRoute(verb: 'GET', url: '/reset-password')]
580
        public function resetPassword(): TemplateResponse {
581
                $this->initialState->provideInitialState('config',
×
582
                        $this->accountService->getConfig($this->userSession->getUser())
×
583
                );
×
584

585
                Util::addScript(Application::APP_ID, 'libresign-main');
×
NEW
586
                Util::addStyle(Application::APP_ID, 'libresign-main');
×
587
                $response = new TemplateResponse(Application::APP_ID, 'reset_password');
×
588

589
                return $response;
×
590
        }
591

592
        /**
593
         * Public page to show validation for a specific file UUID
594
         *
595
         * @param string $uuid File uuid
596
         * @return TemplateResponse<Http::STATUS_OK, array{}>
597
         *
598
         * 200: OK
599
         * 401: Validation page not accessible if unauthenticated
600
         */
601
        #[PrivateValidation]
602
        #[NoAdminRequired]
603
        #[NoCSRFRequired]
604
        #[RequireSetupOk(template: 'validation')]
605
        #[PublicPage]
606
        #[AnonRateLimit(limit: 30, period: 60)]
607
        #[FrontpageRoute(verb: 'GET', url: '/p/validation/{uuid}')]
608
        public function validationFilePublic(string $uuid): TemplateResponse {
609
                $signRequest = null;
×
610
                try {
611
                        $this->signFileService->getFileByUuid($uuid);
×
612
                        $this->fileService->setFileByUuid($uuid);
×
613
                } catch (DoesNotExistException) {
×
614
                        try {
615
                                $signRequest = $this->signFileService->getSignRequestByUuid($uuid);
×
616
                                $libresignFile = $this->signFileService->getFile($signRequest->getFileId());
×
617
                                $this->fileService->setFile($libresignFile);
×
618
                        } catch (DoesNotExistException) {
×
619
                                $this->initialState->provideInitialState('action', JSActions::ACTION_DO_NOTHING);
×
620
                                $this->initialState->provideInitialState('errors', [['message' => $this->l10n->t('Invalid UUID')]]);
×
621
                        }
622
                }
623
                if ($this->userSession->isLoggedIn()) {
×
624
                        $this->initialState->provideInitialState('config',
×
625
                                $this->accountService->getConfig($this->userSession->getUser())
×
626
                        );
×
627
                        $this->fileService->setMe($this->userSession->getUser());
×
628
                } else {
629
                        $this->initialState->provideInitialState('config',
×
630
                                $this->accountService->getConfig()
×
631
                        );
×
632
                }
633

634
                if ($signRequest) {
×
635
                        $this->fileService->setSignRequest($signRequest);
×
636
                }
637

638
                $this->initialState->provideInitialState('legal_information', $this->appConfig->getValueString(Application::APP_ID, 'legal_information'));
×
639

640
                $this->initialState->provideInitialState('file_info',
×
641
                        $this->fileService
×
642
                                ->setIdentifyMethodId($this->sessionService->getIdentifyMethodId())
×
643
                                ->setHost($this->request->getServerHost())
×
644
                                ->showVisibleElements()
×
645
                                ->showSigners()
×
646
                                ->showSettings()
×
647
                                ->showMessages()
×
648
                                ->showValidateFile()
×
649
                                ->toArray()
×
650
                );
×
651

652
                Util::addScript(Application::APP_ID, 'libresign-validation');
×
653
                if (class_exists(LoadViewer::class)) {
×
654
                        $this->eventDispatcher->dispatchTyped(new LoadViewer());
×
655
                }
656
                $response = new TemplateResponse(Application::APP_ID, 'validation', [], TemplateResponse::RENDER_AS_BASE);
×
657

658
                return $response;
×
659
        }
660
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc