From 80998b4813b03b8a8feb36263f6ba4b6ecccf460 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Sun, 8 Oct 2017 20:56:06 +0200 Subject: [PATCH] Create draft package manager --- Module/PackageManager.php | 197 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 Module/PackageManager.php diff --git a/Module/PackageManager.php b/Module/PackageManager.php new file mode 100644 index 000000000..5e8117233 --- /dev/null +++ b/Module/PackageManager.php @@ -0,0 +1,197 @@ +path = $path; + $this->basePath = $basePath; + } + + public function extract(string $path) : bool + { + $this->extractPath = $path; + Zip::unpack($this->path, $this->extractPath); + } + + /** + * Load info data from path. + * + * @return void + * + * @throws PathException This exception is thrown in case the info file path doesn't exist. + * + * @since 1.0.0 + */ + public function load() /* : void */ + { + if(!file_exists($this->extractPath)) { + throw new PathException($this->extractPath); + } + + $this->info = json_decode(file_get_contents($this->extractPath . '/info.json'), true); + } + + public function isValid() : bool + { + return $this->authenticate(file_get_contents($this->extractPath . '/package.cert'), $this->hashFiles()); + } + + private function hashFiles(array $files) : string + { + $files = Directory::list($this->extractPath . '/package'); + $state = \sodium_crypto_generichash_init(); + + foreach($files as $file) { + if($file === 'package.cert') { + continue; + } + + \sodium_crypto_generichash_update($state, file_get_contents($this->extractPath . '/package/' . $file)); + } + + return \sodium_crypto_generichash_final(); + } + + public function install() /* : void */ + { + if(!$this->isValid()) { + throw new \Exception(); + } + + foreach($this->info as $key => $components) { + if(function_exists($this->{$key})) { + $this->{$key}($components); + } + } + } + + private function move($components) + { + foreach($components as $component) { + LocalStorage::move($this->basePath . '/' . $component['from'], $this->basePath . '/' . $component['to'], true); + } + } + + private function copy($components) + { + foreach($components as $component) { + if(StringUtils::startsWith($component['from'], 'Package/')) { + LocalStorage::copy($this->path . '/' . $component['from'], $this->basePath . '/' . $component['to'], true); + } else { + LocalStorage::copy($this->basePath . '/' . $component['from'], $this->basePath . '/' . $component['to'], true); + } + } + } + + private function delete($components) + { + foreach($components as $component) { + LocalStorage::delete($this->basePath . '/' . $component); + } + } + + private function execute($components) + { + foreach($components as $component) { + include $this->basePath . '/' . $component; + } + } + + public function cleanup() + { + File::delete($this->path); + Directory::delete($this->extractPath); + } + + private function authenticate(string $signedHash, string $rawHash) + { + // https://3v4l.org/PN9Xl + $publicKey = 'MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjr73rerPRq3ZwWmrUKsN + Bjg8Wy5lnyWu9HCRQz0fix6grz+NOOsr4m/jazB2knfdtn7fi5XifbIbmrNJY8e6 + musCJ0FTgJPVBqVk7XAFVSRe2gUaCPZrTPtfZ00C3cynjwTlxSdjNtU9N0ZAo17s + VWghH8ki4T2d5Mg1erGOtMJzp5yw47UHUa+KbxUmUV25WMcRYyi7+itD2xANF2AE + +PQZT1dSEU8++NI+zT6tXD/Orv5ikk0whoVqvo6duWejx5n5cpJB4EiMo4Q7epbw + 9uMo9uIKqgQ9y3KdT36GBQkBErFf1dhf8KYJBGYMhO1UJE11dY3XrA7Ij1+zK+ai + duQHOc5EMClUGZQzCJAIU5lj4WEHQ4Lo0gop+fx9hzuBTDxdyOjWSJzkqyuWMkq3 + zEpRBay785iaglaue9XDLee58wY+toiGLBfXe73gsbDqDSOll+cQYNjrronVN7sU + Dc2WyTIVW1Z8KFwK10D3SW0oEylCaGLtClyyihuW7JPu/8Or1Zjf87W82XTm31Fp + YkRgoEMDtVHZq0N2eHpLz1L8zKyT0ogZYN5eH5VlGrPcpwbAludNKlgAJ0hrgED1 + 9YsCBLwJQpFa4VZP7A5a/Qcw8EFAvNkgaPpBbAAtWoDbyOQsez6Jsdan/enfZ18+ + LL7qOB5oFFM/pKlTIeVS+UsCAwEAAQ=='; + $unsignedHash = \sodium_crypto_sign_open($signedHash, $publicKey); + + return $unsignedHash === $rawHash; + } +} \ No newline at end of file