diff --git a/auth/src/android/auth_android.cc b/auth/src/android/auth_android.cc index 965db474a4..afbe82af75 100644 --- a/auth/src/android/auth_android.cc +++ b/auth/src/android/auth_android.cc @@ -188,11 +188,19 @@ void UpdateCurrentUser(AuthData* auth_data) { } } +void SetEmulatorJni(AuthData* auth_data, const char* host, uint32_t port) { + JNIEnv* env = Env(auth_data); + + jstring j_host = env->NewStringUTF(host); + env->CallVoidMethod(AuthImpl(auth_data), + auth::GetMethodId(auth::kUseEmulator), j_host, port); + env->DeleteLocalRef(j_host); + firebase::util::CheckAndClearJniExceptions(env); +} + const char* const kEmulatorLocalHost = "10.0.2.2"; const char* const kEmulatorPort = "9099"; void CheckEmulator(AuthData* auth_data) { - JNIEnv* env = Env(auth_data); - // Use emulator as long as this env variable is set, regardless its value. if (std::getenv("USE_AUTH_EMULATOR") == nullptr) { LogInfo("Using Auth Prod for testing."); @@ -207,12 +215,7 @@ void CheckEmulator(AuthData* auth_data) { if (std::getenv("AUTH_EMULATOR_PORT") != nullptr) { port = std::stoi(std::getenv("AUTH_EMULATOR_PORT")); } - - jstring j_host = env->NewStringUTF(kEmulatorLocalHost); - env->CallVoidMethod(AuthImpl(auth_data), - auth::GetMethodId(auth::kUseEmulator), j_host, port); - env->DeleteLocalRef(j_host); - firebase::util::CheckAndClearJniExceptions(env); + SetEmulatorJni(auth_data, kEmulatorLocalHost, port); } // Release cached Java classes. @@ -828,6 +831,10 @@ Future Auth::SendPasswordResetEmail(const char* email) { return MakeFuture(&futures, handle); } +void Auth::UseEmulator(std::string host, uint32_t port) { + SetEmulatorJni(auth_data_, host.c_str(), port); +} + // Not implemented for Android. void EnableTokenAutoRefresh(AuthData* auth_data) {} void DisableTokenAutoRefresh(AuthData* auth_data) {} diff --git a/auth/src/desktop/auth_desktop.cc b/auth/src/desktop/auth_desktop.cc index b0d5bcbd19..7d3a388baf 100644 --- a/auth/src/desktop/auth_desktop.cc +++ b/auth/src/desktop/auth_desktop.cc @@ -715,6 +715,14 @@ void Auth::UseAppLanguage() { auth_impl->language_code.assign(empty_string); } +void Auth::UseEmulator(std::string host, uint32_t port) { + auto auth_impl = static_cast(auth_data_->auth_impl); + auth_impl->assigned_emulator_url = ""; + auth_impl->assigned_emulator_url.append(host); + auth_impl->assigned_emulator_url.append(":"); + auth_impl->assigned_emulator_url.append(std::to_string(port)); +} + void InitializeTokenRefresher(AuthData* auth_data) { auto auth_impl = static_cast(auth_data->auth_impl); auth_impl->token_refresh_thread.Initialize(auth_data); diff --git a/auth/src/desktop/auth_desktop.h b/auth/src/desktop/auth_desktop.h index 2d407cab16..ac3c010942 100644 --- a/auth/src/desktop/auth_desktop.h +++ b/auth/src/desktop/auth_desktop.h @@ -188,6 +188,8 @@ struct AuthImpl { // The current user language code. This can be set to the app’s current // language by calling SetLanguageCode. std::string language_code; + + std::string assigned_emulator_url; }; // Constant, describing how often we automatically fetch a new auth token. diff --git a/auth/src/desktop/rpcs/auth_request.cc b/auth/src/desktop/rpcs/auth_request.cc index 77fb7ea07c..a4f4b9dd3b 100644 --- a/auth/src/desktop/rpcs/auth_request.cc +++ b/auth/src/desktop/rpcs/auth_request.cc @@ -23,6 +23,8 @@ #include "app/src/heartbeat/heartbeat_controller_desktop.h" #include "app/src/include/firebase/app.h" #include "app/src/include/firebase/internal/mutex.h" +#include "auth/src/desktop/auth_desktop.h" +#include "auth/src/include/firebase/auth.h" #include "firebase/log.h" namespace firebase { @@ -33,39 +35,9 @@ const char* kHeaderFirebaseLocale = "X-Firebase-Locale"; AuthRequest::AuthRequest(::firebase::App& app, const char* schema, bool deliver_heartbeat) - : RequestJson(schema) { - // The user agent strings are cached in static variables here to avoid - // dependencies upon other parts of this library. This complication is due to - // the way the tests are currently configured where each library has minimal - // dependencies. + : RequestJson(schema), app(app) { + CheckEnvEmulator(); - CheckEmulator(); - static std::string auth_user_agent; // NOLINT - static std::string extended_auth_user_agent; // NOLINT - static Mutex* user_agent_mutex = new Mutex(); - MutexLock lock(*user_agent_mutex); - if (auth_user_agent.empty()) { - std::string sdk; - std::string version; - app_common::GetOuterMostSdkAndVersion(&sdk, &version); - // Set the user agent similar to the iOS SDK. Format: - // FirebaseAuth./ - assert(!(sdk.empty() || version.empty())); - std::string sdk_type(sdk.substr(sizeof(FIREBASE_USER_AGENT_PREFIX) - 1)); - auth_user_agent = std::string("FirebaseAuth.") + sdk_type + "/" + version; - // Generage the extended header to set the format specified by b/28531026 - // and b/64693042 to include the platform and framework. - // /// - // where is '(FirebaseCore|FirebaseUI)'. - extended_auth_user_agent = std::string(app_common::kOperatingSystem) + "/" + - sdk + "/" + version + "/" + "FirebaseCore-" + - sdk_type; - } - // TODO(b/244643516): Remove the User-Agent and X-Client-Version headers. - if (!auth_user_agent.empty()) { - add_header("User-Agent", auth_user_agent.c_str()); - add_header("X-Client-Version", extended_auth_user_agent.c_str()); - } if (deliver_heartbeat) { std::shared_ptr heartbeat_controller = app.GetHeartbeatController(); @@ -81,6 +53,17 @@ AuthRequest::AuthRequest(::firebase::App& app, const char* schema, } std::string AuthRequest::GetUrl() { + std::string emulator_url; + Auth* auth_ptr = Auth::GetAuth(&app); + std::string assigned_emulator_url = + static_cast(auth_ptr->auth_data_->auth_impl) + ->assigned_emulator_url; + if (assigned_emulator_url.empty()) { + emulator_url = env_emulator_url; + } else { + emulator_url = assigned_emulator_url; + } + if (emulator_url.empty()) { std::string url(kHttps); url += kServerURL; @@ -94,25 +77,26 @@ std::string AuthRequest::GetUrl() { } } -void AuthRequest::CheckEmulator() { - if (!emulator_url.empty()) { - LogInfo("Emulator Url already set: %s", emulator_url.c_str()); +void AuthRequest::CheckEnvEmulator() { + if (!env_emulator_url.empty()) { + LogInfo("Environment Emulator Url already set: %s", + env_emulator_url.c_str()); return; } + // Use emulator as long as this env variable is set, regardless its value. if (std::getenv("USE_AUTH_EMULATOR") == nullptr) { - LogInfo("Using Auth Prod for testing."); + LogInfo("USE_AUTH_EMULATOR not set."); return; } - LogInfo("Using Auth Emulator."); - emulator_url.append(kEmulatorLocalHost); - emulator_url.append(":"); + env_emulator_url.append(kEmulatorLocalHost); + env_emulator_url.append(":"); // Use AUTH_EMULATOR_PORT if it is set to non empty string, // otherwise use the default port. if (std::getenv("AUTH_EMULATOR_PORT") == nullptr) { - emulator_url.append(kEmulatorPort); + env_emulator_url.append(kEmulatorPort); } else { - emulator_url.append(std::getenv("AUTH_EMULATOR_PORT")); + env_emulator_url.append(std::getenv("AUTH_EMULATOR_PORT")); } } diff --git a/auth/src/desktop/rpcs/auth_request.h b/auth/src/desktop/rpcs/auth_request.h index 88835e946c..889e04aea7 100644 --- a/auth/src/desktop/rpcs/auth_request.h +++ b/auth/src/desktop/rpcs/auth_request.h @@ -55,8 +55,9 @@ class AuthRequest std::string GetUrl(); private: - void CheckEmulator(); - std::string emulator_url; + void CheckEnvEmulator(); + std::string env_emulator_url; + ::firebase::App& app; }; } // namespace auth diff --git a/auth/src/include/firebase/auth.h b/auth/src/include/firebase/auth.h index f9c8bfbf36..9fdab7810b 100644 --- a/auth/src/include/firebase/auth.h +++ b/auth/src/include/firebase/auth.h @@ -45,6 +45,7 @@ struct AuthData; class AuthStateListener; class IdTokenListener; class PhoneAuthProvider; +class AuthRequest; struct AuthCompletionHandle; struct AuthResultCompletionHandle; class FederatedAuthProvider; @@ -631,6 +632,14 @@ class Auth { void RemoveIdTokenListener(IdTokenListener* listener); #endif // not SWIG +#if !defined(DOXYGEN) && !defined(SWIG) + /// + /// Modify this Auth instance to communicate with the Firebase Authentication + /// emulator. + /// + void UseEmulator(std::string host, uint32_t port); +#endif //! defined(DOXYGEN), to hide the api from public documentation. + /// Gets the App this auth object is connected to. App& app(); @@ -653,6 +662,7 @@ class Auth { /// @cond FIREBASE_APP_INTERNAL friend class ::firebase::App; friend class ::firebase::auth::PhoneAuthProvider; + friend class ::firebase::auth::AuthRequest; friend class IdTokenRefreshListener; friend class IdTokenRefreshThread; friend class UserDataPersist; diff --git a/auth/src/ios/auth_ios.mm b/auth/src/ios/auth_ios.mm index 323a1c633a..4b77c1ae9b 100644 --- a/auth/src/ios/auth_ios.mm +++ b/auth/src/ios/auth_ios.mm @@ -157,6 +157,11 @@ void UpdateCurrentUser(AuthData *auth_data) { SetUserImpl(auth_data, user); } +void SetEmulatorJni(AuthData *auth_data, const char *host, uint32_t port) { + NSUInteger ns_port = port; + [AuthImpl(auth_data) useEmulatorWithHost:@(host) port:ns_port]; +} + void CheckEmulator(AuthData *auth_data) { // Use emulator as long as this env variable is set, regardless its value. if (std::getenv("USE_AUTH_EMULATOR") == nullptr) { @@ -171,8 +176,7 @@ void CheckEmulator(AuthData *auth_data) { port = std::stoi(std::getenv("AUTH_EMULATOR_PORT")); } - NSUInteger ns_port = port; - [AuthImpl(auth_data) useEmulatorWithHost:@(kEmulatorLocalHost) port:ns_port]; + SetEmulatorJni(auth_data, kEmulatorLocalHost, port); } // Platform-specific method to initialize AuthData. @@ -699,6 +703,10 @@ void SignInResultCallback(FIRAuthDataResult *_Nullable auth_result, NSError *_Nu return MakeFuture(&futures, handle); } +void Auth::UseEmulator(std::string host, uint32_t port) { + SetEmulatorJni(auth_data_, host.c_str(), port); +} + // Remap iOS SDK errors reported by the UIDelegate. While these errors seem like // user interaction errors, they are actually caused by bad provider ids. NSError *RemapBadProviderIDErrors(NSError *_Nonnull error) {