Example #1
0
 /**
  * Unlocks a uri
  *
  * This method removes a lock from a uri. It is assumed all the supplied information is correct and verified
  *
  * @param string $uri
  * @param LockInfo $lockInfo
  * @return bool
  */
 function unlockNode($uri, LockInfo $lockInfo)
 {
     if (!$this->server->emit('beforeUnlock', [$uri, $lockInfo])) {
         return;
     }
     return $this->locksBackend->unlock($uri, $lockInfo);
 }
Example #2
0
 /**
  * Patch an uri
  *
  * The WebDAV patch request can be used to modify only a part of an
  * existing resource. If the resource does not exist yet and the first
  * offset is not 0, the request fails
  *
  * @param RequestInterface $request
  * @param ResponseInterface $response
  * @return void
  */
 function httpPatch(RequestInterface $request, ResponseInterface $response)
 {
     $path = $request->getPath();
     // Get the node. Will throw a 404 if not found
     $node = $this->server->tree->getNodeForPath($path);
     if (!$node instanceof IPatchSupport) {
         throw new DAV\Exception\MethodNotAllowed('The target resource does not support the PATCH method.');
     }
     $range = $this->getHTTPUpdateRange($request);
     if (!$range) {
         throw new DAV\Exception\BadRequest('No valid "X-Update-Range" found in the headers');
     }
     $contentType = strtolower($request->getHeader('Content-Type'));
     if ($contentType != 'application/x-sabredav-partialupdate') {
         throw new DAV\Exception\UnsupportedMediaType('Unknown Content-Type header "' . $contentType . '"');
     }
     $len = $this->server->httpRequest->getHeader('Content-Length');
     if (!$len) {
         throw new DAV\Exception\LengthRequired('A Content-Length header is required');
     }
     switch ($range[0]) {
         case self::RANGE_START:
             // Calculate the end-range if it doesn't exist.
             if (!$range[2]) {
                 $range[2] = $range[1] + $len - 1;
             } else {
                 if ($range[2] < $range[1]) {
                     throw new DAV\Exception\RequestedRangeNotSatisfiable('The end offset (' . $range[2] . ') is lower than the start offset (' . $range[1] . ')');
                 }
                 if ($range[2] - $range[1] + 1 != $len) {
                     throw new DAV\Exception\RequestedRangeNotSatisfiable('Actual data length (' . $len . ') is not consistent with begin (' . $range[1] . ') and end (' . $range[2] . ') offsets');
                 }
             }
             break;
     }
     if (!$this->server->emit('beforeWriteContent', [$path, $node, null])) {
         return;
     }
     $body = $this->server->httpRequest->getBody();
     $etag = $node->patch($body, $range[0], isset($range[1]) ? $range[1] : null);
     $this->server->emit('afterWriteContent', [$path, $node]);
     $response->setHeader('Content-Length', '0');
     if ($etag) {
         $response->setHeader('ETag', $etag);
     }
     $response->setStatus(204);
     // Breaks the event chain
     return false;
 }
Example #3
0
 function testBrowserPostAction()
 {
     $r = $this->server->emit('onBrowserPostAction', ['calendars/user1', 'mkcalendar', ['name' => 'NEWCALENDAR', '{DAV:}displayname' => 'foo']]);
     $this->assertFalse($r);
     $calendars = $this->caldavBackend->getCalendarsForUser('principals/user1');
     $this->assertEquals(3, count($calendars));
     $newCalendar = null;
     foreach ($calendars as $calendar) {
         if ($calendar['uri'] === 'NEWCALENDAR') {
             $newCalendar = $calendar;
             break;
         }
     }
     if (!$newCalendar) {
         $this->fail('Could not find newly created calendar');
     }
 }
