* * 200: OK */ #[NoAdminRequired] #[NoCSRFRequired] #[RequireSetupOk(template: 'main')] #[FrontpageRoute(verb: 'GET', url: '/')] public function index(): TemplateResponse { $this->initialState->provideInitialState('config', $this->accountService->getConfig($this->userSession->getUser())); $this->initialState->provideInitialState('filters', $this->accountService->getConfigFilters($this->userSession->getUser())); $this->initialState->provideInitialState('certificate_engine', $this->accountService->getCertificateEngineName()); try { $this->validateHelper->canRequestSign($this->userSession->getUser()); $this->initialState->provideInitialState('can_request_sign', true); } catch (LibresignException) { $this->initialState->provideInitialState('can_request_sign', false); } $this->provideSignerSignatues(); $this->initialState->provideInitialState('identify_methods', $this->identifyMethodService->getIdentifyMethodsSettings()); $this->initialState->provideInitialState('signature_flow', $this->appConfig->getValueString(Application::APP_ID, 'signature_flow', \OCA\Libresign\Enum\SignatureFlow::NONE->value)); $this->initialState->provideInitialState('legal_information', $this->appConfig->getValueString(Application::APP_ID, 'legal_information')); Util::addScript(Application::APP_ID, 'libresign-main'); if (class_exists(LoadViewer::class)) { $this->eventDispatcher->dispatchTyped(new LoadViewer()); } $response = new TemplateResponse(Application::APP_ID, 'main'); $policy = new ContentSecurityPolicy(); $policy->allowEvalScript(true); $policy->addAllowedFrameDomain('\'self\''); $response->setContentSecurityPolicy($policy); return $response; } /** * Index page to authenticated users * * This router is used to be possible render pages with /f/, is a * workaround at frontend side to identify pages with authenticated accounts * * @return TemplateResponse * * 200: OK */ #[NoAdminRequired] #[NoCSRFRequired] #[RequireSetupOk(template: 'main')] #[FrontpageRoute(verb: 'GET', url: '/f/')] public function indexF(): TemplateResponse { return $this->index(); } /** * Incomplete page * * @return TemplateResponse * * 200: OK */ #[NoAdminRequired] #[NoCSRFRequired] #[FrontpageRoute(verb: 'GET', url: '/f/incomplete')] public function incomplete(): TemplateResponse { Util::addScript(Application::APP_ID, 'libresign-main'); $response = new TemplateResponse(Application::APP_ID, 'main'); return $response; } /** * Incomplete page in full screen * * @return TemplateResponse * * 200: OK */ #[PublicPage] #[NoCSRFRequired] #[FrontpageRoute(verb: 'GET', url: '/p/incomplete')] public function incompleteP(): TemplateResponse { Util::addScript(Application::APP_ID, 'libresign-main'); $response = new TemplateResponse(Application::APP_ID, 'main', [], TemplateResponse::RENDER_AS_BASE); return $response; } /** * Main page to authenticated signer with a path * * The path is used only by frontend * * @param string $path The path that was sent from frontend * @return TemplateResponse * * 200: OK */ #[NoAdminRequired] #[NoCSRFRequired] #[RequireSetupOk(template: 'main')] #[FrontpageRoute(verb: 'GET', url: '/f/{path}', requirements: ['path' => '.+'])] public function indexFPath(string $path): TemplateResponse { if (preg_match('/validation\/(?[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})$/', $path, $matches)) { try { $this->initialState->provideInitialState('file_info', $this->fileService ->setFileByType('uuid', $matches['uuid']) ->setIdentifyMethodId($this->sessionService->getIdentifyMethodId()) ->setHost($this->request->getServerHost()) ->setMe($this->userSession->getUser()) ->showVisibleElements() ->showSigners() ->showSettings() ->showMessages() ->showValidateFile() ->toArray() ); } catch (LibresignException) { throw new LibresignException(json_encode([ 'action' => JSActions::ACTION_DO_NOTHING, 'errors' => [['message' => $this->l10n->t('Invalid UUID')]], ]), Http::STATUS_NOT_FOUND); } } elseif (preg_match('/sign\/(?[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})/', $path, $matches)) { try { $signRequest = $this->signFileService->getSignRequestByUuid($matches['uuid']); $file = $this->fileService ->setFile($this->signFileService->getFile($signRequest->getFileId())) ->setMe($this->userSession->getUser()) ->setSignRequest($signRequest) ->showSettings() ->toArray(); $this->initialState->provideInitialState('needIdentificationDocuments', $file['settings']['needIdentificationDocuments'] ?? false); $this->initialState->provideInitialState('identificationDocumentsWaitingApproval', $file['settings']['identificationDocumentsWaitingApproval'] ?? false); } catch (\Throwable $e) { throw new LibresignException(json_encode([ 'action' => JSActions::ACTION_DO_NOTHING, 'errors' => [['message' => $this->l10n->t('Invalid UUID')]], ]), Http::STATUS_NOT_FOUND); } } return $this->index(); } /** * Sign page to authenticated signer * * @param string $uuid Sign request uuid * @return TemplateResponse * * 200: OK */ #[NoAdminRequired] #[NoCSRFRequired] #[RequireSetupOk] #[PublicPage] #[RequireSignRequestUuid] #[FrontpageRoute(verb: 'GET', url: '/f/sign/{uuid}')] public function signF(string $uuid): TemplateResponse { $this->initialState->provideInitialState('action', JSActions::ACTION_SIGN_INTERNAL); return $this->index(); } /** * Sign page to authenticated signer with the path of file * * The path is used only by frontend * * @param string $uuid Sign request uuid * @return TemplateResponse * * 200: OK */ #[NoAdminRequired] #[NoCSRFRequired] #[RequireSetupOk] #[PublicPage] #[RequireSignRequestUuid] #[FrontpageRoute(verb: 'GET', url: '/f/sign/{uuid}/{path}', requirements: ['path' => '.+'])] public function signFPath(string $uuid): TemplateResponse { $this->initialState->provideInitialState('action', JSActions::ACTION_SIGN_INTERNAL); return $this->index(); } /** * Sign page to unauthenticated signer * * The path is used only by frontend * * @param string $uuid Sign request uuid * @return TemplateResponse * * 200: OK */ #[NoAdminRequired] #[NoCSRFRequired] #[RequireSetupOk] #[PublicPage] #[RequireSignRequestUuid] #[FrontpageRoute(verb: 'GET', url: '/p/sign/{uuid}/{path}', requirements: ['path' => '.+'])] public function signPPath(string $uuid): TemplateResponse { return $this->sign($uuid); } /** * Sign page to unauthenticated signer * * The path is used only by frontend * * @param string $uuid Sign request uuid * @return TemplateResponse * * 200: OK */ #[PrivateValidation] #[NoAdminRequired] #[NoCSRFRequired] #[RequireSetupOk] #[PublicPage] #[RequireSignRequestUuid] #[FrontpageRoute(verb: 'GET', url: '/p/sign/{uuid}')] public function sign(string $uuid): TemplateResponse { $this->initialState->provideInitialState('action', JSActions::ACTION_SIGN); $this->initialState->provideInitialState('config', $this->accountService->getConfig($this->userSession->getUser()) ); $this->initialState->provideInitialState('filename', $this->getFileEntity()->getName()); $file = $this->fileService ->setFile($this->getFileEntity()) ->setHost($this->request->getServerHost()) ->setMe($this->userSession->getUser()) ->setSignerIdentified() ->setIdentifyMethodId($this->sessionService->getIdentifyMethodId()) ->setSignRequest($this->getSignRequestEntity()) ->showVisibleElements() ->showSigners() ->showSettings() ->toArray(); $this->initialState->provideInitialState('config', [ 'identificationDocumentsFlow' => $file['settings']['needIdentificationDocuments'] ?? false, ]); $this->initialState->provideInitialState('needIdentificationDocuments', $file['settings']['needIdentificationDocuments'] ?? false); $this->initialState->provideInitialState('identificationDocumentsWaitingApproval', $file['settings']['identificationDocumentsWaitingApproval'] ?? false); $this->initialState->provideInitialState('status', $file['status']); $this->initialState->provideInitialState('statusText', $file['statusText']); $this->initialState->provideInitialState('signers', $file['signers']); $this->initialState->provideInitialState('sign_request_uuid', $uuid); $this->provideSignerSignatues(); $this->initialState->provideInitialState('token_length', TokenService::TOKEN_LENGTH); $this->initialState->provideInitialState('description', $this->getSignRequestEntity()->getDescription() ?? ''); $this->initialState->provideInitialState('pdf', $this->signFileService->getFileUrl('url', $this->getFileEntity(), $this->getNextcloudFile(), $uuid) ); $this->initialState->provideInitialState('nodeId', $this->getFileEntity()->getNodeId()); Util::addScript(Application::APP_ID, 'libresign-external'); $response = new TemplateResponse(Application::APP_ID, 'external', [], TemplateResponse::RENDER_AS_BASE); $policy = new ContentSecurityPolicy(); $policy->allowEvalScript(true); $response->setContentSecurityPolicy($policy); return $response; } private function provideSignerSignatues(): void { $signatures = []; if ($this->userSession->getUser()) { $signatures = $this->signerElementsService->getUserElements($this->userSession->getUser()->getUID()); } else { $signatures = $this->signerElementsService->getElementsFromSessionAsArray(); } $this->initialState->provideInitialState('user_signatures', $signatures); } /** * Show signature page * * @param string $uuid Sign request uuid * @return TemplateResponse * * 200: OK * 404: Invalid UUID */ #[NoAdminRequired] #[NoCSRFRequired] #[RequireSetupOk] #[FrontpageRoute(verb: 'GET', url: '/p/id-docs/approve/{uuid}')] #[FrontpageRoute(verb: 'GET', url: '/p/id-docs/approve/{uuid}/{path}', requirements: ['path' => '.+'], postfix: 'private')] public function signIdDoc($uuid): TemplateResponse { try { $fileEntity = $this->signFileService->getFileByUuid($uuid); $this->signFileService->getIdDocById($fileEntity->getId()); } catch (DoesNotExistException) { throw new LibresignException(json_encode([ 'action' => JSActions::ACTION_DO_NOTHING, 'errors' => [['message' => $this->l10n->t('Invalid UUID')]], ]), Http::STATUS_NOT_FOUND); } $this->initialState->provideInitialState('action', JSActions::ACTION_SIGN_ID_DOC); $this->initialState->provideInitialState('config', $this->accountService->getConfig($this->userSession->getUser()) ); $this->initialState->provideInitialState('signer', $this->signFileService->getSignerData( $this->userSession->getUser(), ) ); $this->initialState->provideInitialState('identifyMethods', $this->signFileService->getAvailableIdentifyMethodsFromSettings() ); $this->initialState->provideInitialState('filename', $fileEntity->getName()); $file = $this->fileService ->setFile($fileEntity) ->setHost($this->request->getServerHost()) ->setMe($this->userSession->getUser()) ->setIdentifyMethodId($this->sessionService->getIdentifyMethodId()) ->showVisibleElements() ->showSigners() ->toArray(); $this->initialState->provideInitialState('fileId', $file['nodeId']); $this->initialState->provideInitialState('status', $file['status']); $this->initialState->provideInitialState('statusText', $file['statusText']); $this->initialState->provideInitialState('visibleElements', []); $this->initialState->provideInitialState('signers', []); $this->provideSignerSignatues(); $signatureMethods = $this->identifyMethodService->getSignMethodsOfIdentifiedFactors($this->getSignRequestEntity()->getId()); $this->initialState->provideInitialState('signature_methods', $signatureMethods); $this->initialState->provideInitialState('token_length', TokenService::TOKEN_LENGTH); $this->initialState->provideInitialState('description', ''); $nextcloudFile = $this->signFileService->getNextcloudFile($fileEntity); $this->initialState->provideInitialState('pdf', $this->signFileService->getFileUrl('url', $fileEntity, $nextcloudFile, $uuid) ); Util::addScript(Application::APP_ID, 'libresign-external'); $response = new TemplateResponse(Application::APP_ID, 'external', [], TemplateResponse::RENDER_AS_BASE); $policy = new ContentSecurityPolicy(); $policy->allowEvalScript(true); $response->setContentSecurityPolicy($policy); return $response; } /** * Use UUID of file to get PDF * * @param string $uuid File uuid * @return FileDisplayResponse|DataResponse, array{}> * * 200: OK * 401: Validation page not accessible if unauthenticated * 404: File not found */ #[PrivateValidation] #[NoAdminRequired] #[NoCSRFRequired] #[RequireSetupOk] #[PublicPage] #[AnonRateLimit(limit: 30, period: 60)] #[FrontpageRoute(verb: 'GET', url: '/p/pdf/{uuid}')] public function getPdf($uuid) { try { $file = $this->accountService->getPdfByUuid($uuid); } catch (DoesNotExistException) { return new DataResponse([], Http::STATUS_NOT_FOUND); } return new FileDisplayResponse($file, Http::STATUS_OK, ['Content-Type' => $file->getMimeType()]); } /** * Use UUID of user to get PDF * * @param string $uuid Sign request uuid * @return FileDisplayResponse * * 200: OK * 401: Validation page not accessible if unauthenticated */ #[PrivateValidation] #[NoAdminRequired] #[NoCSRFRequired] #[RequireSignRequestUuid] #[PublicPage] #[RequireSetupOk] #[AnonRateLimit(limit: 30, period: 60)] #[FrontpageRoute(verb: 'GET', url: '/pdf/{uuid}')] public function getPdfFile($uuid): FileDisplayResponse { $file = $this->getNextcloudFile(); return new FileDisplayResponse($file, Http::STATUS_OK, ['Content-Type' => $file->getMimeType()]); } /** * Show validation page * * @return TemplateResponse * * 200: OK * 401: Validation page not accessible if unauthenticated */ #[PrivateValidation] #[NoAdminRequired] #[NoCSRFRequired] #[RequireSetupOk(template: 'validation')] #[PublicPage] #[AnonRateLimit(limit: 30, period: 60)] #[FrontpageRoute(verb: 'GET', url: '/p/validation')] public function validation(): TemplateResponse { if ($this->getFileEntity()) { $this->initialState->provideInitialState('config', $this->accountService->getConfig($this->userSession->getUser()) ); $this->initialState->provideInitialState('file', [ 'uuid' => $this->getFileEntity()?->getUuid(), 'description' => $this->getSignRequestEntity()?->getDescription(), ]); $this->initialState->provideInitialState('filename', $this->getFileEntity()?->getName()); $this->initialState->provideInitialState('pdf', $this->signFileService->getFileUrl('url', $this->getFileEntity(), $this->getNextcloudFile(), $this->request->getParam('uuid')) ); $this->initialState->provideInitialState('signer', $this->signFileService->getSignerData( $this->userSession->getUser(), $this->getSignRequestEntity(), ) ); } Util::addScript(Application::APP_ID, 'libresign-validation'); $response = new TemplateResponse(Application::APP_ID, 'validation', [], TemplateResponse::RENDER_AS_BASE); return $response; } /** * Show validation page * * The path is used only by frontend * * @param string $uuid Sign request uuid * @return TemplateResponse * * 200: OK * 303: Redirected to validation page * 401: Validation page not accessible if unauthenticated */ #[PrivateValidation] #[NoAdminRequired] #[NoCSRFRequired] #[RequireSetupOk] #[PublicPage] #[AnonRateLimit(limit: 30, period: 60)] #[FrontpageRoute(verb: 'GET', url: '/validation/{uuid}')] public function validationFileWithShortUrl(): TemplateResponse { return $this->validationFilePublic($this->request->getParam('uuid')); } /** * Show validation page * * @param string $uuid Sign request uuid * @return TemplateResponse * * 200: OK */ #[NoAdminRequired] #[NoCSRFRequired] #[RequireSetupOk(template: 'main')] #[PublicPage] #[RequireSignRequestUuid] #[FrontpageRoute(verb: 'GET', url: '/reset-password')] public function resetPassword(): TemplateResponse { $this->initialState->provideInitialState('config', $this->accountService->getConfig($this->userSession->getUser()) ); Util::addScript(Application::APP_ID, 'libresign-main'); $response = new TemplateResponse(Application::APP_ID, 'reset_password'); return $response; } /** * Public page to show validation for a specific file UUID * * @param string $uuid File uuid * @return TemplateResponse * * 200: OK * 401: Validation page not accessible if unauthenticated */ #[PrivateValidation] #[NoAdminRequired] #[NoCSRFRequired] #[RequireSetupOk(template: 'validation')] #[PublicPage] #[AnonRateLimit(limit: 30, period: 60)] #[FrontpageRoute(verb: 'GET', url: '/p/validation/{uuid}')] public function validationFilePublic(string $uuid): TemplateResponse { try { $this->signFileService->getFileByUuid($uuid); $this->fileService->setFileByType('uuid', $uuid); } catch (DoesNotExistException) { try { $signRequest = $this->signFileService->getSignRequestByUuid($uuid); $libresignFile = $this->signFileService->getFile($signRequest->getFileId()); $this->fileService->setFile($libresignFile); } catch (DoesNotExistException) { $this->initialState->provideInitialState('action', JSActions::ACTION_DO_NOTHING); $this->initialState->provideInitialState('errors', [['message' => $this->l10n->t('Invalid UUID')]]); } } if ($this->userSession->isLoggedIn()) { $this->initialState->provideInitialState('config', $this->accountService->getConfig($this->userSession->getUser()) ); $this->fileService->setMe($this->userSession->getUser()); } else { $this->initialState->provideInitialState('config', $this->accountService->getConfig() ); } $this->initialState->provideInitialState('legal_information', $this->appConfig->getValueString(Application::APP_ID, 'legal_information')); $this->initialState->provideInitialState('file_info', $this->fileService ->setIdentifyMethodId($this->sessionService->getIdentifyMethodId()) ->setHost($this->request->getServerHost()) ->showVisibleElements() ->showSigners() ->showSettings() ->showMessages() ->showValidateFile() ->toArray() ); Util::addScript(Application::APP_ID, 'libresign-validation'); if (class_exists(LoadViewer::class)) { $this->eventDispatcher->dispatchTyped(new LoadViewer()); } $response = new TemplateResponse(Application::APP_ID, 'validation', [], TemplateResponse::RENDER_AS_BASE); return $response; } }