예제 #1
0
 /**
  * 'beforeMethod' event handles. This event handles intercepts GET requests ending
  * with ?export
  *
  * @param string $method
  * @param string $uri
  * @return bool
  */
 public function beforeMethod($method, $uri)
 {
     if ($method != 'GET') {
         return;
     }
     if ($this->server->httpRequest->getQueryString() != 'export') {
         return;
     }
     // splitting uri
     list($uri) = explode('?', $uri, 2);
     $node = $this->server->tree->getNodeForPath($uri);
     if (!$node instanceof Calendar) {
         return;
     }
     // Checking ACL, if available.
     if ($aclPlugin = $this->server->getPlugin('acl')) {
         $aclPlugin->checkPrivileges($uri, '{DAV:}read');
     }
     $this->server->httpResponse->setHeader('Content-Type', 'text/calendar');
     $this->server->httpResponse->sendStatus(200);
     $nodes = $this->server->getPropertiesForPath($uri, array('{' . Plugin::NS_CALDAV . '}calendar-data'), 1);
     $this->server->httpResponse->sendBody($this->generateICS($nodes));
     // Returning false to break the event chain
     return false;
 }
예제 #2
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;
 }
예제 #3
0
 protected function getUser()
 {
     $user = null;
     $authPlugin = $this->server->getPlugin('auth');
     if ($authPlugin !== null) {
         $user = $authPlugin->getCurrentUser();
     }
     return $user;
 }
예제 #4
0
 function setUp()
 {
     $nodes = [new DAV\Mock\Collection('testdir', ['file1.txt' => 'contents'])];
     $this->server = new DAV\Server($nodes);
     $this->server->addPlugin(new DAV\Auth\Plugin(new DAV\Auth\Backend\Mock()));
     // Login
     $this->server->getPlugin('auth')->beforeMethod(new \Sabre\HTTP\Request(), new \Sabre\HTTP\Response());
     $aclPlugin = new Plugin();
     $this->server->addPlugin($aclPlugin);
 }
예제 #5
0
 function setUp()
 {
     $nodes = [new DAV\SimpleCollection('testdir')];
     $this->server = new DAV\Server($nodes);
     $this->plugin = new Plugin();
     $this->plugin->setDefaultAcl([]);
     $this->server->addPlugin(new DAV\Auth\Plugin(new DAV\Auth\Backend\Mock()));
     // Login
     $this->server->getPlugin('auth')->beforeMethod(new \Sabre\HTTP\Request(), new \Sabre\HTTP\Response());
     $this->server->addPlugin($this->plugin);
 }
예제 #6
0
 /**
  * PropFind
  *
  * @param PropFind $propFind
  * @param BaseINode $node
  * @return void
  */
 function propFind(PropFind $propFind, BaseINode $node)
 {
     $caldavPlugin = $this->server->getPlugin('caldav');
     if ($node instanceof DAVACL\IPrincipal) {
         $principalUrl = $node->getPrincipalUrl();
         // notification-URL property
         $propFind->handle('{' . self::NS_CALENDARSERVER . '}notification-URL', function () use($principalUrl, $caldavPlugin) {
             $notificationPath = $caldavPlugin->getCalendarHomeForPrincipal($principalUrl) . '/notifications/';
             return new DAV\Xml\Property\Href($notificationPath);
         });
     }
     if ($node instanceof INode) {
         $propFind->handle('{' . self::NS_CALENDARSERVER . '}notificationtype', [$node, 'getNotificationType']);
     }
 }
예제 #7
0
 /**
  * This method is used to generate HTML output for the
  * DAV\Browser\Plugin.
  *
  * @param INode $node
  * @param string $output
  * @param string $path
  * @return bool|null
  */
 function htmlActionsPanel(INode $node, &$output, $path)
 {
     if (!$node instanceof ISharedNode) {
         return;
     }
     $aclPlugin = $this->server->getPlugin('acl');
     if ($aclPlugin) {
         if (!$aclPlugin->checkPrivileges($path, '{DAV:}share', \Sabre\DAVACL\Plugin::R_PARENT, false)) {
             // Sharing is not permitted, we will not draw this interface.
             return;
         }
     }
     $output .= '<tr><td colspan="2"><form method="post" action="">
         <h3>Share this resource</h3>
         <input type="hidden" name="sabreAction" value="share" />
         <label>Share with (uri):</label> <input type="text" name="href" placeholder="mailto:user@example.org"/><br />
         <label>Access</label>
             <select name="access">
                 <option value="readwrite">Read-write</option>
                 <option value="read">Read-only</option>
                 <option value="no-access">Revoke access</option>
             </select><br />
          <input type="submit" value="share" />
         </form>
         </td></tr>';
 }
