diff --git a/app/Services/DavClient/Utils/AddressBookGetter.php b/app/Services/DavClient/Utils/AddressBookGetter.php index fa1033b97..62978062c 100644 --- a/app/Services/DavClient/Utils/AddressBookGetter.php +++ b/app/Services/DavClient/Utils/AddressBookGetter.php @@ -78,7 +78,14 @@ class AddressBookGetter */ 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); } @@ -95,17 +102,25 @@ class AddressBookGetter // 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 @@ -113,11 +128,11 @@ class AddressBookGetter * * @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'); } } diff --git a/app/Services/DavClient/Utils/Dav/DavClient.php b/app/Services/DavClient/Utils/Dav/DavClient.php index 481755c6c..29cb7c0e3 100644 --- a/app/Services/DavClient/Utils/Dav/DavClient.php +++ b/app/Services/DavClient/Utils/Dav/DavClient.php @@ -477,11 +477,12 @@ class DavClient * 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)) { diff --git a/tests/Helpers/DavTester.php b/tests/Helpers/DavTester.php index daf892943..74e45f88f 100644 --- a/tests/Helpers/DavTester.php +++ b/tests/Helpers/DavTester.php @@ -89,11 +89,12 @@ class DavTester extends TestCase 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() @@ -125,9 +126,9 @@ class DavTester extends TestCase 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() @@ -135,9 +136,9 @@ class DavTester extends TestCase 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(). ''. '/dav/'. ''. diff --git a/tests/Unit/Services/DavClient/Utils/AddressBookGetterTest.php b/tests/Unit/Services/DavClient/Utils/AddressBookGetterTest.php index 2b9713912..323e2af38 100644 --- a/tests/Unit/Services/DavClient/Utils/AddressBookGetterTest.php +++ b/tests/Unit/Services/DavClient/Utils/AddressBookGetterTest.php @@ -45,6 +45,7 @@ class AddressBookGetterTest extends TestCase public function it_fails_on_server_not_compliant() { $tester = (new DavTester()) + ->userPrincipalEmpty() ->serviceUrl() ->optionsFail() ->fake(); @@ -59,6 +60,7 @@ class AddressBookGetterTest extends TestCase public function it_fails_if_no_userprincipal() { $tester = (new DavTester()) + ->userPrincipalEmpty() ->serviceUrl() ->optionsOk() ->userPrincipalEmpty() @@ -74,6 +76,7 @@ class AddressBookGetterTest extends TestCase public function it_fails_if_no_addressbook() { $tester = (new DavTester()) + ->userPrincipalEmpty() ->serviceUrl() ->optionsOk() ->userPrincipal() @@ -90,11 +93,13 @@ class AddressBookGetterTest extends TestCase public function it_fails_if_no_addressbook_url() { $tester = (new DavTester()) + ->userPrincipalEmpty() ->serviceUrl() ->optionsOk() ->userPrincipal() ->addressbookHome() ->resourceTypeHomeOnly() + ->optionsOk() ->fake(); $client = $tester->client();