diff --git a/Module/InstallerAbstract.php b/Module/InstallerAbstract.php index 3567e91ec..6044f003b 100644 --- a/Module/InstallerAbstract.php +++ b/Module/InstallerAbstract.php @@ -213,7 +213,7 @@ class InstallerAbstract self::installHooks(__DIR__ . '/../../' . $child->getName() . '/' . \basename($file->getName(), '.php') . '/Hooks.php', $file->getPath()); } } elseif ($child instanceof File) { - self::installRoutes(__DIR__ . '/../../' . $child->getName() . '/Hooks.php', $child->getPath()); + self::installHooks(__DIR__ . '/../../' . $child->getName() . '/Hooks.php', $child->getPath()); } } } diff --git a/Module/PackageManager.php b/Module/PackageManager.php index d88d32bdb..c29755587 100644 --- a/Module/PackageManager.php +++ b/Module/PackageManager.php @@ -57,6 +57,14 @@ final class PackageManager */ private $extractPath = ''; + /** + * Public key. + * + * @var string + * @since 1.0.0 + */ + private $publicKey = ''; + /** * Info data. * @@ -68,15 +76,17 @@ final class PackageManager /** * Constructor. * - * @param string $path Package source path e.g. path after download. - * @param string $basePath Path of the application + * @param string $path Package source path e.g. path after download. + * @param string $basePath Path of the application + * @param string $publicKey Public key * * @since 1.0.0 */ - public function __construct(string $path, string $basePath) + public function __construct(string $path, string $basePath, string $publicKey) { - $this->path = $path; - $this->basePath = $basePath; + $this->path = $path; + $this->basePath = $basePath; // todo: maybe remove from here because stupid + $this->publicKey = $publicKey; } /** @@ -136,7 +146,7 @@ final class PackageManager */ private function hashFiles() : string { - $files = Directory::list($this->extractPath . '/package'); + $files = Directory::list($this->extractPath); $state = \sodium_crypto_generichash_init(); foreach ($files as $file) { @@ -144,7 +154,7 @@ final class PackageManager continue; } - $contents = \file_get_contents($this->extractPath . '/package/' . $file); + $contents = \file_get_contents($this->extractPath . '/' . $file); if ($contents === false) { throw new \Exception(); } @@ -171,7 +181,7 @@ final class PackageManager } foreach ($this->info as $key => $components) { - if (function_exists($this->{$key})) { + if (\function_exists($this->{$key})) { $this->{$key}($components); } } @@ -270,9 +280,8 @@ final class PackageManager */ private function authenticate(string $signedHash, string $rawHash) : bool { - // https://3v4l.org/PN9Xl - $publicKey = 'MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjr73rerPRq3ZwWmrUKsNBjg8Wy5lnyWu9HCRQz0fix6grz+NOOsr4m/jazB2knfdtn7fi5XifbIbmrNJY8e6musCJ0FTgJPVBqVk7XAFVSRe2gUaCPZrTPtfZ00C3cynjwTlxSdjNtU9N0ZAo17sVWghH8ki4T2d5Mg1erGOtMJzp5yw47UHUa+KbxUmUV25WMcRYyi7+itD2xANF2AE+PQZT1dSEU8++NI+zT6tXD/Orv5ikk0whoVqvo6duWejx5n5cpJB4EiMo4Q7epbw9uMo9uIKqgQ9y3KdT36GBQkBErFf1dhf8KYJBGYMhO1UJE11dY3XrA7Ij1+zK+aiduQHOc5EMClUGZQzCJAIU5lj4WEHQ4Lo0gop+fx9hzuBTDxdyOjWSJzkqyuWMkq3zEpRBay785iaglaue9XDLee58wY+toiGLBfXe73gsbDqDSOll+cQYNjrronVN7sUDc2WyTIVW1Z8KFwK10D3SW0oEylCaGLtClyyihuW7JPu/8Or1Zjf87W82XTm31FpYkRgoEMDtVHZq0N2eHpLz1L8zKyT0ogZYN5eH5VlGrPcpwbAludNKlgAJ0hrgED19YsCBLwJQpFa4VZP7A5a/Qcw8EFAvNkgaPpBbAAtWoDbyOQsez6Jsdan/enfZ18+LL7qOB5oFFM/pKlTIeVS+UsCAwEAAQ=='; - $unsignedHash = \sodium_crypto_sign_open($signedHash, $publicKey); + return \sodium_crypto_sign_verify_detached($signedHash, $rawHash, $this->publicKey); + //$unsignedHash = \sodium_crypto_sign_open($signedHash, $this->publicKey); return $unsignedHash === $rawHash; } diff --git a/tests/Module/PackageManagerTest.php b/tests/Module/PackageManagerTest.php index 08fbfef1b..d8162c52f 100644 --- a/tests/Module/PackageManagerTest.php +++ b/tests/Module/PackageManagerTest.php @@ -16,11 +16,97 @@ namespace phpOMS\tests\Module; require_once __DIR__ . '/../Autoloader.php'; use phpOMS\Module\PackageManager; +use phpOMS\System\File\Local\File; +use phpOMS\System\File\Local\Directory; +use phpOMS\System\File\Local\LocalStorage; +use phpOMS\Utils\IO\Zip\Zip; +use phpOMS\Utils\StringUtils; class PackageManagerTest extends \PHPUnit\Framework\TestCase { - public function testPackage() + public static function setUpBeforeClass() { - self::markTestIncomplete(); + if (file_exists(__DIR__ . '/testPackage.zip')) { + unlink(__DIR__ . '/testPackage.zip'); + } + + if (file_exists(__DIR__ . '/testPackageExtracted')) { + \array_map('unlink', \glob(__DIR__ . '/testPackageExtracted/*')); + } + + // create keys + $alice_sign_kp = \sodium_crypto_sign_keypair(); + + $alice_sign_secretkey = \sodium_crypto_sign_secretkey($alice_sign_kp); + $alice_sign_publickey = \sodium_crypto_sign_publickey($alice_sign_kp); + + // create signature + $files = Directory::list(__DIR__ . '/testPackage'); + $state = \sodium_crypto_generichash_init(); + + foreach ($files as $file) { + if ($file === 'package.cert') { + continue; + } + + $contents = \file_get_contents(__DIR__ . '/testPackage' . '/' . $file); + if ($contents === false) { + throw new \Exception(); + } + + \sodium_crypto_generichash_update($state, $contents); + } + + $hash = \sodium_crypto_generichash_final($state); + $signature = sodium_crypto_sign_detached($hash, $alice_sign_secretkey); + + \file_put_contents(__DIR__ . '/testPackage/package.cert', $signature); + \file_put_contents(__DIR__ . '/public.key', $alice_sign_publickey); + + // create zip + Zip::pack( + [ + __DIR__ . '/testPackage', + ], + __DIR__ . '/testPackage.zip' + ); + } + + public function testPackageValid() + { + $package = new PackageManager( + __DIR__ . '/testPackage.zip', + '/invalid', + \file_get_contents(__DIR__ . '/public.key') + ); + + $package->extract(__DIR__ . '/testPackageExtracted'); + + self::assertTrue($package->isValid()); + } + + public function testCleanup() + { + $package = new PackageManager( + __DIR__ . '/testPackage.zip', + '/invalid', + \file_get_contents(__DIR__ . '/public.key') + ); + + $package->cleanup(); + + self::assertFalse(file_exists(__DIR__ . '/testPackage.zip')); + self::assertFalse(file_exists(__DIR__ . '/testPackageExtracted')); + } + + public static function tearDownAfterClass() + { + if (file_exists(__DIR__ . '/testPackage.zip')) { + unlink(__DIR__ . '/testPackage.zip'); + } + + if (file_exists(__DIR__ . '/testPackageExtracted')) { + \array_map('unlink', \glob(__DIR__ . '/testPackageExtracted/*')); + } } } diff --git a/tests/Module/testPackage/info.json b/tests/Module/testPackage/info.json new file mode 100644 index 000000000..8d1c8b69c --- /dev/null +++ b/tests/Module/testPackage/info.json @@ -0,0 +1 @@ + diff --git a/tests/Module/testPackage/package.cert b/tests/Module/testPackage/package.cert new file mode 100644 index 000000000..1f27d89ea --- /dev/null +++ b/tests/Module/testPackage/package.cert @@ -0,0 +1 @@ +9  >AM=1[Q5 b3'{z0t=uOz扛h \ No newline at end of file diff --git a/tests/Module/testPackage/testSubPackage/logo.png b/tests/Module/testPackage/testSubPackage/logo.png new file mode 100644 index 000000000..27d7f3c71 Binary files /dev/null and b/tests/Module/testPackage/testSubPackage/logo.png differ diff --git a/tests/Module/testPackage/testSubPackage/test.txt b/tests/Module/testPackage/testSubPackage/test.txt new file mode 100644 index 000000000..cffecd9dd --- /dev/null +++ b/tests/Module/testPackage/testSubPackage/test.txt @@ -0,0 +1,2 @@ + +this is a test file