Example #4
0
 /**
  * Returns a tree of supported privileges for a resource.
  *
  * The returned array structure should be in this form:
  *
  * [
  *    [
  *       'privilege' => '{DAV:}read',
  *       'abstract'  => false,
  *       'aggregates' => []
  *    ]
  * ]
  *
  * Privileges can be nested using "aggregrates". Doing so means that
  * if you assign someone the aggregrating privilege, all the
  * sub-privileges will automatically be granted.
  *
  * Marking a privilege as abstract means that the privilege cannot be
  * directly assigned, but must be assigned via the parent privilege.
  *
  * So a more complex version might look like this:
  *
  * [
  *    [
  *       'privilege' => '{DAV:}read',
  *       'abstract'  => false,
  *       'aggregates' => [
  *          [
  *              'privilege'  => '{DAV:}read-acl',
  *              'abstract'   => false,
  *              'aggregates' => [],
  *          ]
  *       ]
  *    ]
  * ]
  *
  * @param string|INode $node
  * @return array
  */
 function getSupportedPrivilegeSet($node)
 {
     if (is_string($node)) {
         $node = $this->server->tree->getNodeForPath($node);
     }
     $supportedPrivileges = null;
     if ($node instanceof IACL) {
         $supportedPrivileges = $node->getSupportedPrivilegeSet();
     }
     if (is_null($supportedPrivileges)) {
         // Default
         $supportedPrivileges = ['{DAV:}read' => ['abstract' => false, 'aggregates' => ['{DAV:}read-acl' => ['abstract' => false, 'aggregates' => []], '{DAV:}read-current-user-privilege-set' => ['abstract' => false, 'aggregates' => []]]], '{DAV:}write' => ['abstract' => false, 'aggregates' => ['{DAV:}write-properties' => ['abstract' => false, 'aggregates' => []], '{DAV:}write-content' => ['abstract' => false, 'aggregates' => []], '{DAV:}unlock' => ['abstract' => false, 'aggregates' => []]]]];
         if ($node instanceof \Sabre\DAV\ICollection) {
             $supportedPrivileges['{DAV:}write']['aggregates']['{DAV:}bind'] = ['abstract' => false, 'aggregates' => []];
             $supportedPrivileges['{DAV:}write']['aggregates']['{DAV:}unbind'] = ['abstract' => false, 'aggregates' => []];
         }
         if ($node instanceof \Sabre\DAVACL\IACL) {
             $supportedPrivileges['{DAV:}write']['aggregates']['{DAV:}write-acl'] = ['abstract' => false, 'aggregates' => []];
         }
     }
     $this->server->emit('getSupportedPrivilegeSet', [$node, &$supportedPrivileges]);
     return $supportedPrivileges;
 }
