/** * check an app's integrity * @param array $data * @param string $extractDir * @param bool $isShipped * @return array * @throws \Exception */ public static function checkAppsIntegrity($data = array(), $extractDir, $path, $isShipped = false) { $l = \OC::$server->getL10N('lib'); //load the info.xml file of the app if (!is_file($extractDir . '/appinfo/info.xml')) { //try to find it in a subdir $dh = opendir($extractDir); if (is_resource($dh)) { while (($folder = readdir($dh)) !== false) { if ($folder[0] != '.' and is_dir($extractDir . '/' . $folder)) { if (is_file($extractDir . '/' . $folder . '/appinfo/info.xml')) { $extractDir .= '/' . $folder; } } } } } if (!is_file($extractDir . '/appinfo/info.xml')) { OC_Helper::rmdirr($extractDir); if ($data['source'] == 'http') { unlink($path); } throw new \Exception($l->t("App does not provide an info.xml file")); } $info = OC_App::getAppInfo($extractDir . '/appinfo/info.xml', true); // check the code for not allowed calls if (!$isShipped && !OC_Installer::checkCode($info['id'], $extractDir)) { OC_Helper::rmdirr($extractDir); throw new \Exception($l->t("App can't be installed because of not allowed code in the App")); } // check if the app is compatible with this version of ownCloud if (!OC_App::isAppCompatible(OC_Util::getVersion(), $info)) { OC_Helper::rmdirr($extractDir); throw new \Exception($l->t("App can't be installed because it is not compatible with this version of ownCloud")); } // check if shipped tag is set which is only allowed for apps that are shipped with ownCloud if (!$isShipped && isset($info['shipped']) && $info['shipped'] == 'true') { OC_Helper::rmdirr($extractDir); throw new \Exception($l->t("App can't be installed because it contains the <shipped>true</shipped> tag which is not allowed for non shipped apps")); } // check if the ocs version is the same as the version in info.xml/version $versionFile = $extractDir . '/appinfo/version'; if (is_file($versionFile)) { $version = trim(file_get_contents($versionFile)); } else { $version = trim($info['version']); } if (isset($data['appdata']['version']) && $version != trim($data['appdata']['version'])) { OC_Helper::rmdirr($extractDir); throw new \Exception($l->t("App can't be installed because the version in info.xml/version is not the same as the version reported from the app store")); } return $info; }
/** * Test that the isAppCompatible method also supports passing an array * as $ocVersion */ public function testIsAppCompatibleWithArray() { $ocVersion = array(6); $appInfo = array('requiremin' => '6', 'requiremax' => '6'); $this->assertTrue(OC_App::isAppCompatible($ocVersion, $appInfo)); }
/** * @param string $version the oc version to check app compatibility with */ protected function checkAppUpgrade($version) { $apps = \OC_App::getEnabledApps(); $this->emit('\\OC\\Updater', 'appUpgradeCheckBefore'); foreach ($apps as $appId) { $info = \OC_App::getAppInfo($appId); $compatible = \OC_App::isAppCompatible($version, $info); $isShipped = \OC_App::isShipped($appId); if ($compatible && $isShipped && \OC_App::shouldUpgrade($appId)) { /** * FIXME: The preupdate check is performed before the database migration, otherwise database changes * are not possible anymore within it. - Consider this when touching the code. * @link https://github.com/owncloud/core/issues/10980 * @see \OC_App::updateApp */ if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/preupdate.php')) { $this->includePreUpdate($appId); } if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/database.xml')) { $this->emit('\\OC\\Updater', 'appSimulateUpdate', array($appId)); \OC_DB::simulateUpdateDbFromStructure(\OC_App::getAppPath($appId) . '/appinfo/database.xml'); } } } $this->emit('\\OC\\Updater', 'appUpgradeCheck'); }
/** * Returns a list of apps incompatible with the given version * * @param array $version ownCloud version as array of version components * * @return array list of app info from incompatible apps * * @internal */ public function getIncompatibleApps($version) { $apps = $this->getInstalledApps(); $incompatibleApps = array(); foreach ($apps as $appId) { $info = $this->getAppInfo($appId); if (!\OC_App::isAppCompatible($version, $info)) { $incompatibleApps[] = $info; } } return $incompatibleApps; }
/** * Checks if the version requires an update and shows * @param bool $showTemplate Whether an update screen should get shown * @return bool|void */ public static function checkUpgrade($showTemplate = true) { if (\OCP\Util::needUpgrade()) { $systemConfig = \OC::$server->getSystemConfig(); if ($showTemplate && !$systemConfig->getValue('maintenance', false)) { $version = OC_Util::getVersion(); $oldTheme = $systemConfig->getValue('theme'); $systemConfig->setValue('theme', ''); OC_Util::addScript('config'); // needed for web root OC_Util::addScript('update'); $tmpl = new OC_Template('', 'update.admin', 'guest'); $tmpl->assign('version', OC_Util::getVersionString()); // get third party apps $apps = OC_App::getEnabledApps(); $incompatibleApps = array(); foreach ($apps as $appId) { $info = OC_App::getAppInfo($appId); if (!OC_App::isAppCompatible($version, $info)) { $incompatibleApps[] = $info; } } $tmpl->assign('appList', $incompatibleApps); $tmpl->assign('productName', 'ownCloud'); // for now $tmpl->assign('oldTheme', $oldTheme); $tmpl->printPage(); exit; } else { return true; } } return false; }
/** * check an app's integrity * @param array $data * @param string $extractDir * @param string $path * @param bool $isShipped * @return array * @throws \Exception */ public static function checkAppsIntegrity($data, $extractDir, $path, $isShipped = false) { $l = \OC::$server->getL10N('lib'); //load the info.xml file of the app if (!is_file($extractDir . '/appinfo/info.xml')) { //try to find it in a subdir $dh = opendir($extractDir); if (is_resource($dh)) { while (($folder = readdir($dh)) !== false) { if ($folder[0] != '.' and is_dir($extractDir . '/' . $folder)) { if (is_file($extractDir . '/' . $folder . '/appinfo/info.xml')) { $extractDir .= '/' . $folder; } } } } } if (!is_file($extractDir . '/appinfo/info.xml')) { OC_Helper::rmdirr($extractDir); if ($data['source'] === 'http') { unlink($path); } throw new \Exception($l->t("App does not provide an info.xml file")); } $info = OC_App::getAppInfo($extractDir . '/appinfo/info.xml', true); // We can't trust the parsed info.xml file as it may have been tampered // with by an attacker and thus we need to use the local data to check // whether the application needs to be signed. $appId = OC_App::cleanAppId($data['appdata']['id']); $appBelongingToId = OC_App::getInternalAppIdByOcs($appId); if (is_string($appBelongingToId)) { $previouslySigned = \OC::$server->getConfig()->getAppValue($appBelongingToId, 'signed', 'false'); } else { $appBelongingToId = $info['id']; $previouslySigned = 'false'; } if ($data['appdata']['level'] === OC_App::officialApp || $previouslySigned === 'true') { \OC::$server->getConfig()->setAppValue($appBelongingToId, 'signed', 'true'); $integrityResult = \OC::$server->getIntegrityCodeChecker()->verifyAppSignature($appBelongingToId, $extractDir); if ($integrityResult !== []) { $e = new \Exception($l->t('Signature could not get checked. Please contact the app developer and check your admin screen.')); throw $e; } } // check the code for not allowed calls if (!$isShipped && !OC_Installer::checkCode($extractDir)) { OC_Helper::rmdirr($extractDir); throw new \Exception($l->t("App can't be installed because of not allowed code in the App")); } // check if the app is compatible with this version of ownCloud if (!OC_App::isAppCompatible(\OCP\Util::getVersion(), $info)) { OC_Helper::rmdirr($extractDir); throw new \Exception($l->t("App can't be installed because it is not compatible with this version of ownCloud")); } // check if shipped tag is set which is only allowed for apps that are shipped with ownCloud if (!$isShipped && isset($info['shipped']) && $info['shipped'] == 'true') { OC_Helper::rmdirr($extractDir); throw new \Exception($l->t("App can't be installed because it contains the <shipped>true</shipped> tag which is not allowed for non shipped apps")); } // check if the ocs version is the same as the version in info.xml/version $version = trim($info['version']); if (isset($data['appdata']['version']) && $version != trim($data['appdata']['version'])) { OC_Helper::rmdirr($extractDir); throw new \Exception($l->t("App can't be installed because the version in info.xml is not the same as the version reported from the app store")); } return $info; }
/** * runs the update actions in maintenance mode, does not upgrade the source files * except the main .htaccess file * * @param string $currentVersion current version to upgrade to * @param string $installedVersion previous version from which to upgrade from * * @return bool true if the operation succeeded, false otherwise */ private function doUpgrade($currentVersion, $installedVersion) { // Update htaccess files for apache hosts if (isset($_SERVER['SERVER_SOFTWARE']) && strstr($_SERVER['SERVER_SOFTWARE'], 'Apache')) { \OC_Setup::updateHtaccess(); } // create empty file in data dir, so we can later find // out that this is indeed an ownCloud data directory // (in case it didn't exist before) file_put_contents(\OC_Config::getValue('datadirectory', \OC::$SERVERROOT . '/data') . '/.ocdata', ''); /* * START CONFIG CHANGES FOR OLDER VERSIONS */ if (!\OC::$CLI && version_compare($installedVersion, '6.90.1', '<')) { // Add the trusted_domains config if it is not existant // This is added to prevent host header poisoning \OC_Config::setValue('trusted_domains', \OC_Config::getValue('trusted_domains', array(\OC_Request::serverHost()))); } /* * STOP CONFIG CHANGES FOR OLDER VERSIONS */ // pre-upgrade repairs $repair = new \OC\Repair(\OC\Repair::getBeforeUpgradeRepairSteps()); $repair->run(); // simulate DB upgrade if ($this->simulateStepEnabled) { // simulate core DB upgrade \OC_DB::simulateUpdateDbFromStructure(\OC::$SERVERROOT . '/db_structure.xml'); // simulate apps DB upgrade $version = \OC_Util::getVersion(); $apps = \OC_App::getEnabledApps(); foreach ($apps as $appId) { $info = \OC_App::getAppInfo($appId); if (\OC_App::isAppCompatible($version, $info) && \OC_App::shouldUpgrade($appId)) { if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/database.xml')) { \OC_DB::simulateUpdateDbFromStructure(\OC_App::getAppPath($appId) . '/appinfo/database.xml'); } } } $this->emit('\\OC\\Updater', 'dbSimulateUpgrade'); } // upgrade from OC6 to OC7 // TODO removed it again for OC8 $sharePolicy = \OC_Appconfig::getValue('core', 'shareapi_share_policy', 'global'); if ($sharePolicy === 'groups_only') { \OC_Appconfig::setValue('core', 'shareapi_only_share_with_group_members', 'yes'); } if ($this->updateStepEnabled) { // do the real upgrade \OC_DB::updateDbFromStructure(\OC::$SERVERROOT . '/db_structure.xml'); $this->emit('\\OC\\Updater', 'dbUpgrade'); // TODO: why not do this at the end ? \OC_Config::setValue('version', implode('.', \OC_Util::getVersion())); $disabledApps = \OC_App::checkAppsRequirements(); if (!empty($disabledApps)) { $this->emit('\\OC\\Updater', 'disabledApps', array($disabledApps)); } // load all apps to also upgrade enabled apps \OC_App::loadApps(); // post-upgrade repairs $repair = new \OC\Repair(\OC\Repair::getRepairSteps()); $repair->run(); //Invalidate update feed \OC_Appconfig::setValue('core', 'lastupdatedat', 0); } }
/** * @param string $version the oc version to check app compatibilty with */ protected function checkAppUpgrade($version) { $apps = \OC_App::getEnabledApps(); foreach ($apps as $appId) { if ($version) { $info = \OC_App::getAppInfo($appId); $compatible = \OC_App::isAppCompatible($version, $info); } else { $compatible = true; } if ($compatible && \OC_App::shouldUpgrade($appId)) { if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/database.xml')) { \OC_DB::simulateUpdateDbFromStructure(\OC_App::getAppPath($appId) . '/appinfo/database.xml'); } } } $this->emit('\\OC\\Updater', 'appUpgradeCheck'); }