예제 #8
0
 function testInit()
 {
     $fakeServer = new DAV\Server(new DAV\SimpleCollection('bla'));
     $plugin = new Plugin(new Backend\Mock(), 'realm');
     $this->assertTrue($plugin instanceof Plugin);
     $fakeServer->addPlugin($plugin);
     $this->assertEquals($plugin, $fakeServer->getPlugin('auth'));
 }
예제 #9
0
 /**
  * This method is responsible for parsing the request and generating the
  * response for the CALDAV:free-busy-query REPORT.
  *
  * @param \DOMNode $dom
  * @return void
  */
 protected function freeBusyQueryReport(\DOMNode $dom)
 {
     $start = null;
     $end = null;
     foreach ($dom->firstChild->childNodes as $childNode) {
         $clark = DAV\XMLUtil::toClarkNotation($childNode);
         if ($clark == '{' . self::NS_CALDAV . '}time-range') {
             $start = $childNode->getAttribute('start');
             $end = $childNode->getAttribute('end');
             break;
         }
     }
     if ($start) {
         $start = VObject\DateTimeParser::parseDateTime($start);
     }
     if ($end) {
         $end = VObject\DateTimeParser::parseDateTime($end);
     }
     $uri = $this->server->getRequestUri();
     if (!$start && !$end) {
         throw new DAV\Exception\BadRequest('The freebusy report must have a time-range filter');
     }
     $acl = $this->server->getPlugin('acl');
     if ($acl) {
         $acl->checkPrivileges($uri, '{' . self::NS_CALDAV . '}read-free-busy');
     }
     $calendar = $this->server->tree->getNodeForPath($uri);
     if (!$calendar instanceof ICalendar) {
         throw new DAV\Exception\NotImplemented('The free-busy-query REPORT is only implemented on calendars');
     }
     $tzProp = '{' . self::NS_CALDAV . '}calendar-timezone';
     // Figuring out the default timezone for the calendar, for floating
     // times.
     $calendarProps = $this->server->getProperties($uri, [$tzProp]);
     if (isset($calendarProps[$tzProp])) {
         $vtimezoneObj = VObject\Reader::read($calendarProps[$tzProp]);
         $calendarTimeZone = $vtimezoneObj->VTIMEZONE->getTimeZone();
     } else {
         $calendarTimeZone = new DateTimeZone('UTC');
     }
     // Doing a calendar-query first, to make sure we get the most
     // performance.
     $urls = $calendar->calendarQuery(['name' => 'VCALENDAR', 'comp-filters' => [['name' => 'VEVENT', 'comp-filters' => [], 'prop-filters' => [], 'is-not-defined' => false, 'time-range' => ['start' => $start, 'end' => $end]]], 'prop-filters' => [], 'is-not-defined' => false, 'time-range' => null]);
     $objects = array_map(function ($url) use($calendar) {
         $obj = $calendar->getChild($url)->get();
         return $obj;
     }, $urls);
     $generator = new VObject\FreeBusyGenerator();
     $generator->setObjects($objects);
     $generator->setTimeRange($start, $end);
     $generator->setTimeZone($calendarTimeZone);
     $result = $generator->getResult();
     $result = $result->serialize();
     $this->server->httpResponse->setStatus(200);
     $this->server->httpResponse->setHeader('Content-Type', 'text/calendar');
     $this->server->httpResponse->setHeader('Content-Length', strlen($result));
     $this->server->httpResponse->setBody($result);
 }
