Skip to content

Commit

Permalink
fix: fix distant contact etag handle (#5605)
Browse files Browse the repository at this point in the history
  • Loading branch information
asbiin committed Oct 11, 2021
1 parent 6f5e41a commit 1da427f
Show file tree
Hide file tree
Showing 21 changed files with 255 additions and 72 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public function prepareData($obj)
'id' => $obj->id,
'uri' => $this->encodeUri($obj),
'calendardata' => $calendardata,
'etag' => '"'.md5($calendardata).'"',
'etag' => '"'.sha1($calendardata).'"',
'lastmodified' => $obj->updated_at->timestamp,
];
} catch (\Exception $e) {
Expand Down
2 changes: 1 addition & 1 deletion app/Http/Controllers/DAV/Backend/CalDAV/CalDAVTasks.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public function prepareData($obj)
'id' => $obj->id,
'uri' => $this->encodeUri($obj),
'calendardata' => $calendardata,
'etag' => '"'.md5($calendardata).'"',
'etag' => '"'.sha1($calendardata).'"',
'lastmodified' => $obj->updated_at->timestamp,
];
} catch (\Exception $e) {
Expand Down
15 changes: 10 additions & 5 deletions app/Http/Controllers/DAV/Backend/CardDAV/CardDAVBackend.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Sabre\DAV;
use App\Jobs\Dav\UpdateVCard;
use App\Models\Contact\Contact;
use App\Services\VCard\GetEtag;
use App\Models\Account\AddressBook;
use App\Services\VCard\ExportVCard;
use Illuminate\Support\Facades\Bus;
Expand Down Expand Up @@ -189,11 +190,17 @@ public function prepareCard($contact): array
$carddata = $this->refreshObject($contact);
}

$etag = app(GetEtag::class)->execute([
'account_id' => $this->user->account_id,
'contact_id' => $contact->id,
]);

return [
'id' => $contact->hashID(),
'contact_id' => $contact->id,
'uri' => $this->encodeUri($contact),
'carddata' => $carddata,
'etag' => '"'.md5($carddata).'"',
'etag' => $etag,
'distant_etag' => $contact->distant_etag,
'lastmodified' => $contact->updated_at->timestamp,
];
} catch (\Exception $e) {
Expand Down Expand Up @@ -364,9 +371,7 @@ public function createCard($addressBookId, $cardUri, $cardData)
*/
public function updateCard($addressBookId, $cardUri, $cardData): ?string
{
$dto = new ContactUpdateDto($cardUri, '"'.md5($cardData).'"', $cardData);

$job = new UpdateVCard($this->user, $addressBookId, $dto);
$job = new UpdateVCard($this->user, $addressBookId, new ContactUpdateDto($cardUri, null, $cardData));

Bus::batch([$job])
->allowFailures()
Expand Down
21 changes: 14 additions & 7 deletions app/Jobs/Dav/PushVCard.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Illuminate\Bus\Batchable;
use Illuminate\Bus\Queueable;
use App\Models\Contact\Contact;
use Illuminate\Support\Facades\Log;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
Expand Down Expand Up @@ -53,17 +54,23 @@ public function handle(): void

$headers = [];

if ($this->contact->mode === 1) {
$headers['If-Match'] = $this->contact->etag;
} elseif ($this->contact->mode === 2) {
$headers['If-Match'] = '*';
switch ($this->contact->mode) {
case ContactPushDto::MODE_MATCH_ETAG:
$headers['If-Match'] = $this->contact->etag;
break;
case ContactPushDto::MODE_MATCH_ANY:
$headers['If-Match'] = '*';
break;
}

$response = $this->subscription->getClient()
->request('PUT', $this->contact->uri, $this->contact->card, $headers);

if (! empty($etag = $response->header('Etag')) && $etag !== $this->contact->etag) {
Log::warning(__CLASS__.' wrong etag when updating contact. Expected '.$this->contact->etag.', get '.$etag);
}
$etag = $response->header('Etag');

$contact = Contact::where('account_id', $this->subscription->account_id)
->findOrFail($this->contact->contactId);
$contact->distant_etag = empty($etag) ? null : $etag;
$contact->save();
}
}
15 changes: 8 additions & 7 deletions app/Jobs/Dav/UpdateVCard.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
use Illuminate\Support\Arr;
use Illuminate\Bus\Batchable;
use Illuminate\Bus\Queueable;
use App\Models\Contact\Contact;
use App\Services\VCard\GetEtag;
use App\Services\VCard\ImportVCard;
use Illuminate\Support\Facades\Log;
use Illuminate\Queue\SerializesModels;
Expand Down Expand Up @@ -62,7 +62,7 @@ public function handle(): void

$newtag = $this->updateCard($this->addressBookName, $this->contact->uri, $this->contact->card);

if ($newtag !== $this->contact->etag) {
if (! is_null($this->contact->etag) && $newtag !== $this->contact->etag) {
Log::warning(__CLASS__.' wrong etag when updating contact. Expected '.$this->contact->etag.', get '.$newtag, [
'contacturl' => $this->contact->uri,
'carddata' => $this->contact->card,
Expand Down Expand Up @@ -98,18 +98,19 @@ private function updateCard($addressBookId, $cardUri, $cardData): ?string
'user_id' => $this->user->id,
'contact_id' => $contact_id,
'entry' => $cardData,
'etag' => $this->contact->etag,
'behaviour' => ImportVCard::BEHAVIOUR_REPLACE,
'addressBookName' => $addressBookId === $backend->backendUri() ? null : $addressBookId,
]);

if (! Arr::has($result, 'error')) {
$contact = Contact::where('account_id', $this->user->account_id)
->find($result['contact_id']);

return '"'.md5($contact->vcard).'"';
return app(GetEtag::class)->execute([
'account_id' => $this->user->account_id,
'contact_id' => $result['contact_id'],
]);
}
} catch (\Exception $e) {
Log::debug(__CLASS__.' updateCard: '.(string) $e, [
Log::debug(__CLASS__.' updateCard: '.$e->getMessage(), [
$e,
'contacturl' => $cardUri,
'carddata' => $cardData,
Expand Down
2 changes: 1 addition & 1 deletion app/Providers/AppServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public function boot()
$url = $request->getRequestUri();

return Cache::rememberForever('etag.'.$url, function () use ($url) {
return md5($url);
return sha1($url);
});
});
}
Expand Down
25 changes: 19 additions & 6 deletions app/Services/DavClient/Utils/AddressBookContactsPush.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,15 @@ private function preparePushAddedContacts(array $contacts): Collection
->map(function (string $uri): ?PushVCard {
$card = $this->backend()->getCard($this->sync->addressBookName(), $uri);

return $card !== false
? new PushVCard($this->sync->subscription, new ContactPushDto($uri, $card['etag'], $card['carddata']))
: null;
return $card === false ? null
: new PushVCard($this->sync->subscription,
new ContactPushDto(
$uri,
$card['distant_etag'],
$card['carddata'],
$card['contact_id']
)
);
});
}

Expand Down Expand Up @@ -78,9 +84,16 @@ private function preparePushChangedContacts(Collection $changes, array $contacts
})->map(function (string $uri) use ($backend): ?PushVCard {
$card = $backend->getCard($this->sync->addressBookName(), $uri);

return $card !== false
? new PushVCard($this->sync->subscription, new ContactPushDto($uri, $card['etag'], $card['carddata'], ContactPushDto::MODE_MATCH_ETAG))
: null;
return $card === false ? null
: new PushVCard($this->sync->subscription,
new ContactPushDto(
$uri,
$card['distant_etag'],
$card['carddata'],
$card['contact_id'],
$card['distant_etag'] !== null ? ContactPushDto::MODE_MATCH_ETAG : ContactPushDto::MODE_MATCH_ANY
)
);
});
}
}
10 changes: 9 additions & 1 deletion app/Services/DavClient/Utils/AddressBookContactsPushMissed.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,15 @@ private function preparePushMissedContacts(array $added, Collection $distContact
})->map(function (Contact $contact) use ($backend): PushVCard {
$card = $backend->prepareCard($contact);

return new PushVCard($this->sync->subscription, new ContactPushDto($card['uri'], $card['etag'], $card['carddata'], ContactPushDto::MODE_MATCH_ANY));
return new PushVCard($this->sync->subscription,
new ContactPushDto(
$card['uri'],
$contact->distant_etag,
$card['carddata'],
$contact->id,
ContactPushDto::MODE_MATCH_ANY
)
);
});
}
}
6 changes: 3 additions & 3 deletions app/Services/DavClient/Utils/Model/ContactDto.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,17 @@ class ContactDto
public $uri;

