示例#1
0
 /**
  * Intercepts GET requests on addressbook urls ending with ?photo.
  *
  * @param RequestInterface $request
  * @param ResponseInterface $response
  * @return bool|void
  */
 function httpGet(RequestInterface $request, ResponseInterface $response)
 {
     $queryParams = $request->getQueryParameters();
     // TODO: in addition to photo we should also add logo some point in time
     if (!array_key_exists('photo', $queryParams)) {
         return true;
     }
     $path = $request->getPath();
     $node = $this->server->tree->getNodeForPath($path);
     if (!$node instanceof Card) {
         return true;
     }
     $this->server->transactionType = 'carddav-image-export';
     // Checking ACL, if available.
     if ($aclPlugin = $this->server->getPlugin('acl')) {
         /** @var \Sabre\DAVACL\Plugin $aclPlugin */
         $aclPlugin->checkPrivileges($path, '{DAV:}read');
     }
     if ($result = $this->getPhoto($node)) {
         $response->setHeader('Content-Type', $result['Content-Type']);
         $response->setStatus(200);
         $response->setBody($result['body']);
         // Returning false to break the event chain
         return false;
     }
     return true;
 }
示例#2
0
 /**
  * Intercepts GET requests on addressbook urls ending with ?export.
  *
  * @param RequestInterface $request
  * @param ResponseInterface $response
  * @return bool
  */
 function httpGet(RequestInterface $request, ResponseInterface $response)
 {
     $queryParams = $request->getQueryParameters();
     if (!array_key_exists('export', $queryParams)) {
         return;
     }
     $path = $request->getPath();
     $node = $this->server->tree->getNodeForPath($path);
     if (!$node instanceof IAddressBook) {
         return;
     }
     $this->server->transactionType = 'get-addressbook-export';
     // Checking ACL, if available.
     if ($aclPlugin = $this->server->getPlugin('acl')) {
         $aclPlugin->checkPrivileges($path, '{DAV:}read');
     }
     $nodes = $this->server->getPropertiesForPath($path, ['{' . Plugin::NS_CARDDAV . '}address-data'], 1);
     $format = 'text/directory';
     $output = null;
     $filenameExtension = null;
     switch ($format) {
         case 'text/directory':
             $output = $this->generateVCF($nodes);
             $filenameExtension = '.vcf';
             break;
     }
     $filename = preg_replace('/[^a-zA-Z0-9-_ ]/um', '', $node->getName());
     $filename .= '-' . date('Y-m-d') . $filenameExtension;
     $response->setHeader('Content-Disposition', 'attachment; filename="' . $filename . '"');
     $response->setHeader('Content-Type', $format);
     $response->setStatus(200);
     $response->setBody($output);
     // Returning false to break the event chain
     return false;
 }
示例#3
0
 /**
  * Handles POST requests for tree operations not handled in the SabreDAV parent clas
  *
  * @param RequestInterface $request
  * @param ResponseInterface $response
  * @return bool
  */
 public function httpPOSTExtra(RequestInterface $request, ResponseInterface $response)
 {
     $contentType = $request->getHeader('Content-Type');
     list($contentType) = explode(';', $contentType);
     if ($contentType !== 'application/x-www-form-urlencoded' && $contentType !== 'multipart/form-data') {
         return;
     }
     $postVars = $request->getPostData();
     if (!isset($postVars['sabreActionExtra'])) {
         return;
     }
     $uri = $request->getPath();
     switch ($postVars['sabreActionExtra']) {
         case 'del':
             if (isset($postVars['path'])) {
                 // Using basename() because we won't allow slashes
                 list(, $Name) = \Sabre\HTTP\URLUtil::splitPath(trim($postVars['path']));
                 if (!empty($Name) && $this->config->browserplugin_enable_delete === true) {
                     $this->server->tree->delete($uri . '/' . $Name);
                 }
             }
             break;
     }
     $response->setHeader('Location', $request->getUrl());
     $response->setStatus(302);
     return false;
 }
示例#4
0
 /**
  * Plugin that adds a 'Content-Disposition: attachment' header to all files
  * delivered by SabreDAV.
  * @param RequestInterface $request
  * @param ResponseInterface $response
  */
 function httpGet(RequestInterface $request, ResponseInterface $response)
 {
     // Only handle valid files
     $node = $this->tree->getNodeForPath($request->getPath());
     if (!$node instanceof IFile) {
         return;
     }
     $response->addHeader('Content-Disposition', 'attachment');
 }