예제 #10
0
파일: Plugin.php 프로젝트: LobbyOS/server
 /**
  * Returns free-busy information for a specific address. The returned
  * data is an array containing the following properties:
  *
  * calendar-data : A VFREEBUSY VObject
  * request-status : an iTip status code.
  * href: The principal's email address, as requested
  *
  * The following request status codes may be returned:
  *   * 2.0;description
  *   * 3.7;description
  *
  * @param string $email address
  * @param \DateTime $start
  * @param \DateTime $end
  * @param VObject\Component $request
  * @return array
  */
 protected function getFreeBusyForEmail($email, \DateTime $start, \DateTime $end, VObject\Component $request)
 {
     $caldavNS = '{' . Plugin::NS_CALDAV . '}';
     $aclPlugin = $this->server->getPlugin('acl');
     if (substr($email, 0, 7) === 'mailto:') {
         $email = substr($email, 7);
     }
     $result = $aclPlugin->principalSearch(['{http://sabredav.org/ns}email-address' => $email], ['{DAV:}principal-URL', $caldavNS . 'calendar-home-set', '{http://sabredav.org/ns}email-address']);
     if (!count($result)) {
         return ['request-status' => '3.7;Could not find principal', 'href' => 'mailto:' . $email];
     }
     if (!isset($result[0][200][$caldavNS . 'calendar-home-set'])) {
         return ['request-status' => '3.7;No calendar-home-set property found', 'href' => 'mailto:' . $email];
     }
     $homeSet = $result[0][200][$caldavNS . 'calendar-home-set']->getHref();
     // Grabbing the calendar list
     $objects = [];
     foreach ($this->server->tree->getNodeForPath($homeSet)->getChildren() as $node) {
         if (!$node instanceof ICalendar) {
             continue;
         }
         $sct = $caldavNS . 'schedule-calendar-transp';
         $ctz = $caldavNS . 'calendar-timezone';
         $props = $node->getProperties([$sct, $ctz]);
         if (isset($props[$sct]) && $props[$sct]->getValue() == ScheduleCalendarTransp::TRANSPARENT) {
             // If a calendar is marked as 'transparent', it means we must
             // ignore it for free-busy purposes.
             continue;
         }
         $aclPlugin->checkPrivileges($homeSet . $node->getName(), $caldavNS . 'read-free-busy');
         if (isset($props[$ctz])) {
             $vtimezoneObj = VObject\Reader::read($props[$ctz]);
             $calendarTimeZone = $vtimezoneObj->VTIMEZONE->getTimeZone();
         } else {
             $calendarTimeZone = new DateTimeZone('UTC');
         }
         // Getting the list of object uris within the time-range
         $urls = $node->calendarQuery(['name' => 'VCALENDAR', 'comp-filters' => [['name' => 'VEVENT', 'comp-filters' => [], 'prop-filters' => [], 'is-not-defined' => false, 'time-range' => ['start' => $start, 'end' => $end]]], 'prop-filters' => [], 'is-not-defined' => false, 'time-range' => null]);
         $calObjects = array_map(function ($url) use($node) {
             $obj = $node->getChild($url)->get();
             return $obj;
         }, $urls);
         $objects = array_merge($objects, $calObjects);
     }
     $vcalendar = new VObject\Component\VCalendar();
     $vcalendar->METHOD = 'REPLY';
     $generator = new VObject\FreeBusyGenerator();
     $generator->setObjects($objects);
     $generator->setTimeRange($start, $end);
     $generator->setBaseObject($vcalendar);
     $generator->setTimeZone($calendarTimeZone);
     $result = $generator->getResult();
     $vcalendar->VFREEBUSY->ATTENDEE = 'mailto:' . $email;
     $vcalendar->VFREEBUSY->UID = (string) $request->VFREEBUSY->UID;
     $vcalendar->VFREEBUSY->ORGANIZER = clone $request->VFREEBUSY->ORGANIZER;
     return ['calendar-data' => $result, 'request-status' => '2.0;Success', 'href' => 'mailto:' . $email];
 }
예제 #11
0
 function testInit()
 {
     $fakeServer = new DAV\Server(new DAV\SimpleCollection('bla'));
     $plugin = new Plugin(new Backend\Mock());
     $this->assertTrue($plugin instanceof Plugin);
     $fakeServer->addPlugin($plugin);
     $this->assertEquals($plugin, $fakeServer->getPlugin('auth'));
     $this->assertInternalType('array', $plugin->getPluginInfo());
 }
예제 #12
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;
     }
 }
