| // Copyright 2017 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #import "ios/web_view/internal/signin/web_view_device_accounts_provider_impl.h" |
| |
| #import "base/check.h" |
| #import "base/notreached.h" |
| #import "base/strings/sys_string_conversions.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_errors.h" |
| |
| namespace { |
| |
| using AccessTokenInfo = DeviceAccountsProvider::AccessTokenInfo; |
| using AccessTokenResult = DeviceAccountsProvider::AccessTokenResult; |
| |
| // Helper function converting `error` for `identity` to a |
| // GoogleServiceAuthError. |
| GoogleServiceAuthError GoogleServiceAuthErrorFromError(CWVIdentity* identity, |
| NSError* error) { |
| DCHECK(error); |
| |
| CWVSyncError sync_error = |
| [CWVSyncController.dataSource syncErrorForNSError:error |
| identity:identity]; |
| switch (sync_error) { |
| case CWVSyncErrorInvalidGAIACredentials: |
| return GoogleServiceAuthError( |
| GoogleServiceAuthError::State::INVALID_GAIA_CREDENTIALS); |
| case CWVSyncErrorUserNotSignedUp: |
| return GoogleServiceAuthError( |
| GoogleServiceAuthError::State::ACCOUNT_NOT_FOUND); |
| case CWVSyncErrorConnectionFailed: |
| return GoogleServiceAuthError::FromConnectionError(net::ERR_FAILED); |
| case CWVSyncErrorServiceUnavailable: |
| return GoogleServiceAuthError( |
| GoogleServiceAuthError::State::SERVICE_UNAVAILABLE); |
| case CWVSyncErrorRequestCanceled: |
| return GoogleServiceAuthError( |
| GoogleServiceAuthError::State::REQUEST_CANCELED); |
| case CWVSyncErrorUnexpectedServiceResponse: |
| default: |
| return GoogleServiceAuthError( |
| GoogleServiceAuthError::State::UNEXPECTED_SERVICE_RESPONSE); |
| } |
| } |
| |
| // Helper function converting the result of fetching the access token from |
| // what CWVSyncControllerDataSource pass to the callback to what is expected |
| // for AccessTokenCallback. |
| AccessTokenResult AccessTokenResultFrom(NSString* token, |
| NSDate* expiration, |
| CWVIdentity* identity, |
| NSError* error) { |
| if (error) { |
| return base::unexpected(GoogleServiceAuthErrorFromError(identity, error)); |
| } |
| |
| AccessTokenInfo info{base::SysNSStringToUTF8(token), |
| base::Time::FromNSDate(expiration)}; |
| |
| return base::ok(std::move(info)); |
| } |
| |
| } // namespace |
| |
| WebViewDeviceAccountsProviderImpl::WebViewDeviceAccountsProviderImpl() {} |
| |
| WebViewDeviceAccountsProviderImpl::~WebViewDeviceAccountsProviderImpl() = |
| default; |
| |
| void WebViewDeviceAccountsProviderImpl::AddObserver(Observer* observer) { |
| observer_list_.AddObserver(observer); |
| } |
| |
| void WebViewDeviceAccountsProviderImpl::RemoveObserver(Observer* observer) { |
| observer_list_.RemoveObserver(observer); |
| } |
| |
| void WebViewDeviceAccountsProviderImpl::GetAccessToken( |
| const GaiaId& gaia_id, |
| const std::string& client_id, |
| const std::set<std::string>& scopes, |
| AccessTokenCallback callback) { |
| DCHECK(CWVSyncController.dataSource); |
| |
| NSMutableArray<NSString*>* scopes_array = [NSMutableArray array]; |
| for (const auto& scope : scopes) { |
| [scopes_array addObject:base::SysUTF8ToNSString(scope)]; |
| } |
| |
| // AccessTokenCallback is non-copyable. Using __block allocates the memory |
| // directly in the block object at compilation time (instead of doing a |
| // copy). This is required to have correct interaction between move-only |
| // types and Objective-C blocks. |
| __block AccessTokenCallback scoped_callback = std::move(callback); |
| CWVIdentity* identity = |
| [[CWVIdentity alloc] initWithEmail:nil |
| fullName:nil |
| gaiaID:gaia_id.ToNSString()]; |
| [CWVSyncController.dataSource |
| fetchAccessTokenForIdentity:identity |
| scopes:scopes_array |
| completionHandler:^(NSString* access_token, |
| NSDate* expiration_date, NSError* error) { |
| std::move(scoped_callback) |
| .Run(AccessTokenResultFrom(access_token, expiration_date, |
| identity, error)); |
| }]; |
| } |
| |
| std::vector<DeviceAccountsProvider::DeviceAccountInfo> |
| WebViewDeviceAccountsProviderImpl::GetAccountsForProfile() const { |
| // WebView doesn't have profiles, so the accounts for this profile are the |
| // same as the accounts on the device. |
| return GetAccountsOnDevice(); |
| } |
| |
| std::vector<DeviceAccountsProvider::DeviceAccountInfo> |
| WebViewDeviceAccountsProviderImpl::GetAccountsOnDevice() const { |
| DCHECK(CWVSyncController.dataSource); |
| |
| NSArray<CWVIdentity*>* identities = |
| [CWVSyncController.dataSource allKnownIdentities]; |
| std::vector<DeviceAccountInfo> account_infos; |
| for (CWVIdentity* identity in identities) { |
| account_infos.emplace_back(GaiaId(identity.gaiaID), |
| base::SysNSStringToUTF8(identity.email), |
| /*hosted_domain=*/""); |
| } |
| return account_infos; |
| } |