示例#5
0
 /**
  * Intercepts GET requests on calendar urls ending with ?export.
  *
  * @param RequestInterface $request
  * @param ResponseInterface $response
  * @return bool
  */
 function httpGet(RequestInterface $request, ResponseInterface $response)
 {
     $queryParams = $request->getQueryParameters();
     if (!array_key_exists('export', $queryParams)) {
         return;
     }
     $path = $request->getPath();
     $node = $this->server->getProperties($path, ['{DAV:}resourcetype', '{DAV:}displayname', '{http://sabredav.org/ns}sync-token', '{DAV:}sync-token', '{http://apple.com/ns/ical/}calendar-color']);
     if (!isset($node['{DAV:}resourcetype']) || !$node['{DAV:}resourcetype']->is('{' . Plugin::NS_CALDAV . '}calendar')) {
         return;
     }
     // Marking the transactionType, for logging purposes.
     $this->server->transactionType = 'get-calendar-export';
     $properties = $node;
     $start = null;
     $end = null;
     $expand = false;
     $componentType = false;
     if (isset($queryParams['start'])) {
         if (!ctype_digit($queryParams['start'])) {
             throw new BadRequest('The start= parameter must contain a unix timestamp');
         }
         $start = DateTime::createFromFormat('U', $queryParams['start']);
     }
     if (isset($queryParams['end'])) {
         if (!ctype_digit($queryParams['end'])) {
             throw new BadRequest('The end= parameter must contain a unix timestamp');
         }
         $end = DateTime::createFromFormat('U', $queryParams['end']);
     }
     if (isset($queryParams['expand']) && !!$queryParams['expand']) {
         if (!$start || !$end) {
             throw new BadRequest('If you\'d like to expand recurrences, you must specify both a start= and end= parameter.');
         }
         $expand = true;
         $componentType = 'VEVENT';
     }
     if (isset($queryParams['componentType'])) {
         if (!in_array($queryParams['componentType'], ['VEVENT', 'VTODO', 'VJOURNAL'])) {
             throw new BadRequest('You are not allowed to search for components of type: ' . $queryParams['componentType'] . ' here');
         }
         $componentType = $queryParams['componentType'];
     }
     $format = \Sabre\HTTP\Util::Negotiate($request->getHeader('Accept'), ['text/calendar', 'application/calendar+json']);
     if (isset($queryParams['accept'])) {
         if ($queryParams['accept'] === 'application/calendar+json' || $queryParams['accept'] === 'jcal') {
             $format = 'application/calendar+json';
         }
     }
     if (!$format) {
         $format = 'text/calendar';
     }
     $this->generateResponse($path, $start, $end, $expand, $componentType, $format, $properties, $response);
     // Returning false to break the event chain
     return false;
 }
 /**
  * This method intercepts GET requests to non-files, and changes it into an HTTP PROPFIND request
  *
  * @param RequestInterface $request
  * @param ResponseInterface $response
  * @return bool
  */
 function httpGet(RequestInterface $request, ResponseInterface $response)
 {
     $node = $this->server->tree->getNodeForPath($request->getPath());
     if ($node instanceof DAV\IFile) {
         return;
     }
     $subRequest = clone $request;
     $subRequest->setMethod('PROPFIND');
     $this->server->invokeMethod($subRequest, $response);
     return false;
 }
示例#7
0
 /**
  * When this method is called, the backend must check if authentication was
  * successful.
  *
  * The returned value must be one of the following
  *
  * [true, "principals/username"]
  * [false, "reason for failure"]
  *
  * If authentication was successful, it's expected that the authentication
  * backend returns a so-called principal url.
  *
  * Examples of a principal url:
  *
  * principals/admin
  * principals/user1
  * principals/users/joe
  * principals/uid/123457
  *
  * If you don't use WebDAV ACL (RFC3744) we recommend that you simply
  * return a string such as:
  *
  * principals/users/[username]
  *
  * @param RequestInterface $request
  * @param ResponseInterface $response
  * @return array
  */
 function check(RequestInterface $request, ResponseInterface $response)
 {
     $remoteUser = $request->getRawServerValue('REMOTE_USER');
     if (is_null($remoteUser)) {
         $remoteUser = $request->getRawServerValue('REDIRECT_REMOTE_USER');
     }
     if (is_null($remoteUser)) {
         return [false, 'No REMOTE_USER property was found in the PHP $_SERVER super-global. This likely means your server is not configured correctly'];
     }
     return [true, $this->principalPrefix . $remoteUser];
 }