예제 #13
0
 function getServer()
 {
     $tree = array(new MockPropertyNode('node1', array('{http://sabredav.org/ns}simple' => 'foo', '{http://sabredav.org/ns}href' => new DAV\Property\Href('node2'), '{DAV:}displayname' => 'Node 1')), new MockPropertyNode('node2', array('{http://sabredav.org/ns}simple' => 'simple', '{http://sabredav.org/ns}hreflist' => new DAV\Property\HrefList(array('node1', 'node3')), '{DAV:}displayname' => 'Node 2')), new MockPropertyNode('node3', array('{http://sabredav.org/ns}simple' => 'simple', '{DAV:}displayname' => 'Node 3')));
     $fakeServer = new DAV\Server($tree);
     $fakeServer->debugExceptions = true;
     $fakeServer->httpResponse = new HTTP\ResponseMock();
     $plugin = new Plugin();
     $plugin->allowAccessToNodesWithoutACL = true;
     $this->assertTrue($plugin instanceof Plugin);
     $fakeServer->addPlugin($plugin);
     $this->assertEquals($plugin, $fakeServer->getPlugin('acl'));
     return $fakeServer;
 }
예제 #14
0
 function getServer()
 {
     $tree = [new DAV\Mock\PropertiesCollection('node1', [], ['{http://sabredav.org/ns}simple' => 'foo', '{http://sabredav.org/ns}href' => new DAV\Xml\Property\Href('node2'), '{DAV:}displayname' => 'Node 1']), new DAV\Mock\PropertiesCollection('node2', [], ['{http://sabredav.org/ns}simple' => 'simple', '{http://sabredav.org/ns}hreflist' => new DAV\Xml\Property\Href(['node1', 'node3']), '{DAV:}displayname' => 'Node 2']), new DAV\Mock\PropertiesCollection('node3', [], ['{http://sabredav.org/ns}simple' => 'simple', '{DAV:}displayname' => 'Node 3'])];
     $fakeServer = new DAV\Server($tree);
     $fakeServer->sapi = new HTTP\SapiMock();
     $fakeServer->debugExceptions = true;
     $fakeServer->httpResponse = new HTTP\ResponseMock();
     $plugin = new Plugin();
     $plugin->allowAccessToNodesWithoutACL = true;
     $this->assertTrue($plugin instanceof Plugin);
     $fakeServer->addPlugin($plugin);
     $this->assertEquals($plugin, $fakeServer->getPlugin('acl'));
     return $fakeServer;
 }
 function getServer()
 {
     $backend = new PrincipalBackend\Mock();
     $dir = new DAV\SimpleCollection('root');
     $principals = new PrincipalCollection($backend);
     $dir->addChild($principals);
     $fakeServer = new DAV\Server(new DAV\ObjectTree($dir));
     $fakeServer->httpResponse = new HTTP\ResponseMock();
     $plugin = new Plugin($backend, 'realm');
     $this->assertTrue($plugin instanceof Plugin);
     $fakeServer->addPlugin($plugin);
     $this->assertEquals($plugin, $fakeServer->getPlugin('acl'));
     return $fakeServer;
 }
