| // Copyright 2015 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ios/public/provider/chrome/browser/signin/chrome_identity_service.h" |
| |
| #include "base/metrics/histogram_functions.h" |
| #include "base/strings/sys_string_conversions.h" |
| #import "components/signin/internal/identity_manager/account_capabilities_constants.h" |
| #include "google_apis/gaia/gaia_auth_util.h" |
| #import "ios/public/provider/chrome/browser/signin/chrome_identity.h" |
| #include "ios/public/provider/chrome/browser/signin/chrome_identity_interaction_manager.h" |
| |
| #if !defined(__has_feature) || !__has_feature(objc_arc) |
| #error "This file requires ARC support." |
| #endif |
| |
| namespace ios { |
| namespace { |
| |
| // Helper base class for functors. |
| template <typename T> |
| struct Functor { |
| Functor() = default; |
| |
| Functor(const Functor&) = delete; |
| Functor& operator=(const Functor&) = delete; |
| |
| ios::ChromeIdentityService::IdentityIteratorCallback Callback() { |
| // The callback is invoked synchronously and does not escape the scope |
| // in which the Functor is defined. Thus it is safe to use Unretained |
| // here. |
| return base::BindRepeating(&Functor::Run, base::Unretained(this)); |
| } |
| |
| ios::IdentityIteratorCallbackResult Run(ChromeIdentity* identity) { |
| // Filtering of the ChromeIdentity can be done here before calling |
| // the sub-class `Run()` method. This will ensure that all functor |
| // perform the same filtering (and thus consider exactly the same |
| // identities). |
| return static_cast<T*>(this)->Run(identity); |
| } |
| }; |
| |
| // Helper class used to implement HasIdentities(). |
| struct FunctorHasIdentities : Functor<FunctorHasIdentities> { |
| bool has_identities = false; |
| |
| ios::IdentityIteratorCallbackResult Run(ChromeIdentity* identity) { |
| has_identities = true; |
| return ios::kIdentityIteratorInterruptIteration; |
| } |
| }; |
| |
| // Helper class used to implement GetIdentityWithGaiaID(). |
| struct FunctorLookupIdentityByGaiaID : Functor<FunctorLookupIdentityByGaiaID> { |
| NSString* lookup_gaia_id; |
| ChromeIdentity* identity; |
| |
| FunctorLookupIdentityByGaiaID(NSString* gaia_id) |
| : lookup_gaia_id(gaia_id), identity(nil) {} |
| |
| ios::IdentityIteratorCallbackResult Run(ChromeIdentity* identity) { |
| if ([lookup_gaia_id isEqualToString:identity.gaiaID]) { |
| this->identity = identity; |
| return ios::kIdentityIteratorInterruptIteration; |
| } |
| return ios::kIdentityIteratorContinueIteration; |
| } |
| }; |
| |
| // Helper class used to implement GetAllIdentities(). |
| struct FunctorCollectIdentities : Functor<FunctorCollectIdentities> { |
| NSMutableArray<ChromeIdentity*>* identities; |
| |
| FunctorCollectIdentities() : identities([NSMutableArray array]) {} |
| |
| ios::IdentityIteratorCallbackResult Run(ChromeIdentity* identity) { |
| [identities addObject:identity]; |
| return ios::kIdentityIteratorContinueIteration; |
| } |
| }; |
| |
| } // anonymous namespace |
| |
| namespace { |
| ChromeIdentityCapabilityResult CapabilityResultFromNSNumber(NSNumber* result) { |
| DCHECK(result); |
| int resultInt = [result intValue]; |
| DCHECK_GE(resultInt, |
| static_cast<int>(ChromeIdentityCapabilityResult::kFalse)); |
| DCHECK_LE(resultInt, |
| static_cast<int>(ChromeIdentityCapabilityResult::kUnknown)); |
| return static_cast<ChromeIdentityCapabilityResult>(resultInt); |
| } |
| |
| } // namespace |
| |
| ChromeIdentityService::ChromeIdentityService() {} |
| |
| ChromeIdentityService::~ChromeIdentityService() { |
| for (auto& observer : observer_list_) |
| observer.OnChromeIdentityServiceWillBeDestroyed(); |
| } |
| |
| void ChromeIdentityService::DismissDialogs() {} |
| |
| bool ChromeIdentityService::HandleApplicationOpenURL(UIApplication* application, |
| NSURL* url, |
| NSDictionary* options) { |
| return false; |
| } |
| |
| bool ChromeIdentityService::HandleSessionOpenURLContexts(UIScene* scene, |
| NSSet* URLContexts) { |
| return false; |
| } |
| |
| void ChromeIdentityService::ApplicationDidDiscardSceneSessions( |
| NSSet* scene_sessions) {} |
| |
| DismissASMViewControllerBlock |
| ChromeIdentityService::PresentAccountDetailsController( |
| ChromeIdentity* identity, |
| UIViewController* view_controller, |
| BOOL animated) { |
| return nil; |
| } |
| |
| DismissASMViewControllerBlock |
| ChromeIdentityService::PresentWebAndAppSettingDetailsController( |
| ChromeIdentity* identity, |
| UIViewController* view_controller, |
| BOOL animated) { |
| return nil; |
| } |
| |
| ChromeIdentityInteractionManager* |
| ChromeIdentityService::CreateChromeIdentityInteractionManager( |
| id<ChromeIdentityInteractionManagerDelegate> delegate) const { |
| return nil; |
| } |
| |
| void ChromeIdentityService::IterateOverIdentities(IdentityIteratorCallback) {} |
| |
| bool ChromeIdentityService::IsValidIdentity(ChromeIdentity* identity) { |
| return GetIdentityWithGaiaID(base::SysNSStringToUTF8(identity.gaiaID)) != nil; |
| } |
| |
| ChromeIdentity* ChromeIdentityService::GetIdentityWithGaiaID( |
| const std::string& gaia_id) { |
| // Do not iterate if the gaia ID is invalid. |
| if (gaia_id.empty()) |
| return nil; |
| |
| FunctorLookupIdentityByGaiaID helper(base::SysUTF8ToNSString(gaia_id)); |
| IterateOverIdentities(helper.Callback()); |
| return helper.identity; |
| } |
| |
| bool ChromeIdentityService::HasIdentities() { |
| FunctorHasIdentities helper; |
| IterateOverIdentities(helper.Callback()); |
| return helper.has_identities; |
| } |
| |
| NSArray* ChromeIdentityService::GetAllIdentities(PrefService* pref_service) { |
| FunctorCollectIdentities helper; |
| IterateOverIdentities(helper.Callback()); |
| return [helper.identities copy]; |
| } |
| |
| void ChromeIdentityService::ForgetIdentity(ChromeIdentity* identity, |
| ForgetIdentityCallback callback) {} |
| |
| void ChromeIdentityService::GetAccessToken(ChromeIdentity* identity, |
| const std::set<std::string>& scopes, |
| AccessTokenCallback callback) {} |
| |
| void ChromeIdentityService::GetAccessToken(ChromeIdentity* identity, |
| const std::string& client_id, |
| const std::set<std::string>& scopes, |
| AccessTokenCallback callback) {} |
| |
| void ChromeIdentityService::GetAvatarForIdentity(ChromeIdentity* identity, |
| GetAvatarCallback callback) {} |
| |
| UIImage* ChromeIdentityService::GetCachedAvatarForIdentity( |
| ChromeIdentity* identity) { |
| return nil; |
| } |
| |
| void ChromeIdentityService::GetHostedDomainForIdentity( |
| ChromeIdentity* identity, |
| GetHostedDomainCallback callback) {} |
| |
| NSString* ChromeIdentityService::GetCachedHostedDomainForIdentity( |
| ChromeIdentity* identity) { |
| // @gmail.com accounts are end consumer accounts so it is safe to return @"" |
| // even when SSOProfileSource has a nil profile for |sso_identity|. |
| // |
| // Note: This is also needed during the sign-in flow as it avoids waiting for |
| // the profile of |sso_identity| to be fetched from the server. |
| if (gaia::ExtractDomainName(base::SysNSStringToUTF8(identity.userEmail)) == |
| "gmail.com") { |
| return @""; |
| } |
| return nil; |
| } |
| |
| void ChromeIdentityService::CanOfferExtendedSyncPromos( |
| ChromeIdentity* identity, |
| CapabilitiesCallback completion) { |
| NSString* canOfferExtendedChromeSyncPromos = [NSString |
| stringWithUTF8String:kCanOfferExtendedChromeSyncPromosCapabilityName]; |
| base::TimeTicks fetch_start = base::TimeTicks::Now(); |
| FetchCapabilities( |
| @[ canOfferExtendedChromeSyncPromos ], identity, |
| ^(NSDictionary<NSString*, NSNumber*>* capabilities, NSError* error) { |
| base::UmaHistogramTimes( |
| "Signin.AccountCapabilities.GetFromSystemLibraryDuration", |
| base::TimeTicks::Now() - fetch_start); |
| if (!completion) { |
| return; |
| } |
| completion(CapabilityResultFromNSNumber( |
| [capabilities objectForKey:canOfferExtendedChromeSyncPromos])); |
| }); |
| } |
| |
| MDMDeviceStatus ChromeIdentityService::GetMDMDeviceStatus( |
| NSDictionary* user_info) { |
| return 0; |
| } |
| |
| bool ChromeIdentityService::HandleMDMNotification(ChromeIdentity* identity, |
| NSDictionary* user_info, |
| MDMStatusCallback callback) { |
| return false; |
| } |
| |
| bool ChromeIdentityService::IsMDMError(ChromeIdentity* identity, |
| NSError* error) { |
| return false; |
| } |
| |
| void ChromeIdentityService::AddObserver(Observer* observer) { |
| observer_list_.AddObserver(observer); |
| } |
| |
| void ChromeIdentityService::RemoveObserver(Observer* observer) { |
| observer_list_.RemoveObserver(observer); |
| } |
| |
| bool ChromeIdentityService::IsInvalidGrantError(NSDictionary* user_info) { |
| return false; |
| } |
| |
| void ChromeIdentityService::FetchCapabilities( |
| NSArray* capabilities, |
| ChromeIdentity* identity, |
| ChromeIdentityCapabilitiesFetchCompletionBlock completion) { |
| // Implementation provided by subclass. |
| } |
| |
| void ChromeIdentityService::FireIdentityListChanged(bool keychainReload) { |
| for (auto& observer : observer_list_) |
| observer.OnIdentityListChanged(keychainReload); |
| } |
| |
| void ChromeIdentityService::FireAccessTokenRefreshFailed( |
| ChromeIdentity* identity, |
| NSDictionary* user_info) { |
| for (auto& observer : observer_list_) |
| observer.OnAccessTokenRefreshFailed(identity, user_info); |
| } |
| |
| void ChromeIdentityService::FireProfileDidUpdate(ChromeIdentity* identity) { |
| for (auto& observer : observer_list_) |
| observer.OnProfileUpdate(identity); |
| } |
| |
| } // namespace ios |