示例#8
0
 /**
  * We intercept this to handle POST requests on calendars.
  *
  * @param RequestInterface $request
  * @param ResponseInterface $response
  * @return null|bool
  */
 function httpPost(RequestInterface $request, ResponseInterface $response)
 {
     $path = $request->getPath();
     // Only handling xml
     $contentType = $request->getHeader('Content-Type');
     if (strpos($contentType, 'application/xml') === false && strpos($contentType, 'text/xml') === false) {
         return;
     }
     // Making sure the node exists
     try {
         $node = $this->server->tree->getNodeForPath($path);
     } catch (NotFound $e) {
         return;
     }
     // CSRF protection
     $this->protectAgainstCSRF();
     $requestBody = $request->getBodyAsString();
     // If this request handler could not deal with this POST request, it
     // will return 'null' and other plugins get a chance to handle the
     // request.
     //
     // However, we already requested the full body. This is a problem,
     // because a body can only be read once. This is why we preemptively
     // re-populated the request body with the existing data.
     $request->setBody($requestBody);
     $dom = XMLUtil::loadDOMDocument($requestBody);
     $documentType = XMLUtil::toClarkNotation($dom->firstChild);
     switch ($documentType) {
         // Dealing with the 'share' document, which modified invitees on a
         // calendar.
         case '{' . \Sabre\CardDAV\Plugin::NS_CARDDAV . '}share':
             // We can only deal with IShareableCalendar objects
             if (!$node instanceof IShareableAddressBook) {
                 return;
             }
             $this->server->transactionType = 'post-calendar-share';
             // Getting ACL info
             $acl = $this->server->getPlugin('acl');
             // If there's no ACL support, we allow everything
             if ($acl) {
                 $acl->checkPrivileges($path, '{DAV:}write');
             }
             $mutations = $this->parseShareRequest($dom);
             $node->updateShares($mutations[0], $mutations[1]);
             $response->setStatus(200);
             // Adding this because sending a response body may cause issues,
             // and I wanted some type of indicator the response was handled.
             $response->setHeader('X-Sabre-Status', 'everything-went-well');
             // Breaking the event chain
             return false;
     }
 }
示例#9
0
 /**
  * 'beforeMethod' event handles. This event handles intercepts GET requests ending
  * with ?mount
  *
  * @param RequestInterface $request
  * @param ResponseInterface $response
  * @return bool
  */
 function httpGet(RequestInterface $request, ResponseInterface $response)
 {
     $queryParams = $request->getQueryParameters();
     if (!array_key_exists('mount', $queryParams)) {
         return;
     }
     $currentUri = $request->getAbsoluteUrl();
     // Stripping off everything after the ?
     list($currentUri) = explode('?', $currentUri);
     $this->davMount($response, $currentUri);
     // Returning false to break the event chain
     return false;
 }
示例#10
0
 public function releaseLock(RequestInterface $request)
 {
     if ($request->getMethod() !== 'PUT' || isset($_SERVER['HTTP_OC_CHUNKED'])) {
         return;
     }
     try {
         $node = $this->server->tree->getNodeForPath($request->getPath());
     } catch (NotFound $e) {
         return;
     }
     if ($node instanceof Node) {
         $node->releaseLock(ILockingProvider::LOCK_SHARED);
     }
 }
示例#11
0
 public function releaseLock(RequestInterface $request)
 {
     if ($request->getMethod() !== 'PUT') {
         return;
     }
     try {
         $node = $this->tree->getNodeForPath($request->getPath());
     } catch (NotFound $e) {
         return;
     }
     if ($node instanceof Node) {
         $node->releaseLock(ILockingProvider::LOCK_SHARED);
     }
 }
示例#12
0
 /**
  * Detects all unsupported clients and throws a \Sabre\DAV\Exception\Forbidden
  * exception which will result in a 403 to them.
  * @param RequestInterface $request
  * @throws \Sabre\DAV\Exception\Forbidden If the client version is not supported
  */
 public function beforeHandler(RequestInterface $request)
 {
     $userAgent = $request->getHeader('User-Agent');
     if ($userAgent === null) {
         return;
     }
     $minimumSupportedDesktopVersion = $this->config->getSystemValue('minimum.supported.desktop.version', '1.7.0');
     // Match on the mirall version which is in scheme "Mozilla/5.0 (%1) mirall/%2" or
     // "mirall/%1" for older releases
     preg_match("/(?:mirall\\/)([\\d.]+)/i", $userAgent, $versionMatches);
     if (isset($versionMatches[1]) && version_compare($versionMatches[1], $minimumSupportedDesktopVersion) === -1) {
         throw new \Sabre\DAV\Exception\Forbidden('Unsupported client version.');
     }
 }
 /**
  * Intercepts GET requests on addressbook urls ending with ?export.
  *
  * @param RequestInterface $request
  * @param ResponseInterface $response
  * @return bool
  */
 function httpGet(RequestInterface $request, ResponseInterface $response)
 {
     $queryParams = $request->getQueryParameters();
     if (!array_key_exists('export', $queryParams)) {
         return;
     }
     $path = $request->getPath();
     $node = $this->server->tree->getNodeForPath($path);
     if (!$node instanceof IAddressBook) {
         return;
     }
     $this->server->transactionType = 'get-addressbook-export';
     // Checking ACL, if available.
     if ($aclPlugin = $this->server->getPlugin('acl')) {
         $aclPlugin->checkPrivileges($path, '{DAV:}read');
     }
     $response->setHeader('Content-Type', 'text/directory');
     $response->setStatus(200);
     $nodes = $this->server->getPropertiesForPath($path, ['{' . Plugin::NS_CARDDAV . '}address-data'], 1);
     $response->setBody($this->generateVCF($nodes));
     // Returning false to break the event chain
     return false;
 }
