From 3e7c062f3baca83fae1937bf60865be0cd18f96d Mon Sep 17 00:00:00 2001 From: zxu Date: Tue, 27 Feb 2018 14:04:39 -0500 Subject: replacing Auth by C++ auth implementation (#802) * lazy replacing FST(Firebase)CredentialsProvider by (Firebase)CredentialsProvider * lazy replacing FSTUser by User * adding error-code parameter to TokenListener * actually use const user& instead of pointer; also add an error util * add HashUser and pass into the unordered_map * use User in test * use c++ CredentialsProvider and subclass in test * fix unit test * use explicit capture in lambda instead of capture all by reference * cache currentUser explicitly when reset sync engineer test driver * objc object should be captured by value in lambda * replacing Auth/FSTUser by C++ auth implementation * address changes * replacing FSTGetTokenResult by C++ Token implementation * address changes * fix unintentional change in merging * patch the change in objc Auth up-stream * somehow, the lambda-version of set-user-change-listener does not work... fallback to block * address changes * fix another const& v.s. dispatch bug * fix more const& v.s. dispatch bug zxu123 committed * fix a bad sync line * address changes * address change * address change * fix upstream change from merge * fix upstream changes * Suggested fixes for cpp/port_auth (#846) * Get rid of MockDatastore factory This avoids the need to statically allocate (and leak) a credentials provider * Use absl::make_unique std::make_unique technically does not exist until C++14. * #include for std::move * Use std::future for the initial user * fix style --- .../include/firebase/firestore/firestore_errors.h | 115 +++++++++++++++++++++ .../firebase/firestore/auth/credentials_provider.h | 7 +- .../firestore/auth/empty_credentials_provider.cc | 3 +- .../auth/firebase_credentials_provider_apple.mm | 7 +- .../core/src/firebase/firestore/util/error_apple.h | 52 ++++++++++ .../firestore/auth/credentials_provider_test.cc | 7 +- .../auth/empty_credentials_provider_test.cc | 8 +- .../auth/firebase_credentials_provider_test.mm | 12 ++- 8 files changed, 195 insertions(+), 16 deletions(-) create mode 100644 Firestore/core/include/firebase/firestore/firestore_errors.h create mode 100644 Firestore/core/src/firebase/firestore/util/error_apple.h (limited to 'Firestore/core') diff --git a/Firestore/core/include/firebase/firestore/firestore_errors.h b/Firestore/core/include/firebase/firestore/firestore_errors.h new file mode 100644 index 0000000..7a0ff7c --- /dev/null +++ b/Firestore/core/include/firebase/firestore/firestore_errors.h @@ -0,0 +1,115 @@ +/* + * 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. + */ + +#ifndef FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_FIRESTORE_ERRORS_H_ +#define FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_FIRESTORE_ERRORS_H_ + +namespace firebase { +namespace firestore { + +/** + * Error codes used by Cloud Firestore. + * + * The codes are in sync with the Firestore iOS client SDK header file + * FIRFirestoreErrors.h. + */ +enum FirestoreErrorCode { + /** + * The operation completed successfully. NSError objects will never have a + * code with this value. + */ + Ok = 0, + + /** The operation was cancelled (typically by the caller). */ + Cancelled = 1, + + /** Unknown error or an error from a different error domain. */ + Unknown = 2, + + /** + * Client specified an invalid argument. Note that this differs from + * FailedPrecondition. InvalidArgument indicates arguments that are + * problematic regardless of the state of the system (e.g., an invalid field + * name). + */ + InvalidArgument = 3, + + /** + * Deadline expired before operation could complete. For operations that + * change the state of the system, this error may be returned even if the + * operation has completed successfully. For example, a successful response + * from a server could have been delayed long enough for the deadline to + * expire. + */ + DeadlineExceeded = 4, + + /** Some requested document was not found. */ + NotFound = 5, + + /** Some document that we attempted to create already exists. */ + AlreadyExists = 6, + + /** The caller does not have permission to execute the specified operation. */ + PermissionDenied = 7, + + /** + * Some resource has been exhausted, perhaps a per-user quota, or perhaps the + * entire file system is out of space. + */ + ResourceExhausted = 8, + + /** + * Operation was rejected because the system is not in a state required for + * the operation's execution. + */ + FailedPrecondition = 9, + + /** + * The operation was aborted, typically due to a concurrency issue like + * transaction aborts, etc. + */ + Aborted = 10, + + /** Operation was attempted past the valid range. */ + OutOfRange = 11, + + /** Operation is not implemented or not supported/enabled. */ + Unimplemented = 12, + + /** + * Internal errors. Means some invariants expected by underlying system has + * been broken. If you see one of these errors, something is very broken. + */ + Internal = 13, + + /** + * The service is currently unavailable. This is a most likely a transient + * condition and may be corrected by retrying with a backoff. + */ + Unavailable = 14, + + /** Unrecoverable data loss or corruption. */ + DataLoss = 15, + + /** The request does not have valid authentication credentials for the + operation. */ + Unauthenticated = 16 +}; + +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_FIRESTORE_ERRORS_H_ diff --git a/Firestore/core/src/firebase/firestore/auth/credentials_provider.h b/Firestore/core/src/firebase/firestore/auth/credentials_provider.h index 917f8e1..b9a8a24 100644 --- a/Firestore/core/src/firebase/firestore/auth/credentials_provider.h +++ b/Firestore/core/src/firebase/firestore/auth/credentials_provider.h @@ -20,6 +20,7 @@ #include #include +#include "Firestore/core/include/firebase/firestore/firestore_errors.h" #include "Firestore/core/src/firebase/firestore/auth/token.h" #include "Firestore/core/src/firebase/firestore/auth/user.h" #include "absl/strings/string_view.h" @@ -30,8 +31,10 @@ namespace auth { // `TokenErrorListener` is a listener that gets a token or an error. // token: An auth token as a string, or nullptr if error occurred. -// error: The error if one occurred, or else nullptr. -typedef std::function +// error_code: The error code if one occurred, or else FirestoreErrorCode::Ok. +// error_msg: The error if one occurred, or else nullptr. +typedef std::function TokenListener; // Listener notified with a User change. diff --git a/Firestore/core/src/firebase/firestore/auth/empty_credentials_provider.cc b/Firestore/core/src/firebase/firestore/auth/empty_credentials_provider.cc index 6ee7f61..0fa70c0 100644 --- a/Firestore/core/src/firebase/firestore/auth/empty_credentials_provider.cc +++ b/Firestore/core/src/firebase/firestore/auth/empty_credentials_provider.cc @@ -26,7 +26,8 @@ void EmptyCredentialsProvider::GetToken(bool force_refresh, TokenListener completion) { UNUSED(force_refresh); if (completion) { - completion({"", User::Unauthenticated()}, ""); + // Invalid token will force the GRPC fallback to use default settings. + completion(Token::Invalid(), FirestoreErrorCode::Ok, ""); } } 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 index fe3cb24..1babe82 100644 --- a/Firestore/core/src/firebase/firestore/auth/firebase_credentials_provider_apple.mm +++ b/Firestore/core/src/firebase/firestore/auth/firebase_credentials_provider_apple.mm @@ -53,7 +53,7 @@ FirebaseCredentialsProvider::FirebaseCredentialsProvider(FIRApp* app) NSString* user_id = user_info[FIRAuthStateDidChangeInternalNotificationUIDKey]; - User new_user(util::MakeStringView(user_id)); + User new_user = User::FromUid(user_id); if (new_user != contents->current_user) { contents->current_user = new_user; contents->user_counter++; @@ -96,11 +96,12 @@ void FirebaseCredentialsProvider::GetToken(bool force_refresh, // 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()}, + completion(Token::Invalid(), FirestoreErrorCode::Aborted, "getToken aborted due to user change."); } else { completion( - {util::MakeStringView(token), contents->current_user}, + Token{util::MakeStringView(token), contents->current_user}, + error == nil ? FirestoreErrorCode::Ok : error.code, error == nil ? "" : util::MakeStringView(error.localizedDescription)); } }; diff --git a/Firestore/core/src/firebase/firestore/util/error_apple.h b/Firestore/core/src/firebase/firestore/util/error_apple.h new file mode 100644 index 0000000..e31cfd6 --- /dev/null +++ b/Firestore/core/src/firebase/firestore/util/error_apple.h @@ -0,0 +1,52 @@ +/* + * 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. + */ + +#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_ERROR_APPLE_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_ERROR_APPLE_H_ + +// Everything in this header exists for compatibility with Objective-C. +#if __OBJC__ + +#import + +#include "Firestore/Source/Public/FIRFirestoreErrors.h" // for FIRFirestoreErrorDomain +#include "Firestore/core/include/firebase/firestore/firestore_errors.h" +#include "Firestore/core/src/firebase/firestore/util/string_apple.h" +#include "absl/strings/string_view.h" + +namespace firebase { +namespace firestore { +namespace util { + +// Translates a set of error_code and error_msg to an NSError. +inline NSError* WrapNSError(const int64_t error_code, + const absl::string_view error_msg) { + if (error_code == FirestoreErrorCode::Ok) { + return nil; + } + return [NSError + errorWithDomain:FIRFirestoreErrorDomain + code:error_code + userInfo:@{NSLocalizedDescriptionKey : WrapNSString(error_msg)}]; +} + +} // namespace util +} // namespace firestore +} // namespace firebase + +#endif // __OBJC__ + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_ERROR_APPLE_H_ diff --git a/Firestore/core/test/firebase/firestore/auth/credentials_provider_test.cc b/Firestore/core/test/firebase/firestore/auth/credentials_provider_test.cc index 9ae71ba..6895061 100644 --- a/Firestore/core/test/firebase/firestore/auth/credentials_provider_test.cc +++ b/Firestore/core/test/firebase/firestore/auth/credentials_provider_test.cc @@ -25,10 +25,11 @@ namespace auth { #define UNUSED(x) (void)(x) TEST(CredentialsProvider, Typedef) { - TokenListener token_listener = [](Token token, - const absl::string_view error) { + TokenListener token_listener = [](Token token, const int64_t error_code, + const absl::string_view error_msg) { UNUSED(token); - UNUSED(error); + UNUSED(error_code); + UNUSED(error_msg); }; EXPECT_NE(nullptr, token_listener); EXPECT_TRUE(token_listener); diff --git a/Firestore/core/test/firebase/firestore/auth/empty_credentials_provider_test.cc b/Firestore/core/test/firebase/firestore/auth/empty_credentials_provider_test.cc index 39012f0..3b487f3 100644 --- a/Firestore/core/test/firebase/firestore/auth/empty_credentials_provider_test.cc +++ b/Firestore/core/test/firebase/firestore/auth/empty_credentials_provider_test.cc @@ -25,12 +25,14 @@ namespace auth { TEST(EmptyCredentialsProvider, GetToken) { EmptyCredentialsProvider credentials_provider; credentials_provider.GetToken( - /*force_refresh=*/true, [](Token token, const absl::string_view error) { - EXPECT_EQ("", token.token()); + /*force_refresh=*/true, [](Token token, const int64_t error_code, + const absl::string_view error_msg) { + EXPECT_FALSE(token.is_valid()); const User& user = token.user(); EXPECT_EQ("", user.uid()); EXPECT_FALSE(user.is_authenticated()); - EXPECT_EQ("", error); + EXPECT_EQ(FirestoreErrorCode::Ok, error_code); + EXPECT_EQ("", error_msg); }); } diff --git a/Firestore/core/test/firebase/firestore/auth/firebase_credentials_provider_test.mm b/Firestore/core/test/firebase/firestore/auth/firebase_credentials_provider_test.mm index a6ccc4a..3660d53 100644 --- a/Firestore/core/test/firebase/firestore/auth/firebase_credentials_provider_test.mm +++ b/Firestore/core/test/firebase/firestore/auth/firebase_credentials_provider_test.mm @@ -42,12 +42,14 @@ TEST(FirebaseCredentialsProviderTest, GetTokenUnauthenticated) { FirebaseCredentialsProvider credentials_provider(app); credentials_provider.GetToken( - /*force_refresh=*/true, [](Token token, const absl::string_view error) { + /*force_refresh=*/true, [](Token token, const int64_t error_code, + const absl::string_view error_msg) { EXPECT_EQ("", token.token()); const User& user = token.user(); EXPECT_EQ("", user.uid()); EXPECT_FALSE(user.is_authenticated()); - EXPECT_EQ("", error) << error; + EXPECT_EQ(FirestoreErrorCode::Ok, error_code) << error_code; + EXPECT_EQ("", error_msg) << error_msg; }); } @@ -56,12 +58,14 @@ TEST(FirebaseCredentialsProviderTest, GetToken) { FirebaseCredentialsProvider credentials_provider(app); credentials_provider.GetToken( - /*force_refresh=*/true, [](Token token, const absl::string_view error) { + /*force_refresh=*/true, [](Token token, const int64_t error_code, + const absl::string_view error_msg) { EXPECT_EQ("", token.token()); const User& user = token.user(); EXPECT_EQ("fake uid", user.uid()); EXPECT_TRUE(user.is_authenticated()); - EXPECT_EQ("", error) << error; + EXPECT_EQ(FirestoreErrorCode::Ok, error_code) << error_code; + EXPECT_EQ("", error_msg) << error_msg; }); } -- cgit v1.2.3