/** * Download an update into a temp file * * @throws TransferException * @param UpdateInfo $update * @param string $apiEndpoint * @return UpdateFile */ public function downloadUpdateFile(UpdateInfo $update, string $apiEndpoint = 'download') : UpdateFile { if ($this->localUpdateFile instanceof UpdateFile) { $this->log('Local update file used', LogLevel::DEBUG); return $this->localUpdateFile; } try { $version = $update->getVersion(); $body = $this->hail->postReturnBody($update->getChannel() . API::get($apiEndpoint), ['type' => \get_class($this), 'supplier' => $update->getSupplierName(), 'package' => $update->getPackageName(), 'version' => $version]); $outFile = \Airship\tempnam('airship-', $this->ext); $saved = \file_put_contents($outFile, $body); if ($saved !== false) { // To prevent TOCTOU issues down the line $hash = Util::hash($body); $body = null; \clearstatcache(); return new UpdateFile(['path' => $outFile, 'version' => $version, 'hash' => $hash, 'size' => \filesize($outFile)]); } // If we're still here... throw new TransferException(); } catch (TransferException $ex) { $this->log('Automatic update failure.', LogLevel::WARNING, ['exception' => \Airship\throwableToArray($ex), 'channel' => $update->getChannel()]); // Rethrow it to prevent errors on return type throw $ex; } }
/** * Download the file from the update server. * * @param array $update * @return InstallFile * @throws TransferException */ public function download(array $update = []) : InstallFile { if ($this->localInstallFile instanceof InstallFile) { self::$continuumLogger->store(LogLevel::DEBUG, 'Local install file used instead of downloading.', ['installFile' => ['hash' => $this->localInstallFile->getHash(), 'path' => $this->localInstallFile->getPath(), 'signature' => $this->localInstallFile->getSignature(), 'size' => $this->localInstallFile->getSize(), 'version' => $this->localInstallFile->getVersion()]]); return $this->localInstallFile; } // If this was not supplied, we need to get it. if (empty($update)) { $update = $this->getPackageData(); } $supplierName = $this->supplier->getName(); \uasort($update['versions'], function (array $a, array $b) : int { return (int) ($a['version'] <=> $b['version']); }); $data = \array_pop($update['versions']); $version = $data['version']; $body = $this->hail->postReturnBody($update['channel'] . API::get('download'), ['type' => \get_class($this), 'supplier' => $supplierName, 'package' => $this->package, 'version' => $version]); $outFile = \Airship\tempnam('airship-', $this->ext); $saved = \file_put_contents($outFile, $body); if ($saved === false) { throw new TransferException(); } // To prevent TOCTOU issues down the line $hash = Util::hash($body); $body = null; \clearstatcache(); return new InstallFile($this->supplier, ['data' => $data, 'hash' => $hash, 'path' => $outFile, 'size' => \filesize($outFile), 'type' => $this->type, 'version' => $version]); }