예제 #16
0
 /**
  * We intercept this to handle POST requests on a dav resource.
  *
  * @param RequestInterface $request
  * @param ResponseInterface $response
  * @return null|false
  */
 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;
     }
     $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);
     $message = $this->server->xml->parse($requestBody, $request->getUrl(), $documentType);
     switch ($documentType) {
         // Dealing with the 'share' document, which modified invitees on a
         // calendar.
         case '{' . self::NS_OWNCLOUD . '}share':
             // We can only deal with IShareableCalendar objects
             if (!$node instanceof IShareable) {
                 return;
             }
             $this->server->transactionType = 'post-oc-resource-share';
             // Getting ACL info
             $acl = $this->server->getPlugin('acl');
             // If there's no ACL support, we allow everything
             if ($acl) {
                 /** @var \Sabre\DAVACL\Plugin $acl */
                 $acl->checkPrivileges($path, '{DAV:}write');
             }
             $node->updateShares($message->set, $message->remove);
             $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;
     }
 }
 protected function _principalSearchReport(\DOMDocument $dom)
 {
     $requestedProperties = array_keys(\Sabre\DAV\XMLUtil::parseProperties($dom->firstChild));
     $searchTokens = $dom->firstChild->getElementsByTagName('search-token');
     $searchProperties = array();
     if ($searchTokens->length > 0) {
         $searchProperties['{http://calendarserver.org/ns/}search-token'] = $searchTokens->item(0)->nodeValue;
     }
     $result = $this->server->getPlugin('acl')->principalSearch($searchProperties, $requestedProperties);
     $prefer = $this->server->getHTTPPRefer();
     $this->server->httpResponse->sendStatus(207);
     $this->server->httpResponse->setHeader('Content-Type', 'application/xml; charset=utf-8');
     $this->server->httpResponse->setHeader('Vary', 'Brief,Prefer');
     $this->server->httpResponse->sendBody($this->server->generateMultiStatus($result, $prefer['return-minimal']));
 }
 function getServer()
 {
     $backend = new PrincipalBackend\Mock();
     $dir = new DAV\SimpleCollection('root');
     $principals = new PrincipalCollection($backend);
     $dir->addChild($principals);
     $fakeServer = new DAV\Server($dir);
     $fakeServer->sapi = new HTTP\SapiMock();
     $fakeServer->httpResponse = new HTTP\ResponseMock();
     $plugin = new Plugin();
     $plugin->allowUnauthenticatedAccess = false;
     $this->assertTrue($plugin instanceof Plugin);
     $fakeServer->addPlugin($plugin);
     $this->assertEquals($plugin, $fakeServer->getPlugin('acl'));
     return $fakeServer;
 }
예제 #19
0
 function getServer()
 {
     $tree = [new DAV\Mock\PropertiesCollection('node1', [], ['{http://sabredav.org/ns}simple' => 'foo', '{http://sabredav.org/ns}href' => new DAV\Xml\Property\Href('node2'), '{DAV:}displayname' => 'Node 1']), new DAV\Mock\PropertiesCollection('node2', [], ['{http://sabredav.org/ns}simple' => 'simple', '{http://sabredav.org/ns}hreflist' => new DAV\Xml\Property\Href(['node1', 'node3']), '{DAV:}displayname' => 'Node 2']), new DAV\Mock\PropertiesCollection('node3', [], ['{http://sabredav.org/ns}simple' => 'simple', '{DAV:}displayname' => 'Node 3'])];
     $fakeServer = new DAV\Server($tree);
     $fakeServer->sapi = new HTTP\SapiMock();
     $fakeServer->debugExceptions = true;
     $fakeServer->httpResponse = new HTTP\ResponseMock();
     $plugin = new Plugin();
     $plugin->allowUnauthenticatedAccess = false;
     // Anyone can do anything
     $plugin->setDefaultACL([['principal' => '{DAV:}all', 'privilege' => '{DAV:}all']]);
     $this->assertTrue($plugin instanceof Plugin);
     $fakeServer->addPlugin($plugin);
     $this->assertEquals($plugin, $fakeServer->getPlugin('acl'));
     return $fakeServer;
 }
 function getServer()
 {
     $backend = new PrincipalBackend\Mock();
     $dir = new DAV\SimpleCollection('root');
     $principals = new PrincipalCollection($backend);
     $dir->addChild($principals);
     $fakeServer = new DAV\Server($dir);
     $fakeServer->sapi = new HTTP\SapiMock();
     $fakeServer->httpResponse = new HTTP\ResponseMock();
     $fakeServer->debugExceptions = true;
     $plugin = new MockPlugin($backend, 'realm');
     $plugin->allowAccessToNodesWithoutACL = true;
     $this->assertTrue($plugin instanceof Plugin);
     $fakeServer->addPlugin($plugin);
     $this->assertEquals($plugin, $fakeServer->getPlugin('acl'));
     return $fakeServer;
 }