示例#14
0
    /**
     * This method is created to extract information from the WebDAV HTTP 'If:' header
     *
     * The If header can be quite complex, and has a bunch of features. We're using a regex to extract all relevant information
     * The function will return an array, containing structs with the following keys
     *
     *   * uri   - the uri the condition applies to.
     *   * tokens - The lock token. another 2 dimensional array containing 3 elements
     *
     * Example 1:
     *
     * If: (<opaquelocktoken:181d4fae-7d8c-11d0-a765-00a0c91e6bf2>)
     *
     * Would result in:
     *
     * [
     *    [
     *       'uri' => '/request/uri',
     *       'tokens' => [
     *          [
     *              [
     *                  'negate' => false,
     *                  'token'  => 'opaquelocktoken:181d4fae-7d8c-11d0-a765-00a0c91e6bf2',
     *                  'etag'   => ""
     *              ]
     *          ]
     *       ],
     *    ]
     * ]
     *
     * Example 2:
     *
     * If: </path/> (Not <opaquelocktoken:181d4fae-7d8c-11d0-a765-00a0c91e6bf2> ["Im An ETag"]) (["Another ETag"]) </path2/> (Not ["Path2 ETag"])
     *
     * Would result in:
     *
     * [
     *    [
     *       'uri' => 'path',
     *       'tokens' => [
     *          [
     *              [
     *                  'negate' => true,
     *                  'token'  => 'opaquelocktoken:181d4fae-7d8c-11d0-a765-00a0c91e6bf2',
     *                  'etag'   => '"Im An ETag"'
     *              ],
     *              [
     *                  'negate' => false,
     *                  'token'  => '',
     *                  'etag'   => '"Another ETag"'
     *              ]
     *          ]
     *       ],
     *    ],
     *    [
     *       'uri' => 'path2',
     *       'tokens' => [
     *          [
     *              [
     *                  'negate' => true,
     *                  'token'  => '',
     *                  'etag'   => '"Path2 ETag"'
     *              ]
     *          ]
     *       ],
     *    ],
     * ]
     *
     * @return array
     */
    function getIfConditions(RequestInterface $request) {

        $header = $request->getHeader('If');
        if (!$header) return [];

        $matches = [];

        $regex = '/(?:\<(?P<uri>.*?)\>\s)?\((?P<not>Not\s)?(?:\<(?P<token>[^\>]*)\>)?(?:\s?)(?:\[(?P<etag>[^\]]*)\])?\)/im';
        preg_match_all($regex, $header, $matches, PREG_SET_ORDER);

        $conditions = [];

        foreach ($matches as $match) {

            // If there was no uri specified in this match, and there were
            // already conditions parsed, we add the condition to the list of
            // conditions for the previous uri.
            if (!$match['uri'] && count($conditions)) {
                $conditions[count($conditions) - 1]['tokens'][] = [
                    'negate' => $match['not'] ? true : false,
                    'token'  => $match['token'],
                    'etag'   => isset($match['etag']) ? $match['etag'] : ''
                ];
            } else {

                if (!$match['uri']) {
                    $realUri = $request->getPath();
                } else {
                    $realUri = $this->calculateUri($match['uri']);
                }

                $conditions[] = [
                    'uri'    => $realUri,
                    'tokens' => [
                        [
                            'negate' => $match['not'] ? true : false,
                            'token'  => $match['token'],
                            'etag'   => isset($match['etag']) ? $match['etag'] : ''
                        ]
                    ],

                ];
            }

        }

        return $conditions;

    }
示例#15
0
 /**
  * HTTP REPORT method implementation
  *
  * Although the REPORT method is not part of the standard WebDAV spec (it's from rfc3253)
  * It's used in a lot of extensions, so it made sense to implement it into the core.
  *
  * @param RequestInterface $request
  * @param ResponseInterface $response
  * @return bool
  */
 function httpReport(RequestInterface $request, ResponseInterface $response)
 {
     $path = $request->getPath();
     $body = $request->getBodyAsString();
     $dom = XMLUtil::loadDOMDocument($body);
     $reportName = XMLUtil::toClarkNotation($dom->firstChild);
     if ($this->server->emit('report', [$reportName, $dom, $path])) {
         // If emit returned true, it means the report was not supported
         throw new Exception\ReportNotSupported();
     }
     // Sending back false will interupt the event chain and tell the server
     // we've handled this method.
     return false;
 }
示例#16
0
 /**
  * HTTP REPORT method implementation
  *
  * Although the REPORT method is not part of the standard WebDAV spec (it's from rfc3253)
  * It's used in a lot of extensions, so it made sense to implement it into the core.
  *
  * @param RequestInterface $request
  * @param ResponseInterface $response
  * @return bool
  */
 function httpReport(RequestInterface $request, ResponseInterface $response)
 {
     $path = $request->getPath();
     $result = $this->server->xml->parse($request->getBody(), $request->getUrl(), $rootElementName);
     if ($this->server->emit('report', [$rootElementName, $result, $path])) {
         // If emit returned true, it means the report was not supported
         throw new Exception\ReportNotSupported();
     }
     // Sending back false will interupt the event chain and tell the server
     // we've handled this method.
     return false;
 }