/**
* @var string
* @var string|null
*/
public $etag;

/**
* Create a new ContactDto.
*
* @param string $uri
* @param string $etag
* @param string|null $etag
*/
public function __construct(string $uri, string $etag)
public function __construct(string $uri, ?string $etag)
{
$this->uri = $uri;
$this->etag = $etag;
Expand Down
10 changes: 8 additions & 2 deletions app/Services/DavClient/Utils/Model/ContactPushDto.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,23 @@ class ContactPushDto extends ContactUpdateDto

public const MODE_MATCH_ANY = 2;

/**
* @var int
*/
public $contactId;

/**
* Create a new ContactPushDto.
*
* @param string $uri
* @param string $etag
* @param string|null $etag
* @param string|resource $card
* @param int $mode
*/
public function __construct(string $uri, string $etag, $card, int $mode = self::MODE_MATCH_NONE)
public function __construct(string $uri, ?string $etag, $card, int $contact_id, int $mode = self::MODE_MATCH_NONE)
{
parent::__construct($uri, $etag, $card);
$this->mode = $mode;
$this->contactId = $contact_id;
}
}
4 changes: 2 additions & 2 deletions app/Services/DavClient/Utils/Model/ContactUpdateDto.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ class ContactUpdateDto extends ContactDto
* Create a new ContactUpdateDto.
*
* @param string $uri
* @param string $etag
* @param string|null $etag
* @param string|resource $card
*/
public function __construct(string $uri, string $etag, $card)
public function __construct(string $uri, ?string $etag, $card)
{
parent::__construct($uri, $etag);
$this->card = self::transformCard($card);
Expand Down
38 changes: 38 additions & 0 deletions app/Services/VCard/GetEtag.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

namespace App\Services\VCard;

use App\Services\BaseService;
use App\Models\Contact\Contact;

class GetEtag extends BaseService
{
/**
* Get the validation rules that apply to the service.
*
* @return array
*/
public function rules()
{
return [
'account_id' => 'required|integer|exists:accounts,id',
'contact_id' => 'required|integer|exists:contacts,id',
];
}

/**
* Export etag of the VCard.
*
* @param array $data
* @return string
*/
public function execute(array $data): string
{
$this->validate($data);

$contact = Contact::where('account_id', $data['account_id'])
->findOrFail($data['contact_id']);

return $contact->distant_etag ?? '"'.sha1($contact->vcard).'"';
}
}
Loading

0 comments on commit 1da427f

Please sign in to comment.