aboutsummaryrefslogtreecommitdiffhomepage
path: root/AuthSamples/Sample/SettingsViewController.m
diff options
context:
space:
mode:
authorGravatar Paul Beusterien <paulbeusterien@google.com>2017-05-15 12:27:07 -0700
committerGravatar Paul Beusterien <paulbeusterien@google.com>2017-05-15 12:27:07 -0700
commit98ba64449a632518bd2b86fe8d927f4a960d3ddc (patch)
tree131d9c4272fa6179fcda6c5a33fcb3b1bd57ad2e /AuthSamples/Sample/SettingsViewController.m
parent32461366c9e204a527ca05e6e9b9404a2454ac51 (diff)
Initial
Diffstat (limited to 'AuthSamples/Sample/SettingsViewController.m')
-rw-r--r--AuthSamples/Sample/SettingsViewController.m381
1 files changed, 381 insertions, 0 deletions
diff --git a/AuthSamples/Sample/SettingsViewController.m b/AuthSamples/Sample/SettingsViewController.m
new file mode 100644
index 0000000..e7be9a6
--- /dev/null
+++ b/AuthSamples/Sample/SettingsViewController.m
@@ -0,0 +1,381 @@
+/*
+ * Copyright 2017 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "SettingsViewController.h"
+
+#import <objc/runtime.h>
+
+#import "FIRApp.h"
+#import "FIROptions.h"
+#import "FirebaseAuth.h"
+#import "StaticContentTableViewManager.h"
+#import "UIViewController+Alerts.h"
+
+#if INTERNAL_GOOGLE3_BUILD
+#import "googlemac/iPhone/Identity/Firebear/Auth/Source/FIRAuth_Internal.h"
+#import "googlemac/iPhone/Identity/Firebear/Auth/Source/FIRAuthAPNSToken.h"
+#import "googlemac/iPhone/Identity/Firebear/Auth/Source/FIRAuthAPNSTokenManager.h"
+#import "googlemac/iPhone/Identity/Firebear/Auth/Source/FIRAuthAppCredential.h"
+#import "googlemac/iPhone/Identity/Firebear/Auth/Source/FIRAuthAppCredentialManager.h"
+#import "googlemac/iPhone/InstanceID/Firebase/Lib/Source/FIRInstanceID+Internal.h"
+#else
+@interface FIRInstanceID : NSObject
++ (void)notifyTokenRefresh;
+@end
+#endif
+
+/** @var kIdentityToolkitRequestClassName
+ @brief The class name of Identity Toolkit requests.
+ */
+static NSString *const kIdentityToolkitRequestClassName = @"FIRIdentityToolkitRequest";
+
+/** @var kSecureTokenRequestClassName
+ @brief The class name of Secure Token Service requests.
+ */
+static NSString *const kSecureTokenRequestClassName = @"FIRSecureTokenRequest";
+
+/** @var kIdentityToolkitSandboxHost
+ @brief The host of Identity Toolkit sandbox server.
+ */
+static NSString *const kIdentityToolkitSandboxHost = @"www-googleapis-staging.sandbox.google.com";
+
+/** @var kSecureTokenSandboxHost
+ @brief The host of Secure Token Service sandbox server.
+ */
+static NSString *const kSecureTokenSandboxHost = @"staging-securetoken.sandbox.googleapis.com";
+
+/** @var kGoogleServiceInfoPlists
+ @brief a C-array of plist file base names of Google service info to initialize FIRApp.
+ */
+static NSString *const kGoogleServiceInfoPlists[] = {
+ @"GoogleService-Info",
+ @"GoogleService-Info_multi"
+};
+
+/** @var gAPIEndpoints
+ @brief List of API Hosts by request class name.
+ */
+static NSDictionary<NSString *, NSArray<NSString *> *> *gAPIHosts;
+
+/** @var gFirebaseAppOptions
+ @brief List of FIROptions.
+ */
+static NSArray<FIROptions *> *gFirebaseAppOptions;
+
+/** @protocol RequestClass
+ @brief A de-facto protocol followed by request class objects to access its API host.
+ */
+@protocol RequestClass <NSObject>
+- (NSString *)host;
+- (void)setHost:(NSString *)host;
+@end
+
+/** @category FIROptions(ProjectID)
+ @brief A category to FIROption to add the project ID property.
+ */
+@interface FIROptions (ProjectID)
+
+/** @property projectID
+ @brief The Firebase project ID.
+ */
+@property(nonatomic, copy) NSString *projectID;
+
+@end
+
+@implementation FIROptions (ProjectID)
+
+- (NSString *)projectID {
+ return objc_getAssociatedObject(self, @selector(projectID));
+}
+
+- (void)setProjectID:(NSString *)projectID {
+ objc_setAssociatedObject(self, @selector(projectID), projectID, OBJC_ASSOCIATION_COPY_NONATOMIC);
+}
+
+@end
+
+/** @fn versionString
+ @brief Constructs a version string to display.
+ @param string The version in string form.
+ @param number The version in number form.
+ */
+static NSString *versionString(const unsigned char *string, const double number) {
+ return [NSString stringWithFormat:@"\"%s\" (%g)", string, number];
+}
+
+/** @fn requestHost
+ @brief Retrieves the API host for the request class.
+ @param requestClassName The name of the request class.
+ */
+static NSString *APIHost(NSString *requestClassName) {
+ return [(id<RequestClass>)NSClassFromString(requestClassName) host];
+}
+
+/** @fn truncatedString
+ @brief Truncates a string under a maximum length.
+ @param string The original string to be truncated.
+ @param length The maximum length of the truncated string.
+ @return The truncated string, which is not longer than @c length.
+ */
+static NSString *truncatedString(NSString *string, NSUInteger length) {
+ if (string.length <= length) {
+ return string;
+ }
+ NSUInteger half = (length - 3) / 2;
+ return [NSString stringWithFormat:@"%@...%@",
+ [string substringToIndex:half],
+ [string substringFromIndex:string.length - half]];
+}
+
+/** @fn hexString
+ @brief Converts a piece of data into a hexadecimal string.
+ @param data The raw data.
+ @return The hexadecimal string representation of the data.
+ */
+static NSString *hexString(NSData *data) {
+ NSMutableString *string = [NSMutableString stringWithCapacity:data.length * 2];
+ const unsigned char *bytes = data.bytes;
+ for (int idx = 0; idx < data.length; ++idx) {
+ [string appendFormat:@"%02X", (int)bytes[idx]];
+ }
+ return string;
+}
+
+@implementation SettingsViewController
+
+- (void)viewDidLoad {
+ [super viewDidLoad];
+ [self setUpAPIHosts];
+ [self setUpFirebaseAppOptions];
+ [self loadTableView];
+}
+
+- (IBAction)done:(id)sender {
+ [self dismissViewControllerAnimated:YES completion:nil];
+}
+
+- (void)setUpAPIHosts {
+ if (gAPIHosts) {
+ return;
+ }
+ gAPIHosts = @{
+ kIdentityToolkitRequestClassName : @[
+ APIHost(kIdentityToolkitRequestClassName),
+ kIdentityToolkitSandboxHost,
+ ],
+ kSecureTokenRequestClassName : @[
+ APIHost(kSecureTokenRequestClassName),
+ kSecureTokenSandboxHost,
+ ],
+ };
+}
+
+- (void)setUpFirebaseAppOptions {
+ if (gFirebaseAppOptions) {
+ return;
+ }
+ int numberOfOptions = sizeof(kGoogleServiceInfoPlists) / sizeof(*kGoogleServiceInfoPlists);
+ NSMutableArray *appOptions = [[NSMutableArray alloc] initWithCapacity:numberOfOptions];
+ for (int i = 0; i < numberOfOptions; i++) {
+ NSString *plistFileName = kGoogleServiceInfoPlists[i];
+ NSString *plistFilePath = [[NSBundle mainBundle] pathForResource:plistFileName
+ ofType:@"plist"];
+ NSDictionary *optionsDictionary = [NSDictionary dictionaryWithContentsOfFile:plistFilePath];
+ FIROptions *options = [[FIROptions alloc]
+ initWithGoogleAppID:optionsDictionary[@"GOOGLE_APP_ID"]
+ bundleID:optionsDictionary[@"BUNDLE_ID"]
+ GCMSenderID:optionsDictionary[@"GCM_SENDER_ID"]
+ APIKey:optionsDictionary[@"API_KEY"]
+ clientID:optionsDictionary[@"CLIENT_ID"]
+ trackingID:optionsDictionary[@"TRACKING_ID"]
+ androidClientID:optionsDictionary[@"ANDROID_CLIENT_ID"]
+ databaseURL:optionsDictionary[@"DATABASE_URL"]
+ storageBucket:optionsDictionary[@"STORAGE_BUCKET"]
+ deepLinkURLScheme:nil];
+ options.projectID = optionsDictionary[@"PROJECT_ID"];
+ [appOptions addObject:options];
+ }
+ gFirebaseAppOptions = [appOptions copy];
+}
+
+- (void)loadTableView {
+ __weak typeof(self) weakSelf = self;
+ _tableViewManager.contents = [StaticContentTableViewContent contentWithSections:@[
+ [StaticContentTableViewSection sectionWithTitle:@"Versions" cells:@[
+ [StaticContentTableViewCell cellWithTitle:@"FirebaseAuth"
+ value:versionString(
+ FirebaseAuthVersionString, FirebaseAuthVersionNumber)],
+ ]],
+ [StaticContentTableViewSection sectionWithTitle:@"Client Identity" cells:@[
+ [StaticContentTableViewCell cellWithTitle:@"Project"
+ value:[self currentProjectID]
+ action:^{
+ [weakSelf toggleClientProject];
+ }],
+ ]],
+ [StaticContentTableViewSection sectionWithTitle:@"API Hosts" cells:@[
+ [StaticContentTableViewCell cellWithTitle:@"Identity Toolkit"
+ value:APIHost(kIdentityToolkitRequestClassName)
+ action:^{
+ [weakSelf toggleAPIHostWithRequestClassName:kIdentityToolkitRequestClassName];
+ }],
+ [StaticContentTableViewCell cellWithTitle:@"Secure Token"
+ value:APIHost(kSecureTokenRequestClassName)
+ action:^{
+ [weakSelf toggleAPIHostWithRequestClassName:kSecureTokenRequestClassName];
+ }],
+ ]],
+#if INTERNAL_GOOGLE3_BUILD
+ [StaticContentTableViewSection sectionWithTitle:@"Phone Auth" cells:@[
+ [StaticContentTableViewCell cellWithTitle:@"APNs Token"
+ value:[self APNSTokenString]
+ action:^{
+ [weakSelf clearAPNSToken];
+ }],
+ [StaticContentTableViewCell cellWithTitle:@"App Credential"
+ value:[self appCredentialString]
+ action:^{
+ [weakSelf clearAppCredential];
+ }],
+ ]],
+#endif // INTERNAL_GOOGLE3_BUILD
+ ]];
+}
+
+/** @fn toggleAPIHostWithRequestClassName:
+ @brief Toggles the host name of the server that handles RPCs.
+ @param requestClassName The name of the RPC request class.
+ */
+- (void)toggleAPIHostWithRequestClassName:(NSString *)requestClassName {
+ NSString *currentHost = APIHost(requestClassName);
+ NSArray<NSString *> *allHosts = gAPIHosts[requestClassName];
+ NSString *newHost = allHosts[([allHosts indexOfObject:currentHost] + 1) % allHosts.count];
+ [(id<RequestClass>)NSClassFromString(requestClassName) setHost:newHost];
+ [self loadTableView];
+}
+
+/** @fn currentProjectID
+ @brief Returns the the current Firebase project ID.
+ */
+- (NSString *)currentProjectID {
+ NSString *APIKey = [FIRApp defaultApp].options.APIKey;
+ for (FIROptions *options in gFirebaseAppOptions) {
+ if ([options.APIKey isEqualToString:APIKey]) {
+ return options.projectID;
+ }
+ }
+ return nil;
+}
+
+/** @fn toggleClientProject
+ @brief Toggles the Firebase/Google project this client presents by recreating the default
+ FIRApp instance with different options.
+ */
+- (void)toggleClientProject {
+ NSString *APIKey = [FIRApp defaultApp].options.APIKey;
+ for (NSUInteger i = 0 ; i < gFirebaseAppOptions.count; i++) {
+ FIROptions *options = gFirebaseAppOptions[i];
+ if ([options.APIKey isEqualToString:APIKey]) {
+ __weak typeof(self) weakSelf = self;
+ [[FIRApp defaultApp] deleteApp:^(BOOL success) {
+ if (success) {
+ [FIRInstanceID notifyTokenRefresh]; // b/28967043
+ dispatch_async(dispatch_get_main_queue(), ^() {
+ FIROptions *options = gFirebaseAppOptions[(i + 1) % gFirebaseAppOptions.count];
+ [FIRApp configureWithOptions:options];
+ [weakSelf loadTableView];
+ });
+ }
+ }];
+ return;
+ }
+ }
+}
+
+#if INTERNAL_GOOGLE3_BUILD
+
+/** @fn APNSTokenString
+ @brief Returns a string representing APNS token.
+ */
+- (NSString *)APNSTokenString {
+ FIRAuthAPNSToken *token = [FIRAuth auth].tokenManager.token;
+ if (!token) {
+ return @"";
+ }
+ return [NSString stringWithFormat:@"%@(%@)",
+ truncatedString(hexString(token.data), 19),
+ token.type == FIRAuthAPNSTokenTypeProd ? @"P" : @"S"];
+}
+
+/** @fn clearAPNSToken
+ @brief Clears the saved app credential.
+ */
+- (void)clearAPNSToken {
+ FIRAuthAPNSToken *token = [FIRAuth auth].tokenManager.token;
+ if (!token) {
+ return;
+ }
+ NSString *tokenType = token.type == FIRAuthAPNSTokenTypeProd ? @"Production" : @"Sandbox";
+ NSString *message = [NSString stringWithFormat:@"token: %@\ntype: %@",
+ hexString(token.data), tokenType];
+ [self showMessagePromptWithTitle:@"Clear APNs Token?"
+ message:message
+ showCancelButton:YES
+ completion:^(BOOL userPressedOK, NSString *_Nullable userInput) {
+ if (userPressedOK) {
+ [FIRAuth auth].tokenManager.token = nil;
+ [self loadTableView];
+ }
+ }];
+}
+
+/** @fn appCredentialString
+ @brief Returns a string representing app credential.
+ */
+- (NSString *)appCredentialString {
+ FIRAuthAppCredential *credential = [FIRAuth auth].appCredentialManager.credential;
+ if (!credential) {
+ return @"";
+ }
+ return [NSString stringWithFormat:@"%@/%@",
+ truncatedString(credential.receipt, 13),
+ truncatedString(credential.secret, 13)];
+}
+
+/** @fn clearAppCredential
+ @brief Clears the saved app credential.
+ */
+- (void)clearAppCredential {
+ FIRAuthAppCredential *credential = [FIRAuth auth].appCredentialManager.credential;
+ if (!credential) {
+ return;
+ }
+ NSString *message = [NSString stringWithFormat:@"receipt: %@\nsecret: %@",
+ credential.receipt, credential.secret];
+ [self showMessagePromptWithTitle:@"Clear App Credential?"
+ message:message
+ showCancelButton:YES
+ completion:^(BOOL userPressedOK, NSString *_Nullable userInput) {
+ if (userPressedOK) {
+ [[FIRAuth auth].appCredentialManager clearCredential];
+ [self loadTableView];
+ }
+ }];
+}
+
+#endif // INTERNAL_GOOGLE3_BUILD
+
+@end