示例#17
0
 /**
  * Fakes a successful LOCK
  *
  * @param RequestInterface $request
  * @param ResponseInterface $response
  * @return bool
  */
 public function fakeLockProvider(RequestInterface $request, ResponseInterface $response)
 {
     $lockInfo = new LockInfo();
     $lockInfo->token = md5($request->getPath());
     $lockInfo->uri = $request->getPath();
     $lockInfo->depth = \Sabre\DAV\Server::DEPTH_INFINITY;
     $lockInfo->timeout = 1800;
     $body = $this->server->xml->write('{DAV:}prop', ['{DAV:}lockdiscovery' => new LockDiscovery([$lockInfo])]);
     $response->setBody($body);
     return false;
 }
示例#18
0
 /**
  * POST operation on Comments collections
  *
  * @param RequestInterface $request request object
  * @param ResponseInterface $response response object
  * @return null|false
  */
 public function httpPost(RequestInterface $request, ResponseInterface $response)
 {
     $path = $request->getPath();
     $node = $this->server->tree->getNodeForPath($path);
     if (!$node instanceof EntityCollection) {
         return null;
     }
     $data = $request->getBodyAsString();
     $comment = $this->createComment($node->getName(), $node->getId(), $data, $request->getHeader('Content-Type'));
     // update read marker for the current user/poster to avoid
     // having their own comments marked as unread
     $node->setReadMarker(null);
     $url = $request->getUrl() . '/' . urlencode($comment->getId());
     $response->setHeader('Content-Location', $url);
     // created
     $response->setStatus(201);
     return false;
 }
示例#19
0
 /**
  * Returns the HTTP custom range update header
  *
  * This method returns null if there is no well-formed HTTP range request
  * header. It returns array(1) if it was an append request, array(2,
  * $start, $end) if it's a start and end range, lastly it's array(3,
  * $endoffset) if the offset was negative, and should be calculated from
  * the end of the file.
  *
  * Examples:
  *
  * null - invalid
  * [1] - append
  * [2,10,15] - update bytes 10, 11, 12, 13, 14, 15
  * [2,10,null] - update bytes 10 until the end of the patch body
  * [3,-5] - update from 5 bytes from the end of the file.
  *
  * @param RequestInterface $request
  * @return array|null
  */
 function getHTTPUpdateRange(RequestInterface $request)
 {
     $range = $request->getHeader('X-Update-Range');
     if (is_null($range)) {
         return null;
     }
     // Matching "Range: bytes=1234-5678: both numbers are optional
     if (!preg_match('/^(append)|(?:bytes=([0-9]+)-([0-9]*))|(?:bytes=(-[0-9]+))$/i', $range, $matches)) {
         return null;
     }
     if ($matches[1] === 'append') {
         return [self::RANGE_APPEND];
     } elseif (strlen($matches[2]) > 0) {
         return [self::RANGE_START, $matches[2], $matches[3] ?: null];
     } elseif ($matches[4]) {
         return [self::RANGE_END, $matches[4]];
     } else {
         return null;
     }
 }
 /**
  * This method is called when a user could not be authenticated, and
  * authentication was required for the current request.
  *
  * This gives you the opportunity to set authentication headers. The 401
  * status code will already be set.
  *
  * In this case of Basic Auth, this would for example mean that the
  * following header needs to be set:
  *
  * $response->addHeader('WWW-Authenticate', 'Basic realm=SabreDAV');
  *
  * Keep in mind that in the case of multiple authentication backends, other
  * WWW-Authenticate headers may already have been set, and you'll want to
  * append your own WWW-Authenticate header instead of overwriting the
  * existing one.
  *
  * @param RequestInterface  $request
  * @param ResponseInterface $response
  */
 public function challenge(RequestInterface $request, ResponseInterface $response)
 {
     $auth = new Auth\BasicAuth($this->realm, $request, $response, $this->user_manager);
     $userpass = $auth->getCredentials($this->encoder_service);
     if (!$userpass) {
         $auth->requireLogin();
     }
     // Authenticates the user
     if (!$this->validateUserPass($userpass[0], $userpass[1])) {
         $auth->requireLogin();
     }
     $this->currentUser = $userpass[0];
     $request->setCurrentUsername($this->currentUser);
 }
