From 6e913ec34477e2efd23059ca57704bdc69e5f1cb Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Thu, 22 Feb 2024 01:34:21 -0300 Subject: [PATCH] Start to implement jeidison/pdf-signe Signed-off-by: Vitor Mattos --- lib/Handler/PhpNativeHandler.php | 144 ++++++++++++++++++ lib/Handler/Pkcs12Handler.php | 4 +- lib/Service/Install/ConfigureCheckService.php | 8 + lib/Service/Install/InstallService.php | 8 + src/views/Settings/Settings.vue | 3 + src/views/Settings/SignatureEngine.vue | 64 ++++++++ 6 files changed, 229 insertions(+), 2 deletions(-) create mode 100644 lib/Handler/PhpNativeHandler.php create mode 100644 src/views/Settings/SignatureEngine.vue diff --git a/lib/Handler/PhpNativeHandler.php b/lib/Handler/PhpNativeHandler.php new file mode 100644 index 0000000000..c2931eb944 --- /dev/null +++ b/lib/Handler/PhpNativeHandler.php @@ -0,0 +1,144 @@ + + * + * @author Vitor Mattos + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +namespace OCA\Libresign\Handler; + +use Jeidison\JSignPDF\JSignPDF; +use Jeidison\JSignPDF\Sign\JSignParam; +use OCA\Libresign\Exception\LibresignException; +use OCP\AppFramework\Services\IAppConfig; +use Psr\Log\LoggerInterface; + +class PhpNativeHandler extends SignEngineHandler { + /** @var JSignPDF */ + private $jSignPdf; + /** @var JSignParam */ + private $jSignParam; + public const VERSION = '2.2.2'; + + public function __construct( + private IAppConfig $appConfig, + private LoggerInterface $logger, + ) { + } + + public function setJSignPdf(JSignPDF $jSignPdf): void { + $this->jSignPdf = $jSignPdf; + } + + public function getJSignPdf(): JSignPDF { + if (!$this->jSignPdf) { + // @codeCoverageIgnoreStart + $this->setJSignPdf(new JSignPDF()); + // @codeCoverageIgnoreEnd + } + return $this->jSignPdf; + } + + /** + * @psalm-suppress MixedReturnStatement + */ + public function getJSignParam(): JSignParam { + if (!$this->jSignParam) { + $javaPath = $this->appConfig->getAppValue('java_path'); + $this->jSignParam = (new JSignParam()) + ->setTempPath( + $this->appConfig->getAppValue('jsignpdf_temp_path', sys_get_temp_dir() . DIRECTORY_SEPARATOR) + ) + ->setIsUseJavaInstalled(empty($javaPath)) + ->setjSignPdfJarPath( + $this->appConfig->getAppValue('jsignpdf_jar_path', '/opt/jsignpdf-' . self::VERSION . '/JSignPdf.jar') + ); + if (!empty($javaPath)) { + if (!file_exists($javaPath)) { + throw new \Exception('Invalid Java binary. Run occ libresign:install --java'); + } + $this->jSignParam->setJavaPath($javaPath); + } + } + return $this->jSignParam; + } + + /** + * @psalm-suppress MixedReturnStatement + */ + public function sign(): string { + $param = $this->getJSignParam() + ->setCertificate($this->getCertificate()) + ->setPdf($this->getInputFile()->getContent()) + ->setPassword($this->getPassword()); + + $signed = $this->signUsingVisibleElements(); + if ($signed) { + return $signed; + } + $jSignPdf = $this->getJSignPdf(); + $jSignPdf->setParam($param); + return $this->signWrapper($jSignPdf); + } + + private function signUsingVisibleElements(): string { + $visibleElements = $this->getvisibleElements(); + if ($visibleElements) { + $jSignPdf = $this->getJSignPdf(); + $param = $this->getJSignParam(); + foreach ($visibleElements as $element) { + $param + ->setJSignParameters( + $param->getJSignParameters() . + ' -pg ' . $element->getFileElement()->getPage() . + ' -llx ' . $element->getFileElement()->getLlx() . + ' -lly ' . $element->getFileElement()->getLly() . + ' -urx ' . $element->getFileElement()->getUrx() . + ' -ury ' . $element->getFileElement()->getUry() . + ' --l2-text ""' . + ' -V' . + ' --bg-path ' . $element->getTempFile() + ); + $jSignPdf->setParam($param); + $signed = $this->signWrapper($jSignPdf); + } + return $signed; + } + return ''; + } + + private function signWrapper(JSignPDF $jSignPDF): string { + try { + return $jSignPDF->sign(); + } catch (\Throwable $th) { + $rows = str_getcsv($th->getMessage()); + $hashAlgorithm = array_filter($rows, fn ($r) => str_contains($r, 'The chosen hash algorithm')); + if (!empty($hashAlgorithm)) { + $hashAlgorithm = current($hashAlgorithm); + $hashAlgorithm = trim($hashAlgorithm, 'INFO '); + $hashAlgorithm = str_replace('\"', '"', $hashAlgorithm); + $hashAlgorithm = preg_replace('/\.( )/', ".\n", $hashAlgorithm); + throw new LibresignException($hashAlgorithm); + } + $this->logger->error('Error at JSignPdf side. LibreSign can not do nothing. Follow the error message: ' . $th->getMessage()); + throw new \Exception($th->getMessage()); + } + } +} diff --git a/lib/Handler/Pkcs12Handler.php b/lib/Handler/Pkcs12Handler.php index d0c120896a..72a693b6b7 100644 --- a/lib/Handler/Pkcs12Handler.php +++ b/lib/Handler/Pkcs12Handler.php @@ -140,8 +140,8 @@ public function getPfx(?string $uid = null): string { } private function getHandler(): SignEngineHandler { - $sign_engine = $this->appConfig->getAppValue('sign_engine', 'JSignPdf'); - $property = lcfirst($sign_engine) . 'Handler'; + $signature_engine = $this->appConfig->getAppValue('signature_engine', 'JSignPdf'); + $property = lcfirst($signature_engine) . 'Handler'; if (!property_exists($this, $property)) { throw new LibresignException($this->l10n->t('Invalid Sign engine.'), 400); } diff --git a/lib/Service/Install/ConfigureCheckService.php b/lib/Service/Install/ConfigureCheckService.php index ccc79b20c0..7a6cb0c419 100644 --- a/lib/Service/Install/ConfigureCheckService.php +++ b/lib/Service/Install/ConfigureCheckService.php @@ -70,6 +70,10 @@ public function checkSign(): array { * @return ConfigureCheckHelper[] */ public function checkJSignPdf(): array { + $signatureEngine = $this->appConfig->getAppValue('signature_engine', 'jsignpdf'); + if ($signatureEngine !== 'jsignpdf') { + return []; + } $jsignpdJarPath = $this->appConfig->getAppValue('jsignpdf_jar_path'); if ($jsignpdJarPath) { if (file_exists($jsignpdJarPath)) { @@ -182,6 +186,10 @@ public function checkPdftk(): array { * @return ConfigureCheckHelper[] */ private function checkJava(): array { + $signatureEngine = $this->appConfig->getAppValue('signature_engine', 'jsignpdf'); + if ($signatureEngine !== 'jsignpdf') { + return []; + } $javaPath = $this->appConfig->getAppValue('java_path'); if ($javaPath) { if (file_exists($javaPath)) { diff --git a/lib/Service/Install/InstallService.php b/lib/Service/Install/InstallService.php index f64794df03..b0124e1237 100644 --- a/lib/Service/Install/InstallService.php +++ b/lib/Service/Install/InstallService.php @@ -324,6 +324,10 @@ public function setResource(string $resource): self { } public function installJava(?bool $async = false): void { + $signatureEngine = $this->appConfig->getAppValue('signature_engine', 'jsignpdf'); + if ($signatureEngine !== 'jsignpdf') { + return []; + } $this->setResource('java'); if ($async) { $this->runAsync(); @@ -394,6 +398,10 @@ public function uninstallJava(): void { } public function installJSignPdf(?bool $async = false): void { + $signatureEngine = $this->appConfig->getAppValue('signature_engine', 'jsignpdf'); + if ($signatureEngine !== 'jsignpdf') { + return []; + } if (!extension_loaded('zip')) { throw new RuntimeException('Zip extension is not available'); } diff --git a/src/views/Settings/Settings.vue b/src/views/Settings/Settings.vue index 9e64d546cd..80d54901c7 100644 --- a/src/views/Settings/Settings.vue +++ b/src/views/Settings/Settings.vue @@ -24,6 +24,7 @@