예제 #21
0
 /**
  * Returns free-busy information for a specific address. The returned
  * data is an array containing the following properties:
  *
  * calendar-data : A VFREEBUSY VObject
  * request-status : an iTip status code.
  * href: The principal's email address, as requested
  *
  * The following request status codes may be returned:
  *   * 2.0;description
  *   * 3.7;description
  *
  * @param string $email address
  * @param \DateTime $start
  * @param \DateTime $end
  * @param VObject\Component $request
  * @return array
  */
 protected function getFreeBusyForEmail($email, \DateTime $start, \DateTime $end, VObject\Component $request)
 {
     $caldavNS = '{' . Plugin::NS_CALDAV . '}';
     $aclPlugin = $this->server->getPlugin('acl');
     if (substr($email, 0, 7) === 'mailto:') {
         $email = substr($email, 7);
     }
     $result = $aclPlugin->principalSearch(array('{http://sabredav.org/ns}email-address' => $email), array('{DAV:}principal-URL', $caldavNS . 'calendar-home-set', '{http://sabredav.org/ns}email-address'));
     if (!count($result)) {
         return array('request-status' => '3.7;Could not find principal', 'href' => 'mailto:' . $email);
     }
     if (!isset($result[0][200][$caldavNS . 'calendar-home-set'])) {
         return array('request-status' => '3.7;No calendar-home-set property found', 'href' => 'mailto:' . $email);
     }
     $homeSet = $result[0][200][$caldavNS . 'calendar-home-set']->getHref();
     // Grabbing the calendar list
     $objects = array();
     foreach ($this->server->tree->getNodeForPath($homeSet)->getChildren() as $node) {
         if (!$node instanceof ICalendar) {
             continue;
         }
         $aclPlugin->checkPrivileges($homeSet . $node->getName(), $caldavNS . 'read-free-busy');
         // Getting the list of object uris within the time-range
         $urls = $node->calendarQuery(array('name' => 'VCALENDAR', 'comp-filters' => array(array('name' => 'VEVENT', 'comp-filters' => array(), 'prop-filters' => array(), 'is-not-defined' => false, 'time-range' => array('start' => $start, 'end' => $end))), 'prop-filters' => array(), 'is-not-defined' => false, 'time-range' => null));
         $calObjects = array_map(function ($url) use($node) {
             $obj = $node->getChild($url)->get();
             return $obj;
         }, $urls);
         $objects = array_merge($objects, $calObjects);
     }
     $vcalendar = VObject\Component::create('VCALENDAR');
     $vcalendar->VERSION = '2.0';
     $vcalendar->METHOD = 'REPLY';
     $vcalendar->CALSCALE = 'GREGORIAN';
     $vcalendar->PRODID = '-//SabreDAV//SabreDAV ' . DAV\Version::VERSION . '//EN';
     $generator = new VObject\FreeBusyGenerator();
     $generator->setObjects($objects);
     $generator->setTimeRange($start, $end);
     $generator->setBaseObject($vcalendar);
     $result = $generator->getResult();
     $vcalendar->VFREEBUSY->ATTENDEE = 'mailto:' . $email;
     $vcalendar->VFREEBUSY->UID = (string) $request->VFREEBUSY->UID;
     $vcalendar->VFREEBUSY->ORGANIZER = clone $request->VFREEBUSY->ORGANIZER;
     return array('calendar-data' => $result, 'request-status' => '2.0;Success', 'href' => 'mailto:' . $email);
 }
