aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/dav/appinfo/info.xml3
-rw-r--r--apps/dav/composer/composer/autoload_classmap.php2
-rw-r--r--apps/dav/composer/composer/autoload_static.php2
-rw-r--r--apps/dav/lib/DAV/CustomPropertiesBackend.php70
-rw-r--r--apps/dav/lib/Migration/RemoveObjectProperties.php65
-rw-r--r--apps/dav/lib/Migration/Version1024Date20211221144219.php58
6 files changed, 187 insertions, 13 deletions
diff --git a/apps/dav/appinfo/info.xml b/apps/dav/appinfo/info.xml
index 10f78d8332a..deb99b1c33b 100644
--- a/apps/dav/appinfo/info.xml
+++ b/apps/dav/appinfo/info.xml
@@ -5,7 +5,7 @@
<name>WebDAV</name>
<summary>WebDAV endpoint</summary>
<description>WebDAV endpoint</description>
- <version>1.23.0</version>
+ <version>1.24.0</version>
<licence>agpl</licence>
<author>owncloud.org</author>
<namespace>DAV</namespace>
@@ -39,6 +39,7 @@
<step>OCA\DAV\Migration\RemoveOrphanEventsAndContacts</step>
<step>OCA\DAV\Migration\RemoveClassifiedEventActivity</step>
<step>OCA\DAV\Migration\RemoveDeletedUsersCalendarSubscriptions</step>
+ <step>OCA\DAV\Migration\RemoveObjectProperties</step>
</post-migration>
<live-migration>
<step>OCA\DAV\Migration\ChunkCleanup</step>
diff --git a/apps/dav/composer/composer/autoload_classmap.php b/apps/dav/composer/composer/autoload_classmap.php
index f40917fbd01..6f02140df40 100644
--- a/apps/dav/composer/composer/autoload_classmap.php
+++ b/apps/dav/composer/composer/autoload_classmap.php
@@ -257,6 +257,7 @@ return array(
'OCA\\DAV\\Migration\\RegisterBuildReminderIndexBackgroundJob' => $baseDir . '/../lib/Migration/RegisterBuildReminderIndexBackgroundJob.php',
'OCA\\DAV\\Migration\\RemoveClassifiedEventActivity' => $baseDir . '/../lib/Migration/RemoveClassifiedEventActivity.php',
'OCA\\DAV\\Migration\\RemoveDeletedUsersCalendarSubscriptions' => $baseDir . '/../lib/Migration/RemoveDeletedUsersCalendarSubscriptions.php',
+ 'OCA\\DAV\\Migration\\RemoveObjectProperties' => $baseDir . '/../lib/Migration/RemoveObjectProperties.php',
'OCA\\DAV\\Migration\\RemoveOrphanEventsAndContacts' => $baseDir . '/../lib/Migration/RemoveOrphanEventsAndContacts.php',
'OCA\\DAV\\Migration\\Version1004Date20170825134824' => $baseDir . '/../lib/Migration/Version1004Date20170825134824.php',
'OCA\\DAV\\Migration\\Version1004Date20170919104507' => $baseDir . '/../lib/Migration/Version1004Date20170919104507.php',
@@ -278,6 +279,7 @@ return array(
'OCA\\DAV\\Migration\\Version1016Date20201109085907' => $baseDir . '/../lib/Migration/Version1016Date20201109085907.php',
'OCA\\DAV\\Migration\\Version1017Date20210216083742' => $baseDir . '/../lib/Migration/Version1017Date20210216083742.php',
'OCA\\DAV\\Migration\\Version1018Date20210312100735' => $baseDir . '/../lib/Migration/Version1018Date20210312100735.php',
+ 'OCA\\DAV\\Migration\\Version1024Date20211221144219' => $baseDir . '/../lib/Migration/Version1024Date20211221144219.php',
'OCA\\DAV\\Profiler\\ProfilerPlugin' => $baseDir . '/../lib/Profiler/ProfilerPlugin.php',
'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningNode' => $baseDir . '/../lib/Provisioning/Apple/AppleProvisioningNode.php',
'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningPlugin' => $baseDir . '/../lib/Provisioning/Apple/AppleProvisioningPlugin.php',
diff --git a/apps/dav/composer/composer/autoload_static.php b/apps/dav/composer/composer/autoload_static.php
index 60b437c9fac..296b8a497c9 100644
--- a/apps/dav/composer/composer/autoload_static.php
+++ b/apps/dav/composer/composer/autoload_static.php
@@ -272,6 +272,7 @@ class ComposerStaticInitDAV
'OCA\\DAV\\Migration\\RegisterBuildReminderIndexBackgroundJob' => __DIR__ . '/..' . '/../lib/Migration/RegisterBuildReminderIndexBackgroundJob.php',
'OCA\\DAV\\Migration\\RemoveClassifiedEventActivity' => __DIR__ . '/..' . '/../lib/Migration/RemoveClassifiedEventActivity.php',
'OCA\\DAV\\Migration\\RemoveDeletedUsersCalendarSubscriptions' => __DIR__ . '/..' . '/../lib/Migration/RemoveDeletedUsersCalendarSubscriptions.php',
+ 'OCA\\DAV\\Migration\\RemoveObjectProperties' => __DIR__ . '/..' . '/../lib/Migration/RemoveObjectProperties.php',
'OCA\\DAV\\Migration\\RemoveOrphanEventsAndContacts' => __DIR__ . '/..' . '/../lib/Migration/RemoveOrphanEventsAndContacts.php',
'OCA\\DAV\\Migration\\Version1004Date20170825134824' => __DIR__ . '/..' . '/../lib/Migration/Version1004Date20170825134824.php',
'OCA\\DAV\\Migration\\Version1004Date20170919104507' => __DIR__ . '/..' . '/../lib/Migration/Version1004Date20170919104507.php',
@@ -293,6 +294,7 @@ class ComposerStaticInitDAV
'OCA\\DAV\\Migration\\Version1016Date20201109085907' => __DIR__ . '/..' . '/../lib/Migration/Version1016Date20201109085907.php',
'OCA\\DAV\\Migration\\Version1017Date20210216083742' => __DIR__ . '/..' . '/../lib/Migration/Version1017Date20210216083742.php',
'OCA\\DAV\\Migration\\Version1018Date20210312100735' => __DIR__ . '/..' . '/../lib/Migration/Version1018Date20210312100735.php',
+ 'OCA\\DAV\\Migration\\Version1024Date20211221144219' => __DIR__ . '/..' . '/../lib/Migration/Version1024Date20211221144219.php',
'OCA\\DAV\\Profiler\\ProfilerPlugin' => __DIR__ . '/..' . '/../lib/Profiler/ProfilerPlugin.php',
'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningNode' => __DIR__ . '/..' . '/../lib/Provisioning/Apple/AppleProvisioningNode.php',
'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningPlugin' => __DIR__ . '/..' . '/../lib/Provisioning/Apple/AppleProvisioningPlugin.php',
diff --git a/apps/dav/lib/DAV/CustomPropertiesBackend.php b/apps/dav/lib/DAV/CustomPropertiesBackend.php
index acee65cd00d..bd09ac2e4e6 100644
--- a/apps/dav/lib/DAV/CustomPropertiesBackend.php
+++ b/apps/dav/lib/DAV/CustomPropertiesBackend.php
@@ -31,6 +31,7 @@ use Sabre\DAV\PropertyStorage\Backend\BackendInterface;
use Sabre\DAV\PropFind;
use Sabre\DAV\PropPatch;
use Sabre\DAV\Tree;
+use Sabre\DAV\Xml\Property\Complex;
use function array_intersect;
class CustomPropertiesBackend implements BackendInterface {
@@ -39,6 +40,21 @@ class CustomPropertiesBackend implements BackendInterface {
private const TABLE_NAME = 'properties';
/**
+ * Value is stored as string.
+ */
+ public const PROPERTY_TYPE_STRING = 1;
+
+ /**
+ * Value is stored as XML fragment.
+ */
+ public const PROPERTY_TYPE_XML = 2;
+
+ /**
+ * Value is stored as a property object.
+ */
+ public const PROPERTY_TYPE_OBJECT = 3;
+
+ /**
* Ignored properties
*
* @var string[]
@@ -239,7 +255,7 @@ class CustomPropertiesBackend implements BackendInterface {
$result = $qb->executeQuery();
$props = [];
while ($row = $result->fetch()) {
- $props[$row['propertyname']] = $row['propertyvalue'];
+ $props[$row['propertyname']] = $this->decodeValueFromDatabase($row['propertyvalue'], $row['valuetype']);
}
$result->closeCursor();
return $props;
@@ -282,7 +298,7 @@ class CustomPropertiesBackend implements BackendInterface {
$props = [];
while ($row = $result->fetch()) {
- $props[$row['propertyname']] = $row['propertyvalue'];
+ $props[$row['propertyname']] = $this->decodeValueFromDatabase($row['propertyvalue'], $row['valuetype']);
}
$result->closeCursor();
@@ -304,9 +320,9 @@ class CustomPropertiesBackend implements BackendInterface {
' WHERE `userid` = ? AND `propertypath` = ? AND `propertyname` = ?';
$insertStatement = 'INSERT INTO `*PREFIX*properties`' .
- ' (`userid`,`propertypath`,`propertyname`,`propertyvalue`) VALUES(?,?,?,?)';
+ ' (`userid`,`propertypath`,`propertyname`,`propertyvalue`, `valuetype`) VALUES(?,?,?,?,?)';
- $updateStatement = 'UPDATE `*PREFIX*properties` SET `propertyvalue` = ?' .
+ $updateStatement = 'UPDATE `*PREFIX*properties` SET `propertyvalue` = ?, `valuetype` = ?' .
' WHERE `userid` = ? AND `propertypath` = ? AND `propertyname` = ?';
// TODO: use "insert or update" strategy ?
@@ -325,24 +341,22 @@ class CustomPropertiesBackend implements BackendInterface {
);
}
} else {
- if ($propertyValue instanceOf \Sabre\DAV\Xml\Property\Complex) {
- $propertyValue = $propertyValue->getXml();
- } elseif (!is_string($propertyValue)) {
- $propertyValue = (string)$propertyValue;
- }
+ [$value, $valueType] = $this->encodeValueForDatabase($propertyValue);
if (!array_key_exists($propertyName, $existing)) {
$this->connection->executeUpdate($insertStatement,
[
$this->user->getUID(),
$this->formatPath($path),
$propertyName,
- $propertyValue,
+ $value,
+ $valueType
]
);
} else {
$this->connection->executeUpdate($updateStatement,
[
- $propertyValue,
+ $value,
+ $valueType,
$this->user->getUID(),
$this->formatPath($path),
$propertyName,
@@ -367,8 +381,40 @@ class CustomPropertiesBackend implements BackendInterface {
private function formatPath(string $path): string {
if (strlen($path) > 250) {
return sha1($path);
+ }
+
+ return $path;
+ }
+
+ /**
+ * @param mixed $value
+ * @return array
+ */
+ private function encodeValueForDatabase($value): array {
+ if (is_scalar($value)) {
+ $valueType = self::PROPERTY_TYPE_STRING;
+ } elseif ($value instanceof Complex) {
+ $valueType = self::PROPERTY_TYPE_XML;
+ $value = $value->getXml();
} else {
- return $path;
+ $valueType = self::PROPERTY_TYPE_OBJECT;
+ $value = serialize($value);
+ }
+ return [$value, $valueType];
+ }
+
+ /**
+ * @return mixed|Complex|string
+ */
+ private function decodeValueFromDatabase(string $value, int $valueType) {
+ switch ($valueType) {
+ case self::PROPERTY_TYPE_XML:
+ return new Complex($value);
+ case self::PROPERTY_TYPE_OBJECT:
+ return unserialize($value);
+ case self::PROPERTY_TYPE_STRING:
+ default:
+ return $value;
}
}
}
diff --git a/apps/dav/lib/Migration/RemoveObjectProperties.php b/apps/dav/lib/Migration/RemoveObjectProperties.php
new file mode 100644
index 00000000000..c72dfbebfea
--- /dev/null
+++ b/apps/dav/lib/Migration/RemoveObjectProperties.php
@@ -0,0 +1,65 @@
+<?php
+/**
+ * @copyright Copyright (c) 2021, Thomas Citharel <nextcloud@tcit.fr>.
+ *
+ * @author Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * 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, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCA\DAV\Migration;
+
+use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\IDBConnection;
+use OCP\Migration\IOutput;
+use OCP\Migration\IRepairStep;
+
+class RemoveObjectProperties implements IRepairStep {
+ private const RESOURCE_TYPE_PROPERTY = '{DAV:}resourcetype';
+ private const ME_CARD_PROPERTY = '{http://calendarserver.org/ns/}me-card';
+ private const CALENDAR_TRANSP_PROPERTY = '{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp';
+
+ /** @var IDBConnection */
+ private $connection;
+
+ /**
+ * RemoveObjectProperties constructor.
+ *
+ * @param IDBConnection $connection
+ */
+ public function __construct(IDBConnection $connection) {
+ $this->connection = $connection;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getName() {
+ return 'Remove invalid object properties';
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function run(IOutput $output) {
+ $query = $this->connection->getQueryBuilder();
+ $updated = $query->delete('properties')
+ ->where($query->expr()->in('propertyname', $query->createNamedParameter([self::RESOURCE_TYPE_PROPERTY, self::ME_CARD_PROPERTY, self::CALENDAR_TRANSP_PROPERTY], IQueryBuilder::PARAM_STR_ARRAY)))
+ ->andWhere($query->expr()->eq('propertyvalue', $query->createNamedParameter('Object')))
+ ->executeStatement();
+
+ $output->info("$updated invalid object properties removed.");
+ }
+}
diff --git a/apps/dav/lib/Migration/Version1024Date20211221144219.php b/apps/dav/lib/Migration/Version1024Date20211221144219.php
new file mode 100644
index 00000000000..b93f8ac801e
--- /dev/null
+++ b/apps/dav/lib/Migration/Version1024Date20211221144219.php
@@ -0,0 +1,58 @@
+<?php
+
+declare(strict_types=1);
+
+namespace OCA\DAV\Migration;
+
+use Closure;
+use Doctrine\DBAL\Schema\SchemaException;
+use OCA\DAV\DAV\CustomPropertiesBackend;
+use OCP\DB\ISchemaWrapper;
+use OCP\DB\Types;
+use OCP\Migration\IOutput;
+use OCP\Migration\SimpleMigrationStep;
+
+/**
+ * Auto-generated migration step: Please modify to your needs!
+ */
+class Version1024Date20211221144219 extends SimpleMigrationStep {
+
+ /**
+ * @param IOutput $output
+ * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
+ * @param array $options
+ */
+ public function preSchemaChange(IOutput $output, Closure $schemaClosure, array $options): void {
+ }
+
+ /**
+ * @param IOutput $output
+ * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
+ * @param array $options
+ * @return null|ISchemaWrapper
+ * @throws SchemaException
+ */
+ public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
+ /** @var ISchemaWrapper $schema */
+ $schema = $schemaClosure();
+ $propertiesTable = $schema->getTable('properties');
+
+ if ($propertiesTable->hasColumn('valuetype')) {
+ return null;
+ }
+ $propertiesTable->addColumn('valuetype', Types::SMALLINT, [
+ 'notnull' => false,
+ 'default' => CustomPropertiesBackend::PROPERTY_TYPE_STRING
+ ]);
+
+ return $schema;
+ }
+
+ /**
+ * @param IOutput $output
+ * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
+ * @param array $options
+ */
+ public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options): void {
+ }
+}