From d227f4d34ca0f7a6877063784f75481ff6631a4a Mon Sep 17 00:00:00 2001 From: Xheni Myrtaj Date: Mon, 27 May 2019 21:54:58 +0200 Subject: [PATCH] Do not fail integrity check if mimetype list is changed Signed-off-by: Xheni Myrtaj --- .../Mimetype/GenerateMimetypeFileBuilder.php | 105 ++++++++++++++++++ .../Command/Maintenance/Mimetype/UpdateJS.php | 75 +------------ lib/private/Files/Type/Detection.php | 6 + lib/private/IntegrityCheck/Checker.php | 59 ++++++---- lib/private/Server.php | 3 +- resources/config/mimetypealiases.dist.json | 4 +- 6 files changed, 155 insertions(+), 97 deletions(-) create mode 100644 core/Command/Maintenance/Mimetype/GenerateMimetypeFileBuilder.php diff --git a/core/Command/Maintenance/Mimetype/GenerateMimetypeFileBuilder.php b/core/Command/Maintenance/Mimetype/GenerateMimetypeFileBuilder.php new file mode 100644 index 0000000000..7645f801d8 --- /dev/null +++ b/core/Command/Maintenance/Mimetype/GenerateMimetypeFileBuilder.php @@ -0,0 +1,105 @@ + + * + * @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 OC\Core\Command\Maintenance\Mimetype; + + +class GenerateMimetypeFileBuilder +{ + /** + * Generate mime type list file + * @param $aliases + * @return string + */ + public function generateFile($aliases): string { + // Remove comments + $keys = array_filter(array_keys($aliases), function($k) { + return $k[0] === '_'; + }); + foreach($keys as $key) { + unset($aliases[$key]); + } + + // Fetch all files + $dir = new \DirectoryIterator(\OC::$SERVERROOT.'/core/img/filetypes'); + + $files = []; + foreach($dir as $fileInfo) { + if ($fileInfo->isFile()) { + $file = preg_replace('/.[^.]*$/', '', $fileInfo->getFilename()); + $files[] = $file; + } + } + + //Remove duplicates + $files = array_values(array_unique($files)); + sort($files); + + // Fetch all themes! + $themes = []; + $dirs = new \DirectoryIterator(\OC::$SERVERROOT.'/themes/'); + foreach($dirs as $dir) { + //Valid theme dir + if ($dir->isFile() || $dir->isDot()) { + continue; + } + + $theme = $dir->getFilename(); + $themeDir = $dir->getPath() . '/' . $theme . '/core/img/filetypes/'; + // Check if this theme has its own filetype icons + if (!file_exists($themeDir)) { + continue; + } + + $themes[$theme] = []; + // Fetch all the theme icons! + $themeIt = new \DirectoryIterator($themeDir); + foreach ($themeIt as $fileInfo) { + if ($fileInfo->isFile()) { + $file = preg_replace('/.[^.]*$/', '', $fileInfo->getFilename()); + $themes[$theme][] = $file; + } + } + + //Remove Duplicates + $themes[$theme] = array_values(array_unique($themes[$theme])); + sort($themes[$theme]); + } + + //Generate the JS + return '/** +* This file is automatically generated +* DO NOT EDIT MANUALLY! +* +* You can update the list of MimeType Aliases in config/mimetypealiases.json +* The list of files is fetched from core/img/filetypes +* To regenerate this file run ./occ maintenance:mimetype:update-js +*/ +OC.MimeTypeList={ + aliases: ' . json_encode($aliases, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . ', + files: ' . json_encode($files, JSON_PRETTY_PRINT) . ', + themes: ' . json_encode($themes, JSON_PRETTY_PRINT) . ' +}; +'; + } + +} \ No newline at end of file diff --git a/core/Command/Maintenance/Mimetype/UpdateJS.php b/core/Command/Maintenance/Mimetype/UpdateJS.php index a6925c5dc6..0606e210c3 100644 --- a/core/Command/Maintenance/Mimetype/UpdateJS.php +++ b/core/Command/Maintenance/Mimetype/UpdateJS.php @@ -53,78 +53,9 @@ class UpdateJS extends Command { // Fetch all the aliases $aliases = $this->mimetypeDetector->getAllAliases(); - // Remove comments - $keys = array_filter(array_keys($aliases), function($k) { - return $k[0] === '_'; - }); - foreach($keys as $key) { - unset($aliases[$key]); - } - - // Fetch all files - $dir = new \DirectoryIterator(\OC::$SERVERROOT.'/core/img/filetypes'); - - $files = []; - foreach($dir as $fileInfo) { - if ($fileInfo->isFile()) { - $file = preg_replace('/.[^.]*$/', '', $fileInfo->getFilename()); - $files[] = $file; - } - } - - //Remove duplicates - $files = array_values(array_unique($files)); - sort($files); - - // Fetch all themes! - $themes = []; - $dirs = new \DirectoryIterator(\OC::$SERVERROOT.'/themes/'); - foreach($dirs as $dir) { - //Valid theme dir - if ($dir->isFile() || $dir->isDot()) { - continue; - } - - $theme = $dir->getFilename(); - $themeDir = $dir->getPath() . '/' . $theme . '/core/img/filetypes/'; - // Check if this theme has its own filetype icons - if (!file_exists($themeDir)) { - continue; - } - - $themes[$theme] = []; - // Fetch all the theme icons! - $themeIt = new \DirectoryIterator($themeDir); - foreach ($themeIt as $fileInfo) { - if ($fileInfo->isFile()) { - $file = preg_replace('/.[^.]*$/', '', $fileInfo->getFilename()); - $themes[$theme][] = $file; - } - } - - //Remove Duplicates - $themes[$theme] = array_values(array_unique($themes[$theme])); - sort($themes[$theme]); - } - - //Generate the JS - $js = '/** -* This file is automatically generated -* DO NOT EDIT MANUALLY! -* -* You can update the list of MimeType Aliases in config/mimetypealiases.json -* The list of files is fetched from core/img/filetypes -* To regenerate this file run ./occ maintenance:mimetype:update-js -*/ -OC.MimeTypeList={ - aliases: ' . json_encode($aliases, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . ', - files: ' . json_encode($files, JSON_PRETTY_PRINT) . ', - themes: ' . json_encode($themes, JSON_PRETTY_PRINT) . ' -}; -'; - - //Output the JS - file_put_contents(\OC::$SERVERROOT.'/core/js/mimetypelist.js', $js); + // Output the JS + $generatedMimetypeFile = new GenerateMimetypeFileBuilder(); + file_put_contents(\OC::$SERVERROOT.'/core/js/mimetypelist.js', $generatedMimetypeFile->generateFile($aliases)); $output->writeln('mimetypelist.js is updated'); } diff --git a/lib/private/Files/Type/Detection.php b/lib/private/Files/Type/Detection.php index 3207562763..9bbbd0e07c 100644 --- a/lib/private/Files/Type/Detection.php +++ b/lib/private/Files/Type/Detection.php @@ -133,6 +133,12 @@ class Detection implements IMimeTypeDetector { return $this->mimeTypeAlias; } + public function getOnlyDefaultAliases() { + $this->loadMappings(); + $this->mimeTypeAlias = json_decode(file_get_contents($this->defaultConfigDir . '/mimetypealiases.dist.json'), true); + return $this->mimeTypeAlias; + } + /** * Add mimetype mappings if they are not yet present */ diff --git a/lib/private/IntegrityCheck/Checker.php b/lib/private/IntegrityCheck/Checker.php index 0a8876381f..ac4f40b51e 100644 --- a/lib/private/IntegrityCheck/Checker.php +++ b/lib/private/IntegrityCheck/Checker.php @@ -27,6 +27,7 @@ declare(strict_types=1); namespace OC\IntegrityCheck; +use OC\Core\Command\Maintenance\Mimetype\GenerateMimetypeFileBuilder; use OC\IntegrityCheck\Exceptions\InvalidSignatureException; use OC\IntegrityCheck\Helpers\AppLocator; use OC\IntegrityCheck\Helpers\EnvironmentHelper; @@ -34,6 +35,7 @@ use OC\IntegrityCheck\Helpers\FileAccessHelper; use OC\IntegrityCheck\Iterator\ExcludeFileByNameFilterIterator; use OC\IntegrityCheck\Iterator\ExcludeFoldersByPathFilterIterator; use OCP\App\IAppManager; +use OCP\Files\IMimeTypeDetector; use OCP\ICache; use OCP\ICacheFactory; use OCP\IConfig; @@ -67,6 +69,8 @@ class Checker { private $appManager; /** @var ITempManager */ private $tempManager; + /** @var IMimeTypeDetector */ + private $mimeTypeDetector; /** * @param EnvironmentHelper $environmentHelper @@ -76,6 +80,7 @@ class Checker { * @param ICacheFactory $cacheFactory * @param IAppManager $appManager * @param ITempManager $tempManager + * @param IMimeTypeDetector $mimeTypeDetector */ public function __construct(EnvironmentHelper $environmentHelper, FileAccessHelper $fileAccessHelper, @@ -83,7 +88,8 @@ class Checker { IConfig $config = null, ICacheFactory $cacheFactory, IAppManager $appManager = null, - ITempManager $tempManager) { + ITempManager $tempManager, + IMimeTypeDetector $mimeTypeDetector) { $this->environmentHelper = $environmentHelper; $this->fileAccessHelper = $fileAccessHelper; $this->appLocator = $appLocator; @@ -91,6 +97,7 @@ class Checker { $this->cache = $cacheFactory->createDistributed(self::CACHE_KEY); $this->appManager = $appManager; $this->tempManager = $tempManager; + $this->mimeTypeDetector = $mimeTypeDetector; } /** @@ -193,6 +200,14 @@ class Checker { continue; } } + if($filename === $this->environmentHelper->getServerRoot().'/core/js/mimetypelist.js') { + $oldMimetypeList = new GenerateMimetypeFileBuilder(); + $newFile = $oldMimetypeList->generateFile($this->mimeTypeDetector->getAllAliases()); + if($newFile === file_get_contents($filename)) { + $hashes[$relativeFileName] = hash('sha512', $oldMimetypeList->generateFile($this->mimeTypeDetector->getOnlyDefaultAliases())); + continue; + } + } $hashes[$relativeFileName] = hash_file('sha512', $filename); } @@ -220,10 +235,10 @@ class Checker { $signature = $privateKey->sign(json_encode($hashes)); return [ - 'hashes' => $hashes, - 'signature' => base64_encode($signature), - 'certificate' => $certificate->saveX509($certificate->currentCert), - ]; + 'hashes' => $hashes, + 'signature' => base64_encode($signature), + 'certificate' => $certificate->saveX509($certificate->currentCert), + ]; } /** @@ -244,8 +259,8 @@ class Checker { $iterator = $this->getFolderIterator($path); $hashes = $this->generateHashes($iterator, $path); $signature = $this->createSignatureData($hashes, $certificate, $privateKey); - $this->fileAccessHelper->file_put_contents( - $appInfoDir . '/signature.json', + $this->fileAccessHelper->file_put_contents( + $appInfoDir . '/signature.json', json_encode($signature, JSON_PRETTY_PRINT) ); } catch (\Exception $e){ @@ -327,7 +342,7 @@ class Checker { // Verify if certificate has proper CN. "core" CN is always trusted. if($x509->getDN(X509::DN_OPENSSL)['CN'] !== $certificateCN && $x509->getDN(X509::DN_OPENSSL)['CN'] !== 'core') { throw new InvalidSignatureException( - sprintf('Certificate is not valid for required scope. (Requested: %s, current: CN=%s)', $certificateCN, $x509->getDN(true)['CN']) + sprintf('Certificate is not valid for required scope. (Requested: %s, current: CN=%s)', $certificateCN, $x509->getDN(true)['CN']) ); } @@ -484,16 +499,16 @@ class Checker { $path = $this->appLocator->getAppPath($appId); } $result = $this->verify( - $path . '/appinfo/signature.json', - $path, - $appId + $path . '/appinfo/signature.json', + $path, + $appId ); } catch (\Exception $e) { $result = [ - 'EXCEPTION' => [ - 'class' => \get_class($e), - 'message' => $e->getMessage(), - ], + 'EXCEPTION' => [ + 'class' => \get_class($e), + 'message' => $e->getMessage(), + ], ]; } $this->storeResults($appId, $result); @@ -534,16 +549,16 @@ class Checker { public function verifyCoreSignature(): array { try { $result = $this->verify( - $this->environmentHelper->getServerRoot() . '/core/signature.json', - $this->environmentHelper->getServerRoot(), - 'core' + $this->environmentHelper->getServerRoot() . '/core/signature.json', + $this->environmentHelper->getServerRoot(), + 'core' ); } catch (\Exception $e) { $result = [ - 'EXCEPTION' => [ - 'class' => \get_class($e), - 'message' => $e->getMessage(), - ], + 'EXCEPTION' => [ + 'class' => \get_class($e), + 'message' => $e->getMessage(), + ], ]; } $this->storeResults('core', $result); diff --git a/lib/private/Server.php b/lib/private/Server.php index 408b457ec3..599e14f1cd 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -791,7 +791,8 @@ class Server extends ServerContainer implements IServerContainer { $config, $c->getMemCacheFactory(), $appManager, - $c->getTempManager() + $c->getTempManager(), + $c->getMimeTypeDetector() ); }); $this->registerService(\OCP\IRequest::class, function ($c) { diff --git a/resources/config/mimetypealiases.dist.json b/resources/config/mimetypealiases.dist.json index eea7081dd7..384c31b493 100644 --- a/resources/config/mimetypealiases.dist.json +++ b/resources/config/mimetypealiases.dist.json @@ -7,7 +7,6 @@ "_comment5": "./occ maintenance:mimetype:update-js", "_comment6": "Otherwise your update won't propagate through the system.", - "application/coreldraw": "image", "application/epub+zip": "text", "application/font-sfnt": "image", @@ -100,6 +99,7 @@ "text/x-ldif": "text/code", "text/x-python": "text/code", "text/x-shellscript": "text/code", - "web": "text/code" + "web": "text/code", + "application/internet-shortcut": "link" }