Example #5
0
 /**
  * Generates the html directory index for a given url
  *
  * @param string $path
  * @return string
  */
 function generateDirectoryIndex($path)
 {
     $html = $this->generateHeader($path ? $path : '/', $path);
     $node = $this->server->tree->getNodeForPath($path);
     if ($node instanceof DAV\ICollection) {
         $html .= "<section><h1>Nodes</h1>\n";
         $html .= "<table class=\"nodeTable\">";
         $subNodes = $this->server->getPropertiesForChildren($path, ['{DAV:}displayname', '{DAV:}resourcetype', '{DAV:}getcontenttype', '{DAV:}getcontentlength', '{DAV:}getlastmodified']);
         foreach ($subNodes as $subPath => $subProps) {
             $subNode = $this->server->tree->getNodeForPath($subPath);
             $fullPath = $this->server->getBaseUri() . URLUtil::encodePath($subPath);
             list(, $displayPath) = URLUtil::splitPath($subPath);
             $subNodes[$subPath]['subNode'] = $subNode;
             $subNodes[$subPath]['fullPath'] = $fullPath;
             $subNodes[$subPath]['displayPath'] = $displayPath;
         }
         uasort($subNodes, [$this, 'compareNodes']);
         foreach ($subNodes as $subProps) {
             $type = ['string' => 'Unknown', 'icon' => 'cog'];
             if (isset($subProps['{DAV:}resourcetype'])) {
                 $type = $this->mapResourceType($subProps['{DAV:}resourcetype']->getValue(), $subProps['subNode']);
             }
             $html .= '<tr>';
             $html .= '<td class="nameColumn"><a href="' . $this->escapeHTML($subProps['fullPath']) . '"><span class="oi" data-glyph="' . $this->escapeHTML($type['icon']) . '"></span> ' . $this->escapeHTML($subProps['displayPath']) . '</a></td>';
             $html .= '<td class="typeColumn">' . $this->escapeHTML($type['string']) . '</td>';
             $html .= '<td>';
             if (isset($subProps['{DAV:}getcontentlength'])) {
                 $html .= $this->escapeHTML($subProps['{DAV:}getcontentlength'] . ' bytes');
             }
             $html .= '</td><td>';
             if (isset($subProps['{DAV:}getlastmodified'])) {
                 $lastMod = $subProps['{DAV:}getlastmodified']->getTime();
                 $html .= $this->escapeHTML($lastMod->format('F j, Y, g:i a'));
             }
             $html .= '</td>';
             $buttonActions = '';
             if ($subNode instanceof DAV\IFile) {
                 $buttonActions = '<a href="' . $this->escapeHTML($subProps['fullPath']) . '?sabreAction=info"><span class="oi" data-glyph="info"></span></a>';
             }
             $this->server->emit('browserButtonActions', [$subProps['fullPath'], $subProps['subNode'], &$buttonActions]);
             $html .= '<td>' . $buttonActions . '</td>';
             $html .= '</tr>';
         }
         $html .= '</table>';
     }
     $html .= "</section>";
     $html .= "<section><h1>Properties</h1>";
     $html .= "<table class=\"propTable\">";
     // Allprops request
     $propFind = new PropFindAll($path);
     $properties = $this->server->getPropertiesByNode($propFind, $node);
     $properties = $propFind->getResultForMultiStatus()[200];
     foreach ($properties as $propName => $propValue) {
         if (!in_array($propName, $this->uninterestingProperties)) {
             $html .= $this->drawPropertyRow($propName, $propValue);
         }
     }
     $html .= "</table>";
     $html .= "</section>";
     /* Start of generating actions */
     $output = '';
     if ($this->enablePost) {
         $this->server->emit('onHTMLActionsPanel', [$node, &$output]);
     }
     if ($output) {
         $html .= "<section><h1>Actions</h1>";
         $html .= "<div class=\"actions\">\n";
         $html .= $output;
         $html .= "</div>\n";
         $html .= "</section>\n";
     }
     $html .= $this->generateFooter();
     $this->server->httpResponse->setHeader('Content-Security-Policy', "img-src 'self'; style-src 'self';");
     return $html;
 }
