diff --git a/dev/External/ko.js b/dev/External/ko.js index 0d693148d..3bf26dead 100644 --- a/dev/External/ko.js +++ b/dev/External/ko.js @@ -15,6 +15,7 @@ export const * based solely on the values of other observables in the application */ koComputable = fn => ko.computed(fn, {'pure':true}), +// koObservable = value => ko.observable(value), addObservablesTo = (target, observables) => forEachObjectEntry(observables, (key, value) => diff --git a/dev/Settings/User/Contacts.js b/dev/Settings/User/Contacts.js index b3815ed56..8d21cdb83 100644 --- a/dev/Settings/User/Contacts.js +++ b/dev/Settings/User/Contacts.js @@ -2,7 +2,7 @@ import ko from 'ko'; import { koComputable } from 'External/ko'; import { SettingsGet } from 'Common/Globals'; -import { i18n, translateTrigger } from 'Common/Translator'; +import { i18n, translateTrigger, getErrorMessage } from 'Common/Translator'; import { ContactUserStore } from 'Stores/User/Contact'; import Remote from 'Remote/User/Fetch'; @@ -15,6 +15,7 @@ export class UserSettingsContacts /*extends AbstractViewSettings*/ { this.syncUrl = ContactUserStore.syncUrl; this.syncUser = ContactUserStore.syncUser; this.syncPass = ContactUserStore.syncPass; + this.syncError = ko.observable(''); this.syncModeOptions = koComputable(() => { translateTrigger(); @@ -48,4 +49,15 @@ export class UserSettingsContacts /*extends AbstractViewSettings*/ { }) ); } + + test() { + this.syncError(''); + Remote.request('TestContactsSyncData', (iError, data) => { + iError && this.syncError(data.messageAdditional || data.message || getErrorMessage(iError, data)); + }, { + Url: ContactUserStore.syncUrl(), + User: ContactUserStore.syncUser(), + Password: ContactUserStore.syncPass() + }) + } } diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Contacts.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Contacts.php index 5d8a4c291..3e6dd5a07 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Contacts.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Contacts.php @@ -3,13 +3,11 @@ namespace RainLoop\Actions; use RainLoop\Enumerations\Capa; +use RainLoop\Exceptions\ClientException; trait Contacts { - /** - * @var \RainLoop\Providers\AddressBook - */ - protected $oAddressBookProvider = null; + protected ?\RainLoop\Providers\AddressBook $oAddressBookProvider = null; public function AddressBookProvider(?\RainLoop\Model\Account $oAccount = null): \RainLoop\Providers\AddressBook { @@ -61,18 +59,66 @@ trait Contacts return $this->DefaultResponse($bResult); } + public function DoTestContactsSyncData() : array + { + if (!$this->GetCapa(Capa::CONTACTS)) { + throw new ClientException(\RainLoop\Notifications::ContactsSyncError, null, 'Disallowed'); + } + + $oAccount = $this->getAccountFromToken(); + + $sPassword = $this->GetActionParam('Password', ''); + if (static::APP_DUMMY === $sPassword) { + $mData = $this->getContactsSyncData($oAccount); + $sPassword = isset($mData['Password']) ? $mData['Password'] : ''; + } + $sPasswordHMAC = null; + if ($sPassword) { + $oMainAccount = $this->getMainAccountFromToken(); + $sPassword = \SnappyMail\Crypt::EncryptToJSON($sPassword, $oMainAccount->CryptKey()); + if ($sPassword) { + $sPasswordHMAC = \hash_hmac('sha1', $sPassword, $oMainAccount->CryptKey()); + } + } + + $oDriver = $this->fabrica('address-book', $oAccount); + if (!$oDriver) { + throw new ClientException(\RainLoop\Notifications::ContactsSyncError, null, 'No driver'); + } + $oDriver->SetEmail($this->GetMainEmail($oAccount)); + $oDriver->setDAVClientConfig([ + 'Mode' => 2, // readonly + 'User' => $this->GetActionParam('User', ''), + 'Password' => $sPassword, + 'Url' => $this->GetActionParam('Url', ''), + 'PasswordHMAC' => $sPasswordHMAC + ]); + + $oClient = $oDriver->getDavClient(); + if (!$oClient) { + throw new ClientException(\RainLoop\Notifications::ContactsSyncError, null, 'No client'); + } + $oClient->propFind($oClient->urlPath, [ + '{DAV:}getlastmodified', + '{DAV:}resourcetype', + '{DAV:}getetag' + ], 1); + + return $this->TrueResponse(); + } + public function DoContactsSync() : array { $oAccount = $this->getAccountFromToken(); $oAddressBookProvider = $this->AddressBookProvider($oAccount); if (!$oAddressBookProvider) { - throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::ContactsSyncError, null, 'No AddressBookProvider'); + throw new ClientException(\RainLoop\Notifications::ContactsSyncError, null, 'No AddressBookProvider'); } \ignore_user_abort(true); \SnappyMail\HTTP\Stream::start(/*$binary = false*/); \SnappyMail\HTTP\Stream::JSON(['messsage'=>'start']); if (!$oAddressBookProvider->Sync()) { - throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::ContactsSyncError, null, 'AddressBookProvider->Sync() failed'); + throw new ClientException(\RainLoop\Notifications::ContactsSyncError, null, 'AddressBookProvider->Sync() failed'); } return $this->TrueResponse(); } diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook.php index affaecd99..2342d716c 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook.php @@ -4,10 +4,7 @@ namespace RainLoop\Providers; class AddressBook extends AbstractProvider { - /** - * @var \RainLoop\Providers\AddressBook\AddressBookInterface - */ - private $oDriver; + private ?AddressBook\AddressBookInterface $oDriver; public function __construct(?AddressBook\AddressBookInterface $oDriver) { diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/CardDAV.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/CardDAV.php index 6d572a5b1..fca43fac9 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/CardDAV.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/CardDAV.php @@ -265,17 +265,9 @@ trait CardDAV */ private function checkContactsPath(DAVClient $oClient, string $sPath) : bool { - $aResponse = null; - try - { - $aResponse = $oClient->propFind($sPath, array( - '{DAV:}resourcetype' - ), 1); - } - catch (\Throwable $oException) - { - $this->logException($oException); - } + $aResponse = $oClient->propFind($sPath, array( + '{DAV:}resourcetype' + ), 1); $bGood = false; if (\is_array($aResponse)) { @@ -339,7 +331,7 @@ trait CardDAV return $oClient; } - protected function getDavClient() : ?DAVClient + public function getDavClient() : ?DAVClient { if (!$this->aDAVConfig['Mode']) { return null; @@ -405,7 +397,11 @@ trait CardDAV $bGood = $sNewPath && $this->checkContactsPath($oClient, $sNewPath); if (!$bGood) { - $this->logWrite('Contacts path not found at: '.$sPath, \LOG_INFO, 'DAV'); + throw new \RainLoop\Exceptions\ClientException( + \RainLoop\Notifications::ContactsSyncError, + null, + 'Contacts path not found at: '.$sPath + ); } } diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/PdoAddressBook.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/PdoAddressBook.php index 5d025bfaa..155ea781d 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/PdoAddressBook.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/PdoAddressBook.php @@ -129,7 +129,12 @@ class PdoAddressBook return false; } - $oClient = $this->getDavClient(); + try { + $oClient = $this->getDavClient(); + } catch (\Throwable $e) { + \SnappyMail\Log::error('DAV', $e->getMessage()); +// $this->logException($oException); + } if (!$oClient) { \SnappyMail\Log::warning('PdoAddressBook', 'Sync() invalid DavClient'); return false; diff --git a/snappymail/v/0.0.0/app/templates/Views/User/SettingsContacts.html b/snappymail/v/0.0.0/app/templates/Views/User/SettingsContacts.html index 6a734ba91..73c091f9d 100644 --- a/snappymail/v/0.0.0/app/templates/Views/User/SettingsContacts.html +++ b/snappymail/v/0.0.0/app/templates/Views/User/SettingsContacts.html @@ -39,4 +39,9 @@ +