| // Copyright 2018 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #import <UIKit/UIKit.h> |
| |
| #import <memory> |
| |
| #import "base/strings/sys_string_conversions.h" |
| #import "components/autofill/core/browser/studies/autofill_experiments.h" |
| #import "components/password_manager/core/browser/features/password_manager_features_util.h" |
| #import "components/signin/public/base/consent_level.h" |
| #import "components/signin/public/identity_manager/account_info.h" |
| #import "components/signin/public/identity_manager/device_accounts_synchronizer.h" |
| #import "components/signin/public/identity_manager/identity_manager.h" |
| #import "components/signin/public/identity_manager/primary_account_mutator.h" |
| #import "components/sync/service/sync_service.h" |
| #import "components/sync/service/sync_user_settings.h" |
| #import "ios/web_view/internal/sync/cwv_sync_controller_internal.h" |
| #import "ios/web_view/public/cwv_identity.h" |
| #import "ios/web_view/public/cwv_sync_controller_data_source.h" |
| #import "ios/web_view/public/cwv_sync_controller_delegate.h" |
| #import "ios/web_view/public/cwv_web_view.h" |
| |
| @interface CWVSyncController () |
| |
| // Called by WebViewSyncControllerObserverBridge's |OnSyncShutdown|. |
| - (void)didShutdownSync; |
| // Called by WebViewSyncControllerObserverBridge's |OnStateChanged|. |
| - (void)syncStateDidChange; |
| |
| @end |
| |
| namespace ios_web_view { |
| |
| // Bridge that observes syncer::SyncService and calls analagous |
| // methods on CWVSyncController. |
| class WebViewSyncControllerObserverBridge : public syncer::SyncServiceObserver { |
| public: |
| explicit WebViewSyncControllerObserverBridge( |
| CWVSyncController* sync_controller) |
| : sync_controller_(sync_controller) {} |
| |
| void OnStateChanged(syncer::SyncService* sync) override { |
| [sync_controller_ syncStateDidChange]; |
| } |
| |
| void OnSyncShutdown(syncer::SyncService* sync) override { |
| [sync_controller_ didShutdownSync]; |
| } |
| |
| private: |
| __weak CWVSyncController* sync_controller_; |
| }; |
| |
| } // namespace ios_web_view |
| |
| @implementation CWVSyncController { |
| syncer::SyncService* _syncService; |
| signin::IdentityManager* _identityManager; |
| std::unique_ptr<ios_web_view::WebViewSyncControllerObserverBridge> _observer; |
| PrefService* _prefService; |
| syncer::SyncService::TransportState _lastTransportState; |
| } |
| |
| namespace { |
| // Provider of trusted vault features. |
| __weak id<CWVTrustedVaultProvider> gTrustedVaultProvider; |
| // Data source that can provide access tokens. |
| __weak id<CWVSyncControllerDataSource> gSyncDataSource; |
| } // namespace |
| |
| + (void)setTrustedVaultProvider: |
| (id<CWVTrustedVaultProvider>)trustedVaultProvider { |
| gTrustedVaultProvider = trustedVaultProvider; |
| } |
| |
| + (id<CWVTrustedVaultProvider>)trustedVaultProvider { |
| return gTrustedVaultProvider; |
| } |
| |
| + (void)setDataSource:(id<CWVSyncControllerDataSource>)dataSource { |
| gSyncDataSource = dataSource; |
| } |
| |
| + (id<CWVSyncControllerDataSource>)dataSource { |
| return gSyncDataSource; |
| } |
| |
| - (instancetype)initWithSyncService:(syncer::SyncService*)syncService |
| identityManager:(signin::IdentityManager*)identityManager |
| prefService:(PrefService*)prefService { |
| self = [super init]; |
| if (self) { |
| _syncService = syncService; |
| _identityManager = identityManager; |
| _prefService = prefService; |
| _observer = |
| std::make_unique<ios_web_view::WebViewSyncControllerObserverBridge>( |
| self); |
| _syncService->AddObserver(_observer.get()); |
| } |
| return self; |
| } |
| |
| - (void)dealloc { |
| DCHECK(!_syncService) << "-shutDown must be called before -dealloc"; |
| } |
| |
| #pragma mark - Public Methods |
| |
| - (CWVIdentity*)currentIdentity { |
| if (_identityManager->HasPrimaryAccount(signin::ConsentLevel::kSignin)) { |
| CoreAccountInfo accountInfo = |
| _identityManager->GetPrimaryAccountInfo(signin::ConsentLevel::kSignin); |
| return [[CWVIdentity alloc] |
| initWithEmail:base::SysUTF8ToNSString(accountInfo.email) |
| fullName:nil |
| gaiaID:accountInfo.gaia.ToNSString()]; |
| } |
| |
| return nil; |
| } |
| |
| - (BOOL)isPassphraseNeeded { |
| return _syncService->GetUserSettings() |
| ->IsPassphraseRequiredForPreferredDataTypes(); |
| } |
| |
| - (BOOL)isTrustedVaultKeysRequired { |
| return _syncService->GetUserSettings() |
| ->IsTrustedVaultKeyRequiredForPreferredDataTypes(); |
| } |
| |
| - (BOOL)isTrustedVaultRecoverabilityDegraded { |
| return _syncService->GetUserSettings() |
| ->IsTrustedVaultRecoverabilityDegraded(); |
| } |
| |
| - (void)startSyncWithIdentity:(CWVIdentity*)identity { |
| DCHECK(!self.currentIdentity) |
| << "Already syncing! Call -stopSyncAndClearIdentity first."; |
| |
| _identityManager->GetDeviceAccountsSynchronizer() |
| ->ReloadAllAccountsFromSystemWithPrimaryAccount(CoreAccountId()); |
| |
| const GaiaId gaiaId(identity.gaiaID); |
| const CoreAccountId accountId = CoreAccountId::FromGaiaId(gaiaId); |
| CHECK(_identityManager->HasAccountWithRefreshToken(accountId)); |
| |
| _identityManager->GetPrimaryAccountMutator()->SetPrimaryAccount( |
| accountId, signin::ConsentLevel::kSignin, |
| signin_metrics::AccessPoint::kIosChromeWebView); |
| CHECK_EQ(_identityManager->GetPrimaryAccountId(signin::ConsentLevel::kSignin), |
| accountId); |
| |
| autofill::SetUserOptedInWalletSyncTransport(_prefService, accountId, |
| /*opted_in=*/true); |
| if (!CWVWebView.skipAccountStorageCheckEnabled) { |
| // TODO(crbug.com/470332074): Verify whether this should check for "enabled" |
| // instead of "active". |
| CHECK( |
| password_manager::features_util::IsAccountStorageActive(_syncService)); |
| } |
| } |
| |
| - (void)stopSyncAndClearIdentity { |
| auto* primaryAccountMutator = _identityManager->GetPrimaryAccountMutator(); |
| primaryAccountMutator->ClearPrimaryAccount( |
| signin_metrics::ProfileSignout::kUserClickedSignoutSettings); |
| } |
| |
| - (BOOL)unlockWithPassphrase:(NSString*)passphrase { |
| return _syncService->GetUserSettings()->SetDecryptionPassphrase( |
| base::SysNSStringToUTF8(passphrase)); |
| } |
| |
| #pragma mark - Private Methods |
| |
| - (void)didShutdownSync { |
| _syncService->RemoveObserver(_observer.get()); |
| } |
| |
| - (void)syncStateDidChange { |
| if (_lastTransportState != _syncService->GetTransportState()) { |
| _lastTransportState = _syncService->GetTransportState(); |
| |
| if (_lastTransportState == syncer::SyncService::TransportState::ACTIVE) { |
| if ([_delegate |
| respondsToSelector:@selector(syncControllerDidStartSync:)]) { |
| [_delegate syncControllerDidStartSync:self]; |
| } |
| } else if (_lastTransportState == |
| syncer::SyncService::TransportState::DISABLED) { |
| if ([_delegate |
| respondsToSelector:@selector(syncControllerDidStopSync:)]) { |
| [_delegate syncControllerDidStopSync:self]; |
| } |
| } |
| } |
| |
| if ([_delegate respondsToSelector:@selector(syncControllerDidUpdateState:)]) { |
| [_delegate syncControllerDidUpdateState:self]; |
| } |
| } |
| |
| - (void)shutDown { |
| _syncService->RemoveObserver(_observer.get()); |
| _syncService = nullptr; |
| } |
| |
| @end |