예제 #22
0
파일: Plugin.php 프로젝트: n-6/sabre-dav
 /**
  * This method is responsible for parsing the request and generating the
  * response for the CALDAV:free-busy-query REPORT.
  *
  * @param Xml\Request\FreeBusyQueryReport $report
  * @return void
  */
 protected function freeBusyQueryReport(Xml\Request\FreeBusyQueryReport $report)
 {
     $uri = $this->server->getRequestUri();
     $acl = $this->server->getPlugin('acl');
     if ($acl) {
         $acl->checkPrivileges($uri, '{' . self::NS_CALDAV . '}read-free-busy');
     }
     $calendar = $this->server->tree->getNodeForPath($uri);
     if (!$calendar instanceof ICalendar) {
         throw new DAV\Exception\NotImplemented('The free-busy-query REPORT is only implemented on calendars');
     }
     $tzProp = '{' . self::NS_CALDAV . '}calendar-timezone';
     // Figuring out the default timezone for the calendar, for floating
     // times.
     $calendarProps = $this->server->getProperties($uri, [$tzProp]);
     if (isset($calendarProps[$tzProp])) {
         $vtimezoneObj = VObject\Reader::read($calendarProps[$tzProp]);
         $calendarTimeZone = $vtimezoneObj->VTIMEZONE->getTimeZone();
         // Destroy circular references so PHP will garbage collect the object.
         $vtimezoneObj->destroy();
     } else {
         $calendarTimeZone = new DateTimeZone('UTC');
     }
     // Doing a calendar-query first, to make sure we get the most
     // performance.
     $urls = $calendar->calendarQuery(['name' => 'VCALENDAR', 'comp-filters' => [['name' => 'VEVENT', 'comp-filters' => [], 'prop-filters' => [], 'is-not-defined' => false, 'time-range' => ['start' => $report->start, 'end' => $report->end]]], 'prop-filters' => [], 'is-not-defined' => false, 'time-range' => null]);
     $objects = array_map(function ($url) use($calendar) {
         $obj = $calendar->getChild($url)->get();
         return $obj;
     }, $urls);
     $generator = new VObject\FreeBusyGenerator();
     $generator->setObjects($objects);
     $generator->setTimeRange($report->start, $report->end);
     $generator->setTimeZone($calendarTimeZone);
     $result = $generator->getResult();
     $result = $result->serialize();
     $this->server->httpResponse->setStatus(200);
     $this->server->httpResponse->setHeader('Content-Type', 'text/calendar');
     $this->server->httpResponse->setHeader('Content-Length', strlen($result));
     $this->server->httpResponse->setBody($result);
 }
예제 #23
0
 function testACLIntegrationNotBlocked()
 {
     $cbackend = TestUtil::getBackend();
     $pbackend = new DAVACL\PrincipalBackend\Mock();
     $props = array('uri' => 'UUID-123467', 'principaluri' => 'admin', 'id' => 1);
     $tree = array(new Calendar($cbackend, $props), new DAVACL\PrincipalCollection($pbackend));
     $p = new ICSExportPlugin();
     $s = new DAV\Server($tree);
     $s->sapi = new HTTP\SapiMock();
     $s->addPlugin($p);
     $s->addPlugin(new Plugin());
     $s->addPlugin(new DAVACL\Plugin());
     $s->addPlugin(new DAV\Auth\Plugin(new DAV\Auth\Backend\Mock(), 'SabreDAV'));
     // Forcing login
     $s->getPlugin('acl')->adminPrincipals = array('principals/admin');
     $h = HTTP\Sapi::createFromServerArray(['REQUEST_URI' => '/UUID-123467?export', 'REQUEST_METHOD' => 'GET']);
     $s->httpRequest = $h;
     $s->httpResponse = new HTTP\ResponseMock();
     $s->exec();
     $this->assertEquals(200, $s->httpResponse->status, 'Invalid status received. Response body: ' . $s->httpResponse->body);
     $this->assertEquals(array('X-Sabre-Version' => DAV\Version::VERSION, 'Content-Type' => 'text/calendar'), $s->httpResponse->getHeaders());
     $obj = VObject\Reader::read($s->httpResponse->body);
     $this->assertEquals(5, count($obj->children()));
     $this->assertEquals(1, count($obj->VERSION));
     $this->assertEquals(1, count($obj->CALSCALE));
     $this->assertEquals(1, count($obj->PRODID));
     $this->assertEquals(1, count($obj->VTIMEZONE));
     $this->assertEquals(1, count($obj->VEVENT));
 }
