FIRAppCheck.m 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. /*
  2. * Copyright 2020 Google LLC
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import "FirebaseAppCheck/Sources/Public/FirebaseAppCheck/FIRAppCheck.h"
  17. @import AppCheckCore;
  18. @import FirebaseAppCheckInterop;
  19. #import "FirebaseAppCheck/Sources/Public/FirebaseAppCheck/FIRAppCheckErrors.h"
  20. #import "FirebaseAppCheck/Sources/Public/FirebaseAppCheck/FIRAppCheckProvider.h"
  21. #import "FirebaseAppCheck/Sources/Public/FirebaseAppCheck/FIRAppCheckProviderFactory.h"
  22. #import "FirebaseAppCheck/Sources/Core/Errors/FIRAppCheckErrorUtil.h"
  23. #import "FirebaseAppCheck/Sources/Core/FIRAppCheck+Internal.h"
  24. #import "FirebaseAppCheck/Sources/Core/FIRAppCheckLogger.h"
  25. #import "FirebaseAppCheck/Sources/Core/FIRAppCheckSettings.h"
  26. #import "FirebaseAppCheck/Sources/Core/FIRAppCheckToken+Internal.h"
  27. #import "FirebaseAppCheck/Sources/Core/FIRAppCheckTokenResult.h"
  28. #import "FirebaseAppCheck/Sources/Core/FIRInternalAppCheckProvider.h"
  29. NS_ASSUME_NONNULL_BEGIN
  30. /// A notification with the specified name is sent to the default notification center
  31. /// (`NotificationCenter.default`) each time a Firebase app check token is refreshed.
  32. /// The user info dictionary contains `kFIRAppCheckTokenNotificationKey` and
  33. /// `kFIRAppCheckAppNameNotificationKey` keys.
  34. const NSNotificationName FIRAppCheckAppCheckTokenDidChangeNotification =
  35. @"FIRAppCheckAppCheckTokenDidChangeNotification";
  36. /// `userInfo` key for the `AppCheckToken` in `appCheckTokenRefreshNotification`.
  37. NSString *const kFIRAppCheckTokenNotificationKey = @"FIRAppCheckTokenNotificationKey";
  38. /// `userInfo` key for the `FirebaseApp.name` in `appCheckTokenRefreshNotification`.
  39. NSString *const kFIRAppCheckAppNameNotificationKey = @"FIRAppCheckAppNameNotificationKey";
  40. static id<FIRAppCheckProviderFactory> _providerFactory;
  41. static NSString *const kDummyFACTokenValue = @"eyJlcnJvciI6IlVOS05PV05fRVJST1IifQ==";
  42. @interface FIRAppCheck () <FIRAppCheckInterop, GACAppCheckTokenDelegate>
  43. @property(class, nullable) id<FIRAppCheckProviderFactory> providerFactory;
  44. @property(nonatomic, readonly) NSString *appName;
  45. @property(nonatomic, readonly) NSNotificationCenter *notificationCenter;
  46. @property(nonatomic, readonly) FIRAppCheckSettings *settings;
  47. @property(nonatomic, readonly) GACAppCheck *appCheckCore;
  48. @end
  49. @implementation FIRAppCheck
  50. #pragma mark - Internal
  51. - (nullable instancetype)initWithApp:(FIRApp *)app {
  52. id<FIRAppCheckProviderFactory> providerFactory = [FIRAppCheck providerFactory];
  53. if (providerFactory == nil) {
  54. FIRLogError(kFIRLoggerAppCheck, kFIRLoggerAppCheckMessageCodeProviderFactoryIsMissing,
  55. @"Cannot instantiate `FIRAppCheck` for app: %@ without a provider factory. "
  56. @"Please register a provider factory using "
  57. @"`AppCheck.setAppCheckProviderFactory(_ ,forAppName:)` method.",
  58. app.name);
  59. return nil;
  60. }
  61. id<FIRAppCheckProvider> appCheckProvider = [providerFactory createProviderWithApp:app];
  62. if (appCheckProvider == nil) {
  63. FIRLogError(kFIRLoggerAppCheck, kFIRLoggerAppCheckMessageCodeProviderIsMissing,
  64. @"Cannot instantiate `FIRAppCheck` for app: %@ without an app check provider. "
  65. @"Please make sure the provider factory returns a valid app check provider.",
  66. app.name);
  67. return nil;
  68. }
  69. NSString *serviceName = [self serviceNameForApp:app];
  70. NSString *resourceName = [self resourceNameForApp:app];
  71. id<GACAppCheckProvider> appCheckCoreProvider =
  72. [[FIRInternalAppCheckProvider alloc] initWithAppCheckProvider:appCheckProvider];
  73. FIRAppCheckSettings *settings =
  74. [[FIRAppCheckSettings alloc] initWithApp:app
  75. userDefault:[NSUserDefaults standardUserDefaults]
  76. mainBundle:[NSBundle mainBundle]];
  77. GACAppCheck *appCheckCore = [[GACAppCheck alloc] initWithServiceName:serviceName
  78. resourceName:resourceName
  79. appCheckProvider:appCheckCoreProvider
  80. settings:settings
  81. tokenDelegate:self
  82. keychainAccessGroup:app.options.appGroupID];
  83. return [self initWithAppName:app.name
  84. appCheckCore:appCheckCore
  85. appCheckProvider:appCheckProvider
  86. notificationCenter:NSNotificationCenter.defaultCenter
  87. settings:settings];
  88. }
  89. - (instancetype)initWithAppName:(NSString *)appName
  90. appCheckCore:(GACAppCheck *)appCheckCore
  91. appCheckProvider:(id<FIRAppCheckProvider>)appCheckProvider
  92. notificationCenter:(NSNotificationCenter *)notificationCenter
  93. settings:(FIRAppCheckSettings *)settings {
  94. self = [super init];
  95. if (self) {
  96. _appName = appName;
  97. _appCheckCore = appCheckCore;
  98. _notificationCenter = notificationCenter;
  99. _settings = settings;
  100. }
  101. return self;
  102. }
  103. #pragma mark - Public
  104. + (instancetype)appCheck {
  105. FIRApp *defaultApp = [FIRApp defaultApp];
  106. if (!defaultApp) {
  107. [NSException raise:FIRAppCheckErrorDomain
  108. format:@"The default FirebaseApp instance must be configured before the default"
  109. @"AppCheck instance can be initialized. One way to ensure this is to "
  110. @"call `FirebaseApp.configure()` in the App Delegate's "
  111. @"`application(_:didFinishLaunchingWithOptions:)` (or the `@main` struct's "
  112. @"initializer in SwiftUI)."];
  113. }
  114. return [self appCheckWithApp:defaultApp];
  115. }
  116. + (nullable instancetype)appCheckWithApp:(FIRApp *)firebaseApp {
  117. id<FIRAppCheckInterop> appCheck = FIR_COMPONENT(FIRAppCheckInterop, firebaseApp.container);
  118. return (FIRAppCheck *)appCheck;
  119. }
  120. - (void)tokenForcingRefresh:(BOOL)forcingRefresh
  121. completion:(void (^)(FIRAppCheckToken *_Nullable token,
  122. NSError *_Nullable error))handler {
  123. [self.appCheckCore
  124. tokenForcingRefresh:forcingRefresh
  125. completion:^(GACAppCheckTokenResult *result) {
  126. if (result.error) {
  127. handler(nil, [FIRAppCheckErrorUtil publicDomainErrorWithError:result.error]);
  128. return;
  129. }
  130. handler([[FIRAppCheckToken alloc] initWithInternalToken:result.token], nil);
  131. }];
  132. }
  133. - (void)limitedUseTokenWithCompletion:(void (^)(FIRAppCheckToken *_Nullable token,
  134. NSError *_Nullable error))handler {
  135. [self.appCheckCore limitedUseTokenWithCompletion:^(GACAppCheckTokenResult *result) {
  136. if (result.error) {
  137. handler(nil, [FIRAppCheckErrorUtil publicDomainErrorWithError:result.error]);
  138. return;
  139. }
  140. handler([[FIRAppCheckToken alloc] initWithInternalToken:result.token], nil);
  141. }];
  142. }
  143. + (void)setAppCheckProviderFactory:(nullable id<FIRAppCheckProviderFactory>)factory {
  144. self.providerFactory = factory;
  145. }
  146. - (void)setIsTokenAutoRefreshEnabled:(BOOL)isTokenAutoRefreshEnabled {
  147. self.settings.isTokenAutoRefreshEnabled = isTokenAutoRefreshEnabled;
  148. }
  149. - (BOOL)isTokenAutoRefreshEnabled {
  150. return self.settings.isTokenAutoRefreshEnabled;
  151. }
  152. #pragma mark - App Check Provider Ingestion
  153. + (void)setProviderFactory:(nullable id<FIRAppCheckProviderFactory>)providerFactory {
  154. @synchronized(self) {
  155. _providerFactory = providerFactory;
  156. }
  157. }
  158. + (nullable id<FIRAppCheckProviderFactory>)providerFactory {
  159. @synchronized(self) {
  160. return _providerFactory;
  161. }
  162. }
  163. #pragma mark - FIRAppCheckInterop
  164. - (void)getTokenForcingRefresh:(BOOL)forcingRefresh
  165. completion:(FIRAppCheckTokenHandlerInterop)handler {
  166. [self.appCheckCore
  167. tokenForcingRefresh:forcingRefresh
  168. completion:^(GACAppCheckTokenResult *internalResult) {
  169. FIRAppCheckToken *token =
  170. [[FIRAppCheckToken alloc] initWithInternalToken:internalResult.token];
  171. FIRAppCheckTokenResult *tokenResult =
  172. [[FIRAppCheckTokenResult alloc] initWithToken:token.token
  173. error:internalResult.error];
  174. handler(tokenResult);
  175. }];
  176. }
  177. - (void)getLimitedUseTokenWithCompletion:(FIRAppCheckTokenHandlerInterop)handler {
  178. [self.appCheckCore limitedUseTokenWithCompletion:^(GACAppCheckTokenResult *internalResult) {
  179. FIRAppCheckToken *token = [[FIRAppCheckToken alloc] initWithInternalToken:internalResult.token];
  180. FIRAppCheckTokenResult *tokenResult =
  181. [[FIRAppCheckTokenResult alloc] initWithToken:token.token error:internalResult.error];
  182. handler(tokenResult);
  183. }];
  184. }
  185. - (nonnull NSString *)tokenDidChangeNotificationName {
  186. return FIRAppCheckAppCheckTokenDidChangeNotification;
  187. }
  188. - (nonnull NSString *)notificationAppNameKey {
  189. return kFIRAppCheckAppNameNotificationKey;
  190. }
  191. - (nonnull NSString *)notificationTokenKey {
  192. return kFIRAppCheckTokenNotificationKey;
  193. }
  194. #pragma mark - GACAppCheckTokenDelegate
  195. - (void)tokenDidUpdate:(nonnull GACAppCheckToken *)token
  196. serviceName:(nonnull NSString *)serviceName {
  197. FIRAppCheckToken *appCheckToken = [[FIRAppCheckToken alloc] initWithInternalToken:token];
  198. [self postTokenUpdateNotificationWithToken:appCheckToken];
  199. }
  200. #pragma mark - Token update notification
  201. - (void)postTokenUpdateNotificationWithToken:(FIRAppCheckToken *)token {
  202. [self.notificationCenter postNotificationName:FIRAppCheckAppCheckTokenDidChangeNotification
  203. object:self
  204. userInfo:@{
  205. kFIRAppCheckTokenNotificationKey : token.token,
  206. kFIRAppCheckAppNameNotificationKey : self.appName
  207. }];
  208. }
  209. #pragma mark - Helpers
  210. - (NSString *)serviceNameForApp:(FIRApp *)app {
  211. return [NSString stringWithFormat:@"FirebaseApp:%@", app.name];
  212. }
  213. - (NSString *)resourceNameForApp:(FIRApp *)app {
  214. return [NSString
  215. stringWithFormat:@"projects/%@/apps/%@", app.options.projectID, app.options.googleAppID];
  216. }
  217. @end
  218. NS_ASSUME_NONNULL_END