示例#21
0
文件: auth.php 项目: mnefedov/core
 /**
  * @param RequestInterface $request
  * @param ResponseInterface $response
  * @return array
  */
 private function auth(RequestInterface $request, ResponseInterface $response)
 {
     if (\OC_User::handleApacheAuth() || $this->userSession->isLoggedIn() && is_null($this->session->get(self::DAV_AUTHENTICATED)) || $this->userSession->isLoggedIn() && $this->session->get(self::DAV_AUTHENTICATED) === $this->userSession->getUser()->getUID() && $request->getHeader('Authorization') === null) {
         $user = $this->userSession->getUser()->getUID();
         \OC_Util::setupFS($user);
         $this->currentUser = $user;
         $this->session->close();
         return [true, $this->principalPrefix . $user];
     }
     if (!$this->userSession->isLoggedIn() && in_array('XMLHttpRequest', explode(',', $request->getHeader('X-Requested-With')))) {
         // do not re-authenticate over ajax, use dummy auth name to prevent browser popup
         $response->addHeader('WWW-Authenticate', 'DummyBasic realm="' . $this->realm . '"');
         $response->setStatus(401);
         throw new \Sabre\DAV\Exception\NotAuthenticated('Cannot authenticate over ajax calls');
     }
     return parent::check($request, $response);
 }
示例#22
0
 /**
  * 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.
  *
  * In addition, it will also ensure that it checks any missing lokens that
  * must be present in the request, and reject requests without the proper
  * tokens.
  *
  * @param RequestInterface $request
  * @param mixed $conditions
  * @return void
  */
 function validateTokens(RequestInterface $request, &$conditions)
 {
     // First we need to gather a list of locks that must be satisfied.
     $mustLocks = [];
     $method = $request->getMethod();
     // Methods not in that list are operations that doesn't alter any
     // resources, and we don't need to check the lock-states for.
     switch ($method) {
         case 'DELETE':
             $mustLocks = array_merge($mustLocks, $this->getLocks($request->getPath(), true));
             break;
         case 'MKCOL':
         case 'MKCALENDAR':
         case 'PROPPATCH':
         case 'PUT':
         case 'PATCH':
             $mustLocks = array_merge($mustLocks, $this->getLocks($request->getPath(), false));
             break;
         case 'MOVE':
             $mustLocks = array_merge($mustLocks, $this->getLocks($request->getPath(), true));
             $mustLocks = array_merge($mustLocks, $this->getLocks($this->server->calculateUri($request->getHeader('Destination')), false));
             break;
         case 'COPY':
             $mustLocks = array_merge($mustLocks, $this->getLocks($this->server->calculateUri($request->getHeader('Destination')), false));
             break;
         case 'LOCK':
             //Temporary measure.. figure out later why this is needed
             // Here we basically ignore all incoming tokens...
             foreach ($conditions as $ii => $condition) {
                 foreach ($condition['tokens'] as $jj => $token) {
                     $conditions[$ii]['tokens'][$jj]['validToken'] = true;
                 }
             }
             return;
     }
     // It's possible that there's identical locks, because of shared
     // parents. We're removing the duplicates here.
     $tmp = [];
     foreach ($mustLocks as $lock) {
         $tmp[$lock->token] = $lock;
     }
     $mustLocks = array_values($tmp);
     foreach ($conditions as $kk => $condition) {
         foreach ($condition['tokens'] as $ii => $token) {
             // Lock tokens always start with opaquelocktoken:
             if (substr($token['token'], 0, 16) !== 'opaquelocktoken:') {
                 continue;
             }
             $checkToken = substr($token['token'], 16);
             // Looping through our list with locks.
             foreach ($mustLocks as $jj => $mustLock) {
                 if ($mustLock->token == $checkToken) {
                     // We have a match!
                     // Removing this one from mustlocks
                     unset($mustLocks[$jj]);
                     // Marking the condition as valid.
                     $conditions[$kk]['tokens'][$ii]['validToken'] = true;
                     // Advancing to the next token
                     continue 2;
                 }
             }
             // If we got here, it means that there was a
             // lock-token, but it was not in 'mustLocks'.
             //
             // This is an edge-case, as it could mean that token
             // was specified with a url that was not 'required' to
             // check. So we're doing one extra lookup to make sure
             // we really don't know this token.
             //
             // This also gets triggered when the user specified a
             // lock-token that was expired.
             $oddLocks = $this->getLocks($condition['uri']);
             foreach ($oddLocks as $oddLock) {
                 if ($oddLock->token === $checkToken) {
                     // We have a hit!
                     $conditions[$kk]['tokens'][$ii]['validToken'] = true;
                     continue 2;
                 }
             }
             // If we get all the way here, the lock-token was
             // really unknown.
         }
     }
     // If there's any locks left in the 'mustLocks' array, it means that
     // the resource was locked and we must block it.
     if ($mustLocks) {
         throw new DAV\Exception\Locked(reset($mustLocks));
     }
 }