예제 #24
0
 function testACLIntegrationNotBlocked()
 {
     if (!SABRE_HASSQLITE) {
         $this->markTestSkipped('SQLite driver is not available');
     }
     $cbackend = TestUtil::getBackend();
     $pbackend = new DAVACL\PrincipalBackend\Mock();
     $props = array('uri' => 'UUID-123467', 'principaluri' => 'admin', 'id' => 1);
     $tree = array(new Calendar($cbackend, $props), new DAVACL\PrincipalCollection($pbackend));
     $p = new ICSExportPlugin();
     $s = new DAV\Server($tree);
     $s->addPlugin($p);
     $s->addPlugin(new Plugin());
     $s->addPlugin(new DAVACL\Plugin());
     $s->addPlugin(new DAV\Auth\Plugin(new DAV\Auth\Backend\Mock(), 'SabreDAV'));
     // Forcing login
     $s->getPlugin('acl')->adminPrincipals = array('principals/admin');
     $h = new HTTP\Request(array('QUERY_STRING' => 'export', 'REQUEST_URI' => '/UUID-123467', 'REQUEST_METHOD' => 'GET'));
     $s->httpRequest = $h;
     $s->httpResponse = new HTTP\ResponseMock();
     $s->exec();
     $this->assertEquals('HTTP/1.1 200 OK', $s->httpResponse->status, 'Invalid status received. Response body: ' . $s->httpResponse->body);
     $this->assertEquals(array('Content-Type' => 'text/calendar'), $s->httpResponse->headers);
     $obj = VObject\Reader::read($s->httpResponse->body);
     $this->assertEquals(5, count($obj->children()));
     $this->assertEquals(1, count($obj->VERSION));
     $this->assertEquals(1, count($obj->CALSCALE));
     $this->assertEquals(1, count($obj->PRODID));
     $this->assertEquals(1, count($obj->VTIMEZONE));
     $this->assertEquals(1, count($obj->VEVENT));
 }
예제 #25
0
 /**
  * Sets up the plugin
  *
  * This method is automatically called by the server class.
  *
  * @param DAV\Server $server
  * @return void
  */
 function initialize(DAV\Server $server)
 {
     if ($this->allowUnauthenticatedAccess) {
         $authPlugin = $server->getPlugin('auth');
         if (!$authPlugin) {
             throw new \Exception('The Auth plugin must be loaded before the ACL plugin if you want to allow unauthenticated access.');
         }
         $authPlugin->autoRequireLogin = false;
     }
     $this->server = $server;
     $server->on('propFind', [$this, 'propFind'], 20);
     $server->on('beforeMethod', [$this, 'beforeMethod'], 20);
     $server->on('beforeBind', [$this, 'beforeBind'], 20);
     $server->on('beforeUnbind', [$this, 'beforeUnbind'], 20);
     $server->on('propPatch', [$this, 'propPatch']);
     $server->on('beforeUnlock', [$this, 'beforeUnlock'], 20);
     $server->on('report', [$this, 'report']);
     $server->on('method:ACL', [$this, 'httpAcl']);
     $server->on('onHTMLActionsPanel', [$this, 'htmlActionsPanel']);
     $server->on('getPrincipalByUri', function ($principal, &$uri) {
         $uri = $this->getPrincipalByUri($principal);
         // Break event chain
         if ($uri) {
             return false;
         }
     });
     array_push($server->protectedProperties, '{DAV:}alternate-URI-set', '{DAV:}principal-URL', '{DAV:}group-membership', '{DAV:}principal-collection-set', '{DAV:}current-user-principal', '{DAV:}supported-privilege-set', '{DAV:}current-user-privilege-set', '{DAV:}acl', '{DAV:}acl-restrictions', '{DAV:}inherited-acl-set', '{DAV:}owner', '{DAV:}group');
     // Automatically mapping nodes implementing IPrincipal to the
     // {DAV:}principal resourcetype.
     $server->resourceTypeMapping['Sabre\\DAVACL\\IPrincipal'] = '{DAV:}principal';
     // Mapping the group-member-set property to the HrefList property
     // class.
     $server->xml->elementMap['{DAV:}group-member-set'] = 'Sabre\\DAV\\Xml\\Property\\Href';
     $server->xml->elementMap['{DAV:}acl'] = 'Sabre\\DAVACL\\Xml\\Property\\Acl';
     $server->xml->elementMap['{DAV:}acl-principal-prop-set'] = 'Sabre\\DAVACL\\Xml\\Request\\AclPrincipalPropSetReport';
     $server->xml->elementMap['{DAV:}expand-property'] = 'Sabre\\DAVACL\\Xml\\Request\\ExpandPropertyReport';
     $server->xml->elementMap['{DAV:}principal-property-search'] = 'Sabre\\DAVACL\\Xml\\Request\\PrincipalPropertySearchReport';
     $server->xml->elementMap['{DAV:}principal-search-property-set'] = 'Sabre\\DAVACL\\Xml\\Request\\PrincipalSearchPropertySetReport';
     $server->xml->elementMap['{DAV:}principal-match'] = 'Sabre\\DAVACL\\Xml\\Request\\PrincipalMatchReport';
 }