diff options
author | zxu <zxu@google.com> | 2018-02-09 14:28:29 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-02-09 14:28:29 -0500 |
commit | d70c23ece0abf7e1c00166e26fa89a670d34a740 (patch) | |
tree | a59b6eb10bd3394fee37cdf59bee0b666b92b3f5 /Firestore/core/src/firebase/firestore/auth/firebase_credentials_provider_apple.mm | |
parent | 633eb7bb8bbce2d31d682bf5255d9ef5a97a29c5 (diff) |
port Firestore Auth module in C++ (#733)
* Implement firestore/auth/user
* add user to project and some fixes
* implement firestore/auth/{credentials_provider,empty_credentials_provider}
* implement firestore/auth/firebase_credentials_provider
* refactoring firebase_credentials_provider and add (disabled but working) unit test
* add auth test to project
* address changes
* small fix to style and project
* fix the firebase_credentials_provider_test
* fix style
* address changes
* revert the change to static mutex_
* remove my custom plist path
* fix style
* address changes
* refactoring FirebaseCredentialsProvider to fix the issue w.r.t. auth global dispatch queue
* add /*force_refresh=*/ tag to bool literal for style purpose
* Use a shared_ptr/weak_ptr handoff on FirebaseCredentialsProvider (#778)
* Revert "refactoring FirebaseCredentialsProvider to fix the issue w.r.t. auth global dispatch queue"
This reverts commit 87175a4146267d403a774f138b85f8d3b532fa4b.
* Use a shared_ptr/weak_ptr handoff on FirebaseCredentialsProvider
This avoids any problems with callsbacks retaining pointers to objects
destroyed by a C++ destructor
Diffstat (limited to 'Firestore/core/src/firebase/firestore/auth/firebase_credentials_provider_apple.mm')
-rw-r--r-- | Firestore/core/src/firebase/firestore/auth/firebase_credentials_provider_apple.mm | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/Firestore/core/src/firebase/firestore/auth/firebase_credentials_provider_apple.mm b/Firestore/core/src/firebase/firestore/auth/firebase_credentials_provider_apple.mm new file mode 100644 index 0000000..f463958 --- /dev/null +++ b/Firestore/core/src/firebase/firestore/auth/firebase_credentials_provider_apple.mm @@ -0,0 +1,134 @@ +/* + * Copyright 2018 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. + */ + +#include "Firestore/core/src/firebase/firestore/auth/firebase_credentials_provider_apple.h" + +#import <FirebaseCore/FIRApp.h> +#import <FirebaseCore/FIRAppInternal.h> +#import <FirebaseCore/FIROptionsInternal.h> + +#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h" +#include "Firestore/core/src/firebase/firestore/util/string_apple.h" + +namespace firebase { +namespace firestore { +namespace auth { + +FirebaseCredentialsProvider::FirebaseCredentialsProvider(FIRApp* app) + : contents_( + std::make_shared<Contents>(app, util::MakeStringView([app getUID]))) { + std::weak_ptr<Contents> weak_contents = contents_; + + auth_listener_handle_ = [[NSNotificationCenter defaultCenter] + addObserverForName:FIRAuthStateDidChangeInternalNotification + object:nil + queue:nil + usingBlock:^(NSNotification* notification) { + std::shared_ptr<Contents> contents = weak_contents.lock(); + if (!contents) { + return; + } + + std::unique_lock<std::mutex> lock(contents->mutex); + NSDictionary<NSString*, id>* user_info = notification.userInfo; + + // ensure we're only notifiying for the current app. + FIRApp* notified_app = + user_info[FIRAuthStateDidChangeInternalNotificationAppKey]; + if (![contents->app isEqual:notified_app]) { + return; + } + + NSString* user_id = + user_info[FIRAuthStateDidChangeInternalNotificationUIDKey]; + User new_user(util::MakeStringView(user_id)); + if (new_user != contents->current_user) { + contents->current_user = new_user; + contents->user_counter++; + UserChangeListener listener = user_change_listener_; + if (listener) { + listener(contents->current_user); + } + } + }]; +} + +FirebaseCredentialsProvider::~FirebaseCredentialsProvider() { + if (auth_listener_handle_) { + // Even though iOS 9 (and later) and macOS 10.11 (and later) keep a weak + // reference to the observer so we could avoid this removeObserver call, we + // still support iOS 8 which requires it. + [[NSNotificationCenter defaultCenter] removeObserver:auth_listener_handle_]; + } +} + +void FirebaseCredentialsProvider::GetToken(bool force_refresh, + TokenListener completion) { + FIREBASE_ASSERT_MESSAGE(auth_listener_handle_, + "GetToken cannot be called after listener removed."); + + // Take note of the current value of the userCounter so that this method can + // fail if there is a user change while the request is outstanding. + int initial_user_counter = contents_->user_counter; + + std::weak_ptr<Contents> weak_contents = contents_; + void (^get_token_callback)(NSString*, NSError*) = ^( + NSString* _Nullable token, NSError* _Nullable error) { + std::shared_ptr<Contents> contents = weak_contents.lock(); + if (!contents) { + return; + } + + std::unique_lock<std::mutex> lock(contents->mutex); + if (initial_user_counter != contents->user_counter) { + // Cancel the request since the user changed while the request was + // outstanding so the response is likely for a previous user (which + // user, we can't be sure). + completion({"", User::Unauthenticated()}, + "getToken aborted due to user change."); + } else { + completion( + {util::MakeStringView(token), contents->current_user}, + error == nil ? "" : util::MakeStringView(error.localizedDescription)); + } + }; + + [contents_->app getTokenForcingRefresh:force_refresh + withCallback:get_token_callback]; +} + +void FirebaseCredentialsProvider::SetUserChangeListener( + UserChangeListener listener) { + std::unique_lock<std::mutex> lock(contents_->mutex); + if (listener) { + FIREBASE_ASSERT_MESSAGE(!user_change_listener_, + "set user_change_listener twice!"); + // Fire initial event. + listener(contents_->current_user); + } else { + FIREBASE_ASSERT_MESSAGE(auth_listener_handle_, + "removed user_change_listener twice!"); + FIREBASE_ASSERT_MESSAGE(user_change_listener_, + "user_change_listener removed without being set!"); + [[NSNotificationCenter defaultCenter] removeObserver:auth_listener_handle_]; + auth_listener_handle_ = nil; + } + user_change_listener_ = listener; +} + +} // namespace auth +} // namespace firestore +} // namespace firebase |