From 20ef01b2c3d70a15d194309e8eba433f1c8ea45c Mon Sep 17 00:00:00 2001 From: Andreas Heigl Date: Fri, 4 Dec 2020 07:59:13 +0100 Subject: [PATCH] Move away from pect-extension This commit moves away from using the PECL-extension towards using a self-created GnuPG interface that itself agains mimics the functions of the GnuPG extension. This should make testing and execution without GnuPG being available in either an extension or as binary easier. --- .editorconfig | 11 + src/Exception/GpgBinaryNotFound.php | 21 ++ src/Exception/GpgExtensionNotFound.php | 19 ++ src/Factory.php | 69 ++--- src/GnuPG.php | 340 +--------------------- src/GnuPG/Binary.php | 386 +++++++++++++++++++++++++ src/GnuPG/ErrorHandler.php | 11 + src/GnuPG/Extension.php | 45 +++ src/GnuPG/Importer.php | 16 + src/GnuPG/Informer.php | 13 + src/GnuPG/NoGpgAvailable.php | 29 ++ src/GnuPG/Verifier.php | 8 + 12 files changed, 591 insertions(+), 377 deletions(-) create mode 100644 .editorconfig create mode 100644 src/Exception/GpgBinaryNotFound.php create mode 100644 src/Exception/GpgExtensionNotFound.php create mode 100644 src/GnuPG/Binary.php create mode 100644 src/GnuPG/ErrorHandler.php create mode 100644 src/GnuPG/Extension.php create mode 100644 src/GnuPG/Importer.php create mode 100644 src/GnuPG/Informer.php create mode 100644 src/GnuPG/NoGpgAvailable.php create mode 100644 src/GnuPG/Verifier.php diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..0ed5997 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +root = true + +[*] +end_of_line = lf +charset = utf-8 +indent_size = tab +indent_style = tab +insert_final_newline = true +max_line_length = off +trim_trailing_whitespace = true +tab_width = 4 \ No newline at end of file diff --git a/src/Exception/GpgBinaryNotFound.php b/src/Exception/GpgBinaryNotFound.php new file mode 100644 index 0000000..e6f44ed --- /dev/null +++ b/src/Exception/GpgBinaryNotFound.php @@ -0,0 +1,21 @@ +gpgBinary = $gpgBinary; } - public function createGnuPG(Directory $homeDirectory): \Gnupg { - if (\extension_loaded('gnupg')) { - \putenv('GNUPGHOME=' . $homeDirectory->asString()); - $gpg = new \Gnupg(); - $gpg->seterrormode(\Gnupg::ERROR_SILENT); - - return $gpg; + public function createGnuPG(Directory $homeDirectory): GnuPG + { + putenv('GNUPGHOME=' . $homeDirectory->asString()); + try { + return new GPG\Extension(); + } catch (GpgExtensionNotFound $e) { + // Do nothing on purpose } - $gpg = new GnuPG( - new Executor(), - $this->getGPGBinaryPath(), - $this->getTempDirectory(), - $homeDirectory - ); - - if (!\class_exists('\Gnupg')) { - \class_alias(GnuPG::class, '\Gnupg'); - } - - /** @var \Gnupg $gpg */ - return $gpg; - } - - /** - * @throws Exception - */ - private function getGPGBinaryPath(): Filename { - if ($this->gpgBinary === null) { - $which = \stripos(\PHP_OS, 'WIN') === 0 ? 'where.exe' : 'which'; - $result = \exec(\sprintf('%s %s', $which, 'gpg'), $output, $exitCode); - - if ($exitCode !== 0) { - throw new Exception('No gnupg binary found - please specify or install the pecl/gnupg extension.'); - } - $resultLines = \explode("\n", $result, 2); - $this->gpgBinary = new Filename($resultLines[0]); + try { + return GPG\Binary::createwithPaths( + $this->gpgBinary->asString(), + sys_get_temp_dir(), + $homeDirectory->asString() + ); + } catch (GpgBinaryNotFound $e) { + // Do nothing on purpose } - - return $this->gpgBinary; - } - - private function getTempDirectory(): Directory { - return new Directory(\sys_get_temp_dir()); + return new GPG\NoGpgAvailable; } } diff --git a/src/GnuPG.php b/src/GnuPG.php index e3ac8bb..1bbf7ae 100644 --- a/src/GnuPG.php +++ b/src/GnuPG.php @@ -1,334 +1,12 @@ -executor = $executor; - $this->gpgBinary = $gpgBinary; - $this->tmpDirectory = $tmpDirectory; - $this->homeDirectory = $homeDirectory; - } - - public function import(string $key): array { - $tmpFile = $this->createTemporaryFile($key); - $result = $this->execute([ - '--import', - \escapeshellarg($tmpFile->asString()) - ])->getOutput(); - $tmpFile->delete(); - - if (\preg_match('=.*IMPORT_OK\s(\d+)\s(.*)=', \implode('', $result), $matches)) { - return [ - 'imported' => (int)$matches[1], - 'fingerprint' => $matches[2] - ]; - } - - return ['imported' => 0]; - } - - public function keyinfo(string $search): array { - $result = $this->execute([ - '--list-keys', - '--with-fingerprint', - '--with-fingerprint', // duplication intentional - '--fixed-list-mode', - \escapeshellarg($search) - ])->getOutput(); - - return $this->parseInfoOutput($result); - } - - /** - * @return array|false - */ - public function verify(string $message, string $signature) { - $messageFile = $this->createTemporaryFile($message); - $signatureFile = $this->createTemporaryFile($signature); - - $result = $this->execute([ - '--verify', - \escapeshellarg($signatureFile->asString()), - \escapeshellarg($messageFile->asString()) - ]); - - $signatureFile->delete(); - $messageFile->delete(); - - return $this->parseVerifyOutput($result->getOutput(), $result->getExitCode()); - } - - /** - * @return false|string - */ - public function geterror() { - if ($this->lastExitCode === -1) { - return false; - } - - return ErrorStrings::fromCode($this->lastExitCode); - } - - /** - * @return array|false - */ - private function parseVerifyOutput(array $status, int $exitCode) { - $fingerprint = ''; - $timestamp = 0; - $summary = false; - - foreach ($status as $line) { - $parts = \explode(' ', $line); - - if (\count($parts) < 3) { - continue; - } - $fingerprint = $parts[2]; - - if (\strpos($line, 'VALIDSIG') !== false) { - // [GNUPG:] VALIDSIG D8406D0D82947747{...}A394072C20A 2014-07-19 1405769272 0 4 0 1 10 00 D8{...}C20A - /* - VALIDSIG - - The args are: - - - - - - - - - - - - - - - - - - - - - [ ] - */ - $timestamp = $parts[4]; - $summary = 0; - - break; - } - - if (\strpos($line, 'BADSIG') !== false) { - // [GNUPG:] BADSIG 4AA394086372C20A Sebastian Bergmann - $summary = 4; - - break; - } - - if (\strpos($line, 'ERRSIG') !== false) { - // [GNUPG:] ERRSIG 4AA394086372C20A 1 10 00 1405769272 9 - // ERRSIG