Skip to content

Commit

Permalink
Merge pull request #3415 from nextcloud/backport-3184-migration-restr…
Browse files Browse the repository at this point in the history
…iction-by-vendor-version

[stable11] Prevent migration from ownCloud 10 to Nextcloud 11
  • Loading branch information
rullzer committed Mar 30, 2017
2 parents fc43bbe + cf8a680 commit 00a023e
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 104 deletions.
57 changes: 38 additions & 19 deletions lib/private/Updater.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,22 @@ class Updater extends BasicEmitter {
4 => 'Fatal',
];

static protected $validNextcloudReleases = [
'11.0.2.7',
'11.0.2.0',
'11.0.1.2',
'11.0.1.1',
'11.0.0.10',
'11.0.0.7',
'9.1.4.2',
'9.1.4.0',
'9.1.3.2',
'9.1.3.1',
'9.1.1.5',
'9.1.1.0',
'9.1.0.15',
];

/**
* @param IConfig $config
* @param Checker $checker
Expand Down Expand Up @@ -151,13 +167,13 @@ public function upgrade() {
/**
* Return version from which this version is allowed to upgrade from
*
* @return string allowed previous version
* @return array allowed previous versions per vendor
*/
private function getAllowedPreviousVersion() {
private function getAllowedPreviousVersions() {
// this should really be a JSON file
require \OC::$SERVERROOT . '/version.php';
/** @var array $OC_VersionCanBeUpgradedFrom */
return implode('.', $OC_VersionCanBeUpgradedFrom);
return $OC_VersionCanBeUpgradedFrom;
}

/**
Expand All @@ -176,26 +192,29 @@ private function getVendor() {
* Whether an upgrade to a specified version is possible
* @param string $oldVersion
* @param string $newVersion
* @param string $allowedPreviousVersion
* @param array $allowedPreviousVersions
* @return bool
*/
public function isUpgradePossible($oldVersion, $newVersion, $allowedPreviousVersion) {
$allowedUpgrade = (version_compare($allowedPreviousVersion, $oldVersion, '<=')
&& (version_compare($oldVersion, $newVersion, '<=') || $this->config->getSystemValue('debug', false)));

if ($allowedUpgrade) {
return $allowedUpgrade;
public function isUpgradePossible($oldVersion, $newVersion, array $allowedPreviousVersions) {
$version = explode('.', $oldVersion);
$majorMinor = $version[0] . '.' . $version[1];

$currentVendor = $this->config->getAppValue('core', 'vendor', '');
if ($currentVendor === 'nextcloud') {
return isset($allowedPreviousVersions[$currentVendor][$majorMinor])
&& (version_compare($oldVersion, $newVersion, '<=') ||
$this->config->getSystemValue('debug', false));
}

// Upgrade not allowed, someone switching vendor?
if ($this->getVendor() !== $this->config->getAppValue('core', 'vendor', '')) {
$oldVersion = explode('.', $oldVersion);
$newVersion = explode('.', $newVersion);

return $oldVersion[0] === $newVersion[0] && $oldVersion[1] === $newVersion[1];
if ($currentVendor === '') {
// Installed Nextcloud 10 or 11 where the install didn't set the vendor?
if (in_array($oldVersion, self::$validNextcloudReleases, true)) {
return true;
}
}

return false;
// Check if the instance can be migrated
return isset($allowedPreviousVersions[$currentVendor][$majorMinor]);
}

/**
Expand All @@ -209,8 +228,8 @@ public function isUpgradePossible($oldVersion, $newVersion, $allowedPreviousVers
*/
private function doUpgrade($currentVersion, $installedVersion) {
// Stop update if the update is over several major versions
$allowedPreviousVersion = $this->getAllowedPreviousVersion();
if (!self::isUpgradePossible($installedVersion, $currentVersion, $allowedPreviousVersion)) {
$allowedPreviousVersions = $this->getAllowedPreviousVersions();
if (!$this->isUpgradePossible($installedVersion, $currentVersion, $allowedPreviousVersions)) {
throw new \Exception('Updates between multiple major versions and downgrades are unsupported.');
}

Expand Down
107 changes: 23 additions & 84 deletions tests/lib/UpdaterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,93 +56,32 @@ public function setUp() {
);
}

/**
* @param string $baseUrl
* @return string
*/
private function buildUpdateUrl($baseUrl) {
return $baseUrl . '?version='.implode('x', \OCP\Util::getVersion()).'xinstalledatxlastupdatedatx'.\OC_Util::getChannel().'xx';
}

/**
* @return array
*/
public function versionCompatibilityTestData() {
return [
['1', '2', '1', true],
['2', '2', '2', true],
['6.0.5.0', '6.0.6.0', '5.0', true],
['5.0.6.0', '7.0.4.0', '6.0', false],
// allow upgrading within the same major release
['8.0.0.0', '8.0.0.0', '8.0', true],
['8.0.0.0', '8.0.0.4', '8.0', true],
['8.0.0.0', '8.0.1.0', '8.0', true],
['8.0.0.0', '8.0.2.0', '8.0', true],
// does not allow downgrading within the same major release
['8.0.1.0', '8.0.0.0', '8.0', false],
['8.0.2.0', '8.0.1.0', '8.0', false],
['8.0.0.4', '8.0.0.0', '8.0', false],
// allows upgrading within the patch version
['8.0.0.0', '8.0.0.1', '8.0', true],
['8.0.0.0', '8.0.0.2', '8.0', true],
// does not allow downgrading within the same major release
['8.0.0.1', '8.0.0.0', '8.0', false],
['8.0.0.2', '8.0.0.0', '8.0', false],
// allow upgrading to the next major release
['8.0.0.0', '8.1.0.0', '8.0', true],
['8.0.0.0', '8.1.1.0', '8.0', true],
['8.0.0.0', '8.1.1.5', '8.0', true],
['8.0.0.2', '8.1.1.5', '8.0', true],
['8.1.0.0', '8.2.0.0', '8.1', true],
['8.1.0.2', '8.2.0.4', '8.1', true],
['8.1.0.5', '8.2.0.1', '8.1', true],
['8.1.0.0', '8.2.1.0', '8.1', true],
['8.1.0.2', '8.2.1.5', '8.1', true],
['8.1.0.5', '8.2.1.1', '8.1', true],
// does not allow downgrading to the previous major release
['8.1.0.0', '8.0.0.0', '7.0', false],
['8.1.1.0', '8.0.0.0', '7.0', false],
// does not allow skipping major releases
['8.0.0.0', '8.2.0.0', '8.1', false],
['8.0.0.0', '8.2.1.0', '8.1', false],
['8.0.0.0', '9.0.1.0', '8.2', false],
['8.0.0.0', '10.0.0.0', '9.3', false],
// allows updating to the next major release
['8.2.0.0', '9.0.0.0', '8.2', true],
['8.2.0.0', '9.0.0.0', '8.2', true],
['8.2.0.0', '9.0.1.0', '8.2', true],
['8.2.0.0', '9.0.1.1', '8.2', true],
['8.2.0.2', '9.0.1.1', '8.2', true],
['8.2.2.0', '9.0.1.0', '8.2', true],
['8.2.2.2', '9.0.1.1', '8.2', true],
['9.0.0.0', '9.1.0.0', '9.0', true],
['9.0.0.0', '9.1.0.2', '9.0', true],
['9.0.0.2', '9.1.0.1', '9.0', true],
['9.1.0.0', '9.2.0.0', '9.1', true],
['9.2.0.0', '9.3.0.0', '9.2', true],
['9.3.0.0', '10.0.0.0', '9.3', true],
// does not allow updating to the next major release (first number)
['9.0.0.0', '8.2.0.0', '8.1', false],
// other cases
['8.0.0.0', '8.1.5.0', '8.0', true],
['8.2.0.0', '9.0.0.0', '8.2', true],
['8.2.0.0', '9.1.0.0', '9.0', false],
['9.0.0.0', '8.1.0.0', '8.0', false],
['9.0.0.0', '8.0.0.0', '7.0', false],
['9.1.0.0', '8.0.0.0', '7.0', false],
['8.2.0.0', '8.1.0.0', '8.0', false],

// With debug enabled
['8.0.0.0', '8.2.0.0', '8.1', false, true],
['8.1.0.0', '8.2.0.0', '8.1', true, true],
['8.2.0.1', '8.2.0.1', '8.1', true, true],
['8.3.0.0', '8.2.0.0', '8.1', true, true],
// Upgrade with invalid version
['9.1.1.13', '11.0.2.25', ['nextcloud' => ['11.0' => true]], false],
['10.0.1.13', '11.0.2.25', ['nextcloud' => ['11.0' => true]], false],
// Upgrad with valid version
['11.0.1.13', '11.0.2.25', ['nextcloud' => ['11.0' => true]], true],
// Downgrade with valid version
['11.0.2.25', '11.0.1.13', ['nextcloud' => ['11.0' => true]], false],
['11.0.2.25', '11.0.1.13', ['nextcloud' => ['11.0' => true]], true, true],
// Downgrade with invalid version
['11.0.2.25', '10.0.1.13', ['nextcloud' => ['10.0' => true]], false],
['11.0.2.25', '10.0.1.13', ['nextcloud' => ['10.0' => true]], false, true],

// Downgrade of maintenance
['9.0.53.0', '9.0.4.0', '8.1', false, false, 'nextcloud'],
// with vendor switch
['9.0.53.0', '9.0.4.0', '8.1', true, false, ''],
['9.0.53.0', '9.0.4.0', '8.1', true, false, 'owncloud'],
// Migration with unknown vendor
['9.1.1.13', '11.0.2.25', ['nextcloud' => ['9.1' => true]], false, false, 'owncloud'],
['9.1.1.13', '11.0.2.25', ['nextcloud' => ['9.1' => true]], false, true, 'owncloud'],
// Migration with unsupported vendor version
['9.1.1.13', '11.0.2.25', ['owncloud' => ['10.0' => true]], false, false, 'owncloud'],
['9.1.1.13', '11.0.2.25', ['owncloud' => ['10.0' => true]], false, true, 'owncloud'],
// Migration with valid vendor version
['9.1.1.13', '11.0.2.25', ['owncloud' => ['9.1' => true]], true, false, 'owncloud'],
['9.1.1.13', '11.0.2.25', ['owncloud' => ['9.1' => true]], true, true, 'owncloud'],
];
}

Expand All @@ -151,12 +90,12 @@ public function versionCompatibilityTestData() {
*
* @param string $oldVersion
* @param string $newVersion
* @param string $allowedVersion
* @param array $allowedVersions
* @param bool $result
* @param bool $debug
* @param string $vendor
*/
public function testIsUpgradePossible($oldVersion, $newVersion, $allowedVersion, $result, $debug = false, $vendor = 'nextcloud') {
public function testIsUpgradePossible($oldVersion, $newVersion, $allowedVersions, $result, $debug = false, $vendor = 'nextcloud') {
$this->config->expects($this->any())
->method('getSystemValue')
->with('debug', false)
Expand All @@ -166,7 +105,7 @@ public function testIsUpgradePossible($oldVersion, $newVersion, $allowedVersion,
->with('core', 'vendor', '')
->willReturn($vendor);

$this->assertSame($result, $this->updater->isUpgradePossible($oldVersion, $newVersion, $allowedVersion));
$this->assertSame($result, $this->updater->isUpgradePossible($oldVersion, $newVersion, $allowedVersions));
}

public function testSetSkip3rdPartyAppsDisable() {
Expand Down
10 changes: 9 additions & 1 deletion version.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,15 @@
// The human readable string
$OC_VersionString = '11.0.2';

$OC_VersionCanBeUpgradedFrom = array(9, 1);
$OC_VersionCanBeUpgradedFrom = [
'nextcloud' => [
'9.1' => true,
'11.0' => true,
],
'owncloud' => [
'9.1' => true,
],
];

// default Nextcloud channel
$OC_Channel = 'git';
Expand Down

0 comments on commit 00a023e

Please sign in to comment.