Skip to content

Commit

Permalink
fix: fix carddav addressbook add (#5660)
Browse files Browse the repository at this point in the history
  • Loading branch information
ribounette authored Oct 27, 2021
1 parent 48726b5 commit ac44cfb
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 15 deletions.
25 changes: 20 additions & 5 deletions app/Services/DavClient/Utils/AddressBookGetter.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,14 @@ private function getAddressBookData(): array
*/
private function getAddressBookBaseUri(): string
{
$baseUri = $this->client->getServiceUrl();
try {
// Get the principal of this account
$principal = $this->getCurrentUserPrincipal();
$baseUri = $this->client->path($principal);
} catch (\Exception $e) {
$baseUri = $this->client->getServiceUrl();
}

if ($baseUri) {
$this->client->setBaseUri($baseUri);
}
Expand All @@ -95,29 +102,37 @@ private function getAddressBookBaseUri(): string

// Get the AddressBook of this principal
$addressBook = $this->getAddressBookUrl($principal);
$addressBookUrl = $this->client->path($addressBook);

if (! Str::contains($addressBookUrl, 'https://www.googleapis.com')) {
// Check the OPTIONS of the server
$this->checkOptions(true, $addressBookUrl);
}

if ($addressBook === null) {
throw new DavClientException('No address book found');
}

return $this->client->path($addressBook);
return $addressBookUrl;
}

/**
* Check options of the server.
*
* @param bool $addressbook
* @param string $url
* @return void
*
* @see https://datatracker.ietf.org/doc/html/rfc2518#section-15
* @see https://datatracker.ietf.org/doc/html/rfc6352#section-6.1
*
* @throws DavServerNotCompliantException
*/
private function checkOptions()
private function checkOptions(bool $addressbook = false, string $url = '')
{
$options = $this->client->options();
$options = $this->client->options($url);

if (! in_array('1', $options) || ! in_array('3', $options) || ! in_array('addressbook', $options)) {
if (! in_array('1', $options) || ! in_array('3', $options) || ($addressbook && ! in_array('addressbook', $options))) {
throw new DavServerNotCompliantException('server is not compliant with rfc2518 section 15.1, or rfc6352 section 6.1');
}
}
Expand Down
5 changes: 3 additions & 2 deletions app/Services/DavClient/Utils/Dav/DavClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -477,11 +477,12 @@ public function propPatch(array $properties, string $url = ''): bool
* If there was no DAV header, or no contents this method will return an
* empty array.
*
* @param string $url
* @return array
*/
public function options(): array
public function options(string $url = ''): array
{
$response = $this->request('OPTIONS');
$response = $this->request('OPTIONS', $url);

$dav = $response->header('Dav');
if (empty($dav)) {
Expand Down
17 changes: 9 additions & 8 deletions tests/Helpers/DavTester.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,12 @@ public function assert()

public function addressBookBaseUri()
{
return $this->serviceUrl()
->optionsOk()
->userPrincipal()
return $this->userPrincipal('https://test')
->optionsOk('https://test/dav/principals/user@test.com/')
->userPrincipal('https://test/dav/principals/user@test.com/')
->addressbookHome()
->resourceTypeAddressBook();
->resourceTypeAddressBook()
->optionsOk('https://test/dav/addressbooks/user@test.com/contacts/');
}

public function capabilities()
Expand Down Expand Up @@ -125,19 +126,19 @@ public function nonStandardServiceUrl()
return $this->addResponse('https://test/.well-known/carddav', Http::response(null, 301, ['Location' => '/dav/']), null, 'PROPFIND');
}

public function optionsOk()
public function optionsOk(string $url = 'https://test/dav/')
{
return $this->addResponse('https://test/dav/', Http::response(null, 200, ['Dav' => '1, 3, addressbook']), null, 'OPTIONS');
return $this->addResponse($url, Http::response(null, 200, ['Dav' => '1, 3, addressbook']), null, 'OPTIONS');
}

public function optionsFail()
{
return $this->addResponse('https://test/dav/', Http::response(null, 200, ['Dav' => 'bad']), null, 'OPTIONS');
}

public function userPrincipal()
public function userPrincipal(string $url = 'https://test/dav/')
{
return $this->addResponse('https://test/dav/', Http::response($this->multistatusHeader().
return $this->addResponse($url, Http::response($this->multistatusHeader().
'<d:response>'.
'<d:href>/dav/</d:href>'.
'<d:propstat>'.
Expand Down
5 changes: 5 additions & 0 deletions tests/Unit/Services/DavClient/Utils/AddressBookGetterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public function it_get_address_book_data()
public function it_fails_on_server_not_compliant()
{
$tester = (new DavTester())
->userPrincipalEmpty()
->serviceUrl()
->optionsFail()
->fake();
Expand All @@ -59,6 +60,7 @@ public function it_fails_on_server_not_compliant()
public function it_fails_if_no_userprincipal()
{
$tester = (new DavTester())
->userPrincipalEmpty()
->serviceUrl()
->optionsOk()
->userPrincipalEmpty()
Expand All @@ -74,6 +76,7 @@ public function it_fails_if_no_userprincipal()
public function it_fails_if_no_addressbook()
{
$tester = (new DavTester())
->userPrincipalEmpty()
->serviceUrl()
->optionsOk()
->userPrincipal()
Expand All @@ -90,11 +93,13 @@ public function it_fails_if_no_addressbook()
public function it_fails_if_no_addressbook_url()
{
$tester = (new DavTester())
->userPrincipalEmpty()
->serviceUrl()
->optionsOk()
->userPrincipal()
->addressbookHome()
->resourceTypeHomeOnly()
->optionsOk()
->fake();
$client = $tester->client();

Expand Down

0 comments on commit ac44cfb

Please sign in to comment.