示例#23
0
 /**
  * @param RequestInterface $request
  * @param ResponseInterface $response
  * @return array
  * @throws NotAuthenticated
  */
 private function auth(RequestInterface $request, ResponseInterface $response)
 {
     $forcedLogout = false;
     if (!$this->request->passesCSRFCheck() && $this->requiresCSRFCheck()) {
         // In case of a fail with POST we need to recheck the credentials
         if ($this->request->getMethod() === 'POST') {
             $forcedLogout = true;
         } else {
             $response->setStatus(401);
             throw new \Sabre\DAV\Exception\NotAuthenticated('CSRF check not passed.');
         }
     }
     if ($forcedLogout) {
         $this->userSession->logout();
     } else {
         if ($this->twoFactorManager->needsSecondFactor()) {
             throw new \Sabre\DAV\Exception\NotAuthenticated('2FA challenge not passed.');
         }
         if (\OC_User::handleApacheAuth() || $this->userSession->isLoggedIn() && is_null($this->session->get(self::DAV_AUTHENTICATED)) || $this->userSession->isLoggedIn() && $this->session->get(self::DAV_AUTHENTICATED) === $this->userSession->getUser()->getUID() && $request->getHeader('Authorization') === null) {
             $user = $this->userSession->getUser()->getUID();
             \OC_Util::setupFS($user);
             $this->currentUser = $user;
             $this->session->close();
             return [true, $this->principalPrefix . $user];
         }
     }
     if (!$this->userSession->isLoggedIn() && in_array('XMLHttpRequest', explode(',', $request->getHeader('X-Requested-With')))) {
         // do not re-authenticate over ajax, use dummy auth name to prevent browser popup
         $response->addHeader('WWW-Authenticate', 'DummyBasic realm="' . $this->realm . '"');
         $response->setStatus(401);
         throw new \Sabre\DAV\Exception\NotAuthenticated('Cannot authenticate over ajax calls');
     }
     $data = parent::check($request, $response);
     if ($data[0] === true) {
         $startPos = strrpos($data[1], '/') + 1;
         $user = $this->userSession->getUser()->getUID();
         $data[1] = substr_replace($data[1], $user, $startPos);
     }
     return $data;
 }
示例#24
0
文件: Plugin.php 项目: LobbyOS/server
 /**
  * This method checks the 'Schedule-Reply' header
  * and returns false if it's 'F', otherwise true.
  *
  * @param RequestInterface $request
  * @return bool
  */
 private function scheduleReply(RequestInterface $request)
 {
     $scheduleReply = $request->getHeader('Schedule-Reply');
     return $scheduleReply !== 'F';
 }
示例#25
0
 /**
  * Fakes a successful LOCK
  *
  * @param RequestInterface $request
  * @param ResponseInterface $response
  * @return bool
  */
 public function fakeLockProvider(RequestInterface $request, ResponseInterface $response)
 {
     $dom = new \DOMDocument('1.0', 'utf-8');
     $prop = $dom->createElementNS('DAV:', 'd:prop');
     $dom->appendChild($prop);
     $lockDiscovery = $dom->createElementNS('DAV:', 'd:lockdiscovery');
     $prop->appendChild($lockDiscovery);
     $lockInfo = new LockInfo();
     $lockInfo->token = md5($request->getPath());
     $lockInfo->uri = $request->getPath();
     $lockInfo->depth = \Sabre\DAV\Server::DEPTH_INFINITY;
     $lockInfo->timeout = 1800;
     $lockObj = new LockDiscovery([$lockInfo]);
     $lockObj->serialize($this->server, $lockDiscovery);
     $response->setBody($dom->saveXML());
     return false;
 }
 /**
  * This method handles the PROPFIND method.
  *
  * It's a very lazy method, it won't bother checking the request body
  * for which properties were requested, and just sends back a default
  * set of properties.
  *
  * @param RequestInterface $request
  * @param ResponseInterface $hR
  * @param string $tempLocation
  * @return bool
  */
 function httpPropfind(RequestInterface $request, ResponseInterface $hR, $tempLocation)
 {
     if (!file_exists($tempLocation)) {
         return;
     }
     $hR->setHeader('X-Sabre-Temp', 'true');
     $hR->setStatus(207);
     $hR->setHeader('Content-Type', 'application/xml; charset=utf-8');
     $properties = ['href' => $request->getPath(), 200 => ['{DAV:}getlastmodified' => new Xml\Property\GetLastModified(filemtime($tempLocation)), '{DAV:}getcontentlength' => filesize($tempLocation), '{DAV:}resourcetype' => new Xml\Property\ResourceType(null), '{' . Server::NS_SABREDAV . '}tempFile' => true]];
     $data = $this->server->generateMultiStatus([$properties]);
     $hR->setBody($data);
     return false;
 }
示例#27
0
文件: Plugin.php 项目: samj1912/repo
 /**
  * This event is triggered after GET requests.
  *
  * This is used to transform data into jCal, if this was requested.
  *
  * @param RequestInterface $request
  * @param ResponseInterface $response
  * @return void
  */
 function httpAfterGet(RequestInterface $request, ResponseInterface $response)
 {
     if (strpos($response->getHeader('Content-Type'), 'text/vcard') === false) {
         return;
     }
     $target = $this->negotiateVCard($request->getHeader('Accept'), $mimeType);
     $newBody = $this->convertVCard($response->getBody(), $target);
     $response->setBody($newBody);
     $response->setHeader('Content-Type', $mimeType . '; charset=utf-8');
     $response->setHeader('Content-Length', strlen($newBody));
 }