Example #6
0
    /**
     * Generates the html directory index for a given url
     *
     * @param string $path
     * @return string
     */
    function generateDirectoryIndex($path)
    {
        $version = '';
        if (DAV\Server::$exposeVersion) {
            $version = DAV\Version::VERSION;
        }
        $vars = ['path' => $this->escapeHTML($path), 'favicon' => $this->escapeHTML($this->getAssetUrl('favicon.ico')), 'style' => $this->escapeHTML($this->getAssetUrl('sabredav.css')), 'iconstyle' => $this->escapeHTML($this->getAssetUrl('openiconic/open-iconic.css')), 'logo' => $this->escapeHTML($this->getAssetUrl('sabredav.png')), 'baseUrl' => $this->server->getBaseUri()];
        $html = <<<HTML
<!DOCTYPE html>
<html>
<head>
    <title>{$vars['path']}/ - sabre/dav {$version}</title>
    <link rel="shortcut icon" href="{$vars['favicon']}"   type="image/vnd.microsoft.icon" />
    <link rel="stylesheet"    href="{$vars['style']}"     type="text/css" />
    <link rel="stylesheet"    href="{$vars['iconstyle']}" type="text/css" />

</head>
<body>
    <header>
        <div class="logo">
            <a href="{$vars['baseUrl']}"><img src="{$vars['logo']}" alt="sabre/dav" /> {$vars['path']}/</a>
        </div>
    </header>

    <nav>
HTML;
        // If the path is empty, there's no parent.
        if ($path) {
            list($parentUri) = URLUtil::splitPath($path);
            $fullPath = URLUtil::encodePath($this->server->getBaseUri() . $parentUri);
            $html .= '<a href="' . $fullPath . '" class="btn">⇤ Go to parent</a>';
        } else {
            $html .= '<span class="btn disabled">⇤ Go to parent</span>';
        }
        $html .= "</nav>";
        $node = $this->server->tree->getNodeForPath($path);
        if ($node instanceof DAV\ICollection) {
            $html .= "<section><h1>Nodes</h1>\n";
            $html .= "<table class=\"nodeTable\">";
            $subNodes = $this->server->getPropertiesForChildren($path, ['{DAV:}displayname', '{DAV:}resourcetype', '{DAV:}getcontenttype', '{DAV:}getcontentlength', '{DAV:}getlastmodified']);
            foreach ($subNodes as $subPath => $subProps) {
                $subNode = $this->server->tree->getNodeForPath($subPath);
                $fullPath = URLUtil::encodePath($this->server->getBaseUri() . $subPath);
                list(, $displayPath) = URLUtil::splitPath($subPath);
                $subNodes[$subPath]['subNode'] = $subNode;
                $subNodes[$subPath]['fullPath'] = $fullPath;
                $subNodes[$subPath]['displayPath'] = $displayPath;
            }
            uasort($subNodes, [$this, 'compareNodes']);
            foreach ($subNodes as $subProps) {
                $type = ['string' => 'Unknown', 'icon' => 'cog'];
                if (isset($subProps['{DAV:}resourcetype'])) {
                    $type = $this->mapResourceType($subProps['{DAV:}resourcetype']->getValue(), $subProps['subNode']);
                }
                $html .= '<tr>';
                $html .= '<td class="nameColumn"><a href="' . $this->escapeHTML($subProps['fullPath']) . '"><span class="oi" data-glyph="' . $type['icon'] . '"></span> ' . $this->escapeHTML($subProps['displayPath']) . '</a></td>';
                $html .= '<td class="typeColumn">' . $type['string'] . '</td>';
                $html .= '<td>';
                if (isset($subProps['{DAV:}getcontentlength'])) {
                    $html .= $subProps['{DAV:}getcontentlength'] . ' bytes';
                }
                $html .= '</td><td>';
                if (isset($subProps['{DAV:}getlastmodified'])) {
                    $lastMod = $subProps['{DAV:}getlastmodified']->getTime();
                    $html .= $lastMod->format('F j, Y, g:i a');
                }
                $html .= '</td></tr>';
            }
            $html .= '</table>';
        }
        $html .= "</section>";
        $html .= "<section><h1>Properties</h1>";
        $html .= "<table class=\"propTable\">";
        // Allprops request
        $propFind = new PropFindAll($path);
        $properties = $this->server->getPropertiesByNode($propFind, $node);
        $properties = $propFind->getResultForMultiStatus()[200];
        foreach ($properties as $propName => $propValue) {
            $html .= $this->drawPropertyRow($propName, $propValue);
        }
        $html .= "</table>";
        $html .= "</section>";
        /* Start of generating actions */
        $output = '';
        if ($this->enablePost) {
            $this->server->emit('onHTMLActionsPanel', [$node, &$output]);
        }
        if ($output) {
            $html .= "<section><h1>Actions</h1>";
            $html .= "<div class=\"actions\">\n";
            $html .= $output;
            $html .= "</div>\n";
            $html .= "</section>\n";
        }
        $html .= "\n        <footer>Generated by SabreDAV " . $version . " (c)2007-2014 <a href=\"http://sabre.io/\">http://sabre.io/</a></footer>\n        </body>\n        </html>";
        $this->server->httpResponse->setHeader('Content-Security-Policy', "img-src 'self'; style-src 'self';");
        return $html;
    }