aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/sabre/dav/lib/DAV/Sync
diff options
context:
space:
mode:
authorredmatrix <git@macgirvin.com>2016-05-10 17:26:44 -0700
committerredmatrix <git@macgirvin.com>2016-05-10 17:26:44 -0700
commit0b02a6d123b2014705998c94ddf3d460948d3eac (patch)
tree78ff2cab9944a4f5ab3f80ec93cbe1120de90bb2 /vendor/sabre/dav/lib/DAV/Sync
parent40b5b6e9d2da7ab65c8b4d38cdceac83a4d78deb (diff)
downloadvolse-hubzilla-0b02a6d123b2014705998c94ddf3d460948d3eac.tar.gz
volse-hubzilla-0b02a6d123b2014705998c94ddf3d460948d3eac.tar.bz2
volse-hubzilla-0b02a6d123b2014705998c94ddf3d460948d3eac.zip
initial sabre upgrade (needs lots of work - to wit: authentication, redo the browser interface, and rework event export/import)
Diffstat (limited to 'vendor/sabre/dav/lib/DAV/Sync')
-rw-r--r--vendor/sabre/dav/lib/DAV/Sync/ISyncCollection.php88
-rw-r--r--vendor/sabre/dav/lib/DAV/Sync/Plugin.php277
2 files changed, 365 insertions, 0 deletions
diff --git a/vendor/sabre/dav/lib/DAV/Sync/ISyncCollection.php b/vendor/sabre/dav/lib/DAV/Sync/ISyncCollection.php
new file mode 100644
index 000000000..d3dc28a80
--- /dev/null
+++ b/vendor/sabre/dav/lib/DAV/Sync/ISyncCollection.php
@@ -0,0 +1,88 @@
+<?php
+
+namespace Sabre\DAV\Sync;
+
+use Sabre\DAV;
+
+/**
+ * If a class extends ISyncCollection, it supports WebDAV-sync.
+ *
+ * You are responsible for maintaining a changelist for this collection. This
+ * means that if any child nodes in this collection was created, modified or
+ * deleted in any way, you should maintain an updated changelist.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+interface ISyncCollection extends DAV\ICollection {
+
+ /**
+ * This method returns the current sync-token for this collection.
+ * This can be any string.
+ *
+ * If null is returned from this function, the plugin assumes there's no
+ * sync information available.
+ *
+ * @return string|null
+ */
+ function getSyncToken();
+
+ /**
+ * The getChanges method returns all the changes that have happened, since
+ * the specified syncToken and the current collection.
+ *
+ * This function should return an array, such as the following:
+ *
+ * [
+ * 'syncToken' => 'The current synctoken',
+ * 'added' => [
+ * 'new.txt',
+ * ],
+ * 'modified' => [
+ * 'modified.txt',
+ * ],
+ * 'deleted' => array(
+ * 'foo.php.bak',
+ * 'old.txt'
+ * )
+ * ];
+ *
+ * The syncToken property should reflect the *current* syncToken of the
+ * collection, as reported getSyncToken(). This is needed here too, to
+ * ensure the operation is atomic.
+ *
+ * If the syncToken is specified as null, this is an initial sync, and all
+ * members should be reported.
+ *
+ * The modified property is an array of nodenames that have changed since
+ * the last token.
+ *
+ * The deleted property is an array with nodenames, that have been deleted
+ * from collection.
+ *
+ * The second argument is basically the 'depth' of the report. If it's 1,
+ * you only have to report changes that happened only directly in immediate
+ * descendants. If it's 2, it should also include changes from the nodes
+ * below the child collections. (grandchildren)
+ *
+ * The third (optional) argument allows a client to specify how many
+ * results should be returned at most. If the limit is not specified, it
+ * should be treated as infinite.
+ *
+ * If the limit (infinite or not) is higher than you're willing to return,
+ * you should throw a Sabre\DAV\Exception\TooMuchMatches() exception.
+ *
+ * If the syncToken is expired (due to data cleanup) or unknown, you must
+ * return null.
+ *
+ * The limit is 'suggestive'. You are free to ignore it.
+ *
+ * @param string $syncToken
+ * @param int $syncLevel
+ * @param int $limit
+ * @return array
+ */
+ function getChanges($syncToken, $syncLevel, $limit = null);
+
+}
diff --git a/vendor/sabre/dav/lib/DAV/Sync/Plugin.php b/vendor/sabre/dav/lib/DAV/Sync/Plugin.php
new file mode 100644
index 000000000..4a141c72b
--- /dev/null
+++ b/vendor/sabre/dav/lib/DAV/Sync/Plugin.php
@@ -0,0 +1,277 @@
+<?php
+
+namespace Sabre\DAV\Sync;
+
+use Sabre\DAV;
+use Sabre\HTTP\RequestInterface;
+use Sabre\DAV\Xml\Request\SyncCollectionReport;
+
+/**
+ * This plugin all WebDAV-sync capabilities to the Server.
+ *
+ * WebDAV-sync is defined by rfc6578
+ *
+ * The sync capabilities only work with collections that implement
+ * Sabre\DAV\Sync\ISyncCollection.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class Plugin extends DAV\ServerPlugin {
+
+ /**
+ * Reference to server object
+ *
+ * @var DAV\Server
+ */
+ protected $server;
+
+ const SYNCTOKEN_PREFIX = 'http://sabre.io/ns/sync/';
+
+ /**
+ * Returns a plugin name.
+ *
+ * Using this name other plugins will be able to access other plugins
+ * using \Sabre\DAV\Server::getPlugin
+ *
+ * @return string
+ */
+ function getPluginName() {
+
+ return 'sync';
+
+ }
+
+ /**
+ * Initializes the plugin.
+ *
+ * This is when the plugin registers it's hooks.
+ *
+ * @param DAV\Server $server
+ * @return void
+ */
+ function initialize(DAV\Server $server) {
+
+ $this->server = $server;
+ $server->xml->elementMap['{DAV:}sync-collection'] = 'Sabre\\DAV\\Xml\\Request\\SyncCollectionReport';
+
+ $self = $this;
+
+ $server->on('report', function($reportName, $dom, $uri) use ($self) {
+
+ if ($reportName === '{DAV:}sync-collection') {
+ $this->server->transactionType = 'report-sync-collection';
+ $self->syncCollection($uri, $dom);
+ return false;
+ }
+
+ });
+
+ $server->on('propFind', [$this, 'propFind']);
+ $server->on('validateTokens', [$this, 'validateTokens']);
+
+ }
+
+ /**
+ * Returns a list of reports this plugin supports.
+ *
+ * This will be used in the {DAV:}supported-report-set property.
+ * Note that you still need to subscribe to the 'report' event to actually
+ * implement them
+ *
+ * @param string $uri
+ * @return array
+ */
+ function getSupportedReportSet($uri) {
+
+ $node = $this->server->tree->getNodeForPath($uri);
+ if ($node instanceof ISyncCollection && $node->getSyncToken()) {
+ return [
+ '{DAV:}sync-collection',
+ ];
+ }
+
+ return [];
+
+ }
+
+
+ /**
+ * This method handles the {DAV:}sync-collection HTTP REPORT.
+ *
+ * @param string $uri
+ * @param SyncCollectionReport $report
+ * @return void
+ */
+ function syncCollection($uri, SyncCollectionReport $report) {
+
+ // Getting the data
+ $node = $this->server->tree->getNodeForPath($uri);
+ if (!$node instanceof ISyncCollection) {
+ throw new DAV\Exception\ReportNotSupported('The {DAV:}sync-collection REPORT is not supported on this url.');
+ }
+ $token = $node->getSyncToken();
+ if (!$token) {
+ throw new DAV\Exception\ReportNotSupported('No sync information is available at this node');
+ }
+
+ $syncToken = $report->syncToken;
+ if (!is_null($syncToken)) {
+ // Sync-token must start with our prefix
+ if (substr($syncToken, 0, strlen(self::SYNCTOKEN_PREFIX)) !== self::SYNCTOKEN_PREFIX) {
+ throw new DAV\Exception\InvalidSyncToken('Invalid or unknown sync token');
+ }
+
+ $syncToken = substr($syncToken, strlen(self::SYNCTOKEN_PREFIX));
+
+ }
+ $changeInfo = $node->getChanges($syncToken, $report->syncLevel, $report->limit);
+
+ if (is_null($changeInfo)) {
+
+ throw new DAV\Exception\InvalidSyncToken('Invalid or unknown sync token');
+
+ }
+
+ // Encoding the response
+ $this->sendSyncCollectionResponse(
+ $changeInfo['syncToken'],
+ $uri,
+ $changeInfo['added'],
+ $changeInfo['modified'],
+ $changeInfo['deleted'],
+ $report->properties
+ );
+
+ }
+
+ /**
+ * Sends the response to a sync-collection request.
+ *
+ * @param string $syncToken
+ * @param string $collectionUrl
+ * @param array $added
+ * @param array $modified
+ * @param array $deleted
+ * @param array $properties
+ * @return void
+ */
+ protected function sendSyncCollectionResponse($syncToken, $collectionUrl, array $added, array $modified, array $deleted, array $properties) {
+
+
+ $fullPaths = [];
+
+ // Pre-fetching children, if this is possible.
+ foreach (array_merge($added, $modified) as $item) {
+ $fullPath = $collectionUrl . '/' . $item;
+ $fullPaths[] = $fullPath;
+ }
+
+ $responses = [];
+ foreach ($this->server->getPropertiesForMultiplePaths($fullPaths, $properties) as $fullPath => $props) {
+
+ // The 'Property_Response' class is responsible for generating a
+ // single {DAV:}response xml element.
+ $responses[] = new DAV\Xml\Element\Response($fullPath, $props);
+
+ }
+
+
+
+ // Deleted items also show up as 'responses'. They have no properties,
+ // and a single {DAV:}status element set as 'HTTP/1.1 404 Not Found'.
+ foreach ($deleted as $item) {
+
+ $fullPath = $collectionUrl . '/' . $item;
+ $responses[] = new DAV\Xml\Element\Response($fullPath, [], 404);
+
+ }
+ $multiStatus = new DAV\Xml\Response\MultiStatus($responses, self::SYNCTOKEN_PREFIX . $syncToken);
+
+ $this->server->httpResponse->setStatus(207);
+ $this->server->httpResponse->setHeader('Content-Type', 'application/xml; charset=utf-8');
+ $this->server->httpResponse->setBody(
+ $this->server->xml->write('{DAV:}multistatus', $multiStatus, $this->server->getBaseUri())
+ );
+
+ }
+
+ /**
+ * This method is triggered whenever properties are requested for a node.
+ * We intercept this to see if we must return a {DAV:}sync-token.
+ *
+ * @param DAV\PropFind $propFind
+ * @param DAV\INode $node
+ * @return void
+ */
+ function propFind(DAV\PropFind $propFind, DAV\INode $node) {
+
+ $propFind->handle('{DAV:}sync-token', function() use ($node) {
+ if (!$node instanceof ISyncCollection || !$token = $node->getSyncToken()) {
+ return;
+ }
+ return self::SYNCTOKEN_PREFIX . $token;
+ });
+
+ }
+
+ /**
+ * The validateTokens event is triggered before every request.
+ *
+ * It's a moment where this plugin can check all the supplied lock tokens
+ * in the If: header, and check if they are valid.
+ *
+ * @param RequestInterface $request
+ * @param array $conditions
+ * @return void
+ */
+ function validateTokens(RequestInterface $request, &$conditions) {
+
+ foreach ($conditions as $kk => $condition) {
+
+ foreach ($condition['tokens'] as $ii => $token) {
+
+ // Sync-tokens must always start with our designated prefix.
+ if (substr($token['token'], 0, strlen(self::SYNCTOKEN_PREFIX)) !== self::SYNCTOKEN_PREFIX) {
+ continue;
+ }
+
+ // Checking if the token is a match.
+ $node = $this->server->tree->getNodeForPath($condition['uri']);
+
+ if (
+ $node instanceof ISyncCollection &&
+ $node->getSyncToken() == substr($token['token'], strlen(self::SYNCTOKEN_PREFIX))
+ ) {
+ $conditions[$kk]['tokens'][$ii]['validToken'] = true;
+ }
+
+ }
+
+ }
+
+ }
+
+ /**
+ * Returns a bunch of meta-data about the plugin.
+ *
+ * Providing this information is optional, and is mainly displayed by the
+ * Browser plugin.
+ *
+ * The description key in the returned array may contain html and will not
+ * be sanitized.
+ *
+ * @return array
+ */
+ function getPluginInfo() {
+
+ return [
+ 'name' => $this->getPluginName(),
+ 'description' => 'Adds support for WebDAV Collection Sync (rfc6578)',
+ 'link' => 'http://sabre.io/dav/sync/',
+ ];
+
+ }
+
+}