示例#28
0
 /**
  * This event is triggered after GET requests.
  *
  * This is used to transform data into jCal, if this was requested.
  *
  * @param RequestInterface $request
  * @param ResponseInterface $response
  * @return void
  */
 function httpAfterGet(RequestInterface $request, ResponseInterface $response)
 {
     if (strpos($response->getHeader('Content-Type'), 'text/calendar') === false) {
         return;
     }
     $result = HTTP\Util::negotiate($request->getHeader('Accept'), ['text/calendar', 'application/calendar+json']);
     if ($result !== 'application/calendar+json') {
         // Do nothing
         return;
     }
     // Transforming.
     $vobj = VObject\Reader::read($response->getBody());
     $jsonBody = json_encode($vobj->jsonSerialize());
     $response->setBody($jsonBody);
     $response->setHeader('Content-Type', 'application/calendar+json');
     $response->setHeader('Content-Length', strlen($jsonBody));
 }
示例#29
0
 /**
  * This method is responsible for handling the 'ACL' event.
  *
  * @param RequestInterface $request
  * @param ResponseInterface $response
  * @return bool
  */
 function httpAcl(RequestInterface $request, ResponseInterface $response)
 {
     $path = $request->getPath();
     $body = $request->getBodyAsString();
     $dom = DAV\XMLUtil::loadDOMDocument($body);
     $newAcl = Property\Acl::unserialize($dom->firstChild, $this->server->propertyMap)->getPrivileges();
     // Normalizing urls
     foreach ($newAcl as $k => $newAce) {
         $newAcl[$k]['principal'] = $this->server->calculateUri($newAce['principal']);
     }
     $node = $this->server->tree->getNodeForPath($path);
     if (!$node instanceof IACL) {
         throw new DAV\Exception\MethodNotAllowed('This node does not support the ACL method');
     }
     $oldAcl = $this->getACL($node);
     $supportedPrivileges = $this->getFlatPrivilegeSet($node);
     /* Checking if protected principals from the existing principal set are
        not overwritten. */
     foreach ($oldAcl as $oldAce) {
         if (!isset($oldAce['protected']) || !$oldAce['protected']) {
             continue;
         }
         $found = false;
         foreach ($newAcl as $newAce) {
             if ($newAce['privilege'] === $oldAce['privilege'] && $newAce['principal'] === $oldAce['principal'] && $newAce['protected']) {
                 $found = true;
             }
         }
         if (!$found) {
             throw new Exception\AceConflict('This resource contained a protected {DAV:}ace, but this privilege did not occur in the ACL request');
         }
     }
     foreach ($newAcl as $newAce) {
         // Do we recognize the privilege
         if (!isset($supportedPrivileges[$newAce['privilege']])) {
             throw new Exception\NotSupportedPrivilege('The privilege you specified (' . $newAce['privilege'] . ') is not recognized by this server');
         }
         if ($supportedPrivileges[$newAce['privilege']]['abstract']) {
             throw new Exception\NoAbstract('The privilege you specified (' . $newAce['privilege'] . ') is an abstract privilege');
         }
         // Looking up the principal
         try {
             $principal = $this->server->tree->getNodeForPath($newAce['principal']);
         } catch (DAV\Exception\NotFound $e) {
             throw new Exception\NotRecognizedPrincipal('The specified principal (' . $newAce['principal'] . ') does not exist');
         }
         if (!$principal instanceof IPrincipal) {
             throw new Exception\NotRecognizedPrincipal('The specified uri (' . $newAce['principal'] . ') is not a principal');
         }
     }
     $node->setACL($newAcl);
     $response->setStatus(200);
     // Breaking the event chain, because we handled this method.
     return false;
 }
示例#30
0
 /**
  * This event is triggered before the usual GET request handler.
  *
  * We use this to intercept GET calls to notification nodes, and return the
  * proper response.
  *
  * @param RequestInterface $request
  * @param ResponseInterface $response
  * @return void
  */
 function httpGet(RequestInterface $request, ResponseInterface $response)
 {
     $path = $request->getPath();
     try {
         $node = $this->server->tree->getNodeForPath($path);
     } catch (DAV\Exception\NotFound $e) {
         return;
     }
     if (!$node instanceof INode) {
         return;
     }
     $dom = new \DOMDocument('1.0', 'UTF-8');
     $dom->formatOutput = true;
     $root = $dom->createElement('cs:notification');
     foreach ($this->server->xmlNamespaces as $namespace => $prefix) {
         $root->setAttribute('xmlns:' . $prefix, $namespace);
     }
     $dom->appendChild($root);
     $node->getNotificationType()->serializeBody($this->server, $root);
     $response->setHeader('Content-Type', 'application/xml');
     $response->setHeader('ETag', $node->getETag());
     $response->setStatus(200);
     $response->setBody($dom->saveXML());
     // Return false to break the event chain.
     return false;
 }