1212// See the License for the specific language governing permissions and
1313// limitations under the License.
1414
15- import FirebaseCore
1615import Foundation
1716
1817private let kHttpsProtocol = " https: "
1918private let kHttpProtocol = " http: "
20- // Legacy GCIP v1 hosts
19+
20+ private let kEmulatorHostAndPrefixFormat = " %@/%@ "
21+
22+ /// Host for server API calls. This should be changed via
23+ /// `IdentityToolkitRequest.setHost(_ host:)` for testing purposes only.
24+ private nonisolated ( unsafe) var gAPIHost = " www.googleapis.com "
25+
2126private let kFirebaseAuthAPIHost = " www.googleapis.com "
27+ private let kIdentityPlatformAPIHost = " identitytoolkit.googleapis.com "
28+ private let kRegionalGCIPAPIHost = " identityplatform.googleapis.com " // Regional R-GCIP v2 hosts
29+
2230private let kFirebaseAuthStagingAPIHost = " staging-www.sandbox.googleapis.com "
23- // Regional R-GCIP v2 hosts
24- private let kRegionalGCIPAPIHost = " identityplatform.googleapis.com "
25- private let kRegionalGCIPStagingAPIHost = " staging-identityplatform.sandbox.googleapis.com "
26- #if compiler(>=6)
27- private nonisolated ( unsafe) var gAPIHost = " www.googleapis.com "
28- #else
29- private var gAPIHost = " www.googleapis.com "
30- #endif
31-
32- /// Represents a request to an Identity Toolkit endpoint, routing either to
33- /// legacy GCIP v1 or regionalized R-GCIP v2 based on presence of tenantID.
31+ private let kIdentityPlatformStagingAPIHost =
32+ " staging-identitytoolkit.sandbox.googleapis.com "
33+ private let kRegionalGCIPStagingAPIHost =
34+ " staging-identityplatform.sandbox.googleapis.com " // Regional R-GCIP v2 hosts
35+
36+ /// Represents a request to an identity toolkit endpoint routing either to legacy GCIP or
37+ /// regionalized R-GCIP
3438@available ( iOS 13 , tvOS 13 , macOS 10 . 15 , macCatalyst 13 , watchOS 7 , * )
3539class IdentityToolkitRequest {
36- /// RPC endpoint name, e.g. "signInWithPassword" or full exchange path
40+ /// Gets the RPC's endpoint.
3741 let endpoint : String
42+
3843 /// Gets the client's API key used for the request.
3944 var apiKey : String
40- /// The tenant ID of the request. nil if none is available.
45+
46+ /// The tenant ID of the request. nil if none is available (not for r-gcip).
4147 let tenantID : String ?
48+
4249 /// The toggle of using Identity Platform endpoints.
4350 let useIdentityPlatform : Bool
51+
4452 /// The toggle of using staging endpoints.
4553 let useStaging : Bool
54+
4655 /// The type of the client that the request sent from, which should be CLIENT_TYPE_IOS;
4756 var clientType : String
4857
49- /// Optional local emulator host and port
50- var emulatorHostAndPort : String ? {
51- return _requestConfiguration. emulatorHostAndPort
52- }
53-
5458 private let _requestConfiguration : AuthRequestConfiguration
59+
5560 init ( endpoint: String , requestConfiguration: AuthRequestConfiguration ,
5661 useIdentityPlatform: Bool = false , useStaging: Bool = false ) {
5762 self . endpoint = endpoint
@@ -63,75 +68,79 @@ class IdentityToolkitRequest {
6368 tenantID = requestConfiguration. auth? . tenantID
6469 }
6570
66- /// Override this if you need query parameters (default none)
6771 func queryParams( ) -> String {
6872 return " "
6973 }
7074
71- /// Provide the same configuration for AuthBackend
72- func requestConfiguration( ) -> AuthRequestConfiguration {
73- return _requestConfiguration
74- }
75-
76- /// Build the full URL, branching on whether tenantID is set.
75+ /// Returns the request's full URL.
7776 func requestURL( ) -> URL {
78- let protocolScheme : String
79- let hostPrefix : String
77+ let apiProtocol : String
78+ let apiHostAndPathPrefix : String
8079 let urlString : String
81-
82- // R-GCIP v2 if location AND tenantID from requestConfiguration are non-nil.
80+ let emulatorHostAndPort = _requestConfiguration . emulatorHostAndPort
81+ /// R-GCIP
8382 if let region = _requestConfiguration. location,
8483 let tenant = _requestConfiguration. tenantId, // Use tenantId from requestConfiguration
8584 !region. isEmpty,
8685 !tenant. isEmpty {
8786 let projectID = _requestConfiguration. auth? . app? . options. projectID
8887 // Choose emulator, staging, or prod host
89- if let emu = emulatorHostAndPort {
90- protocolScheme = kHttpProtocol
91- hostPrefix = " \( emu ) / \( kRegionalGCIPAPIHost) "
88+ if let emulatorHostAndPort = emulatorHostAndPort {
89+ apiProtocol = kHttpProtocol
90+ apiHostAndPathPrefix = " \( emulatorHostAndPort ) / \( kRegionalGCIPAPIHost) "
9291 } else if useStaging {
93- protocolScheme = kHttpsProtocol
94- hostPrefix = kRegionalGCIPStagingAPIHost
92+ apiProtocol = kHttpsProtocol
93+ apiHostAndPathPrefix = kRegionalGCIPStagingAPIHost
9594 } else {
96- protocolScheme = kHttpsProtocol
97- hostPrefix = kRegionalGCIPAPIHost
95+ apiProtocol = kHttpsProtocol
96+ apiHostAndPathPrefix = kRegionalGCIPAPIHost
9897 }
99-
100- // Regionalized v2 path
10198 urlString =
102- " \( protocolScheme ) // \( hostPrefix ) /v2/projects/ \( projectID ?? " projectID " ) "
99+ " \( apiProtocol ) // \( apiHostAndPathPrefix ) /v2/projects/ \( projectID ?? " projectID " ) "
103100 + " /locations/ \( region) /tenants/ \( tenant) /idpConfigs/ \( endpoint) ?key= \( apiKey) "
101+ }
102+ // legacy gcip existing logic
103+ else if useIdentityPlatform {
104+ if let emulatorHostAndPort = emulatorHostAndPort {
105+ apiProtocol = kHttpProtocol
106+ apiHostAndPathPrefix = " \( emulatorHostAndPort) / \( kIdentityPlatformAPIHost) "
107+ } else if useStaging {
108+ apiHostAndPathPrefix = kIdentityPlatformStagingAPIHost
109+ apiProtocol = kHttpsProtocol
110+ } else {
111+ apiHostAndPathPrefix = kIdentityPlatformAPIHost
112+ apiProtocol = kHttpsProtocol
113+ }
114+ urlString = " \( apiProtocol) // \( apiHostAndPathPrefix) /v2/ \( endpoint) ?key= \( apiKey) "
104115
105116 } else {
106- // Legacy GCIP v1 branch
107- if let emu = emulatorHostAndPort {
108- protocolScheme = kHttpProtocol
109- hostPrefix = " \( emu) / \( kFirebaseAuthAPIHost) "
117+ if let emulatorHostAndPort = emulatorHostAndPort {
118+ apiProtocol = kHttpProtocol
119+ apiHostAndPathPrefix = " \( emulatorHostAndPort) / \( kFirebaseAuthAPIHost) "
110120 } else if useStaging {
111- protocolScheme = kHttpsProtocol
112- hostPrefix = kFirebaseAuthStagingAPIHost
121+ apiProtocol = kHttpsProtocol
122+ apiHostAndPathPrefix = kFirebaseAuthStagingAPIHost
113123 } else {
114- protocolScheme = kHttpsProtocol
115- hostPrefix = kFirebaseAuthAPIHost
124+ apiProtocol = kHttpsProtocol
125+ apiHostAndPathPrefix = kFirebaseAuthAPIHost
116126 }
117127 urlString =
118- " \( protocolScheme) // \( hostPrefix) " +
119- " /identitytoolkit/v3/relyingparty/ \( endpoint) ?key= \( apiKey) "
128+ " \( apiProtocol) // \( apiHostAndPathPrefix) /identitytoolkit/v3/relyingparty/ \( endpoint) ?key= \( apiKey) "
120129 }
121130 guard let returnURL = URL ( string: " \( urlString) \( queryParams ( ) ) " ) else {
122131 fatalError ( " Internal Auth error: Failed to generate URL for \( urlString) " )
123132 }
124133 return returnURL
125134 }
126135
127- // MARK: - Testing API
128-
129- /// For testing: override the global host for legacy flows
130- static var host : String {
131- get { gAPIHost }
132- set { gAPIHost = newValue }
136+ /// Returns the request's configuration.
137+ func requestConfiguration( ) -> AuthRequestConfiguration {
138+ _requestConfiguration
133139 }
134140
141+ // MARK: Internal API for development
142+
143+ static var host : String { gAPIHost }
135144 static func setHost( _ host: String ) {
136145 gAPIHost = host
137146 }
0 commit comments