diff --git a/PRTY.xcodeproj/project.pbxproj b/PRTY.xcodeproj/project.pbxproj index 94bb980..419cac6 100644 --- a/PRTY.xcodeproj/project.pbxproj +++ b/PRTY.xcodeproj/project.pbxproj @@ -7,13 +7,21 @@ objects = { /* Begin PBXBuildFile section */ + 010E02BF2A4F92BA006608F9 /* textFieldStyles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 010E02BE2A4F92BA006608F9 /* textFieldStyles.swift */; }; 0112F5E0291742BF003338FA /* PRTYApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0112F5DF291742BF003338FA /* PRTYApp.swift */; }; - 0112F5E2291742BF003338FA /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0112F5E1291742BF003338FA /* ContentView.swift */; }; 0112F5E4291742C1003338FA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0112F5E3291742C1003338FA /* Assets.xcassets */; }; 0112F5E7291742C1003338FA /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0112F5E6291742C1003338FA /* Preview Assets.xcassets */; }; 0112F5F1291742C1003338FA /* PRTYTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0112F5F0291742C1003338FA /* PRTYTests.swift */; }; 0112F5FB291742C1003338FA /* PRTYUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0112F5FA291742C1003338FA /* PRTYUITests.swift */; }; 0112F5FD291742C1003338FA /* PRTYUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0112F5FC291742C1003338FA /* PRTYUITestsLaunchTests.swift */; }; + 013CF3FE292E9B7700A2EA77 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 013CF3FD292E9B7700A2EA77 /* GoogleService-Info.plist */; }; + 017C542D2A36662B002FAD55 /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 017C542C2A36662B002FAD55 /* HomeView.swift */; }; + 017C54312A366A57002FAD55 /* StartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 017C54302A366A57002FAD55 /* StartView.swift */; }; + 01A4659129785E9700CA3AA5 /* loginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01A4659029785E9700CA3AA5 /* loginView.swift */; }; + 01F08C77293985CA00C79488 /* SignUpView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F08C76293985CA00C79488 /* SignUpView.swift */; }; + 1C6A2402ECC5A061ECD961C2 /* Pods_PRTY.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AF49E55A3A1C1E6E8D04E46E /* Pods_PRTY.framework */; }; + 760C9AB6F1B7C7AA667C0B9C /* Pods_PRTYTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51DB5661152EFE18FD727B0E /* Pods_PRTYTests.framework */; }; + AC2BE6971713AC8487FE62CB /* Pods_PRTY_PRTYUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 70154487C5B29D1158558372 /* Pods_PRTY_PRTYUITests.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -34,9 +42,9 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 010E02BE2A4F92BA006608F9 /* textFieldStyles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = textFieldStyles.swift; sourceTree = ""; }; 0112F5DC291742BF003338FA /* PRTY.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PRTY.app; sourceTree = BUILT_PRODUCTS_DIR; }; 0112F5DF291742BF003338FA /* PRTYApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PRTYApp.swift; sourceTree = ""; }; - 0112F5E1291742BF003338FA /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 0112F5E3291742C1003338FA /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 0112F5E6291742C1003338FA /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 0112F5EC291742C1003338FA /* PRTYTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PRTYTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -44,6 +52,20 @@ 0112F5F6291742C1003338FA /* PRTYUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PRTYUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 0112F5FA291742C1003338FA /* PRTYUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PRTYUITests.swift; sourceTree = ""; }; 0112F5FC291742C1003338FA /* PRTYUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PRTYUITestsLaunchTests.swift; sourceTree = ""; }; + 013CF3FD292E9B7700A2EA77 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; + 017C542C2A36662B002FAD55 /* HomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeView.swift; sourceTree = ""; }; + 017C54302A366A57002FAD55 /* StartView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartView.swift; sourceTree = ""; }; + 01A4659029785E9700CA3AA5 /* loginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = loginView.swift; sourceTree = ""; }; + 01F08C76293985CA00C79488 /* SignUpView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpView.swift; sourceTree = ""; }; + 3085B5D369EBF5FC85FD620B /* Pods-PRTY-PRTYUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PRTY-PRTYUITests.release.xcconfig"; path = "Target Support Files/Pods-PRTY-PRTYUITests/Pods-PRTY-PRTYUITests.release.xcconfig"; sourceTree = ""; }; + 3708BC20144655197B13ED57 /* Pods-PRTYTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PRTYTests.debug.xcconfig"; path = "Target Support Files/Pods-PRTYTests/Pods-PRTYTests.debug.xcconfig"; sourceTree = ""; }; + 51DB5661152EFE18FD727B0E /* Pods_PRTYTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PRTYTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 70154487C5B29D1158558372 /* Pods_PRTY_PRTYUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PRTY_PRTYUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 976E744F962D662B83CAE853 /* Pods-PRTY.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PRTY.release.xcconfig"; path = "Target Support Files/Pods-PRTY/Pods-PRTY.release.xcconfig"; sourceTree = ""; }; + 98F4A9C1FADACC23BF0AA15E /* Pods-PRTY.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PRTY.debug.xcconfig"; path = "Target Support Files/Pods-PRTY/Pods-PRTY.debug.xcconfig"; sourceTree = ""; }; + AF49E55A3A1C1E6E8D04E46E /* Pods_PRTY.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PRTY.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + F54E4A253095805DBE9393BE /* Pods-PRTY-PRTYUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PRTY-PRTYUITests.debug.xcconfig"; path = "Target Support Files/Pods-PRTY-PRTYUITests/Pods-PRTY-PRTYUITests.debug.xcconfig"; sourceTree = ""; }; + F5F03EDD8846081D906A507C /* Pods-PRTYTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PRTYTests.release.xcconfig"; path = "Target Support Files/Pods-PRTYTests/Pods-PRTYTests.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -51,6 +73,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 1C6A2402ECC5A061ECD961C2 /* Pods_PRTY.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -58,6 +81,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 760C9AB6F1B7C7AA667C0B9C /* Pods_PRTYTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -65,12 +89,21 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + AC2BE6971713AC8487FE62CB /* Pods_PRTY_PRTYUITests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 010E02BD2A4F929F006608F9 /* Styles */ = { + isa = PBXGroup; + children = ( + 010E02BE2A4F92BA006608F9 /* textFieldStyles.swift */, + ); + path = Styles; + sourceTree = ""; + }; 0112F5D3291742BF003338FA = { isa = PBXGroup; children = ( @@ -78,6 +111,8 @@ 0112F5EF291742C1003338FA /* PRTYTests */, 0112F5F9291742C1003338FA /* PRTYUITests */, 0112F5DD291742BF003338FA /* Products */, + 1E4755DF18DBE7808BD38C1E /* Pods */, + 9EE010910841684EDC6DD71D /* Frameworks */, ); sourceTree = ""; }; @@ -95,7 +130,10 @@ isa = PBXGroup; children = ( 0112F5DF291742BF003338FA /* PRTYApp.swift */, - 0112F5E1291742BF003338FA /* ContentView.swift */, + 010E02BD2A4F929F006608F9 /* Styles */, + 01BA1C1F2A3BBEA500CDECCF /* models */, + 01912C742970BD9200DCB16C /* Views */, + 013CF3FD292E9B7700A2EA77 /* GoogleService-Info.plist */, 0112F5E3291742C1003338FA /* Assets.xcassets */, 0112F5E5291742C1003338FA /* Preview Content */, ); @@ -127,6 +165,55 @@ path = PRTYUITests; sourceTree = ""; }; + 01382EDA29D8CA9900F9D808 /* auth */ = { + isa = PBXGroup; + children = ( + ); + path = auth; + sourceTree = ""; + }; + 01912C742970BD9200DCB16C /* Views */ = { + isa = PBXGroup; + children = ( + 01A4659029785E9700CA3AA5 /* loginView.swift */, + 017C54302A366A57002FAD55 /* StartView.swift */, + 017C542C2A36662B002FAD55 /* HomeView.swift */, + 01F08C76293985CA00C79488 /* SignUpView.swift */, + ); + path = Views; + sourceTree = ""; + }; + 01BA1C1F2A3BBEA500CDECCF /* models */ = { + isa = PBXGroup; + children = ( + 01382EDA29D8CA9900F9D808 /* auth */, + ); + path = models; + sourceTree = ""; + }; + 1E4755DF18DBE7808BD38C1E /* Pods */ = { + isa = PBXGroup; + children = ( + 98F4A9C1FADACC23BF0AA15E /* Pods-PRTY.debug.xcconfig */, + 976E744F962D662B83CAE853 /* Pods-PRTY.release.xcconfig */, + F54E4A253095805DBE9393BE /* Pods-PRTY-PRTYUITests.debug.xcconfig */, + 3085B5D369EBF5FC85FD620B /* Pods-PRTY-PRTYUITests.release.xcconfig */, + 3708BC20144655197B13ED57 /* Pods-PRTYTests.debug.xcconfig */, + F5F03EDD8846081D906A507C /* Pods-PRTYTests.release.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; + 9EE010910841684EDC6DD71D /* Frameworks */ = { + isa = PBXGroup; + children = ( + AF49E55A3A1C1E6E8D04E46E /* Pods_PRTY.framework */, + 70154487C5B29D1158558372 /* Pods_PRTY_PRTYUITests.framework */, + 51DB5661152EFE18FD727B0E /* Pods_PRTYTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -134,9 +221,11 @@ isa = PBXNativeTarget; buildConfigurationList = 0112F600291742C1003338FA /* Build configuration list for PBXNativeTarget "PRTY" */; buildPhases = ( + B8CF73D9741513B8E6185057 /* [CP] Check Pods Manifest.lock */, 0112F5D8291742BF003338FA /* Sources */, 0112F5D9291742BF003338FA /* Frameworks */, 0112F5DA291742BF003338FA /* Resources */, + FC83BF8D2AD1F1ABC47CA746 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -151,6 +240,7 @@ isa = PBXNativeTarget; buildConfigurationList = 0112F603291742C1003338FA /* Build configuration list for PBXNativeTarget "PRTYTests" */; buildPhases = ( + 88791294738670A39CE95709 /* [CP] Check Pods Manifest.lock */, 0112F5E8291742C1003338FA /* Sources */, 0112F5E9291742C1003338FA /* Frameworks */, 0112F5EA291742C1003338FA /* Resources */, @@ -169,9 +259,11 @@ isa = PBXNativeTarget; buildConfigurationList = 0112F606291742C1003338FA /* Build configuration list for PBXNativeTarget "PRTYUITests" */; buildPhases = ( + 17896F4EBC251F4DA44A72EA /* [CP] Check Pods Manifest.lock */, 0112F5F2291742C1003338FA /* Sources */, 0112F5F3291742C1003338FA /* Frameworks */, 0112F5F4291742C1003338FA /* Resources */, + 8BCDB3BB706FB9E320A1EA19 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -215,6 +307,9 @@ Base, ); mainGroup = 0112F5D3291742BF003338FA; + packageReferences = ( + 0112F609291744A5003338FA /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */, + ); productRefGroup = 0112F5DD291742BF003338FA /* Products */; projectDirPath = ""; projectRoot = ""; @@ -233,6 +328,7 @@ files = ( 0112F5E7291742C1003338FA /* Preview Assets.xcassets in Resources */, 0112F5E4291742C1003338FA /* Assets.xcassets in Resources */, + 013CF3FE292E9B7700A2EA77 /* GoogleService-Info.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -252,13 +348,120 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 17896F4EBC251F4DA44A72EA /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-PRTY-PRTYUITests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 88791294738670A39CE95709 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-PRTYTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 8BCDB3BB706FB9E320A1EA19 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-PRTY-PRTYUITests/Pods-PRTY-PRTYUITests-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-PRTY-PRTYUITests/Pods-PRTY-PRTYUITests-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-PRTY-PRTYUITests/Pods-PRTY-PRTYUITests-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + B8CF73D9741513B8E6185057 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-PRTY-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + FC83BF8D2AD1F1ABC47CA746 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-PRTY/Pods-PRTY-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-PRTY/Pods-PRTY-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-PRTY/Pods-PRTY-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 0112F5D8291742BF003338FA /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 0112F5E2291742BF003338FA /* ContentView.swift in Sources */, 0112F5E0291742BF003338FA /* PRTYApp.swift in Sources */, + 01A4659129785E9700CA3AA5 /* loginView.swift in Sources */, + 017C542D2A36662B002FAD55 /* HomeView.swift in Sources */, + 010E02BF2A4F92BA006608F9 /* textFieldStyles.swift in Sources */, + 01F08C77293985CA00C79488 /* SignUpView.swift in Sources */, + 017C54312A366A57002FAD55 /* StartView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -411,6 +614,7 @@ }; 0112F601291742C1003338FA /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 98F4A9C1FADACC23BF0AA15E /* Pods-PRTY.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; @@ -439,6 +643,7 @@ }; 0112F602291742C1003338FA /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 976E744F962D662B83CAE853 /* Pods-PRTY.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; @@ -467,6 +672,7 @@ }; 0112F604291742C1003338FA /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 3708BC20144655197B13ED57 /* Pods-PRTYTests.debug.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; @@ -486,6 +692,7 @@ }; 0112F605291742C1003338FA /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = F5F03EDD8846081D906A507C /* Pods-PRTYTests.release.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; @@ -505,6 +712,7 @@ }; 0112F607291742C1003338FA /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = F54E4A253095805DBE9393BE /* Pods-PRTY-PRTYUITests.debug.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; @@ -522,6 +730,7 @@ }; 0112F608291742C1003338FA /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 3085B5D369EBF5FC85FD620B /* Pods-PRTY-PRTYUITests.release.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; @@ -577,6 +786,17 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + 0112F609291744A5003338FA /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/firebase/firebase-ios-sdk"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 9.0.0; + }; + }; +/* End XCRemoteSwiftPackageReference section */ }; rootObject = 0112F5D4291742BF003338FA /* Project object */; } diff --git a/PRTY.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/PRTY.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000..e90206a --- /dev/null +++ b/PRTY.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,113 @@ +{ + "pins" : [ + { + "identity" : "abseil-cpp-swiftpm", + "kind" : "remoteSourceControl", + "location" : "https://github.com/firebase/abseil-cpp-SwiftPM.git", + "state" : { + "revision" : "d302de612e3d57c6f4afaf087da18fba8eac72a7", + "version" : "0.20220203.1" + } + }, + { + "identity" : "boringssl-swiftpm", + "kind" : "remoteSourceControl", + "location" : "https://github.com/firebase/boringssl-SwiftPM.git", + "state" : { + "revision" : "79db6516894a932d0ddaff3b05b9da1e4f6c4069", + "version" : "0.9.0" + } + }, + { + "identity" : "firebase-ios-sdk", + "kind" : "remoteSourceControl", + "location" : "https://github.com/firebase/firebase-ios-sdk", + "state" : { + "revision" : "7e80c25b51c2ffa238879b07fbfc5baa54bb3050", + "version" : "9.6.0" + } + }, + { + "identity" : "googleappmeasurement", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/GoogleAppMeasurement.git", + "state" : { + "revision" : "c1cfde8067668027b23a42c29d11c246152fe046", + "version" : "9.6.0" + } + }, + { + "identity" : "googledatatransport", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/GoogleDataTransport.git", + "state" : { + "revision" : "b905c49326b72211531ed9d7baa02d724828a8dc", + "version" : "9.1.4" + } + }, + { + "identity" : "googleutilities", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/GoogleUtilities.git", + "state" : { + "revision" : "f4abe56ce62a779e64b525eb133c8fc2a84bbc1f", + "version" : "7.7.1" + } + }, + { + "identity" : "grpc-ios", + "kind" : "remoteSourceControl", + "location" : "https://github.com/grpc/grpc-ios.git", + "state" : { + "revision" : "2af4f6e9c2b18beae228f50b1198c641be859d2b", + "version" : "1.44.2-grpc" + } + }, + { + "identity" : "gtm-session-fetcher", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/gtm-session-fetcher.git", + "state" : { + "revision" : "19605024d59eaefdb1f6a2cb11ebe75df4421126", + "version" : "2.0.0" + } + }, + { + "identity" : "leveldb", + "kind" : "remoteSourceControl", + "location" : "https://github.com/firebase/leveldb.git", + "state" : { + "revision" : "0706abcc6b0bd9cedfbb015ba840e4a780b5159b", + "version" : "1.22.2" + } + }, + { + "identity" : "nanopb", + "kind" : "remoteSourceControl", + "location" : "https://github.com/firebase/nanopb.git", + "state" : { + "revision" : "819d0a2173aff699fb8c364b6fb906f7cdb1a692", + "version" : "2.30909.0" + } + }, + { + "identity" : "promises", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/promises.git", + "state" : { + "revision" : "3e4e743631e86c8c70dbc6efdc7beaa6e90fd3bb", + "version" : "2.1.1" + } + }, + { + "identity" : "swift-protobuf", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-protobuf.git", + "state" : { + "revision" : "e1499bc69b9040b29184f7f2996f7bab467c1639", + "version" : "1.19.0" + } + } + ], + "version" : 2 +} diff --git a/PRTY.xcodeproj/xcshareddata/xcschemes/PRTY.xcscheme b/PRTY.xcodeproj/xcshareddata/xcschemes/PRTY.xcscheme new file mode 100644 index 0000000..20474ec --- /dev/null +++ b/PRTY.xcodeproj/xcshareddata/xcschemes/PRTY.xcscheme @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/PRTY.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/PRTY.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000..384da8d --- /dev/null +++ b/PRTY.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,6 @@ + + + diff --git a/PRTY.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/xcschememanagement.plist b/PRTY.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/xcschememanagement.plist index 5842d34..79b0eb4 100644 --- a/PRTY.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/PRTY.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/xcschememanagement.plist @@ -6,9 +6,48 @@ PRTY.xcscheme_^#shared#^_ + orderHint + 1 + + Promises (Playground) 1.xcscheme + + isShown + + orderHint + 2 + + Promises (Playground) 2.xcscheme + + isShown + + orderHint + 3 + + Promises (Playground).xcscheme + + isShown + orderHint 0 + SuppressBuildableAutocreation + + 0112F5DB291742BF003338FA + + primary + + + 0112F5EB291742C1003338FA + + primary + + + 0112F5F5291742C1003338FA + + primary + + + diff --git a/PRTY.xcworkspace/contents.xcworkspacedata b/PRTY.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..a6b5dea --- /dev/null +++ b/PRTY.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/PRTY.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/PRTY.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/PRTY.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/PRTY.xcworkspace/xcshareddata/swiftpm/Package.resolved b/PRTY.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000..451ab6d --- /dev/null +++ b/PRTY.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,113 @@ +{ + "pins" : [ + { + "identity" : "abseil-cpp-swiftpm", + "kind" : "remoteSourceControl", + "location" : "https://github.com/firebase/abseil-cpp-SwiftPM.git", + "state" : { + "revision" : "583de9bd60f66b40e78d08599cc92036c2e7e4e1", + "version" : "0.20220203.2" + } + }, + { + "identity" : "boringssl-swiftpm", + "kind" : "remoteSourceControl", + "location" : "https://github.com/firebase/boringssl-SwiftPM.git", + "state" : { + "revision" : "dd3eda2b05a3f459fc3073695ad1b28659066eab", + "version" : "0.9.1" + } + }, + { + "identity" : "firebase-ios-sdk", + "kind" : "remoteSourceControl", + "location" : "https://github.com/firebase/firebase-ios-sdk", + "state" : { + "revision" : "7e80c25b51c2ffa238879b07fbfc5baa54bb3050", + "version" : "9.6.0" + } + }, + { + "identity" : "googleappmeasurement", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/GoogleAppMeasurement.git", + "state" : { + "revision" : "c1cfde8067668027b23a42c29d11c246152fe046", + "version" : "9.6.0" + } + }, + { + "identity" : "googledatatransport", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/GoogleDataTransport.git", + "state" : { + "revision" : "98a00258d4518b7521253a70b7f70bb76d2120fe", + "version" : "9.2.4" + } + }, + { + "identity" : "googleutilities", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/GoogleUtilities.git", + "state" : { + "revision" : "58d03d22beae762eaddbd30cb5a61af90d4b309f", + "version" : "7.11.3" + } + }, + { + "identity" : "grpc-ios", + "kind" : "remoteSourceControl", + "location" : "https://github.com/grpc/grpc-ios.git", + "state" : { + "revision" : "8440b914756e0d26d4f4d054a1c1581daedfc5b6", + "version" : "1.44.3-grpc" + } + }, + { + "identity" : "gtm-session-fetcher", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/gtm-session-fetcher.git", + "state" : { + "revision" : "5ccda3981422a84186387dbb763ba739178b529c", + "version" : "2.3.0" + } + }, + { + "identity" : "leveldb", + "kind" : "remoteSourceControl", + "location" : "https://github.com/firebase/leveldb.git", + "state" : { + "revision" : "0706abcc6b0bd9cedfbb015ba840e4a780b5159b", + "version" : "1.22.2" + } + }, + { + "identity" : "nanopb", + "kind" : "remoteSourceControl", + "location" : "https://github.com/firebase/nanopb.git", + "state" : { + "revision" : "819d0a2173aff699fb8c364b6fb906f7cdb1a692", + "version" : "2.30909.0" + } + }, + { + "identity" : "promises", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/promises.git", + "state" : { + "revision" : "ec957ccddbcc710ccc64c9dcbd4c7006fcf8b73a", + "version" : "2.2.0" + } + }, + { + "identity" : "swift-protobuf", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-protobuf.git", + "state" : { + "revision" : "f25867a208f459d3c5a06935dceb9083b11cd539", + "version" : "1.22.0" + } + } + ], + "version" : 2 +} diff --git a/PRTY.xcworkspace/xcuserdata/quinnbutcher.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/PRTY.xcworkspace/xcuserdata/quinnbutcher.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000..48ea6c9 --- /dev/null +++ b/PRTY.xcworkspace/xcuserdata/quinnbutcher.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,6 @@ + + + diff --git a/PRTY.xcworkspace/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/xcschememanagement.plist b/PRTY.xcworkspace/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..2b76c5f --- /dev/null +++ b/PRTY.xcworkspace/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,30 @@ + + + + + SchemeUserState + + Promises (Playground) 1.xcscheme + + isShown + + orderHint + 21 + + Promises (Playground) 2.xcscheme + + isShown + + orderHint + 22 + + Promises (Playground).xcscheme + + isShown + + orderHint + 20 + + + + diff --git a/PRTY/ContentView.swift b/PRTY/ContentView.swift deleted file mode 100644 index 2874c72..0000000 --- a/PRTY/ContentView.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// ContentView.swift -// PRTY -// -// Created by Quinn Butcher on 11/5/22. -// - -import SwiftUI - -struct ContentView: View { - var body: some View { - VStack { - Image(systemName: "globe") - .imageScale(.large) - .foregroundColor(.accentColor) - Text("Hello, world!") - } - .padding() - } -} - -struct ContentView_Previews: PreviewProvider { - static var previews: some View { - ContentView() - } -} diff --git a/PRTY/GoogleService-Info.plist b/PRTY/GoogleService-Info.plist new file mode 100644 index 0000000..42f10c3 --- /dev/null +++ b/PRTY/GoogleService-Info.plist @@ -0,0 +1,34 @@ + + + + + CLIENT_ID + 695418442783-dl0enahbpahsr4qioqg7rou5u5bsf7t5.apps.googleusercontent.com + REVERSED_CLIENT_ID + com.googleusercontent.apps.695418442783-dl0enahbpahsr4qioqg7rou5u5bsf7t5 + API_KEY + AIzaSyA6qAYFXCrY94fpcxEXxqj4I75v-QMCk4I + GCM_SENDER_ID + 695418442783 + PLIST_VERSION + 1 + BUNDLE_ID + QDB.PRTY + PROJECT_ID + prty-be49d + STORAGE_BUCKET + prty-be49d.appspot.com + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:695418442783:ios:df4ab68e47c276a639712a + + \ No newline at end of file diff --git a/PRTY/PRTYApp.swift b/PRTY/PRTYApp.swift index 4de2d8b..f6d0c8e 100644 --- a/PRTY/PRTYApp.swift +++ b/PRTY/PRTYApp.swift @@ -5,13 +5,55 @@ // Created by Quinn Butcher on 11/5/22. // + import SwiftUI +import Foundation +import FirebaseCore +import RealmSwift + +class AppDelegate: NSObject, UIApplicationDelegate { + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { + FirebaseApp.configure() + return true + } +} + + + @main -struct PRTYApp: App { +struct PRTYApp: SwiftUI.App { + @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate + + + + let app = App(id: "application-prty-vtmer") +// +// func loginToRealmAnonymous() { +// app.login(credentials: Credentials.anonymous) { (error) in +// print("Anonymous login to realm") +// DispatchQueue.main.sync { +// print("Realm login message: \(error)") +// let user = self.app.currentUser +// user?.logOut() { (error) in +// DispatchQueue.main.sync { +// print("Realm user logged out"); +// } +// } +// } +// } +// } +// init() { +// loginToRealmAnonymous() +// } + + var body: some Scene { WindowGroup { - ContentView() + NavigationView { + StartView() + } } } } + diff --git a/PRTY/Styles/textFieldStyles.swift b/PRTY/Styles/textFieldStyles.swift new file mode 100644 index 0000000..6738e98 --- /dev/null +++ b/PRTY/Styles/textFieldStyles.swift @@ -0,0 +1,24 @@ +// +// textFieldStyles.swift +// PRTY +// +// Created by Quinn Butcher on 6/30/23. +// + +import Foundation +import SwiftUI + + + +struct SignUpTextFieldStyle: TextFieldStyle { + func _body(configuration: TextField) -> some View { + configuration + .padding(10) + .disableAutocorrection(true) + .autocapitalization(.none) + .frame(width: 280, height: 45, alignment: .center) + .cornerRadius(20) + .shadow(color: .gray, radius: 10) + } +} + diff --git a/PRTY/Views/AuthView.swift b/PRTY/Views/AuthView.swift new file mode 100644 index 0000000..24f7b20 --- /dev/null +++ b/PRTY/Views/AuthView.swift @@ -0,0 +1,30 @@ +// +// AuthView.swift +// PRTY +// +// Created by Quinn Butcher on 4/1/23. +// + +import SwiftUI + +struct AuthView: View { + @EnvironmentObject private var authModel: AuthViewModel + + var body: some View { + Group { + if authModel.user != nil { + UserProfileView() + } else { + RootView() + } + }.onAppear { + authModel.listenToAuthState() + } + } +} + +struct AuthView_Previews: PreviewProvider { + static var previews: some View { + AuthView().environmentObject(AuthViewModel()) + } +} diff --git a/PRTY/Views/HomeView.swift b/PRTY/Views/HomeView.swift new file mode 100644 index 0000000..3a433fa --- /dev/null +++ b/PRTY/Views/HomeView.swift @@ -0,0 +1,26 @@ +// +// HomeView.swift +// PRTY +// +// Created by Quinn Butcher on 6/11/23. +// + +import SwiftUI + +struct HomeView: View { + + + var body: some View { + VStack { + Text("hello") + } + } + } + + + +struct RootView_Previews: PreviewProvider { + static var previews: some View { + HomeView() + } +} diff --git a/PRTY/Views/SignUpView.swift b/PRTY/Views/SignUpView.swift new file mode 100644 index 0000000..5963bb9 --- /dev/null +++ b/PRTY/Views/SignUpView.swift @@ -0,0 +1,156 @@ +// +// SignUpView.swift +// PRTY +// +// Created by Quinn Butcher on 12/1/22. +// + +import SwiftUI +import FirebaseAuth +import RealmSwift +import Firebase + +struct SignUpView: View { + @State private var firstName: String = "" + @State private var lastName: String = "" + @State private var email: String = "" + @State private var password: String = "" + let app = App(id: "application-prty-vtmer") + + var body: some View { + + ZStack { + VStack(spacing: 16) { + TextField("First Name", text: $firstName) + .textFieldStyle(SignUpTextFieldStyle()) + TextField("Last Name", text: $lastName) + .textFieldStyle(SignUpTextFieldStyle()) + TextField("Email", text: $email) + .keyboardType(.emailAddress) + .textFieldStyle(SignUpTextFieldStyle()) + SecureField("Password", text: $password) + .textFieldStyle(SignUpTextFieldStyle()) + Button(action: { + signUpUser() + + }, label: { + Text("Create Account") + .foregroundColor(.white) + }).frame(width: 280, height: 45, alignment: .center) + .background(Color.blue) + .cornerRadius(8) + } + } + } + + func signUpUser() -> Error? { + var firebaseError: Error? + let email = self.email // get email from the view model + let password = self.password // get password from the view model + Auth.auth().createUser(withEmail: email, password: password) { user, error in + if error == nil { // no error -> proceed with user sign in + print("Creation of Firebase user successful.") + // this is the right time to e.g. send a welcome email to the user + _ = self.signInUserViaEmail() // recommend to continue with a sign-in of the user + } else { // in case of error + firebaseError = error + } + } + return firebaseError + } + + func signInUserViaEmail() -> Error? { + var firebaseError: Error? + let email = self.email + let password = self.password + Auth.auth().signIn(withEmail: email, password: password) { user, error in // try Firebase sign-in + if error == nil { // no error during Firebase sign in occurred + print("Firebase sign in successful with e-mail.") + initiateSynchronizationWithRealm() { (success,error) in // now try to connect to Realm + if error == nil { // option 1: Firebase and Realm sign in both were successful + DispatchQueue.main.async { + // do whatever you want once the sign in was successful + } + } else { // option 2: an error occured signing in to Realm + DispatchQueue.main.async { + print(error?.localizedDescription) + // do whatever you want in case an error occurred (suggest to sign-out from Firebase) + } + } + } + } else { // option 3: in case of error during firebase authentication + firebaseError = error + // do whatever you want in case the sign-in to Firebase failed + } + } + return firebaseError + } + func initiateSynchronizationWithRealm(completionHandler: @escaping (Bool?, Swift.Error?) -> Void) { + self.loadSyncedUserRealm() { (success,error) in + if error != nil { // something went wrong when trying to connect to Realm + completionHandler(false,error) + } else { // everything is fine, connection to Realm established + completionHandler(true,nil) + } + } + } + + func loadSyncedUserRealm(completionHandler: @escaping (Bool?, Swift.Error?) -> Void) { + getSyncUser() { (realmUser,error) in // first, try to retrieve a Realm sync user + if error != nil { // sync user could not be retrieved + print("Realm user could not be retrieved: (\(String(describing: error)))\n") + completionHandler(false,error) + } else { // a Realm sync user could be retrieved + print("Received a Realm user: \(String(describing: realmUser?.id))") + guard let realmUser = realmUser else { return } + let realmUserId = realmUser.id + // in the next line, you probably want to construct your partition string based on the user id + let config = realmUser.configuration(partitionValue: "put-your-partition-string-here") + Realm.asyncOpen(configuration: config) { [self](result) in + switch result { + case .failure(let error): // not able to open the Realm + print("Not able to open user's private sync Realm: (\(error))\n") + print(error.localizedDescription) + completionHandler(false,error) + case .success(let userRealm): // able to open the Realm + print("Successfully opened user's private synced Realm (\(String(describing: realmUserId)))") + completionHandler(true,nil) + } + } + } + } + } + + private func getSyncUser(completionHandler: @escaping (RealmSwift.User?, Swift.Error?) -> Void) { + Auth.auth().currentUser?.getIDToken(){ (idToken, error) in // retrieve the token directly from the Firebase user + if error == nil, let token = idToken { + let credentials = Credentials.jwt(token: token) // create the credentials for Realm based on the token + self.app.login(credentials: credentials, { (result) in + switch result { + case .failure(let error): // something went wrong + print("Login failed: \(error.localizedDescription)") + completionHandler(nil,error) + case .success(let user): // login to MongoDB Realm was successful + print("Successfully logged in as user \(user)") + let user = self.app.currentUser + completionHandler(user,nil) + } + }) + }else{ + print("Error receiving Firebase token") + completionHandler(nil,error) + } + } + } + +} + + + + + +struct SignUpView_Previews: PreviewProvider { + static var previews: some View { + SignUpView() + } +} diff --git a/PRTY/Views/StartView.swift b/PRTY/Views/StartView.swift new file mode 100644 index 0000000..70e63e6 --- /dev/null +++ b/PRTY/Views/StartView.swift @@ -0,0 +1,75 @@ +// +// StartView.swift +// PRTY +// +// Created by Quinn Butcher on 6/11/23. +// + +import SwiftUI + +struct StartView: View { + + let backgroundGradient = LinearGradient(gradient: Gradient(colors: [.red, .orange]), startPoint: .topLeading, endPoint: .bottomTrailing) + + var body: some View { + NavigationStack { + ZStack() { + VStack(alignment: .leading) { + Text("PRTY") + .font(.system(size: 70, weight: .heavy, design: .default)) + + }.frame(maxHeight: .infinity, alignment: .top) + VStack { + NavigationLink { + SignUpView() + } label: { + SignUpButtonContent() + } + Text("OR") + .offset(y:10) + .font(.system(size: 20, weight: .heavy, design: .serif)) + Text("Sign UP with Placeholder") + }.frame(maxHeight: 20, alignment: .center) + VStack(spacing: 10) { + NavigationLink { + loginView() + } label: { + LoginInButtonContent() + } + }.frame(maxHeight: .infinity, alignment: .bottom) + }.background(backgroundGradient) + } + } +} + + + +struct SignUpButtonContent : View { + var body: some View { + Text("Sign up") + .font(.system(size: 30, weight: .heavy, design: .serif)) + .foregroundColor(.black) + .frame(height: 60) + .frame(maxWidth: .infinity, alignment: .center) + .background(.red) + } +} + +struct LoginInButtonContent : View { + var body: some View { + Text("Already Have an Account? Login") + .font(.system(size: 20, weight: .heavy, design: .serif)) + .foregroundColor(.black) + .frame(maxWidth: .infinity, alignment: .bottom) + .frame(height: 100, alignment: .center) + } +} + + + + +struct StartView_Previews: PreviewProvider { + static var previews: some View { + StartView() + } +} diff --git a/PRTY/Views/loginView.swift b/PRTY/Views/loginView.swift new file mode 100644 index 0000000..b9ba704 --- /dev/null +++ b/PRTY/Views/loginView.swift @@ -0,0 +1,23 @@ +// +// loginView.swift +// PRTY +// +// Created by Quinn Butcher on 1/18/23. +// + +import SwiftUI +import FirebaseAuth + +struct loginView: View { + var body: some View { + Text("no") + } +} + + +struct loginView_Previews: PreviewProvider { + static var previews: some View { + loginView() + } +} + diff --git a/Podfile b/Podfile new file mode 100644 index 0000000..f384fe2 --- /dev/null +++ b/Podfile @@ -0,0 +1,32 @@ +# Uncomment the next line to define a global platform for your project +# platform :ios, '16.1' + +target 'PRTY' do + # Comment the next line if you don't want to use dynamic frameworks + use_frameworks! + + # Pods for PRTY + + #Backend + + # Realm + pod 'RealmSwift', '~>10' + + # Firebase + pod 'Firebase/Auth' + pod 'Firebase/Database' + pod 'Firebase/Core' + +#UI + + + target 'PRTYTests' do + inherit! :search_paths + # Pods for testing + end + + target 'PRTYUITests' do + # Pods for testing + end + +end diff --git a/Podfile.lock b/Podfile.lock new file mode 100644 index 0000000..86b9403 --- /dev/null +++ b/Podfile.lock @@ -0,0 +1,150 @@ +PODS: + - Firebase/Auth (10.11.0): + - Firebase/CoreOnly + - FirebaseAuth (~> 10.11.0) + - Firebase/Core (10.11.0): + - Firebase/CoreOnly + - FirebaseAnalytics (~> 10.11.0) + - Firebase/CoreOnly (10.11.0): + - FirebaseCore (= 10.11.0) + - Firebase/Database (10.11.0): + - Firebase/CoreOnly + - FirebaseDatabase (~> 10.11.0) + - FirebaseAnalytics (10.11.0): + - FirebaseAnalytics/AdIdSupport (= 10.11.0) + - FirebaseCore (~> 10.0) + - FirebaseInstallations (~> 10.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.11) + - GoogleUtilities/MethodSwizzler (~> 7.11) + - GoogleUtilities/Network (~> 7.11) + - "GoogleUtilities/NSData+zlib (~> 7.11)" + - nanopb (< 2.30910.0, >= 2.30908.0) + - FirebaseAnalytics/AdIdSupport (10.11.0): + - FirebaseCore (~> 10.0) + - FirebaseInstallations (~> 10.0) + - GoogleAppMeasurement (= 10.11.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.11) + - GoogleUtilities/MethodSwizzler (~> 7.11) + - GoogleUtilities/Network (~> 7.11) + - "GoogleUtilities/NSData+zlib (~> 7.11)" + - nanopb (< 2.30910.0, >= 2.30908.0) + - FirebaseAppCheckInterop (10.11.0) + - FirebaseAuth (10.11.0): + - FirebaseAppCheckInterop (~> 10.0) + - FirebaseCore (~> 10.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.8) + - GoogleUtilities/Environment (~> 7.8) + - GTMSessionFetcher/Core (< 4.0, >= 2.1) + - FirebaseCore (10.11.0): + - FirebaseCoreInternal (~> 10.0) + - GoogleUtilities/Environment (~> 7.8) + - GoogleUtilities/Logger (~> 7.8) + - FirebaseCoreInternal (10.11.0): + - "GoogleUtilities/NSData+zlib (~> 7.8)" + - FirebaseDatabase (10.11.0): + - FirebaseCore (~> 10.0) + - leveldb-library (~> 1.22) + - FirebaseInstallations (10.11.0): + - FirebaseCore (~> 10.0) + - GoogleUtilities/Environment (~> 7.8) + - GoogleUtilities/UserDefaults (~> 7.8) + - PromisesObjC (~> 2.1) + - GoogleAppMeasurement (10.11.0): + - GoogleAppMeasurement/AdIdSupport (= 10.11.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.11) + - GoogleUtilities/MethodSwizzler (~> 7.11) + - GoogleUtilities/Network (~> 7.11) + - "GoogleUtilities/NSData+zlib (~> 7.11)" + - nanopb (< 2.30910.0, >= 2.30908.0) + - GoogleAppMeasurement/AdIdSupport (10.11.0): + - GoogleAppMeasurement/WithoutAdIdSupport (= 10.11.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.11) + - GoogleUtilities/MethodSwizzler (~> 7.11) + - GoogleUtilities/Network (~> 7.11) + - "GoogleUtilities/NSData+zlib (~> 7.11)" + - nanopb (< 2.30910.0, >= 2.30908.0) + - GoogleAppMeasurement/WithoutAdIdSupport (10.11.0): + - GoogleUtilities/AppDelegateSwizzler (~> 7.11) + - GoogleUtilities/MethodSwizzler (~> 7.11) + - GoogleUtilities/Network (~> 7.11) + - "GoogleUtilities/NSData+zlib (~> 7.11)" + - nanopb (< 2.30910.0, >= 2.30908.0) + - GoogleUtilities/AppDelegateSwizzler (7.11.1): + - GoogleUtilities/Environment + - GoogleUtilities/Logger + - GoogleUtilities/Network + - GoogleUtilities/Environment (7.11.1): + - PromisesObjC (< 3.0, >= 1.2) + - GoogleUtilities/Logger (7.11.1): + - GoogleUtilities/Environment + - GoogleUtilities/MethodSwizzler (7.11.1): + - GoogleUtilities/Logger + - GoogleUtilities/Network (7.11.1): + - GoogleUtilities/Logger + - "GoogleUtilities/NSData+zlib" + - GoogleUtilities/Reachability + - "GoogleUtilities/NSData+zlib (7.11.1)" + - GoogleUtilities/Reachability (7.11.1): + - GoogleUtilities/Logger + - GoogleUtilities/UserDefaults (7.11.1): + - GoogleUtilities/Logger + - GTMSessionFetcher/Core (3.1.1) + - leveldb-library (1.22.2) + - nanopb (2.30909.0): + - nanopb/decode (= 2.30909.0) + - nanopb/encode (= 2.30909.0) + - nanopb/decode (2.30909.0) + - nanopb/encode (2.30909.0) + - PromisesObjC (2.2.0) + - Realm (10.41.0): + - Realm/Headers (= 10.41.0) + - Realm/Headers (10.41.0) + - RealmSwift (10.41.0): + - Realm (= 10.41.0) + +DEPENDENCIES: + - Firebase/Auth + - Firebase/Core + - Firebase/Database + - RealmSwift (~> 10) + +SPEC REPOS: + trunk: + - Firebase + - FirebaseAnalytics + - FirebaseAppCheckInterop + - FirebaseAuth + - FirebaseCore + - FirebaseCoreInternal + - FirebaseDatabase + - FirebaseInstallations + - GoogleAppMeasurement + - GoogleUtilities + - GTMSessionFetcher + - leveldb-library + - nanopb + - PromisesObjC + - Realm + - RealmSwift + +SPEC CHECKSUMS: + Firebase: 31d9575c124839fb5abc0db6d39511cc1dab1b85 + FirebaseAnalytics: 6c6bf99e8854475bf1fa342028841be8ecd236da + FirebaseAppCheckInterop: 255b6c0292fe5da995c8b2df0c02f6a3ca7f61b4 + FirebaseAuth: 7aabcb00fbf330db49c207c0d645b8b1b62df0e9 + FirebaseCore: 62fd4d549f5e3f3bd52b7998721c5fa0557fb355 + FirebaseCoreInternal: 9e46c82a14a3b3a25be4e1e151ce6d21536b89c0 + FirebaseDatabase: 4e1cb7f44ce6ffa553033913dd0d634b2310ce65 + FirebaseInstallations: 2a2c6859354cbec0a228a863d4daf6de7c74ced4 + GoogleAppMeasurement: d3dabccdb336fc0ae44b633c8abaa26559893cd9 + GoogleUtilities: 9aa0ad5a7bc171f8bae016300bfcfa3fb8425749 + GTMSessionFetcher: e8647203b65cee28c5f73d0f473d096653945e72 + leveldb-library: f03246171cce0484482ec291f88b6d563699ee06 + nanopb: b552cce312b6c8484180ef47159bc0f65a1f0431 + PromisesObjC: 09985d6d70fbe7878040aa746d78236e6946d2ef + Realm: 669efee7dc1ce0aa9f6739a60f8c0df0a3835067 + RealmSwift: 6b7b0e91b79dc66d5cfceeb3b319cacfc9b1a70e + +PODFILE CHECKSUM: aa7d3da7f5d56ddf2ffa51d4d394794236ee6717 + +COCOAPODS: 1.12.1 diff --git a/Pods/Firebase/CoreOnly/Sources/Firebase.h b/Pods/Firebase/CoreOnly/Sources/Firebase.h new file mode 100755 index 0000000..8a7420d --- /dev/null +++ b/Pods/Firebase/CoreOnly/Sources/Firebase.h @@ -0,0 +1,81 @@ +// Copyright 2019 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 + +#if !defined(__has_include) + #error "Firebase.h won't import anything if your compiler doesn't support __has_include. Please \ + import the headers individually." +#else + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include("FirebaseFunctions-umbrella.h") + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include("FirebaseStorage-umbrella.h") + #import + #endif + +#endif // defined(__has_include) diff --git a/Pods/Firebase/CoreOnly/Sources/module.modulemap b/Pods/Firebase/CoreOnly/Sources/module.modulemap new file mode 100755 index 0000000..3685b54 --- /dev/null +++ b/Pods/Firebase/CoreOnly/Sources/module.modulemap @@ -0,0 +1,4 @@ +module Firebase { + export * + header "Firebase.h" +} \ No newline at end of file diff --git a/Pods/Firebase/LICENSE b/Pods/Firebase/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/Pods/Firebase/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/Pods/Firebase/README.md b/Pods/Firebase/README.md new file mode 100644 index 0000000..85a23bd --- /dev/null +++ b/Pods/Firebase/README.md @@ -0,0 +1,281 @@ +

+ + + + + + + + +
+ + + + + + +

+ +# Firebase Apple Open Source Development + +This repository contains all Apple platform Firebase SDK source except FirebaseAnalytics. + +Firebase is an app development platform with tools to help you build, grow and +monetize your app. More information about Firebase can be found on the +[official Firebase website](https://firebase.google.com). + +## Installation + +See the subsections below for details about the different installation methods. Where +available, it's recommended to install any libraries with a `Swift` suffix to get the +best experience when writing your app in Swift. +1. [Standard pod install](#standard-pod-install) +1. [Swift Package Manager](#swift-package-manager) +1. [Installing from the GitHub repo](#installing-from-github) +1. [Experimental Carthage](#carthage-ios-only) + +### Standard pod install + +Go to +[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup). + +### Swift Package Manager + +Instructions for [Swift Package Manager](https://swift.org/package-manager/) support can be +found at [SwiftPackageManager](SwiftPackageManager.md) Markdown file. + +### Installing from GitHub + +These instructions can be used to access the Firebase repo at other branches, +tags, or commits. + +#### Background + +See +[the Podfile Syntax Reference](https://guides.cocoapods.org/syntax/podfile.html#pod) +for instructions and options about overriding pod source locations. + +#### Accessing Firebase Source Snapshots + +All of the official releases are tagged in this repo and available via CocoaPods. To access a local +source snapshot or unreleased branch, use Podfile directives like the following: + +To access FirebaseFirestore via a branch: +```ruby +pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master' +pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master' +``` + +To access FirebaseMessaging via a checked out version of the firebase-ios-sdk repo do: + +```ruby +pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk' +pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk' +``` + +### Carthage (iOS only) + +Instructions for the experimental Carthage distribution are at +[Carthage](Carthage.md). + +### Using Firebase from a Framework or a library + +[Using Firebase from a Framework or a library](docs/firebase_in_libraries.md) + +## Development + +To develop Firebase software in this repository, ensure that you have at least +the following software: + + * Xcode 14.1 (or later) + +CocoaPods is still the canonical way to develop, but much of the repo now supports +development with Swift Package Manager. + +### CocoaPods + +Install + * CocoaPods 1.10.0 (or later) + * [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +```ruby +pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios +``` + +Note: If the CocoaPods cache is out of date, you may need to run +`pod repo update` before the `pod gen` command. + +Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for +those platforms. Since 10.2, Xcode does not properly handle multi-platform +CocoaPods workspaces. + +Firestore has a self contained Xcode project. See +[Firestore/README](Firestore/README.md) Markdown file. + +#### Development for Catalyst +* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios` +* Check the Mac box in the App-iOS Build Settings +* Sign the App in the Settings Signing & Capabilities tab +* Click Pods in the Project Manager +* Add Signing to the iOS host app and unit test targets +* Select the Unit-unit scheme +* Run it to build and test + +Alternatively disable signing in each target: +* Go to Build Settings tab +* Click `+` +* Select `Add User-Defined Setting` +* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO` + +### Swift Package Manager +* To enable test schemes: `./scripts/setup_spm_tests.sh` +* `open Package.swift` or double click `Package.swift` in Finder. +* Xcode will open the project + * Choose a scheme for a library to build or test suite to run + * Choose a target platform by selecting the run destination along with the scheme + +### Adding a New Firebase Pod + +See [AddNewPod](AddNewPod.md) Markdown file. + +### Managing Headers and Imports + +See [HeadersImports](HeadersImports.md) Markdown file. + +### Code Formatting + +To ensure that the code is formatted consistently, run the script +[./scripts/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/master/scripts/check.sh) +before creating a PR. + +GitHub Actions will verify that any code changes are done in a style compliant +way. Install `clang-format` and `mint`: + +```console +brew install clang-format@16 +brew install mint +``` + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +### Running Sample Apps +In order to run the sample apps and integration tests, you'll need a valid +`GoogleService-Info.plist` file. The Firebase Xcode project contains dummy plist +files without real values, but can be replaced with real plist files. To get your own +`GoogleService-Info.plist` files: + +1. Go to the [Firebase Console](https://console.firebase.google.com/) +2. Create a new Firebase project, if you don't already have one +3. For each sample app you want to test, create a new Firebase app with the sample app's bundle +identifier (e.g. `com.google.Database-Example`) +4. Download the resulting `GoogleService-Info.plist` and add it to the Xcode project. + +### Coverage Report Generation + +See [scripts/code_coverage_report/README](scripts/code_coverage_report/README.md) Markdown file. + +## Specific Component Instructions +See the sections below for any special instructions for those components. + +### Firebase Auth + +If you're doing specific Firebase Auth development, see +[the Auth Sample README](FirebaseAuth/Tests/Sample/README.md) for instructions about +building and running the FirebaseAuth pod along with various samples and tests. + +### Firebase Database + +The Firebase Database Integration tests can be run against a locally running Database Emulator +or against a production instance. + +To run against a local emulator instance, invoke `./scripts/run_database_emulator.sh start` before +running the integration test. + +To run against a production instance, provide a valid GoogleServices-Info.plist and copy it to +`FirebaseDatabase/Tests/Resources/GoogleService-Info.plist`. Your Security Rule must be set to +[public](https://firebase.google.com/docs/database/security/quickstart) while your tests are +running. + +### Firebase Performance Monitoring +If you're doing specific Firebase Performance Monitoring development, see +[the Performance README](FirebasePerformance/README.md) for instructions about building the SDK +and [the Performance TestApp README](FirebasePerformance/Tests/TestApp/README.md) for instructions about +integrating Performance with the dev test App. + +### Firebase Storage + +To run the Storage Integration tests, follow the instructions in +[StorageIntegration.swift](FirebaseStorage/Tests/Integration/StorageIntegration.swift). + +#### Push Notifications + +Push notifications can only be delivered to specially provisioned App IDs in the developer portal. +In order to actually test receiving push notifications, you will need to: + +1. Change the bundle identifier of the sample app to something you own in your Apple Developer +account, and enable that App ID for push notifications. +2. You'll also need to +[upload your APNs Provider Authentication Key or certificate to the +Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs) +at **Project Settings > Cloud Messaging > [Your Firebase App]**. +3. Ensure your iOS device is added to your Apple Developer portal as a test device. + +#### iOS Simulator + +The iOS Simulator cannot register for remote notifications, and will not receive push notifications. +In order to receive push notifications, you'll have to follow the steps above and run the app on a +physical device. + +## Building with Firebase on Apple platforms + +Firebase 8.9.0 introduced official beta support for macOS, Catalyst, and tvOS. watchOS continues +to be community supported. Thanks to community contributions for many of the multi-platform PRs. + +At this time, most of Firebase's products are available across Apple platforms. There are still +a few gaps, especially on watchOS. For details about the current support matrix, see +[this chart](https://firebase.google.com/docs/ios/learn-more#firebase_library_support_by_platform) +in Firebase's documentation. + +### watchOS +Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and +work on watchOS. See the [Independent Watch App Sample](Example/watchOSSample). + +Keep in mind that watchOS is not officially supported by Firebase. While we can catch basic unit +test issues with GitHub Actions, there may be some changes where the SDK no longer works as expected +on watchOS. If you encounter this, please +[file an issue](https://github.com/firebase/firebase-ios-sdk/issues). + +During app setup in the console, you may get to a step that mentions something like "Checking if the +app has communicated with our servers". This relies on Analytics and will not work on watchOS. +**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected. + +#### Additional Crashlytics Notes +* watchOS has limited support. Due to watchOS restrictions, mach exceptions and signal crashes are +not recorded. (Crashes in SwiftUI are generated as mach exceptions, so will not be recorded) + +## Combine +Thanks to contributions from the community, _FirebaseCombineSwift_ contains support for Apple's Combine +framework. This module is currently under development, and not yet supported for use in production +environments. Fore more details, please refer to the [docs](FirebaseCombineSwift/README.md). + +## Roadmap + +See [Roadmap](ROADMAP.md) for more about the Firebase Apple SDK Open Source +plans and directions. + +## Contributing + +See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase +Apple SDK. + +## License + +The contents of this repository are licensed under the +[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). + +Your use of Firebase is governed by the +[Terms of Service for Firebase Services](https://firebase.google.com/terms/). diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/Info.plist b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/Info.plist new file mode 100644 index 0000000..f0667f5 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/Info.plist @@ -0,0 +1,95 @@ + + + + + AvailableLibraries + + + LibraryIdentifier + ios-arm64 + LibraryPath + FirebaseAnalytics.framework + SupportedArchitectures + + arm64 + + SupportedPlatform + ios + + + LibraryIdentifier + ios-arm64_x86_64-simulator + LibraryPath + FirebaseAnalytics.framework + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + ios + SupportedPlatformVariant + simulator + + + LibraryIdentifier + ios-arm64_x86_64-maccatalyst + LibraryPath + FirebaseAnalytics.framework + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + ios + SupportedPlatformVariant + maccatalyst + + + LibraryIdentifier + tvos-arm64_x86_64-simulator + LibraryPath + FirebaseAnalytics.framework + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + tvos + SupportedPlatformVariant + simulator + + + LibraryIdentifier + macos-arm64_x86_64 + LibraryPath + FirebaseAnalytics.framework + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + macos + + + LibraryIdentifier + tvos-arm64 + LibraryPath + FirebaseAnalytics.framework + SupportedArchitectures + + arm64 + + SupportedPlatform + tvos + + + CFBundlePackageType + XFWK + XCFrameworkFormatVersion + 1.0 + + diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/FirebaseAnalytics b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/FirebaseAnalytics new file mode 100644 index 0000000..2553c85 Binary files /dev/null and b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/FirebaseAnalytics differ diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h new file mode 100644 index 0000000..cb1e407 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h @@ -0,0 +1,80 @@ +#import + +#import "FIRAnalytics.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Provides App Delegate handlers to be used in your App Delegate. +/// +/// To save time integrating Firebase Analytics in an application, Firebase Analytics does not +/// require delegation implementation from the AppDelegate if neither SwiftUI nor UIScene lifecycle +/// is adopted. Instead this is automatically done by Firebase Analytics. Should you choose instead +/// to delegate manually, you can turn off the App Delegate Proxy by adding +/// FirebaseAppDelegateProxyEnabled into your app's Info.plist and setting it to boolean `NO`, and +/// adding the methods in this category to corresponding delegation handlers. +/// +/// To handle Universal Links, you must return `true` in +/// `UIApplicationDelegate.application(_:didFinishLaunchingWithOptions:)`. +@interface FIRAnalytics (AppDelegate) + +/// Handles events related to a URL session that are waiting to be processed. +/// +/// 1. If SwiftUI lifecycle is adopted, call this method from +/// `UIApplicationDelegate.application(_:handleEventsForBackgroundURLSession:completionHandler:)` +/// in your app delegate. +/// +/// 2. If SwiftUI lifecycle is not adopted, Firebase Analytics does not require delegation +/// implementation from the AppDelegate. If you choose instead to delegate manually, you can set +/// FirebaseAppDelegateProxyEnabled to boolean `NO` in your app's Info.plist and call this method +/// from +/// `UIApplicationDelegate.application(_:handleEventsForBackgroundURLSession:completionHandler:)` +/// in your app delegate. +/// +/// @param identifier The identifier of the URL session requiring attention. +/// @param completionHandler The completion handler to call when you finish processing the events. +/// Calling this completion handler lets the system know that your app's user interface is +/// updated and a new snapshot can be taken. ++ (void)handleEventsForBackgroundURLSession:(NSString *)identifier + completionHandler:(nullable void (^)(void))completionHandler; + +/// Handles the event when the app is launched by a URL (custom URL scheme or universal link). +/// +/// 1. If SwiftUI lifecycle is adopted, use `onOpenURL(perform:)` to register a handler and call +/// this method in the handler. +/// +/// 2. If UIScene lifecycle is adopted, call this method from +/// `UISceneDelegate.scene(_:willConnectTo:options:)` and +/// `UISceneDelegate.scene(_:openURLContexts:)` when the URL contexts are available. +/// +/// 3. If neither SwiftUI nor UIScene lifecycle is adopted, Firebase Analytics does not require +/// delegation implementation from the AppDelegate. If you choose instead to delegate manually, you +/// can set FirebaseAppDelegateProxyEnabled to boolean `NO` in your app's Info.plist and call this +/// method from `UIApplicationDelegate.application(_:open:options:)` in your app delegate. +/// +/// @param url The URL resource to open. This resource can be a network resource or a file. ++ (void)handleOpenURL:(NSURL *)url; + +/// Handles the event when the app receives data associated with user activity that includes a +/// Universal Link. +/// +/// 1. If SwiftUI lifecycle is adopted, use `onOpenURL(perform:)` to register a handler and call +/// `Analytics.handleOpen(_:)` instead in the handler. +/// +/// 2. If UIScene lifecycle is adopted, call this method from +/// `UISceneDelegate.scene(_:willConnectTo:options:)` and `UISceneDelegate.scene(_:continue:)` when +/// NSUserActivity is available. See the [Apple +/// doc](https://developer.apple.com/documentation/xcode/supporting-universal-links-in-your-app) for +/// more details. +/// +/// 3. If neither SwiftUI nor UIScene lifecycle is adopted, Firebase Analytics does not require +/// delegation implementation from the AppDelegate. If you choose instead to delegate manually, you +/// can set FirebaseAppDelegateProxyEnabled to boolean `NO` in your app's Info.plist and call this +/// method from `UIApplication.application(_:continue:restorationHandler:)` in your app delegate. +/// +/// @param userActivity The activity object containing the data associated with the task the user +/// was performing. ++ (void)handleUserActivity:(id)userActivity; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+Consent.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+Consent.h new file mode 100644 index 0000000..7f89831 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+Consent.h @@ -0,0 +1,33 @@ +#import + +#import "FIRAnalytics.h" + +NS_ASSUME_NONNULL_BEGIN + +/// The type of consent to set. Supported consent types are `ConsentType.adStorage` and +/// `ConsentType.analyticsStorage`. Omitting a type retains its previous status. +typedef NSString *FIRConsentType NS_TYPED_ENUM NS_SWIFT_NAME(ConsentType); +extern FIRConsentType const FIRConsentTypeAdStorage; +extern FIRConsentType const FIRConsentTypeAnalyticsStorage; + +/// The status value of the consent type. Supported statuses are `ConsentStatus.granted` and +/// `ConsentStatus.denied`. +typedef NSString *FIRConsentStatus NS_TYPED_ENUM NS_SWIFT_NAME(ConsentStatus); +extern FIRConsentStatus const FIRConsentStatusDenied; +extern FIRConsentStatus const FIRConsentStatusGranted; + +/// Sets the applicable end user consent state. +@interface FIRAnalytics (Consent) + +/// Sets the applicable end user consent state (e.g. for device identifiers) for this app on this +/// device. Use the consent settings to specify individual consent type values. Settings are +/// persisted across app sessions. By default consent types are set to `ConsentStatus.granted`. +/// +/// @param consentSettings A Dictionary of consent types. Supported consent type keys are +/// `ConsentType.adStorage` and `ConsentType.analyticsStorage`. Valid values are +/// `ConsentStatus.granted` and `ConsentStatus.denied`. ++ (void)setConsent:(NSDictionary *)consentSettings; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+OnDevice.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+OnDevice.h new file mode 100644 index 0000000..1d9a438 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+OnDevice.h @@ -0,0 +1,19 @@ +#import + +#import "FIRAnalytics.h" + +NS_ASSUME_NONNULL_BEGIN + +API_UNAVAILABLE(macCatalyst, macos, tvos, watchos) +@interface FIRAnalytics (OnDevice) + +/// Initiates on-device conversion measurement given a user email address. Requires dependency +/// GoogleAppMeasurementOnDeviceConversion to be linked in, otherwise it is a no-op. +/// @param emailAddress User email address. Include a domain name for all email addresses +/// (e.g. gmail.com or hotmail.co.jp). ++ (void)initiateOnDeviceConversionMeasurementWithEmailAddress:(NSString *)emailAddress + NS_SWIFT_NAME(initiateOnDeviceConversionMeasurement(emailAddress:)); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics.h new file mode 100644 index 0000000..e7ce5dc --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics.h @@ -0,0 +1,154 @@ +#import + +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" + +NS_ASSUME_NONNULL_BEGIN + +/// The top level Firebase Analytics singleton that provides methods for logging events and setting +/// user properties. See the developer guides for general +/// information on using Firebase Analytics in your apps. +/// +/// @note The Analytics SDK uses SQLite to persist events and other app-specific data. Calling +/// certain thread-unsafe global SQLite methods like `sqlite3_shutdown()` can result in +/// unexpected crashes at runtime. +NS_SWIFT_NAME(Analytics) +@interface FIRAnalytics : NSObject + +/// Logs an app event. The event can have up to 25 parameters. Events with the same name must have +/// the same parameters. Up to 500 event names are supported. Using predefined events and/or +/// parameters is recommended for optimal reporting. +/// +/// The following event names are reserved and cannot be used: +///
    +///
  • ad_activeview
  • +///
  • ad_click
  • +///
  • ad_exposure
  • +///
  • ad_query
  • +///
  • ad_reward
  • +///
  • adunit_exposure
  • +///
  • app_clear_data
  • +///
  • app_exception
  • +///
  • app_remove
  • +///
  • app_store_refund
  • +///
  • app_store_subscription_cancel
  • +///
  • app_store_subscription_convert
  • +///
  • app_store_subscription_renew
  • +///
  • app_update
  • +///
  • app_upgrade
  • +///
  • dynamic_link_app_open
  • +///
  • dynamic_link_app_update
  • +///
  • dynamic_link_first_open
  • +///
  • error
  • +///
  • firebase_campaign
  • +///
  • first_open
  • +///
  • first_visit
  • +///
  • in_app_purchase
  • +///
  • notification_dismiss
  • +///
  • notification_foreground
  • +///
  • notification_open
  • +///
  • notification_receive
  • +///
  • os_update
  • +///
  • session_start
  • +///
  • session_start_with_rollout
  • +///
  • user_engagement
  • +///
+/// +/// @param name The name of the event. Should contain 1 to 40 alphanumeric characters or +/// underscores. The name must start with an alphabetic character. Some event names are +/// reserved. See FIREventNames.h for the list of reserved event names. The "firebase_", +/// "google_", and "ga_" prefixes are reserved and should not be used. Note that event names are +/// case-sensitive and that logging two events whose names differ only in case will result in +/// two distinct events. To manually log screen view events, use the `screen_view` event name. +/// @param parameters The dictionary of event parameters. Passing `nil` indicates that the event has +/// no parameters. Parameter names can be up to 40 characters long and must start with an +/// alphabetic character and contain only alphanumeric characters and underscores. Only String, +/// Int, and Double parameter types are supported. String parameter values can be up to 100 +/// characters long. The "firebase_", "google_", and "ga_" prefixes are reserved and should not +/// be used for parameter names. ++ (void)logEventWithName:(NSString *)name + parameters:(nullable NSDictionary *)parameters + NS_SWIFT_NAME(logEvent(_:parameters:)); + +/// Sets a user property to a given value. Up to 25 user property names are supported. Once set, +/// user property values persist throughout the app lifecycle and across sessions. +/// +/// The following user property names are reserved and cannot be used: +///
    +///
  • first_open_time
  • +///
  • last_deep_link_referrer
  • +///
  • user_id
  • +///
+/// +/// @param value The value of the user property. Values can be up to 36 characters long. Setting the +/// value to `nil` removes the user property. +/// @param name The name of the user property to set. Should contain 1 to 24 alphanumeric characters +/// or underscores and must start with an alphabetic character. The "firebase_", "google_", and +/// "ga_" prefixes are reserved and should not be used for user property names. ++ (void)setUserPropertyString:(nullable NSString *)value forName:(NSString *)name + NS_SWIFT_NAME(setUserProperty(_:forName:)); + +/// Sets the user ID property. This feature must be used in accordance with +/// Google's Privacy Policy +/// +/// @param userID The user ID to ascribe to the user of this app on this device, which must be +/// non-empty and no more than 256 characters long. Setting userID to `nil` removes the user ID. ++ (void)setUserID:(nullable NSString *)userID; + +/// Sets whether analytics collection is enabled for this app on this device. This setting is +/// persisted across app sessions. By default it is enabled. +/// +/// @param analyticsCollectionEnabled A flag that enables or disables Analytics collection. ++ (void)setAnalyticsCollectionEnabled:(BOOL)analyticsCollectionEnabled; + +/// Sets the interval of inactivity in seconds that terminates the current session. The default +/// value is 1800 seconds (30 minutes). +/// +/// @param sessionTimeoutInterval The custom time of inactivity in seconds before the current +/// session terminates. ++ (void)setSessionTimeoutInterval:(NSTimeInterval)sessionTimeoutInterval; + +/// Asynchronously retrieves the identifier of the current app session. +/// +/// The session ID retrieval could fail due to Analytics collection disabled, app session expired, +/// etc. +/// +/// @param completion The completion handler to call when the session ID retrieval is complete. This +/// handler is executed on a system-defined global concurrent queue. +/// This completion handler takes the following parameters: +/// sessionID The identifier of the current app session. The value is undefined if the +/// request failed. +/// error An error object that indicates why the request failed, or `nil` if the request +/// was successful. ++ (void)sessionIDWithCompletion:(void (^)(int64_t sessionID, NSError *_Nullable error))completion; + +/// Returns the unique ID for this instance of the application or `nil` if +/// `ConsentType.analyticsStorage` has been set to `ConsentStatus.denied`. +/// +/// @see `FIRAnalytics+Consent.h` ++ (nullable NSString *)appInstanceID; + +/// Clears all analytics data for this instance from the device and resets the app instance ID. ++ (void)resetAnalyticsData; + +/// Adds parameters that will be set on every event logged from the SDK, including automatic ones. +/// The values passed in the parameters dictionary will be added to the dictionary of default event +/// parameters. These parameters persist across app runs. They are of lower precedence than event +/// parameters, so if an event parameter and a parameter set using this API have the same name, the +/// value of the event parameter will be used. The same limitations on event parameters apply to +/// default event parameters. +/// +/// @param parameters Parameters to be added to the dictionary of parameters added to every event. +/// They will be added to the dictionary of default event parameters, replacing any existing +/// parameter with the same name. Valid parameters are String, Int, and Double. Setting a key's +/// value to `NSNull()` will clear that parameter. Passing in a `nil` dictionary will clear all +/// parameters. ++ (void)setDefaultEventParameters:(nullable NSDictionary *)parameters; + +/// Unavailable. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIREventNames.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIREventNames.h new file mode 100644 index 0000000..1e69a44 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIREventNames.h @@ -0,0 +1,418 @@ +/// @file FIREventNames.h +/// +/// Predefined event names. +/// +/// An Event is an important occurrence in your app that you want to measure. You can report up to +/// 500 different types of Events per app and you can associate up to 25 unique parameters with each +/// Event type. Some common events are suggested below, but you may also choose to specify custom +/// Event types that are associated with your specific app. Each event type is identified by a +/// unique name. Event names can be up to 40 characters long, may only contain alphanumeric +/// characters and underscores ("_"), and must start with an alphabetic character. The "firebase_", +/// "google_", and "ga_" prefixes are reserved and should not be used. + +#import + +/// Ad Impression event. This event signifies when a user sees an ad impression. Note: If you supply +/// the @c AnalyticsParameterValue parameter, you must also supply the @c AnalyticsParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterAdPlatform (String) (optional)
  • +///
  • @c AnalyticsParameterAdFormat (String) (optional)
  • +///
  • @c AnalyticsParameterAdSource (String) (optional)
  • +///
  • @c AnalyticsParameterAdUnitName (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAdImpression NS_SWIFT_NAME(AnalyticsEventAdImpression) = + @"ad_impression"; + +/// Add Payment Info event. This event signifies that a user has submitted their payment +/// information. Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply +/// the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterPaymentType (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddPaymentInfo NS_SWIFT_NAME(AnalyticsEventAddPaymentInfo) = + @"add_payment_info"; + +/// Add Shipping Info event. This event signifies that a user has submitted their shipping +/// information. Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply +/// the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterShippingTier (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddShippingInfo NS_SWIFT_NAME(AnalyticsEventAddShippingInfo) = + @"add_shipping_info"; + +/// E-Commerce Add To Cart event. This event signifies that an item(s) was added to a cart for +/// purchase. Add this event to a funnel with @c AnalyticsEventPurchase to gauge the effectiveness +/// of your checkout process. Note: If you supply the @c AnalyticsParameterValue parameter, you must +/// also supply the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed +/// accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddToCart NS_SWIFT_NAME(AnalyticsEventAddToCart) = @"add_to_cart"; + +/// E-Commerce Add To Wishlist event. This event signifies that an item was added to a wishlist. Use +/// this event to identify popular gift items. Note: If you supply the @c AnalyticsParameterValue +/// parameter, you must also supply the @c AnalyticsParameterCurrency parameter so that revenue +/// metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddToWishlist NS_SWIFT_NAME(AnalyticsEventAddToWishlist) = + @"add_to_wishlist"; + +/// App Open event. By logging this event when an App becomes active, developers can understand how +/// often users leave and return during the course of a Session. Although Sessions are automatically +/// reported, this event can provide further clarification around the continuous engagement of +/// app-users. +static NSString *const kFIREventAppOpen NS_SWIFT_NAME(AnalyticsEventAppOpen) = @"app_open"; + +/// E-Commerce Begin Checkout event. This event signifies that a user has begun the process of +/// checking out. Add this event to a funnel with your @c AnalyticsEventPurchase event to gauge the +/// effectiveness of your checkout process. Note: If you supply the @c AnalyticsParameterValue +/// parameter, you must also supply the @c AnalyticsParameterCurrency parameter so that revenue +/// metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventBeginCheckout NS_SWIFT_NAME(AnalyticsEventBeginCheckout) = + @"begin_checkout"; + +/// Campaign Detail event. Log this event to supply the referral details of a re-engagement +/// campaign. Note: you must supply at least one of the required parameters +/// AnalyticsParameterSource, AnalyticsParameterMedium or AnalyticsParameterCampaign. Params: +/// +///
    +///
  • @c AnalyticsParameterSource (String)
  • +///
  • @c AnalyticsParameterMedium (String)
  • +///
  • @c AnalyticsParameterCampaign (String)
  • +///
  • @c AnalyticsParameterTerm (String) (optional)
  • +///
  • @c AnalyticsParameterContent (String) (optional)
  • +///
  • @c AnalyticsParameterAdNetworkClickID (String) (optional)
  • +///
  • @c AnalyticsParameterCP1 (String) (optional)
  • +///
  • @c AnalyticsParameterCampaignID (String) (optional)
  • +///
  • @c AnalyticsParameterCreativeFormat (String) (optional)
  • +///
  • @c AnalyticsParameterMarketingTactic (String) (optional)
  • +///
  • @c AnalyticsParameterSourcePlatform (String) (optional)
  • +///
+static NSString *const kFIREventCampaignDetails NS_SWIFT_NAME(AnalyticsEventCampaignDetails) = + @"campaign_details"; + +/// Earn Virtual Currency event. This event tracks the awarding of virtual currency in your app. Log +/// this along with @c AnalyticsEventSpendVirtualCurrency to better understand your virtual economy. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterVirtualCurrencyName (String)
  • +///
  • @c AnalyticsParameterValue (Int or Double)
  • +///
+static NSString *const kFIREventEarnVirtualCurrency + NS_SWIFT_NAME(AnalyticsEventEarnVirtualCurrency) = @"earn_virtual_currency"; + +/// Generate Lead event. Log this event when a lead has been generated in the app to understand the +/// efficacy of your install and re-engagement campaigns. Note: If you supply the +/// @c AnalyticsParameterValue parameter, you must also supply the @c AnalyticsParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventGenerateLead NS_SWIFT_NAME(AnalyticsEventGenerateLead) = + @"generate_lead"; + +/// Join Group event. Log this event when a user joins a group such as a guild, team or family. Use +/// this event to analyze how popular certain groups or social features are in your app. Params: +/// +///
    +///
  • @c AnalyticsParameterGroupID (String)
  • +///
+static NSString *const kFIREventJoinGroup NS_SWIFT_NAME(AnalyticsEventJoinGroup) = @"join_group"; + +/// Level End event. Log this event when the user finishes a level. Params: +/// +///
    +///
  • @c AnalyticsParameterLevelName (String)
  • +///
  • @c AnalyticsParameterSuccess (String)
  • +///
+static NSString *const kFIREventLevelEnd NS_SWIFT_NAME(AnalyticsEventLevelEnd) = @"level_end"; + +/// Level Start event. Log this event when the user starts a new level. Params: +/// +///
    +///
  • @c AnalyticsParameterLevelName (String)
  • +///
+static NSString *const kFIREventLevelStart NS_SWIFT_NAME(AnalyticsEventLevelStart) = @"level_start"; + +/// Level Up event. This event signifies that a player has leveled up in your gaming app. It can +/// help you gauge the level distribution of your userbase and help you identify certain levels that +/// are difficult to pass. Params: +/// +///
    +///
  • @c AnalyticsParameterLevel (Int)
  • +///
  • @c AnalyticsParameterCharacter (String) (optional)
  • +///
+static NSString *const kFIREventLevelUp NS_SWIFT_NAME(AnalyticsEventLevelUp) = @"level_up"; + +/// Login event. Apps with a login feature can report this event to signify that a user has logged +/// in. +static NSString *const kFIREventLogin NS_SWIFT_NAME(AnalyticsEventLogin) = @"login"; + +/// Post Score event. Log this event when the user posts a score in your gaming app. This event can +/// help you understand how users are actually performing in your game and it can help you correlate +/// high scores with certain audiences or behaviors. Params: +/// +///
    +///
  • @c AnalyticsParameterScore (Int)
  • +///
  • @c AnalyticsParameterLevel (Int) (optional)
  • +///
  • @c AnalyticsParameterCharacter (String) (optional)
  • +///
+static NSString *const kFIREventPostScore NS_SWIFT_NAME(AnalyticsEventPostScore) = @"post_score"; + +/// E-Commerce Purchase event. This event signifies that an item(s) was purchased by a user. Note: +/// This is different from the in-app purchase event, which is reported automatically for App +/// Store-based apps. Note: If you supply the @c AnalyticsParameterValue parameter, you must also +/// supply the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed +/// accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterAffiliation (String) (optional)
  • +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterEndDate (String) (optional)
  • +///
  • @c AnalyticsParameterItemID (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterShipping (Double) (optional)
  • +///
  • @c AnalyticsParameterStartDate (String) (optional)
  • +///
  • @c AnalyticsParameterTax (Double) (optional)
  • +///
  • @c AnalyticsParameterTransactionID (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventPurchase NS_SWIFT_NAME(AnalyticsEventPurchase) = @"purchase"; + +/// E-Commerce Refund event. This event signifies that a refund was issued. Note: If you supply the +/// @c AnalyticsParameterValue parameter, you must also supply the @c AnalyticsParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterAffiliation (String) (optional)
  • +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterShipping (Double) (optional)
  • +///
  • @c AnalyticsParameterTax (Double) (optional)
  • +///
  • @c AnalyticsParameterTransactionID (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventRefund NS_SWIFT_NAME(AnalyticsEventRefund) = @"refund"; + +/// E-Commerce Remove from Cart event. This event signifies that an item(s) was removed from a cart. +/// Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply the @c +/// AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventRemoveFromCart NS_SWIFT_NAME(AnalyticsEventRemoveFromCart) = + @"remove_from_cart"; + +/// Screen View event. This event signifies a screen view. Use this when a screen transition occurs. +/// This event can be logged irrespective of whether automatic screen tracking is enabled. Params: +/// +///
    +///
  • @c AnalyticsParameterScreenClass (String) (optional)
  • +///
  • @c AnalyticsParameterScreenName (String) (optional)
  • +///
+static NSString *const kFIREventScreenView NS_SWIFT_NAME(AnalyticsEventScreenView) = @"screen_view"; + +/// Search event. Apps that support search features can use this event to contextualize search +/// operations by supplying the appropriate, corresponding parameters. This event can help you +/// identify the most popular content in your app. Params: +/// +///
    +///
  • @c AnalyticsParameterSearchTerm (String)
  • +///
  • @c AnalyticsParameterStartDate (String) (optional)
  • +///
  • @c AnalyticsParameterEndDate (String) (optional)
  • +///
  • @c AnalyticsParameterNumberOfNights (Int) (optional) for hotel bookings
  • +///
  • @c AnalyticsParameterNumberOfRooms (Int) (optional) for hotel bookings
  • +///
  • @c AnalyticsParameterNumberOfPassengers (Int) (optional) for travel bookings
  • +///
  • @c AnalyticsParameterOrigin (String) (optional)
  • +///
  • @c AnalyticsParameterDestination (String) (optional)
  • +///
  • @c AnalyticsParameterTravelClass (String) (optional) for travel bookings
  • +///
+static NSString *const kFIREventSearch NS_SWIFT_NAME(AnalyticsEventSearch) = @"search"; + +/// Select Content event. This general purpose event signifies that a user has selected some content +/// of a certain type in an app. The content can be any object in your app. This event can help you +/// identify popular content and categories of content in your app. Params: +/// +///
    +///
  • @c AnalyticsParameterContentType (String)
  • +///
  • @c AnalyticsParameterItemID (String)
  • +///
+static NSString *const kFIREventSelectContent NS_SWIFT_NAME(AnalyticsEventSelectContent) = + @"select_content"; + +/// Select Item event. This event signifies that an item was selected by a user from a list. Use the +/// appropriate parameters to contextualize the event. Use this event to discover the most popular +/// items selected. Params: +/// +///
    +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterItemListID (String) (optional)
  • +///
  • @c AnalyticsParameterItemListName (String) (optional)
  • +///
+static NSString *const kFIREventSelectItem NS_SWIFT_NAME(AnalyticsEventSelectItem) = @"select_item"; + +/// Select promotion event. This event signifies that a user has selected a promotion offer. Use the +/// appropriate parameters to contextualize the event, such as the item(s) for which the promotion +/// applies. Params: +/// +///
    +///
  • @c AnalyticsParameterCreativeName (String) (optional)
  • +///
  • @c AnalyticsParameterCreativeSlot (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterLocationID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionName (String) (optional)
  • +///
+static NSString *const kFIREventSelectPromotion NS_SWIFT_NAME(AnalyticsEventSelectPromotion) = + @"select_promotion"; + +/// Share event. Apps with social features can log the Share event to identify the most viral +/// content. Params: +/// +///
    +///
  • @c AnalyticsParameterContentType (String)
  • +///
  • @c AnalyticsParameterItemID (String)
  • +///
+static NSString *const kFIREventShare NS_SWIFT_NAME(AnalyticsEventShare) = @"share"; + +/// Sign Up event. This event indicates that a user has signed up for an account in your app. The +/// parameter signifies the method by which the user signed up. Use this event to understand the +/// different behaviors between logged in and logged out users. Params: +/// +///
    +///
  • @c AnalyticsParameterMethod (String)
  • +///
+static NSString *const kFIREventSignUp NS_SWIFT_NAME(AnalyticsEventSignUp) = @"sign_up"; + +/// Spend Virtual Currency event. This event tracks the sale of virtual goods in your app and can +/// help you identify which virtual goods are the most popular objects of purchase. Params: +/// +///
    +///
  • @c AnalyticsParameterItemName (String)
  • +///
  • @c AnalyticsParameterVirtualCurrencyName (String)
  • +///
  • @c AnalyticsParameterValue (Int or Double)
  • +///
+static NSString *const kFIREventSpendVirtualCurrency + NS_SWIFT_NAME(AnalyticsEventSpendVirtualCurrency) = @"spend_virtual_currency"; + +/// Tutorial Begin event. This event signifies the start of the on-boarding process in your app. Use +/// this in a funnel with @c AnalyticsEventTutorialComplete to understand how many users complete +/// this process and move on to the full app experience. +static NSString *const kFIREventTutorialBegin NS_SWIFT_NAME(AnalyticsEventTutorialBegin) = + @"tutorial_begin"; + +/// Tutorial End event. Use this event to signify the user's completion of your app's on-boarding +/// process. Add this to a funnel with @c AnalyticsEventTutorialBegin to gauge the completion rate +/// of your on-boarding process. +static NSString *const kFIREventTutorialComplete NS_SWIFT_NAME(AnalyticsEventTutorialComplete) = + @"tutorial_complete"; + +/// Unlock Achievement event. Log this event when the user has unlocked an achievement in your +/// game. Since achievements generally represent the breadth of a gaming experience, this event can +/// help you understand how many users are experiencing all that your game has to offer. Params: +/// +///
    +///
  • @c AnalyticsParameterAchievementID (String)
  • +///
+static NSString *const kFIREventUnlockAchievement NS_SWIFT_NAME(AnalyticsEventUnlockAchievement) = + @"unlock_achievement"; + +/// E-commerce View Cart event. This event signifies that a user has viewed their cart. Use this to +/// analyze your purchase funnel. Note: If you supply the @c AnalyticsParameterValue parameter, you +/// must also supply the @c AnalyticsParameterCurrency parameter so that revenue metrics can be +/// computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventViewCart NS_SWIFT_NAME(AnalyticsEventViewCart) = @"view_cart"; + +/// View Item event. This event signifies that a user has viewed an item. Use the appropriate +/// parameters to contextualize the event. Use this event to discover the most popular items viewed +/// in your app. Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply +/// the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventViewItem NS_SWIFT_NAME(AnalyticsEventViewItem) = @"view_item"; + +/// View Item List event. Log this event when a user sees a list of items or offerings. Params: +/// +///
    +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterItemListID (String) (optional)
  • +///
  • @c AnalyticsParameterItemListName (String) (optional)
  • +///
+static NSString *const kFIREventViewItemList NS_SWIFT_NAME(AnalyticsEventViewItemList) = + @"view_item_list"; + +/// View Promotion event. This event signifies that a promotion was shown to a user. Add this event +/// to a funnel with the @c AnalyticsEventAddToCart and @c AnalyticsEventPurchase to gauge your +/// conversion process. Params: +/// +///
    +///
  • @c AnalyticsParameterCreativeName (String) (optional)
  • +///
  • @c AnalyticsParameterCreativeSlot (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterLocationID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionName (String) (optional)
  • +///
+static NSString *const kFIREventViewPromotion NS_SWIFT_NAME(AnalyticsEventViewPromotion) = + @"view_promotion"; + +/// View Search Results event. Log this event when the user has been presented with the results of a +/// search. Params: +/// +///
    +///
  • @c AnalyticsParameterSearchTerm (String)
  • +///
+static NSString *const kFIREventViewSearchResults NS_SWIFT_NAME(AnalyticsEventViewSearchResults) = + @"view_search_results"; diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIRParameterNames.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIRParameterNames.h new file mode 100644 index 0000000..b001ca5 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIRParameterNames.h @@ -0,0 +1,721 @@ +/// @file FIRParameterNames.h +/// +/// Predefined event parameter names. +/// +/// Params supply information that contextualize Events. You can associate up to 25 unique Params +/// with each Event type. Some Params are suggested below for certain common Events, but you are +/// not limited to these. You may supply extra Params for suggested Events or custom Params for +/// Custom events. Param names can be up to 40 characters long, may only contain alphanumeric +/// characters and underscores ("_"), and must start with an alphabetic character. Param values can +/// be up to 100 characters long. The "firebase_", "google_", and "ga_" prefixes are reserved and +/// should not be used. + +#import + +/// Game achievement ID (String). +///
+///     let params = [
+///       AnalyticsParameterAchievementID : "10_matches_won",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAchievementID NS_SWIFT_NAME(AnalyticsParameterAchievementID) = + @"achievement_id"; + +/// The ad format (e.g. Banner, Interstitial, Rewarded, Native, Rewarded Interstitial, Instream). +/// (String). +///
+///     let params = [
+///       AnalyticsParameterAdFormat : "Banner",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdFormat NS_SWIFT_NAME(AnalyticsParameterAdFormat) = + @"ad_format"; + +/// Ad Network Click ID (String). Used for network-specific click IDs which vary in format. +///
+///     let params = [
+///       AnalyticsParameterAdNetworkClickID : "1234567",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdNetworkClickID + NS_SWIFT_NAME(AnalyticsParameterAdNetworkClickID) = @"aclid"; + +/// The ad platform (e.g. MoPub, IronSource) (String). +///
+///     let params = [
+///       AnalyticsParameterAdPlatform : "MoPub",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdPlatform NS_SWIFT_NAME(AnalyticsParameterAdPlatform) = + @"ad_platform"; + +/// The ad source (e.g. AdColony) (String). +///
+///     let params = [
+///       AnalyticsParameterAdSource : "AdColony",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdSource NS_SWIFT_NAME(AnalyticsParameterAdSource) = + @"ad_source"; + +/// The ad unit name (e.g. Banner_03) (String). +///
+///     let params = [
+///       AnalyticsParameterAdUnitName : "Banner_03",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdUnitName NS_SWIFT_NAME(AnalyticsParameterAdUnitName) = + @"ad_unit_name"; + +/// A product affiliation to designate a supplying company or brick and mortar store location +/// (String).
+///     let params = [
+///       AnalyticsParameterAffiliation : "Google Store",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAffiliation NS_SWIFT_NAME(AnalyticsParameterAffiliation) = + @"affiliation"; + +/// Campaign custom parameter (String). Used as a method of capturing custom data in a campaign. +/// Use varies by network. +///
+///     let params = [
+///       AnalyticsParameterCP1 : "custom_data",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCP1 NS_SWIFT_NAME(AnalyticsParameterCP1) = @"cp1"; + +/// The individual campaign name, slogan, promo code, etc. Some networks have pre-defined macro to +/// capture campaign information, otherwise can be populated by developer. Highly Recommended +/// (String). +///
+///     let params = [
+///       AnalyticsParameterCampaign : "winter_promotion",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCampaign NS_SWIFT_NAME(AnalyticsParameterCampaign) = + @"campaign"; + +/// Campaign ID (String). Used for keyword analysis to identify a specific product promotion or +/// strategic campaign. This is a required key for GA4 data import. +///
+///     let params = [
+///       AnalyticsParameterCampaignID : "7877652710",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCampaignID NS_SWIFT_NAME(AnalyticsParameterCampaignID) = + @"campaign_id"; + +/// Character used in game (String). +///
+///     let params = [
+///       AnalyticsParameterCharacter : "beat_boss",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCharacter NS_SWIFT_NAME(AnalyticsParameterCharacter) = + @"character"; + +/// Campaign content (String). +static NSString *const kFIRParameterContent NS_SWIFT_NAME(AnalyticsParameterContent) = @"content"; + +/// Type of content selected (String). +///
+///     let params = [
+///       AnalyticsParameterContentType : "news article",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterContentType NS_SWIFT_NAME(AnalyticsParameterContentType) = + @"content_type"; + +/// Coupon code used for a purchase (String). +///
+///     let params = [
+///       AnalyticsParameterCoupon : "SUMMER_FUN",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCoupon NS_SWIFT_NAME(AnalyticsParameterCoupon) = @"coupon"; + +/// Creative Format (String). Used to identify the high-level classification of the type of ad +/// served by a specific campaign. +///
+///     let params = [
+///       AnalyticsParameterCreativeFormat : "display",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCreativeFormat NS_SWIFT_NAME(AnalyticsParameterCreativeFormat) = + @"creative_format"; + +/// The name of a creative used in a promotional spot (String). +///
+///     let params = [
+///       AnalyticsParameterCreativeName : "Summer Sale",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCreativeName NS_SWIFT_NAME(AnalyticsParameterCreativeName) = + @"creative_name"; + +/// The name of a creative slot (String). +///
+///     let params = [
+///       AnalyticsParameterCreativeSlot : "summer_banner2",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCreativeSlot NS_SWIFT_NAME(AnalyticsParameterCreativeSlot) = + @"creative_slot"; + +/// Currency of the purchase or items associated with the event, in 3-letter +/// ISO_4217 format (String). +///
+///     let params = [
+///       AnalyticsParameterCurrency : "USD",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCurrency NS_SWIFT_NAME(AnalyticsParameterCurrency) = + @"currency"; + +/// Flight or Travel destination (String). +///
+///     let params = [
+///       AnalyticsParameterDestination : "Mountain View, CA",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterDestination NS_SWIFT_NAME(AnalyticsParameterDestination) = + @"destination"; + +/// Monetary value of discount associated with a purchase (Double). +///
+///     let params = [
+///       AnalyticsParameterDiscount : 2.0,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $2.00 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterDiscount NS_SWIFT_NAME(AnalyticsParameterDiscount) = + @"discount"; + +/// The arrival date, check-out date or rental end date for the item. This should be in +/// YYYY-MM-DD format (String). +///
+///     let params = [
+///       AnalyticsParameterEndDate : "2015-09-14",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterEndDate NS_SWIFT_NAME(AnalyticsParameterEndDate) = @"end_date"; + +/// Indicates that the associated event should either extend the current session or start a new +/// session if no session was active when the event was logged. Specify 1 to extend the current +/// session or to start a new session; any other value will not extend or start a session. +///
+///     let params = [
+///       AnalyticsParameterExtendSession : 1,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterExtendSession NS_SWIFT_NAME(AnalyticsParameterExtendSession) = + @"extend_session"; + +/// Flight number for travel events (String). +///
+///     let params = [
+///       AnalyticsParameterFlightNumber : "ZZ800",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterFlightNumber NS_SWIFT_NAME(AnalyticsParameterFlightNumber) = + @"flight_number"; + +/// Group/clan/guild ID (String). +///
+///     let params = [
+///       AnalyticsParameterGroupID : "g1",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterGroupID NS_SWIFT_NAME(AnalyticsParameterGroupID) = @"group_id"; + +/// The index of the item in a list (Int). +///
+///     let params = [
+///       AnalyticsParameterIndex : 5,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterIndex NS_SWIFT_NAME(AnalyticsParameterIndex) = @"index"; + +/// Item brand (String). +///
+///     let params = [
+///       AnalyticsParameterItemBrand : "Google",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemBrand NS_SWIFT_NAME(AnalyticsParameterItemBrand) = + @"item_brand"; + +/// Item category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory NS_SWIFT_NAME(AnalyticsParameterItemCategory) = + @"item_category"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory2 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory2 NS_SWIFT_NAME(AnalyticsParameterItemCategory2) = + @"item_category2"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory3 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory3 NS_SWIFT_NAME(AnalyticsParameterItemCategory3) = + @"item_category3"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory4 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory4 NS_SWIFT_NAME(AnalyticsParameterItemCategory4) = + @"item_category4"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory5 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory5 NS_SWIFT_NAME(AnalyticsParameterItemCategory5) = + @"item_category5"; + +/// Item ID (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemID : "SKU_12345",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemID NS_SWIFT_NAME(AnalyticsParameterItemID) = @"item_id"; + +/// The ID of the list in which the item was presented to the user (String). +///
+///     let params = [
+///       AnalyticsParameterItemListID : "ABC123",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemListID NS_SWIFT_NAME(AnalyticsParameterItemListID) = + @"item_list_id"; + +/// The name of the list in which the item was presented to the user (String). +///
+///     let params = [
+///       AnalyticsParameterItemListName : "Related products",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemListName NS_SWIFT_NAME(AnalyticsParameterItemListName) = + @"item_list_name"; + +/// Item Name (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemName : "jeggings",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemName NS_SWIFT_NAME(AnalyticsParameterItemName) = + @"item_name"; + +/// Item variant (String). +///
+///     let params = [
+///       AnalyticsParameterItemVariant : "Black",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemVariant NS_SWIFT_NAME(AnalyticsParameterItemVariant) = + @"item_variant"; + +/// The list of items involved in the transaction expressed as `[[String: Any]]`. +///
+///     let params = [
+///       AnalyticsParameterItems : [
+///         [AnalyticsParameterItemName : "jeggings", AnalyticsParameterItemCategory : "pants"],
+///         [AnalyticsParameterItemName : "boots", AnalyticsParameterItemCategory : "shoes"],
+///       ],
+///     ]
+/// 
+static NSString *const kFIRParameterItems NS_SWIFT_NAME(AnalyticsParameterItems) = @"items"; + +/// Level in game (Int). +///
+///     let params = [
+///       AnalyticsParameterLevel : 42,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLevel NS_SWIFT_NAME(AnalyticsParameterLevel) = @"level"; + +/// The name of a level in a game (String). +///
+///     let params = [
+///       AnalyticsParameterLevelName : "room_1",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLevelName NS_SWIFT_NAME(AnalyticsParameterLevelName) = + @"level_name"; + +/// Location (String). The Google Place ID +/// that corresponds to the associated event. Alternatively, you can supply your own custom +/// Location ID. +///
+///     let params = [
+///       AnalyticsParameterLocation : "ChIJiyj437sx3YAR9kUWC8QkLzQ",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLocation NS_SWIFT_NAME(AnalyticsParameterLocation) = + @"location"; + +/// The location associated with the event. Preferred to be the Google +/// Place ID that corresponds to the +/// associated item but could be overridden to a custom location ID string.(String). +///
+///     let params = [
+///       AnalyticsParameterLocationID : "ChIJiyj437sx3YAR9kUWC8QkLzQ",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLocationID NS_SWIFT_NAME(AnalyticsParameterLocationID) = + @"location_id"; + +/// Marketing Tactic (String). Used to identify the targeting criteria applied to a specific +/// campaign. +///
+///     let params = [
+///       AnalyticsParameterMarketingTactic : "Remarketing",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterMarketingTactic + NS_SWIFT_NAME(AnalyticsParameterMarketingTactic) = @"marketing_tactic"; + +/// The advertising or marketing medium, for example: cpc, banner, email, push. Highly recommended +/// (String). +///
+///     let params = [
+///       AnalyticsParameterMedium : "email",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterMedium NS_SWIFT_NAME(AnalyticsParameterMedium) = @"medium"; + +/// A particular approach used in an operation; for example, "facebook" or "email" in the context +/// of a sign_up or login event. (String). +///
+///     let params = [
+///       AnalyticsParameterMethod : "google",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterMethod NS_SWIFT_NAME(AnalyticsParameterMethod) = @"method"; + +/// Number of nights staying at hotel (Int). +///
+///     let params = [
+///       AnalyticsParameterNumberOfNights : 3,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterNumberOfNights + NS_SWIFT_NAME(AnalyticsParameterNumberOfNights) = @"number_of_nights"; + +/// Number of passengers traveling (Int). +///
+///     let params = [
+///       AnalyticsParameterNumberOfPassengers : 11,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterNumberOfPassengers + NS_SWIFT_NAME(AnalyticsParameterNumberOfPassengers) = @"number_of_passengers"; + +/// Number of rooms for travel events (Int). +///
+///     let params = [
+///       AnalyticsParameterNumberOfRooms : 2,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterNumberOfRooms NS_SWIFT_NAME(AnalyticsParameterNumberOfRooms) = + @"number_of_rooms"; + +/// Flight or Travel origin (String). +///
+///     let params = [
+///       AnalyticsParameterOrigin : "Mountain View, CA",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterOrigin NS_SWIFT_NAME(AnalyticsParameterOrigin) = @"origin"; + +/// The chosen method of payment (String). +///
+///     let params = [
+///       AnalyticsParameterPaymentType : "Visa",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPaymentType NS_SWIFT_NAME(AnalyticsParameterPaymentType) = + @"payment_type"; + +/// Purchase price (Double). +///
+///     let params = [
+///       AnalyticsParameterPrice : 1.0,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $1.00 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPrice NS_SWIFT_NAME(AnalyticsParameterPrice) = @"price"; + +/// The ID of a product promotion (String). +///
+///     let params = [
+///       AnalyticsParameterPromotionID : "ABC123",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPromotionID NS_SWIFT_NAME(AnalyticsParameterPromotionID) = + @"promotion_id"; + +/// The name of a product promotion (String). +///
+///     let params = [
+///       AnalyticsParameterPromotionName : "Summer Sale",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPromotionName NS_SWIFT_NAME(AnalyticsParameterPromotionName) = + @"promotion_name"; + +/// Purchase quantity (Int). +///
+///     let params = [
+///       AnalyticsParameterQuantity : 1,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterQuantity NS_SWIFT_NAME(AnalyticsParameterQuantity) = + @"quantity"; + +/// Score in game (Int). +///
+///     let params = [
+///       AnalyticsParameterScore : 4200,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterScore NS_SWIFT_NAME(AnalyticsParameterScore) = @"score"; + +/// Current screen class, such as the class name of the UIViewController, logged with screen_view +/// event and added to every event (String). +///
+///     let params = [
+///       AnalyticsParameterScreenClass : "LoginViewController",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterScreenClass NS_SWIFT_NAME(AnalyticsParameterScreenClass) = + @"screen_class"; + +/// Current screen name, such as the name of the UIViewController, logged with screen_view event and +/// added to every event (String). +///
+///     let params = [
+///       AnalyticsParameterScreenName : "LoginView",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterScreenName NS_SWIFT_NAME(AnalyticsParameterScreenName) = + @"screen_name"; + +/// The search string/keywords used (String). +///
+///     let params = [
+///       AnalyticsParameterSearchTerm : "periodic table",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSearchTerm NS_SWIFT_NAME(AnalyticsParameterSearchTerm) = + @"search_term"; + +/// Shipping cost associated with a transaction (Double). +///
+///     let params = [
+///       AnalyticsParameterShipping : 5.99,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $5.99 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterShipping NS_SWIFT_NAME(AnalyticsParameterShipping) = + @"shipping"; + +/// The shipping tier (e.g. Ground, Air, Next-day) selected for delivery of the purchased item +/// (String). +///
+///     let params = [
+///       AnalyticsParameterShippingTier : "Ground",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterShippingTier NS_SWIFT_NAME(AnalyticsParameterShippingTier) = + @"shipping_tier"; + +/// The origin of your traffic, such as an Ad network (for example, google) or partner (urban +/// airship). Identify the advertiser, site, publication, etc. that is sending traffic to your +/// property. Highly recommended (String). +///
+///     let params = [
+///       AnalyticsParameterSource : "InMobi",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSource NS_SWIFT_NAME(AnalyticsParameterSource) = @"source"; + +/// Source Platform (String). Used to identify the platform responsible for directing traffic to a +/// given Analytics property (e.g., a buying platform where budgets, targeting criteria, etc. are +/// set, a platform for managing organic traffic data, etc.). +///
+///     let params = [
+///       AnalyticsParameterSourcePlatform : "sa360",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSourcePlatform NS_SWIFT_NAME(AnalyticsParameterSourcePlatform) = + @"source_platform"; + +/// The departure date, check-in date or rental start date for the item. This should be in +/// YYYY-MM-DD format (String). +///
+///     let params = [
+///       AnalyticsParameterStartDate : "2015-09-14",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterStartDate NS_SWIFT_NAME(AnalyticsParameterStartDate) = + @"start_date"; + +/// The result of an operation. Specify 1 to indicate success and 0 to indicate failure (Int). +///
+///     let params = [
+///       AnalyticsParameterSuccess : 1,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSuccess NS_SWIFT_NAME(AnalyticsParameterSuccess) = @"success"; + +/// Tax cost associated with a transaction (Double). +///
+///     let params = [
+///       AnalyticsParameterTax : 2.43,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $2.43 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTax NS_SWIFT_NAME(AnalyticsParameterTax) = @"tax"; + +/// If you're manually tagging keyword campaigns, you should use utm_term to specify the keyword +/// (String). +///
+///     let params = [
+///       AnalyticsParameterTerm : "game",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTerm NS_SWIFT_NAME(AnalyticsParameterTerm) = @"term"; + +/// The unique identifier of a transaction (String). +///
+///     let params = [
+///       AnalyticsParameterTransactionID : "T12345",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTransactionID NS_SWIFT_NAME(AnalyticsParameterTransactionID) = + @"transaction_id"; + +/// Travel class (String). +///
+///     let params = [
+///       AnalyticsParameterTravelClass : "business",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTravelClass NS_SWIFT_NAME(AnalyticsParameterTravelClass) = + @"travel_class"; + +/// A context-specific numeric value which is accumulated automatically for each event type. This is +/// a general purpose parameter that is useful for accumulating a key metric that pertains to an +/// event. Examples include revenue, distance, time and points. Value should be specified as Int or +/// Double. +/// Notes: Values for pre-defined currency-related events (such as @c AnalyticsEventAddToCart) +/// should be supplied using Double and must be accompanied by a @c AnalyticsParameterCurrency +/// parameter. The valid range of accumulated values is +/// [-9,223,372,036,854.77, 9,223,372,036,854.77]. Supplying a non-numeric value, omitting the +/// corresponding @c AnalyticsParameterCurrency parameter, or supplying an invalid +/// currency code for conversion events will cause that +/// conversion to be omitted from reporting. +///
+///     let params = [
+///       AnalyticsParameterValue : 3.99,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $3.99 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterValue NS_SWIFT_NAME(AnalyticsParameterValue) = @"value"; + +/// Name of virtual currency type (String). +///
+///     let params = [
+///       AnalyticsParameterVirtualCurrencyName : "virtual_currency_name",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterVirtualCurrencyName + NS_SWIFT_NAME(AnalyticsParameterVirtualCurrencyName) = @"virtual_currency_name"; diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h new file mode 100644 index 0000000..2442d8a --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h @@ -0,0 +1,28 @@ +/// @file FIRUserPropertyNames.h +/// +/// Predefined user property names. +/// +/// A UserProperty is an attribute that describes the app-user. By supplying UserProperties, you can +/// later analyze different behaviors of various segments of your userbase. You may supply up to 25 +/// unique UserProperties per app, and you can use the name and value of your choosing for each one. +/// UserProperty names can be up to 24 characters long, may only contain alphanumeric characters and +/// underscores ("_"), and must start with an alphabetic character. UserProperty values can be up to +/// 36 characters long. The "firebase_", "google_", and "ga_" prefixes are reserved and should not +/// be used. + +#import + +/// Indicates whether events logged by Google Analytics can be used to personalize ads for the user. +/// Set to "YES" to enable, or "NO" to disable. Default is enabled. See the +/// documentation for +/// more details and information about related settings. +/// +///
+///     Analytics.setUserProperty("NO", forName: AnalyticsUserPropertyAllowAdPersonalizationSignals)
+/// 
+static NSString *const kFIRUserPropertyAllowAdPersonalizationSignals + NS_SWIFT_NAME(AnalyticsUserPropertyAllowAdPersonalizationSignals) = @"allow_personalized_ads"; + +/// The method used to sign in. For example, "google", "facebook" or "twitter". +static NSString *const kFIRUserPropertySignUpMethod + NS_SWIFT_NAME(AnalyticsUserPropertySignUpMethod) = @"sign_up_method"; diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-umbrella.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-umbrella.h new file mode 100644 index 0000000..ad84fbb --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-umbrella.h @@ -0,0 +1,24 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "FIRAnalytics+AppDelegate.h" +#import "FIRAnalytics+Consent.h" +#import "FIRAnalytics+OnDevice.h" +#import "FIRAnalytics.h" +#import "FirebaseAnalytics.h" +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" + +FOUNDATION_EXPORT double FirebaseAnalyticsVersionNumber; +FOUNDATION_EXPORT const unsigned char FirebaseAnalyticsVersionString[]; + diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h new file mode 100644 index 0000000..351da20 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h @@ -0,0 +1,7 @@ +#import "FIRAnalytics+AppDelegate.h" +#import "FIRAnalytics+Consent.h" +#import "FIRAnalytics+OnDevice.h" +#import "FIRAnalytics.h" +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Info.plist b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Info.plist new file mode 100644 index 0000000..1674c5f --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleExecutable + FirebaseAnalytics + CFBundleIdentifier + com.firebase.Firebase-FirebaseAnalytics + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + FirebaseAnalytics + CFBundlePackageType + FMWK + CFBundleVersion + 10.11.0 + DTSDKName + iphonesimulator11.2 + + diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Modules/module.modulemap b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Modules/module.modulemap new file mode 100644 index 0000000..37eb24b --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Modules/module.modulemap @@ -0,0 +1,12 @@ +framework module FirebaseAnalytics { +umbrella header "FirebaseAnalytics-umbrella.h" +export * +module * { export * } + link framework "Foundation" + link framework "Security" + link framework "SystemConfiguration" + link framework "UIKit" + link "c++" + link "sqlite3" + link "z" +} diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/FirebaseAnalytics b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/FirebaseAnalytics new file mode 100644 index 0000000..36c0973 Binary files /dev/null and b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/FirebaseAnalytics differ diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h new file mode 100644 index 0000000..cb1e407 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h @@ -0,0 +1,80 @@ +#import + +#import "FIRAnalytics.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Provides App Delegate handlers to be used in your App Delegate. +/// +/// To save time integrating Firebase Analytics in an application, Firebase Analytics does not +/// require delegation implementation from the AppDelegate if neither SwiftUI nor UIScene lifecycle +/// is adopted. Instead this is automatically done by Firebase Analytics. Should you choose instead +/// to delegate manually, you can turn off the App Delegate Proxy by adding +/// FirebaseAppDelegateProxyEnabled into your app's Info.plist and setting it to boolean `NO`, and +/// adding the methods in this category to corresponding delegation handlers. +/// +/// To handle Universal Links, you must return `true` in +/// `UIApplicationDelegate.application(_:didFinishLaunchingWithOptions:)`. +@interface FIRAnalytics (AppDelegate) + +/// Handles events related to a URL session that are waiting to be processed. +/// +/// 1. If SwiftUI lifecycle is adopted, call this method from +/// `UIApplicationDelegate.application(_:handleEventsForBackgroundURLSession:completionHandler:)` +/// in your app delegate. +/// +/// 2. If SwiftUI lifecycle is not adopted, Firebase Analytics does not require delegation +/// implementation from the AppDelegate. If you choose instead to delegate manually, you can set +/// FirebaseAppDelegateProxyEnabled to boolean `NO` in your app's Info.plist and call this method +/// from +/// `UIApplicationDelegate.application(_:handleEventsForBackgroundURLSession:completionHandler:)` +/// in your app delegate. +/// +/// @param identifier The identifier of the URL session requiring attention. +/// @param completionHandler The completion handler to call when you finish processing the events. +/// Calling this completion handler lets the system know that your app's user interface is +/// updated and a new snapshot can be taken. ++ (void)handleEventsForBackgroundURLSession:(NSString *)identifier + completionHandler:(nullable void (^)(void))completionHandler; + +/// Handles the event when the app is launched by a URL (custom URL scheme or universal link). +/// +/// 1. If SwiftUI lifecycle is adopted, use `onOpenURL(perform:)` to register a handler and call +/// this method in the handler. +/// +/// 2. If UIScene lifecycle is adopted, call this method from +/// `UISceneDelegate.scene(_:willConnectTo:options:)` and +/// `UISceneDelegate.scene(_:openURLContexts:)` when the URL contexts are available. +/// +/// 3. If neither SwiftUI nor UIScene lifecycle is adopted, Firebase Analytics does not require +/// delegation implementation from the AppDelegate. If you choose instead to delegate manually, you +/// can set FirebaseAppDelegateProxyEnabled to boolean `NO` in your app's Info.plist and call this +/// method from `UIApplicationDelegate.application(_:open:options:)` in your app delegate. +/// +/// @param url The URL resource to open. This resource can be a network resource or a file. ++ (void)handleOpenURL:(NSURL *)url; + +/// Handles the event when the app receives data associated with user activity that includes a +/// Universal Link. +/// +/// 1. If SwiftUI lifecycle is adopted, use `onOpenURL(perform:)` to register a handler and call +/// `Analytics.handleOpen(_:)` instead in the handler. +/// +/// 2. If UIScene lifecycle is adopted, call this method from +/// `UISceneDelegate.scene(_:willConnectTo:options:)` and `UISceneDelegate.scene(_:continue:)` when +/// NSUserActivity is available. See the [Apple +/// doc](https://developer.apple.com/documentation/xcode/supporting-universal-links-in-your-app) for +/// more details. +/// +/// 3. If neither SwiftUI nor UIScene lifecycle is adopted, Firebase Analytics does not require +/// delegation implementation from the AppDelegate. If you choose instead to delegate manually, you +/// can set FirebaseAppDelegateProxyEnabled to boolean `NO` in your app's Info.plist and call this +/// method from `UIApplication.application(_:continue:restorationHandler:)` in your app delegate. +/// +/// @param userActivity The activity object containing the data associated with the task the user +/// was performing. ++ (void)handleUserActivity:(id)userActivity; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Headers/FIRAnalytics+Consent.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Headers/FIRAnalytics+Consent.h new file mode 100644 index 0000000..7f89831 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Headers/FIRAnalytics+Consent.h @@ -0,0 +1,33 @@ +#import + +#import "FIRAnalytics.h" + +NS_ASSUME_NONNULL_BEGIN + +/// The type of consent to set. Supported consent types are `ConsentType.adStorage` and +/// `ConsentType.analyticsStorage`. Omitting a type retains its previous status. +typedef NSString *FIRConsentType NS_TYPED_ENUM NS_SWIFT_NAME(ConsentType); +extern FIRConsentType const FIRConsentTypeAdStorage; +extern FIRConsentType const FIRConsentTypeAnalyticsStorage; + +/// The status value of the consent type. Supported statuses are `ConsentStatus.granted` and +/// `ConsentStatus.denied`. +typedef NSString *FIRConsentStatus NS_TYPED_ENUM NS_SWIFT_NAME(ConsentStatus); +extern FIRConsentStatus const FIRConsentStatusDenied; +extern FIRConsentStatus const FIRConsentStatusGranted; + +/// Sets the applicable end user consent state. +@interface FIRAnalytics (Consent) + +/// Sets the applicable end user consent state (e.g. for device identifiers) for this app on this +/// device. Use the consent settings to specify individual consent type values. Settings are +/// persisted across app sessions. By default consent types are set to `ConsentStatus.granted`. +/// +/// @param consentSettings A Dictionary of consent types. Supported consent type keys are +/// `ConsentType.adStorage` and `ConsentType.analyticsStorage`. Valid values are +/// `ConsentStatus.granted` and `ConsentStatus.denied`. ++ (void)setConsent:(NSDictionary *)consentSettings; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Headers/FIRAnalytics+OnDevice.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Headers/FIRAnalytics+OnDevice.h new file mode 100644 index 0000000..1d9a438 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Headers/FIRAnalytics+OnDevice.h @@ -0,0 +1,19 @@ +#import + +#import "FIRAnalytics.h" + +NS_ASSUME_NONNULL_BEGIN + +API_UNAVAILABLE(macCatalyst, macos, tvos, watchos) +@interface FIRAnalytics (OnDevice) + +/// Initiates on-device conversion measurement given a user email address. Requires dependency +/// GoogleAppMeasurementOnDeviceConversion to be linked in, otherwise it is a no-op. +/// @param emailAddress User email address. Include a domain name for all email addresses +/// (e.g. gmail.com or hotmail.co.jp). ++ (void)initiateOnDeviceConversionMeasurementWithEmailAddress:(NSString *)emailAddress + NS_SWIFT_NAME(initiateOnDeviceConversionMeasurement(emailAddress:)); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Headers/FIRAnalytics.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Headers/FIRAnalytics.h new file mode 100644 index 0000000..e7ce5dc --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Headers/FIRAnalytics.h @@ -0,0 +1,154 @@ +#import + +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" + +NS_ASSUME_NONNULL_BEGIN + +/// The top level Firebase Analytics singleton that provides methods for logging events and setting +/// user properties. See the developer guides for general +/// information on using Firebase Analytics in your apps. +/// +/// @note The Analytics SDK uses SQLite to persist events and other app-specific data. Calling +/// certain thread-unsafe global SQLite methods like `sqlite3_shutdown()` can result in +/// unexpected crashes at runtime. +NS_SWIFT_NAME(Analytics) +@interface FIRAnalytics : NSObject + +/// Logs an app event. The event can have up to 25 parameters. Events with the same name must have +/// the same parameters. Up to 500 event names are supported. Using predefined events and/or +/// parameters is recommended for optimal reporting. +/// +/// The following event names are reserved and cannot be used: +///
    +///
  • ad_activeview
  • +///
  • ad_click
  • +///
  • ad_exposure
  • +///
  • ad_query
  • +///
  • ad_reward
  • +///
  • adunit_exposure
  • +///
  • app_clear_data
  • +///
  • app_exception
  • +///
  • app_remove
  • +///
  • app_store_refund
  • +///
  • app_store_subscription_cancel
  • +///
  • app_store_subscription_convert
  • +///
  • app_store_subscription_renew
  • +///
  • app_update
  • +///
  • app_upgrade
  • +///
  • dynamic_link_app_open
  • +///
  • dynamic_link_app_update
  • +///
  • dynamic_link_first_open
  • +///
  • error
  • +///
  • firebase_campaign
  • +///
  • first_open
  • +///
  • first_visit
  • +///
  • in_app_purchase
  • +///
  • notification_dismiss
  • +///
  • notification_foreground
  • +///
  • notification_open
  • +///
  • notification_receive
  • +///
  • os_update
  • +///
  • session_start
  • +///
  • session_start_with_rollout
  • +///
  • user_engagement
  • +///
+/// +/// @param name The name of the event. Should contain 1 to 40 alphanumeric characters or +/// underscores. The name must start with an alphabetic character. Some event names are +/// reserved. See FIREventNames.h for the list of reserved event names. The "firebase_", +/// "google_", and "ga_" prefixes are reserved and should not be used. Note that event names are +/// case-sensitive and that logging two events whose names differ only in case will result in +/// two distinct events. To manually log screen view events, use the `screen_view` event name. +/// @param parameters The dictionary of event parameters. Passing `nil` indicates that the event has +/// no parameters. Parameter names can be up to 40 characters long and must start with an +/// alphabetic character and contain only alphanumeric characters and underscores. Only String, +/// Int, and Double parameter types are supported. String parameter values can be up to 100 +/// characters long. The "firebase_", "google_", and "ga_" prefixes are reserved and should not +/// be used for parameter names. ++ (void)logEventWithName:(NSString *)name + parameters:(nullable NSDictionary *)parameters + NS_SWIFT_NAME(logEvent(_:parameters:)); + +/// Sets a user property to a given value. Up to 25 user property names are supported. Once set, +/// user property values persist throughout the app lifecycle and across sessions. +/// +/// The following user property names are reserved and cannot be used: +///
    +///
  • first_open_time
  • +///
  • last_deep_link_referrer
  • +///
  • user_id
  • +///
+/// +/// @param value The value of the user property. Values can be up to 36 characters long. Setting the +/// value to `nil` removes the user property. +/// @param name The name of the user property to set. Should contain 1 to 24 alphanumeric characters +/// or underscores and must start with an alphabetic character. The "firebase_", "google_", and +/// "ga_" prefixes are reserved and should not be used for user property names. ++ (void)setUserPropertyString:(nullable NSString *)value forName:(NSString *)name + NS_SWIFT_NAME(setUserProperty(_:forName:)); + +/// Sets the user ID property. This feature must be used in accordance with +/// Google's Privacy Policy +/// +/// @param userID The user ID to ascribe to the user of this app on this device, which must be +/// non-empty and no more than 256 characters long. Setting userID to `nil` removes the user ID. ++ (void)setUserID:(nullable NSString *)userID; + +/// Sets whether analytics collection is enabled for this app on this device. This setting is +/// persisted across app sessions. By default it is enabled. +/// +/// @param analyticsCollectionEnabled A flag that enables or disables Analytics collection. ++ (void)setAnalyticsCollectionEnabled:(BOOL)analyticsCollectionEnabled; + +/// Sets the interval of inactivity in seconds that terminates the current session. The default +/// value is 1800 seconds (30 minutes). +/// +/// @param sessionTimeoutInterval The custom time of inactivity in seconds before the current +/// session terminates. ++ (void)setSessionTimeoutInterval:(NSTimeInterval)sessionTimeoutInterval; + +/// Asynchronously retrieves the identifier of the current app session. +/// +/// The session ID retrieval could fail due to Analytics collection disabled, app session expired, +/// etc. +/// +/// @param completion The completion handler to call when the session ID retrieval is complete. This +/// handler is executed on a system-defined global concurrent queue. +/// This completion handler takes the following parameters: +/// sessionID The identifier of the current app session. The value is undefined if the +/// request failed. +/// error An error object that indicates why the request failed, or `nil` if the request +/// was successful. ++ (void)sessionIDWithCompletion:(void (^)(int64_t sessionID, NSError *_Nullable error))completion; + +/// Returns the unique ID for this instance of the application or `nil` if +/// `ConsentType.analyticsStorage` has been set to `ConsentStatus.denied`. +/// +/// @see `FIRAnalytics+Consent.h` ++ (nullable NSString *)appInstanceID; + +/// Clears all analytics data for this instance from the device and resets the app instance ID. ++ (void)resetAnalyticsData; + +/// Adds parameters that will be set on every event logged from the SDK, including automatic ones. +/// The values passed in the parameters dictionary will be added to the dictionary of default event +/// parameters. These parameters persist across app runs. They are of lower precedence than event +/// parameters, so if an event parameter and a parameter set using this API have the same name, the +/// value of the event parameter will be used. The same limitations on event parameters apply to +/// default event parameters. +/// +/// @param parameters Parameters to be added to the dictionary of parameters added to every event. +/// They will be added to the dictionary of default event parameters, replacing any existing +/// parameter with the same name. Valid parameters are String, Int, and Double. Setting a key's +/// value to `NSNull()` will clear that parameter. Passing in a `nil` dictionary will clear all +/// parameters. ++ (void)setDefaultEventParameters:(nullable NSDictionary *)parameters; + +/// Unavailable. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Headers/FIREventNames.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Headers/FIREventNames.h new file mode 100644 index 0000000..1e69a44 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Headers/FIREventNames.h @@ -0,0 +1,418 @@ +/// @file FIREventNames.h +/// +/// Predefined event names. +/// +/// An Event is an important occurrence in your app that you want to measure. You can report up to +/// 500 different types of Events per app and you can associate up to 25 unique parameters with each +/// Event type. Some common events are suggested below, but you may also choose to specify custom +/// Event types that are associated with your specific app. Each event type is identified by a +/// unique name. Event names can be up to 40 characters long, may only contain alphanumeric +/// characters and underscores ("_"), and must start with an alphabetic character. The "firebase_", +/// "google_", and "ga_" prefixes are reserved and should not be used. + +#import + +/// Ad Impression event. This event signifies when a user sees an ad impression. Note: If you supply +/// the @c AnalyticsParameterValue parameter, you must also supply the @c AnalyticsParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterAdPlatform (String) (optional)
  • +///
  • @c AnalyticsParameterAdFormat (String) (optional)
  • +///
  • @c AnalyticsParameterAdSource (String) (optional)
  • +///
  • @c AnalyticsParameterAdUnitName (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAdImpression NS_SWIFT_NAME(AnalyticsEventAdImpression) = + @"ad_impression"; + +/// Add Payment Info event. This event signifies that a user has submitted their payment +/// information. Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply +/// the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterPaymentType (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddPaymentInfo NS_SWIFT_NAME(AnalyticsEventAddPaymentInfo) = + @"add_payment_info"; + +/// Add Shipping Info event. This event signifies that a user has submitted their shipping +/// information. Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply +/// the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterShippingTier (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddShippingInfo NS_SWIFT_NAME(AnalyticsEventAddShippingInfo) = + @"add_shipping_info"; + +/// E-Commerce Add To Cart event. This event signifies that an item(s) was added to a cart for +/// purchase. Add this event to a funnel with @c AnalyticsEventPurchase to gauge the effectiveness +/// of your checkout process. Note: If you supply the @c AnalyticsParameterValue parameter, you must +/// also supply the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed +/// accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddToCart NS_SWIFT_NAME(AnalyticsEventAddToCart) = @"add_to_cart"; + +/// E-Commerce Add To Wishlist event. This event signifies that an item was added to a wishlist. Use +/// this event to identify popular gift items. Note: If you supply the @c AnalyticsParameterValue +/// parameter, you must also supply the @c AnalyticsParameterCurrency parameter so that revenue +/// metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddToWishlist NS_SWIFT_NAME(AnalyticsEventAddToWishlist) = + @"add_to_wishlist"; + +/// App Open event. By logging this event when an App becomes active, developers can understand how +/// often users leave and return during the course of a Session. Although Sessions are automatically +/// reported, this event can provide further clarification around the continuous engagement of +/// app-users. +static NSString *const kFIREventAppOpen NS_SWIFT_NAME(AnalyticsEventAppOpen) = @"app_open"; + +/// E-Commerce Begin Checkout event. This event signifies that a user has begun the process of +/// checking out. Add this event to a funnel with your @c AnalyticsEventPurchase event to gauge the +/// effectiveness of your checkout process. Note: If you supply the @c AnalyticsParameterValue +/// parameter, you must also supply the @c AnalyticsParameterCurrency parameter so that revenue +/// metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventBeginCheckout NS_SWIFT_NAME(AnalyticsEventBeginCheckout) = + @"begin_checkout"; + +/// Campaign Detail event. Log this event to supply the referral details of a re-engagement +/// campaign. Note: you must supply at least one of the required parameters +/// AnalyticsParameterSource, AnalyticsParameterMedium or AnalyticsParameterCampaign. Params: +/// +///
    +///
  • @c AnalyticsParameterSource (String)
  • +///
  • @c AnalyticsParameterMedium (String)
  • +///
  • @c AnalyticsParameterCampaign (String)
  • +///
  • @c AnalyticsParameterTerm (String) (optional)
  • +///
  • @c AnalyticsParameterContent (String) (optional)
  • +///
  • @c AnalyticsParameterAdNetworkClickID (String) (optional)
  • +///
  • @c AnalyticsParameterCP1 (String) (optional)
  • +///
  • @c AnalyticsParameterCampaignID (String) (optional)
  • +///
  • @c AnalyticsParameterCreativeFormat (String) (optional)
  • +///
  • @c AnalyticsParameterMarketingTactic (String) (optional)
  • +///
  • @c AnalyticsParameterSourcePlatform (String) (optional)
  • +///
+static NSString *const kFIREventCampaignDetails NS_SWIFT_NAME(AnalyticsEventCampaignDetails) = + @"campaign_details"; + +/// Earn Virtual Currency event. This event tracks the awarding of virtual currency in your app. Log +/// this along with @c AnalyticsEventSpendVirtualCurrency to better understand your virtual economy. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterVirtualCurrencyName (String)
  • +///
  • @c AnalyticsParameterValue (Int or Double)
  • +///
+static NSString *const kFIREventEarnVirtualCurrency + NS_SWIFT_NAME(AnalyticsEventEarnVirtualCurrency) = @"earn_virtual_currency"; + +/// Generate Lead event. Log this event when a lead has been generated in the app to understand the +/// efficacy of your install and re-engagement campaigns. Note: If you supply the +/// @c AnalyticsParameterValue parameter, you must also supply the @c AnalyticsParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventGenerateLead NS_SWIFT_NAME(AnalyticsEventGenerateLead) = + @"generate_lead"; + +/// Join Group event. Log this event when a user joins a group such as a guild, team or family. Use +/// this event to analyze how popular certain groups or social features are in your app. Params: +/// +///
    +///
  • @c AnalyticsParameterGroupID (String)
  • +///
+static NSString *const kFIREventJoinGroup NS_SWIFT_NAME(AnalyticsEventJoinGroup) = @"join_group"; + +/// Level End event. Log this event when the user finishes a level. Params: +/// +///
    +///
  • @c AnalyticsParameterLevelName (String)
  • +///
  • @c AnalyticsParameterSuccess (String)
  • +///
+static NSString *const kFIREventLevelEnd NS_SWIFT_NAME(AnalyticsEventLevelEnd) = @"level_end"; + +/// Level Start event. Log this event when the user starts a new level. Params: +/// +///
    +///
  • @c AnalyticsParameterLevelName (String)
  • +///
+static NSString *const kFIREventLevelStart NS_SWIFT_NAME(AnalyticsEventLevelStart) = @"level_start"; + +/// Level Up event. This event signifies that a player has leveled up in your gaming app. It can +/// help you gauge the level distribution of your userbase and help you identify certain levels that +/// are difficult to pass. Params: +/// +///
    +///
  • @c AnalyticsParameterLevel (Int)
  • +///
  • @c AnalyticsParameterCharacter (String) (optional)
  • +///
+static NSString *const kFIREventLevelUp NS_SWIFT_NAME(AnalyticsEventLevelUp) = @"level_up"; + +/// Login event. Apps with a login feature can report this event to signify that a user has logged +/// in. +static NSString *const kFIREventLogin NS_SWIFT_NAME(AnalyticsEventLogin) = @"login"; + +/// Post Score event. Log this event when the user posts a score in your gaming app. This event can +/// help you understand how users are actually performing in your game and it can help you correlate +/// high scores with certain audiences or behaviors. Params: +/// +///
    +///
  • @c AnalyticsParameterScore (Int)
  • +///
  • @c AnalyticsParameterLevel (Int) (optional)
  • +///
  • @c AnalyticsParameterCharacter (String) (optional)
  • +///
+static NSString *const kFIREventPostScore NS_SWIFT_NAME(AnalyticsEventPostScore) = @"post_score"; + +/// E-Commerce Purchase event. This event signifies that an item(s) was purchased by a user. Note: +/// This is different from the in-app purchase event, which is reported automatically for App +/// Store-based apps. Note: If you supply the @c AnalyticsParameterValue parameter, you must also +/// supply the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed +/// accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterAffiliation (String) (optional)
  • +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterEndDate (String) (optional)
  • +///
  • @c AnalyticsParameterItemID (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterShipping (Double) (optional)
  • +///
  • @c AnalyticsParameterStartDate (String) (optional)
  • +///
  • @c AnalyticsParameterTax (Double) (optional)
  • +///
  • @c AnalyticsParameterTransactionID (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventPurchase NS_SWIFT_NAME(AnalyticsEventPurchase) = @"purchase"; + +/// E-Commerce Refund event. This event signifies that a refund was issued. Note: If you supply the +/// @c AnalyticsParameterValue parameter, you must also supply the @c AnalyticsParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterAffiliation (String) (optional)
  • +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterShipping (Double) (optional)
  • +///
  • @c AnalyticsParameterTax (Double) (optional)
  • +///
  • @c AnalyticsParameterTransactionID (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventRefund NS_SWIFT_NAME(AnalyticsEventRefund) = @"refund"; + +/// E-Commerce Remove from Cart event. This event signifies that an item(s) was removed from a cart. +/// Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply the @c +/// AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventRemoveFromCart NS_SWIFT_NAME(AnalyticsEventRemoveFromCart) = + @"remove_from_cart"; + +/// Screen View event. This event signifies a screen view. Use this when a screen transition occurs. +/// This event can be logged irrespective of whether automatic screen tracking is enabled. Params: +/// +///
    +///
  • @c AnalyticsParameterScreenClass (String) (optional)
  • +///
  • @c AnalyticsParameterScreenName (String) (optional)
  • +///
+static NSString *const kFIREventScreenView NS_SWIFT_NAME(AnalyticsEventScreenView) = @"screen_view"; + +/// Search event. Apps that support search features can use this event to contextualize search +/// operations by supplying the appropriate, corresponding parameters. This event can help you +/// identify the most popular content in your app. Params: +/// +///
    +///
  • @c AnalyticsParameterSearchTerm (String)
  • +///
  • @c AnalyticsParameterStartDate (String) (optional)
  • +///
  • @c AnalyticsParameterEndDate (String) (optional)
  • +///
  • @c AnalyticsParameterNumberOfNights (Int) (optional) for hotel bookings
  • +///
  • @c AnalyticsParameterNumberOfRooms (Int) (optional) for hotel bookings
  • +///
  • @c AnalyticsParameterNumberOfPassengers (Int) (optional) for travel bookings
  • +///
  • @c AnalyticsParameterOrigin (String) (optional)
  • +///
  • @c AnalyticsParameterDestination (String) (optional)
  • +///
  • @c AnalyticsParameterTravelClass (String) (optional) for travel bookings
  • +///
+static NSString *const kFIREventSearch NS_SWIFT_NAME(AnalyticsEventSearch) = @"search"; + +/// Select Content event. This general purpose event signifies that a user has selected some content +/// of a certain type in an app. The content can be any object in your app. This event can help you +/// identify popular content and categories of content in your app. Params: +/// +///
    +///
  • @c AnalyticsParameterContentType (String)
  • +///
  • @c AnalyticsParameterItemID (String)
  • +///
+static NSString *const kFIREventSelectContent NS_SWIFT_NAME(AnalyticsEventSelectContent) = + @"select_content"; + +/// Select Item event. This event signifies that an item was selected by a user from a list. Use the +/// appropriate parameters to contextualize the event. Use this event to discover the most popular +/// items selected. Params: +/// +///
    +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterItemListID (String) (optional)
  • +///
  • @c AnalyticsParameterItemListName (String) (optional)
  • +///
+static NSString *const kFIREventSelectItem NS_SWIFT_NAME(AnalyticsEventSelectItem) = @"select_item"; + +/// Select promotion event. This event signifies that a user has selected a promotion offer. Use the +/// appropriate parameters to contextualize the event, such as the item(s) for which the promotion +/// applies. Params: +/// +///
    +///
  • @c AnalyticsParameterCreativeName (String) (optional)
  • +///
  • @c AnalyticsParameterCreativeSlot (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterLocationID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionName (String) (optional)
  • +///
+static NSString *const kFIREventSelectPromotion NS_SWIFT_NAME(AnalyticsEventSelectPromotion) = + @"select_promotion"; + +/// Share event. Apps with social features can log the Share event to identify the most viral +/// content. Params: +/// +///
    +///
  • @c AnalyticsParameterContentType (String)
  • +///
  • @c AnalyticsParameterItemID (String)
  • +///
+static NSString *const kFIREventShare NS_SWIFT_NAME(AnalyticsEventShare) = @"share"; + +/// Sign Up event. This event indicates that a user has signed up for an account in your app. The +/// parameter signifies the method by which the user signed up. Use this event to understand the +/// different behaviors between logged in and logged out users. Params: +/// +///
    +///
  • @c AnalyticsParameterMethod (String)
  • +///
+static NSString *const kFIREventSignUp NS_SWIFT_NAME(AnalyticsEventSignUp) = @"sign_up"; + +/// Spend Virtual Currency event. This event tracks the sale of virtual goods in your app and can +/// help you identify which virtual goods are the most popular objects of purchase. Params: +/// +///
    +///
  • @c AnalyticsParameterItemName (String)
  • +///
  • @c AnalyticsParameterVirtualCurrencyName (String)
  • +///
  • @c AnalyticsParameterValue (Int or Double)
  • +///
+static NSString *const kFIREventSpendVirtualCurrency + NS_SWIFT_NAME(AnalyticsEventSpendVirtualCurrency) = @"spend_virtual_currency"; + +/// Tutorial Begin event. This event signifies the start of the on-boarding process in your app. Use +/// this in a funnel with @c AnalyticsEventTutorialComplete to understand how many users complete +/// this process and move on to the full app experience. +static NSString *const kFIREventTutorialBegin NS_SWIFT_NAME(AnalyticsEventTutorialBegin) = + @"tutorial_begin"; + +/// Tutorial End event. Use this event to signify the user's completion of your app's on-boarding +/// process. Add this to a funnel with @c AnalyticsEventTutorialBegin to gauge the completion rate +/// of your on-boarding process. +static NSString *const kFIREventTutorialComplete NS_SWIFT_NAME(AnalyticsEventTutorialComplete) = + @"tutorial_complete"; + +/// Unlock Achievement event. Log this event when the user has unlocked an achievement in your +/// game. Since achievements generally represent the breadth of a gaming experience, this event can +/// help you understand how many users are experiencing all that your game has to offer. Params: +/// +///
    +///
  • @c AnalyticsParameterAchievementID (String)
  • +///
+static NSString *const kFIREventUnlockAchievement NS_SWIFT_NAME(AnalyticsEventUnlockAchievement) = + @"unlock_achievement"; + +/// E-commerce View Cart event. This event signifies that a user has viewed their cart. Use this to +/// analyze your purchase funnel. Note: If you supply the @c AnalyticsParameterValue parameter, you +/// must also supply the @c AnalyticsParameterCurrency parameter so that revenue metrics can be +/// computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventViewCart NS_SWIFT_NAME(AnalyticsEventViewCart) = @"view_cart"; + +/// View Item event. This event signifies that a user has viewed an item. Use the appropriate +/// parameters to contextualize the event. Use this event to discover the most popular items viewed +/// in your app. Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply +/// the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventViewItem NS_SWIFT_NAME(AnalyticsEventViewItem) = @"view_item"; + +/// View Item List event. Log this event when a user sees a list of items or offerings. Params: +/// +///
    +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterItemListID (String) (optional)
  • +///
  • @c AnalyticsParameterItemListName (String) (optional)
  • +///
+static NSString *const kFIREventViewItemList NS_SWIFT_NAME(AnalyticsEventViewItemList) = + @"view_item_list"; + +/// View Promotion event. This event signifies that a promotion was shown to a user. Add this event +/// to a funnel with the @c AnalyticsEventAddToCart and @c AnalyticsEventPurchase to gauge your +/// conversion process. Params: +/// +///
    +///
  • @c AnalyticsParameterCreativeName (String) (optional)
  • +///
  • @c AnalyticsParameterCreativeSlot (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterLocationID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionName (String) (optional)
  • +///
+static NSString *const kFIREventViewPromotion NS_SWIFT_NAME(AnalyticsEventViewPromotion) = + @"view_promotion"; + +/// View Search Results event. Log this event when the user has been presented with the results of a +/// search. Params: +/// +///
    +///
  • @c AnalyticsParameterSearchTerm (String)
  • +///
+static NSString *const kFIREventViewSearchResults NS_SWIFT_NAME(AnalyticsEventViewSearchResults) = + @"view_search_results"; diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Headers/FIRParameterNames.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Headers/FIRParameterNames.h new file mode 100644 index 0000000..b001ca5 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Headers/FIRParameterNames.h @@ -0,0 +1,721 @@ +/// @file FIRParameterNames.h +/// +/// Predefined event parameter names. +/// +/// Params supply information that contextualize Events. You can associate up to 25 unique Params +/// with each Event type. Some Params are suggested below for certain common Events, but you are +/// not limited to these. You may supply extra Params for suggested Events or custom Params for +/// Custom events. Param names can be up to 40 characters long, may only contain alphanumeric +/// characters and underscores ("_"), and must start with an alphabetic character. Param values can +/// be up to 100 characters long. The "firebase_", "google_", and "ga_" prefixes are reserved and +/// should not be used. + +#import + +/// Game achievement ID (String). +///
+///     let params = [
+///       AnalyticsParameterAchievementID : "10_matches_won",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAchievementID NS_SWIFT_NAME(AnalyticsParameterAchievementID) = + @"achievement_id"; + +/// The ad format (e.g. Banner, Interstitial, Rewarded, Native, Rewarded Interstitial, Instream). +/// (String). +///
+///     let params = [
+///       AnalyticsParameterAdFormat : "Banner",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdFormat NS_SWIFT_NAME(AnalyticsParameterAdFormat) = + @"ad_format"; + +/// Ad Network Click ID (String). Used for network-specific click IDs which vary in format. +///
+///     let params = [
+///       AnalyticsParameterAdNetworkClickID : "1234567",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdNetworkClickID + NS_SWIFT_NAME(AnalyticsParameterAdNetworkClickID) = @"aclid"; + +/// The ad platform (e.g. MoPub, IronSource) (String). +///
+///     let params = [
+///       AnalyticsParameterAdPlatform : "MoPub",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdPlatform NS_SWIFT_NAME(AnalyticsParameterAdPlatform) = + @"ad_platform"; + +/// The ad source (e.g. AdColony) (String). +///
+///     let params = [
+///       AnalyticsParameterAdSource : "AdColony",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdSource NS_SWIFT_NAME(AnalyticsParameterAdSource) = + @"ad_source"; + +/// The ad unit name (e.g. Banner_03) (String). +///
+///     let params = [
+///       AnalyticsParameterAdUnitName : "Banner_03",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdUnitName NS_SWIFT_NAME(AnalyticsParameterAdUnitName) = + @"ad_unit_name"; + +/// A product affiliation to designate a supplying company or brick and mortar store location +/// (String).
+///     let params = [
+///       AnalyticsParameterAffiliation : "Google Store",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAffiliation NS_SWIFT_NAME(AnalyticsParameterAffiliation) = + @"affiliation"; + +/// Campaign custom parameter (String). Used as a method of capturing custom data in a campaign. +/// Use varies by network. +///
+///     let params = [
+///       AnalyticsParameterCP1 : "custom_data",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCP1 NS_SWIFT_NAME(AnalyticsParameterCP1) = @"cp1"; + +/// The individual campaign name, slogan, promo code, etc. Some networks have pre-defined macro to +/// capture campaign information, otherwise can be populated by developer. Highly Recommended +/// (String). +///
+///     let params = [
+///       AnalyticsParameterCampaign : "winter_promotion",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCampaign NS_SWIFT_NAME(AnalyticsParameterCampaign) = + @"campaign"; + +/// Campaign ID (String). Used for keyword analysis to identify a specific product promotion or +/// strategic campaign. This is a required key for GA4 data import. +///
+///     let params = [
+///       AnalyticsParameterCampaignID : "7877652710",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCampaignID NS_SWIFT_NAME(AnalyticsParameterCampaignID) = + @"campaign_id"; + +/// Character used in game (String). +///
+///     let params = [
+///       AnalyticsParameterCharacter : "beat_boss",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCharacter NS_SWIFT_NAME(AnalyticsParameterCharacter) = + @"character"; + +/// Campaign content (String). +static NSString *const kFIRParameterContent NS_SWIFT_NAME(AnalyticsParameterContent) = @"content"; + +/// Type of content selected (String). +///
+///     let params = [
+///       AnalyticsParameterContentType : "news article",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterContentType NS_SWIFT_NAME(AnalyticsParameterContentType) = + @"content_type"; + +/// Coupon code used for a purchase (String). +///
+///     let params = [
+///       AnalyticsParameterCoupon : "SUMMER_FUN",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCoupon NS_SWIFT_NAME(AnalyticsParameterCoupon) = @"coupon"; + +/// Creative Format (String). Used to identify the high-level classification of the type of ad +/// served by a specific campaign. +///
+///     let params = [
+///       AnalyticsParameterCreativeFormat : "display",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCreativeFormat NS_SWIFT_NAME(AnalyticsParameterCreativeFormat) = + @"creative_format"; + +/// The name of a creative used in a promotional spot (String). +///
+///     let params = [
+///       AnalyticsParameterCreativeName : "Summer Sale",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCreativeName NS_SWIFT_NAME(AnalyticsParameterCreativeName) = + @"creative_name"; + +/// The name of a creative slot (String). +///
+///     let params = [
+///       AnalyticsParameterCreativeSlot : "summer_banner2",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCreativeSlot NS_SWIFT_NAME(AnalyticsParameterCreativeSlot) = + @"creative_slot"; + +/// Currency of the purchase or items associated with the event, in 3-letter +/// ISO_4217 format (String). +///
+///     let params = [
+///       AnalyticsParameterCurrency : "USD",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCurrency NS_SWIFT_NAME(AnalyticsParameterCurrency) = + @"currency"; + +/// Flight or Travel destination (String). +///
+///     let params = [
+///       AnalyticsParameterDestination : "Mountain View, CA",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterDestination NS_SWIFT_NAME(AnalyticsParameterDestination) = + @"destination"; + +/// Monetary value of discount associated with a purchase (Double). +///
+///     let params = [
+///       AnalyticsParameterDiscount : 2.0,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $2.00 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterDiscount NS_SWIFT_NAME(AnalyticsParameterDiscount) = + @"discount"; + +/// The arrival date, check-out date or rental end date for the item. This should be in +/// YYYY-MM-DD format (String). +///
+///     let params = [
+///       AnalyticsParameterEndDate : "2015-09-14",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterEndDate NS_SWIFT_NAME(AnalyticsParameterEndDate) = @"end_date"; + +/// Indicates that the associated event should either extend the current session or start a new +/// session if no session was active when the event was logged. Specify 1 to extend the current +/// session or to start a new session; any other value will not extend or start a session. +///
+///     let params = [
+///       AnalyticsParameterExtendSession : 1,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterExtendSession NS_SWIFT_NAME(AnalyticsParameterExtendSession) = + @"extend_session"; + +/// Flight number for travel events (String). +///
+///     let params = [
+///       AnalyticsParameterFlightNumber : "ZZ800",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterFlightNumber NS_SWIFT_NAME(AnalyticsParameterFlightNumber) = + @"flight_number"; + +/// Group/clan/guild ID (String). +///
+///     let params = [
+///       AnalyticsParameterGroupID : "g1",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterGroupID NS_SWIFT_NAME(AnalyticsParameterGroupID) = @"group_id"; + +/// The index of the item in a list (Int). +///
+///     let params = [
+///       AnalyticsParameterIndex : 5,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterIndex NS_SWIFT_NAME(AnalyticsParameterIndex) = @"index"; + +/// Item brand (String). +///
+///     let params = [
+///       AnalyticsParameterItemBrand : "Google",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemBrand NS_SWIFT_NAME(AnalyticsParameterItemBrand) = + @"item_brand"; + +/// Item category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory NS_SWIFT_NAME(AnalyticsParameterItemCategory) = + @"item_category"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory2 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory2 NS_SWIFT_NAME(AnalyticsParameterItemCategory2) = + @"item_category2"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory3 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory3 NS_SWIFT_NAME(AnalyticsParameterItemCategory3) = + @"item_category3"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory4 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory4 NS_SWIFT_NAME(AnalyticsParameterItemCategory4) = + @"item_category4"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory5 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory5 NS_SWIFT_NAME(AnalyticsParameterItemCategory5) = + @"item_category5"; + +/// Item ID (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemID : "SKU_12345",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemID NS_SWIFT_NAME(AnalyticsParameterItemID) = @"item_id"; + +/// The ID of the list in which the item was presented to the user (String). +///
+///     let params = [
+///       AnalyticsParameterItemListID : "ABC123",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemListID NS_SWIFT_NAME(AnalyticsParameterItemListID) = + @"item_list_id"; + +/// The name of the list in which the item was presented to the user (String). +///
+///     let params = [
+///       AnalyticsParameterItemListName : "Related products",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemListName NS_SWIFT_NAME(AnalyticsParameterItemListName) = + @"item_list_name"; + +/// Item Name (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemName : "jeggings",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemName NS_SWIFT_NAME(AnalyticsParameterItemName) = + @"item_name"; + +/// Item variant (String). +///
+///     let params = [
+///       AnalyticsParameterItemVariant : "Black",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemVariant NS_SWIFT_NAME(AnalyticsParameterItemVariant) = + @"item_variant"; + +/// The list of items involved in the transaction expressed as `[[String: Any]]`. +///
+///     let params = [
+///       AnalyticsParameterItems : [
+///         [AnalyticsParameterItemName : "jeggings", AnalyticsParameterItemCategory : "pants"],
+///         [AnalyticsParameterItemName : "boots", AnalyticsParameterItemCategory : "shoes"],
+///       ],
+///     ]
+/// 
+static NSString *const kFIRParameterItems NS_SWIFT_NAME(AnalyticsParameterItems) = @"items"; + +/// Level in game (Int). +///
+///     let params = [
+///       AnalyticsParameterLevel : 42,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLevel NS_SWIFT_NAME(AnalyticsParameterLevel) = @"level"; + +/// The name of a level in a game (String). +///
+///     let params = [
+///       AnalyticsParameterLevelName : "room_1",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLevelName NS_SWIFT_NAME(AnalyticsParameterLevelName) = + @"level_name"; + +/// Location (String). The Google Place ID +/// that corresponds to the associated event. Alternatively, you can supply your own custom +/// Location ID. +///
+///     let params = [
+///       AnalyticsParameterLocation : "ChIJiyj437sx3YAR9kUWC8QkLzQ",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLocation NS_SWIFT_NAME(AnalyticsParameterLocation) = + @"location"; + +/// The location associated with the event. Preferred to be the Google +/// Place ID that corresponds to the +/// associated item but could be overridden to a custom location ID string.(String). +///
+///     let params = [
+///       AnalyticsParameterLocationID : "ChIJiyj437sx3YAR9kUWC8QkLzQ",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLocationID NS_SWIFT_NAME(AnalyticsParameterLocationID) = + @"location_id"; + +/// Marketing Tactic (String). Used to identify the targeting criteria applied to a specific +/// campaign. +///
+///     let params = [
+///       AnalyticsParameterMarketingTactic : "Remarketing",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterMarketingTactic + NS_SWIFT_NAME(AnalyticsParameterMarketingTactic) = @"marketing_tactic"; + +/// The advertising or marketing medium, for example: cpc, banner, email, push. Highly recommended +/// (String). +///
+///     let params = [
+///       AnalyticsParameterMedium : "email",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterMedium NS_SWIFT_NAME(AnalyticsParameterMedium) = @"medium"; + +/// A particular approach used in an operation; for example, "facebook" or "email" in the context +/// of a sign_up or login event. (String). +///
+///     let params = [
+///       AnalyticsParameterMethod : "google",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterMethod NS_SWIFT_NAME(AnalyticsParameterMethod) = @"method"; + +/// Number of nights staying at hotel (Int). +///
+///     let params = [
+///       AnalyticsParameterNumberOfNights : 3,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterNumberOfNights + NS_SWIFT_NAME(AnalyticsParameterNumberOfNights) = @"number_of_nights"; + +/// Number of passengers traveling (Int). +///
+///     let params = [
+///       AnalyticsParameterNumberOfPassengers : 11,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterNumberOfPassengers + NS_SWIFT_NAME(AnalyticsParameterNumberOfPassengers) = @"number_of_passengers"; + +/// Number of rooms for travel events (Int). +///
+///     let params = [
+///       AnalyticsParameterNumberOfRooms : 2,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterNumberOfRooms NS_SWIFT_NAME(AnalyticsParameterNumberOfRooms) = + @"number_of_rooms"; + +/// Flight or Travel origin (String). +///
+///     let params = [
+///       AnalyticsParameterOrigin : "Mountain View, CA",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterOrigin NS_SWIFT_NAME(AnalyticsParameterOrigin) = @"origin"; + +/// The chosen method of payment (String). +///
+///     let params = [
+///       AnalyticsParameterPaymentType : "Visa",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPaymentType NS_SWIFT_NAME(AnalyticsParameterPaymentType) = + @"payment_type"; + +/// Purchase price (Double). +///
+///     let params = [
+///       AnalyticsParameterPrice : 1.0,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $1.00 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPrice NS_SWIFT_NAME(AnalyticsParameterPrice) = @"price"; + +/// The ID of a product promotion (String). +///
+///     let params = [
+///       AnalyticsParameterPromotionID : "ABC123",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPromotionID NS_SWIFT_NAME(AnalyticsParameterPromotionID) = + @"promotion_id"; + +/// The name of a product promotion (String). +///
+///     let params = [
+///       AnalyticsParameterPromotionName : "Summer Sale",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPromotionName NS_SWIFT_NAME(AnalyticsParameterPromotionName) = + @"promotion_name"; + +/// Purchase quantity (Int). +///
+///     let params = [
+///       AnalyticsParameterQuantity : 1,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterQuantity NS_SWIFT_NAME(AnalyticsParameterQuantity) = + @"quantity"; + +/// Score in game (Int). +///
+///     let params = [
+///       AnalyticsParameterScore : 4200,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterScore NS_SWIFT_NAME(AnalyticsParameterScore) = @"score"; + +/// Current screen class, such as the class name of the UIViewController, logged with screen_view +/// event and added to every event (String). +///
+///     let params = [
+///       AnalyticsParameterScreenClass : "LoginViewController",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterScreenClass NS_SWIFT_NAME(AnalyticsParameterScreenClass) = + @"screen_class"; + +/// Current screen name, such as the name of the UIViewController, logged with screen_view event and +/// added to every event (String). +///
+///     let params = [
+///       AnalyticsParameterScreenName : "LoginView",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterScreenName NS_SWIFT_NAME(AnalyticsParameterScreenName) = + @"screen_name"; + +/// The search string/keywords used (String). +///
+///     let params = [
+///       AnalyticsParameterSearchTerm : "periodic table",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSearchTerm NS_SWIFT_NAME(AnalyticsParameterSearchTerm) = + @"search_term"; + +/// Shipping cost associated with a transaction (Double). +///
+///     let params = [
+///       AnalyticsParameterShipping : 5.99,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $5.99 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterShipping NS_SWIFT_NAME(AnalyticsParameterShipping) = + @"shipping"; + +/// The shipping tier (e.g. Ground, Air, Next-day) selected for delivery of the purchased item +/// (String). +///
+///     let params = [
+///       AnalyticsParameterShippingTier : "Ground",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterShippingTier NS_SWIFT_NAME(AnalyticsParameterShippingTier) = + @"shipping_tier"; + +/// The origin of your traffic, such as an Ad network (for example, google) or partner (urban +/// airship). Identify the advertiser, site, publication, etc. that is sending traffic to your +/// property. Highly recommended (String). +///
+///     let params = [
+///       AnalyticsParameterSource : "InMobi",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSource NS_SWIFT_NAME(AnalyticsParameterSource) = @"source"; + +/// Source Platform (String). Used to identify the platform responsible for directing traffic to a +/// given Analytics property (e.g., a buying platform where budgets, targeting criteria, etc. are +/// set, a platform for managing organic traffic data, etc.). +///
+///     let params = [
+///       AnalyticsParameterSourcePlatform : "sa360",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSourcePlatform NS_SWIFT_NAME(AnalyticsParameterSourcePlatform) = + @"source_platform"; + +/// The departure date, check-in date or rental start date for the item. This should be in +/// YYYY-MM-DD format (String). +///
+///     let params = [
+///       AnalyticsParameterStartDate : "2015-09-14",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterStartDate NS_SWIFT_NAME(AnalyticsParameterStartDate) = + @"start_date"; + +/// The result of an operation. Specify 1 to indicate success and 0 to indicate failure (Int). +///
+///     let params = [
+///       AnalyticsParameterSuccess : 1,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSuccess NS_SWIFT_NAME(AnalyticsParameterSuccess) = @"success"; + +/// Tax cost associated with a transaction (Double). +///
+///     let params = [
+///       AnalyticsParameterTax : 2.43,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $2.43 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTax NS_SWIFT_NAME(AnalyticsParameterTax) = @"tax"; + +/// If you're manually tagging keyword campaigns, you should use utm_term to specify the keyword +/// (String). +///
+///     let params = [
+///       AnalyticsParameterTerm : "game",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTerm NS_SWIFT_NAME(AnalyticsParameterTerm) = @"term"; + +/// The unique identifier of a transaction (String). +///
+///     let params = [
+///       AnalyticsParameterTransactionID : "T12345",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTransactionID NS_SWIFT_NAME(AnalyticsParameterTransactionID) = + @"transaction_id"; + +/// Travel class (String). +///
+///     let params = [
+///       AnalyticsParameterTravelClass : "business",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTravelClass NS_SWIFT_NAME(AnalyticsParameterTravelClass) = + @"travel_class"; + +/// A context-specific numeric value which is accumulated automatically for each event type. This is +/// a general purpose parameter that is useful for accumulating a key metric that pertains to an +/// event. Examples include revenue, distance, time and points. Value should be specified as Int or +/// Double. +/// Notes: Values for pre-defined currency-related events (such as @c AnalyticsEventAddToCart) +/// should be supplied using Double and must be accompanied by a @c AnalyticsParameterCurrency +/// parameter. The valid range of accumulated values is +/// [-9,223,372,036,854.77, 9,223,372,036,854.77]. Supplying a non-numeric value, omitting the +/// corresponding @c AnalyticsParameterCurrency parameter, or supplying an invalid +/// currency code for conversion events will cause that +/// conversion to be omitted from reporting. +///
+///     let params = [
+///       AnalyticsParameterValue : 3.99,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $3.99 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterValue NS_SWIFT_NAME(AnalyticsParameterValue) = @"value"; + +/// Name of virtual currency type (String). +///
+///     let params = [
+///       AnalyticsParameterVirtualCurrencyName : "virtual_currency_name",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterVirtualCurrencyName + NS_SWIFT_NAME(AnalyticsParameterVirtualCurrencyName) = @"virtual_currency_name"; diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h new file mode 100644 index 0000000..2442d8a --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h @@ -0,0 +1,28 @@ +/// @file FIRUserPropertyNames.h +/// +/// Predefined user property names. +/// +/// A UserProperty is an attribute that describes the app-user. By supplying UserProperties, you can +/// later analyze different behaviors of various segments of your userbase. You may supply up to 25 +/// unique UserProperties per app, and you can use the name and value of your choosing for each one. +/// UserProperty names can be up to 24 characters long, may only contain alphanumeric characters and +/// underscores ("_"), and must start with an alphabetic character. UserProperty values can be up to +/// 36 characters long. The "firebase_", "google_", and "ga_" prefixes are reserved and should not +/// be used. + +#import + +/// Indicates whether events logged by Google Analytics can be used to personalize ads for the user. +/// Set to "YES" to enable, or "NO" to disable. Default is enabled. See the +/// documentation for +/// more details and information about related settings. +/// +///
+///     Analytics.setUserProperty("NO", forName: AnalyticsUserPropertyAllowAdPersonalizationSignals)
+/// 
+static NSString *const kFIRUserPropertyAllowAdPersonalizationSignals + NS_SWIFT_NAME(AnalyticsUserPropertyAllowAdPersonalizationSignals) = @"allow_personalized_ads"; + +/// The method used to sign in. For example, "google", "facebook" or "twitter". +static NSString *const kFIRUserPropertySignUpMethod + NS_SWIFT_NAME(AnalyticsUserPropertySignUpMethod) = @"sign_up_method"; diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-umbrella.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-umbrella.h new file mode 100644 index 0000000..ad84fbb --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-umbrella.h @@ -0,0 +1,24 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "FIRAnalytics+AppDelegate.h" +#import "FIRAnalytics+Consent.h" +#import "FIRAnalytics+OnDevice.h" +#import "FIRAnalytics.h" +#import "FirebaseAnalytics.h" +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" + +FOUNDATION_EXPORT double FirebaseAnalyticsVersionNumber; +FOUNDATION_EXPORT const unsigned char FirebaseAnalyticsVersionString[]; + diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h new file mode 100644 index 0000000..351da20 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h @@ -0,0 +1,7 @@ +#import "FIRAnalytics+AppDelegate.h" +#import "FIRAnalytics+Consent.h" +#import "FIRAnalytics+OnDevice.h" +#import "FIRAnalytics.h" +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Info.plist b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Info.plist new file mode 100644 index 0000000..1674c5f --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleExecutable + FirebaseAnalytics + CFBundleIdentifier + com.firebase.Firebase-FirebaseAnalytics + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + FirebaseAnalytics + CFBundlePackageType + FMWK + CFBundleVersion + 10.11.0 + DTSDKName + iphonesimulator11.2 + + diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Modules/module.modulemap b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Modules/module.modulemap new file mode 100644 index 0000000..37eb24b --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Modules/module.modulemap @@ -0,0 +1,12 @@ +framework module FirebaseAnalytics { +umbrella header "FirebaseAnalytics-umbrella.h" +export * +module * { export * } + link framework "Foundation" + link framework "Security" + link framework "SystemConfiguration" + link framework "UIKit" + link "c++" + link "sqlite3" + link "z" +} diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/FirebaseAnalytics b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/FirebaseAnalytics new file mode 100644 index 0000000..4bd36c2 Binary files /dev/null and b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/FirebaseAnalytics differ diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h new file mode 100644 index 0000000..cb1e407 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h @@ -0,0 +1,80 @@ +#import + +#import "FIRAnalytics.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Provides App Delegate handlers to be used in your App Delegate. +/// +/// To save time integrating Firebase Analytics in an application, Firebase Analytics does not +/// require delegation implementation from the AppDelegate if neither SwiftUI nor UIScene lifecycle +/// is adopted. Instead this is automatically done by Firebase Analytics. Should you choose instead +/// to delegate manually, you can turn off the App Delegate Proxy by adding +/// FirebaseAppDelegateProxyEnabled into your app's Info.plist and setting it to boolean `NO`, and +/// adding the methods in this category to corresponding delegation handlers. +/// +/// To handle Universal Links, you must return `true` in +/// `UIApplicationDelegate.application(_:didFinishLaunchingWithOptions:)`. +@interface FIRAnalytics (AppDelegate) + +/// Handles events related to a URL session that are waiting to be processed. +/// +/// 1. If SwiftUI lifecycle is adopted, call this method from +/// `UIApplicationDelegate.application(_:handleEventsForBackgroundURLSession:completionHandler:)` +/// in your app delegate. +/// +/// 2. If SwiftUI lifecycle is not adopted, Firebase Analytics does not require delegation +/// implementation from the AppDelegate. If you choose instead to delegate manually, you can set +/// FirebaseAppDelegateProxyEnabled to boolean `NO` in your app's Info.plist and call this method +/// from +/// `UIApplicationDelegate.application(_:handleEventsForBackgroundURLSession:completionHandler:)` +/// in your app delegate. +/// +/// @param identifier The identifier of the URL session requiring attention. +/// @param completionHandler The completion handler to call when you finish processing the events. +/// Calling this completion handler lets the system know that your app's user interface is +/// updated and a new snapshot can be taken. ++ (void)handleEventsForBackgroundURLSession:(NSString *)identifier + completionHandler:(nullable void (^)(void))completionHandler; + +/// Handles the event when the app is launched by a URL (custom URL scheme or universal link). +/// +/// 1. If SwiftUI lifecycle is adopted, use `onOpenURL(perform:)` to register a handler and call +/// this method in the handler. +/// +/// 2. If UIScene lifecycle is adopted, call this method from +/// `UISceneDelegate.scene(_:willConnectTo:options:)` and +/// `UISceneDelegate.scene(_:openURLContexts:)` when the URL contexts are available. +/// +/// 3. If neither SwiftUI nor UIScene lifecycle is adopted, Firebase Analytics does not require +/// delegation implementation from the AppDelegate. If you choose instead to delegate manually, you +/// can set FirebaseAppDelegateProxyEnabled to boolean `NO` in your app's Info.plist and call this +/// method from `UIApplicationDelegate.application(_:open:options:)` in your app delegate. +/// +/// @param url The URL resource to open. This resource can be a network resource or a file. ++ (void)handleOpenURL:(NSURL *)url; + +/// Handles the event when the app receives data associated with user activity that includes a +/// Universal Link. +/// +/// 1. If SwiftUI lifecycle is adopted, use `onOpenURL(perform:)` to register a handler and call +/// `Analytics.handleOpen(_:)` instead in the handler. +/// +/// 2. If UIScene lifecycle is adopted, call this method from +/// `UISceneDelegate.scene(_:willConnectTo:options:)` and `UISceneDelegate.scene(_:continue:)` when +/// NSUserActivity is available. See the [Apple +/// doc](https://developer.apple.com/documentation/xcode/supporting-universal-links-in-your-app) for +/// more details. +/// +/// 3. If neither SwiftUI nor UIScene lifecycle is adopted, Firebase Analytics does not require +/// delegation implementation from the AppDelegate. If you choose instead to delegate manually, you +/// can set FirebaseAppDelegateProxyEnabled to boolean `NO` in your app's Info.plist and call this +/// method from `UIApplication.application(_:continue:restorationHandler:)` in your app delegate. +/// +/// @param userActivity The activity object containing the data associated with the task the user +/// was performing. ++ (void)handleUserActivity:(id)userActivity; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+Consent.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+Consent.h new file mode 100644 index 0000000..7f89831 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+Consent.h @@ -0,0 +1,33 @@ +#import + +#import "FIRAnalytics.h" + +NS_ASSUME_NONNULL_BEGIN + +/// The type of consent to set. Supported consent types are `ConsentType.adStorage` and +/// `ConsentType.analyticsStorage`. Omitting a type retains its previous status. +typedef NSString *FIRConsentType NS_TYPED_ENUM NS_SWIFT_NAME(ConsentType); +extern FIRConsentType const FIRConsentTypeAdStorage; +extern FIRConsentType const FIRConsentTypeAnalyticsStorage; + +/// The status value of the consent type. Supported statuses are `ConsentStatus.granted` and +/// `ConsentStatus.denied`. +typedef NSString *FIRConsentStatus NS_TYPED_ENUM NS_SWIFT_NAME(ConsentStatus); +extern FIRConsentStatus const FIRConsentStatusDenied; +extern FIRConsentStatus const FIRConsentStatusGranted; + +/// Sets the applicable end user consent state. +@interface FIRAnalytics (Consent) + +/// Sets the applicable end user consent state (e.g. for device identifiers) for this app on this +/// device. Use the consent settings to specify individual consent type values. Settings are +/// persisted across app sessions. By default consent types are set to `ConsentStatus.granted`. +/// +/// @param consentSettings A Dictionary of consent types. Supported consent type keys are +/// `ConsentType.adStorage` and `ConsentType.analyticsStorage`. Valid values are +/// `ConsentStatus.granted` and `ConsentStatus.denied`. ++ (void)setConsent:(NSDictionary *)consentSettings; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+OnDevice.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+OnDevice.h new file mode 100644 index 0000000..1d9a438 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+OnDevice.h @@ -0,0 +1,19 @@ +#import + +#import "FIRAnalytics.h" + +NS_ASSUME_NONNULL_BEGIN + +API_UNAVAILABLE(macCatalyst, macos, tvos, watchos) +@interface FIRAnalytics (OnDevice) + +/// Initiates on-device conversion measurement given a user email address. Requires dependency +/// GoogleAppMeasurementOnDeviceConversion to be linked in, otherwise it is a no-op. +/// @param emailAddress User email address. Include a domain name for all email addresses +/// (e.g. gmail.com or hotmail.co.jp). ++ (void)initiateOnDeviceConversionMeasurementWithEmailAddress:(NSString *)emailAddress + NS_SWIFT_NAME(initiateOnDeviceConversionMeasurement(emailAddress:)); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics.h new file mode 100644 index 0000000..e7ce5dc --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics.h @@ -0,0 +1,154 @@ +#import + +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" + +NS_ASSUME_NONNULL_BEGIN + +/// The top level Firebase Analytics singleton that provides methods for logging events and setting +/// user properties. See the developer guides for general +/// information on using Firebase Analytics in your apps. +/// +/// @note The Analytics SDK uses SQLite to persist events and other app-specific data. Calling +/// certain thread-unsafe global SQLite methods like `sqlite3_shutdown()` can result in +/// unexpected crashes at runtime. +NS_SWIFT_NAME(Analytics) +@interface FIRAnalytics : NSObject + +/// Logs an app event. The event can have up to 25 parameters. Events with the same name must have +/// the same parameters. Up to 500 event names are supported. Using predefined events and/or +/// parameters is recommended for optimal reporting. +/// +/// The following event names are reserved and cannot be used: +///
    +///
  • ad_activeview
  • +///
  • ad_click
  • +///
  • ad_exposure
  • +///
  • ad_query
  • +///
  • ad_reward
  • +///
  • adunit_exposure
  • +///
  • app_clear_data
  • +///
  • app_exception
  • +///
  • app_remove
  • +///
  • app_store_refund
  • +///
  • app_store_subscription_cancel
  • +///
  • app_store_subscription_convert
  • +///
  • app_store_subscription_renew
  • +///
  • app_update
  • +///
  • app_upgrade
  • +///
  • dynamic_link_app_open
  • +///
  • dynamic_link_app_update
  • +///
  • dynamic_link_first_open
  • +///
  • error
  • +///
  • firebase_campaign
  • +///
  • first_open
  • +///
  • first_visit
  • +///
  • in_app_purchase
  • +///
  • notification_dismiss
  • +///
  • notification_foreground
  • +///
  • notification_open
  • +///
  • notification_receive
  • +///
  • os_update
  • +///
  • session_start
  • +///
  • session_start_with_rollout
  • +///
  • user_engagement
  • +///
+/// +/// @param name The name of the event. Should contain 1 to 40 alphanumeric characters or +/// underscores. The name must start with an alphabetic character. Some event names are +/// reserved. See FIREventNames.h for the list of reserved event names. The "firebase_", +/// "google_", and "ga_" prefixes are reserved and should not be used. Note that event names are +/// case-sensitive and that logging two events whose names differ only in case will result in +/// two distinct events. To manually log screen view events, use the `screen_view` event name. +/// @param parameters The dictionary of event parameters. Passing `nil` indicates that the event has +/// no parameters. Parameter names can be up to 40 characters long and must start with an +/// alphabetic character and contain only alphanumeric characters and underscores. Only String, +/// Int, and Double parameter types are supported. String parameter values can be up to 100 +/// characters long. The "firebase_", "google_", and "ga_" prefixes are reserved and should not +/// be used for parameter names. ++ (void)logEventWithName:(NSString *)name + parameters:(nullable NSDictionary *)parameters + NS_SWIFT_NAME(logEvent(_:parameters:)); + +/// Sets a user property to a given value. Up to 25 user property names are supported. Once set, +/// user property values persist throughout the app lifecycle and across sessions. +/// +/// The following user property names are reserved and cannot be used: +///
    +///
  • first_open_time
  • +///
  • last_deep_link_referrer
  • +///
  • user_id
  • +///
+/// +/// @param value The value of the user property. Values can be up to 36 characters long. Setting the +/// value to `nil` removes the user property. +/// @param name The name of the user property to set. Should contain 1 to 24 alphanumeric characters +/// or underscores and must start with an alphabetic character. The "firebase_", "google_", and +/// "ga_" prefixes are reserved and should not be used for user property names. ++ (void)setUserPropertyString:(nullable NSString *)value forName:(NSString *)name + NS_SWIFT_NAME(setUserProperty(_:forName:)); + +/// Sets the user ID property. This feature must be used in accordance with +/// Google's Privacy Policy +/// +/// @param userID The user ID to ascribe to the user of this app on this device, which must be +/// non-empty and no more than 256 characters long. Setting userID to `nil` removes the user ID. ++ (void)setUserID:(nullable NSString *)userID; + +/// Sets whether analytics collection is enabled for this app on this device. This setting is +/// persisted across app sessions. By default it is enabled. +/// +/// @param analyticsCollectionEnabled A flag that enables or disables Analytics collection. ++ (void)setAnalyticsCollectionEnabled:(BOOL)analyticsCollectionEnabled; + +/// Sets the interval of inactivity in seconds that terminates the current session. The default +/// value is 1800 seconds (30 minutes). +/// +/// @param sessionTimeoutInterval The custom time of inactivity in seconds before the current +/// session terminates. ++ (void)setSessionTimeoutInterval:(NSTimeInterval)sessionTimeoutInterval; + +/// Asynchronously retrieves the identifier of the current app session. +/// +/// The session ID retrieval could fail due to Analytics collection disabled, app session expired, +/// etc. +/// +/// @param completion The completion handler to call when the session ID retrieval is complete. This +/// handler is executed on a system-defined global concurrent queue. +/// This completion handler takes the following parameters: +/// sessionID The identifier of the current app session. The value is undefined if the +/// request failed. +/// error An error object that indicates why the request failed, or `nil` if the request +/// was successful. ++ (void)sessionIDWithCompletion:(void (^)(int64_t sessionID, NSError *_Nullable error))completion; + +/// Returns the unique ID for this instance of the application or `nil` if +/// `ConsentType.analyticsStorage` has been set to `ConsentStatus.denied`. +/// +/// @see `FIRAnalytics+Consent.h` ++ (nullable NSString *)appInstanceID; + +/// Clears all analytics data for this instance from the device and resets the app instance ID. ++ (void)resetAnalyticsData; + +/// Adds parameters that will be set on every event logged from the SDK, including automatic ones. +/// The values passed in the parameters dictionary will be added to the dictionary of default event +/// parameters. These parameters persist across app runs. They are of lower precedence than event +/// parameters, so if an event parameter and a parameter set using this API have the same name, the +/// value of the event parameter will be used. The same limitations on event parameters apply to +/// default event parameters. +/// +/// @param parameters Parameters to be added to the dictionary of parameters added to every event. +/// They will be added to the dictionary of default event parameters, replacing any existing +/// parameter with the same name. Valid parameters are String, Int, and Double. Setting a key's +/// value to `NSNull()` will clear that parameter. Passing in a `nil` dictionary will clear all +/// parameters. ++ (void)setDefaultEventParameters:(nullable NSDictionary *)parameters; + +/// Unavailable. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIREventNames.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIREventNames.h new file mode 100644 index 0000000..1e69a44 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIREventNames.h @@ -0,0 +1,418 @@ +/// @file FIREventNames.h +/// +/// Predefined event names. +/// +/// An Event is an important occurrence in your app that you want to measure. You can report up to +/// 500 different types of Events per app and you can associate up to 25 unique parameters with each +/// Event type. Some common events are suggested below, but you may also choose to specify custom +/// Event types that are associated with your specific app. Each event type is identified by a +/// unique name. Event names can be up to 40 characters long, may only contain alphanumeric +/// characters and underscores ("_"), and must start with an alphabetic character. The "firebase_", +/// "google_", and "ga_" prefixes are reserved and should not be used. + +#import + +/// Ad Impression event. This event signifies when a user sees an ad impression. Note: If you supply +/// the @c AnalyticsParameterValue parameter, you must also supply the @c AnalyticsParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterAdPlatform (String) (optional)
  • +///
  • @c AnalyticsParameterAdFormat (String) (optional)
  • +///
  • @c AnalyticsParameterAdSource (String) (optional)
  • +///
  • @c AnalyticsParameterAdUnitName (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAdImpression NS_SWIFT_NAME(AnalyticsEventAdImpression) = + @"ad_impression"; + +/// Add Payment Info event. This event signifies that a user has submitted their payment +/// information. Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply +/// the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterPaymentType (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddPaymentInfo NS_SWIFT_NAME(AnalyticsEventAddPaymentInfo) = + @"add_payment_info"; + +/// Add Shipping Info event. This event signifies that a user has submitted their shipping +/// information. Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply +/// the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterShippingTier (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddShippingInfo NS_SWIFT_NAME(AnalyticsEventAddShippingInfo) = + @"add_shipping_info"; + +/// E-Commerce Add To Cart event. This event signifies that an item(s) was added to a cart for +/// purchase. Add this event to a funnel with @c AnalyticsEventPurchase to gauge the effectiveness +/// of your checkout process. Note: If you supply the @c AnalyticsParameterValue parameter, you must +/// also supply the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed +/// accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddToCart NS_SWIFT_NAME(AnalyticsEventAddToCart) = @"add_to_cart"; + +/// E-Commerce Add To Wishlist event. This event signifies that an item was added to a wishlist. Use +/// this event to identify popular gift items. Note: If you supply the @c AnalyticsParameterValue +/// parameter, you must also supply the @c AnalyticsParameterCurrency parameter so that revenue +/// metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddToWishlist NS_SWIFT_NAME(AnalyticsEventAddToWishlist) = + @"add_to_wishlist"; + +/// App Open event. By logging this event when an App becomes active, developers can understand how +/// often users leave and return during the course of a Session. Although Sessions are automatically +/// reported, this event can provide further clarification around the continuous engagement of +/// app-users. +static NSString *const kFIREventAppOpen NS_SWIFT_NAME(AnalyticsEventAppOpen) = @"app_open"; + +/// E-Commerce Begin Checkout event. This event signifies that a user has begun the process of +/// checking out. Add this event to a funnel with your @c AnalyticsEventPurchase event to gauge the +/// effectiveness of your checkout process. Note: If you supply the @c AnalyticsParameterValue +/// parameter, you must also supply the @c AnalyticsParameterCurrency parameter so that revenue +/// metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventBeginCheckout NS_SWIFT_NAME(AnalyticsEventBeginCheckout) = + @"begin_checkout"; + +/// Campaign Detail event. Log this event to supply the referral details of a re-engagement +/// campaign. Note: you must supply at least one of the required parameters +/// AnalyticsParameterSource, AnalyticsParameterMedium or AnalyticsParameterCampaign. Params: +/// +///
    +///
  • @c AnalyticsParameterSource (String)
  • +///
  • @c AnalyticsParameterMedium (String)
  • +///
  • @c AnalyticsParameterCampaign (String)
  • +///
  • @c AnalyticsParameterTerm (String) (optional)
  • +///
  • @c AnalyticsParameterContent (String) (optional)
  • +///
  • @c AnalyticsParameterAdNetworkClickID (String) (optional)
  • +///
  • @c AnalyticsParameterCP1 (String) (optional)
  • +///
  • @c AnalyticsParameterCampaignID (String) (optional)
  • +///
  • @c AnalyticsParameterCreativeFormat (String) (optional)
  • +///
  • @c AnalyticsParameterMarketingTactic (String) (optional)
  • +///
  • @c AnalyticsParameterSourcePlatform (String) (optional)
  • +///
+static NSString *const kFIREventCampaignDetails NS_SWIFT_NAME(AnalyticsEventCampaignDetails) = + @"campaign_details"; + +/// Earn Virtual Currency event. This event tracks the awarding of virtual currency in your app. Log +/// this along with @c AnalyticsEventSpendVirtualCurrency to better understand your virtual economy. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterVirtualCurrencyName (String)
  • +///
  • @c AnalyticsParameterValue (Int or Double)
  • +///
+static NSString *const kFIREventEarnVirtualCurrency + NS_SWIFT_NAME(AnalyticsEventEarnVirtualCurrency) = @"earn_virtual_currency"; + +/// Generate Lead event. Log this event when a lead has been generated in the app to understand the +/// efficacy of your install and re-engagement campaigns. Note: If you supply the +/// @c AnalyticsParameterValue parameter, you must also supply the @c AnalyticsParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventGenerateLead NS_SWIFT_NAME(AnalyticsEventGenerateLead) = + @"generate_lead"; + +/// Join Group event. Log this event when a user joins a group such as a guild, team or family. Use +/// this event to analyze how popular certain groups or social features are in your app. Params: +/// +///
    +///
  • @c AnalyticsParameterGroupID (String)
  • +///
+static NSString *const kFIREventJoinGroup NS_SWIFT_NAME(AnalyticsEventJoinGroup) = @"join_group"; + +/// Level End event. Log this event when the user finishes a level. Params: +/// +///
    +///
  • @c AnalyticsParameterLevelName (String)
  • +///
  • @c AnalyticsParameterSuccess (String)
  • +///
+static NSString *const kFIREventLevelEnd NS_SWIFT_NAME(AnalyticsEventLevelEnd) = @"level_end"; + +/// Level Start event. Log this event when the user starts a new level. Params: +/// +///
    +///
  • @c AnalyticsParameterLevelName (String)
  • +///
+static NSString *const kFIREventLevelStart NS_SWIFT_NAME(AnalyticsEventLevelStart) = @"level_start"; + +/// Level Up event. This event signifies that a player has leveled up in your gaming app. It can +/// help you gauge the level distribution of your userbase and help you identify certain levels that +/// are difficult to pass. Params: +/// +///
    +///
  • @c AnalyticsParameterLevel (Int)
  • +///
  • @c AnalyticsParameterCharacter (String) (optional)
  • +///
+static NSString *const kFIREventLevelUp NS_SWIFT_NAME(AnalyticsEventLevelUp) = @"level_up"; + +/// Login event. Apps with a login feature can report this event to signify that a user has logged +/// in. +static NSString *const kFIREventLogin NS_SWIFT_NAME(AnalyticsEventLogin) = @"login"; + +/// Post Score event. Log this event when the user posts a score in your gaming app. This event can +/// help you understand how users are actually performing in your game and it can help you correlate +/// high scores with certain audiences or behaviors. Params: +/// +///
    +///
  • @c AnalyticsParameterScore (Int)
  • +///
  • @c AnalyticsParameterLevel (Int) (optional)
  • +///
  • @c AnalyticsParameterCharacter (String) (optional)
  • +///
+static NSString *const kFIREventPostScore NS_SWIFT_NAME(AnalyticsEventPostScore) = @"post_score"; + +/// E-Commerce Purchase event. This event signifies that an item(s) was purchased by a user. Note: +/// This is different from the in-app purchase event, which is reported automatically for App +/// Store-based apps. Note: If you supply the @c AnalyticsParameterValue parameter, you must also +/// supply the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed +/// accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterAffiliation (String) (optional)
  • +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterEndDate (String) (optional)
  • +///
  • @c AnalyticsParameterItemID (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterShipping (Double) (optional)
  • +///
  • @c AnalyticsParameterStartDate (String) (optional)
  • +///
  • @c AnalyticsParameterTax (Double) (optional)
  • +///
  • @c AnalyticsParameterTransactionID (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventPurchase NS_SWIFT_NAME(AnalyticsEventPurchase) = @"purchase"; + +/// E-Commerce Refund event. This event signifies that a refund was issued. Note: If you supply the +/// @c AnalyticsParameterValue parameter, you must also supply the @c AnalyticsParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterAffiliation (String) (optional)
  • +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterShipping (Double) (optional)
  • +///
  • @c AnalyticsParameterTax (Double) (optional)
  • +///
  • @c AnalyticsParameterTransactionID (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventRefund NS_SWIFT_NAME(AnalyticsEventRefund) = @"refund"; + +/// E-Commerce Remove from Cart event. This event signifies that an item(s) was removed from a cart. +/// Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply the @c +/// AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventRemoveFromCart NS_SWIFT_NAME(AnalyticsEventRemoveFromCart) = + @"remove_from_cart"; + +/// Screen View event. This event signifies a screen view. Use this when a screen transition occurs. +/// This event can be logged irrespective of whether automatic screen tracking is enabled. Params: +/// +///
    +///
  • @c AnalyticsParameterScreenClass (String) (optional)
  • +///
  • @c AnalyticsParameterScreenName (String) (optional)
  • +///
+static NSString *const kFIREventScreenView NS_SWIFT_NAME(AnalyticsEventScreenView) = @"screen_view"; + +/// Search event. Apps that support search features can use this event to contextualize search +/// operations by supplying the appropriate, corresponding parameters. This event can help you +/// identify the most popular content in your app. Params: +/// +///
    +///
  • @c AnalyticsParameterSearchTerm (String)
  • +///
  • @c AnalyticsParameterStartDate (String) (optional)
  • +///
  • @c AnalyticsParameterEndDate (String) (optional)
  • +///
  • @c AnalyticsParameterNumberOfNights (Int) (optional) for hotel bookings
  • +///
  • @c AnalyticsParameterNumberOfRooms (Int) (optional) for hotel bookings
  • +///
  • @c AnalyticsParameterNumberOfPassengers (Int) (optional) for travel bookings
  • +///
  • @c AnalyticsParameterOrigin (String) (optional)
  • +///
  • @c AnalyticsParameterDestination (String) (optional)
  • +///
  • @c AnalyticsParameterTravelClass (String) (optional) for travel bookings
  • +///
+static NSString *const kFIREventSearch NS_SWIFT_NAME(AnalyticsEventSearch) = @"search"; + +/// Select Content event. This general purpose event signifies that a user has selected some content +/// of a certain type in an app. The content can be any object in your app. This event can help you +/// identify popular content and categories of content in your app. Params: +/// +///
    +///
  • @c AnalyticsParameterContentType (String)
  • +///
  • @c AnalyticsParameterItemID (String)
  • +///
+static NSString *const kFIREventSelectContent NS_SWIFT_NAME(AnalyticsEventSelectContent) = + @"select_content"; + +/// Select Item event. This event signifies that an item was selected by a user from a list. Use the +/// appropriate parameters to contextualize the event. Use this event to discover the most popular +/// items selected. Params: +/// +///
    +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterItemListID (String) (optional)
  • +///
  • @c AnalyticsParameterItemListName (String) (optional)
  • +///
+static NSString *const kFIREventSelectItem NS_SWIFT_NAME(AnalyticsEventSelectItem) = @"select_item"; + +/// Select promotion event. This event signifies that a user has selected a promotion offer. Use the +/// appropriate parameters to contextualize the event, such as the item(s) for which the promotion +/// applies. Params: +/// +///
    +///
  • @c AnalyticsParameterCreativeName (String) (optional)
  • +///
  • @c AnalyticsParameterCreativeSlot (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterLocationID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionName (String) (optional)
  • +///
+static NSString *const kFIREventSelectPromotion NS_SWIFT_NAME(AnalyticsEventSelectPromotion) = + @"select_promotion"; + +/// Share event. Apps with social features can log the Share event to identify the most viral +/// content. Params: +/// +///
    +///
  • @c AnalyticsParameterContentType (String)
  • +///
  • @c AnalyticsParameterItemID (String)
  • +///
+static NSString *const kFIREventShare NS_SWIFT_NAME(AnalyticsEventShare) = @"share"; + +/// Sign Up event. This event indicates that a user has signed up for an account in your app. The +/// parameter signifies the method by which the user signed up. Use this event to understand the +/// different behaviors between logged in and logged out users. Params: +/// +///
    +///
  • @c AnalyticsParameterMethod (String)
  • +///
+static NSString *const kFIREventSignUp NS_SWIFT_NAME(AnalyticsEventSignUp) = @"sign_up"; + +/// Spend Virtual Currency event. This event tracks the sale of virtual goods in your app and can +/// help you identify which virtual goods are the most popular objects of purchase. Params: +/// +///
    +///
  • @c AnalyticsParameterItemName (String)
  • +///
  • @c AnalyticsParameterVirtualCurrencyName (String)
  • +///
  • @c AnalyticsParameterValue (Int or Double)
  • +///
+static NSString *const kFIREventSpendVirtualCurrency + NS_SWIFT_NAME(AnalyticsEventSpendVirtualCurrency) = @"spend_virtual_currency"; + +/// Tutorial Begin event. This event signifies the start of the on-boarding process in your app. Use +/// this in a funnel with @c AnalyticsEventTutorialComplete to understand how many users complete +/// this process and move on to the full app experience. +static NSString *const kFIREventTutorialBegin NS_SWIFT_NAME(AnalyticsEventTutorialBegin) = + @"tutorial_begin"; + +/// Tutorial End event. Use this event to signify the user's completion of your app's on-boarding +/// process. Add this to a funnel with @c AnalyticsEventTutorialBegin to gauge the completion rate +/// of your on-boarding process. +static NSString *const kFIREventTutorialComplete NS_SWIFT_NAME(AnalyticsEventTutorialComplete) = + @"tutorial_complete"; + +/// Unlock Achievement event. Log this event when the user has unlocked an achievement in your +/// game. Since achievements generally represent the breadth of a gaming experience, this event can +/// help you understand how many users are experiencing all that your game has to offer. Params: +/// +///
    +///
  • @c AnalyticsParameterAchievementID (String)
  • +///
+static NSString *const kFIREventUnlockAchievement NS_SWIFT_NAME(AnalyticsEventUnlockAchievement) = + @"unlock_achievement"; + +/// E-commerce View Cart event. This event signifies that a user has viewed their cart. Use this to +/// analyze your purchase funnel. Note: If you supply the @c AnalyticsParameterValue parameter, you +/// must also supply the @c AnalyticsParameterCurrency parameter so that revenue metrics can be +/// computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventViewCart NS_SWIFT_NAME(AnalyticsEventViewCart) = @"view_cart"; + +/// View Item event. This event signifies that a user has viewed an item. Use the appropriate +/// parameters to contextualize the event. Use this event to discover the most popular items viewed +/// in your app. Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply +/// the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventViewItem NS_SWIFT_NAME(AnalyticsEventViewItem) = @"view_item"; + +/// View Item List event. Log this event when a user sees a list of items or offerings. Params: +/// +///
    +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterItemListID (String) (optional)
  • +///
  • @c AnalyticsParameterItemListName (String) (optional)
  • +///
+static NSString *const kFIREventViewItemList NS_SWIFT_NAME(AnalyticsEventViewItemList) = + @"view_item_list"; + +/// View Promotion event. This event signifies that a promotion was shown to a user. Add this event +/// to a funnel with the @c AnalyticsEventAddToCart and @c AnalyticsEventPurchase to gauge your +/// conversion process. Params: +/// +///
    +///
  • @c AnalyticsParameterCreativeName (String) (optional)
  • +///
  • @c AnalyticsParameterCreativeSlot (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterLocationID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionName (String) (optional)
  • +///
+static NSString *const kFIREventViewPromotion NS_SWIFT_NAME(AnalyticsEventViewPromotion) = + @"view_promotion"; + +/// View Search Results event. Log this event when the user has been presented with the results of a +/// search. Params: +/// +///
    +///
  • @c AnalyticsParameterSearchTerm (String)
  • +///
+static NSString *const kFIREventViewSearchResults NS_SWIFT_NAME(AnalyticsEventViewSearchResults) = + @"view_search_results"; diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRParameterNames.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRParameterNames.h new file mode 100644 index 0000000..b001ca5 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRParameterNames.h @@ -0,0 +1,721 @@ +/// @file FIRParameterNames.h +/// +/// Predefined event parameter names. +/// +/// Params supply information that contextualize Events. You can associate up to 25 unique Params +/// with each Event type. Some Params are suggested below for certain common Events, but you are +/// not limited to these. You may supply extra Params for suggested Events or custom Params for +/// Custom events. Param names can be up to 40 characters long, may only contain alphanumeric +/// characters and underscores ("_"), and must start with an alphabetic character. Param values can +/// be up to 100 characters long. The "firebase_", "google_", and "ga_" prefixes are reserved and +/// should not be used. + +#import + +/// Game achievement ID (String). +///
+///     let params = [
+///       AnalyticsParameterAchievementID : "10_matches_won",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAchievementID NS_SWIFT_NAME(AnalyticsParameterAchievementID) = + @"achievement_id"; + +/// The ad format (e.g. Banner, Interstitial, Rewarded, Native, Rewarded Interstitial, Instream). +/// (String). +///
+///     let params = [
+///       AnalyticsParameterAdFormat : "Banner",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdFormat NS_SWIFT_NAME(AnalyticsParameterAdFormat) = + @"ad_format"; + +/// Ad Network Click ID (String). Used for network-specific click IDs which vary in format. +///
+///     let params = [
+///       AnalyticsParameterAdNetworkClickID : "1234567",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdNetworkClickID + NS_SWIFT_NAME(AnalyticsParameterAdNetworkClickID) = @"aclid"; + +/// The ad platform (e.g. MoPub, IronSource) (String). +///
+///     let params = [
+///       AnalyticsParameterAdPlatform : "MoPub",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdPlatform NS_SWIFT_NAME(AnalyticsParameterAdPlatform) = + @"ad_platform"; + +/// The ad source (e.g. AdColony) (String). +///
+///     let params = [
+///       AnalyticsParameterAdSource : "AdColony",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdSource NS_SWIFT_NAME(AnalyticsParameterAdSource) = + @"ad_source"; + +/// The ad unit name (e.g. Banner_03) (String). +///
+///     let params = [
+///       AnalyticsParameterAdUnitName : "Banner_03",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdUnitName NS_SWIFT_NAME(AnalyticsParameterAdUnitName) = + @"ad_unit_name"; + +/// A product affiliation to designate a supplying company or brick and mortar store location +/// (String).
+///     let params = [
+///       AnalyticsParameterAffiliation : "Google Store",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAffiliation NS_SWIFT_NAME(AnalyticsParameterAffiliation) = + @"affiliation"; + +/// Campaign custom parameter (String). Used as a method of capturing custom data in a campaign. +/// Use varies by network. +///
+///     let params = [
+///       AnalyticsParameterCP1 : "custom_data",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCP1 NS_SWIFT_NAME(AnalyticsParameterCP1) = @"cp1"; + +/// The individual campaign name, slogan, promo code, etc. Some networks have pre-defined macro to +/// capture campaign information, otherwise can be populated by developer. Highly Recommended +/// (String). +///
+///     let params = [
+///       AnalyticsParameterCampaign : "winter_promotion",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCampaign NS_SWIFT_NAME(AnalyticsParameterCampaign) = + @"campaign"; + +/// Campaign ID (String). Used for keyword analysis to identify a specific product promotion or +/// strategic campaign. This is a required key for GA4 data import. +///
+///     let params = [
+///       AnalyticsParameterCampaignID : "7877652710",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCampaignID NS_SWIFT_NAME(AnalyticsParameterCampaignID) = + @"campaign_id"; + +/// Character used in game (String). +///
+///     let params = [
+///       AnalyticsParameterCharacter : "beat_boss",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCharacter NS_SWIFT_NAME(AnalyticsParameterCharacter) = + @"character"; + +/// Campaign content (String). +static NSString *const kFIRParameterContent NS_SWIFT_NAME(AnalyticsParameterContent) = @"content"; + +/// Type of content selected (String). +///
+///     let params = [
+///       AnalyticsParameterContentType : "news article",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterContentType NS_SWIFT_NAME(AnalyticsParameterContentType) = + @"content_type"; + +/// Coupon code used for a purchase (String). +///
+///     let params = [
+///       AnalyticsParameterCoupon : "SUMMER_FUN",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCoupon NS_SWIFT_NAME(AnalyticsParameterCoupon) = @"coupon"; + +/// Creative Format (String). Used to identify the high-level classification of the type of ad +/// served by a specific campaign. +///
+///     let params = [
+///       AnalyticsParameterCreativeFormat : "display",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCreativeFormat NS_SWIFT_NAME(AnalyticsParameterCreativeFormat) = + @"creative_format"; + +/// The name of a creative used in a promotional spot (String). +///
+///     let params = [
+///       AnalyticsParameterCreativeName : "Summer Sale",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCreativeName NS_SWIFT_NAME(AnalyticsParameterCreativeName) = + @"creative_name"; + +/// The name of a creative slot (String). +///
+///     let params = [
+///       AnalyticsParameterCreativeSlot : "summer_banner2",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCreativeSlot NS_SWIFT_NAME(AnalyticsParameterCreativeSlot) = + @"creative_slot"; + +/// Currency of the purchase or items associated with the event, in 3-letter +/// ISO_4217 format (String). +///
+///     let params = [
+///       AnalyticsParameterCurrency : "USD",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCurrency NS_SWIFT_NAME(AnalyticsParameterCurrency) = + @"currency"; + +/// Flight or Travel destination (String). +///
+///     let params = [
+///       AnalyticsParameterDestination : "Mountain View, CA",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterDestination NS_SWIFT_NAME(AnalyticsParameterDestination) = + @"destination"; + +/// Monetary value of discount associated with a purchase (Double). +///
+///     let params = [
+///       AnalyticsParameterDiscount : 2.0,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $2.00 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterDiscount NS_SWIFT_NAME(AnalyticsParameterDiscount) = + @"discount"; + +/// The arrival date, check-out date or rental end date for the item. This should be in +/// YYYY-MM-DD format (String). +///
+///     let params = [
+///       AnalyticsParameterEndDate : "2015-09-14",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterEndDate NS_SWIFT_NAME(AnalyticsParameterEndDate) = @"end_date"; + +/// Indicates that the associated event should either extend the current session or start a new +/// session if no session was active when the event was logged. Specify 1 to extend the current +/// session or to start a new session; any other value will not extend or start a session. +///
+///     let params = [
+///       AnalyticsParameterExtendSession : 1,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterExtendSession NS_SWIFT_NAME(AnalyticsParameterExtendSession) = + @"extend_session"; + +/// Flight number for travel events (String). +///
+///     let params = [
+///       AnalyticsParameterFlightNumber : "ZZ800",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterFlightNumber NS_SWIFT_NAME(AnalyticsParameterFlightNumber) = + @"flight_number"; + +/// Group/clan/guild ID (String). +///
+///     let params = [
+///       AnalyticsParameterGroupID : "g1",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterGroupID NS_SWIFT_NAME(AnalyticsParameterGroupID) = @"group_id"; + +/// The index of the item in a list (Int). +///
+///     let params = [
+///       AnalyticsParameterIndex : 5,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterIndex NS_SWIFT_NAME(AnalyticsParameterIndex) = @"index"; + +/// Item brand (String). +///
+///     let params = [
+///       AnalyticsParameterItemBrand : "Google",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemBrand NS_SWIFT_NAME(AnalyticsParameterItemBrand) = + @"item_brand"; + +/// Item category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory NS_SWIFT_NAME(AnalyticsParameterItemCategory) = + @"item_category"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory2 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory2 NS_SWIFT_NAME(AnalyticsParameterItemCategory2) = + @"item_category2"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory3 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory3 NS_SWIFT_NAME(AnalyticsParameterItemCategory3) = + @"item_category3"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory4 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory4 NS_SWIFT_NAME(AnalyticsParameterItemCategory4) = + @"item_category4"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory5 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory5 NS_SWIFT_NAME(AnalyticsParameterItemCategory5) = + @"item_category5"; + +/// Item ID (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemID : "SKU_12345",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemID NS_SWIFT_NAME(AnalyticsParameterItemID) = @"item_id"; + +/// The ID of the list in which the item was presented to the user (String). +///
+///     let params = [
+///       AnalyticsParameterItemListID : "ABC123",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemListID NS_SWIFT_NAME(AnalyticsParameterItemListID) = + @"item_list_id"; + +/// The name of the list in which the item was presented to the user (String). +///
+///     let params = [
+///       AnalyticsParameterItemListName : "Related products",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemListName NS_SWIFT_NAME(AnalyticsParameterItemListName) = + @"item_list_name"; + +/// Item Name (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemName : "jeggings",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemName NS_SWIFT_NAME(AnalyticsParameterItemName) = + @"item_name"; + +/// Item variant (String). +///
+///     let params = [
+///       AnalyticsParameterItemVariant : "Black",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemVariant NS_SWIFT_NAME(AnalyticsParameterItemVariant) = + @"item_variant"; + +/// The list of items involved in the transaction expressed as `[[String: Any]]`. +///
+///     let params = [
+///       AnalyticsParameterItems : [
+///         [AnalyticsParameterItemName : "jeggings", AnalyticsParameterItemCategory : "pants"],
+///         [AnalyticsParameterItemName : "boots", AnalyticsParameterItemCategory : "shoes"],
+///       ],
+///     ]
+/// 
+static NSString *const kFIRParameterItems NS_SWIFT_NAME(AnalyticsParameterItems) = @"items"; + +/// Level in game (Int). +///
+///     let params = [
+///       AnalyticsParameterLevel : 42,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLevel NS_SWIFT_NAME(AnalyticsParameterLevel) = @"level"; + +/// The name of a level in a game (String). +///
+///     let params = [
+///       AnalyticsParameterLevelName : "room_1",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLevelName NS_SWIFT_NAME(AnalyticsParameterLevelName) = + @"level_name"; + +/// Location (String). The Google Place ID +/// that corresponds to the associated event. Alternatively, you can supply your own custom +/// Location ID. +///
+///     let params = [
+///       AnalyticsParameterLocation : "ChIJiyj437sx3YAR9kUWC8QkLzQ",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLocation NS_SWIFT_NAME(AnalyticsParameterLocation) = + @"location"; + +/// The location associated with the event. Preferred to be the Google +/// Place ID that corresponds to the +/// associated item but could be overridden to a custom location ID string.(String). +///
+///     let params = [
+///       AnalyticsParameterLocationID : "ChIJiyj437sx3YAR9kUWC8QkLzQ",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLocationID NS_SWIFT_NAME(AnalyticsParameterLocationID) = + @"location_id"; + +/// Marketing Tactic (String). Used to identify the targeting criteria applied to a specific +/// campaign. +///
+///     let params = [
+///       AnalyticsParameterMarketingTactic : "Remarketing",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterMarketingTactic + NS_SWIFT_NAME(AnalyticsParameterMarketingTactic) = @"marketing_tactic"; + +/// The advertising or marketing medium, for example: cpc, banner, email, push. Highly recommended +/// (String). +///
+///     let params = [
+///       AnalyticsParameterMedium : "email",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterMedium NS_SWIFT_NAME(AnalyticsParameterMedium) = @"medium"; + +/// A particular approach used in an operation; for example, "facebook" or "email" in the context +/// of a sign_up or login event. (String). +///
+///     let params = [
+///       AnalyticsParameterMethod : "google",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterMethod NS_SWIFT_NAME(AnalyticsParameterMethod) = @"method"; + +/// Number of nights staying at hotel (Int). +///
+///     let params = [
+///       AnalyticsParameterNumberOfNights : 3,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterNumberOfNights + NS_SWIFT_NAME(AnalyticsParameterNumberOfNights) = @"number_of_nights"; + +/// Number of passengers traveling (Int). +///
+///     let params = [
+///       AnalyticsParameterNumberOfPassengers : 11,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterNumberOfPassengers + NS_SWIFT_NAME(AnalyticsParameterNumberOfPassengers) = @"number_of_passengers"; + +/// Number of rooms for travel events (Int). +///
+///     let params = [
+///       AnalyticsParameterNumberOfRooms : 2,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterNumberOfRooms NS_SWIFT_NAME(AnalyticsParameterNumberOfRooms) = + @"number_of_rooms"; + +/// Flight or Travel origin (String). +///
+///     let params = [
+///       AnalyticsParameterOrigin : "Mountain View, CA",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterOrigin NS_SWIFT_NAME(AnalyticsParameterOrigin) = @"origin"; + +/// The chosen method of payment (String). +///
+///     let params = [
+///       AnalyticsParameterPaymentType : "Visa",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPaymentType NS_SWIFT_NAME(AnalyticsParameterPaymentType) = + @"payment_type"; + +/// Purchase price (Double). +///
+///     let params = [
+///       AnalyticsParameterPrice : 1.0,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $1.00 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPrice NS_SWIFT_NAME(AnalyticsParameterPrice) = @"price"; + +/// The ID of a product promotion (String). +///
+///     let params = [
+///       AnalyticsParameterPromotionID : "ABC123",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPromotionID NS_SWIFT_NAME(AnalyticsParameterPromotionID) = + @"promotion_id"; + +/// The name of a product promotion (String). +///
+///     let params = [
+///       AnalyticsParameterPromotionName : "Summer Sale",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPromotionName NS_SWIFT_NAME(AnalyticsParameterPromotionName) = + @"promotion_name"; + +/// Purchase quantity (Int). +///
+///     let params = [
+///       AnalyticsParameterQuantity : 1,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterQuantity NS_SWIFT_NAME(AnalyticsParameterQuantity) = + @"quantity"; + +/// Score in game (Int). +///
+///     let params = [
+///       AnalyticsParameterScore : 4200,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterScore NS_SWIFT_NAME(AnalyticsParameterScore) = @"score"; + +/// Current screen class, such as the class name of the UIViewController, logged with screen_view +/// event and added to every event (String). +///
+///     let params = [
+///       AnalyticsParameterScreenClass : "LoginViewController",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterScreenClass NS_SWIFT_NAME(AnalyticsParameterScreenClass) = + @"screen_class"; + +/// Current screen name, such as the name of the UIViewController, logged with screen_view event and +/// added to every event (String). +///
+///     let params = [
+///       AnalyticsParameterScreenName : "LoginView",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterScreenName NS_SWIFT_NAME(AnalyticsParameterScreenName) = + @"screen_name"; + +/// The search string/keywords used (String). +///
+///     let params = [
+///       AnalyticsParameterSearchTerm : "periodic table",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSearchTerm NS_SWIFT_NAME(AnalyticsParameterSearchTerm) = + @"search_term"; + +/// Shipping cost associated with a transaction (Double). +///
+///     let params = [
+///       AnalyticsParameterShipping : 5.99,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $5.99 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterShipping NS_SWIFT_NAME(AnalyticsParameterShipping) = + @"shipping"; + +/// The shipping tier (e.g. Ground, Air, Next-day) selected for delivery of the purchased item +/// (String). +///
+///     let params = [
+///       AnalyticsParameterShippingTier : "Ground",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterShippingTier NS_SWIFT_NAME(AnalyticsParameterShippingTier) = + @"shipping_tier"; + +/// The origin of your traffic, such as an Ad network (for example, google) or partner (urban +/// airship). Identify the advertiser, site, publication, etc. that is sending traffic to your +/// property. Highly recommended (String). +///
+///     let params = [
+///       AnalyticsParameterSource : "InMobi",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSource NS_SWIFT_NAME(AnalyticsParameterSource) = @"source"; + +/// Source Platform (String). Used to identify the platform responsible for directing traffic to a +/// given Analytics property (e.g., a buying platform where budgets, targeting criteria, etc. are +/// set, a platform for managing organic traffic data, etc.). +///
+///     let params = [
+///       AnalyticsParameterSourcePlatform : "sa360",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSourcePlatform NS_SWIFT_NAME(AnalyticsParameterSourcePlatform) = + @"source_platform"; + +/// The departure date, check-in date or rental start date for the item. This should be in +/// YYYY-MM-DD format (String). +///
+///     let params = [
+///       AnalyticsParameterStartDate : "2015-09-14",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterStartDate NS_SWIFT_NAME(AnalyticsParameterStartDate) = + @"start_date"; + +/// The result of an operation. Specify 1 to indicate success and 0 to indicate failure (Int). +///
+///     let params = [
+///       AnalyticsParameterSuccess : 1,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSuccess NS_SWIFT_NAME(AnalyticsParameterSuccess) = @"success"; + +/// Tax cost associated with a transaction (Double). +///
+///     let params = [
+///       AnalyticsParameterTax : 2.43,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $2.43 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTax NS_SWIFT_NAME(AnalyticsParameterTax) = @"tax"; + +/// If you're manually tagging keyword campaigns, you should use utm_term to specify the keyword +/// (String). +///
+///     let params = [
+///       AnalyticsParameterTerm : "game",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTerm NS_SWIFT_NAME(AnalyticsParameterTerm) = @"term"; + +/// The unique identifier of a transaction (String). +///
+///     let params = [
+///       AnalyticsParameterTransactionID : "T12345",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTransactionID NS_SWIFT_NAME(AnalyticsParameterTransactionID) = + @"transaction_id"; + +/// Travel class (String). +///
+///     let params = [
+///       AnalyticsParameterTravelClass : "business",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTravelClass NS_SWIFT_NAME(AnalyticsParameterTravelClass) = + @"travel_class"; + +/// A context-specific numeric value which is accumulated automatically for each event type. This is +/// a general purpose parameter that is useful for accumulating a key metric that pertains to an +/// event. Examples include revenue, distance, time and points. Value should be specified as Int or +/// Double. +/// Notes: Values for pre-defined currency-related events (such as @c AnalyticsEventAddToCart) +/// should be supplied using Double and must be accompanied by a @c AnalyticsParameterCurrency +/// parameter. The valid range of accumulated values is +/// [-9,223,372,036,854.77, 9,223,372,036,854.77]. Supplying a non-numeric value, omitting the +/// corresponding @c AnalyticsParameterCurrency parameter, or supplying an invalid +/// currency code for conversion events will cause that +/// conversion to be omitted from reporting. +///
+///     let params = [
+///       AnalyticsParameterValue : 3.99,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $3.99 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterValue NS_SWIFT_NAME(AnalyticsParameterValue) = @"value"; + +/// Name of virtual currency type (String). +///
+///     let params = [
+///       AnalyticsParameterVirtualCurrencyName : "virtual_currency_name",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterVirtualCurrencyName + NS_SWIFT_NAME(AnalyticsParameterVirtualCurrencyName) = @"virtual_currency_name"; diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h new file mode 100644 index 0000000..2442d8a --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h @@ -0,0 +1,28 @@ +/// @file FIRUserPropertyNames.h +/// +/// Predefined user property names. +/// +/// A UserProperty is an attribute that describes the app-user. By supplying UserProperties, you can +/// later analyze different behaviors of various segments of your userbase. You may supply up to 25 +/// unique UserProperties per app, and you can use the name and value of your choosing for each one. +/// UserProperty names can be up to 24 characters long, may only contain alphanumeric characters and +/// underscores ("_"), and must start with an alphabetic character. UserProperty values can be up to +/// 36 characters long. The "firebase_", "google_", and "ga_" prefixes are reserved and should not +/// be used. + +#import + +/// Indicates whether events logged by Google Analytics can be used to personalize ads for the user. +/// Set to "YES" to enable, or "NO" to disable. Default is enabled. See the +/// documentation for +/// more details and information about related settings. +/// +///
+///     Analytics.setUserProperty("NO", forName: AnalyticsUserPropertyAllowAdPersonalizationSignals)
+/// 
+static NSString *const kFIRUserPropertyAllowAdPersonalizationSignals + NS_SWIFT_NAME(AnalyticsUserPropertyAllowAdPersonalizationSignals) = @"allow_personalized_ads"; + +/// The method used to sign in. For example, "google", "facebook" or "twitter". +static NSString *const kFIRUserPropertySignUpMethod + NS_SWIFT_NAME(AnalyticsUserPropertySignUpMethod) = @"sign_up_method"; diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-umbrella.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-umbrella.h new file mode 100644 index 0000000..ad84fbb --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-umbrella.h @@ -0,0 +1,24 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "FIRAnalytics+AppDelegate.h" +#import "FIRAnalytics+Consent.h" +#import "FIRAnalytics+OnDevice.h" +#import "FIRAnalytics.h" +#import "FirebaseAnalytics.h" +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" + +FOUNDATION_EXPORT double FirebaseAnalyticsVersionNumber; +FOUNDATION_EXPORT const unsigned char FirebaseAnalyticsVersionString[]; + diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h new file mode 100644 index 0000000..351da20 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h @@ -0,0 +1,7 @@ +#import "FIRAnalytics+AppDelegate.h" +#import "FIRAnalytics+Consent.h" +#import "FIRAnalytics+OnDevice.h" +#import "FIRAnalytics.h" +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Info.plist b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Info.plist new file mode 100644 index 0000000..1674c5f --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleExecutable + FirebaseAnalytics + CFBundleIdentifier + com.firebase.Firebase-FirebaseAnalytics + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + FirebaseAnalytics + CFBundlePackageType + FMWK + CFBundleVersion + 10.11.0 + DTSDKName + iphonesimulator11.2 + + diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/module.modulemap b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/module.modulemap new file mode 100644 index 0000000..37eb24b --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/module.modulemap @@ -0,0 +1,12 @@ +framework module FirebaseAnalytics { +umbrella header "FirebaseAnalytics-umbrella.h" +export * +module * { export * } + link framework "Foundation" + link framework "Security" + link framework "SystemConfiguration" + link framework "UIKit" + link "c++" + link "sqlite3" + link "z" +} diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/FirebaseAnalytics b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/FirebaseAnalytics new file mode 100644 index 0000000..0689f36 Binary files /dev/null and b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/FirebaseAnalytics differ diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h new file mode 100644 index 0000000..cb1e407 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h @@ -0,0 +1,80 @@ +#import + +#import "FIRAnalytics.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Provides App Delegate handlers to be used in your App Delegate. +/// +/// To save time integrating Firebase Analytics in an application, Firebase Analytics does not +/// require delegation implementation from the AppDelegate if neither SwiftUI nor UIScene lifecycle +/// is adopted. Instead this is automatically done by Firebase Analytics. Should you choose instead +/// to delegate manually, you can turn off the App Delegate Proxy by adding +/// FirebaseAppDelegateProxyEnabled into your app's Info.plist and setting it to boolean `NO`, and +/// adding the methods in this category to corresponding delegation handlers. +/// +/// To handle Universal Links, you must return `true` in +/// `UIApplicationDelegate.application(_:didFinishLaunchingWithOptions:)`. +@interface FIRAnalytics (AppDelegate) + +/// Handles events related to a URL session that are waiting to be processed. +/// +/// 1. If SwiftUI lifecycle is adopted, call this method from +/// `UIApplicationDelegate.application(_:handleEventsForBackgroundURLSession:completionHandler:)` +/// in your app delegate. +/// +/// 2. If SwiftUI lifecycle is not adopted, Firebase Analytics does not require delegation +/// implementation from the AppDelegate. If you choose instead to delegate manually, you can set +/// FirebaseAppDelegateProxyEnabled to boolean `NO` in your app's Info.plist and call this method +/// from +/// `UIApplicationDelegate.application(_:handleEventsForBackgroundURLSession:completionHandler:)` +/// in your app delegate. +/// +/// @param identifier The identifier of the URL session requiring attention. +/// @param completionHandler The completion handler to call when you finish processing the events. +/// Calling this completion handler lets the system know that your app's user interface is +/// updated and a new snapshot can be taken. ++ (void)handleEventsForBackgroundURLSession:(NSString *)identifier + completionHandler:(nullable void (^)(void))completionHandler; + +/// Handles the event when the app is launched by a URL (custom URL scheme or universal link). +/// +/// 1. If SwiftUI lifecycle is adopted, use `onOpenURL(perform:)` to register a handler and call +/// this method in the handler. +/// +/// 2. If UIScene lifecycle is adopted, call this method from +/// `UISceneDelegate.scene(_:willConnectTo:options:)` and +/// `UISceneDelegate.scene(_:openURLContexts:)` when the URL contexts are available. +/// +/// 3. If neither SwiftUI nor UIScene lifecycle is adopted, Firebase Analytics does not require +/// delegation implementation from the AppDelegate. If you choose instead to delegate manually, you +/// can set FirebaseAppDelegateProxyEnabled to boolean `NO` in your app's Info.plist and call this +/// method from `UIApplicationDelegate.application(_:open:options:)` in your app delegate. +/// +/// @param url The URL resource to open. This resource can be a network resource or a file. ++ (void)handleOpenURL:(NSURL *)url; + +/// Handles the event when the app receives data associated with user activity that includes a +/// Universal Link. +/// +/// 1. If SwiftUI lifecycle is adopted, use `onOpenURL(perform:)` to register a handler and call +/// `Analytics.handleOpen(_:)` instead in the handler. +/// +/// 2. If UIScene lifecycle is adopted, call this method from +/// `UISceneDelegate.scene(_:willConnectTo:options:)` and `UISceneDelegate.scene(_:continue:)` when +/// NSUserActivity is available. See the [Apple +/// doc](https://developer.apple.com/documentation/xcode/supporting-universal-links-in-your-app) for +/// more details. +/// +/// 3. If neither SwiftUI nor UIScene lifecycle is adopted, Firebase Analytics does not require +/// delegation implementation from the AppDelegate. If you choose instead to delegate manually, you +/// can set FirebaseAppDelegateProxyEnabled to boolean `NO` in your app's Info.plist and call this +/// method from `UIApplication.application(_:continue:restorationHandler:)` in your app delegate. +/// +/// @param userActivity The activity object containing the data associated with the task the user +/// was performing. ++ (void)handleUserActivity:(id)userActivity; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Headers/FIRAnalytics+Consent.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Headers/FIRAnalytics+Consent.h new file mode 100644 index 0000000..7f89831 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Headers/FIRAnalytics+Consent.h @@ -0,0 +1,33 @@ +#import + +#import "FIRAnalytics.h" + +NS_ASSUME_NONNULL_BEGIN + +/// The type of consent to set. Supported consent types are `ConsentType.adStorage` and +/// `ConsentType.analyticsStorage`. Omitting a type retains its previous status. +typedef NSString *FIRConsentType NS_TYPED_ENUM NS_SWIFT_NAME(ConsentType); +extern FIRConsentType const FIRConsentTypeAdStorage; +extern FIRConsentType const FIRConsentTypeAnalyticsStorage; + +/// The status value of the consent type. Supported statuses are `ConsentStatus.granted` and +/// `ConsentStatus.denied`. +typedef NSString *FIRConsentStatus NS_TYPED_ENUM NS_SWIFT_NAME(ConsentStatus); +extern FIRConsentStatus const FIRConsentStatusDenied; +extern FIRConsentStatus const FIRConsentStatusGranted; + +/// Sets the applicable end user consent state. +@interface FIRAnalytics (Consent) + +/// Sets the applicable end user consent state (e.g. for device identifiers) for this app on this +/// device. Use the consent settings to specify individual consent type values. Settings are +/// persisted across app sessions. By default consent types are set to `ConsentStatus.granted`. +/// +/// @param consentSettings A Dictionary of consent types. Supported consent type keys are +/// `ConsentType.adStorage` and `ConsentType.analyticsStorage`. Valid values are +/// `ConsentStatus.granted` and `ConsentStatus.denied`. ++ (void)setConsent:(NSDictionary *)consentSettings; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Headers/FIRAnalytics+OnDevice.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Headers/FIRAnalytics+OnDevice.h new file mode 100644 index 0000000..1d9a438 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Headers/FIRAnalytics+OnDevice.h @@ -0,0 +1,19 @@ +#import + +#import "FIRAnalytics.h" + +NS_ASSUME_NONNULL_BEGIN + +API_UNAVAILABLE(macCatalyst, macos, tvos, watchos) +@interface FIRAnalytics (OnDevice) + +/// Initiates on-device conversion measurement given a user email address. Requires dependency +/// GoogleAppMeasurementOnDeviceConversion to be linked in, otherwise it is a no-op. +/// @param emailAddress User email address. Include a domain name for all email addresses +/// (e.g. gmail.com or hotmail.co.jp). ++ (void)initiateOnDeviceConversionMeasurementWithEmailAddress:(NSString *)emailAddress + NS_SWIFT_NAME(initiateOnDeviceConversionMeasurement(emailAddress:)); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Headers/FIRAnalytics.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Headers/FIRAnalytics.h new file mode 100644 index 0000000..e7ce5dc --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Headers/FIRAnalytics.h @@ -0,0 +1,154 @@ +#import + +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" + +NS_ASSUME_NONNULL_BEGIN + +/// The top level Firebase Analytics singleton that provides methods for logging events and setting +/// user properties. See the developer guides for general +/// information on using Firebase Analytics in your apps. +/// +/// @note The Analytics SDK uses SQLite to persist events and other app-specific data. Calling +/// certain thread-unsafe global SQLite methods like `sqlite3_shutdown()` can result in +/// unexpected crashes at runtime. +NS_SWIFT_NAME(Analytics) +@interface FIRAnalytics : NSObject + +/// Logs an app event. The event can have up to 25 parameters. Events with the same name must have +/// the same parameters. Up to 500 event names are supported. Using predefined events and/or +/// parameters is recommended for optimal reporting. +/// +/// The following event names are reserved and cannot be used: +///
    +///
  • ad_activeview
  • +///
  • ad_click
  • +///
  • ad_exposure
  • +///
  • ad_query
  • +///
  • ad_reward
  • +///
  • adunit_exposure
  • +///
  • app_clear_data
  • +///
  • app_exception
  • +///
  • app_remove
  • +///
  • app_store_refund
  • +///
  • app_store_subscription_cancel
  • +///
  • app_store_subscription_convert
  • +///
  • app_store_subscription_renew
  • +///
  • app_update
  • +///
  • app_upgrade
  • +///
  • dynamic_link_app_open
  • +///
  • dynamic_link_app_update
  • +///
  • dynamic_link_first_open
  • +///
  • error
  • +///
  • firebase_campaign
  • +///
  • first_open
  • +///
  • first_visit
  • +///
  • in_app_purchase
  • +///
  • notification_dismiss
  • +///
  • notification_foreground
  • +///
  • notification_open
  • +///
  • notification_receive
  • +///
  • os_update
  • +///
  • session_start
  • +///
  • session_start_with_rollout
  • +///
  • user_engagement
  • +///
+/// +/// @param name The name of the event. Should contain 1 to 40 alphanumeric characters or +/// underscores. The name must start with an alphabetic character. Some event names are +/// reserved. See FIREventNames.h for the list of reserved event names. The "firebase_", +/// "google_", and "ga_" prefixes are reserved and should not be used. Note that event names are +/// case-sensitive and that logging two events whose names differ only in case will result in +/// two distinct events. To manually log screen view events, use the `screen_view` event name. +/// @param parameters The dictionary of event parameters. Passing `nil` indicates that the event has +/// no parameters. Parameter names can be up to 40 characters long and must start with an +/// alphabetic character and contain only alphanumeric characters and underscores. Only String, +/// Int, and Double parameter types are supported. String parameter values can be up to 100 +/// characters long. The "firebase_", "google_", and "ga_" prefixes are reserved and should not +/// be used for parameter names. ++ (void)logEventWithName:(NSString *)name + parameters:(nullable NSDictionary *)parameters + NS_SWIFT_NAME(logEvent(_:parameters:)); + +/// Sets a user property to a given value. Up to 25 user property names are supported. Once set, +/// user property values persist throughout the app lifecycle and across sessions. +/// +/// The following user property names are reserved and cannot be used: +///
    +///
  • first_open_time
  • +///
  • last_deep_link_referrer
  • +///
  • user_id
  • +///
+/// +/// @param value The value of the user property. Values can be up to 36 characters long. Setting the +/// value to `nil` removes the user property. +/// @param name The name of the user property to set. Should contain 1 to 24 alphanumeric characters +/// or underscores and must start with an alphabetic character. The "firebase_", "google_", and +/// "ga_" prefixes are reserved and should not be used for user property names. ++ (void)setUserPropertyString:(nullable NSString *)value forName:(NSString *)name + NS_SWIFT_NAME(setUserProperty(_:forName:)); + +/// Sets the user ID property. This feature must be used in accordance with +/// Google's Privacy Policy +/// +/// @param userID The user ID to ascribe to the user of this app on this device, which must be +/// non-empty and no more than 256 characters long. Setting userID to `nil` removes the user ID. ++ (void)setUserID:(nullable NSString *)userID; + +/// Sets whether analytics collection is enabled for this app on this device. This setting is +/// persisted across app sessions. By default it is enabled. +/// +/// @param analyticsCollectionEnabled A flag that enables or disables Analytics collection. ++ (void)setAnalyticsCollectionEnabled:(BOOL)analyticsCollectionEnabled; + +/// Sets the interval of inactivity in seconds that terminates the current session. The default +/// value is 1800 seconds (30 minutes). +/// +/// @param sessionTimeoutInterval The custom time of inactivity in seconds before the current +/// session terminates. ++ (void)setSessionTimeoutInterval:(NSTimeInterval)sessionTimeoutInterval; + +/// Asynchronously retrieves the identifier of the current app session. +/// +/// The session ID retrieval could fail due to Analytics collection disabled, app session expired, +/// etc. +/// +/// @param completion The completion handler to call when the session ID retrieval is complete. This +/// handler is executed on a system-defined global concurrent queue. +/// This completion handler takes the following parameters: +/// sessionID The identifier of the current app session. The value is undefined if the +/// request failed. +/// error An error object that indicates why the request failed, or `nil` if the request +/// was successful. ++ (void)sessionIDWithCompletion:(void (^)(int64_t sessionID, NSError *_Nullable error))completion; + +/// Returns the unique ID for this instance of the application or `nil` if +/// `ConsentType.analyticsStorage` has been set to `ConsentStatus.denied`. +/// +/// @see `FIRAnalytics+Consent.h` ++ (nullable NSString *)appInstanceID; + +/// Clears all analytics data for this instance from the device and resets the app instance ID. ++ (void)resetAnalyticsData; + +/// Adds parameters that will be set on every event logged from the SDK, including automatic ones. +/// The values passed in the parameters dictionary will be added to the dictionary of default event +/// parameters. These parameters persist across app runs. They are of lower precedence than event +/// parameters, so if an event parameter and a parameter set using this API have the same name, the +/// value of the event parameter will be used. The same limitations on event parameters apply to +/// default event parameters. +/// +/// @param parameters Parameters to be added to the dictionary of parameters added to every event. +/// They will be added to the dictionary of default event parameters, replacing any existing +/// parameter with the same name. Valid parameters are String, Int, and Double. Setting a key's +/// value to `NSNull()` will clear that parameter. Passing in a `nil` dictionary will clear all +/// parameters. ++ (void)setDefaultEventParameters:(nullable NSDictionary *)parameters; + +/// Unavailable. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Headers/FIREventNames.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Headers/FIREventNames.h new file mode 100644 index 0000000..1e69a44 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Headers/FIREventNames.h @@ -0,0 +1,418 @@ +/// @file FIREventNames.h +/// +/// Predefined event names. +/// +/// An Event is an important occurrence in your app that you want to measure. You can report up to +/// 500 different types of Events per app and you can associate up to 25 unique parameters with each +/// Event type. Some common events are suggested below, but you may also choose to specify custom +/// Event types that are associated with your specific app. Each event type is identified by a +/// unique name. Event names can be up to 40 characters long, may only contain alphanumeric +/// characters and underscores ("_"), and must start with an alphabetic character. The "firebase_", +/// "google_", and "ga_" prefixes are reserved and should not be used. + +#import + +/// Ad Impression event. This event signifies when a user sees an ad impression. Note: If you supply +/// the @c AnalyticsParameterValue parameter, you must also supply the @c AnalyticsParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterAdPlatform (String) (optional)
  • +///
  • @c AnalyticsParameterAdFormat (String) (optional)
  • +///
  • @c AnalyticsParameterAdSource (String) (optional)
  • +///
  • @c AnalyticsParameterAdUnitName (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAdImpression NS_SWIFT_NAME(AnalyticsEventAdImpression) = + @"ad_impression"; + +/// Add Payment Info event. This event signifies that a user has submitted their payment +/// information. Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply +/// the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterPaymentType (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddPaymentInfo NS_SWIFT_NAME(AnalyticsEventAddPaymentInfo) = + @"add_payment_info"; + +/// Add Shipping Info event. This event signifies that a user has submitted their shipping +/// information. Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply +/// the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterShippingTier (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddShippingInfo NS_SWIFT_NAME(AnalyticsEventAddShippingInfo) = + @"add_shipping_info"; + +/// E-Commerce Add To Cart event. This event signifies that an item(s) was added to a cart for +/// purchase. Add this event to a funnel with @c AnalyticsEventPurchase to gauge the effectiveness +/// of your checkout process. Note: If you supply the @c AnalyticsParameterValue parameter, you must +/// also supply the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed +/// accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddToCart NS_SWIFT_NAME(AnalyticsEventAddToCart) = @"add_to_cart"; + +/// E-Commerce Add To Wishlist event. This event signifies that an item was added to a wishlist. Use +/// this event to identify popular gift items. Note: If you supply the @c AnalyticsParameterValue +/// parameter, you must also supply the @c AnalyticsParameterCurrency parameter so that revenue +/// metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddToWishlist NS_SWIFT_NAME(AnalyticsEventAddToWishlist) = + @"add_to_wishlist"; + +/// App Open event. By logging this event when an App becomes active, developers can understand how +/// often users leave and return during the course of a Session. Although Sessions are automatically +/// reported, this event can provide further clarification around the continuous engagement of +/// app-users. +static NSString *const kFIREventAppOpen NS_SWIFT_NAME(AnalyticsEventAppOpen) = @"app_open"; + +/// E-Commerce Begin Checkout event. This event signifies that a user has begun the process of +/// checking out. Add this event to a funnel with your @c AnalyticsEventPurchase event to gauge the +/// effectiveness of your checkout process. Note: If you supply the @c AnalyticsParameterValue +/// parameter, you must also supply the @c AnalyticsParameterCurrency parameter so that revenue +/// metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventBeginCheckout NS_SWIFT_NAME(AnalyticsEventBeginCheckout) = + @"begin_checkout"; + +/// Campaign Detail event. Log this event to supply the referral details of a re-engagement +/// campaign. Note: you must supply at least one of the required parameters +/// AnalyticsParameterSource, AnalyticsParameterMedium or AnalyticsParameterCampaign. Params: +/// +///
    +///
  • @c AnalyticsParameterSource (String)
  • +///
  • @c AnalyticsParameterMedium (String)
  • +///
  • @c AnalyticsParameterCampaign (String)
  • +///
  • @c AnalyticsParameterTerm (String) (optional)
  • +///
  • @c AnalyticsParameterContent (String) (optional)
  • +///
  • @c AnalyticsParameterAdNetworkClickID (String) (optional)
  • +///
  • @c AnalyticsParameterCP1 (String) (optional)
  • +///
  • @c AnalyticsParameterCampaignID (String) (optional)
  • +///
  • @c AnalyticsParameterCreativeFormat (String) (optional)
  • +///
  • @c AnalyticsParameterMarketingTactic (String) (optional)
  • +///
  • @c AnalyticsParameterSourcePlatform (String) (optional)
  • +///
+static NSString *const kFIREventCampaignDetails NS_SWIFT_NAME(AnalyticsEventCampaignDetails) = + @"campaign_details"; + +/// Earn Virtual Currency event. This event tracks the awarding of virtual currency in your app. Log +/// this along with @c AnalyticsEventSpendVirtualCurrency to better understand your virtual economy. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterVirtualCurrencyName (String)
  • +///
  • @c AnalyticsParameterValue (Int or Double)
  • +///
+static NSString *const kFIREventEarnVirtualCurrency + NS_SWIFT_NAME(AnalyticsEventEarnVirtualCurrency) = @"earn_virtual_currency"; + +/// Generate Lead event. Log this event when a lead has been generated in the app to understand the +/// efficacy of your install and re-engagement campaigns. Note: If you supply the +/// @c AnalyticsParameterValue parameter, you must also supply the @c AnalyticsParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventGenerateLead NS_SWIFT_NAME(AnalyticsEventGenerateLead) = + @"generate_lead"; + +/// Join Group event. Log this event when a user joins a group such as a guild, team or family. Use +/// this event to analyze how popular certain groups or social features are in your app. Params: +/// +///
    +///
  • @c AnalyticsParameterGroupID (String)
  • +///
+static NSString *const kFIREventJoinGroup NS_SWIFT_NAME(AnalyticsEventJoinGroup) = @"join_group"; + +/// Level End event. Log this event when the user finishes a level. Params: +/// +///
    +///
  • @c AnalyticsParameterLevelName (String)
  • +///
  • @c AnalyticsParameterSuccess (String)
  • +///
+static NSString *const kFIREventLevelEnd NS_SWIFT_NAME(AnalyticsEventLevelEnd) = @"level_end"; + +/// Level Start event. Log this event when the user starts a new level. Params: +/// +///
    +///
  • @c AnalyticsParameterLevelName (String)
  • +///
+static NSString *const kFIREventLevelStart NS_SWIFT_NAME(AnalyticsEventLevelStart) = @"level_start"; + +/// Level Up event. This event signifies that a player has leveled up in your gaming app. It can +/// help you gauge the level distribution of your userbase and help you identify certain levels that +/// are difficult to pass. Params: +/// +///
    +///
  • @c AnalyticsParameterLevel (Int)
  • +///
  • @c AnalyticsParameterCharacter (String) (optional)
  • +///
+static NSString *const kFIREventLevelUp NS_SWIFT_NAME(AnalyticsEventLevelUp) = @"level_up"; + +/// Login event. Apps with a login feature can report this event to signify that a user has logged +/// in. +static NSString *const kFIREventLogin NS_SWIFT_NAME(AnalyticsEventLogin) = @"login"; + +/// Post Score event. Log this event when the user posts a score in your gaming app. This event can +/// help you understand how users are actually performing in your game and it can help you correlate +/// high scores with certain audiences or behaviors. Params: +/// +///
    +///
  • @c AnalyticsParameterScore (Int)
  • +///
  • @c AnalyticsParameterLevel (Int) (optional)
  • +///
  • @c AnalyticsParameterCharacter (String) (optional)
  • +///
+static NSString *const kFIREventPostScore NS_SWIFT_NAME(AnalyticsEventPostScore) = @"post_score"; + +/// E-Commerce Purchase event. This event signifies that an item(s) was purchased by a user. Note: +/// This is different from the in-app purchase event, which is reported automatically for App +/// Store-based apps. Note: If you supply the @c AnalyticsParameterValue parameter, you must also +/// supply the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed +/// accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterAffiliation (String) (optional)
  • +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterEndDate (String) (optional)
  • +///
  • @c AnalyticsParameterItemID (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterShipping (Double) (optional)
  • +///
  • @c AnalyticsParameterStartDate (String) (optional)
  • +///
  • @c AnalyticsParameterTax (Double) (optional)
  • +///
  • @c AnalyticsParameterTransactionID (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventPurchase NS_SWIFT_NAME(AnalyticsEventPurchase) = @"purchase"; + +/// E-Commerce Refund event. This event signifies that a refund was issued. Note: If you supply the +/// @c AnalyticsParameterValue parameter, you must also supply the @c AnalyticsParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterAffiliation (String) (optional)
  • +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterShipping (Double) (optional)
  • +///
  • @c AnalyticsParameterTax (Double) (optional)
  • +///
  • @c AnalyticsParameterTransactionID (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventRefund NS_SWIFT_NAME(AnalyticsEventRefund) = @"refund"; + +/// E-Commerce Remove from Cart event. This event signifies that an item(s) was removed from a cart. +/// Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply the @c +/// AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventRemoveFromCart NS_SWIFT_NAME(AnalyticsEventRemoveFromCart) = + @"remove_from_cart"; + +/// Screen View event. This event signifies a screen view. Use this when a screen transition occurs. +/// This event can be logged irrespective of whether automatic screen tracking is enabled. Params: +/// +///
    +///
  • @c AnalyticsParameterScreenClass (String) (optional)
  • +///
  • @c AnalyticsParameterScreenName (String) (optional)
  • +///
+static NSString *const kFIREventScreenView NS_SWIFT_NAME(AnalyticsEventScreenView) = @"screen_view"; + +/// Search event. Apps that support search features can use this event to contextualize search +/// operations by supplying the appropriate, corresponding parameters. This event can help you +/// identify the most popular content in your app. Params: +/// +///
    +///
  • @c AnalyticsParameterSearchTerm (String)
  • +///
  • @c AnalyticsParameterStartDate (String) (optional)
  • +///
  • @c AnalyticsParameterEndDate (String) (optional)
  • +///
  • @c AnalyticsParameterNumberOfNights (Int) (optional) for hotel bookings
  • +///
  • @c AnalyticsParameterNumberOfRooms (Int) (optional) for hotel bookings
  • +///
  • @c AnalyticsParameterNumberOfPassengers (Int) (optional) for travel bookings
  • +///
  • @c AnalyticsParameterOrigin (String) (optional)
  • +///
  • @c AnalyticsParameterDestination (String) (optional)
  • +///
  • @c AnalyticsParameterTravelClass (String) (optional) for travel bookings
  • +///
+static NSString *const kFIREventSearch NS_SWIFT_NAME(AnalyticsEventSearch) = @"search"; + +/// Select Content event. This general purpose event signifies that a user has selected some content +/// of a certain type in an app. The content can be any object in your app. This event can help you +/// identify popular content and categories of content in your app. Params: +/// +///
    +///
  • @c AnalyticsParameterContentType (String)
  • +///
  • @c AnalyticsParameterItemID (String)
  • +///
+static NSString *const kFIREventSelectContent NS_SWIFT_NAME(AnalyticsEventSelectContent) = + @"select_content"; + +/// Select Item event. This event signifies that an item was selected by a user from a list. Use the +/// appropriate parameters to contextualize the event. Use this event to discover the most popular +/// items selected. Params: +/// +///
    +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterItemListID (String) (optional)
  • +///
  • @c AnalyticsParameterItemListName (String) (optional)
  • +///
+static NSString *const kFIREventSelectItem NS_SWIFT_NAME(AnalyticsEventSelectItem) = @"select_item"; + +/// Select promotion event. This event signifies that a user has selected a promotion offer. Use the +/// appropriate parameters to contextualize the event, such as the item(s) for which the promotion +/// applies. Params: +/// +///
    +///
  • @c AnalyticsParameterCreativeName (String) (optional)
  • +///
  • @c AnalyticsParameterCreativeSlot (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterLocationID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionName (String) (optional)
  • +///
+static NSString *const kFIREventSelectPromotion NS_SWIFT_NAME(AnalyticsEventSelectPromotion) = + @"select_promotion"; + +/// Share event. Apps with social features can log the Share event to identify the most viral +/// content. Params: +/// +///
    +///
  • @c AnalyticsParameterContentType (String)
  • +///
  • @c AnalyticsParameterItemID (String)
  • +///
+static NSString *const kFIREventShare NS_SWIFT_NAME(AnalyticsEventShare) = @"share"; + +/// Sign Up event. This event indicates that a user has signed up for an account in your app. The +/// parameter signifies the method by which the user signed up. Use this event to understand the +/// different behaviors between logged in and logged out users. Params: +/// +///
    +///
  • @c AnalyticsParameterMethod (String)
  • +///
+static NSString *const kFIREventSignUp NS_SWIFT_NAME(AnalyticsEventSignUp) = @"sign_up"; + +/// Spend Virtual Currency event. This event tracks the sale of virtual goods in your app and can +/// help you identify which virtual goods are the most popular objects of purchase. Params: +/// +///
    +///
  • @c AnalyticsParameterItemName (String)
  • +///
  • @c AnalyticsParameterVirtualCurrencyName (String)
  • +///
  • @c AnalyticsParameterValue (Int or Double)
  • +///
+static NSString *const kFIREventSpendVirtualCurrency + NS_SWIFT_NAME(AnalyticsEventSpendVirtualCurrency) = @"spend_virtual_currency"; + +/// Tutorial Begin event. This event signifies the start of the on-boarding process in your app. Use +/// this in a funnel with @c AnalyticsEventTutorialComplete to understand how many users complete +/// this process and move on to the full app experience. +static NSString *const kFIREventTutorialBegin NS_SWIFT_NAME(AnalyticsEventTutorialBegin) = + @"tutorial_begin"; + +/// Tutorial End event. Use this event to signify the user's completion of your app's on-boarding +/// process. Add this to a funnel with @c AnalyticsEventTutorialBegin to gauge the completion rate +/// of your on-boarding process. +static NSString *const kFIREventTutorialComplete NS_SWIFT_NAME(AnalyticsEventTutorialComplete) = + @"tutorial_complete"; + +/// Unlock Achievement event. Log this event when the user has unlocked an achievement in your +/// game. Since achievements generally represent the breadth of a gaming experience, this event can +/// help you understand how many users are experiencing all that your game has to offer. Params: +/// +///
    +///
  • @c AnalyticsParameterAchievementID (String)
  • +///
+static NSString *const kFIREventUnlockAchievement NS_SWIFT_NAME(AnalyticsEventUnlockAchievement) = + @"unlock_achievement"; + +/// E-commerce View Cart event. This event signifies that a user has viewed their cart. Use this to +/// analyze your purchase funnel. Note: If you supply the @c AnalyticsParameterValue parameter, you +/// must also supply the @c AnalyticsParameterCurrency parameter so that revenue metrics can be +/// computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventViewCart NS_SWIFT_NAME(AnalyticsEventViewCart) = @"view_cart"; + +/// View Item event. This event signifies that a user has viewed an item. Use the appropriate +/// parameters to contextualize the event. Use this event to discover the most popular items viewed +/// in your app. Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply +/// the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventViewItem NS_SWIFT_NAME(AnalyticsEventViewItem) = @"view_item"; + +/// View Item List event. Log this event when a user sees a list of items or offerings. Params: +/// +///
    +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterItemListID (String) (optional)
  • +///
  • @c AnalyticsParameterItemListName (String) (optional)
  • +///
+static NSString *const kFIREventViewItemList NS_SWIFT_NAME(AnalyticsEventViewItemList) = + @"view_item_list"; + +/// View Promotion event. This event signifies that a promotion was shown to a user. Add this event +/// to a funnel with the @c AnalyticsEventAddToCart and @c AnalyticsEventPurchase to gauge your +/// conversion process. Params: +/// +///
    +///
  • @c AnalyticsParameterCreativeName (String) (optional)
  • +///
  • @c AnalyticsParameterCreativeSlot (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterLocationID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionName (String) (optional)
  • +///
+static NSString *const kFIREventViewPromotion NS_SWIFT_NAME(AnalyticsEventViewPromotion) = + @"view_promotion"; + +/// View Search Results event. Log this event when the user has been presented with the results of a +/// search. Params: +/// +///
    +///
  • @c AnalyticsParameterSearchTerm (String)
  • +///
+static NSString *const kFIREventViewSearchResults NS_SWIFT_NAME(AnalyticsEventViewSearchResults) = + @"view_search_results"; diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Headers/FIRParameterNames.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Headers/FIRParameterNames.h new file mode 100644 index 0000000..b001ca5 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Headers/FIRParameterNames.h @@ -0,0 +1,721 @@ +/// @file FIRParameterNames.h +/// +/// Predefined event parameter names. +/// +/// Params supply information that contextualize Events. You can associate up to 25 unique Params +/// with each Event type. Some Params are suggested below for certain common Events, but you are +/// not limited to these. You may supply extra Params for suggested Events or custom Params for +/// Custom events. Param names can be up to 40 characters long, may only contain alphanumeric +/// characters and underscores ("_"), and must start with an alphabetic character. Param values can +/// be up to 100 characters long. The "firebase_", "google_", and "ga_" prefixes are reserved and +/// should not be used. + +#import + +/// Game achievement ID (String). +///
+///     let params = [
+///       AnalyticsParameterAchievementID : "10_matches_won",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAchievementID NS_SWIFT_NAME(AnalyticsParameterAchievementID) = + @"achievement_id"; + +/// The ad format (e.g. Banner, Interstitial, Rewarded, Native, Rewarded Interstitial, Instream). +/// (String). +///
+///     let params = [
+///       AnalyticsParameterAdFormat : "Banner",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdFormat NS_SWIFT_NAME(AnalyticsParameterAdFormat) = + @"ad_format"; + +/// Ad Network Click ID (String). Used for network-specific click IDs which vary in format. +///
+///     let params = [
+///       AnalyticsParameterAdNetworkClickID : "1234567",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdNetworkClickID + NS_SWIFT_NAME(AnalyticsParameterAdNetworkClickID) = @"aclid"; + +/// The ad platform (e.g. MoPub, IronSource) (String). +///
+///     let params = [
+///       AnalyticsParameterAdPlatform : "MoPub",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdPlatform NS_SWIFT_NAME(AnalyticsParameterAdPlatform) = + @"ad_platform"; + +/// The ad source (e.g. AdColony) (String). +///
+///     let params = [
+///       AnalyticsParameterAdSource : "AdColony",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdSource NS_SWIFT_NAME(AnalyticsParameterAdSource) = + @"ad_source"; + +/// The ad unit name (e.g. Banner_03) (String). +///
+///     let params = [
+///       AnalyticsParameterAdUnitName : "Banner_03",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdUnitName NS_SWIFT_NAME(AnalyticsParameterAdUnitName) = + @"ad_unit_name"; + +/// A product affiliation to designate a supplying company or brick and mortar store location +/// (String).
+///     let params = [
+///       AnalyticsParameterAffiliation : "Google Store",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAffiliation NS_SWIFT_NAME(AnalyticsParameterAffiliation) = + @"affiliation"; + +/// Campaign custom parameter (String). Used as a method of capturing custom data in a campaign. +/// Use varies by network. +///
+///     let params = [
+///       AnalyticsParameterCP1 : "custom_data",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCP1 NS_SWIFT_NAME(AnalyticsParameterCP1) = @"cp1"; + +/// The individual campaign name, slogan, promo code, etc. Some networks have pre-defined macro to +/// capture campaign information, otherwise can be populated by developer. Highly Recommended +/// (String). +///
+///     let params = [
+///       AnalyticsParameterCampaign : "winter_promotion",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCampaign NS_SWIFT_NAME(AnalyticsParameterCampaign) = + @"campaign"; + +/// Campaign ID (String). Used for keyword analysis to identify a specific product promotion or +/// strategic campaign. This is a required key for GA4 data import. +///
+///     let params = [
+///       AnalyticsParameterCampaignID : "7877652710",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCampaignID NS_SWIFT_NAME(AnalyticsParameterCampaignID) = + @"campaign_id"; + +/// Character used in game (String). +///
+///     let params = [
+///       AnalyticsParameterCharacter : "beat_boss",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCharacter NS_SWIFT_NAME(AnalyticsParameterCharacter) = + @"character"; + +/// Campaign content (String). +static NSString *const kFIRParameterContent NS_SWIFT_NAME(AnalyticsParameterContent) = @"content"; + +/// Type of content selected (String). +///
+///     let params = [
+///       AnalyticsParameterContentType : "news article",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterContentType NS_SWIFT_NAME(AnalyticsParameterContentType) = + @"content_type"; + +/// Coupon code used for a purchase (String). +///
+///     let params = [
+///       AnalyticsParameterCoupon : "SUMMER_FUN",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCoupon NS_SWIFT_NAME(AnalyticsParameterCoupon) = @"coupon"; + +/// Creative Format (String). Used to identify the high-level classification of the type of ad +/// served by a specific campaign. +///
+///     let params = [
+///       AnalyticsParameterCreativeFormat : "display",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCreativeFormat NS_SWIFT_NAME(AnalyticsParameterCreativeFormat) = + @"creative_format"; + +/// The name of a creative used in a promotional spot (String). +///
+///     let params = [
+///       AnalyticsParameterCreativeName : "Summer Sale",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCreativeName NS_SWIFT_NAME(AnalyticsParameterCreativeName) = + @"creative_name"; + +/// The name of a creative slot (String). +///
+///     let params = [
+///       AnalyticsParameterCreativeSlot : "summer_banner2",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCreativeSlot NS_SWIFT_NAME(AnalyticsParameterCreativeSlot) = + @"creative_slot"; + +/// Currency of the purchase or items associated with the event, in 3-letter +/// ISO_4217 format (String). +///
+///     let params = [
+///       AnalyticsParameterCurrency : "USD",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCurrency NS_SWIFT_NAME(AnalyticsParameterCurrency) = + @"currency"; + +/// Flight or Travel destination (String). +///
+///     let params = [
+///       AnalyticsParameterDestination : "Mountain View, CA",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterDestination NS_SWIFT_NAME(AnalyticsParameterDestination) = + @"destination"; + +/// Monetary value of discount associated with a purchase (Double). +///
+///     let params = [
+///       AnalyticsParameterDiscount : 2.0,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $2.00 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterDiscount NS_SWIFT_NAME(AnalyticsParameterDiscount) = + @"discount"; + +/// The arrival date, check-out date or rental end date for the item. This should be in +/// YYYY-MM-DD format (String). +///
+///     let params = [
+///       AnalyticsParameterEndDate : "2015-09-14",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterEndDate NS_SWIFT_NAME(AnalyticsParameterEndDate) = @"end_date"; + +/// Indicates that the associated event should either extend the current session or start a new +/// session if no session was active when the event was logged. Specify 1 to extend the current +/// session or to start a new session; any other value will not extend or start a session. +///
+///     let params = [
+///       AnalyticsParameterExtendSession : 1,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterExtendSession NS_SWIFT_NAME(AnalyticsParameterExtendSession) = + @"extend_session"; + +/// Flight number for travel events (String). +///
+///     let params = [
+///       AnalyticsParameterFlightNumber : "ZZ800",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterFlightNumber NS_SWIFT_NAME(AnalyticsParameterFlightNumber) = + @"flight_number"; + +/// Group/clan/guild ID (String). +///
+///     let params = [
+///       AnalyticsParameterGroupID : "g1",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterGroupID NS_SWIFT_NAME(AnalyticsParameterGroupID) = @"group_id"; + +/// The index of the item in a list (Int). +///
+///     let params = [
+///       AnalyticsParameterIndex : 5,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterIndex NS_SWIFT_NAME(AnalyticsParameterIndex) = @"index"; + +/// Item brand (String). +///
+///     let params = [
+///       AnalyticsParameterItemBrand : "Google",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemBrand NS_SWIFT_NAME(AnalyticsParameterItemBrand) = + @"item_brand"; + +/// Item category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory NS_SWIFT_NAME(AnalyticsParameterItemCategory) = + @"item_category"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory2 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory2 NS_SWIFT_NAME(AnalyticsParameterItemCategory2) = + @"item_category2"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory3 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory3 NS_SWIFT_NAME(AnalyticsParameterItemCategory3) = + @"item_category3"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory4 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory4 NS_SWIFT_NAME(AnalyticsParameterItemCategory4) = + @"item_category4"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory5 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory5 NS_SWIFT_NAME(AnalyticsParameterItemCategory5) = + @"item_category5"; + +/// Item ID (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemID : "SKU_12345",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemID NS_SWIFT_NAME(AnalyticsParameterItemID) = @"item_id"; + +/// The ID of the list in which the item was presented to the user (String). +///
+///     let params = [
+///       AnalyticsParameterItemListID : "ABC123",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemListID NS_SWIFT_NAME(AnalyticsParameterItemListID) = + @"item_list_id"; + +/// The name of the list in which the item was presented to the user (String). +///
+///     let params = [
+///       AnalyticsParameterItemListName : "Related products",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemListName NS_SWIFT_NAME(AnalyticsParameterItemListName) = + @"item_list_name"; + +/// Item Name (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemName : "jeggings",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemName NS_SWIFT_NAME(AnalyticsParameterItemName) = + @"item_name"; + +/// Item variant (String). +///
+///     let params = [
+///       AnalyticsParameterItemVariant : "Black",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemVariant NS_SWIFT_NAME(AnalyticsParameterItemVariant) = + @"item_variant"; + +/// The list of items involved in the transaction expressed as `[[String: Any]]`. +///
+///     let params = [
+///       AnalyticsParameterItems : [
+///         [AnalyticsParameterItemName : "jeggings", AnalyticsParameterItemCategory : "pants"],
+///         [AnalyticsParameterItemName : "boots", AnalyticsParameterItemCategory : "shoes"],
+///       ],
+///     ]
+/// 
+static NSString *const kFIRParameterItems NS_SWIFT_NAME(AnalyticsParameterItems) = @"items"; + +/// Level in game (Int). +///
+///     let params = [
+///       AnalyticsParameterLevel : 42,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLevel NS_SWIFT_NAME(AnalyticsParameterLevel) = @"level"; + +/// The name of a level in a game (String). +///
+///     let params = [
+///       AnalyticsParameterLevelName : "room_1",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLevelName NS_SWIFT_NAME(AnalyticsParameterLevelName) = + @"level_name"; + +/// Location (String). The Google Place ID +/// that corresponds to the associated event. Alternatively, you can supply your own custom +/// Location ID. +///
+///     let params = [
+///       AnalyticsParameterLocation : "ChIJiyj437sx3YAR9kUWC8QkLzQ",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLocation NS_SWIFT_NAME(AnalyticsParameterLocation) = + @"location"; + +/// The location associated with the event. Preferred to be the Google +/// Place ID that corresponds to the +/// associated item but could be overridden to a custom location ID string.(String). +///
+///     let params = [
+///       AnalyticsParameterLocationID : "ChIJiyj437sx3YAR9kUWC8QkLzQ",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLocationID NS_SWIFT_NAME(AnalyticsParameterLocationID) = + @"location_id"; + +/// Marketing Tactic (String). Used to identify the targeting criteria applied to a specific +/// campaign. +///
+///     let params = [
+///       AnalyticsParameterMarketingTactic : "Remarketing",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterMarketingTactic + NS_SWIFT_NAME(AnalyticsParameterMarketingTactic) = @"marketing_tactic"; + +/// The advertising or marketing medium, for example: cpc, banner, email, push. Highly recommended +/// (String). +///
+///     let params = [
+///       AnalyticsParameterMedium : "email",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterMedium NS_SWIFT_NAME(AnalyticsParameterMedium) = @"medium"; + +/// A particular approach used in an operation; for example, "facebook" or "email" in the context +/// of a sign_up or login event. (String). +///
+///     let params = [
+///       AnalyticsParameterMethod : "google",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterMethod NS_SWIFT_NAME(AnalyticsParameterMethod) = @"method"; + +/// Number of nights staying at hotel (Int). +///
+///     let params = [
+///       AnalyticsParameterNumberOfNights : 3,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterNumberOfNights + NS_SWIFT_NAME(AnalyticsParameterNumberOfNights) = @"number_of_nights"; + +/// Number of passengers traveling (Int). +///
+///     let params = [
+///       AnalyticsParameterNumberOfPassengers : 11,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterNumberOfPassengers + NS_SWIFT_NAME(AnalyticsParameterNumberOfPassengers) = @"number_of_passengers"; + +/// Number of rooms for travel events (Int). +///
+///     let params = [
+///       AnalyticsParameterNumberOfRooms : 2,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterNumberOfRooms NS_SWIFT_NAME(AnalyticsParameterNumberOfRooms) = + @"number_of_rooms"; + +/// Flight or Travel origin (String). +///
+///     let params = [
+///       AnalyticsParameterOrigin : "Mountain View, CA",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterOrigin NS_SWIFT_NAME(AnalyticsParameterOrigin) = @"origin"; + +/// The chosen method of payment (String). +///
+///     let params = [
+///       AnalyticsParameterPaymentType : "Visa",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPaymentType NS_SWIFT_NAME(AnalyticsParameterPaymentType) = + @"payment_type"; + +/// Purchase price (Double). +///
+///     let params = [
+///       AnalyticsParameterPrice : 1.0,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $1.00 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPrice NS_SWIFT_NAME(AnalyticsParameterPrice) = @"price"; + +/// The ID of a product promotion (String). +///
+///     let params = [
+///       AnalyticsParameterPromotionID : "ABC123",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPromotionID NS_SWIFT_NAME(AnalyticsParameterPromotionID) = + @"promotion_id"; + +/// The name of a product promotion (String). +///
+///     let params = [
+///       AnalyticsParameterPromotionName : "Summer Sale",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPromotionName NS_SWIFT_NAME(AnalyticsParameterPromotionName) = + @"promotion_name"; + +/// Purchase quantity (Int). +///
+///     let params = [
+///       AnalyticsParameterQuantity : 1,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterQuantity NS_SWIFT_NAME(AnalyticsParameterQuantity) = + @"quantity"; + +/// Score in game (Int). +///
+///     let params = [
+///       AnalyticsParameterScore : 4200,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterScore NS_SWIFT_NAME(AnalyticsParameterScore) = @"score"; + +/// Current screen class, such as the class name of the UIViewController, logged with screen_view +/// event and added to every event (String). +///
+///     let params = [
+///       AnalyticsParameterScreenClass : "LoginViewController",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterScreenClass NS_SWIFT_NAME(AnalyticsParameterScreenClass) = + @"screen_class"; + +/// Current screen name, such as the name of the UIViewController, logged with screen_view event and +/// added to every event (String). +///
+///     let params = [
+///       AnalyticsParameterScreenName : "LoginView",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterScreenName NS_SWIFT_NAME(AnalyticsParameterScreenName) = + @"screen_name"; + +/// The search string/keywords used (String). +///
+///     let params = [
+///       AnalyticsParameterSearchTerm : "periodic table",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSearchTerm NS_SWIFT_NAME(AnalyticsParameterSearchTerm) = + @"search_term"; + +/// Shipping cost associated with a transaction (Double). +///
+///     let params = [
+///       AnalyticsParameterShipping : 5.99,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $5.99 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterShipping NS_SWIFT_NAME(AnalyticsParameterShipping) = + @"shipping"; + +/// The shipping tier (e.g. Ground, Air, Next-day) selected for delivery of the purchased item +/// (String). +///
+///     let params = [
+///       AnalyticsParameterShippingTier : "Ground",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterShippingTier NS_SWIFT_NAME(AnalyticsParameterShippingTier) = + @"shipping_tier"; + +/// The origin of your traffic, such as an Ad network (for example, google) or partner (urban +/// airship). Identify the advertiser, site, publication, etc. that is sending traffic to your +/// property. Highly recommended (String). +///
+///     let params = [
+///       AnalyticsParameterSource : "InMobi",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSource NS_SWIFT_NAME(AnalyticsParameterSource) = @"source"; + +/// Source Platform (String). Used to identify the platform responsible for directing traffic to a +/// given Analytics property (e.g., a buying platform where budgets, targeting criteria, etc. are +/// set, a platform for managing organic traffic data, etc.). +///
+///     let params = [
+///       AnalyticsParameterSourcePlatform : "sa360",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSourcePlatform NS_SWIFT_NAME(AnalyticsParameterSourcePlatform) = + @"source_platform"; + +/// The departure date, check-in date or rental start date for the item. This should be in +/// YYYY-MM-DD format (String). +///
+///     let params = [
+///       AnalyticsParameterStartDate : "2015-09-14",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterStartDate NS_SWIFT_NAME(AnalyticsParameterStartDate) = + @"start_date"; + +/// The result of an operation. Specify 1 to indicate success and 0 to indicate failure (Int). +///
+///     let params = [
+///       AnalyticsParameterSuccess : 1,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSuccess NS_SWIFT_NAME(AnalyticsParameterSuccess) = @"success"; + +/// Tax cost associated with a transaction (Double). +///
+///     let params = [
+///       AnalyticsParameterTax : 2.43,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $2.43 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTax NS_SWIFT_NAME(AnalyticsParameterTax) = @"tax"; + +/// If you're manually tagging keyword campaigns, you should use utm_term to specify the keyword +/// (String). +///
+///     let params = [
+///       AnalyticsParameterTerm : "game",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTerm NS_SWIFT_NAME(AnalyticsParameterTerm) = @"term"; + +/// The unique identifier of a transaction (String). +///
+///     let params = [
+///       AnalyticsParameterTransactionID : "T12345",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTransactionID NS_SWIFT_NAME(AnalyticsParameterTransactionID) = + @"transaction_id"; + +/// Travel class (String). +///
+///     let params = [
+///       AnalyticsParameterTravelClass : "business",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTravelClass NS_SWIFT_NAME(AnalyticsParameterTravelClass) = + @"travel_class"; + +/// A context-specific numeric value which is accumulated automatically for each event type. This is +/// a general purpose parameter that is useful for accumulating a key metric that pertains to an +/// event. Examples include revenue, distance, time and points. Value should be specified as Int or +/// Double. +/// Notes: Values for pre-defined currency-related events (such as @c AnalyticsEventAddToCart) +/// should be supplied using Double and must be accompanied by a @c AnalyticsParameterCurrency +/// parameter. The valid range of accumulated values is +/// [-9,223,372,036,854.77, 9,223,372,036,854.77]. Supplying a non-numeric value, omitting the +/// corresponding @c AnalyticsParameterCurrency parameter, or supplying an invalid +/// currency code for conversion events will cause that +/// conversion to be omitted from reporting. +///
+///     let params = [
+///       AnalyticsParameterValue : 3.99,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $3.99 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterValue NS_SWIFT_NAME(AnalyticsParameterValue) = @"value"; + +/// Name of virtual currency type (String). +///
+///     let params = [
+///       AnalyticsParameterVirtualCurrencyName : "virtual_currency_name",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterVirtualCurrencyName + NS_SWIFT_NAME(AnalyticsParameterVirtualCurrencyName) = @"virtual_currency_name"; diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h new file mode 100644 index 0000000..2442d8a --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h @@ -0,0 +1,28 @@ +/// @file FIRUserPropertyNames.h +/// +/// Predefined user property names. +/// +/// A UserProperty is an attribute that describes the app-user. By supplying UserProperties, you can +/// later analyze different behaviors of various segments of your userbase. You may supply up to 25 +/// unique UserProperties per app, and you can use the name and value of your choosing for each one. +/// UserProperty names can be up to 24 characters long, may only contain alphanumeric characters and +/// underscores ("_"), and must start with an alphabetic character. UserProperty values can be up to +/// 36 characters long. The "firebase_", "google_", and "ga_" prefixes are reserved and should not +/// be used. + +#import + +/// Indicates whether events logged by Google Analytics can be used to personalize ads for the user. +/// Set to "YES" to enable, or "NO" to disable. Default is enabled. See the +/// documentation for +/// more details and information about related settings. +/// +///
+///     Analytics.setUserProperty("NO", forName: AnalyticsUserPropertyAllowAdPersonalizationSignals)
+/// 
+static NSString *const kFIRUserPropertyAllowAdPersonalizationSignals + NS_SWIFT_NAME(AnalyticsUserPropertyAllowAdPersonalizationSignals) = @"allow_personalized_ads"; + +/// The method used to sign in. For example, "google", "facebook" or "twitter". +static NSString *const kFIRUserPropertySignUpMethod + NS_SWIFT_NAME(AnalyticsUserPropertySignUpMethod) = @"sign_up_method"; diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-umbrella.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-umbrella.h new file mode 100644 index 0000000..58342c6 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-umbrella.h @@ -0,0 +1,24 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "FIRAnalytics+AppDelegate.h" +#import "FIRAnalytics+Consent.h" +#import "FIRAnalytics+OnDevice.h" +#import "FIRAnalytics.h" +#import "FirebaseAnalytics.h" +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" + +FOUNDATION_EXPORT double FirebaseAnalyticsVersionNumber; +FOUNDATION_EXPORT const unsigned char FirebaseAnalyticsVersionString[]; + diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h new file mode 100644 index 0000000..351da20 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h @@ -0,0 +1,7 @@ +#import "FIRAnalytics+AppDelegate.h" +#import "FIRAnalytics+Consent.h" +#import "FIRAnalytics+OnDevice.h" +#import "FIRAnalytics.h" +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Info.plist b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Info.plist new file mode 100644 index 0000000..1674c5f --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleExecutable + FirebaseAnalytics + CFBundleIdentifier + com.firebase.Firebase-FirebaseAnalytics + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + FirebaseAnalytics + CFBundlePackageType + FMWK + CFBundleVersion + 10.11.0 + DTSDKName + iphonesimulator11.2 + + diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Modules/module.modulemap b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Modules/module.modulemap new file mode 100644 index 0000000..e33d8fa --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Modules/module.modulemap @@ -0,0 +1,12 @@ +framework module FirebaseAnalytics { +umbrella header "FirebaseAnalytics-umbrella.h" +export * +module * { export * } + link framework "AppKit" + link framework "Foundation" + link framework "Security" + link framework "SystemConfiguration" + link "c++" + link "sqlite3" + link "z" +} diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/FirebaseAnalytics b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/FirebaseAnalytics new file mode 100644 index 0000000..3029369 Binary files /dev/null and b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/FirebaseAnalytics differ diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h new file mode 100644 index 0000000..cb1e407 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h @@ -0,0 +1,80 @@ +#import + +#import "FIRAnalytics.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Provides App Delegate handlers to be used in your App Delegate. +/// +/// To save time integrating Firebase Analytics in an application, Firebase Analytics does not +/// require delegation implementation from the AppDelegate if neither SwiftUI nor UIScene lifecycle +/// is adopted. Instead this is automatically done by Firebase Analytics. Should you choose instead +/// to delegate manually, you can turn off the App Delegate Proxy by adding +/// FirebaseAppDelegateProxyEnabled into your app's Info.plist and setting it to boolean `NO`, and +/// adding the methods in this category to corresponding delegation handlers. +/// +/// To handle Universal Links, you must return `true` in +/// `UIApplicationDelegate.application(_:didFinishLaunchingWithOptions:)`. +@interface FIRAnalytics (AppDelegate) + +/// Handles events related to a URL session that are waiting to be processed. +/// +/// 1. If SwiftUI lifecycle is adopted, call this method from +/// `UIApplicationDelegate.application(_:handleEventsForBackgroundURLSession:completionHandler:)` +/// in your app delegate. +/// +/// 2. If SwiftUI lifecycle is not adopted, Firebase Analytics does not require delegation +/// implementation from the AppDelegate. If you choose instead to delegate manually, you can set +/// FirebaseAppDelegateProxyEnabled to boolean `NO` in your app's Info.plist and call this method +/// from +/// `UIApplicationDelegate.application(_:handleEventsForBackgroundURLSession:completionHandler:)` +/// in your app delegate. +/// +/// @param identifier The identifier of the URL session requiring attention. +/// @param completionHandler The completion handler to call when you finish processing the events. +/// Calling this completion handler lets the system know that your app's user interface is +/// updated and a new snapshot can be taken. ++ (void)handleEventsForBackgroundURLSession:(NSString *)identifier + completionHandler:(nullable void (^)(void))completionHandler; + +/// Handles the event when the app is launched by a URL (custom URL scheme or universal link). +/// +/// 1. If SwiftUI lifecycle is adopted, use `onOpenURL(perform:)` to register a handler and call +/// this method in the handler. +/// +/// 2. If UIScene lifecycle is adopted, call this method from +/// `UISceneDelegate.scene(_:willConnectTo:options:)` and +/// `UISceneDelegate.scene(_:openURLContexts:)` when the URL contexts are available. +/// +/// 3. If neither SwiftUI nor UIScene lifecycle is adopted, Firebase Analytics does not require +/// delegation implementation from the AppDelegate. If you choose instead to delegate manually, you +/// can set FirebaseAppDelegateProxyEnabled to boolean `NO` in your app's Info.plist and call this +/// method from `UIApplicationDelegate.application(_:open:options:)` in your app delegate. +/// +/// @param url The URL resource to open. This resource can be a network resource or a file. ++ (void)handleOpenURL:(NSURL *)url; + +/// Handles the event when the app receives data associated with user activity that includes a +/// Universal Link. +/// +/// 1. If SwiftUI lifecycle is adopted, use `onOpenURL(perform:)` to register a handler and call +/// `Analytics.handleOpen(_:)` instead in the handler. +/// +/// 2. If UIScene lifecycle is adopted, call this method from +/// `UISceneDelegate.scene(_:willConnectTo:options:)` and `UISceneDelegate.scene(_:continue:)` when +/// NSUserActivity is available. See the [Apple +/// doc](https://developer.apple.com/documentation/xcode/supporting-universal-links-in-your-app) for +/// more details. +/// +/// 3. If neither SwiftUI nor UIScene lifecycle is adopted, Firebase Analytics does not require +/// delegation implementation from the AppDelegate. If you choose instead to delegate manually, you +/// can set FirebaseAppDelegateProxyEnabled to boolean `NO` in your app's Info.plist and call this +/// method from `UIApplication.application(_:continue:restorationHandler:)` in your app delegate. +/// +/// @param userActivity The activity object containing the data associated with the task the user +/// was performing. ++ (void)handleUserActivity:(id)userActivity; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+Consent.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+Consent.h new file mode 100644 index 0000000..7f89831 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+Consent.h @@ -0,0 +1,33 @@ +#import + +#import "FIRAnalytics.h" + +NS_ASSUME_NONNULL_BEGIN + +/// The type of consent to set. Supported consent types are `ConsentType.adStorage` and +/// `ConsentType.analyticsStorage`. Omitting a type retains its previous status. +typedef NSString *FIRConsentType NS_TYPED_ENUM NS_SWIFT_NAME(ConsentType); +extern FIRConsentType const FIRConsentTypeAdStorage; +extern FIRConsentType const FIRConsentTypeAnalyticsStorage; + +/// The status value of the consent type. Supported statuses are `ConsentStatus.granted` and +/// `ConsentStatus.denied`. +typedef NSString *FIRConsentStatus NS_TYPED_ENUM NS_SWIFT_NAME(ConsentStatus); +extern FIRConsentStatus const FIRConsentStatusDenied; +extern FIRConsentStatus const FIRConsentStatusGranted; + +/// Sets the applicable end user consent state. +@interface FIRAnalytics (Consent) + +/// Sets the applicable end user consent state (e.g. for device identifiers) for this app on this +/// device. Use the consent settings to specify individual consent type values. Settings are +/// persisted across app sessions. By default consent types are set to `ConsentStatus.granted`. +/// +/// @param consentSettings A Dictionary of consent types. Supported consent type keys are +/// `ConsentType.adStorage` and `ConsentType.analyticsStorage`. Valid values are +/// `ConsentStatus.granted` and `ConsentStatus.denied`. ++ (void)setConsent:(NSDictionary *)consentSettings; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+OnDevice.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+OnDevice.h new file mode 100644 index 0000000..1d9a438 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+OnDevice.h @@ -0,0 +1,19 @@ +#import + +#import "FIRAnalytics.h" + +NS_ASSUME_NONNULL_BEGIN + +API_UNAVAILABLE(macCatalyst, macos, tvos, watchos) +@interface FIRAnalytics (OnDevice) + +/// Initiates on-device conversion measurement given a user email address. Requires dependency +/// GoogleAppMeasurementOnDeviceConversion to be linked in, otherwise it is a no-op. +/// @param emailAddress User email address. Include a domain name for all email addresses +/// (e.g. gmail.com or hotmail.co.jp). ++ (void)initiateOnDeviceConversionMeasurementWithEmailAddress:(NSString *)emailAddress + NS_SWIFT_NAME(initiateOnDeviceConversionMeasurement(emailAddress:)); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics.h new file mode 100644 index 0000000..e7ce5dc --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics.h @@ -0,0 +1,154 @@ +#import + +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" + +NS_ASSUME_NONNULL_BEGIN + +/// The top level Firebase Analytics singleton that provides methods for logging events and setting +/// user properties. See the developer guides for general +/// information on using Firebase Analytics in your apps. +/// +/// @note The Analytics SDK uses SQLite to persist events and other app-specific data. Calling +/// certain thread-unsafe global SQLite methods like `sqlite3_shutdown()` can result in +/// unexpected crashes at runtime. +NS_SWIFT_NAME(Analytics) +@interface FIRAnalytics : NSObject + +/// Logs an app event. The event can have up to 25 parameters. Events with the same name must have +/// the same parameters. Up to 500 event names are supported. Using predefined events and/or +/// parameters is recommended for optimal reporting. +/// +/// The following event names are reserved and cannot be used: +///
    +///
  • ad_activeview
  • +///
  • ad_click
  • +///
  • ad_exposure
  • +///
  • ad_query
  • +///
  • ad_reward
  • +///
  • adunit_exposure
  • +///
  • app_clear_data
  • +///
  • app_exception
  • +///
  • app_remove
  • +///
  • app_store_refund
  • +///
  • app_store_subscription_cancel
  • +///
  • app_store_subscription_convert
  • +///
  • app_store_subscription_renew
  • +///
  • app_update
  • +///
  • app_upgrade
  • +///
  • dynamic_link_app_open
  • +///
  • dynamic_link_app_update
  • +///
  • dynamic_link_first_open
  • +///
  • error
  • +///
  • firebase_campaign
  • +///
  • first_open
  • +///
  • first_visit
  • +///
  • in_app_purchase
  • +///
  • notification_dismiss
  • +///
  • notification_foreground
  • +///
  • notification_open
  • +///
  • notification_receive
  • +///
  • os_update
  • +///
  • session_start
  • +///
  • session_start_with_rollout
  • +///
  • user_engagement
  • +///
+/// +/// @param name The name of the event. Should contain 1 to 40 alphanumeric characters or +/// underscores. The name must start with an alphabetic character. Some event names are +/// reserved. See FIREventNames.h for the list of reserved event names. The "firebase_", +/// "google_", and "ga_" prefixes are reserved and should not be used. Note that event names are +/// case-sensitive and that logging two events whose names differ only in case will result in +/// two distinct events. To manually log screen view events, use the `screen_view` event name. +/// @param parameters The dictionary of event parameters. Passing `nil` indicates that the event has +/// no parameters. Parameter names can be up to 40 characters long and must start with an +/// alphabetic character and contain only alphanumeric characters and underscores. Only String, +/// Int, and Double parameter types are supported. String parameter values can be up to 100 +/// characters long. The "firebase_", "google_", and "ga_" prefixes are reserved and should not +/// be used for parameter names. ++ (void)logEventWithName:(NSString *)name + parameters:(nullable NSDictionary *)parameters + NS_SWIFT_NAME(logEvent(_:parameters:)); + +/// Sets a user property to a given value. Up to 25 user property names are supported. Once set, +/// user property values persist throughout the app lifecycle and across sessions. +/// +/// The following user property names are reserved and cannot be used: +///
    +///
  • first_open_time
  • +///
  • last_deep_link_referrer
  • +///
  • user_id
  • +///
+/// +/// @param value The value of the user property. Values can be up to 36 characters long. Setting the +/// value to `nil` removes the user property. +/// @param name The name of the user property to set. Should contain 1 to 24 alphanumeric characters +/// or underscores and must start with an alphabetic character. The "firebase_", "google_", and +/// "ga_" prefixes are reserved and should not be used for user property names. ++ (void)setUserPropertyString:(nullable NSString *)value forName:(NSString *)name + NS_SWIFT_NAME(setUserProperty(_:forName:)); + +/// Sets the user ID property. This feature must be used in accordance with +/// Google's Privacy Policy +/// +/// @param userID The user ID to ascribe to the user of this app on this device, which must be +/// non-empty and no more than 256 characters long. Setting userID to `nil` removes the user ID. ++ (void)setUserID:(nullable NSString *)userID; + +/// Sets whether analytics collection is enabled for this app on this device. This setting is +/// persisted across app sessions. By default it is enabled. +/// +/// @param analyticsCollectionEnabled A flag that enables or disables Analytics collection. ++ (void)setAnalyticsCollectionEnabled:(BOOL)analyticsCollectionEnabled; + +/// Sets the interval of inactivity in seconds that terminates the current session. The default +/// value is 1800 seconds (30 minutes). +/// +/// @param sessionTimeoutInterval The custom time of inactivity in seconds before the current +/// session terminates. ++ (void)setSessionTimeoutInterval:(NSTimeInterval)sessionTimeoutInterval; + +/// Asynchronously retrieves the identifier of the current app session. +/// +/// The session ID retrieval could fail due to Analytics collection disabled, app session expired, +/// etc. +/// +/// @param completion The completion handler to call when the session ID retrieval is complete. This +/// handler is executed on a system-defined global concurrent queue. +/// This completion handler takes the following parameters: +/// sessionID The identifier of the current app session. The value is undefined if the +/// request failed. +/// error An error object that indicates why the request failed, or `nil` if the request +/// was successful. ++ (void)sessionIDWithCompletion:(void (^)(int64_t sessionID, NSError *_Nullable error))completion; + +/// Returns the unique ID for this instance of the application or `nil` if +/// `ConsentType.analyticsStorage` has been set to `ConsentStatus.denied`. +/// +/// @see `FIRAnalytics+Consent.h` ++ (nullable NSString *)appInstanceID; + +/// Clears all analytics data for this instance from the device and resets the app instance ID. ++ (void)resetAnalyticsData; + +/// Adds parameters that will be set on every event logged from the SDK, including automatic ones. +/// The values passed in the parameters dictionary will be added to the dictionary of default event +/// parameters. These parameters persist across app runs. They are of lower precedence than event +/// parameters, so if an event parameter and a parameter set using this API have the same name, the +/// value of the event parameter will be used. The same limitations on event parameters apply to +/// default event parameters. +/// +/// @param parameters Parameters to be added to the dictionary of parameters added to every event. +/// They will be added to the dictionary of default event parameters, replacing any existing +/// parameter with the same name. Valid parameters are String, Int, and Double. Setting a key's +/// value to `NSNull()` will clear that parameter. Passing in a `nil` dictionary will clear all +/// parameters. ++ (void)setDefaultEventParameters:(nullable NSDictionary *)parameters; + +/// Unavailable. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIREventNames.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIREventNames.h new file mode 100644 index 0000000..1e69a44 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIREventNames.h @@ -0,0 +1,418 @@ +/// @file FIREventNames.h +/// +/// Predefined event names. +/// +/// An Event is an important occurrence in your app that you want to measure. You can report up to +/// 500 different types of Events per app and you can associate up to 25 unique parameters with each +/// Event type. Some common events are suggested below, but you may also choose to specify custom +/// Event types that are associated with your specific app. Each event type is identified by a +/// unique name. Event names can be up to 40 characters long, may only contain alphanumeric +/// characters and underscores ("_"), and must start with an alphabetic character. The "firebase_", +/// "google_", and "ga_" prefixes are reserved and should not be used. + +#import + +/// Ad Impression event. This event signifies when a user sees an ad impression. Note: If you supply +/// the @c AnalyticsParameterValue parameter, you must also supply the @c AnalyticsParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterAdPlatform (String) (optional)
  • +///
  • @c AnalyticsParameterAdFormat (String) (optional)
  • +///
  • @c AnalyticsParameterAdSource (String) (optional)
  • +///
  • @c AnalyticsParameterAdUnitName (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAdImpression NS_SWIFT_NAME(AnalyticsEventAdImpression) = + @"ad_impression"; + +/// Add Payment Info event. This event signifies that a user has submitted their payment +/// information. Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply +/// the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterPaymentType (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddPaymentInfo NS_SWIFT_NAME(AnalyticsEventAddPaymentInfo) = + @"add_payment_info"; + +/// Add Shipping Info event. This event signifies that a user has submitted their shipping +/// information. Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply +/// the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterShippingTier (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddShippingInfo NS_SWIFT_NAME(AnalyticsEventAddShippingInfo) = + @"add_shipping_info"; + +/// E-Commerce Add To Cart event. This event signifies that an item(s) was added to a cart for +/// purchase. Add this event to a funnel with @c AnalyticsEventPurchase to gauge the effectiveness +/// of your checkout process. Note: If you supply the @c AnalyticsParameterValue parameter, you must +/// also supply the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed +/// accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddToCart NS_SWIFT_NAME(AnalyticsEventAddToCart) = @"add_to_cart"; + +/// E-Commerce Add To Wishlist event. This event signifies that an item was added to a wishlist. Use +/// this event to identify popular gift items. Note: If you supply the @c AnalyticsParameterValue +/// parameter, you must also supply the @c AnalyticsParameterCurrency parameter so that revenue +/// metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddToWishlist NS_SWIFT_NAME(AnalyticsEventAddToWishlist) = + @"add_to_wishlist"; + +/// App Open event. By logging this event when an App becomes active, developers can understand how +/// often users leave and return during the course of a Session. Although Sessions are automatically +/// reported, this event can provide further clarification around the continuous engagement of +/// app-users. +static NSString *const kFIREventAppOpen NS_SWIFT_NAME(AnalyticsEventAppOpen) = @"app_open"; + +/// E-Commerce Begin Checkout event. This event signifies that a user has begun the process of +/// checking out. Add this event to a funnel with your @c AnalyticsEventPurchase event to gauge the +/// effectiveness of your checkout process. Note: If you supply the @c AnalyticsParameterValue +/// parameter, you must also supply the @c AnalyticsParameterCurrency parameter so that revenue +/// metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventBeginCheckout NS_SWIFT_NAME(AnalyticsEventBeginCheckout) = + @"begin_checkout"; + +/// Campaign Detail event. Log this event to supply the referral details of a re-engagement +/// campaign. Note: you must supply at least one of the required parameters +/// AnalyticsParameterSource, AnalyticsParameterMedium or AnalyticsParameterCampaign. Params: +/// +///
    +///
  • @c AnalyticsParameterSource (String)
  • +///
  • @c AnalyticsParameterMedium (String)
  • +///
  • @c AnalyticsParameterCampaign (String)
  • +///
  • @c AnalyticsParameterTerm (String) (optional)
  • +///
  • @c AnalyticsParameterContent (String) (optional)
  • +///
  • @c AnalyticsParameterAdNetworkClickID (String) (optional)
  • +///
  • @c AnalyticsParameterCP1 (String) (optional)
  • +///
  • @c AnalyticsParameterCampaignID (String) (optional)
  • +///
  • @c AnalyticsParameterCreativeFormat (String) (optional)
  • +///
  • @c AnalyticsParameterMarketingTactic (String) (optional)
  • +///
  • @c AnalyticsParameterSourcePlatform (String) (optional)
  • +///
+static NSString *const kFIREventCampaignDetails NS_SWIFT_NAME(AnalyticsEventCampaignDetails) = + @"campaign_details"; + +/// Earn Virtual Currency event. This event tracks the awarding of virtual currency in your app. Log +/// this along with @c AnalyticsEventSpendVirtualCurrency to better understand your virtual economy. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterVirtualCurrencyName (String)
  • +///
  • @c AnalyticsParameterValue (Int or Double)
  • +///
+static NSString *const kFIREventEarnVirtualCurrency + NS_SWIFT_NAME(AnalyticsEventEarnVirtualCurrency) = @"earn_virtual_currency"; + +/// Generate Lead event. Log this event when a lead has been generated in the app to understand the +/// efficacy of your install and re-engagement campaigns. Note: If you supply the +/// @c AnalyticsParameterValue parameter, you must also supply the @c AnalyticsParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventGenerateLead NS_SWIFT_NAME(AnalyticsEventGenerateLead) = + @"generate_lead"; + +/// Join Group event. Log this event when a user joins a group such as a guild, team or family. Use +/// this event to analyze how popular certain groups or social features are in your app. Params: +/// +///
    +///
  • @c AnalyticsParameterGroupID (String)
  • +///
+static NSString *const kFIREventJoinGroup NS_SWIFT_NAME(AnalyticsEventJoinGroup) = @"join_group"; + +/// Level End event. Log this event when the user finishes a level. Params: +/// +///
    +///
  • @c AnalyticsParameterLevelName (String)
  • +///
  • @c AnalyticsParameterSuccess (String)
  • +///
+static NSString *const kFIREventLevelEnd NS_SWIFT_NAME(AnalyticsEventLevelEnd) = @"level_end"; + +/// Level Start event. Log this event when the user starts a new level. Params: +/// +///
    +///
  • @c AnalyticsParameterLevelName (String)
  • +///
+static NSString *const kFIREventLevelStart NS_SWIFT_NAME(AnalyticsEventLevelStart) = @"level_start"; + +/// Level Up event. This event signifies that a player has leveled up in your gaming app. It can +/// help you gauge the level distribution of your userbase and help you identify certain levels that +/// are difficult to pass. Params: +/// +///
    +///
  • @c AnalyticsParameterLevel (Int)
  • +///
  • @c AnalyticsParameterCharacter (String) (optional)
  • +///
+static NSString *const kFIREventLevelUp NS_SWIFT_NAME(AnalyticsEventLevelUp) = @"level_up"; + +/// Login event. Apps with a login feature can report this event to signify that a user has logged +/// in. +static NSString *const kFIREventLogin NS_SWIFT_NAME(AnalyticsEventLogin) = @"login"; + +/// Post Score event. Log this event when the user posts a score in your gaming app. This event can +/// help you understand how users are actually performing in your game and it can help you correlate +/// high scores with certain audiences or behaviors. Params: +/// +///
    +///
  • @c AnalyticsParameterScore (Int)
  • +///
  • @c AnalyticsParameterLevel (Int) (optional)
  • +///
  • @c AnalyticsParameterCharacter (String) (optional)
  • +///
+static NSString *const kFIREventPostScore NS_SWIFT_NAME(AnalyticsEventPostScore) = @"post_score"; + +/// E-Commerce Purchase event. This event signifies that an item(s) was purchased by a user. Note: +/// This is different from the in-app purchase event, which is reported automatically for App +/// Store-based apps. Note: If you supply the @c AnalyticsParameterValue parameter, you must also +/// supply the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed +/// accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterAffiliation (String) (optional)
  • +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterEndDate (String) (optional)
  • +///
  • @c AnalyticsParameterItemID (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterShipping (Double) (optional)
  • +///
  • @c AnalyticsParameterStartDate (String) (optional)
  • +///
  • @c AnalyticsParameterTax (Double) (optional)
  • +///
  • @c AnalyticsParameterTransactionID (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventPurchase NS_SWIFT_NAME(AnalyticsEventPurchase) = @"purchase"; + +/// E-Commerce Refund event. This event signifies that a refund was issued. Note: If you supply the +/// @c AnalyticsParameterValue parameter, you must also supply the @c AnalyticsParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterAffiliation (String) (optional)
  • +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterShipping (Double) (optional)
  • +///
  • @c AnalyticsParameterTax (Double) (optional)
  • +///
  • @c AnalyticsParameterTransactionID (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventRefund NS_SWIFT_NAME(AnalyticsEventRefund) = @"refund"; + +/// E-Commerce Remove from Cart event. This event signifies that an item(s) was removed from a cart. +/// Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply the @c +/// AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventRemoveFromCart NS_SWIFT_NAME(AnalyticsEventRemoveFromCart) = + @"remove_from_cart"; + +/// Screen View event. This event signifies a screen view. Use this when a screen transition occurs. +/// This event can be logged irrespective of whether automatic screen tracking is enabled. Params: +/// +///
    +///
  • @c AnalyticsParameterScreenClass (String) (optional)
  • +///
  • @c AnalyticsParameterScreenName (String) (optional)
  • +///
+static NSString *const kFIREventScreenView NS_SWIFT_NAME(AnalyticsEventScreenView) = @"screen_view"; + +/// Search event. Apps that support search features can use this event to contextualize search +/// operations by supplying the appropriate, corresponding parameters. This event can help you +/// identify the most popular content in your app. Params: +/// +///
    +///
  • @c AnalyticsParameterSearchTerm (String)
  • +///
  • @c AnalyticsParameterStartDate (String) (optional)
  • +///
  • @c AnalyticsParameterEndDate (String) (optional)
  • +///
  • @c AnalyticsParameterNumberOfNights (Int) (optional) for hotel bookings
  • +///
  • @c AnalyticsParameterNumberOfRooms (Int) (optional) for hotel bookings
  • +///
  • @c AnalyticsParameterNumberOfPassengers (Int) (optional) for travel bookings
  • +///
  • @c AnalyticsParameterOrigin (String) (optional)
  • +///
  • @c AnalyticsParameterDestination (String) (optional)
  • +///
  • @c AnalyticsParameterTravelClass (String) (optional) for travel bookings
  • +///
+static NSString *const kFIREventSearch NS_SWIFT_NAME(AnalyticsEventSearch) = @"search"; + +/// Select Content event. This general purpose event signifies that a user has selected some content +/// of a certain type in an app. The content can be any object in your app. This event can help you +/// identify popular content and categories of content in your app. Params: +/// +///
    +///
  • @c AnalyticsParameterContentType (String)
  • +///
  • @c AnalyticsParameterItemID (String)
  • +///
+static NSString *const kFIREventSelectContent NS_SWIFT_NAME(AnalyticsEventSelectContent) = + @"select_content"; + +/// Select Item event. This event signifies that an item was selected by a user from a list. Use the +/// appropriate parameters to contextualize the event. Use this event to discover the most popular +/// items selected. Params: +/// +///
    +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterItemListID (String) (optional)
  • +///
  • @c AnalyticsParameterItemListName (String) (optional)
  • +///
+static NSString *const kFIREventSelectItem NS_SWIFT_NAME(AnalyticsEventSelectItem) = @"select_item"; + +/// Select promotion event. This event signifies that a user has selected a promotion offer. Use the +/// appropriate parameters to contextualize the event, such as the item(s) for which the promotion +/// applies. Params: +/// +///
    +///
  • @c AnalyticsParameterCreativeName (String) (optional)
  • +///
  • @c AnalyticsParameterCreativeSlot (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterLocationID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionName (String) (optional)
  • +///
+static NSString *const kFIREventSelectPromotion NS_SWIFT_NAME(AnalyticsEventSelectPromotion) = + @"select_promotion"; + +/// Share event. Apps with social features can log the Share event to identify the most viral +/// content. Params: +/// +///
    +///
  • @c AnalyticsParameterContentType (String)
  • +///
  • @c AnalyticsParameterItemID (String)
  • +///
+static NSString *const kFIREventShare NS_SWIFT_NAME(AnalyticsEventShare) = @"share"; + +/// Sign Up event. This event indicates that a user has signed up for an account in your app. The +/// parameter signifies the method by which the user signed up. Use this event to understand the +/// different behaviors between logged in and logged out users. Params: +/// +///
    +///
  • @c AnalyticsParameterMethod (String)
  • +///
+static NSString *const kFIREventSignUp NS_SWIFT_NAME(AnalyticsEventSignUp) = @"sign_up"; + +/// Spend Virtual Currency event. This event tracks the sale of virtual goods in your app and can +/// help you identify which virtual goods are the most popular objects of purchase. Params: +/// +///
    +///
  • @c AnalyticsParameterItemName (String)
  • +///
  • @c AnalyticsParameterVirtualCurrencyName (String)
  • +///
  • @c AnalyticsParameterValue (Int or Double)
  • +///
+static NSString *const kFIREventSpendVirtualCurrency + NS_SWIFT_NAME(AnalyticsEventSpendVirtualCurrency) = @"spend_virtual_currency"; + +/// Tutorial Begin event. This event signifies the start of the on-boarding process in your app. Use +/// this in a funnel with @c AnalyticsEventTutorialComplete to understand how many users complete +/// this process and move on to the full app experience. +static NSString *const kFIREventTutorialBegin NS_SWIFT_NAME(AnalyticsEventTutorialBegin) = + @"tutorial_begin"; + +/// Tutorial End event. Use this event to signify the user's completion of your app's on-boarding +/// process. Add this to a funnel with @c AnalyticsEventTutorialBegin to gauge the completion rate +/// of your on-boarding process. +static NSString *const kFIREventTutorialComplete NS_SWIFT_NAME(AnalyticsEventTutorialComplete) = + @"tutorial_complete"; + +/// Unlock Achievement event. Log this event when the user has unlocked an achievement in your +/// game. Since achievements generally represent the breadth of a gaming experience, this event can +/// help you understand how many users are experiencing all that your game has to offer. Params: +/// +///
    +///
  • @c AnalyticsParameterAchievementID (String)
  • +///
+static NSString *const kFIREventUnlockAchievement NS_SWIFT_NAME(AnalyticsEventUnlockAchievement) = + @"unlock_achievement"; + +/// E-commerce View Cart event. This event signifies that a user has viewed their cart. Use this to +/// analyze your purchase funnel. Note: If you supply the @c AnalyticsParameterValue parameter, you +/// must also supply the @c AnalyticsParameterCurrency parameter so that revenue metrics can be +/// computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventViewCart NS_SWIFT_NAME(AnalyticsEventViewCart) = @"view_cart"; + +/// View Item event. This event signifies that a user has viewed an item. Use the appropriate +/// parameters to contextualize the event. Use this event to discover the most popular items viewed +/// in your app. Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply +/// the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventViewItem NS_SWIFT_NAME(AnalyticsEventViewItem) = @"view_item"; + +/// View Item List event. Log this event when a user sees a list of items or offerings. Params: +/// +///
    +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterItemListID (String) (optional)
  • +///
  • @c AnalyticsParameterItemListName (String) (optional)
  • +///
+static NSString *const kFIREventViewItemList NS_SWIFT_NAME(AnalyticsEventViewItemList) = + @"view_item_list"; + +/// View Promotion event. This event signifies that a promotion was shown to a user. Add this event +/// to a funnel with the @c AnalyticsEventAddToCart and @c AnalyticsEventPurchase to gauge your +/// conversion process. Params: +/// +///
    +///
  • @c AnalyticsParameterCreativeName (String) (optional)
  • +///
  • @c AnalyticsParameterCreativeSlot (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterLocationID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionName (String) (optional)
  • +///
+static NSString *const kFIREventViewPromotion NS_SWIFT_NAME(AnalyticsEventViewPromotion) = + @"view_promotion"; + +/// View Search Results event. Log this event when the user has been presented with the results of a +/// search. Params: +/// +///
    +///
  • @c AnalyticsParameterSearchTerm (String)
  • +///
+static NSString *const kFIREventViewSearchResults NS_SWIFT_NAME(AnalyticsEventViewSearchResults) = + @"view_search_results"; diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIRParameterNames.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIRParameterNames.h new file mode 100644 index 0000000..b001ca5 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIRParameterNames.h @@ -0,0 +1,721 @@ +/// @file FIRParameterNames.h +/// +/// Predefined event parameter names. +/// +/// Params supply information that contextualize Events. You can associate up to 25 unique Params +/// with each Event type. Some Params are suggested below for certain common Events, but you are +/// not limited to these. You may supply extra Params for suggested Events or custom Params for +/// Custom events. Param names can be up to 40 characters long, may only contain alphanumeric +/// characters and underscores ("_"), and must start with an alphabetic character. Param values can +/// be up to 100 characters long. The "firebase_", "google_", and "ga_" prefixes are reserved and +/// should not be used. + +#import + +/// Game achievement ID (String). +///
+///     let params = [
+///       AnalyticsParameterAchievementID : "10_matches_won",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAchievementID NS_SWIFT_NAME(AnalyticsParameterAchievementID) = + @"achievement_id"; + +/// The ad format (e.g. Banner, Interstitial, Rewarded, Native, Rewarded Interstitial, Instream). +/// (String). +///
+///     let params = [
+///       AnalyticsParameterAdFormat : "Banner",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdFormat NS_SWIFT_NAME(AnalyticsParameterAdFormat) = + @"ad_format"; + +/// Ad Network Click ID (String). Used for network-specific click IDs which vary in format. +///
+///     let params = [
+///       AnalyticsParameterAdNetworkClickID : "1234567",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdNetworkClickID + NS_SWIFT_NAME(AnalyticsParameterAdNetworkClickID) = @"aclid"; + +/// The ad platform (e.g. MoPub, IronSource) (String). +///
+///     let params = [
+///       AnalyticsParameterAdPlatform : "MoPub",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdPlatform NS_SWIFT_NAME(AnalyticsParameterAdPlatform) = + @"ad_platform"; + +/// The ad source (e.g. AdColony) (String). +///
+///     let params = [
+///       AnalyticsParameterAdSource : "AdColony",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdSource NS_SWIFT_NAME(AnalyticsParameterAdSource) = + @"ad_source"; + +/// The ad unit name (e.g. Banner_03) (String). +///
+///     let params = [
+///       AnalyticsParameterAdUnitName : "Banner_03",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdUnitName NS_SWIFT_NAME(AnalyticsParameterAdUnitName) = + @"ad_unit_name"; + +/// A product affiliation to designate a supplying company or brick and mortar store location +/// (String).
+///     let params = [
+///       AnalyticsParameterAffiliation : "Google Store",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAffiliation NS_SWIFT_NAME(AnalyticsParameterAffiliation) = + @"affiliation"; + +/// Campaign custom parameter (String). Used as a method of capturing custom data in a campaign. +/// Use varies by network. +///
+///     let params = [
+///       AnalyticsParameterCP1 : "custom_data",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCP1 NS_SWIFT_NAME(AnalyticsParameterCP1) = @"cp1"; + +/// The individual campaign name, slogan, promo code, etc. Some networks have pre-defined macro to +/// capture campaign information, otherwise can be populated by developer. Highly Recommended +/// (String). +///
+///     let params = [
+///       AnalyticsParameterCampaign : "winter_promotion",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCampaign NS_SWIFT_NAME(AnalyticsParameterCampaign) = + @"campaign"; + +/// Campaign ID (String). Used for keyword analysis to identify a specific product promotion or +/// strategic campaign. This is a required key for GA4 data import. +///
+///     let params = [
+///       AnalyticsParameterCampaignID : "7877652710",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCampaignID NS_SWIFT_NAME(AnalyticsParameterCampaignID) = + @"campaign_id"; + +/// Character used in game (String). +///
+///     let params = [
+///       AnalyticsParameterCharacter : "beat_boss",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCharacter NS_SWIFT_NAME(AnalyticsParameterCharacter) = + @"character"; + +/// Campaign content (String). +static NSString *const kFIRParameterContent NS_SWIFT_NAME(AnalyticsParameterContent) = @"content"; + +/// Type of content selected (String). +///
+///     let params = [
+///       AnalyticsParameterContentType : "news article",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterContentType NS_SWIFT_NAME(AnalyticsParameterContentType) = + @"content_type"; + +/// Coupon code used for a purchase (String). +///
+///     let params = [
+///       AnalyticsParameterCoupon : "SUMMER_FUN",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCoupon NS_SWIFT_NAME(AnalyticsParameterCoupon) = @"coupon"; + +/// Creative Format (String). Used to identify the high-level classification of the type of ad +/// served by a specific campaign. +///
+///     let params = [
+///       AnalyticsParameterCreativeFormat : "display",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCreativeFormat NS_SWIFT_NAME(AnalyticsParameterCreativeFormat) = + @"creative_format"; + +/// The name of a creative used in a promotional spot (String). +///
+///     let params = [
+///       AnalyticsParameterCreativeName : "Summer Sale",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCreativeName NS_SWIFT_NAME(AnalyticsParameterCreativeName) = + @"creative_name"; + +/// The name of a creative slot (String). +///
+///     let params = [
+///       AnalyticsParameterCreativeSlot : "summer_banner2",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCreativeSlot NS_SWIFT_NAME(AnalyticsParameterCreativeSlot) = + @"creative_slot"; + +/// Currency of the purchase or items associated with the event, in 3-letter +/// ISO_4217 format (String). +///
+///     let params = [
+///       AnalyticsParameterCurrency : "USD",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCurrency NS_SWIFT_NAME(AnalyticsParameterCurrency) = + @"currency"; + +/// Flight or Travel destination (String). +///
+///     let params = [
+///       AnalyticsParameterDestination : "Mountain View, CA",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterDestination NS_SWIFT_NAME(AnalyticsParameterDestination) = + @"destination"; + +/// Monetary value of discount associated with a purchase (Double). +///
+///     let params = [
+///       AnalyticsParameterDiscount : 2.0,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $2.00 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterDiscount NS_SWIFT_NAME(AnalyticsParameterDiscount) = + @"discount"; + +/// The arrival date, check-out date or rental end date for the item. This should be in +/// YYYY-MM-DD format (String). +///
+///     let params = [
+///       AnalyticsParameterEndDate : "2015-09-14",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterEndDate NS_SWIFT_NAME(AnalyticsParameterEndDate) = @"end_date"; + +/// Indicates that the associated event should either extend the current session or start a new +/// session if no session was active when the event was logged. Specify 1 to extend the current +/// session or to start a new session; any other value will not extend or start a session. +///
+///     let params = [
+///       AnalyticsParameterExtendSession : 1,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterExtendSession NS_SWIFT_NAME(AnalyticsParameterExtendSession) = + @"extend_session"; + +/// Flight number for travel events (String). +///
+///     let params = [
+///       AnalyticsParameterFlightNumber : "ZZ800",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterFlightNumber NS_SWIFT_NAME(AnalyticsParameterFlightNumber) = + @"flight_number"; + +/// Group/clan/guild ID (String). +///
+///     let params = [
+///       AnalyticsParameterGroupID : "g1",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterGroupID NS_SWIFT_NAME(AnalyticsParameterGroupID) = @"group_id"; + +/// The index of the item in a list (Int). +///
+///     let params = [
+///       AnalyticsParameterIndex : 5,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterIndex NS_SWIFT_NAME(AnalyticsParameterIndex) = @"index"; + +/// Item brand (String). +///
+///     let params = [
+///       AnalyticsParameterItemBrand : "Google",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemBrand NS_SWIFT_NAME(AnalyticsParameterItemBrand) = + @"item_brand"; + +/// Item category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory NS_SWIFT_NAME(AnalyticsParameterItemCategory) = + @"item_category"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory2 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory2 NS_SWIFT_NAME(AnalyticsParameterItemCategory2) = + @"item_category2"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory3 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory3 NS_SWIFT_NAME(AnalyticsParameterItemCategory3) = + @"item_category3"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory4 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory4 NS_SWIFT_NAME(AnalyticsParameterItemCategory4) = + @"item_category4"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory5 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory5 NS_SWIFT_NAME(AnalyticsParameterItemCategory5) = + @"item_category5"; + +/// Item ID (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemID : "SKU_12345",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemID NS_SWIFT_NAME(AnalyticsParameterItemID) = @"item_id"; + +/// The ID of the list in which the item was presented to the user (String). +///
+///     let params = [
+///       AnalyticsParameterItemListID : "ABC123",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemListID NS_SWIFT_NAME(AnalyticsParameterItemListID) = + @"item_list_id"; + +/// The name of the list in which the item was presented to the user (String). +///
+///     let params = [
+///       AnalyticsParameterItemListName : "Related products",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemListName NS_SWIFT_NAME(AnalyticsParameterItemListName) = + @"item_list_name"; + +/// Item Name (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemName : "jeggings",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemName NS_SWIFT_NAME(AnalyticsParameterItemName) = + @"item_name"; + +/// Item variant (String). +///
+///     let params = [
+///       AnalyticsParameterItemVariant : "Black",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemVariant NS_SWIFT_NAME(AnalyticsParameterItemVariant) = + @"item_variant"; + +/// The list of items involved in the transaction expressed as `[[String: Any]]`. +///
+///     let params = [
+///       AnalyticsParameterItems : [
+///         [AnalyticsParameterItemName : "jeggings", AnalyticsParameterItemCategory : "pants"],
+///         [AnalyticsParameterItemName : "boots", AnalyticsParameterItemCategory : "shoes"],
+///       ],
+///     ]
+/// 
+static NSString *const kFIRParameterItems NS_SWIFT_NAME(AnalyticsParameterItems) = @"items"; + +/// Level in game (Int). +///
+///     let params = [
+///       AnalyticsParameterLevel : 42,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLevel NS_SWIFT_NAME(AnalyticsParameterLevel) = @"level"; + +/// The name of a level in a game (String). +///
+///     let params = [
+///       AnalyticsParameterLevelName : "room_1",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLevelName NS_SWIFT_NAME(AnalyticsParameterLevelName) = + @"level_name"; + +/// Location (String). The Google Place ID +/// that corresponds to the associated event. Alternatively, you can supply your own custom +/// Location ID. +///
+///     let params = [
+///       AnalyticsParameterLocation : "ChIJiyj437sx3YAR9kUWC8QkLzQ",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLocation NS_SWIFT_NAME(AnalyticsParameterLocation) = + @"location"; + +/// The location associated with the event. Preferred to be the Google +/// Place ID that corresponds to the +/// associated item but could be overridden to a custom location ID string.(String). +///
+///     let params = [
+///       AnalyticsParameterLocationID : "ChIJiyj437sx3YAR9kUWC8QkLzQ",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLocationID NS_SWIFT_NAME(AnalyticsParameterLocationID) = + @"location_id"; + +/// Marketing Tactic (String). Used to identify the targeting criteria applied to a specific +/// campaign. +///
+///     let params = [
+///       AnalyticsParameterMarketingTactic : "Remarketing",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterMarketingTactic + NS_SWIFT_NAME(AnalyticsParameterMarketingTactic) = @"marketing_tactic"; + +/// The advertising or marketing medium, for example: cpc, banner, email, push. Highly recommended +/// (String). +///
+///     let params = [
+///       AnalyticsParameterMedium : "email",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterMedium NS_SWIFT_NAME(AnalyticsParameterMedium) = @"medium"; + +/// A particular approach used in an operation; for example, "facebook" or "email" in the context +/// of a sign_up or login event. (String). +///
+///     let params = [
+///       AnalyticsParameterMethod : "google",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterMethod NS_SWIFT_NAME(AnalyticsParameterMethod) = @"method"; + +/// Number of nights staying at hotel (Int). +///
+///     let params = [
+///       AnalyticsParameterNumberOfNights : 3,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterNumberOfNights + NS_SWIFT_NAME(AnalyticsParameterNumberOfNights) = @"number_of_nights"; + +/// Number of passengers traveling (Int). +///
+///     let params = [
+///       AnalyticsParameterNumberOfPassengers : 11,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterNumberOfPassengers + NS_SWIFT_NAME(AnalyticsParameterNumberOfPassengers) = @"number_of_passengers"; + +/// Number of rooms for travel events (Int). +///
+///     let params = [
+///       AnalyticsParameterNumberOfRooms : 2,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterNumberOfRooms NS_SWIFT_NAME(AnalyticsParameterNumberOfRooms) = + @"number_of_rooms"; + +/// Flight or Travel origin (String). +///
+///     let params = [
+///       AnalyticsParameterOrigin : "Mountain View, CA",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterOrigin NS_SWIFT_NAME(AnalyticsParameterOrigin) = @"origin"; + +/// The chosen method of payment (String). +///
+///     let params = [
+///       AnalyticsParameterPaymentType : "Visa",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPaymentType NS_SWIFT_NAME(AnalyticsParameterPaymentType) = + @"payment_type"; + +/// Purchase price (Double). +///
+///     let params = [
+///       AnalyticsParameterPrice : 1.0,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $1.00 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPrice NS_SWIFT_NAME(AnalyticsParameterPrice) = @"price"; + +/// The ID of a product promotion (String). +///
+///     let params = [
+///       AnalyticsParameterPromotionID : "ABC123",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPromotionID NS_SWIFT_NAME(AnalyticsParameterPromotionID) = + @"promotion_id"; + +/// The name of a product promotion (String). +///
+///     let params = [
+///       AnalyticsParameterPromotionName : "Summer Sale",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPromotionName NS_SWIFT_NAME(AnalyticsParameterPromotionName) = + @"promotion_name"; + +/// Purchase quantity (Int). +///
+///     let params = [
+///       AnalyticsParameterQuantity : 1,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterQuantity NS_SWIFT_NAME(AnalyticsParameterQuantity) = + @"quantity"; + +/// Score in game (Int). +///
+///     let params = [
+///       AnalyticsParameterScore : 4200,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterScore NS_SWIFT_NAME(AnalyticsParameterScore) = @"score"; + +/// Current screen class, such as the class name of the UIViewController, logged with screen_view +/// event and added to every event (String). +///
+///     let params = [
+///       AnalyticsParameterScreenClass : "LoginViewController",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterScreenClass NS_SWIFT_NAME(AnalyticsParameterScreenClass) = + @"screen_class"; + +/// Current screen name, such as the name of the UIViewController, logged with screen_view event and +/// added to every event (String). +///
+///     let params = [
+///       AnalyticsParameterScreenName : "LoginView",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterScreenName NS_SWIFT_NAME(AnalyticsParameterScreenName) = + @"screen_name"; + +/// The search string/keywords used (String). +///
+///     let params = [
+///       AnalyticsParameterSearchTerm : "periodic table",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSearchTerm NS_SWIFT_NAME(AnalyticsParameterSearchTerm) = + @"search_term"; + +/// Shipping cost associated with a transaction (Double). +///
+///     let params = [
+///       AnalyticsParameterShipping : 5.99,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $5.99 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterShipping NS_SWIFT_NAME(AnalyticsParameterShipping) = + @"shipping"; + +/// The shipping tier (e.g. Ground, Air, Next-day) selected for delivery of the purchased item +/// (String). +///
+///     let params = [
+///       AnalyticsParameterShippingTier : "Ground",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterShippingTier NS_SWIFT_NAME(AnalyticsParameterShippingTier) = + @"shipping_tier"; + +/// The origin of your traffic, such as an Ad network (for example, google) or partner (urban +/// airship). Identify the advertiser, site, publication, etc. that is sending traffic to your +/// property. Highly recommended (String). +///
+///     let params = [
+///       AnalyticsParameterSource : "InMobi",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSource NS_SWIFT_NAME(AnalyticsParameterSource) = @"source"; + +/// Source Platform (String). Used to identify the platform responsible for directing traffic to a +/// given Analytics property (e.g., a buying platform where budgets, targeting criteria, etc. are +/// set, a platform for managing organic traffic data, etc.). +///
+///     let params = [
+///       AnalyticsParameterSourcePlatform : "sa360",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSourcePlatform NS_SWIFT_NAME(AnalyticsParameterSourcePlatform) = + @"source_platform"; + +/// The departure date, check-in date or rental start date for the item. This should be in +/// YYYY-MM-DD format (String). +///
+///     let params = [
+///       AnalyticsParameterStartDate : "2015-09-14",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterStartDate NS_SWIFT_NAME(AnalyticsParameterStartDate) = + @"start_date"; + +/// The result of an operation. Specify 1 to indicate success and 0 to indicate failure (Int). +///
+///     let params = [
+///       AnalyticsParameterSuccess : 1,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSuccess NS_SWIFT_NAME(AnalyticsParameterSuccess) = @"success"; + +/// Tax cost associated with a transaction (Double). +///
+///     let params = [
+///       AnalyticsParameterTax : 2.43,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $2.43 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTax NS_SWIFT_NAME(AnalyticsParameterTax) = @"tax"; + +/// If you're manually tagging keyword campaigns, you should use utm_term to specify the keyword +/// (String). +///
+///     let params = [
+///       AnalyticsParameterTerm : "game",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTerm NS_SWIFT_NAME(AnalyticsParameterTerm) = @"term"; + +/// The unique identifier of a transaction (String). +///
+///     let params = [
+///       AnalyticsParameterTransactionID : "T12345",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTransactionID NS_SWIFT_NAME(AnalyticsParameterTransactionID) = + @"transaction_id"; + +/// Travel class (String). +///
+///     let params = [
+///       AnalyticsParameterTravelClass : "business",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTravelClass NS_SWIFT_NAME(AnalyticsParameterTravelClass) = + @"travel_class"; + +/// A context-specific numeric value which is accumulated automatically for each event type. This is +/// a general purpose parameter that is useful for accumulating a key metric that pertains to an +/// event. Examples include revenue, distance, time and points. Value should be specified as Int or +/// Double. +/// Notes: Values for pre-defined currency-related events (such as @c AnalyticsEventAddToCart) +/// should be supplied using Double and must be accompanied by a @c AnalyticsParameterCurrency +/// parameter. The valid range of accumulated values is +/// [-9,223,372,036,854.77, 9,223,372,036,854.77]. Supplying a non-numeric value, omitting the +/// corresponding @c AnalyticsParameterCurrency parameter, or supplying an invalid +/// currency code for conversion events will cause that +/// conversion to be omitted from reporting. +///
+///     let params = [
+///       AnalyticsParameterValue : 3.99,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $3.99 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterValue NS_SWIFT_NAME(AnalyticsParameterValue) = @"value"; + +/// Name of virtual currency type (String). +///
+///     let params = [
+///       AnalyticsParameterVirtualCurrencyName : "virtual_currency_name",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterVirtualCurrencyName + NS_SWIFT_NAME(AnalyticsParameterVirtualCurrencyName) = @"virtual_currency_name"; diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h new file mode 100644 index 0000000..2442d8a --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h @@ -0,0 +1,28 @@ +/// @file FIRUserPropertyNames.h +/// +/// Predefined user property names. +/// +/// A UserProperty is an attribute that describes the app-user. By supplying UserProperties, you can +/// later analyze different behaviors of various segments of your userbase. You may supply up to 25 +/// unique UserProperties per app, and you can use the name and value of your choosing for each one. +/// UserProperty names can be up to 24 characters long, may only contain alphanumeric characters and +/// underscores ("_"), and must start with an alphabetic character. UserProperty values can be up to +/// 36 characters long. The "firebase_", "google_", and "ga_" prefixes are reserved and should not +/// be used. + +#import + +/// Indicates whether events logged by Google Analytics can be used to personalize ads for the user. +/// Set to "YES" to enable, or "NO" to disable. Default is enabled. See the +/// documentation for +/// more details and information about related settings. +/// +///
+///     Analytics.setUserProperty("NO", forName: AnalyticsUserPropertyAllowAdPersonalizationSignals)
+/// 
+static NSString *const kFIRUserPropertyAllowAdPersonalizationSignals + NS_SWIFT_NAME(AnalyticsUserPropertyAllowAdPersonalizationSignals) = @"allow_personalized_ads"; + +/// The method used to sign in. For example, "google", "facebook" or "twitter". +static NSString *const kFIRUserPropertySignUpMethod + NS_SWIFT_NAME(AnalyticsUserPropertySignUpMethod) = @"sign_up_method"; diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-umbrella.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-umbrella.h new file mode 100644 index 0000000..ad84fbb --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-umbrella.h @@ -0,0 +1,24 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "FIRAnalytics+AppDelegate.h" +#import "FIRAnalytics+Consent.h" +#import "FIRAnalytics+OnDevice.h" +#import "FIRAnalytics.h" +#import "FirebaseAnalytics.h" +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" + +FOUNDATION_EXPORT double FirebaseAnalyticsVersionNumber; +FOUNDATION_EXPORT const unsigned char FirebaseAnalyticsVersionString[]; + diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h new file mode 100644 index 0000000..351da20 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h @@ -0,0 +1,7 @@ +#import "FIRAnalytics+AppDelegate.h" +#import "FIRAnalytics+Consent.h" +#import "FIRAnalytics+OnDevice.h" +#import "FIRAnalytics.h" +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Info.plist b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Info.plist new file mode 100644 index 0000000..1674c5f --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleExecutable + FirebaseAnalytics + CFBundleIdentifier + com.firebase.Firebase-FirebaseAnalytics + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + FirebaseAnalytics + CFBundlePackageType + FMWK + CFBundleVersion + 10.11.0 + DTSDKName + iphonesimulator11.2 + + diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Modules/module.modulemap b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Modules/module.modulemap new file mode 100644 index 0000000..37eb24b --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Modules/module.modulemap @@ -0,0 +1,12 @@ +framework module FirebaseAnalytics { +umbrella header "FirebaseAnalytics-umbrella.h" +export * +module * { export * } + link framework "Foundation" + link framework "Security" + link framework "SystemConfiguration" + link framework "UIKit" + link "c++" + link "sqlite3" + link "z" +} diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/FirebaseAnalytics b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/FirebaseAnalytics new file mode 100644 index 0000000..fc73d7b Binary files /dev/null and b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/FirebaseAnalytics differ diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h new file mode 100644 index 0000000..cb1e407 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h @@ -0,0 +1,80 @@ +#import + +#import "FIRAnalytics.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Provides App Delegate handlers to be used in your App Delegate. +/// +/// To save time integrating Firebase Analytics in an application, Firebase Analytics does not +/// require delegation implementation from the AppDelegate if neither SwiftUI nor UIScene lifecycle +/// is adopted. Instead this is automatically done by Firebase Analytics. Should you choose instead +/// to delegate manually, you can turn off the App Delegate Proxy by adding +/// FirebaseAppDelegateProxyEnabled into your app's Info.plist and setting it to boolean `NO`, and +/// adding the methods in this category to corresponding delegation handlers. +/// +/// To handle Universal Links, you must return `true` in +/// `UIApplicationDelegate.application(_:didFinishLaunchingWithOptions:)`. +@interface FIRAnalytics (AppDelegate) + +/// Handles events related to a URL session that are waiting to be processed. +/// +/// 1. If SwiftUI lifecycle is adopted, call this method from +/// `UIApplicationDelegate.application(_:handleEventsForBackgroundURLSession:completionHandler:)` +/// in your app delegate. +/// +/// 2. If SwiftUI lifecycle is not adopted, Firebase Analytics does not require delegation +/// implementation from the AppDelegate. If you choose instead to delegate manually, you can set +/// FirebaseAppDelegateProxyEnabled to boolean `NO` in your app's Info.plist and call this method +/// from +/// `UIApplicationDelegate.application(_:handleEventsForBackgroundURLSession:completionHandler:)` +/// in your app delegate. +/// +/// @param identifier The identifier of the URL session requiring attention. +/// @param completionHandler The completion handler to call when you finish processing the events. +/// Calling this completion handler lets the system know that your app's user interface is +/// updated and a new snapshot can be taken. ++ (void)handleEventsForBackgroundURLSession:(NSString *)identifier + completionHandler:(nullable void (^)(void))completionHandler; + +/// Handles the event when the app is launched by a URL (custom URL scheme or universal link). +/// +/// 1. If SwiftUI lifecycle is adopted, use `onOpenURL(perform:)` to register a handler and call +/// this method in the handler. +/// +/// 2. If UIScene lifecycle is adopted, call this method from +/// `UISceneDelegate.scene(_:willConnectTo:options:)` and +/// `UISceneDelegate.scene(_:openURLContexts:)` when the URL contexts are available. +/// +/// 3. If neither SwiftUI nor UIScene lifecycle is adopted, Firebase Analytics does not require +/// delegation implementation from the AppDelegate. If you choose instead to delegate manually, you +/// can set FirebaseAppDelegateProxyEnabled to boolean `NO` in your app's Info.plist and call this +/// method from `UIApplicationDelegate.application(_:open:options:)` in your app delegate. +/// +/// @param url The URL resource to open. This resource can be a network resource or a file. ++ (void)handleOpenURL:(NSURL *)url; + +/// Handles the event when the app receives data associated with user activity that includes a +/// Universal Link. +/// +/// 1. If SwiftUI lifecycle is adopted, use `onOpenURL(perform:)` to register a handler and call +/// `Analytics.handleOpen(_:)` instead in the handler. +/// +/// 2. If UIScene lifecycle is adopted, call this method from +/// `UISceneDelegate.scene(_:willConnectTo:options:)` and `UISceneDelegate.scene(_:continue:)` when +/// NSUserActivity is available. See the [Apple +/// doc](https://developer.apple.com/documentation/xcode/supporting-universal-links-in-your-app) for +/// more details. +/// +/// 3. If neither SwiftUI nor UIScene lifecycle is adopted, Firebase Analytics does not require +/// delegation implementation from the AppDelegate. If you choose instead to delegate manually, you +/// can set FirebaseAppDelegateProxyEnabled to boolean `NO` in your app's Info.plist and call this +/// method from `UIApplication.application(_:continue:restorationHandler:)` in your app delegate. +/// +/// @param userActivity The activity object containing the data associated with the task the user +/// was performing. ++ (void)handleUserActivity:(id)userActivity; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+Consent.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+Consent.h new file mode 100644 index 0000000..7f89831 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+Consent.h @@ -0,0 +1,33 @@ +#import + +#import "FIRAnalytics.h" + +NS_ASSUME_NONNULL_BEGIN + +/// The type of consent to set. Supported consent types are `ConsentType.adStorage` and +/// `ConsentType.analyticsStorage`. Omitting a type retains its previous status. +typedef NSString *FIRConsentType NS_TYPED_ENUM NS_SWIFT_NAME(ConsentType); +extern FIRConsentType const FIRConsentTypeAdStorage; +extern FIRConsentType const FIRConsentTypeAnalyticsStorage; + +/// The status value of the consent type. Supported statuses are `ConsentStatus.granted` and +/// `ConsentStatus.denied`. +typedef NSString *FIRConsentStatus NS_TYPED_ENUM NS_SWIFT_NAME(ConsentStatus); +extern FIRConsentStatus const FIRConsentStatusDenied; +extern FIRConsentStatus const FIRConsentStatusGranted; + +/// Sets the applicable end user consent state. +@interface FIRAnalytics (Consent) + +/// Sets the applicable end user consent state (e.g. for device identifiers) for this app on this +/// device. Use the consent settings to specify individual consent type values. Settings are +/// persisted across app sessions. By default consent types are set to `ConsentStatus.granted`. +/// +/// @param consentSettings A Dictionary of consent types. Supported consent type keys are +/// `ConsentType.adStorage` and `ConsentType.analyticsStorage`. Valid values are +/// `ConsentStatus.granted` and `ConsentStatus.denied`. ++ (void)setConsent:(NSDictionary *)consentSettings; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+OnDevice.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+OnDevice.h new file mode 100644 index 0000000..1d9a438 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+OnDevice.h @@ -0,0 +1,19 @@ +#import + +#import "FIRAnalytics.h" + +NS_ASSUME_NONNULL_BEGIN + +API_UNAVAILABLE(macCatalyst, macos, tvos, watchos) +@interface FIRAnalytics (OnDevice) + +/// Initiates on-device conversion measurement given a user email address. Requires dependency +/// GoogleAppMeasurementOnDeviceConversion to be linked in, otherwise it is a no-op. +/// @param emailAddress User email address. Include a domain name for all email addresses +/// (e.g. gmail.com or hotmail.co.jp). ++ (void)initiateOnDeviceConversionMeasurementWithEmailAddress:(NSString *)emailAddress + NS_SWIFT_NAME(initiateOnDeviceConversionMeasurement(emailAddress:)); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics.h new file mode 100644 index 0000000..e7ce5dc --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics.h @@ -0,0 +1,154 @@ +#import + +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" + +NS_ASSUME_NONNULL_BEGIN + +/// The top level Firebase Analytics singleton that provides methods for logging events and setting +/// user properties. See the developer guides for general +/// information on using Firebase Analytics in your apps. +/// +/// @note The Analytics SDK uses SQLite to persist events and other app-specific data. Calling +/// certain thread-unsafe global SQLite methods like `sqlite3_shutdown()` can result in +/// unexpected crashes at runtime. +NS_SWIFT_NAME(Analytics) +@interface FIRAnalytics : NSObject + +/// Logs an app event. The event can have up to 25 parameters. Events with the same name must have +/// the same parameters. Up to 500 event names are supported. Using predefined events and/or +/// parameters is recommended for optimal reporting. +/// +/// The following event names are reserved and cannot be used: +///
    +///
  • ad_activeview
  • +///
  • ad_click
  • +///
  • ad_exposure
  • +///
  • ad_query
  • +///
  • ad_reward
  • +///
  • adunit_exposure
  • +///
  • app_clear_data
  • +///
  • app_exception
  • +///
  • app_remove
  • +///
  • app_store_refund
  • +///
  • app_store_subscription_cancel
  • +///
  • app_store_subscription_convert
  • +///
  • app_store_subscription_renew
  • +///
  • app_update
  • +///
  • app_upgrade
  • +///
  • dynamic_link_app_open
  • +///
  • dynamic_link_app_update
  • +///
  • dynamic_link_first_open
  • +///
  • error
  • +///
  • firebase_campaign
  • +///
  • first_open
  • +///
  • first_visit
  • +///
  • in_app_purchase
  • +///
  • notification_dismiss
  • +///
  • notification_foreground
  • +///
  • notification_open
  • +///
  • notification_receive
  • +///
  • os_update
  • +///
  • session_start
  • +///
  • session_start_with_rollout
  • +///
  • user_engagement
  • +///
+/// +/// @param name The name of the event. Should contain 1 to 40 alphanumeric characters or +/// underscores. The name must start with an alphabetic character. Some event names are +/// reserved. See FIREventNames.h for the list of reserved event names. The "firebase_", +/// "google_", and "ga_" prefixes are reserved and should not be used. Note that event names are +/// case-sensitive and that logging two events whose names differ only in case will result in +/// two distinct events. To manually log screen view events, use the `screen_view` event name. +/// @param parameters The dictionary of event parameters. Passing `nil` indicates that the event has +/// no parameters. Parameter names can be up to 40 characters long and must start with an +/// alphabetic character and contain only alphanumeric characters and underscores. Only String, +/// Int, and Double parameter types are supported. String parameter values can be up to 100 +/// characters long. The "firebase_", "google_", and "ga_" prefixes are reserved and should not +/// be used for parameter names. ++ (void)logEventWithName:(NSString *)name + parameters:(nullable NSDictionary *)parameters + NS_SWIFT_NAME(logEvent(_:parameters:)); + +/// Sets a user property to a given value. Up to 25 user property names are supported. Once set, +/// user property values persist throughout the app lifecycle and across sessions. +/// +/// The following user property names are reserved and cannot be used: +///
    +///
  • first_open_time
  • +///
  • last_deep_link_referrer
  • +///
  • user_id
  • +///
+/// +/// @param value The value of the user property. Values can be up to 36 characters long. Setting the +/// value to `nil` removes the user property. +/// @param name The name of the user property to set. Should contain 1 to 24 alphanumeric characters +/// or underscores and must start with an alphabetic character. The "firebase_", "google_", and +/// "ga_" prefixes are reserved and should not be used for user property names. ++ (void)setUserPropertyString:(nullable NSString *)value forName:(NSString *)name + NS_SWIFT_NAME(setUserProperty(_:forName:)); + +/// Sets the user ID property. This feature must be used in accordance with +/// Google's Privacy Policy +/// +/// @param userID The user ID to ascribe to the user of this app on this device, which must be +/// non-empty and no more than 256 characters long. Setting userID to `nil` removes the user ID. ++ (void)setUserID:(nullable NSString *)userID; + +/// Sets whether analytics collection is enabled for this app on this device. This setting is +/// persisted across app sessions. By default it is enabled. +/// +/// @param analyticsCollectionEnabled A flag that enables or disables Analytics collection. ++ (void)setAnalyticsCollectionEnabled:(BOOL)analyticsCollectionEnabled; + +/// Sets the interval of inactivity in seconds that terminates the current session. The default +/// value is 1800 seconds (30 minutes). +/// +/// @param sessionTimeoutInterval The custom time of inactivity in seconds before the current +/// session terminates. ++ (void)setSessionTimeoutInterval:(NSTimeInterval)sessionTimeoutInterval; + +/// Asynchronously retrieves the identifier of the current app session. +/// +/// The session ID retrieval could fail due to Analytics collection disabled, app session expired, +/// etc. +/// +/// @param completion The completion handler to call when the session ID retrieval is complete. This +/// handler is executed on a system-defined global concurrent queue. +/// This completion handler takes the following parameters: +/// sessionID The identifier of the current app session. The value is undefined if the +/// request failed. +/// error An error object that indicates why the request failed, or `nil` if the request +/// was successful. ++ (void)sessionIDWithCompletion:(void (^)(int64_t sessionID, NSError *_Nullable error))completion; + +/// Returns the unique ID for this instance of the application or `nil` if +/// `ConsentType.analyticsStorage` has been set to `ConsentStatus.denied`. +/// +/// @see `FIRAnalytics+Consent.h` ++ (nullable NSString *)appInstanceID; + +/// Clears all analytics data for this instance from the device and resets the app instance ID. ++ (void)resetAnalyticsData; + +/// Adds parameters that will be set on every event logged from the SDK, including automatic ones. +/// The values passed in the parameters dictionary will be added to the dictionary of default event +/// parameters. These parameters persist across app runs. They are of lower precedence than event +/// parameters, so if an event parameter and a parameter set using this API have the same name, the +/// value of the event parameter will be used. The same limitations on event parameters apply to +/// default event parameters. +/// +/// @param parameters Parameters to be added to the dictionary of parameters added to every event. +/// They will be added to the dictionary of default event parameters, replacing any existing +/// parameter with the same name. Valid parameters are String, Int, and Double. Setting a key's +/// value to `NSNull()` will clear that parameter. Passing in a `nil` dictionary will clear all +/// parameters. ++ (void)setDefaultEventParameters:(nullable NSDictionary *)parameters; + +/// Unavailable. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIREventNames.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIREventNames.h new file mode 100644 index 0000000..1e69a44 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIREventNames.h @@ -0,0 +1,418 @@ +/// @file FIREventNames.h +/// +/// Predefined event names. +/// +/// An Event is an important occurrence in your app that you want to measure. You can report up to +/// 500 different types of Events per app and you can associate up to 25 unique parameters with each +/// Event type. Some common events are suggested below, but you may also choose to specify custom +/// Event types that are associated with your specific app. Each event type is identified by a +/// unique name. Event names can be up to 40 characters long, may only contain alphanumeric +/// characters and underscores ("_"), and must start with an alphabetic character. The "firebase_", +/// "google_", and "ga_" prefixes are reserved and should not be used. + +#import + +/// Ad Impression event. This event signifies when a user sees an ad impression. Note: If you supply +/// the @c AnalyticsParameterValue parameter, you must also supply the @c AnalyticsParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterAdPlatform (String) (optional)
  • +///
  • @c AnalyticsParameterAdFormat (String) (optional)
  • +///
  • @c AnalyticsParameterAdSource (String) (optional)
  • +///
  • @c AnalyticsParameterAdUnitName (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAdImpression NS_SWIFT_NAME(AnalyticsEventAdImpression) = + @"ad_impression"; + +/// Add Payment Info event. This event signifies that a user has submitted their payment +/// information. Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply +/// the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterPaymentType (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddPaymentInfo NS_SWIFT_NAME(AnalyticsEventAddPaymentInfo) = + @"add_payment_info"; + +/// Add Shipping Info event. This event signifies that a user has submitted their shipping +/// information. Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply +/// the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterShippingTier (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddShippingInfo NS_SWIFT_NAME(AnalyticsEventAddShippingInfo) = + @"add_shipping_info"; + +/// E-Commerce Add To Cart event. This event signifies that an item(s) was added to a cart for +/// purchase. Add this event to a funnel with @c AnalyticsEventPurchase to gauge the effectiveness +/// of your checkout process. Note: If you supply the @c AnalyticsParameterValue parameter, you must +/// also supply the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed +/// accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddToCart NS_SWIFT_NAME(AnalyticsEventAddToCart) = @"add_to_cart"; + +/// E-Commerce Add To Wishlist event. This event signifies that an item was added to a wishlist. Use +/// this event to identify popular gift items. Note: If you supply the @c AnalyticsParameterValue +/// parameter, you must also supply the @c AnalyticsParameterCurrency parameter so that revenue +/// metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddToWishlist NS_SWIFT_NAME(AnalyticsEventAddToWishlist) = + @"add_to_wishlist"; + +/// App Open event. By logging this event when an App becomes active, developers can understand how +/// often users leave and return during the course of a Session. Although Sessions are automatically +/// reported, this event can provide further clarification around the continuous engagement of +/// app-users. +static NSString *const kFIREventAppOpen NS_SWIFT_NAME(AnalyticsEventAppOpen) = @"app_open"; + +/// E-Commerce Begin Checkout event. This event signifies that a user has begun the process of +/// checking out. Add this event to a funnel with your @c AnalyticsEventPurchase event to gauge the +/// effectiveness of your checkout process. Note: If you supply the @c AnalyticsParameterValue +/// parameter, you must also supply the @c AnalyticsParameterCurrency parameter so that revenue +/// metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventBeginCheckout NS_SWIFT_NAME(AnalyticsEventBeginCheckout) = + @"begin_checkout"; + +/// Campaign Detail event. Log this event to supply the referral details of a re-engagement +/// campaign. Note: you must supply at least one of the required parameters +/// AnalyticsParameterSource, AnalyticsParameterMedium or AnalyticsParameterCampaign. Params: +/// +///
    +///
  • @c AnalyticsParameterSource (String)
  • +///
  • @c AnalyticsParameterMedium (String)
  • +///
  • @c AnalyticsParameterCampaign (String)
  • +///
  • @c AnalyticsParameterTerm (String) (optional)
  • +///
  • @c AnalyticsParameterContent (String) (optional)
  • +///
  • @c AnalyticsParameterAdNetworkClickID (String) (optional)
  • +///
  • @c AnalyticsParameterCP1 (String) (optional)
  • +///
  • @c AnalyticsParameterCampaignID (String) (optional)
  • +///
  • @c AnalyticsParameterCreativeFormat (String) (optional)
  • +///
  • @c AnalyticsParameterMarketingTactic (String) (optional)
  • +///
  • @c AnalyticsParameterSourcePlatform (String) (optional)
  • +///
+static NSString *const kFIREventCampaignDetails NS_SWIFT_NAME(AnalyticsEventCampaignDetails) = + @"campaign_details"; + +/// Earn Virtual Currency event. This event tracks the awarding of virtual currency in your app. Log +/// this along with @c AnalyticsEventSpendVirtualCurrency to better understand your virtual economy. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterVirtualCurrencyName (String)
  • +///
  • @c AnalyticsParameterValue (Int or Double)
  • +///
+static NSString *const kFIREventEarnVirtualCurrency + NS_SWIFT_NAME(AnalyticsEventEarnVirtualCurrency) = @"earn_virtual_currency"; + +/// Generate Lead event. Log this event when a lead has been generated in the app to understand the +/// efficacy of your install and re-engagement campaigns. Note: If you supply the +/// @c AnalyticsParameterValue parameter, you must also supply the @c AnalyticsParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventGenerateLead NS_SWIFT_NAME(AnalyticsEventGenerateLead) = + @"generate_lead"; + +/// Join Group event. Log this event when a user joins a group such as a guild, team or family. Use +/// this event to analyze how popular certain groups or social features are in your app. Params: +/// +///
    +///
  • @c AnalyticsParameterGroupID (String)
  • +///
+static NSString *const kFIREventJoinGroup NS_SWIFT_NAME(AnalyticsEventJoinGroup) = @"join_group"; + +/// Level End event. Log this event when the user finishes a level. Params: +/// +///
    +///
  • @c AnalyticsParameterLevelName (String)
  • +///
  • @c AnalyticsParameterSuccess (String)
  • +///
+static NSString *const kFIREventLevelEnd NS_SWIFT_NAME(AnalyticsEventLevelEnd) = @"level_end"; + +/// Level Start event. Log this event when the user starts a new level. Params: +/// +///
    +///
  • @c AnalyticsParameterLevelName (String)
  • +///
+static NSString *const kFIREventLevelStart NS_SWIFT_NAME(AnalyticsEventLevelStart) = @"level_start"; + +/// Level Up event. This event signifies that a player has leveled up in your gaming app. It can +/// help you gauge the level distribution of your userbase and help you identify certain levels that +/// are difficult to pass. Params: +/// +///
    +///
  • @c AnalyticsParameterLevel (Int)
  • +///
  • @c AnalyticsParameterCharacter (String) (optional)
  • +///
+static NSString *const kFIREventLevelUp NS_SWIFT_NAME(AnalyticsEventLevelUp) = @"level_up"; + +/// Login event. Apps with a login feature can report this event to signify that a user has logged +/// in. +static NSString *const kFIREventLogin NS_SWIFT_NAME(AnalyticsEventLogin) = @"login"; + +/// Post Score event. Log this event when the user posts a score in your gaming app. This event can +/// help you understand how users are actually performing in your game and it can help you correlate +/// high scores with certain audiences or behaviors. Params: +/// +///
    +///
  • @c AnalyticsParameterScore (Int)
  • +///
  • @c AnalyticsParameterLevel (Int) (optional)
  • +///
  • @c AnalyticsParameterCharacter (String) (optional)
  • +///
+static NSString *const kFIREventPostScore NS_SWIFT_NAME(AnalyticsEventPostScore) = @"post_score"; + +/// E-Commerce Purchase event. This event signifies that an item(s) was purchased by a user. Note: +/// This is different from the in-app purchase event, which is reported automatically for App +/// Store-based apps. Note: If you supply the @c AnalyticsParameterValue parameter, you must also +/// supply the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed +/// accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterAffiliation (String) (optional)
  • +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterEndDate (String) (optional)
  • +///
  • @c AnalyticsParameterItemID (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterShipping (Double) (optional)
  • +///
  • @c AnalyticsParameterStartDate (String) (optional)
  • +///
  • @c AnalyticsParameterTax (Double) (optional)
  • +///
  • @c AnalyticsParameterTransactionID (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventPurchase NS_SWIFT_NAME(AnalyticsEventPurchase) = @"purchase"; + +/// E-Commerce Refund event. This event signifies that a refund was issued. Note: If you supply the +/// @c AnalyticsParameterValue parameter, you must also supply the @c AnalyticsParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterAffiliation (String) (optional)
  • +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterShipping (Double) (optional)
  • +///
  • @c AnalyticsParameterTax (Double) (optional)
  • +///
  • @c AnalyticsParameterTransactionID (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventRefund NS_SWIFT_NAME(AnalyticsEventRefund) = @"refund"; + +/// E-Commerce Remove from Cart event. This event signifies that an item(s) was removed from a cart. +/// Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply the @c +/// AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventRemoveFromCart NS_SWIFT_NAME(AnalyticsEventRemoveFromCart) = + @"remove_from_cart"; + +/// Screen View event. This event signifies a screen view. Use this when a screen transition occurs. +/// This event can be logged irrespective of whether automatic screen tracking is enabled. Params: +/// +///
    +///
  • @c AnalyticsParameterScreenClass (String) (optional)
  • +///
  • @c AnalyticsParameterScreenName (String) (optional)
  • +///
+static NSString *const kFIREventScreenView NS_SWIFT_NAME(AnalyticsEventScreenView) = @"screen_view"; + +/// Search event. Apps that support search features can use this event to contextualize search +/// operations by supplying the appropriate, corresponding parameters. This event can help you +/// identify the most popular content in your app. Params: +/// +///
    +///
  • @c AnalyticsParameterSearchTerm (String)
  • +///
  • @c AnalyticsParameterStartDate (String) (optional)
  • +///
  • @c AnalyticsParameterEndDate (String) (optional)
  • +///
  • @c AnalyticsParameterNumberOfNights (Int) (optional) for hotel bookings
  • +///
  • @c AnalyticsParameterNumberOfRooms (Int) (optional) for hotel bookings
  • +///
  • @c AnalyticsParameterNumberOfPassengers (Int) (optional) for travel bookings
  • +///
  • @c AnalyticsParameterOrigin (String) (optional)
  • +///
  • @c AnalyticsParameterDestination (String) (optional)
  • +///
  • @c AnalyticsParameterTravelClass (String) (optional) for travel bookings
  • +///
+static NSString *const kFIREventSearch NS_SWIFT_NAME(AnalyticsEventSearch) = @"search"; + +/// Select Content event. This general purpose event signifies that a user has selected some content +/// of a certain type in an app. The content can be any object in your app. This event can help you +/// identify popular content and categories of content in your app. Params: +/// +///
    +///
  • @c AnalyticsParameterContentType (String)
  • +///
  • @c AnalyticsParameterItemID (String)
  • +///
+static NSString *const kFIREventSelectContent NS_SWIFT_NAME(AnalyticsEventSelectContent) = + @"select_content"; + +/// Select Item event. This event signifies that an item was selected by a user from a list. Use the +/// appropriate parameters to contextualize the event. Use this event to discover the most popular +/// items selected. Params: +/// +///
    +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterItemListID (String) (optional)
  • +///
  • @c AnalyticsParameterItemListName (String) (optional)
  • +///
+static NSString *const kFIREventSelectItem NS_SWIFT_NAME(AnalyticsEventSelectItem) = @"select_item"; + +/// Select promotion event. This event signifies that a user has selected a promotion offer. Use the +/// appropriate parameters to contextualize the event, such as the item(s) for which the promotion +/// applies. Params: +/// +///
    +///
  • @c AnalyticsParameterCreativeName (String) (optional)
  • +///
  • @c AnalyticsParameterCreativeSlot (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterLocationID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionName (String) (optional)
  • +///
+static NSString *const kFIREventSelectPromotion NS_SWIFT_NAME(AnalyticsEventSelectPromotion) = + @"select_promotion"; + +/// Share event. Apps with social features can log the Share event to identify the most viral +/// content. Params: +/// +///
    +///
  • @c AnalyticsParameterContentType (String)
  • +///
  • @c AnalyticsParameterItemID (String)
  • +///
+static NSString *const kFIREventShare NS_SWIFT_NAME(AnalyticsEventShare) = @"share"; + +/// Sign Up event. This event indicates that a user has signed up for an account in your app. The +/// parameter signifies the method by which the user signed up. Use this event to understand the +/// different behaviors between logged in and logged out users. Params: +/// +///
    +///
  • @c AnalyticsParameterMethod (String)
  • +///
+static NSString *const kFIREventSignUp NS_SWIFT_NAME(AnalyticsEventSignUp) = @"sign_up"; + +/// Spend Virtual Currency event. This event tracks the sale of virtual goods in your app and can +/// help you identify which virtual goods are the most popular objects of purchase. Params: +/// +///
    +///
  • @c AnalyticsParameterItemName (String)
  • +///
  • @c AnalyticsParameterVirtualCurrencyName (String)
  • +///
  • @c AnalyticsParameterValue (Int or Double)
  • +///
+static NSString *const kFIREventSpendVirtualCurrency + NS_SWIFT_NAME(AnalyticsEventSpendVirtualCurrency) = @"spend_virtual_currency"; + +/// Tutorial Begin event. This event signifies the start of the on-boarding process in your app. Use +/// this in a funnel with @c AnalyticsEventTutorialComplete to understand how many users complete +/// this process and move on to the full app experience. +static NSString *const kFIREventTutorialBegin NS_SWIFT_NAME(AnalyticsEventTutorialBegin) = + @"tutorial_begin"; + +/// Tutorial End event. Use this event to signify the user's completion of your app's on-boarding +/// process. Add this to a funnel with @c AnalyticsEventTutorialBegin to gauge the completion rate +/// of your on-boarding process. +static NSString *const kFIREventTutorialComplete NS_SWIFT_NAME(AnalyticsEventTutorialComplete) = + @"tutorial_complete"; + +/// Unlock Achievement event. Log this event when the user has unlocked an achievement in your +/// game. Since achievements generally represent the breadth of a gaming experience, this event can +/// help you understand how many users are experiencing all that your game has to offer. Params: +/// +///
    +///
  • @c AnalyticsParameterAchievementID (String)
  • +///
+static NSString *const kFIREventUnlockAchievement NS_SWIFT_NAME(AnalyticsEventUnlockAchievement) = + @"unlock_achievement"; + +/// E-commerce View Cart event. This event signifies that a user has viewed their cart. Use this to +/// analyze your purchase funnel. Note: If you supply the @c AnalyticsParameterValue parameter, you +/// must also supply the @c AnalyticsParameterCurrency parameter so that revenue metrics can be +/// computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventViewCart NS_SWIFT_NAME(AnalyticsEventViewCart) = @"view_cart"; + +/// View Item event. This event signifies that a user has viewed an item. Use the appropriate +/// parameters to contextualize the event. Use this event to discover the most popular items viewed +/// in your app. Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply +/// the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventViewItem NS_SWIFT_NAME(AnalyticsEventViewItem) = @"view_item"; + +/// View Item List event. Log this event when a user sees a list of items or offerings. Params: +/// +///
    +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterItemListID (String) (optional)
  • +///
  • @c AnalyticsParameterItemListName (String) (optional)
  • +///
+static NSString *const kFIREventViewItemList NS_SWIFT_NAME(AnalyticsEventViewItemList) = + @"view_item_list"; + +/// View Promotion event. This event signifies that a promotion was shown to a user. Add this event +/// to a funnel with the @c AnalyticsEventAddToCart and @c AnalyticsEventPurchase to gauge your +/// conversion process. Params: +/// +///
    +///
  • @c AnalyticsParameterCreativeName (String) (optional)
  • +///
  • @c AnalyticsParameterCreativeSlot (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterLocationID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionName (String) (optional)
  • +///
+static NSString *const kFIREventViewPromotion NS_SWIFT_NAME(AnalyticsEventViewPromotion) = + @"view_promotion"; + +/// View Search Results event. Log this event when the user has been presented with the results of a +/// search. Params: +/// +///
    +///
  • @c AnalyticsParameterSearchTerm (String)
  • +///
+static NSString *const kFIREventViewSearchResults NS_SWIFT_NAME(AnalyticsEventViewSearchResults) = + @"view_search_results"; diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRParameterNames.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRParameterNames.h new file mode 100644 index 0000000..b001ca5 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRParameterNames.h @@ -0,0 +1,721 @@ +/// @file FIRParameterNames.h +/// +/// Predefined event parameter names. +/// +/// Params supply information that contextualize Events. You can associate up to 25 unique Params +/// with each Event type. Some Params are suggested below for certain common Events, but you are +/// not limited to these. You may supply extra Params for suggested Events or custom Params for +/// Custom events. Param names can be up to 40 characters long, may only contain alphanumeric +/// characters and underscores ("_"), and must start with an alphabetic character. Param values can +/// be up to 100 characters long. The "firebase_", "google_", and "ga_" prefixes are reserved and +/// should not be used. + +#import + +/// Game achievement ID (String). +///
+///     let params = [
+///       AnalyticsParameterAchievementID : "10_matches_won",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAchievementID NS_SWIFT_NAME(AnalyticsParameterAchievementID) = + @"achievement_id"; + +/// The ad format (e.g. Banner, Interstitial, Rewarded, Native, Rewarded Interstitial, Instream). +/// (String). +///
+///     let params = [
+///       AnalyticsParameterAdFormat : "Banner",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdFormat NS_SWIFT_NAME(AnalyticsParameterAdFormat) = + @"ad_format"; + +/// Ad Network Click ID (String). Used for network-specific click IDs which vary in format. +///
+///     let params = [
+///       AnalyticsParameterAdNetworkClickID : "1234567",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdNetworkClickID + NS_SWIFT_NAME(AnalyticsParameterAdNetworkClickID) = @"aclid"; + +/// The ad platform (e.g. MoPub, IronSource) (String). +///
+///     let params = [
+///       AnalyticsParameterAdPlatform : "MoPub",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdPlatform NS_SWIFT_NAME(AnalyticsParameterAdPlatform) = + @"ad_platform"; + +/// The ad source (e.g. AdColony) (String). +///
+///     let params = [
+///       AnalyticsParameterAdSource : "AdColony",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdSource NS_SWIFT_NAME(AnalyticsParameterAdSource) = + @"ad_source"; + +/// The ad unit name (e.g. Banner_03) (String). +///
+///     let params = [
+///       AnalyticsParameterAdUnitName : "Banner_03",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdUnitName NS_SWIFT_NAME(AnalyticsParameterAdUnitName) = + @"ad_unit_name"; + +/// A product affiliation to designate a supplying company or brick and mortar store location +/// (String).
+///     let params = [
+///       AnalyticsParameterAffiliation : "Google Store",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAffiliation NS_SWIFT_NAME(AnalyticsParameterAffiliation) = + @"affiliation"; + +/// Campaign custom parameter (String). Used as a method of capturing custom data in a campaign. +/// Use varies by network. +///
+///     let params = [
+///       AnalyticsParameterCP1 : "custom_data",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCP1 NS_SWIFT_NAME(AnalyticsParameterCP1) = @"cp1"; + +/// The individual campaign name, slogan, promo code, etc. Some networks have pre-defined macro to +/// capture campaign information, otherwise can be populated by developer. Highly Recommended +/// (String). +///
+///     let params = [
+///       AnalyticsParameterCampaign : "winter_promotion",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCampaign NS_SWIFT_NAME(AnalyticsParameterCampaign) = + @"campaign"; + +/// Campaign ID (String). Used for keyword analysis to identify a specific product promotion or +/// strategic campaign. This is a required key for GA4 data import. +///
+///     let params = [
+///       AnalyticsParameterCampaignID : "7877652710",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCampaignID NS_SWIFT_NAME(AnalyticsParameterCampaignID) = + @"campaign_id"; + +/// Character used in game (String). +///
+///     let params = [
+///       AnalyticsParameterCharacter : "beat_boss",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCharacter NS_SWIFT_NAME(AnalyticsParameterCharacter) = + @"character"; + +/// Campaign content (String). +static NSString *const kFIRParameterContent NS_SWIFT_NAME(AnalyticsParameterContent) = @"content"; + +/// Type of content selected (String). +///
+///     let params = [
+///       AnalyticsParameterContentType : "news article",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterContentType NS_SWIFT_NAME(AnalyticsParameterContentType) = + @"content_type"; + +/// Coupon code used for a purchase (String). +///
+///     let params = [
+///       AnalyticsParameterCoupon : "SUMMER_FUN",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCoupon NS_SWIFT_NAME(AnalyticsParameterCoupon) = @"coupon"; + +/// Creative Format (String). Used to identify the high-level classification of the type of ad +/// served by a specific campaign. +///
+///     let params = [
+///       AnalyticsParameterCreativeFormat : "display",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCreativeFormat NS_SWIFT_NAME(AnalyticsParameterCreativeFormat) = + @"creative_format"; + +/// The name of a creative used in a promotional spot (String). +///
+///     let params = [
+///       AnalyticsParameterCreativeName : "Summer Sale",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCreativeName NS_SWIFT_NAME(AnalyticsParameterCreativeName) = + @"creative_name"; + +/// The name of a creative slot (String). +///
+///     let params = [
+///       AnalyticsParameterCreativeSlot : "summer_banner2",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCreativeSlot NS_SWIFT_NAME(AnalyticsParameterCreativeSlot) = + @"creative_slot"; + +/// Currency of the purchase or items associated with the event, in 3-letter +/// ISO_4217 format (String). +///
+///     let params = [
+///       AnalyticsParameterCurrency : "USD",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCurrency NS_SWIFT_NAME(AnalyticsParameterCurrency) = + @"currency"; + +/// Flight or Travel destination (String). +///
+///     let params = [
+///       AnalyticsParameterDestination : "Mountain View, CA",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterDestination NS_SWIFT_NAME(AnalyticsParameterDestination) = + @"destination"; + +/// Monetary value of discount associated with a purchase (Double). +///
+///     let params = [
+///       AnalyticsParameterDiscount : 2.0,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $2.00 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterDiscount NS_SWIFT_NAME(AnalyticsParameterDiscount) = + @"discount"; + +/// The arrival date, check-out date or rental end date for the item. This should be in +/// YYYY-MM-DD format (String). +///
+///     let params = [
+///       AnalyticsParameterEndDate : "2015-09-14",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterEndDate NS_SWIFT_NAME(AnalyticsParameterEndDate) = @"end_date"; + +/// Indicates that the associated event should either extend the current session or start a new +/// session if no session was active when the event was logged. Specify 1 to extend the current +/// session or to start a new session; any other value will not extend or start a session. +///
+///     let params = [
+///       AnalyticsParameterExtendSession : 1,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterExtendSession NS_SWIFT_NAME(AnalyticsParameterExtendSession) = + @"extend_session"; + +/// Flight number for travel events (String). +///
+///     let params = [
+///       AnalyticsParameterFlightNumber : "ZZ800",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterFlightNumber NS_SWIFT_NAME(AnalyticsParameterFlightNumber) = + @"flight_number"; + +/// Group/clan/guild ID (String). +///
+///     let params = [
+///       AnalyticsParameterGroupID : "g1",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterGroupID NS_SWIFT_NAME(AnalyticsParameterGroupID) = @"group_id"; + +/// The index of the item in a list (Int). +///
+///     let params = [
+///       AnalyticsParameterIndex : 5,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterIndex NS_SWIFT_NAME(AnalyticsParameterIndex) = @"index"; + +/// Item brand (String). +///
+///     let params = [
+///       AnalyticsParameterItemBrand : "Google",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemBrand NS_SWIFT_NAME(AnalyticsParameterItemBrand) = + @"item_brand"; + +/// Item category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory NS_SWIFT_NAME(AnalyticsParameterItemCategory) = + @"item_category"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory2 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory2 NS_SWIFT_NAME(AnalyticsParameterItemCategory2) = + @"item_category2"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory3 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory3 NS_SWIFT_NAME(AnalyticsParameterItemCategory3) = + @"item_category3"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory4 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory4 NS_SWIFT_NAME(AnalyticsParameterItemCategory4) = + @"item_category4"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory5 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory5 NS_SWIFT_NAME(AnalyticsParameterItemCategory5) = + @"item_category5"; + +/// Item ID (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemID : "SKU_12345",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemID NS_SWIFT_NAME(AnalyticsParameterItemID) = @"item_id"; + +/// The ID of the list in which the item was presented to the user (String). +///
+///     let params = [
+///       AnalyticsParameterItemListID : "ABC123",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemListID NS_SWIFT_NAME(AnalyticsParameterItemListID) = + @"item_list_id"; + +/// The name of the list in which the item was presented to the user (String). +///
+///     let params = [
+///       AnalyticsParameterItemListName : "Related products",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemListName NS_SWIFT_NAME(AnalyticsParameterItemListName) = + @"item_list_name"; + +/// Item Name (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemName : "jeggings",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemName NS_SWIFT_NAME(AnalyticsParameterItemName) = + @"item_name"; + +/// Item variant (String). +///
+///     let params = [
+///       AnalyticsParameterItemVariant : "Black",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemVariant NS_SWIFT_NAME(AnalyticsParameterItemVariant) = + @"item_variant"; + +/// The list of items involved in the transaction expressed as `[[String: Any]]`. +///
+///     let params = [
+///       AnalyticsParameterItems : [
+///         [AnalyticsParameterItemName : "jeggings", AnalyticsParameterItemCategory : "pants"],
+///         [AnalyticsParameterItemName : "boots", AnalyticsParameterItemCategory : "shoes"],
+///       ],
+///     ]
+/// 
+static NSString *const kFIRParameterItems NS_SWIFT_NAME(AnalyticsParameterItems) = @"items"; + +/// Level in game (Int). +///
+///     let params = [
+///       AnalyticsParameterLevel : 42,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLevel NS_SWIFT_NAME(AnalyticsParameterLevel) = @"level"; + +/// The name of a level in a game (String). +///
+///     let params = [
+///       AnalyticsParameterLevelName : "room_1",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLevelName NS_SWIFT_NAME(AnalyticsParameterLevelName) = + @"level_name"; + +/// Location (String). The Google Place ID +/// that corresponds to the associated event. Alternatively, you can supply your own custom +/// Location ID. +///
+///     let params = [
+///       AnalyticsParameterLocation : "ChIJiyj437sx3YAR9kUWC8QkLzQ",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLocation NS_SWIFT_NAME(AnalyticsParameterLocation) = + @"location"; + +/// The location associated with the event. Preferred to be the Google +/// Place ID that corresponds to the +/// associated item but could be overridden to a custom location ID string.(String). +///
+///     let params = [
+///       AnalyticsParameterLocationID : "ChIJiyj437sx3YAR9kUWC8QkLzQ",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLocationID NS_SWIFT_NAME(AnalyticsParameterLocationID) = + @"location_id"; + +/// Marketing Tactic (String). Used to identify the targeting criteria applied to a specific +/// campaign. +///
+///     let params = [
+///       AnalyticsParameterMarketingTactic : "Remarketing",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterMarketingTactic + NS_SWIFT_NAME(AnalyticsParameterMarketingTactic) = @"marketing_tactic"; + +/// The advertising or marketing medium, for example: cpc, banner, email, push. Highly recommended +/// (String). +///
+///     let params = [
+///       AnalyticsParameterMedium : "email",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterMedium NS_SWIFT_NAME(AnalyticsParameterMedium) = @"medium"; + +/// A particular approach used in an operation; for example, "facebook" or "email" in the context +/// of a sign_up or login event. (String). +///
+///     let params = [
+///       AnalyticsParameterMethod : "google",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterMethod NS_SWIFT_NAME(AnalyticsParameterMethod) = @"method"; + +/// Number of nights staying at hotel (Int). +///
+///     let params = [
+///       AnalyticsParameterNumberOfNights : 3,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterNumberOfNights + NS_SWIFT_NAME(AnalyticsParameterNumberOfNights) = @"number_of_nights"; + +/// Number of passengers traveling (Int). +///
+///     let params = [
+///       AnalyticsParameterNumberOfPassengers : 11,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterNumberOfPassengers + NS_SWIFT_NAME(AnalyticsParameterNumberOfPassengers) = @"number_of_passengers"; + +/// Number of rooms for travel events (Int). +///
+///     let params = [
+///       AnalyticsParameterNumberOfRooms : 2,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterNumberOfRooms NS_SWIFT_NAME(AnalyticsParameterNumberOfRooms) = + @"number_of_rooms"; + +/// Flight or Travel origin (String). +///
+///     let params = [
+///       AnalyticsParameterOrigin : "Mountain View, CA",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterOrigin NS_SWIFT_NAME(AnalyticsParameterOrigin) = @"origin"; + +/// The chosen method of payment (String). +///
+///     let params = [
+///       AnalyticsParameterPaymentType : "Visa",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPaymentType NS_SWIFT_NAME(AnalyticsParameterPaymentType) = + @"payment_type"; + +/// Purchase price (Double). +///
+///     let params = [
+///       AnalyticsParameterPrice : 1.0,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $1.00 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPrice NS_SWIFT_NAME(AnalyticsParameterPrice) = @"price"; + +/// The ID of a product promotion (String). +///
+///     let params = [
+///       AnalyticsParameterPromotionID : "ABC123",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPromotionID NS_SWIFT_NAME(AnalyticsParameterPromotionID) = + @"promotion_id"; + +/// The name of a product promotion (String). +///
+///     let params = [
+///       AnalyticsParameterPromotionName : "Summer Sale",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPromotionName NS_SWIFT_NAME(AnalyticsParameterPromotionName) = + @"promotion_name"; + +/// Purchase quantity (Int). +///
+///     let params = [
+///       AnalyticsParameterQuantity : 1,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterQuantity NS_SWIFT_NAME(AnalyticsParameterQuantity) = + @"quantity"; + +/// Score in game (Int). +///
+///     let params = [
+///       AnalyticsParameterScore : 4200,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterScore NS_SWIFT_NAME(AnalyticsParameterScore) = @"score"; + +/// Current screen class, such as the class name of the UIViewController, logged with screen_view +/// event and added to every event (String). +///
+///     let params = [
+///       AnalyticsParameterScreenClass : "LoginViewController",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterScreenClass NS_SWIFT_NAME(AnalyticsParameterScreenClass) = + @"screen_class"; + +/// Current screen name, such as the name of the UIViewController, logged with screen_view event and +/// added to every event (String). +///
+///     let params = [
+///       AnalyticsParameterScreenName : "LoginView",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterScreenName NS_SWIFT_NAME(AnalyticsParameterScreenName) = + @"screen_name"; + +/// The search string/keywords used (String). +///
+///     let params = [
+///       AnalyticsParameterSearchTerm : "periodic table",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSearchTerm NS_SWIFT_NAME(AnalyticsParameterSearchTerm) = + @"search_term"; + +/// Shipping cost associated with a transaction (Double). +///
+///     let params = [
+///       AnalyticsParameterShipping : 5.99,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $5.99 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterShipping NS_SWIFT_NAME(AnalyticsParameterShipping) = + @"shipping"; + +/// The shipping tier (e.g. Ground, Air, Next-day) selected for delivery of the purchased item +/// (String). +///
+///     let params = [
+///       AnalyticsParameterShippingTier : "Ground",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterShippingTier NS_SWIFT_NAME(AnalyticsParameterShippingTier) = + @"shipping_tier"; + +/// The origin of your traffic, such as an Ad network (for example, google) or partner (urban +/// airship). Identify the advertiser, site, publication, etc. that is sending traffic to your +/// property. Highly recommended (String). +///
+///     let params = [
+///       AnalyticsParameterSource : "InMobi",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSource NS_SWIFT_NAME(AnalyticsParameterSource) = @"source"; + +/// Source Platform (String). Used to identify the platform responsible for directing traffic to a +/// given Analytics property (e.g., a buying platform where budgets, targeting criteria, etc. are +/// set, a platform for managing organic traffic data, etc.). +///
+///     let params = [
+///       AnalyticsParameterSourcePlatform : "sa360",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSourcePlatform NS_SWIFT_NAME(AnalyticsParameterSourcePlatform) = + @"source_platform"; + +/// The departure date, check-in date or rental start date for the item. This should be in +/// YYYY-MM-DD format (String). +///
+///     let params = [
+///       AnalyticsParameterStartDate : "2015-09-14",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterStartDate NS_SWIFT_NAME(AnalyticsParameterStartDate) = + @"start_date"; + +/// The result of an operation. Specify 1 to indicate success and 0 to indicate failure (Int). +///
+///     let params = [
+///       AnalyticsParameterSuccess : 1,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSuccess NS_SWIFT_NAME(AnalyticsParameterSuccess) = @"success"; + +/// Tax cost associated with a transaction (Double). +///
+///     let params = [
+///       AnalyticsParameterTax : 2.43,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $2.43 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTax NS_SWIFT_NAME(AnalyticsParameterTax) = @"tax"; + +/// If you're manually tagging keyword campaigns, you should use utm_term to specify the keyword +/// (String). +///
+///     let params = [
+///       AnalyticsParameterTerm : "game",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTerm NS_SWIFT_NAME(AnalyticsParameterTerm) = @"term"; + +/// The unique identifier of a transaction (String). +///
+///     let params = [
+///       AnalyticsParameterTransactionID : "T12345",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTransactionID NS_SWIFT_NAME(AnalyticsParameterTransactionID) = + @"transaction_id"; + +/// Travel class (String). +///
+///     let params = [
+///       AnalyticsParameterTravelClass : "business",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTravelClass NS_SWIFT_NAME(AnalyticsParameterTravelClass) = + @"travel_class"; + +/// A context-specific numeric value which is accumulated automatically for each event type. This is +/// a general purpose parameter that is useful for accumulating a key metric that pertains to an +/// event. Examples include revenue, distance, time and points. Value should be specified as Int or +/// Double. +/// Notes: Values for pre-defined currency-related events (such as @c AnalyticsEventAddToCart) +/// should be supplied using Double and must be accompanied by a @c AnalyticsParameterCurrency +/// parameter. The valid range of accumulated values is +/// [-9,223,372,036,854.77, 9,223,372,036,854.77]. Supplying a non-numeric value, omitting the +/// corresponding @c AnalyticsParameterCurrency parameter, or supplying an invalid +/// currency code for conversion events will cause that +/// conversion to be omitted from reporting. +///
+///     let params = [
+///       AnalyticsParameterValue : 3.99,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $3.99 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterValue NS_SWIFT_NAME(AnalyticsParameterValue) = @"value"; + +/// Name of virtual currency type (String). +///
+///     let params = [
+///       AnalyticsParameterVirtualCurrencyName : "virtual_currency_name",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterVirtualCurrencyName + NS_SWIFT_NAME(AnalyticsParameterVirtualCurrencyName) = @"virtual_currency_name"; diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h new file mode 100644 index 0000000..2442d8a --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h @@ -0,0 +1,28 @@ +/// @file FIRUserPropertyNames.h +/// +/// Predefined user property names. +/// +/// A UserProperty is an attribute that describes the app-user. By supplying UserProperties, you can +/// later analyze different behaviors of various segments of your userbase. You may supply up to 25 +/// unique UserProperties per app, and you can use the name and value of your choosing for each one. +/// UserProperty names can be up to 24 characters long, may only contain alphanumeric characters and +/// underscores ("_"), and must start with an alphabetic character. UserProperty values can be up to +/// 36 characters long. The "firebase_", "google_", and "ga_" prefixes are reserved and should not +/// be used. + +#import + +/// Indicates whether events logged by Google Analytics can be used to personalize ads for the user. +/// Set to "YES" to enable, or "NO" to disable. Default is enabled. See the +/// documentation for +/// more details and information about related settings. +/// +///
+///     Analytics.setUserProperty("NO", forName: AnalyticsUserPropertyAllowAdPersonalizationSignals)
+/// 
+static NSString *const kFIRUserPropertyAllowAdPersonalizationSignals + NS_SWIFT_NAME(AnalyticsUserPropertyAllowAdPersonalizationSignals) = @"allow_personalized_ads"; + +/// The method used to sign in. For example, "google", "facebook" or "twitter". +static NSString *const kFIRUserPropertySignUpMethod + NS_SWIFT_NAME(AnalyticsUserPropertySignUpMethod) = @"sign_up_method"; diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-umbrella.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-umbrella.h new file mode 100644 index 0000000..ad84fbb --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-umbrella.h @@ -0,0 +1,24 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "FIRAnalytics+AppDelegate.h" +#import "FIRAnalytics+Consent.h" +#import "FIRAnalytics+OnDevice.h" +#import "FIRAnalytics.h" +#import "FirebaseAnalytics.h" +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" + +FOUNDATION_EXPORT double FirebaseAnalyticsVersionNumber; +FOUNDATION_EXPORT const unsigned char FirebaseAnalyticsVersionString[]; + diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h new file mode 100644 index 0000000..351da20 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h @@ -0,0 +1,7 @@ +#import "FIRAnalytics+AppDelegate.h" +#import "FIRAnalytics+Consent.h" +#import "FIRAnalytics+OnDevice.h" +#import "FIRAnalytics.h" +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Info.plist b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Info.plist new file mode 100644 index 0000000..1674c5f --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleExecutable + FirebaseAnalytics + CFBundleIdentifier + com.firebase.Firebase-FirebaseAnalytics + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + FirebaseAnalytics + CFBundlePackageType + FMWK + CFBundleVersion + 10.11.0 + DTSDKName + iphonesimulator11.2 + + diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/module.modulemap b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/module.modulemap new file mode 100644 index 0000000..37eb24b --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/module.modulemap @@ -0,0 +1,12 @@ +framework module FirebaseAnalytics { +umbrella header "FirebaseAnalytics-umbrella.h" +export * +module * { export * } + link framework "Foundation" + link framework "Security" + link framework "SystemConfiguration" + link framework "UIKit" + link "c++" + link "sqlite3" + link "z" +} diff --git a/Pods/FirebaseAppCheckInterop/FirebaseAppCheck/Interop/FIRAppCheckInterop.h b/Pods/FirebaseAppCheckInterop/FirebaseAppCheck/Interop/FIRAppCheckInterop.h new file mode 100644 index 0000000..11ade09 --- /dev/null +++ b/Pods/FirebaseAppCheckInterop/FirebaseAppCheck/Interop/FIRAppCheckInterop.h @@ -0,0 +1,56 @@ +/* + * Copyright 2020 Google LLC + * + * 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 + +@protocol FIRAppCheckTokenResultInterop; + +NS_ASSUME_NONNULL_BEGIN + +NS_SWIFT_NAME(AppCheckTokenHandlerInterop) +typedef void (^FIRAppCheckTokenHandlerInterop)(id tokenResult); + +NS_SWIFT_NAME(AppCheckInterop) @protocol FIRAppCheckInterop + +/// Retrieve a cached or generate a new FAA Token. If forcingRefresh == YES always generates a new +/// token and updates the cache. +- (void)getTokenForcingRefresh:(BOOL)forcingRefresh + completion:(FIRAppCheckTokenHandlerInterop)handler + NS_SWIFT_NAME(getToken(forcingRefresh:completion:)); + +/// A notification with the specified name is sent to the default notification center +/// (`NotificationCenter.default`) each time a Firebase app check token is refreshed. +/// The user info dictionary contains `-[self notificationTokenKey]` and +/// `-[self notificationAppNameKey]` keys. +- (NSString *)tokenDidChangeNotificationName; + +/// `userInfo` key for the FAC token in a notification for `tokenDidChangeNotificationName`. +- (NSString *)notificationTokenKey; +/// `userInfo` key for the `FirebaseApp.name` in a notification for +/// `tokenDidChangeNotificationName`. +- (NSString *)notificationAppNameKey; + +// MARK: - Optional API + +@optional + +/// Retrieve a new limited-use Firebase App Check token +- (void)getLimitedUseTokenWithCompletion:(FIRAppCheckTokenHandlerInterop)handler + NS_SWIFT_NAME(getLimitedUseToken(completion:)); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAppCheckInterop/FirebaseAppCheck/Interop/FIRAppCheckTokenResultInterop.h b/Pods/FirebaseAppCheckInterop/FirebaseAppCheck/Interop/FIRAppCheckTokenResultInterop.h new file mode 100644 index 0000000..cb86a1b --- /dev/null +++ b/Pods/FirebaseAppCheckInterop/FirebaseAppCheck/Interop/FIRAppCheckTokenResultInterop.h @@ -0,0 +1,32 @@ +/* + * Copyright 2020 Google LLC + * + * 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 + +NS_ASSUME_NONNULL_BEGIN + +@protocol FIRAppCheckTokenResultInterop + +/// App Check token in the case of success or a dummy token in the case of a failure. +/// In general, the value of the token should always be set to the request header. +@property(nonatomic, readonly) NSString *token; + +/// A token fetch error in the case of a failure or `nil` in the case of success. +@property(nonatomic, readonly, nullable) NSError *error; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAppCheckInterop/FirebaseAppCheck/Interop/dummy.m b/Pods/FirebaseAppCheckInterop/FirebaseAppCheck/Interop/dummy.m new file mode 100644 index 0000000..2e503fe --- /dev/null +++ b/Pods/FirebaseAppCheckInterop/FirebaseAppCheck/Interop/dummy.m @@ -0,0 +1,17 @@ +/* + * Copyright 2022 Google LLC + * + * 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. + */ + +// Swift Package Manager needs at least one source file. diff --git a/Pods/FirebaseAppCheckInterop/LICENSE b/Pods/FirebaseAppCheckInterop/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/Pods/FirebaseAppCheckInterop/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/Pods/FirebaseAppCheckInterop/README.md b/Pods/FirebaseAppCheckInterop/README.md new file mode 100644 index 0000000..85a23bd --- /dev/null +++ b/Pods/FirebaseAppCheckInterop/README.md @@ -0,0 +1,281 @@ +

+ + + + + + + + +
+ + + + + + +

+ +# Firebase Apple Open Source Development + +This repository contains all Apple platform Firebase SDK source except FirebaseAnalytics. + +Firebase is an app development platform with tools to help you build, grow and +monetize your app. More information about Firebase can be found on the +[official Firebase website](https://firebase.google.com). + +## Installation + +See the subsections below for details about the different installation methods. Where +available, it's recommended to install any libraries with a `Swift` suffix to get the +best experience when writing your app in Swift. +1. [Standard pod install](#standard-pod-install) +1. [Swift Package Manager](#swift-package-manager) +1. [Installing from the GitHub repo](#installing-from-github) +1. [Experimental Carthage](#carthage-ios-only) + +### Standard pod install + +Go to +[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup). + +### Swift Package Manager + +Instructions for [Swift Package Manager](https://swift.org/package-manager/) support can be +found at [SwiftPackageManager](SwiftPackageManager.md) Markdown file. + +### Installing from GitHub + +These instructions can be used to access the Firebase repo at other branches, +tags, or commits. + +#### Background + +See +[the Podfile Syntax Reference](https://guides.cocoapods.org/syntax/podfile.html#pod) +for instructions and options about overriding pod source locations. + +#### Accessing Firebase Source Snapshots + +All of the official releases are tagged in this repo and available via CocoaPods. To access a local +source snapshot or unreleased branch, use Podfile directives like the following: + +To access FirebaseFirestore via a branch: +```ruby +pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master' +pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master' +``` + +To access FirebaseMessaging via a checked out version of the firebase-ios-sdk repo do: + +```ruby +pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk' +pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk' +``` + +### Carthage (iOS only) + +Instructions for the experimental Carthage distribution are at +[Carthage](Carthage.md). + +### Using Firebase from a Framework or a library + +[Using Firebase from a Framework or a library](docs/firebase_in_libraries.md) + +## Development + +To develop Firebase software in this repository, ensure that you have at least +the following software: + + * Xcode 14.1 (or later) + +CocoaPods is still the canonical way to develop, but much of the repo now supports +development with Swift Package Manager. + +### CocoaPods + +Install + * CocoaPods 1.10.0 (or later) + * [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +```ruby +pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios +``` + +Note: If the CocoaPods cache is out of date, you may need to run +`pod repo update` before the `pod gen` command. + +Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for +those platforms. Since 10.2, Xcode does not properly handle multi-platform +CocoaPods workspaces. + +Firestore has a self contained Xcode project. See +[Firestore/README](Firestore/README.md) Markdown file. + +#### Development for Catalyst +* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios` +* Check the Mac box in the App-iOS Build Settings +* Sign the App in the Settings Signing & Capabilities tab +* Click Pods in the Project Manager +* Add Signing to the iOS host app and unit test targets +* Select the Unit-unit scheme +* Run it to build and test + +Alternatively disable signing in each target: +* Go to Build Settings tab +* Click `+` +* Select `Add User-Defined Setting` +* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO` + +### Swift Package Manager +* To enable test schemes: `./scripts/setup_spm_tests.sh` +* `open Package.swift` or double click `Package.swift` in Finder. +* Xcode will open the project + * Choose a scheme for a library to build or test suite to run + * Choose a target platform by selecting the run destination along with the scheme + +### Adding a New Firebase Pod + +See [AddNewPod](AddNewPod.md) Markdown file. + +### Managing Headers and Imports + +See [HeadersImports](HeadersImports.md) Markdown file. + +### Code Formatting + +To ensure that the code is formatted consistently, run the script +[./scripts/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/master/scripts/check.sh) +before creating a PR. + +GitHub Actions will verify that any code changes are done in a style compliant +way. Install `clang-format` and `mint`: + +```console +brew install clang-format@16 +brew install mint +``` + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +### Running Sample Apps +In order to run the sample apps and integration tests, you'll need a valid +`GoogleService-Info.plist` file. The Firebase Xcode project contains dummy plist +files without real values, but can be replaced with real plist files. To get your own +`GoogleService-Info.plist` files: + +1. Go to the [Firebase Console](https://console.firebase.google.com/) +2. Create a new Firebase project, if you don't already have one +3. For each sample app you want to test, create a new Firebase app with the sample app's bundle +identifier (e.g. `com.google.Database-Example`) +4. Download the resulting `GoogleService-Info.plist` and add it to the Xcode project. + +### Coverage Report Generation + +See [scripts/code_coverage_report/README](scripts/code_coverage_report/README.md) Markdown file. + +## Specific Component Instructions +See the sections below for any special instructions for those components. + +### Firebase Auth + +If you're doing specific Firebase Auth development, see +[the Auth Sample README](FirebaseAuth/Tests/Sample/README.md) for instructions about +building and running the FirebaseAuth pod along with various samples and tests. + +### Firebase Database + +The Firebase Database Integration tests can be run against a locally running Database Emulator +or against a production instance. + +To run against a local emulator instance, invoke `./scripts/run_database_emulator.sh start` before +running the integration test. + +To run against a production instance, provide a valid GoogleServices-Info.plist and copy it to +`FirebaseDatabase/Tests/Resources/GoogleService-Info.plist`. Your Security Rule must be set to +[public](https://firebase.google.com/docs/database/security/quickstart) while your tests are +running. + +### Firebase Performance Monitoring +If you're doing specific Firebase Performance Monitoring development, see +[the Performance README](FirebasePerformance/README.md) for instructions about building the SDK +and [the Performance TestApp README](FirebasePerformance/Tests/TestApp/README.md) for instructions about +integrating Performance with the dev test App. + +### Firebase Storage + +To run the Storage Integration tests, follow the instructions in +[StorageIntegration.swift](FirebaseStorage/Tests/Integration/StorageIntegration.swift). + +#### Push Notifications + +Push notifications can only be delivered to specially provisioned App IDs in the developer portal. +In order to actually test receiving push notifications, you will need to: + +1. Change the bundle identifier of the sample app to something you own in your Apple Developer +account, and enable that App ID for push notifications. +2. You'll also need to +[upload your APNs Provider Authentication Key or certificate to the +Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs) +at **Project Settings > Cloud Messaging > [Your Firebase App]**. +3. Ensure your iOS device is added to your Apple Developer portal as a test device. + +#### iOS Simulator + +The iOS Simulator cannot register for remote notifications, and will not receive push notifications. +In order to receive push notifications, you'll have to follow the steps above and run the app on a +physical device. + +## Building with Firebase on Apple platforms + +Firebase 8.9.0 introduced official beta support for macOS, Catalyst, and tvOS. watchOS continues +to be community supported. Thanks to community contributions for many of the multi-platform PRs. + +At this time, most of Firebase's products are available across Apple platforms. There are still +a few gaps, especially on watchOS. For details about the current support matrix, see +[this chart](https://firebase.google.com/docs/ios/learn-more#firebase_library_support_by_platform) +in Firebase's documentation. + +### watchOS +Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and +work on watchOS. See the [Independent Watch App Sample](Example/watchOSSample). + +Keep in mind that watchOS is not officially supported by Firebase. While we can catch basic unit +test issues with GitHub Actions, there may be some changes where the SDK no longer works as expected +on watchOS. If you encounter this, please +[file an issue](https://github.com/firebase/firebase-ios-sdk/issues). + +During app setup in the console, you may get to a step that mentions something like "Checking if the +app has communicated with our servers". This relies on Analytics and will not work on watchOS. +**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected. + +#### Additional Crashlytics Notes +* watchOS has limited support. Due to watchOS restrictions, mach exceptions and signal crashes are +not recorded. (Crashes in SwiftUI are generated as mach exceptions, so will not be recorded) + +## Combine +Thanks to contributions from the community, _FirebaseCombineSwift_ contains support for Apple's Combine +framework. This module is currently under development, and not yet supported for use in production +environments. Fore more details, please refer to the [docs](FirebaseCombineSwift/README.md). + +## Roadmap + +See [Roadmap](ROADMAP.md) for more about the Firebase Apple SDK Open Source +plans and directions. + +## Contributing + +See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase +Apple SDK. + +## License + +The contents of this repository are licensed under the +[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). + +Your use of Firebase is governed by the +[Terms of Service for Firebase Services](https://firebase.google.com/terms/). diff --git a/Pods/FirebaseAuth/FirebaseAppCheck/Interop/FIRAppCheckInterop.h b/Pods/FirebaseAuth/FirebaseAppCheck/Interop/FIRAppCheckInterop.h new file mode 100644 index 0000000..11ade09 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAppCheck/Interop/FIRAppCheckInterop.h @@ -0,0 +1,56 @@ +/* + * Copyright 2020 Google LLC + * + * 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 + +@protocol FIRAppCheckTokenResultInterop; + +NS_ASSUME_NONNULL_BEGIN + +NS_SWIFT_NAME(AppCheckTokenHandlerInterop) +typedef void (^FIRAppCheckTokenHandlerInterop)(id tokenResult); + +NS_SWIFT_NAME(AppCheckInterop) @protocol FIRAppCheckInterop + +/// Retrieve a cached or generate a new FAA Token. If forcingRefresh == YES always generates a new +/// token and updates the cache. +- (void)getTokenForcingRefresh:(BOOL)forcingRefresh + completion:(FIRAppCheckTokenHandlerInterop)handler + NS_SWIFT_NAME(getToken(forcingRefresh:completion:)); + +/// A notification with the specified name is sent to the default notification center +/// (`NotificationCenter.default`) each time a Firebase app check token is refreshed. +/// The user info dictionary contains `-[self notificationTokenKey]` and +/// `-[self notificationAppNameKey]` keys. +- (NSString *)tokenDidChangeNotificationName; + +/// `userInfo` key for the FAC token in a notification for `tokenDidChangeNotificationName`. +- (NSString *)notificationTokenKey; +/// `userInfo` key for the `FirebaseApp.name` in a notification for +/// `tokenDidChangeNotificationName`. +- (NSString *)notificationAppNameKey; + +// MARK: - Optional API + +@optional + +/// Retrieve a new limited-use Firebase App Check token +- (void)getLimitedUseTokenWithCompletion:(FIRAppCheckTokenHandlerInterop)handler + NS_SWIFT_NAME(getLimitedUseToken(completion:)); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAppCheck/Interop/FIRAppCheckTokenResultInterop.h b/Pods/FirebaseAuth/FirebaseAppCheck/Interop/FIRAppCheckTokenResultInterop.h new file mode 100644 index 0000000..cb86a1b --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAppCheck/Interop/FIRAppCheckTokenResultInterop.h @@ -0,0 +1,32 @@ +/* + * Copyright 2020 Google LLC + * + * 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 + +NS_ASSUME_NONNULL_BEGIN + +@protocol FIRAppCheckTokenResultInterop + +/// App Check token in the case of success or a dummy token in the case of a failure. +/// In general, the value of the token should always be set to the request header. +@property(nonatomic, readonly) NSString *token; + +/// A token fetch error in the case of a failure or `nil` in the case of success. +@property(nonatomic, readonly, nullable) NSError *error; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/CHANGELOG.md b/Pods/FirebaseAuth/FirebaseAuth/CHANGELOG.md new file mode 100644 index 0000000..73d567f --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/CHANGELOG.md @@ -0,0 +1,363 @@ +# 10.8.0 +- [added] Added Firebase App Check support to Firebase Auth. (#11056) +- [added] Added Sign in with Apple token revocation support. (#9906) + +# 10.7.0 +- [added] Added an API for developers to pass the fullName from the Sign in with Apple credential to Firebase. (#10068) + +# 10.6.0 +- [fixed] Fixed a bug where user is created in a specific tenant although tenantID was not specified. (#10748) +- [fixed] Fixed a bug where the resolver exposed in MFA is not associated to the correct app. (#10690) + +# 10.5.0 +- [fixed] Use team player ID, game player ID and fetchItems for signature verification. (#10441) +- [fixed] Prevent keychain pop-up when accessing Auth keychain in a Mac + app. Note that using Firebase Auth in a Mac app requires that the app + is signed with a provisioning profile that has the Keychain Sharing + capability enabled (see Firebase 9.6.0 release notes). (#10582) + +# 10.4.0 +- [fixed] Fix secure coding bugs in MFA. (#10632) +- [fixed] Added handling of error returned from a blocking cloud function. (#10628) + +# 10.2.0 +- [fixed] Fix a bug where the linking/reauth flows errors are not caught. (#10267) +- [fixed] Force to recaptcha verification flow for phone auth in simulators. (#10426) + +# 10.1.0 +- [fixed] Fix a bug where multi factor phone number returns `NULL`. (#10296) + +# 9.5.0 +- [fixed] Fix a bug where phone multi factor id is not correctly retrieved. (#10061) + +# 9.2.0 +- [fixed] Catch keychain errors instead of using the `isProtectedDataAvailable` API for handling prewarming issue. (#9869) + +# 9.0.0 +- [fixed] **Breaking change:** Fixed an ObjC-to-Swift API conversion error where `getStoredUser(forAccessGroup:)` returned a non-optional type. This change is breaking for Swift users only (#8599). +- [fixed] Fixed an iOS 15 keychain access issue related to prewarming. (#8695) + +# 8.14.0 +- [added] Started to collect the Firebase user agent for Firebase Auth. (#9066) + +# 8.12.0 +- [added] Added documentation note and error logging to `getStoredUser(forAccessGroup:)` regarding tvOS keychain sharing issues. (#8878) +- [fixed] Partial fix for expired ID token issue. (#6521) + +# 8.11.0 +- [changed] Added a `X-Firebase-GMPID` header to network requests. (#9046) +- [fixed] Added multi-tenancy support to generic OAuth providers. (#7990) +- [fixed] macOS Extension access to Shared Keychain by adding `kSecUseDataProtectionKeychain` recommended key. (#6876) + +# 8.9.0 +- [changed] Improved error logging. (#8704) +- [added] Added MFA support for email link sign-in. (#8705) + +# 8.8.0 +- [fixed] Fall back to reCAPTCHA for phone auth app verification if the push notification is not received before the timeout. (#8653) + +# 8.6.0 +- [fixed] Annotated platform-level availability using `API_UNAVAILABLE` instead of conditionally compiling certain methods with `#if` directives. (#8451) + +# 8.5.0 +- [fixed] Fixed an analyze issue introduced in Xcode 12.5. (#8411) + +# 8.2.0 +- [fixed] Fixed analyze issues introduced in Xcode 12.5. (#8210) +- [fixed] Fixed a bug in the link with email link, Game Center, and phone auth flows. (#8196) + +# 8.0.0 +- [fixed] Fixed a crash that occurred when assigning auth settings. (#7670) + +# 7.8.0 +- [fixed] Fixed auth state sharing during first app launch. (#7472) + +# 7.6.0 +- [fixed] Auth emulator now works across the local network. (#7350) +- [fixed] Fixed incorrect import for watchOS (#7425) + +# 7.4.0 +- [fixed] Check if the reverse client ID is configured as a custom URL scheme before setting it as the callback scheme. (#7211) +- [added] Add ability to sync auth state across devices. (#6924) +- [fixed] Add multi-tenancy support for email link sign-in. (#7246) + +# 7.3.0 +- [fixed] Catalyst browser issue with `verifyPhoneNumber` API. (#7049) + +# 7.1.0 +- [fixed] Fixed completion handler issue in `application(_:didReceiveRemoteNotification:fetchCompletionHandler:)` method. (#6863) + +# 7.0.0 +- [removed] Remove deprecated APIs `dataForKey`,`fetchProvidersForEmail:completion`, `signInAndRetrieveDataWithCredential:completion`, `reauthenticateAndRetrieveDataWithCredential:completion`, `linkAndRetrieveDataWithCredential:completion`. (#6607) +- [added] Add support for the auth emulator. (#6624) +- [changed] The global variables `FirebaseAuthVersionNum` and `FirebaseAuthVersionStr` are deleted. + `FirebaseVersion()` or `FIRFirebaseVersion()` should be used instead. + +# 6.9.1 +- [fixed] Internal source documentation. (#6371) + +# 6.9.0 +- [added] Added support for multi-tenancy (#6142). +- [added] Added basic watchOS support. (#4621) +- [changed] Improved Xcode completion of public API completion handlers in Swift. (#6283) + +# 6.8.0 +- [fixed] Fix bug where multiple keychain entries would result in user persistence failure. (#5906) +- [changed] Added support for using GOOGLE_APP_ID in generic IDP and phone auth reCAPTCHA fallback flows. (#6121) + +# 6.7.1 +- [fixed] Fixed a multithreaded memory access issue on iOS. (#5979) + +# 6.7.0 +- [changed] Functionally neutral source reorganization for preliminary Swift Package Manager support. (#5856) + +# 6.5.3 +- [changed] Remove unused mfa request field "mfa_provider" (#5397) +- [fixed] Suppress deprecation warnings when targeting iOS versions up to iOS 13. (#5437) + +# 6.5.2 +- [fixed] Handle calls to `useUserAccessGroup` soon after configure. (#4175) + +# 6.5.1 +- [changed] File structure changes. No functional change. +- [changed] Code formatting changes. + +# 6.5.0 +- [feature] Added support of Multi-factor Authentication. (#4823) + +# 6.4.1 +- [fixed] Added support of UISceneDelegate for URL redirect. (#4380) +- [fixed] Fixed rawNonce in encoder. (#4337) + +# 6.4.0 +- [feature] Added support for Sign-in with Apple. (#4183) + +# 6.3.1 +- [fixed] Removed usage of a deprecated property on iOS 13. (#4066) + +# 6.3.0 +- [added] Added methods allowing developers to link and reauthenticate with federated providers. (#3971) + +# 6.2.3 +- [fixed] Make sure the first valid auth domain is retrieved. (#3493) +- [fixed] Add assertion for Facebook generic IDP flow. (#3208) +- [fixed] Build for Catalyst. (#3549) + +# 6.2.2 +- [fixed] Fixed an issue where unlinking an email auth provider raised an incorrect error stating the account was not linked to an email auth provider. (#3405) +- [changed] Renamed internal Keychain classes. (#3473) + +# 6.2.1 +- [added] Add new client error MISSING_CLIENT_IDENTIFIER. (#3341) + +# 6.2.0 +- [feature] Expose `secret` of OAuth credential in public header. (#3089) +- [fixed] Fix a keychain issue where API key is incorrectly set. (#3239) + +# 6.1.2 +- [fixed] Fix line limits and linter warnings in public documentation. (#3139) + +# 6.1.1 +- [fixed] Fix an issue where a user can't link with email provider by email link. (#3030) + +# 6.1.0 +- [added] Add support of web.app as an auth domain. (#2959) +- [fixed] Fix an issue where the return type of `getStoredUserForAccessGroup:error:` is nonnull. (#2879) + +# 6.0.0 +- [added] Add support of single sign on. (#2684) +- [deprecated] Deprecate `reauthenticateAndRetrieveDataWithCredential:completion:`, `signInAndRetrieveDataWithCredential:completion:`, `linkAndRetrieveDataWithCredential:completion:`, `fetchProvidersForEmail:completion:`. (#2723, #2756) +- [added] Returned oauth secret token in Generic IDP sign-in for Twitter. (#2663) +- [removed] Remove pendingToken from public API. (#2676) +- [changed] `GULAppDelegateSwizzler` is used for the app delegate swizzling. (#2591) + +# 5.4.2 +- [added] Support new error code ERROR_INVALID_PROVIDER_ID. (#2629) + +# 5.4.1 +- [deprecated] Deprecate Microsoft and Yahoo OAuth Provider ID (#2517) +- [fixed] Fix an issue where an exception was thrown when linking OAuth credentials. (#2521) +- [fixed] Fix an issue where a wrong error was thrown when handling error with + FEDERATED_USER_ID_ALREADY_LINKED. (#2522) + +# 5.4.0 +- [added] Add support of Generic IDP (#2405). + +# 5.3.0 +- [changed] Use the new registerInternalLibrary API to register with FirebaseCore. (#2137) + +# 5.2.0 +- [added] Add support of Game Center sign in (#2127). + +# 5.1.0 +- [added] Add support of custom FDL domain link (#2121). + +# 5.0.5 +- [changed] Restore SafariServices framework dependency (#2002). + +# 5.0.4 +- [fixed] Fix analyzer issues (#1740). + +# 5.0.3 +- [added] Add `FIRAuthErrorCodeMalformedJWT`, which is raised on JWT token parsing. + failures during auth operations (#1436). +- [changed] Migrate to use FirebaseAuthInterop interfaces to access FirebaseAuth (#1501). + +# 5.0.2 +- [fixed] Fix an issue where JWT date timestamps weren't parsed correctly. (#1319) +- [fixed] Fix an issue where anonymous accounts weren't correctly promoted to + non-anonymous when linked with passwordless email auth accounts. (#1383) +- [fixed] Fix an exception from using an invalidated NSURLSession. (#1261) +- [fixed] Fix a data race issue caught by the sanitizer. (#1446) + +# 5.0.1 +- [fixed] Restore 4.x level of support for extensions (#1357). + +# 5.0.0 +- [added] Adds APIs for phone Auth testing to bypass the verification flow (#1192). +- [feature] Changes the callback block signature for sign in and create user methods + to provide an AuthDataResult that includes the user and user info (#1123, #1186). +- [changed] Removes GoogleToolboxForMac dependency (#1175). +- [removed] Removes miscellaneous deprecated APIs (#1188, #1200). + +# 4.6.1 +- [fixed] Fixes crash which occurred when certain Firebase IDTokens were being parsed (#1076). + +# 4.6.0 +- [added] Adds `getIDTokenResultWithCompletion:` and `getIDTokenResultForcingRefresh:completion:` APIs which + call back with an AuthTokenResult object. The Auth token result object contains the ID token JWT string and other properties associated with the token including the decoded available payload claims (#1004). +- [added] Adds the `updateCurrentUser:completion:` API which sets the currentUser on the calling Auth instance to the provided user object (#1018). +- [added] Adds client-side validation to prevent setting `handleCodeInApp` to false when performing + email-link authentication. If `handleCodeInApp` is set to false an invalid argument exception + is thrown (#931). +- [added] Adds support for passing the deep link (which is embedded in the sign-in link sent via email) to the + `signInWithEmail:link:completion:` and `isSignInWithEmailLink:` methods during an + email/link sign-in flow (#1023). + +# 4.5.0 +- [added] Adds new API which provides a way to determine the sign-in methods associated with an + email address. +- [added] Adds new API which allows authentication using only an email link (Passwordless Authentication + with email link). + +# 4.4.4 +- [fixed] Addresses CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF warnings that surface in newer versions of + Xcode and CocoaPods. +- [fixed] Improves FIRUser documentation with clear message explaining when Firebase Auth attempts to validate + users and what happens when an invalidated user is detected (#694) . + +# 4.4.3 +- [added] Adds an explicit dependency on CoreGraphics from Firebase Auth. + +# 4.4.2 +- [fixed] Fixes bug where the FIRAuthResult object returned following a Phone Number authentication + always contained a nil FIRAdditionalUserInfo object. Now the FIRAdditionalUserInfo object is + never nil and its newUser field is populated correctly. + +# 4.4.0 +- [fixed] Adds new APIs which return an AuthDataResult object after successfully creating an + Email/Password user, signing in anonymously, signing in with Email/Password and signing + in with Custom Token. The AuthDataResult object contains the new user and additional + information pertaining to the new user. + +# 4.3.2 +- [fixed] Improves error handling for the phone number sign-in reCAPTCHA flow. +- [fixed] Improves error handling for phone number linking flow. +- [fixed] Fixes issue where after linking an anonymous user to a phone number the user remained + anonymous. + +# 4.3.1 +- [changed] Internal clean up. + +# 4.3.0 +- [added] Provides account creation and last sign-in dates as metadata to the user + object. +- [added] Returns more descriptive errors for some error cases of the phone number + sign-in reCAPTCHA flow. +- [fixed] Fixes an issue that invalid users were not automatically signed out earlier. +- [fixed] Fixes an issue that ID token listeners were not fired in some cases. + +# 4.2.1 +- [fixed] Fixes a threading issue in phone number auth that completion block was not + executed on the main thread in some error cases. + +# 4.2.0 +- [added] Adds new phone number verification API which makes use of an intelligent reCAPTCHA to verify the application. + +# 4.1.1 +- [changed] Improves some method documentation in headers. + +# 4.1.0 +- [added] Allows the app to handle continue URL natively, e.g., from password reset + email. +- [added] Allows the app to set language code, e.g., for sending password reset email. +- [fixed] Fixes an issue that user's phone number did not persist on client. +- [fixed] Fixes an issue that recover email action code type was reported as unknown. +- [feature] Improves app start-up time by moving initialization off from the main + thread. +- [fixed] Better reports missing email error when creating a new password user. +- [fixed] Changes console message logging levels to be more consistent with other + Firebase products on the iOS platform. + +# 4.0.0 +- [added] Adds Phone Number Authentication. +- [added] Adds support for generic OAuth2 identity providers. +- [added] Adds methods that return additional user data from identity providers if + available when authenticating users. +- [added] Improves session management by automatically refreshing tokens if possible + and signing out users if the session is detected invalidated, for example, + after the user changed password or deleted account from another device. +- [fixed] Fixes an issue that reauthentication creates new user account if the user + credential is valid but does not match the currently signed in user. +- [fixed] Fixes an issue that the "password" provider is not immediately listed on the + client side after adding a password to an account. +- [changed] Changes factory methods to return non-null FIRAuth instances or raises an + exception, instead of returning nullable instances. +- [changed] Changes auth state change listener to only be triggered when the user changes. +- [added] Adds a new listener which is triggered whenever the ID token is changed. +- [changed] Switches ERROR_EMAIL_ALREADY_IN_USE to + ERROR_ACCOUNT_EXISTS_WITH_DIFFERENT_CREDENTIAL when the email used in the + signInWithCredential: call is already in use by another account. +- [deprecated] Deprecates FIREmailPasswordAuthProvider in favor of FIREmailAuthProvider. +- [deprecated] Deprecates getTokenWithCompletion in favor of getIDTokenWithCompletion on + FIRUser. +- [fixed] Changes Swift API names to better align with Swift convention. + +# 3.1.1 +- [added] Allows handling of additional errors when sending OOB action emails. The + server can respond with the following new error messages: + INVALID_MESSAGE_PAYLOAD,INVALID_SENDER and INVALID_RECIPIENT_EMAIL. +- [fixed] Removes incorrect reference to FIRAuthErrorCodeCredentialTooOld in FIRUser.h. +- [added] Provides additional error information from server if available. + +# 3.1.0 +- [added] Adds FIRAuth methods that enable the app to follow up with user actions + delivered by email, such as verifying email address or reset password. +- [fixed] No longer applies the keychain workaround introduced in v3.0.5 on iOS 10.2 + simulator or above since the issue has been fixed. +- [fixed] Fixes nullability compilation warnings when used in Swift. +- [fixed] Better reports missing password error. + +# 3.0.6 +- [changed] Switches to depend on open sourced GoogleToolboxForMac and GTMSessionFetcher. +- [fixed] Improves logging of keychain error when initializing. + +# 3.0.5 +- [fixed] Works around a keychain issue in iOS 10 simulator. +- [fixed] Reports the correct error for invalid email when signing in with email and + password. + +# 3.0.4 +- [fixed] Fixes a race condition bug that could crash the app with an exception from + NSURLSession on iOS 9. + +# 3.0.3 +- [added] Adds documentation for all possible errors returned by each method. +- [fixed] Improves error handling and messages for a variety of error conditions. +- [fixed] Whether or not an user is considered anonymous is now consistent with other + platforms. +- [changed] A saved signed in user is now siloed between different Firebase projects + within the same app. + +# 3.0.2 +- Initial public release. diff --git a/Pods/FirebaseAuth/FirebaseAuth/Interop/FIRAuthInterop.h b/Pods/FirebaseAuth/FirebaseAuth/Interop/FIRAuthInterop.h new file mode 100644 index 0000000..f710e39 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Interop/FIRAuthInterop.h @@ -0,0 +1,47 @@ +/* + * 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 FIRAuthInterop_h +#define FIRAuthInterop_h + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRTokenCallback + @brief The type of block which gets called when a token is ready. + */ +typedef void (^FIRTokenCallback)(NSString *_Nullable token, NSError *_Nullable error) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/// Common methods for Auth interoperability. +NS_SWIFT_NAME(AuthInterop) +@protocol FIRAuthInterop + +/// Retrieves the Firebase authentication token, possibly refreshing it if it has expired. +- (void)getTokenForcingRefresh:(BOOL)forceRefresh + withCallback: + (void (^)(NSString *_Nullable token, NSError *_Nullable error))callback + NS_SWIFT_NAME(getToken(forcingRefresh:completion:)); + +/// Get the current Auth user's UID. Returns nil if there is no user signed in. +- (nullable NSString *)getUserID; + +@end + +NS_ASSUME_NONNULL_END + +#endif /* FIRAuthInterop_h */ diff --git a/Pods/FirebaseAuth/FirebaseAuth/README.md b/Pods/FirebaseAuth/FirebaseAuth/README.md new file mode 100644 index 0000000..84818f8 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/README.md @@ -0,0 +1,17 @@ +# Firebase Auth for iOS + +Firebase Auth enables apps to easily support multiple authentication options +for their end users. + +Please visit [our developer site](https://firebase.google.com/docs/auth/) for +integration instructions, documentation, support information, and terms of +service. + +# Firebase Auth Development + +Example/Auth contains a set of samples and tests that integrate with +FirebaseAuth. + +The unit tests run without any additional configuration along with the rest of +Firebase. See [Tests/Sample/README.md](Tests/Sample/README.md) for +information about setting up, running, and testing the samples. diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRActionCodeSettings.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRActionCodeSettings.m new file mode 100644 index 0000000..b1671e6 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRActionCodeSettings.m @@ -0,0 +1,45 @@ +/* + * 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/LICENSE2.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 "FirebaseAuth/Sources/Public/FirebaseAuth/FIRActionCodeSettings.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRActionCodeSettings + +- (instancetype)init { + self = [super init]; + if (self) { + _iOSBundleID = [NSBundle mainBundle].bundleIdentifier; + } + return self; +} + +- (void)setIOSBundleID:(NSString *)iOSBundleID { + _iOSBundleID = [iOSBundleID copy]; +} + +- (void)setAndroidPackageName:(NSString *)androidPackageName + installIfNotAvailable:(BOOL)installIfNotAvailable + minimumVersion:(nullable NSString *)minimumVersion { + _androidPackageName = [androidPackageName copy]; + _androidInstallIfNotAvailable = installIfNotAvailable; + _androidMinimumVersion = [minimumVersion copy]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuth.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuth.m new file mode 100644 index 0000000..7efc3d1 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuth.m @@ -0,0 +1,2372 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Auth/FIRAuth_Internal.h" + +#if __has_include() +#import +#endif + +#import +#import +#import +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FirebaseAuth.h" +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" + +#import "FirebaseAppCheck/Interop/FIRAppCheckInterop.h" +#import "FirebaseAuth/Sources/Auth/FIRAuthDataResult_Internal.h" +#import "FirebaseAuth/Sources/Auth/FIRAuthDispatcher.h" +#import "FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.h" +#import "FirebaseAuth/Sources/Auth/FIRAuthOperationType.h" +#import "FirebaseAuth/Sources/AuthProvider/Email/FIREmailPasswordAuthCredential.h" +#import "FirebaseAuth/Sources/AuthProvider/FIRAuthCredential_Internal.h" +#import "FirebaseAuth/Sources/AuthProvider/GameCenter/FIRGameCenterAuthCredential.h" +#import "FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthCredential_Internal.h" +#import "FirebaseAuth/Sources/Backend/FIRAuthBackend.h" +#import "FirebaseAuth/Sources/Backend/FIRAuthRequestConfiguration.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRRevokeTokenRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRRevokeTokenResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberResponse.h" +#import "FirebaseAuth/Sources/Storage/FIRAuthKeychainServices.h" +#import "FirebaseAuth/Sources/SystemService/FIRAuthStoredUserManager.h" +#import "FirebaseAuth/Sources/User/FIRAdditionalUserInfo_Internal.h" +#import "FirebaseAuth/Sources/User/FIRUser_Internal.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthWebUtils.h" + +#if TARGET_OS_IOS +#import "FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthCredential_Internal.h" +#import "FirebaseAuth/Sources/SystemService/FIRAuthAPNSToken.h" +#import "FirebaseAuth/Sources/SystemService/FIRAuthAPNSTokenManager.h" +#import "FirebaseAuth/Sources/SystemService/FIRAuthAppCredentialManager.h" +#import "FirebaseAuth/Sources/SystemService/FIRAuthNotificationManager.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthURLPresenter.h" +#endif + +NS_ASSUME_NONNULL_BEGIN + +#pragma mark-- Logger Service String. +FIRLoggerService kFIRLoggerAuth = @"[FirebaseAuth]"; + +#pragma mark - Constants + +#if defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0 +const NSNotificationName FIRAuthStateDidChangeNotification = @"FIRAuthStateDidChangeNotification"; +#else +NSString *const FIRAuthStateDidChangeNotification = @"FIRAuthStateDidChangeNotification"; +#endif // defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0 + +/** @var kMaxWaitTimeForBackoff + @brief The maximum wait time before attempting to retry auto refreshing tokens after a failed + attempt. + @remarks This is the upper limit (in seconds) of the exponential backoff used for retrying + token refresh. + */ +static NSTimeInterval kMaxWaitTimeForBackoff = 16 * 60; + +/** @var kTokenRefreshHeadStart + @brief The amount of time before the token expires that proactive refresh should be attempted. + */ +NSTimeInterval kTokenRefreshHeadStart = 5 * 60; + +/** @var kUserKey + @brief Key of user stored in the keychain. Prefixed with a Firebase app name. + */ +static NSString *const kUserKey = @"%@_firebase_user"; + +/** @var kMissingEmailInvalidParameterExceptionReason + @brief The reason for @c invalidParameterException when the email used to initiate password + reset is nil. + */ +static NSString *const kMissingEmailInvalidParameterExceptionReason = + @"The email used to initiate password reset cannot be nil."; + +/** @var kHandleCodeInAppFalseExceptionReason + @brief The reason for @c invalidParameterException when the handleCodeInApp parameter is false + on the ActionCodeSettings object used to send the link for Email-link Authentication. + */ +static NSString *const kHandleCodeInAppFalseExceptionReason = + @"You must set handleCodeInApp in your ActionCodeSettings to true for Email-link " + "Authentication."; + +static NSString *const kInvalidEmailSignInLinkExceptionMessage = + @"The link provided is not valid for email/link sign-in. Please check the link by calling " + "isSignInWithEmailLink:link: on Auth before attempting to use it for email/link sign-in."; + +/** @var kPasswordResetRequestType + @brief The action code type value for resetting password in the check action code response. + */ +static NSString *const kPasswordResetRequestType = @"PASSWORD_RESET"; + +/** @var kVerifyEmailRequestType + @brief The action code type value for verifying email in the check action code response. + */ +static NSString *const kVerifyEmailRequestType = @"VERIFY_EMAIL"; + +/** @var kRecoverEmailRequestType + @brief The action code type value for recovering email in the check action code response. + */ +static NSString *const kRecoverEmailRequestType = @"RECOVER_EMAIL"; + +/** @var kEmailLinkSignInRequestType + @brief The action code type value for an email sign-in link in the check action code response. +*/ +static NSString *const kEmailLinkSignInRequestType = @"EMAIL_SIGNIN"; + +/** @var kVerifyAndChangeEmailRequestType + @brief The action code type value for verifying and changing email in the check action code + response. + */ +static NSString *const kVerifyAndChangeEmailRequestType = @"VERIFY_AND_CHANGE_EMAIL"; + +/** @var kRevertSecondFactorAdditionRequestType + @brief The action code type value for reverting second factor addition in the check action code + response. + */ +static NSString *const kRevertSecondFactorAdditionRequestType = @"REVERT_SECOND_FACTOR_ADDITION"; + +/** @var kMissingPasswordReason + @brief The reason why the @c FIRAuthErrorCodeWeakPassword error is thrown. + @remarks This error message will be localized in the future. + */ +static NSString *const kMissingPasswordReason = @"Missing Password"; + +/** @var gKeychainServiceNameForAppName + @brief A map from Firebase app name to keychain service names. + @remarks This map is needed for looking up the keychain service name after the FIRApp instance + is deleted, to remove the associated keychain item. Accessing should occur within a + @syncronized([FIRAuth class]) context. + */ +static NSMutableDictionary *gKeychainServiceNameForAppName; + +#pragma mark - FIRActionCodeInfo + +@interface FIRActionCodeInfo () + +/** + @brief The operation being performed. + */ +@property(nonatomic, readwrite) FIRActionCodeOperation operation; + +/** @property email + @brief The email address to which the code was sent. The new email address in the case of + FIRActionCodeOperationRecoverEmail. + */ +@property(nonatomic, nullable, readwrite, copy) NSString *email; + +/** @property previousEmail + @brief The current email address in the case of FIRActionCodeOperationRecoverEmail. + */ +@property(nonatomic, nullable, readwrite, copy) NSString *previousEmail; + +#if TARGET_OS_IOS +/** @property multiFactorInfo + @brief The MultiFactorInfo object of the second factor to be reverted in case of + FIRActionCodeMultiFactorInfoKey. + */ +@property(nonatomic, nullable, readwrite) FIRMultiFactorInfo *multiFactorInfo; +#endif + +@end + +@implementation FIRActionCodeInfo + +- (instancetype)initWithOperation:(FIRActionCodeOperation)operation + email:(NSString *)email + newEmail:(nullable NSString *)newEmail { + self = [super init]; + if (self) { + _operation = operation; + if (newEmail) { + _email = [newEmail copy]; + _previousEmail = [email copy]; + } else { + _email = [email copy]; + } + } + return self; +} + +/** @fn actionCodeOperationForRequestType: + @brief Returns the corresponding operation type per provided request type string. + @param requestType Request type returned in in the server response. + @return The corresponding FIRActionCodeOperation for the supplied request type. + */ ++ (FIRActionCodeOperation)actionCodeOperationForRequestType:(NSString *)requestType { + if ([requestType isEqualToString:kPasswordResetRequestType]) { + return FIRActionCodeOperationPasswordReset; + } + if ([requestType isEqualToString:kVerifyEmailRequestType]) { + return FIRActionCodeOperationVerifyEmail; + } + if ([requestType isEqualToString:kRecoverEmailRequestType]) { + return FIRActionCodeOperationRecoverEmail; + } + if ([requestType isEqualToString:kEmailLinkSignInRequestType]) { + return FIRActionCodeOperationEmailLink; + } + if ([requestType isEqualToString:kVerifyAndChangeEmailRequestType]) { + return FIRActionCodeOperationVerifyAndChangeEmail; + } + if ([requestType isEqualToString:kRevertSecondFactorAdditionRequestType]) { + return FIRActionCodeOperationRevertSecondFactorAddition; + } + return FIRActionCodeOperationUnknown; +} + +@end + +#pragma mark - FIRActionCodeURL + +@implementation FIRActionCodeURL + +/** @fn FIRAuthParseURL:NSString + @brief Parses an incoming URL into all available query items. + @param urlString The url to be parsed. + @return A dictionary of available query items in the target URL. + */ ++ (NSDictionary *)parseURL:(NSString *)urlString { + NSString *linkURL = [NSURLComponents componentsWithString:urlString].query; + if (!linkURL) { + return @{}; + } + NSArray *URLComponents = [linkURL componentsSeparatedByString:@"&"]; + NSMutableDictionary *queryItems = + [[NSMutableDictionary alloc] initWithCapacity:URLComponents.count]; + for (NSString *component in URLComponents) { + NSRange equalRange = [component rangeOfString:@"="]; + if (equalRange.location != NSNotFound) { + NSString *queryItemKey = + [[component substringToIndex:equalRange.location] stringByRemovingPercentEncoding]; + NSString *queryItemValue = + [[component substringFromIndex:equalRange.location + 1] stringByRemovingPercentEncoding]; + if (queryItemKey && queryItemValue) { + queryItems[queryItemKey] = queryItemValue; + } + } + } + return queryItems; +} + ++ (nullable instancetype)actionCodeURLWithLink:(NSString *)link { + NSDictionary *queryItems = [FIRActionCodeURL parseURL:link]; + if (!queryItems.count) { + NSURLComponents *urlComponents = [NSURLComponents componentsWithString:link]; + queryItems = [FIRActionCodeURL parseURL:urlComponents.query]; + } + if (!queryItems.count) { + return nil; + } + NSString *APIKey = queryItems[@"apiKey"]; + NSString *actionCode = queryItems[@"oobCode"]; + NSString *continueURLString = queryItems[@"continueUrl"]; + NSString *languageCode = queryItems[@"languageCode"]; + NSString *mode = queryItems[@"mode"]; + NSString *tenantID = queryItems[@"tenantID"]; + return [[FIRActionCodeURL alloc] initWithAPIKey:APIKey + actionCode:actionCode + continueURLString:continueURLString + languageCode:languageCode + mode:mode + tenantID:tenantID]; +} + +- (nullable instancetype)initWithAPIKey:(NSString *)APIKey + actionCode:(NSString *)actionCode + continueURLString:(NSString *)continueURLString + languageCode:(NSString *)languageCode + mode:(NSString *)mode + tenantID:(NSString *)tenantID { + self = [super init]; + if (self) { + _APIKey = APIKey; + _operation = [FIRActionCodeInfo actionCodeOperationForRequestType:mode]; + _code = actionCode; + _continueURL = [NSURL URLWithString:continueURLString]; + _languageCode = languageCode; + } + return self; +} + +@end + +#pragma mark - FIRAuth + +#if TARGET_OS_IOS +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 +@interface FIRAuth () +#else +@interface FIRAuth () +#endif +#else +@interface FIRAuth () +#endif + +/** @property firebaseAppId + @brief The Firebase app ID. + */ +@property(nonatomic, copy, readonly) NSString *firebaseAppId; + +/** @property additionalFrameworkMarker + @brief Additional framework marker that will be added as part of the header of every request. + */ +@property(nonatomic, copy, nullable) NSString *additionalFrameworkMarker; + +/** @property storedUserManager + @brief The stored user manager. + */ +@property(nonatomic, strong, nullable) FIRAuthStoredUserManager *storedUserManager; + +/** @fn initWithApp: + @brief Creates a @c FIRAuth instance associated with the provided @c FIRApp instance. + @param app The application to associate the auth instance with. + */ +- (instancetype)initWithApp:(FIRApp *)app; + +@end + +@implementation FIRAuth { + /** @var _currentUser + @brief The current user. + */ + FIRUser *_currentUser; + + /** @var _firebaseAppName + @brief The Firebase app name. + */ + NSString *_firebaseAppName; + + /** @var _listenerHandles + @brief Handles returned from @c NSNotificationCenter for blocks which are "auth state did + change" notification listeners. + @remarks Mutations should occur within a @syncronized(self) context. + */ + NSMutableArray *_listenerHandles; + + /** @var _keychainServices + @brief The keychain service. + */ + FIRAuthKeychainServices *_keychainServices; + + /** @var _lastNotifiedUserToken + @brief The user access (ID) token used last time for posting auth state changed notification. + */ + NSString *_lastNotifiedUserToken; + + /** @var _autoRefreshTokens + @brief This flag denotes whether or not tokens should be automatically refreshed. + @remarks Will only be set to @YES if the another Firebase service is included (additionally to + Firebase Auth). + */ + BOOL _autoRefreshTokens; + + /** @var _autoRefreshScheduled + @brief Whether or not token auto-refresh is currently scheduled. + */ + BOOL _autoRefreshScheduled; + + /** @var _isAppInBackground + @brief A flag that is set to YES if the app is put in the background and no when the app is + returned to the foreground. + */ + BOOL _isAppInBackground; + + /** @var _applicationDidBecomeActiveObserver + @brief An opaque object to act as the observer for UIApplicationDidBecomeActiveNotification. + */ + id _applicationDidBecomeActiveObserver; + + /** @var _applicationDidBecomeActiveObserver + @brief An opaque object to act as the observer for + UIApplicationDidEnterBackgroundNotification. + */ + id _applicationDidEnterBackgroundObserver; + + /** @var _protectedDataDidBecomeAvailableObserver + @brief An opaque object to act as the observer for + UIApplicationProtectedDataDidBecomeAvailable. + */ + id _protectedDataDidBecomeAvailableObserver; +} + ++ (void)load { + [FIRApp registerInternalLibrary:(Class)self withName:@"fire-auth"]; +} + ++ (void)initialize { + gKeychainServiceNameForAppName = [[NSMutableDictionary alloc] init]; +} + ++ (FIRAuth *)auth { + FIRApp *defaultApp = [FIRApp defaultApp]; + if (!defaultApp) { + [NSException + raise:NSInternalInconsistencyException + format:@"The default FirebaseApp instance must be configured before the default Auth" + @"instance can be initialized. One way to ensure this is to call " + @"`FirebaseApp.configure()` in the App Delegate's " + @"`application(_:didFinishLaunchingWithOptions:)` (or the `@main` struct's " + @"initializer in SwiftUI)."]; + } + return [self authWithApp:defaultApp]; +} + ++ (FIRAuth *)authWithApp:(FIRApp *)app { + // Get the instance of Auth from the container, which will create or return the cached instance + // associated with this app. + id auth = FIR_COMPONENT(FIRAuthInterop, app.container); + return (FIRAuth *)auth; +} + +- (instancetype)initWithApp:(FIRApp *)app { + [FIRAuth setKeychainServiceNameForApp:app]; + self = [self initWithAPIKey:app.options.APIKey + appName:app.name + appID:app.options.googleAppID + heartbeatLogger:app.heartbeatLogger + appCheck:FIR_COMPONENT(FIRAppCheckInterop, app.container)]; + if (self) { + _app = app; +#if TARGET_OS_IOS + _authURLPresenter = [[FIRAuthURLPresenter alloc] init]; +#endif + } + return self; +} + +- (nullable instancetype)initWithAPIKey:(NSString *)APIKey + appName:(NSString *)appName + appID:(NSString *)appID { + return [self initWithAPIKey:APIKey appName:appName appID:appID heartbeatLogger:nil appCheck:nil]; +} + +- (nullable instancetype)initWithAPIKey:(NSString *)APIKey + appName:(NSString *)appName + appID:(NSString *)appID + heartbeatLogger:(nullable id)heartbeatLogger + appCheck:(nullable id)appCheck { + self = [super init]; + if (self) { + _listenerHandles = [NSMutableArray array]; + _requestConfiguration = [[FIRAuthRequestConfiguration alloc] initWithAPIKey:APIKey + appID:appID + auth:self + heartbeatLogger:heartbeatLogger + appCheck:appCheck]; + _firebaseAppName = [appName copy]; +#if TARGET_OS_IOS + _settings = [[FIRAuthSettings alloc] init]; + + [GULAppDelegateSwizzler proxyOriginalDelegateIncludingAPNSMethods]; + [GULSceneDelegateSwizzler proxyOriginalSceneDelegate]; +#endif // TARGET_OS_IOS + + [self protectedDataInitialization]; + } + return self; +} + +- (void)protectedDataInitialization { + // Continue with the rest of initialization in the work thread. + __weak FIRAuth *weakSelf = self; + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + // Load current user from Keychain. + FIRAuth *strongSelf = weakSelf; + if (!strongSelf) { + return; + } + NSString *keychainServiceName = + [FIRAuth keychainServiceNameForAppName:strongSelf->_firebaseAppName]; + if (keychainServiceName) { + strongSelf->_keychainServices = + [[FIRAuthKeychainServices alloc] initWithService:keychainServiceName]; + strongSelf.storedUserManager = + [[FIRAuthStoredUserManager alloc] initWithServiceName:keychainServiceName]; + } + + NSString *storedUserAccessGroup = [strongSelf.storedUserManager getStoredUserAccessGroup]; + if (!storedUserAccessGroup) { + FIRUser *user; + NSError *error; + if ([strongSelf getUser:&user error:&error]) { + strongSelf.tenantID = user.tenantID; + [strongSelf updateCurrentUser:user byForce:NO savingToDisk:NO error:&error]; + self->_lastNotifiedUserToken = user.rawAccessToken; + } else { +#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_MACCATALYST + if (error.code == FIRAuthErrorCodeKeychainError) { + // If there's a keychain error, assume it is due to the keychain being accessed + // before the device is unlocked as a result of prewarming, and listen for the + // UIApplicationProtectedDataDidBecomeAvailable notification. + [strongSelf addProtectedDataDidBecomeAvailableObserver]; + } +#endif // TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_MACCATALYST + FIRLogError(kFIRLoggerAuth, @"I-AUT000001", + @"Error loading saved user when starting up: %@", error); + } + } else { + NSError *error; + [strongSelf internalUseUserAccessGroup:storedUserAccessGroup error:&error]; + if (error) { +#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_MACCATALYST + if (error.code == FIRAuthErrorCodeKeychainError) { + // If there's a keychain error, assume it is due to the keychain being accessed + // before the device is unlocked as a result of prewarming, and listen for the + // UIApplicationProtectedDataDidBecomeAvailable notification. + [strongSelf addProtectedDataDidBecomeAvailableObserver]; + } +#endif // TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_MACCATALYST + FIRLogError(kFIRLoggerAuth, @"I-AUT000001", + @"Error loading saved user when starting up: %@", error); + } + } + +#if TARGET_OS_IOS + static Class applicationClass = nil; + // iOS App extensions should not call [UIApplication sharedApplication], even if UIApplication + // responds to it. + if (![GULAppEnvironmentUtil isAppExtension]) { + Class cls = NSClassFromString(@"UIApplication"); + if (cls && [cls respondsToSelector:@selector(sharedApplication)]) { + applicationClass = cls; + } + } + UIApplication *application = [applicationClass sharedApplication]; + + if (application) { + // Initialize for phone number auth. + strongSelf->_tokenManager = [[FIRAuthAPNSTokenManager alloc] initWithApplication:application]; + + strongSelf->_appCredentialManager = + [[FIRAuthAppCredentialManager alloc] initWithKeychain:strongSelf->_keychainServices]; + + strongSelf->_notificationManager = [[FIRAuthNotificationManager alloc] + initWithApplication:application + appCredentialManager:strongSelf->_appCredentialManager]; + } + + [GULAppDelegateSwizzler registerAppDelegateInterceptor:strongSelf]; +#if ((TARGET_OS_IOS || TARGET_OS_TV) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= 130000)) + if (@available(iOS 13, tvos 13, *)) { + [GULSceneDelegateSwizzler registerSceneDelegateInterceptor:strongSelf]; + } +#endif // ((TARGET_OS_IOS || TARGET_OS_TV) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= 130000)) +#endif // TARGET_OS_IOS + }); +} + +#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_MACCATALYST +- (void)addProtectedDataDidBecomeAvailableObserver { + __weak FIRAuth *weakSelf = self; + self->_protectedDataDidBecomeAvailableObserver = [[NSNotificationCenter defaultCenter] + addObserverForName:UIApplicationProtectedDataDidBecomeAvailable + object:nil + queue:nil + usingBlock:^(NSNotification *notification) { + FIRAuth *strongSelf = weakSelf; + [[NSNotificationCenter defaultCenter] + removeObserver:strongSelf->_protectedDataDidBecomeAvailableObserver + name:UIApplicationProtectedDataDidBecomeAvailable + object:nil]; + [strongSelf protectedDataInitialization]; + }]; +} +#endif // TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_MACCATALYST + +- (void)dealloc { + @synchronized(self) { + NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter]; + while (_listenerHandles.count != 0) { + FIRAuthStateDidChangeListenerHandle handleToRemove = _listenerHandles.lastObject; + [defaultCenter removeObserver:handleToRemove]; + [_listenerHandles removeLastObject]; + } + +#if TARGET_OS_IOS + [defaultCenter removeObserver:_applicationDidBecomeActiveObserver + name:UIApplicationDidBecomeActiveNotification + object:nil]; + [defaultCenter removeObserver:_applicationDidEnterBackgroundObserver + name:UIApplicationDidEnterBackgroundNotification + object:nil]; +#endif + } +} + +#pragma mark - Public API + +- (nullable FIRUser *)currentUser { + __block FIRUser *result; + dispatch_sync(FIRAuthGlobalWorkQueue(), ^{ + result = self->_currentUser; + }); + return result; +} + +- (void)signInWithProvider:(id)provider + UIDelegate:(nullable id)UIDelegate + completion:(nullable FIRAuthDataResultCallback)completion { +#if TARGET_OS_IOS + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + FIRAuthDataResultCallback decoratedCallback = + [self signInFlowAuthDataResultCallbackByDecoratingCallback:completion]; + [provider getCredentialWithUIDelegate:UIDelegate + completion:^(FIRAuthCredential *_Nullable credential, + NSError *_Nullable error) { + if (error) { + decoratedCallback(nil, error); + return; + } + [self + internalSignInAndRetrieveDataWithCredential:credential + isReauthentication:NO + callback:decoratedCallback]; + }]; + }); +#endif // TARGET_OS_IOS +} + +- (void)fetchSignInMethodsForEmail:(nonnull NSString *)email + completion:(nullable FIRSignInMethodQueryCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + FIRCreateAuthURIRequest *request = + [[FIRCreateAuthURIRequest alloc] initWithIdentifier:email + continueURI:@"http://www.google.com/" + requestConfiguration:self->_requestConfiguration]; + [FIRAuthBackend + createAuthURI:request + callback:^(FIRCreateAuthURIResponse *_Nullable response, NSError *_Nullable error) { + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(response.signinMethods, error); + }); + } + }]; + }); +} + +- (void)signInWithEmail:(NSString *)email + password:(NSString *)password + completion:(nullable FIRAuthDataResultCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + FIRAuthDataResultCallback decoratedCallback = + [self signInFlowAuthDataResultCallbackByDecoratingCallback:completion]; + [self internalSignInAndRetrieveDataWithEmail:email + password:password + completion:^(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error) { + decoratedCallback(authResult, error); + }]; + }); +} + +- (void)signInWithEmail:(NSString *)email + link:(NSString *)link + completion:(nullable FIRAuthDataResultCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + FIRAuthDataResultCallback decoratedCallback = + [self signInFlowAuthDataResultCallbackByDecoratingCallback:completion]; + FIREmailPasswordAuthCredential *credential = + [[FIREmailPasswordAuthCredential alloc] initWithEmail:email link:link]; + [self internalSignInAndRetrieveDataWithCredential:credential + isReauthentication:NO + callback:^(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error) { + decoratedCallback(authResult, error); + }]; + }); +} + +/** @fn signInWithEmail:password:callback: + @brief Signs in using an email address and password. + @param email The user's email address. + @param password The user's password. + @param callback A block which is invoked when the sign in finishes (or is cancelled.) Invoked + asynchronously on the global auth work queue in the future. + @remarks This is the internal counterpart of this method, which uses a callback that does not + update the current user. + */ +- (void)signInWithEmail:(NSString *)email + password:(NSString *)password + callback:(FIRAuthResultCallback)callback { + FIRVerifyPasswordRequest *request = + [[FIRVerifyPasswordRequest alloc] initWithEmail:email + password:password + requestConfiguration:_requestConfiguration]; + + if (![request.password length]) { + callback(nil, [FIRAuthErrorUtils wrongPasswordErrorWithMessage:nil]); + return; + } + [FIRAuthBackend + verifyPassword:request + callback:^(FIRVerifyPasswordResponse *_Nullable response, NSError *_Nullable error) { + if (error) { + callback(nil, error); + return; + } + [self completeSignInWithAccessToken:response.IDToken + accessTokenExpirationDate:response.approximateExpirationDate + refreshToken:response.refreshToken + anonymous:NO + callback:callback]; + }]; +} + +/** @fn internalSignInAndRetrieveDataWithEmail:password:callback: + @brief Signs in using an email address and password. + @param email The user's email address. + @param password The user's password. + @param completion A block which is invoked when the sign in finishes (or is cancelled.) Invoked + asynchronously on the global auth work queue in the future. + @remarks This is the internal counterpart of this method, which uses a callback that does not + update the current user. + */ +- (void)internalSignInAndRetrieveDataWithEmail:(NSString *)email + password:(NSString *)password + completion:(FIRAuthDataResultCallback)completion { + FIREmailPasswordAuthCredential *credential = + [[FIREmailPasswordAuthCredential alloc] initWithEmail:email password:password]; + [self internalSignInAndRetrieveDataWithCredential:credential + isReauthentication:NO + callback:completion]; +} + +/** @fn signInAndRetrieveDataWithGameCenterCredential:callback: + @brief Signs in using a game center credential. + @param credential The Game Center Auth Credential used to sign in. + @param callback A block which is invoked when the sign in finished (or is cancelled). Invoked + asynchronously on the global auth work queue in the future. + */ +- (void)signInAndRetrieveDataWithGameCenterCredential:(FIRGameCenterAuthCredential *)credential + callback:(FIRAuthDataResultCallback)callback { + FIRSignInWithGameCenterRequest *request = + [[FIRSignInWithGameCenterRequest alloc] initWithPlayerID:credential.playerID + teamPlayerID:credential.teamPlayerID + gamePlayerID:credential.gamePlayerID + publicKeyURL:credential.publicKeyURL + signature:credential.signature + salt:credential.salt + timestamp:credential.timestamp + displayName:credential.displayName + requestConfiguration:_requestConfiguration]; + [FIRAuthBackend + signInWithGameCenter:request + callback:^(FIRSignInWithGameCenterResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + if (callback) { + callback(nil, error); + } + return; + } + + [self + completeSignInWithAccessToken:response.IDToken + accessTokenExpirationDate:response.approximateExpirationDate + refreshToken:response.refreshToken + anonymous:NO + callback:^(FIRUser *_Nullable user, + NSError *_Nullable error) { + if (error && callback) { + callback(nil, error); + return; + } + FIRAdditionalUserInfo *additionalUserInfo = + [[FIRAdditionalUserInfo alloc] + initWithProviderID: + FIRGameCenterAuthProviderID + profile:nil + username:nil + isNewUser:response.isNewUser]; + FIRAuthDataResult *result = + user ? [[FIRAuthDataResult alloc] + initWithUser:user + additionalUserInfo:additionalUserInfo] + : nil; + if (callback) { + callback(result, error); + } + }]; + }]; +} + +/** @fn internalSignInAndRetrieveDataWithEmail:link:completion: + @brief Signs in using an email and email sign-in link. + @param email The user's email address. + @param link The email sign-in link. + @param callback A block which is invoked when the sign in finishes (or is cancelled.) Invoked + asynchronously on the global auth work queue in the future. + */ +- (void)internalSignInAndRetrieveDataWithEmail:(nonnull NSString *)email + link:(nonnull NSString *)link + callback:(nullable FIRAuthDataResultCallback)callback { + if (![self isSignInWithEmailLink:link]) { + [FIRAuthExceptionUtils + raiseInvalidParameterExceptionWithReason:kInvalidEmailSignInLinkExceptionMessage]; + return; + } + NSDictionary *queryItems = [FIRAuthWebUtils parseURL:link]; + if (![queryItems count]) { + NSURLComponents *urlComponents = [NSURLComponents componentsWithString:link]; + queryItems = [FIRAuthWebUtils parseURL:urlComponents.query]; + } + NSString *actionCode = queryItems[@"oobCode"]; + + FIREmailLinkSignInRequest *request = + [[FIREmailLinkSignInRequest alloc] initWithEmail:email + oobCode:actionCode + requestConfiguration:_requestConfiguration]; + + [FIRAuthBackend + emailLinkSignin:request + callback:^(FIREmailLinkSignInResponse *_Nullable response, NSError *_Nullable error) { + if (error) { + if (callback) { + callback(nil, error); + } + return; + } + [self completeSignInWithAccessToken:response.IDToken + accessTokenExpirationDate:response.approximateExpirationDate + refreshToken:response.refreshToken + anonymous:NO + callback:^(FIRUser *_Nullable user, + NSError *_Nullable error) { + if (error && callback) { + callback(nil, error); + return; + } + FIRAdditionalUserInfo *additionalUserInfo = + [[FIRAdditionalUserInfo alloc] + initWithProviderID:FIREmailAuthProviderID + profile:nil + username:nil + isNewUser:response.isNewUser]; + FIRAuthDataResult *result = + user ? [[FIRAuthDataResult alloc] + initWithUser:user + additionalUserInfo:additionalUserInfo] + : nil; + if (callback) { + callback(result, error); + } + }]; + }]; +} + +- (void)signInWithCredential:(FIRAuthCredential *)credential + completion:(nullable FIRAuthDataResultCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + FIRAuthDataResultCallback callback = + [self signInFlowAuthDataResultCallbackByDecoratingCallback:completion]; + [self internalSignInAndRetrieveDataWithCredential:credential + isReauthentication:NO + callback:callback]; + }); +} + +- (void)internalSignInWithCredential:(FIRAuthCredential *)credential + callback:(FIRAuthResultCallback)callback { + [self internalSignInAndRetrieveDataWithCredential:credential + isReauthentication:NO + callback:^(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error) { + callback(authResult.user, error); + }]; +} + +- (void)internalSignInAndRetrieveDataWithCredential:(FIRAuthCredential *)credential + isReauthentication:(BOOL)isReauthentication + callback:(nullable FIRAuthDataResultCallback)callback { + if ([credential isKindOfClass:[FIREmailPasswordAuthCredential class]]) { + // Special case for email/password credentials + FIREmailPasswordAuthCredential *emailPasswordCredential = + (FIREmailPasswordAuthCredential *)credential; + + if (emailPasswordCredential.link) { + // Email link sign in + [self internalSignInAndRetrieveDataWithEmail:emailPasswordCredential.email + link:emailPasswordCredential.link + callback:callback]; + } else { + // Email password sign in + FIRAuthResultCallback completeEmailSignIn = + ^(FIRUser *_Nullable user, NSError *_Nullable error) { + if (callback) { + if (error) { + callback(nil, error); + return; + } + FIRAdditionalUserInfo *additionalUserInfo = + [[FIRAdditionalUserInfo alloc] initWithProviderID:FIREmailAuthProviderID + profile:nil + username:nil + isNewUser:NO]; + FIRAuthDataResult *result = + user ? [[FIRAuthDataResult alloc] initWithUser:user + additionalUserInfo:additionalUserInfo] + : nil; + callback(result, error); + } + }; + + [self signInWithEmail:emailPasswordCredential.email + password:emailPasswordCredential.password + callback:completeEmailSignIn]; + } + return; + } + + if ([credential isKindOfClass:[FIRGameCenterAuthCredential class]]) { + // Special case for Game Center credentials. + [self signInAndRetrieveDataWithGameCenterCredential:(FIRGameCenterAuthCredential *)credential + callback:callback]; + return; + } + +#if TARGET_OS_IOS + if ([credential isKindOfClass:[FIRPhoneAuthCredential class]]) { + // Special case for phone auth credentials + FIRPhoneAuthCredential *phoneCredential = (FIRPhoneAuthCredential *)credential; + FIRAuthOperationType operation = + isReauthentication ? FIRAuthOperationTypeReauth : FIRAuthOperationTypeSignUpOrSignIn; + [self + signInWithPhoneCredential:phoneCredential + operation:operation + callback:^(FIRVerifyPhoneNumberResponse *_Nullable response, + NSError *_Nullable error) { + if (callback) { + if (error) { + callback(nil, error); + return; + } + + [self + completeSignInWithAccessToken:response.IDToken + accessTokenExpirationDate:response.approximateExpirationDate + refreshToken:response.refreshToken + anonymous:NO + callback:^(FIRUser *_Nullable user, + NSError *_Nullable error) { + if (error && callback) { + callback(nil, error); + return; + } + FIRAdditionalUserInfo *additionalUserInfo = + [[FIRAdditionalUserInfo alloc] + initWithProviderID: + FIRPhoneAuthProviderID + profile:nil + username:nil + isNewUser:response + .isNewUser]; + FIRAuthDataResult *result = + user ? [[FIRAuthDataResult alloc] + initWithUser:user + additionalUserInfo: + additionalUserInfo] + : nil; + if (callback) { + callback(result, error); + } + }]; + } + }]; + return; + } +#endif + FIRVerifyAssertionRequest *request = + [[FIRVerifyAssertionRequest alloc] initWithProviderID:credential.provider + requestConfiguration:_requestConfiguration]; + request.autoCreate = !isReauthentication; + [credential prepareVerifyAssertionRequest:request]; + [FIRAuthBackend + verifyAssertion:request + callback:^(FIRVerifyAssertionResponse *response, NSError *error) { + if (error) { + if (callback) { + callback(nil, error); + } + return; + } + + if (response.needConfirmation) { + if (callback) { + NSString *email = response.email; + FIROAuthCredential *credential = + [[FIROAuthCredential alloc] initWithVerifyAssertionResponse:response]; + callback(nil, + [FIRAuthErrorUtils + accountExistsWithDifferentCredentialErrorWithEmail:email + updatedCredential:credential]); + } + return; + } + + if (!response.providerID.length) { + if (callback) { + callback(nil, [FIRAuthErrorUtils + unexpectedResponseWithDeserializedResponse:response]); + } + return; + } + [self + completeSignInWithAccessToken:response.IDToken + accessTokenExpirationDate:response.approximateExpirationDate + refreshToken:response.refreshToken + anonymous:NO + callback:^(FIRUser *_Nullable user, + NSError *_Nullable error) { + if (callback) { + if (error) { + callback(nil, error); + return; + } + FIRAdditionalUserInfo *additionalUserInfo = + [FIRAdditionalUserInfo + userInfoWithVerifyAssertionResponse:response]; + FIROAuthCredential *updatedOAuthCredential = + [[FIROAuthCredential alloc] + initWithVerifyAssertionResponse:response]; + FIRAuthDataResult *result = + user + ? [[FIRAuthDataResult alloc] + initWithUser:user + additionalUserInfo:additionalUserInfo + credential:updatedOAuthCredential] + : nil; + callback(result, error); + } + }]; + }]; +} + +- (void)signInAnonymouslyWithCompletion:(nullable FIRAuthDataResultCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + FIRAuthDataResultCallback decoratedCallback = + [self signInFlowAuthDataResultCallbackByDecoratingCallback:completion]; + if (self->_currentUser.anonymous) { + FIRAuthDataResult *result = [[FIRAuthDataResult alloc] initWithUser:self->_currentUser + additionalUserInfo:nil]; + decoratedCallback(result, nil); + return; + } + [self internalSignInAnonymouslyWithCompletion:^(FIRSignUpNewUserResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + decoratedCallback(nil, error); + return; + } + [self completeSignInWithAccessToken:response.IDToken + accessTokenExpirationDate:response.approximateExpirationDate + refreshToken:response.refreshToken + anonymous:YES + callback:^(FIRUser *_Nullable user, NSError *_Nullable error) { + if (error) { + decoratedCallback(nil, error); + return; + } + FIRAdditionalUserInfo *additionalUserInfo = + [[FIRAdditionalUserInfo alloc] initWithProviderID:nil + profile:nil + username:nil + isNewUser:YES]; + FIRAuthDataResult *authDataResult = + user ? [[FIRAuthDataResult alloc] + initWithUser:user + additionalUserInfo:additionalUserInfo] + : nil; + decoratedCallback(authDataResult, error); + }]; + }]; + }); +} + +- (void)signInWithCustomToken:(NSString *)token + completion:(nullable FIRAuthDataResultCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + FIRAuthDataResultCallback decoratedCallback = + [self signInFlowAuthDataResultCallbackByDecoratingCallback:completion]; + [self internalSignInAndRetrieveDataWithCustomToken:token + completion:^(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error) { + decoratedCallback(authResult, error); + }]; + }); +} + +- (void)createUserWithEmail:(NSString *)email + password:(NSString *)password + completion:(nullable FIRAuthDataResultCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + FIRAuthDataResultCallback decoratedCallback = + [self signInFlowAuthDataResultCallbackByDecoratingCallback:completion]; + [self internalCreateUserWithEmail:email + password:password + completion:^(FIRSignUpNewUserResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + decoratedCallback(nil, error); + return; + } + [self + completeSignInWithAccessToken:response.IDToken + accessTokenExpirationDate:response.approximateExpirationDate + refreshToken:response.refreshToken + anonymous:NO + callback:^(FIRUser *_Nullable user, + NSError *_Nullable error) { + if (error) { + decoratedCallback(nil, error); + return; + } + FIRAdditionalUserInfo *additionalUserInfo = + [[FIRAdditionalUserInfo alloc] + initWithProviderID: + FIREmailAuthProviderID + profile:nil + username:nil + isNewUser:YES]; + FIRAuthDataResult *authDataResult = + user ? [[FIRAuthDataResult alloc] + initWithUser:user + additionalUserInfo: + additionalUserInfo] + : nil; + decoratedCallback(authDataResult, error); + }]; + }]; + }); +} + +- (void)confirmPasswordResetWithCode:(NSString *)code + newPassword:(NSString *)newPassword + completion:(FIRConfirmPasswordResetCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + FIRResetPasswordRequest *request = + [[FIRResetPasswordRequest alloc] initWithOobCode:code + newPassword:newPassword + requestConfiguration:self->_requestConfiguration]; + [FIRAuthBackend + resetPassword:request + callback:^(FIRResetPasswordResponse *_Nullable response, NSError *_Nullable error) { + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + if (error) { + completion(error); + return; + } + completion(nil); + }); + } + }]; + }); +} + +- (void)checkActionCode:(NSString *)code completion:(FIRCheckActionCodeCallBack)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + FIRResetPasswordRequest *request = + [[FIRResetPasswordRequest alloc] initWithOobCode:code + newPassword:nil + requestConfiguration:self->_requestConfiguration]; + [FIRAuthBackend + resetPassword:request + callback:^(FIRResetPasswordResponse *_Nullable response, NSError *_Nullable error) { + if (completion) { + if (error) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(nil, error); + }); + return; + } + FIRActionCodeOperation operation = + [FIRActionCodeInfo actionCodeOperationForRequestType:response.requestType]; + FIRActionCodeInfo *actionCodeInfo = + [[FIRActionCodeInfo alloc] initWithOperation:operation + email:response.email + newEmail:response.verifiedEmail]; + dispatch_async(dispatch_get_main_queue(), ^{ + completion(actionCodeInfo, nil); + }); + } + }]; + }); +} + +- (void)verifyPasswordResetCode:(NSString *)code + completion:(FIRVerifyPasswordResetCodeCallback)completion { + [self checkActionCode:code + completion:^(FIRActionCodeInfo *_Nullable info, NSError *_Nullable error) { + if (completion) { + if (error) { + completion(nil, error); + return; + } + completion(info.email, nil); + } + }]; +} + +- (void)applyActionCode:(NSString *)code completion:(FIRApplyActionCodeCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + FIRSetAccountInfoRequest *request = + [[FIRSetAccountInfoRequest alloc] initWithRequestConfiguration:self->_requestConfiguration]; + request.OOBCode = code; + [FIRAuthBackend + setAccountInfo:request + callback:^(FIRSetAccountInfoResponse *_Nullable response, NSError *_Nullable error) { + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(error); + }); + } + }]; + }); +} + +- (void)sendPasswordResetWithEmail:(NSString *)email + completion:(nullable FIRSendPasswordResetCallback)completion { + [self sendPasswordResetWithNullableActionCodeSettings:nil email:email completion:completion]; +} + +- (void)sendPasswordResetWithEmail:(NSString *)email + actionCodeSettings:(FIRActionCodeSettings *)actionCodeSettings + completion:(nullable FIRSendPasswordResetCallback)completion { + [self sendPasswordResetWithNullableActionCodeSettings:actionCodeSettings + email:email + completion:completion]; +} + +/** @fn sendPasswordResetWithNullableActionCodeSettings:actionCodeSetting:email:completion: + @brief Initiates a password reset for the given email address and @FIRActionCodeSettings object. + + @param actionCodeSettings Optionally, An @c FIRActionCodeSettings object containing settings + related to the handling action codes. + @param email The email address of the user. + @param completion Optionally; a block which is invoked when the request finishes. Invoked + asynchronously on the main thread in the future. + */ +- (void)sendPasswordResetWithNullableActionCodeSettings: + (nullable FIRActionCodeSettings *)actionCodeSettings + email:(NSString *)email + completion: + (nullable FIRSendPasswordResetCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + if (!email) { + [FIRAuthExceptionUtils + raiseInvalidParameterExceptionWithReason:kMissingEmailInvalidParameterExceptionReason]; + return; + } + FIRGetOOBConfirmationCodeRequest *request = [FIRGetOOBConfirmationCodeRequest + passwordResetRequestWithEmail:email + actionCodeSettings:actionCodeSettings + requestConfiguration:self->_requestConfiguration]; + [FIRAuthBackend getOOBConfirmationCode:request + callback:^(FIRGetOOBConfirmationCodeResponse *_Nullable response, + NSError *_Nullable error) { + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(error); + }); + } + }]; + }); +} + +- (void)sendSignInLinkToEmail:(nonnull NSString *)email + actionCodeSettings:(nonnull FIRActionCodeSettings *)actionCodeSettings + completion:(nullable FIRSendSignInLinkToEmailCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + if (!email) { + [FIRAuthExceptionUtils + raiseInvalidParameterExceptionWithReason:kMissingEmailInvalidParameterExceptionReason]; + } + + if (!actionCodeSettings.handleCodeInApp) { + [FIRAuthExceptionUtils + raiseInvalidParameterExceptionWithReason:kHandleCodeInAppFalseExceptionReason]; + } + FIRGetOOBConfirmationCodeRequest *request = + [FIRGetOOBConfirmationCodeRequest signInWithEmailLinkRequest:email + actionCodeSettings:actionCodeSettings + requestConfiguration:self->_requestConfiguration]; + [FIRAuthBackend getOOBConfirmationCode:request + callback:^(FIRGetOOBConfirmationCodeResponse *_Nullable response, + NSError *_Nullable error) { + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(error); + }); + } + }]; + }); +} + +- (void)updateCurrentUser:(FIRUser *)user completion:(nullable FIRUserUpdateCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + if (!user) { + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion([FIRAuthErrorUtils nullUserErrorWithMessage:nil]); + }); + } + return; + } + void (^updateUserBlock)(FIRUser *user) = ^(FIRUser *user) { + NSError *error; + [self updateCurrentUser:user byForce:YES savingToDisk:YES error:(&error)]; + if (error) { + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(error); + }); + } + return; + } + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(nil); + }); + } + }; + if (![user.requestConfiguration.APIKey isEqualToString:self->_requestConfiguration.APIKey]) { + // If the API keys are different, then we need to confirm that the user belongs to the same + // project before proceeding. + user.requestConfiguration = self->_requestConfiguration; + [user reloadWithCompletion:^(NSError *_Nullable error) { + if (error) { + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(error); + }); + } + return; + } + updateUserBlock(user); + }]; + } else { + updateUserBlock(user); + } + }); +} + +- (BOOL)signOut:(NSError *_Nullable __autoreleasing *_Nullable)error { + __block BOOL result = YES; + dispatch_sync(FIRAuthGlobalWorkQueue(), ^{ + if (!self->_currentUser) { + return; + } + result = [self updateCurrentUser:nil byForce:NO savingToDisk:YES error:error]; + }); + return result; +} + +- (BOOL)signOutByForceWithUserID:(NSString *)userID error:(NSError *_Nullable *_Nullable)error { + if (_currentUser.uid != userID) { + return YES; + } + return [self updateCurrentUser:nil byForce:YES savingToDisk:YES error:error]; +} + +- (BOOL)isSignInWithEmailLink:(NSString *)link { + if (link.length == 0) { + return NO; + } + NSDictionary *queryItems = [FIRAuthWebUtils parseURL:link]; + if (![queryItems count]) { + NSURLComponents *urlComponents = [NSURLComponents componentsWithString:link]; + if (!urlComponents.query) { + return NO; + } + queryItems = [FIRAuthWebUtils parseURL:urlComponents.query]; + } + + if (![queryItems count]) { + return NO; + } + + NSString *actionCode = queryItems[@"oobCode"]; + NSString *mode = queryItems[@"mode"]; + + if (actionCode && [mode isEqualToString:@"signIn"]) { + return YES; + } + return NO; +} + +- (FIRAuthStateDidChangeListenerHandle)addAuthStateDidChangeListener: + (FIRAuthStateDidChangeListenerBlock)listener { + __block BOOL firstInvocation = YES; + __block NSString *previousUserID; + return [self addIDTokenDidChangeListener:^(FIRAuth *_Nonnull auth, FIRUser *_Nullable user) { + BOOL shouldCallListener = firstInvocation || !(previousUserID == user.uid || + [previousUserID isEqualToString:user.uid]); + firstInvocation = NO; + previousUserID = [user.uid copy]; + if (shouldCallListener) { + listener(auth, user); + } + }]; +} + +- (void)removeAuthStateDidChangeListener:(FIRAuthStateDidChangeListenerHandle)listenerHandle { + [self removeIDTokenDidChangeListener:listenerHandle]; +} + +- (FIRIDTokenDidChangeListenerHandle)addIDTokenDidChangeListener: + (FIRIDTokenDidChangeListenerBlock)listener { + if (!listener) { + [NSException raise:NSInvalidArgumentException format:@"Listener must not be nil."]; + return nil; + } + FIRAuthStateDidChangeListenerHandle handle; + NSNotificationCenter *notifications = [NSNotificationCenter defaultCenter]; + handle = [notifications addObserverForName:FIRAuthStateDidChangeNotification + object:self + queue:[NSOperationQueue mainQueue] + usingBlock:^(NSNotification *_Nonnull notification) { + FIRAuth *auth = notification.object; + listener(auth, auth.currentUser); + }]; + @synchronized(self) { + [_listenerHandles addObject:handle]; + } + dispatch_async(dispatch_get_main_queue(), ^{ + listener(self, self->_currentUser); + }); + return handle; +} + +- (void)removeIDTokenDidChangeListener:(FIRIDTokenDidChangeListenerHandle)listenerHandle { + [[NSNotificationCenter defaultCenter] removeObserver:listenerHandle]; + @synchronized(self) { + [_listenerHandles removeObject:listenerHandle]; + } +} + +- (void)useAppLanguage { + dispatch_sync(FIRAuthGlobalWorkQueue(), ^{ + self->_requestConfiguration.languageCode = [[NSLocale preferredLanguages] firstObject]; + }); +} + +- (void)useEmulatorWithHost:(NSString *)host port:(NSInteger)port { + NSAssert(host.length > 0, @"Cannot connect to nil or empty host"); + + NSString *formattedHost; + if ([host containsString:@":"]) { + // Host is an IPv6 address and should be formatted with surrounding brackets. + formattedHost = [NSString stringWithFormat:@"[%@]", host]; + } else { + formattedHost = host; + } + + dispatch_sync(FIRAuthGlobalWorkQueue(), ^{ + self->_requestConfiguration.emulatorHostAndPort = + [NSString stringWithFormat:@"%@:%ld", formattedHost, (long)port]; +#if TARGET_OS_IOS + self->_settings.appVerificationDisabledForTesting = YES; +#endif + }); +} + +- (nullable NSString *)languageCode { + return _requestConfiguration.languageCode; +} + +- (void)setLanguageCode:(nullable NSString *)languageCode { + dispatch_sync(FIRAuthGlobalWorkQueue(), ^{ + self->_requestConfiguration.languageCode = [languageCode copy]; + }); +} + +- (nullable NSString *)additionalFrameworkMarker { + return self->_requestConfiguration.additionalFrameworkMarker; +} + +- (void)setAdditionalFrameworkMarker:(nullable NSString *)additionalFrameworkMarker { + dispatch_sync(FIRAuthGlobalWorkQueue(), ^{ + self->_requestConfiguration.additionalFrameworkMarker = [additionalFrameworkMarker copy]; + }); +} + +- (void)revokeTokenWithAuthorizationCode:(NSString *)authorizationCode + completion:(nullable void (^)(NSError *_Nullable error))completion { + [self.currentUser + getIDTokenWithCompletion:^(NSString *_Nullable idToken, NSError *_Nullable error) { + if (error) { + if (completion) { + completion(error); + } + return; + } + FIRRevokeTokenRequest *request = + [[FIRRevokeTokenRequest alloc] initWithToken:authorizationCode + idToken:idToken + requestConfiguration:self->_requestConfiguration]; + [FIRAuthBackend + revokeToken:request + callback:^(FIRRevokeTokenResponse *_Nullable response, NSError *_Nullable error) { + if (completion) { + if (error) { + completion(error); + } else { + completion(nil); + } + } + }]; + }]; +} + +#if TARGET_OS_IOS +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-property-ivar" +// The warning is ignored because we use the token manager to get the token, instead of using the +// ivar. +- (nullable NSData *)APNSToken { + __block NSData *result = nil; + dispatch_sync(FIRAuthGlobalWorkQueue(), ^{ + result = self->_tokenManager.token.data; + }); + return result; +} +#pragma clang diagnostic pop + +#pragma mark - UIApplicationDelegate + +- (void)application:(UIApplication *)application + didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { + [self setAPNSToken:deviceToken type:FIRAuthAPNSTokenTypeUnknown]; +} + +- (void)application:(UIApplication *)application + didFailToRegisterForRemoteNotificationsWithError:(NSError *)error { + dispatch_sync(FIRAuthGlobalWorkQueue(), ^{ + [self->_tokenManager cancelWithError:error]; + }); +} + +- (void)application:(UIApplication *)application + didReceiveRemoteNotification:(NSDictionary *)userInfo + fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { + [self canHandleNotification:userInfo]; + completionHandler(UIBackgroundFetchResultNoData); +} + +// iOS 10 deprecation +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" +- (void)application:(UIApplication *)application + didReceiveRemoteNotification:(NSDictionary *)userInfo { + [self canHandleNotification:userInfo]; +} +#pragma clang diagnostic pop + +- (BOOL)application:(UIApplication *)app + openURL:(NSURL *)url + options:(NSDictionary *)options { + return [self canHandleURL:url]; +} + +// iOS 10 deprecation +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" +- (BOOL)application:(UIApplication *)application + openURL:(NSURL *)url + sourceApplication:(nullable NSString *)sourceApplication + annotation:(id)annotation { + return [self canHandleURL:url]; +} +#pragma clang diagnostic pop + +- (void)setAPNSToken:(NSData *)token type:(FIRAuthAPNSTokenType)type { + dispatch_sync(FIRAuthGlobalWorkQueue(), ^{ + self->_tokenManager.token = [[FIRAuthAPNSToken alloc] initWithData:token type:type]; + }); +} + +- (BOOL)canHandleNotification:(NSDictionary *)userInfo { + __block BOOL result = NO; + dispatch_sync(FIRAuthGlobalWorkQueue(), ^{ + result = [self->_notificationManager canHandleNotification:userInfo]; + }); + return result; +} + +- (BOOL)canHandleURL:(NSURL *)URL { + __block BOOL result = NO; + dispatch_sync(FIRAuthGlobalWorkQueue(), ^{ + result = [self->_authURLPresenter canHandleURL:URL]; + }); + return result; +} + +#pragma mark - UISceneDelegate +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 +- (void)scene:(UIScene *)scene + openURLContexts:(NSSet *)URLContexts API_AVAILABLE(ios(13.0)) { + for (UIOpenURLContext *urlContext in URLContexts) { + NSURL *url = [urlContext URL]; + [self canHandleURL:url]; + } +} +#endif // __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 +#endif // TARGET_OS_IOS + +#pragma mark - Internal Methods + +#if TARGET_OS_IOS +/** @fn signInWithPhoneCredential:callback: + @brief Signs in using a phone credential. + @param credential The Phone Auth credential used to sign in. + @param operation The type of operation for which this sign-in attempt is initiated. + @param callback A block which is invoked when the sign in finishes (or is cancelled.) Invoked + asynchronously on the global auth work queue in the future. + */ +- (void)signInWithPhoneCredential:(FIRPhoneAuthCredential *)credential + operation:(FIRAuthOperationType)operation + callback:(FIRVerifyPhoneNumberResponseCallback)callback { + if (credential.temporaryProof.length && credential.phoneNumber.length) { + FIRVerifyPhoneNumberRequest *request = + [[FIRVerifyPhoneNumberRequest alloc] initWithTemporaryProof:credential.temporaryProof + phoneNumber:credential.phoneNumber + operation:operation + requestConfiguration:_requestConfiguration]; + [FIRAuthBackend verifyPhoneNumber:request callback:callback]; + return; + } + + if (!credential.verificationID.length) { + callback(nil, [FIRAuthErrorUtils missingVerificationIDErrorWithMessage:nil]); + return; + } + if (!credential.verificationCode.length) { + callback(nil, [FIRAuthErrorUtils missingVerificationCodeErrorWithMessage:nil]); + return; + } + FIRVerifyPhoneNumberRequest *request = + [[FIRVerifyPhoneNumberRequest alloc] initWithVerificationID:credential.verificationID + verificationCode:credential.verificationCode + operation:operation + requestConfiguration:_requestConfiguration]; + [FIRAuthBackend verifyPhoneNumber:request callback:callback]; +} + +#endif + +/** @fn internalSignInAndRetrieveDataWithCustomToken:completion: + @brief Signs in a Firebase user given a custom token. + @param token A self-signed custom auth token. + @param completion A block which is invoked when the custom token sign in request completes. + */ +- (void)internalSignInAndRetrieveDataWithCustomToken:(NSString *)token + completion:(FIRAuthDataResultCallback)completion { + FIRVerifyCustomTokenRequest *request = + [[FIRVerifyCustomTokenRequest alloc] initWithToken:token + requestConfiguration:_requestConfiguration]; + [FIRAuthBackend + verifyCustomToken:request + callback:^(FIRVerifyCustomTokenResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + completion(nil, error); + return; + } + [self completeSignInWithAccessToken:response.IDToken + accessTokenExpirationDate:response.approximateExpirationDate + refreshToken:response.refreshToken + anonymous:NO + callback:^(FIRUser *_Nullable user, + NSError *_Nullable error) { + if (error) { + completion(nil, error); + return; + } + FIRAdditionalUserInfo *additonalUserInfo = + [[FIRAdditionalUserInfo alloc] + initWithProviderID:nil + profile:nil + username:nil + isNewUser:response.isNewUser]; + FIRAuthDataResult *result = + user ? [[FIRAuthDataResult alloc] + initWithUser:user + additionalUserInfo:additonalUserInfo] + : nil; + completion(result, error); + }]; + }]; +} + +/** @fn internalCreateUserWithEmail:password:completion: + @brief Makes a backend request attempting to create a new Firebase user given an email address + and password. + @param email The email address used to create the new Firebase user. + @param password The password used to create the new Firebase user. + @param completion Optionally; a block which is invoked when the request finishes. + */ +- (void)internalCreateUserWithEmail:(NSString *)email + password:(NSString *)password + completion:(nullable FIRSignupNewUserCallback)completion { + FIRSignUpNewUserRequest *request = + [[FIRSignUpNewUserRequest alloc] initWithEmail:email + password:password + displayName:nil + requestConfiguration:_requestConfiguration]; + if (![request.password length]) { + completion( + nil, [FIRAuthErrorUtils weakPasswordErrorWithServerResponseReason:kMissingPasswordReason]); + return; + } + if (![request.email length]) { + completion(nil, [FIRAuthErrorUtils missingEmailErrorWithMessage:nil]); + return; + } + [FIRAuthBackend signUpNewUser:request callback:completion]; +} + +/** @fn internalSignInAnonymouslyWithCompletion: + @param completion A block which is invoked when the anonymous sign in request completes. + */ +- (void)internalSignInAnonymouslyWithCompletion:(FIRSignupNewUserCallback)completion { + FIRSignUpNewUserRequest *request = + [[FIRSignUpNewUserRequest alloc] initWithRequestConfiguration:_requestConfiguration]; + [FIRAuthBackend signUpNewUser:request callback:completion]; +} + +/** @fn possiblyPostAuthStateChangeNotification + @brief Posts the auth state change notificaton if current user's token has been changed. + */ +- (void)possiblyPostAuthStateChangeNotification { + NSString *token = _currentUser.rawAccessToken; + if (_lastNotifiedUserToken == token || + (token != nil && [_lastNotifiedUserToken isEqualToString:token])) { + return; + } + _lastNotifiedUserToken = token; + if (_autoRefreshTokens) { + // Shedule new refresh task after successful attempt. + [self scheduleAutoTokenRefresh]; + } + NSMutableDictionary *internalNotificationParameters = [NSMutableDictionary dictionary]; + if (self.app) { + internalNotificationParameters[FIRAuthStateDidChangeInternalNotificationAppKey] = self.app; + } + if (token.length) { + internalNotificationParameters[FIRAuthStateDidChangeInternalNotificationTokenKey] = token; + } + internalNotificationParameters[FIRAuthStateDidChangeInternalNotificationUIDKey] = + _currentUser.uid; + NSNotificationCenter *notifications = [NSNotificationCenter defaultCenter]; + dispatch_async(dispatch_get_main_queue(), ^{ + [notifications postNotificationName:FIRAuthStateDidChangeInternalNotification + object:self + userInfo:internalNotificationParameters]; + [notifications postNotificationName:FIRAuthStateDidChangeNotification object:self]; + }); +} + +- (BOOL)updateKeychainWithUser:(FIRUser *)user error:(NSError *_Nullable *_Nullable)error { + if (user != _currentUser) { + // No-op if the user is no longer signed in. This is not considered an error as we don't check + // whether the user is still current on other callbacks of user operations either. + return YES; + } + if ([self saveUser:user error:error]) { + [self possiblyPostAuthStateChangeNotification]; + return YES; + } + return NO; +} + +/** @fn setKeychainServiceNameForApp + @brief Sets the keychain service name global data for the particular app. + @param app The Firebase app to set keychain service name for. + */ ++ (void)setKeychainServiceNameForApp:(FIRApp *)app { + @synchronized(self) { + gKeychainServiceNameForAppName[app.name] = + [@"firebase_auth_" stringByAppendingString:app.options.googleAppID]; + } +} + +/** @fn keychainServiceNameForAppName: + @brief Gets the keychain service name global data for the particular app by name. + @param appName The name of the Firebase app to get keychain service name for. + */ ++ (NSString *)keychainServiceNameForAppName:(NSString *)appName { + @synchronized(self) { + return gKeychainServiceNameForAppName[appName]; + } +} + +/** @fn deleteKeychainServiceNameForAppName: + @brief Deletes the keychain service name global data for the particular app by name. + @param appName The name of the Firebase app to delete keychain service name for. + */ ++ (void)deleteKeychainServiceNameForAppName:(NSString *)appName { + @synchronized(self) { + [gKeychainServiceNameForAppName removeObjectForKey:appName]; + } +} + +/** @fn scheduleAutoTokenRefreshWithDelay: + @brief Schedules a task to automatically refresh tokens on the current user. The token refresh + is scheduled 5 minutes before the scheduled expiration time. + @remarks If the token expires in less than 5 minutes, schedule the token refresh immediately. + */ +- (void)scheduleAutoTokenRefresh { + NSTimeInterval tokenExpirationInterval = + [_currentUser.accessTokenExpirationDate timeIntervalSinceNow] - kTokenRefreshHeadStart; + [self scheduleAutoTokenRefreshWithDelay:MAX(tokenExpirationInterval, 0) retry:NO]; +} + +/** @fn scheduleAutoTokenRefreshWithDelay: + @brief Schedules a task to automatically refresh tokens on the current user. + @param delay The delay in seconds after which the token refresh task should be scheduled to be + executed. + @param retry Flag to determine whether the invocation is a retry attempt or not. + */ +- (void)scheduleAutoTokenRefreshWithDelay:(NSTimeInterval)delay retry:(BOOL)retry { + NSString *accessToken = _currentUser.rawAccessToken; + if (!accessToken) { + return; + } + if (retry) { + FIRLogInfo(kFIRLoggerAuth, @"I-AUT000003", + @"Token auto-refresh re-scheduled in %02d:%02d " + @"because of error on previous refresh attempt.", + (int)ceil(delay) / 60, (int)ceil(delay) % 60); + } else { + FIRLogInfo(kFIRLoggerAuth, @"I-AUT000004", + @"Token auto-refresh scheduled in %02d:%02d for the new token.", + (int)ceil(delay) / 60, (int)ceil(delay) % 60); + } + _autoRefreshScheduled = YES; + __weak FIRAuth *weakSelf = self; + [[FIRAuthDispatcher sharedInstance] + dispatchAfterDelay:delay + queue:FIRAuthGlobalWorkQueue() + task:^(void) { + FIRAuth *strongSelf = weakSelf; + if (!strongSelf) { + return; + } + if (![strongSelf->_currentUser.rawAccessToken isEqualToString:accessToken]) { + // Another auto refresh must have been scheduled, so keep + // _autoRefreshScheduled unchanged. + return; + } + strongSelf->_autoRefreshScheduled = NO; + if (strongSelf->_isAppInBackground) { + return; + } + NSString *uid = strongSelf->_currentUser.uid; + [strongSelf->_currentUser + internalGetTokenForcingRefresh:YES + callback:^(NSString *_Nullable token, + NSError *_Nullable error) { + if (![strongSelf->_currentUser.uid + isEqualToString:uid]) { + return; + } + if (error) { + // Kicks off exponential back off logic to retry + // failed attempt. Starts with one minute delay + // (60 seconds) if this is the first failed + // attempt. + NSTimeInterval rescheduleDelay; + if (retry) { + rescheduleDelay = + MIN(delay * 2, kMaxWaitTimeForBackoff); + } else { + rescheduleDelay = 60; + } + [strongSelf + scheduleAutoTokenRefreshWithDelay: + rescheduleDelay + retry:YES]; + } + }]; + }]; +} + +#pragma mark - + +/** @fn completeSignInWithTokenService:callback: + @brief Completes a sign-in flow once we have access and refresh tokens for the user. + @param accessToken The STS access token. + @param accessTokenExpirationDate The approximate expiration date of the access token. + @param refreshToken The STS refresh token. + @param anonymous Whether or not the user is anonymous. + @param callback Called when the user has been signed in or when an error occurred. Invoked + asynchronously on the global auth work queue in the future. + */ +- (void)completeSignInWithAccessToken:(nullable NSString *)accessToken + accessTokenExpirationDate:(nullable NSDate *)accessTokenExpirationDate + refreshToken:(nullable NSString *)refreshToken + anonymous:(BOOL)anonymous + callback:(FIRAuthResultCallback)callback { + [FIRUser retrieveUserWithAuth:self + accessToken:accessToken + accessTokenExpirationDate:accessTokenExpirationDate + refreshToken:refreshToken + anonymous:anonymous + callback:callback]; +} + +/** @fn signInFlowAuthResultCallbackByDecoratingCallback: + @brief Creates a FIRAuthResultCallback block which wraps another FIRAuthResultCallback; trying + to update the current user before forwarding it's invocations along to a subject block + @param callback Called when the user has been updated or when an error has occurred. Invoked + asynchronously on the main thread in the future. + @return Returns a block that updates the current user. + @remarks Typically invoked as part of the complete sign-in flow. For any other uses please + consider alternative ways of updating the current user. +*/ +- (FIRAuthResultCallback)signInFlowAuthResultCallbackByDecoratingCallback: + (nullable FIRAuthResultCallback)callback { + return ^(FIRUser *_Nullable user, NSError *_Nullable error) { + if (error) { + if (callback) { + dispatch_async(dispatch_get_main_queue(), ^{ + callback(nil, error); + }); + } + return; + } + if (![self updateCurrentUser:user byForce:NO savingToDisk:YES error:&error]) { + if (callback) { + dispatch_async(dispatch_get_main_queue(), ^{ + callback(nil, error); + }); + } + return; + } + if (callback) { + dispatch_async(dispatch_get_main_queue(), ^{ + callback(user, nil); + }); + } + }; +} + +/** @fn signInFlowAuthDataResultCallbackByDecoratingCallback: + @brief Creates a FIRAuthDataResultCallback block which wraps another FIRAuthDataResultCallback; + trying to update the current user before forwarding it's invocations along to a subject + block. + @param callback Called when the user has been updated or when an error has occurred. Invoked + asynchronously on the main thread in the future. + @return Returns a block that updates the current user. + @remarks Typically invoked as part of the complete sign-in flow. For any other uses please + consider alternative ways of updating the current user. +*/ +- (FIRAuthDataResultCallback)signInFlowAuthDataResultCallbackByDecoratingCallback: + (nullable FIRAuthDataResultCallback)callback { + return ^(FIRAuthDataResult *_Nullable authResult, NSError *_Nullable error) { + if (error) { + if (callback) { + dispatch_async(dispatch_get_main_queue(), ^{ + callback(nil, error); + }); + } + return; + } + if (![self updateCurrentUser:authResult.user byForce:NO savingToDisk:YES error:&error]) { + if (callback) { + dispatch_async(dispatch_get_main_queue(), ^{ + callback(nil, error); + }); + } + return; + } + if (callback) { + dispatch_async(dispatch_get_main_queue(), ^{ + callback(authResult, nil); + }); + } + }; +} + +#pragma mark - User-Related Methods + +/** @fn updateCurrentUser:byForce:savingToDisk:error: + @brief Update the current user; initializing the user's internal properties correctly, and + optionally saving the user to disk. + @remarks This method is called during: sign in and sign out events, as well as during class + initialization time. The only time the saveToDisk parameter should be set to NO is during + class initialization time because the user was just read from disk. + @param user The user to use as the current user (including nil, which is passed at sign out + time.) + @param saveToDisk Indicates the method should persist the user data to disk. + */ +- (BOOL)updateCurrentUser:(nullable FIRUser *)user + byForce:(BOOL)force + savingToDisk:(BOOL)saveToDisk + error:(NSError *_Nullable *_Nullable)error { + if (user == _currentUser) { + [self possiblyPostAuthStateChangeNotification]; + return YES; + } + if (user) { + if ((user.tenantID || self.tenantID) && ![self.tenantID isEqualToString:user.tenantID]) { + if (error) { + *error = [FIRAuthErrorUtils tenantIDMismatchError]; + } + return NO; + } + } + + BOOL success = YES; + if (saveToDisk) { + success = [self saveUser:user error:error]; + } + if (success || force) { + _currentUser = user; + [self possiblyPostAuthStateChangeNotification]; + } + return success; +} + +/** @fn saveUser:error: + @brief Persists user. + @param user The user to save. + @param outError Return value for any error which occurs. + @return @YES on success, @NO otherwise. + */ +- (BOOL)saveUser:(nullable FIRUser *)user error:(NSError *_Nullable *_Nullable)outError { + BOOL success; + + if (!self.userAccessGroup) { + NSString *userKey = [NSString stringWithFormat:kUserKey, _firebaseAppName]; + if (!user) { + success = [_keychainServices removeDataForKey:userKey error:outError]; + } else { +#if TARGET_OS_WATCH + NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:false]; +#else + // Encode the user object. + NSMutableData *archiveData = [NSMutableData data]; +// iOS 12 deprecation +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + NSKeyedArchiver *archiver = + [[NSKeyedArchiver alloc] initForWritingWithMutableData:archiveData]; +#pragma clang diagnostic pop +#endif // TARGET_OS_WATCH + [archiver encodeObject:user forKey:userKey]; + [archiver finishEncoding]; + +#if TARGET_OS_WATCH + NSData *archiveData = archiver.encodedData; +#endif // TARGET_OS_WATCH + + // Save the user object's encoded value. + success = [_keychainServices setData:archiveData forKey:userKey error:outError]; + } + } else { + if (!user) { + success = + [self.storedUserManager removeStoredUserForAccessGroup:self.userAccessGroup + shareAuthStateAcrossDevices:self.shareAuthStateAcrossDevices + projectIdentifier:self.app.options.APIKey + error:outError]; + } else { + success = [self.storedUserManager setStoredUser:user + forAccessGroup:self.userAccessGroup + shareAuthStateAcrossDevices:self.shareAuthStateAcrossDevices + projectIdentifier:self.app.options.APIKey + error:outError]; + } + } + + return success; +} + +/** @fn getUser:error: + @brief Retrieves the saved user associated, if one exists, from the keychain. + @param outUser An out parameter which is populated with the saved user, if one exists. + @param error Return value for any error which occurs. + @return YES if the operation was a success (irrespective of whether or not a saved user existed + for the given @c firebaseAppId,) NO if an error occurred. + */ +- (BOOL)getUser:(FIRUser *_Nullable *)outUser error:(NSError *_Nullable *_Nullable)error { + if (!self.userAccessGroup) { + NSString *userKey = [NSString stringWithFormat:kUserKey, _firebaseAppName]; + + NSError *keychainError; + NSData *encodedUserData = [_keychainServices dataForKey:userKey error:&keychainError]; + if (keychainError) { + if (error) { + *error = keychainError; + } + return NO; + } + if (!encodedUserData) { + *outUser = nil; + return YES; + } +#if TARGET_OS_WATCH + NSKeyedUnarchiver *unarchiver = + [[NSKeyedUnarchiver alloc] initForReadingFromData:encodedUserData error:error]; + if (error && *error) { + return NO; + } +#else +// iOS 12 deprecation +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + NSKeyedUnarchiver *unarchiver = + [[NSKeyedUnarchiver alloc] initForReadingWithData:encodedUserData]; +#pragma clang diagnostic pop +#endif // TARGET_OS_WATCH + FIRUser *user = [unarchiver decodeObjectOfClass:[FIRUser class] forKey:userKey]; + user.auth = self; + *outUser = user; + + return YES; + } else { + FIRUser *user = + [self.storedUserManager getStoredUserForAccessGroup:self.userAccessGroup + shareAuthStateAcrossDevices:self.shareAuthStateAcrossDevices + projectIdentifier:self.app.options.APIKey + error:error]; + user.auth = self; + *outUser = user; + if (user) { + return YES; + } else { + if (error && *error) { + return NO; + } else { + return YES; + } + } + } +} + +#pragma mark - Interoperability + ++ (nonnull NSArray *)componentsToRegister { + FIRComponentCreationBlock authCreationBlock = + ^id _Nullable(FIRComponentContainer *_Nonnull container, BOOL *_Nonnull isCacheable) { + *isCacheable = YES; + return [[FIRAuth alloc] initWithApp:container.app]; + }; + FIRComponent *authInterop = [FIRComponent componentWithProtocol:@protocol(FIRAuthInterop) + instantiationTiming:FIRInstantiationTimingAlwaysEager + dependencies:@[] + creationBlock:authCreationBlock]; + return @[ authInterop ]; +} + +#pragma mark - FIRComponentLifecycleMaintainer + +- (void)appWillBeDeleted:(nonnull FIRApp *)app { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + // This doesn't stop any request already issued, see b/27704535 . + NSString *keychainServiceName = [FIRAuth keychainServiceNameForAppName:app.name]; + if (keychainServiceName) { + [[self class] deleteKeychainServiceNameForAppName:app.name]; + FIRAuthKeychainServices *keychain = + [[FIRAuthKeychainServices alloc] initWithService:keychainServiceName]; + NSString *userKey = [NSString stringWithFormat:kUserKey, app.name]; + [keychain removeDataForKey:userKey error:NULL]; + } + dispatch_async(dispatch_get_main_queue(), ^{ + // TODO: Move over to fire an event instead, once ready. + [[NSNotificationCenter defaultCenter] postNotificationName:FIRAuthStateDidChangeNotification + object:nil]; + }); + }); +} + +#pragma mark - FIRAuthInterop + +- (void)getTokenForcingRefresh:(BOOL)forceRefresh withCallback:(FIRTokenCallback)callback { + __weak FIRAuth *weakSelf = self; + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + FIRAuth *strongSelf = weakSelf; + // Enable token auto-refresh if not aleady enabled. + if (strongSelf && !strongSelf->_autoRefreshTokens) { + FIRLogInfo(kFIRLoggerAuth, @"I-AUT000002", @"Token auto-refresh enabled."); + strongSelf->_autoRefreshTokens = YES; + [strongSelf scheduleAutoTokenRefresh]; + +#if TARGET_OS_IOS || TARGET_OS_TV // TODO: Is a similar mechanism needed on macOS? + strongSelf->_applicationDidBecomeActiveObserver = [[NSNotificationCenter defaultCenter] + addObserverForName:UIApplicationDidBecomeActiveNotification + object:nil + queue:nil + usingBlock:^(NSNotification *notification) { + FIRAuth *strongSelf = weakSelf; + if (strongSelf) { + strongSelf->_isAppInBackground = NO; + if (!strongSelf->_autoRefreshScheduled) { + [weakSelf scheduleAutoTokenRefresh]; + } + } + }]; + strongSelf->_applicationDidEnterBackgroundObserver = [[NSNotificationCenter defaultCenter] + addObserverForName:UIApplicationDidEnterBackgroundNotification + object:nil + queue:nil + usingBlock:^(NSNotification *notification) { + FIRAuth *strongSelf = weakSelf; + if (strongSelf) { + strongSelf->_isAppInBackground = YES; + } + }]; +#endif + } + // Call back with 'nil' if there is no current user. + if (!strongSelf || !strongSelf->_currentUser) { + dispatch_async(dispatch_get_main_queue(), ^{ + callback(nil, nil); + }); + return; + } + // Call back with current user token. + [strongSelf->_currentUser + internalGetTokenForcingRefresh:forceRefresh + callback:^(NSString *_Nullable token, NSError *_Nullable error) { + dispatch_async(dispatch_get_main_queue(), ^{ + callback(token, error); + }); + }]; + }); +} + +- (nullable NSString *)getUserID { + return _currentUser.uid; +} + +#pragma mark - Keychain sharing + +- (BOOL)internalUseUserAccessGroup:(NSString *_Nullable)accessGroup + error:(NSError *_Nullable *_Nullable)outError { + BOOL success; + success = [self.storedUserManager setStoredUserAccessGroup:accessGroup]; + if (!success) { + return NO; + } + + FIRUser *user = [self getStoredUserForAccessGroup:accessGroup error:outError]; + if (!user && outError && *outError) { + return NO; + } + success = [self updateCurrentUser:user byForce:NO savingToDisk:NO error:outError]; + if (!success) { + return NO; + } + + if (_userAccessGroup == nil && accessGroup != nil) { + NSString *userKey = [NSString stringWithFormat:kUserKey, _firebaseAppName]; + [_keychainServices removeDataForKey:userKey error:outError]; + } + _userAccessGroup = accessGroup; + self->_lastNotifiedUserToken = user.rawAccessToken; + + return YES; +} + +- (BOOL)useUserAccessGroup:(NSString *_Nullable)accessGroup + error:(NSError *_Nullable *_Nullable)outError { + // self.storedUserManager is initialized asynchronously. Make sure it is done. + dispatch_sync(FIRAuthGlobalWorkQueue(), ^{ + }); + return [self internalUseUserAccessGroup:accessGroup error:outError]; +} + +- (nullable FIRUser *)getStoredUserForAccessGroup:(NSString *_Nullable)accessGroup + error:(NSError *_Nullable *_Nullable)outError { + FIRUser *user; + if (!accessGroup) { + NSString *userKey = [NSString stringWithFormat:kUserKey, _firebaseAppName]; + NSData *encodedUserData = [_keychainServices dataForKey:userKey error:outError]; + if (!encodedUserData) { + return nil; + } + +#if TARGET_OS_WATCH + NSKeyedUnarchiver *unarchiver = + [[NSKeyedUnarchiver alloc] initForReadingFromData:encodedUserData error:outError]; + if (outError && *outError) { + return nil; + } +#else +// iOS 12 deprecation +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + NSKeyedUnarchiver *unarchiver = + [[NSKeyedUnarchiver alloc] initForReadingWithData:encodedUserData]; +#pragma clang diagnostic pop +#endif // TARGET_OS_WATCH + user = [unarchiver decodeObjectOfClass:[FIRUser class] forKey:userKey]; + } else { +#if TARGET_OS_TV + if (self.shareAuthStateAcrossDevices) { + FIRLogError(kFIRLoggerAuth, @"I-AUT000001", + @"Getting a stored user for a given access group is not supported " + @"on tvOS when `shareAuthStateAcrossDevices` is set to `true` (#8878)." + @"This case will return `nil`."); + return nil; + } +#endif // TARGET_OS_TV + + user = [self.storedUserManager getStoredUserForAccessGroup:accessGroup + shareAuthStateAcrossDevices:self.shareAuthStateAcrossDevices + projectIdentifier:self.app.options.APIKey + error:outError]; + } + + user.auth = self; + return user; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthDataResult.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthDataResult.m new file mode 100644 index 0000000..dc8d035 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthDataResult.m @@ -0,0 +1,83 @@ +/* + * 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 "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAdditionalUserInfo.h" +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIROAuthCredential.h" +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRUser.h" + +#import "FirebaseAuth/Sources/Auth/FIRAuthDataResult_Internal.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRAuthDataResult + +/** @var kAdditionalUserInfoCodingKey + @brief The key used to encode the additionalUserInfo property for NSSecureCoding. + */ +static NSString *const kAdditionalUserInfoCodingKey = @"additionalUserInfo"; + +/** @var kUserCodingKey + @brief The key used to encode the user property for NSSecureCoding. + */ +static NSString *const kUserCodingKey = @"user"; + +/** @var kCredentialCodingKey + @brief The key used to encode the credential for NSSecureCoding. + */ +static NSString *const kCredentialCodingKey = @"credential"; + +- (nullable instancetype)initWithUser:(FIRUser *)user + additionalUserInfo:(nullable FIRAdditionalUserInfo *)additionalUserInfo { + return [self initWithUser:user additionalUserInfo:additionalUserInfo credential:nil]; +} + +- (nullable instancetype)initWithUser:(FIRUser *)user + additionalUserInfo:(nullable FIRAdditionalUserInfo *)additionalUserInfo + credential:(nullable FIROAuthCredential *)credential { + self = [super init]; + if (self) { + _additionalUserInfo = additionalUserInfo; + _user = user; + _credential = credential; + } + return self; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + FIRUser *user = [aDecoder decodeObjectOfClass:[FIRUser class] forKey:kUserCodingKey]; + FIRAdditionalUserInfo *additionalUserInfo = + [aDecoder decodeObjectOfClass:[FIRAdditionalUserInfo class] + forKey:kAdditionalUserInfoCodingKey]; + FIROAuthCredential *credential = [aDecoder decodeObjectOfClass:[FIROAuthCredential class] + forKey:kCredentialCodingKey]; + return [self initWithUser:user additionalUserInfo:additionalUserInfo credential:credential]; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:_user forKey:kUserCodingKey]; + [aCoder encodeObject:_additionalUserInfo forKey:kAdditionalUserInfoCodingKey]; + [aCoder encodeObject:_credential forKey:kCredentialCodingKey]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthDataResult_Internal.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthDataResult_Internal.h new file mode 100644 index 0000000..ff5f4c2 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthDataResult_Internal.h @@ -0,0 +1,46 @@ +/* + * 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 "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthDataResult.h" + +@class FIROAuthCredential; + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRAuthDataResult () + +/** @fn initWithUser:additionalUserInfo: + @brief Designated initializer. + @param user The signed in user reference. + @param additionalUserInfo The additional user info if available. + */ +- (nullable instancetype)initWithUser:(FIRUser *)user + additionalUserInfo:(nullable FIRAdditionalUserInfo *)additionalUserInfo; + +/** @fn initWithUser:additionalUserInfo: + @brief Designated initializer. + @param user The signed in user reference. + @param additionalUserInfo The additional user info if available. + @param credential The updated OAuth credential if available. + */ +- (nullable instancetype)initWithUser:(FIRUser *)user + additionalUserInfo:(nullable FIRAdditionalUserInfo *)additionalUserInfo + credential:(nullable FIROAuthCredential *)credential + NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthDispatcher.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthDispatcher.h new file mode 100644 index 0000000..16ccbc2 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthDispatcher.h @@ -0,0 +1,63 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRAuthDispatcherImplBlock + @brief The type of block which can be set as the implementation for @c + dispatchAfterDelay:queue:callback: . + + @param delay The delay in seconds after which the task will be scheduled to execute. + @param queue The dispatch queue on which the task will be submitted. + @param task The task (block) to be scheduled for future execution. + */ +typedef void (^FIRAuthDispatcherImplBlock)(NSTimeInterval delay, + dispatch_queue_t queue, + void (^task)(void)); + +/** @class FIRAuthDispatchAfter + @brief A utility class used to facilitate scheduling tasks to be executed in the future. + */ +@interface FIRAuthDispatcher : NSObject + +/** @property dispatchAfterImplementation + @brief Allows custom implementation of dispatchAfterDelay:queue:callback:. + @remarks Set to nil to restore default implementation. + */ +@property(nonatomic, nullable, copy) FIRAuthDispatcherImplBlock dispatchAfterImplementation; + +/** @fn dispatchAfterDelay:queue:callback: + @brief Schedules task in the future after a specified delay. + + @param delay The delay in seconds after which the task will be scheduled to execute. + @param queue The dispatch queue on which the task will be submitted. + @param task The task (block) to be scheduled for future execution. + */ +- (void)dispatchAfterDelay:(NSTimeInterval)delay + queue:(dispatch_queue_t)queue + task:(void (^)(void))task; + +/** @fn sharedInstance + @brief Gets the shared instance of this class. + @return The shared instance of this clss + */ ++ (instancetype)sharedInstance; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthDispatcher.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthDispatcher.m new file mode 100644 index 0000000..e5e32c3 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthDispatcher.m @@ -0,0 +1,46 @@ +/* + * 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 "FirebaseAuth/Sources/Auth/FIRAuthDispatcher.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRAuthDispatcher + +@synthesize dispatchAfterImplementation = _dispatchAfterImplementation; + ++ (instancetype)sharedInstance { + static dispatch_once_t onceToken; + static FIRAuthDispatcher *sharedInstance; + dispatch_once(&onceToken, ^{ + sharedInstance = [[self alloc] init]; + }); + return sharedInstance; +} + +- (void)dispatchAfterDelay:(NSTimeInterval)delay + queue:(dispatch_queue_t)queue + task:(void (^)(void))task { + if (_dispatchAfterImplementation) { + _dispatchAfterImplementation(delay, queue, task); + return; + } + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delay * NSEC_PER_SEC), queue, task); +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.h new file mode 100644 index 0000000..55bb1a7 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.h @@ -0,0 +1,31 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** @fn FIRAuthGlobalWorkQueue + @brief Retrieves the global serial work queue for Firebase Auth. + @return The global serial dispatch queue. + @remarks To ensure thread safety, all auth code must be executed in either this global work + queue, or a serial queue that has its target queue set to this work queue. All public method + implementations that may involve contested code shall dispatch to this work queue as the + first thing they do. + */ +extern dispatch_queue_t FIRAuthGlobalWorkQueue(void); + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.m new file mode 100644 index 0000000..92addeb --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.m @@ -0,0 +1,30 @@ +/* + * 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 "FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.h" + +NS_ASSUME_NONNULL_BEGIN + +dispatch_queue_t FIRAuthGlobalWorkQueue(void) { + static dispatch_once_t once; + static dispatch_queue_t queue; + dispatch_once(&once, ^{ + queue = dispatch_queue_create("com.google.firebase.auth.globalWorkQueue", NULL); + }); + return queue; +} + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthOperationType.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthOperationType.h new file mode 100644 index 0000000..62d6cd1 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthOperationType.h @@ -0,0 +1,47 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** + @brief Indicates the type of operation performed for RPCs that support the operation + parameter. + */ +typedef NS_ENUM(NSInteger, FIRAuthOperationType) { + /** Indicates that the operation type is uspecified. + */ + FIRAuthOperationTypeUnspecified = 0, + + /** Indicates that the operation type is sign in or sign up. + */ + FIRAuthOperationTypeSignUpOrSignIn = 1, + + /** Indicates that the operation type is reauthentication. + */ + FIRAuthOperationTypeReauth = 2, + + /** Indicates that the operation type is update. + */ + FIRAuthOperationTypeUpdate = 3, + + /** Indicates that the operation type is link. + */ + FIRAuthOperationTypeLink = 4, +}; + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthSerialTaskQueue.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthSerialTaskQueue.h new file mode 100644 index 0000000..cdae046 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthSerialTaskQueue.h @@ -0,0 +1,50 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRAuthSerialTaskCompletionBlock + @brief The type of method a @c FIRAuthSerialTask must call when it is complete. + */ +typedef void (^FIRAuthSerialTaskCompletionBlock)(void); + +/** @typedef FIRAuthSerialTask + @brief Represents a unit of work submitted to a task queue. + @param complete The task MUST call the complete method when done. + */ +typedef void (^FIRAuthSerialTask)(FIRAuthSerialTaskCompletionBlock complete); + +/** @class FIRAuthSerialTaskQueue + @brief An easy to use serial task queue which supports a callback-based completion notification + system for easy asyncronous call chaining. + */ +@interface FIRAuthSerialTaskQueue : NSObject + +/** @fn enqueueTask: + @brief Enqueues a task for serial execution in the queue. + @remarks The task MUST call the complete method when done. This method is thread-safe. + The task block won't be executed concurrently with any other blocks in other task queues or + the global work queue as returned by @c FIRAuthGlobalWorkQueue , but an uncompleted task + (e.g. task block finished executation before complete method is called at a later time) + does not affect other task queues or the global work queue. + */ +- (void)enqueueTask:(FIRAuthSerialTask)task; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthSerialTaskQueue.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthSerialTaskQueue.m new file mode 100644 index 0000000..4bded78 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthSerialTaskQueue.m @@ -0,0 +1,56 @@ +/* + * 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 "FirebaseAuth/Sources/Auth/FIRAuthSerialTaskQueue.h" + +#import "FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRAuthSerialTaskQueue { + /** @var _dispatchQueue + @brief The asyncronous dispatch queue into which tasks are enqueued and processed + serially. + */ + dispatch_queue_t _dispatchQueue; +} + +- (instancetype)init { + self = [super init]; + if (self) { + _dispatchQueue = dispatch_queue_create("com.google.firebase.auth.serialTaskQueue", NULL); + dispatch_set_target_queue(_dispatchQueue, FIRAuthGlobalWorkQueue()); + } + return self; +} + +- (void)enqueueTask:(FIRAuthSerialTask)task { + // This dispatch queue will run tasks serially in FIFO order, as long as it's not suspended. + dispatch_async(self->_dispatchQueue, ^{ + // But as soon as a task is started, stop other tasks from running until the task calls it's + // completion handler, which allows the queue to resume processing of tasks. This allows the + // task to perform other asyncronous actions on other dispatch queues and "get back to us" when + // all of their sub-tasks are complete. + dispatch_suspend(self->_dispatchQueue); + task(^{ + dispatch_resume(self->_dispatchQueue); + }); + }); +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthSettings.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthSettings.m new file mode 100644 index 0000000..8715897 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthSettings.m @@ -0,0 +1,40 @@ +/* + * 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/LICENSE2.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 "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthSettings.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRAuthSettings + +- (instancetype)init { + self = [super init]; + if (self) { + _appVerificationDisabledForTesting = NO; + } + return self; +} + +- (instancetype)copyWithZone:(NSZone *__unused _Nullable)zone { + // Auth settings are mutable, so always return a copy. + FIRAuthSettings *newSettings = [[FIRAuthSettings alloc] init]; + newSettings.appVerificationDisabledForTesting = self.isAppVerificationDisabledForTesting; + return newSettings; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthTokenResult.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthTokenResult.m new file mode 100644 index 0000000..fd857e3 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthTokenResult.m @@ -0,0 +1,166 @@ +/* + * 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. + */ + +#import "FirebaseAuth/Sources/Auth/FIRAuthTokenResult_Internal.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kExpirationDateKey + @brief The key used to encode the expirationDate property for NSSecureCoding. + */ +static NSString *const kExpirationDateKey = @"expiratinDate"; + +/** @var kTokenKey + @brief The key used to encode the token property for NSSecureCoding. + */ +static NSString *const kTokenKey = @"token"; + +/** @var kAuthDateKey + @brief The key used to encode the authDate property for NSSecureCoding. + */ +static NSString *const kAuthDateKey = @"authDate"; + +/** @var kIssuedDateKey + @brief The key used to encode the issuedDate property for NSSecureCoding. + */ +static NSString *const kIssuedDateKey = @"issuedDate"; + +/** @var kSignInProviderKey + @brief The key used to encode the signInProvider property for NSSecureCoding. + */ +static NSString *const kSignInProviderKey = @"signInProvider"; + +/** @var kSignInSecondFactorKey + @brief The key used to encode the signInSecondFactor property for NSSecureCoding. + */ +static NSString *const kSignInSecondFactorKey = @"signInSecondFactor"; + +/** @var kClaimsKey + @brief The key used to encode the claims property for NSSecureCoding. + */ +static NSString *const kClaimsKey = @"claims"; + +@implementation FIRAuthTokenResult + +- (instancetype)initWithToken:(NSString *)token + expirationDate:(NSDate *)expirationDate + authDate:(NSDate *)authDate + issuedAtDate:(NSDate *)issuedAtDate + signInProvider:(NSString *)signInProvider + signInSecondFactor:(NSString *)signInSecondFactor + claims:(NSDictionary *)claims { + self = [super init]; + if (self) { + _token = token; + _expirationDate = expirationDate; + _authDate = authDate; + _issuedAtDate = issuedAtDate; + _signInProvider = signInProvider; + _signInSecondFactor = signInSecondFactor; + _claims = claims; + } + return self; +} + ++ (nullable FIRAuthTokenResult *)tokenResultWithToken:(NSString *)token { + NSArray *tokenStringArray = [token componentsSeparatedByString:@"."]; + + // The JWT should have three parts, though we only use the second in this method. + if (tokenStringArray.count != 3) { + return nil; + } + + // The token payload is always the second index of the array. + NSString *IDToken = tokenStringArray[1]; + + // Convert the base64URL encoded string to a base64 encoded string. + // Replace "_" with "/" + NSMutableString *tokenPayload = [[IDToken stringByReplacingOccurrencesOfString:@"_" + withString:@"/"] mutableCopy]; + + // Replace "-" with "+" + [tokenPayload replaceOccurrencesOfString:@"-" + withString:@"+" + options:kNilOptions + range:NSMakeRange(0, tokenPayload.length)]; + + // Pad the token payload with "=" signs if the payload's length is not a multiple of 4. + while ((tokenPayload.length % 4) != 0) { + [tokenPayload appendFormat:@"="]; + } + NSData *decodedTokenPayloadData = + [[NSData alloc] initWithBase64EncodedString:tokenPayload + options:NSDataBase64DecodingIgnoreUnknownCharacters]; + if (!decodedTokenPayloadData) { + return nil; + } + NSError *jsonError = nil; + NSJSONReadingOptions options = NSJSONReadingMutableContainers | NSJSONReadingAllowFragments; + NSDictionary *tokenPayloadDictionary = + [NSJSONSerialization JSONObjectWithData:decodedTokenPayloadData + options:options + error:&jsonError]; + if (jsonError != nil) { + return nil; + } + + if (!tokenPayloadDictionary) { + return nil; + } + + // These are dates since 00:00:00 January 1 1970, as described by the Terminology section in + // the JWT spec. https://tools.ietf.org/html/rfc7519 + NSDate *expirationDate = + [NSDate dateWithTimeIntervalSince1970:[tokenPayloadDictionary[@"exp"] doubleValue]]; + NSDate *authDate = + [NSDate dateWithTimeIntervalSince1970:[tokenPayloadDictionary[@"auth_time"] doubleValue]]; + NSDate *issuedAtDate = + [NSDate dateWithTimeIntervalSince1970:[tokenPayloadDictionary[@"iat"] doubleValue]]; + + NSDictionary *firebaseTokenPayloadDictionary = tokenPayloadDictionary[@"firebase"]; + NSString *signInProvider = firebaseTokenPayloadDictionary[@"sign_in_provider"]; + NSString *signInSecondFactor = firebaseTokenPayloadDictionary[@"sign_in_second_factor"]; + + FIRAuthTokenResult *tokenResult = + [[FIRAuthTokenResult alloc] initWithToken:token + expirationDate:expirationDate + authDate:authDate + issuedAtDate:issuedAtDate + signInProvider:signInProvider + signInSecondFactor:signInSecondFactor + claims:tokenPayloadDictionary]; + return tokenResult; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + NSString *token = [aDecoder decodeObjectOfClass:[NSDate class] forKey:kTokenKey]; + return [FIRAuthTokenResult tokenResultWithToken:token]; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:_token forKey:kTokenKey]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthTokenResult_Internal.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthTokenResult_Internal.h new file mode 100644 index 0000000..6a5f7ad --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuthTokenResult_Internal.h @@ -0,0 +1,36 @@ +/* + * 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. + */ + +#import +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthTokenResult.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @extension FIRAuthAPNSTokenResult + @brief An internal class used to expose internal methods of FIRAuthAPNSTokenResult. + */ +@interface FIRAuthTokenResult () + +/** @fn tokenResultWithToken: + @brief Parse a token string to a structured token. + @param token The token string to parse. + @return A structured token result. +*/ ++ (nullable FIRAuthTokenResult *)tokenResultWithToken:(NSString *)token; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuth_Internal.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuth_Internal.h new file mode 100644 index 0000000..cdb1e33 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Auth/FIRAuth_Internal.h @@ -0,0 +1,154 @@ +/* + * 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 +#import "FirebaseAuth/Interop/FIRAuthInterop.h" +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuth.h" +#import "FirebaseCore/Extension/FIRLogger.h" + +@class FIRAuthRequestConfiguration; +@class FIRAuthURLPresenter; + +#if TARGET_OS_IOS +@class FIRAuthAPNSTokenManager; +@class FIRAuthAppCredentialManager; +@class FIRAuthNotificationManager; +#endif + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRAuth () + +/** @property requestConfiguration + @brief The configuration object comprising of paramters needed to make a request to Firebase + Auth's backend. + */ +@property(nonatomic, copy, readonly) FIRAuthRequestConfiguration *requestConfiguration; + +#if TARGET_OS_IOS + +/** @property tokenManager + @brief The manager for APNs tokens used by phone number auth. + */ +@property(nonatomic, strong, readonly) FIRAuthAPNSTokenManager *tokenManager; + +/** @property appCredentailManager + @brief The manager for app credentials used by phone number auth. + */ +@property(nonatomic, strong, readonly) FIRAuthAppCredentialManager *appCredentialManager; + +/** @property notificationManager + @brief The manager for remote notifications used by phone number auth. + */ +@property(nonatomic, strong, readonly) FIRAuthNotificationManager *notificationManager; + +#endif // TARGET_OS_IOS + +/** @property authURLPresenter + @brief An object that takes care of presenting URLs via the auth instance. + */ +@property(nonatomic, strong, readonly) FIRAuthURLPresenter *authURLPresenter; + +/** @fn initWithAPIKey:appName: + @brief Designated initializer. + @param APIKey The Google Developers Console API key for making requests from your app. + @param appName The name property of the previously created @c FIRApp instance. + @param appID The app ID of the Firebase application. + */ +- (nullable instancetype)initWithAPIKey:(NSString *)APIKey + appName:(NSString *)appName + appID:(NSString *)appID; + +/** @fn getUserID + @brief Gets the identifier of the current user, if any. + @return The identifier of the current user, or nil if there is no current user. + */ +- (nullable NSString *)getUserID; + +/** @fn updateKeychainWithUser:error: + @brief Updates the keychain for the given user. + @param user The user to be updated. + @param error The error caused the method to fail if the method returns NO. + @return Whether updating keychain has succeeded or not. + @remarks Called by @c FIRUser when user info or token changes occur. + */ +- (BOOL)updateKeychainWithUser:(FIRUser *)user error:(NSError *_Nullable *_Nullable)error; + +/** @fn internalSignInWithCredential:callback: + @brief Convenience method for @c internalSignInAndRetrieveDataWithCredential:callback: + This method doesn't return additional identity provider data. +*/ +- (void)internalSignInWithCredential:(FIRAuthCredential *)credential + callback:(FIRAuthResultCallback)callback; + +/** @fn internalSignInAndRetrieveDataWithCredential:callback: + @brief Asynchronously signs in Firebase with the given 3rd party credentials (e.g. a Facebook + login Access Token, a Google ID Token/Access Token pair, etc.) and returns additional + identity provider data. + @param credential The credential supplied by the IdP. + @param isReauthentication Indicates whether or not the current invocation originated from an + attempt to reauthenticate. + @param callback A block which is invoked when the sign in finishes (or is cancelled.) Invoked + asynchronously on the auth global work queue in the future. + @remarks This is the internal counterpart of this method, which uses a callback that does not + update the current user. + */ +- (void)internalSignInAndRetrieveDataWithCredential:(FIRAuthCredential *)credential + isReauthentication:(BOOL)isReauthentication + callback:(nullable FIRAuthDataResultCallback)callback; + +/** @fn signOutByForceWithUserID:error: + @brief Signs out the current user. + @param userID The ID of the user to force sign out. + @param error An optional out parameter for error results. + @return @YES when the sign out request was successful. @NO otherwise. + */ +- (BOOL)signOutByForceWithUserID:(NSString *)userID error:(NSError *_Nullable *_Nullable)error; + +/** @fn completeSignInWithTokenService:callback: + @brief Completes a sign-in flow once we have access and refresh tokens for the user. + @param accessToken The STS access token. + @param accessTokenExpirationDate The approximate expiration date of the access token. + @param refreshToken The STS refresh token. + @param anonymous Whether or not the user is anonymous. + @param callback Called when the user has been signed in or when an error occurred. Invoked + asynchronously on the global auth work queue in the future. +*/ +- (void)completeSignInWithAccessToken:(nullable NSString *)accessToken + accessTokenExpirationDate:(nullable NSDate *)accessTokenExpirationDate + refreshToken:(nullable NSString *)refreshToken + anonymous:(BOOL)anonymous + callback:(FIRAuthResultCallback)callback; + +/** @fn signInFlowAuthResultCallbackByDecoratingCallback: + @brief Creates a FIRAuthResultCallback block which wraps another FIRAuthResultCallback; trying + to update the current user before forwarding it's invocations along to a subject block + @param callback Called when the user has been updated or when an error has occurred. Invoked + asynchronously on the main thread in the future. + @return Returns a block that updates the current user. + @remarks Typically invoked as part of the complete sign-in flow. For any other uses please + consider alternative ways of updating the current user. +*/ +- (FIRAuthDataResultCallback)signInFlowAuthDataResultCallbackByDecoratingCallback: + (nullable FIRAuthDataResultCallback)callback; + +@end + +/// Logger Service String + +extern FIRLoggerService kFIRLoggerAuth; + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Email/FIREmailAuthProvider.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Email/FIREmailAuthProvider.m new file mode 100644 index 0000000..731e79b --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Email/FIREmailAuthProvider.m @@ -0,0 +1,41 @@ +/* + * 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 "FirebaseAuth/Sources/Public/FirebaseAuth/FIREmailAuthProvider.h" + +#import "FirebaseAuth/Sources/AuthProvider/Email/FIREmailPasswordAuthCredential.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIREmailAuthProvider + +- (instancetype)init { + @throw [NSException exceptionWithName:@"Attempt to call unavailable initializer." + reason:@"This class is not meant to be initialized." + userInfo:nil]; +} + ++ (FIRAuthCredential *)credentialWithEmail:(NSString *)email password:(NSString *)password { + return [[FIREmailPasswordAuthCredential alloc] initWithEmail:email password:password]; +} + ++ (FIRAuthCredential *)credentialWithEmail:(NSString *)email link:(NSString *)link { + return [[FIREmailPasswordAuthCredential alloc] initWithEmail:email link:link]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Email/FIREmailPasswordAuthCredential.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Email/FIREmailPasswordAuthCredential.h new file mode 100644 index 0000000..df683e6 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Email/FIREmailPasswordAuthCredential.h @@ -0,0 +1,61 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/AuthProvider/FIRAuthCredential_Internal.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIREmailPasswordAuthCredential + @brief Internal implementation of FIRAuthCredential for Email/Password credentials. + */ +@interface FIREmailPasswordAuthCredential : FIRAuthCredential + +/** @property email + @brief The user's email address. + */ +@property(nonatomic, readonly) NSString *email; + +/** @property password + @brief The user's password. + */ +@property(nonatomic, readonly) NSString *password; + +/** @property link + @brief The email sign-in link. + */ +@property(nonatomic, readonly) NSString *link; + +/** @fn initWithEmail:password: + @brief Designated initializer. + @param email The user's email address. + @param password The user's password. + */ +- (nullable instancetype)initWithEmail:(NSString *)email + password:(NSString *)password NS_DESIGNATED_INITIALIZER; + +/** @fn initWithEmail:link: + @brief Designated initializer. + @param email The user's email address. + @param link The email sign-in link. + */ +- (nullable instancetype)initWithEmail:(NSString *)email + link:(NSString *)link NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Email/FIREmailPasswordAuthCredential.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Email/FIREmailPasswordAuthCredential.m new file mode 100644 index 0000000..a427f5d --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Email/FIREmailPasswordAuthCredential.m @@ -0,0 +1,92 @@ +/* + * 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 "FirebaseAuth/Sources/AuthProvider/Email/FIREmailPasswordAuthCredential.h" + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIREmailAuthProvider.h" + +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIREmailPasswordAuthCredential () + +- (nullable instancetype)initWithProvider:(NSString *)provider NS_UNAVAILABLE; + +@end + +@implementation FIREmailPasswordAuthCredential + +- (nullable instancetype)initWithProvider:(NSString *)provider { + [FIRAuthExceptionUtils + raiseMethodNotImplementedExceptionWithReason:@"Please call the designated initializer."]; + return nil; +} + +- (nullable instancetype)initWithEmail:(NSString *)email password:(NSString *)password { + self = [super initWithProvider:FIREmailAuthProviderID]; + if (self) { + _email = [email copy]; + _password = [password copy]; + } + return self; +} + +- (nullable instancetype)initWithEmail:(NSString *)email link:(NSString *)link { + self = [super initWithProvider:FIREmailAuthProviderID]; + if (self) { + _email = [email copy]; + _link = [link copy]; + } + return self; +} + +- (void)prepareVerifyAssertionRequest:(FIRVerifyAssertionRequest *)request { + [FIRAuthExceptionUtils + raiseMethodNotImplementedExceptionWithReason: + @"Attempt to call prepareVerifyAssertionRequest: on a FIREmailPasswordAuthCredential."]; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + NSString *email = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"email"]; + NSString *password = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"password"]; + NSString *link = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"link"]; + if (email.length && password.length) { + self = [self initWithEmail:email password:password]; + } else if (email.length && link.length) { + self = [self initWithEmail:email link:link]; + } else { + self = nil; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:self.email forKey:@"email"]; + [aCoder encodeObject:self.password forKey:@"password"]; + [aCoder encodeObject:self.link forKey:@"link"]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/FIRAuthCredential.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/FIRAuthCredential.m new file mode 100644 index 0000000..2f633f7 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/FIRAuthCredential.m @@ -0,0 +1,46 @@ +/* + * 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 "FirebaseAuth/Sources/AuthProvider/FIRAuthCredential_Internal.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRAuthCredential + +- (instancetype)init { + @throw [NSException exceptionWithName:@"Attempt to call unavailable initializer." + reason:@"This class is an abstract base class. It's init method " + "should not be called directly." + userInfo:nil]; +} + +- (nullable instancetype)initWithProvider:(NSString *)provider { + self = [super init]; + if (self) { + _provider = [provider copy]; + } + return self; +} + +- (void)prepareVerifyAssertionRequest:(FIRVerifyAssertionRequest *)request { + @throw [NSException exceptionWithName:@"Attempt to call virtual method." + reason:@"This method must be overridden by a subclass." + userInfo:nil]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/FIRAuthCredential_Internal.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/FIRAuthCredential_Internal.h new file mode 100644 index 0000000..41f3c90 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/FIRAuthCredential_Internal.h @@ -0,0 +1,41 @@ +/* + * 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 "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthCredential.h" + +@class FIRVerifyAssertionRequest; + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRAuthCredential () + +/** @fn initWithProvider: + @brief Designated initializer. + @remarks This is the designated initializer for internal/friend subclasses. + @param provider The provider name. + */ +- (nullable instancetype)initWithProvider:(NSString *)provider NS_DESIGNATED_INITIALIZER; + +/** @fn prepareVerifyAssertionRequest: + @brief Called immediately before a request to the verifyAssertion endpoint is made. Implementers + should update the passed request instance with their credentials. + @param request The request to be updated with credentials. + */ +- (void)prepareVerifyAssertionRequest:(FIRVerifyAssertionRequest *)request; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/FIRAuthProvider.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/FIRAuthProvider.m new file mode 100644 index 0000000..6192ad6 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/FIRAuthProvider.m @@ -0,0 +1,66 @@ +/* + * 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 + +#pragma mark - Provider ID constants + +// Declared 'extern' in FIRGoogleAuthProvider.h +NSString *const FIRGoogleAuthProviderID = @"google.com"; + +// Declared 'extern' in FIRFacebookAuthProvider.h +NSString *const FIRFacebookAuthProviderID = @"facebook.com"; + +// Declared 'extern' in FIREmailAuthProvider.h +NSString *const FIREmailAuthProviderID = @"password"; + +// Declared 'extern' in FIRTwitterAuthProvider.h +NSString *const FIRTwitterAuthProviderID = @"twitter.com"; + +// Declared 'extern' in FIRGitHubAuthProvider.h +NSString *const FIRGitHubAuthProviderID = @"github.com"; + +// Declared 'extern' in FIRPhoneAuthProvider.h +NSString *const FIRPhoneAuthProviderID = @"phone"; + +// Declared 'extern' in FIRGameCenterAuthProvider.h +NSString *const FIRGameCenterAuthProviderID = @"gc.apple.com"; + +#pragma mark - sign-in methods constants + +// Declared 'extern' in FIRGoogleAuthProvider.h +NSString *const FIRGoogleAuthSignInMethod = @"google.com"; + +// Declared 'extern' in FIREmailAuthProvider.h +NSString *const FIREmailPasswordAuthSignInMethod = @"password"; + +// Declared 'extern' in FIREmailAuthProvider.h +NSString *const FIREmailLinkAuthSignInMethod = @"emailLink"; + +// Declared 'extern' in FIRTwitterAuthProvider.h +NSString *const FIRTwitterAuthSignInMethod = @"twitter.com"; + +// Declared 'extern' in FIRFacebookAuthProvider.h +NSString *const FIRFacebookAuthSignInMethod = @"facebook.com"; + +// Declared 'extern' in FIRGitHubAuthProvider.h +NSString *const FIRGitHubAuthSignInMethod = @"github.com"; + +// Declared 'extern' in FIRPhoneAuthProvider.h +NSString *const FIRPhoneAuthSignInMethod = @"phone"; + +// Declared 'extern' in FIRGameCenterAuthProvider.h +NSString *const FIRGameCenterAuthSignInMethod = @"gc.apple.com"; diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Facebook/FIRFacebookAuthCredential.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Facebook/FIRFacebookAuthCredential.h new file mode 100644 index 0000000..646ddba --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Facebook/FIRFacebookAuthCredential.h @@ -0,0 +1,36 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/AuthProvider/FIRAuthCredential_Internal.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRFacebookAuthCredential + @brief Internal implementation of FIRAuthCredential for the Facebook IdP. + */ +@interface FIRFacebookAuthCredential : FIRAuthCredential + +/** @fn initWithAccessToken: + @brief Designated initializer. + @param accessToken The Access Token obtained from Facebook. + */ +- (nullable instancetype)initWithAccessToken:(NSString *)accessToken NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Facebook/FIRFacebookAuthCredential.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Facebook/FIRFacebookAuthCredential.m new file mode 100644 index 0000000..c2ba6f1 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Facebook/FIRFacebookAuthCredential.m @@ -0,0 +1,72 @@ +/* + * 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 "FirebaseAuth/Sources/AuthProvider/Facebook/FIRFacebookAuthCredential.h" + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRFacebookAuthProvider.h" + +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRFacebookAuthCredential () + +- (nullable instancetype)initWithProvider:(NSString *)provider NS_UNAVAILABLE; + +@end + +@implementation FIRFacebookAuthCredential { + NSString *_accessToken; +} + +- (nullable instancetype)initWithProvider:(NSString *)provider { + [FIRAuthExceptionUtils + raiseMethodNotImplementedExceptionWithReason:@"Please call the designated initializer."]; + return nil; +} + +- (nullable instancetype)initWithAccessToken:(NSString *)accessToken { + self = [super initWithProvider:FIRFacebookAuthProviderID]; + if (self) { + _accessToken = [accessToken copy]; + } + return self; +} + +- (void)prepareVerifyAssertionRequest:(FIRVerifyAssertionRequest *)request { + request.providerAccessToken = _accessToken; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + NSString *accessToken = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"accessToken"]; + self = [self initWithAccessToken:accessToken]; + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:_accessToken forKey:@"accessToken"]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Facebook/FIRFacebookAuthProvider.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Facebook/FIRFacebookAuthProvider.m new file mode 100644 index 0000000..afdbb93 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Facebook/FIRFacebookAuthProvider.m @@ -0,0 +1,40 @@ +/* + * 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 "FirebaseAuth/Sources/Public/FirebaseAuth/FIRFacebookAuthProvider.h" + +#import "FirebaseAuth/Sources/AuthProvider/Facebook/FIRFacebookAuthCredential.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h" + +// FIRFacebookAuthProviderID is defined in FIRAuthProvider.m. + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRFacebookAuthProvider + +- (instancetype)init { + [FIRAuthExceptionUtils + raiseMethodNotImplementedExceptionWithReason:@"This class is not meant to be initialized."]; + return nil; +} + ++ (FIRAuthCredential *)credentialWithAccessToken:(NSString *)accessToken { + return [[FIRFacebookAuthCredential alloc] initWithAccessToken:accessToken]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GameCenter/FIRGameCenterAuthCredential.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GameCenter/FIRGameCenterAuthCredential.h new file mode 100644 index 0000000..e76f099 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GameCenter/FIRGameCenterAuthCredential.h @@ -0,0 +1,92 @@ +/* + * 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. + */ + +#import +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthCredential.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRGameCenterAuthCredential + @brief Internal implementation of FIRAuthCredential for Game Center credentials. + */ +@interface FIRGameCenterAuthCredential : FIRAuthCredential + +/** @property playerID + @brief The ID of the Game Center local player. + */ +@property(nonatomic, readonly) NSString *playerID; + +/** @property teamPlayerID + @brief The team player ID of the Game Center local player. + */ +@property(nonatomic, readonly) NSString *teamPlayerID; + +/** @property gamePlayerID + @brief The game player ID of the Game Center local player. + */ +@property(nonatomic, readonly) NSString *gamePlayerID; + +/** @property publicKeyURL + @brief The URL for the public encryption key. + */ +@property(nonatomic, readonly) NSURL *publicKeyURL; + +/** @property signature + @brief The verification signature data generated. + */ +@property(nonatomic, readonly) NSData *signature; + +/** @property salt + @brief A random string used to compute the hash and keep it randomized. + */ +@property(nonatomic, readonly) NSData *salt; + +/** @property timestamp + @brief The date and time that the signature was created. + */ +@property(nonatomic, readonly) uint64_t timestamp; + +/** @property displayName + @brief The display name of the local Game Center player. + */ +@property(nonatomic, readonly) NSString *displayName; + +/** @fn initWithPlayerID:publicKeyURL:signature:salt:timestamp:displayName: + @brief Designated initializer. + @param publicKeyURL The URL for the public encryption key. + @param signature The verification signature generated. + @param salt A random string used to compute the hash and keep it randomized. + @param timestamp The date and time that the signature was created. + @param displayName The display name of the Game Center player. + */ +- (nullable instancetype)initWithPlayerID:(NSString *)playerID + teamPlayerID:(nullable NSString *)teamPlayerID + gamePlayerID:(nullable NSString *)gamePlayerID + publicKeyURL:(NSURL *)publicKeyURL + signature:(NSData *)signature + salt:(NSData *)salt + timestamp:(uint64_t)timestamp + displayName:(NSString *)displayName NS_DESIGNATED_INITIALIZER; + +/** @fn initWithProvider: + @brief Initializer with a provider name. + @param provider The provider name. + */ +- (nullable instancetype)initWithProvider:(NSString *)provider NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GameCenter/FIRGameCenterAuthCredential.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GameCenter/FIRGameCenterAuthCredential.m new file mode 100644 index 0000000..bd56386 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GameCenter/FIRGameCenterAuthCredential.m @@ -0,0 +1,102 @@ +/* + * 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. + */ + +#import "FirebaseAuth/Sources/AuthProvider/GameCenter/FIRGameCenterAuthCredential.h" + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRGameCenterAuthProvider.h" + +#import "FirebaseAuth/Sources/AuthProvider/FIRAuthCredential_Internal.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRGameCenterAuthCredential + +- (nullable instancetype)initWithProvider:(NSString *)provider { + [FIRAuthExceptionUtils + raiseMethodNotImplementedExceptionWithReason:@"Please call the designated initializer."]; + return nil; +} + +- (nullable instancetype)initWithPlayerID:(NSString *)playerID + teamPlayerID:(nullable NSString *)teamPlayerID + gamePlayerID:(nullable NSString *)gamePlayerID + publicKeyURL:(NSURL *)publicKeyURL + signature:(NSData *)signature + salt:(NSData *)salt + timestamp:(uint64_t)timestamp + displayName:(NSString *)displayName { + self = [super initWithProvider:FIRGameCenterAuthProviderID]; + if (self) { + _playerID = [playerID copy]; + _teamPlayerID = [teamPlayerID copy]; + _gamePlayerID = [gamePlayerID copy]; + _publicKeyURL = [publicKeyURL copy]; + _signature = [signature copy]; + _salt = [salt copy]; + _timestamp = timestamp; + _displayName = [displayName copy]; + } + return self; +} + +- (void)prepareVerifyAssertionRequest:(FIRVerifyAssertionRequest *)request { + [FIRAuthExceptionUtils + raiseMethodNotImplementedExceptionWithReason: + @"Attempt to call prepareVerifyAssertionRequest: on a FIRGameCenterAuthCredential."]; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + NSString *playerID = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"playerID"]; + NSString *teamPlayerID = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"teamPlayerID"]; + NSString *gamePlayerID = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"gamePlayerID"]; + NSURL *publicKeyURL = [aDecoder decodeObjectOfClass:[NSURL class] forKey:@"publicKeyURL"]; + NSData *signature = [aDecoder decodeObjectOfClass:[NSData class] forKey:@"signature"]; + NSData *salt = [aDecoder decodeObjectOfClass:[NSData class] forKey:@"salt"]; + NSNumber *timestamp = [aDecoder decodeObjectOfClass:[NSNumber class] forKey:@"timestamp"]; + NSString *displayName = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"displayName"]; + self = [self initWithPlayerID:playerID + teamPlayerID:teamPlayerID + gamePlayerID:gamePlayerID + publicKeyURL:publicKeyURL + signature:signature + salt:salt + timestamp:timestamp.unsignedLongLongValue + displayName:displayName]; + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:self.playerID forKey:@"playerID"]; + [aCoder encodeObject:self.teamPlayerID forKey:@"teamPlayerID"]; + [aCoder encodeObject:self.gamePlayerID forKey:@"gamePlayerID"]; + [aCoder encodeObject:self.publicKeyURL forKey:@"publicKeyURL"]; + [aCoder encodeObject:self.signature forKey:@"signature"]; + [aCoder encodeObject:self.salt forKey:@"salt"]; + [aCoder encodeObject:[NSNumber numberWithUnsignedLongLong:self.timestamp] forKey:@"timestamp"]; + [aCoder encodeObject:self.displayName forKey:@"displayName"]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GameCenter/FIRGameCenterAuthProvider.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GameCenter/FIRGameCenterAuthProvider.m new file mode 100644 index 0000000..93a76e2 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GameCenter/FIRGameCenterAuthProvider.m @@ -0,0 +1,125 @@ +/* + * 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. + */ + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRGameCenterAuthProvider.h" +#import + +#import "FirebaseAuth/Sources/AuthProvider/GameCenter/FIRGameCenterAuthCredential.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRGameCenterAuthProvider + +- (instancetype)init { + [FIRAuthExceptionUtils + raiseMethodNotImplementedExceptionWithReason:@"This class is not meant to be initialized."]; + return nil; +} + ++ (void)getCredentialWithCompletion:(FIRGameCenterCredentialCallback)completion { + /** + Linking GameKit.framework without using it on macOS results in App Store rejection. + Thus we don't link GameKit.framework to our SDK directly. `optionalLocalPlayer` is used for + checking whether the APP that consuming our SDK has linked GameKit.framework. If not, a + `GameKitNotLinkedError` will be raised. + **/ + GKLocalPlayer *_Nullable optionalLocalPlayer = [[NSClassFromString(@"GKLocalPlayer") alloc] init]; + + if (!optionalLocalPlayer) { + if (completion) { + completion(nil, [FIRAuthErrorUtils gameKitNotLinkedError]); + } + return; + } + + __weak GKLocalPlayer *localPlayer = [[optionalLocalPlayer class] localPlayer]; + if (!localPlayer.isAuthenticated) { + if (completion) { + completion(nil, [FIRAuthErrorUtils localPlayerNotAuthenticatedError]); + } + return; + } + if (@available(iOS 13.5, macOS 10.15.5, macCatalyst 13.5, + // Availability of fetchItemsForIdentityVerificationSignature was extended to tvOS 13.4.8 in + // Xcode 14 (from tvOS 13.5 in Xcode 13). + // TODO: Remove this check when we no longer support Xcode 13. +#if defined(__TVOS_16_0) + tvOS 13.4.8, +#else + tvOS 13.5, +#endif + *)) { + [localPlayer fetchItemsForIdentityVerificationSignature:^( + NSURL *_Nullable publicKeyURL, NSData *_Nullable signature, + NSData *_Nullable salt, uint64_t timestamp, NSError *_Nullable error) { + if (error) { + if (completion) { + completion(nil, error); + } + } else { + FIRGameCenterAuthCredential *credential = + [[FIRGameCenterAuthCredential alloc] initWithPlayerID:localPlayer.playerID + teamPlayerID:localPlayer.teamPlayerID + gamePlayerID:localPlayer.gamePlayerID + publicKeyURL:publicKeyURL + signature:signature + salt:salt + timestamp:timestamp + displayName:localPlayer.displayName]; + completion(credential, nil); + } + }]; + } else { + [localPlayer generateIdentityVerificationSignatureWithCompletionHandler:^( + NSURL *publicKeyURL, NSData *signature, NSData *salt, uint64_t timestamp, + NSError *error) { + if (error) { + if (completion) { + completion(nil, error); + } + } else { + if (completion) { + /** + @c `localPlayer.alias` is actually the displayname needed, instead of + `localPlayer.displayname`. For more information, check + https://developer.apple.com/documentation/gamekit/gkplayer + **/ + NSString *displayName = localPlayer.alias; +// iOS 13 deprecation +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + FIRGameCenterAuthCredential *credential = + [[FIRGameCenterAuthCredential alloc] initWithPlayerID:localPlayer.playerID + teamPlayerID:nil + gamePlayerID:nil + publicKeyURL:publicKeyURL + signature:signature + salt:salt + timestamp:timestamp + displayName:displayName]; +#pragma clang diagnostic pop + completion(credential, nil); + } + } + }]; + } +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GitHub/FIRGitHubAuthCredential.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GitHub/FIRGitHubAuthCredential.h new file mode 100644 index 0000000..f6765c4 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GitHub/FIRGitHubAuthCredential.h @@ -0,0 +1,41 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/AuthProvider/FIRAuthCredential_Internal.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRGitHubAuthCredential + @brief Internal implementation of FIRAuthCredential for GitHub credentials. + */ +@interface FIRGitHubAuthCredential : FIRAuthCredential + +/** @property token + @brief The GitHub OAuth access token. + */ +@property(nonatomic, readonly) NSString *token; + +/** @fn initWithToken: + @brief Designated initializer. + @param token The GitHub OAuth access token. + */ +- (nullable instancetype)initWithToken:(NSString *)token NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GitHub/FIRGitHubAuthCredential.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GitHub/FIRGitHubAuthCredential.m new file mode 100644 index 0000000..c752e20 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GitHub/FIRGitHubAuthCredential.m @@ -0,0 +1,70 @@ +/* + * 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 "FirebaseAuth/Sources/AuthProvider/GitHub/FIRGitHubAuthCredential.h" + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRGitHubAuthProvider.h" + +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRGitHubAuthCredential () + +- (nullable instancetype)initWithProvider:(NSString *)provider NS_UNAVAILABLE; + +@end + +@implementation FIRGitHubAuthCredential + +- (nullable instancetype)initWithProvider:(NSString *)provider { + [FIRAuthExceptionUtils + raiseMethodNotImplementedExceptionWithReason:@"Please call the designated initializer."]; + return nil; +} + +- (nullable instancetype)initWithToken:(NSString *)token { + self = [super initWithProvider:FIRGitHubAuthProviderID]; + if (self) { + _token = [token copy]; + } + return self; +} + +- (void)prepareVerifyAssertionRequest:(FIRVerifyAssertionRequest *)request { + request.providerAccessToken = _token; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + NSString *token = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"token"]; + self = [self initWithToken:token]; + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:self.token forKey:@"token"]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GitHub/FIRGitHubAuthProvider.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GitHub/FIRGitHubAuthProvider.m new file mode 100644 index 0000000..1f853d8 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/GitHub/FIRGitHubAuthProvider.m @@ -0,0 +1,40 @@ +/* + * 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 "FirebaseAuth/Sources/Public/FirebaseAuth/FIRGitHubAuthProvider.h" + +#import "FirebaseAuth/Sources/AuthProvider/GitHub/FIRGitHubAuthCredential.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h" + +// FIRGitHubAuthProviderID is defined in FIRAuthProvider.m. + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRGitHubAuthProvider + +- (instancetype)init { + [FIRAuthExceptionUtils + raiseMethodNotImplementedExceptionWithReason:@"This class is not meant to be initialized."]; + return nil; +} + ++ (FIRAuthCredential *)credentialWithToken:(NSString *)token { + return [[FIRGitHubAuthCredential alloc] initWithToken:token]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Google/FIRGoogleAuthCredential.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Google/FIRGoogleAuthCredential.h new file mode 100644 index 0000000..6d205c1 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Google/FIRGoogleAuthCredential.h @@ -0,0 +1,38 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/AuthProvider/FIRAuthCredential_Internal.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRGoogleAuthCredential + @brief Internal implementation of FIRAuthCredential for the Google IdP. + */ +@interface FIRGoogleAuthCredential : FIRAuthCredential + +/** @fn initWithIDToken:accessToken: + @brief Designated initializer. + @param IDToken The ID Token obtained from Google. + @param accessToken The Access Token obtained from Google. + */ +- (nullable instancetype)initWithIDToken:(NSString *)IDToken + accessToken:(NSString *)accessToken NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Google/FIRGoogleAuthCredential.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Google/FIRGoogleAuthCredential.m new file mode 100644 index 0000000..149445d --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Google/FIRGoogleAuthCredential.m @@ -0,0 +1,77 @@ +/* + * 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 "FirebaseAuth/Sources/AuthProvider/Google/FIRGoogleAuthCredential.h" + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRGoogleAuthProvider.h" + +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRGoogleAuthCredential () + +- (nullable instancetype)initWithProvider:(NSString *)provider NS_UNAVAILABLE; + +@end + +@implementation FIRGoogleAuthCredential { + NSString *_IDToken; + NSString *_accessToken; +} + +- (nullable instancetype)initWithProvider:(NSString *)provider { + [FIRAuthExceptionUtils + raiseMethodNotImplementedExceptionWithReason:@"Please call the designated initializer."]; + return nil; +} + +- (nullable instancetype)initWithIDToken:(NSString *)IDToken accessToken:(NSString *)accessToken { + self = [super initWithProvider:FIRGoogleAuthProviderID]; + if (self) { + _IDToken = [IDToken copy]; + _accessToken = [accessToken copy]; + } + return self; +} + +- (void)prepareVerifyAssertionRequest:(FIRVerifyAssertionRequest *)request { + request.providerIDToken = _IDToken; + request.providerAccessToken = _accessToken; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + NSString *IDToken = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"IDToken"]; + NSString *accessToken = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"accessToken"]; + self = [self initWithIDToken:IDToken accessToken:accessToken]; + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:_IDToken forKey:@"IDToken"]; + [aCoder encodeObject:_accessToken forKey:@"accessToken"]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Google/FIRGoogleAuthProvider.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Google/FIRGoogleAuthProvider.m new file mode 100644 index 0000000..51e2fc8 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Google/FIRGoogleAuthProvider.m @@ -0,0 +1,41 @@ +/* + * 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 "FirebaseAuth/Sources/Public/FirebaseAuth/FIRGoogleAuthProvider.h" + +#import "FirebaseAuth/Sources/AuthProvider/Google/FIRGoogleAuthCredential.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h" + +// FIRGoogleAuthProviderID is defined in FIRAuthProvider.m. + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRGoogleAuthProvider + +- (instancetype)init { + [FIRAuthExceptionUtils + raiseMethodNotImplementedExceptionWithReason:@"This class is not meant to be initialized."]; + return nil; +} + ++ (FIRAuthCredential *)credentialWithIDToken:(NSString *)IDToken + accessToken:(NSString *)accessToken { + return [[FIRGoogleAuthCredential alloc] initWithIDToken:IDToken accessToken:accessToken]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthCredential.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthCredential.m new file mode 100644 index 0000000..d066a6f --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthCredential.m @@ -0,0 +1,139 @@ +/* + * 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 "FirebaseAuth/Sources/Public/FirebaseAuth/FIROAuthCredential.h" + +#import "FirebaseAuth/Sources/AuthProvider/FIRAuthCredential_Internal.h" +#import "FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthCredential_Internal.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIROAuthCredential () + +@property(nonatomic, nullable) NSString *rawNonce; + +- (nullable instancetype)initWithProvider:(NSString *)provider NS_UNAVAILABLE; + +@end + +@implementation FIROAuthCredential + +- (nullable instancetype)initWithProvider:(NSString *)provider { + [FIRAuthExceptionUtils + raiseMethodNotImplementedExceptionWithReason:@"Please call the designated initializer."]; + return nil; +} + +- (instancetype)initWithProviderID:(NSString *)providerID + IDToken:(nullable NSString *)IDToken + rawNonce:(nullable NSString *)rawNonce + accessToken:(nullable NSString *)accessToken + secret:(nullable NSString *)secret + fullName:(nullable NSPersonNameComponents *)fullName + pendingToken:(nullable NSString *)pendingToken { + self = [super initWithProvider:providerID]; + if (self) { + _IDToken = IDToken; + _rawNonce = rawNonce; + _accessToken = accessToken; + _pendingToken = pendingToken; + _secret = secret; + _fullName = fullName; + } + return self; +} + +- (instancetype)initWithProviderID:(NSString *)providerID + sessionID:(NSString *)sessionID + OAuthResponseURLString:(NSString *)OAuthResponseURLString { + self = [self initWithProviderID:providerID + IDToken:nil + rawNonce:nil + accessToken:nil + secret:nil + fullName:nil + pendingToken:nil]; + if (self) { + _OAuthResponseURLString = OAuthResponseURLString; + _sessionID = sessionID; + } + return self; +} + +- (nullable instancetype)initWithVerifyAssertionResponse:(FIRVerifyAssertionResponse *)response { + if (response.oauthIDToken.length || response.oauthAccessToken.length || + response.oauthSecretToken.length) { + return [self initWithProviderID:response.providerID + IDToken:response.oauthIDToken + rawNonce:nil + accessToken:response.oauthAccessToken + secret:response.oauthSecretToken + fullName:nil + pendingToken:response.pendingToken]; + } + return nil; +} + +- (void)prepareVerifyAssertionRequest:(FIRVerifyAssertionRequest *)request { + request.providerIDToken = _IDToken; + request.providerRawNonce = _rawNonce; + request.providerAccessToken = _accessToken; + request.requestURI = _OAuthResponseURLString; + request.sessionID = _sessionID; + request.providerOAuthTokenSecret = _secret; + request.pendingToken = _pendingToken; + request.fullName = _fullName; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + NSString *IDToken = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"IDToken"]; + NSString *rawNonce = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"rawNonce"]; + NSString *accessToken = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"accessToken"]; + NSString *pendingToken = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"pendingToken"]; + NSString *secret = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"secret"]; + NSPersonNameComponents *fullName = [aDecoder decodeObjectOfClass:[NSPersonNameComponents class] + forKey:@"fullName"]; + self = [self initWithProviderID:self.provider + IDToken:IDToken + rawNonce:rawNonce + accessToken:accessToken + secret:secret + fullName:fullName + pendingToken:pendingToken]; + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:self.IDToken forKey:@"IDToken"]; + [aCoder encodeObject:self.rawNonce forKey:@"rawNonce"]; + [aCoder encodeObject:self.accessToken forKey:@"accessToken"]; + [aCoder encodeObject:self.pendingToken forKey:@"pendingToken"]; + [aCoder encodeObject:self.secret forKey:@"secret"]; + [aCoder encodeObject:self.fullName forKey:@"fullName"]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthCredential_Internal.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthCredential_Internal.h new file mode 100644 index 0000000..2d05bcc --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthCredential_Internal.h @@ -0,0 +1,85 @@ +/* + * 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 +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIROAuthCredential.h" + +@class FIRVerifyAssertionResponse; + +NS_ASSUME_NONNULL_BEGIN + +/** @extension FIROAuthCredential + @brief Internal implementation of FIRAuthCredential for generic credentials. + */ +@interface FIROAuthCredential () + +/** @property OAuthResponseURLString + @brief A string representation of the response URL corresponding to this OAuthCredential. + */ +@property(nonatomic, readonly, nullable) NSString *OAuthResponseURLString; + +/** @property sessionID + @brief The session ID used when completing the headful-lite flow. + */ +@property(nonatomic, readonly, nullable) NSString *sessionID; + +/** @property pendingToken + @brief The pending token used when completing the headful-lite flow. + */ +@property(nonatomic, readonly, nullable) NSString *pendingToken; + +/** @property fullName + @brief The full name of the user associated with this OAuthCredential. + */ +@property(nonatomic, readonly, nullable) NSPersonNameComponents *fullName; + +/** @fn initWithProviderId:IDToken:rawNonce:accessToken:secret:fullName:pendingToken + @brief Designated initializer. + @param providerID The provider ID associated with the credential being created. + @param IDToken The ID Token associated with the credential being created. + @param rawNonce The raw nonce associated with the Auth credential being created. + @param accessToken The access token associated with the credential being created. + @param secret The secret associated with the credential being created. + @param fullName The full name associated with the credential being created. + @param pendingToken The pending token associated with the credential being created. + */ +- (instancetype)initWithProviderID:(NSString *)providerID + IDToken:(nullable NSString *)IDToken + rawNonce:(nullable NSString *)rawNonce + accessToken:(nullable NSString *)accessToken + secret:(nullable NSString *)secret + fullName:(nullable NSPersonNameComponents *)fullName + pendingToken:(nullable NSString *)pendingToken NS_DESIGNATED_INITIALIZER; + +/** @fn initWithProviderId:sessionID:OAuthResponseURLString: + @brief Intitializer which takes a sessionID and an OAuthResponseURLString. + @param providerID The provider ID associated with the credential being created. + @param sessionID The session ID used when completing the headful-lite flow. + @param OAuthResponseURLString The error that occurred if any. + */ +- (instancetype)initWithProviderID:(NSString *)providerID + sessionID:(NSString *)sessionID + OAuthResponseURLString:(NSString *)OAuthResponseURLString; + +/** @fn initWithVerifyAssertionResponse + @brief Intitializer which takes an verifyAssertion response. + @param response The verifyAssertion Response to create the credential instance. + */ +- (nullable instancetype)initWithVerifyAssertionResponse:(FIRVerifyAssertionResponse *)response; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthProvider.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthProvider.m new file mode 100644 index 0000000..fc7036f --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthProvider.m @@ -0,0 +1,494 @@ +/* + * 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 "FirebaseAuth/Sources/Public/FirebaseAuth/FIROAuthProvider.h" +#include +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRFacebookAuthProvider.h" +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIROAuthCredential.h" +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" + +#import "FirebaseAppCheck/Interop/FIRAppCheckTokenResultInterop.h" +#import "FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.h" +#import "FirebaseAuth/Sources/Auth/FIRAuth_Internal.h" +#import "FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthCredential_Internal.h" +#import "FirebaseAuth/Sources/Backend/FIRAuthBackend.h" +#import "FirebaseAuth/Sources/Backend/FIRAuthRequestConfiguration.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthWebUtils.h" + +#if TARGET_OS_IOS +#import "FirebaseAuth/Sources/Utilities/FIRAuthURLPresenter.h" +#endif + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRHeadfulLiteURLCallBack + @brief The callback invoked at the end of the flow to fetch a headful-lite URL. + @param headfulLiteURL The headful lite URL. + @param error The error that occurred while fetching the headful-lite, if any. + */ +typedef void (^FIRHeadfulLiteURLCallBack)(NSURL *_Nullable headfulLiteURL, + NSError *_Nullable error); + +/** @var kHeadfulLiteURLStringFormat + @brief The format of the URL used to open the headful lite page during sign-in. + */ +NSString *const kHeadfulLiteURLStringFormat = @"https://%@/__/auth/handler?%@"; + +/** @var kHeadfulLiteEmulatorURLStringFormat + @brief The format of the URL used to open the emulated headful lite page during sign-in. + */ +NSString *const kHeadfulLiteEmulatorURLStringFormat = @"http://%@/emulator/auth/handler?%@"; + +/** @var kauthTypeSignInWithRedirect + @brief The auth type to be specified in the sign-in request with redirect request and response. + */ +static NSString *const kAuthTypeSignInWithRedirect = @"signInWithRedirect"; + +/** @var kCustomUrlSchemePrefix + @brief The prefix to append to the Firebase app ID custom callback scheme.. + */ +static NSString *const kCustomUrlSchemePrefix = @"app-"; + +@implementation FIROAuthProvider { + /** @var _auth + @brief The auth instance used for launching the URL presenter. + */ + FIRAuth *_auth; + + /** @var _callbackScheme + @brief The callback URL scheme used for headful-lite sign-in. + */ + NSString *_callbackScheme; + + /** @var _usingClientIDScheme + @brief True if the reverse client ID is registered as a custom URL scheme, and false + otherwise. + */ + BOOL _usingClientIDScheme; +} + ++ (FIROAuthCredential *)credentialWithProviderID:(NSString *)providerID + IDToken:(NSString *)IDToken + accessToken:(nullable NSString *)accessToken { + return [[FIROAuthCredential alloc] initWithProviderID:providerID + IDToken:IDToken + rawNonce:nil + accessToken:accessToken + secret:nil + fullName:nil + pendingToken:nil]; +} + ++ (FIROAuthCredential *)credentialWithProviderID:(NSString *)providerID + accessToken:(NSString *)accessToken { + return [[FIROAuthCredential alloc] initWithProviderID:providerID + IDToken:nil + rawNonce:nil + accessToken:accessToken + secret:nil + fullName:nil + pendingToken:nil]; +} + ++ (FIROAuthCredential *)credentialWithProviderID:(NSString *)providerID + IDToken:(NSString *)IDToken + rawNonce:(nullable NSString *)rawNonce + accessToken:(nullable NSString *)accessToken { + return [[FIROAuthCredential alloc] initWithProviderID:providerID + IDToken:IDToken + rawNonce:rawNonce + accessToken:accessToken + secret:nil + fullName:nil + pendingToken:nil]; +} + ++ (FIROAuthCredential *)credentialWithProviderID:(NSString *)providerID + IDToken:(NSString *)IDToken + rawNonce:(nullable NSString *)rawNonce { + return [[FIROAuthCredential alloc] initWithProviderID:providerID + IDToken:IDToken + rawNonce:rawNonce + accessToken:nil + secret:nil + fullName:nil + pendingToken:nil]; +} + ++ (FIROAuthCredential *)appleCredentialWithIDToken:(NSString *)IDToken + rawNonce:(nullable NSString *)rawNonce + fullName:(nullable NSPersonNameComponents *)fullName { + return [[FIROAuthCredential alloc] initWithProviderID:@"apple.com" + IDToken:IDToken + rawNonce:rawNonce + accessToken:nil + secret:nil + fullName:fullName + pendingToken:nil]; +} + ++ (instancetype)providerWithProviderID:(NSString *)providerID { + return [[self alloc] initWithProviderID:providerID auth:[FIRAuth auth]]; +} + ++ (instancetype)providerWithProviderID:(NSString *)providerID auth:(FIRAuth *)auth { + return [[self alloc] initWithProviderID:providerID auth:auth]; +} + +#if TARGET_OS_IOS +- (void)getCredentialWithUIDelegate:(nullable id)UIDelegate + completion:(nullable FIRAuthCredentialCallback)completion { + if (![FIRAuthWebUtils isCallbackSchemeRegisteredForCustomURLScheme:self->_callbackScheme]) { + [NSException raise:NSInternalInconsistencyException + format:@"Please register custom URL scheme '%@' in the app's Info.plist file.", + self->_callbackScheme]; + } + __weak __typeof__(self) weakSelf = self; + __weak FIRAuth *weakAuth = _auth; + __weak NSString *weakProviderID = _providerID; + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + FIRAuthCredentialCallback callbackOnMainThread = + ^(FIRAuthCredential *_Nullable credential, NSError *_Nullable error) { + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(credential, error); + }); + } + }; + NSString *eventID = [FIRAuthWebUtils randomStringWithLength:10]; + NSString *sessionID = [FIRAuthWebUtils randomStringWithLength:10]; + __strong __typeof__(self) strongSelf = weakSelf; + [strongSelf + getHeadFulLiteURLWithEventID:eventID + sessionID:sessionID + completion:^(NSURL *_Nullable headfulLiteURL, NSError *_Nullable error) { + if (error) { + callbackOnMainThread(nil, error); + return; + } + FIRAuthURLCallbackMatcher callbackMatcher = + ^BOOL(NSURL *_Nullable callbackURL) { + return [FIRAuthWebUtils + isExpectedCallbackURL:callbackURL + eventID:eventID + authType:kAuthTypeSignInWithRedirect + callbackScheme:strongSelf->_callbackScheme]; + }; + __strong FIRAuth *strongAuth = weakAuth; + [strongAuth.authURLPresenter + presentURL:headfulLiteURL + UIDelegate:UIDelegate + callbackMatcher:callbackMatcher + completion:^(NSURL *_Nullable callbackURL, + NSError *_Nullable error) { + if (error) { + callbackOnMainThread(nil, error); + return; + } + NSString *OAuthResponseURLString = + [strongSelf OAuthResponseForURL:callbackURL + error:&error]; + if (error) { + callbackOnMainThread(nil, error); + return; + } + __strong NSString *strongProviderID = weakProviderID; + FIROAuthCredential *credential = [[FIROAuthCredential alloc] + initWithProviderID:strongProviderID + sessionID:sessionID + OAuthResponseURLString:OAuthResponseURLString]; + callbackOnMainThread(credential, nil); + }]; + }]; + }); +} +#endif // TARGET_OS_IOS + +#pragma mark - Internal Methods + +/** @fn initWithProviderID:auth: + @brief returns an instance of @c FIROAuthProvider associated with the provided auth instance. + @param auth The Auth instance to be associated with the OAuthProvider instance. + @return An Instance of @c FIROAuthProvider. + */ +- (nullable instancetype)initWithProviderID:(NSString *)providerID auth:(FIRAuth *)auth { + if (!auth.requestConfiguration.emulatorHostAndPort) { + NSAssert(![providerID isEqual:FIRFacebookAuthProviderID], + @"Sign in with Facebook is not supported via generic IDP; the Facebook TOS " + "dictate that you must use the Facebook iOS SDK for Facebook login."); + NSAssert(![providerID isEqual:@"apple.com"], + @"Sign in with Apple is not supported via generic IDP; You must use the Apple iOS SDK" + " for Sign in with Apple."); + } + self = [super init]; + if (self) { + _auth = auth; + _providerID = providerID; + if (_auth.app.options.clientID) { + NSString *reverseClientIDScheme = + [[[_auth.app.options.clientID componentsSeparatedByString:@"."] + reverseObjectEnumerator].allObjects componentsJoinedByString:@"."]; + if ([FIRAuthWebUtils isCallbackSchemeRegisteredForCustomURLScheme:reverseClientIDScheme]) { + _callbackScheme = reverseClientIDScheme; + _usingClientIDScheme = YES; + } + } + + if (!_usingClientIDScheme) { + _callbackScheme = [kCustomUrlSchemePrefix + stringByAppendingString:[_auth.app.options.googleAppID + stringByReplacingOccurrencesOfString:@":" + withString:@"-"]]; + } + } + return self; +} + +/** @fn OAuthResponseForURL:error: + @brief Parses the redirected URL and returns a string representation of the OAuth response URL. + @param URL The url to be parsed for an OAuth response URL. + @param error The error that occurred if any. + @return The OAuth response if successful. + */ +- (nullable NSString *)OAuthResponseForURL:(NSURL *)URL error:(NSError *_Nullable *_Nullable)error { + NSDictionary *URLQueryItems = + [FIRAuthWebUtils dictionaryWithHttpArgumentsString:URL.query]; + NSURL *deepLinkURL = [NSURL URLWithString:URLQueryItems[@"deep_link_id"]]; + URLQueryItems = [FIRAuthWebUtils dictionaryWithHttpArgumentsString:deepLinkURL.query]; + NSString *queryItemLink = URLQueryItems[@"link"]; + if (queryItemLink) { + return queryItemLink; + } + if (!error) { + return nil; + } + NSData *errorData = [URLQueryItems[@"firebaseError"] dataUsingEncoding:NSUTF8StringEncoding]; + NSError *jsonError; + NSDictionary *errorDict = [NSJSONSerialization JSONObjectWithData:errorData + options:0 + error:&jsonError]; + if (jsonError) { + *error = [FIRAuthErrorUtils JSONSerializationErrorWithUnderlyingError:jsonError]; + return nil; + } + *error = [FIRAuthErrorUtils URLResponseErrorWithCode:errorDict[@"code"] + message:errorDict[@"message"]]; + if (!*error) { + NSString *reason; + if (errorDict[@"code"] && errorDict[@"message"]) { + reason = [NSString stringWithFormat:@"[%@] - %@", errorDict[@"code"], errorDict[@"message"]]; + } + *error = [FIRAuthErrorUtils webSignInUserInteractionFailureWithReason:reason]; + } + return nil; +} + +/** @fn getHeadFulLiteURLWithEventID:completion: + @brief Constructs a URL used for opening a headful-lite flow using a given event + ID and session ID. + @param eventID The event ID used for this purpose. + @param sessionID The session ID used when completing the headful lite flow. + @param completion The callback invoked after the URL has been constructed or an error + has been encountered. + */ +- (void)getHeadFulLiteURLWithEventID:(NSString *)eventID + sessionID:(NSString *)sessionID + completion:(FIRHeadfulLiteURLCallBack)completion { + __weak __typeof__(self) weakSelf = self; + [FIRAuthWebUtils + fetchAuthDomainWithRequestConfiguration:_auth.requestConfiguration + completion:^(NSString *_Nullable authDomain, + NSError *_Nullable error) { + if (error) { + if (completion) { + completion(nil, error); + } + return; + } + __strong __typeof__(self) strongSelf = weakSelf; + NSString *bundleID = [NSBundle mainBundle].bundleIdentifier; + NSString *clientID = strongSelf->_auth.app.options.clientID; + NSString *appID = strongSelf->_auth.app.options.googleAppID; + NSString *apiKey = + strongSelf->_auth.requestConfiguration.APIKey; + NSString *tenantID = strongSelf->_auth.tenantID; + id appCheck = + strongSelf->_auth.requestConfiguration.appCheck; + NSMutableDictionary *urlArguments = [@{ + @"apiKey" : apiKey, + @"authType" : kAuthTypeSignInWithRedirect, + @"ibi" : bundleID ?: @"", + @"sessionId" : [strongSelf hashforString:sessionID], + @"v" : [FIRAuthBackend authUserAgent], + @"eventId" : eventID, + @"providerId" : strongSelf->_providerID, + } mutableCopy]; + if (strongSelf->_usingClientIDScheme) { + urlArguments[@"clientId"] = clientID; + } else { + urlArguments[@"appId"] = appID; + } + if (tenantID) { + urlArguments[@"tid"] = tenantID; + } + if (strongSelf.scopes.count) { + urlArguments[@"scopes"] = + [strongSelf.scopes componentsJoinedByString:@","]; + } + if (strongSelf.customParameters.count) { + NSString *customParameters = + [strongSelf customParametersStringWithError:&error]; + if (error) { + completion(nil, error); + return; + } + if (customParameters) { + urlArguments[@"customParameters"] = customParameters; + } + } + if (strongSelf->_auth.requestConfiguration.languageCode) { + urlArguments[@"hl"] = + strongSelf->_auth.requestConfiguration.languageCode; + } + + NSString *argumentsString = [strongSelf + httpArgumentsStringForArgsDictionary:urlArguments]; + NSString *URLString; + if (strongSelf->_auth.requestConfiguration + .emulatorHostAndPort) { + URLString = [NSString + stringWithFormat:kHeadfulLiteEmulatorURLStringFormat, + authDomain, argumentsString]; + } else { + URLString = + [NSString stringWithFormat:kHeadfulLiteURLStringFormat, + authDomain, argumentsString]; + } + NSCharacterSet *set = + [NSCharacterSet URLFragmentAllowedCharacterSet]; + NSURLComponents *components = [[NSURLComponents alloc] + initWithString: + [URLString + stringByAddingPercentEncodingWithAllowedCharacters: + set]]; + if (appCheck) { + [appCheck + getTokenForcingRefresh:false + completion:^( + id _Nonnull tokenResult) { + if (tokenResult.error) { + FIRLogWarning( + kFIRLoggerAuth, @"I-AUT000018", + @"Error getting App Check token; " + @"using placeholder token " + @"instead. Error: %@", + tokenResult.error); + } + NSString *appCheckTokenFragment = [@"fac=" + stringByAppendingString:tokenResult + .token]; + [components + setFragment:appCheckTokenFragment]; + + if (completion) { + completion([components URL], nil); + } + }]; + + } else { + if (completion) { + completion([components URL], nil); + } + } + }]; +} + +/** @fn customParametersString + @brief Returns a JSON string representation of the custom parameters dictionary corresponding + to the OAuthProvider. + @return The JSON string representation of the custom parameters dictionary corresponding + to the OAuthProvider. + */ +- (nullable NSString *)customParametersStringWithError:(NSError *_Nullable *_Nullable)error { + if (!_customParameters.count) { + return nil; + } + + if (!error) { + return nil; + } + NSError *jsonError; + NSData *customParametersJSONData = [NSJSONSerialization dataWithJSONObject:_customParameters + options:0 + error:&jsonError]; + if (jsonError) { + *error = [FIRAuthErrorUtils JSONSerializationErrorWithUnderlyingError:jsonError]; + return nil; + } + + NSString *customParamsRawJSON = [[NSString alloc] initWithData:customParametersJSONData + encoding:NSUTF8StringEncoding]; + return customParamsRawJSON; +} + +/** @fn hashforString: + @brief Returns the SHA256 hash representation of a given string object. + @param string The string for which a SHA256 hash is desired. + @return An hexadecimal string representation of the SHA256 hash. + */ +- (NSString *)hashforString:(NSString *)string { + NSData *sessionIDData = [string dataUsingEncoding:NSUTF8StringEncoding]; + NSMutableData *hashOutputData = [NSMutableData dataWithLength:CC_SHA256_DIGEST_LENGTH]; + if (CC_SHA256(sessionIDData.bytes, (CC_LONG)[sessionIDData length], + hashOutputData.mutableBytes)) { + } + return [self hexStringFromData:hashOutputData]; + ; +} + +/** @fn hexStringFromData: + @brief Returns the hexadecimal string representation of an NSData object. + @param data The NSData object for which a hexadecical string is desired. + @return The hexadecimal string representation of the supplied NSData object. + */ +- (NSString *)hexStringFromData:(NSData *)data { + const unsigned char *dataBuffer = (const unsigned char *)[data bytes]; + NSMutableString *string = [[NSMutableString alloc] init]; + for (unsigned int i = 0; i < data.length; i++) { + [string appendFormat:@"%02lx", (unsigned long)dataBuffer[i]]; + } + return [string copy]; +} + +- (NSString *)httpArgumentsStringForArgsDictionary:(NSDictionary *)argsDictionary { + NSMutableArray *arguments = [NSMutableArray arrayWithCapacity:argsDictionary.count]; + NSString *key; + for (key in argsDictionary) { + NSString *description = [argsDictionary[key] description]; + [arguments + addObject:[NSString + stringWithFormat:@"%@=%@", + [FIRAuthWebUtils stringByUnescapingFromURLArgument:key], + [FIRAuthWebUtils + stringByUnescapingFromURLArgument:description]]]; + } + return [arguments componentsJoinedByString:@"&"]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthCredential.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthCredential.m new file mode 100644 index 0000000..4c197bd --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthCredential.m @@ -0,0 +1,107 @@ +/* + * 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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthCredential.h" + +#import "FirebaseAuth/Sources/AuthProvider/FIRAuthCredential_Internal.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h" + +#if TARGET_OS_IOS +#import "FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthCredential_Internal.h" +#endif + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRPhoneAuthCredential () + +- (nullable instancetype)initWithProvider:(NSString *)provider NS_UNAVAILABLE; + +@end + +@implementation FIRPhoneAuthCredential + +- (instancetype)initWithTemporaryProof:(NSString *)temporaryProof + phoneNumber:(NSString *)phoneNumber + providerID:(NSString *)providerID { + self = [super initWithProvider:providerID]; + if (self) { + _temporaryProof = [temporaryProof copy]; + _phoneNumber = [phoneNumber copy]; + } + return self; +} + +- (nullable instancetype)initWithProvider:(NSString *)provider { + [FIRAuthExceptionUtils + raiseMethodNotImplementedExceptionWithReason:@"Please call the designated initializer."]; + return nil; +} + +- (instancetype)initWithProviderID:(NSString *)providerID + verificationID:(NSString *)verificationID + verificationCode:(NSString *)verificationCode { + self = [super initWithProvider:providerID]; + if (self) { + _verificationID = [verificationID copy]; + _verificationCode = [verificationCode copy]; + } + return self; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + NSString *verificationID = [aDecoder decodeObjectOfClass:[NSString class] + forKey:@"verificationID"]; + NSString *verificationCode = [aDecoder decodeObjectOfClass:[NSString class] + forKey:@"verificationCode"]; + NSString *temporaryProof = [aDecoder decodeObjectOfClass:[NSString class] + forKey:@"temporaryProof"]; + NSString *phoneNumber = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"phoneNumber"]; + if (temporaryProof.length && phoneNumber.length) { + self = [self initWithTemporaryProof:temporaryProof + phoneNumber:phoneNumber + providerID:self.provider]; + } else if (verificationID.length && verificationCode.length) { + self = [self initWithProviderID:self.provider + verificationID:verificationID + verificationCode:verificationCode]; + } else { + self = nil; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:self.verificationID forKey:@"verificationID"]; + [aCoder encodeObject:self.verificationCode forKey:@"verificationCode"]; + [aCoder encodeObject:self.temporaryProof forKey:@"temporaryProof"]; + [aCoder encodeObject:self.phoneNumber forKey:@"phoneNumber"]; +} + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthCredential_Internal.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthCredential_Internal.h new file mode 100644 index 0000000..78c1b74 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthCredential_Internal.h @@ -0,0 +1,73 @@ +/* + * 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 +#if TARGET_OS_IOS + +#import +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthCredential.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @extension FIRPhoneAuthCredential + @brief Internal implementation of FIRAuthCredential for Phone Auth credentials. + */ +@interface FIRPhoneAuthCredential () + +/** @var verificationID + @brief The verification ID obtained from invoking @c verifyPhoneNumber:completion: + */ +@property(nonatomic, readonly, nonnull) NSString *verificationID; + +/** @var verificationCode + @brief The verification code provided by the user. + */ +@property(nonatomic, readonly, nonnull) NSString *verificationCode; + +/** @var temporaryProof + @brief The a temporary proof code perftaining to this credential, returned from the backend. + */ +@property(nonatomic, readonly, nonnull) NSString *temporaryProof; + +/** @var phoneNumber + @brief The a phone number pertaining to this credential, returned from the backend. + */ +@property(nonatomic, readonly, nonnull) NSString *phoneNumber; + +/** @var initWithTemporaryProof:phoneNumber: + @brief Designated Initializer. + @param providerID The provider ID associated with the phone auth credential being created. + */ +- (instancetype)initWithTemporaryProof:(NSString *)temporaryProof + phoneNumber:(NSString *)phoneNumber + providerID:(NSString *)providerID NS_DESIGNATED_INITIALIZER; + +/** @var initWithProviderID:verificationID:verificationCode: + @brief Designated Initializer. + @param providerID The provider ID associated with the phone auth credential being created. + @param verificationID The verification ID associated witht Phone Auth credential being created. + @param verificationCode The verification code associated witht Phone Auth credential being + created. + */ +- (instancetype)initWithProviderID:(NSString *)providerID + verificationID:(NSString *)verificationID + verificationCode:(NSString *)verificationCode NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthProvider.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthProvider.m new file mode 100644 index 0000000..cd28f81 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthProvider.m @@ -0,0 +1,792 @@ +/* + * 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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthSettings.h" +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorResolver.h" +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthProvider.h" +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" + +#import "FirebaseAppCheck/Interop/FIRAppCheckTokenResultInterop.h" +#import "FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.h" +#import "FirebaseAuth/Sources/Auth/FIRAuth_Internal.h" +#import "FirebaseAuth/Sources/Backend/FIRAuthBackend+MultiFactor.h" +#import "FirebaseAuth/Sources/Backend/FIRAuthBackend.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneRequestInfo.h" +#import "FirebaseAuth/Sources/MultiFactor/FIRMultiFactorSession+Internal.h" +#import "FirebaseAuth/Sources/SystemService/FIRAuthAPNSToken.h" +#import "FirebaseAuth/Sources/SystemService/FIRAuthAPNSTokenManager.h" +#import "FirebaseAuth/Sources/SystemService/FIRAuthAppCredential.h" +#import "FirebaseAuth/Sources/SystemService/FIRAuthAppCredentialManager.h" +#import "FirebaseAuth/Sources/SystemService/FIRAuthNotificationManager.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthURLPresenter.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthWebUtils.h" + +#if TARGET_OS_IOS +#import "FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthCredential_Internal.h" +#import "FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorInfo+Internal.h" +#endif + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRReCAPTCHAURLCallBack + @brief The callback invoked at the end of the flow to fetch a reCAPTCHA URL. + @param reCAPTCHAURL The reCAPTCHA URL. + @param error The error that occurred while fetching the reCAPTCHAURL, if any. + */ +typedef void (^FIRReCAPTCHAURLCallBack)(NSURL *_Nullable reCAPTCHAURL, NSError *_Nullable error); + +/** @typedef FIRVerifyClientCallback + @brief The callback invoked at the end of a client verification flow. + @param appCredential credential that proves the identity of the app during a phone + authentication flow. + @param error The error that occurred while verifying the app, if any. + */ +typedef void (^FIRVerifyClientCallback)(FIRAuthAppCredential *_Nullable appCredential, + NSString *_Nullable reCAPTCHAToken, + NSError *_Nullable error); + +/** @typedef FIRFetchAuthDomainCallback + @brief The callback invoked at the end of the flow to fetch the Auth domain. + @param authDomain The Auth domain. + @param error The error that occurred while fetching the auth domain, if any. + */ +typedef void (^FIRFetchAuthDomainCallback)(NSString *_Nullable authDomain, + NSError *_Nullable error); + +/** @var kauthTypeVerifyApp + @brief The auth type to be specified in the app verification request. + */ +static NSString *const kAuthTypeVerifyApp = @"verifyApp"; + +/** @var kCustomUrlSchemePrefix + @brief The prefix to append to the Firebase app ID custom callback scheme.. + */ +static NSString *const kCustomUrlSchemePrefix = @"app-"; + +/** @var kReCAPTCHAURLStringFormat + @brief The format of the URL used to open the reCAPTCHA page during app verification. + */ +NSString *const kReCAPTCHAURLStringFormat = @"https://%@/__/auth/handler?"; + +extern NSString *const FIRPhoneMultiFactorID; + +@implementation FIRPhoneAuthProvider { + /** @var _auth + @brief The auth instance used for verifying the phone number. + */ + FIRAuth *_auth; + + /** @var _callbackScheme + @brief The callback URL scheme used for reCAPTCHA fallback. + */ + NSString *_callbackScheme; + + /** @var _usingClientIDScheme + @brief True if the reverse client ID is registered as a custom URL scheme, and false + otherwise. + */ + BOOL _usingClientIDScheme; +} + +/** @fn initWithAuth: + @brief returns an instance of @c FIRPhoneAuthProvider associated with the provided auth + instance. + @return An Instance of @c FIRPhoneAuthProvider. + */ +- (nullable instancetype)initWithAuth:(FIRAuth *)auth { + self = [super init]; + if (self) { + _auth = auth; + if (_auth.app.options.clientID) { + NSString *reverseClientIDScheme = + [[[_auth.app.options.clientID componentsSeparatedByString:@"."] + reverseObjectEnumerator].allObjects componentsJoinedByString:@"."]; + if ([FIRAuthWebUtils isCallbackSchemeRegisteredForCustomURLScheme:reverseClientIDScheme]) { + _callbackScheme = reverseClientIDScheme; + _usingClientIDScheme = YES; + } + } + if (!_usingClientIDScheme) { + _callbackScheme = [kCustomUrlSchemePrefix + stringByAppendingString:[_auth.app.options.googleAppID + stringByReplacingOccurrencesOfString:@":" + withString:@"-"]]; + } + } + return self; +} + +- (void)verifyPhoneNumber:(NSString *)phoneNumber + UIDelegate:(nullable id)UIDelegate + completion:(nullable FIRVerificationResultCallback)completion { + if (![FIRAuthWebUtils isCallbackSchemeRegisteredForCustomURLScheme:_callbackScheme]) { + [NSException raise:NSInternalInconsistencyException + format:@"Please register custom URL scheme '%@' in the app's Info.plist file.", + _callbackScheme]; + } + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + FIRVerificationResultCallback callBackOnMainThread = + ^(NSString *_Nullable verificationID, NSError *_Nullable error) { + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(verificationID, error); + }); + } + }; + [self + internalVerifyPhoneNumber:phoneNumber + UIDelegate:UIDelegate + completion:^(NSString *_Nullable verificationID, NSError *_Nullable error) { + if (!error) { + callBackOnMainThread(verificationID, nil); + return; + } else { + callBackOnMainThread(nil, error); + return; + } + }]; + }); +} + +- (void)verifyPhoneNumberWithMultiFactorInfo:(FIRPhoneMultiFactorInfo *)phoneMultiFactorInfo + UIDelegate:(nullable id)UIDelegate + multiFactorSession:(nullable FIRMultiFactorSession *)session + completion:(nullable FIRVerificationResultCallback)completion { + session.multiFactorInfo = phoneMultiFactorInfo; + [self verifyPhoneNumber:phoneMultiFactorInfo.phoneNumber + UIDelegate:UIDelegate + multiFactorSession:session + completion:completion]; +} + +- (void)verifyPhoneNumber:(NSString *)phoneNumber + UIDelegate:(nullable id)UIDelegate + multiFactorSession:(nullable FIRMultiFactorSession *)session + completion:(nullable FIRVerificationResultCallback)completion { + if (!session) { + [self verifyPhoneNumber:phoneNumber UIDelegate:UIDelegate completion:completion]; + return; + } + + if (![FIRAuthWebUtils isCallbackSchemeRegisteredForCustomURLScheme:_callbackScheme]) { + [NSException raise:NSInternalInconsistencyException + format:@"Please register custom URL scheme '%@' in the app's Info.plist file.", + _callbackScheme]; + } + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + FIRVerificationResultCallback callBackOnMainThread = + ^(NSString *_Nullable verificationID, NSError *_Nullable error) { + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(verificationID, error); + }); + } + }; + [self + internalVerifyPhoneNumber:phoneNumber + UIDelegate:UIDelegate + multiFactorSession:session + completion:^(NSString *_Nullable verificationID, NSError *_Nullable error) { + if (!error) { + callBackOnMainThread(verificationID, nil); + return; + } else { + callBackOnMainThread(nil, error); + return; + } + }]; + }); +} + +- (FIRPhoneAuthCredential *)credentialWithVerificationID:(NSString *)verificationID + verificationCode:(NSString *)verificationCode { + return [[FIRPhoneAuthCredential alloc] initWithProviderID:FIRPhoneAuthProviderID + verificationID:verificationID + verificationCode:verificationCode]; +} + ++ (instancetype)provider { + return [[self alloc] initWithAuth:[FIRAuth auth]]; +} + ++ (instancetype)providerWithAuth:(FIRAuth *)auth { + return [[self alloc] initWithAuth:auth]; +} + +#pragma mark - Internal Methods + +/** @fn reCAPTCHATokenForURL:error: + @brief Parses the reCAPTCHA URL and returns the reCAPTCHA token. + @param URL The url to be parsed for a reCAPTCHA token. + @param error The error that occurred if any. + @return The reCAPTCHA token if successful. + */ +- (nullable NSString *)reCAPTCHATokenForURL:(NSURL *)URL error:(NSError **_Nonnull)error { + NSURLComponents *actualURLComponents = [NSURLComponents componentsWithURL:URL + resolvingAgainstBaseURL:NO]; + NSArray *queryItems = [actualURLComponents queryItems]; + NSString *deepLinkURL = [FIRAuthWebUtils queryItemValue:@"deep_link_id" from:queryItems]; + NSData *errorData; + if (deepLinkURL) { + actualURLComponents = [NSURLComponents componentsWithString:deepLinkURL]; + queryItems = [actualURLComponents queryItems]; + NSString *recaptchaToken = [FIRAuthWebUtils queryItemValue:@"recaptchaToken" from:queryItems]; + if (recaptchaToken) { + return recaptchaToken; + } + NSString *firebaseError = [FIRAuthWebUtils queryItemValue:@"firebaseError" from:queryItems]; + errorData = [firebaseError dataUsingEncoding:NSUTF8StringEncoding]; + } else { + errorData = nil; + } + if (error != NULL && errorData != nil) { + NSError *jsonError; + NSDictionary *errorDict = [NSJSONSerialization JSONObjectWithData:errorData + options:0 + error:&jsonError]; + if (jsonError) { + *error = [FIRAuthErrorUtils JSONSerializationErrorWithUnderlyingError:jsonError]; + return nil; + } + *error = [FIRAuthErrorUtils URLResponseErrorWithCode:errorDict[@"code"] + message:errorDict[@"message"]]; + if (!*error) { + NSString *reason; + if (errorDict[@"code"] && errorDict[@"message"]) { + reason = + [NSString stringWithFormat:@"[%@] - %@", errorDict[@"code"], errorDict[@"message"]]; + } else { + reason = [NSString stringWithFormat:@"An unknown error occurred with the following " + "response: %@", + deepLinkURL]; + } + *error = [FIRAuthErrorUtils appVerificationUserInteractionFailureWithReason:reason]; + } + } + return nil; +} + +/** @fn internalVerifyPhoneNumber:completion: + @brief Starts the phone number authentication flow by sending a verifcation code to the + specified phone number. + @param phoneNumber The phone number to be verified. + @param completion The callback to be invoked when the verification flow is finished. + */ + +- (void)internalVerifyPhoneNumber:(NSString *)phoneNumber + UIDelegate:(nullable id)UIDelegate + completion:(nullable FIRVerificationResultCallback)completion { + if (!phoneNumber.length) { + completion(nil, [FIRAuthErrorUtils missingPhoneNumberErrorWithMessage:nil]); + return; + } + [_auth.notificationManager + checkNotificationForwardingWithCallback:^(BOOL isNotificationBeingForwarded) { + if (!isNotificationBeingForwarded) { + completion(nil, [FIRAuthErrorUtils notificationNotForwardedError]); + return; + } + FIRVerificationResultCallback callback = + ^(NSString *_Nullable verificationID, NSError *_Nullable error) { + if (completion) { + completion(verificationID, error); + } + }; + [self verifyClientAndSendVerificationCodeToPhoneNumber:phoneNumber + retryOnInvalidAppCredential:YES + UIDelegate:UIDelegate + callback:callback]; + }]; +} + +- (void)internalVerifyPhoneNumber:(NSString *)phoneNumber + UIDelegate:(nullable id)UIDelegate + multiFactorSession:(nullable FIRMultiFactorSession *)session + completion:(nullable FIRVerificationResultCallback)completion { + if (!phoneNumber.length) { + if (completion) { + completion(nil, [FIRAuthErrorUtils missingPhoneNumberErrorWithMessage:nil]); + } + return; + } + [_auth.notificationManager + checkNotificationForwardingWithCallback:^(BOOL isNotificationBeingForwarded) { + if (!isNotificationBeingForwarded) { + if (completion) { + completion(nil, [FIRAuthErrorUtils notificationNotForwardedError]); + } + return; + } + FIRVerificationResultCallback callback = + ^(NSString *_Nullable verificationID, NSError *_Nullable error) { + if (completion) { + completion(verificationID, error); + } + }; + [self verifyClientAndSendVerificationCodeToPhoneNumber:phoneNumber + retryOnInvalidAppCredential:YES + UIDelegate:UIDelegate + multiFactorSession:session + callback:callback]; + }]; +} + +/** @fn verifyClientAndSendVerificationCodeToPhoneNumber:retryOnInvalidAppCredential:callback: + @brief Starts the flow to verify the client via silent push notification. + @param retryOnInvalidAppCredential Whether of not the flow should be retried if an + FIRAuthErrorCodeInvalidAppCredential error is returned from the backend. + @param phoneNumber The phone number to be verified. + @param callback The callback to be invoked on the global work queue when the flow is + finished. + */ +- (void)verifyClientAndSendVerificationCodeToPhoneNumber:(NSString *)phoneNumber + retryOnInvalidAppCredential:(BOOL)retryOnInvalidAppCredential + UIDelegate:(nullable id)UIDelegate + callback:(FIRVerificationResultCallback)callback { + if (_auth.settings.isAppVerificationDisabledForTesting) { + FIRSendVerificationCodeRequest *request = + [[FIRSendVerificationCodeRequest alloc] initWithPhoneNumber:phoneNumber + appCredential:nil + reCAPTCHAToken:nil + requestConfiguration:_auth.requestConfiguration]; + [FIRAuthBackend sendVerificationCode:request + callback:^(FIRSendVerificationCodeResponse *_Nullable response, + NSError *_Nullable error) { + callback(response.verificationID, error); + }]; + return; + } + [self + verifyClientWithUIDelegate:UIDelegate + completion:^(FIRAuthAppCredential *_Nullable appCredential, + NSString *_Nullable reCAPTCHAToken, NSError *_Nullable error) { + if (error) { + callback(nil, error); + return; + } + FIRSendVerificationCodeRequest *_Nullable request; + if (appCredential) { + request = [[FIRSendVerificationCodeRequest alloc] + initWithPhoneNumber:phoneNumber + appCredential:appCredential + reCAPTCHAToken:nil + requestConfiguration:self->_auth.requestConfiguration]; + } else if (reCAPTCHAToken) { + request = [[FIRSendVerificationCodeRequest alloc] + initWithPhoneNumber:phoneNumber + appCredential:nil + reCAPTCHAToken:reCAPTCHAToken + requestConfiguration:self->_auth.requestConfiguration]; + } + if (request) { + [FIRAuthBackend + sendVerificationCode:request + callback:^( + FIRSendVerificationCodeResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + if (error.code == + FIRAuthErrorCodeInvalidAppCredential) { + if (retryOnInvalidAppCredential) { + [self->_auth + .appCredentialManager clearCredential]; + [self + verifyClientAndSendVerificationCodeToPhoneNumber: + phoneNumber + retryOnInvalidAppCredential: + NO + UIDelegate: + UIDelegate + callback: + callback]; + return; + } + callback( + nil, + [FIRAuthErrorUtils + unexpectedResponseWithDeserializedResponse: + nil + underlyingError: + error]); + return; + } + callback(nil, error); + return; + } + callback(response.verificationID, nil); + }]; + } + }]; +} + +- (void)verifyClientAndSendVerificationCodeToPhoneNumber:(NSString *)phoneNumber + retryOnInvalidAppCredential:(BOOL)retryOnInvalidAppCredential + UIDelegate:(nullable id)UIDelegate + multiFactorSession:(nullable FIRMultiFactorSession *)session + callback:(FIRVerificationResultCallback)callback { + if (_auth.settings.isAppVerificationDisabledForTesting) { + FIRSendVerificationCodeRequest *request = + [[FIRSendVerificationCodeRequest alloc] initWithPhoneNumber:phoneNumber + appCredential:nil + reCAPTCHAToken:nil + requestConfiguration:_auth.requestConfiguration]; + [FIRAuthBackend sendVerificationCode:request + callback:^(FIRSendVerificationCodeResponse *_Nullable response, + NSError *_Nullable error) { + callback(response.verificationID, error); + }]; + return; + } + + [self + verifyClientWithUIDelegate:UIDelegate + completion:^(FIRAuthAppCredential *_Nullable appCredential, + NSString *_Nullable reCAPTCHAToken, NSError *_Nullable error) { + if (error) { + if (callback) { + callback(nil, error); + } + return; + } + + NSString *IDToken = session.IDToken; + FIRAuthProtoStartMFAPhoneRequestInfo *startMFARequestInfo = + [[FIRAuthProtoStartMFAPhoneRequestInfo alloc] + initWithPhoneNumber:phoneNumber + appCredential:appCredential + reCAPTCHAToken:reCAPTCHAToken]; + if (session.IDToken) { + FIRStartMFAEnrollmentRequest *request = + [[FIRStartMFAEnrollmentRequest alloc] + initWithIDToken:IDToken + enrollmentInfo:startMFARequestInfo + requestConfiguration:self->_auth.requestConfiguration]; + [FIRAuthBackend + startMultiFactorEnrollment:request + callback:^(FIRStartMFAEnrollmentResponse + *_Nullable response, + NSError *_Nullable error) { + if (error) { + if (error.code == + FIRAuthErrorCodeInvalidAppCredential) { + if (retryOnInvalidAppCredential) { + [self->_auth.appCredentialManager + clearCredential]; + [self + verifyClientAndSendVerificationCodeToPhoneNumber: + phoneNumber + retryOnInvalidAppCredential: + NO + UIDelegate: + UIDelegate + multiFactorSession: + session + callback: + callback]; + return; + } + if (callback) { + callback( + nil, + [FIRAuthErrorUtils + unexpectedResponseWithDeserializedResponse: + nil + underlyingError: + error]); + } + return; + } else { + if (callback) { + callback(nil, error); + } + } + } else { + if (callback) { + callback( + response.enrollmentResponse.sessionInfo, + nil); + } + } + }]; + } else { + FIRStartMFASignInRequest *request = [[FIRStartMFASignInRequest alloc] + initWithMFAPendingCredential:session.MFAPendingCredential + MFAEnrollmentID:session.multiFactorInfo.UID + signInInfo:startMFARequestInfo + requestConfiguration:self->_auth.requestConfiguration]; + [FIRAuthBackend + startMultiFactorSignIn:request + callback:^( + FIRStartMFASignInResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + if (error.code == + FIRAuthErrorCodeInvalidAppCredential) { + if (retryOnInvalidAppCredential) { + [self->_auth + .appCredentialManager clearCredential]; + [self + verifyClientAndSendVerificationCodeToPhoneNumber: + phoneNumber + retryOnInvalidAppCredential: + NO + UIDelegate: + UIDelegate + multiFactorSession: + session + callback: + callback]; + return; + } + if (callback) { + callback( + nil, + [FIRAuthErrorUtils + unexpectedResponseWithDeserializedResponse: + nil + underlyingError: + error]); + } + return; + } else { + if (callback) { + callback(nil, error); + } + } + } else { + if (callback) { + callback(response.responseInfo.sessionInfo, nil); + } + } + }]; + } + }]; +} + +/** @fn verifyClientWithCompletion:completion: + @brief Continues the flow to verify the client via silent push notification. + @param completion The callback to be invoked when the client verification flow is finished. + */ +- (void)verifyClientWithUIDelegate:(nullable id)UIDelegate + completion:(FIRVerifyClientCallback)completion { +// Remove the simulator check below after FCM supports APNs in simulators +#if TARGET_OS_SIMULATOR + if (@available(iOS 16, *)) { + NSDictionary *environment = [[NSProcessInfo processInfo] environment]; + if ((environment[@"XCTestConfigurationFilePath"] == nil)) { + [self reCAPTCHAFlowWithUIDelegate:UIDelegate completion:completion]; + return; + } + } +#endif + + if (_auth.appCredentialManager.credential) { + completion(_auth.appCredentialManager.credential, nil, nil); + return; + } + [_auth.tokenManager getTokenWithCallback:^(FIRAuthAPNSToken *_Nullable token, + NSError *_Nullable error) { + if (!token) { + [self reCAPTCHAFlowWithUIDelegate:UIDelegate completion:completion]; + return; + } + FIRVerifyClientRequest *request = + [[FIRVerifyClientRequest alloc] initWithAppToken:token.string + isSandbox:token.type == FIRAuthAPNSTokenTypeSandbox + requestConfiguration:self->_auth.requestConfiguration]; + [FIRAuthBackend + verifyClient:request + callback:^(FIRVerifyClientResponse *_Nullable response, NSError *_Nullable error) { + if (error) { + NSError *underlyingError = error.userInfo[NSUnderlyingErrorKey]; + BOOL isInvalidAppCredential = + error.code == FIRAuthErrorCodeInternalError && + underlyingError.code == FIRAuthErrorCodeInvalidAppCredential; + if (error.code != FIRAuthErrorCodeMissingAppToken && !isInvalidAppCredential) { + completion(nil, nil, error); + return; + } else { + [self reCAPTCHAFlowWithUIDelegate:UIDelegate completion:completion]; + return; + } + } + NSTimeInterval timeout = [response.suggestedTimeOutDate timeIntervalSinceNow]; + [self->_auth.appCredentialManager + didStartVerificationWithReceipt:response.receipt + timeout:timeout + callback:^(FIRAuthAppCredential *credential) { + if (!credential.secret) { + FIRLogWarning(kFIRLoggerAuth, @"I-AUT000014", + @"Failed to receive remote notification " + @"to verify app identity within " + @"%.0f second(s), falling back to " + @"reCAPTCHA verification.", + timeout); + [self reCAPTCHAFlowWithUIDelegate:UIDelegate + completion:completion]; + return; + } + completion(credential, nil, nil); + }]; + }]; + }]; +} + +- (void)reCAPTCHAFlowWithUIDelegate:(nullable id)UIDelegate + completion:(FIRVerifyClientCallback)completion { + NSString *eventID = [FIRAuthWebUtils randomStringWithLength:10]; + [self + reCAPTCHAURLWithEventID:eventID + completion:^(NSURL *_Nullable reCAPTCHAURL, NSError *_Nullable error) { + if (error) { + completion(nil, nil, error); + return; + } + FIRAuthURLCallbackMatcher callbackMatcher = + ^BOOL(NSURL *_Nullable callbackURL) { + return [FIRAuthWebUtils isExpectedCallbackURL:callbackURL + eventID:eventID + authType:kAuthTypeVerifyApp + callbackScheme:self->_callbackScheme]; + }; + [self->_auth.authURLPresenter + presentURL:reCAPTCHAURL + UIDelegate:UIDelegate + callbackMatcher:callbackMatcher + completion:^(NSURL *_Nullable callbackURL, NSError *_Nullable error) { + if (error) { + completion(nil, nil, error); + return; + } + NSError *reCAPTCHAError; + NSString *reCAPTCHAToken = + [self reCAPTCHATokenForURL:callbackURL error:&reCAPTCHAError]; + if (!reCAPTCHAToken) { + completion(nil, nil, reCAPTCHAError); + return; + } else { + completion(nil, reCAPTCHAToken, nil); + return; + } + }]; + }]; +} + +/** @fn reCAPTCHAURLWithEventID:completion: + @brief Constructs a URL used for opening a reCAPTCHA app verification flow using a given event + ID. + @param eventID The event ID used for this purpose. + @param completion The callback invoked after the URL has been constructed or an error + has been encountered. + */ +- (void)reCAPTCHAURLWithEventID:(NSString *)eventID completion:(FIRReCAPTCHAURLCallBack)completion { + [FIRAuthWebUtils + fetchAuthDomainWithRequestConfiguration:_auth.requestConfiguration + completion:^(NSString *_Nullable authDomain, + NSError *_Nullable error) { + if (error) { + if (completion) { + completion(nil, error); + } + return; + } + NSString *bundleID = [NSBundle mainBundle].bundleIdentifier; + NSString *clientID = self->_auth.app.options.clientID; + NSString *appID = self->_auth.app.options.googleAppID; + NSString *apiKey = self->_auth.requestConfiguration.APIKey; + id appCheck = + self->_auth.requestConfiguration.appCheck; + + NSMutableArray *queryItems = [@[ + [NSURLQueryItem queryItemWithName:@"apiKey" value:apiKey], + [NSURLQueryItem queryItemWithName:@"authType" + value:kAuthTypeVerifyApp], + [NSURLQueryItem queryItemWithName:@"ibi" + value:bundleID ?: @""], + [NSURLQueryItem + queryItemWithName:@"v" + value:[FIRAuthBackend authUserAgent]], + [NSURLQueryItem queryItemWithName:@"eventId" value:eventID] + ] mutableCopy]; + if (self->_usingClientIDScheme) { + [queryItems + addObject:[NSURLQueryItem queryItemWithName:@"clientId" + value:clientID]]; + } else { + [queryItems + addObject:[NSURLQueryItem queryItemWithName:@"appId" + value:appID]]; + } + if (self->_auth.requestConfiguration.languageCode) { + [queryItems + addObject:[NSURLQueryItem + queryItemWithName:@"hl" + value:self->_auth + .requestConfiguration + .languageCode]]; + } + NSURLComponents *components = [[NSURLComponents alloc] + initWithString: + [NSString stringWithFormat:kReCAPTCHAURLStringFormat, + authDomain]]; + [components setQueryItems:queryItems]; + if (appCheck) { + [appCheck + getTokenForcingRefresh:false + completion:^( + id _Nonnull tokenResult) { + if (tokenResult.error) { + FIRLogWarning( + kFIRLoggerAuth, @"I-AUT000018", + @"Error getting App Check token; " + @"using placeholder token " + @"instead. Error: %@", + tokenResult.error); + } + NSString *appCheckTokenFragment = [@"fac=" + stringByAppendingString:tokenResult + .token]; + [components + setFragment:appCheckTokenFragment]; + if (completion) { + completion([components URL], nil); + } + }]; + } else { + if (completion) { + completion([components URL], nil); + } + } + }]; +} + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Twitter/FIRTwitterAuthCredential.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Twitter/FIRTwitterAuthCredential.h new file mode 100644 index 0000000..ad25dc6 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Twitter/FIRTwitterAuthCredential.h @@ -0,0 +1,48 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/AuthProvider/FIRAuthCredential_Internal.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRTwitterAuthCredential + @brief Internal implementation of FIRAuthCredential for Twitter credentials. + */ +@interface FIRTwitterAuthCredential : FIRAuthCredential + +/** @property token + @brief The Twitter OAuth token. + */ +@property(nonatomic, readonly) NSString *token; + +/** @property secret + @brief The Twitter OAuth secret. + */ +@property(nonatomic, readonly) NSString *secret; + +/** @fn initWithToken:secret: + @brief Designated initializer. + @param token The Twitter OAuth token. + @param secret The Twitter OAuth secret. + */ +- (nullable instancetype)initWithToken:(NSString *)token + secret:(NSString *)secret NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Twitter/FIRTwitterAuthCredential.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Twitter/FIRTwitterAuthCredential.m new file mode 100644 index 0000000..255e344 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Twitter/FIRTwitterAuthCredential.m @@ -0,0 +1,74 @@ +/* + * 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 "FirebaseAuth/Sources/AuthProvider/Twitter/FIRTwitterAuthCredential.h" + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRTwitterAuthProvider.h" + +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRTwitterAuthCredential () + +- (nullable instancetype)initWithProvider:(NSString *)provider NS_UNAVAILABLE; + +@end + +@implementation FIRTwitterAuthCredential + +- (nullable instancetype)initWithProvider:(NSString *)provider { + [FIRAuthExceptionUtils + raiseMethodNotImplementedExceptionWithReason:@"Please call the designated initializer."]; + return nil; +} + +- (nullable instancetype)initWithToken:(NSString *)token secret:(NSString *)secret { + self = [super initWithProvider:FIRTwitterAuthProviderID]; + if (self) { + _token = [token copy]; + _secret = [secret copy]; + } + return self; +} + +- (void)prepareVerifyAssertionRequest:(FIRVerifyAssertionRequest *)request { + request.providerAccessToken = _token; + request.providerOAuthTokenSecret = _secret; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + NSString *token = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"token"]; + NSString *secret = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"secret"]; + self = [self initWithToken:token secret:secret]; + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:self.token forKey:@"token"]; + [aCoder encodeObject:self.secret forKey:@"secret"]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Twitter/FIRTwitterAuthProvider.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Twitter/FIRTwitterAuthProvider.m new file mode 100644 index 0000000..27483e0 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/AuthProvider/Twitter/FIRTwitterAuthProvider.m @@ -0,0 +1,40 @@ +/* + * 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 "FirebaseAuth/Sources/Public/FirebaseAuth/FIRTwitterAuthProvider.h" + +#import "FirebaseAuth/Sources/AuthProvider/Twitter/FIRTwitterAuthCredential.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h" + +// FIRTwitterAuthProviderID is defined in FIRAuthProvider.m. + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRTwitterAuthProvider + +- (instancetype)init { + [FIRAuthExceptionUtils + raiseMethodNotImplementedExceptionWithReason:@"This class is not meant to be initialized."]; + return nil; +} + ++ (FIRAuthCredential *)credentialWithToken:(NSString *)token secret:(NSString *)secret { + return [[FIRTwitterAuthCredential alloc] initWithToken:token secret:secret]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthBackend+MultiFactor.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthBackend+MultiFactor.h new file mode 100644 index 0000000..8ed6253 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthBackend+MultiFactor.h @@ -0,0 +1,125 @@ +/* + * Copyright 2019 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/LICENSE2.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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Backend/FIRAuthBackend.h" +#import "FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFARequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFAResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRStartMFAEnrollmentResponseCallback + @brief The type of block used to return the result of a call to the startMFAEnroll endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. +*/ +typedef void (^FIRStartMFAEnrollmentResponseCallback)( + FIRStartMFAEnrollmentResponse *_Nullable response, NSError *_Nullable error); + +/** @typedef FIRFinalizeMFAEnrollmentResponseCallback + @brief The type of block used to return the result of a call to the finalizeMFAEnroll endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. +*/ +typedef void (^FIRFinalizeMFAEnrollmentResponseCallback)( + FIRFinalizeMFAEnrollmentResponse *_Nullable response, NSError *_Nullable error); + +/** @typedef FIRStartMFASignInResponseCallback + @brief The type of block used to return the result of a call to the startMFASignIn endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. +*/ +typedef void (^FIRStartMFASignInResponseCallback)(FIRStartMFASignInResponse *_Nullable response, + NSError *_Nullable error); + +/** @typedef FIRFinalizeMFASignInResponseCallback + @brief The type of block used to return the result of a call to the finalizeMFASignIn endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. +*/ +typedef void (^FIRFinalizeMFASignInResponseCallback)( + FIRFinalizeMFASignInResponse *_Nullable response, NSError *_Nullable error); + +/** @typedef FIRWithdrawMFAResponseCallback + @brief The type of block used to return the result of a call to the MFAUnenroll endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. +*/ +typedef void (^FIRWithdrawMFAResponseCallback)(FIRWithdrawMFAResponse *_Nullable response, + NSError *_Nullable error); + +@interface FIRAuthBackend (MultiFactor) + +/** @fn startMultiFactorEnrollment:callback: + @brief Calls the startMFAEnrollment endpoint. + @param request The request parameters. + @param callback The callback. +*/ ++ (void)startMultiFactorEnrollment:(FIRStartMFAEnrollmentRequest *)request + callback:(FIRStartMFAEnrollmentResponseCallback)callback; + +/** @fn finalizeMultiFactorEnrollment:callback: + @brief Calls the finalizeMultiFactorEnrollment endpoint. + @param request The request parameters. + @param callback The callback. +*/ ++ (void)finalizeMultiFactorEnrollment:(FIRFinalizeMFAEnrollmentRequest *)request + callback:(FIRFinalizeMFAEnrollmentResponseCallback)callback; + +/** @fn startMultiFactorSignIn:callback: + @brief Calls the startMultiFactorSignIn endpoint. + @param request The request parameters. + @param callback The callback. +*/ ++ (void)startMultiFactorSignIn:(FIRStartMFASignInRequest *)request + callback:(FIRStartMFASignInResponseCallback)callback; + +/** @fn finalizeMultiFactorSignIn:callback: + @brief Calls the finalizeMultiFactorSignIn endpoint. + @param request The request parameters. + @param callback The callback. +*/ ++ (void)finalizeMultiFactorSignIn:(FIRFinalizeMFASignInRequest *)request + callback:(FIRFinalizeMFASignInResponseCallback)callback; + +/** @fn withdrawMultiFactor:callback: + @brief Calls the withdrawMultiFactor endpoint. + @param request The request parameters. + @param callback The callback. +*/ ++ (void)withdrawMultiFactor:(FIRWithdrawMFARequest *)request + callback:(FIRWithdrawMFAResponseCallback)callback; + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthBackend+MultiFactor.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthBackend+MultiFactor.m new file mode 100644 index 0000000..7c305a4 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthBackend+MultiFactor.m @@ -0,0 +1,96 @@ +/* + * Copyright 2019 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/LICENSE2.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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Backend/FIRAuthBackend+MultiFactor.h" + +@implementation FIRAuthBackend (MultiFactor) + ++ (void)startMultiFactorEnrollment:(FIRStartMFAEnrollmentRequest *)request + callback:(FIRStartMFAEnrollmentResponseCallback)callback { + FIRStartMFAEnrollmentResponse *response = [[FIRStartMFAEnrollmentResponse alloc] init]; + [[self implementation] postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + } else { + callback(response, nil); + } + }]; +} + ++ (void)finalizeMultiFactorEnrollment:(FIRFinalizeMFAEnrollmentRequest *)request + callback:(FIRFinalizeMFAEnrollmentResponseCallback)callback { + FIRFinalizeMFAEnrollmentResponse *response = [[FIRFinalizeMFAEnrollmentResponse alloc] init]; + [[self implementation] postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + } else { + callback(response, nil); + } + }]; +} + ++ (void)startMultiFactorSignIn:(FIRStartMFASignInRequest *)request + callback:(FIRStartMFASignInResponseCallback)callback { + FIRStartMFASignInResponse *response = [[FIRStartMFASignInResponse alloc] init]; + [[self implementation] postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + } else { + callback(response, nil); + } + }]; +} + ++ (void)finalizeMultiFactorSignIn:(FIRFinalizeMFASignInRequest *)request + callback:(FIRFinalizeMFASignInResponseCallback)callback { + FIRFinalizeMFASignInResponse *response = [[FIRFinalizeMFASignInResponse alloc] init]; + [[self implementation] postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + } else { + callback(response, nil); + } + }]; +} + ++ (void)withdrawMultiFactor:(FIRWithdrawMFARequest *)request + callback:(FIRWithdrawMFAResponseCallback)callback { + FIRWithdrawMFAResponse *response = [[FIRWithdrawMFAResponse alloc] init]; + [[self implementation] postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + } else { + callback(response, nil); + } + }]; +} + +@end + +#endif diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthBackend.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthBackend.h new file mode 100644 index 0000000..e02cc45 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthBackend.h @@ -0,0 +1,651 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" + +@class FIRAuthRequestConfiguration; +@class FIRCreateAuthURIRequest; +@class FIRCreateAuthURIResponse; +@class FIRDeleteAccountRequest; +@class FIRDeleteAccountResponse; +@class FIREmailLinkSignInRequest; +@class FIREmailLinkSignInResponse; +@class FIRGetAccountInfoRequest; +@class FIRGetAccountInfoResponse; +@class FIRGetProjectConfigRequest; +@class FIRGetProjectConfigResponse; +@class FIRGetOOBConfirmationCodeRequest; +@class FIRGetOOBConfirmationCodeResponse; +@class FIRResetPasswordRequest; +@class FIRResetPasswordResponse; +@class FIRSecureTokenRequest; +@class FIRSecureTokenResponse; +@class FIRSetAccountInfoRequest; +@class FIRSetAccountInfoResponse; +@class FIRVerifyAssertionRequest; +@class FIRVerifyAssertionResponse; +@class FIRVerifyClientRequest; +@class FIRVerifyClientResponse; +@class FIRVerifyCustomTokenRequest; +@class FIRVerifyCustomTokenResponse; +@class FIRVerifyPasswordRequest; +@class FIRVerifyPasswordResponse; +@class FIRVerifyPhoneNumberRequest; +@class FIRVerifyPhoneNumberResponse; +@class FIRSendVerificationCodeRequest; +@class FIRSendVerificationCodeResponse; +@class FIRSignInWithGameCenterRequest; +@class FIRSignInWithGameCenterResponse; +@class FIRSignUpNewUserRequest; +@class FIRSignUpNewUserResponse; +@class FIRRevokeTokenRequest; +@class FIRRevokeTokenResponse; + +@protocol FIRAuthBackendImplementation; +@protocol FIRAuthBackendRPCIssuer; + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRAuthBackendRPCIssuerCompletionHandler + @brief The type of block used to return the result of a call to an endpoint. + @param data The HTTP response body. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. + */ +typedef void (^FIRAuthBackendRPCIssuerCompletionHandler)(NSData *_Nullable data, + NSError *_Nullable error); + +/** @typedef FIRCreateAuthURIResponseCallback + @brief The type of block used to return the result of a call to the createAuthURI + endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. + */ +typedef void (^FIRCreateAuthURIResponseCallback)(FIRCreateAuthURIResponse *_Nullable response, + NSError *_Nullable error); + +/** @typedef FIRGetAccountInfoResponseCallback + @brief The type of block used to return the result of a call to the getAccountInfo + endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. + */ +typedef void (^FIRGetAccountInfoResponseCallback)(FIRGetAccountInfoResponse *_Nullable response, + NSError *_Nullable error); + +/** @typedef FIRGetProjectConfigResponseCallback + @brief The type of block used to return the result of a call to the getProjectInfo + endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. + */ +typedef void (^FIRGetProjectConfigResponseCallback)(FIRGetProjectConfigResponse *_Nullable response, + NSError *_Nullable error); + +/** @typedef FIRSetAccountInfoResponseCallback + @brief The type of block used to return the result of a call to the setAccountInfo + endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. + */ +typedef void (^FIRSetAccountInfoResponseCallback)(FIRSetAccountInfoResponse *_Nullable response, + NSError *_Nullable error); + +/** @typedef FIRSecureTokenResponseCallback + @brief The type of block used to return the result of a call to the token endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. + */ +typedef void (^FIRSecureTokenResponseCallback)(FIRSecureTokenResponse *_Nullable response, + NSError *_Nullable error); + +/** @typedef FIRVerifyAssertionResponseCallback + @brief The type of block used to return the result of a call to the verifyAssertion + endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. + */ +typedef void (^FIRVerifyAssertionResponseCallback)(FIRVerifyAssertionResponse *_Nullable response, + NSError *_Nullable error); + +/** @typedef FIRVerifyPasswordResponseCallback + @brief The type of block used to return the result of a call to the verifyPassword + endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. + */ +typedef void (^FIRVerifyPasswordResponseCallback)(FIRVerifyPasswordResponse *_Nullable response, + NSError *_Nullable error); + +/** @typedef FIREmailLinkSigninResponseCallback + @brief The type of block used to return the result of a call to the emailLinkSignin + endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. + */ +typedef void (^FIREmailLinkSigninResponseCallback)(FIREmailLinkSignInResponse *_Nullable response, + NSError *_Nullable error); + +/** @typedef FIRVerifyCustomTokenResponseCallback + @brief The type of block used to return the result of a call to the verifyCustomToken + endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. + */ +typedef void (^FIRVerifyCustomTokenResponseCallback)( + FIRVerifyCustomTokenResponse *_Nullable response, NSError *_Nullable error); + +/** @typedef FIRDeleteCallBack + @brief The type of block called when a request delete account has finished. + @param error The error which occurred, or nil if the request was successful. + */ +typedef void (^FIRDeleteCallBack)(NSError *_Nullable error); + +/** @typedef FIRGetOOBConfirmationCodeResponseCallback + @brief The type of block used to return the result of a call to the getOOBConfirmationCode + endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. + */ +typedef void (^FIRGetOOBConfirmationCodeResponseCallback)( + FIRGetOOBConfirmationCodeResponse *_Nullable response, NSError *_Nullable error); + +/** @typedef FIRSignupNewUserCallback + @brief The type of block used to return the result of a call to the signupNewUser endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. + */ +typedef void (^FIRSignupNewUserCallback)(FIRSignUpNewUserResponse *_Nullable response, + NSError *_Nullable error); + +/** @typedef FIRResetPasswordCallback + @brief The type of block used to return the result of a call to the resetPassword endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. + */ +typedef void (^FIRResetPasswordCallback)(FIRResetPasswordResponse *_Nullable response, + NSError *_Nullable error); + +/** @typedef FIRSendVerificationCodeResponseCallback + @brief The type of block used to return the result of a call to the sendVerificationCode + endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. + */ +typedef void (^FIRSendVerificationCodeResponseCallback)( + FIRSendVerificationCodeResponse *_Nullable response, NSError *_Nullable error); + +/** @typedef FIRVerifyPhoneNumberResponseCallback + @brief The type of block used to return the result of a call to the verifyPhoneNumber endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. + */ +typedef void (^FIRVerifyPhoneNumberResponseCallback)( + FIRVerifyPhoneNumberResponse *_Nullable response, NSError *_Nullable error); + +/** @typedef FIRVerifyClientResponseCallback + @brief The type of block used to return the result of a call to the verifyClient endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. + */ +typedef void (^FIRVerifyClientResponseCallback)(FIRVerifyClientResponse *_Nullable response, + NSError *_Nullable error); + +/** @typedef FIRRevokeTokenResponseCallback + @brief The type of block used to return the result of a call to the revokeToken endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. + */ +typedef void (^FIRRevokeTokenResponseCallback)(FIRRevokeTokenResponse *_Nullable response, + NSError *_Nullable error); + +/** @typedef FIRSignInWithGameCenterResponseCallback + @brief The type of block used to return the result of a call to the SignInWithGameCenter + endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. + */ +typedef void (^FIRSignInWithGameCenterResponseCallback)( + FIRSignInWithGameCenterResponse *_Nullable response, NSError *_Nullable error); + +/** @class FIRAuthBackend + @brief Simple static class with methods representing the backend RPCs. + @remarks All callback blocks passed as method parameters are invoked asynchronously on the + global work queue in the future. See + https://github.com/firebase/firebase-ios-sdk/tree/master/FirebaseAuth/Docs/threading.md + */ +@interface FIRAuthBackend : NSObject + +/** @fn authUserAgent + @brief Retrieves the Firebase Auth user agent. + @return The Firebase Auth user agent. + */ ++ (NSString *)authUserAgent; + ++ (id)implementation; + +/** @fn setBackendImplementation: + @brief Changes the default backend implementation to something else. + @param backendImplementation The backend implementation to use. + @remarks This is not, generally, safe to call in a scenario where other backend requests may + be occuring. This is specifically to help mock the backend for testing purposes. + */ ++ (void)setBackendImplementation:(id)backendImplementation; + +/** @fn setDefaultBackendImplementationWithRPCIssuer: + @brief Uses the default backend implementation, but with a custom RPC issuer. + @param RPCIssuer The RPC issuer to use. If @c nil, will use the default implementation. + @remarks This is not, generally, safe to call in a scenario where other backend requests may + be occuring. This is specifically to help test the backend interfaces (requests, responses, + and shared FIRAuthBackend logic.) + */ ++ (void)setDefaultBackendImplementationWithRPCIssuer: + (nullable id)RPCIssuer; + +/** @fn createAuthURI:callback: + @brief Calls the createAuthURI endpoint, which is responsible for creating the URI used by the + IdP to authenticate the user. + @param request The request parameters. + @param callback The callback. + */ ++ (void)createAuthURI:(FIRCreateAuthURIRequest *)request + callback:(FIRCreateAuthURIResponseCallback)callback; + +/** @fn getAccountInfo:callback: + @brief Calls the getAccountInfo endpoint, which returns account info for a given account. + @param request The request parameters. + @param callback The callback. + */ ++ (void)getAccountInfo:(FIRGetAccountInfoRequest *)request + callback:(FIRGetAccountInfoResponseCallback)callback; + +/** @fn getProjectConfig:callback: + @brief Calls the getProjectConfig endpoint, which returns configuration information for a given + project. + @param request An object wrapping the backend get request. + @param callback The callback. + */ ++ (void)getProjectConfig:(FIRGetProjectConfigRequest *)request + callback:(FIRGetProjectConfigResponseCallback)callback; + +/** @fn setAccountInfo:callback: + @brief Calls the setAccountInfo endpoint, which is responsible for setting account info for a + user, for example, to sign up a new user with email and password. + @param request The request parameters. + @param callback The callback. + */ ++ (void)setAccountInfo:(FIRSetAccountInfoRequest *)request + callback:(FIRSetAccountInfoResponseCallback)callback; + +/** @fn verifyAssertion:callback: + @brief Calls the verifyAssertion endpoint, which is responsible for authenticating a + user who has IDP-related credentials (an ID Token, an Access Token, etc.) + @param request The request parameters. + @param callback The callback. + */ ++ (void)verifyAssertion:(FIRVerifyAssertionRequest *)request + callback:(FIRVerifyAssertionResponseCallback)callback; + +/** @fn verifyCustomToken:callback: + @brief Calls the verifyCustomToken endpoint, which is responsible for authenticating a + user who has BYOAuth credentials (a self-signed token using their BYOAuth private key.) + @param request The request parameters. + @param callback The callback. + */ ++ (void)verifyCustomToken:(FIRVerifyCustomTokenRequest *)request + callback:(FIRVerifyCustomTokenResponseCallback)callback; + +/** @fn verifyPassword:callback: + @brief Calls the verifyPassword endpoint, which is responsible for authenticating a + user who has email and password credentials. + @param request The request parameters. + @param callback The callback. + */ ++ (void)verifyPassword:(FIRVerifyPasswordRequest *)request + callback:(FIRVerifyPasswordResponseCallback)callback; + +/** @fn emailLinkSignin:callback: + @brief Calls the emailLinkSignin endpoint, which is responsible for authenticating a + user through passwordless sign-in. + @param request The request parameters. + @param callback The callback. + */ ++ (void)emailLinkSignin:(FIREmailLinkSignInRequest *)request + callback:(FIREmailLinkSigninResponseCallback)callback; + +/** @fn secureToken:callback: + @brief Calls the token endpoint, which is responsible for performing STS token exchanges and + token refreshes. + @param request The request parameters. + @param callback The callback. + */ ++ (void)secureToken:(FIRSecureTokenRequest *)request + callback:(FIRSecureTokenResponseCallback)callback; + +/** @fn getOOBConfirmationCode:callback: + @brief Calls the getOOBConfirmationCode endpoint, which is responsible for sending email change + request emails, and password reset emails. + @param request The request parameters. + @param callback The callback. + */ ++ (void)getOOBConfirmationCode:(FIRGetOOBConfirmationCodeRequest *)request + callback:(FIRGetOOBConfirmationCodeResponseCallback)callback; + +/** @fn signUpNewUser: + @brief Calls the signUpNewUser endpoint, which is responsible anonymously signing up a user + or signing in a user anonymously. + @param request The request parameters. + @param callback The callback. + */ ++ (void)signUpNewUser:(FIRSignUpNewUserRequest *)request + callback:(FIRSignupNewUserCallback)callback; + +/** @fn resetPassword:callback + @brief Calls the resetPassword endpoint, which is responsible for resetting a user's password + given an OOB code and new password. + @param request The request parameters. + @param callback The callback. + */ ++ (void)resetPassword:(FIRResetPasswordRequest *)request + callback:(FIRResetPasswordCallback)callback; + +/** @fn deleteAccount: + @brief Calls the DeleteAccount endpoint, which is responsible for deleting a user. + @param request The request parameters. + @param callback The callback. + */ ++ (void)deleteAccount:(FIRDeleteAccountRequest *)request callback:(FIRDeleteCallBack)callback; + +/** @fn SignInWithGameCenter:callback: + @brief Calls the SignInWithGameCenter endpoint, which is responsible for authenticating a user + who has Game Center credentials. + @param request The request parameters. + @param callback The callback. + */ ++ (void)signInWithGameCenter:(FIRSignInWithGameCenterRequest *)request + callback:(FIRSignInWithGameCenterResponseCallback)callback; + +#if TARGET_OS_IOS +/** @fn sendVerificationCode:callback: + @brief Calls the sendVerificationCode endpoint, which is responsible for sending the + verification code to a phone number specified in the request parameters. + @param request The request parameters. + @param callback The callback. + */ ++ (void)sendVerificationCode:(FIRSendVerificationCodeRequest *)request + callback:(FIRSendVerificationCodeResponseCallback)callback; + +/** @fn verifyPhoneNumber:callback: + @brief Calls the verifyPhoneNumber endpoint, which is responsible for sending the verification + code to a phone number specified in the request parameters. + @param request The request parameters. + @param callback The callback. + */ ++ (void)verifyPhoneNumber:(FIRVerifyPhoneNumberRequest *)request + callback:(FIRVerifyPhoneNumberResponseCallback)callback; + +/** @fn verifyClient:callback: + @brief Calls the verifyClient endpoint, which is responsible for sending the silent push + notification used for app validation to the device provided in the request parameters. + @param request The request parameters. + @param callback The callback. + */ ++ (void)verifyClient:(FIRVerifyClientRequest *)request + callback:(FIRVerifyClientResponseCallback)callback; + +#endif + +/** @fn revokeToken:callback: + @brief Calls the revokeToken endpoint, which is responsible for revoking the given token + provided in the request parameters. + @param request The request parameters. + @param callback The callback. + */ ++ (void)revokeToken:(FIRRevokeTokenRequest *)request + callback:(FIRRevokeTokenResponseCallback)callback; + +@end + +/** @protocol FIRAuthBackendRPCIssuer + @brief Used to make FIRAuthBackend + */ +@protocol FIRAuthBackendRPCIssuer + +/** @fn asyncPostToURLWithRequestConfiguration:URL:body:contentType:completionHandler: + @brief Asynchronously seXnds a POST request. + @param requestConfiguration The request to be made. + @param URL The request URL. + @param body Request body. + @param contentType Content type of the body. + @param handler provided that handles POST response. Invoked asynchronously on the auth global + work queue in the future. + */ +- (void)asyncPostToURLWithRequestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + URL:(NSURL *)URL + body:(nullable NSData *)body + contentType:(NSString *)contentType + completionHandler:(FIRAuthBackendRPCIssuerCompletionHandler)handler; + +@end + +/** @protocol FIRAuthBackendImplementation + @brief Used to make FIRAuthBackend provide a layer of indirection to an actual RPC-based backend + or a mock backend. + */ +@protocol FIRAuthBackendImplementation + +/** @fn createAuthURI:callback: + @brief Calls the createAuthURI endpoint, which is responsible for creating the URI used by the + IdP to authenticate the user. + @param request The request parameters. + @param callback The callback. + */ +- (void)createAuthURI:(FIRCreateAuthURIRequest *)request + callback:(FIRCreateAuthURIResponseCallback)callback; + +/** @fn getAccountInfo:callback: + @brief Calls the getAccountInfo endpoint, which returns account info for a given account. + @param request The request parameters. + @param callback The callback. + */ +- (void)getAccountInfo:(FIRGetAccountInfoRequest *)request + callback:(FIRGetAccountInfoResponseCallback)callback; + +/** @fn getProjectConfig:callback: + @brief Calls the getProjectInfo endpoint, which returns configuration information for a given + project. + @param request The request parameters. + @param callback The callback. + */ +- (void)getProjectConfig:(FIRGetProjectConfigRequest *)request + callback:(FIRGetProjectConfigResponseCallback)callback; + +/** @fn setAccountInfo:callback: + @brief Calls the setAccountInfo endpoint, which is responsible for setting account info for a + user, for example, to sign up a new user with email and password. + @param request The request parameters. + @param callback The callback. + */ +- (void)setAccountInfo:(FIRSetAccountInfoRequest *)request + callback:(FIRSetAccountInfoResponseCallback)callback; + +/** @fn verifyAssertion:callback: + @brief Calls the verifyAssertion endpoint, which is responsible for authenticating a + user who has IDP-related credentials (an ID Token, an Access Token, etc.) + @param request The request parameters. + @param callback The callback. + */ +- (void)verifyAssertion:(FIRVerifyAssertionRequest *)request + callback:(FIRVerifyAssertionResponseCallback)callback; + +/** @fn verifyCustomToken:callback: + @brief Calls the verifyCustomToken endpoint, which is responsible for authenticating a + user who has BYOAuth credentials (a self-signed token using their BYOAuth private key.) + @param request The request parameters. + @param callback The callback. + */ +- (void)verifyCustomToken:(FIRVerifyCustomTokenRequest *)request + callback:(FIRVerifyCustomTokenResponseCallback)callback; + +/** @fn verifyPassword:callback: + @brief Calls the verifyPassword endpoint, which is responsible for authenticating a + user who has email and password credentials. + @param request The request parameters. + @param callback The callback. + */ +- (void)verifyPassword:(FIRVerifyPasswordRequest *)request + callback:(FIRVerifyPasswordResponseCallback)callback; + +/** @fn emailLinkSignin:callback: + @brief Calls the emailLinkSignin endpoint, which is responsible for authenticating a + user through passwordless sign-in. + @param request The request parameters. + @param callback The callback. + */ +- (void)emailLinkSignin:(FIREmailLinkSignInRequest *)request + callback:(FIREmailLinkSigninResponseCallback)callback; + +/** @fn secureToken:callback: + @brief Calls the token endpoint, which is responsible for performing STS token exchanges and + token refreshes. + @param request The request parameters. + @param callback The callback. + */ +- (void)secureToken:(FIRSecureTokenRequest *)request + callback:(FIRSecureTokenResponseCallback)callback; + +/** @fn getOOBConfirmationCode:callback: + @brief Calls the getOOBConfirmationCode endpoint, which is responsible for sending email change + request emails, email sign-in link emails, and password reset emails. + @param request The request parameters. + @param callback The callback. + */ +- (void)getOOBConfirmationCode:(FIRGetOOBConfirmationCodeRequest *)request + callback:(FIRGetOOBConfirmationCodeResponseCallback)callback; + +/** @fn signUpNewUser: + @brief Calls the signUpNewUser endpoint, which is responsible anonymously signing up a user + or signing in a user anonymously. + @param request The request parameters. + @param callback The callback. + */ +- (void)signUpNewUser:(FIRSignUpNewUserRequest *)request + callback:(FIRSignupNewUserCallback)callback; + +/** @fn deleteAccount: + @brief Calls the DeleteAccount endpoint, which is responsible for deleting a user. + @param request The request parameters. + @param callback The callback. + */ +- (void)deleteAccount:(FIRDeleteAccountRequest *)request callback:(FIRDeleteCallBack)callback; + +#if TARGET_OS_IOS +/** @fn sendVerificationCode:callback: + @brief Calls the sendVerificationCode endpoint, which is responsible for sending the + verification code to a phone number specified in the request parameters. + @param request The request parameters. + @param callback The callback. + */ +- (void)sendVerificationCode:(FIRSendVerificationCodeRequest *)request + callback:(FIRSendVerificationCodeResponseCallback)callback; + +/** @fn verifyPhoneNumber:callback: + @brief Calls the verifyPhoneNumber endpoint, which is responsible for sending the verification + code to a phone number specified in the request parameters. + @param request The request parameters. + @param callback The callback. + */ +- (void)verifyPhoneNumber:(FIRVerifyPhoneNumberRequest *)request + callback:(FIRVerifyPhoneNumberResponseCallback)callback; + +/** @fn verifyClient:callback: + @brief Calls the verifyClient endpoint, which is responsible for sending the silent push + notification used for app validation to the device provided in the request parameters. + @param request The request parameters. + @param callback The callback. + */ +- (void)verifyClient:(FIRVerifyClientRequest *)request + callback:(FIRVerifyClientResponseCallback)callback; + +#endif + +/** @fn revokeToken:callback: + @brief Calls the revokeToken endpoint, which is responsible for revoking the given token + provided in the request parameters. + @param request The request parameters. + @param callback The callback. + */ +- (void)revokeToken:(FIRRevokeTokenRequest *)request + callback:(FIRRevokeTokenResponseCallback)callback; + +/** @fn SignInWithGameCenter:callback: + @brief Calls the SignInWithGameCenter endpoint, which is responsible for authenticating a user + who has Game Center credentials. + @param request The request parameters. + @param callback The callback. + */ +- (void)signInWithGameCenter:(FIRSignInWithGameCenterRequest *)request + callback:(FIRSignInWithGameCenterResponseCallback)callback; + +/** @fn resetPassword:callback + @brief Calls the resetPassword endpoint, which is responsible for resetting a user's password + given an OOB code and new password. + @param request The request parameters. + @param callback The callback. + */ +- (void)resetPassword:(FIRResetPasswordRequest *)request + callback:(FIRResetPasswordCallback)callback; + +/** @fn postWithRequest:response:callback: + @brief Calls the RPC using HTTP POST. + @remarks Possible error responses: + @see FIRAuthInternalErrorCodeRPCRequestEncodingError + @see FIRAuthInternalErrorCodeJSONSerializationError + @see FIRAuthInternalErrorCodeNetworkError + @see FIRAuthInternalErrorCodeUnexpectedErrorResponse + @see FIRAuthInternalErrorCodeUnexpectedResponse + @see FIRAuthInternalErrorCodeRPCResponseDecodingError + @param request The request. + @param response The empty response to be filled. + @param callback The callback for both success and failure. +*/ +- (void)postWithRequest:(id)request + response:(id)response + callback:(void (^)(NSError *_Nullable error))callback; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthBackend.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthBackend.m new file mode 100644 index 0000000..eacf6d3 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthBackend.m @@ -0,0 +1,1539 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/FIRAuthBackend.h" + +#if SWIFT_PACKAGE +@import GTMSessionFetcherCore; +#else +#import +#import +#endif + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FirebaseAuth.h" + +#import "FirebaseAppCheck/Interop/FIRAppCheckInterop.h" +#import "FirebaseAppCheck/Interop/FIRAppCheckTokenResultInterop.h" +#import "FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.h" +#import "FirebaseAuth/Sources/Auth/FIRAuth_Internal.h" +#import "FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthCredential_Internal.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRRevokeTokenRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRRevokeTokenResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberResponse.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h" +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" + +#if TARGET_OS_IOS +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthProvider.h" + +#import "FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthCredential_Internal.h" +#import "FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorInfo+Internal.h" +#endif + +NS_ASSUME_NONNULL_BEGIN + +/** @var kClientVersionHeader + @brief HTTP header name for the client version. + */ +static NSString *const kClientVersionHeader = @"X-Client-Version"; + +/** @var kIosBundleIdentifierHeader + @brief HTTP header name for iOS bundle ID. + */ +static NSString *const kIosBundleIdentifierHeader = @"X-Ios-Bundle-Identifier"; + +/** @var kFirebaseLocalHeader + @brief HTTP header name for the firebase locale. + */ +static NSString *const kFirebaseLocalHeader = @"X-Firebase-Locale"; + +/** @var kFirebaseAppIDHeader + @brief HTTP header name for the Firebase app ID. + */ +static NSString *const kFirebaseAppIDHeader = @"X-Firebase-GMPID"; + +/** @var kFirebaseHeartbeatHeader + @brief HTTP header name for a Firebase heartbeats payload. + */ +static NSString *const kFirebaseHeartbeatHeader = @"X-Firebase-Client"; + +/** @var kFirebaseAuthCoreFrameworkMarker + @brief The marker in the HTTP header that indicates the request comes from Firebase Auth Core. + */ +static NSString *const kFirebaseAuthCoreFrameworkMarker = @"FirebaseCore-iOS"; + +/** @var kJSONContentType + @brief The value of the HTTP content-type header for JSON payloads. + */ +static NSString *const kJSONContentType = @"application/json"; + +/** @var kErrorDataKey + @brief Key for error data in NSError returned by @c GTMSessionFetcher. + */ +static NSString *const kErrorDataKey = @"data"; + +/** @var kErrorKey + @brief The key for the "error" value in JSON responses from the server. + */ +static NSString *const kErrorKey = @"error"; + +/** @var kErrorsKey + @brief The key for the "errors" value in JSON responses from the server. + */ +static NSString *const kErrorsKey = @"errors"; + +/** @var kReasonKey + @brief The key for the "reason" value in JSON responses from the server. + */ +static NSString *const kReasonKey = @"reason"; + +/** @var kInvalidKeyReasonValue + @brief The value for the "reason" key indicating an invalid API Key was received by the server. + */ +static NSString *const kInvalidKeyReasonValue = @"keyInvalid"; + +/** @var kAppNotAuthorizedReasonValue + @brief The value for the "reason" key indicating the App is not authorized to use Firebase + Authentication. + */ +static NSString *const kAppNotAuthorizedReasonValue = @"ipRefererBlocked"; + +/** @var kErrorMessageKey + @brief The key for an error's "message" value in JSON responses from the server. + */ +static NSString *const kErrorMessageKey = @"message"; + +/** @var kReturnIDPCredentialErrorMessageKey + @brief The key for "errorMessage" value in JSON responses from the server, In case + returnIDPCredential of a verifyAssertion request is set to @YES. + */ +static NSString *const kReturnIDPCredentialErrorMessageKey = @"errorMessage"; + +/** @var kUserNotFoundErrorMessage + @brief This is the error message returned when the user is not found, which means the user + account has been deleted given the token was once valid. + */ +static NSString *const kUserNotFoundErrorMessage = @"USER_NOT_FOUND"; + +/** @var kUserDeletedErrorMessage + @brief This is the error message the server will respond with if the user entered an invalid + email address. + */ +static NSString *const kUserDeletedErrorMessage = @"EMAIL_NOT_FOUND"; + +/** @var kInvalidLocalIDErrorMessage + @brief This is the error message the server responds with if the user local id in the id token + does not exit. + */ +static NSString *const kInvalidLocalIDErrorMessage = @"INVALID_LOCAL_ID"; + +/** @var kUserTokenExpiredErrorMessage + @brief The error returned by the server if the token issue time is older than the account's + valid_since time. + */ +static NSString *const kUserTokenExpiredErrorMessage = @"TOKEN_EXPIRED"; + +/** @var kTooManyRequestsErrorMessage + @brief This is the error message the server will respond with if too many requests were made to + a server method. + */ +static NSString *const kTooManyRequestsErrorMessage = @"TOO_MANY_ATTEMPTS_TRY_LATER"; + +/** @var kInvalidCustomTokenErrorMessage + @brief This is the error message the server will respond with if there is a validation error + with the custom token. + */ +static NSString *const kInvalidCustomTokenErrorMessage = @"INVALID_CUSTOM_TOKEN"; + +/** @var kCustomTokenMismatch + @brief This is the error message the server will respond with if the service account and API key + belong to different projects. + */ +static NSString *const kCustomTokenMismatch = @"CREDENTIAL_MISMATCH"; + +/** @var kInvalidCredentialErrorMessage + @brief This is the error message the server responds with if the IDP token or requestUri is + invalid. + */ +static NSString *const kInvalidCredentialErrorMessage = @"INVALID_IDP_RESPONSE"; + +/** @var kUserDisabledErrorMessage + @brief The error returned by the server if the user account is diabled. + */ +static NSString *const kUserDisabledErrorMessage = @"USER_DISABLED"; + +/** @var kOperationNotAllowedErrorMessage + @brief This is the error message the server will respond with if Admin disables IDP specified by + provider. + */ +static NSString *const kOperationNotAllowedErrorMessage = @"OPERATION_NOT_ALLOWED"; + +/** @var kPasswordLoginDisabledErrorMessage + @brief This is the error message the server responds with if password login is disabled. + */ +static NSString *const kPasswordLoginDisabledErrorMessage = @"PASSWORD_LOGIN_DISABLED"; + +/** @var kEmailAlreadyInUseErrorMessage + @brief This is the error message the server responds with if the email address already exists. + */ +static NSString *const kEmailAlreadyInUseErrorMessage = @"EMAIL_EXISTS"; + +/** @var kInvalidEmailErrorMessage + @brief The error returned by the server if the email is invalid. + */ +static NSString *const kInvalidEmailErrorMessage = @"INVALID_EMAIL"; + +/** @var kInvalidIdentifierErrorMessage + @brief The error returned by the server if the identifier is invalid. + */ +static NSString *const kInvalidIdentifierErrorMessage = @"INVALID_IDENTIFIER"; + +/** @var kWrongPasswordErrorMessage + @brief This is the error message the server will respond with if the user entered a wrong + password. + */ +static NSString *const kWrongPasswordErrorMessage = @"INVALID_PASSWORD"; + +/** @var kCredentialTooOldErrorMessage + @brief This is the error message the server responds with if account change is attempted 5 + minutes after signing in. + */ +static NSString *const kCredentialTooOldErrorMessage = @"CREDENTIAL_TOO_OLD_LOGIN_AGAIN"; + +/** @var kFederatedUserIDAlreadyLinkedMessage + @brief This is the error message the server will respond with if the federated user ID has been + already linked with another account. + */ +static NSString *const kFederatedUserIDAlreadyLinkedMessage = @"FEDERATED_USER_ID_ALREADY_LINKED"; + +/** @var kInvalidUserTokenErrorMessage + @brief This is the error message the server responds with if user's saved auth credential is + invalid, and the user needs to sign in again. + */ +static NSString *const kInvalidUserTokenErrorMessage = @"INVALID_ID_TOKEN"; + +/** @var kWeakPasswordErrorMessagePrefix + @brief This is the prefix for the error message the server responds with if user's new password + to be set is too weak. + */ +static NSString *const kWeakPasswordErrorMessagePrefix = @"WEAK_PASSWORD"; + +/** @var kExpiredActionCodeErrorMessage + @brief This is the error message the server will respond with if the action code is expired. + */ +static NSString *const kExpiredActionCodeErrorMessage = @"EXPIRED_OOB_CODE"; + +/** @var kInvalidActionCodeErrorMessage + @brief This is the error message the server will respond with if the action code is invalid. + */ +static NSString *const kInvalidActionCodeErrorMessage = @"INVALID_OOB_CODE"; + +/** @var kMissingEmailErrorMessage + @brief This is the error message the server will respond with if the email address is missing + during a "send password reset email" attempt. + */ +static NSString *const kMissingEmailErrorMessage = @"MISSING_EMAIL"; + +/** @var kInvalidSenderEmailErrorMessage + @brief This is the error message the server will respond with if the sender email is invalid + during a "send password reset email" attempt. + */ +static NSString *const kInvalidSenderEmailErrorMessage = @"INVALID_SENDER"; + +/** @var kInvalidMessagePayloadErrorMessage + @brief This is the error message the server will respond with if there are invalid parameters in + the payload during a "send password reset email" attempt. + */ +static NSString *const kInvalidMessagePayloadErrorMessage = @"INVALID_MESSAGE_PAYLOAD"; + +/** @var kInvalidRecipientEmailErrorMessage + @brief This is the error message the server will respond with if the recipient email is invalid. + */ +static NSString *const kInvalidRecipientEmailErrorMessage = @"INVALID_RECIPIENT_EMAIL"; + +/** @var kMissingIosBundleIDErrorMessage + @brief This is the error message the server will respond with if iOS bundle ID is missing but + the iOS App store ID is provided. + */ +static NSString *const kMissingIosBundleIDErrorMessage = @"MISSING_IOS_BUNDLE_ID"; + +/** @var kMissingAndroidPackageNameErrorMessage + @brief This is the error message the server will respond with if Android Package Name is missing + but the flag indicating the app should be installed is set to true. + */ +static NSString *const kMissingAndroidPackageNameErrorMessage = @"MISSING_ANDROID_PACKAGE_NAME"; + +/** @var kUnauthorizedDomainErrorMessage + @brief This is the error message the server will respond with if the domain of the continue URL + specified is not allowlisted in the Firebase console. + */ +static NSString *const kUnauthorizedDomainErrorMessage = @"UNAUTHORIZED_DOMAIN"; + +/** @var kInvalidProviderIDErrorMessage + @brief This is the error message the server will respond with if the provider id given for the + web operation is invalid. + */ +static NSString *const kInvalidProviderIDErrorMessage = @"INVALID_PROVIDER_ID"; + +/** @var kInvalidDynamicLinkDomainErrorMessage + @brief This is the error message the server will respond with if the dynamic link domain + provided in the request is invalid. + */ +static NSString *const kInvalidDynamicLinkDomainErrorMessage = @"INVALID_DYNAMIC_LINK_DOMAIN"; + +/** @var kInvalidContinueURIErrorMessage + @brief This is the error message the server will respond with if the continue URL provided in + the request is invalid. + */ +static NSString *const kInvalidContinueURIErrorMessage = @"INVALID_CONTINUE_URI"; + +/** @var kMissingContinueURIErrorMessage + @brief This is the error message the server will respond with if there was no continue URI + present in a request that required one. + */ +static NSString *const kMissingContinueURIErrorMessage = @"MISSING_CONTINUE_URI"; + +/** @var kInvalidPhoneNumberErrorMessage + @brief This is the error message the server will respond with if an incorrectly formatted phone + number is provided. + */ +static NSString *const kInvalidPhoneNumberErrorMessage = @"INVALID_PHONE_NUMBER"; + +/** @var kInvalidVerificationCodeErrorMessage + @brief This is the error message the server will respond with if an invalid verification code is + provided. + */ +static NSString *const kInvalidVerificationCodeErrorMessage = @"INVALID_CODE"; + +/** @var kInvalidSessionInfoErrorMessage + @brief This is the error message the server will respond with if an invalid session info + (verification ID) is provided. + */ +static NSString *const kInvalidSessionInfoErrorMessage = @"INVALID_SESSION_INFO"; + +/** @var kSessionExpiredErrorMessage + @brief This is the error message the server will respond with if the SMS code has expired before + it is used. + */ +static NSString *const kSessionExpiredErrorMessage = @"SESSION_EXPIRED"; + +/** @var kMissingOrInvalidNonceErrorMessage + @brief This is the error message the server will respond with if the nonce is missing or + invalid. + */ +static NSString *const kMissingOrInvalidNonceErrorMessage = @"MISSING_OR_INVALID_NONCE"; + +/** @var kMissingAppTokenErrorMessage + @brief This is the error message the server will respond with if the APNS token is missing in a + verifyClient request. + */ +static NSString *const kMissingAppTokenErrorMessage = @"MISSING_IOS_APP_TOKEN"; + +/** @var kMissingAppCredentialErrorMessage + @brief This is the error message the server will respond with if the app token is missing in a + sendVerificationCode request. + */ +static NSString *const kMissingAppCredentialErrorMessage = @"MISSING_APP_CREDENTIAL"; + +/** @var kInvalidAppCredentialErrorMessage + @brief This is the error message the server will respond with if the app credential in a + sendVerificationCode request is invalid. + */ +static NSString *const kInvalidAppCredentialErrorMessage = @"INVALID_APP_CREDENTIAL"; + +/** @var kQuoutaExceededErrorMessage + @brief This is the error message the server will respond with if the quota for SMS text messages + has been exceeded for the project. + */ +static NSString *const kQuoutaExceededErrorMessage = @"QUOTA_EXCEEDED"; + +/** @var kAppNotVerifiedErrorMessage + @brief This is the error message the server will respond with if Firebase could not verify the + app during a phone authentication flow. + */ +static NSString *const kAppNotVerifiedErrorMessage = @"APP_NOT_VERIFIED"; + +/** @var kMissingClientIdentifier + @brief This is the error message the server will respond with if Firebase could not verify the + app during a phone authentication flow when a real phone number is used and app verification + is disabled for testing. + */ +static NSString *const kMissingClientIdentifier = @"MISSING_CLIENT_IDENTIFIER"; + +/** @var kCaptchaCheckFailedErrorMessage + @brief This is the error message the server will respond with if the reCAPTCHA token provided is + invalid. + */ +static NSString *const kCaptchaCheckFailedErrorMessage = @"CAPTCHA_CHECK_FAILED"; + +/** @var kTenantIDMismatch + @brief This is the error message the server will respond with if the tenant id mismatches. + */ +static NSString *const kTenantIDMismatch = @"TENANT_ID_MISMATCH"; + +/** @var kUnsupportedTenantOperation + @brief This is the error message the server will respond with if the operation does not support + multi-tenant. + */ +static NSString *const kUnsupportedTenantOperation = @"UNSUPPORTED_TENANT_OPERATION"; + +/** @var kMissingMFAPendingCredentialErrorMessage + @brief This is the error message the server will respond with if the MFA pending credential is + missing. + */ +static NSString *const kMissingMFAPendingCredentialErrorMessage = @"MISSING_MFA_PENDING_CREDENTIAL"; + +/** @var kMissingMFAEnrollmentIDErrorMessage + @brief This is the error message the server will respond with if the MFA enrollment ID is missing. + */ +static NSString *const kMissingMFAEnrollmentIDErrorMessage = @"MISSING_MFA_ENROLLMENT_ID"; + +/** @var kInvalidMFAPendingCredentialErrorMessage + @brief This is the error message the server will respond with if the MFA pending credential is + invalid. + */ +static NSString *const kInvalidMFAPendingCredentialErrorMessage = @"INVALID_MFA_PENDING_CREDENTIAL"; + +/** @var kMFAEnrollmentNotFoundErrorMessage + @brief This is the error message the server will respond with if the MFA enrollment info is not + found. + */ +static NSString *const kMFAEnrollmentNotFoundErrorMessage = @"MFA_ENROLLMENT_NOT_FOUND"; + +/** @var kAdminOnlyOperationErrorMessage + @brief This is the error message the server will respond with if the operation is admin only. + */ +static NSString *const kAdminOnlyOperationErrorMessage = @"ADMIN_ONLY_OPERATION"; + +/** @var kUnverifiedEmailErrorMessage + @brief This is the error message the server will respond with if the email is unverified. + */ +static NSString *const kUnverifiedEmailErrorMessage = @"UNVERIFIED_EMAIL"; + +/** @var kSecondFactorExistsErrorMessage + @brief This is the error message the server will respond with if the second factor already exsists. + */ +static NSString *const kSecondFactorExistsErrorMessage = @"SECOND_FACTOR_EXISTS"; + +/** @var kSecondFactorLimitExceededErrorMessage + @brief This is the error message the server will respond with if the number of second factor + reaches the limit. + */ +static NSString *const kSecondFactorLimitExceededErrorMessage = @"SECOND_FACTOR_LIMIT_EXCEEDED"; + +/** @var kUnsupportedFirstFactorErrorMessage + @brief This is the error message the server will respond with if the first factor doesn't support + MFA. + */ +static NSString *const kUnsupportedFirstFactorErrorMessage = @"UNSUPPORTED_FIRST_FACTOR"; + +/** @var kBlockingCloudFunctionErrorResponse + @brief This is the error message blocking Cloud Functions. + */ +static NSString *const kBlockingCloudFunctionErrorResponse = @"BLOCKING_FUNCTION_ERROR_RESPONSE"; + +/** @var kEmailChangeNeedsVerificationErrorMessage + @brief This is the error message the server will respond with if changing an unverified email. + */ +static NSString *const kEmailChangeNeedsVerificationErrorMessage = + @"EMAIL_CHANGE_NEEDS_VERIFICATION"; + +/** @var kInvalidPendingToken + @brief Generic IDP error codes. + */ +static NSString *const kInvalidPendingToken = @"INVALID_PENDING_TOKEN"; + +/** @var gBackendImplementation + @brief The singleton FIRAuthBackendImplementation instance to use. + */ +static id gBackendImplementation; + +/** @class FIRAuthBackendRPCImplementation + @brief The default RPC-based backend implementation. + */ +@interface FIRAuthBackendRPCImplementation : NSObject + +/** @property RPCIssuer + @brief An instance of FIRAuthBackendRPCIssuer for making RPC requests. Allows the RPC + requests/responses to be easily faked. + */ +@property(nonatomic, strong) id RPCIssuer; + +@end + +@implementation FIRAuthBackend + ++ (id)implementation { + if (!gBackendImplementation) { + gBackendImplementation = [[FIRAuthBackendRPCImplementation alloc] init]; + } + return gBackendImplementation; +} + ++ (void)setBackendImplementation:(id)backendImplementation { + gBackendImplementation = backendImplementation; +} + ++ (void)setDefaultBackendImplementationWithRPCIssuer: + (nullable id)RPCIssuer { + FIRAuthBackendRPCImplementation *defaultImplementation = + [[FIRAuthBackendRPCImplementation alloc] init]; + if (RPCIssuer) { + defaultImplementation.RPCIssuer = RPCIssuer; + } + gBackendImplementation = defaultImplementation; +} + ++ (void)createAuthURI:(FIRCreateAuthURIRequest *)request + callback:(FIRCreateAuthURIResponseCallback)callback { + [[self implementation] createAuthURI:request callback:callback]; +} + ++ (void)getAccountInfo:(FIRGetAccountInfoRequest *)request + callback:(FIRGetAccountInfoResponseCallback)callback { + [[self implementation] getAccountInfo:request callback:callback]; +} + ++ (void)getProjectConfig:(FIRGetProjectConfigRequest *)request + callback:(FIRGetProjectConfigResponseCallback)callback { + [[self implementation] getProjectConfig:request callback:callback]; +} + ++ (void)setAccountInfo:(FIRSetAccountInfoRequest *)request + callback:(FIRSetAccountInfoResponseCallback)callback { + [[self implementation] setAccountInfo:request callback:callback]; +} + ++ (void)verifyAssertion:(FIRVerifyAssertionRequest *)request + callback:(FIRVerifyAssertionResponseCallback)callback { + [[self implementation] verifyAssertion:request callback:callback]; +} + ++ (void)verifyCustomToken:(FIRVerifyCustomTokenRequest *)request + callback:(FIRVerifyCustomTokenResponseCallback)callback { + [[self implementation] verifyCustomToken:request callback:callback]; +} + ++ (void)verifyPassword:(FIRVerifyPasswordRequest *)request + callback:(FIRVerifyPasswordResponseCallback)callback { + [[self implementation] verifyPassword:request callback:callback]; +} + ++ (void)emailLinkSignin:(FIREmailLinkSignInRequest *)request + callback:(FIREmailLinkSigninResponseCallback)callback { + [[self implementation] emailLinkSignin:request callback:callback]; +} + ++ (void)secureToken:(FIRSecureTokenRequest *)request + callback:(FIRSecureTokenResponseCallback)callback { + [[self implementation] secureToken:request callback:callback]; +} + ++ (void)getOOBConfirmationCode:(FIRGetOOBConfirmationCodeRequest *)request + callback:(FIRGetOOBConfirmationCodeResponseCallback)callback { + [[self implementation] getOOBConfirmationCode:request callback:callback]; +} + ++ (void)signUpNewUser:(FIRSignUpNewUserRequest *)request + callback:(FIRSignupNewUserCallback)callback { + [[self implementation] signUpNewUser:request callback:callback]; +} + ++ (void)deleteAccount:(FIRDeleteAccountRequest *)request callback:(FIRDeleteCallBack)callback { + [[self implementation] deleteAccount:request callback:callback]; +} + ++ (void)signInWithGameCenter:(FIRSignInWithGameCenterRequest *)request + callback:(FIRSignInWithGameCenterResponseCallback)callback { + [[self implementation] signInWithGameCenter:request callback:callback]; +} + +#if TARGET_OS_IOS ++ (void)sendVerificationCode:(FIRSendVerificationCodeRequest *)request + callback:(FIRSendVerificationCodeResponseCallback)callback { + [[self implementation] sendVerificationCode:request callback:callback]; +} + ++ (void)verifyPhoneNumber:(FIRVerifyPhoneNumberRequest *)request + callback:(FIRVerifyPhoneNumberResponseCallback)callback { + [[self implementation] verifyPhoneNumber:request callback:callback]; +} + ++ (void)verifyClient:(id)request callback:(FIRVerifyClientResponseCallback)callback { + [[self implementation] verifyClient:request callback:callback]; +} + +#endif + ++ (void)revokeToken:(FIRRevokeTokenRequest *)request + callback:(FIRRevokeTokenResponseCallback)callback { + [[self implementation] revokeToken:request callback:callback]; +} + ++ (void)resetPassword:(FIRResetPasswordRequest *)request + callback:(FIRResetPasswordCallback)callback { + [[self implementation] resetPassword:request callback:callback]; +} + ++ (NSString *)authUserAgent { + return [NSString stringWithFormat:@"FirebaseAuth.iOS/%@ %@", FIRFirebaseVersion(), + GTMFetcherStandardUserAgentString(nil)]; +} + ++ (void)requestWithURL:(NSURL *)URL + contentType:(NSString *)contentType + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + completionHandler:(void (^)(NSMutableURLRequest *_Nullable))completionHandler { + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL]; + [request setValue:contentType forHTTPHeaderField:@"Content-Type"]; + NSString *additionalFrameworkMarker = + requestConfiguration.additionalFrameworkMarker ?: kFirebaseAuthCoreFrameworkMarker; + NSString *clientVersion = [NSString + stringWithFormat:@"iOS/FirebaseSDK/%@/%@", FIRFirebaseVersion(), additionalFrameworkMarker]; + [request setValue:clientVersion forHTTPHeaderField:kClientVersionHeader]; + NSString *bundleID = [[NSBundle mainBundle] bundleIdentifier]; + [request setValue:bundleID forHTTPHeaderField:kIosBundleIdentifierHeader]; + NSString *appID = requestConfiguration.appID; + [request setValue:appID forHTTPHeaderField:kFirebaseAppIDHeader]; + [request setValue:FIRHeaderValueFromHeartbeatsPayload( + [requestConfiguration.heartbeatLogger flushHeartbeatsIntoPayload]) + forHTTPHeaderField:kFirebaseHeartbeatHeader]; + NSArray *preferredLocalizations = [NSBundle mainBundle].preferredLocalizations; + if (preferredLocalizations.count) { + NSString *acceptLanguage = preferredLocalizations.firstObject; + [request setValue:acceptLanguage forHTTPHeaderField:@"Accept-Language"]; + } + NSString *languageCode = requestConfiguration.languageCode; + if (languageCode.length) { + [request setValue:languageCode forHTTPHeaderField:kFirebaseLocalHeader]; + } + if (requestConfiguration.appCheck) { + [requestConfiguration.appCheck + getTokenForcingRefresh:false + completion:^(id _Nonnull tokenResult) { + if (tokenResult.error) { + FIRLogWarning(kFIRLoggerAuth, @"I-AUT000018", + @"Error getting App Check token; using placeholder token " + @"instead. Error: %@", + tokenResult.error); + } + [request setValue:tokenResult.token + forHTTPHeaderField:@"X-Firebase-AppCheck"]; + completionHandler(request); + }]; + } else { + completionHandler(request); + } +} + +@end + +@interface FIRAuthBackendRPCIssuerImplementation : NSObject +@end + +@implementation FIRAuthBackendRPCIssuerImplementation { + /** @var The session fetcher service. + */ + GTMSessionFetcherService *_fetcherService; +} + +- (instancetype)init { + self = [super init]; + if (self) { + _fetcherService = [[GTMSessionFetcherService alloc] init]; + _fetcherService.userAgent = [FIRAuthBackend authUserAgent]; + _fetcherService.callbackQueue = FIRAuthGlobalWorkQueue(); + + // Avoid reusing the session to prevent + // https://github.com/firebase/firebase-ios-sdk/issues/1261 + _fetcherService.reuseSession = NO; + } + return self; +} + +- (void)asyncPostToURLWithRequestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + URL:(NSURL *)URL + body:(nullable NSData *)body + contentType:(NSString *)contentType + completionHandler: + (void (^)(NSData *_Nullable, NSError *_Nullable))handler { + [FIRAuthBackend requestWithURL:URL + contentType:contentType + requestConfiguration:requestConfiguration + completionHandler:^(NSMutableURLRequest *request) { + GTMSessionFetcher *fetcher = [self->_fetcherService fetcherWithRequest:request]; + NSString *emulatorHostAndPort = requestConfiguration.emulatorHostAndPort; + if (emulatorHostAndPort) { + fetcher.allowLocalhostRequest = YES; + fetcher.allowedInsecureSchemes = @[ @"http" ]; + } + fetcher.bodyData = body; + [fetcher beginFetchWithCompletionHandler:handler]; + }]; +} + +@end + +@implementation FIRAuthBackendRPCImplementation + +- (instancetype)init { + self = [super init]; + if (self) { + _RPCIssuer = [[FIRAuthBackendRPCIssuerImplementation alloc] init]; + } + return self; +} + +- (void)createAuthURI:(FIRCreateAuthURIRequest *)request + callback:(FIRCreateAuthURIResponseCallback)callback { + FIRCreateAuthURIResponse *response = [[FIRCreateAuthURIResponse alloc] init]; + [self postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + } else { + callback(response, nil); + } + }]; +} + +- (void)getAccountInfo:(FIRGetAccountInfoRequest *)request + callback:(FIRGetAccountInfoResponseCallback)callback { + FIRGetAccountInfoResponse *response = [[FIRGetAccountInfoResponse alloc] init]; + [self postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + } else { + callback(response, nil); + } + }]; +} + +- (void)getProjectConfig:(FIRGetProjectConfigRequest *)request + callback:(FIRGetProjectConfigResponseCallback)callback { + FIRGetProjectConfigResponse *response = [[FIRGetProjectConfigResponse alloc] init]; + [self postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + } else { + callback(response, nil); + } + }]; +} + +- (void)setAccountInfo:(FIRSetAccountInfoRequest *)request + callback:(FIRSetAccountInfoResponseCallback)callback { + FIRSetAccountInfoResponse *response = [[FIRSetAccountInfoResponse alloc] init]; + [self postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + } else { + callback(response, nil); + } + }]; +} + +- (void)verifyAssertion:(FIRVerifyAssertionRequest *)request + callback:(FIRVerifyAssertionResponseCallback)callback { + FIRVerifyAssertionResponse *response = [[FIRVerifyAssertionResponse alloc] init]; + [self + postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + } else { + if (!response.IDToken && response.MFAInfo) { +#if TARGET_OS_IOS + NSMutableArray *multiFactorInfo = [NSMutableArray array]; + for (FIRAuthProtoMFAEnrollment *MFAEnrollment in response.MFAInfo) { + FIRPhoneMultiFactorInfo *info = + [[FIRPhoneMultiFactorInfo alloc] initWithProto:MFAEnrollment]; + [multiFactorInfo addObject:info]; + } + NSError *multiFactorRequiredError = [FIRAuthErrorUtils + secondFactorRequiredErrorWithPendingCredential:response.MFAPendingCredential + hints:multiFactorInfo + auth:request.requestConfiguration + .auth]; + callback(nil, multiFactorRequiredError); +#endif + } else { + callback(response, nil); + } + } + }]; +} + +- (void)verifyCustomToken:(FIRVerifyCustomTokenRequest *)request + callback:(FIRVerifyCustomTokenResponseCallback)callback { + FIRVerifyCustomTokenResponse *response = [[FIRVerifyCustomTokenResponse alloc] init]; + [self postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + } else { + callback(response, nil); + } + }]; +} + +- (void)verifyPassword:(FIRVerifyPasswordRequest *)request + callback:(FIRVerifyPasswordResponseCallback)callback { + FIRVerifyPasswordResponse *response = [[FIRVerifyPasswordResponse alloc] init]; + [self + postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + } else { + if (!response.IDToken && response.MFAInfo) { +#if TARGET_OS_IOS + NSMutableArray *multiFactorInfo = [NSMutableArray array]; + for (FIRAuthProtoMFAEnrollment *MFAEnrollment in response.MFAInfo) { + FIRPhoneMultiFactorInfo *info = + [[FIRPhoneMultiFactorInfo alloc] initWithProto:MFAEnrollment]; + [multiFactorInfo addObject:info]; + } + NSError *multiFactorRequiredError = [FIRAuthErrorUtils + secondFactorRequiredErrorWithPendingCredential:response.MFAPendingCredential + hints:multiFactorInfo + auth:request.requestConfiguration + .auth]; + callback(nil, multiFactorRequiredError); +#endif + } else { + callback(response, nil); + } + } + }]; +} + +- (void)emailLinkSignin:(FIREmailLinkSignInRequest *)request + callback:(FIREmailLinkSigninResponseCallback)callback { + FIREmailLinkSignInResponse *response = [[FIREmailLinkSignInResponse alloc] init]; + [self + postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + } else { + if (!response.IDToken && response.MFAInfo) { +#if TARGET_OS_IOS + NSMutableArray *multiFactorInfo = [NSMutableArray array]; + for (FIRAuthProtoMFAEnrollment *MFAEnrollment in response.MFAInfo) { + FIRPhoneMultiFactorInfo *info = + [[FIRPhoneMultiFactorInfo alloc] initWithProto:MFAEnrollment]; + [multiFactorInfo addObject:info]; + } + NSError *multiFactorRequiredError = [FIRAuthErrorUtils + secondFactorRequiredErrorWithPendingCredential:response.MFAPendingCredential + hints:multiFactorInfo + auth:request.requestConfiguration + .auth]; + callback(nil, multiFactorRequiredError); +#endif + } else { + callback(response, nil); + } + } + }]; +} + +- (void)secureToken:(FIRSecureTokenRequest *)request + callback:(FIRSecureTokenResponseCallback)callback { + FIRSecureTokenResponse *response = [[FIRSecureTokenResponse alloc] init]; + [self postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + } else { + callback(response, nil); + } + }]; +} + +- (void)getOOBConfirmationCode:(FIRGetOOBConfirmationCodeRequest *)request + callback:(FIRGetOOBConfirmationCodeResponseCallback)callback { + FIRGetOOBConfirmationCodeResponse *response = [[FIRGetOOBConfirmationCodeResponse alloc] init]; + [self postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + } else { + callback(response, nil); + } + }]; +} + +- (void)signUpNewUser:(FIRSignUpNewUserRequest *)request + callback:(FIRSignupNewUserCallback)callback { + FIRSignUpNewUserResponse *response = [[FIRSignUpNewUserResponse alloc] init]; + [self postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + } else { + callback(response, nil); + } + }]; +} + +- (void)deleteAccount:(FIRDeleteAccountRequest *)request callback:(FIRDeleteCallBack)callback { + FIRDeleteAccountResponse *response = [[FIRDeleteAccountResponse alloc] init]; + [self postWithRequest:request response:response callback:callback]; +} + +#if TARGET_OS_IOS +- (void)sendVerificationCode:(FIRSendVerificationCodeRequest *)request + callback:(FIRSendVerificationCodeResponseCallback)callback { + FIRSendVerificationCodeResponse *response = [[FIRSendVerificationCodeResponse alloc] init]; + [self postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + } else { + callback(response, error); + } + }]; +} + +- (void)verifyPhoneNumber:(FIRVerifyPhoneNumberRequest *)request + callback:(FIRVerifyPhoneNumberResponseCallback)callback { + FIRVerifyPhoneNumberResponse *response = [[FIRVerifyPhoneNumberResponse alloc] init]; + [self + postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + return; + } + // Check whether or not the successful response is actually the special case phone + // auth flow that returns a temporary proof and phone number. + if (response.phoneNumber.length && response.temporaryProof.length) { + FIRPhoneAuthCredential *credential = + [[FIRPhoneAuthCredential alloc] initWithTemporaryProof:response.temporaryProof + phoneNumber:response.phoneNumber + providerID:FIRPhoneAuthProviderID]; + callback(nil, [FIRAuthErrorUtils credentialAlreadyInUseErrorWithMessage:nil + credential:credential + email:nil]); + return; + } + callback(response, nil); + }]; +} + +- (void)verifyClient:(id)request callback:(FIRVerifyClientResponseCallback)callback { + FIRVerifyClientResponse *response = [[FIRVerifyClientResponse alloc] init]; + [self postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + return; + } + callback(response, nil); + }]; +} + +#endif + +- (void)revokeToken:(FIRRevokeTokenRequest *)request + callback:(FIRRevokeTokenResponseCallback)callback { + FIRRevokeTokenResponse *response = [[FIRRevokeTokenResponse alloc] init]; + [self + postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, [FIRAuthErrorUtils + invalidCredentialErrorWithMessage:[error localizedDescription]]); + return; + } + callback(response, nil); + }]; +} + +- (void)resetPassword:(FIRResetPasswordRequest *)request + callback:(FIRResetPasswordCallback)callback { + FIRResetPasswordResponse *response = [[FIRResetPasswordResponse alloc] init]; + [self postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + callback(nil, error); + return; + } + callback(response, nil); + }]; +} + +- (void)signInWithGameCenter:(FIRSignInWithGameCenterRequest *)request + callback:(FIRSignInWithGameCenterResponseCallback)callback { + FIRSignInWithGameCenterResponse *response = [[FIRSignInWithGameCenterResponse alloc] init]; + [self postWithRequest:request + response:response + callback:^(NSError *error) { + if (error) { + if (callback) { + callback(nil, error); + } + } else { + if (callback) { + callback(response, nil); + } + } + }]; +} + +#pragma mark - Generic RPC handling methods + +/** @fn postWithRequest:response:callback: + @brief Calls the RPC using HTTP POST. + @remarks Possible error responses: + @see FIRAuthInternalErrorCodeRPCRequestEncodingError + @see FIRAuthInternalErrorCodeJSONSerializationError + @see FIRAuthInternalErrorCodeNetworkError + @see FIRAuthInternalErrorCodeUnexpectedErrorResponse + @see FIRAuthInternalErrorCodeUnexpectedResponse + @see FIRAuthInternalErrorCodeRPCResponseDecodingError + @param request The request. + @param response The empty response to be filled. + @param callback The callback for both success and failure. + */ +- (void)postWithRequest:(id)request + response:(id)response + callback:(void (^)(NSError *_Nullable error))callback { + NSError *error; + NSData *bodyData; + if ([request containsPostBody]) { + id postBody = [request unencodedHTTPRequestBodyWithError:&error]; + if (!postBody) { + callback([FIRAuthErrorUtils RPCRequestEncodingErrorWithUnderlyingError:error]); + return; + } + + NSJSONWritingOptions JSONWritingOptions = 0; +#if DEBUG + JSONWritingOptions |= NSJSONWritingPrettyPrinted; +#endif + + if ([NSJSONSerialization isValidJSONObject:postBody]) { + bodyData = [NSJSONSerialization dataWithJSONObject:postBody + options:JSONWritingOptions + error:&error]; + if (!bodyData) { + // This is an untested case. This happens exclusively when there is an error in the + // framework implementation of dataWithJSONObject:options:error:. This shouldn't normally + // occur as isValidJSONObject: should return NO in any case we should encounter an error. + error = [FIRAuthErrorUtils JSONSerializationErrorWithUnderlyingError:error]; + } + } else { + error = [FIRAuthErrorUtils JSONSerializationErrorForUnencodableType]; + } + if (!bodyData) { + callback(error); + return; + } + } + + [_RPCIssuer + asyncPostToURLWithRequestConfiguration:[request requestConfiguration] + URL:[request requestURL] + body:bodyData + contentType:kJSONContentType + completionHandler:^(NSData *data, NSError *error) { + // If there is an error with no body data at all, then this must be a + // network error. + if (error && !data) { + callback([FIRAuthErrorUtils networkErrorWithUnderlyingError:error]); + return; + } + + // Try to decode the HTTP response data which may contain either a + // successful response or error message. + NSError *jsonError; + NSDictionary *dictionary = + [NSJSONSerialization JSONObjectWithData:data + options:NSJSONReadingMutableLeaves + error:&jsonError]; + if (!dictionary) { + if (error) { + // We have an error, but we couldn't decode the body, so we have no + // additional information other than the raw response and the + // original NSError (the jsonError is infered by the error code + // (FIRAuthErrorCodeUnexpectedHTTPResponse, and is irrelevant.) + callback([FIRAuthErrorUtils + unexpectedErrorResponseWithData:data + underlyingError:error]); + } else { + // This is supposed to be a "successful" response, but we couldn't + // deserialize the body. + callback([FIRAuthErrorUtils unexpectedResponseWithData:data + underlyingError:jsonError]); + } + return; + } + if (![dictionary isKindOfClass:[NSDictionary class]]) { + if (error) { + callback([FIRAuthErrorUtils + unexpectedErrorResponseWithDeserializedResponse:dictionary + underlyingError:error]); + } else { + callback([FIRAuthErrorUtils + unexpectedResponseWithDeserializedResponse:dictionary]); + } + return; + } + + // At this point we either have an error with successfully decoded + // details in the body, or we have a response which must pass further + // validation before we know it's truly successful. We deal with the + // case where we have an error with successfully decoded error details + // first: + if (error) { + NSDictionary *errorDictionary = dictionary[kErrorKey]; + if ([errorDictionary isKindOfClass:[NSDictionary class]]) { + id errorMessage = errorDictionary[kErrorMessageKey]; + if ([errorMessage isKindOfClass:[NSString class]]) { + NSString *errorMessageString = (NSString *)errorMessage; + + // Contruct client error. + NSError *clientError = [[self class] + clientErrorWithServerErrorMessage:errorMessageString + errorDictionary:errorDictionary + response:response]; + if (clientError) { + callback(clientError); + return; + } + } + // Not a message we know, return the message directly. + if (errorMessage) { + NSError *unexpecterErrorResponse = [FIRAuthErrorUtils + unexpectedErrorResponseWithDeserializedResponse: + errorDictionary + underlyingError:error]; + callback(unexpecterErrorResponse); + return; + } + } + // No error message at all, return the decoded response. + callback([FIRAuthErrorUtils + unexpectedErrorResponseWithDeserializedResponse:dictionary + underlyingError:error]); + return; + } + + // Finally, we try to populate the response object with the JSON + // values. + if (![response setWithDictionary:dictionary error:&error]) { + callback([FIRAuthErrorUtils + RPCResponseDecodingErrorWithDeserializedResponse:dictionary + underlyingError:error]); + return; + } + // In case returnIDPCredential of a verifyAssertion request is set to + // @YES, the server may return a 200 with a response that may contain a + // server error. + if ([request isKindOfClass:[FIRVerifyAssertionRequest class]]) { + FIRVerifyAssertionRequest *verifyAssertionRequest = + (FIRVerifyAssertionRequest *)request; + if (verifyAssertionRequest.returnIDPCredential) { + NSString *errorMessage = + dictionary[kReturnIDPCredentialErrorMessageKey]; + if ([errorMessage isKindOfClass:[NSString class]]) { + NSString *errorString = (NSString *)errorMessage; + NSError *clientError = + [[self class] clientErrorWithServerErrorMessage:errorString + errorDictionary:@{} + response:response]; + if (clientError) { + callback(clientError); + return; + } + } + } + } + // Success! The response object originally passed in can be used by the + // caller. + callback(nil); + }]; +} + +/** @fn clientErrorWithServerErrorMessage:errorDictionary: + @brief Translates known server errors to client errors. + @param serverErrorMessage The error message from the server. + @param errorDictionary The error part of the response from the server. + @param response The response from the server RPC. + @return A client error, if any. + */ ++ (nullable NSError *)clientErrorWithServerErrorMessage:(NSString *)serverErrorMessage + errorDictionary:(NSDictionary *)errorDictionary + response:(id)response { + NSString *shortErrorMessage = serverErrorMessage; + NSString *serverDetailErrorMessage; + NSRange colonRange = [serverErrorMessage rangeOfString:@":"]; + if (colonRange.location != NSNotFound) { + shortErrorMessage = [serverErrorMessage substringToIndex:colonRange.location]; + shortErrorMessage = + [shortErrorMessage stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; + serverDetailErrorMessage = [serverErrorMessage substringFromIndex:colonRange.location + 1]; + serverDetailErrorMessage = [serverDetailErrorMessage + stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; + } + + // Delegate the responsibility for constructing the client error to the response object, + // if possible. + SEL clientErrorWithServerErrorMessageSelector = @selector(clientErrorWithShortErrorMessage: + detailErrorMessage:); + if ([response respondsToSelector:clientErrorWithServerErrorMessageSelector]) { + NSError *error = [response clientErrorWithShortErrorMessage:shortErrorMessage + detailErrorMessage:serverDetailErrorMessage]; + if (error) { + return error; + } + } + + if ([shortErrorMessage isEqualToString:kUserNotFoundErrorMessage]) { + return [FIRAuthErrorUtils userNotFoundErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kUserDeletedErrorMessage]) { + return [FIRAuthErrorUtils userNotFoundErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kInvalidLocalIDErrorMessage]) { + // This case shouldn't be necessary but it is for now: b/27908364 . + return [FIRAuthErrorUtils userNotFoundErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kUserTokenExpiredErrorMessage]) { + return [FIRAuthErrorUtils userTokenExpiredErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kTooManyRequestsErrorMessage]) { + return [FIRAuthErrorUtils tooManyRequestsErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kInvalidCustomTokenErrorMessage]) { + return [FIRAuthErrorUtils invalidCustomTokenErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kCustomTokenMismatch]) { + return [FIRAuthErrorUtils customTokenMistmatchErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kInvalidCredentialErrorMessage] || + [shortErrorMessage isEqualToString:kInvalidPendingToken]) { + return [FIRAuthErrorUtils invalidCredentialErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kUserDisabledErrorMessage]) { + return [FIRAuthErrorUtils userDisabledErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kOperationNotAllowedErrorMessage]) { + return [FIRAuthErrorUtils operationNotAllowedErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kPasswordLoginDisabledErrorMessage]) { + return [FIRAuthErrorUtils operationNotAllowedErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kEmailAlreadyInUseErrorMessage]) { + return [FIRAuthErrorUtils emailAlreadyInUseErrorWithEmail:nil]; + } + + if ([shortErrorMessage isEqualToString:kInvalidEmailErrorMessage]) { + return [FIRAuthErrorUtils invalidEmailErrorWithMessage:serverDetailErrorMessage]; + } + + // "INVALID_IDENTIFIER" can be returned by createAuthURI RPC. Considering email addresses are + // currently the only identifiers, we surface the FIRAuthErrorCodeInvalidEmail error code in this + // case. + if ([shortErrorMessage isEqualToString:kInvalidIdentifierErrorMessage]) { + return [FIRAuthErrorUtils invalidEmailErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kWrongPasswordErrorMessage]) { + return [FIRAuthErrorUtils wrongPasswordErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kCredentialTooOldErrorMessage]) { + return [FIRAuthErrorUtils requiresRecentLoginErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kInvalidUserTokenErrorMessage]) { + return [FIRAuthErrorUtils invalidUserTokenErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kFederatedUserIDAlreadyLinkedMessage]) { + FIROAuthCredential *credential; + NSString *email; + if ([response isKindOfClass:[FIRVerifyAssertionResponse class]]) { + FIRVerifyAssertionResponse *verifyAssertion = (FIRVerifyAssertionResponse *)response; + credential = [[FIROAuthCredential alloc] initWithVerifyAssertionResponse:verifyAssertion]; + email = verifyAssertion.email; + } + return [FIRAuthErrorUtils credentialAlreadyInUseErrorWithMessage:serverDetailErrorMessage + credential:credential + email:email]; + } + + if ([shortErrorMessage isEqualToString:kWeakPasswordErrorMessagePrefix]) { + return [FIRAuthErrorUtils weakPasswordErrorWithServerResponseReason:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kExpiredActionCodeErrorMessage]) { + return [FIRAuthErrorUtils expiredActionCodeErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kInvalidActionCodeErrorMessage]) { + return [FIRAuthErrorUtils invalidActionCodeErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kMissingEmailErrorMessage]) { + return [FIRAuthErrorUtils missingEmailErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kInvalidSenderEmailErrorMessage]) { + return [FIRAuthErrorUtils invalidSenderErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kInvalidMessagePayloadErrorMessage]) { + return [FIRAuthErrorUtils invalidMessagePayloadErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kInvalidRecipientEmailErrorMessage]) { + return [FIRAuthErrorUtils invalidRecipientEmailErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kMissingIosBundleIDErrorMessage]) { + return [FIRAuthErrorUtils missingIosBundleIDErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kMissingAndroidPackageNameErrorMessage]) { + return [FIRAuthErrorUtils missingAndroidPackageNameErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kUnauthorizedDomainErrorMessage]) { + return [FIRAuthErrorUtils unauthorizedDomainErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kInvalidContinueURIErrorMessage]) { + return [FIRAuthErrorUtils invalidContinueURIErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kInvalidProviderIDErrorMessage]) { + return [FIRAuthErrorUtils invalidProviderIDErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kInvalidDynamicLinkDomainErrorMessage]) { + return [FIRAuthErrorUtils invalidDynamicLinkDomainErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kMissingContinueURIErrorMessage]) { + return [FIRAuthErrorUtils missingContinueURIErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kInvalidPhoneNumberErrorMessage]) { + return [FIRAuthErrorUtils invalidPhoneNumberErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kInvalidSessionInfoErrorMessage]) { + return [FIRAuthErrorUtils invalidVerificationIDErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kInvalidVerificationCodeErrorMessage]) { + return [FIRAuthErrorUtils invalidVerificationCodeErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kSessionExpiredErrorMessage]) { + return [FIRAuthErrorUtils sessionExpiredErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kMissingAppTokenErrorMessage]) { + return [FIRAuthErrorUtils missingAppTokenErrorWithUnderlyingError:nil]; + } + + if ([shortErrorMessage isEqualToString:kMissingAppCredentialErrorMessage]) { + return [FIRAuthErrorUtils missingAppCredentialWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kInvalidAppCredentialErrorMessage]) { + return [FIRAuthErrorUtils invalidAppCredentialWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kQuoutaExceededErrorMessage]) { + return [FIRAuthErrorUtils quotaExceededErrorWithMessage:serverErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kAppNotVerifiedErrorMessage]) { + return [FIRAuthErrorUtils appNotVerifiedErrorWithMessage:serverErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kMissingClientIdentifier]) { + return [FIRAuthErrorUtils missingClientIdentifierErrorWithMessage:serverErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kCaptchaCheckFailedErrorMessage]) { + return [FIRAuthErrorUtils captchaCheckFailedErrorWithMessage:serverErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kMissingOrInvalidNonceErrorMessage]) { + return [FIRAuthErrorUtils missingOrInvalidNonceErrorWithMessage:serverDetailErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kMissingMFAPendingCredentialErrorMessage]) { + return [FIRAuthErrorUtils errorWithCode:FIRAuthInternalErrorCodeMissingMultiFactorSession + message:serverErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kMissingMFAEnrollmentIDErrorMessage]) { + return [FIRAuthErrorUtils errorWithCode:FIRAuthInternalErrorCodeMissingMultiFactorInfo + message:serverErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kInvalidMFAPendingCredentialErrorMessage]) { + return [FIRAuthErrorUtils errorWithCode:FIRAuthInternalErrorCodeInvalidMultiFactorSession + message:serverErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kMFAEnrollmentNotFoundErrorMessage]) { + return [FIRAuthErrorUtils errorWithCode:FIRAuthInternalErrorCodeMultiFactorInfoNotFound + message:serverErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kAdminOnlyOperationErrorMessage]) { + return [FIRAuthErrorUtils errorWithCode:FIRAuthInternalErrorCodeAdminRestrictedOperation + message:serverErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kUnverifiedEmailErrorMessage]) { + return [FIRAuthErrorUtils errorWithCode:FIRAuthInternalErrorCodeUnverifiedEmail + message:serverErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kSecondFactorExistsErrorMessage]) { + return [FIRAuthErrorUtils errorWithCode:FIRAuthInternalErrorCodeSecondFactorAlreadyEnrolled + message:serverErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kSecondFactorLimitExceededErrorMessage]) { + return [FIRAuthErrorUtils errorWithCode:FIRAuthInternalErrorCodeMaximumSecondFactorCountExceeded + message:serverErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kUnsupportedFirstFactorErrorMessage]) { + return [FIRAuthErrorUtils errorWithCode:FIRAuthInternalErrorCodeUnsupportedFirstFactor + message:serverErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kEmailChangeNeedsVerificationErrorMessage]) { + return [FIRAuthErrorUtils errorWithCode:FIRAuthInternalErrorCodeEmailChangeNeedsVerification + message:serverErrorMessage]; + } + + if ([shortErrorMessage isEqualToString:kTenantIDMismatch]) { + return [FIRAuthErrorUtils tenantIDMismatchError]; + } + + if ([shortErrorMessage isEqualToString:kUnsupportedTenantOperation]) { + return [FIRAuthErrorUtils unsupportedTenantOperationError]; + } + + if ([shortErrorMessage isEqualToString:kBlockingCloudFunctionErrorResponse]) { + return + [FIRAuthErrorUtils blockingCloudFunctionServerResponseWithMessage:serverDetailErrorMessage]; + } + + // In this case we handle an error that might be specified in the underlying errors dictionary, + // the error message in determined based on the @c reason key in the dictionary. + if (errorDictionary[kErrorsKey]) { + // Check for underlying error with reason = keyInvalid; + id underlyingErrors = errorDictionary[kErrorsKey]; + if ([underlyingErrors isKindOfClass:[NSArray class]]) { + NSArray *underlyingErrorsArray = (NSArray *)underlyingErrors; + for (id underlyingError in underlyingErrorsArray) { + if ([underlyingError isKindOfClass:[NSDictionary class]]) { + NSDictionary *underlyingErrorDictionary = (NSDictionary *)underlyingError; + NSString *reason = underlyingErrorDictionary[kReasonKey]; + if ([reason hasPrefix:kInvalidKeyReasonValue]) { + return [FIRAuthErrorUtils invalidAPIKeyError]; + } + if ([reason isEqualToString:kAppNotAuthorizedReasonValue]) { + return [FIRAuthErrorUtils appNotAuthorizedError]; + } + } + } + } + } + return nil; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h new file mode 100644 index 0000000..9ca4f44 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h @@ -0,0 +1,57 @@ +/* + * 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 + +@class FIRAuthRequestConfiguration; + +NS_ASSUME_NONNULL_BEGIN + +/** @protocol FIRAuthRPCRequest + @brief The generic interface for an RPC request needed by @c FIRAuthBackend. + */ +@protocol FIRAuthRPCRequest + +/** @fn requestURL + @brief Gets the request's full URL. + */ +- (NSURL *)requestURL; + +@optional + +/** @fn containsPostBody + @brief Returns whether the request contains a post body or not. Requests without a post body + are get requests. + @remarks The default implementation returns YES. + */ +- (BOOL)containsPostBody; + +/** @fn UnencodedHTTPRequestBodyWithError: + @brief Creates unencoded HTTP body representing the request. + @param error An out field for an error which occurred constructing the request. + @return The HTTP body data representing the request before any encoding, or nil for error. + */ +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error; + +/** @fn requestConfiguration + @brief Obtains the request configurations if available. + @return Returns the request configurations. + */ +- (FIRAuthRequestConfiguration *)requestConfiguration; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h new file mode 100644 index 0000000..0fe981a --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h @@ -0,0 +1,48 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** @protocol FIRAuthRPCResponse + @brief The generic interface for an RPC response needed by @c FIRAuthBackend. + */ +@protocol FIRAuthRPCResponse + +/** @fn setFieldsWithDictionary:error: + @brief Sets the response instance from the decoded JSON response. + @param dictionary The dictionary decoded from HTTP JSON response. + @param error An out field for an error which occurred constructing the request. + @return Whether the operation was successful or not. + */ +- (BOOL)setWithDictionary:(NSDictionary *)dictionary error:(NSError *_Nullable *_Nullable)error; + +@optional + +/** @fn clientErrorWithshortErrorMessage:detailErrorMessage + @brief This optional method allows response classes to create client errors given a short error + message and a detail error message from the server. + @param shortErrorMessage The short error message from the server. + @param detailErrorMessage The detailed error message from the server. + @return A client error, if any. + */ +- (nullable NSError *)clientErrorWithShortErrorMessage:(NSString *)shortErrorMessage + detailErrorMessage:(nullable NSString *)detailErrorMessage; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthRequestConfiguration.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthRequestConfiguration.h new file mode 100644 index 0000000..57aef80 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthRequestConfiguration.h @@ -0,0 +1,107 @@ +/* + * 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 + +#import "FirebaseAppCheck/Interop/FIRAppCheckInterop.h" +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuth.h" + +@protocol FIRHeartbeatLoggerProtocol; + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRAuthRequestConfiguration + @brief Defines configurations to be added to a request to Firebase Auth's backend. + */ +@interface FIRAuthRequestConfiguration : NSObject + +/** @property APIKey + @brief The Firebase Auth API key used in the request. + */ +@property(nonatomic, copy, readonly) NSString *APIKey; + +/** @property appID + @brief The Firebase appID used in the request. + */ +@property(nonatomic, copy, readonly) NSString *appID; + +/** @property auth + @brief The FIRAuth instance used in the request. + */ +@property(nonatomic, weak, readonly, nullable) FIRAuth *auth; + +/** @property heartbeatLogger + @brief The heartbeat logger used to add heartbeats to the corresponding request's header. + */ +@property(nonatomic, copy, nullable) id heartbeatLogger; +/** @property appCheck + @brief The appCheck is used to generate a token. + */ +@property(nonatomic, copy, nullable) id appCheck; + +/** @property LanguageCode + @brief The language code used in the request. + */ +@property(nonatomic, copy, nullable) NSString *languageCode; + +/** @property additionalFrameworkMarker + @brief Additional framework marker that will be added as part of the header of every request. + */ +@property(nonatomic, copy, nullable) NSString *additionalFrameworkMarker; + +/** @property emulatorHostAndPort + @brief If set, the local emulator host and port to point to instead of the remote backend. + */ +@property(nonatomic, copy, nullable) NSString *emulatorHostAndPort; + +- (instancetype)init NS_UNAVAILABLE; + +/** @fn initWithAPIKey:appID: + @brief Convenience initializer. + @param APIKey The API key to be used in the request. + @param appID The Firebase app ID to be passed in the request header. + */ +- (nullable instancetype)initWithAPIKey:(NSString *)APIKey appID:(NSString *)appID; + +/** @fn initWithAPIKey:appID:auth: + @brief Convenience initializer. + @param APIKey The API key to be used in the request. + @param appID The Firebase app ID to be passed in the request header. + @param auth The FIRAuth instance used in the request. + */ +- (nullable instancetype)initWithAPIKey:(NSString *)APIKey + appID:(NSString *)appID + auth:(nullable FIRAuth *)auth; + +/** @fn initWithAPIKey:appID:auth:heartbeatLogger:appCheck: + @brief Designated initializer. + @param APIKey The API key to be used in the request. + @param appID The Firebase app ID to be passed in the request header. + @param auth The FIRAuth instance used in the request. + @param heartbeatLogger The heartbeat logger used to add heartbeats to the request header. + @param appCheck The appCheck interop is a library to generate app check token. + */ +- (nullable instancetype)initWithAPIKey:(NSString *)APIKey + appID:(NSString *)appID + auth:(nullable FIRAuth *)auth + heartbeatLogger:(nullable id)heartbeatLogger + appCheck:(nullable id)appCheck + NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthRequestConfiguration.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthRequestConfiguration.m new file mode 100644 index 0000000..e808262 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRAuthRequestConfiguration.m @@ -0,0 +1,53 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/FIRAuthRequestConfiguration.h" + +#import "FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRAuthRequestConfiguration + +- (nullable instancetype)initWithAPIKey:(NSString *)APIKey appID:(NSString *)appID { + return [self initWithAPIKey:APIKey appID:appID auth:nil heartbeatLogger:nil appCheck:nil]; +} + +- (nullable instancetype)initWithAPIKey:(NSString *)APIKey + appID:(NSString *)appID + auth:(nullable FIRAuth *)auth { + return [self initWithAPIKey:APIKey appID:appID auth:auth heartbeatLogger:nil appCheck:nil]; +} + +- (nullable instancetype)initWithAPIKey:(NSString *)APIKey + appID:(NSString *)appID + auth:(nullable FIRAuth *)auth + heartbeatLogger:(nullable id)heartbeatLogger + appCheck:(nullable id)appCheck { + self = [super init]; + if (self) { + _APIKey = [APIKey copy]; + _appID = [appID copy]; + _auth = auth; + _heartbeatLogger = heartbeatLogger; + _appCheck = appCheck; + } + return self; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h new file mode 100644 index 0000000..b021d53 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h @@ -0,0 +1,76 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRequestConfiguration.h" + +@class FIRAuthRequestConfiguration; + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRIdentityToolkitRequest + @brief Represents a request to an identity toolkit endpoint. + */ +@interface FIRIdentityToolkitRequest : NSObject + +/** @property endpoint + @brief Gets the RPC's endpoint. + */ +@property(nonatomic, copy, readonly) NSString *endpoint; + +/** @property APIKey + @brief Gets the client's API key used for the request. + */ +@property(nonatomic, copy, readonly) NSString *APIKey; + +/** @property tenantID + @brief The tenant ID of the request. nil if none is available. + */ +@property(nonatomic, copy, readonly, nullable) NSString *tenantID; + +/** @fn init + @brief Please use initWithEndpoint:APIKey: + */ +- (instancetype)init NS_UNAVAILABLE; + +/** @fn initWithEndpoint:APIKey: + @brief Designated initializer. + @param endpoint The endpoint name. + @param requestConfiguration An object containing configurations to be added to the request. + */ +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_DESIGNATED_INITIALIZER; + +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + useIdentityPlatform:(BOOL)useIdentityPlatform + useStaging:(BOOL)useStaging; + +/** @fn requestURL + @brief Gets the request's full URL. + */ +- (NSURL *)requestURL; + +/** @fn requestConfiguration + @brief Gets the request's configuration. + */ +- (FIRAuthRequestConfiguration *)requestConfiguration; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.m new file mode 100644 index 0000000..de58296 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.m @@ -0,0 +1,140 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuth.h" + +NS_ASSUME_NONNULL_BEGIN + +static NSString *const kHttpsProtocol = @"https:"; +static NSString *const kHttpProtocol = @"http:"; + +static NSString *const kFirebaseAuthAPIURLFormat = + @"%@//%@/identitytoolkit/v3/relyingparty/%@?key=%@"; +static NSString *const kIdentityPlatformAPIURLFormat = @"%@//%@/v2/%@?key=%@"; +static NSString *const kEmulatorHostAndPrefixFormat = @"%@/%@"; + +static NSString *gAPIHost = @"www.googleapis.com"; + +static NSString *kFirebaseAuthAPIHost = @"www.googleapis.com"; +static NSString *kIdentityPlatformAPIHost = @"identitytoolkit.googleapis.com"; + +static NSString *kFirebaseAuthStagingAPIHost = @"staging-www.sandbox.googleapis.com"; +static NSString *kIdentityPlatformStagingAPIHost = + @"staging-identitytoolkit.sandbox.googleapis.com"; + +@implementation FIRIdentityToolkitRequest { + FIRAuthRequestConfiguration *_requestConfiguration; + + BOOL _useIdentityPlatform; + + BOOL _useStaging; +} + +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super init]; + if (self) { + _APIKey = [requestConfiguration.APIKey copy]; + _endpoint = [endpoint copy]; + _requestConfiguration = requestConfiguration; + _useIdentityPlatform = NO; + _useStaging = NO; + + // Automatically set the tenant ID. If the request is initialized before FIRAuth is configured, + // set tenant ID to nil. + @try { + _tenantID = [self requestConfiguration].auth.tenantID; + } @catch (NSException *e) { + _tenantID = nil; + } + } + return self; +} + +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + useIdentityPlatform:(BOOL)useIdentityPlatform + useStaging:(BOOL)useStaging { + self = [self initWithEndpoint:endpoint requestConfiguration:requestConfiguration]; + if (self) { + _useIdentityPlatform = useIdentityPlatform; + _useStaging = useStaging; + } + return self; +} + +- (BOOL)containsPostBody { + return YES; +} + +- (NSURL *)requestURL { + NSString *apiURLFormat; + NSString *apiProtocol; + NSString *apiHostAndPathPrefix; + + NSString *emulatorHostAndPort = _requestConfiguration.emulatorHostAndPort; + + if (_useIdentityPlatform) { + apiURLFormat = kIdentityPlatformAPIURLFormat; + apiProtocol = kHttpsProtocol; + if (emulatorHostAndPort) { + apiProtocol = kHttpProtocol; + apiHostAndPathPrefix = + [NSString stringWithFormat:kEmulatorHostAndPrefixFormat, emulatorHostAndPort, + kIdentityPlatformAPIHost]; + } else if (_useStaging) { + apiHostAndPathPrefix = kIdentityPlatformStagingAPIHost; + } else { + apiHostAndPathPrefix = kIdentityPlatformAPIHost; + } + } else { + apiURLFormat = kFirebaseAuthAPIURLFormat; + apiProtocol = kHttpsProtocol; + if (emulatorHostAndPort) { + apiProtocol = kHttpProtocol; + apiHostAndPathPrefix = [NSString + stringWithFormat:kEmulatorHostAndPrefixFormat, emulatorHostAndPort, kFirebaseAuthAPIHost]; + } else if (_useStaging) { + apiHostAndPathPrefix = kFirebaseAuthStagingAPIHost; + } else { + apiHostAndPathPrefix = kFirebaseAuthAPIHost; + } + } + NSString *URLString = [NSString + stringWithFormat:apiURLFormat, apiProtocol, apiHostAndPathPrefix, _endpoint, _APIKey]; + NSURL *URL = [NSURL URLWithString:URLString]; + return URL; +} + +- (FIRAuthRequestConfiguration *)requestConfiguration { + return _requestConfiguration; +} + +#pragma mark - Internal API for development + ++ (NSString *)host { + return gAPIHost; +} + ++ (void)setHost:(NSString *)host { + gAPIHost = host; +} + +NS_ASSUME_NONNULL_END + +@end diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIRequest.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIRequest.h new file mode 100644 index 0000000..633ffa9 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIRequest.h @@ -0,0 +1,88 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRCreateAuthURIRequest + @brief Represents the parameters for the createAuthUri endpoint. + @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/createAuthUri + */ +@interface FIRCreateAuthURIRequest : FIRIdentityToolkitRequest + +/** @property identifier + @brief The email or federated ID of the user. + */ +@property(nonatomic, copy) NSString *identifier; + +/** @property continueURI + @brief The URI to which the IDP redirects the user after the federated login flow. + */ +@property(nonatomic, copy) NSString *continueURI; + +/** @property openIDRealm + @brief Optional realm for OpenID protocol. The sub string "scheme://domain:port" of the param + "continueUri" is used if this is not set. + */ +@property(nonatomic, copy, nullable) NSString *openIDRealm; + +/** @property providerID + @brief The IdP ID. For white listed IdPs it's a short domain name e.g. google.com, aol.com, + live.net and yahoo.com. For other OpenID IdPs it's the OP identifier. + */ +@property(nonatomic, copy, nullable) NSString *providerID; + +/** @property clientID + @brief The relying party OAuth client ID. + */ +@property(nonatomic, copy, nullable) NSString *clientID; + +/** @property context + @brief The opaque value used by the client to maintain context info between the authentication + request and the IDP callback. + */ +@property(nonatomic, copy, nullable) NSString *context; + +/** @property appID + @brief The iOS client application's bundle identifier. + */ +@property(nonatomic, copy, nullable) NSString *appID; + +/** @fn initWithEndpoint:requestConfiguration:requestConfiguration. + @brief Please use initWithIdentifier:continueURI:requestConfiguration: instead. + */ +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_UNAVAILABLE; + +/** @fn initWithIdentifier:continueURI:requestConfiguration: + @brief Designated initializer. + @param identifier The email or federated ID of the user. + @param continueURI The URI to which the IDP redirects the user after the federated login flow. + @param requestConfiguration An object containing configurations to be added to the request. + */ +- (nullable instancetype)initWithIdentifier:(NSString *)identifier + continueURI:(NSString *)continueURI + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIRequest.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIRequest.m new file mode 100644 index 0000000..8a7baa6 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIRequest.m @@ -0,0 +1,105 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kCreateAuthURIEndpoint + @brief The "createAuthUri" endpoint. + */ +static NSString *const kCreateAuthURIEndpoint = @"createAuthUri"; + +/** @var kProviderIDKey + @brief The key for the "providerId" value in the request. + */ +static NSString *const kProviderIDKey = @"providerId"; + +/** @var kIdentifierKey + @brief The key for the "identifier" value in the request. + */ +static NSString *const kIdentifierKey = @"identifier"; + +/** @var kContinueURIKey + @brief The key for the "continueUri" value in the request. + */ +static NSString *const kContinueURIKey = @"continueUri"; + +/** @var kOpenIDRealmKey + @brief The key for the "openidRealm" value in the request. + */ +static NSString *const kOpenIDRealmKey = @"openidRealm"; + +/** @var kClientIDKey + @brief The key for the "clientId" value in the request. + */ +static NSString *const kClientIDKey = @"clientId"; + +/** @var kContextKey + @brief The key for the "context" value in the request. + */ +static NSString *const kContextKey = @"context"; + +/** @var kAppIDKey + @brief The key for the "appId" value in the request. + */ +static NSString *const kAppIDKey = @"appId"; + +/** @var kTenantIDKey + @brief The key for the tenant id value in the request. + */ +static NSString *const kTenantIDKey = @"tenantId"; + +@implementation FIRCreateAuthURIRequest + +- (nullable instancetype)initWithIdentifier:(NSString *)identifier + continueURI:(NSString *)continueURI + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kCreateAuthURIEndpoint requestConfiguration:requestConfiguration]; + if (self) { + _identifier = [identifier copy]; + _continueURI = [continueURI copy]; + } + return self; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error { + NSMutableDictionary *postBody = + [@{kIdentifierKey : _identifier, kContinueURIKey : _continueURI} mutableCopy]; + if (_providerID) { + postBody[kProviderIDKey] = _providerID; + } + if (_openIDRealm) { + postBody[kOpenIDRealmKey] = _openIDRealm; + } + if (_clientID) { + postBody[kClientIDKey] = _clientID; + } + if (_context) { + postBody[kContextKey] = _context; + } + if (_appID) { + postBody[kAppIDKey] = _appID; + } + if (self.tenantID) { + postBody[kTenantIDKey] = self.tenantID; + } + return [postBody copy]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIResponse.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIResponse.h new file mode 100644 index 0000000..79c5ea7 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIResponse.h @@ -0,0 +1,61 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRCreateAuthURIResponse + @brief Represents the parameters for the createAuthUri endpoint. + @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/createAuthUri + */ +@interface FIRCreateAuthURIResponse : NSObject + +/** @property authUri + @brief The URI used by the IDP to authenticate the user. + */ +@property(nonatomic, strong, readonly, nullable) NSString *authURI; + +/** @property registered + @brief Whether the user is registered if the identifier is an email. + */ +@property(nonatomic, assign, readonly) BOOL registered; + +/** @property providerId + @brief The provider ID of the auth URI. + */ +@property(nonatomic, strong, readonly, nullable) NSString *providerID; + +/** @property forExistingProvider + @brief True if the authUri is for user's existing provider. + */ +@property(nonatomic, assign, readonly) BOOL forExistingProvider; + +/** @property allProviders + @brief A list of provider IDs the passed @c identifier could use to sign in with. + */ +@property(nonatomic, copy, readonly, nullable) NSArray *allProviders; + +/** @property signinMethods + @brief A list of sign-in methods available for the passed @c identifier. + */ +@property(nonatomic, copy, readonly, nullable) NSArray *signinMethods; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIResponse.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIResponse.m new file mode 100644 index 0000000..bf422c9 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIResponse.m @@ -0,0 +1,35 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRCreateAuthURIResponse + +- (BOOL)setWithDictionary:(NSDictionary *)dictionary error:(NSError *_Nullable *_Nullable)error { + _providerID = [dictionary[@"providerId"] copy]; + _authURI = [dictionary[@"authUri"] copy]; + _registered = [dictionary[@"registered"] boolValue]; + _forExistingProvider = [dictionary[@"forExistingProvider"] boolValue]; + _allProviders = [dictionary[@"allProviders"] copy]; + _signinMethods = [dictionary[@"signinMethods"] copy]; + return YES; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountRequest.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountRequest.h new file mode 100644 index 0000000..b6b6e40 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountRequest.h @@ -0,0 +1,50 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRDeleteAccountRequest + @brief Represents the parameters for the deleteAccount endpoint. + @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/deleteAccount + */ +@interface FIRDeleteAccountRequest : FIRIdentityToolkitRequest + +/** @fn initWithEndpoint:requestConfiguration:requestConfiguration. + @brief Please use initWitLocalID:accessToken:requestConfiguration instead. + */ +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_UNAVAILABLE; + +/** @fn initWitLocalID:accessToken:requestConfiguration. + @brief Designated initializer. + @param localID The local ID. + @param accessToken The access token. + @param requestConfiguration An object containing configurations to be added to the request. + */ +- (nullable instancetype)initWitLocalID:(NSString *)localID + accessToken:(NSString *)accessToken + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountRequest.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountRequest.m new file mode 100644 index 0000000..8bc6c52 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountRequest.m @@ -0,0 +1,69 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kCreateAuthURIEndpoint + @brief The "deleteAccount" endpoint. + */ +static NSString *const kDeleteAccountEndpoint = @"deleteAccount"; + +/** @var kIDTokenKey + @brief The key for the "idToken" value in the request. This is actually the STS Access Token, + despite it's confusing (backwards compatiable) parameter name. + */ +static NSString *const kIDTokenKey = @"idToken"; + +/** @var kLocalIDKey + @brief The key for the "localID" value in the request. + */ +static NSString *const kLocalIDKey = @"localId"; + +@implementation FIRDeleteAccountRequest { + /** @var _accessToken + @brief The STS Access Token of the authenticated user. + */ + NSString *_accessToken; + + /** @var _localID + @brief The localID of the user. + */ + NSString *_localID; +} + +- (nullable instancetype)initWitLocalID:(NSString *)localID + accessToken:(NSString *)accessToken + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kDeleteAccountEndpoint requestConfiguration:requestConfiguration]; + if (self) { + _localID = [localID copy]; + _accessToken = [accessToken copy]; + } + return self; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error { + NSMutableDictionary *postBody = [NSMutableDictionary dictionary]; + postBody[kIDTokenKey] = _accessToken; + postBody[kLocalIDKey] = _localID; + return [postBody copy]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountResponse.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountResponse.h new file mode 100644 index 0000000..bc4d0d9 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountResponse.h @@ -0,0 +1,30 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRDeleteAccountResponse + @brief Represents the response from the deleteAccount endpoint. + @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/deleteAccount + */ +@interface FIRDeleteAccountResponse : NSObject +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountResponse.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountResponse.m new file mode 100644 index 0000000..fba1b6b --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountResponse.m @@ -0,0 +1,29 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRDeleteAccountResponse + +- (BOOL)setWithDictionary:(NSDictionary *)dictionary error:(NSError *_Nullable *_Nullable)error { + return YES; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInRequest.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInRequest.h new file mode 100644 index 0000000..752ffb4 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInRequest.h @@ -0,0 +1,66 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIREmailLinkSignInRequest + @brief Represents the parameters for the emailLinkSignin endpoint. + */ +@interface FIREmailLinkSignInRequest : FIRIdentityToolkitRequest + +#pragma mark - Components of "postBody" + +/** @property email + @brief The email identifier used to complete the email link sign-in. + */ +@property(nonatomic, copy, readonly) NSString *email; + +/** @property oobCode + @brief The OOB code used to complete the email link sign-in flow. + */ +@property(nonatomic, copy, readonly) NSString *oobCode; + +/** @property IDToken + @brief The ID Token code potentially used to complete the email link sign-in flow. + */ +@property(nonatomic, copy) NSString *IDToken; + +/** @fn initWithEndpoint:requestConfiguration: + @brief Please use initWithProviderID:requestConfifuration instead. + */ +- (instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration NS_UNAVAILABLE; + +/** @fn initWithProviderID:requestConfifuration + @brief Designated initializer. + @param email The email identifier used to complete hte email link sign-in flow. + @param oobCode The OOB code used to complete the email link sign-in flow. + @param requestConfiguration An object containing configurations to be added to the request. + + */ +- (instancetype)initWithEmail:(NSString *)email + oobCode:(NSString *)oobCode + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInRequest.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInRequest.m new file mode 100644 index 0000000..5ce4522 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInRequest.m @@ -0,0 +1,82 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kEmailLinkSigninEndpoint + @brief The "EmailLinkSignin" endpoint. + */ +static NSString *const kEmailLinkSigninEndpoint = @"emailLinkSignin"; + +/** @var kEmailKey + @brief The key for the "identifier" value in the request. + */ +static NSString *const kEmailKey = @"email"; + +/** @var kEmailLinkKey + @brief The key for the "emailLink" value in the request. + */ +static NSString *const kOOBCodeKey = @"oobCode"; + +/** @var kIDTokenKey + @brief The key for the "IDToken" value in the request. + */ +static NSString *const kIDTokenKey = @"idToken"; + +/** @var kPostBodyKey + @brief The key for the "postBody" value in the request. + */ +static NSString *const kPostBodyKey = @"postBody"; + +/** @var kTenantIDKey + @brief The key for the tenant id value in the request. + */ +static NSString *const kTenantIDKey = @"tenantId"; + +@implementation FIREmailLinkSignInRequest + +- (instancetype)initWithEmail:(NSString *)email + oobCode:(NSString *)oobCode + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kEmailLinkSigninEndpoint + requestConfiguration:requestConfiguration]; + if (self) { + _email = email; + _oobCode = oobCode; + } + return self; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error { + NSMutableDictionary *postBody = [@{ + kEmailKey : _email, + kOOBCodeKey : _oobCode, + } mutableCopy]; + + if (_IDToken) { + postBody[kIDTokenKey] = _IDToken; + } + if (self.tenantID) { + postBody[kTenantIDKey] = self.tenantID; + } + return [postBody copy]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInResponse.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInResponse.h new file mode 100644 index 0000000..767ec5f --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInResponse.h @@ -0,0 +1,71 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProtoMFAEnrollment.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRVerifyAssertionResponse + @brief Represents the response from the emailLinkSignin endpoint. + */ +@interface FIREmailLinkSignInResponse : NSObject + +/** @property IDToken + @brief The ID token in the email link sign-in response. + */ +@property(nonatomic, copy, readonly) NSString *IDToken; + +/** @property email + @brief The email returned by the IdP. + */ +@property(nonatomic, strong, readonly, nullable) NSString *email; + +/** @property refreshToken + @brief The refreshToken returned by the server. + */ +@property(nonatomic, strong, readonly, nullable) NSString *refreshToken; + +/** @property localID + @brief The Firebase Auth user ID. + */ +@property(nonatomic, strong, readonly, nullable) NSString *localID; + +/** @property approximateExpirationDate + @brief The approximate expiration date of the access token. + */ +@property(nonatomic, copy, readonly, nullable) NSDate *approximateExpirationDate; + +/** @property isNewUser + @brief Flag indicating that the user signing in is a new user and not a returning user. + */ +@property(nonatomic, assign) BOOL isNewUser; + +/** @property MFAPendingCredential + @brief An opaque string that functions as proof that the user has successfully passed the first + factor check. +*/ +@property(nonatomic, strong, readonly, nullable) NSString *MFAPendingCredential; + +/** @property MFAInfo + @brief Info on which multi-factor authentication providers are enabled. +*/ +@property(nonatomic, strong, readonly, nullable) NSArray *MFAInfo; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInResponse.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInResponse.m new file mode 100644 index 0000000..5ca8882 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInResponse.m @@ -0,0 +1,50 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIREmailLinkSignInResponse + +- (BOOL)setWithDictionary:(NSDictionary *)dictionary error:(NSError *_Nullable *_Nullable)error { + _localID = [dictionary[@"localId"] copy]; + _email = [dictionary[@"email"] copy]; + _IDToken = [dictionary[@"idToken"] copy]; + _isNewUser = [dictionary[@"isNewUser"] boolValue]; + _refreshToken = [dictionary[@"refreshToken"] copy]; + _approximateExpirationDate = + [dictionary[@"expiresIn"] isKindOfClass:[NSString class]] + ? [NSDate dateWithTimeIntervalSinceNow:[dictionary[@"expiresIn"] doubleValue]] + : nil; + if (dictionary[@"mfaInfo"] != nil) { + NSMutableArray *MFAInfo = [NSMutableArray array]; + NSArray *MFAInfoDataArray = dictionary[@"mfaInfo"]; + for (NSDictionary *MFAInfoData in MFAInfoDataArray) { + FIRAuthProtoMFAEnrollment *MFAEnrollment = + [[FIRAuthProtoMFAEnrollment alloc] initWithDictionary:MFAInfoData]; + [MFAInfo addObject:MFAEnrollment]; + } + _MFAInfo = MFAInfo; + } + _MFAPendingCredential = [dictionary[@"mfaPendingCredential"] copy]; + + return YES; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoRequest.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoRequest.h new file mode 100644 index 0000000..7d78500 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoRequest.h @@ -0,0 +1,53 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRGetAccountInfoRequest + @brief Represents the parameters for the getAccountInfo endpoint. + @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/getAccountInfo + */ +@interface FIRGetAccountInfoRequest : FIRIdentityToolkitRequest + +/** @property accessToken + @brief The STS Access Token for the authenticated user. + */ +@property(nonatomic, copy) NSString *accessToken; + +/** @fn initWithEndpoint:requestConfiguration:requestConfiguration + @brief Please use initWithAccessToken:requestConfiguration: instead. + */ +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_UNAVAILABLE; + +/** @fn initWithAccessToken:requestConfiguration + @brief Designated initializer. + @param accessToken The Access Token of the authenticated user. + @param requestConfiguration An object containing configurations to be added to the request. + */ +- (nullable instancetype)initWithAccessToken:(NSString *)accessToken + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoRequest.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoRequest.m new file mode 100644 index 0000000..db86f93 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoRequest.m @@ -0,0 +1,49 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kGetAccountInfoEndpoint + @brief The "getAccountInfo" endpoint. + */ +static NSString *const kGetAccountInfoEndpoint = @"getAccountInfo"; + +/** @var kIDTokenKey + @brief The key for the "idToken" value in the request. This is actually the STS Access Token, + despite it's confusing (backwards compatiable) parameter name. + */ +static NSString *const kIDTokenKey = @"idToken"; + +@implementation FIRGetAccountInfoRequest + +- (nullable instancetype)initWithAccessToken:(NSString *)accessToken + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kGetAccountInfoEndpoint requestConfiguration:requestConfiguration]; + if (self) { + _accessToken = [accessToken copy]; + } + return self; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error { + return @{kIDTokenKey : _accessToken}; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoResponse.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoResponse.h new file mode 100644 index 0000000..14e7f88 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoResponse.h @@ -0,0 +1,158 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProtoMFAEnrollment.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRGetAccountInfoResponseProviderUserInfo + @brief Represents the provider user info part of the response from the getAccountInfo endpoint. + @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/getAccountInfo + */ +@interface FIRGetAccountInfoResponseProviderUserInfo : NSObject + +/** @property providerID + @brief The ID of the identity provider. + */ +@property(nonatomic, strong, readonly, nullable) NSString *providerID; + +/** @property displayName + @brief The user's display name at the identity provider. + */ +@property(nonatomic, strong, readonly, nullable) NSString *displayName; + +/** @property photoURL + @brief The user's photo URL at the identity provider. + */ +@property(nonatomic, strong, readonly, nullable) NSURL *photoURL; + +/** @property federatedID + @brief The user's identifier at the identity provider. + */ +@property(nonatomic, strong, readonly, nullable) NSString *federatedID; + +/** @property email + @brief The user's email at the identity provider. + */ +@property(nonatomic, strong, readonly, nullable) NSString *email; + +/** @property phoneNumber + @brief A phone number associated with the user. + */ +@property(nonatomic, readonly, nullable) NSString *phoneNumber; + +/** @fn init + @brief Please use initWithDictionary: + */ +- (instancetype)init NS_UNAVAILABLE; + +/** @fn initWithAPIKey: + @brief Designated initializer. + @param dictionary The provider user info data from endpoint. + */ +- (instancetype)initWithDictionary:(NSDictionary *)dictionary NS_DESIGNATED_INITIALIZER; + +@end + +/** @class FIRGetAccountInfoResponseUser + @brief Represents the firebase user info part of the response from the getAccountInfo endpoint. + @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/getAccountInfo + */ +@interface FIRGetAccountInfoResponseUser : NSObject + +/** @property localID + @brief The ID of the user. + */ +@property(nonatomic, strong, readonly, nullable) NSString *localID; + +/** @property email + @brief The email or the user. + */ +@property(nonatomic, strong, readonly, nullable) NSString *email; + +/** @property emailVerified + @brief Whether the email has been verified. + */ +@property(nonatomic, assign, readonly) BOOL emailVerified; + +/** @property displayName + @brief The display name of the user. + */ +@property(nonatomic, strong, readonly, nullable) NSString *displayName; + +/** @property photoURL + @brief The user's photo URL. + */ +@property(nonatomic, strong, readonly, nullable) NSURL *photoURL; + +/** @property creationDate + @brief The user's creation date. + */ +@property(nonatomic, strong, readonly, nullable) NSDate *creationDate; + +/** @property lastSignInDate + @brief The user's last login date. + */ +@property(nonatomic, strong, readonly, nullable) NSDate *lastLoginDate; + +/** @property providerUserInfo + @brief The user's profiles at the associated identity providers. + */ +@property(nonatomic, strong, readonly, nullable) + NSArray *providerUserInfo; + +/** @property passwordHash + @brief Information about user's password. + @remarks This is not necessarily the hash of user's actual password. + */ +@property(nonatomic, strong, readonly, nullable) NSString *passwordHash; + +/** @property phoneNumber + @brief A phone number associated with the user. + */ +@property(nonatomic, readonly, nullable) NSString *phoneNumber; + +@property(nonatomic, strong, readonly, nullable) + NSArray *MFAEnrollments; + +/** @fn init + @brief Please use initWithDictionary: + */ +- (instancetype)init NS_UNAVAILABLE; + +/** @fn initWithAPIKey: + @brief Designated initializer. + @param dictionary The provider user info data from endpoint. + */ +- (instancetype)initWithDictionary:(NSDictionary *)dictionary NS_DESIGNATED_INITIALIZER; + +@end + +/** @class FIRGetAccountInfoResponse + @brief Represents the response from the setAccountInfo endpoint. + @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/getAccountInfo + */ +@interface FIRGetAccountInfoResponse : NSObject + +/** @property providerUserInfo + @brief The requested users' profiles. + */ +@property(nonatomic, strong, readonly, nullable) NSArray *users; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoResponse.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoResponse.m new file mode 100644 index 0000000..6b812bd --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoResponse.m @@ -0,0 +1,117 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoResponse.h" + +#import "FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kErrorKey + @brief The key for the "error" value in JSON responses from the server. + */ +static NSString *const kErrorKey = @"error"; + +@implementation FIRGetAccountInfoResponseProviderUserInfo + +- (instancetype)initWithDictionary:(NSDictionary *)dictionary { + self = [super init]; + if (self) { + _providerID = [dictionary[@"providerId"] copy]; + _displayName = [dictionary[@"displayName"] copy]; + NSString *photoURL = dictionary[@"photoUrl"]; + if (photoURL) { + _photoURL = [NSURL URLWithString:photoURL]; + } + _federatedID = [dictionary[@"federatedId"] copy]; + _email = [dictionary[@"email"] copy]; + _phoneNumber = [dictionary[@"phoneNumber"] copy]; + } + return self; +} + +@end + +@implementation FIRGetAccountInfoResponseUser + +- (instancetype)initWithDictionary:(NSDictionary *)dictionary { + self = [super init]; + if (self) { + NSArray *providerUserInfoData = dictionary[@"providerUserInfo"]; + if (providerUserInfoData) { + NSMutableArray *providerUserInfoArray = + [NSMutableArray arrayWithCapacity:providerUserInfoData.count]; + for (NSDictionary *dictionary in providerUserInfoData) { + [providerUserInfoArray addObject:[[FIRGetAccountInfoResponseProviderUserInfo alloc] + initWithDictionary:dictionary]]; + } + _providerUserInfo = [providerUserInfoArray copy]; + } + _localID = [dictionary[@"localId"] copy]; + _displayName = [dictionary[@"displayName"] copy]; + _email = [dictionary[@"email"] copy]; + NSString *photoURL = dictionary[@"photoUrl"]; + if (photoURL) { + _photoURL = [NSURL URLWithString:photoURL]; + } + if ([dictionary[@"createdAt"] isKindOfClass:[NSString class]]) { + // Divide by 1000 in order to convert miliseconds to seconds. + NSTimeInterval creationDateTimeInterval = [dictionary[@"createdAt"] doubleValue] / 1000; + _creationDate = [NSDate dateWithTimeIntervalSince1970:creationDateTimeInterval]; + } + if ([dictionary[@"lastLoginAt"] isKindOfClass:[NSString class]]) { + // Divide by 1000 in order to convert miliseconds to seconds + NSTimeInterval creationDateTimeInterval = [dictionary[@"lastLoginAt"] doubleValue] / 1000; + _lastLoginDate = [NSDate dateWithTimeIntervalSince1970:creationDateTimeInterval]; + } + _emailVerified = [dictionary[@"emailVerified"] boolValue]; + _passwordHash = [dictionary[@"passwordHash"] copy]; + _phoneNumber = [dictionary[@"phoneNumber"] copy]; + NSArray *MFAEnrollmentData = dictionary[@"mfaInfo"]; + if (MFAEnrollmentData) { + NSMutableArray *MFAEnrollments = + [NSMutableArray arrayWithCapacity:MFAEnrollmentData.count]; + for (NSDictionary *dictionary in MFAEnrollmentData) { + [MFAEnrollments + addObject:[[FIRAuthProtoMFAEnrollment alloc] initWithDictionary:dictionary]]; + } + _MFAEnrollments = [MFAEnrollments copy]; + } + } + return self; +} + +@end + +@implementation FIRGetAccountInfoResponse + +- (BOOL)setWithDictionary:(NSDictionary *)dictionary error:(NSError *_Nullable *_Nullable)error { + NSArray *usersData = dictionary[@"users"]; + // The client side never sends a getAccountInfo request with multiple localID, so only one user + // data is expected in the response. + if (![usersData isKindOfClass:[NSArray class]] || usersData.count != 1) { + if (error) { + *error = [FIRAuthErrorUtils unexpectedResponseWithDeserializedResponse:dictionary]; + } + return NO; + } + _users = @[ [[FIRGetAccountInfoResponseUser alloc] initWithDictionary:usersData.firstObject] ]; + return YES; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeRequest.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeRequest.h new file mode 100644 index 0000000..dc48a3e --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeRequest.h @@ -0,0 +1,178 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" + +@class FIRActionCodeSettings; + +NS_ASSUME_NONNULL_BEGIN + +/** @enum FIRGetOOBConfirmationCodeRequestType + @brief Types of OOB Confirmation Code requests. + */ +typedef NS_ENUM(NSInteger, FIRGetOOBConfirmationCodeRequestType) { + /** @var FIRGetOOBConfirmationCodeRequestTypePasswordReset + @brief Requests a password reset code. + */ + FIRGetOOBConfirmationCodeRequestTypePasswordReset, + + /** @var FIRGetOOBConfirmationCodeRequestTypeVerifyEmail + @brief Requests an email verification code. + */ + FIRGetOOBConfirmationCodeRequestTypeVerifyEmail, + + /** @var FIRGetOOBConfirmationCodeRequestTypeEmailLink + @brief Requests an email sign-in link. + */ + FIRGetOOBConfirmationCodeRequestTypeEmailLink, + + /** @var FIRGetOOBConfirmationCodeRequestTypeVerifyBeforeUpdateEmail + @brief Requests an verify before update email. + */ + FIRGetOOBConfirmationCodeRequestTypeVerifyBeforeUpdateEmail, +}; + +/** @enum FIRGetOOBConfirmationCodeRequest + @brief Represents the parameters for the getOOBConfirmationCode endpoint. + */ +@interface FIRGetOOBConfirmationCodeRequest : FIRIdentityToolkitRequest + +/** @property requestType + @brief The types of OOB Confirmation Code to request. + */ +@property(nonatomic, assign, readonly) FIRGetOOBConfirmationCodeRequestType requestType; + +/** @property email + @brief The email of the user. + @remarks For password reset. + */ +@property(nonatomic, copy, nullable, readonly) NSString *email; + +/** @property updatedEmail + @brief The new email to be updated. + @remarks For verifyBeforeUpdateEmail. + */ +@property(nonatomic, copy, nullable, readonly) NSString *updatedEmail; + +/** @property accessToken + @brief The STS Access Token of the authenticated user. + @remarks For email change. + */ +@property(nonatomic, copy, nullable, readonly) NSString *accessToken; + +/** @property continueURL + @brief This URL represents the state/Continue URL in the form of a universal link. + */ +@property(nonatomic, copy, nullable, readonly) NSString *continueURL; + +/** @property iOSBundleID + @brief The iOS bundle Identifier, if available. + */ +@property(nonatomic, copy, nullable, readonly) NSString *iOSBundleID; + +/** @property androidPackageName + @brief The Android package name, if available. + */ +@property(nonatomic, copy, nullable, readonly) NSString *androidPackageName; + +/** @property androidMinimumVersion + @brief The minimum Android version supported, if available. + */ +@property(nonatomic, copy, nullable, readonly) NSString *androidMinimumVersion; + +/** @property androidInstallIfNotAvailable + @brief Indicates whether or not the Android app should be installed if not already available. + */ +@property(nonatomic, assign, readonly) BOOL androidInstallApp; + +/** @property handleCodeInApp + @brief Indicates whether the action code link will open the app directly or after being + redirected from a Firebase owned web widget. + */ +@property(assign, nonatomic) BOOL handleCodeInApp; + +/** @property dynamicLinkDomain + @brief The Firebase Dynamic Link domain used for out of band code flow. + */ +@property(copy, nonatomic, nullable) NSString *dynamicLinkDomain; + +/** @fn passwordResetRequestWithEmail:actionCodeSettings:requestConfiguration: + @brief Creates a password reset request. + @param email The user's email address. + @param actionCodeSettings An object of FIRActionCodeSettings which specifies action code + settings to be applied to the password reset request. + @param requestConfiguration An object containing configurations to be added to the request. + @return A password reset request. + */ ++ (nullable FIRGetOOBConfirmationCodeRequest *) + passwordResetRequestWithEmail:(NSString *)email + actionCodeSettings:(nullable FIRActionCodeSettings *)actionCodeSettings + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration; + +/** @fn verifyEmailRequestWithAccessToken:actionCodeSettings:requestConfiguration: + @brief Creates a password reset request. + @param accessToken The user's STS Access Token. + @param actionCodeSettings An object of FIRActionCodeSettings which specifies action code + settings to be applied to the email verification request. + @param requestConfiguration An object containing configurations to be added to the request. + @return A password reset request. + */ ++ (nullable FIRGetOOBConfirmationCodeRequest *) + verifyEmailRequestWithAccessToken:(NSString *)accessToken + actionCodeSettings:(nullable FIRActionCodeSettings *)actionCodeSettings + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration; + +/** @fn signInWithEmailLinkRequest:actionCodeSettings:requestConfiguration: + @brief Creates a sign-in with email link. + @param email The user's email address. + @param actionCodeSettings An object of FIRActionCodeSettings which specifies action code + settings to be applied to the email sign-in link. + @param requestConfiguration An object containing configurations to be added to the request. + @return An email sign-in link request. + */ ++ (nullable FIRGetOOBConfirmationCodeRequest *) + signInWithEmailLinkRequest:(NSString *)email + actionCodeSettings:(nullable FIRActionCodeSettings *)actionCodeSettings + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration; + +/** @fn verifyBeforeUpdateEmailWithAccessToken:newEmail:actionCodeSettings:requestConfiguration: + @brief Creates a verifyBeforeUpdateEmail request. + @param accessToken The user's STS Access Token. + @param newEmail The user's email address to be updated. + @param actionCodeSettings An object of FIRActionCodeSettings which specifies action code + settings to be applied to the password reset request. + @param requestConfiguration An object containing configurations to be added to the request. + @return A verifyBeforeUpdateEmail request. + */ ++ (nullable FIRGetOOBConfirmationCodeRequest *) + verifyBeforeUpdateEmailWithAccessToken:(NSString *)accessToken + newEmail:(NSString *)newEmail + actionCodeSettings:(nullable FIRActionCodeSettings *)actionCodeSettings + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration; + +/** @fn init + @brief Please use a factory method. + */ +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeRequest.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeRequest.m new file mode 100644 index 0000000..a749a54 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeRequest.m @@ -0,0 +1,296 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeRequest.h" + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRActionCodeSettings.h" + +#import "FirebaseAuth/Sources/Auth/FIRAuth_Internal.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kEndpoint + @brief The getOobConfirmationCode endpoint name. + */ +static NSString *const kGetOobConfirmationCodeEndpoint = @"getOobConfirmationCode"; + +/** @var kRequestTypeKey + @brief The name of the required "requestType" property in the request. + */ +static NSString *const kRequestTypeKey = @"requestType"; + +/** @var kEmailKey + @brief The name of the "email" property in the request. + */ +static NSString *const kEmailKey = @"email"; + +/** @var kNewEmailKey + @brief The name of the "newEmail" property in the request. + */ +static NSString *const kNewEmailKey = @"newEmail"; + +/** @var kIDTokenKey + @brief The key for the "idToken" value in the request. This is actually the STS Access Token, + despite it's confusing (backwards compatiable) parameter name. + */ +static NSString *const kIDTokenKey = @"idToken"; + +/** @var kContinueURLKey + @brief The key for the "continue URL" value in the request. + */ +static NSString *const kContinueURLKey = @"continueUrl"; + +/** @var kIosBundeIDKey + @brief The key for the "iOS Bundle Identifier" value in the request. + */ +static NSString *const kIosBundleIDKey = @"iOSBundleId"; + +/** @var kAndroidPackageNameKey + @brief The key for the "Android Package Name" value in the request. + */ +static NSString *const kAndroidPackageNameKey = @"androidPackageName"; + +/** @var kAndroidInstallAppKey + @brief The key for the request parameter indicating whether the android app should be installed + or not. + */ +static NSString *const kAndroidInstallAppKey = @"androidInstallApp"; + +/** @var kAndroidMinimumVersionKey + @brief The key for the "minimum Android version supported" value in the request. + */ +static NSString *const kAndroidMinimumVersionKey = @"androidMinimumVersion"; + +/** @var kCanHandleCodeInAppKey + @brief The key for the request parameter indicating whether the action code can be handled in + the app or not. + */ +static NSString *const kCanHandleCodeInAppKey = @"canHandleCodeInApp"; + +/** @var kDynamicLinkDomainKey + @brief The key for the "dynamic link domain" value in the request. + */ +static NSString *const kDynamicLinkDomainKey = @"dynamicLinkDomain"; + +/** @var kPasswordResetRequestTypeValue + @brief The value for the "PASSWORD_RESET" request type. + */ +static NSString *const kPasswordResetRequestTypeValue = @"PASSWORD_RESET"; + +/** @var kEmailLinkSignInTypeValue + @brief The value for the "EMAIL_SIGNIN" request type. + */ +static NSString *const kEmailLinkSignInTypeValue = @"EMAIL_SIGNIN"; + +/** @var kVerifyEmailRequestTypeValue + @brief The value for the "VERIFY_EMAIL" request type. + */ +static NSString *const kVerifyEmailRequestTypeValue = @"VERIFY_EMAIL"; + +/** @var kVerifyBeforeUpdateEmailRequestTypeValue + @brief The value for the "VERIFY_AND_CHANGE_EMAIL" request type. + */ +static NSString *const kVerifyBeforeUpdateEmailRequestTypeValue = @"VERIFY_AND_CHANGE_EMAIL"; + +/** @var kTenantIDKey + @brief The key for the tenant id value in the request. + */ +static NSString *const kTenantIDKey = @"tenantId"; + +@interface FIRGetOOBConfirmationCodeRequest () + +/** @fn initWithRequestType:email:APIKey: + @brief Designated initializer. + @param requestType The types of OOB Confirmation Code to request. + @param email The email of the user. + @param newEmail The email of the user to be updated. + @param accessToken The STS Access Token of the currently signed in user. + @param actionCodeSettings An object of FIRActionCodeSettings which specifies action code + settings to be applied to the OOB code request. + @param requestConfiguration An object containing configurations to be added to the request. + */ +- (nullable instancetype)initWithRequestType:(FIRGetOOBConfirmationCodeRequestType)requestType + email:(nullable NSString *)email + newEmail:(nullable NSString *)newEmail + accessToken:(nullable NSString *)accessToken + actionCodeSettings:(nullable FIRActionCodeSettings *)actionCodeSettings + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_DESIGNATED_INITIALIZER; + +@end + +@implementation FIRGetOOBConfirmationCodeRequest + +/** @var requestTypeStringValueForRequestType: + @brief Returns the string equivilent for an @c FIRGetOOBConfirmationCodeRequestType value. + */ ++ (NSString *)requestTypeStringValueForRequestType: + (FIRGetOOBConfirmationCodeRequestType)requestType { + switch (requestType) { + case FIRGetOOBConfirmationCodeRequestTypePasswordReset: + return kPasswordResetRequestTypeValue; + case FIRGetOOBConfirmationCodeRequestTypeVerifyEmail: + return kVerifyEmailRequestTypeValue; + case FIRGetOOBConfirmationCodeRequestTypeEmailLink: + return kEmailLinkSignInTypeValue; + case FIRGetOOBConfirmationCodeRequestTypeVerifyBeforeUpdateEmail: + return kVerifyBeforeUpdateEmailRequestTypeValue; + // No default case so that we get a compiler warning if a new value was added to the enum. + } +} + ++ (nullable FIRGetOOBConfirmationCodeRequest *) + passwordResetRequestWithEmail:(NSString *)email + actionCodeSettings:(nullable FIRActionCodeSettings *)actionCodeSettings + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + return [[self alloc] initWithRequestType:FIRGetOOBConfirmationCodeRequestTypePasswordReset + email:email + newEmail:nil + accessToken:nil + actionCodeSettings:actionCodeSettings + requestConfiguration:requestConfiguration]; +} + ++ (nullable FIRGetOOBConfirmationCodeRequest *) + verifyEmailRequestWithAccessToken:(NSString *)accessToken + actionCodeSettings:(nullable FIRActionCodeSettings *)actionCodeSettings + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + return [[self alloc] initWithRequestType:FIRGetOOBConfirmationCodeRequestTypeVerifyEmail + email:nil + newEmail:nil + accessToken:accessToken + actionCodeSettings:actionCodeSettings + requestConfiguration:requestConfiguration]; +} + ++ (nullable FIRGetOOBConfirmationCodeRequest *) + signInWithEmailLinkRequest:(NSString *)email + actionCodeSettings:(nullable FIRActionCodeSettings *)actionCodeSettings + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + return [[self alloc] initWithRequestType:FIRGetOOBConfirmationCodeRequestTypeEmailLink + email:email + newEmail:nil + accessToken:nil + actionCodeSettings:actionCodeSettings + requestConfiguration:requestConfiguration]; +} + ++ (nullable FIRGetOOBConfirmationCodeRequest *) + verifyBeforeUpdateEmailWithAccessToken:(NSString *)accessToken + newEmail:(NSString *)newEmail + actionCodeSettings:(nullable FIRActionCodeSettings *)actionCodeSettings + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + return + [[self alloc] initWithRequestType:FIRGetOOBConfirmationCodeRequestTypeVerifyBeforeUpdateEmail + email:nil + newEmail:newEmail + accessToken:accessToken + actionCodeSettings:actionCodeSettings + requestConfiguration:requestConfiguration]; +} + +- (nullable instancetype)initWithRequestType:(FIRGetOOBConfirmationCodeRequestType)requestType + email:(nullable NSString *)email + newEmail:(nullable NSString *)newEmail + accessToken:(nullable NSString *)accessToken + actionCodeSettings:(nullable FIRActionCodeSettings *)actionCodeSettings + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kGetOobConfirmationCodeEndpoint + requestConfiguration:requestConfiguration]; + if (self) { + _requestType = requestType; + _email = email; + _updatedEmail = newEmail; + _accessToken = accessToken; + _continueURL = actionCodeSettings.URL.absoluteString; + _iOSBundleID = actionCodeSettings.iOSBundleID; + _androidPackageName = actionCodeSettings.androidPackageName; + _androidMinimumVersion = actionCodeSettings.androidMinimumVersion; + _androidInstallApp = actionCodeSettings.androidInstallIfNotAvailable; + _handleCodeInApp = actionCodeSettings.handleCodeInApp; + _dynamicLinkDomain = actionCodeSettings.dynamicLinkDomain; + } + return self; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error { + NSMutableDictionary *body = + [@{kRequestTypeKey : [[self class] requestTypeStringValueForRequestType:_requestType]} + mutableCopy]; + + // For password reset requests, we only need an email address in addition to the already required + // fields. + if (_requestType == FIRGetOOBConfirmationCodeRequestTypePasswordReset) { + body[kEmailKey] = _email; + } + + // For verify email requests, we only need an STS Access Token in addition to the already required + // fields. + if (_requestType == FIRGetOOBConfirmationCodeRequestTypeVerifyEmail) { + body[kIDTokenKey] = _accessToken; + } + + // For email sign-in link requests, we only need an email address in addition to the already + // required fields. + if (_requestType == FIRGetOOBConfirmationCodeRequestTypeEmailLink) { + body[kEmailKey] = _email; + } + + // For email sign-in link requests, we only need an STS Access Token, a new email address in + // addition to the already required fields. + if (_requestType == FIRGetOOBConfirmationCodeRequestTypeVerifyBeforeUpdateEmail) { + body[kNewEmailKey] = _updatedEmail; + body[kIDTokenKey] = _accessToken; + } + + if (_continueURL) { + body[kContinueURLKey] = _continueURL; + } + + if (_iOSBundleID) { + body[kIosBundleIDKey] = _iOSBundleID; + } + + if (_androidPackageName) { + body[kAndroidPackageNameKey] = _androidPackageName; + } + + if (_androidMinimumVersion) { + body[kAndroidMinimumVersionKey] = _androidMinimumVersion; + } + + if (_androidInstallApp) { + body[kAndroidInstallAppKey] = @YES; + } + + if (_handleCodeInApp) { + body[kCanHandleCodeInAppKey] = @YES; + } + + if (_dynamicLinkDomain) { + body[kDynamicLinkDomainKey] = _dynamicLinkDomain; + } + if (self.tenantID) { + body[kTenantIDKey] = self.tenantID; + } + + return body; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeResponse.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeResponse.h new file mode 100644 index 0000000..9ea445e --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeResponse.h @@ -0,0 +1,35 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRGetOOBConfirmationCodeResponse + @brief Represents the response from the getOobConfirmationCode endpoint. + */ +@interface FIRGetOOBConfirmationCodeResponse : NSObject + +/** @property OOBCode + @brief The OOB code returned by the server in some cases. + */ +@property(nonatomic, copy, readonly, nullable) NSString *OOBCode; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeResponse.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeResponse.m new file mode 100644 index 0000000..7eef688 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeResponse.m @@ -0,0 +1,35 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kOOBCodeKey + @brief The name of the field in the response JSON for the OOB code. + */ +static NSString *const kOOBCodeKey = @"oobCode"; + +@implementation FIRGetOOBConfirmationCodeResponse + +- (BOOL)setWithDictionary:(NSDictionary *)dictionary error:(NSError *_Nullable *_Nullable)error { + _OOBCode = [dictionary[kOOBCodeKey] copy]; + return YES; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigRequest.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigRequest.h new file mode 100644 index 0000000..cfaefcc --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigRequest.h @@ -0,0 +1,40 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRGetProjectConfigRequest : FIRIdentityToolkitRequest + +/** @fn initWithEndpoint:requestConfiguration: + @brief Please use initWithRequestConfiguration: + */ +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_UNAVAILABLE; + +/** @fn initWithTemporaryProof:phoneNumberAPIKey + @brief Designated initializer. + @param requestConfiguration An object containing configurations to be added to the request. + */ +- (nullable instancetype)initWithRequestConfiguration: + (FIRAuthRequestConfiguration *)requestConfiguration NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigRequest.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigRequest.m new file mode 100644 index 0000000..402f220 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigRequest.m @@ -0,0 +1,40 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kGetProjectConfigEndPoint + @brief The "getProjectConfig" endpoint. + */ +static NSString *const kGetProjectConfigEndPoint = @"getProjectConfig"; + +@implementation FIRGetProjectConfigRequest + +- (nullable instancetype)initWithRequestConfiguration: + (FIRAuthRequestConfiguration *)requestConfiguration { + return [super initWithEndpoint:kGetProjectConfigEndPoint + requestConfiguration:requestConfiguration]; +} + +- (BOOL)containsPostBody { + return NO; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigResponse.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigResponse.h new file mode 100644 index 0000000..71f79c9 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigResponse.h @@ -0,0 +1,40 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRGetProjectConfigResponse + @brief Represents the response from the getProjectConfig endpoint. + */ +@interface FIRGetProjectConfigResponse : NSObject + +/** @property projectID + @brief The unique ID pertaining to the current project. + */ +@property(nonatomic, strong, readonly, nullable) NSString *projectID; + +/** @property authorizedDomains + @brief A list of domains allowlisted for the current project. + */ +@property(nonatomic, strong, readonly, nullable) NSArray *authorizedDomains; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigResponse.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigResponse.m new file mode 100644 index 0000000..38a3ba0 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigResponse.m @@ -0,0 +1,40 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRGetProjectConfigResponse + +- (BOOL)setWithDictionary:(NSDictionary *)dictionary error:(NSError *_Nullable *_Nullable)error { + _projectID = [dictionary[@"projectId"] copy]; + id authorizedDomains = dictionary[@"authorizedDomains"]; + if ([authorizedDomains isKindOfClass:[NSString class]]) { + NSData *data = [authorizedDomains dataUsingEncoding:NSUTF8StringEncoding]; + authorizedDomains = [NSJSONSerialization JSONObjectWithData:data + options:NSJSONReadingMutableLeaves + error:nil]; + } + if ([authorizedDomains isKindOfClass:[NSArray class]]) { + _authorizedDomains = [[NSArray alloc] initWithArray:authorizedDomains copyItems:YES]; + } + return YES; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordRequest.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordRequest.h new file mode 100644 index 0000000..1b918f5 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordRequest.h @@ -0,0 +1,55 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRResetPasswordRequest : FIRIdentityToolkitRequest + +/** @property oobCode + @brief The oobCode sent in the request. + */ +@property(nonatomic, copy, readonly) NSString *oobCode; + +/** @property updatedPassword + @brief The new password sent in the request. + */ +@property(nonatomic, copy, readonly) NSString *updatedPassword; + +/** @fn initWithEndpoint:requestConfiguration: + @brief Please use initWithOobCode:newPassword:requestConfiguration: instead. + */ +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_UNAVAILABLE; + +/** @fn initWithOobCode:newPassword:requestConfiguration: + @brief Designated initializer. + @param oobCode The OOB Code. + @param newPassword The new password. + @param requestConfiguration An object containing configurations to be added to the request. + */ +- (nullable instancetype)initWithOobCode:(NSString *)oobCode + newPassword:(nullable NSString *)newPassword + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordRequest.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordRequest.m new file mode 100644 index 0000000..7579b29 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordRequest.m @@ -0,0 +1,68 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kResetPasswordEndpoint + @brief The "resetPassword" endpoint. + */ +static NSString *const kResetPasswordEndpoint = @"resetPassword"; + +/** @var kOOBCodeKey + @brief The "resetPassword" key. + */ +static NSString *const kOOBCodeKey = @"oobCode"; + +/** @var kCurrentPasswordKey + @brief The "newPassword" key. + */ +static NSString *const kCurrentPasswordKey = @"newPassword"; + +/** @var kTenantIDKey + @brief The key for the tenant id value in the request. + */ +static NSString *const kTenantIDKey = @"tenantId"; + +@implementation FIRResetPasswordRequest + +- (nullable instancetype)initWithOobCode:(NSString *)oobCode + newPassword:(nullable NSString *)newPassword + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kResetPasswordEndpoint requestConfiguration:requestConfiguration]; + if (self) { + _oobCode = oobCode; + _updatedPassword = newPassword; + } + return self; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error { + NSMutableDictionary *postBody = [NSMutableDictionary dictionary]; + postBody[kOOBCodeKey] = _oobCode; + if (_updatedPassword) { + postBody[kCurrentPasswordKey] = _updatedPassword; + } + if (self.tenantID) { + postBody[kTenantIDKey] = self.tenantID; + } + return [postBody copy]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordResponse.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordResponse.h new file mode 100644 index 0000000..3e8c560 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordResponse.h @@ -0,0 +1,52 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRAuthResetPasswordResponse + @brief Represents the response from the resetPassword endpoint. + @remarks Possible error codes: + - FIRAuthErrorCodeWeakPassword + - FIRAuthErrorCodeUserDisabled + - FIRAuthErrorCodeOperationNotAllowed + - FIRAuthErrorCodeExpiredActionCode + - FIRAuthErrorCodeInvalidActionCode + @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/resetPassword + */ +@interface FIRResetPasswordResponse : NSObject + +/** @property email + @brief The email address corresponding to the reset password request. + */ +@property(nonatomic, strong, readonly) NSString *email; + +/** @property verifiedEmail + @brief The verified email returned from the backend. + */ +@property(nonatomic, strong, readonly) NSString *verifiedEmail; + +/** @property requestType + @brief The tpye of request as returned by the backend. + */ +@property(nonatomic, strong, readonly) NSString *requestType; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordResponse.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordResponse.m new file mode 100644 index 0000000..5ad1e36 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordResponse.m @@ -0,0 +1,32 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRResetPasswordResponse + +- (BOOL)setWithDictionary:(NSDictionary *)dictionary error:(NSError *_Nullable *_Nullable)error { + _email = [dictionary[@"email"] copy]; + _requestType = [dictionary[@"requestType"] copy]; + _verifiedEmail = [dictionary[@"newEmail"] copy]; + return YES; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRRevokeTokenRequest.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRRevokeTokenRequest.h new file mode 100644 index 0000000..3d4c7b7 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRRevokeTokenRequest.h @@ -0,0 +1,63 @@ +/* + * Copyright 2023 Google LLC + * + * 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 "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRRevokeTokenRequest : FIRIdentityToolkitRequest + +/** @property providerID + @brief The provider that issued the token to revoke. + */ +@property(nonatomic, copy, nullable) NSString *providerID; + +/** @property tokenType + @brief The type of the token to revoke. + */ +@property(nonatomic) NSInteger tokenType; + +/** @property token + @brief The token to be revoked. + */ +@property(nonatomic, copy, nullable) NSString *token; + +/** @property idToken + @brief The ID Token associated with this credential. + */ +@property(nonatomic, copy, nullable) NSString *idToken; + +/** @fn initWithEndpoint:requestConfiguration: + @brief Please use initWithToken:requestConfiguration: instead. + */ +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_UNAVAILABLE; + +/** @fn initWithAppToken:isSandbox:requestConfiguration: + @brief Designated initializer. + @param token The token to be revoked. + @param idToken The id token associated with the current user. + @param requestConfiguration An object containing configurations to be added to the request. + */ +- (nullable instancetype)initWithToken:(NSString *)token + idToken:(NSString *)idToken + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRRevokeTokenRequest.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRRevokeTokenRequest.m new file mode 100644 index 0000000..418329f --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRRevokeTokenRequest.m @@ -0,0 +1,103 @@ +/* + * Copyright 2023 Google LLC + * + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRRevokeTokenRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kRevokeTokenEndpoint + @brief The endpoint for the revokeToken request. + */ +static NSString *const kRevokeTokenEndpoint = @"accounts:revokeToken"; + +/** @var kProviderIDKey + @brief The key for the provider that issued the token to revoke. + */ +static NSString *const kProviderIDKey = @"providerId"; + +/** @var kTokenTypeKey + @brief The key for the type of the token to revoke. + */ +static NSString *const kTokenTypeKey = @"tokenType"; + +/** @var kTokenKey + @brief The key for the token to be revoked. + */ +static NSString *const kTokenKey = @"token"; + +/** @var kIDTokenKey + @brief The key for the ID Token associated with this credential. + */ +static NSString *const kIDTokenKey = @"idToken"; + +typedef NS_ENUM(NSInteger, FIRTokenType) { + /** Indicates that the token type is unspecified. + */ + FIRTokenTypeUnspecified = 0, + + /** Indicates that the token type is refresh token. + */ + FIRTokenTypeRefreshToken = 1, + + /** Indicates that the token type is access token. + */ + FIRTokenTypeAccessToken = 2, + + /** Indicates that the token type is authorization code. + */ + FIRTokenTypeAuthorizationCode = 3, +}; + +@implementation FIRRevokeTokenRequest + +- (nullable instancetype)initWithToken:(NSString *)token + idToken:(NSString *)idToken + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kRevokeTokenEndpoint + requestConfiguration:requestConfiguration + useIdentityPlatform:YES + useStaging:NO]; + if (self) { + // Apple and authorization code are the only provider and token type we support for now. + // Generalize this initializer to accept other providers and token types once supported. + _providerID = @"apple.com"; + _tokenType = FIRTokenTypeAuthorizationCode; + _token = token; + _idToken = idToken; + } + return self; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *__autoreleasing _Nullable *)error { + NSMutableDictionary *postBody = [NSMutableDictionary dictionary]; + if (_providerID) { + postBody[kProviderIDKey] = _providerID; + } + if (_tokenType) { + postBody[kTokenTypeKey] = [NSNumber numberWithInteger:_tokenType].stringValue; + } + if (_token) { + postBody[kTokenKey] = _token; + } + if (_idToken) { + postBody[kIDTokenKey] = _idToken; + } + return [postBody copy]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRRevokeTokenResponse.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRRevokeTokenResponse.h new file mode 100644 index 0000000..270ec53 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRRevokeTokenResponse.h @@ -0,0 +1,27 @@ +/* + * Copyright 2023 Google LLC + * + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRRevokeTokenResponse : NSObject + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRRevokeTokenResponse.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRRevokeTokenResponse.m new file mode 100644 index 0000000..328e66f --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRRevokeTokenResponse.m @@ -0,0 +1,29 @@ +/* + * Copyright 2023 Google LLC + * + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRRevokeTokenResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRRevokeTokenResponse + +- (BOOL)setWithDictionary:(NSDictionary *)dictionary error:(NSError *_Nullable *_Nullable)error { + return YES; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenRequest.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenRequest.h new file mode 100644 index 0000000..07e3901 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenRequest.h @@ -0,0 +1,64 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRSecureTokenRequest + @brief Represents the parameters for the token endpoint. + */ +@interface FIRSecureTokenRequest : NSObject + +/** @property refreshToken + @brief The client's refresh token. + */ +@property(nonatomic, copy, readonly, nullable) NSString *refreshToken; + +/** @property APIKey + @brief The client's API Key. + */ +@property(nonatomic, copy, readonly) NSString *APIKey; + +/** @fn refreshRequestWithRefreshToken:requestConfiguration: + @brief Creates a refresh request with the given refresh token. + @param refreshToken The refresh token. + @param requestConfiguration An object containing configurations to be added to the request. + @return A refresh request. + */ ++ (FIRSecureTokenRequest *)refreshRequestWithRefreshToken:(NSString *)refreshToken + requestConfiguration: + (FIRAuthRequestConfiguration *)requestConfiguration; + +/** @fn init + @brief Please use initWithRefreshToken:requestConfiguration: + */ +- (instancetype)init NS_UNAVAILABLE; + +/** @fn initWithRefreshToken:requestConfiguration: + @brief Designated initializer. + @param refreshToken The client's refresh token (for refresh requests.) + @param requestConfiguration An object containing configurations to be added to the request. + */ +- (nullable instancetype)initWithRefreshToken:(NSString *)refreshToken + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenRequest.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenRequest.m new file mode 100644 index 0000000..48966e6 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenRequest.m @@ -0,0 +1,122 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenRequest.h" + +#import "FirebaseAuth/Sources/Backend/FIRAuthRequestConfiguration.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kFIRSecureTokenServiceGetTokenURLFormat + @brief The format of the secure token service URLs. Requires string format substitution with + the client's API Key. + */ +static NSString *const kFIRSecureTokenServiceGetTokenURLFormat = @"https://%@/v1/token?key=%@"; + +/** @var kFIREmulatorURLFormat + @brief The format of the emulated secure token service URLs. Requires string format substitution + with the emulator host, the gAPIHost, and the client's API Key. + */ +static NSString *const kFIREmulatorURLFormat = @"http://%@/%@/v1/token?key=%@"; + +/** @var kFIRSecureTokenServiceGrantTypeRefreshToken + @brief The string value of the @c FIRSecureTokenRequestGrantTypeRefreshToken request type. + */ +static NSString *const kFIRSecureTokenServiceGrantTypeRefreshToken = @"refresh_token"; + +/** @var kGrantTypeKey + @brief The key for the "grantType" parameter in the request. + */ +static NSString *const kGrantTypeKey = @"grantType"; + +/** @var kRefreshTokenKey + @brief The key for the "refreshToken" parameter in the request. + */ +static NSString *const kRefreshTokenKey = @"refreshToken"; + +/** @var gAPIHost + @brief Host for server API calls. + */ +static NSString *gAPIHost = @"securetoken.googleapis.com"; + +@implementation FIRSecureTokenRequest { + /** @var _requestConfiguration + @brief Contains configuration relevant to the request. + */ + FIRAuthRequestConfiguration *_requestConfiguration; +} + ++ (FIRSecureTokenRequest *)refreshRequestWithRefreshToken:(NSString *)refreshToken + requestConfiguration: + (FIRAuthRequestConfiguration *)requestConfiguration { + return [[self alloc] initWithRefreshToken:refreshToken requestConfiguration:requestConfiguration]; +} + +- (nullable instancetype)initWithRefreshToken:(NSString *)refreshToken + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super init]; + if (self) { + _refreshToken = [refreshToken copy]; + _APIKey = [requestConfiguration.APIKey copy]; + _requestConfiguration = requestConfiguration; + } + return self; +} + +- (FIRAuthRequestConfiguration *)requestConfiguration { + return _requestConfiguration; +} + +- (NSURL *)requestURL { + NSString *URLString; + + NSString *emulatorHostAndPort = _requestConfiguration.emulatorHostAndPort; + if (emulatorHostAndPort) { + URLString = + [NSString stringWithFormat:kFIREmulatorURLFormat, emulatorHostAndPort, gAPIHost, _APIKey]; + } else { + URLString = + [NSString stringWithFormat:kFIRSecureTokenServiceGetTokenURLFormat, gAPIHost, _APIKey]; + } + NSURL *URL = [NSURL URLWithString:URLString]; + return URL; +} + +- (BOOL)containsPostBody { + return YES; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error { + NSMutableDictionary *postBody = [@{ + kGrantTypeKey : kFIRSecureTokenServiceGrantTypeRefreshToken, + kRefreshTokenKey : _refreshToken + } mutableCopy]; + return [postBody copy]; +} + +#pragma mark - Internal API for development + ++ (NSString *)host { + return gAPIHost; +} + ++ (void)setHost:(NSString *)host { + gAPIHost = host; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenResponse.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenResponse.h new file mode 100644 index 0000000..a45f9ad --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenResponse.h @@ -0,0 +1,50 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRSecureTokenResponse + @brief Represents the response from the token endpoint. + */ +@interface FIRSecureTokenResponse : NSObject + +/** @property approximateExpirationDate + @brief The approximate expiration date of the access token. + */ +@property(nonatomic, copy, readonly, nullable) NSDate *approximateExpirationDate; + +/** @property refreshToken + @brief The refresh token. (Possibly an updated one for refresh requests.) + */ +@property(nonatomic, copy, readonly, nullable) NSString *refreshToken; + +/** @property accessToken + @brief The new access token. + */ +@property(nonatomic, copy, readonly, nullable) NSString *accessToken; + +/** @property IDToken + @brief The new ID Token. + */ +@property(nonatomic, copy, readonly, nullable) NSString *IDToken; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenResponse.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenResponse.m new file mode 100644 index 0000000..5d4c00a --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenResponse.m @@ -0,0 +1,73 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenResponse.h" + +#import "FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kExpiresInKey + @brief The key for the number of seconds till the access token expires. + */ +static NSString *const kExpiresInKey = @"expires_in"; + +/** @var kRefreshTokenKey + @brief The key for the refresh token. + */ +static NSString *const kRefreshTokenKey = @"refresh_token"; + +/** @var kAccessTokenKey + @brief The key for the access token. + */ +static NSString *const kAccessTokenKey = @"access_token"; + +/** @var kIDTokenKey + @brief The key for the "id_token" value in the response. + */ +static NSString *const kIDTokenKey = @"id_token"; + +@implementation FIRSecureTokenResponse + +- (nullable NSString *)expectedKind { + return nil; +} + +- (BOOL)setWithDictionary:(NSDictionary *)dictionary error:(NSError *_Nullable *_Nullable)error { + _refreshToken = dictionary[kRefreshTokenKey]; + _accessToken = dictionary[kAccessTokenKey]; + _IDToken = dictionary[kIDTokenKey]; + if (!_accessToken.length) { + if (error) { + *error = [FIRAuthErrorUtils unexpectedResponseWithDeserializedResponse:dictionary]; + } + return NO; + } + id expiresIn = dictionary[kExpiresInKey]; + if (![expiresIn isKindOfClass:[NSString class]]) { + if (error) { + *error = [FIRAuthErrorUtils unexpectedResponseWithDeserializedResponse:dictionary]; + } + return NO; + } + + _approximateExpirationDate = [NSDate dateWithTimeIntervalSinceNow:[expiresIn doubleValue]]; + return YES; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeRequest.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeRequest.h new file mode 100644 index 0000000..974eb6a --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeRequest.h @@ -0,0 +1,64 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" + +@class FIRAuthAppCredential; + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRSendVerificationCodeRequest : FIRIdentityToolkitRequest + +/** @property phoneNumber + @brief The phone number to which the verification code should be sent. + */ +@property(nonatomic, strong, readonly) NSString *phoneNumber; + +/** @property appCredential + @brief The credential to prove the identity of the app in order to send the verification code. + */ +@property(nonatomic, strong, readonly, nullable) FIRAuthAppCredential *appCredential; + +/** @property reCAPTCHAToken + @brief The reCAPTCHA token to prove the identity of the app in order to send the verification + code. + */ +@property(nonatomic, strong, readonly, nullable) NSString *reCAPTCHAToken; + +/** @fn initWithEndpoint:requestConfiguration: + @brief Please use initWithPhoneNumber:appCredentials:requestConfiguration: instead. + */ +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_UNAVAILABLE; + +/** @fn initWithPhoneNumber:appCredentials:requestConfiguration: + @brief Designated initializer. + @param phoneNumber The phone number to which the verification code is to be sent. + @param appCredential The credential that proves the identity of the app. + @param reCAPTCHAToken The reCAPTCHA token that proves the identity of the app. + @param requestConfiguration An object containing configurations to be added to the request. + */ +- (nullable instancetype)initWithPhoneNumber:(NSString *)phoneNumber + appCredential:(nullable FIRAuthAppCredential *)appCredential + reCAPTCHAToken:(nullable NSString *)reCAPTCHAToken + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeRequest.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeRequest.m new file mode 100644 index 0000000..15e2681 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeRequest.m @@ -0,0 +1,92 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeRequest.h" + +#import "FirebaseAuth/Sources/SystemService/FIRAuthAppCredential.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kSendVerificationCodeEndPoint + @brief The "sendVerificationCodeEnd" endpoint. + */ +static NSString *const kSendVerificationCodeEndPoint = @"sendVerificationCode"; + +/** @var kPhoneNumberKey + @brief The key for the Phone Number parameter in the request. + */ +static NSString *const kPhoneNumberKey = @"phoneNumber"; + +/** @var kReceiptKey + @brief The key for the receipt parameter in the request. + */ +static NSString *const kReceiptKey = @"iosReceipt"; + +/** @var kSecretKey + @brief The key for the Secret parameter in the request. + */ +static NSString *const kSecretKey = @"iosSecret"; + +/** @var kreCAPTCHATokenKey + @brief The key for the reCAPTCHAToken parameter in the request. + */ +static NSString *const kreCAPTCHATokenKey = @"recaptchaToken"; + +/** @var kTenantIDKey + @brief The key for the tenant id value in the request. + */ +static NSString *const kTenantIDKey = @"tenantId"; + +@implementation FIRSendVerificationCodeRequest { +} + +- (nullable instancetype)initWithPhoneNumber:(NSString *)phoneNumber + appCredential:(nullable FIRAuthAppCredential *)appCredential + reCAPTCHAToken:(nullable NSString *)reCAPTCHAToken + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kSendVerificationCodeEndPoint + requestConfiguration:requestConfiguration]; + if (self) { + _phoneNumber = [phoneNumber copy]; + _appCredential = appCredential; + _reCAPTCHAToken = [reCAPTCHAToken copy]; + } + return self; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error { + NSMutableDictionary *postBody = [NSMutableDictionary dictionary]; + if (_phoneNumber) { + postBody[kPhoneNumberKey] = _phoneNumber; + } + if (_appCredential.receipt) { + postBody[kReceiptKey] = _appCredential.receipt; + } + if (_appCredential.secret) { + postBody[kSecretKey] = _appCredential.secret; + } + if (_reCAPTCHAToken) { + postBody[kreCAPTCHATokenKey] = _reCAPTCHAToken; + } + if (self.tenantID) { + postBody[kTenantIDKey] = self.tenantID; + } + return [postBody copy]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeResponse.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeResponse.h new file mode 100644 index 0000000..605f3f4 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeResponse.h @@ -0,0 +1,32 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRSendVerificationCodeResponse : NSObject + +/** @property verificationID + @brief Encrypted session information returned by the backend. + */ +@property(nonatomic, readonly) NSString *verificationID; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeResponse.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeResponse.m new file mode 100644 index 0000000..6e8598c --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeResponse.m @@ -0,0 +1,35 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRSendVerificationCodeResponse + +// TODO: remove when resolving b/37169084 . +- (nullable NSString *)expectedKind { + return nil; +} + +- (BOOL)setWithDictionary:(NSDictionary *)dictionary error:(NSError *_Nullable *_Nullable)error { + _verificationID = [dictionary[@"sessionInfo"] copy]; + return YES; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoRequest.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoRequest.h new file mode 100644 index 0000000..5ba22ba --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoRequest.h @@ -0,0 +1,151 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" + +@class FIRGetAccountInfoResponse; + +NS_ASSUME_NONNULL_BEGIN + +/** @var FIRSetAccountInfoUserAttributeEmail + @brief Constant for email attribute used in "deleteAttributes". + */ +extern NSString *const FIRSetAccountInfoUserAttributeEmail; + +/** @var FIRSetAccountInfoUserAttributeDisplayName + @brief Constant for displayName attribute used in "deleteAttributes". + */ +extern NSString *const FIRSetAccountInfoUserAttributeDisplayName; + +/** @var FIRSetAccountInfoUserAttributeProvider + @brief Constant for provider attribute used in "deleteAttributes". + */ +extern NSString *const FIRSetAccountInfoUserAttributeProvider; + +/** @var FIRSetAccountInfoUserAttributePhotoURL + @brief Constant for photoURL attribute used in "deleteAttributes". + */ +extern NSString *const FIRSetAccountInfoUserAttributePhotoURL; + +/** @var FIRSetAccountInfoUserAttributePassword + @brief Constant for password attribute used in "deleteAttributes". + */ +extern NSString *const FIRSetAccountInfoUserAttributePassword; + +/** @class FIRSetAccountInfoRequest + @brief Represents the parameters for the setAccountInfo endpoint. + @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/setAccountInfo + */ +@interface FIRSetAccountInfoRequest : FIRIdentityToolkitRequest + +/** @property accessToken + @brief The STS Access Token of the authenticated user. + */ +@property(nonatomic, copy, nullable) NSString *accessToken; + +/** @property displayName + @brief The name of the user. + */ +@property(nonatomic, copy, nullable) NSString *displayName; + +/** @property localID + @brief The local ID of the user. + */ +@property(nonatomic, copy, nullable) NSString *localID; + +/** @property email + @brief The email of the user. + */ +@property(nonatomic, copy, nullable) NSString *email; + +/** @property photoURL + @brief The photoURL of the user. + */ +@property(nonatomic, copy, nullable) NSURL *photoURL; + +/** @property password + @brief The new password of the user. + */ +@property(nonatomic, copy, nullable) NSString *password; + +/** @property providers + @brief The associated identity providers of the user. + */ +@property(nonatomic, copy, nullable) NSArray *providers; + +/** @property OOBCode + @brief The out-of-band code of the change email request. + */ +@property(nonatomic, copy, nullable) NSString *OOBCode; + +/** @property emailVerified + @brief Whether to mark the email as verified or not. + */ +@property(nonatomic, assign) BOOL emailVerified; + +/** @property upgradeToFederatedLogin + @brief Whether to mark the user to upgrade to federated login. + */ +@property(nonatomic, assign) BOOL upgradeToFederatedLogin; + +/** @property captchaChallenge + @brief The captcha challenge. + */ +@property(nonatomic, copy, nullable) NSString *captchaChallenge; + +/** @property captchaResponse + @brief Response to the captcha. + */ +@property(nonatomic, copy, nullable) NSString *captchaResponse; + +/** @property deleteAttributes + @brief The list of user attributes to delete. + @remarks Every element of the list must be one of the predefined constant starts with + "FIRSetAccountInfoUserAttribute". + */ +@property(nonatomic, copy, nullable) NSArray *deleteAttributes; + +/** @property deleteProviders + @brief The list of identity providers to delete. + */ +@property(nonatomic, copy, nullable) NSArray *deleteProviders; + +/** @property returnSecureToken + @brief Whether the response should return access token and refresh token directly. + @remarks The default value is @c YES . + */ +@property(nonatomic, assign) BOOL returnSecureToken; + +/** @fn initWithEndpoint:requestConfiguration: + @brief Please use initWithAPIKey:email:password:displayName:requestConfiguration instead. + */ +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_UNAVAILABLE; + +/** @fn initWithRequestConfiguration: + @brief Designated initializer. + @param requestConfiguration An object containing configurations to be added to the request. + */ +- (nullable instancetype)initWithRequestConfiguration: + (FIRAuthRequestConfiguration *)requestConfiguration NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoRequest.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoRequest.m new file mode 100644 index 0000000..6e7291e --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoRequest.m @@ -0,0 +1,187 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoRequest.h" + +#import "FirebaseAuth/Sources/Auth/FIRAuth_Internal.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoResponse.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h" + +NS_ASSUME_NONNULL_BEGIN + +NSString *const FIRSetAccountInfoUserAttributeEmail = @"EMAIL"; + +NSString *const FIRSetAccountInfoUserAttributeDisplayName = @"DISPLAY_NAME"; + +NSString *const FIRSetAccountInfoUserAttributeProvider = @"PROVIDER"; + +NSString *const FIRSetAccountInfoUserAttributePhotoURL = @"PHOTO_URL"; + +NSString *const FIRSetAccountInfoUserAttributePassword = @"PASSWORD"; + +/** @var kCreateAuthURIEndpoint + @brief The "setAccountInfo" endpoint. + */ +static NSString *const kSetAccountInfoEndpoint = @"setAccountInfo"; + +/** @var kIDTokenKey + @brief The key for the "idToken" value in the request. This is actually the STS Access Token, + despite it's confusing (backwards compatiable) parameter name. + */ +static NSString *const kIDTokenKey = @"idToken"; + +/** @var kDisplayNameKey + @brief The key for the "displayName" value in the request. + */ +static NSString *const kDisplayNameKey = @"displayName"; + +/** @var kLocalIDKey + @brief The key for the "localID" value in the request. + */ +static NSString *const kLocalIDKey = @"localId"; + +/** @var kEmailKey + @brief The key for the "email" value in the request. + */ +static NSString *const kEmailKey = @"email"; + +/** @var kPasswordKey + @brief The key for the "password" value in the request. + */ +static NSString *const kPasswordKey = @"password"; + +/** @var kPhotoURLKey + @brief The key for the "photoURL" value in the request. + */ +static NSString *const kPhotoURLKey = @"photoUrl"; + +/** @var kProvidersKey + @brief The key for the "providers" value in the request. + */ +static NSString *const kProvidersKey = @"provider"; + +/** @var kOOBCodeKey + @brief The key for the "OOBCode" value in the request. + */ +static NSString *const kOOBCodeKey = @"oobCode"; + +/** @var kEmailVerifiedKey + @brief The key for the "emailVerified" value in the request. + */ +static NSString *const kEmailVerifiedKey = @"emailVerified"; + +/** @var kUpgradeToFederatedLoginKey + @brief The key for the "upgradeToFederatedLogin" value in the request. + */ +static NSString *const kUpgradeToFederatedLoginKey = @"upgradeToFederatedLogin"; + +/** @var kCaptchaChallengeKey + @brief The key for the "captchaChallenge" value in the request. + */ +static NSString *const kCaptchaChallengeKey = @"captchaChallenge"; + +/** @var kCaptchaResponseKey + @brief The key for the "captchaResponse" value in the request. + */ +static NSString *const kCaptchaResponseKey = @"captchaResponse"; + +/** @var kDeleteAttributesKey + @brief The key for the "deleteAttribute" value in the request. + */ +static NSString *const kDeleteAttributesKey = @"deleteAttribute"; + +/** @var kDeleteProvidersKey + @brief The key for the "deleteProvider" value in the request. + */ +static NSString *const kDeleteProvidersKey = @"deleteProvider"; + +/** @var kReturnSecureTokenKey + @brief The key for the "returnSecureToken" value in the request. + */ +static NSString *const kReturnSecureTokenKey = @"returnSecureToken"; + +/** @var kTenantIDKey + @brief The key for the tenant id value in the request. + */ +static NSString *const kTenantIDKey = @"tenantId"; + +@implementation FIRSetAccountInfoRequest + +- (nullable instancetype)initWithRequestConfiguration: + (FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kSetAccountInfoEndpoint requestConfiguration:requestConfiguration]; + if (self) { + _returnSecureToken = YES; + } + return self; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error { + NSMutableDictionary *postBody = [NSMutableDictionary dictionary]; + if (_accessToken) { + postBody[kIDTokenKey] = _accessToken; + } + if (_displayName) { + postBody[kDisplayNameKey] = _displayName; + } + if (_localID) { + postBody[kLocalIDKey] = _localID; + } + if (_email) { + postBody[kEmailKey] = _email; + } + if (_password) { + postBody[kPasswordKey] = _password; + } + if (_photoURL) { + postBody[kPhotoURLKey] = _photoURL.absoluteString; + } + if (_providers) { + postBody[kProvidersKey] = _providers; + } + if (_OOBCode) { + postBody[kOOBCodeKey] = _OOBCode; + } + if (_emailVerified) { + postBody[kEmailVerifiedKey] = @YES; + } + if (_upgradeToFederatedLogin) { + postBody[kUpgradeToFederatedLoginKey] = @YES; + } + if (_captchaChallenge) { + postBody[kCaptchaChallengeKey] = _captchaChallenge; + } + if (_captchaResponse) { + postBody[kCaptchaResponseKey] = _captchaResponse; + } + if (_deleteAttributes) { + postBody[kDeleteAttributesKey] = _deleteAttributes; + } + if (_deleteProviders) { + postBody[kDeleteProvidersKey] = _deleteProviders; + } + if (_returnSecureToken) { + postBody[kReturnSecureTokenKey] = @YES; + } + if (self.tenantID) { + postBody[kTenantIDKey] = self.tenantID; + } + return [postBody copy]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoResponse.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoResponse.h new file mode 100644 index 0000000..9e30930 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoResponse.h @@ -0,0 +1,98 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRSetAccountInfoResponseProviderUserInfo + @brief Represents the provider user info part of the response from the setAccountInfo endpoint. + @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/setAccountInfo + */ +@interface FIRSetAccountInfoResponseProviderUserInfo : NSObject + +/** @property providerID + @brief The ID of the identity provider. + */ +@property(nonatomic, strong, readonly, nullable) NSString *providerID; + +/** @property displayName + @brief The user's display name at the identity provider. + */ +@property(nonatomic, strong, readonly, nullable) NSString *displayName; + +/** @property photoURL + @brief The user's photo URL at the identity provider. + */ +@property(nonatomic, strong, readonly, nullable) NSURL *photoURL; + +/** @fn init + @brief Please use initWithDictionary: + */ +- (instancetype)init NS_UNAVAILABLE; + +/** @fn initWithAPIKey: + @brief Designated initializer. + @param dictionary The provider user info data from endpoint. + */ +- (instancetype)initWithDictionary:(NSDictionary *)dictionary NS_DESIGNATED_INITIALIZER; + +@end + +/** @class FIRSetAccountInfoResponse + @brief Represents the response from the setAccountInfo endpoint. + @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/setAccountInfo + */ +@interface FIRSetAccountInfoResponse : NSObject + +/** @property email + @brief The email or the user. + */ +@property(nonatomic, strong, readonly, nullable) NSString *email; + +/** @property displayName + @brief The display name of the user. + */ +@property(nonatomic, strong, readonly, nullable) NSString *displayName; + +/** @property providerUserInfo + @brief The user's profiles at the associated identity providers. + */ +@property(nonatomic, strong, readonly, nullable) + NSArray *providerUserInfo; + +/** @property IDToken + @brief Either an authorization code suitable for performing an STS token exchange, or the + access token from Secure Token Service, depending on whether @c returnSecureToken is set + on the request. + */ +@property(nonatomic, strong, readonly, nullable) NSString *IDToken; + +/** @property approximateExpirationDate + @brief The approximate expiration date of the access token. + */ +@property(nonatomic, copy, readonly, nullable) NSDate *approximateExpirationDate; + +/** @property refreshToken + @brief The refresh token from Secure Token Service. + */ +@property(nonatomic, strong, readonly, nullable) NSString *refreshToken; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoResponse.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoResponse.m new file mode 100644 index 0000000..138fba3 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoResponse.m @@ -0,0 +1,64 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRSetAccountInfoResponseProviderUserInfo + +- (instancetype)initWithDictionary:(NSDictionary *)dictionary { + self = [super init]; + if (self) { + _providerID = [dictionary[@"providerId"] copy]; + _displayName = [dictionary[@"displayName"] copy]; + NSString *photoURL = dictionary[@"photoUrl"]; + if (photoURL) { + _photoURL = [NSURL URLWithString:photoURL]; + } + } + return self; +} + +@end + +@implementation FIRSetAccountInfoResponse + +- (BOOL)setWithDictionary:(NSDictionary *)dictionary error:(NSError *_Nullable *_Nullable)error { + _email = [dictionary[@"email"] copy]; + _displayName = [dictionary[@"displayName"] copy]; + _IDToken = [dictionary[@"idToken"] copy]; + _approximateExpirationDate = + [dictionary[@"expiresIn"] isKindOfClass:[NSString class]] + ? [NSDate dateWithTimeIntervalSinceNow:[dictionary[@"expiresIn"] doubleValue]] + : nil; + _refreshToken = [dictionary[@"refreshToken"] copy]; + NSArray *providerUserInfoData = dictionary[@"providerUserInfo"]; + if (providerUserInfoData) { + NSMutableArray *providerUserInfoArray = + [NSMutableArray arrayWithCapacity:providerUserInfoData.count]; + for (NSDictionary *dictionary in providerUserInfoData) { + [providerUserInfoArray addObject:[[FIRSetAccountInfoResponseProviderUserInfo alloc] + initWithDictionary:dictionary]]; + } + _providerUserInfo = [providerUserInfoArray copy]; + } + return YES; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterRequest.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterRequest.h new file mode 100644 index 0000000..85a4948 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterRequest.h @@ -0,0 +1,103 @@ +/* + * 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. + */ + +#import + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRSignInWithGameCenterRequest + @brief The request to sign in with Game Center account + */ +@interface FIRSignInWithGameCenterRequest : FIRIdentityToolkitRequest + +/** @property playerID + @brief The playerID to verify. + */ +@property(nonatomic, copy) NSString *playerID; + +/** @property teamPlayerID + @brief The team player ID of the Game Center local player. + */ +@property(nonatomic, readonly) NSString *teamPlayerID; + +/** @property gamePlayerID + @brief The game player ID of the Game Center local player. + */ +@property(nonatomic, readonly) NSString *gamePlayerID; + +/** @property publicKeyURL + @brief The URL for the public encryption key. + */ +@property(nonatomic, copy) NSURL *publicKeyURL; + +/** @property signature + @brief The verification signature data generated by Game Center. + */ +@property(nonatomic, copy) NSData *signature; + +/** @property salt + @brief A random strong used to compute the hash and keep it randomized. + */ +@property(nonatomic, copy) NSData *salt; + +/** @property timestamp + @brief The date and time that the signature was created. + */ +@property(nonatomic, assign) uint64_t timestamp; + +/** @property accessToken + @brief The STS Access Token for the authenticated user, only needed for linking the user. + */ +@property(nonatomic, copy, nullable) NSString *accessToken; + +/** @property displayName + @brief The display name of the local Game Center player. + */ +@property(nonatomic, copy, nullable) NSString *displayName; + +/** @fn initWithEndpoint:requestConfiguration: + @brief Please use initWithPlayerID:publicKeyURL:signature:salt:timestamp:requestConfiguration:. + */ +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_UNAVAILABLE; + +/** @fn initWithPlayerID:publicKeyURL:signature:salt:timestamp:displayName:requestConfiguration: + @brief Designated initializer. + @param playerID The ID of the Game Center player. + @param publicKeyURL The URL for the public encryption key. + @param signature The verification signature generated. + @param salt A random string used to compute the hash and keep it randomized. + @param timestamp The date and time that the signature was created. + @param displayName The display name of the Game Center player. + */ +- (nullable instancetype)initWithPlayerID:(NSString *)playerID + teamPlayerID:(nullable NSString *)teamPlayerID + gamePlayerID:(nullable NSString *)gamePlayerID + publicKeyURL:(NSURL *)publicKeyURL + signature:(NSData *)signature + salt:(NSData *)salt + timestamp:(uint64_t)timestamp + displayName:(NSString *)displayName + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterRequest.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterRequest.m new file mode 100644 index 0000000..79bf645 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterRequest.m @@ -0,0 +1,90 @@ +/* + * 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. + */ + +#import "FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterRequest.h" + +#import "FirebaseAuth/Sources/Utilities/NSData+FIRBase64.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kSignInWithGameCenterEndPoint + @brief The "SignInWithGameCenter" endpoint. + */ +static NSString *const kSignInWithGameCenterEndPoint = @"signInWithGameCenter"; + +@implementation FIRSignInWithGameCenterRequest + +- (nullable instancetype)initWithPlayerID:(NSString *)playerID + teamPlayerID:(nullable NSString *)teamPlayerID + gamePlayerID:(nullable NSString *)gamePlayerID + publicKeyURL:(NSURL *)publicKeyURL + signature:(NSData *)signature + salt:(NSData *)salt + timestamp:(uint64_t)timestamp + displayName:(NSString *)displayName + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kSignInWithGameCenterEndPoint + requestConfiguration:requestConfiguration]; + if (self) { + _playerID = playerID; + _teamPlayerID = [teamPlayerID copy]; + _gamePlayerID = [gamePlayerID copy]; + _publicKeyURL = [publicKeyURL copy]; + _signature = [signature copy]; + _salt = [salt copy]; + _timestamp = timestamp; + _displayName = displayName; + } + return self; +} + +#pragma mark - FIRAuthRPCRequest + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *__autoreleasing _Nullable *)error { + NSMutableDictionary *postBody = [NSMutableDictionary dictionary]; + if (_playerID) { + postBody[@"playerId"] = _playerID; + } + if (_teamPlayerID) { + postBody[@"teamPlayerId"] = _teamPlayerID; + } + if (_gamePlayerID) { + postBody[@"gamePlayerId"] = _gamePlayerID; + } + if (_publicKeyURL) { + postBody[@"publicKeyUrl"] = _publicKeyURL.absoluteString; + } + if (_signature) { + postBody[@"signature"] = [_signature fir_base64URLEncodedStringWithOptions:0]; + } + if (_salt) { + postBody[@"salt"] = [_salt fir_base64URLEncodedStringWithOptions:0]; + } + if (_timestamp != 0) { + postBody[@"timestamp"] = [NSNumber numberWithUnsignedLongLong:_timestamp]; + } + if (_accessToken) { + postBody[@"idToken"] = _accessToken; + } + if (_displayName) { + postBody[@"displayName"] = _displayName; + } + return [postBody copy]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterResponse.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterResponse.h new file mode 100644 index 0000000..3089176 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterResponse.h @@ -0,0 +1,74 @@ +/* + * 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. + */ + +#import + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRSignInWithGameCenterResponse : NSObject + +/** @property IDToken + @brief Either an authorization code suitable for performing an STS token exchange, or the access + token from Secure Token Service, depending on whether @c returnSecureToken is set on the + request. + */ +@property(nonatomic, copy, readonly, nullable) NSString *IDToken; + +/** @property refreshToken + @brief The refresh token from Secure Token Service. + */ +@property(nonatomic, copy, readonly, nullable) NSString *refreshToken; + +/** @property localID + @brief The Firebase Auth user ID. + */ +@property(nonatomic, copy, readonly, nullable) NSString *localID; + +/** @property playerID + @brief The verified player ID. + */ +@property(nonatomic, copy, readonly, nullable) NSString *playerID; + +/** @property teamPlayerID + @brief The verified team player ID. + */ +@property(nonatomic, copy, readonly, nullable) NSString *teamPlayerID; + +/** @property gamePlayerID + @brief The verified game player ID. + */ +@property(nonatomic, copy, readonly, nullable) NSString *gamePlayerID; + +/** @property approximateExpirationDate + @brief The approximate expiration date of the access token. + */ +@property(nonatomic, copy, readonly, nullable) NSDate *approximateExpirationDate; + +/** @property isNewUser + @brief Flag indicating that the user signing in is a new user and not a returning user. + */ +@property(nonatomic, assign) BOOL isNewUser; + +/** @property displayName + @brief The user's Game Center display name. + */ +@property(nonatomic, copy, readonly, nullable) NSString *displayName; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterResponse.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterResponse.m new file mode 100644 index 0000000..9cc6d1a --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterResponse.m @@ -0,0 +1,42 @@ +/* + * 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. + */ + +#import "FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRSignInWithGameCenterResponse + +- (BOOL)setWithDictionary:(NSDictionary *)dictionary error:(NSError *_Nullable *_Nullable)error { + _IDToken = [dictionary[@"idToken"] copy]; + _refreshToken = [dictionary[@"refreshToken"] copy]; + _localID = [dictionary[@"localId"] copy]; + _approximateExpirationDate = nil; + if ([dictionary[@"expiresIn"] isKindOfClass:[NSString class]]) { + _approximateExpirationDate = + [NSDate dateWithTimeIntervalSinceNow:[dictionary[@"expiresIn"] integerValue]]; + } + _playerID = [dictionary[@"playerId"] copy]; + _teamPlayerID = [dictionary[@"teamPlayerId"] copy]; + _gamePlayerID = [dictionary[@"gamePlayerId"] copy]; + _isNewUser = [dictionary[@"isNewUser"] boolValue]; + _displayName = [dictionary[@"displayName"] copy]; + return YES; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.h new file mode 100644 index 0000000..070290d --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.h @@ -0,0 +1,72 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRSignUpNewUserRequest : FIRIdentityToolkitRequest + +/** @property email + @brief The email of the user. + */ +@property(nonatomic, copy, nullable) NSString *email; + +/** @property password + @brief The password inputed by the user. + */ +@property(nonatomic, copy, nullable) NSString *password; + +/** @property displayName + @brief The password inputed by the user. + */ +@property(nonatomic, copy, nullable) NSString *displayName; + +/** @property returnSecureToken + @brief Whether the response should return access token and refresh token directly. + @remarks The default value is @c YES . + */ +@property(nonatomic, assign) BOOL returnSecureToken; + +/** @fn initWithEndpoint:requestConfiguration: + @brief Please use initWithAPIKey:email:password:displayName:requestConfiguration instead. + */ +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_UNAVAILABLE; + +/** @fn initWithEndpoint:requestConfiguration: + @brief initializer for anonymous sign-in. + */ +- (nullable instancetype)initWithRequestConfiguration: + (FIRAuthRequestConfiguration *)requestConfiguration; + +/** @fn initWithAPIKey:email:password:displayName:requestConfiguration + @brief Designated initializer. + @param requestConfiguration An object containing configurations to be added to the request. + */ +- (nullable instancetype)initWithEmail:(nullable NSString *)email + password:(nullable NSString *)password + displayName:(nullable NSString *)displayName + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.m new file mode 100644 index 0000000..198e450 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.m @@ -0,0 +1,98 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kSignupNewUserEndpoint + @brief The "SingupNewUserEndpoint" endpoint. + */ +static NSString *const kSignupNewUserEndpoint = @"signupNewUser"; + +/** @var kEmailKey + @brief The key for the "email" value in the request. + */ +static NSString *const kEmailKey = @"email"; + +/** @var kPasswordKey + @brief The key for the "password" value in the request. + */ +static NSString *const kPasswordKey = @"password"; + +/** @var kDisplayNameKey + @brief The key for the "kDisplayName" value in the request. + */ +static NSString *const kDisplayNameKey = @"displayName"; + +/** @var kReturnSecureTokenKey + @brief The key for the "returnSecureToken" value in the request. + */ +static NSString *const kReturnSecureTokenKey = @"returnSecureToken"; + +/** @var kTenantIDKey + @brief The key for the tenant id value in the request. + */ +static NSString *const kTenantIDKey = @"tenantId"; + +@implementation FIRSignUpNewUserRequest + +- (nullable instancetype)initWithEmail:(nullable NSString *)email + password:(nullable NSString *)password + displayName:(nullable NSString *)displayName + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kSignupNewUserEndpoint requestConfiguration:requestConfiguration]; + if (self) { + _email = [email copy]; + _password = [password copy]; + _displayName = [displayName copy]; + _returnSecureToken = YES; + } + return self; +} + +- (nullable instancetype)initWithRequestConfiguration: + (FIRAuthRequestConfiguration *)requestConfiguration { + self = [self initWithEmail:nil + password:nil + displayName:nil + requestConfiguration:requestConfiguration]; + return self; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error { + NSMutableDictionary *postBody = [NSMutableDictionary dictionary]; + if (_email) { + postBody[kEmailKey] = _email; + } + if (_password) { + postBody[kPasswordKey] = _password; + } + if (_displayName) { + postBody[kDisplayNameKey] = _displayName; + } + if (_returnSecureToken) { + postBody[kReturnSecureTokenKey] = @YES; + } + if (self.tenantID) { + postBody[kTenantIDKey] = self.tenantID; + } + return [postBody copy]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserResponse.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserResponse.h new file mode 100644 index 0000000..f2e74f6 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserResponse.h @@ -0,0 +1,44 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRSignUpNewUserResponse : NSObject + +/** @property IDToken + @brief Either an authorization code suitable for performing an STS token exchange, or the + access token from Secure Token Service, depending on whether @c returnSecureToken is set + on the request. + */ +@property(nonatomic, strong, readonly, nullable) NSString *IDToken; + +/** @property approximateExpirationDate + @brief The approximate expiration date of the access token. + */ +@property(nonatomic, copy, readonly, nullable) NSDate *approximateExpirationDate; + +/** @property refreshToken + @brief The refresh token from Secure Token Service. + */ +@property(nonatomic, strong, readonly, nullable) NSString *refreshToken; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserResponse.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserResponse.m new file mode 100644 index 0000000..bdfa6d5 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserResponse.m @@ -0,0 +1,35 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRSignUpNewUserResponse + +- (BOOL)setWithDictionary:(NSDictionary *)dictionary error:(NSError *_Nullable *_Nullable)error { + _IDToken = [dictionary[@"idToken"] copy]; + _approximateExpirationDate = + [dictionary[@"expiresIn"] isKindOfClass:[NSString class]] + ? [NSDate dateWithTimeIntervalSinceNow:[dictionary[@"expiresIn"] doubleValue]] + : nil; + _refreshToken = [dictionary[@"refreshToken"] copy]; + return YES; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h new file mode 100644 index 0000000..f69c12b --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h @@ -0,0 +1,123 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRVerifyAssertionRequest + @brief Represents the parameters for the verifyAssertion endpoint. + @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/verifyAssertion + */ +@interface FIRVerifyAssertionRequest : FIRIdentityToolkitRequest + +/** @property requestURI + @brief The URI to which the IDP redirects the user back. It may contain federated login result + params added by the IDP. + */ +@property(nonatomic, copy, nullable) NSString *requestURI; + +/** @property pendingToken + @brief The Firebase ID Token for the IDP pending to be confirmed by the user. + */ +@property(nonatomic, copy, nullable) NSString *pendingToken; + +/** @property accessToken + @brief The STS Access Token for the authenticated user, only needed for linking the user. + */ +@property(nonatomic, copy, nullable) NSString *accessToken; + +/** @property returnSecureToken + @brief Whether the response should return access token and refresh token directly. + @remarks The default value is @c YES . + */ +@property(nonatomic, assign) BOOL returnSecureToken; + +#pragma mark - Components of "postBody" + +/** @property providerID + @brief The ID of the IDP whose credentials are being presented to the endpoint. + */ +@property(nonatomic, copy, readonly) NSString *providerID; + +/** @property providerAccessToken + @brief An access token from the IDP. + */ +@property(nonatomic, copy, nullable) NSString *providerAccessToken; + +/** @property providerIDToken + @brief An ID Token from the IDP. + */ +@property(nonatomic, copy, nullable) NSString *providerIDToken; + +/** @property providerRawNonce + @brief An raw nonce from the IDP. + */ +@property(nonatomic, copy, nullable) NSString *providerRawNonce; + +/** @property returnIDPCredential + @brief Whether the response should return the IDP credential directly. + */ +@property(nonatomic, assign) BOOL returnIDPCredential; + +/** @property providerOAuthTokenSecret + @brief A session ID used to map this request to a headful-lite flow. + */ +@property(nonatomic, copy, nullable) NSString *sessionID; + +/** @property providerOAuthTokenSecret + @brief An OAuth client secret from the IDP. + */ +@property(nonatomic, copy, nullable) NSString *providerOAuthTokenSecret; + +/** @property inputEmail + @brief The originally entered email in the UI. + */ +@property(nonatomic, copy, nullable) NSString *inputEmail; + +/** @property autoCreate + @brief A flag that indicates whether or not the user should be automatically created. + */ +@property(nonatomic, assign) BOOL autoCreate; + +/** @property fullName + @brief A full name from the IdP. + */ +@property(nonatomic, copy, nullable) NSPersonNameComponents *fullName; + +/** @fn initWithEndpoint:requestConfiguration: + @brief Please use initWithProviderID:requestConfifuration instead. + */ +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_UNAVAILABLE; + +/** @fn initWithProviderID:requestConfifuration + @brief Designated initializer. + @param providerID The auth provider's ID. + @param requestConfiguration An object containing configurations to be added to the request. + + */ +- (nullable instancetype)initWithProviderID:(NSString *)providerID + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.m new file mode 100644 index 0000000..57e6ec0 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.m @@ -0,0 +1,226 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kVerifyAssertionEndpoint + @brief The "verifyAssertion" endpoint. + */ +static NSString *const kVerifyAssertionEndpoint = @"verifyAssertion"; + +/** @var kProviderIDKey + @brief The key for the "providerId" value in the request. + */ +static NSString *const kProviderIDKey = @"providerId"; + +/** @var kProviderIDTokenKey + @brief The key for the "id_token" value in the request. + */ +static NSString *const kProviderIDTokenKey = @"id_token"; + +/** @var kProviderNonceKey + @brief The key for the "nonce" value in the request. + */ +static NSString *const kProviderNonceKey = @"nonce"; + +/** @var kProviderAccessTokenKey + @brief The key for the "access_token" value in the request. + */ +static NSString *const kProviderAccessTokenKey = @"access_token"; + +/** @var kProviderOAuthTokenSecretKey + @brief The key for the "oauth_token_secret" value in the request. + */ +static NSString *const kProviderOAuthTokenSecretKey = @"oauth_token_secret"; + +/** @var kIdentifierKey + @brief The key for the "identifier" value in the request. + */ +static NSString *const kIdentifierKey = @"identifier"; + +/** @var kRequestURIKey + @brief The key for the "requestUri" value in the request. + */ +static NSString *const kRequestURIKey = @"requestUri"; + +/** @var kPostBodyKey + @brief The key for the "postBody" value in the request. + */ +static NSString *const kPostBodyKey = @"postBody"; + +/** @var kPendingTokenKey + @brief The key for the "pendingToken" value in the request. + */ +static NSString *const kPendingTokenKey = @"pendingToken"; + +/** @var kAutoCreateKey + @brief The key for the "autoCreate" value in the request. + */ +static NSString *const kAutoCreateKey = @"autoCreate"; + +/** @var kIDTokenKey + @brief The key for the "idToken" value in the request. This is actually the STS Access Token, + despite it's confusing (backwards compatiable) parameter name. + */ +static NSString *const kIDTokenKey = @"idToken"; + +/** @var kReturnSecureTokenKey + @brief The key for the "returnSecureToken" value in the request. + */ +static NSString *const kReturnSecureTokenKey = @"returnSecureToken"; + +/** @var kUserKey + @brief The key for the "user" value in the request. The value is a JSON object that contains the + name of the user. + */ +static NSString *const kUserKey = @"user"; + +/** @var kNameKey + @brief The key for the "name" value in the request. The value is a JSON object that contains the + first and/or last name of the user. + */ +static NSString *const kNameKey = @"name"; + +/** @var kFirstNameKey + @brief The key for the "firstName" value in the request. + */ +static NSString *const kFirstNameKey = @"firstName"; + +/** @var kLastNameKey + @brief The key for the "lastName" value in the request. + */ +static NSString *const kLastNameKey = @"lastName"; + +/** @var kReturnIDPCredentialKey + @brief The key for the "returnIdpCredential" value in the request. + */ +static NSString *const kReturnIDPCredentialKey = @"returnIdpCredential"; + +/** @var kSessionIDKey + @brief The key for the "sessionID" value in the request. + */ +static NSString *const kSessionIDKey = @"sessionId"; + +/** @var kTenantIDKey + @brief The key for the tenant id value in the request. + */ +static NSString *const kTenantIDKey = @"tenantId"; + +@implementation FIRVerifyAssertionRequest + +- (nullable instancetype)initWithProviderID:(NSString *)providerID + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kVerifyAssertionEndpoint + requestConfiguration:requestConfiguration]; + if (self) { + _providerID = providerID; + _returnSecureToken = YES; + _autoCreate = YES; + _returnIDPCredential = YES; + } + return self; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error { + NSURLComponents *components = [[NSURLComponents alloc] init]; + NSMutableArray *queryItems = + [@[ [NSURLQueryItem queryItemWithName:kProviderIDKey value:_providerID] ] mutableCopy]; + + if (_providerIDToken) { + [queryItems addObject:[NSURLQueryItem queryItemWithName:kProviderIDTokenKey + value:_providerIDToken]]; + } + + if (_providerRawNonce) { + [queryItems addObject:[NSURLQueryItem queryItemWithName:kProviderNonceKey + value:_providerRawNonce]]; + } + + if (_providerAccessToken) { + [queryItems addObject:[NSURLQueryItem queryItemWithName:kProviderAccessTokenKey + value:_providerAccessToken]]; + } + + if (!_providerIDToken && !_providerAccessToken && !_pendingToken && !_requestURI) { + [NSException + raise:NSInvalidArgumentException + format:@"One of IDToken, accessToken, pendingToken, or requestURI must be supplied."]; + } + + if (_providerOAuthTokenSecret) { + [queryItems addObject:[NSURLQueryItem queryItemWithName:kProviderOAuthTokenSecretKey + value:_providerOAuthTokenSecret]]; + } + + if (_inputEmail) { + [queryItems addObject:[NSURLQueryItem queryItemWithName:kIdentifierKey value:_inputEmail]]; + } + + if (_fullName.givenName || _fullName.familyName) { + NSMutableDictionary *nameDict = [[NSMutableDictionary alloc] init]; + if (_fullName.givenName) { + nameDict[kFirstNameKey] = _fullName.givenName; + } + if (_fullName.familyName) { + nameDict[kLastNameKey] = _fullName.familyName; + } + NSDictionary *userDict = [NSDictionary dictionaryWithObject:nameDict forKey:kNameKey]; + NSData *userJson = [NSJSONSerialization dataWithJSONObject:userDict options:0 error:error]; + [queryItems + addObject:[NSURLQueryItem + queryItemWithName:kUserKey + value:[[NSString alloc] initWithData:userJson + encoding:NSUTF8StringEncoding]]]; + } + + [components setQueryItems:queryItems]; + NSMutableDictionary *body = [@{ + kRequestURIKey : _requestURI ?: @"http://localhost", // Unused by server, but required + kPostBodyKey : [components query] + } mutableCopy]; + + if (_pendingToken) { + body[kPendingTokenKey] = _pendingToken; + } + if (_accessToken) { + body[kIDTokenKey] = _accessToken; + } + if (_returnSecureToken) { + body[kReturnSecureTokenKey] = @YES; + } + + if (_returnIDPCredential) { + body[kReturnIDPCredentialKey] = @YES; + } + + if (_sessionID) { + body[kSessionIDKey] = _sessionID; + } + + if (self.tenantID) { + body[kTenantIDKey] = self.tenantID; + } + + body[kAutoCreateKey] = @(_autoCreate); + + return body; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.h new file mode 100644 index 0000000..128ff99 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.h @@ -0,0 +1,221 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProtoMFAEnrollment.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRVerifyAssertionResponse + @brief Represents the response from the verifyAssertion endpoint. + @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/verifyAssertion + */ +@interface FIRVerifyAssertionResponse : NSObject + +/** @property federatedID + @brief The unique ID identifies the IdP account. + */ +@property(nonatomic, strong, readonly, nullable) NSString *federatedID; + +/** @property providerID + @brief The IdP ID. For white listed IdPs it's a short domain name e.g. google.com, aol.com, + live.net and yahoo.com. If the "providerId" param is set to OpenID OP identifer other than + the whilte listed IdPs the OP identifier is returned. If the "identifier" param is federated + ID in the createAuthUri request. The domain part of the federated ID is returned. + */ +@property(nonatomic, strong, readonly, nullable) NSString *providerID; + +/** @property localID + @brief The RP local ID if it's already been mapped to the IdP account identified by the + federated ID. + */ +@property(nonatomic, strong, readonly, nullable) NSString *localID; + +/** @property email + @brief The email returned by the IdP. NOTE: The federated login user may not own the email. + */ +@property(nonatomic, strong, readonly, nullable) NSString *email; + +/** @property inputEmail + @brief It's the identifier param in the createAuthUri request if the identifier is an email. It + can be used to check whether the user input email is different from the asserted email. + */ +@property(nonatomic, strong, readonly, nullable) NSString *inputEmail; + +/** @property originalEmail + @brief The original email stored in the mapping storage. It's returned when the federated ID is + associated to a different email. + */ +@property(nonatomic, strong, readonly, nullable) NSString *originalEmail; + +/** @property oauthRequestToken + @brief The user approved request token for the OpenID OAuth extension. + */ +@property(nonatomic, strong, readonly, nullable) NSString *oauthRequestToken; + +/** @property oauthScope + @brief The scope for the OpenID OAuth extension. + */ +@property(nonatomic, strong, readonly, nullable) NSString *oauthScope; + +/** @property firstName + @brief The first name of the user. + */ +@property(nonatomic, strong, readonly, nullable) NSString *firstName; + +/** @property lastName + @brief The last name of the user. + */ +@property(nonatomic, strong, readonly, nullable) NSString *lastName; + +/** @property fullName + @brief The full name of the user. + */ +@property(nonatomic, strong, readonly, nullable) NSString *fullName; + +/** @property nickName + @brief The nick name of the user. + */ +@property(nonatomic, strong, readonly, nullable) NSString *nickName; + +/** @property displayName + @brief The display name of the user. + */ +@property(nonatomic, strong, readonly, nullable) NSString *displayName; + +/** @property IDToken + @brief Either an authorization code suitable for performing an STS token exchange, or the + access token from Secure Token Service, depending on whether @c returnSecureToken is set + on the request. + */ +@property(nonatomic, strong, readonly, nullable) NSString *IDToken; + +/** @property approximateExpirationDate + @brief The approximate expiration date of the access token. + */ +@property(nonatomic, copy, readonly, nullable) NSDate *approximateExpirationDate; + +/** @property refreshToken + @brief The refresh token from Secure Token Service. + */ +@property(nonatomic, strong, readonly, nullable) NSString *refreshToken; + +/** @property action + @brief The action code. + */ +@property(nonatomic, strong, readonly, nullable) NSString *action; + +/** @property language + @brief The language preference of the user. + */ +@property(nonatomic, strong, readonly, nullable) NSString *language; + +/** @property timeZone + @brief The timezone of the user. + */ +@property(nonatomic, strong, readonly, nullable) NSString *timeZone; + +/** @property photoURL + @brief The URI of the public accessible profile picture. + */ +@property(nonatomic, strong, readonly, nullable) NSURL *photoURL; + +/** @property dateOfBirth + @brief The birth date of the IdP account. + */ +@property(nonatomic, strong, readonly, nullable) NSString *dateOfBirth; + +/** @property context + @brief The opaque value used by the client to maintain context info between the authentication + request and the IDP callback. + */ +@property(nonatomic, strong, readonly, nullable) NSString *context; + +/** @property verifiedProvider + @brief When action is 'map', contains the idps which can be used for confirmation. + */ +@property(nonatomic, strong, readonly, nullable) NSArray *verifiedProvider; + +/** @property needConfirmation + @brief Whether the assertion is from a non-trusted IDP and need account linking confirmation. + */ +@property(nonatomic, assign) BOOL needConfirmation; + +/** @property emailRecycled + @brief It's true if the email is recycled. + */ +@property(nonatomic, assign) BOOL emailRecycled; + +/** @property emailVerified + @brief The value is true if the IDP is also the email provider. It means the user owns the + email. + */ +@property(nonatomic, assign) BOOL emailVerified; + +/** @property isNewUser + @brief Flag indicating that the user signing in is a new user and not a returning user. + */ +@property(nonatomic, assign) BOOL isNewUser; + +/** @property profile + @brief Dictionary containing the additional IdP specific information. + */ +@property(nonatomic, readonly, nullable) NSDictionary *profile; + +/** @property username + @brief The name of the user. + */ +@property(nonatomic, strong, readonly, nullable) NSString *username; + +/** @property oauthIDToken + @brief The ID token for the OpenID OAuth extension. + */ +@property(nonatomic, strong, readonly, nullable) NSString *oauthIDToken; + +/** @property oauthExpirationDate + @brief The approximate expiration date of the oauth access token. + */ +@property(nonatomic, copy, readonly, nullable) NSDate *oauthExpirationDate; + +/** @property oauthAccessToken + @brief The access token for the OpenID OAuth extension. + */ +@property(nonatomic, strong, readonly, nullable) NSString *oauthAccessToken; + +/** @property oauthSecretToken + @brief The secret for the OpenID OAuth extention. + */ +@property(nonatomic, readonly, nullable) NSString *oauthSecretToken; + +/** @property pendingToken + @brief The pending ID Token string. + */ +@property(nonatomic, copy, nullable) NSString *pendingToken; + +/** @property MFAPendingCredential + @brief An opaque string that functions as proof that the user has successfully passed the first + factor check. +*/ +@property(nonatomic, strong, readonly, nullable) NSString *MFAPendingCredential; + +/** @property MFAInfo + @brief Info on which multi-factor authentication providers are enabled. +*/ +@property(nonatomic, strong, readonly, nullable) NSArray *MFAInfo; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.m new file mode 100644 index 0000000..6c605e7 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.m @@ -0,0 +1,100 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRVerifyAssertionResponse + +- (BOOL)setWithDictionary:(NSDictionary *)dictionary error:(NSError *_Nullable *_Nullable)error { + _federatedID = [dictionary[@"federatedId"] copy]; + _providerID = [dictionary[@"providerId"] copy]; + _localID = [dictionary[@"localId"] copy]; + _emailRecycled = [dictionary[@"emailRecycled"] boolValue]; + _emailVerified = [dictionary[@"emailVerified"] boolValue]; + _email = [dictionary[@"email"] copy]; + _inputEmail = [dictionary[@"inputEmail"] copy]; + _originalEmail = [dictionary[@"originalEmail"] copy]; + _oauthRequestToken = [dictionary[@"oauthRequestToken"] copy]; + _oauthScope = [dictionary[@"oauthScope"] copy]; + _firstName = [dictionary[@"firstName"] copy]; + _lastName = [dictionary[@"lastName"] copy]; + _fullName = [dictionary[@"fullName"] copy]; + _nickName = [dictionary[@"nickName"] copy]; + _displayName = [dictionary[@"displayName"] copy]; + _IDToken = [dictionary[@"idToken"] copy]; + _approximateExpirationDate = + [dictionary[@"expiresIn"] isKindOfClass:[NSString class]] + ? [NSDate dateWithTimeIntervalSinceNow:[dictionary[@"expiresIn"] doubleValue]] + : nil; + _refreshToken = [dictionary[@"refreshToken"] copy]; + _isNewUser = [dictionary[@"isNewUser"] boolValue]; + id rawUserInfo = dictionary[@"rawUserInfo"]; + if ([rawUserInfo isKindOfClass:[NSString class]]) { + NSData *data = [rawUserInfo dataUsingEncoding:NSUTF8StringEncoding]; + rawUserInfo = [NSJSONSerialization JSONObjectWithData:data + options:NSJSONReadingMutableLeaves + error:nil]; + } + if ([rawUserInfo isKindOfClass:[NSDictionary class]]) { + _profile = [[NSDictionary alloc] initWithDictionary:rawUserInfo copyItems:YES]; + } + _username = [dictionary[@"username"] copy]; + _action = [dictionary[@"action"] copy]; + _language = [dictionary[@"language"] copy]; + _timeZone = [dictionary[@"timeZone"] copy]; + _photoURL = dictionary[@"photoUrl"] ? [NSURL URLWithString:dictionary[@"photoUrl"]] : nil; + _dateOfBirth = [dictionary[@"dateOfBirth"] copy]; + _context = [dictionary[@"context"] copy]; + _needConfirmation = [dictionary[@"needConfirmation"] boolValue]; + id verifiedProvider = dictionary[@"verifiedProvider"]; + if ([verifiedProvider isKindOfClass:[NSString class]]) { + NSData *data = [verifiedProvider dataUsingEncoding:NSUTF8StringEncoding]; + verifiedProvider = [NSJSONSerialization JSONObjectWithData:data + options:NSJSONReadingMutableLeaves + error:nil]; + } + if ([verifiedProvider isKindOfClass:[NSArray class]]) { + _verifiedProvider = [[NSArray alloc] initWithArray:verifiedProvider copyItems:YES]; + } + _oauthIDToken = [dictionary[@"oauthIdToken"] copy]; + _oauthExpirationDate = + [dictionary[@"oauthExpireIn"] isKindOfClass:[NSString class]] + ? [NSDate dateWithTimeIntervalSinceNow:[dictionary[@"oauthExpireIn"] doubleValue]] + : nil; + _oauthAccessToken = [dictionary[@"oauthAccessToken"] copy]; + _oauthSecretToken = [dictionary[@"oauthTokenSecret"] copy]; + _pendingToken = [dictionary[@"pendingToken"] copy]; + + if (dictionary[@"mfaInfo"] != nil) { + NSMutableArray *MFAInfo = [NSMutableArray array]; + NSArray *MFAInfoDataArray = dictionary[@"mfaInfo"]; + for (NSDictionary *MFAInfoData in MFAInfoDataArray) { + FIRAuthProtoMFAEnrollment *MFAEnrollment = + [[FIRAuthProtoMFAEnrollment alloc] initWithDictionary:MFAInfoData]; + [MFAInfo addObject:MFAEnrollment]; + } + _MFAInfo = MFAInfo; + } + _MFAPendingCredential = [dictionary[@"mfaPendingCredential"] copy]; + + return YES; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientRequest.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientRequest.h new file mode 100644 index 0000000..7b4d3bc --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientRequest.h @@ -0,0 +1,55 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRVerifyClientRequest : FIRIdentityToolkitRequest + +/** @property appToken + @brief The APNS device token. + */ +@property(nonatomic, readonly, nullable) NSString *appToken; + +/** @property isSandbox + @brief The flag that denotes if the appToken pertains to Sandbox or Production. + */ +@property(nonatomic, assign, readonly) BOOL isSandbox; + +/** @fn initWithEndpoint:requestConfiguration: + @brief Please use initWithToken:requestConfiguration: instead. + */ +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_UNAVAILABLE; + +/** @fn initWithAppToken:isSandbox:requestConfiguration: + @brief Designated initializer. + @param appToken The APNS device token. + @param isSandbox The flag indicating whether or not the app token provided is for Sandbox or + Production. + @param requestConfiguration An object containing configurations to be added to the request. + */ +- (nullable instancetype)initWithAppToken:(nullable NSString *)appToken + isSandbox:(BOOL)isSandbox + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientRequest.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientRequest.m new file mode 100644 index 0000000..02e984c --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientRequest.m @@ -0,0 +1,62 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kVerifyClientEndpoint + @brief The endpoint for the verifyClient request. + */ +static NSString *const kVerifyClientEndpoint = @"verifyClient"; + +/** @var kAppTokenKey + @brief The key for the appToken request paramenter. + */ +static NSString *const kAPPTokenKey = @"appToken"; + +/** @var kIsSandboxKey + @brief The key for the isSandbox request parameter + */ +static NSString *const kIsSandboxKey = @"isSandbox"; + +@implementation FIRVerifyClientRequest + +- (nullable instancetype)initWithAppToken:(nullable NSString *)appToken + isSandbox:(BOOL)isSandbox + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kVerifyClientEndpoint requestConfiguration:requestConfiguration]; + if (self) { + _appToken = appToken; + _isSandbox = isSandbox; + } + return self; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *__autoreleasing _Nullable *)error { + NSMutableDictionary *postBody = [NSMutableDictionary dictionary]; + if (_appToken) { + postBody[kAPPTokenKey] = _appToken; + } + if (_isSandbox) { + postBody[kIsSandboxKey] = @YES; + } + return [postBody copy]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientResponse.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientResponse.h new file mode 100644 index 0000000..40e6907 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientResponse.h @@ -0,0 +1,38 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRVerifyClientResponse : NSObject + +/** @property receipt + @brief Receipt that the APNS token was successfully validated with APNS. + */ +@property(nonatomic, copy, readonly, nullable) NSString *receipt; + +/** @property suggestedTimeOut + @brief The date after which delivery of the silent push notification is considered to have + failed. + */ +@property(nonatomic, copy, readonly, nullable) NSDate *suggestedTimeOutDate; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientResponse.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientResponse.m new file mode 100644 index 0000000..78d648c --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientResponse.m @@ -0,0 +1,34 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRVerifyClientResponse + +- (BOOL)setWithDictionary:(NSDictionary *)dictionary error:(NSError *_Nullable *_Nullable)error { + _receipt = dictionary[@"receipt"]; + _suggestedTimeOutDate = + [dictionary[@"suggestedTimeout"] isKindOfClass:[NSString class]] + ? [NSDate dateWithTimeIntervalSinceNow:[dictionary[@"suggestedTimeout"] doubleValue]] + : nil; + return YES; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenRequest.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenRequest.h new file mode 100644 index 0000000..abea35a --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenRequest.h @@ -0,0 +1,58 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRVerifyCustomTokenRequest + @brief Represents the parameters for the verifyCustomToken endpoint. + */ +@interface FIRVerifyCustomTokenRequest : FIRIdentityToolkitRequest + +/** @property token + @brief The self-signed token from the client's BYOAuth server. + */ +@property(nonatomic, copy, readonly) NSString *token; + +/** @property returnSecureToken + @brief Whether the response should return access token and refresh token directly. + @remarks The default value is @c YES . + */ +@property(nonatomic, assign) BOOL returnSecureToken; + +/** @fn initWithEndpoint:requestConfiguration: + @brief Please use initWithToken:requestConfiguration: instead. + */ +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_UNAVAILABLE; + +/** @fn initWithToken:requestConfiguration: + @brief Designated initializer. + @param token The self-signed token from the client's BYOAuth server. + @param requestConfiguration An object containing configurations to be added to the request. + */ +- (nullable instancetype)initWithToken:(NSString *)token + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenRequest.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenRequest.m new file mode 100644 index 0000000..a49f53f --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenRequest.m @@ -0,0 +1,67 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kVerifyCustomTokenEndpoint + @brief The "verifyPassword" endpoint. + */ +static NSString *const kVerifyCustomTokenEndpoint = @"verifyCustomToken"; + +/** @var kTokenKey + @brief The key for the "token" value in the request. + */ +static NSString *const kTokenKey = @"token"; + +/** @var kReturnSecureTokenKey + @brief The key for the "returnSecureToken" value in the request. + */ +static NSString *const kReturnSecureTokenKey = @"returnSecureToken"; + +/** @var kTenantIDKey + @brief The key for the tenant id value in the request. + */ +static NSString *const kTenantIDKey = @"tenantId"; + +@implementation FIRVerifyCustomTokenRequest + +- (nullable instancetype)initWithToken:(NSString *)token + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kVerifyCustomTokenEndpoint + requestConfiguration:requestConfiguration]; + if (self) { + _token = [token copy]; + _returnSecureToken = YES; + } + return self; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error { + NSMutableDictionary *body = [@{kTokenKey : _token} mutableCopy]; + if (_returnSecureToken) { + body[kReturnSecureTokenKey] = @YES; + } + if (self.tenantID) { + body[kTenantIDKey] = self.tenantID; + } + return body; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenResponse.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenResponse.h new file mode 100644 index 0000000..7484a94 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenResponse.h @@ -0,0 +1,52 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRVerifyCustomTokenResponse + @brief Represents the response from the verifyCustomToken endpoint. + */ +@interface FIRVerifyCustomTokenResponse : NSObject + +/** @property IDToken + @brief Either an authorization code suitable for performing an STS token exchange, or the + access token from Secure Token Service, depending on whether @c returnSecureToken is set + on the request. + */ +@property(nonatomic, strong, readonly, nullable) NSString *IDToken; + +/** @property approximateExpirationDate + @brief The approximate expiration date of the access token. + */ +@property(nonatomic, copy, readonly, nullable) NSDate *approximateExpirationDate; + +/** @property refreshToken + @brief The refresh token from Secure Token Service. + */ +@property(nonatomic, strong, readonly, nullable) NSString *refreshToken; + +/** @property isNewUser + @brief Flag indicating that the user signing in is a new user and not a returning user. + */ +@property(nonatomic, assign) BOOL isNewUser; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenResponse.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenResponse.m new file mode 100644 index 0000000..1bbe645 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenResponse.m @@ -0,0 +1,36 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRVerifyCustomTokenResponse + +- (BOOL)setWithDictionary:(NSDictionary *)dictionary error:(NSError *_Nullable *_Nullable)error { + _IDToken = [dictionary[@"idToken"] copy]; + _approximateExpirationDate = + [dictionary[@"expiresIn"] isKindOfClass:[NSString class]] + ? [NSDate dateWithTimeIntervalSinceNow:[dictionary[@"expiresIn"] doubleValue]] + : nil; + _refreshToken = [dictionary[@"refreshToken"] copy]; + _isNewUser = [dictionary[@"isNewUser"] boolValue]; + return YES; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordRequest.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordRequest.h new file mode 100644 index 0000000..5931578 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordRequest.h @@ -0,0 +1,81 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRVerifyPasswordRequest + @brief Represents the parameters for the verifyPassword endpoint. + @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/verifyPassword + */ +@interface FIRVerifyPasswordRequest : FIRIdentityToolkitRequest + +/** @property email + @brief The email of the user. + */ +@property(nonatomic, copy) NSString *email; + +/** @property password + @brief The password inputed by the user. + */ +@property(nonatomic, copy) NSString *password; + +/** @property pendingIDToken + @brief The GITKit token for the non-trusted IDP, which is to be confirmed by the user. + */ +@property(nonatomic, copy, nullable) NSString *pendingIDToken; + +/** @property captchaChallenge + @brief The captcha challenge. + */ +@property(nonatomic, copy, nullable) NSString *captchaChallenge; + +/** @property captchaResponse + @brief Response to the captcha. + */ +@property(nonatomic, copy, nullable) NSString *captchaResponse; + +/** @property returnSecureToken + @brief Whether the response should return access token and refresh token directly. + @remarks The default value is @c YES . + */ +@property(nonatomic, assign) BOOL returnSecureToken; + +/** @fn initWithEndpoint:requestConfiguration: + @brief Please use initWithEmail:password:requestConfiguration: + */ +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_UNAVAILABLE; + +/** @fn initWithEmail:password:requestConfiguration: + @brief Designated initializer. + @param email The email of the user. + @param password The password inputed by the user. + @param requestConfiguration The configu + */ +- (nullable instancetype)initWithEmail:(NSString *)email + password:(NSString *)password + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordRequest.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordRequest.m new file mode 100644 index 0000000..97ac2a7 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordRequest.m @@ -0,0 +1,103 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kVerifyPasswordEndpoint + @brief The "verifyPassword" endpoint. + */ +static NSString *const kVerifyPasswordEndpoint = @"verifyPassword"; + +/** @var kEmailKey + @brief The key for the "email" value in the request. + */ +static NSString *const kEmailKey = @"email"; + +/** @var kPasswordKey + @brief The key for the "password" value in the request. + */ +static NSString *const kPasswordKey = @"password"; + +/** @var kPendingIDTokenKey + @brief The key for the "pendingIdToken" value in the request. + */ +static NSString *const kPendingIDTokenKey = @"pendingIdToken"; + +/** @var kCaptchaChallengeKey + @brief The key for the "captchaChallenge" value in the request. + */ +static NSString *const kCaptchaChallengeKey = @"captchaChallenge"; + +/** @var kCaptchaResponseKey + @brief The key for the "captchaResponse" value in the request. + */ +static NSString *const kCaptchaResponseKey = @"captchaResponse"; + +/** @var kReturnSecureTokenKey + @brief The key for the "returnSecureToken" value in the request. + */ +static NSString *const kReturnSecureTokenKey = @"returnSecureToken"; + +/** @var kTenantIDKey + @brief The key for the tenant id value in the request. + */ +static NSString *const kTenantIDKey = @"tenantId"; + +@implementation FIRVerifyPasswordRequest + +- (nullable instancetype)initWithEmail:(NSString *)email + password:(NSString *)password + requestConfiguration:(nonnull FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kVerifyPasswordEndpoint requestConfiguration:requestConfiguration]; + if (self) { + _email = [email copy]; + _password = [password copy]; + _returnSecureToken = YES; + } + return self; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error { + NSMutableDictionary *postBody = [NSMutableDictionary dictionary]; + if (_email) { + postBody[kEmailKey] = _email; + } + if (_password) { + postBody[kPasswordKey] = _password; + } + if (_pendingIDToken) { + postBody[kPendingIDTokenKey] = _pendingIDToken; + } + if (_captchaChallenge) { + postBody[kCaptchaChallengeKey] = _captchaChallenge; + } + if (_captchaResponse) { + postBody[kCaptchaResponseKey] = _captchaResponse; + } + if (_returnSecureToken) { + postBody[kReturnSecureTokenKey] = @YES; + } + if (self.tenantID) { + postBody[kTenantIDKey] = self.tenantID; + } + return [postBody copy]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordResponse.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordResponse.h new file mode 100644 index 0000000..8f95da8 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordResponse.h @@ -0,0 +1,82 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProtoMFAEnrollment.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRVerifyPasswordResponse + @brief Represents the response from the verifyPassword endpoint. + @remarks Possible error codes: + - FIRAuthInternalErrorCodeUserDisabled + - FIRAuthInternalErrorCodeEmailNotFound + @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/verifyPassword + */ +@interface FIRVerifyPasswordResponse : NSObject + +/** @property localID + @brief The RP local ID if it's already been mapped to the IdP account identified by the + federated ID. + */ +@property(nonatomic, strong, readonly, nullable) NSString *localID; + +/** @property email + @brief The email returned by the IdP. NOTE: The federated login user may not own the email. + */ +@property(nonatomic, strong, readonly, nullable) NSString *email; + +/** @property displayName + @brief The display name of the user. + */ +@property(nonatomic, strong, readonly, nullable) NSString *displayName; + +/** @property IDToken + @brief Either an authorization code suitable for performing an STS token exchange, or the + access token from Secure Token Service, depending on whether @c returnSecureToken is set + on the request. + */ +@property(nonatomic, strong, readonly, nullable) NSString *IDToken; + +/** @property approximateExpirationDate + @brief The approximate expiration date of the access token. + */ +@property(nonatomic, copy, readonly, nullable) NSDate *approximateExpirationDate; + +/** @property refreshToken + @brief The refresh token from Secure Token Service. + */ +@property(nonatomic, strong, readonly, nullable) NSString *refreshToken; + +/** @property photoURL + @brief The URI of the public accessible profile picture. + */ +@property(nonatomic, strong, readonly, nullable) NSURL *photoURL; + +/** @property MFAPendingCredential + @brief An opaque string that functions as proof that the user has successfully passed the first + factor check. +*/ +@property(nonatomic, strong, readonly, nullable) NSString *MFAPendingCredential; + +/** @property MFAInfo + @brief Info on which multi-factor authentication providers are enabled. +*/ +@property(nonatomic, strong, readonly, nullable) NSArray *MFAInfo; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordResponse.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordResponse.m new file mode 100644 index 0000000..df8208f --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordResponse.m @@ -0,0 +1,52 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRVerifyPasswordResponse + +- (BOOL)setWithDictionary:(NSDictionary *)dictionary error:(NSError *_Nullable *_Nullable)error { + _localID = [dictionary[@"localId"] copy]; + _email = [dictionary[@"email"] copy]; + _displayName = [dictionary[@"displayName"] copy]; + _IDToken = [dictionary[@"idToken"] copy]; + _approximateExpirationDate = + [dictionary[@"expiresIn"] isKindOfClass:[NSString class]] + ? [NSDate dateWithTimeIntervalSinceNow:[dictionary[@"expiresIn"] doubleValue]] + : nil; + _refreshToken = [dictionary[@"refreshToken"] copy]; + _photoURL = dictionary[@"photoUrl"] ? [NSURL URLWithString:dictionary[@"photoUrl"]] : nil; + + if (dictionary[@"mfaInfo"] != nil) { + NSMutableArray *MFAInfo = [NSMutableArray array]; + NSArray *MFAInfoDataArray = dictionary[@"mfaInfo"]; + for (NSDictionary *MFAInfoData in MFAInfoDataArray) { + FIRAuthProtoMFAEnrollment *MFAEnrollment = + [[FIRAuthProtoMFAEnrollment alloc] initWithDictionary:MFAInfoData]; + [MFAInfo addObject:MFAEnrollment]; + } + _MFAInfo = MFAInfo; + } + _MFAPendingCredential = [dictionary[@"mfaPendingCredential"] copy]; + + return YES; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberRequest.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberRequest.h new file mode 100644 index 0000000..da8d4e8 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberRequest.h @@ -0,0 +1,90 @@ +/* + * 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 "FirebaseAuth/Sources/Auth/FIRAuthOperationType.h" +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRVerifyPhoneNumberRequest : FIRIdentityToolkitRequest + +/** @property verificationID + @brief The verification ID obtained from the response of @c sendVerificationCode. +*/ +@property(nonatomic, readonly, nullable) NSString *verificationID; + +/** @property verificationCode + @brief The verification code provided by the user. +*/ +@property(nonatomic, readonly, nullable) NSString *verificationCode; + +/** @property accessToken + @brief The STS Access Token for the authenticated user. + */ +@property(nonatomic, copy, nullable) NSString *accessToken; + +/** @var temporaryProof + @brief The temporary proof code, previously returned from the backend. + */ +@property(nonatomic, readonly, nonnull) NSString *temporaryProof; + +/** @var phoneNumber + @brief The phone number to be verified in the request. + */ +@property(nonatomic, readonly, nonnull) NSString *phoneNumber; + +/** @var operation + @brief The type of operation triggering this verify phone number request. + */ +@property(nonatomic, assign, readonly) FIRAuthOperationType operation; + +/** @fn initWithEndpoint:requestConfiguration: + @brief Please use initWithVerificationID:verificationCode:requestConfiguration + */ +- (nullable instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_UNAVAILABLE; + +/** @fn initWithTemporaryProof:phoneNumberAPIKey + @brief Designated initializer. + @param temporaryProof The temporary proof sent by the backed. + @param phoneNumber The phone number associated with the credential to be signed in. + @param operation Indicates what operation triggered the verify phone number request. + @param requestConfiguration An object containing configurations to be added to the request. + */ +- (nullable instancetype)initWithTemporaryProof:(NSString *)temporaryProof + phoneNumber:(NSString *)phoneNumber + operation:(FIRAuthOperationType)operation + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_DESIGNATED_INITIALIZER; + +/** @fn initWithVerificationID:verificationCode:requestConfiguration + @brief Designated initializer. + @param verificationID The verification ID obtained from the response of @c sendVerificationCode. + @param verificationCode The verification code provided by the user. + @param operation Indicates what operation triggered the verify phone number request. + @param requestConfiguration An object containing configurations to be added to the request. + */ +- (nullable instancetype)initWithVerificationID:(NSString *)verificationID + verificationCode:(NSString *)verificationCode + operation:(FIRAuthOperationType)operation + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberRequest.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberRequest.m new file mode 100644 index 0000000..99cb54b --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberRequest.m @@ -0,0 +1,141 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kVerifyPhoneNumberEndPoint + @brief The "verifyPhoneNumber" endpoint. + */ +static NSString *const kVerifyPhoneNumberEndPoint = @"verifyPhoneNumber"; + +/** @var kVerificationIDKey + @brief The key for the verification ID parameter in the request. + */ +static NSString *const kVerificationIDKey = @"sessionInfo"; + +/** @var kVerificationCodeKey + @brief The key for the verification code parameter in the request. + */ +static NSString *const kVerificationCodeKey = @"code"; + +/** @var kIDTokenKey + @brief The key for the "ID Token" value in the request. + */ +static NSString *const kIDTokenKey = @"idToken"; + +/** @var kTemporaryProofKey + @brief The key for the temporary proof value in the request. + */ +static NSString *const kTemporaryProofKey = @"temporaryProof"; + +/** @var kPhoneNumberKey + @brief The key for the phone number value in the request. + */ +static NSString *const kPhoneNumberKey = @"phoneNumber"; + +/** @var kOperationKey + @brief The key for the operation value in the request. + */ +static NSString *const kOperationKey = @"operation"; + +/** @var kTenantIDKey + @brief The key for the tenant id value in the request. + */ +static NSString *const kTenantIDKey = @"tenantId"; + +@implementation FIRVerifyPhoneNumberRequest + +- (nullable instancetype)initWithTemporaryProof:(NSString *)temporaryProof + phoneNumber:(NSString *)phoneNumber + operation:(FIRAuthOperationType)operation + requestConfiguration: + (FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kVerifyPhoneNumberEndPoint + requestConfiguration:requestConfiguration]; + if (self) { + _temporaryProof = [temporaryProof copy]; + _phoneNumber = [phoneNumber copy]; + _operation = operation; + } + return self; +} + +- (nullable instancetype)initWithVerificationID:(NSString *)verificationID + verificationCode:(NSString *)verificationCode + operation:(FIRAuthOperationType)operation + requestConfiguration: + (FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kVerifyPhoneNumberEndPoint + requestConfiguration:requestConfiguration]; + if (self) { + _verificationID = verificationID; + _verificationCode = verificationCode; + _operation = operation; + } + return self; +} + +/** @fn FIRAuthOperationString + @brief Returns a string object corresponding to the provided FIRAuthOperationType value. + @param operationType The value of the FIRAuthOperationType enum which will be translated to its + corresponding string value. + @return The string value corresponding to the FIRAuthOperationType argument. + */ +NSString *const FIRAuthOperationString(FIRAuthOperationType operationType) { + switch (operationType) { + case FIRAuthOperationTypeUnspecified: + return @"VERIFY_OP_UNSPECIFIED"; + case FIRAuthOperationTypeSignUpOrSignIn: + return @"SIGN_UP_OR_IN"; + case FIRAuthOperationTypeReauth: + return @"REAUTH"; + case FIRAuthOperationTypeLink: + return @"LINK"; + case FIRAuthOperationTypeUpdate: + return @"UPDATE"; + } +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *__autoreleasing _Nullable *)error { + NSMutableDictionary *postBody = [NSMutableDictionary dictionary]; + if (_verificationID) { + postBody[kVerificationIDKey] = _verificationID; + } + if (_verificationCode) { + postBody[kVerificationCodeKey] = _verificationCode; + } + if (_accessToken) { + postBody[kIDTokenKey] = _accessToken; + } + if (_temporaryProof) { + postBody[kTemporaryProofKey] = _temporaryProof; + } + if (_phoneNumber) { + postBody[kPhoneNumberKey] = _phoneNumber; + } + if (self.tenantID) { + postBody[kTenantIDKey] = self.tenantID; + } + NSString *operation = FIRAuthOperationString(_operation); + postBody[kOperationKey] = operation; + return [postBody copy]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberResponse.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberResponse.h new file mode 100644 index 0000000..7817ccf --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberResponse.h @@ -0,0 +1,64 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRVerifyPhoneNumberResponse : NSObject + +/** @property IDToken + @brief Either an authorization code suitable for performing an STS token exchange, or the + access token from Secure Token Service, depending on whether @c returnSecureToken is set + on the request. + */ +@property(nonatomic, strong, readonly, nullable) NSString *IDToken; + +/** @property refreshToken + @brief The refresh token from Secure Token Service. + */ +@property(nonatomic, strong, readonly, nullable) NSString *refreshToken; + +/** @property localID + @brief The Firebase Auth user ID. + */ +@property(nonatomic, strong, readonly, nullable) NSString *localID; + +/** @property phoneNumber + @brief The verified phone number. + */ +@property(nonatomic, strong, readonly, nullable) NSString *phoneNumber; + +/** @property temporaryProof + @brief The temporary proof code returned by the backend. + */ +@property(nonatomic, strong, readonly, nullable) NSString *temporaryProof; + +/** @property isNewUser + @brief Flag indicating that the user signing in is a new user and not a returning user. + */ +@property(nonatomic, assign) BOOL isNewUser; + +/** @property approximateExpirationDate + @brief The approximate expiration date of the access token. + */ +@property(nonatomic, copy, readonly, nullable) NSDate *approximateExpirationDate; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberResponse.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberResponse.m new file mode 100644 index 0000000..902fb96 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberResponse.m @@ -0,0 +1,43 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRVerifyPhoneNumberResponse + +- (nullable NSString *)expectedKind { + return nil; +} + +- (BOOL)setWithDictionary:(NSDictionary *)dictionary error:(NSError *_Nullable *_Nullable)error { + _IDToken = [dictionary[@"idToken"] copy]; + _refreshToken = [dictionary[@"refreshToken"] copy]; + _isNewUser = [dictionary[@"isNewUser"] boolValue]; + _localID = [dictionary[@"localId"] copy]; + _phoneNumber = [dictionary[@"phoneNumber"] copy]; + _temporaryProof = [dictionary[@"temporaryProof"] copy]; + _approximateExpirationDate = + [dictionary[@"expiresIn"] isKindOfClass:[NSString class]] + ? [NSDate dateWithTimeIntervalSinceNow:[dictionary[@"expiresIn"] doubleValue]] + : nil; + return YES; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentRequest.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentRequest.h new file mode 100644 index 0000000..edd8a73 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentRequest.h @@ -0,0 +1,39 @@ +/* + * Copyright 2019 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/LICENSE2.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 "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneRequestInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRFinalizeMFAEnrollmentRequest : FIRIdentityToolkitRequest + +@property(nonatomic, copy, readonly, nullable) NSString *IDToken; + +@property(nonatomic, copy, readonly, nullable) NSString *displayName; + +@property(nonatomic, copy, readonly, nullable) + FIRAuthProtoFinalizeMFAPhoneRequestInfo *verificationInfo; + +- (nullable instancetype)initWithIDToken:(NSString *)IDToken + displayName:(NSString *)displayName + verificationInfo:(FIRAuthProtoFinalizeMFAPhoneRequestInfo *)verificationInfo + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentRequest.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentRequest.m new file mode 100644 index 0000000..80926bd --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentRequest.m @@ -0,0 +1,63 @@ +/* + * Copyright 2019 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/LICENSE2.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 "FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentRequest.h" + +static NSString *const kFinalizeMFAEnrollmentEndPoint = @"accounts/mfaEnrollment:finalize"; + +/** @var kTenantIDKey + @brief The key for the tenant id value in the request. + */ +static NSString *const kTenantIDKey = @"tenantId"; + +@implementation FIRFinalizeMFAEnrollmentRequest + +- (nullable instancetype)initWithIDToken:(NSString *)IDToken + displayName:(NSString *)displayName + verificationInfo:(FIRAuthProtoFinalizeMFAPhoneRequestInfo *)verificationInfo + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kFinalizeMFAEnrollmentEndPoint + requestConfiguration:requestConfiguration + useIdentityPlatform:YES + useStaging:NO]; + if (self) { + _IDToken = IDToken; + _displayName = displayName; + _verificationInfo = verificationInfo; + } + return self; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *__autoreleasing _Nullable *)error { + NSMutableDictionary *postBody = [NSMutableDictionary dictionary]; + if (_IDToken) { + postBody[@"idToken"] = _IDToken; + } + if (_displayName) { + postBody[@"displayName"] = _displayName; + } + if (_verificationInfo) { + if ([_verificationInfo isKindOfClass:[FIRAuthProtoFinalizeMFAPhoneRequestInfo class]]) { + postBody[@"phoneVerificationInfo"] = [_verificationInfo dictionary]; + } + } + if (self.tenantID) { + postBody[kTenantIDKey] = self.tenantID; + } + return [postBody copy]; +} + +@end diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentResponse.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentResponse.h new file mode 100644 index 0000000..aca12a1 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentResponse.h @@ -0,0 +1,30 @@ +/* + * Copyright 2019 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/LICENSE2.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 "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneResponseInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRFinalizeMFAEnrollmentResponse : NSObject + +@property(nonatomic, copy, readonly, nullable) NSString *IDToken; + +@property(nonatomic, copy, readonly, nullable) NSString *refreshToken; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentResponse.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentResponse.m new file mode 100644 index 0000000..1e9cac5 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentResponse.m @@ -0,0 +1,30 @@ +/* + * Copyright 2019 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/LICENSE2.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 "FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentResponse.h" + +#import "FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneResponseInfo.h" + +@implementation FIRFinalizeMFAEnrollmentResponse + +- (BOOL)setWithDictionary:(nonnull NSDictionary *)dictionary + error:(NSError *__autoreleasing _Nullable *_Nullable)error { + _IDToken = [dictionary[@"idToken"] copy]; + _refreshToken = [dictionary[@"refreshToken"] copy]; + return YES; +} + +@end diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentRequest.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentRequest.h new file mode 100644 index 0000000..62599f6 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentRequest.h @@ -0,0 +1,35 @@ +/* + * Copyright 2019 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/LICENSE2.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 "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneRequestInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRStartMFAEnrollmentRequest : FIRIdentityToolkitRequest + +@property(nonatomic, copy, readonly, nullable) NSString *IDToken; + +@property(nonatomic, copy, readonly, nullable) FIRAuthProtoStartMFAPhoneRequestInfo *enrollmentInfo; + +- (nullable instancetype)initWithIDToken:(NSString *)IDToken + enrollmentInfo:(FIRAuthProtoStartMFAPhoneRequestInfo *)enrollmentInfo + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentRequest.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentRequest.m new file mode 100644 index 0000000..1504cc2 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentRequest.m @@ -0,0 +1,60 @@ +/* + * Copyright 2019 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/LICENSE2.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 "FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentRequest.h" + +#import "FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneRequestInfo.h" + +static NSString *const kStartMFAEnrollmentEndPoint = @"accounts/mfaEnrollment:start"; + +/** @var kTenantIDKey + @brief The key for the tenant id value in the request. + */ +static NSString *const kTenantIDKey = @"tenantId"; + +@implementation FIRStartMFAEnrollmentRequest + +- (nullable instancetype)initWithIDToken:(NSString *)IDToken + enrollmentInfo:(FIRAuthProtoStartMFAPhoneRequestInfo *)enrollmentInfo + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kStartMFAEnrollmentEndPoint + requestConfiguration:requestConfiguration + useIdentityPlatform:YES + useStaging:NO]; + if (self) { + _IDToken = IDToken; + _enrollmentInfo = enrollmentInfo; + } + return self; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *__autoreleasing _Nullable *)error { + NSMutableDictionary *postBody = [NSMutableDictionary dictionary]; + if (_IDToken) { + postBody[@"idToken"] = _IDToken; + } + if (_enrollmentInfo) { + if ([_enrollmentInfo isKindOfClass:[FIRAuthProtoStartMFAPhoneRequestInfo class]]) { + postBody[@"phoneEnrollmentInfo"] = [_enrollmentInfo dictionary]; + } + } + if (self.tenantID) { + postBody[kTenantIDKey] = self.tenantID; + } + return [postBody copy]; +} + +@end diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentResponse.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentResponse.h new file mode 100644 index 0000000..d0d5bda --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentResponse.h @@ -0,0 +1,29 @@ +/* + * Copyright 2019 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/LICENSE2.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 "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneResponseInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRStartMFAEnrollmentResponse : NSObject + +@property(nonatomic, copy, readonly, nullable) + FIRAuthProtoStartMFAPhoneResponseInfo *enrollmentResponse; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentResponse.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentResponse.m new file mode 100644 index 0000000..658462c --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentResponse.m @@ -0,0 +1,34 @@ +/* + * Copyright 2019 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/LICENSE2.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 "FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentResponse.h" + +#import "FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneResponseInfo.h" + +@implementation FIRStartMFAEnrollmentResponse + +- (BOOL)setWithDictionary:(nonnull NSDictionary *)dictionary + error:(NSError *__autoreleasing _Nullable *_Nullable)error { + if (dictionary[@"phoneSessionInfo"] != nil) { + NSDictionary *data = dictionary[@"phoneSessionInfo"]; + _enrollmentResponse = [[FIRAuthProtoStartMFAPhoneResponseInfo alloc] initWithDictionary:data]; + } else { + return NO; + } + return YES; +} + +@end diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInRequest.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInRequest.h new file mode 100644 index 0000000..155f5ea --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInRequest.h @@ -0,0 +1,37 @@ +/* + * Copyright 2019 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/LICENSE2.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 "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneRequestInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRFinalizeMFASignInRequest : FIRIdentityToolkitRequest + +@property(nonatomic, copy, readonly, nullable) NSString *MFAPendingCredential; + +@property(nonatomic, copy, readonly, nullable) + FIRAuthProtoFinalizeMFAPhoneRequestInfo *verificationInfo; + +- (nullable instancetype) + initWithMFAPendingCredential:(NSString *)MFAPendingCredential + verificationInfo:(FIRAuthProtoFinalizeMFAPhoneRequestInfo *)verificationInfo + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInRequest.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInRequest.m new file mode 100644 index 0000000..cae48ca --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInRequest.m @@ -0,0 +1,59 @@ +/* + * Copyright 2019 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/LICENSE2.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 "FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInRequest.h" + +static NSString *const kFinalizeMFASignInEndPoint = @"accounts/mfaSignIn:finalize"; + +/** @var kTenantIDKey + @brief The key for the tenant id value in the request. + */ +static NSString *const kTenantIDKey = @"tenantId"; + +@implementation FIRFinalizeMFASignInRequest + +- (nullable instancetype) + initWithMFAPendingCredential:(NSString *)MFAPendingCredential + verificationInfo:(FIRAuthProtoFinalizeMFAPhoneRequestInfo *)verificationInfo + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kFinalizeMFASignInEndPoint + requestConfiguration:requestConfiguration + useIdentityPlatform:YES + useStaging:NO]; + if (self) { + _MFAPendingCredential = MFAPendingCredential; + _verificationInfo = verificationInfo; + } + return self; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *__autoreleasing _Nullable *)error { + NSMutableDictionary *postBody = [NSMutableDictionary dictionary]; + if (_MFAPendingCredential) { + postBody[@"mfaPendingCredential"] = _MFAPendingCredential; + } + if (_verificationInfo) { + if ([_verificationInfo isKindOfClass:[FIRAuthProtoFinalizeMFAPhoneRequestInfo class]]) { + postBody[@"phoneVerificationInfo"] = [_verificationInfo dictionary]; + } + } + if (self.tenantID) { + postBody[kTenantIDKey] = self.tenantID; + } + return [postBody copy]; +} + +@end diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInResponse.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInResponse.h new file mode 100644 index 0000000..5ad8bd6 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInResponse.h @@ -0,0 +1,30 @@ +/* + * Copyright 2019 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/LICENSE2.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 "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneResponseInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRFinalizeMFASignInResponse : NSObject + +@property(nonatomic, copy, readonly, nullable) NSString *IDToken; + +@property(nonatomic, copy, readonly, nullable) NSString *refreshToken; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInResponse.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInResponse.m new file mode 100644 index 0000000..0763880 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInResponse.m @@ -0,0 +1,28 @@ +/* + * Copyright 2019 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/LICENSE2.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 "FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInResponse.h" + +@implementation FIRFinalizeMFASignInResponse + +- (BOOL)setWithDictionary:(nonnull NSDictionary *)dictionary + error:(NSError *__autoreleasing _Nullable *_Nullable)error { + _IDToken = [dictionary[@"idToken"] copy]; + _refreshToken = [dictionary[@"refreshToken"] copy]; + return YES; +} + +@end diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInRequest.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInRequest.h new file mode 100644 index 0000000..8a12bad --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInRequest.h @@ -0,0 +1,39 @@ +/* + * Copyright 2019 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/LICENSE2.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 "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneRequestInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRStartMFASignInRequest : FIRIdentityToolkitRequest + +@property(nonatomic, copy, readonly, nullable) NSString *MFAPendingCredential; + +@property(nonatomic, copy, readonly, nullable) NSString *MFAEnrollmentID; + +@property(nonatomic, copy, readonly, nullable) FIRAuthProtoStartMFAPhoneRequestInfo *signInInfo; + +- (nullable instancetype) + initWithMFAPendingCredential:(NSString *)MFAPendingCredential + MFAEnrollmentID:(NSString *)MFAEnrollmentID + signInInfo:(FIRAuthProtoStartMFAPhoneRequestInfo *)signInInfo + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInRequest.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInRequest.m new file mode 100644 index 0000000..dee5b2c --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInRequest.m @@ -0,0 +1,64 @@ +/* + * Copyright 2019 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/LICENSE2.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 "FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInRequest.h" + +static NSString *const kStartMFASignInEndPoint = @"accounts/mfaSignIn:start"; + +/** @var kTenantIDKey + @brief The key for the tenant id value in the request. + */ +static NSString *const kTenantIDKey = @"tenantId"; + +@implementation FIRStartMFASignInRequest + +- (nullable instancetype) + initWithMFAPendingCredential:(NSString *)MFAPendingCredential + MFAEnrollmentID:(NSString *)MFAEnrollmentID + signInInfo:(FIRAuthProtoStartMFAPhoneRequestInfo *)signInInfo + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kStartMFASignInEndPoint + requestConfiguration:requestConfiguration + useIdentityPlatform:YES + useStaging:NO]; + if (self) { + _MFAPendingCredential = MFAPendingCredential; + _MFAEnrollmentID = MFAEnrollmentID; + _signInInfo = signInInfo; + } + return self; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *__autoreleasing _Nullable *)error { + NSMutableDictionary *postBody = [NSMutableDictionary dictionary]; + if (_MFAPendingCredential) { + postBody[@"mfaPendingCredential"] = _MFAPendingCredential; + } + if (_MFAEnrollmentID) { + postBody[@"mfaEnrollmentId"] = _MFAEnrollmentID; + } + if (_signInInfo) { + if ([_signInInfo isKindOfClass:[FIRAuthProtoStartMFAPhoneRequestInfo class]]) { + postBody[@"phoneSignInInfo"] = [_signInInfo dictionary]; + } + } + if (self.tenantID) { + postBody[kTenantIDKey] = self.tenantID; + } + return [postBody copy]; +} + +@end diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInResponse.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInResponse.h new file mode 100644 index 0000000..bd1c372 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInResponse.h @@ -0,0 +1,28 @@ +/* + * Copyright 2019 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/LICENSE2.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 "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneResponseInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRStartMFASignInResponse : NSObject + +@property(nonatomic, copy, readonly, nullable) FIRAuthProtoStartMFAPhoneResponseInfo *responseInfo; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInResponse.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInResponse.m new file mode 100644 index 0000000..7ad49f8 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInResponse.m @@ -0,0 +1,32 @@ +/* + * Copyright 2019 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/LICENSE2.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 "FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInResponse.h" + +@implementation FIRStartMFASignInResponse + +- (BOOL)setWithDictionary:(nonnull NSDictionary *)dictionary + error:(NSError *__autoreleasing _Nullable *_Nullable)error { + if (dictionary[@"phoneResponseInfo"] != nil) { + NSDictionary *data = dictionary[@"phoneResponseInfo"]; + _responseInfo = [[FIRAuthProtoStartMFAPhoneResponseInfo alloc] initWithDictionary:data]; + } else { + return NO; + } + return YES; +} + +@end diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFARequest.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFARequest.h new file mode 100644 index 0000000..df211f8 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFARequest.h @@ -0,0 +1,34 @@ +/* + * Copyright 2019 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/LICENSE2.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 "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h" +#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRWithdrawMFARequest : FIRIdentityToolkitRequest + +@property(nonatomic, copy, readonly, nullable) NSString *IDToken; + +@property(nonatomic, copy, readonly, nullable) NSString *MFAEnrollmentID; + +- (nullable instancetype)initWithIDToken:(NSString *)IDToken + MFAEnrollmentID:(NSString *)MFAEnrollmentID + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFARequest.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFARequest.m new file mode 100644 index 0000000..a7038c3 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFARequest.m @@ -0,0 +1,60 @@ +/* + * Copyright 2019 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/LICENSE2.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 "FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFARequest.h" + +NS_ASSUME_NONNULL_BEGIN + +static NSString *const kWithdrawMFAEndPoint = @"accounts/mfaEnrollment:withdraw"; + +/** @var kTenantIDKey + @brief The key for the tenant id value in the request. + */ +static NSString *const kTenantIDKey = @"tenantId"; + +@implementation FIRWithdrawMFARequest + +- (nullable instancetype)initWithIDToken:(NSString *)IDToken + MFAEnrollmentID:(NSString *)MFAEnrollmentID + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kWithdrawMFAEndPoint + requestConfiguration:requestConfiguration + useIdentityPlatform:YES + useStaging:NO]; + if (self) { + _IDToken = IDToken; + _MFAEnrollmentID = MFAEnrollmentID; + } + return self; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *__autoreleasing _Nullable *)error { + NSMutableDictionary *postBody = [NSMutableDictionary dictionary]; + if (_IDToken) { + postBody[@"idToken"] = _IDToken; + } + if (_MFAEnrollmentID) { + postBody[@"mfaEnrollmentId"] = _MFAEnrollmentID; + } + if (self.tenantID) { + postBody[kTenantIDKey] = self.tenantID; + } + return [postBody copy]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFAResponse.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFAResponse.h new file mode 100644 index 0000000..84adf82 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFAResponse.h @@ -0,0 +1,29 @@ +/* + * Copyright 2019 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/LICENSE2.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 "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRWithdrawMFAResponse : NSObject + +@property(nonatomic, copy, readonly, nullable) NSString *IDToken; + +@property(nonatomic, copy, readonly, nullable) NSString *refreshToken; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFAResponse.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFAResponse.m new file mode 100644 index 0000000..7d1c3c7 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFAResponse.m @@ -0,0 +1,32 @@ +/* + * Copyright 2019 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/LICENSE2.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 "FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFAResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRWithdrawMFAResponse + +- (BOOL)setWithDictionary:(nonnull NSDictionary *)dictionary + error:(NSError *__autoreleasing _Nullable *_Nullable)error { + _IDToken = [dictionary[@"idToken"] copy]; + _refreshToken = [dictionary[@"refreshToken"] copy]; + return YES; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProto.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProto.h new file mode 100644 index 0000000..5d0d861 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProto.h @@ -0,0 +1,30 @@ +/* + * Copyright 2019 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 + +NS_ASSUME_NONNULL_BEGIN + +@protocol FIRAuthProto + +@optional +- (instancetype)initWithDictionary:(NSDictionary *)dictionary; + +- (NSDictionary *)dictionary; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProtoMFAEnrollment.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProtoMFAEnrollment.h new file mode 100644 index 0000000..c463cdc --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProtoMFAEnrollment.h @@ -0,0 +1,33 @@ +/* + * Copyright 2019 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 "FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProto.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRAuthProtoMFAEnrollment : NSObject + +@property(nonatomic, copy, readonly, nullable) NSString *phoneInfo; + +@property(nonatomic, copy, readonly, nullable) NSString *MFAEnrollmentID; + +@property(nonatomic, copy, readonly, nullable) NSString *displayName; + +@property(nonatomic, copy, readonly, nullable) NSDate *enrolledAt; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProtoMFAEnrollment.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProtoMFAEnrollment.m new file mode 100644 index 0000000..3166475 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProtoMFAEnrollment.m @@ -0,0 +1,43 @@ +/* + * Copyright 2019 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 "FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProtoMFAEnrollment.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRAuthProtoMFAEnrollment + +- (instancetype)initWithDictionary:(NSDictionary *)dictionary { + self = [super init]; + if (self) { + if (dictionary[@"phoneInfo"]) { + _phoneInfo = dictionary[@"phoneInfo"]; + } + _MFAEnrollmentID = dictionary[@"mfaEnrollmentId"]; + _displayName = dictionary[@"displayName"]; + if ([dictionary[@"enrolledAt"] isKindOfClass:[NSString class]]) { + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; + [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZ"]; + NSDate *date = [dateFormatter dateFromString:dictionary[@"enrolledAt"]]; + _enrolledAt = date; + } + } + return self; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneRequestInfo.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneRequestInfo.h new file mode 100644 index 0000000..df6e39a --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneRequestInfo.h @@ -0,0 +1,31 @@ +/* + * Copyright 2019 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 "FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProto.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRAuthProtoFinalizeMFAPhoneRequestInfo : NSObject + +@property(nonatomic, strong, readonly, nullable) NSString *sessionInfo; + +@property(nonatomic, strong, readonly, nullable) NSString *code; + +- (instancetype)initWithSessionInfo:(NSString *)sessionInfo + verificationCode:(NSString *)verificationCode; +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneRequestInfo.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneRequestInfo.m new file mode 100644 index 0000000..b233a13 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneRequestInfo.m @@ -0,0 +1,46 @@ +/* + * Copyright 2019 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 "FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneRequestInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRAuthProtoFinalizeMFAPhoneRequestInfo + +- (instancetype)initWithSessionInfo:(NSString *)sessionInfo + verificationCode:(NSString *)verificationCode { + self = [super init]; + if (self) { + _sessionInfo = sessionInfo; + _code = verificationCode; + } + return self; +} + +- (NSDictionary *)dictionary { + NSMutableDictionary *dict = [NSMutableDictionary dictionary]; + if (_sessionInfo) { + dict[@"sessionInfo"] = _sessionInfo; + } + if (_code) { + dict[@"code"] = _code; + } + return [dict copy]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneResponseInfo.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneResponseInfo.h new file mode 100644 index 0000000..fc9af6e --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneResponseInfo.h @@ -0,0 +1,27 @@ +/* + * Copyright 2019 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 "FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProto.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRAuthProtoFinalizeMFAPhoneResponseInfo : NSObject + +@property(nonatomic, copy, readonly, nullable) NSString *phoneNumber; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneResponseInfo.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneResponseInfo.m new file mode 100644 index 0000000..f8f1d96 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneResponseInfo.m @@ -0,0 +1,33 @@ +/* + * Copyright 2019 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 "FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneResponseInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRAuthProtoFinalizeMFAPhoneResponseInfo + +- (instancetype)initWithDictionary:(NSDictionary *)dictionary { + self = [super init]; + if (self) { + _phoneNumber = [dictionary[@"phoneNumber"] copy]; + } + return self; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneRequestInfo.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneRequestInfo.h new file mode 100644 index 0000000..e17315f --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneRequestInfo.h @@ -0,0 +1,36 @@ +/* + * Copyright 2019 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 "FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProto.h" +#import "FirebaseAuth/Sources/SystemService/FIRAuthAppCredential.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRAuthProtoStartMFAPhoneRequestInfo : NSObject + +@property(nonatomic, strong, readonly, nullable) NSString *phoneNumber; + +@property(nonatomic, strong, readonly, nullable) FIRAuthAppCredential *appCredential; + +@property(nonatomic, strong, readonly, nullable) NSString *reCAPTCHAToken; + +- (nullable instancetype)initWithPhoneNumber:(NSString *)phoneNumber + appCredential:(nullable FIRAuthAppCredential *)appCredential + reCAPTCHAToken:(nullable NSString *)reCAPTCHAToken; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneRequestInfo.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneRequestInfo.m new file mode 100644 index 0000000..1c0ffea --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneRequestInfo.m @@ -0,0 +1,74 @@ +/* + * Copyright 2019 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 "FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneRequestInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kPhoneNumberKey + @brief The key for the Phone Number parameter in the request. + */ +static NSString *const kPhoneNumberKey = @"phoneNumber"; + +/** @var kReceiptKey + @brief The key for the receipt parameter in the request. + */ +static NSString *const kReceiptKey = @"iosReceipt"; + +/** @var kSecretKey + @brief The key for the Secret parameter in the request. + */ +static NSString *const kSecretKey = @"iosSecret"; + +/** @var kreCAPTCHATokenKey + @brief The key for the reCAPTCHAToken parameter in the request. + */ +static NSString *const kreCAPTCHATokenKey = @"recaptchaToken"; + +@implementation FIRAuthProtoStartMFAPhoneRequestInfo + +- (nullable instancetype)initWithPhoneNumber:(NSString *)phoneNumber + appCredential:(nullable FIRAuthAppCredential *)appCredential + reCAPTCHAToken:(nullable NSString *)reCAPTCHAToken { + self = [super init]; + if (self) { + _phoneNumber = [phoneNumber copy]; + _appCredential = appCredential; + _reCAPTCHAToken = [reCAPTCHAToken copy]; + } + return self; +} + +- (NSDictionary *)dictionary { + NSMutableDictionary *dict = [NSMutableDictionary dictionary]; + if (_phoneNumber) { + dict[kPhoneNumberKey] = _phoneNumber; + } + if (_appCredential.receipt) { + dict[kReceiptKey] = _appCredential.receipt; + } + if (_appCredential.secret) { + dict[kSecretKey] = _appCredential.secret; + } + if (_reCAPTCHAToken) { + dict[kreCAPTCHATokenKey] = _reCAPTCHAToken; + } + return [dict copy]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneResponseInfo.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneResponseInfo.h new file mode 100644 index 0000000..1cdb690 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneResponseInfo.h @@ -0,0 +1,27 @@ +/* + * Copyright 2019 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 "FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProto.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRAuthProtoStartMFAPhoneResponseInfo : NSObject + +@property(nonatomic, copy, readonly, nullable) NSString *sessionInfo; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneResponseInfo.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneResponseInfo.m new file mode 100644 index 0000000..065e417 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneResponseInfo.m @@ -0,0 +1,33 @@ +/* + * Copyright 2019 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 "FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneResponseInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRAuthProtoStartMFAPhoneResponseInfo + +- (instancetype)initWithDictionary:(NSDictionary *)dictionary { + self = [super init]; + if (self) { + _sessionInfo = [dictionary[@"sessionInfo"] copy]; + } + return self; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactor+Internal.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactor+Internal.h new file mode 100644 index 0000000..43bebdb --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactor+Internal.h @@ -0,0 +1,39 @@ +/* + * Copyright 2019 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/LICENSE2.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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactor.h" + +#import "FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProtoMFAEnrollment.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRMultiFactor () + +@property(nonatomic, weak) FIRUser *user; + +/** @fn initWithMFAEnrollments: + @brief Initialize a multi factor instance with a list of MFA enrollments. +*/ +- (instancetype)initWithMFAEnrollments:(NSArray *)MFAEnrollments; + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactor.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactor.m new file mode 100644 index 0000000..8cd66b9 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactor.m @@ -0,0 +1,201 @@ +/* + * Copyright 2019 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/LICENSE2.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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactor.h" + +#import "FirebaseAuth/Sources/Auth/FIRAuthDataResult_Internal.h" +#import "FirebaseAuth/Sources/Auth/FIRAuth_Internal.h" +#import "FirebaseAuth/Sources/Backend/FIRAuthBackend+MultiFactor.h" +#import "FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentRequest.h" +#import "FirebaseAuth/Sources/MultiFactor/FIRMultiFactor+Internal.h" +#import "FirebaseAuth/Sources/MultiFactor/FIRMultiFactorInfo+Internal.h" +#import "FirebaseAuth/Sources/MultiFactor/FIRMultiFactorSession+Internal.h" +#import "FirebaseAuth/Sources/User/FIRUser_Internal.h" + +#if TARGET_OS_IOS +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorAssertion.h" + +#import "FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthCredential_Internal.h" +#import "FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorAssertion+Internal.h" +#import "FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorInfo+Internal.h" + +#endif + +NS_ASSUME_NONNULL_BEGIN + +static NSString *kEnrolledFactorsCodingKey = @"enrolledFactors"; + +static NSString *kUserCodingKey = @"user"; + +@implementation FIRMultiFactor + +- (void)getSessionWithCompletion:(nullable FIRMultiFactorSessionCallback)completion { + FIRMultiFactorSession *session = [FIRMultiFactorSession sessionForCurrentUser]; + if (completion) { + completion(session, nil); + } +} + +- (void)enrollWithAssertion:(FIRMultiFactorAssertion *)assertion + displayName:(nullable NSString *)displayName + completion:(nullable FIRAuthVoidErrorCallback)completion { +#if TARGET_OS_IOS + FIRPhoneMultiFactorAssertion *phoneAssertion = (FIRPhoneMultiFactorAssertion *)assertion; + FIRAuthProtoFinalizeMFAPhoneRequestInfo *finalizeMFAPhoneRequestInfo = + [[FIRAuthProtoFinalizeMFAPhoneRequestInfo alloc] + initWithSessionInfo:phoneAssertion.authCredential.verificationID + verificationCode:phoneAssertion.authCredential.verificationCode]; + FIRFinalizeMFAEnrollmentRequest *request = + [[FIRFinalizeMFAEnrollmentRequest alloc] initWithIDToken:self.user.rawAccessToken + displayName:displayName + verificationInfo:finalizeMFAPhoneRequestInfo + requestConfiguration:self.user.requestConfiguration]; + [FIRAuthBackend + finalizeMultiFactorEnrollment:request + callback:^(FIRFinalizeMFAEnrollmentResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + if (completion) { + completion(error); + } + } else { + [FIRAuth.auth + completeSignInWithAccessToken:response.IDToken + accessTokenExpirationDate:nil + refreshToken:response.refreshToken + anonymous:NO + callback:^(FIRUser *_Nullable user, + NSError *_Nullable error) { + FIRAuthDataResult *result = + [[FIRAuthDataResult alloc] + initWithUser:user + additionalUserInfo:nil]; + FIRAuthDataResultCallback + decoratedCallback = [FIRAuth.auth + signInFlowAuthDataResultCallbackByDecoratingCallback: + ^(FIRAuthDataResult + *_Nullable authResult, + NSError *_Nullable error) { + if (completion) { + completion(error); + } + }]; + decoratedCallback(result, error); + }]; + } + }]; +#endif +} + +- (void)unenrollWithInfo:(FIRMultiFactorInfo *)factorInfo + completion:(nullable FIRAuthVoidErrorCallback)completion { + [self unenrollWithFactorUID:factorInfo.UID completion:completion]; +} + +- (void)unenrollWithFactorUID:(NSString *)factorUID + completion:(nullable FIRAuthVoidErrorCallback)completion { + FIRWithdrawMFARequest *request = + [[FIRWithdrawMFARequest alloc] initWithIDToken:self.user.rawAccessToken + MFAEnrollmentID:factorUID + requestConfiguration:self.user.requestConfiguration]; + [FIRAuthBackend + withdrawMultiFactor:request + callback:^(FIRWithdrawMFAResponse *_Nullable response, NSError *_Nullable error) { + if (error) { + if (completion) { + completion(error); + } + } else { + [FIRAuth.auth + completeSignInWithAccessToken:response.IDToken + accessTokenExpirationDate:nil + refreshToken:response.refreshToken + anonymous:NO + callback:^(FIRUser *_Nullable user, + NSError *_Nullable error) { + FIRAuthDataResult *result = + [[FIRAuthDataResult alloc] initWithUser:user + additionalUserInfo:nil]; + FIRAuthDataResultCallback decoratedCallback = [FIRAuth + .auth + signInFlowAuthDataResultCallbackByDecoratingCallback: + ^(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error) { + if (error) { + [[FIRAuth auth] signOut:NULL]; + } + if (completion) { + completion(error); + } + }]; + decoratedCallback(result, error); + }]; + } + }]; +} + +#pragma mark - Internal + +- (instancetype)initWithMFAEnrollments:(NSArray *)MFAEnrollments { + self = [super init]; + + if (self) { + NSMutableArray *multiFactorInfoArray = [[NSMutableArray alloc] init]; + for (FIRAuthProtoMFAEnrollment *MFAEnrollment in MFAEnrollments) { + if (MFAEnrollment.phoneInfo) { + FIRMultiFactorInfo *multiFactorInfo = + [[FIRPhoneMultiFactorInfo alloc] initWithProto:MFAEnrollment]; + [multiFactorInfoArray addObject:multiFactorInfo]; + } + } + _enrolledFactors = [multiFactorInfoArray copy]; + } + + return self; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + self = [self init]; + if (self) { + NSSet *enrolledFactorsClasses = [NSSet setWithArray:@[ + [NSArray class], [FIRMultiFactorInfo class], [FIRPhoneMultiFactorInfo class] + ]]; + NSArray *enrolledFactors = + [aDecoder decodeObjectOfClasses:enrolledFactorsClasses forKey:kEnrolledFactorsCodingKey]; + _enrolledFactors = enrolledFactors; + // Do not decode `user` weak property. + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:_enrolledFactors forKey:kEnrolledFactorsCodingKey]; + // Do not encode `user` weak property. +} + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorAssertion+Internal.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorAssertion+Internal.h new file mode 100644 index 0000000..1d8fd62 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorAssertion+Internal.h @@ -0,0 +1,33 @@ +/* + * Copyright 2019 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/LICENSE2.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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorAssertion.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRMultiFactorAssertion () { + @protected + NSString *_factorID; +} + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorAssertion.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorAssertion.m new file mode 100644 index 0000000..d5bd9b3 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorAssertion.m @@ -0,0 +1,29 @@ +/* + * Copyright 2019 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/LICENSE2.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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorAssertion.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRMultiFactorAssertion +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorConstants.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorConstants.m new file mode 100644 index 0000000..ba8570b --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorConstants.m @@ -0,0 +1,26 @@ +/* + * Copyright 2019 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 +#if TARGET_OS_IOS + +#import + +#pragma mark - Multi Factor ID constants + +NSString *const FIRPhoneMultiFactorID = @"phone"; + +#endif diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorInfo+Internal.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorInfo+Internal.h new file mode 100644 index 0000000..c45a0ea --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorInfo+Internal.h @@ -0,0 +1,45 @@ +/* + * Copyright 2019 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/LICENSE2.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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorInfo.h" + +#import "FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProtoMFAEnrollment.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRMultiFactorInfo () { + @protected + NSString *_factorID; +} + +- (instancetype)initWithProto:(FIRAuthProtoMFAEnrollment *)proto; + +#pragma mark - NSSecureCoding +// Note that we're not able to indicate FIRMultiFactorInfo conforming to NSSecureCoding in an +// internal header file, so the following NSSecureCoding methods are explicitly declared. + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder; + +- (void)encodeWithCoder:(NSCoder *)aCoder; + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorInfo.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorInfo.m new file mode 100644 index 0000000..e38e047 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorInfo.m @@ -0,0 +1,74 @@ +/* + * Copyright 2019 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/LICENSE2.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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorInfo.h" + +#import "FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProtoMFAEnrollment.h" + +static NSString *kUIDCodingKey = @"uid"; + +static NSString *kDisplayNameCodingKey = @"displayName"; + +static NSString *kEnrollmentDateCodingKey = @"enrollmentDate"; + +static NSString *kFactorIDCodingKey = @"factorID"; + +@implementation FIRMultiFactorInfo + +#pragma mark - Internal + +- (instancetype)initWithProto:(FIRAuthProtoMFAEnrollment *)proto { + self = [super init]; + + if (self) { + _UID = proto.MFAEnrollmentID; + _displayName = proto.displayName; + _enrollmentDate = proto.enrolledAt; + } + + return self; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + self = [self init]; + if (self) { + _UID = [aDecoder decodeObjectOfClass:[NSString class] forKey:kUIDCodingKey]; + _displayName = [aDecoder decodeObjectOfClass:[NSString class] forKey:kDisplayNameCodingKey]; + _enrollmentDate = [aDecoder decodeObjectOfClass:[NSDate class] forKey:kEnrollmentDateCodingKey]; + _factorID = [aDecoder decodeObjectOfClass:[NSString class] forKey:kFactorIDCodingKey]; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:_UID forKey:kUIDCodingKey]; + [aCoder encodeObject:_displayName forKey:kDisplayNameCodingKey]; + [aCoder encodeObject:_enrollmentDate forKey:kEnrollmentDateCodingKey]; + [aCoder encodeObject:_factorID forKey:kFactorIDCodingKey]; +} + +@end + +#endif diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorResolver+Internal.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorResolver+Internal.h new file mode 100644 index 0000000..2516216 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorResolver+Internal.h @@ -0,0 +1,35 @@ +/* + * Copyright 2019 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/LICENSE2.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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorResolver.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRMultiFactorResolver () + +@property(nonatomic) NSString *MFAPendingCredential; + +- (instancetype)initWithMFAPendingCredential:(NSString *_Nullable)MFAPendingCredential + hints:(NSArray *)hints + auth:(FIRAuth *)auth; + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorResolver.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorResolver.m new file mode 100644 index 0000000..cbb06f7 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorResolver.m @@ -0,0 +1,102 @@ +/* + * Copyright 2019 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/LICENSE2.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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAdditionalUserInfo.h" +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorResolver.h" + +#import "FirebaseAuth/Sources/Auth/FIRAuthDataResult_Internal.h" +#import "FirebaseAuth/Sources/Auth/FIRAuth_Internal.h" +#import "FirebaseAuth/Sources/Backend/FIRAuthBackend+MultiFactor.h" +#import "FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneRequestInfo.h" +#import "FirebaseAuth/Sources/MultiFactor/FIRMultiFactorResolver+Internal.h" +#import "FirebaseAuth/Sources/MultiFactor/FIRMultiFactorSession+Internal.h" + +#if TARGET_OS_IOS +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorAssertion.h" + +#import "FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthCredential_Internal.h" +#import "FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorAssertion+Internal.h" +#endif + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRMultiFactorResolver + +- (instancetype)initWithMFAPendingCredential:(NSString *_Nullable)MFAPendingCredential + hints:(NSArray *)hints + auth:(FIRAuth *)auth { + self = [super init]; + if (self) { + _MFAPendingCredential = MFAPendingCredential; + _hints = hints; + _auth = auth; + _session = [[FIRMultiFactorSession alloc] init]; + _session.MFAPendingCredential = MFAPendingCredential; + } + return self; +} + +- (void)resolveSignInWithAssertion:(nonnull FIRMultiFactorAssertion *)assertion + completion:(nullable FIRAuthDataResultCallback)completion { +#if TARGET_OS_IOS + FIRPhoneMultiFactorAssertion *phoneAssertion = (FIRPhoneMultiFactorAssertion *)assertion; + FIRAuthProtoFinalizeMFAPhoneRequestInfo *finalizeMFAPhoneRequestInfo = + [[FIRAuthProtoFinalizeMFAPhoneRequestInfo alloc] + initWithSessionInfo:phoneAssertion.authCredential.verificationID + verificationCode:phoneAssertion.authCredential.verificationCode]; + FIRFinalizeMFASignInRequest *request = [[FIRFinalizeMFASignInRequest alloc] + initWithMFAPendingCredential:self.MFAPendingCredential + verificationInfo:finalizeMFAPhoneRequestInfo + requestConfiguration:self.auth.requestConfiguration]; + [FIRAuthBackend + finalizeMultiFactorSignIn:request + callback:^(FIRFinalizeMFASignInResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + if (completion) { + completion(nil, error); + } + } else { + [FIRAuth.auth + completeSignInWithAccessToken:response.IDToken + accessTokenExpirationDate:nil + refreshToken:response.refreshToken + anonymous:NO + callback:^(FIRUser *_Nullable user, + NSError *_Nullable error) { + FIRAuthDataResult *result = + [[FIRAuthDataResult alloc] + initWithUser:user + additionalUserInfo:nil]; + FIRAuthDataResultCallback decoratedCallback = + [FIRAuth.auth + signInFlowAuthDataResultCallbackByDecoratingCallback: + completion]; + decoratedCallback(result, error); + }]; + } + }]; +#endif +} + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorSession+Internal.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorSession+Internal.h new file mode 100644 index 0000000..7e903f4 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorSession+Internal.h @@ -0,0 +1,39 @@ +/* + * Copyright 2019 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/LICENSE2.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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorInfo.h" +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorSession.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRMultiFactorSession () + +@property(nonatomic, readonly) NSString *IDToken; + +@property(nonatomic) NSString *MFAPendingCredential; + +@property(nonatomic) FIRMultiFactorInfo *multiFactorInfo; + ++ (FIRMultiFactorSession *)sessionForCurrentUser; + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorSession.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorSession.m new file mode 100644 index 0000000..6967740 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/FIRMultiFactorSession.m @@ -0,0 +1,52 @@ +/* + * Copyright 2019 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/LICENSE2.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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuth.h" +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorSession.h" + +#import "FirebaseAuth/Sources/MultiFactor/FIRMultiFactorSession+Internal.h" +#import "FirebaseAuth/Sources/User/FIRUser_Internal.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRMultiFactorSession + +#pragma mark - Private + +- (instancetype)initWithIDToken:(NSString *)IDToken { + self = [super init]; + if (self) { + _IDToken = IDToken; + } + return self; +} + +#pragma mark - Internal + ++ (FIRMultiFactorSession *)sessionForCurrentUser { + FIRUser *currentUser = [[FIRAuth auth] currentUser]; + NSString *IDToken = currentUser.rawAccessToken; + FIRMultiFactorSession *session = [[FIRMultiFactorSession alloc] initWithIDToken:IDToken]; + return session; +} + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorAssertion+Internal.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorAssertion+Internal.h new file mode 100644 index 0000000..e88a8ac --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorAssertion+Internal.h @@ -0,0 +1,33 @@ +/* + * Copyright 2019 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/LICENSE2.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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthCredential.h" +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorAssertion.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRPhoneMultiFactorAssertion () + +@property(nonatomic) FIRPhoneAuthCredential *authCredential; + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorAssertion.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorAssertion.m new file mode 100644 index 0000000..9004519 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorAssertion.m @@ -0,0 +1,43 @@ +/* + * Copyright 2019 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/LICENSE2.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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorAssertion.h" + +#import "FirebaseAuth/Sources/MultiFactor/FIRMultiFactorAssertion+Internal.h" +#import "FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorAssertion+Internal.h" + +NS_ASSUME_NONNULL_BEGIN + +extern NSString *const _Nonnull FIRPhoneMultiFactorID; + +@implementation FIRPhoneMultiFactorAssertion + +- (instancetype)init { + self = [super init]; + if (self) { + _factorID = FIRPhoneMultiFactorID; + } + return self; +} + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorGenerator.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorGenerator.m new file mode 100644 index 0000000..124dffb --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorGenerator.m @@ -0,0 +1,36 @@ +/* + * Copyright 2019 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/LICENSE2.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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorAssertion.h" +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorGenerator.h" + +#import "FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorAssertion+Internal.h" + +@implementation FIRPhoneMultiFactorGenerator + ++ (FIRPhoneMultiFactorAssertion *)assertionWithCredential: + (FIRPhoneAuthCredential *)phoneAuthCredential { + FIRPhoneMultiFactorAssertion *assertion = [[FIRPhoneMultiFactorAssertion alloc] init]; + assertion.authCredential = phoneAuthCredential; + return assertion; +} + +@end + +#endif diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorInfo+Internal.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorInfo+Internal.h new file mode 100644 index 0000000..0679755 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorInfo+Internal.h @@ -0,0 +1,30 @@ +/* + * Copyright 2019 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/LICENSE2.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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorInfo.h" + +@class FIRAuthProtoMFAEnrollment; + +@interface FIRPhoneMultiFactorInfo () + +- (instancetype)initWithProto:(FIRAuthProtoMFAEnrollment *)proto; + +@end + +#endif diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorInfo.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorInfo.m new file mode 100644 index 0000000..1f5b2a7 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorInfo.m @@ -0,0 +1,62 @@ +/* + * Copyright 2019 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/LICENSE2.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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorInfo.h" +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorInfo.h" + +#import "FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProtoMFAEnrollment.h" +#import "FirebaseAuth/Sources/MultiFactor/FIRMultiFactorInfo+Internal.h" + +static NSString *kPhoneNumberCodingKey = @"phoneNumber"; + +extern NSString *const FIRPhoneMultiFactorID; + +@implementation FIRPhoneMultiFactorInfo + +- (instancetype)initWithProto:(FIRAuthProtoMFAEnrollment *)proto { + self = [super initWithProto:proto]; + if (self) { + _factorID = FIRPhoneMultiFactorID; + _phoneNumber = proto.phoneInfo; + } + return self; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + self = [super initWithCoder:aDecoder]; + if (self) { + _phoneNumber = [aDecoder decodeObjectOfClass:[NSString class] forKey:kPhoneNumberCodingKey]; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [super encodeWithCoder:aCoder]; + [aCoder encodeObject:_phoneNumber forKey:kPhoneNumberCodingKey]; +} + +@end + +#endif diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRActionCodeSettings.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRActionCodeSettings.h new file mode 100644 index 0000000..5024bd5 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRActionCodeSettings.h @@ -0,0 +1,89 @@ +/* + * 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/LICENSE2.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 + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRActionCodeSettings + @brief Used to set and retrieve settings related to handling action codes. + */ +NS_SWIFT_NAME(ActionCodeSettings) +@interface FIRActionCodeSettings : NSObject + +/** @property URL + @brief This URL represents the state/Continue URL in the form of a universal link. + @remarks This URL can should be constructed as a universal link that would either directly open + the app where the action code would be handled or continue to the app after the action code + is handled by Firebase. + */ +@property(nonatomic, copy, nullable) NSURL *URL; + +/** @property handleCodeInApp + @brief Indicates whether the action code link will open the app directly or after being + redirected from a Firebase owned web widget. + */ +@property(assign, nonatomic) BOOL handleCodeInApp; + +/** @property iOSBundleID + @brief The iOS bundle ID, if available. The default value is the current app's bundle ID. + */ +@property(copy, nonatomic, readonly, nullable) NSString *iOSBundleID; + +/** @property androidPackageName + @brief The Android package name, if available. + */ +@property(nonatomic, copy, readonly, nullable) NSString *androidPackageName; + +/** @property androidMinimumVersion + @brief The minimum Android version supported, if available. + */ +@property(nonatomic, copy, readonly, nullable) NSString *androidMinimumVersion; + +/** @property androidInstallIfNotAvailable + @brief Indicates whether the Android app should be installed on a device where it is not + available. + */ +@property(nonatomic, assign, readonly) BOOL androidInstallIfNotAvailable; + +/** @property dynamicLinkDomain + @brief The Firebase Dynamic Link domain used for out of band code flow. + */ +@property(copy, nonatomic, nullable) NSString *dynamicLinkDomain; + +/** @fn setIOSBundleID + @brief Sets the iOS bundle Id. + @param iOSBundleID The iOS bundle ID. + */ +- (void)setIOSBundleID:(NSString *)iOSBundleID; + +/** @fn setAndroidPackageName:installIfNotAvailable:minimumVersion: + @brief Sets the Android package name, the flag to indicate whether or not to install the app + and the minimum Android version supported. + @param androidPackageName The Android package name. + @param installIfNotAvailable Indicates whether or not the app should be installed if not + available. + @param minimumVersion The minimum version of Android supported. + @remarks If installIfNotAvailable is set to YES and the link is opened on an android device, it + will try to install the app if not already available. Otherwise the web URL is used. + */ +- (void)setAndroidPackageName:(NSString *)androidPackageName + installIfNotAvailable:(BOOL)installIfNotAvailable + minimumVersion:(nullable NSString *)minimumVersion; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAdditionalUserInfo.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAdditionalUserInfo.h new file mode 100644 index 0000000..1d15b0c --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAdditionalUserInfo.h @@ -0,0 +1,57 @@ +/* + * 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 + +@class FIRVerifyAssertionResponse; + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRAdditionalUserInfo + @brief Represents additional user data returned from an identity provider. + */ +NS_SWIFT_NAME(AdditionalUserInfo) +@interface FIRAdditionalUserInfo : NSObject + +/** @fn init + @brief This class should not be initialized manually. `AdditionalUserInfo` can be retrieved + from from an instance of `AuthDataResult`. + */ +- (instancetype)init NS_UNAVAILABLE; + +/** @property providerID + @brief The provider identifier. + */ +@property(nonatomic, readonly) NSString *providerID; + +/** @property profile + @brief Dictionary containing the additional IdP specific information. + */ +@property(nonatomic, readonly, nullable) NSDictionary *profile; + +/** @property username + @brief username The name of the user. + */ +@property(nonatomic, readonly, nullable) NSString *username; + +/** @property newUser + @brief Indicates whether or not the current user was signed in for the first time. + */ +@property(nonatomic, readonly, getter=isNewUser) BOOL newUser; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuth.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuth.h new file mode 100644 index 0000000..9c3927d --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuth.h @@ -0,0 +1,882 @@ +/* + * 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 +#import + +#import "FIRAuthAPNSTokenType.h" +#import "FIRAuthErrors.h" + +@class FIRActionCodeSettings; +@class FIRApp; +@class FIRAuth; +@class FIRAuthCredential; +@class FIRAuthDataResult; +@class FIRAuthSettings; +@class FIRUser; +@protocol FIRAuthUIDelegate; +@protocol FIRFederatedAuthProvider; + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRUserUpdateCallback + @brief The type of block invoked when a request to update the current user is completed. + */ +typedef void (^FIRUserUpdateCallback)(NSError *_Nullable error) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/** @typedef FIRAuthStateDidChangeListenerHandle + @brief The type of handle returned by `Auth.addAuthStateDidChangeListener(_:)`. + */ +// clang-format off +// clang-format12 merges the next two lines. +typedef id FIRAuthStateDidChangeListenerHandle + NS_SWIFT_NAME(AuthStateDidChangeListenerHandle); +// clang-format on + +/** @typedef FIRAuthStateDidChangeListenerBlock + @brief The type of block which can be registered as a listener for auth state did change events. + + @param auth The Auth object on which state changes occurred. + @param user Optionally; the current signed in user, if any. + */ +typedef void (^FIRAuthStateDidChangeListenerBlock)(FIRAuth *auth, FIRUser *_Nullable user) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/** @typedef FIRIDTokenDidChangeListenerHandle + @brief The type of handle returned by `Auth.addIDTokenDidChangeListener(_:)`. + */ +// clang-format off +// clang-format12 merges the next two lines. +typedef id FIRIDTokenDidChangeListenerHandle + NS_SWIFT_NAME(IDTokenDidChangeListenerHandle); +// clang-format on + +/** @typedef FIRIDTokenDidChangeListenerBlock + @brief The type of block which can be registered as a listener for ID token did change events. + + @param auth The Auth object on which ID token changes occurred. + @param user Optionally; the current signed in user, if any. + */ +typedef void (^FIRIDTokenDidChangeListenerBlock)(FIRAuth *auth, FIRUser *_Nullable user) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/** @typedef FIRAuthDataResultCallback + @brief The type of block invoked when sign-in related events complete. + + @param authResult Optionally; Result of sign-in request containing both the user and + the additional user info associated with the user. + @param error Optionally; the error which occurred - or nil if the request was successful. + */ +typedef void (^FIRAuthDataResultCallback)(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); +/** + @brief The name of the `NSNotificationCenter` notification which is posted when the auth state + changes (for example, a new token has been produced, a user signs in or signs out). The + object parameter of the notification is the sender `Auth` instance. + */ +extern const NSNotificationName FIRAuthStateDidChangeNotification NS_SWIFT_NAME(AuthStateDidChange); + +/** @typedef FIRAuthResultCallback + @brief The type of block invoked when sign-in related events complete. + + @param user Optionally; the signed in user, if any. + @param error Optionally; if an error occurs, this is the NSError object that describes the + problem. Set to nil otherwise. + */ +typedef void (^FIRAuthResultCallback)(FIRUser *_Nullable user, NSError *_Nullable error) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/** @typedef FIRProviderQueryCallback + @brief The type of block invoked when a list of identity providers for a given email address is + requested. + + @param providers Optionally; a list of provider identifiers, if any. + @see GoogleAuthProviderID etc. + @param error Optionally; if an error occurs, this is the NSError object that describes the + problem. Set to nil otherwise. + */ +typedef void (^FIRProviderQueryCallback)(NSArray *_Nullable providers, + NSError *_Nullable error) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/** @typedef FIRSignInMethodQueryCallback + @brief The type of block invoked when a list of sign-in methods for a given email address is + requested. + */ +typedef void (^FIRSignInMethodQueryCallback)(NSArray *_Nullable, NSError *_Nullable) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/** @typedef FIRSendPasswordResetCallback + @brief The type of block invoked when sending a password reset email. + + @param error Optionally; if an error occurs, this is the NSError object that describes the + problem. Set to nil otherwise. + */ +typedef void (^FIRSendPasswordResetCallback)(NSError *_Nullable error) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/** @typedef FIRSendSignInLinkToEmailCallback + @brief The type of block invoked when sending an email sign-in link email. + */ +typedef void (^FIRSendSignInLinkToEmailCallback)(NSError *_Nullable error) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/** @typedef FIRConfirmPasswordResetCallback + @brief The type of block invoked when performing a password reset. + + @param error Optionally; if an error occurs, this is the NSError object that describes the + problem. Set to nil otherwise. + */ +typedef void (^FIRConfirmPasswordResetCallback)(NSError *_Nullable error) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/** @typedef FIRVerifyPasswordResetCodeCallback + @brief The type of block invoked when verifying that an out of band code should be used to + perform password reset. + + @param email Optionally; the email address of the user for which the out of band code applies. + @param error Optionally; if an error occurs, this is the NSError object that describes the + problem. Set to nil otherwise. + */ +typedef void (^FIRVerifyPasswordResetCodeCallback)(NSString *_Nullable email, + NSError *_Nullable error) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/** @typedef FIRApplyActionCodeCallback + @brief The type of block invoked when applying an action code. + + @param error Optionally; if an error occurs, this is the NSError object that describes the + problem. Set to nil otherwise. + */ +typedef void (^FIRApplyActionCodeCallback)(NSError *_Nullable error) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +typedef void (^FIRAuthVoidErrorCallback)(NSError *_Nullable) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/** @class FIRActionCodeInfo + @brief Manages information regarding action codes. + */ +NS_SWIFT_NAME(ActionCodeInfo) +@interface FIRActionCodeInfo : NSObject + +/** + @brief Operations which can be performed with action codes. + */ +typedef NS_ENUM(NSInteger, FIRActionCodeOperation) { + /** Action code for unknown operation. */ + FIRActionCodeOperationUnknown = 0, + + /** Action code for password reset operation. */ + FIRActionCodeOperationPasswordReset = 1, + + /** Action code for verify email operation. */ + FIRActionCodeOperationVerifyEmail = 2, + + /** Action code for recover email operation. */ + FIRActionCodeOperationRecoverEmail = 3, + + /** Action code for email link operation. */ + FIRActionCodeOperationEmailLink = 4, + + /** Action code for verifying and changing email */ + FIRActionCodeOperationVerifyAndChangeEmail = 5, + + /** Action code for reverting second factor addition */ + FIRActionCodeOperationRevertSecondFactorAddition = 6, + +} NS_SWIFT_NAME(ActionCodeOperation); + +/** + @brief The operation being performed. + */ +@property(nonatomic, readonly) FIRActionCodeOperation operation; + +/** @property email + @brief The email address to which the code was sent. The new email address in the case of + `ActionCodeOperationRecoverEmail`. + */ +@property(nonatomic, nullable, readonly, copy) NSString *email; + +/** @property previousEmail + @brief The email that is being recovered in the case of `ActionCodeOperationRecoverEmail`. + */ +@property(nonatomic, nullable, readonly, copy) NSString *previousEmail; + +/** @fn init + @brief please use initWithOperation: instead. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +/** @class FIRActionCodeURL + @brief This class will allow developers to easily extract information about out of band links. + */ +NS_SWIFT_NAME(ActionCodeURL) +@interface FIRActionCodeURL : NSObject + +/** @property APIKey + @brief Returns the API key from the link. nil, if not provided. + */ +@property(nonatomic, nullable, copy, readonly) NSString *APIKey; + +/** @property operation + @brief Returns the mode of oob action. The property will be of `FIRActionCodeOperation` type. + It will return `FIRActionCodeOperationUnknown` if no oob action is provided. + */ +@property(nonatomic, readonly) FIRActionCodeOperation operation; + +/** @property code + @brief Returns the email action code from the link. nil, if not provided. + */ +@property(nonatomic, nullable, copy, readonly) NSString *code; + +/** @property continueURL + @brief Returns the continue URL from the link. nil, if not provided. + */ +@property(nonatomic, nullable, copy, readonly) NSURL *continueURL; + +/** @property languageCode + @brief Returns the language code from the link. nil, if not provided. + */ +@property(nonatomic, nullable, copy, readonly) NSString *languageCode; + +/** @fn actionCodeURLWithLink: + @brief Construct an `ActionCodeURL` from an out of band link (e.g. email link). + @param link The oob link string used to construct the action code URL. + @return The `ActionCodeURL` object constructed based on the oob link provided. + */ ++ (nullable instancetype)actionCodeURLWithLink:(NSString *)link; + +/** @fn init + @brief Please use `init(link:)` in Swift or `actionCodeURLWithLink:` in Objective-C + instead. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +/** @typedef FIRCheckActionCodeCallBack + @brief The type of block invoked when performing a check action code operation. + + @param info Metadata corresponding to the action code. + @param error Optionally; if an error occurs, this is the NSError object that describes the + problem. Set to nil otherwise. + */ +typedef void (^FIRCheckActionCodeCallBack)(FIRActionCodeInfo *_Nullable info, + NSError *_Nullable error) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/** @class FIRAuth + @brief Manages authentication for Firebase apps. + @remarks This class is thread-safe. + */ +NS_SWIFT_NAME(Auth) +@interface FIRAuth : NSObject + +/** @fn auth + @brief Gets the auth object for the default Firebase app. + @remarks The default Firebase app must have already been configured or an exception will be + raised. + */ ++ (FIRAuth *)auth NS_SWIFT_NAME(auth()); + +/** @fn authWithApp: + @brief Gets the auth object for a `FirebaseApp`. + + @param app The app for which to retrieve the associated `Auth` instance. + @return The `Auth` instance associated with the given app. + */ ++ (FIRAuth *)authWithApp:(FIRApp *)app NS_SWIFT_NAME(auth(app:)); + +/** @property app + @brief Gets the `FirebaseApp` object that this auth object is connected to. + */ +@property(nonatomic, weak, readonly, nullable) FIRApp *app; + +/** @property currentUser + @brief Synchronously gets the cached current user, or null if there is none. + */ +@property(nonatomic, strong, readonly, nullable) FIRUser *currentUser; + +/** @property languageCode + @brief The current user language code. This property can be set to the app's current language by + calling `useAppLanguage()`. + + @remarks The string used to set this property must be a language code that follows BCP 47. + */ +@property(nonatomic, copy, nullable) NSString *languageCode; + +/** @property settings + @brief Contains settings related to the auth object. + */ +@property(nonatomic, copy, nullable) FIRAuthSettings *settings; + +/** @property userAccessGroup + @brief The current user access group that the Auth instance is using. Default is nil. + */ +@property(readonly, nonatomic, copy, nullable) NSString *userAccessGroup; + +/** @property shareAuthStateAcrossDevices + @brief Contains shareAuthStateAcrossDevices setting related to the auth object. + @remarks If userAccessGroup is not set, setting shareAuthStateAcrossDevices will + have no effect. You should set shareAuthStateAcrossDevices to it's desired + state and then set the userAccessGroup after. + */ +@property(nonatomic) BOOL shareAuthStateAcrossDevices; + +/** @property tenantID + @brief The tenant ID of the auth instance. nil if none is available. + */ +@property(nonatomic, copy, nullable) NSString *tenantID; + +/** @property APNSToken + @brief The APNs token used for phone number authentication. The type of the token (production + or sandbox) will be automatically detected based on your provisioning profile. + This property is available on iOS only. + @remarks If swizzling is disabled, the APNs Token must be set for phone number auth to work, + by either setting this property or by calling `setAPNSToken(_:type:)`. + */ +@property(nonatomic, strong, nullable) NSData *APNSToken API_UNAVAILABLE(macos, tvos, watchos); + +/** @fn init + @brief Please access auth instances using `Auth.auth()` and `Auth.auth(app:)`. + */ +- (instancetype)init NS_UNAVAILABLE; + +/** @fn updateCurrentUser:completion: + @brief Sets the `currentUser` on the receiver to the provided user object. + @param user The user object to be set as the current user of the calling Auth instance. + @param completion Optionally; a block invoked after the user of the calling Auth instance has + been updated or an error was encountered. + */ +- (void)updateCurrentUser:(FIRUser *)user + completion:(nullable void (^)(NSError *_Nullable error))completion; + +/** @fn fetchSignInMethodsForEmail:completion: + @brief Fetches the list of all sign-in methods previously used for the provided email address. + + @param email The email address for which to obtain a list of sign-in methods. + @param completion Optionally; a block which is invoked when the list of sign in methods for the + specified email address is ready or an error was encountered. Invoked asynchronously on the + main thread in the future. + + @remarks Possible error codes: + + + `AuthErrorCodeInvalidEmail` - Indicates the email address is malformed. + + @remarks See @c AuthErrors for a list of error codes that are common to all API methods. + */ + +- (void)fetchSignInMethodsForEmail:(NSString *)email + completion:(nullable void (^)(NSArray *_Nullable, + NSError *_Nullable))completion; + +/** @fn signInWithEmail:password:completion: + @brief Signs in using an email address and password. + + @param email The user's email address. + @param password The user's password. + @param completion Optionally; a block which is invoked when the sign in flow finishes, or is + canceled. Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: + + + `AuthErrorCodeOperationNotAllowed` - Indicates that email and password + accounts are not enabled. Enable them in the Auth section of the + Firebase console. + + `AuthErrorCodeUserDisabled` - Indicates the user's account is disabled. + + `AuthErrorCodeWrongPassword` - Indicates the user attempted + sign in with an incorrect password. + + `AuthErrorCodeInvalidEmail` - Indicates the email address is malformed. + + + @remarks See `AuthErrors` for a list of error codes that are common to all API methods. + */ +- (void)signInWithEmail:(NSString *)email + password:(NSString *)password + completion:(nullable void (^)(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error))completion; + +/** @fn signInWithEmail:link:completion: + @brief Signs in using an email address and email sign-in link. + + @param email The user's email address. + @param link The email sign-in link. + @param completion Optionally; a block which is invoked when the sign in flow finishes, or is + canceled. Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: + + + `AuthErrorCodeOperationNotAllowed` - Indicates that email and email sign-in link + accounts are not enabled. Enable them in the Auth section of the + Firebase console. + + `AuthErrorCodeUserDisabled` - Indicates the user's account is disabled. + + `AuthErrorCodeInvalidEmail` - Indicates the email address is invalid. + + + @remarks See `AuthErrors` for a list of error codes that are common to all API methods. + */ + +- (void)signInWithEmail:(NSString *)email + link:(NSString *)link + completion:(nullable void (^)(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error))completion + API_UNAVAILABLE(watchos); + +/** @fn signInWithProvider:UIDelegate:completion: + @brief Signs in using the provided auth provider instance. + This method is available on iOS, macOS Catalyst, and tvOS only. + + @param provider An instance of an auth provider used to initiate the sign-in flow. + @param UIDelegate Optionally an instance of a class conforming to the AuthUIDelegate + protocol, this is used for presenting the web context. If nil, a default AuthUIDelegate + will be used. + @param completion Optionally; a block which is invoked when the sign in flow finishes, or is + canceled. Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: +
    +
  • @c AuthErrorCodeOperationNotAllowed - Indicates that email and password + accounts are not enabled. Enable them in the Auth section of the + Firebase console. +
  • +
  • @c AuthErrorCodeUserDisabled - Indicates the user's account is disabled. +
  • +
  • @c AuthErrorCodeWebNetworkRequestFailed - Indicates that a network request within a + SFSafariViewController or WKWebView failed. +
  • +
  • @c AuthErrorCodeWebInternalError - Indicates that an internal error occurred within a + SFSafariViewController or WKWebView. +
  • +
  • @c AuthErrorCodeWebSignInUserInteractionFailure - Indicates a general failure during + a web sign-in flow. +
  • +
  • @c AuthErrorCodeWebContextAlreadyPresented - Indicates that an attempt was made to + present a new web context while one was already being presented. +
  • +
  • @c AuthErrorCodeWebContextCancelled - Indicates that the URL presentation was + cancelled prematurely by the user. +
  • +
  • @c AuthErrorCodeAccountExistsWithDifferentCredential - Indicates the email asserted + by the credential (e.g. the email in a Facebook access token) is already in use by an + existing account, that cannot be authenticated with this sign-in method. Call + fetchProvidersForEmail for this user’s email and then prompt them to sign in with any of + the sign-in providers returned. This error will only be thrown if the "One account per + email address" setting is enabled in the Firebase console, under Auth settings. +
  • +
+ + @remarks See @c AuthErrors for a list of error codes that are common to all API methods. + */ +- (void)signInWithProvider:(id)provider + UIDelegate:(nullable id)UIDelegate + completion:(nullable void (^)(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error))completion + API_UNAVAILABLE(macosx, watchos); + +/** @fn signInWithCredential:completion: + @brief Asynchronously signs in to Firebase with the given 3rd-party credentials (e.g. a Facebook + login Access Token, a Google ID Token/Access Token pair, etc.) and returns additional + identity provider data. + + @param credential The credential supplied by the IdP. + @param completion Optionally; a block which is invoked when the sign in flow finishes, or is + canceled. Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: + + + `AuthErrorCodeInvalidCredential` - Indicates the supplied credential is invalid. + This could happen if it has expired or it is malformed. + + `AuthErrorCodeOperationNotAllowed` - Indicates that accounts + with the identity provider represented by the credential are not enabled. + Enable them in the Auth section of the Firebase console. + + `AuthErrorCodeAccountExistsWithDifferentCredential` - Indicates the email asserted + by the credential (e.g. the email in a Facebook access token) is already in use by an + existing account, that cannot be authenticated with this sign-in method. Call + fetchProvidersForEmail for this user’s email and then prompt them to sign in with any of + the sign-in providers returned. This error will only be thrown if the "One account per + email address" setting is enabled in the Firebase console, under Auth settings. + + `AuthErrorCodeUserDisabled` - Indicates the user's account is disabled. + + `AuthErrorCodeWrongPassword` - Indicates the user attempted sign in with an + incorrect password, if credential is of the type EmailPasswordAuthCredential. + + `AuthErrorCodeInvalidEmail` - Indicates the email address is malformed. + + `AuthErrorCodeMissingVerificationID` - Indicates that the phone auth credential was + created with an empty verification ID. + + `AuthErrorCodeMissingVerificationCode` - Indicates that the phone auth credential + was created with an empty verification code. + + `AuthErrorCodeInvalidVerificationCode` - Indicates that the phone auth credential + was created with an invalid verification Code. + + `AuthErrorCodeInvalidVerificationID` - Indicates that the phone auth credential was + created with an invalid verification ID. + + `AuthErrorCodeSessionExpired` - Indicates that the SMS code has expired. + + @remarks See `AuthErrors` for a list of error codes that are common to all API methods +*/ +- (void)signInWithCredential:(FIRAuthCredential *)credential + completion:(nullable void (^)(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error))completion; + +/** @fn signInAnonymouslyWithCompletion: + @brief Asynchronously creates and becomes an anonymous user. + @param completion Optionally; a block which is invoked when the sign in finishes, or is + canceled. Invoked asynchronously on the main thread in the future. + + @remarks If there is already an anonymous user signed in, that user will be returned instead. + If there is any other existing user signed in, that user will be signed out. + + @remarks Possible error codes: + + + `AuthErrorCodeOperationNotAllowed` - Indicates that anonymous accounts are + not enabled. Enable them in the Auth section of the Firebase console. + + @remarks See `AuthErrors` for a list of error codes that are common to all API methods. + */ +- (void)signInAnonymouslyWithCompletion:(nullable void (^)(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error))completion; + +/** @fn signInWithCustomToken:completion: + @brief Asynchronously signs in to Firebase with the given Auth token. + + @param token A self-signed custom auth token. + @param completion Optionally; a block which is invoked when the sign in finishes, or is + canceled. Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: + + + `AuthErrorCodeInvalidCustomToken` - Indicates a validation error with + the custom token. + + `AuthErrorCodeCustomTokenMismatch` - Indicates the service account and the API key + belong to different projects. + + @remarks See `AuthErrors` for a list of error codes that are common to all API methods. + */ +- (void)signInWithCustomToken:(NSString *)token + completion:(nullable void (^)(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error))completion; + +/** @fn createUserWithEmail:password:completion: + @brief Creates and, on success, signs in a user with the given email address and password. + + @param email The user's email address. + @param password The user's desired password. + @param completion Optionally; a block which is invoked when the sign up flow finishes, or is + canceled. Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: + + + `AuthErrorCodeInvalidEmail` - Indicates the email address is malformed. + + `AuthErrorCodeEmailAlreadyInUse` - Indicates the email used to attempt sign up + already exists. Call fetchProvidersForEmail to check which sign-in mechanisms the user + used, and prompt the user to sign in with one of those. + + `AuthErrorCodeOperationNotAllowed` - Indicates that email and password accounts + are not enabled. Enable them in the Auth section of the Firebase console. + + `AuthErrorCodeWeakPassword` - Indicates an attempt to set a password that is + considered too weak. The NSLocalizedFailureReasonErrorKey field in the NSError.userInfo + dictionary object will contain more detailed explanation that can be shown to the user. + + @remarks See `AuthErrors` for a list of error codes that are common to all API methods. + */ +- (void)createUserWithEmail:(NSString *)email + password:(NSString *)password + completion:(nullable void (^)(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error))completion; + +/** @fn confirmPasswordResetWithCode:newPassword:completion: + @brief Resets the password given a code sent to the user outside of the app and a new password + for the user. + + @param newPassword The new password. + @param completion Optionally; a block which is invoked when the request finishes. Invoked + asynchronously on the main thread in the future. + + @remarks Possible error codes: + + + `AuthErrorCodeWeakPassword` - Indicates an attempt to set a password that is + considered too weak. + + `AuthErrorCodeOperationNotAllowed` - Indicates the administrator disabled sign + in with the specified identity provider. + + `AuthErrorCodeExpiredActionCode` - Indicates the OOB code is expired. + + `AuthErrorCodeInvalidActionCode` - Indicates the OOB code is invalid. + + @remarks See `AuthErrors` for a list of error codes that are common to all API methods. + */ +- (void)confirmPasswordResetWithCode:(NSString *)code + newPassword:(NSString *)newPassword + completion:(void (^)(NSError *_Nullable error))completion; + +/** @fn checkActionCode:completion: + @brief Checks the validity of an out of band code. + + @param code The out of band code to check validity. + @param completion Optionally; a block which is invoked when the request finishes. Invoked + asynchronously on the main thread in the future. + */ +- (void)checkActionCode:(NSString *)code + completion: + (void (^)(FIRActionCodeInfo *_Nullable info, NSError *_Nullable error))completion; + +/** @fn verifyPasswordResetCode:completion: + @brief Checks the validity of a verify password reset code. + + @param code The password reset code to be verified. + @param completion Optionally; a block which is invoked when the request finishes. Invoked + asynchronously on the main thread in the future. + */ +- (void)verifyPasswordResetCode:(NSString *)code + completion: + (void (^)(NSString *_Nullable email, NSError *_Nullable error))completion; + +/** @fn applyActionCode:completion: + @brief Applies out of band code. + + @param code The out of band code to be applied. + @param completion Optionally; a block which is invoked when the request finishes. Invoked + asynchronously on the main thread in the future. + + @remarks This method will not work for out of band codes which require an additional parameter, + such as password reset code. + */ +- (void)applyActionCode:(NSString *)code completion:(void (^)(NSError *_Nullable error))completion; + +/** @fn sendPasswordResetWithEmail:completion: + @brief Initiates a password reset for the given email address. + + @param email The email address of the user. + @param completion Optionally; a block which is invoked when the request finishes. Invoked + asynchronously on the main thread in the future. + + @remarks Possible error codes: + + + `AuthErrorCodeInvalidRecipientEmail` - Indicates an invalid recipient email was + sent in the request. + + `AuthErrorCodeInvalidSender` - Indicates an invalid sender email is set in + the console for this action. + + `AuthErrorCodeInvalidMessagePayload` - Indicates an invalid email template for + sending update email. + + + */ +- (void)sendPasswordResetWithEmail:(NSString *)email + completion:(nullable void (^)(NSError *_Nullable error))completion; + +/** @fn sendPasswordResetWithEmail:actionCodeSetting:completion: + @brief Initiates a password reset for the given email address and `ActionCodeSettings` object. + + @param email The email address of the user. + @param actionCodeSettings An `ActionCodeSettings` object containing settings related to + handling action codes. + @param completion Optionally; a block which is invoked when the request finishes. Invoked + asynchronously on the main thread in the future. + + @remarks Possible error codes: + + + `AuthErrorCodeInvalidRecipientEmail` - Indicates an invalid recipient email was + sent in the request. + + `AuthErrorCodeInvalidSender` - Indicates an invalid sender email is set in + the console for this action. + + `AuthErrorCodeInvalidMessagePayload` - Indicates an invalid email template for + sending update email. + + `AuthErrorCodeMissingIosBundleID` - Indicates that the iOS bundle ID is missing when + `handleCodeInApp` is set to true. + + `AuthErrorCodeMissingAndroidPackageName` - Indicates that the android package name + is missing when the `androidInstallApp` flag is set to true. + + `AuthErrorCodeUnauthorizedDomain` - Indicates that the domain specified in the + continue URL is not allowlisted in the Firebase console. + + `AuthErrorCodeInvalidContinueURI` - Indicates that the domain specified in the + continue URL is not valid. + + + */ +- (void)sendPasswordResetWithEmail:(NSString *)email + actionCodeSettings:(FIRActionCodeSettings *)actionCodeSettings + completion:(nullable void (^)(NSError *_Nullable error))completion; + +/** @fn sendSignInLinkToEmail:actionCodeSettings:completion: + @brief Sends a sign in with email link to provided email address. + + @param email The email address of the user. + @param actionCodeSettings An `ActionCodeSettings` object containing settings related to + handling action codes. + @param completion Optionally; a block which is invoked when the request finishes. Invoked + asynchronously on the main thread in the future. + */ +- (void)sendSignInLinkToEmail:(NSString *)email + actionCodeSettings:(FIRActionCodeSettings *)actionCodeSettings + completion:(nullable void (^)(NSError *_Nullable error))completion + API_UNAVAILABLE(watchos); + +/** @fn signOut: + @brief Signs out the current user. + + @param error Optionally; if an error occurs, upon return contains an NSError object that + describes the problem; is nil otherwise. + @return @YES when the sign out request was successful. @NO otherwise. + + @remarks Possible error codes: + + + `AuthErrorCodeKeychainError` - Indicates an error occurred when accessing the + keychain. The `NSLocalizedFailureReasonErrorKey` field in the `userInfo` + dictionary will contain more information about the error encountered. + + */ +- (BOOL)signOut:(NSError *_Nullable *_Nullable)error; + +/** @fn isSignInWithEmailLink + @brief Checks if link is an email sign-in link. + + @param link The email sign-in link. + @return Returns true when the link passed matches the expected format of an email sign-in link. + */ +- (BOOL)isSignInWithEmailLink:(NSString *)link API_UNAVAILABLE(watchos); + +/** @fn addAuthStateDidChangeListener: + @brief Registers a block as an "auth state did change" listener. To be invoked when: + + + The block is registered as a listener, + + A user with a different UID from the current user has signed in, or + + The current user has signed out. + + @param listener The block to be invoked. The block is always invoked asynchronously on the main + thread, even for it's initial invocation after having been added as a listener. + + @remarks The block is invoked immediately after adding it according to it's standard invocation + semantics, asynchronously on the main thread. Users should pay special attention to + making sure the block does not inadvertently retain objects which should not be retained by + the long-lived block. The block itself will be retained by `Auth` until it is + unregistered or until the `Auth` instance is otherwise deallocated. + + @return A handle useful for manually unregistering the block as a listener. + */ + +- (FIRAuthStateDidChangeListenerHandle)addAuthStateDidChangeListener: + (void (^)(FIRAuth *auth, FIRUser *_Nullable user))listener; + +/** @fn removeAuthStateDidChangeListener: + @brief Unregisters a block as an "auth state did change" listener. + + @param listenerHandle The handle for the listener. + */ +- (void)removeAuthStateDidChangeListener:(FIRAuthStateDidChangeListenerHandle)listenerHandle; + +/** @fn addIDTokenDidChangeListener: + @brief Registers a block as an "ID token did change" listener. To be invoked when: + + + The block is registered as a listener, + + A user with a different UID from the current user has signed in, + + The ID token of the current user has been refreshed, or + + The current user has signed out. + + @param listener The block to be invoked. The block is always invoked asynchronously on the main + thread, even for it's initial invocation after having been added as a listener. + + @remarks The block is invoked immediately after adding it according to it's standard invocation + semantics, asynchronously on the main thread. Users should pay special attention to + making sure the block does not inadvertently retain objects which should not be retained by + the long-lived block. The block itself will be retained by `Auth` until it is + unregistered or until the `Auth` instance is otherwise deallocated. + + @return A handle useful for manually unregistering the block as a listener. + */ +- (FIRIDTokenDidChangeListenerHandle)addIDTokenDidChangeListener: + (void (^)(FIRAuth *auth, FIRUser *_Nullable user))listener; + +/** @fn removeIDTokenDidChangeListener: + @brief Unregisters a block as an "ID token did change" listener. + + @param listenerHandle The handle for the listener. + */ +- (void)removeIDTokenDidChangeListener:(FIRIDTokenDidChangeListenerHandle)listenerHandle; + +/** @fn useAppLanguage + @brief Sets `languageCode` to the app's current language. + */ +- (void)useAppLanguage; + +/** @fn useEmulatorWithHost:port + @brief Configures Firebase Auth to connect to an emulated host instead of the remote backend. + */ +- (void)useEmulatorWithHost:(NSString *)host port:(NSInteger)port; + +/** @fn canHandleURL: + @brief Whether the specific URL is handled by `Auth` . + This method is available on iOS only. + @param URL The URL received by the application delegate from any of the openURL method. + @return Whether or the URL is handled. YES means the URL is for Firebase Auth + so the caller should ignore the URL from further processing, and NO means the + the URL is for the app (or another library) so the caller should continue handling + this URL as usual. + @remarks If swizzling is disabled, URLs received by the application delegate must be forwarded + to this method for phone number auth to work. + */ +- (BOOL)canHandleURL:(nonnull NSURL *)URL API_UNAVAILABLE(macos, tvos, watchos); + +/** @fn setAPNSToken:type: + @brief Sets the APNs token along with its type. + This method is available on iOS only. + @remarks If swizzling is disabled, the APNs Token must be set for phone number auth to work, + by either setting calling this method or by setting the `APNSToken` property. + */ +- (void)setAPNSToken:(NSData *)token + type:(FIRAuthAPNSTokenType)type API_UNAVAILABLE(macos, tvos, watchos); + +/** @fn canHandleNotification: + @brief Whether the specific remote notification is handled by `Auth` . + This method is available on iOS only. + @param userInfo A dictionary that contains information related to the + notification in question. + @return Whether or the notification is handled. A return value of true means the notification + is for Firebase Auth so the caller should ignore the notification from further processing, + and false means the notification is for the app (or another library) so the caller + should continue handling this notification as usual. + @remarks If swizzling is disabled, related remote notifications must be forwarded to this method + for phone number auth to work. + */ +- (BOOL)canHandleNotification:(NSDictionary *)userInfo API_UNAVAILABLE(macos, tvos, watchos); + +/** @fn revokeTokenWithAuthorizationCode:Completion + @brief Revoke the users token with authorization code. + @param completion (Optional) the block invoked when the request to revoke the token is + complete, or fails. Invoked asynchronously on the main thread in the future. + */ +- (void)revokeTokenWithAuthorizationCode:(NSString *)authorizationCode + completion:(nullable void (^)(NSError *_Nullable error))completion; + +#pragma mark - User sharing + +/** @fn useUserAccessGroup:error: + @brief Switch userAccessGroup and current user to the given accessGroup and the user stored in + it. + */ +- (BOOL)useUserAccessGroup:(NSString *_Nullable)accessGroup + error:(NSError *_Nullable *_Nullable)outError; + +/** @fn getStoredUserForAccessGroup:error: + @brief Get the stored user in the given accessGroup. + @note This API is not supported on tvOS when `shareAuthStateAcrossDevices` is set to `true`. + This case will return `nil`. + Please refer to https://github.com/firebase/firebase-ios-sdk/issues/8878 for details. + */ +- (nullable FIRUser *)getStoredUserForAccessGroup:(NSString *_Nullable)accessGroup + error:(NSError *_Nullable *_Nullable)outError + __attribute__((swift_error(nonnull_error))); // This method can return `nil` on success. + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthAPNSTokenType.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthAPNSTokenType.h new file mode 100644 index 0000000..95fc2df --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthAPNSTokenType.h @@ -0,0 +1,41 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** + * @brief The APNs token type for the app. + * This enum is available on iOS, macOS Catalyst, tvOS, and watchOS only. + */ +typedef NS_ENUM(NSInteger, FIRAuthAPNSTokenType) { + + /** Unknown token type. + The actual token type will be detected from the provisioning profile in the app's bundle. + */ + FIRAuthAPNSTokenTypeUnknown, + + /** Sandbox token type. + */ + FIRAuthAPNSTokenTypeSandbox, + + /** Production token type. + */ + FIRAuthAPNSTokenTypeProd, +} NS_SWIFT_NAME(AuthAPNSTokenType) API_UNAVAILABLE(macosx); + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthCredential.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthCredential.h new file mode 100644 index 0000000..106d844 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthCredential.h @@ -0,0 +1,41 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRAuthCredential + @brief Represents a credential. + */ +NS_SWIFT_NAME(AuthCredential) +@interface FIRAuthCredential : NSObject + +/** @property provider + @brief Gets the name of the identity provider for the credential. + */ +@property(nonatomic, copy, readonly) NSString *provider; + +/** @fn init + @brief This is an abstract base class. Concrete instances should be created via factory + methods available in the various authentication provider libraries (like the Facebook + provider or the Google provider libraries.) + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthDataResult.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthDataResult.h new file mode 100644 index 0000000..cae975a --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthDataResult.h @@ -0,0 +1,57 @@ +/* + * 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 + +@class FIRAdditionalUserInfo; +@class FIRAuthCredential; +@class FIRUser; + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRAuthDataResult + @brief Helper object that contains the result of a successful sign-in, link and reauthenticate + action. It contains references to a `User` instance and a `AdditionalUserInfo` instance. + */ +NS_SWIFT_NAME(AuthDataResult) +@interface FIRAuthDataResult : NSObject + +/** @fn init + @brief This class should not be initialized manually. `AuthDataResult` instance is + returned as part of `AuthDataResultCallback`. + */ +- (instancetype)init NS_UNAVAILABLE; + +/** @property user + @brief The signed in user. + */ +@property(nonatomic, readonly) FIRUser *user; + +/** @property additionalUserInfo + @brief If available contains the additional IdP specific information about signed in user. + */ +@property(nonatomic, readonly, nullable) FIRAdditionalUserInfo *additionalUserInfo; + +/** @property credential + @brief This property will be non-nil after a successful headful-lite sign-in via + `signIn(with:uiDelegate:completion:)`. May be used to obtain the accessToken and/or IDToken + pertaining to a recently signed-in user. + */ +@property(nonatomic, readonly, nullable) FIRAuthCredential *credential; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthErrors.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthErrors.h new file mode 100644 index 0000000..05b0376 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthErrors.h @@ -0,0 +1,441 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRAuthErrors + @remarks Error Codes common to all API Methods: + + + `AuthErrorCodeNetworkError` + + `AuthErrorCodeUserNotFound` + + `AuthErrorCodeUserTokenExpired` + + `AuthErrorCodeTooManyRequests` + + `AuthErrorCodeInvalidAPIKey` + + `AuthErrorCodeAppNotAuthorized` + + `AuthErrorCodeKeychainError` + + `AuthErrorCodeInternalError` + + @remarks Common error codes for `User` operations: + + + `AuthErrorCodeInvalidUserToken` + + `AuthErrorCodeUserDisabled` + + */ +NS_SWIFT_NAME(AuthErrors) +@interface FIRAuthErrors + +/** + @brief The Firebase Auth error domain. + */ +extern NSString *const FIRAuthErrorDomain NS_SWIFT_NAME(AuthErrorDomain); + +/** + @brief The name of the key for the error short string of an error code. + */ +extern NSString *const FIRAuthErrorUserInfoNameKey NS_SWIFT_NAME(AuthErrorUserInfoNameKey); + +/** + @brief Errors with one of the following three codes: + - `AuthErrorCodeAccountExistsWithDifferentCredential` + - `AuthErrorCodeCredentialAlreadyInUse` + - `AuthErrorCodeEmailAlreadyInUse` + may contain an `NSError.userInfo` dictinary object which contains this key. The value + associated with this key is an NSString of the email address of the account that already + exists. + */ +extern NSString *const FIRAuthErrorUserInfoEmailKey NS_SWIFT_NAME(AuthErrorUserInfoEmailKey); + +/** + @brief The key used to read the updated Auth credential from the userInfo dictionary of the + NSError object returned. This is the updated auth credential the developer should use for + recovery if applicable. + */ +// clang-format off +// clang-format12 will merge lines and exceed 100 character limit. +extern NSString *const FIRAuthErrorUserInfoUpdatedCredentialKey + NS_SWIFT_NAME(AuthErrorUserInfoUpdatedCredentialKey); + +/** + @brief The key used to read the MFA resolver from the userInfo dictionary of the NSError object + returned when 2FA is required for sign-incompletion. + */ +extern NSString *const FIRAuthErrorUserInfoMultiFactorResolverKey + NS_SWIFT_NAME(AuthErrorUserInfoMultiFactorResolverKey); +// clang-format on + +/** + @brief Error codes used by Firebase Auth. + */ +typedef NS_ERROR_ENUM(FIRAuthErrorDomain, FIRAuthErrorCode){ + /** Indicates a validation error with the custom token. + */ + FIRAuthErrorCodeInvalidCustomToken = 17000, + + /** Indicates the service account and the API key belong to different projects. + */ + FIRAuthErrorCodeCustomTokenMismatch = 17002, + + /** Indicates the IDP token or requestUri is invalid. + */ + FIRAuthErrorCodeInvalidCredential = 17004, + + /** Indicates the user's account is disabled on the server. + */ + FIRAuthErrorCodeUserDisabled = 17005, + + /** Indicates the administrator disabled sign in with the specified identity provider. + */ + FIRAuthErrorCodeOperationNotAllowed = 17006, + + /** Indicates the email used to attempt a sign up is already in use. + */ + FIRAuthErrorCodeEmailAlreadyInUse = 17007, + + /** Indicates the email is invalid. + */ + FIRAuthErrorCodeInvalidEmail = 17008, + + /** Indicates the user attempted sign in with a wrong password. + */ + FIRAuthErrorCodeWrongPassword = 17009, + + /** Indicates that too many requests were made to a server method. + */ + FIRAuthErrorCodeTooManyRequests = 17010, + + /** Indicates the user account was not found. + */ + FIRAuthErrorCodeUserNotFound = 17011, + + /** Indicates account linking is required. + */ + FIRAuthErrorCodeAccountExistsWithDifferentCredential = 17012, + + /** Indicates the user has attemped to change email or password more than 5 minutes after + signing in. + */ + FIRAuthErrorCodeRequiresRecentLogin = 17014, + + /** Indicates an attempt to link a provider to which the account is already linked. + */ + FIRAuthErrorCodeProviderAlreadyLinked = 17015, + + /** Indicates an attempt to unlink a provider that is not linked. + */ + FIRAuthErrorCodeNoSuchProvider = 17016, + + /** Indicates user's saved auth credential is invalid, the user needs to sign in again. + */ + FIRAuthErrorCodeInvalidUserToken = 17017, + + /** Indicates a network error occurred (such as a timeout, interrupted connection, or + unreachable host). These types of errors are often recoverable with a retry. The + `NSUnderlyingError` field in the `NSError.userInfo` dictionary will contain the error + encountered. + */ + FIRAuthErrorCodeNetworkError = 17020, + + /** Indicates the saved token has expired, for example, the user may have changed account + password on another device. The user needs to sign in again on the device that made this + request. + */ + FIRAuthErrorCodeUserTokenExpired = 17021, + + /** Indicates an invalid API key was supplied in the request. + */ + FIRAuthErrorCodeInvalidAPIKey = 17023, + + /** Indicates that an attempt was made to reauthenticate with a user which is not the current + user. + */ + FIRAuthErrorCodeUserMismatch = 17024, + + /** Indicates an attempt to link with a credential that has already been linked with a + different Firebase account + */ + FIRAuthErrorCodeCredentialAlreadyInUse = 17025, + + /** Indicates an attempt to set a password that is considered too weak. + */ + FIRAuthErrorCodeWeakPassword = 17026, + + /** Indicates the App is not authorized to use Firebase Authentication with the + provided API Key. + */ + FIRAuthErrorCodeAppNotAuthorized = 17028, + + /** Indicates the OOB code is expired. + */ + FIRAuthErrorCodeExpiredActionCode = 17029, + + /** Indicates the OOB code is invalid. + */ + FIRAuthErrorCodeInvalidActionCode = 17030, + + /** Indicates that there are invalid parameters in the payload during a "send password reset + * email" attempt. + */ + FIRAuthErrorCodeInvalidMessagePayload = 17031, + + /** Indicates that the sender email is invalid during a "send password reset email" attempt. + */ + FIRAuthErrorCodeInvalidSender = 17032, + + /** Indicates that the recipient email is invalid. + */ + FIRAuthErrorCodeInvalidRecipientEmail = 17033, + + /** Indicates that an email address was expected but one was not provided. + */ + FIRAuthErrorCodeMissingEmail = 17034, + + // The enum values 17035 is reserved and should NOT be used for new error codes. + + /** Indicates that the iOS bundle ID is missing when a iOS App Store ID is provided. + */ + FIRAuthErrorCodeMissingIosBundleID = 17036, + + /** Indicates that the android package name is missing when the `androidInstallApp` flag is set + to true. + */ + FIRAuthErrorCodeMissingAndroidPackageName = 17037, + + /** Indicates that the domain specified in the continue URL is not allowlisted in the Firebase + console. + */ + FIRAuthErrorCodeUnauthorizedDomain = 17038, + + /** Indicates that the domain specified in the continue URI is not valid. + */ + FIRAuthErrorCodeInvalidContinueURI = 17039, + + /** Indicates that a continue URI was not provided in a request to the backend which requires + one. + */ + FIRAuthErrorCodeMissingContinueURI = 17040, + + /** Indicates that a phone number was not provided in a call to + `verifyPhoneNumber:completion:`. + */ + FIRAuthErrorCodeMissingPhoneNumber = 17041, + + /** Indicates that an invalid phone number was provided in a call to + `verifyPhoneNumber:completion:`. + */ + FIRAuthErrorCodeInvalidPhoneNumber = 17042, + + /** Indicates that the phone auth credential was created with an empty verification code. + */ + FIRAuthErrorCodeMissingVerificationCode = 17043, + + /** Indicates that an invalid verification code was used in the verifyPhoneNumber request. + */ + FIRAuthErrorCodeInvalidVerificationCode = 17044, + + /** Indicates that the phone auth credential was created with an empty verification ID. + */ + FIRAuthErrorCodeMissingVerificationID = 17045, + + /** Indicates that an invalid verification ID was used in the verifyPhoneNumber request. + */ + FIRAuthErrorCodeInvalidVerificationID = 17046, + + /** Indicates that the APNS device token is missing in the verifyClient request. + */ + FIRAuthErrorCodeMissingAppCredential = 17047, + + /** Indicates that an invalid APNS device token was used in the verifyClient request. + */ + FIRAuthErrorCodeInvalidAppCredential = 17048, + + // The enum values between 17048 and 17051 are reserved and should NOT be used for new error + // codes. + + /** Indicates that the SMS code has expired. + */ + FIRAuthErrorCodeSessionExpired = 17051, + + /** Indicates that the quota of SMS messages for a given project has been exceeded. + */ + FIRAuthErrorCodeQuotaExceeded = 17052, + + /** Indicates that the APNs device token could not be obtained. The app may not have set up + remote notification correctly, or may fail to forward the APNs device token to Auth + if app delegate swizzling is disabled. + */ + FIRAuthErrorCodeMissingAppToken = 17053, + + /** Indicates that the app fails to forward remote notification to Auth. + */ + FIRAuthErrorCodeNotificationNotForwarded = 17054, + + /** Indicates that the app could not be verified by Firebase during phone number authentication. + */ + FIRAuthErrorCodeAppNotVerified = 17055, + + /** Indicates that the reCAPTCHA token is not valid. + */ + FIRAuthErrorCodeCaptchaCheckFailed = 17056, + + /** Indicates that an attempt was made to present a new web context while one was already being + presented. + */ + FIRAuthErrorCodeWebContextAlreadyPresented = 17057, + + /** Indicates that the URL presentation was cancelled prematurely by the user. + */ + FIRAuthErrorCodeWebContextCancelled = 17058, + + /** Indicates a general failure during the app verification flow. + */ + FIRAuthErrorCodeAppVerificationUserInteractionFailure = 17059, + + /** Indicates that the clientID used to invoke a web flow is invalid. + */ + FIRAuthErrorCodeInvalidClientID = 17060, + + /** Indicates that a network request within a SFSafariViewController or WKWebView failed. + */ + FIRAuthErrorCodeWebNetworkRequestFailed = 17061, + + /** Indicates that an internal error occurred within a SFSafariViewController or WKWebView. + */ + FIRAuthErrorCodeWebInternalError = 17062, + + /** Indicates a general failure during a web sign-in flow. + */ + FIRAuthErrorCodeWebSignInUserInteractionFailure = 17063, + + /** Indicates that the local player was not authenticated prior to attempting Game Center + signin. + */ + FIRAuthErrorCodeLocalPlayerNotAuthenticated = 17066, + + /** Indicates that a non-null user was expected as an argmument to the operation but a null + user was provided. + */ + FIRAuthErrorCodeNullUser = 17067, + + /** Indicates that a Firebase Dynamic Link is not activated. + */ + FIRAuthErrorCodeDynamicLinkNotActivated = 17068, + + /** + * Represents the error code for when the given provider id for a web operation is invalid. + */ + FIRAuthErrorCodeInvalidProviderID = 17071, + + /** + * Represents the error code for when an attempt is made to update the current user with a + * tenantId that differs from the current FirebaseAuth instance's tenantId. + */ + FIRAuthErrorCodeTenantIDMismatch = 17072, + + /** + * Represents the error code for when a request is made to the backend with an associated tenant + * ID for an operation that does not support multi-tenancy. + */ + FIRAuthErrorCodeUnsupportedTenantOperation = 17073, + + /** Indicates that the Firebase Dynamic Link domain used is either not configured or is + unauthorized for the current project. + */ + FIRAuthErrorCodeInvalidDynamicLinkDomain = 17074, + + /** Indicates that the credential is rejected because it's misformed or mismatching. + */ + FIRAuthErrorCodeRejectedCredential = 17075, + + /** Indicates that the GameKit framework is not linked prior to attempting Game Center signin. + */ + FIRAuthErrorCodeGameKitNotLinked = 17076, + + /** Indicates that the second factor is required for signin. + */ + FIRAuthErrorCodeSecondFactorRequired = 17078, + + /** Indicates that the multi factor session is missing. + */ + FIRAuthErrorCodeMissingMultiFactorSession = 17081, + + /** Indicates that the multi factor info is missing. + */ + FIRAuthErrorCodeMissingMultiFactorInfo = 17082, + + /** Indicates that the multi factor session is invalid. + */ + FIRAuthErrorCodeInvalidMultiFactorSession = 17083, + + /** Indicates that the multi factor info is not found. + */ + FIRAuthErrorCodeMultiFactorInfoNotFound = 17084, + + /** Indicates that the operation is admin restricted. + */ + FIRAuthErrorCodeAdminRestrictedOperation = 17085, + + /** Indicates that the email is required for verification. + */ + FIRAuthErrorCodeUnverifiedEmail = 17086, + + /** Indicates that the second factor is already enrolled. + */ + FIRAuthErrorCodeSecondFactorAlreadyEnrolled = 17087, + + /** Indicates that the maximum second factor count is exceeded. + */ + FIRAuthErrorCodeMaximumSecondFactorCountExceeded = 17088, + + /** Indicates that the first factor is not supported. + */ + FIRAuthErrorCodeUnsupportedFirstFactor = 17089, + + /** Indicates that the a verifed email is required to changed to. + */ + FIRAuthErrorCodeEmailChangeNeedsVerification = 17090, + + /** Indicates that the nonce is missing or invalid. + */ + FIRAuthErrorCodeMissingOrInvalidNonce = 17094, + + /** Raised when a Cloud Function returns a blocking error. Will include a message returned from + * the function. + */ + FIRAuthErrorCodeBlockingCloudFunctionError = 17105, + + /** Indicates an error for when the client identifier is missing. + */ + FIRAuthErrorCodeMissingClientIdentifier = 17993, + + /** Indicates an error occurred while attempting to access the keychain. + */ + FIRAuthErrorCodeKeychainError = 17995, + + /** Indicates an internal error occurred. + */ + FIRAuthErrorCodeInternalError = 17999, + + /** Raised when a JWT fails to parse correctly. May be accompanied by an underlying error + describing which step of the JWT parsing process failed. + */ + FIRAuthErrorCodeMalformedJWT = 18000, +} NS_SWIFT_NAME(AuthErrorCode); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthSettings.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthSettings.h new file mode 100644 index 0000000..1746627 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthSettings.h @@ -0,0 +1,35 @@ +/* + * 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. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRAuthSettings + @brief Determines settings related to an auth object. + */ +NS_SWIFT_NAME(AuthSettings) +@interface FIRAuthSettings : NSObject + +/** @property appVerificationDisabledForTesting + @brief Flag to determine whether app verification should be disabled for testing or not. + */ +@property(nonatomic, assign, getter=isAppVerificationDisabledForTesting) + BOOL appVerificationDisabledForTesting; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthTokenResult.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthTokenResult.h new file mode 100644 index 0000000..3c98c5f --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthTokenResult.h @@ -0,0 +1,69 @@ +/* + * 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. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRAuthTokenResult + @brief A data class containing the ID token JWT string and other properties associated with the + token including the decoded payload claims. + */ +NS_SWIFT_NAME(AuthTokenResult) +@interface FIRAuthTokenResult : NSObject + +/** @property token + @brief Stores the JWT string of the ID token. + */ +@property(nonatomic, readonly) NSString *token; + +/** @property expirationDate + @brief Stores the ID token's expiration date. + */ +@property(nonatomic, readonly) NSDate *expirationDate; + +/** @property authDate + @brief Stores the ID token's authentication date. + @remarks This is the date the user was signed in and NOT the date the token was refreshed. + */ +@property(nonatomic, readonly) NSDate *authDate; + +/** @property issuedAtDate + @brief Stores the date that the ID token was issued. + @remarks This is the date last refreshed and NOT the last authentication date. + */ +@property(nonatomic, readonly) NSDate *issuedAtDate; + +/** @property signInProvider + @brief Stores sign-in provider through which the token was obtained. + @remarks This does not necessarily map to provider IDs. + */ +@property(nonatomic, readonly) NSString *signInProvider; + +/** @property signInSecondFactor + @brief Stores sign-in second factor through which the token was obtained. + */ +@property(nonatomic, readonly) NSString *signInSecondFactor; + +/** @property claims + @brief Stores the entire payload of claims found on the ID token. This includes the standard + reserved claims as well as custom claims set by the developer via the Admin SDK. + */ +@property(nonatomic, readonly) NSDictionary *claims; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthUIDelegate.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthUIDelegate.h new file mode 100644 index 0000000..01ab83e --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthUIDelegate.h @@ -0,0 +1,54 @@ +/* + * 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 + +@class UIViewController; + +NS_ASSUME_NONNULL_BEGIN + +/** @protocol FIRAuthUIDelegate + @brief A protocol to handle user interface interactions for Firebase Auth. + This protocol is available on iOS, macOS Catalyst, and tvOS only. + */ +NS_SWIFT_NAME(AuthUIDelegate) API_UNAVAILABLE(macosx, watchos) @protocol FIRAuthUIDelegate + +/** @fn presentViewController:animated:completion: + @brief If implemented, this method will be invoked when Firebase Auth needs to display a view + controller. + @param viewControllerToPresent The view controller to be presented. + @param flag Decides whether the view controller presentation should be animated or not. + @param completion The block to execute after the presentation finishes. This block has no return + value and takes no parameters. +*/ +- (void)presentViewController:(UIViewController *)viewControllerToPresent + animated:(BOOL)flag + completion:(void (^_Nullable)(void))completion; + +/** @fn dismissViewControllerAnimated:completion: + @brief If implemented, this method will be invoked when Firebase Auth needs to display a view + controller. + @param flag Decides whether removing the view controller should be animated or not. + @param completion The block to execute after the presentation finishes. This block has no return + value and takes no parameters. +*/ +- (void)dismissViewControllerAnimated:(BOOL)flag + completion:(void (^_Nullable)(void))completion + NS_SWIFT_NAME(dismiss(animated:completion:)); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIREmailAuthProvider.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIREmailAuthProvider.h new file mode 100644 index 0000000..0153a22 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIREmailAuthProvider.h @@ -0,0 +1,73 @@ +/* + * 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 + +@class FIRAuthCredential; + +NS_ASSUME_NONNULL_BEGIN + +/** + @brief A string constant identifying the email & password identity provider. + */ +extern NSString *const FIREmailAuthProviderID NS_SWIFT_NAME(EmailAuthProviderID); + +/** + @brief A string constant identifying the email-link sign-in method. + */ +extern NSString *const FIREmailLinkAuthSignInMethod NS_SWIFT_NAME(EmailLinkAuthSignInMethod); + +/** + @brief A string constant identifying the email & password sign-in method. + */ +// clang-format off +// clang-format12 merges the next two lines. +extern NSString *const FIREmailPasswordAuthSignInMethod + NS_SWIFT_NAME(EmailPasswordAuthSignInMethod); +// clang-format on + +/** @class FIREmailAuthProvider + @brief A concrete implementation of `AuthProvider` for Email & Password Sign In. + */ +NS_SWIFT_NAME(EmailAuthProvider) +@interface FIREmailAuthProvider : NSObject + +/** @fn credentialWithEmail:password: + @brief Creates an `AuthCredential` for an email & password sign in. + + @param email The user's email address. + @param password The user's password. + @return An `AuthCredential` containing the email & password credential. + */ ++ (FIRAuthCredential *)credentialWithEmail:(NSString *)email password:(NSString *)password; + +/** @fn credentialWithEmail:Link: + @brief Creates an `AuthCredential` for an email & link sign in. + + @param email The user's email address. + @param link The email sign-in link. + @return An `AuthCredential` containing the email & link credential. + */ ++ (FIRAuthCredential *)credentialWithEmail:(NSString *)email link:(NSString *)link; + +/** @fn init + @brief This class is not meant to be initialized directly. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRFacebookAuthProvider.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRFacebookAuthProvider.h new file mode 100644 index 0000000..33a9c4e --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRFacebookAuthProvider.h @@ -0,0 +1,54 @@ +/* + * 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 + +@class FIRAuthCredential; + +NS_ASSUME_NONNULL_BEGIN + +/** + @brief A string constant identifying the Facebook identity provider. + */ +extern NSString *const FIRFacebookAuthProviderID NS_SWIFT_NAME(FacebookAuthProviderID); + +/** + @brief A string constant identifying the Facebook sign-in method. + */ +extern NSString *const _Nonnull FIRFacebookAuthSignInMethod NS_SWIFT_NAME(FacebookAuthSignInMethod); + +/** @class FIRFacebookAuthProvider + @brief Utility class for constructing Facebook credentials. + */ +NS_SWIFT_NAME(FacebookAuthProvider) +@interface FIRFacebookAuthProvider : NSObject + +/** @fn credentialWithAccessToken: + @brief Creates an `AuthCredential` for a Facebook sign in. + + @param accessToken The access token from Facebook. + @return An `AuthCredential` containing the Facebook credentials. + */ ++ (FIRAuthCredential *)credentialWithAccessToken:(NSString *)accessToken; + +/** @fn init + @brief This class should not be initialized. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRFederatedAuthProvider.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRFederatedAuthProvider.h new file mode 100644 index 0000000..ff81ed4 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRFederatedAuthProvider.h @@ -0,0 +1,54 @@ +/* + * 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 + +#import "FIRAuthUIDelegate.h" + +@class FIRAuthCredential; + +NS_ASSUME_NONNULL_BEGIN + +/** + Utility type for constructing federated auth provider credentials. + */ +NS_SWIFT_NAME(FederatedAuthProvider) +@protocol FIRFederatedAuthProvider + +/** @typedef FIRAuthCredentialCallback + @brief The type of block invoked when obtaining an auth credential. + @param credential The credential obtained. + @param error The error that occurred if any. + */ +typedef void (^FIRAuthCredentialCallback)(FIRAuthCredential *_Nullable credential, + NSError *_Nullable error) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/** @fn getCredentialWithUIDelegate:completion: + @brief Used to obtain an auth credential via a mobile web flow. + This method is available on iOS only. + @param UIDelegate An optional UI delegate used to present the mobile web flow. + @param completion Optionally; a block which is invoked asynchronously on the main thread when + the mobile web flow is completed. + */ +- (void)getCredentialWithUIDelegate:(nullable id)UIDelegate + completion:(nullable void (^)(FIRAuthCredential *_Nullable credential, + NSError *_Nullable error))completion + API_UNAVAILABLE(macos, tvos, watchos); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRGameCenterAuthProvider.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRGameCenterAuthProvider.h new file mode 100644 index 0000000..f8043e0 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRGameCenterAuthProvider.h @@ -0,0 +1,65 @@ +/* + * 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. + */ + +#import + +@class FIRAuthCredential; + +NS_ASSUME_NONNULL_BEGIN + +/** + @brief A string constant identifying the Game Center identity provider. + */ +extern NSString *const FIRGameCenterAuthProviderID NS_SWIFT_NAME(GameCenterAuthProviderID); + +/** + @brief A string constant identifying the Game Center sign-in method. + */ +extern NSString *const _Nonnull FIRGameCenterAuthSignInMethod NS_SWIFT_NAME( + GameCenterAuthSignInMethod); + +/** @typedef FIRGameCenterCredentialCallback + @brief The type of block invoked when the Game Center credential code has finished. + @param credential On success, the credential will be provided, nil otherwise. + @param error On error, the error that occurred, nil otherwise. + */ +typedef void (^FIRGameCenterCredentialCallback)(FIRAuthCredential *_Nullable credential, + NSError *_Nullable error) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/** @class FIRGameCenterAuthProvider + @brief A concrete implementation of `AuthProvider` for Game Center Sign In. Not available on + watchOS. + */ +API_UNAVAILABLE(watchos) +NS_SWIFT_NAME(GameCenterAuthProvider) +@interface FIRGameCenterAuthProvider : NSObject + +/** @fn getCredentialWithCompletion: + @brief Creates an `AuthCredential` for a Game Center sign in. + */ ++ (void)getCredentialWithCompletion: + (void (^)(FIRAuthCredential *_Nullable credential, NSError *_Nullable error))completion + NS_SWIFT_NAME(getCredential(completion:)); + +/** @fn init + @brief This class is not meant to be initialized. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRGitHubAuthProvider.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRGitHubAuthProvider.h new file mode 100644 index 0000000..389214f --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRGitHubAuthProvider.h @@ -0,0 +1,54 @@ +/* + * 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 + +@class FIRAuthCredential; + +NS_ASSUME_NONNULL_BEGIN + +/** + @brief A string constant identifying the GitHub identity provider. + */ +extern NSString *const FIRGitHubAuthProviderID NS_SWIFT_NAME(GitHubAuthProviderID); + +/** + @brief A string constant identifying the GitHub sign-in method. + */ +extern NSString *const _Nonnull FIRGitHubAuthSignInMethod NS_SWIFT_NAME(GitHubAuthSignInMethod); + +/** @class FIRGitHubAuthProvider + @brief Utility class for constructing GitHub credentials. + */ +NS_SWIFT_NAME(GitHubAuthProvider) +@interface FIRGitHubAuthProvider : NSObject + +/** @fn credentialWithToken: + @brief Creates an `AuthCredential` for a GitHub sign in. + + @param token The GitHub OAuth access token. + @return An AuthCredential containing the GitHub credential. + */ ++ (FIRAuthCredential *)credentialWithToken:(NSString *)token; + +/** @fn init + @brief This class is not meant to be initialized. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRGoogleAuthProvider.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRGoogleAuthProvider.h new file mode 100644 index 0000000..dd5c9e9 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRGoogleAuthProvider.h @@ -0,0 +1,56 @@ +/* + * 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 + +@class FIRAuthCredential; + +NS_ASSUME_NONNULL_BEGIN + +/** + @brief A string constant identifying the Google identity provider. + */ +extern NSString *const FIRGoogleAuthProviderID NS_SWIFT_NAME(GoogleAuthProviderID); + +/** + @brief A string constant identifying the Google sign-in method. + */ +extern NSString *const _Nonnull FIRGoogleAuthSignInMethod NS_SWIFT_NAME(GoogleAuthSignInMethod); + +/** @class FIRGoogleAuthProvider + @brief Utility class for constructing Google Sign In credentials. + */ +NS_SWIFT_NAME(GoogleAuthProvider) +@interface FIRGoogleAuthProvider : NSObject + +/** @fn credentialWithIDToken:accessToken: + @brief Creates an `AuthCredential` for a Google sign in. + + @param IDToken The ID Token from Google. + @param accessToken The Access Token from Google. + @return An AuthCredential containing the Google credentials. + */ ++ (FIRAuthCredential *)credentialWithIDToken:(NSString *)IDToken + accessToken:(NSString *)accessToken; + +/** @fn init + @brief This class should not be initialized. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactor.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactor.h new file mode 100644 index 0000000..713bbfe --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactor.h @@ -0,0 +1,90 @@ +/* + * Copyright 2019 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/LICENSE2.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 + +#import "FIRAuth.h" +#import "FIRMultiFactorAssertion.h" +#import "FIRMultiFactorInfo.h" +#import "FIRMultiFactorSession.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRMultiFactorSessionCallback + @brief The callback that triggered when a developer calls `getSessionWithCompletion`. + This type is available on iOS only. + @param session The multi factor session returned, if any. + @param error The error which occurred, if any. +*/ +typedef void (^FIRMultiFactorSessionCallback)(FIRMultiFactorSession *_Nullable session, + NSError *_Nullable error) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead.") + API_UNAVAILABLE(macos, tvos, watchos); + +/** + @brief The string identifier for second factors. e.g. "phone". + This constant is available on iOS only. +*/ +extern NSString *const _Nonnull FIRPhoneMultiFactorID NS_SWIFT_NAME(PhoneMultiFactorID) + API_UNAVAILABLE(macos, tvos, watchos); + +/** @class FIRMultiFactor + @brief The interface defining the multi factor related properties and operations pertaining to a + user. + This class is available on iOS only. +*/ +NS_SWIFT_NAME(MultiFactor) API_UNAVAILABLE(macos, tvos, watchos) @interface FIRMultiFactor + : NSObject + +@property(nonatomic, readonly) NSArray *enrolledFactors; + +/** @fn getSessionWithCompletion: + @brief Get a session for a second factor enrollment operation. + @param completion A block with the session identifier for a second factor enrollment operation. + This is used to identify the current user trying to enroll a second factor. +*/ +- (void)getSessionWithCompletion:(nullable void (^)(FIRMultiFactorSession *_Nullable credential, + NSError *_Nullable error))completion; + +/** @fn enrollWithAssertion:displayName:completion: + @brief Enrolls a second factor as identified by the `MultiFactorAssertion` parameter for the + current user. + @param displayName An optional display name associated with the multi factor to enroll. + @param completion The block invoked when the request is complete, or fails. +*/ +- (void)enrollWithAssertion:(FIRMultiFactorAssertion *)assertion + displayName:(nullable NSString *)displayName + completion:(nullable void (^)(NSError *_Nullable error))completion; + +/** @fn unenrollWithInfo:completion: + @brief Unenroll the given multi factor. + @param completion The block invoked when the request to send the verification email is complete, + or fails. +*/ +- (void)unenrollWithInfo:(FIRMultiFactorInfo *)factorInfo + completion:(nullable void (^)(NSError *_Nullable error))completion; + +/** @fn unenrollWithFactorUID:completion: + @brief Unenroll the given multi factor. + @param completion The block invoked when the request to send the verification email is complete, + or fails. +*/ +- (void)unenrollWithFactorUID:(NSString *)factorUID + completion:(nullable void (^)(NSError *_Nullable error))completion; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorAssertion.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorAssertion.h new file mode 100644 index 0000000..f3bc340 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorAssertion.h @@ -0,0 +1,36 @@ +/* + * Copyright 2019 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/LICENSE2.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 + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRMultiFactorAssertion + @brief The base class for asserting ownership of a second factor. This is equivalent to the + AuthCredential class. + This class is available on iOS only. +*/ +NS_SWIFT_NAME(MultiFactorAssertion) API_UNAVAILABLE(macos, tvos, watchos) + @interface FIRMultiFactorAssertion : NSObject + +/** + @brief The second factor identifier for this opaque object asserting a second factor. +*/ +@property(nonatomic, readonly, nonnull) NSString *factorID; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorInfo.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorInfo.h new file mode 100644 index 0000000..8c02660 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorInfo.h @@ -0,0 +1,50 @@ +/* + * Copyright 2019 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/LICENSE2.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 + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRMultiFactorInfo + @brief Safe public structure used to represent a second factor entity from a client perspective. + This class is available on iOS only. +*/ +NS_SWIFT_NAME(MultiFactorInfo) API_UNAVAILABLE(macos, tvos, watchos) @interface FIRMultiFactorInfo + : NSObject + +/** + @brief The multi-factor enrollment ID. +*/ +@property(nonatomic, readonly) NSString *UID; + +/** + @brief The user friendly name of the current second factor. +*/ +@property(nonatomic, readonly, nullable) NSString *displayName; + +/** + @brief The second factor enrollment date. +*/ +@property(nonatomic, readonly) NSDate *enrollmentDate; + +/** + @brief The identifier of the second factor. +*/ +@property(nonatomic, readonly) NSString *factorID; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorResolver.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorResolver.h new file mode 100644 index 0000000..6a102c5 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorResolver.h @@ -0,0 +1,56 @@ +/* + * Copyright 2019 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/LICENSE2.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 "FIRMultiFactor.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRMultiFactorResolver + @brief The data structure used to help developers resolve 2nd factor requirements on users that + have opted in to 2 factor authentication. + This class is available on iOS only. +*/ +NS_SWIFT_NAME(MultiFactorResolver) API_UNAVAILABLE(macos, tvos, watchos) + @interface FIRMultiFactorResolver : NSObject + +/** + @brief The opaque session identifier for the current sign-in flow. +*/ +@property(nonatomic, readonly) FIRMultiFactorSession *session; + +/** + @brief The list of hints for the second factors needed to complete the sign-in for the current + session. +*/ +@property(nonatomic, readonly) NSArray *hints NS_SWIFT_NAME(hints); + +/** + @brief The Auth reference for the current FIRMultiResolver. +*/ +@property(nonatomic, readonly) FIRAuth *auth; + +/** @fn resolveSignInWithAssertion:completion: + @brief A helper function to help users complete sign in with a second factor using an + FIRMultiFactorAssertion confirming the user successfully completed the second factor + challenge. + @param completion The block invoked when the request is complete, or fails. +*/ +- (void)resolveSignInWithAssertion:(FIRMultiFactorAssertion *)assertion + completion:(nullable FIRAuthDataResultCallback)completion; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorSession.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorSession.h new file mode 100644 index 0000000..1b64b28 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorSession.h @@ -0,0 +1,31 @@ +/* + * Copyright 2019 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/LICENSE2.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 + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRMultiFactorSession + @brief Opaque object that identifies the current session to enroll a second factor or to + complete sign in when previously enrolled. + This class is available on iOS only. + */ +NS_SWIFT_NAME(MultiFactorSession) API_UNAVAILABLE(macos, tvos, watchos) + @interface FIRMultiFactorSession : NSObject + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIROAuthCredential.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIROAuthCredential.h new file mode 100644 index 0000000..94abe4f --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIROAuthCredential.h @@ -0,0 +1,53 @@ +/* + * 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 + +#import "FIRAuthCredential.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIROAuthCredential + @brief Internal implementation of FIRAuthCredential for generic credentials. + */ +NS_SWIFT_NAME(OAuthCredential) +@interface FIROAuthCredential : FIRAuthCredential + +/** @property IDToken + @brief The ID Token associated with this credential. + */ +@property(nonatomic, readonly, nullable) NSString *IDToken; + +/** @property accessToken + @brief The access token associated with this credential. + */ +@property(nonatomic, readonly, nullable) NSString *accessToken; + +/** @property secret + @brief The secret associated with this credential. This will be nil for OAuth 2.0 providers. + @detail OAuthCredential already exposes a providerId getter. This will help the developer + determine whether an access token/secret pair is needed. + */ +@property(nonatomic, readonly, nullable) NSString *secret; + +/** @fn init + @brief This class is not supposed to be instantiated directly. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIROAuthProvider.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIROAuthProvider.h new file mode 100644 index 0000000..2c2128c --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIROAuthProvider.h @@ -0,0 +1,140 @@ +/* + * 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 + +#import "FIRFederatedAuthProvider.h" + +@class FIRAuth; +@class FIROAuthCredential; + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIROAuthProvider + @brief A concrete implementation of `AuthProvider` for generic OAuth Providers. + */ +NS_SWIFT_NAME(OAuthProvider) +@interface FIROAuthProvider : NSObject + +/** @property scopes + @brief Array used to configure the OAuth scopes. + */ +@property(nonatomic, copy, nullable) NSArray *scopes; + +/** @property customParameters + @brief Dictionary used to configure the OAuth custom parameters. + */ +@property(nonatomic, copy, nullable) NSDictionary *customParameters; + +/** @property providerID + @brief The provider ID indicating the specific OAuth provider this OAuthProvider instance + represents. + */ +@property(nonatomic, copy, readonly) NSString *providerID; + +/** @fn providerWithProviderID: + @param providerID The provider ID of the IDP for which this auth provider instance will be + configured. + @return An instance of `OAuthProvider` corresponding to the specified provider ID. + */ ++ (FIROAuthProvider *)providerWithProviderID:(NSString *)providerID; + +/** @fn providerWithProviderID:auth: + @param providerID The provider ID of the IDP for which this auth provider instance will be + configured. + @param auth The auth instance to be associated with the `OAuthProvider` instance. + @return An instance of `OAuthProvider` corresponding to the specified provider ID. + */ ++ (FIROAuthProvider *)providerWithProviderID:(NSString *)providerID auth:(FIRAuth *)auth; + +/** @fn credentialWithProviderID:IDToken:accessToken: + @brief Creates an `AuthCredential` for the OAuth 2 provider identified by provider ID, ID + token, and access token. + + @param providerID The provider ID associated with the Auth credential being created. + @param IDToken The IDToken associated with the Auth credential being created. + @param accessToken The access token associated with the Auth credential be created, if + available. + @return A `AuthCredential` for the specified provider ID, ID token and access token. + */ ++ (FIROAuthCredential *)credentialWithProviderID:(NSString *)providerID + IDToken:(NSString *)IDToken + accessToken:(nullable NSString *)accessToken; + +/** @fn credentialWithProviderID:accessToken: + @brief Creates an `AuthCredential` for the OAuth 2 provider identified by provider ID using + an ID token. + + @param providerID The provider ID associated with the Auth credential being created. + @param accessToken The access token associated with the Auth credential be created + @return An `AuthCredential`. + */ ++ (FIROAuthCredential *)credentialWithProviderID:(NSString *)providerID + accessToken:(NSString *)accessToken; + +/** @fn credentialWithProviderID:IDToken:rawNonce:accessToken: + @brief Creates an `AuthCredential` for that OAuth 2 provider identified by provider ID, ID + token, raw nonce, and access token. + + @param providerID The provider ID associated with the Auth credential being created. + @param IDToken The IDToken associated with the Auth credential being created. + @param rawNonce The raw nonce associated with the Auth credential being created. + @param accessToken The access token associated with the Auth credential be created, if + available. + @return A `AuthCredential` for the specified provider ID, ID token and access token. + */ ++ (FIROAuthCredential *)credentialWithProviderID:(NSString *)providerID + IDToken:(NSString *)IDToken + rawNonce:(nullable NSString *)rawNonce + accessToken:(nullable NSString *)accessToken; + +/** @fn credentialWithProviderID:IDToken:rawNonce: + @brief Creates an `AuthCredential` for that OAuth 2 provider identified by providerID using + an ID token and raw nonce. + + @param providerID The provider ID associated with the Auth credential being created. + @param IDToken The IDToken associated with the Auth credential being created. + @param rawNonce The raw nonce associated with the Auth credential being created. + @return A `AuthCredential`. + */ ++ (FIROAuthCredential *)credentialWithProviderID:(NSString *)providerID + IDToken:(NSString *)IDToken + rawNonce:(nullable NSString *)rawNonce; + +/** @fn appleCredentialWithIDToken:rawNonce:fullName: + * @brief Creates an `AuthCredential` for the Sign in with Apple OAuth 2 provider identified by ID + * token, raw nonce, and full name. This method is specific to the Sign in with Apple OAuth 2 + * provider as this provider requires the full name to be passed explicitly. + * + * @param IDToken The IDToken associated with the Sign in with Apple Auth credential being created. + * @param rawNonce The raw nonce associated with the Sign in with Apple Auth credential being + * created. + * @param fullName The full name associated with the Sign in with Apple Auth credential being + * created. + * @return An `AuthCredential`. + */ ++ (FIROAuthCredential *)appleCredentialWithIDToken:(NSString *)IDToken + rawNonce:(nullable NSString *)rawNonce + fullName:(nullable NSPersonNameComponents *)fullName; + +/** @fn init + @brief This class is not meant to be initialized. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthCredential.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthCredential.h new file mode 100644 index 0000000..deea1dd --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthCredential.h @@ -0,0 +1,37 @@ +/* + * 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 + +#import "FIRAuthCredential.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRPhoneAuthCredential + @brief Implementation of FIRAuthCredential for Phone Auth credentials. + This class is available on iOS only. + */ +NS_SWIFT_NAME(PhoneAuthCredential) API_UNAVAILABLE(macos, tvos, watchos) + @interface FIRPhoneAuthCredential : FIRAuthCredential + +/** @fn init + @brief This class is not supposed to be instantiated directly. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthProvider.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthProvider.h new file mode 100644 index 0000000..2e4ee1c --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthProvider.h @@ -0,0 +1,147 @@ +/* + * 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 + +@class FIRAuth; +@class FIRMultiFactorSession; +@class FIRPhoneAuthCredential; +@class FIRPhoneMultiFactorInfo; +@protocol FIRAuthUIDelegate; + +NS_ASSUME_NONNULL_BEGIN + +/** @var FIRPhoneAuthProviderID + @brief A string constant identifying the phone identity provider. + This constant is available on iOS only. + */ +extern NSString *const FIRPhoneAuthProviderID NS_SWIFT_NAME(PhoneAuthProviderID) + API_UNAVAILABLE(macos, tvos, watchos); + +/** @var FIRPhoneAuthProviderID + @brief A string constant identifying the phone sign-in method. + This constant is available on iOS only. + */ +extern NSString *const _Nonnull FIRPhoneAuthSignInMethod NS_SWIFT_NAME(PhoneAuthSignInMethod) + API_UNAVAILABLE(macos, tvos, watchos); + +/** @typedef FIRVerificationResultCallback + @brief The type of block invoked when a request to send a verification code has finished. + This type is available on iOS only. + + @param verificationID On success, the verification ID provided, nil otherwise. + @param error On error, the error that occurred, nil otherwise. + */ +typedef void (^FIRVerificationResultCallback)(NSString *_Nullable verificationID, + NSError *_Nullable error) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead.") + API_UNAVAILABLE(macos, tvos, watchos); + +/** @class FIRPhoneAuthProvider + @brief A concrete implementation of `AuthProvider` for phone auth providers. + This class is available on iOS only. + */ +NS_SWIFT_NAME(PhoneAuthProvider) API_UNAVAILABLE(macos, tvos, watchos) + @interface FIRPhoneAuthProvider : NSObject + +/** @fn provider + @brief Returns an instance of `PhoneAuthProvider` for the default `Auth` object. + */ ++ (instancetype)provider NS_SWIFT_NAME(provider()); + +/** @fn providerWithAuth: + @brief Returns an instance of `PhoneAuthProvider` for the provided `Auth` object. + @param auth The auth object to associate with the phone auth provider instance. + */ ++ (instancetype)providerWithAuth:(FIRAuth *)auth NS_SWIFT_NAME(provider(auth:)); + +/** @fn verifyPhoneNumber:UIDelegate:completion: + @brief Starts the phone number authentication flow by sending a verification code to the + specified phone number. + @param phoneNumber The phone number to be verified. + @param UIDelegate An object used to present the SFSafariViewController. The object is retained + by this method until the completion block is executed. + @param completion The callback to be invoked when the verification flow is finished. + @remarks Possible error codes: + + + `AuthErrorCodeCaptchaCheckFailed` - Indicates that the reCAPTCHA token obtained by + the Firebase Auth is invalid or has expired. + + `AuthErrorCodeQuotaExceeded` - Indicates that the phone verification quota for this + project has been exceeded. + + `AuthErrorCodeInvalidPhoneNumber` - Indicates that the phone number provided is + invalid. + + `AuthErrorCodeMissingPhoneNumber` - Indicates that a phone number was not provided. + */ +- (void)verifyPhoneNumber:(NSString *)phoneNumber + UIDelegate:(nullable id)UIDelegate + completion:(nullable void (^)(NSString *_Nullable verificationID, + NSError *_Nullable error))completion; + +/** @fn verifyPhoneNumber:UIDelegate:multiFactorSession:completion: + @brief Verify ownership of the second factor phone number by the current user. + @param phoneNumber The phone number to be verified. + @param UIDelegate An object used to present the SFSafariViewController. The object is retained + by this method until the completion block is executed. + @param session A session to identify the MFA flow. For enrollment, this identifies the user + trying to enroll. For sign-in, this identifies that the user already passed the first + factor challenge. + @param completion The callback to be invoked when the verification flow is finished. +*/ +- (void)verifyPhoneNumber:(NSString *)phoneNumber + UIDelegate:(nullable id)UIDelegate + multiFactorSession:(nullable FIRMultiFactorSession *)session + completion:(nullable void (^)(NSString *_Nullable verificationID, + NSError *_Nullable error))completion; + +/** @fn verifyPhoneNumberWithMultiFactorInfo:UIDelegate:multiFactorSession:completion: + @brief Verify ownership of the second factor phone number by the current user. + @param phoneMultiFactorInfo The phone multi factor whose number need to be verified. + @param UIDelegate An object used to present the SFSafariViewController. The object is retained + by this method until the completion block is executed. + @param session A session to identify the MFA flow. For enrollment, this identifies the user + trying to enroll. For sign-in, this identifies that the user already passed the first + factor challenge. + @param completion The callback to be invoked when the verification flow is finished. +*/ +- (void)verifyPhoneNumberWithMultiFactorInfo:(FIRPhoneMultiFactorInfo *)phoneMultiFactorInfo + UIDelegate:(nullable id)UIDelegate + multiFactorSession:(nullable FIRMultiFactorSession *)session + completion: + (nullable void (^)(NSString *_Nullable verificationID, + NSError *_Nullable error))completion; + +/** @fn credentialWithVerificationID:verificationCode: + @brief Creates an `AuthCredential` for the phone number provider identified by the + verification ID and verification code. + + @param verificationID The verification ID obtained from invoking + verifyPhoneNumber:completion: + @param verificationCode The verification code obtained from the user. + @return The corresponding phone auth credential for the verification ID and verification code + provided. + */ +- (FIRPhoneAuthCredential *)credentialWithVerificationID:(NSString *)verificationID + verificationCode:(NSString *)verificationCode; + +/** @fn init + @brief Please use the `provider()` or `provider(auth:)` methods to obtain an instance of + `PhoneAuthProvider`. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorAssertion.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorAssertion.h new file mode 100644 index 0000000..13e6a42 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorAssertion.h @@ -0,0 +1,33 @@ +/* + * Copyright 2019 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/LICENSE2.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 + +#import "FIRMultiFactorAssertion.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRPhoneMultiFactorAssertion + @brief The subclass of base class FIRMultiFactorAssertion, used to assert ownership of a phone + second factor. + This class is available on iOS only. +*/ +NS_SWIFT_NAME(PhoneMultiFactorAssertion) API_UNAVAILABLE(macos, tvos, watchos) + @interface FIRPhoneMultiFactorAssertion : FIRMultiFactorAssertion + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorGenerator.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorGenerator.h new file mode 100644 index 0000000..355b927 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorGenerator.h @@ -0,0 +1,43 @@ +/* + * Copyright 2019 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/LICENSE2.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 + +#import "FIRPhoneAuthCredential.h" +#import "FIRPhoneMultiFactorAssertion.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRPhoneMultiFactorGenerator + @brief The data structure used to help initialize an assertion for a second factor entity to the + Firebase Auth/CICP server. Depending on the type of second factor, this will help generate + the assertion. + This class is available on iOS only. +*/ +NS_SWIFT_NAME(PhoneMultiFactorGenerator) API_UNAVAILABLE(macos, tvos, watchos) + @interface FIRPhoneMultiFactorGenerator : NSObject + +/** @fn assertionWithCredential: + @brief Initializes the MFA assertion to confirm ownership of the phone second factor. Note that + this API is used for both enrolling and signing in with a phone second factor. + @param phoneAuthCredential The phone auth credential used for multi factor flows. +*/ ++ (FIRPhoneMultiFactorAssertion *)assertionWithCredential: + (FIRPhoneAuthCredential *)phoneAuthCredential; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorInfo.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorInfo.h new file mode 100644 index 0000000..fe119ef --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorInfo.h @@ -0,0 +1,38 @@ +/* + * Copyright 2019 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/LICENSE2.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 + +#import "FIRMultiFactorInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRPhoneMultiFactorInfo + @brief Extends the MultiFactorInfo class for phone number second factors. + The identifier of this second factor is "phone". + This class is available on iOS only. +*/ +NS_SWIFT_NAME(PhoneMultiFactorInfo) API_UNAVAILABLE(macos, tvos, watchos) + @interface FIRPhoneMultiFactorInfo : FIRMultiFactorInfo + +/** + @brief This is the phone number associated with the current second factor. +*/ +@property(nonatomic, readonly, nonnull) NSString *phoneNumber; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRTwitterAuthProvider.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRTwitterAuthProvider.h new file mode 100644 index 0000000..850199f --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRTwitterAuthProvider.h @@ -0,0 +1,54 @@ +/* + * 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 + +@class FIRAuthCredential; + +NS_ASSUME_NONNULL_BEGIN + +/** + @brief A string constant identifying the Twitter identity provider. + */ +extern NSString *const FIRTwitterAuthProviderID NS_SWIFT_NAME(TwitterAuthProviderID); +/** + @brief A string constant identifying the Twitter sign-in method. + */ +extern NSString *const _Nonnull FIRTwitterAuthSignInMethod NS_SWIFT_NAME(TwitterAuthSignInMethod); + +/** @class FIRTwitterAuthProvider + @brief Utility class for constructing Twitter credentials. + */ +NS_SWIFT_NAME(TwitterAuthProvider) +@interface FIRTwitterAuthProvider : NSObject + +/** @fn credentialWithToken:secret: + @brief Creates an `AuthCredential` for a Twitter sign in. + + @param token The Twitter OAuth token. + @param secret The Twitter OAuth secret. + @return An AuthCredential containing the Twitter credential. + */ ++ (FIRAuthCredential *)credentialWithToken:(NSString *)token secret:(NSString *)secret; + +/** @fn init + @brief This class is not meant to be initialized. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRUser.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRUser.h new file mode 100644 index 0000000..9fb1fbb --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRUser.h @@ -0,0 +1,550 @@ +/* + * 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 + +#import "FIRAuth.h" +#import "FIRAuthDataResult.h" +#import "FIRMultiFactor.h" +#import "FIRUserInfo.h" + +@class FIRAuthTokenResult; +@class FIRPhoneAuthCredential; +@class FIRUserProfileChangeRequest; +@class FIRUserMetadata; +@protocol FIRAuthUIDelegate; + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRAuthTokenCallback + @brief The type of block called when a token is ready for use. + @see `User.getIDToken()` + @see `User.idTokenForcingRefresh(_:)` + + @param token Optionally; an access token if the request was successful. + @param error Optionally; the error which occurred - or nil if the request was successful. + + @remarks One of `token` or `error` will always be non-nil. + */ +typedef void (^FIRAuthTokenCallback)(NSString *_Nullable token, NSError *_Nullable error) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/** @typedef FIRAuthTokenResultCallback + @brief The type of block called when a token is ready for use. + @see `User.getIDToken()` + @see `User.idTokenForcingRefresh(_:)` + + @param tokenResult Optionally; an object containing the raw access token string as well as other + useful data pertaining to the token. + @param error Optionally; the error which occurred - or nil if the request was successful. + + @remarks One of `token` or `error` will always be non-nil. + */ +typedef void (^FIRAuthTokenResultCallback)(FIRAuthTokenResult *_Nullable tokenResult, + NSError *_Nullable error) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/** @typedef FIRUserProfileChangeCallback + @brief The type of block called when a user profile change has finished. + + @param error Optionally; the error which occurred - or nil if the request was successful. + */ +typedef void (^FIRUserProfileChangeCallback)(NSError *_Nullable error) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/** @typedef FIRSendEmailVerificationCallback + @brief The type of block called when a request to send an email verification has finished. + + @param error Optionally; the error which occurred - or nil if the request was successful. + */ +typedef void (^FIRSendEmailVerificationCallback)(NSError *_Nullable error) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/** @class FIRUser + @brief Represents a user. Firebase Auth does not attempt to validate users + when loading them from the keychain. Invalidated users (such as those + whose passwords have been changed on another client) are automatically + logged out when an auth-dependent operation is attempted or when the + ID token is automatically refreshed. + @remarks This class is thread-safe. + */ +NS_SWIFT_NAME(User) +@interface FIRUser : NSObject + +/** @property anonymous + @brief Indicates the user represents an anonymous user. + */ +@property(nonatomic, readonly, getter=isAnonymous) BOOL anonymous; + +/** @property emailVerified + @brief Indicates the email address associated with this user has been verified. + */ +@property(nonatomic, readonly, getter=isEmailVerified) BOOL emailVerified; + +/** @property refreshToken + @brief A refresh token; useful for obtaining new access tokens independently. + @remarks This property should only be used for advanced scenarios, and is not typically needed. + */ +@property(nonatomic, readonly, nullable) NSString *refreshToken; + +/** @property providerData + @brief Profile data for each identity provider, if any. + @remarks This data is cached on sign-in and updated when linking or unlinking. + */ +@property(nonatomic, readonly, nonnull) NSArray> *providerData; + +/** @property metadata + @brief Metadata associated with the Firebase user in question. + */ +@property(nonatomic, readonly, nonnull) FIRUserMetadata *metadata; + +/** @property tenantID + @brief The tenant ID of the current user. nil if none is available. + */ +@property(nonatomic, readonly, nullable) NSString *tenantID; + +/** @property multiFactor + @brief Multi factor object associated with the user. + This property is available on iOS only. +*/ +@property(nonatomic, readonly, nonnull) + FIRMultiFactor *multiFactor API_UNAVAILABLE(macos, tvos, watchos); + +/** @fn init + @brief This class should not be instantiated. + @remarks To retrieve the current user, use `Auth.currentUser`. To sign a user + in or out, use the methods on `Auth`. + */ +- (instancetype)init NS_UNAVAILABLE; + +/** @fn updateEmail:completion: + @brief Updates the email address for the user. On success, the cached user profile data is + updated. + @remarks May fail if there is already an account with this email address that was created using + email and password authentication. + + @param email The email address for the user. + @param completion Optionally; the block invoked when the user profile change has finished. + Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: + + + `AuthErrorCodeInvalidRecipientEmail` - Indicates an invalid recipient email was + sent in the request. + + `AuthErrorCodeInvalidSender` - Indicates an invalid sender email is set in + the console for this action. + + `AuthErrorCodeInvalidMessagePayload` - Indicates an invalid email template for + sending update email. + + `AuthErrorCodeEmailAlreadyInUse` - Indicates the email is already in use by another + account. + + `AuthErrorCodeInvalidEmail` - Indicates the email address is malformed. + + `AuthErrorCodeRequiresRecentLogin` - Updating a user’s email is a security + sensitive operation that requires a recent login from the user. This error indicates + the user has not signed in recently enough. To resolve, reauthenticate the user by + calling `reauthenticate(with:)`. + + @remarks See `AuthErrors` for a list of error codes that are common to all `User` methods. + */ +- (void)updateEmail:(NSString *)email + completion:(nullable void (^)(NSError *_Nullable error))completion + NS_SWIFT_NAME(updateEmail(to:completion:)); + +/** @fn updatePassword:completion: + @brief Updates the password for the user. On success, the cached user profile data is updated. + + @param password The new password for the user. + @param completion Optionally; the block invoked when the user profile change has finished. + Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: + + + `AuthErrorCodeOperationNotAllowed` - Indicates the administrator disabled + sign in with the specified identity provider. + + `AuthErrorCodeRequiresRecentLogin` - Updating a user’s password is a security + sensitive operation that requires a recent login from the user. This error indicates + the user has not signed in recently enough. To resolve, reauthenticate the user by + calling `reauthenticate(with:)`. + + `AuthErrorCodeWeakPassword` - Indicates an attempt to set a password that is + considered too weak. The `NSLocalizedFailureReasonErrorKey` field in the `userInfo` + dictionary object will contain more detailed explanation that can be shown to the user. + + @remarks See `AuthErrors` for a list of error codes that are common to all `User` methods. + */ +- (void)updatePassword:(NSString *)password + completion:(nullable void (^)(NSError *_Nullable error))completion + NS_SWIFT_NAME(updatePassword(to:completion:)); + +/** @fn updatePhoneNumberCredential:completion: + @brief Updates the phone number for the user. On success, the cached user profile data is + updated. + This method is available on iOS only. + + @param phoneNumberCredential The new phone number credential corresponding to the phone number + to be added to the Firebase account, if a phone number is already linked to the account this + new phone number will replace it. + @param completion Optionally; the block invoked when the user profile change has finished. + Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: + + + `AuthErrorCodeRequiresRecentLogin` - Updating a user’s phone number is a security + sensitive operation that requires a recent login from the user. This error indicates + the user has not signed in recently enough. To resolve, reauthenticate the user by + calling `reauthenticate(with:)`. + + @remarks See `AuthErrors` for a list of error codes that are common to all `User` methods. + */ +- (void)updatePhoneNumberCredential:(FIRPhoneAuthCredential *)phoneNumberCredential + completion:(nullable void (^)(NSError *_Nullable error))completion + API_UNAVAILABLE(macos, tvos, watchos); + +/** @fn profileChangeRequest + @brief Creates an object which may be used to change the user's profile data. + + @remarks Set the properties of the returned object, then call + `UserProfileChangeRequest.commitChanges()` to perform the updates atomically. + + @return An object which may be used to change the user's profile data atomically. + */ +- (FIRUserProfileChangeRequest *)profileChangeRequest NS_SWIFT_NAME(createProfileChangeRequest()); + +/** @fn reloadWithCompletion: + @brief Reloads the user's profile data from the server. + + @param completion Optionally; the block invoked when the reload has finished. Invoked + asynchronously on the main thread in the future. + + @remarks May fail with a `AuthErrorCodeRequiresRecentLogin` error code. In this case + you should call `reauthenticate(with:)` before re-invoking + `updateEmail(to:)`. + + @remarks See `AuthErrors` for a list of error codes that are common to all API methods. + */ +- (void)reloadWithCompletion:(nullable void (^)(NSError *_Nullable error))completion; + +/** @fn reauthenticateWithCredential:completion: + @brief Renews the user's authentication tokens by validating a fresh set of credentials supplied + by the user and returns additional identity provider data. + + @param credential A user-supplied credential, which will be validated by the server. This can be + a successful third-party identity provider sign-in, or an email address and password. + @param completion Optionally; the block invoked when the re-authentication operation has + finished. Invoked asynchronously on the main thread in the future. + + @remarks If the user associated with the supplied credential is different from the current user, + or if the validation of the supplied credentials fails; an error is returned and the current + user remains signed in. + + @remarks Possible error codes: + + + `AuthErrorCodeInvalidCredential` - Indicates the supplied credential is invalid. + This could happen if it has expired or it is malformed. + + `AuthErrorCodeOperationNotAllowed` - Indicates that accounts with the + identity provider represented by the credential are not enabled. Enable them in the + Auth section of the Firebase console. + + `AuthErrorCodeEmailAlreadyInUse` - Indicates the email asserted by the credential + (e.g. the email in a Facebook access token) is already in use by an existing account, + that cannot be authenticated with this method. Call `Auth.fetchSignInMethods(forEmail:)` + for this user’s email and then prompt them to sign in with any of the sign-in providers + returned. This error will only be thrown if the "One account per email address" + setting is enabled in the Firebase console, under Auth settings. Please note that the + error code raised in this specific situation may not be the same on Web and Android. + + `AuthErrorCodeUserDisabled` - Indicates the user's account is disabled. + + `AuthErrorCodeWrongPassword` - Indicates the user attempted reauthentication with + an incorrect password, if credential is of the type `EmailPasswordAuthCredential`. + + `AuthErrorCodeUserMismatch` - Indicates that an attempt was made to + reauthenticate with a user which is not the current user. + + `AuthErrorCodeInvalidEmail` - Indicates the email address is malformed. + + @remarks See `FIRAuthErrors` for a list of error codes that are common to all API methods. + */ +- (void)reauthenticateWithCredential:(FIRAuthCredential *)credential + completion:(nullable void (^)(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error))completion; + +/** @fn reauthenticateWithProvider:UIDelegate:completion: + @brief Renews the user's authentication using the provided auth provider instance. + This method is available on iOS, macOS Catalyst, and tvOS only. + + @param provider An instance of an auth provider used to initiate the reauthenticate flow. + @param UIDelegate Optionally an instance of a class conforming to the `AuthUIDelegate` + protocol, used for presenting the web context. If nil, a default `AuthUIDelegate` + will be used. + @param completion Optionally; a block which is invoked when the reauthenticate flow finishes, or + is canceled. Invoked asynchronously on the main thread in the future. + */ +- (void)reauthenticateWithProvider:(id)provider + UIDelegate:(nullable id)UIDelegate + completion:(nullable void (^)(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error))completion + NS_SWIFT_NAME(reauthenticate(with:uiDelegate:completion:))API_UNAVAILABLE(macosx, watchos); + +/** @fn getIDTokenResultWithCompletion: + @brief Retrieves the Firebase authentication token, possibly refreshing it if it has expired. + + @param completion Optionally; the block invoked when the token is available. Invoked + asynchronously on the main thread in the future. + + @remarks See `AuthErrors` for a list of error codes that are common to all API methods. + */ +- (void)getIDTokenResultWithCompletion:(nullable void (^)(FIRAuthTokenResult *_Nullable tokenResult, + NSError *_Nullable error))completion + NS_SWIFT_NAME(getIDTokenResult(completion:)); + +/** @fn getIDTokenResultForcingRefresh:completion: + @brief Retrieves the Firebase authentication token, possibly refreshing it if it has expired. + + @param forceRefresh Forces a token refresh. Useful if the token becomes invalid for some reason + other than an expiration. + @param completion Optionally; the block invoked when the token is available. Invoked + asynchronously on the main thread in the future. + + @remarks The authentication token will be refreshed (by making a network request) if it has + expired, or if `forceRefresh` is YES. + + @remarks See `AuthErrors` for a list of error codes that are common to all API methods. + */ +- (void)getIDTokenResultForcingRefresh:(BOOL)forceRefresh + completion:(nullable void (^)(FIRAuthTokenResult *_Nullable tokenResult, + NSError *_Nullable error))completion + NS_SWIFT_NAME(getIDTokenResult(forcingRefresh:completion:)); + +/** @fn getIDTokenWithCompletion: + @brief Retrieves the Firebase authentication token, possibly refreshing it if it has expired. + + @param completion Optionally; the block invoked when the token is available. Invoked + asynchronously on the main thread in the future. + + @remarks See `AuthErrors` for a list of error codes that are common to all API methods. + */ +- (void)getIDTokenWithCompletion: + (nullable void (^)(NSString *_Nullable token, NSError *_Nullable error))completion + NS_SWIFT_NAME(getIDToken(completion:)); + +/** @fn getIDTokenForcingRefresh:completion: + @brief Retrieves the Firebase authentication token, possibly refreshing it if it has expired. + + @param forceRefresh Forces a token refresh. Useful if the token becomes invalid for some reason + other than an expiration. + @param completion Optionally; the block invoked when the token is available. Invoked + asynchronously on the main thread in the future. + + @remarks The authentication token will be refreshed (by making a network request) if it has + expired, or if `forceRefresh` is true. + + @remarks See `AuthErrors` for a list of error codes that are common to all API methods. + */ +- (void)getIDTokenForcingRefresh:(BOOL)forceRefresh + completion:(nullable void (^)(NSString *_Nullable token, + NSError *_Nullable error))completion; + +/** @fn linkWithCredential:completion: + @brief Associates a user account from a third-party identity provider with this user and + returns additional identity provider data. + + @param credential The credential for the identity provider. + @param completion Optionally; the block invoked when the unlinking is complete, or fails. + Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: + + + `AuthErrorCodeProviderAlreadyLinked` - Indicates an attempt to link a provider of a + type already linked to this account. + + `AuthErrorCodeCredentialAlreadyInUse` - Indicates an attempt to link with a + credential that has already been linked with a different Firebase account. + + `AuthErrorCodeOperationNotAllowed` - Indicates that accounts with the identity + provider represented by the credential are not enabled. Enable them in the Auth section + of the Firebase console. + + @remarks This method may also return error codes associated with `updateEmail(to:)` and + `updatePassword(to:)` on `User`. + + @remarks See `AuthErrors` for a list of error codes that are common to all `User` methods. + */ +- (void)linkWithCredential:(FIRAuthCredential *)credential + completion:(nullable void (^)(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error))completion; + +/** @fn linkWithProvider:UIDelegate:completion: + @brief link the user with the provided auth provider instance. + This method is available on iOS, macOS Catalyst, and tvOS only. + + @param provider An instance of an auth provider used to initiate the link flow. + @param UIDelegate Optionally an instance of a class conforming to the `AuthUIDelegate` + protocol used for presenting the web context. If nil, a default `AuthUIDelegate` + will be used. + @param completion Optionally; a block which is invoked when the link flow finishes, or + is canceled. Invoked asynchronously on the main thread in the future. + */ +- (void)linkWithProvider:(id)provider + UIDelegate:(nullable id)UIDelegate + completion:(nullable void (^)(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error))completion + NS_SWIFT_NAME(link(with:uiDelegate:completion:))API_UNAVAILABLE(macosx, watchos); + +/** @fn unlinkFromProvider:completion: + @brief Disassociates a user account from a third-party identity provider with this user. + + @param provider The provider ID of the provider to unlink. + @param completion Optionally; the block invoked when the unlinking is complete, or fails. + Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: + + + `AuthErrorCodeNoSuchProvider` - Indicates an attempt to unlink a provider + that is not linked to the account. + + `AuthErrorCodeRequiresRecentLogin` - Updating email is a security sensitive + operation that requires a recent login from the user. This error indicates the user + has not signed in recently enough. To resolve, reauthenticate the user by calling + `reauthenticate(with:)`. + + @remarks See `AuthErrors` for a list of error codes that are common to all `User` methods. + */ +- (void)unlinkFromProvider:(NSString *)provider + completion:(nullable void (^)(FIRUser *_Nullable user, + NSError *_Nullable error))completion; + +/** @fn sendEmailVerificationWithCompletion: + @brief Initiates email verification for the user. + + @param completion Optionally; the block invoked when the request to send an email verification + is complete, or fails. Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: + + + `AuthErrorCodeInvalidRecipientEmail` - Indicates an invalid recipient email was + sent in the request. + + `AuthErrorCodeInvalidSender` - Indicates an invalid sender email is set in + the console for this action. + + `AuthErrorCodeInvalidMessagePayload` - Indicates an invalid email template for + sending update email. + + `AuthErrorCodeUserNotFound` - Indicates the user account was not found. + + @remarks See `AuthErrors` for a list of error codes that are common to all `User` methods. + */ +- (void)sendEmailVerificationWithCompletion:(nullable void (^)(NSError *_Nullable error))completion; + +/** @fn sendEmailVerificationWithActionCodeSettings:completion: + @brief Initiates email verification for the user. + + @param actionCodeSettings An `ActionCodeSettings` object containing settings related to + handling action codes. + + @remarks Possible error codes: + + + `AuthErrorCodeInvalidRecipientEmail` - Indicates an invalid recipient email was + sent in the request. + + `AuthErrorCodeInvalidSender` - Indicates an invalid sender email is set in + the console for this action. + + `AuthErrorCodeInvalidMessagePayload` - Indicates an invalid email template for + sending update email. + + `AuthErrorCodeUserNotFound` - Indicates the user account was not found. + + `AuthErrorCodeMissingIosBundleID` - Indicates that the iOS bundle ID is missing when + a iOS App Store ID is provided. + + `AuthErrorCodeMissingAndroidPackageName` - Indicates that the android package name + is missing when the `androidInstallApp` flag is set to true. + + `AuthErrorCodeUnauthorizedDomain` - Indicates that the domain specified in the + continue URL is not allowlisted in the Firebase console. + + `AuthErrorCodeInvalidContinueURI` - Indicates that the domain specified in the + continue URL is not valid. + */ +- (void)sendEmailVerificationWithActionCodeSettings:(FIRActionCodeSettings *)actionCodeSettings + completion:(nullable void (^)(NSError *_Nullable error)) + completion; + +/** @fn deleteWithCompletion: + @brief Deletes the user account (also signs out the user, if this was the current user). + + @param completion Optionally; the block invoked when the request to delete the account is + complete, or fails. Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: + + + `AuthErrorCodeRequiresRecentLogin` - Updating email is a security sensitive + operation that requires a recent login from the user. This error indicates the user + has not signed in recently enough. To resolve, reauthenticate the user by calling + `reauthenticate(with:)`. + + @remarks See `AuthErrors` for a list of error codes that are common to all `User` methods. + + */ +- (void)deleteWithCompletion:(nullable void (^)(NSError *_Nullable error))completion; + +/** @fn sendEmailVerificationBeforeUpdatingEmail:completion: + @brief Send an email to verify the ownership of the account then update to the new email. + @param email The email to be updated to. + @param completion Optionally; the block invoked when the request to send the verification + email is complete, or fails. +*/ +- (void)sendEmailVerificationBeforeUpdatingEmail:(nonnull NSString *)email + completion: + (nullable void (^)(NSError *_Nullable error))completion; + +/** @fn sendEmailVerificationBeforeUpdatingEmail:completion: + @brief Send an email to verify the ownership of the account then update to the new email. + @param email The email to be updated to. + @param actionCodeSettings An `ActionCodeSettings` object containing settings related to + handling action codes. + @param completion Optionally; the block invoked when the request to send the verification + email is complete, or fails. +*/ +- (void)sendEmailVerificationBeforeUpdatingEmail:(nonnull NSString *)email + actionCodeSettings:(nonnull FIRActionCodeSettings *)actionCodeSettings + completion: + (nullable void (^)(NSError *_Nullable error))completion; + +@end + +/** @class FIRUserProfileChangeRequest + @brief Represents an object capable of updating a user's profile data. + @remarks Properties are marked as being part of a profile update when they are set. Setting a + property value to nil is not the same as leaving the property unassigned. + */ +NS_SWIFT_NAME(UserProfileChangeRequest) +@interface FIRUserProfileChangeRequest : NSObject + +/** @fn init + @brief Please use `User.createProfileChangeRequest()` instead. + */ +- (instancetype)init NS_UNAVAILABLE; + +/** @property displayName + @brief The user's display name. + @remarks It is an error to set this property after calling + `commitChanges()`. + */ +@property(nonatomic, copy, nullable) NSString *displayName; + +/** @property photoURL + @brief The user's photo URL. + @remarks It is an error to set this property after calling + `commitChanges()`. + */ +@property(nonatomic, copy, nullable) NSURL *photoURL; + +/** @fn commitChangesWithCompletion: + @brief Commits any pending changes. + @remarks This method should only be called once. Once called, property values should not be + changed. + + @param completion Optionally; the block invoked when the user profile change has been applied. + Invoked asynchronously on the main thread in the future. + */ +- (void)commitChangesWithCompletion:(nullable void (^)(NSError *_Nullable error))completion; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRUserInfo.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRUserInfo.h new file mode 100644 index 0000000..04eca49 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRUserInfo.h @@ -0,0 +1,60 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** + @brief Represents user data returned from an identity provider. + */ +NS_SWIFT_NAME(UserInfo) +@protocol FIRUserInfo + +/** @property providerID + @brief The provider identifier. + */ +@property(nonatomic, copy, readonly) NSString *providerID; + +/** @property uid + @brief The provider's user ID for the user. + */ +@property(nonatomic, copy, readonly) NSString *uid; + +/** @property displayName + @brief The name of the user. + */ +@property(nonatomic, copy, readonly, nullable) NSString *displayName; + +/** @property photoURL + @brief The URL of the user's profile photo. + */ +@property(nonatomic, copy, readonly, nullable) NSURL *photoURL; + +/** @property email + @brief The user's email address. + */ +@property(nonatomic, copy, readonly, nullable) NSString *email; + +/** @property phoneNumber + @brief A phone number associated with the user. + @remarks This property is only available for users authenticated via phone number auth. + */ +@property(nonatomic, readonly, nullable) NSString *phoneNumber; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRUserMetadata.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRUserMetadata.h new file mode 100644 index 0000000..3ceae38 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FIRUserMetadata.h @@ -0,0 +1,45 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRUserMetadata + @brief A data class representing the metadata corresponding to a Firebase user. + */ +NS_SWIFT_NAME(UserMetadata) +@interface FIRUserMetadata : NSObject + +/** @property lastSignInDate + @brief Stores the last sign in date for the corresponding Firebase user. + */ +@property(copy, nonatomic, readonly, nullable) NSDate *lastSignInDate; + +/** @property creationDate + @brief Stores the creation date for the corresponding Firebase user. + */ +@property(copy, nonatomic, readonly, nullable) NSDate *creationDate; + +/** @fn init + @brief This class should not be initialized manually, an instance of this class can be obtained + from a Firebase user object. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FirebaseAuth.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FirebaseAuth.h new file mode 100644 index 0000000..3d922b2 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Public/FirebaseAuth/FirebaseAuth.h @@ -0,0 +1,51 @@ +/* + * 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 + +#import "FIRActionCodeSettings.h" +#import "FIRAdditionalUserInfo.h" +#import "FIRAuth.h" +#import "FIRAuthCredential.h" +#import "FIRAuthDataResult.h" +#import "FIRAuthErrors.h" +#import "FIRAuthTokenResult.h" +#import "FIREmailAuthProvider.h" +#import "FIRFacebookAuthProvider.h" +#import "FIRFederatedAuthProvider.h" +#import "FIRGameCenterAuthProvider.h" +#import "FIRGitHubAuthProvider.h" +#import "FIRGoogleAuthProvider.h" +#import "FIRMultiFactor.h" +#import "FIRMultiFactorAssertion.h" +#import "FIRMultiFactorInfo.h" +#import "FIRMultiFactorResolver.h" +#import "FIRMultiFactorSession.h" +#import "FIROAuthCredential.h" +#import "FIROAuthProvider.h" +#import "FIRTwitterAuthProvider.h" +#import "FIRUser.h" +#import "FIRUserInfo.h" +#import "FIRUserMetadata.h" + +#import "FIRAuthAPNSTokenType.h" +#import "FIRAuthSettings.h" +#import "FIRAuthUIDelegate.h" +#import "FIRPhoneAuthCredential.h" +#import "FIRPhoneAuthProvider.h" +#import "FIRPhoneMultiFactorAssertion.h" +#import "FIRPhoneMultiFactorGenerator.h" +#import "FIRPhoneMultiFactorInfo.h" diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Storage/FIRAuthKeychainServices.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Storage/FIRAuthKeychainServices.h new file mode 100644 index 0000000..ff7c05d --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Storage/FIRAuthKeychainServices.h @@ -0,0 +1,99 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** + @brief The protocol for permanant data storage. + */ +@protocol FIRAuthStorage + +/** @fn initWithService: + @brief Initialize a @c FIRAuthStorage instance. + @param service The name of the storage service to use. + @return An initialized @c FIRAuthStorage instance for the specified service. + */ +- (id)initWithService:(NSString *)service; + +/** @fn dataForKey:error: + @brief Gets the data for @c key in the storage. The key is set for the attribute + @c kSecAttrAccount of a generic password query. + @param key The key to use. + @param error The address to store any error that occurs during the process, if not NULL. + If the operation was successful, its content is set to @c nil . + @return The data stored in the storage for @c key, if any. + */ +- (nullable NSData *)dataForKey:(NSString *)key error:(NSError **_Nullable)error; + +/** @fn setData:forKey:error: + @brief Sets the data for @c key in the storage. The key is set for the attribute + @c kSecAttrAccount of a generic password query. + @param data The data to store. + @param key The key to use. + @param error The address to store any error that occurs during the process, if not NULL. + @return Whether the operation succeeded or not. + */ +- (BOOL)setData:(NSData *)data forKey:(NSString *)key error:(NSError **_Nullable)error; + +/** @fn removeDataForKey:error: + @brief Removes the data for @c key in the storage. The key is set for the attribute + @c kSecAttrAccount of a generic password query. + @param key The key to use. + @param error The address to store any error that occurs during the process, if not NULL. + @return Whether the operation succeeded or not. + */ +- (BOOL)removeDataForKey:(NSString *)key error:(NSError **_Nullable)error; + +@end + +/** @class FIRAuthKeychain + @brief The utility class to manipulate data in iOS Keychain. + */ +@interface FIRAuthKeychainServices : NSObject + +/** @fn getItemWithQuery:error: + @brief Get the item from keychain by given query. + @param query The query to query the keychain. + @param outError The address to store any error that occurs during the process, if not nil. + @return The item of the given query. nil if not exsit. + */ +- (nullable NSData *)getItemWithQuery:(NSDictionary *)query + error:(NSError *_Nullable *_Nullable)outError; + +/** @fn setItem:withQuery:error: + @brief Set the item into keychain with given query. + @param item The item to be added into keychain. + @param query The query to query the keychain. + @param outError The address to store any error that occurs during the process, if not nil. + @return Whether the operation succeed. + */ +- (BOOL)setItem:(NSData *)item + withQuery:(NSDictionary *)query + error:(NSError *_Nullable *_Nullable)outError; + +/** @fn getItemWithQuery:error: + @brief Remove the item with given queryfrom keychain. + @param query The query to query the keychain. + @param outError The address to store any error that occurs during the process, if not nil. + @return Whether the operation succeed. + */ +- (BOOL)removeItemWithQuery:(NSDictionary *)query error:(NSError *_Nullable *_Nullable)outError; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Storage/FIRAuthKeychainServices.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Storage/FIRAuthKeychainServices.m new file mode 100644 index 0000000..0ebb4cd --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Storage/FIRAuthKeychainServices.m @@ -0,0 +1,359 @@ +/* + * 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 "FirebaseAuth/Sources/Storage/FIRAuthKeychainServices.h" + +#import + +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" + +#import "FirebaseAuth/Sources/Auth/FIRAuth_Internal.h" +#import "FirebaseAuth/Sources/Storage/FIRAuthUserDefaults.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h" + +/** @var kAccountPrefix + @brief The prefix string for keychain item account attribute before the key. + @remarks A number "1" is encoded in the prefix in case we need to upgrade the scheme in future. + */ +static NSString *const kAccountPrefix = @"firebase_auth_1_"; + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRAuthKeychainServices { + /** @var _service + @brief The name of the keychain service. + */ + NSString *_service; + + /** @var _legacyItemDeletedForKey + @brief Indicates whether or not this class knows that the legacy item for a particular key has + been deleted. + @remarks This dictionary is to avoid unecessary keychain operations against legacy items. + */ + NSMutableDictionary *_legacyEntryDeletedForKey; +} + +- (id)initWithService:(NSString *)service { + self = [super init]; + if (self) { + _service = [service copy]; + _legacyEntryDeletedForKey = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (nullable NSData *)dataForKey:(NSString *)key error:(NSError **_Nullable)error { + if (!key.length) { + [NSException raise:NSInvalidArgumentException format:@"%@", @"The key cannot be nil or empty."]; + return nil; + } + NSData *data = [self itemWithQuery:[self genericPasswordQueryWithKey:key] error:error]; + if (error && *error) { + return nil; + } + if (data) { + return data; + } + // Check for legacy form. + if (_legacyEntryDeletedForKey[key]) { + return nil; + } + data = [self itemWithQuery:[self legacyGenericPasswordQueryWithKey:key] error:error]; + if (error && *error) { + return nil; + } + if (!data) { + // Mark legacy data as non-existing so we don't have to query it again. + _legacyEntryDeletedForKey[key] = @YES; + return nil; + } + // Move the data to current form. + if (![self setData:data forKey:key error:error]) { + return nil; + } + [self deleteLegacyItemWithKey:key]; + return data; +} + +- (BOOL)setData:(NSData *)data forKey:(NSString *)key error:(NSError **_Nullable)error { + if (!key.length) { + [NSException raise:NSInvalidArgumentException format:@"%@", @"The key cannot be nil or empty."]; + return NO; + } + NSDictionary *attributes = @{ + (__bridge id)kSecValueData : data, + (__bridge id)kSecAttrAccessible : (__bridge id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, + }; + return [self setItemWithQuery:[self genericPasswordQueryWithKey:key] + attributes:attributes + error:error]; +} + +- (BOOL)removeDataForKey:(NSString *)key error:(NSError **_Nullable)error { + if (!key.length) { + [NSException raise:NSInvalidArgumentException format:@"%@", @"The key cannot be nil or empty."]; + return NO; + } + if (![self deleteItemWithQuery:[self genericPasswordQueryWithKey:key] error:error]) { + return NO; + } + // Legacy form item, if exists, also needs to be removed, otherwise it will be exposed when + // current form item is removed, leading to incorrect semantics. + [self deleteLegacyItemWithKey:key]; + return YES; +} + +#pragma mark - Private methods for non-sharing keychain operations + +- (nullable NSData *)itemWithQuery:(NSDictionary *)query error:(NSError **_Nullable)error { + NSMutableDictionary *returningQuery = [query mutableCopy]; + returningQuery[(__bridge id)kSecReturnData] = @YES; + returningQuery[(__bridge id)kSecReturnAttributes] = @YES; + // Using a match limit of 2 means that we can check whether there is more than one item. + // If we used a match limit of 1 we would never find out. + returningQuery[(__bridge id)kSecMatchLimit] = @2; + + CFArrayRef result = NULL; + OSStatus status = + SecItemCopyMatching((__bridge CFDictionaryRef)returningQuery, (CFTypeRef *)&result); + + if (status == noErr && result != NULL) { + NSArray *items = (__bridge_transfer NSArray *)result; + if (items.count == 0) { + if (error) { + // The keychain query returned no error, but there were no items found. + *error = [FIRAuthErrorUtils keychainErrorWithFunction:@"SecItemCopyMatching" status:status]; + } + return nil; + } else if (items.count > 1) { + // More than one keychain item was found, all but the first will be ignored. + FIRLogWarning( + kFIRLoggerAuth, @"I-AUT000005", + @"Keychain query returned multiple results, all but the first will be ignored: %@", + items); + } + + if (error) { + *error = nil; + } + // Return the non-legacy item. + for (NSDictionary *item in items) { + if (item[(__bridge NSString *)kSecAttrService] != nil) { + return item[(__bridge id)kSecValueData]; + } + } + + // If they were all legacy items, just return the first one. + // This should not happen, since only one account should be + // stored. + return items[0][(__bridge id)kSecValueData]; + } + + if (status == errSecItemNotFound) { + if (error) { + *error = nil; + } + } else { + if (error) { + *error = [FIRAuthErrorUtils keychainErrorWithFunction:@"SecItemCopyMatching" status:status]; + } + } + return nil; +} + +- (BOOL)setItemWithQuery:(NSDictionary *)query + attributes:(NSDictionary *)attributes + error:(NSError **_Nullable)error { + NSMutableDictionary *combined = [attributes mutableCopy]; + [combined addEntriesFromDictionary:query]; + BOOL hasItem = NO; + OSStatus status = SecItemAdd((__bridge CFDictionaryRef)combined, NULL); + + if (status == errSecDuplicateItem) { + hasItem = YES; + status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)attributes); + } + + if (status == noErr) { + return YES; + } + if (error) { + NSString *function = hasItem ? @"SecItemUpdate" : @"SecItemAdd"; + *error = [FIRAuthErrorUtils keychainErrorWithFunction:function status:status]; + } + return NO; +} + +- (BOOL)deleteItemWithQuery:(NSDictionary *)query error:(NSError **_Nullable)error { + OSStatus status = SecItemDelete((__bridge CFDictionaryRef)query); + if (status == noErr || status == errSecItemNotFound) { + return YES; + } + if (error) { + *error = [FIRAuthErrorUtils keychainErrorWithFunction:@"SecItemDelete" status:status]; + } + return NO; +} + +/** @fn deleteLegacyItemsWithKey: + @brief Deletes legacy item from the keychain if it is not already known to be deleted. + @param key The key for the item. + */ +- (void)deleteLegacyItemWithKey:(NSString *)key { + if (_legacyEntryDeletedForKey[key]) { + return; + } + NSDictionary *query = [self legacyGenericPasswordQueryWithKey:key]; + SecItemDelete((__bridge CFDictionaryRef)query); + _legacyEntryDeletedForKey[key] = @YES; +} + +/** @fn genericPasswordQueryWithKey: + @brief Returns a keychain query of generic password to be used to manipulate key'ed value. + @param key The key for the value being manipulated, used as the account field in the query. + */ +- (NSDictionary *)genericPasswordQueryWithKey:(NSString *)key { + NSMutableDictionary *query = @{ + (__bridge id)kSecClass : (__bridge id)kSecClassGenericPassword, + (__bridge id)kSecAttrAccount : [kAccountPrefix stringByAppendingString:key], + (__bridge id)kSecAttrService : _service, + } + .mutableCopy; + + // TODO(ncooke3): Refactor Auth to provide a user defaults based + // implementation for unit testing purposes on macOS. +#ifndef FIREBASE_AUTH_MACOS_TESTING + // The below key prevents keychain popups from appearing on the client. It + // requires a configured provisioing profile to function properly–– which + // cannot be checked into the repo. Rather than disable most of the Auth + // testing suite on macOS, the key is omitted. Paired with the + // `scripts/configure_test_keychain.sh` script, the popups do not block CI. + // See go/firebase-macos-keychain-popups for more details. + if (@available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, watchOS 6.0, *)) { + query[(__bridge id)kSecUseDataProtectionKeychain] = (__bridge id)kCFBooleanTrue; + } +#endif // FIREBASE_AUTH_MACOS_TESTING + + return [query copy]; +} + +/** @fn legacyGenericPasswordQueryWithKey: + @brief Returns a keychain query of generic password without service field, which is used by + previous version of this class. + @param key The key for the value being manipulated, used as the account field in the query. + */ +- (NSDictionary *)legacyGenericPasswordQueryWithKey:(NSString *)key { + return @{ + (__bridge id)kSecClass : (__bridge id)kSecClassGenericPassword, + (__bridge id)kSecAttrAccount : key, + }; +} + +#pragma mark - Private methods for shared keychain operations + +- (nullable NSData *)getItemWithQuery:(NSDictionary *)query + error:(NSError *_Nullable *_Nullable)outError { + NSMutableDictionary *mutableQuery = [query mutableCopy]; + + mutableQuery[(__bridge id)kSecReturnData] = @YES; + mutableQuery[(__bridge id)kSecReturnAttributes] = @YES; + mutableQuery[(__bridge id)kSecMatchLimit] = @2; + + CFArrayRef result = NULL; + OSStatus status = + SecItemCopyMatching((__bridge CFDictionaryRef)mutableQuery, (CFTypeRef *)&result); + + if (status == noErr && result != NULL) { + NSArray *items = (__bridge_transfer NSArray *)result; + if (items.count != 1) { + if (outError) { + *outError = [FIRAuthErrorUtils keychainErrorWithFunction:@"SecItemCopyMatching" + status:status]; + } + return nil; + } + + if (outError) { + *outError = nil; + } + NSDictionary *item = items[0]; + return item[(__bridge id)kSecValueData]; + } + + if (status == errSecItemNotFound) { + if (outError) { + *outError = nil; + } + } else { + if (outError) { + *outError = [FIRAuthErrorUtils keychainErrorWithFunction:@"SecItemCopyMatching" + status:status]; + } + } + return nil; +} + +- (BOOL)setItem:(NSData *)item + withQuery:(NSDictionary *)query + error:(NSError *_Nullable *_Nullable)outError { + NSData *existingItem = [self getItemWithQuery:query error:outError]; + if (outError && *outError) { + return NO; + } + + OSStatus status; + if (!existingItem) { + NSMutableDictionary *queryWithItem = [query mutableCopy]; + [queryWithItem setObject:item forKey:(__bridge id)kSecValueData]; + status = SecItemAdd((__bridge CFDictionaryRef)queryWithItem, NULL); + } else { + NSDictionary *attributes = @{(__bridge id)kSecValueData : item}; + status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)attributes); + } + + if (status == noErr) { + if (outError) { + *outError = nil; + } + return YES; + } + + NSString *function = existingItem ? @"SecItemUpdate" : @"SecItemAdd"; + if (outError) { + *outError = [FIRAuthErrorUtils keychainErrorWithFunction:function status:status]; + } + return NO; +} + +- (BOOL)removeItemWithQuery:(NSDictionary *)query error:(NSError *_Nullable *_Nullable)outError { + OSStatus status = SecItemDelete((__bridge CFDictionaryRef)query); + + if (status == noErr || status == errSecItemNotFound) { + if (outError) { + *outError = nil; + } + return YES; + } + + if (outError) { + *outError = [FIRAuthErrorUtils keychainErrorWithFunction:@"SecItemDelete" status:status]; + } + return NO; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Storage/FIRAuthUserDefaults.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Storage/FIRAuthUserDefaults.h new file mode 100644 index 0000000..dfd8aad --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Storage/FIRAuthUserDefaults.h @@ -0,0 +1,36 @@ +/* + * 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 + +#import "FirebaseAuth/Sources/Storage/FIRAuthKeychainServices.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRAuthUserDefaults + @brief The utility class to storage data in NSUserDefaults. + */ +@interface FIRAuthUserDefaults : NSObject + +/** @fn clear + @brief Clears all data from the storage. + @remarks This method is only supposed to be called from tests. + */ +- (void)clear; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Storage/FIRAuthUserDefaults.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Storage/FIRAuthUserDefaults.m new file mode 100644 index 0000000..b109450 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Storage/FIRAuthUserDefaults.m @@ -0,0 +1,74 @@ +/* + * 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 "FirebaseAuth/Sources/Storage/FIRAuthUserDefaults.h" + +NS_ASSUME_NONNULL_BEGIN + +static NSString *const kPersistentDomainNamePrefix = @"com.google.Firebase.Auth."; + +@implementation FIRAuthUserDefaults { + /** @var _persistentDomainName + @brief The name of the persistent domain in user defaults. + */ + NSString *_persistentDomainName; + + /** @var _storage + @brief The backing NSUserDefaults storage for this instance. + */ + NSUserDefaults *_storage; +} + +- (instancetype)initWithService:(NSString *)service { + self = [super init]; + if (self) { + _persistentDomainName = [kPersistentDomainNamePrefix stringByAppendingString:service]; + _storage = [[NSUserDefaults alloc] init]; + } + return self; +} + +- (nullable NSData *)dataForKey:(NSString *)key error:(NSError **_Nullable)error { + if (error) { + *error = nil; + } + NSDictionary *allData = [_storage persistentDomainForName:_persistentDomainName]; + return allData[key]; +} + +- (BOOL)setData:(NSData *)data forKey:(NSString *)key error:(NSError **_Nullable)error { + NSMutableDictionary *allData = + [([_storage persistentDomainForName:_persistentDomainName] ?: @{}) mutableCopy]; + allData[key] = data; + [_storage setPersistentDomain:allData forName:_persistentDomainName]; + return YES; +} + +- (BOOL)removeDataForKey:(NSString *)key error:(NSError **_Nullable)error { + NSMutableDictionary *allData = + [[_storage persistentDomainForName:_persistentDomainName] mutableCopy]; + [allData removeObjectForKey:key]; + [_storage setPersistentDomain:allData forName:_persistentDomainName]; + return YES; +} + +- (void)clear { + [_storage setPersistentDomain:@{} forName:_persistentDomainName]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAPNSToken.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAPNSToken.h new file mode 100644 index 0000000..d06de11 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAPNSToken.h @@ -0,0 +1,63 @@ +/* + * 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 +#if !TARGET_OS_OSX + +#import +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthAPNSTokenType.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRAuthAPNSToken + @brief A data structure for an APNs token. + */ +@interface FIRAuthAPNSToken : NSObject + +/** @property data + @brief The APNs token data. + */ +@property(nonatomic, strong, readonly) NSData *data; + +/** @property string + @brief The uppercase hexadecimal string form of the APNs token data. + */ +@property(nonatomic, strong, readonly) NSString *string; + +/** @property type + @brief The APNs token type. + */ +@property(nonatomic, assign, readonly) FIRAuthAPNSTokenType type; + +/** @fn initWithData:type: + @brief Initializes the instance. + @param data The APNs token data. + @param type The APNs token type. + @return The initialized instance. + */ +- (instancetype)initWithData:(NSData *)data + type:(FIRAuthAPNSTokenType)type NS_DESIGNATED_INITIALIZER; + +/** @fn init + @brief Call @c initWithData:type: to get an instance of this class. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAPNSToken.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAPNSToken.m new file mode 100644 index 0000000..4937942 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAPNSToken.m @@ -0,0 +1,57 @@ +/* + * 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 +#if !TARGET_OS_OSX + +#import "FirebaseAuth/Sources/SystemService/FIRAuthAPNSToken.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRAuthAPNSToken { + /** @var _string + @brief The lazy-initialized string form of the token data. + */ + NSString *_string; +} + +- (instancetype)initWithData:(NSData *)data type:(FIRAuthAPNSTokenType)type { + self = [super init]; + if (self) { + _data = [data copy]; + _type = type; + } + return self; +} + +- (NSString *)string { + if (!_string) { + NSUInteger capacity = _data.length * 2; + NSMutableString *tokenString = [NSMutableString stringWithCapacity:capacity]; + const unsigned char *tokenData = _data.bytes; + for (int idx = 0; idx < _data.length; ++idx) { + [tokenString appendFormat:@"%02X", (int)tokenData[idx]]; + } + _string = tokenString; + } + return _string; +} + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAPNSTokenManager.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAPNSTokenManager.h new file mode 100644 index 0000000..c4e2cfb --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAPNSTokenManager.h @@ -0,0 +1,83 @@ +/* + * 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 +#if !TARGET_OS_OSX && !TARGET_OS_WATCH + +#import +#import + +@class FIRAuthAPNSToken; + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRAuthAPNSTokenCallback + @brief The type of block to receive an APNs token. + @param token The APNs token if one is available. + @param error The error happened if any. + @remarks Both `token` and `error` being `nil` means the request timed-out. + */ +typedef void (^FIRAuthAPNSTokenCallback)(FIRAuthAPNSToken *_Nullable token, + NSError *_Nullable error); + +/** @class FIRAuthAPNSTokenManager + @brief A class to manage APNs token in memory. + */ +@interface FIRAuthAPNSTokenManager : NSObject + +/** @property token + @brief The APNs token, if one is available. + @remarks Setting a token with FIRAuthAPNSTokenTypeUnknown will automatically converts it to + a token with the automatically detected type. + */ +@property(nonatomic, strong, nullable) FIRAuthAPNSToken *token; + +/** @property timeout + @brief The timeout for registering for remote notification. + @remarks Only tests should access this property. + */ +@property(nonatomic, assign) NSTimeInterval timeout; + +/** @fn init + @brief Call @c initWithApplication: to initialize an instance of this class. + */ +- (instancetype)init NS_UNAVAILABLE; + +/** @fn initWithApplication: + @brief Initializes the instance. + @param application The @c UIApplication to request the token from. + @return The initialized instance. + */ +- (instancetype)initWithApplication:(UIApplication *)application NS_DESIGNATED_INITIALIZER; + +/** @fn getTokenWithCallback: + @brief Attempts to get the APNs token. + @param callback The block to be called either immediately or in future, either when a token + becomes available, or when timeout occurs, whichever happens earlier. + */ +- (void)getTokenWithCallback:(FIRAuthAPNSTokenCallback)callback; + +/** @fn cancelWithError: + @brief Cancels any pending `getTokenWithCallback:` request. + @param error The error to return. + */ +- (void)cancelWithError:(NSError *)error; + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAPNSTokenManager.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAPNSTokenManager.m new file mode 100644 index 0000000..0445996 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAPNSTokenManager.m @@ -0,0 +1,250 @@ +/* + * 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 +#if !TARGET_OS_OSX && !TARGET_OS_WATCH + +#import +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" + +#import "FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.h" +#import "FirebaseAuth/Sources/Auth/FIRAuth_Internal.h" +#import "FirebaseAuth/Sources/SystemService/FIRAuthAPNSToken.h" +#import "FirebaseAuth/Sources/SystemService/FIRAuthAPNSTokenManager.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kRegistrationTimeout + @brief Timeout for registration for remote notification. + @remarks Once we start to handle `application:didFailToRegisterForRemoteNotificationsWithError:` + we probably don't have to use timeout at all. + */ +static const NSTimeInterval kRegistrationTimeout = 5; + +/** @var kLegacyRegistrationTimeout + @brief Timeout for registration for remote notification on iOS 7. + */ +static const NSTimeInterval kLegacyRegistrationTimeout = 30; + +@implementation FIRAuthAPNSTokenManager { + /** @var _application + @brief The @c UIApplication to request the token from. + */ + UIApplication *_application; + + /** @var _pendingCallbacks + @brief The list of all pending callbacks for the APNs token. + */ + NSMutableArray *_pendingCallbacks; +} + +- (instancetype)initWithApplication:(UIApplication *)application { + self = [super init]; + if (self) { + _application = application; + _timeout = [_application respondsToSelector:@selector(registerForRemoteNotifications)] + ? kRegistrationTimeout + : kLegacyRegistrationTimeout; + } + return self; +} + +- (void)getTokenWithCallback:(FIRAuthAPNSTokenCallback)callback { + if (_token) { + callback(_token, nil); + return; + } + if (_pendingCallbacks) { + [_pendingCallbacks addObject:callback]; + return; + } + _pendingCallbacks = + [[NSMutableArray alloc] initWithObjects:callback, nil]; + dispatch_async(dispatch_get_main_queue(), ^{ + if ([self->_application respondsToSelector:@selector(registerForRemoteNotifications)]) { + [self->_application registerForRemoteNotifications]; + } else { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#if TARGET_OS_IOS + [self->_application registerForRemoteNotificationTypes:UIRemoteNotificationTypeAlert]; +#endif // TARGET_OS_IOS +#pragma clang diagnostic pop + } + }); + NSArray *applicableCallbacks = _pendingCallbacks; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_timeout * NSEC_PER_SEC)), + FIRAuthGlobalWorkQueue(), ^{ + // Only cancel if the pending callbacks remain the same, i.e., not triggered yet. + if (applicableCallbacks == self->_pendingCallbacks) { + [self callBackWithToken:nil error:nil]; + } + }); +} + +- (void)setToken:(nullable FIRAuthAPNSToken *)token { + if (!token) { + _token = nil; + return; + } + if (token.type == FIRAuthAPNSTokenTypeUnknown) { + static FIRAuthAPNSTokenType detectedTokenType = FIRAuthAPNSTokenTypeUnknown; + if (detectedTokenType == FIRAuthAPNSTokenTypeUnknown) { + detectedTokenType = + [[self class] isProductionApp] ? FIRAuthAPNSTokenTypeProd : FIRAuthAPNSTokenTypeSandbox; + } + token = [[FIRAuthAPNSToken alloc] initWithData:token.data type:detectedTokenType]; + } + _token = token; + [self callBackWithToken:token error:nil]; +} + +- (void)cancelWithError:(NSError *)error { + [self callBackWithToken:nil error:error]; +} + +#pragma mark - Internal methods + +/** @fn callBack + @brief Calls back all pending callbacks with APNs token or error. + @param token The APNs token if one is available. + @param error The error occurred, if any. + */ +- (void)callBackWithToken:(nullable FIRAuthAPNSToken *)token error:(nullable NSError *)error { + if (!_pendingCallbacks) { + return; + } + NSArray *allCallbacks = _pendingCallbacks; + _pendingCallbacks = nil; + for (FIRAuthAPNSTokenCallback callback in allCallbacks) { + callback(token, error); + } +}; + +/** @fn isProductionApp + @brief Whether or not the app has production (versus sandbox) provisioning profile. + */ ++ (BOOL)isProductionApp { + const BOOL defaultAppTypeProd = YES; + + NSError *error = nil; + + if ([GULAppEnvironmentUtil isSimulator]) { + FIRLogInfo(kFIRLoggerAuth, @"I-AUT000006", @"Assuming prod APNs token type on simulator."); + return defaultAppTypeProd; + } + + // Apps distributed via AppStore or TestFlight use the Production APNS certificates. + if ([GULAppEnvironmentUtil isFromAppStore]) { + return defaultAppTypeProd; + } + NSString *path = [[[NSBundle mainBundle] bundlePath] + stringByAppendingPathComponent:@"embedded.mobileprovision"]; + if ([GULAppEnvironmentUtil isAppStoreReceiptSandbox] && !path.length) { + // Distributed via TestFlight + return defaultAppTypeProd; + } + + NSMutableData *profileData = [NSMutableData dataWithContentsOfFile:path options:0 error:&error]; + + if (!profileData.length || error) { + FIRLogInfo(kFIRLoggerAuth, @"I-AUT000007", @"Error while reading embedded mobileprovision %@", + error); + return defaultAppTypeProd; + } + + // The "embedded.mobileprovision" sometimes contains characters with value 0, which signals the + // end of a c-string and halts the ASCII parser, or with value > 127, which violates strict 7-bit + // ASCII. Replace any 0s or invalid characters in the input. + uint8_t *profileBytes = (uint8_t *)profileData.bytes; + for (int i = 0; i < profileData.length; i++) { + uint8_t currentByte = profileBytes[i]; + if (!currentByte || currentByte > 127) { + profileBytes[i] = '.'; + } + } + + NSString *embeddedProfile = [[NSString alloc] initWithBytesNoCopy:profileBytes + length:profileData.length + encoding:NSASCIIStringEncoding + freeWhenDone:NO]; + + if (error || !embeddedProfile.length) { + FIRLogInfo(kFIRLoggerAuth, @"I-AUT000008", @"Error while reading embedded mobileprovision %@", + error); + return defaultAppTypeProd; + } + + NSScanner *scanner = [NSScanner scannerWithString:embeddedProfile]; + NSString *plistContents; + if ([scanner scanUpToString:@"" intoString:&plistContents]) { + plistContents = [plistContents stringByAppendingString:@""]; + } + } + + if (!plistContents.length) { + return defaultAppTypeProd; + } + + NSData *data = [plistContents dataUsingEncoding:NSUTF8StringEncoding]; + if (!data.length) { + FIRLogInfo(kFIRLoggerAuth, @"I-AUT000009", + @"Couldn't read plist fetched from embedded mobileprovision"); + return defaultAppTypeProd; + } + + NSError *plistMapError; + id plistData = [NSPropertyListSerialization propertyListWithData:data + options:NSPropertyListImmutable + format:nil + error:&plistMapError]; + if (plistMapError || ![plistData isKindOfClass:[NSDictionary class]]) { + FIRLogInfo(kFIRLoggerAuth, @"I-AUT000010", @"Error while converting assumed plist to dict %@", + plistMapError.localizedDescription); + return defaultAppTypeProd; + } + NSDictionary *plistMap = (NSDictionary *)plistData; + + if ([plistMap valueForKeyPath:@"ProvisionedDevices"]) { + FIRLogInfo(kFIRLoggerAuth, @"I-AUT000011", + @"Provisioning profile has specifically provisioned devices, " + @"most likely a Dev profile."); + } + + NSString *apsEnvironment = [plistMap valueForKeyPath:@"Entitlements.aps-environment"]; + FIRLogDebug(kFIRLoggerAuth, @"I-AUT000012", @"APNS Environment in profile: %@", apsEnvironment); + + // No aps-environment in the profile. + if (!apsEnvironment.length) { + FIRLogInfo(kFIRLoggerAuth, @"I-AUT000013", + @"No aps-environment set. If testing on a device APNS is not " + @"correctly configured. Please recheck your provisioning profiles."); + return defaultAppTypeProd; + } + + if ([apsEnvironment isEqualToString:@"development"]) { + return NO; + } + + return defaultAppTypeProd; +} + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAppCredential.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAppCredential.h new file mode 100644 index 0000000..ceb93e2 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAppCredential.h @@ -0,0 +1,52 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRAuthAppCredential + @brief A class represents a credential that proves the identity of the app. + */ +@interface FIRAuthAppCredential : NSObject + +/** @property receipt + @brief The server acknowledgement of receiving client's claim of identity. + */ +@property(nonatomic, strong, readonly) NSString *receipt; + +/** @property secret + @brief The secret that the client received from server via a trusted channel, if ever. + */ +@property(nonatomic, strong, readonly, nullable) NSString *secret; + +/** @fn initWithReceipt:secret: + @brief Initializes the instance. + @param receipt The server acknowledgement of receiving client's claim of identity. + @param secret The secret that the client received from server via a trusted channel, if ever. + @return The initialized instance. + */ +- (instancetype)initWithReceipt:(NSString *)receipt + secret:(nullable NSString *)secret NS_DESIGNATED_INITIALIZER; + +/** @fn init + @brief Call @c initWithReceipt:secret: to get an instance of this class. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAppCredential.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAppCredential.m new file mode 100644 index 0000000..7bf1021 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAppCredential.m @@ -0,0 +1,64 @@ +/* + * 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 "FirebaseAuth/Sources/SystemService/FIRAuthAppCredential.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kReceiptKey + @brief The key used to encode the receipt property for NSSecureCoding. + */ +static NSString *const kReceiptKey = @"receipt"; + +/** @var kSecretKey + @brief The key used to encode the secret property for NSSecureCoding. + */ +static NSString *const kSecretKey = @"secret"; + +@implementation FIRAuthAppCredential + +- (instancetype)initWithReceipt:(NSString *)receipt secret:(nullable NSString *)secret { + self = [super init]; + if (self) { + _receipt = [receipt copy]; + _secret = [secret copy]; + } + return self; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + NSString *receipt = [aDecoder decodeObjectOfClass:[NSString class] forKey:kReceiptKey]; + if (!receipt) { + return nil; + } + NSString *secret = [aDecoder decodeObjectOfClass:[NSString class] forKey:kSecretKey]; + return [self initWithReceipt:receipt secret:secret]; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:_receipt forKey:kReceiptKey]; + [aCoder encodeObject:_secret forKey:kSecretKey]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAppCredentialManager.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAppCredentialManager.h new file mode 100644 index 0000000..efbbe7a --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAppCredentialManager.h @@ -0,0 +1,90 @@ +/* + * 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 +#if !TARGET_OS_OSX + +#import + +#import "FirebaseAuth/Sources/Storage/FIRAuthKeychainServices.h" +#import "FirebaseAuth/Sources/SystemService/FIRAuthAppCredential.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRAuthAppCredentialCallback + @brief The type of block to receive an app crdential. + @param credential The best available app credential at the time. + */ +typedef void (^FIRAuthAppCredentialCallback)(FIRAuthAppCredential *credential); + +/** @class FIRAuthAppCredentialManager + @brief A class to manage app credentials backed by iOS Keychain. + */ +@interface FIRAuthAppCredentialManager : NSObject + +/** @property credential + @brief The full credential (which has a secret) to be used by the app, if one is available. + */ +@property(nonatomic, strong, readonly, nullable) FIRAuthAppCredential *credential; + +/** @property maximumNumberOfPendingReceipts + @brief The maximum (but not necessarily the minimum) number of pending receipts to be kept. + @remarks Only tests should access this property. + */ +@property(nonatomic, assign, readonly) NSUInteger maximumNumberOfPendingReceipts; + +/** @fn init + @brief Call @c initWithKeychain: to initialize an instance of this class. + */ +- (instancetype)init NS_UNAVAILABLE; + +/** @fn initWithKeychain: + @brief Initializes the instance. + @param keychain The iOS Keychain storage to back up the app credential with. + @return The initialized instance. + */ +- (instancetype)initWithKeychain:(FIRAuthKeychainServices *)keychain NS_DESIGNATED_INITIALIZER; + +/** @fn didStartVerificationWithReceipt:timeout:callback: + @brief Notifies that the app verification process has started. + @param receipt The receipt for verification. + @param timeout The timeout value for how long the callback is waited to be called. + @param callback The block to be called in future either when the verification finishes, or + when timeout occurs, whichever happens earlier. + */ +- (void)didStartVerificationWithReceipt:(NSString *)receipt + timeout:(NSTimeInterval)timeout + callback:(FIRAuthAppCredentialCallback)callback; + +/** @fn canFinishVerificationWithReceipt: + @brief Attempts to finish verification. + @param receipt The receipt to match the original receipt obtained when verification started. + @param secret The secret to complete the verification. + @return Whether or not the receipt matches a pending verification, and finishes verification + if it does. + */ +- (BOOL)canFinishVerificationWithReceipt:(NSString *)receipt secret:(NSString *)secret; + +/** @fn clearCredential + @brief Clears the saved credential, to be used in the case that it is rejected by the server. + */ +- (void)clearCredential; + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAppCredentialManager.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAppCredentialManager.m new file mode 100644 index 0000000..52673f0 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthAppCredentialManager.m @@ -0,0 +1,180 @@ +/* + * 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 +#if !TARGET_OS_OSX + +#import "FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.h" +#import "FirebaseAuth/Sources/Storage/FIRAuthKeychainServices.h" +#import "FirebaseAuth/Sources/SystemService/FIRAuthAppCredential.h" +#import "FirebaseAuth/Sources/SystemService/FIRAuthAppCredentialManager.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kKeychainDataKey + @brief The keychain key for the data. + */ +static NSString *const kKeychainDataKey = @"app_credentials"; + +/** @var kFullCredentialKey + @brief The data key for the full app credential. + */ +static NSString *const kFullCredentialKey = @"full_credential"; + +/** @var kPendingReceiptsKey + @brief The data key for the array of pending receipts. + */ +static NSString *const kPendingReceiptsKey = @"pending_receipts"; + +/** @var kMaximumNumberOfPendingReceipts + @brief The maximum number of partial credentials kept by this class. + */ +static const NSUInteger kMaximumNumberOfPendingReceipts = 32; + +@implementation FIRAuthAppCredentialManager { + /** @var _keychainServices + @brief The keychain for app credentials to load from and to save to. + */ + FIRAuthKeychainServices *_keychainServices; + + /** @var _pendingReceipts + @brief A list of pending receipts sorted in the order they were recorded. + */ + NSMutableArray *_pendingReceipts; + + /** @var _callbacksByReceipt + @brief A map from pending receipts to callbacks. + */ + NSMutableDictionary *_callbacksByReceipt; +} + +- (instancetype)initWithKeychain:(FIRAuthKeychainServices *)keychain { + self = [super init]; + if (self) { + _keychainServices = keychain; + // Load the credentials from keychain if possible. + NSError *error; + NSData *encodedData = [_keychainServices dataForKey:kKeychainDataKey error:&error]; + if (!error && encodedData) { +#if TARGET_OS_WATCH + NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:encodedData + error:&error]; +#else +// iOS 12 deprecation +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + NSKeyedUnarchiver *unarchiver = + [[NSKeyedUnarchiver alloc] initForReadingWithData:encodedData]; +#pragma clang diagnostic pop +#endif // TARGET_OS_WATCH + FIRAuthAppCredential *credential = + [unarchiver decodeObjectOfClass:[FIRAuthAppCredential class] forKey:kFullCredentialKey]; + if ([credential isKindOfClass:[FIRAuthAppCredential class]] && !error) { + _credential = credential; + } + NSSet *allowedClasses = + [NSSet setWithObjects:[NSArray class], [NSString class], nil]; + NSArray *pendingReceipts = [unarchiver decodeObjectOfClasses:allowedClasses + forKey:kPendingReceiptsKey]; + if ([pendingReceipts isKindOfClass:[NSArray class]]) { + _pendingReceipts = [pendingReceipts mutableCopy]; + } + } + if (!_pendingReceipts) { + _pendingReceipts = [[NSMutableArray alloc] init]; + } + _callbacksByReceipt = + [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (NSUInteger)maximumNumberOfPendingReceipts { + return kMaximumNumberOfPendingReceipts; +} + +- (void)didStartVerificationWithReceipt:(NSString *)receipt + timeout:(NSTimeInterval)timeout + callback:(FIRAuthAppCredentialCallback)callback { + [_pendingReceipts removeObject:receipt]; + if (_pendingReceipts.count >= kMaximumNumberOfPendingReceipts) { + [_pendingReceipts removeObjectAtIndex:0]; + } + [_pendingReceipts addObject:receipt]; + _callbacksByReceipt[receipt] = callback; + [self saveData]; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeout * NSEC_PER_SEC)), + FIRAuthGlobalWorkQueue(), ^{ + [self callBackWithReceipt:receipt]; + }); +} + +- (BOOL)canFinishVerificationWithReceipt:(NSString *)receipt secret:(NSString *)secret { + if (![_pendingReceipts containsObject:receipt]) { + return NO; + } + [_pendingReceipts removeObject:receipt]; + _credential = [[FIRAuthAppCredential alloc] initWithReceipt:receipt secret:secret]; + [self saveData]; + [self callBackWithReceipt:receipt]; + return YES; +} + +- (void)clearCredential { + _credential = nil; + [self saveData]; +} + +#pragma mark - Internal methods + +/** @fn saveData + @brief Save the data in memory to the keychain ignoring any errors. + */ +- (void)saveData { + NSMutableData *archiveData = [NSMutableData data]; +// iOS 12 deprecation +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:archiveData]; +#pragma clang diagnostic pop + [archiver encodeObject:_credential forKey:kFullCredentialKey]; + [archiver encodeObject:_pendingReceipts forKey:kPendingReceiptsKey]; + [archiver finishEncoding]; + [_keychainServices setData:archiveData forKey:kKeychainDataKey error:NULL]; +} + +/** @fn callBackWithReceipt: + @brief Calls the saved callback for the specifc receipt. + @param receipt The receipt associated with the callback. + */ +- (void)callBackWithReceipt:(NSString *)receipt { + FIRAuthAppCredentialCallback callback = _callbacksByReceipt[receipt]; + if (!callback) { + return; + } + [_callbacksByReceipt removeObjectForKey:receipt]; + if (_credential) { + callback(_credential); + } else { + callback([[FIRAuthAppCredential alloc] initWithReceipt:receipt secret:nil]); + } +} + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthNotificationManager.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthNotificationManager.h new file mode 100644 index 0000000..12b6f3e --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthNotificationManager.h @@ -0,0 +1,76 @@ +/* + * 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 +#if !TARGET_OS_OSX && !TARGET_OS_WATCH + +#import +#import + +@class FIRAuthAppCredentialManager; + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRAuthNotificationForwardingCallback + @brief The type of block to receive whether or not remote notifications are being forwarded. + @param isNotificationBeingForwarded Whether or not remote notifications are being forwarded. + */ +typedef void (^FIRAuthNotificationForwardingCallback)(BOOL isNotificationBeingForwarded); + +/** @class FIRAuthNotificationManager + */ +@interface FIRAuthNotificationManager : NSObject + +/** @property timeout + @brief The timeout for checking for notification forwarding. + @remarks Only tests should access this property. + */ +@property(nonatomic, assign) NSTimeInterval timeout; + +/** @fn initWithApplication:appCredentialManager: + @brief Initializes the instance. + @param application The application. + @param appCredentialManager The object to handle app credentials delivered via notification. + @return The initialized instance. + */ +- (instancetype)initWithApplication:(UIApplication *)application + appCredentialManager:(FIRAuthAppCredentialManager *)appCredentialManager + NS_DESIGNATED_INITIALIZER; + +/** @fn init + @brief please use initWithAppCredentialManager: instead. + */ +- (instancetype)init NS_UNAVAILABLE; + +/** @fn checkNotificationForwardingWithCallback: + @brief Checks whether or not remote notifications are being forwarded to this class. + @param callback The block to be called either immediately or in future once a result + is available. + */ +- (void)checkNotificationForwardingWithCallback:(FIRAuthNotificationForwardingCallback)callback; + +/** @fn canHandleNotification: + @brief Attempts to handle the remote notification. + @param notification The notification in question. + @return Whether or the notification has been handled. + */ +- (BOOL)canHandleNotification:(NSDictionary *)notification; + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthNotificationManager.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthNotificationManager.m new file mode 100644 index 0000000..3fa4a31 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthNotificationManager.m @@ -0,0 +1,189 @@ +/* + * 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 +#if !TARGET_OS_OSX && !TARGET_OS_WATCH + +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" + +#import "FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.h" +#import "FirebaseAuth/Sources/Auth/FIRAuth_Internal.h" +#import "FirebaseAuth/Sources/SystemService/FIRAuthAppCredential.h" +#import "FirebaseAuth/Sources/SystemService/FIRAuthAppCredentialManager.h" +#import "FirebaseAuth/Sources/SystemService/FIRAuthNotificationManager.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kNotificationKey + @brief The key to locate payload data in the remote notification. + */ +static NSString *const kNotificationDataKey = @"com.google.firebase.auth"; + +/** @var kNotificationReceiptKey + @brief The key for the receipt in the remote notification payload data. + */ +static NSString *const kNotificationReceiptKey = @"receipt"; + +/** @var kNotificationSecretKey + @brief The key for the secret in the remote notification payload data. + */ +static NSString *const kNotificationSecretKey = @"secret"; + +/** @var kNotificationProberKey + @brief The key for marking the prober in the remote notification payload data. + */ +static NSString *const kNotificationProberKey = @"warning"; + +/** @var kProbingTimeout + @brief Timeout for probing whether the app delegate forwards the remote notification to us. + */ +static const NSTimeInterval kProbingTimeout = 1; + +@implementation FIRAuthNotificationManager { + /** @var _application + @brief The application. + */ + UIApplication *_application; + + /** @var _appCredentialManager + @brief The object to handle app credentials delivered via notification. + */ + FIRAuthAppCredentialManager *_appCredentialManager; + + /** @var _hasCheckedNotificationForwarding + @brief Whether notification forwarding has been checked or not. + */ + BOOL _hasCheckedNotificationForwarding; + + /** @var _isNotificationBeingForwarded + @brief Whether or not notification is being forwarded + */ + BOOL _isNotificationBeingForwarded; + + /** @var _pendingCallbacks + @brief All pending callbacks while a check is being performed. + */ + NSMutableArray *_pendingCallbacks; +} + +- (instancetype)initWithApplication:(UIApplication *)application + appCredentialManager:(FIRAuthAppCredentialManager *)appCredentialManager { + self = [super init]; + if (self) { + _application = application; + _appCredentialManager = appCredentialManager; + _timeout = kProbingTimeout; + } + return self; +} + +- (void)checkNotificationForwardingWithCallback:(FIRAuthNotificationForwardingCallback)callback { + if (_pendingCallbacks) { + [_pendingCallbacks addObject:callback]; + return; + } + if (_hasCheckedNotificationForwarding) { + callback(_isNotificationBeingForwarded); + return; + } + _hasCheckedNotificationForwarding = YES; + _pendingCallbacks = + [[NSMutableArray alloc] initWithObjects:callback, nil]; + dispatch_async(dispatch_get_main_queue(), ^{ + NSDictionary *proberNotification = @{ + kNotificationDataKey : @{ + kNotificationProberKey : @"This fake notification should be forwarded to Firebase Auth." + } + }; + if ([self->_application.delegate + respondsToSelector:@selector(application: + didReceiveRemoteNotification:fetchCompletionHandler:)]) { + [self->_application.delegate application:self->_application + didReceiveRemoteNotification:proberNotification + fetchCompletionHandler:^(UIBackgroundFetchResult result){ + }]; +#if !TARGET_OS_TV + } else if ([self->_application.delegate + respondsToSelector:@selector(application:didReceiveRemoteNotification:)]) { +// iOS 10 deprecation +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + [self->_application.delegate application:self->_application + didReceiveRemoteNotification:proberNotification]; +#pragma clang diagnostic pop +#endif + } else { + FIRLogWarning(kFIRLoggerAuth, @"I-AUT000015", + @"The UIApplicationDelegate must handle remote notification for phone number " + @"authentication to work."); + } + }); + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_timeout * NSEC_PER_SEC)), + FIRAuthGlobalWorkQueue(), ^{ + [self callBack]; + }); +} + +- (BOOL)canHandleNotification:(NSDictionary *)notification { + NSDictionary *data = notification[kNotificationDataKey]; + if ([data isKindOfClass:[NSString class]]) { + // Deserialize in case the data is a JSON string. + NSData *JSONData = [((NSString *)data) dataUsingEncoding:NSUTF8StringEncoding]; + data = [NSJSONSerialization JSONObjectWithData:JSONData options:0 error:NULL]; + } + if (![data isKindOfClass:[NSDictionary class]]) { + return NO; + } + if (data[kNotificationProberKey]) { + if (!_pendingCallbacks) { + // The prober notification probably comes from another instance, so pass it along. + return NO; + } + _isNotificationBeingForwarded = YES; + [self callBack]; + return YES; + } + NSString *receipt = data[kNotificationReceiptKey]; + if (![receipt isKindOfClass:[NSString class]]) { + return NO; + } + NSString *secret = data[kNotificationSecretKey]; + if (![receipt isKindOfClass:[NSString class]]) { + return NO; + } + return [_appCredentialManager canFinishVerificationWithReceipt:receipt secret:secret]; +} + +#pragma mark - Internal methods + +/** @fn callBack + @brief Calls back all pending callbacks with the result of notification forwarding check. + */ +- (void)callBack { + if (!_pendingCallbacks) { + return; + } + NSArray *allCallbacks = _pendingCallbacks; + _pendingCallbacks = nil; + for (FIRAuthNotificationForwardingCallback callback in allCallbacks) { + callback(_isNotificationBeingForwarded); + } +}; + +@end +NS_ASSUME_NONNULL_END + +#endif diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthStoredUserManager.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthStoredUserManager.h new file mode 100644 index 0000000..4d5e9ca --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthStoredUserManager.h @@ -0,0 +1,105 @@ +/* + * Copyright 2019 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 +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRUser.h" + +#import "FirebaseAuth/Sources/Storage/FIRAuthKeychainServices.h" +#import "FirebaseAuth/Sources/Storage/FIRAuthUserDefaults.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRAuthStoredUserManager : NSObject + +/** @property keychain + @brief The mediator object to access to the system Keychain services. + */ +@property(readonly, nonatomic, strong) FIRAuthKeychainServices *keychainServices; + +/** @property userDefaults + @brief The mediator object to access to the system User Defaults services. + */ +@property(readonly, nonatomic, strong) FIRAuthUserDefaults *userDefaults; + +/** @fn init + @brief The default initializer is disabled. + */ +- (instancetype)init NS_UNAVAILABLE; + +/** @fn initWithServiceName: + @brief The designated initializer. + @param serviceName The service name to initialize with. + */ +- (instancetype)initWithServiceName:(NSString *)serviceName NS_DESIGNATED_INITIALIZER; + +/** @fn getStoredUserAccessGroupWithError: + @brief Get the user access group stored locally. + */ +- (nullable NSString *)getStoredUserAccessGroup; + +/** @fn setStoredUserAccessGroup:error: + @brief The setter of the user access group stored locally. + @param accessGroup The access group to be set. + */ +- (BOOL)setStoredUserAccessGroup:(NSString *_Nullable)accessGroup; + +/** @fn getStoredUserForAccessGroup:projectID:error: + @brief The getter of the user stored locally. + @param accessGroup The access group to retrieve the user from. + @param shareAuthStateAcrossDevices If true, the keychain will be synced across the end-user's + iCloud. + @param projectIdentifier An identifier of the project that the user associates with. Currently, + we use API KEY. + @param outError Return value for any error which occurs. + */ +- (nullable FIRUser *)getStoredUserForAccessGroup:(NSString *)accessGroup + shareAuthStateAcrossDevices:(BOOL)shareAuthStateAcrossDevices + projectIdentifier:(NSString *)projectIdentifier + error:(NSError *_Nullable *_Nullable)outError; + +/** @fn setStoredUser:forAccessGroup:projectID:error: + @brief The setter of the user stored locally. + @param user The user to be stored. + @param accessGroup The access group to store the user in. + @param shareAuthStateAcrossDevices If true, the keychain will be synced across the end-user's + iCloud. + @param projectIdentifier An identifier of the project that the user associates with. Currently, + we use API KEY. + @param outError Return value for any error which occurs. + */ +- (BOOL)setStoredUser:(FIRUser *)user + forAccessGroup:(NSString *)accessGroup + shareAuthStateAcrossDevices:(BOOL)shareAuthStateAcrossDevices + projectIdentifier:(NSString *)projectIdentifier + error:(NSError *_Nullable *_Nullable)outError; + +/** @fn removeStoredUserForAccessGroup:projectID:error: + @brief Remove the user that stored locally. + @param accessGroup The access group to remove the user from. + @param shareAuthStateAcrossDevices If true, the keychain will be synced across the end-user's + iCloud. + @param projectIdentifier An identifier of the project that the user associates with. Currently, + we use API KEY. + @param outError Return value for any error which occurs. + */ +- (BOOL)removeStoredUserForAccessGroup:(NSString *)accessGroup + shareAuthStateAcrossDevices:(BOOL)shareAuthStateAcrossDevices + projectIdentifier:(NSString *)projectIdentifier + error:(NSError *_Nullable *_Nullable)outError; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthStoredUserManager.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthStoredUserManager.m new file mode 100644 index 0000000..8a8fd30 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRAuthStoredUserManager.m @@ -0,0 +1,181 @@ +/* + * Copyright 2019 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 "FirebaseAuth/Sources/SystemService/FIRAuthStoredUserManager.h" + +#import "FirebaseAuth/Sources/User/FIRUser_Internal.h" + +/** @var kUserAccessGroupKey + @brief Key of user access group stored in user defaults. Used for retrieve the user access + group at launch. + */ +static NSString *kStoredUserAccessGroupKey = @"firebase_auth_stored_user_access_group"; + +/** @var kSharedKeychainAccountValue + @brief Default value for kSecAttrAccount of shared keychain items. + */ +static NSString *kSharedKeychainAccountValue = @"firebase_auth_firebase_user"; + +/** @var kStoredUserCoderKey + @brief The key to encode and decode the stored user. + */ +static NSString *kStoredUserCoderKey = @"firebase_auth_stored_user_coder_key"; + +@implementation FIRAuthStoredUserManager + +#pragma mark - Initializers + +- (instancetype)initWithServiceName:(NSString *)serviceName { + self = [super init]; + if (self) { + _keychainServices = [[FIRAuthKeychainServices alloc] initWithService:serviceName]; + _userDefaults = [[FIRAuthUserDefaults alloc] initWithService:serviceName]; + } + return self; +} + +#pragma mark - User Access Group + +- (NSString *_Nullable)getStoredUserAccessGroup { + NSData *data = [self.userDefaults dataForKey:kStoredUserAccessGroupKey error:NULL]; + if (data) { + NSString *userAccessGroup = [NSString stringWithUTF8String:data.bytes]; + return userAccessGroup; + } else { + return nil; + } +} + +- (BOOL)setStoredUserAccessGroup:(NSString *_Nullable)accessGroup { + NSData *data = [accessGroup dataUsingEncoding:NSUTF8StringEncoding]; + if (!data) { + return [self.userDefaults removeDataForKey:kStoredUserAccessGroupKey error:NULL]; + } else { + return [self.userDefaults setData:data forKey:kStoredUserAccessGroupKey error:NULL]; + } +} + +#pragma mark - User for Access Group + +- (FIRUser *)getStoredUserForAccessGroup:(NSString *)accessGroup + shareAuthStateAcrossDevices:(BOOL)shareAuthStateAcrossDevices + projectIdentifier:(NSString *)projectIdentifier + error:(NSError *_Nullable *_Nullable)outError { + NSMutableDictionary *query = [self keychainQueryForAccessGroup:accessGroup + shareAuthStateAcrossDevices:shareAuthStateAcrossDevices + projectIdentifier:projectIdentifier]; + NSData *data = [self.keychainServices getItemWithQuery:query error:outError]; + // If there's an outError parameter and it's populated, or there's no data, return. + if ((outError && *outError) || !data) { + return nil; + } +#if TARGET_OS_WATCH + NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:data + error:outError]; + if (outError && *outError) { + return nil; + } +#else +// iOS 12 deprecation +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; +#pragma clang diagnostic pop +#endif // TARGET_OS_WATCH + FIRUser *user = [unarchiver decodeObjectOfClass:[FIRUser class] forKey:kStoredUserCoderKey]; + + return user; +} + +- (BOOL)setStoredUser:(FIRUser *)user + forAccessGroup:(NSString *)accessGroup + shareAuthStateAcrossDevices:(BOOL)shareAuthStateAcrossDevices + projectIdentifier:(NSString *)projectIdentifier + error:(NSError *_Nullable *_Nullable)outError { + NSMutableDictionary *query = [self keychainQueryForAccessGroup:accessGroup + shareAuthStateAcrossDevices:shareAuthStateAcrossDevices + projectIdentifier:projectIdentifier]; + if (shareAuthStateAcrossDevices) { + query[(__bridge id)kSecAttrAccessible] = (__bridge id)kSecAttrAccessibleAfterFirstUnlock; + } else { + query[(__bridge id)kSecAttrAccessible] = + (__bridge id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly; + } +#if TARGET_OS_WATCH + NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:false]; +#else + NSMutableData *data = [NSMutableData data]; +// iOS 12 deprecation +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; +#pragma clang diagnostic pop +#endif // TARGET_OS_WATCH + [archiver encodeObject:user forKey:kStoredUserCoderKey]; + [archiver finishEncoding]; + +#if TARGET_OS_WATCH + NSData *data = archiver.encodedData; +#endif // TARGET_OS_WATCH + + return [self.keychainServices setItem:data withQuery:query error:outError]; +} + +- (BOOL)removeStoredUserForAccessGroup:(NSString *)accessGroup + shareAuthStateAcrossDevices:(BOOL)shareAuthStateAcrossDevices + projectIdentifier:(NSString *)projectIdentifier + error:(NSError *_Nullable *_Nullable)outError { + NSMutableDictionary *query = [self keychainQueryForAccessGroup:accessGroup + shareAuthStateAcrossDevices:shareAuthStateAcrossDevices + projectIdentifier:projectIdentifier]; + if (shareAuthStateAcrossDevices) { + query[(__bridge id)kSecAttrAccessible] = (__bridge id)kSecAttrAccessibleAfterFirstUnlock; + } else { + query[(__bridge id)kSecAttrAccessible] = + (__bridge id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly; + } + return [self.keychainServices removeItemWithQuery:query error:outError]; +} + +#pragma mark - Internal Methods + +- (NSMutableDictionary *)keychainQueryForAccessGroup:(NSString *)accessGroup + shareAuthStateAcrossDevices:(BOOL)shareAuthStateAcrossDevices + projectIdentifier:(NSString *)projectIdentifier { + NSMutableDictionary *query = [[NSMutableDictionary alloc] init]; + query[(__bridge id)kSecClass] = (__bridge id)kSecClassGenericPassword; + query[(__bridge id)kSecAttrAccessGroup] = accessGroup; + query[(__bridge id)kSecAttrService] = projectIdentifier; + query[(__bridge id)kSecAttrAccount] = kSharedKeychainAccountValue; + + if (@available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, watchOS 6.0, *)) { + /* + "The data protection key affects operations only in macOS. + Other platforms automatically behave as if the key is set to true, + and ignore the key in the query dictionary. You can safely use the key on all platforms." + [kSecUseDataProtectionKeychain](https://developer.apple.com/documentation/security/ksecusedataprotectionkeychain) + */ + query[(__bridge id)kSecUseDataProtectionKeychain] = (__bridge id)kCFBooleanTrue; + } + + if (shareAuthStateAcrossDevices) { + query[(__bridge id)kSecAttrSynchronizable] = (__bridge id)kCFBooleanTrue; + } + + return query; +} + +@end diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRSecureTokenService.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRSecureTokenService.h new file mode 100644 index 0000000..d569691 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRSecureTokenService.h @@ -0,0 +1,91 @@ +/* + * 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 + +@class FIRAuthRequestConfiguration; + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRFetchAccessTokenCallback + @brief The callback used to return the value of attempting to fetch an access token. + + In the event the operation was successful @c token will be set and @c error will be @c nil. + In the event of failure @c token will be @c nil and @c error will be set. + @c tokenUpdated indicates whether either the access or the refresh token has been updated. + + The token returned should be considered ephemeral and not cached. It should be used immediately + and discarded. All operations that need this token should call fetchAccessToken and do their + work from the callback. + */ +typedef void (^FIRFetchAccessTokenCallback)(NSString *_Nullable token, + NSError *_Nullable error, + BOOL tokenUpdated); + +/** @class FIRSecureTokenService + @brief Provides services for token exchanges and refreshes. + */ +@interface FIRSecureTokenService : NSObject + +/** @property requestConfiguration + @brief The configuration for making requests to server. + */ +@property(nonatomic, strong) FIRAuthRequestConfiguration *requestConfiguration; + +/** @property rawAccessToken + @brief The cached access token. + @remarks This method is specifically for providing the access token to internal clients during + deserialization and sign-in events, and should not be used to retrieve the access token by + anyone else. + */ +@property(nonatomic, copy, readonly) NSString *rawAccessToken; + +/** @property refreshToken + @brief The refresh token for the user, or @c nil if the user has yet completed sign-in flow. + @remarks This property needs to be set manually after the instance is decoded from archive. + */ +@property(nonatomic, copy, readonly, nullable) NSString *refreshToken; + +/** @property accessTokenExpirationDate + @brief The expiration date of the cached access token. + */ +@property(nonatomic, copy, readonly, nullable) NSDate *accessTokenExpirationDate; + +/** @fn initWithRequestConfiguration:accessToken:accessTokenExpirationDate:refreshToken + @brief Creates a @c FIRSecureTokenService with access and refresh tokens. + @param requestConfiguration The configuration for making requests to server. + @param accessToken The STS access token. + @param accessTokenExpirationDate The approximate expiration date of the access token. + @param refreshToken The STS refresh token. + */ +- (instancetype)initWithRequestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + accessToken:(nullable NSString *)accessToken + accessTokenExpirationDate:(nullable NSDate *)accessTokenExpirationDate + refreshToken:(NSString *)refreshToken; + +/** @fn fetchAccessTokenForcingRefresh:callback: + @brief Fetch a fresh ephemeral access token for the ID associated with this instance. The token + received in the callback should be considered short lived and not cached. + @param forceRefresh Forces the token to be refreshed. + @param callback Callback block that will be called to return either the token or an error. + Invoked asyncronously on the auth global work queue in the future. + */ +- (void)fetchAccessTokenForcingRefresh:(BOOL)forceRefresh + callback:(FIRFetchAccessTokenCallback)callback; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRSecureTokenService.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRSecureTokenService.m new file mode 100644 index 0000000..3950f7a --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/SystemService/FIRSecureTokenService.m @@ -0,0 +1,224 @@ +/* + * 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 "FirebaseAuth/Sources/SystemService/FIRSecureTokenService.h" + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuth.h" + +#import "FirebaseAuth/Sources/Auth/FIRAuthSerialTaskQueue.h" +#import "FirebaseAuth/Sources/Auth/FIRAuthTokenResult_Internal.h" +#import "FirebaseAuth/Sources/Auth/FIRAuth_Internal.h" +#import "FirebaseAuth/Sources/Backend/FIRAuthBackend.h" +#import "FirebaseAuth/Sources/Backend/FIRAuthRequestConfiguration.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenResponse.h" + +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kAPIKeyCodingKey + @brief The key used to encode the APIKey for NSSecureCoding. + */ +static NSString *const kAPIKeyCodingKey = @"APIKey"; + +/** @var kRefreshTokenKey + @brief The key used to encode the refresh token for NSSecureCoding. + */ +static NSString *const kRefreshTokenKey = @"refreshToken"; + +/** @var kAccessTokenKey + @brief The key used to encode the access token for NSSecureCoding. + */ +static NSString *const kAccessTokenKey = @"accessToken"; + +/** @var kAccessTokenExpirationDateKey + @brief The key used to encode the access token expiration date for NSSecureCoding. + */ +static NSString *const kAccessTokenExpirationDateKey = @"accessTokenExpirationDate"; + +/** @var kFiveMinutes + @brief Five minutes (in seconds.) + */ +static const NSTimeInterval kFiveMinutes = 5 * 60; + +@interface FIRSecureTokenService () +- (instancetype)init NS_DESIGNATED_INITIALIZER; +@end + +@implementation FIRSecureTokenService { + /** @var _taskQueue + @brief Used to serialize all requests for access tokens. + */ + FIRAuthSerialTaskQueue *_taskQueue; + + /** @var _accessToken + @brief The currently cached access token. Or |nil| if no token is currently cached. + */ + NSString *_Nullable _accessToken; +} + +- (instancetype)init { + self = [super init]; + if (self) { + _taskQueue = [[FIRAuthSerialTaskQueue alloc] init]; + } + return self; +} + +- (instancetype)initWithRequestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + accessToken:(nullable NSString *)accessToken + accessTokenExpirationDate:(nullable NSDate *)accessTokenExpirationDate + refreshToken:(NSString *)refreshToken { + self = [self init]; + if (self) { + _requestConfiguration = requestConfiguration; + _accessToken = [accessToken copy]; + _accessTokenExpirationDate = [accessTokenExpirationDate copy]; + _refreshToken = [refreshToken copy]; + } + return self; +} + +- (void)fetchAccessTokenForcingRefresh:(BOOL)forceRefresh + callback:(FIRFetchAccessTokenCallback)callback { + [_taskQueue enqueueTask:^(FIRAuthSerialTaskCompletionBlock complete) { + if (!forceRefresh && [self hasValidAccessToken]) { + complete(); + callback(self->_accessToken, nil, NO); + } else { + FIRLogDebug(kFIRLoggerAuth, @"I-AUT000017", @"Fetching new token from backend."); + [self requestAccessToken:YES + callback:^(NSString *_Nullable token, NSError *_Nullable error, + BOOL tokenUpdated) { + complete(); + callback(token, error, tokenUpdated); + }]; + } + }]; +} + +- (NSString *)rawAccessToken { + return _accessToken; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + NSString *refreshToken = [aDecoder decodeObjectOfClass:[NSString class] forKey:kRefreshTokenKey]; + NSString *accessToken = [aDecoder decodeObjectOfClass:[NSString class] forKey:kAccessTokenKey]; + NSDate *accessTokenExpirationDate = [aDecoder decodeObjectOfClass:[NSDate class] + forKey:kAccessTokenExpirationDateKey]; + if (!refreshToken) { + return nil; + } + self = [self init]; + if (self) { + _refreshToken = refreshToken; + _accessToken = accessToken; + _accessTokenExpirationDate = accessTokenExpirationDate; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + // The API key is encoded even it is not used in decoding to be compatible with previous versions + // of the library. + [aCoder encodeObject:_requestConfiguration.APIKey forKey:kAPIKeyCodingKey]; + // Authorization code is not encoded because it is not long-lived. + [aCoder encodeObject:_refreshToken forKey:kRefreshTokenKey]; + [aCoder encodeObject:_accessToken forKey:kAccessTokenKey]; + [aCoder encodeObject:_accessTokenExpirationDate forKey:kAccessTokenExpirationDateKey]; +} + +#pragma mark - Private methods + +/** @fn requestAccessToken: + @brief Makes a request to STS for an access token. + @details This handles both the case that the token has not been granted yet and that it just + needs to be refreshed. The caller is responsible for making sure that this is occurring in + a @c _taskQueue task. + @param callback Called when the fetch is complete. Invoked asynchronously on the main thread in + the future. + @remarks Because this method is guaranteed to only be called from tasks enqueued in + @c _taskQueue, we do not need any @synchronized guards around access to _accessToken/etc. + since only one of those tasks is ever running at a time, and those tasks are the only + access to and mutation of these instance variables. + */ +- (void)requestAccessToken:(BOOL)retryIfExpired callback:(FIRFetchAccessTokenCallback)callback { + FIRSecureTokenRequest *request = + [FIRSecureTokenRequest refreshRequestWithRefreshToken:_refreshToken + requestConfiguration:_requestConfiguration]; + [FIRAuthBackend + secureToken:request + callback:^(FIRSecureTokenResponse *_Nullable response, NSError *_Nullable error) { + BOOL tokenUpdated = NO; + NSString *newAccessToken = response.accessToken; + if (newAccessToken.length && ![newAccessToken isEqualToString:self->_accessToken]) { + FIRAuthTokenResult *tokenResult = + [FIRAuthTokenResult tokenResultWithToken:newAccessToken]; + // There is an edge case where the request for a new access token may be made right + // before the app goes inactive, resulting in the callback being invoked much later + // with an expired access token. This does not fully solve the issue, as if the + // callback is invoked less than an hour after the request is made, a token is not + // re-requested here but the approximateExpirationDate will still be off since that is + // computed at the time the token is received. + if (retryIfExpired && + [tokenResult.expirationDate timeIntervalSinceNow] <= kFiveMinutes) { + // We only retry once, to avoid an infinite loop in the case that an end-user has + // their local time skewed by over an hour. + [self requestAccessToken:NO callback:callback]; + return; + } + self->_accessToken = [newAccessToken copy]; + self->_accessTokenExpirationDate = response.approximateExpirationDate; + tokenUpdated = YES; + FIRLogDebug(kFIRLoggerAuth, @"I-AUT000017", + @"Updated access token. Estimated expiration date: %@, current date: %@", + self->_accessTokenExpirationDate, [NSDate date]); + } + NSString *newRefreshToken = response.refreshToken; + if (newRefreshToken.length && ![newRefreshToken isEqualToString:self->_refreshToken]) { + self->_refreshToken = [newRefreshToken copy]; + tokenUpdated = YES; + } + callback(newAccessToken, error, tokenUpdated); + }]; +} + +- (BOOL)hasValidAccessToken { + BOOL hasValidAccessToken = + _accessToken && [_accessTokenExpirationDate timeIntervalSinceNow] > kFiveMinutes; + if (hasValidAccessToken) { + FIRLogDebug(kFIRLoggerAuth, @"I-AUT000017", + @"Has valid access token. Estimated expiration date: %@, current date: %@", + _accessTokenExpirationDate, [NSDate date]); + } else { + FIRLogDebug( + kFIRLoggerAuth, @"I-AUT000017", + @"Does not have valid access token. Estimated expiration date: %@, current date: %@", + _accessTokenExpirationDate, [NSDate date]); + } + return hasValidAccessToken; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRAdditionalUserInfo.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRAdditionalUserInfo.m new file mode 100644 index 0000000..52f56c4 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRAdditionalUserInfo.m @@ -0,0 +1,97 @@ +/* + * 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 "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.h" +#import "FirebaseAuth/Sources/User/FIRAdditionalUserInfo_Internal.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRAdditionalUserInfo + +/** @var kProviderIDCodingKey + @brief The key used to encode the providerID property for NSSecureCoding. + */ +static NSString *const kProviderIDCodingKey = @"providerID"; + +/** @var kProfileCodingKey + @brief The key used to encode the profile property for NSSecureCoding. + */ +static NSString *const kProfileCodingKey = @"profile"; + +/** @var kUsernameCodingKey + @brief The key used to encode the username property for NSSecureCoding. + */ +static NSString *const kUsernameCodingKey = @"username"; + +/** @var kNewUserKey + @brief The key used to encode the newUser property for NSSecureCoding. + */ +static NSString *const kNewUserKey = @"newUser"; + ++ (nullable instancetype)userInfoWithVerifyAssertionResponse: + (FIRVerifyAssertionResponse *)verifyAssertionResponse { + return [[self alloc] initWithProviderID:verifyAssertionResponse.providerID + profile:verifyAssertionResponse.profile + username:verifyAssertionResponse.username + isNewUser:verifyAssertionResponse.isNewUser]; +} + +- (nullable instancetype)initWithProviderID:(nullable NSString *)providerID + profile:(nullable NSDictionary *)profile + username:(nullable NSString *)username + isNewUser:(BOOL)isNewUser { + self = [super init]; + if (self) { + _providerID = [providerID copy]; + if (profile) { + _profile = [[NSDictionary alloc] initWithDictionary:profile copyItems:YES]; + } + _username = [username copy]; + _newUser = isNewUser; + } + return self; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + NSString *providerID = [aDecoder decodeObjectOfClass:[NSString class] + forKey:kProviderIDCodingKey]; + NSDictionary *profile = [aDecoder decodeObjectOfClass:[NSDictionary class] + forKey:kProfileCodingKey]; + NSString *username = [aDecoder decodeObjectOfClass:[NSString class] forKey:kUsernameCodingKey]; + NSNumber *isNewUser = [aDecoder decodeObjectOfClass:[NSNumber class] forKey:kNewUserKey]; + + return [self initWithProviderID:providerID + profile:profile + username:username + isNewUser:isNewUser.boolValue]; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:_providerID forKey:kProviderIDCodingKey]; + [aCoder encodeObject:_profile forKey:kProfileCodingKey]; + [aCoder encodeObject:_username forKey:kUsernameCodingKey]; + [aCoder encodeObject:[NSNumber numberWithBool:_newUser] forKey:kNewUserKey]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRAdditionalUserInfo_Internal.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRAdditionalUserInfo_Internal.h new file mode 100644 index 0000000..d0be10c --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRAdditionalUserInfo_Internal.h @@ -0,0 +1,46 @@ +/* + * 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 "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAdditionalUserInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRAdditionalUserInfo () + +/** @fn userInfoWithVerifyAssertionResponse: + @brief A convenience factory method for constructing a @c FIRAdditionalUserInfo instance from + data returned by the verifyAssertion endpoint. + @param verifyAssertionResponse Data returned by the verifyAssertion endpoint. + @return A new instance of @c FIRAdditionalUserInfo using data from the verifyAssertion endpoint. + */ ++ (nullable instancetype)userInfoWithVerifyAssertionResponse: + (FIRVerifyAssertionResponse *)verifyAssertionResponse; + +/** @fn initWithProviderID:profile:username: + @brief Designated initializer. + @param providerID The provider identifier. + @param profile Dictionary containing the additional IdP specific information. + @param username The name of the user. + @param isNewUser Indicates whether or not the current user was signed in for the first time. + */ +- (nullable instancetype)initWithProviderID:(nullable NSString *)providerID + profile:(nullable NSDictionary *)profile + username:(nullable NSString *)username + isNewUser:(BOOL)isNewUser NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUser.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUser.m new file mode 100644 index 0000000..71ab955 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUser.m @@ -0,0 +1,1651 @@ +/* + * 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 "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuth.h" +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIREmailAuthProvider.h" +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRFederatedAuthProvider.h" +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" + +#import "FirebaseAuth/Sources/Auth/FIRAuthDataResult_Internal.h" +#import "FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.h" +#import "FirebaseAuth/Sources/Auth/FIRAuthOperationType.h" +#import "FirebaseAuth/Sources/Auth/FIRAuthSerialTaskQueue.h" +#import "FirebaseAuth/Sources/Auth/FIRAuthTokenResult_Internal.h" +#import "FirebaseAuth/Sources/Auth/FIRAuth_Internal.h" +#import "FirebaseAuth/Sources/AuthProvider/Email/FIREmailPasswordAuthCredential.h" +#import "FirebaseAuth/Sources/AuthProvider/FIRAuthCredential_Internal.h" +#import "FirebaseAuth/Sources/AuthProvider/GameCenter/FIRGameCenterAuthCredential.h" +#import "FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthCredential_Internal.h" +#import "FirebaseAuth/Sources/Backend/FIRAuthBackend.h" +#import "FirebaseAuth/Sources/Backend/FIRAuthRequestConfiguration.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberResponse.h" +#import "FirebaseAuth/Sources/MultiFactor/FIRMultiFactor+Internal.h" +#import "FirebaseAuth/Sources/SystemService/FIRSecureTokenService.h" +#import "FirebaseAuth/Sources/User/FIRAdditionalUserInfo_Internal.h" +#import "FirebaseAuth/Sources/User/FIRUserInfoImpl.h" +#import "FirebaseAuth/Sources/User/FIRUserMetadata_Internal.h" +#import "FirebaseAuth/Sources/User/FIRUser_Internal.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthWebUtils.h" + +#if TARGET_OS_IOS +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthProvider.h" + +#import "FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthCredential_Internal.h" +#endif + +NS_ASSUME_NONNULL_BEGIN + +/** @var kUserIDCodingKey + @brief The key used to encode the user ID for NSSecureCoding. + */ +static NSString *const kUserIDCodingKey = @"userID"; + +/** @var kHasEmailPasswordCredentialCodingKey + @brief The key used to encode the hasEmailPasswordCredential property for NSSecureCoding. + */ +static NSString *const kHasEmailPasswordCredentialCodingKey = @"hasEmailPassword"; + +/** @var kAnonymousCodingKey + @brief The key used to encode the anonymous property for NSSecureCoding. + */ +static NSString *const kAnonymousCodingKey = @"anonymous"; + +/** @var kEmailCodingKey + @brief The key used to encode the email property for NSSecureCoding. + */ +static NSString *const kEmailCodingKey = @"email"; + +/** @var kPhoneNumberCodingKey + @brief The key used to encode the phoneNumber property for NSSecureCoding. + */ +static NSString *const kPhoneNumberCodingKey = @"phoneNumber"; + +/** @var kEmailVerifiedCodingKey + @brief The key used to encode the isEmailVerified property for NSSecureCoding. + */ +static NSString *const kEmailVerifiedCodingKey = @"emailVerified"; + +/** @var kDisplayNameCodingKey + @brief The key used to encode the displayName property for NSSecureCoding. + */ +static NSString *const kDisplayNameCodingKey = @"displayName"; + +/** @var kPhotoURLCodingKey + @brief The key used to encode the photoURL property for NSSecureCoding. + */ +static NSString *const kPhotoURLCodingKey = @"photoURL"; + +/** @var kProviderDataKey + @brief The key used to encode the providerData instance variable for NSSecureCoding. + */ +static NSString *const kProviderDataKey = @"providerData"; + +/** @var kAPIKeyCodingKey + @brief The key used to encode the APIKey instance variable for NSSecureCoding. + */ +static NSString *const kAPIKeyCodingKey = @"APIKey"; + +/** @var kFirebaseAppIDCodingKey + @brief The key used to encode the appID instance variable for NSSecureCoding. + */ +static NSString *const kFirebaseAppIDCodingKey = @"firebaseAppID"; + +/** @var kTokenServiceCodingKey + @brief The key used to encode the tokenService instance variable for NSSecureCoding. + */ +static NSString *const kTokenServiceCodingKey = @"tokenService"; + +/** @var kMetadataCodingKey + @brief The key used to encode the metadata instance variable for NSSecureCoding. + */ +static NSString *const kMetadataCodingKey = @"metadata"; + +static NSString *const kMultiFactorCodingKey = @"multiFactor"; + +/** @var kTenantIDKey + @brief The key used to encode the tenantID instance variable for NSSecureCoding. + */ +static NSString *const kTenantIDCodingKey = @"tenantID"; + +/** @var kMissingUsersErrorMessage + @brief The error message when there is no users array in the getAccountInfo response. + */ +static NSString *const kMissingUsersErrorMessage = @"users"; + +/** @typedef CallbackWithError + @brief The type for a callback block that only takes an error parameter. + */ +typedef void (^CallbackWithError)(NSError *_Nullable); + +/** @typedef CallbackWithUserAndError + @brief The type for a callback block that takes a user parameter and an error parameter. + */ +typedef void (^CallbackWithUserAndError)(FIRUser *_Nullable, NSError *_Nullable); + +/** @typedef CallbackWithUserAndError + @brief The type for a callback block that takes a user parameter and an error parameter. + */ +typedef void (^CallbackWithAuthDataResultAndError)(FIRAuthDataResult *_Nullable, + NSError *_Nullable); + +/** @var kMissingPasswordReason + @brief The reason why the @c FIRAuthErrorCodeWeakPassword error is thrown. + @remarks This error message will be localized in the future. + */ +static NSString *const kMissingPasswordReason = @"Missing Password"; + +/** @fn callInMainThreadWithError + @brief Calls a callback in main thread with error. + @param callback The callback to be called in main thread. + @param error The error to pass to callback. + */ +static void callInMainThreadWithError(_Nullable CallbackWithError callback, + NSError *_Nullable error) { + if (callback) { + dispatch_async(dispatch_get_main_queue(), ^{ + callback(error); + }); + } +} + +/** @fn callInMainThreadWithUserAndError + @brief Calls a callback in main thread with user and error. + @param callback The callback to be called in main thread. + @param user The user to pass to callback if there is no error. + @param error The error to pass to callback. + */ +static void callInMainThreadWithUserAndError(_Nullable CallbackWithUserAndError callback, + FIRUser *_Nonnull user, + NSError *_Nullable error) { + if (callback) { + dispatch_async(dispatch_get_main_queue(), ^{ + callback(error ? nil : user, error); + }); + } +} + +/** @fn callInMainThreadWithUserAndError + @brief Calls a callback in main thread with user and error. + @param callback The callback to be called in main thread. + @param result The result to pass to callback if there is no error. + @param error The error to pass to callback. + */ +static void callInMainThreadWithAuthDataResultAndError( + _Nullable CallbackWithAuthDataResultAndError callback, + FIRAuthDataResult *_Nullable result, + NSError *_Nullable error) { + if (callback) { + dispatch_async(dispatch_get_main_queue(), ^{ + callback(result, error); + }); + } +} + +@interface FIRUserProfileChangeRequest () + +/** @fn initWithUser: + @brief Designated initializer. + @param user The user for which we are updating profile information. + */ +- (nullable instancetype)initWithUser:(FIRUser *)user NS_DESIGNATED_INITIALIZER; + +@end + +@interface FIRUser () + +/** @property anonymous + @brief Whether the current user is anonymous. + */ +@property(nonatomic, readwrite) BOOL anonymous; + +/** @property tenantID + @brief The tenant ID of the current user. nil if none is available. + */ +@property(nonatomic, readwrite, nullable) NSString *tenantID; + +@end + +@implementation FIRUser { + /** @var _hasEmailPasswordCredential + @brief Whether or not the user can be authenticated by using Firebase email and password. + */ + BOOL _hasEmailPasswordCredential; + + /** @var _providerData + @brief Provider specific user data. + */ + NSDictionary *_providerData; + + /** @var _taskQueue + @brief Used to serialize the update profile calls. + */ + FIRAuthSerialTaskQueue *_taskQueue; + + /** @var _tokenService + @brief A secure token service associated with this user. For performing token exchanges and + refreshing access tokens. + */ + FIRSecureTokenService *_tokenService; +} + +#pragma mark - Properties + +// Explicitly @synthesize because these properties are defined in FIRUserInfo protocol. +@synthesize uid = _userID; +@synthesize displayName = _displayName; +@synthesize photoURL = _photoURL; +@synthesize email = _email; +@synthesize phoneNumber = _phoneNumber; + +#pragma mark - + ++ (void)retrieveUserWithAuth:(FIRAuth *)auth + accessToken:(nullable NSString *)accessToken + accessTokenExpirationDate:(nullable NSDate *)accessTokenExpirationDate + refreshToken:(nullable NSString *)refreshToken + anonymous:(BOOL)anonymous + callback:(FIRRetrieveUserCallback)callback { + FIRSecureTokenService *tokenService = + [[FIRSecureTokenService alloc] initWithRequestConfiguration:auth.requestConfiguration + accessToken:accessToken + accessTokenExpirationDate:accessTokenExpirationDate + refreshToken:refreshToken]; + FIRUser *user = [[self alloc] initWithTokenService:tokenService]; + user.auth = auth; + user.tenantID = auth.tenantID; + user.requestConfiguration = auth.requestConfiguration; + [user internalGetTokenWithCallback:^(NSString *_Nullable accessToken, NSError *_Nullable error) { + if (error) { + callback(nil, error); + return; + } + FIRGetAccountInfoRequest *getAccountInfoRequest = + [[FIRGetAccountInfoRequest alloc] initWithAccessToken:accessToken + requestConfiguration:auth.requestConfiguration]; + [FIRAuthBackend + getAccountInfo:getAccountInfoRequest + callback:^(FIRGetAccountInfoResponse *_Nullable response, NSError *_Nullable error) { + if (error) { + // No need to sign out user here for errors because the user hasn't been signed in + // yet. + callback(nil, error); + return; + } + user.anonymous = anonymous; + [user updateWithGetAccountInfoResponse:response]; + callback(user, nil); + }]; + }]; +} + +- (instancetype)initWithTokenService:(FIRSecureTokenService *)tokenService { + self = [super init]; + if (self) { + _providerData = @{}; + _taskQueue = [[FIRAuthSerialTaskQueue alloc] init]; + _tokenService = tokenService; + } + return self; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + NSString *userID = [aDecoder decodeObjectOfClass:[NSString class] forKey:kUserIDCodingKey]; + BOOL hasAnonymousKey = [aDecoder containsValueForKey:kAnonymousCodingKey]; + BOOL anonymous = [aDecoder decodeBoolForKey:kAnonymousCodingKey]; + BOOL hasEmailPasswordCredential = + [aDecoder decodeBoolForKey:kHasEmailPasswordCredentialCodingKey]; + NSString *displayName = [aDecoder decodeObjectOfClass:[NSString class] + forKey:kDisplayNameCodingKey]; + NSURL *photoURL = [aDecoder decodeObjectOfClass:[NSURL class] forKey:kPhotoURLCodingKey]; + NSString *email = [aDecoder decodeObjectOfClass:[NSString class] forKey:kEmailCodingKey]; + NSString *phoneNumber = [aDecoder decodeObjectOfClass:[NSString class] + forKey:kPhoneNumberCodingKey]; + BOOL emailVerified = [aDecoder decodeBoolForKey:kEmailVerifiedCodingKey]; + NSSet *providerDataClasses = + [NSSet setWithArray:@[ [NSDictionary class], [NSString class], [FIRUserInfoImpl class] ]]; + NSDictionary *providerData = + [aDecoder decodeObjectOfClasses:providerDataClasses forKey:kProviderDataKey]; + FIRSecureTokenService *tokenService = [aDecoder decodeObjectOfClass:[FIRSecureTokenService class] + forKey:kTokenServiceCodingKey]; + FIRUserMetadata *metadata = [aDecoder decodeObjectOfClass:[FIRUserMetadata class] + forKey:kMetadataCodingKey]; + NSString *tenantID = [aDecoder decodeObjectOfClass:[NSString class] forKey:kTenantIDCodingKey]; + NSString *APIKey = [aDecoder decodeObjectOfClass:[NSString class] forKey:kAPIKeyCodingKey]; + NSString *appID = [aDecoder decodeObjectOfClass:[NSString class] forKey:kFirebaseAppIDCodingKey]; +#if TARGET_OS_IOS + FIRMultiFactor *multiFactor = [aDecoder decodeObjectOfClass:[FIRMultiFactor class] + forKey:kMultiFactorCodingKey]; +#endif + if (!userID || !tokenService) { + return nil; + } + self = [self initWithTokenService:tokenService]; + if (self) { + _userID = userID; + // Previous version of this code didn't save 'anonymous' bit directly but deduced it from + // 'hasEmailPasswordCredential' and 'providerData' instead, so here backward compatibility is + // provided to read old format data. + _anonymous = hasAnonymousKey ? anonymous : (!hasEmailPasswordCredential && !providerData.count); + _hasEmailPasswordCredential = hasEmailPasswordCredential; + _email = email; + _emailVerified = emailVerified; + _displayName = displayName; + _photoURL = photoURL; + _providerData = providerData; + _phoneNumber = phoneNumber; + _metadata = metadata ?: [[FIRUserMetadata alloc] initWithCreationDate:nil lastSignInDate:nil]; + _tenantID = tenantID; + // The `heartbeatLogger` and `appCheck` will be set later via a property update. + _requestConfiguration = [[FIRAuthRequestConfiguration alloc] initWithAPIKey:APIKey + appID:appID + auth:_auth + heartbeatLogger:nil + appCheck:nil]; +#if TARGET_OS_IOS + _multiFactor = multiFactor ?: [[FIRMultiFactor alloc] init]; + _multiFactor.user = self; +#endif + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:_userID forKey:kUserIDCodingKey]; + [aCoder encodeBool:self.anonymous forKey:kAnonymousCodingKey]; + [aCoder encodeBool:_hasEmailPasswordCredential forKey:kHasEmailPasswordCredentialCodingKey]; + [aCoder encodeObject:_providerData forKey:kProviderDataKey]; + [aCoder encodeObject:_email forKey:kEmailCodingKey]; + [aCoder encodeObject:_phoneNumber forKey:kPhoneNumberCodingKey]; + [aCoder encodeBool:_emailVerified forKey:kEmailVerifiedCodingKey]; + [aCoder encodeObject:_photoURL forKey:kPhotoURLCodingKey]; + [aCoder encodeObject:_displayName forKey:kDisplayNameCodingKey]; + [aCoder encodeObject:_metadata forKey:kMetadataCodingKey]; + [aCoder encodeObject:_tenantID forKey:kTenantIDCodingKey]; + [aCoder encodeObject:_auth.requestConfiguration.APIKey forKey:kAPIKeyCodingKey]; + [aCoder encodeObject:_auth.requestConfiguration.appID forKey:kFirebaseAppIDCodingKey]; + [aCoder encodeObject:_tokenService forKey:kTokenServiceCodingKey]; +#if TARGET_OS_IOS + [aCoder encodeObject:_multiFactor forKey:kMultiFactorCodingKey]; +#endif +} + +#pragma mark - + +- (void)setAuth:(nullable FIRAuth *)auth { + _auth = auth; + _tokenService.requestConfiguration = auth.requestConfiguration; + _requestConfiguration = auth.requestConfiguration; +} + +- (NSString *)providerID { + return @"Firebase"; +} + +- (NSArray> *)providerData { + return _providerData.allValues; +} + +/** @fn getAccountInfoRefreshingCache: + @brief Gets the users's account data from the server, updating our local values. + @param callback Invoked when the request to getAccountInfo has completed, or when an error has + been detected. Invoked asynchronously on the auth global work queue in the future. + */ +- (void)getAccountInfoRefreshingCache:(void (^)(FIRGetAccountInfoResponseUser *_Nullable user, + NSError *_Nullable error))callback { + [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken, NSError *_Nullable error) { + if (error) { + callback(nil, error); + return; + } + FIRGetAccountInfoRequest *getAccountInfoRequest = + [[FIRGetAccountInfoRequest alloc] initWithAccessToken:accessToken + requestConfiguration:self->_auth.requestConfiguration]; + [FIRAuthBackend + getAccountInfo:getAccountInfoRequest + callback:^(FIRGetAccountInfoResponse *_Nullable response, NSError *_Nullable error) { + if (error) { + [self signOutIfTokenIsInvalidWithError:error]; + callback(nil, error); + return; + } + [self updateWithGetAccountInfoResponse:response]; + if (![self updateKeychain:&error]) { + callback(nil, error); + return; + } + callback(response.users.firstObject, nil); + }]; + }]; +} + +- (void)updateWithGetAccountInfoResponse:(FIRGetAccountInfoResponse *)response { + FIRGetAccountInfoResponseUser *user = response.users.firstObject; + _userID = user.localID; + _email = user.email; + _emailVerified = user.emailVerified; + _displayName = user.displayName; + _photoURL = user.photoURL; + _phoneNumber = user.phoneNumber; + _hasEmailPasswordCredential = user.passwordHash.length > 0; + _metadata = [[FIRUserMetadata alloc] initWithCreationDate:user.creationDate + lastSignInDate:user.lastLoginDate]; + NSMutableDictionary *providerData = + [NSMutableDictionary dictionary]; + for (FIRGetAccountInfoResponseProviderUserInfo *providerUserInfo in user.providerUserInfo) { + FIRUserInfoImpl *userInfo = + [FIRUserInfoImpl userInfoWithGetAccountInfoResponseProviderUserInfo:providerUserInfo]; + if (userInfo) { + providerData[providerUserInfo.providerID] = userInfo; + } + } + _providerData = [providerData copy]; +#if TARGET_OS_IOS + _multiFactor = [[FIRMultiFactor alloc] initWithMFAEnrollments:user.MFAEnrollments]; + _multiFactor.user = self; +#endif +} + +/** @fn executeUserUpdateWithChanges:callback: + @brief Performs a setAccountInfo request by mutating the results of a getAccountInfo response, + atomically in regards to other calls to this method. + @param changeBlock A block responsible for mutating a template @c FIRSetAccountInfoRequest + @param callback A block to invoke when the change is complete. Invoked asynchronously on the + auth global work queue in the future. + */ +- (void)executeUserUpdateWithChanges:(void (^)(FIRGetAccountInfoResponseUser *, + FIRSetAccountInfoRequest *))changeBlock + callback:(nonnull FIRUserProfileChangeCallback)callback { + [_taskQueue enqueueTask:^(FIRAuthSerialTaskCompletionBlock _Nonnull complete) { + [self getAccountInfoRefreshingCache:^(FIRGetAccountInfoResponseUser *_Nullable user, + NSError *_Nullable error) { + if (error) { + complete(); + callback(error); + return; + } + [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken, + NSError *_Nullable error) { + if (error) { + complete(); + callback(error); + return; + } + FIRAuthRequestConfiguration *configuration = self->_auth.requestConfiguration; + // Mutate setAccountInfoRequest in block: + FIRSetAccountInfoRequest *setAccountInfoRequest = + [[FIRSetAccountInfoRequest alloc] initWithRequestConfiguration:configuration]; + setAccountInfoRequest.accessToken = accessToken; + changeBlock(user, setAccountInfoRequest); + // Execute request: + [FIRAuthBackend + setAccountInfo:setAccountInfoRequest + callback:^(FIRSetAccountInfoResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + [self signOutIfTokenIsInvalidWithError:error]; + complete(); + callback(error); + return; + } + if (response.IDToken && response.refreshToken) { + FIRSecureTokenService *tokenService = [[FIRSecureTokenService alloc] + initWithRequestConfiguration:configuration + accessToken:response.IDToken + accessTokenExpirationDate:response.approximateExpirationDate + refreshToken:response.refreshToken]; + [self setTokenService:tokenService + callback:^(NSError *_Nullable error) { + complete(); + callback(error); + }]; + return; + } + complete(); + callback(nil); + }]; + }]; + }]; + }]; +} + +/** @fn updateKeychain: + @brief Updates the keychain for user token or info changes. + @param error The error if NO is returned. + @return Whether the operation is successful. + */ +- (BOOL)updateKeychain:(NSError *_Nullable *_Nullable)error { + return [_auth updateKeychainWithUser:self error:error]; +} + +/** @fn setTokenService:callback: + @brief Sets a new token service for the @c FIRUser instance. + @param tokenService The new token service object. + @param callback The block to be called in the global auth working queue once finished. + @remarks The method makes sure the token service has access and refresh token and the new tokens + are saved in the keychain before calling back. + */ +- (void)setTokenService:(FIRSecureTokenService *)tokenService + callback:(nonnull CallbackWithError)callback { + [tokenService fetchAccessTokenForcingRefresh:NO + callback:^(NSString *_Nullable token, + NSError *_Nullable error, BOOL tokenUpdated) { + if (error) { + callback(error); + return; + } + self->_tokenService = tokenService; + if (![self updateKeychain:&error]) { + callback(error); + return; + } + callback(nil); + }]; +} + +#pragma mark - + +/** @fn updateEmail:password:callback: + @brief Updates email address and/or password for the current user. + @remarks May fail if there is already an email/password-based account for the same email + address. + @param email The email address for the user, if to be updated. + @param password The new password for the user, if to be updated. + @param callback The block called when the user profile change has finished. Invoked + asynchronously on the auth global work queue in the future. + @remarks May fail with a @c FIRAuthErrorCodeRequiresRecentLogin error code. + Call @c reauthentateWithCredential:completion: beforehand to avoid this error case. + */ +- (void)updateEmail:(nullable NSString *)email + password:(nullable NSString *)password + callback:(nonnull FIRUserProfileChangeCallback)callback { + if (password && ![password length]) { + callback([FIRAuthErrorUtils weakPasswordErrorWithServerResponseReason:kMissingPasswordReason]); + return; + } + BOOL hadEmailPasswordCredential = _hasEmailPasswordCredential; + [self + executeUserUpdateWithChanges:^(FIRGetAccountInfoResponseUser *user, + FIRSetAccountInfoRequest *request) { + if (email) { + request.email = email; + } + if (password) { + request.password = password; + } + } + callback:^(NSError *error) { + if (error) { + callback(error); + return; + } + if (email) { + self->_email = [email copy]; + } + if (self->_email) { + if (!hadEmailPasswordCredential) { + // The list of providers need to be updated for the newly added email-password provider. + [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken, + NSError *_Nullable error) { + if (error) { + callback(error); + return; + } + FIRAuthRequestConfiguration *requestConfiguration = self->_auth.requestConfiguration; + FIRGetAccountInfoRequest *getAccountInfoRequest = + [[FIRGetAccountInfoRequest alloc] initWithAccessToken:accessToken + requestConfiguration:requestConfiguration]; + [FIRAuthBackend + getAccountInfo:getAccountInfoRequest + callback:^(FIRGetAccountInfoResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + [self signOutIfTokenIsInvalidWithError:error]; + callback(error); + return; + } + for (FIRGetAccountInfoResponseUser *userAccountInfo in response.users) { + // Set the account to non-anonymous if there are any providers, even if + // they're not email/password ones. + if (userAccountInfo.providerUserInfo.count > 0) { + self.anonymous = NO; + } + for (FIRGetAccountInfoResponseProviderUserInfo + *providerUserInfo in userAccountInfo.providerUserInfo) { + if ([providerUserInfo.providerID + isEqualToString:FIREmailAuthProviderID]) { + self->_hasEmailPasswordCredential = YES; + break; + } + } + } + [self updateWithGetAccountInfoResponse:response]; + if (![self updateKeychain:&error]) { + callback(error); + return; + } + callback(nil); + }]; + }]; + return; + } + } + if (![self updateKeychain:&error]) { + callback(error); + return; + } + callback(nil); + }]; +} + +- (void)updateEmail:(NSString *)email completion:(nullable FIRUserProfileChangeCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + [self updateEmail:email + password:nil + callback:^(NSError *_Nullable error) { + callInMainThreadWithError(completion, error); + }]; + }); +} + +- (void)updatePassword:(NSString *)password + completion:(nullable FIRUserProfileChangeCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + [self updateEmail:nil + password:password + callback:^(NSError *_Nullable error) { + callInMainThreadWithError(completion, error); + }]; + }); +} + +#if TARGET_OS_IOS +/** @fn internalUpdateOrLinkPhoneNumberCredential:completion: + @brief Updates the phone number for the user. On success, the cached user profile data is + updated. + + @param phoneAuthCredential The new phone number credential corresponding to the phone number + to be added to the Firebase account, if a phone number is already linked to the account this + new phone number will replace it. + @param isLinkOperation Boolean value indicating whether or not this is a link operation. + @param completion Optionally; the block invoked when the user profile change has finished. + Invoked asynchronously on the global work queue in the future. + */ +- (void)internalUpdateOrLinkPhoneNumberCredential:(FIRPhoneAuthCredential *)phoneAuthCredential + isLinkOperation:(BOOL)isLinkOperation + completion:(FIRUserProfileChangeCallback)completion { + [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken, NSError *_Nullable error) { + if (error) { + completion(error); + return; + } + FIRAuthOperationType operation = + isLinkOperation ? FIRAuthOperationTypeLink : FIRAuthOperationTypeUpdate; + FIRVerifyPhoneNumberRequest *request = [[FIRVerifyPhoneNumberRequest alloc] + initWithVerificationID:phoneAuthCredential.verificationID + verificationCode:phoneAuthCredential.verificationCode + operation:operation + requestConfiguration:self->_auth.requestConfiguration]; + request.accessToken = accessToken; + [FIRAuthBackend verifyPhoneNumber:request + callback:^(FIRVerifyPhoneNumberResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + [self signOutIfTokenIsInvalidWithError:error]; + completion(error); + return; + } + FIRAuthRequestConfiguration *requestConfiguration = + self.auth.requestConfiguration; + // Update the new token and refresh user info again. + self->_tokenService = [[FIRSecureTokenService alloc] + initWithRequestConfiguration:requestConfiguration + accessToken:response.IDToken + accessTokenExpirationDate:response.approximateExpirationDate + refreshToken:response.refreshToken]; + // Get account info to update cached user info. + [self getAccountInfoRefreshingCache:^( + FIRGetAccountInfoResponseUser *_Nullable user, + NSError *_Nullable error) { + if (error) { + [self signOutIfTokenIsInvalidWithError:error]; + completion(error); + return; + } + self.anonymous = NO; + if (![self updateKeychain:&error]) { + completion(error); + return; + } + completion(nil); + }]; + }]; + }]; +} + +- (void)updatePhoneNumberCredential:(FIRPhoneAuthCredential *)phoneAuthCredential + completion:(nullable FIRUserProfileChangeCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + [self internalUpdateOrLinkPhoneNumberCredential:phoneAuthCredential + isLinkOperation:NO + completion:^(NSError *_Nullable error) { + callInMainThreadWithError(completion, error); + }]; + }); +} +#endif + +- (FIRUserProfileChangeRequest *)profileChangeRequest { + __block FIRUserProfileChangeRequest *result; + dispatch_sync(FIRAuthGlobalWorkQueue(), ^{ + result = [[FIRUserProfileChangeRequest alloc] initWithUser:self]; + }); + return result; +} + +- (void)setDisplayName:(NSString *)displayName { + _displayName = [displayName copy]; +} + +- (void)setPhotoURL:(NSURL *)photoURL { + _photoURL = [photoURL copy]; +} + +- (NSString *)rawAccessToken { + return _tokenService.rawAccessToken; +} + +- (NSDate *)accessTokenExpirationDate { + return _tokenService.accessTokenExpirationDate; +} + +#pragma mark - + +- (void)reloadWithCompletion:(nullable FIRUserProfileChangeCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + [self getAccountInfoRefreshingCache:^(FIRGetAccountInfoResponseUser *_Nullable user, + NSError *_Nullable error) { + callInMainThreadWithError(completion, error); + }]; + }); +} + +#pragma mark - + +- (void)reauthenticateWithCredential:(FIRAuthCredential *)credential + completion:(nullable FIRAuthDataResultCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + [self->_auth + internalSignInAndRetrieveDataWithCredential:credential + isReauthentication:YES + callback:^(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error) { + if (error) { + // If "user not found" error returned by backend, + // translate to user mismatch error which is more + // accurate. + if (error.code == FIRAuthErrorCodeUserNotFound) { + error = [FIRAuthErrorUtils userMismatchError]; + } + callInMainThreadWithAuthDataResultAndError( + completion, authResult, error); + return; + } + if (![authResult.user.uid + isEqual:[self->_auth getUserID]]) { + callInMainThreadWithAuthDataResultAndError( + completion, authResult, + [FIRAuthErrorUtils userMismatchError]); + return; + } + // Successful reauthenticate + [self + setTokenService:authResult.user->_tokenService + callback:^(NSError *_Nullable error) { + callInMainThreadWithAuthDataResultAndError( + completion, authResult, error); + }]; + }]; + }); +} + +- (void)reauthenticateWithProvider:(id)provider + UIDelegate:(nullable id)UIDelegate + completion:(nullable FIRAuthDataResultCallback)completion { +#if TARGET_OS_IOS + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + [provider getCredentialWithUIDelegate:UIDelegate + completion:^(FIRAuthCredential *_Nullable credential, + NSError *_Nullable error) { + if (error) { + completion(nil, error); + return; + } + [self reauthenticateWithCredential:credential + completion:completion]; + }]; + }); +#endif // TARGET_OS_IOS +} + +- (nullable NSString *)refreshToken { + __block NSString *result; + dispatch_sync(FIRAuthGlobalWorkQueue(), ^{ + result = self->_tokenService.refreshToken; + }); + return result; +} + +- (void)getIDTokenWithCompletion:(nullable FIRAuthTokenCallback)completion { + // |getIDTokenForcingRefresh:completion:| is also a public API so there is no need to dispatch to + // global work queue here. + [self getIDTokenForcingRefresh:NO completion:completion]; +} + +- (void)getIDTokenForcingRefresh:(BOOL)forceRefresh + completion:(nullable FIRAuthTokenCallback)completion { + [self getIDTokenResultForcingRefresh:forceRefresh + completion:^(FIRAuthTokenResult *_Nullable tokenResult, + NSError *_Nullable error) { + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(tokenResult.token, error); + }); + } + }]; +} + +- (void)getIDTokenResultWithCompletion:(nullable FIRAuthTokenResultCallback)completion { + [self getIDTokenResultForcingRefresh:NO + completion:^(FIRAuthTokenResult *_Nullable tokenResult, + NSError *_Nullable error) { + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(tokenResult, error); + }); + } + }]; +} + +- (void)getIDTokenResultForcingRefresh:(BOOL)forceRefresh + completion:(nullable FIRAuthTokenResultCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + [self + internalGetTokenForcingRefresh:forceRefresh + callback:^(NSString *_Nullable token, NSError *_Nullable error) { + FIRAuthTokenResult *tokenResult; + if (token) { + tokenResult = [FIRAuthTokenResult tokenResultWithToken:token]; + FIRLogDebug(kFIRLoggerAuth, @"I-AUT000017", + @"Actual token expiration date: %@, current date: %@", + tokenResult.expirationDate, [NSDate date]); + } + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(tokenResult, error); + }); + } + }]; + }); +} + +/** @fn parseIDToken:error: + @brief Parses the provided IDToken and returns an instance of FIRAuthTokenResult containing + claims obtained from the IDToken. + + @param token The raw text of the Firebase IDToken encoded in base64. + @param error An out parameter which would contain any error that occurs during parsing. + @return An instance of FIRAuthTokenResult containing claims obtained from the IDToken. + + @remarks IDToken returned from the backend in some cases is of a length that is not a multiple + of 4. In these cases this function pads the token with as many "=" characters as needed and + then attempts to parse the token. If the token cannot be parsed an error is returned via the + "error" out parameter. + */ +- (nullable FIRAuthTokenResult *)parseIDToken:(NSString *)token error:(NSError **)error { + // Though this is an internal method, errors returned here are surfaced in user-visible + // callbacks. + if (error) { + *error = nil; + } + NSArray *tokenStringArray = [token componentsSeparatedByString:@"."]; + + // The JWT should have three parts, though we only use the second in this method. + if (tokenStringArray.count != 3) { + if (error) { + *error = [FIRAuthErrorUtils malformedJWTErrorWithToken:token underlyingError:nil]; + } + return nil; + } + + // The token payload is always the second index of the array. + NSString *IDToken = tokenStringArray[1]; + + // Convert the base64URL encoded string to a base64 encoded string. + // Replace "_" with "/" + NSMutableString *tokenPayload = [[IDToken stringByReplacingOccurrencesOfString:@"_" + withString:@"/"] mutableCopy]; + + // Replace "-" with "+" + [tokenPayload replaceOccurrencesOfString:@"-" + withString:@"+" + options:kNilOptions + range:NSMakeRange(0, tokenPayload.length)]; + + // Pad the token payload with "=" signs if the payload's length is not a multiple of 4. + while ((tokenPayload.length % 4) != 0) { + [tokenPayload appendFormat:@"="]; + } + NSData *decodedTokenPayloadData = + [[NSData alloc] initWithBase64EncodedString:tokenPayload + options:NSDataBase64DecodingIgnoreUnknownCharacters]; + if (!decodedTokenPayloadData) { + if (error) { + *error = [FIRAuthErrorUtils malformedJWTErrorWithToken:token underlyingError:nil]; + } + return nil; + } + NSError *jsonError = nil; + NSJSONReadingOptions options = NSJSONReadingMutableContainers | NSJSONReadingAllowFragments; + NSDictionary *tokenPayloadDictionary = + [NSJSONSerialization JSONObjectWithData:decodedTokenPayloadData + options:options + error:&jsonError]; + if (jsonError != nil) { + if (error) { + *error = [FIRAuthErrorUtils malformedJWTErrorWithToken:token underlyingError:jsonError]; + } + return nil; + } + + if (!tokenPayloadDictionary) { + if (error) { + *error = [FIRAuthErrorUtils malformedJWTErrorWithToken:token underlyingError:nil]; + } + return nil; + } + + FIRAuthTokenResult *result = [FIRAuthTokenResult tokenResultWithToken:token]; + return result; +} + +/** @fn internalGetTokenForcingRefresh:callback: + @brief Retrieves the Firebase authentication token, possibly refreshing it if it has expired. + @param callback The block to invoke when the token is available. Invoked asynchronously on the + global work thread in the future. + */ +- (void)internalGetTokenWithCallback:(nonnull FIRAuthTokenCallback)callback { + [self internalGetTokenForcingRefresh:NO callback:callback]; +} + +- (void)internalGetTokenForcingRefresh:(BOOL)forceRefresh + callback:(nonnull FIRAuthTokenCallback)callback { + [_tokenService fetchAccessTokenForcingRefresh:forceRefresh + callback:^(NSString *_Nullable token, + NSError *_Nullable error, BOOL tokenUpdated) { + if (error) { + [self signOutIfTokenIsInvalidWithError:error]; + callback(nil, error); + return; + } + if (tokenUpdated) { + if (![self updateKeychain:&error]) { + callback(nil, error); + return; + } + } + callback(token, nil); + }]; +} + +- (void)sendEmailVerificationBeforeUpdatingEmail:(nonnull NSString *)email + completion:(nullable FIRAuthVoidErrorCallback)completion { + [self internalVerifyBeforeUpdateEmailWithNewEmail:email + actionCodeSettings:nil + completion:completion]; +} + +- (void)sendEmailVerificationBeforeUpdatingEmail:(nonnull NSString *)email + actionCodeSettings:(nonnull FIRActionCodeSettings *)actionCodeSettings + completion:(nullable FIRAuthVoidErrorCallback)completion { + [self internalVerifyBeforeUpdateEmailWithNewEmail:email + actionCodeSettings:actionCodeSettings + completion:completion]; +} + +- (void)internalVerifyBeforeUpdateEmailWithNewEmail:(NSString *)newEmail + actionCodeSettings: + (nullable FIRActionCodeSettings *)actionCodeSettings + completion:(FIRVerifyBeforeUpdateEmailCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + [self + internalGetTokenWithCallback:^(NSString *_Nullable accessToken, NSError *_Nullable error) { + if (error) { + callInMainThreadWithError(completion, error); + return; + } + FIRAuthRequestConfiguration *configuration = self->_auth.requestConfiguration; + FIRActionCodeSettings *settings = actionCodeSettings; + FIRGetOOBConfirmationCodeRequest *request = [FIRGetOOBConfirmationCodeRequest + verifyBeforeUpdateEmailWithAccessToken:accessToken + newEmail:newEmail + actionCodeSettings:settings + requestConfiguration:configuration]; + [FIRAuthBackend + getOOBConfirmationCode:request + callback:^(FIRGetOOBConfirmationCodeResponse *_Nullable response, + NSError *_Nullable error) { + callInMainThreadWithError(completion, error); + }]; + }]; + }); +} + +- (void)linkWithCredential:(FIRAuthCredential *)credential + completion:(nullable FIRAuthDataResultCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + if (self->_providerData[credential.provider]) { + callInMainThreadWithAuthDataResultAndError(completion, nil, + [FIRAuthErrorUtils providerAlreadyLinkedError]); + return; + } + FIRAuthDataResult *result = [[FIRAuthDataResult alloc] initWithUser:self + additionalUserInfo:nil]; + if ([credential isKindOfClass:[FIREmailPasswordAuthCredential class]]) { + if (self->_hasEmailPasswordCredential) { + callInMainThreadWithAuthDataResultAndError(completion, nil, + [FIRAuthErrorUtils providerAlreadyLinkedError]); + return; + } + FIREmailPasswordAuthCredential *emailPasswordCredential = + (FIREmailPasswordAuthCredential *)credential; + if (emailPasswordCredential.password) { + [self updateEmail:emailPasswordCredential.email + password:emailPasswordCredential.password + callback:^(NSError *error) { + if (error) { + callInMainThreadWithAuthDataResultAndError(completion, nil, error); + } else { + callInMainThreadWithAuthDataResultAndError(completion, result, nil); + } + }]; + } else { + [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken, + NSError *_Nullable error) { + NSDictionary *queryItems = + [FIRAuthWebUtils parseURL:emailPasswordCredential.link]; + if (![queryItems count]) { + NSURLComponents *urlComponents = + [NSURLComponents componentsWithString:emailPasswordCredential.link]; + queryItems = [FIRAuthWebUtils parseURL:urlComponents.query]; + } + NSString *actionCode = queryItems[@"oobCode"]; + FIRAuthRequestConfiguration *requestConfiguration = self.auth.requestConfiguration; + FIREmailLinkSignInRequest *request = + [[FIREmailLinkSignInRequest alloc] initWithEmail:emailPasswordCredential.email + oobCode:actionCode + requestConfiguration:requestConfiguration]; + request.IDToken = accessToken; + [FIRAuthBackend + emailLinkSignin:request + callback:^(FIREmailLinkSignInResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + callInMainThreadWithAuthDataResultAndError(completion, nil, error); + } else { + // Update the new token and refresh user info again. + self->_tokenService = [[FIRSecureTokenService alloc] + initWithRequestConfiguration:requestConfiguration + accessToken:response.IDToken + accessTokenExpirationDate:response.approximateExpirationDate + refreshToken:response.refreshToken]; + [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken, + NSError *_Nullable error) { + if (error) { + callInMainThreadWithAuthDataResultAndError(completion, nil, error); + return; + } + + FIRGetAccountInfoRequest *getAccountInfoRequest = + [[FIRGetAccountInfoRequest alloc] + initWithAccessToken:accessToken + requestConfiguration:requestConfiguration]; + [FIRAuthBackend + getAccountInfo:getAccountInfoRequest + callback:^(FIRGetAccountInfoResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + [self signOutIfTokenIsInvalidWithError:error]; + callInMainThreadWithAuthDataResultAndError(completion, nil, + error); + return; + } + self.anonymous = NO; + [self updateWithGetAccountInfoResponse:response]; + if (![self updateKeychain:&error]) { + callInMainThreadWithAuthDataResultAndError(completion, nil, + error); + return; + } + callInMainThreadWithAuthDataResultAndError(completion, + result, nil); + }]; + }]; + } + }]; + }]; + } + return; + } + + if ([credential isKindOfClass:[FIRGameCenterAuthCredential class]]) { + FIRGameCenterAuthCredential *gameCenterCredential = (FIRGameCenterAuthCredential *)credential; + [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken, + NSError *_Nullable error) { + FIRAuthRequestConfiguration *requestConfiguration = self.auth.requestConfiguration; + FIRSignInWithGameCenterRequest *gameCenterRequest = [[FIRSignInWithGameCenterRequest alloc] + initWithPlayerID:gameCenterCredential.playerID + teamPlayerID:gameCenterCredential.teamPlayerID + gamePlayerID:gameCenterCredential.gamePlayerID + publicKeyURL:gameCenterCredential.publicKeyURL + signature:gameCenterCredential.signature + salt:gameCenterCredential.salt + timestamp:gameCenterCredential.timestamp + displayName:gameCenterCredential.displayName + requestConfiguration:requestConfiguration]; + gameCenterRequest.accessToken = accessToken; + + [FIRAuthBackend + signInWithGameCenter:gameCenterRequest + callback:^(FIRSignInWithGameCenterResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + callInMainThreadWithAuthDataResultAndError(completion, nil, error); + } else { + // Update the new token and refresh user info again. + self->_tokenService = [[FIRSecureTokenService alloc] + initWithRequestConfiguration:requestConfiguration + accessToken:response.IDToken + accessTokenExpirationDate:response.approximateExpirationDate + refreshToken:response.refreshToken]; + [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken, + NSError *_Nullable error) { + if (error) { + callInMainThreadWithAuthDataResultAndError(completion, nil, error); + return; + } + + FIRGetAccountInfoRequest *getAccountInfoRequest = + [[FIRGetAccountInfoRequest alloc] + initWithAccessToken:accessToken + requestConfiguration:requestConfiguration]; + [FIRAuthBackend + getAccountInfo:getAccountInfoRequest + callback:^(FIRGetAccountInfoResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + [self signOutIfTokenIsInvalidWithError:error]; + callInMainThreadWithAuthDataResultAndError(completion, + nil, error); + return; + } + self.anonymous = NO; + [self updateWithGetAccountInfoResponse:response]; + if (![self updateKeychain:&error]) { + callInMainThreadWithAuthDataResultAndError(completion, + nil, error); + return; + } + callInMainThreadWithAuthDataResultAndError(completion, + result, nil); + }]; + }]; + } + }]; + }]; + return; + } + +#if TARGET_OS_IOS + if ([credential isKindOfClass:[FIRPhoneAuthCredential class]]) { + FIRPhoneAuthCredential *phoneAuthCredential = (FIRPhoneAuthCredential *)credential; + [self internalUpdateOrLinkPhoneNumberCredential:phoneAuthCredential + isLinkOperation:YES + completion:^(NSError *_Nullable error) { + if (error) { + callInMainThreadWithAuthDataResultAndError( + completion, nil, error); + } else { + callInMainThreadWithAuthDataResultAndError( + completion, result, nil); + } + }]; + return; + } +#endif + + [self->_taskQueue enqueueTask:^(FIRAuthSerialTaskCompletionBlock _Nonnull complete) { + CallbackWithAuthDataResultAndError completeWithError = + ^(FIRAuthDataResult *result, NSError *error) { + complete(); + callInMainThreadWithAuthDataResultAndError(completion, result, error); + }; + [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken, + NSError *_Nullable error) { + if (error) { + completeWithError(nil, error); + return; + } + FIRAuthRequestConfiguration *requestConfiguration = self->_auth.requestConfiguration; + FIRVerifyAssertionRequest *request = + [[FIRVerifyAssertionRequest alloc] initWithProviderID:credential.provider + requestConfiguration:requestConfiguration]; + [credential prepareVerifyAssertionRequest:request]; + request.accessToken = accessToken; + [FIRAuthBackend + verifyAssertion:request + callback:^(FIRVerifyAssertionResponse *response, NSError *error) { + if (error) { + [self signOutIfTokenIsInvalidWithError:error]; + completeWithError(nil, error); + return; + } + FIRAdditionalUserInfo *additionalUserInfo = + [FIRAdditionalUserInfo userInfoWithVerifyAssertionResponse:response]; + FIROAuthCredential *updatedOAuthCredential = + [[FIROAuthCredential alloc] initWithVerifyAssertionResponse:response]; + FIRAuthDataResult *result = + [[FIRAuthDataResult alloc] initWithUser:self + additionalUserInfo:additionalUserInfo + credential:updatedOAuthCredential]; + // Update the new token and refresh user info again. + self->_tokenService = [[FIRSecureTokenService alloc] + initWithRequestConfiguration:requestConfiguration + accessToken:response.IDToken + accessTokenExpirationDate:response.approximateExpirationDate + refreshToken:response.refreshToken]; + [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken, + NSError *_Nullable error) { + if (error) { + completeWithError(nil, error); + return; + } + FIRGetAccountInfoRequest *getAccountInfoRequest = + [[FIRGetAccountInfoRequest alloc] + initWithAccessToken:accessToken + requestConfiguration:requestConfiguration]; + [FIRAuthBackend + getAccountInfo:getAccountInfoRequest + callback:^(FIRGetAccountInfoResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + [self signOutIfTokenIsInvalidWithError:error]; + completeWithError(nil, error); + return; + } + self.anonymous = NO; + [self updateWithGetAccountInfoResponse:response]; + if (![self updateKeychain:&error]) { + completeWithError(nil, error); + return; + } + completeWithError(result, nil); + }]; + }]; + }]; + }]; + }]; + }); +} + +- (void)linkWithProvider:(id)provider + UIDelegate:(nullable id)UIDelegate + completion:(nullable FIRAuthDataResultCallback)completion { +#if TARGET_OS_IOS + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + [provider getCredentialWithUIDelegate:UIDelegate + completion:^(FIRAuthCredential *_Nullable credential, + NSError *_Nullable error) { + if (error) { + completion(nil, error); + return; + } + [self linkWithCredential:credential completion:completion]; + }]; + }); +#endif // TARGET_OS_IOS +} + +- (void)unlinkFromProvider:(NSString *)provider + completion:(nullable FIRAuthResultCallback)completion { + [_taskQueue enqueueTask:^(FIRAuthSerialTaskCompletionBlock _Nonnull complete) { + CallbackWithError completeAndCallbackWithError = ^(NSError *error) { + complete(); + callInMainThreadWithUserAndError(completion, self, error); + }; + [self + internalGetTokenWithCallback:^(NSString *_Nullable accessToken, NSError *_Nullable error) { + if (error) { + completeAndCallbackWithError(error); + return; + } + FIRAuthRequestConfiguration *requestConfiguration = self->_auth.requestConfiguration; + FIRSetAccountInfoRequest *setAccountInfoRequest = + [[FIRSetAccountInfoRequest alloc] initWithRequestConfiguration:requestConfiguration]; + setAccountInfoRequest.accessToken = accessToken; + + if (!self->_providerData[provider]) { + completeAndCallbackWithError([FIRAuthErrorUtils noSuchProviderError]); + return; + } + setAccountInfoRequest.deleteProviders = @[ provider ]; + + [FIRAuthBackend + setAccountInfo:setAccountInfoRequest + callback:^(FIRSetAccountInfoResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + [self signOutIfTokenIsInvalidWithError:error]; + completeAndCallbackWithError(error); + return; + } + + // We can't just use the provider info objects in FIRSetAccountInfoResponse + // because they don't have localID and email fields. Remove the specific + // provider manually. + NSMutableDictionary *mutableProviderData = [self->_providerData mutableCopy]; + [mutableProviderData removeObjectForKey:provider]; + self->_providerData = [mutableProviderData copy]; + + if ([provider isEqualToString:FIREmailAuthProviderID]) { + self->_hasEmailPasswordCredential = NO; + } +#if TARGET_OS_IOS + // After successfully unlinking a phone auth provider, remove the phone number + // from the cached user info. + if ([provider isEqualToString:FIRPhoneAuthProviderID]) { + self->_phoneNumber = nil; + } +#endif + + if (response.IDToken && response.refreshToken) { + FIRSecureTokenService *tokenService = [[FIRSecureTokenService alloc] + initWithRequestConfiguration:requestConfiguration + accessToken:response.IDToken + accessTokenExpirationDate:response.approximateExpirationDate + refreshToken:response.refreshToken]; + [self setTokenService:tokenService + callback:^(NSError *_Nullable error) { + completeAndCallbackWithError(error); + }]; + return; + } + if (![self updateKeychain:&error]) { + completeAndCallbackWithError(error); + return; + } + completeAndCallbackWithError(nil); + }]; + }]; + }]; +} + +- (void)sendEmailVerificationWithCompletion:(nullable FIRSendEmailVerificationCallback)completion { + [self sendEmailVerificationWithNullableActionCodeSettings:nil completion:completion]; +} + +- (void)sendEmailVerificationWithActionCodeSettings:(FIRActionCodeSettings *)actionCodeSettings + completion: + (nullable FIRSendEmailVerificationCallback)completion { + [self sendEmailVerificationWithNullableActionCodeSettings:actionCodeSettings + completion:completion]; +} + +/** @fn sendEmailVerificationWithNullableActionCodeSettings:completion: + @brief Initiates email verification for the user. + + @param actionCodeSettings Optionally, a @c FIRActionCodeSettings object containing settings + related to the handling action codes. + */ +- (void)sendEmailVerificationWithNullableActionCodeSettings: + (nullable FIRActionCodeSettings *)actionCodeSettings + completion: + (nullable FIRSendEmailVerificationCallback) + completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + [self + internalGetTokenWithCallback:^(NSString *_Nullable accessToken, NSError *_Nullable error) { + if (error) { + callInMainThreadWithError(completion, error); + return; + } + FIRAuthRequestConfiguration *configuration = self->_auth.requestConfiguration; + FIRGetOOBConfirmationCodeRequest *request = + [FIRGetOOBConfirmationCodeRequest verifyEmailRequestWithAccessToken:accessToken + actionCodeSettings:actionCodeSettings + requestConfiguration:configuration]; + [FIRAuthBackend + getOOBConfirmationCode:request + callback:^(FIRGetOOBConfirmationCodeResponse *_Nullable response, + NSError *_Nullable error) { + [self signOutIfTokenIsInvalidWithError:error]; + callInMainThreadWithError(completion, error); + }]; + }]; + }); +} + +- (void)deleteWithCompletion:(nullable FIRUserProfileChangeCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + [self + internalGetTokenWithCallback:^(NSString *_Nullable accessToken, NSError *_Nullable error) { + if (error) { + callInMainThreadWithError(completion, error); + return; + } + FIRDeleteAccountRequest *deleteUserRequest = + [[FIRDeleteAccountRequest alloc] initWitLocalID:self->_userID + accessToken:accessToken + requestConfiguration:self->_auth.requestConfiguration]; + [FIRAuthBackend deleteAccount:deleteUserRequest + callback:^(NSError *_Nullable error) { + if (error) { + callInMainThreadWithError(completion, error); + return; + } + if (![self->_auth signOutByForceWithUserID:self->_userID + error:&error]) { + callInMainThreadWithError(completion, error); + return; + } + callInMainThreadWithError(completion, error); + }]; + }]; + }); +} + +/** @fn signOutIfTokenIsInvalidWithError: + @brief Signs out this user if the user or the token is invalid. + @param error The error from the server. + */ +- (void)signOutIfTokenIsInvalidWithError:(nullable NSError *)error { + NSInteger errorCode = error.code; + if (errorCode == FIRAuthErrorCodeUserNotFound || errorCode == FIRAuthErrorCodeUserDisabled || + errorCode == FIRAuthErrorCodeInvalidUserToken || + errorCode == FIRAuthErrorCodeUserTokenExpired) { + FIRLogNotice(kFIRLoggerAuth, @"I-AUT000016", + @"Invalid user token detected, user is automatically signed out."); + [_auth signOutByForceWithUserID:_userID error:NULL]; + } +} + +@end + +@implementation FIRUserProfileChangeRequest { + /** @var _user + @brief The user associated with the change request. + */ + FIRUser *_user; + + /** @var _displayName + @brief The display name value to set if @c _displayNameSet is YES. + */ + NSString *_displayName; + + /** @var _displayNameSet + @brief Indicates the display name should be part of the change request. + */ + BOOL _displayNameSet; + + /** @var _photoURL + @brief The photo URL value to set if @c _displayNameSet is YES. + */ + NSURL *_photoURL; + + /** @var _photoURLSet + @brief Indicates the photo URL should be part of the change request. + */ + BOOL _photoURLSet; + + /** @var _consumed + @brief Indicates the @c commitChangesWithCallback: method has already been invoked. + */ + BOOL _consumed; +} + +- (nullable instancetype)initWithUser:(FIRUser *)user { + self = [super init]; + if (self) { + _user = user; + } + return self; +} + +- (nullable NSString *)displayName { + return _displayName; +} + +- (void)setDisplayName:(nullable NSString *)displayName { + dispatch_sync(FIRAuthGlobalWorkQueue(), ^{ + if (self->_consumed) { + [NSException + raise:NSInternalInconsistencyException + format:@"%@", @"Invalid call to setDisplayName: after commitChangesWithCallback:."]; + return; + } + self->_displayNameSet = YES; + self->_displayName = [displayName copy]; + }); +} + +- (nullable NSURL *)photoURL { + return _photoURL; +} + +- (void)setPhotoURL:(nullable NSURL *)photoURL { + dispatch_sync(FIRAuthGlobalWorkQueue(), ^{ + if (self->_consumed) { + [NSException raise:NSInternalInconsistencyException + format:@"%@", @"Invalid call to setPhotoURL: after commitChangesWithCallback:."]; + return; + } + self->_photoURLSet = YES; + self->_photoURL = [photoURL copy]; + }); +} + +/** @fn hasUpdates + @brief Indicates at least one field has a value which needs to be committed. + */ +- (BOOL)hasUpdates { + return _displayNameSet || _photoURLSet; +} + +- (void)commitChangesWithCompletion:(nullable FIRUserProfileChangeCallback)completion { + dispatch_sync(FIRAuthGlobalWorkQueue(), ^{ + if (self->_consumed) { + [NSException raise:NSInternalInconsistencyException + format:@"%@", @"commitChangesWithCallback: should only be called once."]; + return; + } + self->_consumed = YES; + // Return fast if there is nothing to update: + if (![self hasUpdates]) { + callInMainThreadWithError(completion, nil); + return; + } + NSString *displayName = [self->_displayName copy]; + BOOL displayNameWasSet = self->_displayNameSet; + NSURL *photoURL = [self->_photoURL copy]; + BOOL photoURLWasSet = self->_photoURLSet; + [self->_user + executeUserUpdateWithChanges:^(FIRGetAccountInfoResponseUser *user, + FIRSetAccountInfoRequest *request) { + if (photoURLWasSet) { + request.photoURL = photoURL; + } + if (displayNameWasSet) { + request.displayName = displayName; + } + } + callback:^(NSError *_Nullable error) { + if (error) { + callInMainThreadWithError(completion, error); + return; + } + if (displayNameWasSet) { + [self->_user setDisplayName:displayName]; + } + if (photoURLWasSet) { + [self->_user setPhotoURL:photoURL]; + } + if (![self->_user updateKeychain:&error]) { + callInMainThreadWithError(completion, error); + return; + } + callInMainThreadWithError(completion, nil); + }]; + }); +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUserInfoImpl.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUserInfoImpl.h new file mode 100644 index 0000000..8d6b377 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUserInfoImpl.h @@ -0,0 +1,60 @@ +/* + * 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 +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRUserInfo.h" + +@class FIRGetAccountInfoResponseProviderUserInfo; + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRUserInfoImpl : NSObject + +/** @fn userInfoWithGetAccountInfoResponseProviderUserInfo: + @brief A convenience factory method for constructing a @c FIRUserInfo instance from data + returned by the getAccountInfo endpoint. + @param providerUserInfo Data returned by the getAccountInfo endpoint. + @return A new instance of @c FIRUserInfo using data from the getAccountInfo endpoint. + */ ++ (nullable instancetype)userInfoWithGetAccountInfoResponseProviderUserInfo: + (FIRGetAccountInfoResponseProviderUserInfo *)providerUserInfo; + +/** @fn init + @brief This class should not be initialized manually. + @see FIRUser.providerData + */ +- (instancetype)init NS_UNAVAILABLE; + +/** @fn initWithProviderID:userID:displayName:photoURL:email: + @brief Designated initializer. + @param providerID The provider identifier. + @param userID The unique user ID for the user (the value of the @c uid field in the token.) + @param displayName The name of the user. + @param photoURL The URL of the user's profile photo. + @param email The user's email address. + @param phoneNumber The user's phone number. + */ +- (nullable instancetype)initWithProviderID:(NSString *)providerID + userID:(NSString *)userID + displayName:(nullable NSString *)displayName + photoURL:(nullable NSURL *)photoURL + email:(nullable NSString *)email + phoneNumber:(nullable NSString *)phoneNumber + NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUserInfoImpl.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUserInfoImpl.m new file mode 100644 index 0000000..5092606 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUserInfoImpl.m @@ -0,0 +1,131 @@ +/* + * 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 "FirebaseAuth/Sources/User/FIRUserInfoImpl.h" + +#import "FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var kProviderIDCodingKey + @brief The key used to encode the providerID property for NSSecureCoding. + */ +static NSString *const kProviderIDCodingKey = @"providerID"; + +/** @var kUserIDCodingKey + @brief The key used to encode the userID property for NSSecureCoding. + */ +static NSString *const kUserIDCodingKey = @"userID"; + +/** @var kDisplayNameCodingKey + @brief The key used to encode the displayName property for NSSecureCoding. + */ +static NSString *const kDisplayNameCodingKey = @"displayName"; + +/** @var kProfileURLCodingKey + @brief The key used to encode the profileURL property for NSSecureCoding. + */ +static NSString *const kProfileURLCodingKey = @"profileURL"; + +/** @var kPhotoURLCodingKey + @brief The key used to encode the photoURL property for NSSecureCoding. + */ +static NSString *const kPhotoURLCodingKey = @"photoURL"; + +/** @var kEmailCodingKey + @brief The key used to encode the email property for NSSecureCoding. + */ +static NSString *const kEmailCodingKey = @"email"; + +/** @var kPhoneNumberCodingKey + @brief The key used to encode the phoneNumber property for NSSecureCoding. + */ +static NSString *const kPhoneNumberCodingKey = @"phoneNumber"; + +@implementation FIRUserInfoImpl + +@synthesize providerID = _providerID; +@synthesize uid = _userID; +@synthesize displayName = _displayName; +@synthesize photoURL = _photoURL; +@synthesize email = _email; +@synthesize phoneNumber = _phoneNumber; + ++ (nullable instancetype)userInfoWithGetAccountInfoResponseProviderUserInfo: + (FIRGetAccountInfoResponseProviderUserInfo *)providerUserInfo { + return [[self alloc] initWithProviderID:providerUserInfo.providerID + userID:providerUserInfo.federatedID + displayName:providerUserInfo.displayName + photoURL:providerUserInfo.photoURL + email:providerUserInfo.email + phoneNumber:providerUserInfo.phoneNumber]; +} + +- (nullable instancetype)initWithProviderID:(NSString *)providerID + userID:(NSString *)userID + displayName:(nullable NSString *)displayName + photoURL:(nullable NSURL *)photoURL + email:(nullable NSString *)email + phoneNumber:(nullable NSString *)phoneNumber { + self = [super init]; + if (self) { + _providerID = [providerID copy]; + _userID = [userID copy]; + _displayName = [displayName copy]; + _photoURL = [photoURL copy]; + _email = [email copy]; + _phoneNumber = [phoneNumber copy]; + } + return self; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + NSString *providerID = [aDecoder decodeObjectOfClass:[NSString class] + forKey:kProviderIDCodingKey]; + NSString *userID = [aDecoder decodeObjectOfClass:[NSString class] forKey:kUserIDCodingKey]; + NSString *displayName = [aDecoder decodeObjectOfClass:[NSString class] + forKey:kDisplayNameCodingKey]; + NSURL *photoURL = [aDecoder decodeObjectOfClass:[NSURL class] forKey:kPhotoURLCodingKey]; + NSString *email = [aDecoder decodeObjectOfClass:[NSString class] forKey:kEmailCodingKey]; + NSString *phoneNumber = [aDecoder decodeObjectOfClass:[NSString class] + forKey:kPhoneNumberCodingKey]; + + return [self initWithProviderID:providerID + userID:userID + displayName:displayName + photoURL:photoURL + email:email + phoneNumber:phoneNumber]; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:_providerID forKey:kProviderIDCodingKey]; + [aCoder encodeObject:_userID forKey:kUserIDCodingKey]; + [aCoder encodeObject:_displayName forKey:kDisplayNameCodingKey]; + [aCoder encodeObject:_photoURL forKey:kPhotoURLCodingKey]; + [aCoder encodeObject:_email forKey:kEmailCodingKey]; + [aCoder encodeObject:_phoneNumber forKey:kPhoneNumberCodingKey]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUserMetadata.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUserMetadata.m new file mode 100644 index 0000000..ba46ebd --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUserMetadata.m @@ -0,0 +1,64 @@ +/* + * 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 "FirebaseAuth/Sources/User/FIRUserMetadata_Internal.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRUserMetadata + +/** @var kCreationDateCodingKey + @brief The key used to encode the creationDate property for NSSecureCoding. + */ +static NSString *const kCreationDateCodingKey = @"creationDate"; + +/** @var kLastSignInDateCodingKey + @brief The key used to encode the lastSignInDate property for NSSecureCoding. + */ +static NSString *const kLastSignInDateCodingKey = @"lastSignInDate"; + +- (instancetype)initWithCreationDate:(nullable NSDate *)creationDate + lastSignInDate:(nullable NSDate *)lastSignInDate { + self = [super init]; + if (self) { + _creationDate = [creationDate copy]; + _lastSignInDate = [lastSignInDate copy]; + } + return self; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + NSDate *creationDate = [aDecoder decodeObjectOfClass:[NSDate class] + forKey:kCreationDateCodingKey]; + NSDate *lastSignInDate = [aDecoder decodeObjectOfClass:[NSDate class] + forKey:kLastSignInDateCodingKey]; + return [self initWithCreationDate:creationDate lastSignInDate:lastSignInDate]; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:_creationDate forKey:kCreationDateCodingKey]; + [aCoder encodeObject:_lastSignInDate forKey:kLastSignInDateCodingKey]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUserMetadata_Internal.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUserMetadata_Internal.h new file mode 100644 index 0000000..20a19de --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUserMetadata_Internal.h @@ -0,0 +1,37 @@ +/* + * 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 +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRUserMetadata.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @extension FIRUserMetadata + @brief An internal class used to expose internal methods of FIRUserMetadata. + */ +@interface FIRUserMetadata () + +/** @fn initWithCreationDate:lastSignInDate: + @brief Designated initializer. + @param creationDate The creation date of the corresponding user. + @param lastSignInDate The date of the last recorded sign-in of the corresponding user. + */ +- (instancetype)initWithCreationDate:(nullable NSDate *)creationDate + lastSignInDate:(nullable NSDate *)lastSignInDate NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUser_Internal.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUser_Internal.h new file mode 100644 index 0000000..54524f2 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/User/FIRUser_Internal.h @@ -0,0 +1,107 @@ +/* + * 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 "FirebaseAuth/Sources/Public/FirebaseAuth/FIRUser.h" + +@class FIRAuth; +@class FIRAuthRequestConfiguration; + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRRetrieveUserCallback + @brief The type of block that is invoked when the construction of a user succeeds or fails. + @param user The user that was constructed, or nil if user construction failed. + @param error The error which occurred, or nil if the request was successful. + */ +typedef void (^FIRRetrieveUserCallback)(FIRUser *_Nullable user, NSError *_Nullable error); + +/** @typedef FIRVerifyBeforeUpdateEmailCallback + @brief The type of block called when a request to verify before update email has finished. + @param error Optionally; the error which occurred - or nil if the request was successful. + */ +typedef void (^FIRVerifyBeforeUpdateEmailCallback)(NSError *_Nullable error); + +@interface FIRUser () + +/** @property rawAccessToken + @brief The cached access token. + @remarks This method is specifically for providing the access token to internal clients during + deserialization and sign-in events, and should not be used to retrieve the access token by + anyone else. + */ +@property(nonatomic, copy, readonly) NSString *rawAccessToken; + +/** @property auth + @brief A weak reference to a FIRAuth instance associated with this instance. + */ +@property(nonatomic, weak) FIRAuth *auth; + +/** @property auth + @brief A strong reference to a requestConfiguration instance associated with this user instance. + */ +@property(nonatomic, strong) FIRAuthRequestConfiguration *requestConfiguration; + +/** @var accessTokenExpirationDate + @brief The expiration date of the cached access token. + */ +@property(nonatomic, copy, readonly) NSDate *accessTokenExpirationDate; + +/** @fn retrieveUserWithAuth:accessToken:accessTokenExpirationDate:refreshToken:callback: + @brief Constructs a user with Secure Token Service tokens, and obtains user details from the + getAccountInfo endpoint. + @param auth The associated FIRAuth instance. + @param accessToken The Secure Token Service access token. + @param accessTokenExpirationDate The approximate expiration date of the access token. + @param refreshToken The Secure Token Service refresh token. + @param anonymous Whether or not the user is anonymous. + @param callback A block which is invoked when the construction succeeds or fails. Invoked + asynchronously on the auth global work queue in the future. + */ ++ (void)retrieveUserWithAuth:(FIRAuth *)auth + accessToken:(nullable NSString *)accessToken + accessTokenExpirationDate:(nullable NSDate *)accessTokenExpirationDate + refreshToken:(nullable NSString *)refreshToken + anonymous:(BOOL)anonymous + callback:(FIRRetrieveUserCallback)callback; + +/** @fn internalGetTokenForcingRefresh:callback: + @brief Retrieves the Firebase authentication token, possibly refreshing it if it has expired. + @param forceRefresh Forces a token refresh. Useful if the token becomes invalid for some reason + other than an expiration. + @param callback The block to invoke when the token is available. Invoked asynchronously on the + global work thread in the future. + */ +- (void)internalGetTokenForcingRefresh:(BOOL)forceRefresh + callback:(nonnull FIRAuthTokenCallback)callback; + +/** @fn internalVerifyBeforeUpdateEmailWithNewEmail:actionCodeSettings:callback: + @brief Sends a verification email to newEmail. Upon redemption of the link in the email, + this user's email will be changed to newEmail and that email will be marked verified. + @param newEmail the user's new email. + @param actionCodeSettings the optional FIRActionCodeSettings object to allow linking back + to your app in the email. + @param completion The block to invoke when the call succeeds or fails. Invoked asynchronously on + the global work thread in the future. + + */ +- (void)internalVerifyBeforeUpdateEmailWithNewEmail:(NSString *)newEmail + actionCodeSettings: + (nullable FIRActionCodeSettings *)actionCodeSettings + completion:(FIRVerifyBeforeUpdateEmailCallback)completion; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthDefaultUIDelegate.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthDefaultUIDelegate.h new file mode 100644 index 0000000..4946d16 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthDefaultUIDelegate.h @@ -0,0 +1,47 @@ +/* + * 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 +#if !TARGET_OS_OSX && !TARGET_OS_WATCH + +#import +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthUIDelegate.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRAuthDefaultUIDelegate + @brief Class responsible for providing a default FIRAuthUIDelegte. + @remarks This class should be used in the case that a UIDelegate was expected and necessary to + continue a given flow, but none was provided. + */ +@interface FIRAuthDefaultUIDelegate : NSObject + +/** @fn defaultUIDelegate + @brief Unavailable. Please use @c +defaultUIDelegate: + */ +- (instancetype)init NS_UNAVAILABLE; + +/** @fn defaultUIDelegate + @brief Returns a default FIRAuthUIDelegate object. + @return The default FIRAuthUIDelegate object. + */ ++ (id)defaultUIDelegate; + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthDefaultUIDelegate.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthDefaultUIDelegate.m new file mode 100644 index 0000000..7b421a2 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthDefaultUIDelegate.m @@ -0,0 +1,126 @@ +/* + * 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 +#if !TARGET_OS_OSX && !TARGET_OS_WATCH + +#import +#import + +#import "FirebaseAuth/Sources/Utilities/FIRAuthDefaultUIDelegate.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRAuthDefaultUIDelegate () + +/** @fn initWithViewController: + @brief Initializes the instance with a view controller. + @param viewController The view controller as the presenting view controller in @c + FIRAuthUIDelegate. + @return The initialized instance. + */ +- (instancetype)initWithViewController:(nullable UIViewController *)viewController + NS_DESIGNATED_INITIALIZER; + +@end + +@implementation FIRAuthDefaultUIDelegate { + /** @var _viewController + @brief The presenting view controller. + */ + UIViewController *_viewController; +} + +- (instancetype)initWithViewController:(nullable UIViewController *)viewController { + self = [super init]; + if (self) { + _viewController = viewController; + } + return self; +} + +- (void)presentViewController:(UIViewController *)viewControllerToPresent + animated:(BOOL)flag + completion:(nullable void (^)(void))completion { + [_viewController presentViewController:viewControllerToPresent + animated:flag + completion:completion]; +} + +- (void)dismissViewControllerAnimated:(BOOL)flag completion:(nullable void (^)(void))completion { + [_viewController dismissViewControllerAnimated:flag completion:completion]; +} + ++ (id)defaultUIDelegate { + // iOS App extensions should not call [UIApplication sharedApplication], even if UIApplication + // responds to it. + static Class applicationClass = nil; + if (![GULAppEnvironmentUtil isAppExtension]) { + Class cls = NSClassFromString(@"UIApplication"); + if (cls && [cls respondsToSelector:NSSelectorFromString(@"sharedApplication")]) { + applicationClass = cls; + } + } + + UIViewController *topViewController; +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 + if (@available(iOS 13.0, tvOS 13.0, *)) { + UIApplication *application = [applicationClass sharedApplication]; + NSSet *connectedScenes = application.connectedScenes; + for (UIScene *scene in connectedScenes) { + if ([scene isKindOfClass:[UIWindowScene class]]) { + UIWindowScene *windowScene = (UIWindowScene *)scene; + for (UIWindow *window in windowScene.windows) { + if (window.isKeyWindow) { + topViewController = window.rootViewController; + } + } + } + } + } else { + UIApplication *application = [applicationClass sharedApplication]; +// iOS 13 deprecation +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + topViewController = application.keyWindow.rootViewController; +#pragma clang diagnostic pop + } +#else + UIApplication *application = [applicationClass sharedApplication]; + topViewController = application.keyWindow.rootViewController; +#endif + + while (true) { + if (topViewController.presentedViewController) { + topViewController = topViewController.presentedViewController; + } else if ([topViewController isKindOfClass:[UINavigationController class]]) { + UINavigationController *nav = (UINavigationController *)topViewController; + topViewController = nav.topViewController; + } else if ([topViewController isKindOfClass:[UITabBarController class]]) { + UITabBarController *tab = (UITabBarController *)topViewController; + topViewController = tab.selectedViewController; + } else { + break; + } + } + return [[FIRAuthDefaultUIDelegate alloc] initWithViewController:topViewController]; +} + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h new file mode 100644 index 0000000..11136ab --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h @@ -0,0 +1,613 @@ +/* + * 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 +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuth.h" +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorInfo.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthInternalErrors.h" + +@class FIRAuthCredential; + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRAuthErrorUtils + @brief Utility class used to construct @c NSError instances. + */ +@interface FIRAuthErrorUtils : NSObject + ++ (NSError *)errorWithCode:(FIRAuthInternalErrorCode)code message:(nullable NSString *)message; + +/** @fn RPCRequestEncodingErrorWithUnderlyingError + @brief Constructs an @c NSError with the @c FIRAuthInternalErrorCodeRPCRequestEncodingError + code and a populated @c NSUnderlyingErrorKey in the @c NSError.userInfo dictionary. + @param underlyingError The value of the @c NSUnderlyingErrorKey key. + @remarks This error is used when an @c FIRAuthRPCRequest.unencodedHTTPRequestBodyWithError: + invocation returns an error. The error returned is wrapped in this internal error code. + */ ++ (NSError *)RPCRequestEncodingErrorWithUnderlyingError:(NSError *)underlyingError; + +/** @fn JSONSerializationErrorForUnencodableType + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeJSONSerializationError code. + @remarks This error is used when an @c NSJSONSerialization.isValidJSONObject: check fails, not + for when an error is returned from @c NSJSONSerialization.dataWithJSONObject:options:error:. + */ ++ (NSError *)JSONSerializationErrorForUnencodableType; + +/** @fn JSONSerializationErrorWithUnderlyingError: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeJSONSerializationError code, and the + @c underlyingError as the @c NSUnderlyingErrorKey value in the @c NSError.userInfo + dictionary. + @param underlyingError The value of the @c NSUnderlyingErrorKey key. + @remarks This error is used when an invocation of + @c NSJSONSerialization.dataWithJSONObject:options:error: returns an error. + */ ++ (NSError *)JSONSerializationErrorWithUnderlyingError:(NSError *)underlyingError; + +/** @fn networkErrorWithUnderlyingError: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeNetworkError code, and the + @c underlyingError as the @c NSUnderlyingErrorKey value in the @c NSError.userInfo + dictionary. + @param underlyingError The value of the @c NSUnderlyingErrorKey key. Should be the error from + GTM. + @remarks This error is used when a network request results in an error, and no body data was + returned. + */ ++ (NSError *)networkErrorWithUnderlyingError:(NSError *)underlyingError; + +/** @fn unexpectedErrorResponseWithUnderlyingError: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeNetworkError code, and the + @c underlyingError as the @c NSUnderlyingErrorKey value. + @param data The value of the @c FIRAuthErrorUserInfoDataKey key in the @c NSError.userInfo + dictionary. + @param underlyingError The value of the @c NSUnderlyingErrorKey key in the @c NSError.userInfo + dictionary. + @remarks This error is used when a network request results in an error, and unserializable body + data was returned. + */ ++ (NSError *)unexpectedErrorResponseWithData:(NSData *)data + underlyingError:(NSError *)underlyingError; + +/** @fn unexpectedErrorResponseWithDeserializedResponse: + @brief Constructs an @c NSError with the @c FIRAuthInternalErrorCodeUnexpectedErrorResponse + code, and a populated @c FIRAuthErrorUserInfoDeserializedResponseKey key in the + @c NSError.userInfo dictionary. + @param deserializedResponse The value of the @c FIRAuthErrorUserInfoDeserializedResponseKey key. + @remarks This error is used when a network request results in an error, and the body data was + deserializable as JSON, but couldn't be decoded as an error. + */ ++ (NSError *)unexpectedErrorResponseWithDeserializedResponse:(id)deserializedResponse; + +/** @fn unexpectedErrorResponseWithDeserializedResponse:underlyingError: + @brief Constructs an @c NSError with the @c FIRAuthInternalErrorCodeUnexpectedErrorResponse + code, and populated @c FIRAuthErrorUserInfoDeserializedResponseKey and + @c NSUnderlyingErrorKey keys in the @c NSError.userInfo dictionary. + @param deserializedResponse The value of the @c FIRAuthErrorUserInfoDeserializedResponseKey key. + @param underlyingError The value of the @c NSUnderlyingErrorKey key. + @remarks This error is used when a network request results in an error, and the body data was + deserializable as JSON, but couldn't be decoded as an error. + */ ++ (NSError *)unexpectedErrorResponseWithDeserializedResponse:(id)deserializedResponse + underlyingError:(NSError *)underlyingError; + +/** @fn malformedJWTErrorWithToken:underlyingError: + @brief Constructs an @c NSError with the code set to @c FIRAuthErrorCodeMalformedJWT and + populates the userInfo dictionary with an error message, the bad token, and an underlying + error that may have occurred when parsing. + @param token The token that failed to parse. + @param underlyingError The error that caused this error. If this parameter is nil, the + NSUnderlyingErrorKey value will not be set. + @remarks This error is returned when JWT parsing fails. + @return An @c FIRAuthErrorCodeMalformedJWT error wrapping an underlying error, if available. + */ ++ (NSError *)malformedJWTErrorWithToken:(NSString *)token + underlyingError:(NSError *_Nullable)underlyingError; + +/** @fn unexpectedResponseWithData:underlyingError: + @brief Constructs an @c NSError with the @c FIRAuthInternalErrorCodeUnexpectedResponse + code, and a populated @c FIRAuthErrorUserInfoDataKey key in the @c NSError.userInfo + dictionary. + @param data The value of the @c FIRAuthErrorUserInfoDataKey key in the @c NSError.userInfo + dictionary. + @param underlyingError The value of the @c NSUnderlyingErrorKey key in the @c NSError.userInfo + dictionary. + @remarks This error is used when a network request is apparently successful, but the body data + couldn't be deserialized as JSON. + */ ++ (NSError *)unexpectedResponseWithData:(NSData *)data underlyingError:(NSError *)underlyingError; +; + +/** @fn unexpectedResponseWithDeserializedResponse: + @brief Constructs an @c NSError with the @c FIRAuthInternalErrorCodeUnexpectedResponse + code, and a populated @c FIRAuthErrorUserInfoDeserializedResponseKey key in the + @c NSError.userInfo dictionary. + @param deserializedResponse The value of the @c FIRAuthErrorUserInfoDeserializedResponseKey key. + @remarks This error is used when a network request is apparently successful, the body data was + successfully deserialized as JSON, but the JSON wasn't a dictionary. + */ ++ (NSError *)unexpectedResponseWithDeserializedResponse:(id)deserializedResponse; + +/** @fn unexpectedResponseWithDeserializedResponse:underlyingError: + @brief Constructs an @c NSError with the @c FIRAuthInternalErrorCodeUnexpectedResponse + code, and populated @c FIRAuthErrorUserInfoDeserializedResponseKey and + @c NSUnderlyingErrorKey keys in the @c NSError.userInfo dictionary. + @param deserializedResponse The value of the @c FIRAuthErrorUserInfoDeserializedResponseKey key. + @param underlyingError The value of the @c NSUnderlyingErrorKey key. + @remarks This error is used when a network request was apparently successful, the body data was + successfully deserialized as JSON, but the data type of the response was unexpected. + */ ++ (NSError *)unexpectedResponseWithDeserializedResponse:(nullable id)deserializedResponse + underlyingError:(NSError *)underlyingError; + +/** @fn RPCResponseDecodingErrorWithDeserializedResponse:underlyingError: + @brief Constructs an @c NSError with the @c FIRAuthInternalErrorCodeRPCResponseDecodingError + code, and populated @c FIRAuthErrorUserInfoDeserializedResponseKey and + @c NSUnderlyingErrorKey keys in the @c NSError.userInfo dictionary. + @param deserializedResponse The value of the @c FIRAuthErrorUserInfoDeserializedResponseKey key. + @param underlyingError The value of the @c NSUnderlyingErrorKey key. + @remarks This error is used when an invocation of @c FIRAuthRPCResponse.setWithDictionary:error: + resulted in an error. + */ ++ (NSError *)RPCResponseDecodingErrorWithDeserializedResponse:(id)deserializedResponse + underlyingError:(NSError *)underlyingError; + +/** @fn emailAlreadyInUseErrorWithEmail: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeEmailExists code. + @param email The email address that is already in use. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)emailAlreadyInUseErrorWithEmail:(nullable NSString *)email; + +/** @fn userDisabledErrorWithMessageWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeUserDisabled code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)userDisabledErrorWithMessage:(nullable NSString *)message; + +/** @fn wrongPasswordErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeWrongPassword code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)wrongPasswordErrorWithMessage:(nullable NSString *)message; + +/** @fn tooManyRequestsErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeTooManyRequests Code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)tooManyRequestsErrorWithMessage:(nullable NSString *)message; + +/** @fn invalidCustomTokenErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidCustomToken code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)invalidCustomTokenErrorWithMessage:(nullable NSString *)message; + +/** @fn customTokenMistmatchErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeCustomTokenMismatch code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)customTokenMistmatchErrorWithMessage:(nullable NSString *)message; + +/** @fn invalidCredentialErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidCredential code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)invalidCredentialErrorWithMessage:(nullable NSString *)message; + +/** @fn requiresRecentLoginError + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeRequiresRecentLogin code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)requiresRecentLoginErrorWithMessage:(nullable NSString *)message; + +/** @fn invalidUserTokenErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidUserToken code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)invalidUserTokenErrorWithMessage:(nullable NSString *)message; + +/** @fn invalidEmailErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidEmail code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)invalidEmailErrorWithMessage:(nullable NSString *)message; + +/** @fn accountExistsWithDifferentCredentialErrorWithEmail: + @brief Constructs an @c NSError with the @c FIRAuthErrorAccountExistsWithDifferentCredential + code. + @param email The email address that is already associated with an existing account + @param updatedCredential The updated credential for the existing account + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)accountExistsWithDifferentCredentialErrorWithEmail:(nullable NSString *)email + updatedCredential: + (nullable FIRAuthCredential *)updatedCredential; + +/** @fn providerAlreadyLinkedErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeProviderAlreadyLinked code. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)providerAlreadyLinkedError; + +/** @fn noSuchProviderError + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeNoSuchProvider code. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)noSuchProviderError; + +/** @fn userTokenExpiredErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeUserTokenExpired code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)userTokenExpiredErrorWithMessage:(nullable NSString *)message; + +/** @fn userNotFoundErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeUserNotFound code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)userNotFoundErrorWithMessage:(nullable NSString *)message; + +/** @fn invalidLocalAPIKeyErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidAPIKey code. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)invalidAPIKeyError; + +/** @fn userMismatchError + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeUserMismatch code. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)userMismatchError; + +/** @fn credentialAlreadyInUseErrorWithMessage:email: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeCredentialAlreadyInUse code. + @param message Error message from the backend, if any. + @param credential Auth credential to be added to the Error User Info dictionary. + @param email Email to be added to the Error User Info dictionary. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)credentialAlreadyInUseErrorWithMessage:(nullable NSString *)message + credential:(nullable FIRAuthCredential *)credential + email:(nullable NSString *)email; +/** @fn operationNotAllowedErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeOperationNotAllowed code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)operationNotAllowedErrorWithMessage:(nullable NSString *)message; + +/** @fn weakPasswordErrorWithServerResponseReason: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeWeakPassword code. + @param serverResponseReason A more detailed explanation string from server response. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)weakPasswordErrorWithServerResponseReason:(nullable NSString *)serverResponseReason; + +/** @fn appNotAuthorizedError + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeAppNotAuthorized code. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)appNotAuthorizedError; + +/** @fn expiredActionCodeErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeExpiredActionCode code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)expiredActionCodeErrorWithMessage:(nullable NSString *)message; + +/** @fn invalidActionCodeErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidActionCode code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)invalidActionCodeErrorWithMessage:(nullable NSString *)message; + +/** @fn invalidMessagePayloadError: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidMessagePayload code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)invalidMessagePayloadErrorWithMessage:(nullable NSString *)message; + +/** @fn invalidSenderErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidSender code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)invalidSenderErrorWithMessage:(nullable NSString *)message; + +/** @fn invalidRecipientEmailError: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidRecipientEmail code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)invalidRecipientEmailErrorWithMessage:(nullable NSString *)message; + +/** @fn missingIosBundleIDErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeMissingIosBundleID code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)missingIosBundleIDErrorWithMessage:(nullable NSString *)message; + +/** @fn missingAndroidPackageNameErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeMissingAndroidPackageName code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)missingAndroidPackageNameErrorWithMessage:(nullable NSString *)message; + +/** @fn unauthorizedDomainErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeUnauthorizedDomain code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)unauthorizedDomainErrorWithMessage:(nullable NSString *)message; + +/** @fn invalidContinueURIErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidContinueURI code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)invalidContinueURIErrorWithMessage:(nullable NSString *)message; + +/** @fn missingContinueURIErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeMissingContinueURI code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)missingContinueURIErrorWithMessage:(nullable NSString *)message; + +/** @fn missingEmailErrorWithMessage + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeMissingEmail code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)missingEmailErrorWithMessage:(nullable NSString *)message; + +/** @fn missingPhoneNumberErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeMissingPhoneNumber code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)missingPhoneNumberErrorWithMessage:(nullable NSString *)message; + +/** @fn invalidPhoneNumberErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidPhoneNumber code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)invalidPhoneNumberErrorWithMessage:(nullable NSString *)message; + +/** @fn missingVerificationCodeErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeMissingVerificationCode code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)missingVerificationCodeErrorWithMessage:(nullable NSString *)message; + +/** @fn invalidVerificationCodeErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidVerificationCode code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)invalidVerificationCodeErrorWithMessage:(nullable NSString *)message; + +/** @fn missingVerificationIDErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeMissingVerificationID code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)missingVerificationIDErrorWithMessage:(nullable NSString *)message; + +/** @fn invalidVerificationIDErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidVerificationID code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)invalidVerificationIDErrorWithMessage:(nullable NSString *)message; + +/** @fn sessionExpiredErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeSessionExpired code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)sessionExpiredErrorWithMessage:(nullable NSString *)message; + +/** @fn missingAppCredentialWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorMissingCredential code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)missingAppCredentialWithMessage:(nullable NSString *)message; + +/** @fn invalidAppCredentialWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorInvalidCredential code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)invalidAppCredentialWithMessage:(nullable NSString *)message; + +/** @fn quotaExceededErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeQuotaExceeded code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)quotaExceededErrorWithMessage:(nullable NSString *)message; + +/** @fn missingAppTokenErrorWithUnderlyingError + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeMissingAppToken code. + @param underlyingError The underlying error, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)missingAppTokenErrorWithUnderlyingError:(nullable NSError *)underlyingError; + +/** @fn localPlayerNotAuthenticatedError + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeLocalPlayerNotAuthenticated code. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)localPlayerNotAuthenticatedError; + +/** @fn gameKitNotLinkedError + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeGameKitNotLinked code. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)gameKitNotLinkedError; + +/** @fn notificationNotForwardedError + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeNotificationNotForwarded code. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)notificationNotForwardedError; + +#if TARGET_OS_IOS +/** @fn secondFactorRequiredError + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeSecondFactorRequired code. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *) + secondFactorRequiredErrorWithPendingCredential:(NSString *)MFAPendingCredential + hints:(NSArray *)multiFactorInfo + auth:(FIRAuth *)auth; +#endif + +/** @fn appNotVerifiedErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeAppNotVerified code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)appNotVerifiedErrorWithMessage:(nullable NSString *)message; + +/** @fn missingClientIdentifierErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeMissingClientIdentifier code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)missingClientIdentifierErrorWithMessage:(nullable NSString *)message; + +/** @fn captchaCheckFailedErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCaptchaCheckFailed code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)captchaCheckFailedErrorWithMessage:(nullable NSString *)message; + +/** @fn webContextAlreadyPresentedErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeWebContextAlreadyPresented code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)webContextAlreadyPresentedErrorWithMessage:(nullable NSString *)message; + +/** @fn webContextCancelledErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeWebContextCancelled code. + @param message Error message from the backend, if any. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)webContextCancelledErrorWithMessage:(nullable NSString *)message; + +/** @fn appVerificationUserInteractionFailureWithReason: + @brief Constructs an @c NSError with the @c + FIRAuthErrorCodeAppVerificationUserInteractionFailure code. + @param reason Reason for error, returned via URL response. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)appVerificationUserInteractionFailureWithReason:(NSString *)reason; + +/** @fn webSignInUserInteractionFailureWithReason: + @brief Constructs an @c NSError with the @c + FIRAuthErrorCodeWebSignInUserInteractionFailure code. + @param reason Reason for error, returned via URL response. + @return The NSError instance associated with the given FIRAuthError. + */ ++ (NSError *)webSignInUserInteractionFailureWithReason:(nullable NSString *)reason; + +/** @fn URLResponseErrorWithCode:message: + @brief Constructs an @c NSError with the code and message provided. + @param message Error message from the backend, if any. + @return The nullable NSError instance associated with the given error message, if one is found. + */ ++ (nullable NSError *)URLResponseErrorWithCode:(NSString *)code + message:(nullable NSString *)message; + +/** @fn nullUserErrorWithMessage: + @brief Constructs an @c NSError with the code and message provided. + @param message Error message from the backend, if any. + @return The nullable NSError instance associated with the given error message, if one is found. + */ ++ (NSError *)nullUserErrorWithMessage:(nullable NSString *)message; + +/** @fn invalidProviderIDErrorWithMessage: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeInvalidProviderID code. + @param message Error message from the backend, if any. + @remarks This error indicates that the provider id given for the web operation is invalid. + */ ++ (NSError *)invalidProviderIDErrorWithMessage:(nullable NSString *)message; + +/** @fn invalidDynamicLinkDomainErrorWithMessage: + @brief Constructs an @c NSError with the code and message provided. + @param message Error message from the backend, if any. + @return The nullable NSError instance associated with the given error message, if one is found. + */ ++ (NSError *)invalidDynamicLinkDomainErrorWithMessage:(nullable NSString *)message; + +/** @fn keychainErrorWithFunction:status: + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeKeychainError code. + @param keychainFunction The keychain function which was invoked and yielded an unexpected + response. The @c NSLocalizedFailureReasonErrorKey field in the @c NSError.userInfo + dictionary will contain a string partially comprised of this value. + @param status The response status from the invoked keychain function. The + @c NSLocalizedFailureReasonErrorKey field in the @c NSError.userInfo dictionary will contain + a string partially comprised of this value. + */ ++ (NSError *)keychainErrorWithFunction:(NSString *)keychainFunction status:(OSStatus)status; + +/** @fn missingOrInvalidNonceErrorWithMessage: + @brief Constructs an @c NSError with the code and message provided. + @param message Error message from the backend, if any. + @return The nullable NSError instance associated with the given error message, if one is found. +*/ ++ (NSError *)missingOrInvalidNonceErrorWithMessage:(nullable NSString *)message; + +/** @fn tenantIDMismatchError + @brief Constructs an @c NSError with the @c FIRAuthErrorCodeTenantIDMismatch code. + @remarks This error is used when an attempt is made to update the current user with a + tenantId that differs from the current FirebaseAuth instance's tenantId. + */ ++ (NSError *)tenantIDMismatchError; + +/** @fn unsupportedTenantOperationError + @brief Constructs an @c NSError with the @c FIRUnsupportedTenantOperation code. + @remarks This error indicates the operation is not supported in a multi-tenant context. + */ ++ (NSError *)unsupportedTenantOperationError; + ++ (NSError *)blockingCloudFunctionServerResponseWithMessage:(nullable NSString *)message; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.m new file mode 100644 index 0000000..e2aa5d6 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.m @@ -0,0 +1,1448 @@ +/* + * 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 "FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h" + +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthCredential.h" + +#import "FirebaseAuth/Sources/MultiFactor/FIRMultiFactorResolver+Internal.h" + +NS_ASSUME_NONNULL_BEGIN + +NSString *const FIRAuthErrorDomain = @"FIRAuthErrorDomain"; + +NSString *const FIRAuthInternalErrorDomain = @"FIRAuthInternalErrorDomain"; + +NSString *const FIRAuthErrorUserInfoDeserializedResponseKey = + @"FIRAuthErrorUserInfoDeserializedResponseKey"; + +NSString *const FIRAuthErrorUserInfoDataKey = @"FIRAuthErrorUserInfoDataKey"; + +NSString *const FIRAuthErrorUserInfoEmailKey = @"FIRAuthErrorUserInfoEmailKey"; + +NSString *const FIRAuthErrorUserInfoUpdatedCredentialKey = + @"FIRAuthErrorUserInfoUpdatedCredentialKey"; + +NSString *const FIRAuthErrorUserInfoNameKey = @"FIRAuthErrorUserInfoNameKey"; + +NSString *const FIRAuthErrorUserInfoMultiFactorResolverKey = + @"FIRAuthErrorUserInfoMultiFactorResolverKey"; + +/** @var kServerErrorDetailMarker + @brief This marker indicates that the server error message contains a detail error message which + should be used instead of the hardcoded client error message. + */ +static NSString *const kServerErrorDetailMarker = @" : "; + +#pragma mark - URL response error codes + +/** @var kURLResponseErrorCodeInvalidClientID + @brief Error code that indicates that the client ID provided was invalid. + */ +static NSString *const kURLResponseErrorCodeInvalidClientID = @"auth/invalid-oauth-client-id"; + +/** @var kURLResponseErrorCodeNetworkRequestFailed + @brief Error code that indicates that a network request within the SFSafariViewController or + WKWebView failed. + */ +static NSString *const kURLResponseErrorCodeNetworkRequestFailed = @"auth/network-request-failed"; + +/** @var kURLResponseErrorCodeInternalError + @brief Error code that indicates that an internal error occurred within the + SFSafariViewController or WKWebView failed. + */ +static NSString *const kURLResponseErrorCodeInternalError = @"auth/internal-error"; + +#pragma mark - Standard Error Messages + +/** @var kFIRAuthErrorMessageInvalidCustomToken + @brief Message for @c FIRAuthErrorCodeInvalidCustomToken error code. + */ +static NSString *const kFIRAuthErrorMessageInvalidCustomToken = + @"The custom token format is " + "incorrect. Please check the documentation."; + +/** @var kFIRAuthErrorMessageCustomTokenMismatch + @brief Message for @c FIRAuthErrorCodeCustomTokenMismatch error code. + */ +static NSString *const kFIRAuthErrorMessageCustomTokenMismatch = @"The custom token corresponds to " + "a different audience or issuer."; + +/** @var kFIRAuthErrorMessageInvalidEmail + @brief Message for @c FIRAuthErrorCodeInvalidEmail error code. + */ +static NSString *const kFIRAuthErrorMessageInvalidEmail = @"The email address is badly formatted."; + +/** @var kFIRAuthErrorMessageInvalidCredential + @brief Message for @c FIRAuthErrorCodeInvalidCredential error code. + */ +static NSString *const kFIRAuthErrorMessageInvalidCredential = @"The supplied auth credential is " + "malformed or has expired."; + +/** @var kFIRAuthErrorMessageUserDisabled + @brief Message for @c FIRAuthErrorCodeUserDisabled error code. + */ +static NSString *const kFIRAuthErrorMessageUserDisabled = @"The user account has been disabled by " + "an administrator."; + +/** @var kFIRAuthErrorMessageEmailAlreadyInUse + @brief Message for @c FIRAuthErrorCodeEmailAlreadyInUse error code. + */ +static NSString *const kFIRAuthErrorMessageEmailAlreadyInUse = @"The email address is already in " + "use by another account."; + +/** @var kFIRAuthErrorMessageWrongPassword + @brief Message for @c FIRAuthErrorCodeWrongPassword error code. + */ +static NSString *const kFIRAuthErrorMessageWrongPassword = @"The password is invalid or the user " + "does not have a password."; + +/** @var kFIRAuthErrorMessageTooManyRequests + @brief Message for @c FIRAuthErrorCodeTooManyRequests error code. + */ +static NSString *const kFIRAuthErrorMessageTooManyRequests = + @"We have blocked all requests from " + "this device due to unusual activity. Try again later."; + +/** @var kFIRAuthErrorMessageAccountExistsWithDifferentCredential + @brief Message for @c FIRAuthErrorCodeAccountExistsWithDifferentCredential error code. + */ +static NSString *const kFIRAuthErrorMessageAccountExistsWithDifferentCredential = + @"An account " + "already exists with the same email address but different sign-in credentials. Sign in using " + "a " + "provider associated with this email address."; + +/** @var kFIRAuthErrorMessageRequiresRecentLogin + @brief Message for @c FIRAuthErrorCodeRequiresRecentLogin error code. + */ +static NSString *const kFIRAuthErrorMessageRequiresRecentLogin = + @"This operation is sensitive and " + "requires recent authentication. Log in again before retrying this request."; + +/** @var kFIRAuthErrorMessageProviderAlreadyLinked + @brief Message for @c FIRAuthErrorCodeProviderAlreadyExists error code. + */ +static NSString *const kFIRAuthErrorMessageProviderAlreadyLinked = + @"[ERROR_PROVIDER_ALREADY_LINKED] - User can only be linked to one identity for the given " + "provider."; + +/** @var kFIRAuthErrorMessageNoSuchProvider + @brief Message for @c FIRAuthErrorCodeNoSuchProvider error code. + */ +static NSString *const kFIRAuthErrorMessageNoSuchProvider = @"User was not linked to an account " + "with the given provider."; + +/** @var kFIRAuthErrorMessageInvalidUserToken + @brief Message for @c FIRAuthErrorCodeInvalidUserToken error code. + */ +static NSString *const kFIRAuthErrorMessageInvalidUserToken = + @"This user's credential isn't valid " + "for this project. This can happen if the user's token has been tampered with, or if the user " + "doesn’t belong to the project associated with the API key used in your request."; + +/** @var kFIRAuthErrorMessageNetworkError + @brief Message for @c FIRAuthErrorCodeNetworkError error code. + */ +static NSString *const kFIRAuthErrorMessageNetworkError = + @"Network error (such as timeout, " + "interrupted connection or unreachable host) has occurred."; + +/** @var kFIRAuthErrorMessageKeychainError + @brief Message for @c FIRAuthErrorCodeKeychainError error code. + */ +static NSString *const kFIRAuthErrorMessageKeychainError = + @"An error occurred when accessing the " + "keychain. The NSLocalizedFailureReasonErrorKey field in the NSError.userInfo dictionary " + "will contain more information about the error encountered"; + +/** @var kFIRAuthErrorMessageMissingClientIdentifier + @brief Message for @c FIRAuthErrorCodeMissingClientIdentifier error code. + */ +static NSString *const kFIRAuthErrorMessageMissingClientIdentifier = + @"The request does not contain " + "any client identifier."; + +/** @var kFIRAuthErrorMessageUserTokenExpired + @brief Message for @c FIRAuthErrorCodeTokenExpired error code. + */ +static NSString *const kFIRAuthErrorMessageUserTokenExpired = + @"The user's credential is no longer " + "valid. The user must sign in again."; + +/** @var kFIRAuthErrorMessageUserNotFound + @brief Message for @c FIRAuthErrorCodeUserNotFound error code. + */ +static NSString *const kFIRAuthErrorMessageUserNotFound = + @"There is no user record corresponding " + "to this identifier. The user may have been deleted."; + +/** @var kFIRAuthErrorMessageInvalidAPIKey + @brief Message for @c FIRAuthErrorCodeInvalidAPIKey error code. + @remarks This error is not thrown by the server. + */ +static NSString *const kFIRAuthErrorMessageInvalidAPIKey = @"An invalid API Key was supplied in " + "the request."; + +/** @var kFIRAuthErrorMessageUserMismatch. + @brief Message for @c FIRAuthErrorCodeInvalidAPIKey error code. + */ +static NSString *const FIRAuthErrorMessageUserMismatch = + @"The supplied credentials do not " + "correspond to the previously signed in user."; + +/** @var kFIRAuthErrorMessageCredentialAlreadyInUse + @brief Message for @c FIRAuthErrorCodeCredentialAlreadyInUse error code. + */ +static NSString *const kFIRAuthErrorMessageCredentialAlreadyInUse = + @"This credential is already " + "associated with a different user account."; + +/** @var kFIRAuthErrorMessageOperationNotAllowed + @brief Message for @c FIRAuthErrorCodeOperationNotAllowed error code. + */ +static NSString *const kFIRAuthErrorMessageOperationNotAllowed = + @"The given sign-in provider is " + "disabled for this Firebase project. Enable it in the Firebase console, under the sign-in " + "method tab of the Auth section."; + +/** @var kFIRAuthErrorMessageWeakPassword + @brief Message for @c FIRAuthErrorCodeWeakPassword error code. + */ +static NSString *const kFIRAuthErrorMessageWeakPassword = @"The password must be 6 characters long " + "or more."; + +/** @var kFIRAuthErrorMessageAppNotAuthorized + @brief Message for @c FIRAuthErrorCodeAppNotAuthorized error code. + */ +static NSString *const kFIRAuthErrorMessageAppNotAuthorized = + @"This app is not authorized to use " + "Firebase Authentication with the provided API key. Review your key configuration in the " + "Google API console and ensure that it accepts requests from your app's bundle ID."; + +/** @var kFIRAuthErrorMessageExpiredActionCode + @brief Message for @c FIRAuthErrorCodeExpiredActionCode error code. + */ +static NSString *const kFIRAuthErrorMessageExpiredActionCode = @"The action code has expired."; + +/** @var kFIRAuthErrorMessageInvalidActionCode + @brief Message for @c FIRAuthErrorCodeInvalidActionCode error code. + */ +static NSString *const kFIRAuthErrorMessageInvalidActionCode = + @"The action code is invalid. This " + "can happen if the code is malformed, expired, or has already been used."; + +/** @var kFIRAuthErrorMessageInvalidMessagePayload + @brief Message for @c FIRAuthErrorCodeInvalidMessagePayload error code. + */ +static NSString *const kFIRAuthErrorMessageInvalidMessagePayload = + @"The action code is invalid. " + "This can happen if the code is malformed, expired, or has already been used."; + +/** @var kFIRAuthErrorMessageInvalidSender + @brief Message for @c FIRAuthErrorCodeInvalidSender error code. + */ +static NSString *const kFIRAuthErrorMessageInvalidSender = + @"The email template corresponding to " + "this action contains invalid characters in its message. Please fix by going to the Auth " + "email " + "templates section in the Firebase Console."; + +/** @var kFIRAuthErrorMessageInvalidRecipientEmail + @brief Message for @c FIRAuthErrorCodeInvalidRecipient error code. + */ +static NSString *const kFIRAuthErrorMessageInvalidRecipientEmail = + @"The action code is invalid. " + "This can happen if the code is malformed, expired, or has already been used."; + +/** @var kFIRAuthErrorMessageMissingIosBundleID + @brief Message for @c FIRAuthErrorCodeMissingIosbundleID error code. + */ +static NSString *const kFIRAuthErrorMessageMissingIosBundleID = + @"An iOS Bundle ID must be provided if an App Store ID is provided."; + +/** @var kFIRAuthErrorMessageMissingAndroidPackageName + @brief Message for @c FIRAuthErrorCodeMissingAndroidPackageName error code. + */ +static NSString *const kFIRAuthErrorMessageMissingAndroidPackageName = + @"An Android Package Name must be provided if the Android App is required to be installed."; + +/** @var kFIRAuthErrorMessageUnauthorizedDomain + @brief Message for @c FIRAuthErrorCodeUnauthorizedDomain error code. + */ +static NSString *const kFIRAuthErrorMessageUnauthorizedDomain = + @"The domain of the continue URL " + "is not allowlisted. Please allowlist the domain in the Firebase console."; + +/** @var kFIRAuthErrorMessageInvalidContinueURI + @brief Message for @c FIRAuthErrorCodeInvalidContinueURI error code. + */ +static NSString *const kFIRAuthErrorMessageInvalidContinueURI = + @"The continue URL provided in the request is invalid."; + +/** @var kFIRAuthErrorMessageMissingEmail + @brief Message for @c FIRAuthErrorCodeMissingEmail error code. + */ +static NSString *const kFIRAuthErrorMessageMissingEmail = @"An email address must be provided."; + +/** @var kFIRAuthErrorMessageMissingContinueURI + @brief Message for @c FIRAuthErrorCodeMissingContinueURI error code. + */ +static NSString *const kFIRAuthErrorMessageMissingContinueURI = + @"A continue URL must be provided in the request."; + +/** @var kFIRAuthErrorMessageMissingPhoneNumber + @brief Message for @c FIRAuthErrorCodeMissingPhoneNumber error code. + */ +static NSString *const kFIRAuthErrorMessageMissingPhoneNumber = + @"To send verification codes, provide a phone number for the recipient."; + +/** @var kFIRAuthErrorMessageInvalidPhoneNumber + @brief Message for @c FIRAuthErrorCodeInvalidPhoneNumber error code. + */ +static NSString *const kFIRAuthErrorMessageInvalidPhoneNumber = + @"The format of the phone number provided is incorrect. Please enter the phone number in a " + "format that can be parsed into E.164 format. E.164 phone numbers are written in the format " + "[+][country code][subscriber number including area code]."; + +/** @var kFIRAuthErrorMessageMissingVerificationCode + @brief Message for @c FIRAuthErrorCodeMissingVerificationCode error code. + */ +static NSString *const kFIRAuthErrorMessageMissingVerificationCode = + @"The phone auth credential was created with an empty SMS verification Code."; + +/** @var kFIRAuthErrorMessageInvalidVerificationCode + @brief Message for @c FIRAuthErrorCodeInvalidVerificationCode error code. + */ +static NSString *const kFIRAuthErrorMessageInvalidVerificationCode = + @"The SMS verification code used to create the phone auth credential is invalid. Please resend " + "the verification code SMS and be sure to use the verification code provided by the user."; + +/** @var kFIRAuthErrorMessageMissingVerificationID + @brief Message for @c FIRAuthErrorCodeInvalidVerificationID error code. + */ +static NSString *const kFIRAuthErrorMessageMissingVerificationID = + @"The phone auth credential was created with an empty verification ID."; + +/** @var kFIRAuthErrorMessageInvalidVerificationID + @brief Message for @c FIRAuthErrorCodeInvalidVerificationID error code. + */ +static NSString *const kFIRAuthErrorMessageInvalidVerificationID = + @"The verification ID used to create the phone auth credential is invalid."; + +/** @var kFIRAuthErrorMessageLocalPlayerNotAuthenticated + @brief Message for @c FIRAuthErrorCodeLocalPlayerNotAuthenticated error code. + */ +static NSString *const kFIRAuthErrorMessageLocalPlayerNotAuthenticated = + @"The local player is not authenticated. Please log the local player in to Game Center."; + +/** @var kFIRAuthErrorMessageGameKitNotLinked + @brief Message for @c kFIRAuthErrorMessageGameKitNotLinked error code. + */ +static NSString *const kFIRAuthErrorMessageGameKitNotLinked = + @"The GameKit framework is not linked. Please turn on the Game Center capability."; + +/** @var kFIRAuthErrorMessageSessionExpired + @brief Message for @c FIRAuthErrorCodeSessionExpired error code. + */ +static NSString *const kFIRAuthErrorMessageSessionExpired = + @"The SMS code has expired. Please " + @"re-send the verification code to try again."; + +/** @var kFIRAuthErrorMessageMissingAppCredential + @brief Message for @c FIRAuthErrorCodeMissingAppCredential error code. + */ +static NSString *const kFIRAuthErrorMessageMissingAppCredential = + @"The phone verification request " + "is missing an APNs Device token. Firebase Auth automatically detects APNs Device Tokens, " + "however, if method swizzling is disabled, the APNs token must be set via the APNSToken " + "property on FIRAuth or by calling setAPNSToken:type on FIRAuth."; + +/** @var kFIRAuthErrorMessageInvalidAppCredential + @brief Message for @c FIRAuthErrorCodeInvalidAppCredential error code. + */ +static NSString *const kFIRAuthErrorMessageInvalidAppCredential = + @"The APNs device token provided " + "is either incorrect or does not match the private certificate uploaded to the Firebase " + "Console."; + +/** @var kFIRAuthErrorMessageQuotaExceeded + @brief Message for @c FIRAuthErrorCodeQuotaExceeded error code. + */ +static NSString *const kFIRAuthErrorMessageQuotaExceeded = @"The quota for this operation " + "has been exceeded."; + +/** @var kFIRAuthErrorMessageMissingAppToken + @brief Message for @c FIRAuthErrorCodeMissingAppToken error code. + */ +static NSString *const kFIRAuthErrorMessageMissingAppToken = + @"There seems to be a problem with " + "your project's Firebase phone number authentication set-up, please make sure to follow the " + "instructions found at https://firebase.google.com/docs/auth/ios/phone-auth"; + +/** @var kFIRAuthErrorMessageMissingAppToken + @brief Message for @c FIRAuthErrorCodeMissingAppToken error code. + */ +static NSString *const kFIRAuthErrorMessageNotificationNotForwarded = + @"If app delegate swizzling " + "is disabled, remote notifications received by UIApplicationDelegate need to be forwarded to " + "FIRAuth's canHandleNotificaton: method."; + +/** @var kFIRAuthErrorMessageAppNotVerified + @brief Message for @c FIRAuthErrorCodeMissingAppToken error code. + */ +static NSString *const kFIRAuthErrorMessageAppNotVerified = + @"Firebase could not retrieve the " + "silent push notification and therefore could not verify your app. Ensure that you configured " + "your app correctly to receive push notifications."; + +/** @var kFIRAuthErrorMessageCaptchaCheckFailed + @brief Message for @c FIRAuthErrorCodeCaptchaCheckFailed error code. + */ +static NSString *const kFIRAuthErrorMessageCaptchaCheckFailed = + @"The reCAPTCHA response token " + "provided is either invalid, expired or already"; + +/** @var kFIRAuthErrorMessageWebContextAlreadyPresented + @brief Message for @c FIRAuthErrorCodeWebContextAlreadyPresented error code. + */ +static NSString *const kFIRAuthErrorMessageWebContextAlreadyPresented = + @"User interaction is " + "still ongoing, another view cannot be presented."; + +/** @var kFIRAuthErrorMessageWebContextCancelled + @brief Message for @c FIRAuthErrorCodeWebContextCancelled error code. + */ +static NSString *const kFIRAuthErrorMessageWebContextCancelled = @"The interaction was cancelled " + "by the user."; + +/** @var kFIRAuthErrorMessageInvalidClientID + @brief Message for @c FIRAuthErrorCodeInvalidClientID error code. + */ +static NSString *const kFIRAuthErrorMessageInvalidClientID = + @"The OAuth client ID provided is " + "either invalid or does not match the specified API key."; + +/** @var kFIRAuthErrorMessageWebRequestFailed + @brief Message for @c FIRAuthErrorCodeWebRequestFailed error code. + */ +static NSString *const kFIRAuthErrorMessageWebRequestFailed = + @"A network error (such as timeout, " + "interrupted connection, or unreachable host) has occurred within the web context."; + +/** @var kFIRAuthErrorMessageWebInternalError + @brief Message for @c FIRAuthErrorCodeWebInternalError error code. + */ +static NSString *const kFIRAuthErrorMessageWebInternalError = + @"An internal error has occurred " + "within the SFSafariViewController or WKWebView."; + +/** @var kFIRAuthErrorMessageAppVerificationUserInteractionFailure + @brief Message for @c FIRAuthErrorCodeInvalidClientID error code. + */ +static NSString *const kFIRAuthErrorMessageAppVerificationUserInteractionFailure = + @"The app " + "verification process has failed, print and inspect the error details for more information"; + +/** @var kFIRAuthErrorMessageNullUser + @brief Message for @c FIRAuthErrorCodeNullUser error code. + */ +static NSString *const kFIRAuthErrorMessageNullUser = + @"A null user object was provided as the " + "argument for an operation which requires a non-null user object."; + +/** @var kFIRAuthErrorMessageInvalidProviderID + @brief Message for @c FIRAuthErrorCodeInvalidProviderID error code. + */ +static NSString *const kFIRAuthErrorMessageInvalidProviderID = + @"The provider ID provided for the " + "attempted web operation is invalid."; + +/** @var kFIRAuthErrorMessageInvalidDynamicLinkDomain + @brief Message for @c kFIRAuthErrorMessageInvalidDynamicLinkDomain error code. + */ +static NSString *const kFIRAuthErrorMessageInvalidDynamicLinkDomain = + @"The " + "Firebase Dynamic Link domain used is either not configured or is unauthorized " + "for the current project."; + +/** @var kFIRAuthErrorMessageInternalError + @brief Message for @c FIRAuthErrorCodeInternalError error code. + */ +static NSString *const kFIRAuthErrorMessageInternalError = + @"An internal error has occurred, " + "print and inspect the error details for more information."; + +/** @var kFIRAuthErrorMessageMalformedJWT + @brief Error message constant describing @c FIRAuthErrorCodeMalformedJWT errors. + */ +static NSString *const kFIRAuthErrorMessageMalformedJWT = + @"Failed to parse JWT. Check the userInfo dictionary for the full token."; + +/** @var kFIRAuthErrorMessageSecondFactorRequired + @brief Message for @c kFIRAuthErrorMessageSecondFactorRequired error code. + */ +static NSString *const kFIRAuthErrorMessageSecondFactorRequired = + @"Please complete a second factor challenge to finish signing into this account."; + +/** @var kFIRAuthErrorMessageSecondFactorRequired + @brief Message for @c kFIRAuthErrorMessageSecondFactorRequired error code. + */ +static NSString *const FIRAuthErrorMessageMissingMultiFactorSession = + @"The request is missing proof of first factor successful sign-in."; + +/** @var kFIRAuthErrorMessageSecondFactorRequired + @brief Message for @c kFIRAuthErrorMessageSecondFactorRequired error code. + */ +static NSString *const FIRAuthErrorMessageMissingMultiFactorInfo = + @"No second factor identifier is provided."; + +/** @var kFIRAuthErrorMessageSecondFactorRequired + @brief Message for @c kFIRAuthErrorMessageSecondFactorRequired error code. + */ +static NSString *const FIRAuthErrorMessageInvalidMultiFactorSession = + @"The request does not contain a valid proof of first factor successful sign-in."; + +/** @var kFIRAuthErrorMessageSecondFactorRequired + @brief Message for @c kFIRAuthErrorMessageSecondFactorRequired error code. + */ +static NSString *const FIRAuthErrorMessageMultiFactorInfoNotFound = + @"The user does not have a second factor matching the identifier provided."; + +/** @var kFIRAuthErrorMessageSecondFactorRequired + @brief Message for @c kFIRAuthErrorMessageSecondFactorRequired error code. + */ +static NSString *const FIRAuthErrorMessageAdminRestrictedOperation = + @"This operation is restricted to administrators only."; + +/** @var kFIRAuthErrorMessageSecondFactorRequired + @brief Message for @c kFIRAuthErrorMessageSecondFactorRequired error code. + */ +static NSString *const FIRAuthErrorMessageUnverifiedEmail = + @"The operation requires a verified email."; + +/** @var kFIRAuthErrorMessageSecondFactorRequired + @brief Message for @c kFIRAuthErrorMessageSecondFactorRequired error code. + */ +static NSString *const FIRAuthErrorMessageSecondFactorAlreadyEnrolled = + @"The second factor is already enrolled on this account."; + +/** @var kFIRAuthErrorMessageSecondFactorRequired + @brief Message for @c kFIRAuthErrorMessageSecondFactorRequired error code. + */ +static NSString *const FIRAuthErrorMessageMaximumSecondFactorCountExceeded = + @"The maximum allowed number of second factors on a user has been exceeded."; + +/** @var kFIRAuthErrorMessageSecondFactorRequired + @brief Message for @c kFIRAuthErrorMessageSecondFactorRequired error code. + */ +static NSString *const FIRAuthErrorMessageUnsupportedFirstFactor = + @"Enrolling a second factor or signing in with a multi-factor account requires sign-in with a " + @"supported first factor."; + +/** @var kFIRAuthErrorMessageSecondFactorRequired + @brief Message for @c kFIRAuthErrorMessageSecondFactorRequired error code. + */ +static NSString *const FIRAuthErrorMessageEmailChangeNeedsVerification = + @"Multi-factor users must always have a verified email."; + +/** @var kFIRAuthErrorMessageDynamicLinkNotActivated + @brief Error message constant describing @c FIRAuthErrorCodeDynamicLinkNotActivated errors. + */ +static NSString *const kFIRAuthErrorMessageDynamicLinkNotActivated = + @"Please activate Dynamic Links in the Firebase Console and agree to the terms and conditions."; + +/** @var kFIRAuthErrorMessageRejectedCredential + @brief Error message constant describing @c FIRAuthErrorCodeRejectedCredential errors. + */ +static NSString *const kFIRAuthErrorMessageRejectedCredential = + @"The request contains malformed or mismatching credentials."; + +/** @var kFIRAuthErrorMessageMissingOrInvalidNonce + @brief Error message constant describing @c FIRAuthErrorCodeMissingOrInvalidNonce errors. + */ +static NSString *const kFIRAuthErrorMessageMissingOrInvalidNonce = + @"The request contains malformed or mismatched credentials."; + +/** @var kFIRAuthErrorMessageTenantIDMismatch. + @brief Message for @c FIRAuthErrorCodeTenantIDMismatch error code. + */ +static NSString *const kFIRAuthErrorMessageTenantIDMismatch = + @"The provided user's tenant ID does" + "not match the Auth instance's tenant ID."; + +/** @var kFIRAuthErrorMessageUnsupportedTenantOperation + @brief Message for @c FIRAuthErrorCodeUnsupportedTenantOperation error code. + */ +static NSString *const kFIRAuthErrorMessageUnsupportedTenantOperation = + @"This operation is not" + "supported in a multi-tenant context."; + +/** @var kFIRAuthErrorMessageBlockingCloudFunctionReturnedError + @brief Message for @c FIRAuthErrorCodeBlockingCloudFunctionError error code. + */ +static NSString *const kFIRAuthErrorMessageBlockingCloudFunctionReturnedError = + @"Blocking cloud function returned an error."; + +/** @var FIRAuthErrorDescription + @brief The error descrioption, based on the error code. + @remarks No default case so that we get a compiler warning if a new value was added to the enum. + */ +static NSString *FIRAuthErrorDescription(FIRAuthErrorCode code) { + switch (code) { + case FIRAuthErrorCodeInvalidCustomToken: + return kFIRAuthErrorMessageInvalidCustomToken; + case FIRAuthErrorCodeCustomTokenMismatch: + return kFIRAuthErrorMessageCustomTokenMismatch; + case FIRAuthErrorCodeInvalidEmail: + return kFIRAuthErrorMessageInvalidEmail; + case FIRAuthErrorCodeInvalidCredential: + return kFIRAuthErrorMessageInvalidCredential; + case FIRAuthErrorCodeUserDisabled: + return kFIRAuthErrorMessageUserDisabled; + case FIRAuthErrorCodeEmailAlreadyInUse: + return kFIRAuthErrorMessageEmailAlreadyInUse; + case FIRAuthErrorCodeWrongPassword: + return kFIRAuthErrorMessageWrongPassword; + case FIRAuthErrorCodeTooManyRequests: + return kFIRAuthErrorMessageTooManyRequests; + case FIRAuthErrorCodeAccountExistsWithDifferentCredential: + return kFIRAuthErrorMessageAccountExistsWithDifferentCredential; + case FIRAuthErrorCodeRequiresRecentLogin: + return kFIRAuthErrorMessageRequiresRecentLogin; + case FIRAuthErrorCodeProviderAlreadyLinked: + return kFIRAuthErrorMessageProviderAlreadyLinked; + case FIRAuthErrorCodeNoSuchProvider: + return kFIRAuthErrorMessageNoSuchProvider; + case FIRAuthErrorCodeInvalidUserToken: + return kFIRAuthErrorMessageInvalidUserToken; + case FIRAuthErrorCodeNetworkError: + return kFIRAuthErrorMessageNetworkError; + case FIRAuthErrorCodeKeychainError: + return kFIRAuthErrorMessageKeychainError; + case FIRAuthErrorCodeMissingClientIdentifier: + return kFIRAuthErrorMessageMissingClientIdentifier; + case FIRAuthErrorCodeUserTokenExpired: + return kFIRAuthErrorMessageUserTokenExpired; + case FIRAuthErrorCodeUserNotFound: + return kFIRAuthErrorMessageUserNotFound; + case FIRAuthErrorCodeInvalidAPIKey: + return kFIRAuthErrorMessageInvalidAPIKey; + case FIRAuthErrorCodeCredentialAlreadyInUse: + return kFIRAuthErrorMessageCredentialAlreadyInUse; + case FIRAuthErrorCodeInternalError: + return kFIRAuthErrorMessageInternalError; + case FIRAuthErrorCodeUserMismatch: + return FIRAuthErrorMessageUserMismatch; + case FIRAuthErrorCodeOperationNotAllowed: + return kFIRAuthErrorMessageOperationNotAllowed; + case FIRAuthErrorCodeWeakPassword: + return kFIRAuthErrorMessageWeakPassword; + case FIRAuthErrorCodeAppNotAuthorized: + return kFIRAuthErrorMessageAppNotAuthorized; + case FIRAuthErrorCodeExpiredActionCode: + return kFIRAuthErrorMessageExpiredActionCode; + case FIRAuthErrorCodeInvalidActionCode: + return kFIRAuthErrorMessageInvalidActionCode; + case FIRAuthErrorCodeInvalidSender: + return kFIRAuthErrorMessageInvalidSender; + case FIRAuthErrorCodeInvalidMessagePayload: + return kFIRAuthErrorMessageInvalidMessagePayload; + case FIRAuthErrorCodeInvalidRecipientEmail: + return kFIRAuthErrorMessageInvalidRecipientEmail; + case FIRAuthErrorCodeMissingIosBundleID: + return kFIRAuthErrorMessageMissingIosBundleID; + case FIRAuthErrorCodeMissingAndroidPackageName: + return kFIRAuthErrorMessageMissingAndroidPackageName; + case FIRAuthErrorCodeUnauthorizedDomain: + return kFIRAuthErrorMessageUnauthorizedDomain; + case FIRAuthErrorCodeInvalidContinueURI: + return kFIRAuthErrorMessageInvalidContinueURI; + case FIRAuthErrorCodeMissingContinueURI: + return kFIRAuthErrorMessageMissingContinueURI; + case FIRAuthErrorCodeMissingEmail: + return kFIRAuthErrorMessageMissingEmail; + case FIRAuthErrorCodeMissingPhoneNumber: + return kFIRAuthErrorMessageMissingPhoneNumber; + case FIRAuthErrorCodeInvalidPhoneNumber: + return kFIRAuthErrorMessageInvalidPhoneNumber; + case FIRAuthErrorCodeMissingVerificationCode: + return kFIRAuthErrorMessageMissingVerificationCode; + case FIRAuthErrorCodeInvalidVerificationCode: + return kFIRAuthErrorMessageInvalidVerificationCode; + case FIRAuthErrorCodeMissingVerificationID: + return kFIRAuthErrorMessageMissingVerificationID; + case FIRAuthErrorCodeInvalidVerificationID: + return kFIRAuthErrorMessageInvalidVerificationID; + case FIRAuthErrorCodeSessionExpired: + return kFIRAuthErrorMessageSessionExpired; + case FIRAuthErrorCodeMissingAppCredential: + return kFIRAuthErrorMessageMissingAppCredential; + case FIRAuthErrorCodeInvalidAppCredential: + return kFIRAuthErrorMessageInvalidAppCredential; + case FIRAuthErrorCodeQuotaExceeded: + return kFIRAuthErrorMessageQuotaExceeded; + case FIRAuthErrorCodeMissingAppToken: + return kFIRAuthErrorMessageMissingAppToken; + case FIRAuthErrorCodeNotificationNotForwarded: + return kFIRAuthErrorMessageNotificationNotForwarded; + case FIRAuthErrorCodeAppNotVerified: + return kFIRAuthErrorMessageAppNotVerified; + case FIRAuthErrorCodeCaptchaCheckFailed: + return kFIRAuthErrorMessageCaptchaCheckFailed; + case FIRAuthErrorCodeWebContextAlreadyPresented: + return kFIRAuthErrorMessageWebContextAlreadyPresented; + case FIRAuthErrorCodeWebContextCancelled: + return kFIRAuthErrorMessageWebContextCancelled; + case FIRAuthErrorCodeInvalidClientID: + return kFIRAuthErrorMessageInvalidClientID; + case FIRAuthErrorCodeAppVerificationUserInteractionFailure: + return kFIRAuthErrorMessageAppVerificationUserInteractionFailure; + case FIRAuthErrorCodeWebNetworkRequestFailed: + return kFIRAuthErrorMessageWebRequestFailed; + case FIRAuthErrorCodeNullUser: + return kFIRAuthErrorMessageNullUser; + case FIRAuthErrorCodeInvalidProviderID: + return kFIRAuthErrorMessageInvalidProviderID; + case FIRAuthErrorCodeInvalidDynamicLinkDomain: + return kFIRAuthErrorMessageInvalidDynamicLinkDomain; + case FIRAuthErrorCodeWebInternalError: + return kFIRAuthErrorMessageWebInternalError; + case FIRAuthErrorCodeWebSignInUserInteractionFailure: + return kFIRAuthErrorMessageAppVerificationUserInteractionFailure; + case FIRAuthErrorCodeMalformedJWT: + return kFIRAuthErrorMessageMalformedJWT; + case FIRAuthErrorCodeLocalPlayerNotAuthenticated: + return kFIRAuthErrorMessageLocalPlayerNotAuthenticated; + case FIRAuthErrorCodeGameKitNotLinked: + return kFIRAuthErrorMessageGameKitNotLinked; + case FIRAuthErrorCodeSecondFactorRequired: + return kFIRAuthErrorMessageSecondFactorRequired; + case FIRAuthErrorCodeMissingMultiFactorSession: + return FIRAuthErrorMessageMissingMultiFactorSession; + case FIRAuthErrorCodeMissingMultiFactorInfo: + return FIRAuthErrorMessageMissingMultiFactorInfo; + case FIRAuthErrorCodeInvalidMultiFactorSession: + return FIRAuthErrorMessageInvalidMultiFactorSession; + case FIRAuthErrorCodeMultiFactorInfoNotFound: + return FIRAuthErrorMessageMultiFactorInfoNotFound; + case FIRAuthErrorCodeAdminRestrictedOperation: + return FIRAuthErrorMessageAdminRestrictedOperation; + case FIRAuthErrorCodeUnverifiedEmail: + return FIRAuthErrorMessageUnverifiedEmail; + case FIRAuthErrorCodeSecondFactorAlreadyEnrolled: + return FIRAuthErrorMessageSecondFactorAlreadyEnrolled; + case FIRAuthErrorCodeMaximumSecondFactorCountExceeded: + return FIRAuthErrorMessageMaximumSecondFactorCountExceeded; + case FIRAuthErrorCodeUnsupportedFirstFactor: + return FIRAuthErrorMessageUnsupportedFirstFactor; + case FIRAuthErrorCodeEmailChangeNeedsVerification: + return FIRAuthErrorMessageEmailChangeNeedsVerification; + case FIRAuthErrorCodeDynamicLinkNotActivated: + return kFIRAuthErrorMessageDynamicLinkNotActivated; + case FIRAuthErrorCodeRejectedCredential: + return kFIRAuthErrorMessageRejectedCredential; + case FIRAuthErrorCodeMissingOrInvalidNonce: + return kFIRAuthErrorMessageMissingOrInvalidNonce; + case FIRAuthErrorCodeTenantIDMismatch: + return kFIRAuthErrorMessageTenantIDMismatch; + case FIRAuthErrorCodeUnsupportedTenantOperation: + return kFIRAuthErrorMessageUnsupportedTenantOperation; + case FIRAuthErrorCodeBlockingCloudFunctionError: + return kFIRAuthErrorMessageBlockingCloudFunctionReturnedError; + } +} + +/** @var FIRAuthErrorCodeString + @brief The error short string, based on the error code. + @remarks No default case so that we get a compiler warning if a new value was added to the enum. + */ +static NSString *const FIRAuthErrorCodeString(FIRAuthErrorCode code) { + switch (code) { + case FIRAuthErrorCodeInvalidCustomToken: + return @"ERROR_INVALID_CUSTOM_TOKEN"; + case FIRAuthErrorCodeCustomTokenMismatch: + return @"ERROR_CUSTOM_TOKEN_MISMATCH"; + case FIRAuthErrorCodeInvalidEmail: + return @"ERROR_INVALID_EMAIL"; + case FIRAuthErrorCodeInvalidCredential: + return @"ERROR_INVALID_CREDENTIAL"; + case FIRAuthErrorCodeUserDisabled: + return @"ERROR_USER_DISABLED"; + case FIRAuthErrorCodeEmailAlreadyInUse: + return @"ERROR_EMAIL_ALREADY_IN_USE"; + case FIRAuthErrorCodeWrongPassword: + return @"ERROR_WRONG_PASSWORD"; + case FIRAuthErrorCodeTooManyRequests: + return @"ERROR_TOO_MANY_REQUESTS"; + case FIRAuthErrorCodeAccountExistsWithDifferentCredential: + return @"ERROR_ACCOUNT_EXISTS_WITH_DIFFERENT_CREDENTIAL"; + case FIRAuthErrorCodeRequiresRecentLogin: + return @"ERROR_REQUIRES_RECENT_LOGIN"; + case FIRAuthErrorCodeProviderAlreadyLinked: + return @"ERROR_PROVIDER_ALREADY_LINKED"; + case FIRAuthErrorCodeNoSuchProvider: + return @"ERROR_NO_SUCH_PROVIDER"; + case FIRAuthErrorCodeInvalidUserToken: + return @"ERROR_INVALID_USER_TOKEN"; + case FIRAuthErrorCodeNetworkError: + return @"ERROR_NETWORK_REQUEST_FAILED"; + case FIRAuthErrorCodeKeychainError: + return @"ERROR_KEYCHAIN_ERROR"; + case FIRAuthErrorCodeMissingClientIdentifier: + return @"ERROR_MISSING_CLIENT_IDENTIFIER"; + case FIRAuthErrorCodeUserTokenExpired: + return @"ERROR_USER_TOKEN_EXPIRED"; + case FIRAuthErrorCodeUserNotFound: + return @"ERROR_USER_NOT_FOUND"; + case FIRAuthErrorCodeInvalidAPIKey: + return @"ERROR_INVALID_API_KEY"; + case FIRAuthErrorCodeCredentialAlreadyInUse: + return @"ERROR_CREDENTIAL_ALREADY_IN_USE"; + case FIRAuthErrorCodeInternalError: + return @"ERROR_INTERNAL_ERROR"; + case FIRAuthErrorCodeUserMismatch: + return @"ERROR_USER_MISMATCH"; + case FIRAuthErrorCodeOperationNotAllowed: + return @"ERROR_OPERATION_NOT_ALLOWED"; + case FIRAuthErrorCodeWeakPassword: + return @"ERROR_WEAK_PASSWORD"; + case FIRAuthErrorCodeAppNotAuthorized: + return @"ERROR_APP_NOT_AUTHORIZED"; + case FIRAuthErrorCodeExpiredActionCode: + return @"ERROR_EXPIRED_ACTION_CODE"; + case FIRAuthErrorCodeInvalidActionCode: + return @"ERROR_INVALID_ACTION_CODE"; + case FIRAuthErrorCodeInvalidMessagePayload: + return @"ERROR_INVALID_MESSAGE_PAYLOAD"; + case FIRAuthErrorCodeInvalidSender: + return @"ERROR_INVALID_SENDER"; + case FIRAuthErrorCodeInvalidRecipientEmail: + return @"ERROR_INVALID_RECIPIENT_EMAIL"; + case FIRAuthErrorCodeMissingIosBundleID: + return @"ERROR_MISSING_IOS_BUNDLE_ID"; + case FIRAuthErrorCodeMissingAndroidPackageName: + return @"ERROR_MISSING_ANDROID_PKG_NAME"; + case FIRAuthErrorCodeUnauthorizedDomain: + return @"ERROR_UNAUTHORIZED_DOMAIN"; + case FIRAuthErrorCodeInvalidContinueURI: + return @"ERROR_INVALID_CONTINUE_URI"; + case FIRAuthErrorCodeMissingContinueURI: + return @"ERROR_MISSING_CONTINUE_URI"; + case FIRAuthErrorCodeMissingEmail: + return @"ERROR_MISSING_EMAIL"; + case FIRAuthErrorCodeMissingPhoneNumber: + return @"ERROR_MISSING_PHONE_NUMBER"; + case FIRAuthErrorCodeInvalidPhoneNumber: + return @"ERROR_INVALID_PHONE_NUMBER"; + case FIRAuthErrorCodeMissingVerificationCode: + return @"ERROR_MISSING_VERIFICATION_CODE"; + case FIRAuthErrorCodeInvalidVerificationCode: + return @"ERROR_INVALID_VERIFICATION_CODE"; + case FIRAuthErrorCodeMissingVerificationID: + return @"ERROR_MISSING_VERIFICATION_ID"; + case FIRAuthErrorCodeInvalidVerificationID: + return @"ERROR_INVALID_VERIFICATION_ID"; + case FIRAuthErrorCodeSessionExpired: + return @"ERROR_SESSION_EXPIRED"; + case FIRAuthErrorCodeMissingAppCredential: + return @"MISSING_APP_CREDENTIAL"; + case FIRAuthErrorCodeInvalidAppCredential: + return @"INVALID_APP_CREDENTIAL"; + case FIRAuthErrorCodeQuotaExceeded: + return @"ERROR_QUOTA_EXCEEDED"; + case FIRAuthErrorCodeMissingAppToken: + return @"ERROR_MISSING_APP_TOKEN"; + case FIRAuthErrorCodeNotificationNotForwarded: + return @"ERROR_NOTIFICATION_NOT_FORWARDED"; + case FIRAuthErrorCodeAppNotVerified: + return @"ERROR_APP_NOT_VERIFIED"; + case FIRAuthErrorCodeCaptchaCheckFailed: + return @"ERROR_CAPTCHA_CHECK_FAILED"; + case FIRAuthErrorCodeWebContextAlreadyPresented: + return @"ERROR_WEB_CONTEXT_ALREADY_PRESENTED"; + case FIRAuthErrorCodeWebContextCancelled: + return @"ERROR_WEB_CONTEXT_CANCELLED"; + case FIRAuthErrorCodeInvalidClientID: + return @"ERROR_INVALID_CLIENT_ID"; + case FIRAuthErrorCodeAppVerificationUserInteractionFailure: + return @"ERROR_APP_VERIFICATION_FAILED"; + case FIRAuthErrorCodeWebNetworkRequestFailed: + return @"ERROR_WEB_NETWORK_REQUEST_FAILED"; + case FIRAuthErrorCodeNullUser: + return @"ERROR_NULL_USER"; + case FIRAuthErrorCodeInvalidProviderID: + return @"ERROR_INVALID_PROVIDER_ID"; + case FIRAuthErrorCodeInvalidDynamicLinkDomain: + return @"ERROR_INVALID_DYNAMIC_LINK_DOMAIN"; + case FIRAuthErrorCodeWebInternalError: + return @"ERROR_WEB_INTERNAL_ERROR"; + case FIRAuthErrorCodeWebSignInUserInteractionFailure: + return @"ERROR_WEB_USER_INTERACTION_FAILURE"; + case FIRAuthErrorCodeMalformedJWT: + return @"ERROR_MALFORMED_JWT"; + case FIRAuthErrorCodeLocalPlayerNotAuthenticated: + return @"ERROR_LOCAL_PLAYER_NOT_AUTHENTICATED"; + case FIRAuthErrorCodeGameKitNotLinked: + return @"ERROR_GAME_KIT_NOT_LINKED"; + case FIRAuthErrorCodeSecondFactorRequired: + return @"ERROR_SECOND_FACTOR_REQUIRED"; + case FIRAuthErrorCodeMissingMultiFactorSession: + return @"ERROR_MISSING_MULTI_FACTOR_SESSION"; + case FIRAuthErrorCodeMissingMultiFactorInfo: + return @"ERROR_MISSING_MULTI_FACTOR_INFO"; + case FIRAuthErrorCodeInvalidMultiFactorSession: + return @"ERROR_INVALID_MULTI_FACTOR_SESSION"; + case FIRAuthErrorCodeMultiFactorInfoNotFound: + return @"ERROR_MULTI_FACTOR_INFO_NOT_FOUND"; + case FIRAuthErrorCodeAdminRestrictedOperation: + return @"ERROR_ADMIN_RESTRICTED_OPERATION"; + case FIRAuthErrorCodeUnverifiedEmail: + return @"ERROR_UNVERIFIED_EMAIL"; + case FIRAuthErrorCodeSecondFactorAlreadyEnrolled: + return @"ERROR_SECOND_FACTOR_ALREADY_ENROLLED"; + case FIRAuthErrorCodeMaximumSecondFactorCountExceeded: + return @"ERROR_MAXIMUM_SECOND_FACTOR_COUNT_EXCEEDED"; + case FIRAuthErrorCodeUnsupportedFirstFactor: + return @"ERROR_UNSUPPORTED_FIRST_FACTOR"; + case FIRAuthErrorCodeEmailChangeNeedsVerification: + return @"ERROR_EMAIL_CHANGE_NEEDS_VERIFICATION"; + case FIRAuthErrorCodeDynamicLinkNotActivated: + return @"ERROR_DYNAMIC_LINK_NOT_ACTIVATED"; + case FIRAuthErrorCodeRejectedCredential: + return @"ERROR_REJECTED_CREDENTIAL"; + case FIRAuthErrorCodeMissingOrInvalidNonce: + return @"ERROR_MISSING_OR_INVALID_NONCE"; + case FIRAuthErrorCodeTenantIDMismatch: + return @"ERROR_TENANT_ID_MISMATCH"; + case FIRAuthErrorCodeUnsupportedTenantOperation: + return @"ERROR_UNSUPPORTED_TENANT_OPERATION"; + case FIRAuthErrorCodeBlockingCloudFunctionError: + return @"ERROR_BLOCKING_CLOUD_FUNCTION_RETURNED_ERROR"; + } +} + +@implementation FIRAuthErrorUtils + ++ (NSError *)errorWithCode:(FIRAuthInternalErrorCode)code { + return [self errorWithCode:code message:nil]; +} + ++ (NSError *)errorWithCode:(FIRAuthInternalErrorCode)code message:(nullable NSString *)message { + NSDictionary *userInfo = nil; + if (message.length) { + userInfo = @{NSLocalizedDescriptionKey : message}; + } + return [self errorWithCode:code userInfo:userInfo]; +} + ++ (NSError *)errorWithCode:(FIRAuthInternalErrorCode)code + underlyingError:(nullable NSError *)underlyingError { + NSDictionary *errorUserInfo; + if (underlyingError) { + errorUserInfo = @{NSUnderlyingErrorKey : underlyingError}; + } + return [self errorWithCode:code userInfo:errorUserInfo]; +} + ++ (NSError *)errorWithCode:(FIRAuthInternalErrorCode)code + userInfo:(nullable NSDictionary *)userInfo { + BOOL isPublic = (code & FIRAuthPublicErrorCodeFlag) == FIRAuthPublicErrorCodeFlag; + if (isPublic) { + // This is a public error. Return it as a public error and add a description. + NSInteger errorCode = code & ~FIRAuthPublicErrorCodeFlag; + NSMutableDictionary *errorUserInfo = [NSMutableDictionary dictionary]; + if (userInfo) { + [errorUserInfo addEntriesFromDictionary:userInfo]; + } + if (!errorUserInfo[NSLocalizedDescriptionKey]) { + errorUserInfo[NSLocalizedDescriptionKey] = FIRAuthErrorDescription(errorCode); + } + errorUserInfo[FIRAuthErrorUserInfoNameKey] = FIRAuthErrorCodeString(errorCode); + return [NSError errorWithDomain:FIRAuthErrorDomain code:errorCode userInfo:errorUserInfo]; + } else { + // This is an internal error. Wrap it in an internal error. + NSError *error = [NSError errorWithDomain:FIRAuthInternalErrorDomain + code:code + userInfo:userInfo]; + return [self errorWithCode:FIRAuthInternalErrorCodeInternalError underlyingError:error]; + } +} + ++ (NSError *)RPCRequestEncodingErrorWithUnderlyingError:(NSError *)underlyingError { + return [self errorWithCode:FIRAuthInternalErrorCodeRPCRequestEncodingError + underlyingError:underlyingError]; +} + ++ (NSError *)JSONSerializationErrorForUnencodableType { + return [self errorWithCode:FIRAuthInternalErrorCodeJSONSerializationError]; +} + ++ (NSError *)JSONSerializationErrorWithUnderlyingError:(NSError *)underlyingError { + return [self errorWithCode:FIRAuthInternalErrorCodeJSONSerializationError + underlyingError:underlyingError]; +} + ++ (NSError *)networkErrorWithUnderlyingError:(NSError *)underlyingError { + return [self errorWithCode:FIRAuthInternalErrorCodeNetworkError underlyingError:underlyingError]; +} + ++ (NSError *)unexpectedErrorResponseWithData:(NSData *)data + underlyingError:(NSError *)underlyingError { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + if (data) { + userInfo[FIRAuthErrorUserInfoDataKey] = data; + } + if (underlyingError) { + userInfo[NSUnderlyingErrorKey] = underlyingError; + } + return [self errorWithCode:FIRAuthInternalErrorCodeUnexpectedErrorResponse + userInfo:[userInfo copy]]; +} + ++ (NSError *)unexpectedErrorResponseWithDeserializedResponse:(id)deserializedResponse { + NSDictionary *userInfo; + if (deserializedResponse) { + userInfo = @{ + FIRAuthErrorUserInfoDeserializedResponseKey : deserializedResponse, + }; + } + return [self errorWithCode:FIRAuthInternalErrorCodeUnexpectedErrorResponse userInfo:userInfo]; +} + ++ (NSError *)unexpectedErrorResponseWithDeserializedResponse:(id)deserializedResponse + underlyingError:(NSError *)underlyingError { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + if (deserializedResponse) { + userInfo[FIRAuthErrorUserInfoDeserializedResponseKey] = deserializedResponse; + } + if (underlyingError) { + userInfo[NSUnderlyingErrorKey] = underlyingError; + } + return [self errorWithCode:FIRAuthInternalErrorCodeUnexpectedErrorResponse + userInfo:[userInfo copy]]; +} + ++ (NSError *)malformedJWTErrorWithToken:(NSString *)token + underlyingError:(NSError *_Nullable)underlyingError { + NSMutableDictionary *userInfo = + [NSMutableDictionary dictionaryWithObject:kFIRAuthErrorMessageMalformedJWT + forKey:NSLocalizedDescriptionKey]; + [userInfo setObject:token forKey:FIRAuthErrorUserInfoDataKey]; + if (underlyingError != nil) { + [userInfo setObject:underlyingError forKey:NSUnderlyingErrorKey]; + } + return [self errorWithCode:FIRAuthInternalErrorCodeMalformedJWT userInfo:[userInfo copy]]; +} + ++ (NSError *)unexpectedResponseWithData:(NSData *)data underlyingError:(NSError *)underlyingError { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + if (data) { + userInfo[FIRAuthErrorUserInfoDataKey] = data; + } + if (underlyingError) { + userInfo[NSUnderlyingErrorKey] = underlyingError; + } + return [self errorWithCode:FIRAuthInternalErrorCodeUnexpectedResponse userInfo:[userInfo copy]]; +} + ++ (NSError *)unexpectedResponseWithDeserializedResponse:(id)deserializedResponse { + NSDictionary *userInfo; + if (deserializedResponse) { + userInfo = @{ + FIRAuthErrorUserInfoDeserializedResponseKey : deserializedResponse, + }; + } + return [self errorWithCode:FIRAuthInternalErrorCodeUnexpectedResponse userInfo:userInfo]; +} + ++ (NSError *)unexpectedResponseWithDeserializedResponse:(nullable id)deserializedResponse + underlyingError:(NSError *)underlyingError { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + if (deserializedResponse) { + userInfo[FIRAuthErrorUserInfoDeserializedResponseKey] = deserializedResponse; + } + if (underlyingError) { + userInfo[NSUnderlyingErrorKey] = underlyingError; + } + return [self errorWithCode:FIRAuthInternalErrorCodeUnexpectedResponse userInfo:[userInfo copy]]; +} + ++ (NSError *)RPCResponseDecodingErrorWithDeserializedResponse:(id)deserializedResponse + underlyingError:(NSError *)underlyingError { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + if (deserializedResponse) { + userInfo[FIRAuthErrorUserInfoDeserializedResponseKey] = deserializedResponse; + } + if (underlyingError) { + userInfo[NSUnderlyingErrorKey] = underlyingError; + } + return [self errorWithCode:FIRAuthInternalErrorCodeRPCResponseDecodingError + userInfo:[userInfo copy]]; +} + ++ (NSError *)emailAlreadyInUseErrorWithEmail:(nullable NSString *)email { + NSDictionary *userInfo; + if (email.length) { + userInfo = @{ + FIRAuthErrorUserInfoEmailKey : email, + }; + } + return [self errorWithCode:FIRAuthInternalErrorCodeEmailAlreadyInUse userInfo:userInfo]; +} + ++ (NSError *)userDisabledErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeUserDisabled message:message]; +} + ++ (NSError *)wrongPasswordErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeWrongPassword message:message]; +} + ++ (NSError *)tooManyRequestsErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeTooManyRequests message:message]; +} + ++ (NSError *)invalidCustomTokenErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeInvalidCustomToken message:message]; +} + ++ (NSError *)customTokenMistmatchErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeCustomTokenMismatch message:message]; +} + ++ (NSError *)invalidCredentialErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeInvalidCredential message:message]; +} + ++ (NSError *)requiresRecentLoginErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeRequiresRecentLogin message:message]; +} + ++ (NSError *)invalidUserTokenErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeInvalidUserToken message:message]; +} + ++ (NSError *)invalidEmailErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeInvalidEmail message:message]; +} + ++ (NSError *)accountExistsWithDifferentCredentialErrorWithEmail:(nullable NSString *)email + updatedCredential: + (nullable FIRAuthCredential *)updatedCredential { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + if (email) { + userInfo[FIRAuthErrorUserInfoEmailKey] = email; + } + if (updatedCredential) { + userInfo[FIRAuthErrorUserInfoUpdatedCredentialKey] = updatedCredential; + } + return [self errorWithCode:FIRAuthInternalErrorCodeAccountExistsWithDifferentCredential + userInfo:userInfo]; +} + ++ (NSError *)providerAlreadyLinkedError { + return [self errorWithCode:FIRAuthInternalErrorCodeProviderAlreadyLinked]; +} + ++ (NSError *)noSuchProviderError { + return [self errorWithCode:FIRAuthInternalErrorCodeNoSuchProvider]; +} + ++ (NSError *)userTokenExpiredErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeUserTokenExpired message:message]; +} + ++ (NSError *)userNotFoundErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeUserNotFound message:message]; +} + ++ (NSError *)invalidAPIKeyError { + return [self errorWithCode:FIRAuthInternalErrorCodeInvalidAPIKey]; +} + ++ (NSError *)userMismatchError { + return [self errorWithCode:FIRAuthInternalErrorCodeUserMismatch]; +} + ++ (NSError *)credentialAlreadyInUseErrorWithMessage:(nullable NSString *)message + credential:(nullable FIRAuthCredential *)credential + email:(nullable NSString *)email { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + if (credential) { + userInfo[FIRAuthErrorUserInfoUpdatedCredentialKey] = credential; + } + if (email.length) { + userInfo[FIRAuthErrorUserInfoEmailKey] = email; + } + if (userInfo.count) { + return [self errorWithCode:FIRAuthInternalErrorCodeCredentialAlreadyInUse userInfo:userInfo]; + } + return [self errorWithCode:FIRAuthInternalErrorCodeCredentialAlreadyInUse message:message]; +} + ++ (NSError *)operationNotAllowedErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeOperationNotAllowed message:message]; +} + ++ (NSError *)weakPasswordErrorWithServerResponseReason:(nullable NSString *)reason { + NSDictionary *userInfo; + if (reason.length) { + userInfo = @{ + NSLocalizedFailureReasonErrorKey : reason, + }; + } + return [self errorWithCode:FIRAuthInternalErrorCodeWeakPassword userInfo:userInfo]; +} + ++ (NSError *)appNotAuthorizedError { + return [self errorWithCode:FIRAuthInternalErrorCodeAppNotAuthorized]; +} + ++ (NSError *)expiredActionCodeErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeExpiredActionCode message:message]; +} + ++ (NSError *)invalidActionCodeErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeInvalidActionCode message:message]; +} + ++ (NSError *)invalidMessagePayloadErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeInvalidMessagePayload message:message]; +} + ++ (NSError *)invalidSenderErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeInvalidSender message:message]; +} + ++ (NSError *)invalidRecipientEmailErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeInvalidRecipientEmail message:message]; +} + ++ (NSError *)missingIosBundleIDErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthinternalErrorCodeMissingIosBundleID message:message]; +} + ++ (NSError *)missingAndroidPackageNameErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeMissingAndroidPackageName message:message]; +} + ++ (NSError *)unauthorizedDomainErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeUnauthorizedDomain message:message]; +} + ++ (NSError *)invalidContinueURIErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeInvalidContinueURI message:message]; +} + ++ (NSError *)missingContinueURIErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeMissingContinueURI message:message]; +} + ++ (NSError *)missingEmailErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeMissingEmail message:message]; +} + ++ (NSError *)missingPhoneNumberErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeMissingPhoneNumber message:message]; +} + ++ (NSError *)invalidPhoneNumberErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeInvalidPhoneNumber message:message]; +} + ++ (NSError *)missingVerificationCodeErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeMissingVerificationCode message:message]; +} + ++ (NSError *)invalidVerificationCodeErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeInvalidVerificationCode message:message]; +} + ++ (NSError *)missingVerificationIDErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeMissingVerificationID message:message]; +} + ++ (NSError *)invalidVerificationIDErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeInvalidVerificationID message:message]; +} + ++ (NSError *)sessionExpiredErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeSessionExpired message:message]; +} + ++ (NSError *)missingAppCredentialWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeMissingAppCredential message:message]; +} + ++ (NSError *)invalidAppCredentialWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeInvalidAppCredential message:message]; +} + ++ (NSError *)quotaExceededErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeQuotaExceeded message:message]; +} + ++ (NSError *)missingAppTokenErrorWithUnderlyingError:(nullable NSError *)underlyingError { + return [self errorWithCode:FIRAuthInternalErrorCodeMissingAppToken + underlyingError:underlyingError]; +} + ++ (NSError *)localPlayerNotAuthenticatedError { + return [self errorWithCode:FIRAuthInternalErrorCodeLocalPlayerNotAuthenticated]; +} + ++ (NSError *)gameKitNotLinkedError { + return [self errorWithCode:FIRAuthInternalErrorCodeGameKitNotLinked]; +} + +#if TARGET_OS_IOS ++ (NSError *)secondFactorRequiredErrorWithPendingCredential:(NSString *)MFAPendingCredential + hints:(NSArray *)hints + auth:(FIRAuth *)auth { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + if (MFAPendingCredential && hints) { + FIRMultiFactorResolver *resolver = + [[FIRMultiFactorResolver alloc] initWithMFAPendingCredential:MFAPendingCredential + hints:hints + auth:auth]; + userInfo[FIRAuthErrorUserInfoMultiFactorResolverKey] = resolver; + } + return [self errorWithCode:FIRAuthInternalErrorCodeSecondFactorRequired userInfo:userInfo]; +} +#endif + ++ (NSError *)notificationNotForwardedError { + return [self errorWithCode:FIRAuthInternalErrorCodeNotificationNotForwarded]; +} + ++ (NSError *)appNotVerifiedErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeAppNotVerified message:message]; +} + ++ (NSError *)missingClientIdentifierErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeMissingClientIdentifier message:message]; +} + ++ (NSError *)captchaCheckFailedErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeCaptchaCheckFailed message:message]; +} + ++ (NSError *)webContextAlreadyPresentedErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeWebContextAlreadyPresented message:message]; +} + ++ (NSError *)webContextCancelledErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeWebContextCancelled message:message]; +} + ++ (NSError *)appVerificationUserInteractionFailureWithReason:(NSString *)reason { + NSDictionary *userInfo; + if (reason.length) { + userInfo = @{ + NSLocalizedFailureReasonErrorKey : reason, + }; + } + return [self errorWithCode:FIRAuthInternalErrorCodeAppVerificationUserInteractionFailure + userInfo:userInfo]; +} + ++ (NSError *)webSignInUserInteractionFailureWithReason:(nullable NSString *)reason { + NSDictionary *userInfo; + if (reason.length) { + userInfo = @{ + NSLocalizedFailureReasonErrorKey : reason, + }; + } + return [self errorWithCode:FIRAuthInternalErrorCodeWebSignInUserInteractionFailure + userInfo:userInfo]; +} + ++ (nullable NSError *)URLResponseErrorWithCode:(NSString *)code + message:(nullable NSString *)message { + if ([code isEqualToString:kURLResponseErrorCodeInvalidClientID]) { + return [self errorWithCode:FIRAuthInternalErrorCodeInvalidClientID message:message]; + } + if ([code isEqualToString:kURLResponseErrorCodeNetworkRequestFailed]) { + return [self errorWithCode:FIRAuthInternalErrorCodeWebNetworkRequestFailed message:message]; + } + if ([code isEqualToString:kURLResponseErrorCodeInternalError]) { + return [self errorWithCode:FIRAuthInternalErrorCodeWebInternalError message:message]; + } + return nil; +} + ++ (NSError *)nullUserErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeNullUser message:message]; +} + ++ (NSError *)invalidProviderIDErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeInvalidProviderID message:message]; +} + ++ (NSError *)invalidDynamicLinkDomainErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeInvalidDynamicLinkDomain message:message]; +} + ++ (NSError *)missingOrInvalidNonceErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeMissingOrInvalidNonce message:message]; +} + ++ (NSError *)keychainErrorWithFunction:(NSString *)keychainFunction status:(OSStatus)status { + NSString *failureReason = [NSString stringWithFormat:@"%@ (%li)", keychainFunction, (long)status]; + return [self errorWithCode:FIRAuthInternalErrorCodeKeychainError + userInfo:@{ + NSLocalizedFailureReasonErrorKey : failureReason, + }]; +} + ++ (NSError *)tenantIDMismatchError { + return [self errorWithCode:FIRAuthInternalErrorCodeTenantIDMismatch]; +} + ++ (NSError *)unsupportedTenantOperationError { + return [self errorWithCode:FIRAuthInternalErrorCodeUnsupportedTenantOperation]; +} + ++ (NSError *)blockingCloudFunctionServerResponseWithMessage:(nullable NSString *)message { + if (message == nil) { + return [self errorWithCode:FIRAuthInternalErrorBlockingCloudFunctionError message:message]; + } + + NSString *jsonString = + [message stringByReplacingOccurrencesOfString:@"HTTP Cloud Function returned an error:" + withString:@""]; + jsonString = [jsonString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; + + NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding]; + NSError *jsonError; + NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:jsonData + options:0 + error:&jsonError]; + + if (jsonError) { + return [self JSONSerializationErrorWithUnderlyingError:jsonError]; + } + + NSDictionary *errorDict = jsonDict[@"error"]; + NSString *errorMessage = errorDict[@"message"]; + + return [self errorWithCode:FIRAuthInternalErrorBlockingCloudFunctionError message:errorMessage]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h new file mode 100644 index 0000000..3ae9159 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h @@ -0,0 +1,41 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRAuthExceptionUtils + @brief Utility class used to raise standardized Auth related exceptions. +*/ +@interface FIRAuthExceptionUtils : NSObject + +/** @fn raiseInvalidParameterExceptionWithReason: + @brief raises the "invalid parameter" exception + @param reason string will contain a description of the error. + */ ++ (void)raiseInvalidParameterExceptionWithReason:(nullable NSString *)reason; + +/** @fn raiseMethodNotImplementedExceptionWithReason: + @brief raises the "method not implemented" exception + @param reason string will contain a description of the error. + @see FIRMethodNotImplementedException + */ ++ (void)raiseMethodNotImplementedExceptionWithReason:(nullable NSString *)reason; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.m new file mode 100644 index 0000000..783d4a4 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.m @@ -0,0 +1,41 @@ +/* + * 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 "FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var FIRMethodNotImplementedException + @brief The name of the "Method Not Implemented" exception. + */ +static NSString *const FIRMethodNotImplementedException = @"FIRMethodNotImplementedException"; + +@implementation FIRAuthExceptionUtils + ++ (void)raiseInvalidParameterExceptionWithReason:(nullable NSString *)reason { + [NSException raise:NSInvalidArgumentException format:@"%@", reason]; +} + ++ (void)raiseMethodNotImplementedExceptionWithReason:(nullable NSString *)reason { + NSException *exception = [NSException exceptionWithName:FIRMethodNotImplementedException + reason:reason + userInfo:nil]; + [exception raise]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthInternalErrors.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthInternalErrors.h new file mode 100644 index 0000000..96046f8 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthInternalErrors.h @@ -0,0 +1,548 @@ +/* + * 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 +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthErrors.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @var FIRAuthPublicErrorCodeFlag + @brief Bitmask value indicating the error represents a public error code when this bit is + zeroed. Error codes which don't contain this flag will be wrapped in an @c NSError whose + code is @c FIRAuthErrorCodeInternalError. + */ +static const NSInteger FIRAuthPublicErrorCodeFlag = 1 << 20; + +/** @var FIRAuthInternalErrorDomain + @brief The Firebase Auth error domain for internal errors. + */ +extern NSString *const FIRAuthInternalErrorDomain; + +/** @var FIRAuthErrorUserInfoDeserializedResponseKey + @brief Errors with the code @c FIRAuthErrorCodeUnexpectedResponseError, + @c FIRAuthErrorCodeUnexpectedErrorResponseError, and + @c FIRAuthInternalErrorCodeRPCResponseDecodingError may contain an @c NSError.userInfo + dictionary which contains this key. The value associated with this key is an object of + unspecified contents containing the deserialized server response. + */ +extern NSString *const FIRAuthErrorUserInfoDeserializedResponseKey; + +/** @var FIRAuthErrorUserInfoDataKey + @brief Errors with the code @c FIRAuthErrorCodeUnexpectedResponseError or + @c FIRAuthErrorCodeUnexpectedErrorResponseError may contain an @c NSError.userInfo + dictionary which contains this key. The value associated with this key is an @c NSString + which represents the response from a server to an RPC which could not be deserialized. + */ +extern NSString *const FIRAuthErrorUserInfoDataKey; + +/** @var FIRAuthInternalErrorCode + @brief Error codes used internally by Firebase Auth. + @remarks All errors are generated using an internal error code. These errors are automatically + converted to the appropriate public version of the @c NSError by the methods in + @c FIRAuthErrorUtils + */ +typedef NS_ENUM(NSInteger, FIRAuthInternalErrorCode) { + /** @var FIRAuthInternalErrorCodeNetworkError + @brief Indicates a network error occurred (such as a timeout, interrupted connection, or + unreachable host.) + @remarks These types of errors are often recoverable with a retry. + + See the @c NSUnderlyingError value in the @c NSError.userInfo dictionary for details about + the network error which occurred. + */ + FIRAuthInternalErrorCodeNetworkError = FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeNetworkError, + + /** @var FIRAuthInternalErrorCodeEmailAlreadyInUse + @brief The email used to attempt a sign-up already exists. + */ + FIRAuthInternalErrorCodeEmailAlreadyInUse = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeEmailAlreadyInUse, + + /** @var FIRAuthInternalErrorCodeUserDisabled + @brief Indicates the user's account is disabled on the server side. + */ + FIRAuthInternalErrorCodeUserDisabled = FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeUserDisabled, + + /** @var FIRAuthInternalErrorCodeWrongPassword + @brief Indicates the user attempted sign in with a wrong password + */ + FIRAuthInternalErrorCodeWrongPassword = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeWrongPassword, + + /** @var FIRAuthInternalErrorCodeKeychainError + @brief Indicates an error occurred accessing the keychain. + @remarks The @c NSLocalizedFailureReasonErrorKey field in the @c NSError.userInfo dictionary + will contain more information about the error encountered. + */ + FIRAuthInternalErrorCodeKeychainError = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeKeychainError, + + /** @var FIRAuthInternalErrorCodeMissingClientIdentifier + @brief Indicates an error for when the client identifier is missing. + */ + FIRAuthInternalErrorCodeMissingClientIdentifier = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeMissingClientIdentifier, + + /** @var FIRAuthInternalErrorCodeInternalError + @brief An internal error occurred. + @remarks This value is here for consistency. It's also used to make the implementation of + wrapping internal errors simpler. + */ + FIRAuthInternalErrorCodeInternalError = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeInternalError, + + /** @var FIRAuthInternalErrorCodeTooManyRequests + @brief Indicates that too many requests were made to a server method. + */ + FIRAuthInternalErrorCodeTooManyRequests = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeTooManyRequests, + + /** @var FIRAuthInternalErrorCodeInvalidCustomToken + @brief Indicates a validation error with the custom token. + */ + FIRAuthInternalErrorCodeInvalidCustomToken = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeInvalidCustomToken, + + /** @var FIRAuthInternalErrorCodeCredentialMismatch + @brief Indicates the service account and the API key belong to different projects. + */ + FIRAuthInternalErrorCodeCustomTokenMismatch = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeCustomTokenMismatch, + + /** @var FIRAuthInternalErrorCodeInvalidCredential + @brief Indicates the IDP token or requestUri is invalid. + */ + FIRAuthInternalErrorCodeInvalidCredential = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeInvalidCredential, + + /** @var FIRAuthInternalErrorCodeRequiresRecentLogin + @brief Indicates the user has attemped to change email or password more than 5 minutes after + signing in. + */ + FIRAuthInternalErrorCodeRequiresRecentLogin = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeRequiresRecentLogin, + + /** @var FIRAuthInternalErrorCodeInvalidUserToken + @brief Indicates user's saved auth credential is invalid, the user needs to sign in again. + */ + FIRAuthInternalErrorCodeInvalidUserToken = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeInvalidUserToken, + + /** @var FIRAuthInternalErrorCodeInvalidEmail + @brief Indicates the email identifier is invalid. + */ + FIRAuthInternalErrorCodeInvalidEmail = FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeInvalidEmail, + + /** @var FIRAuthInternalErrorCodeAccountExistsWithDifferentCredential + @brief Indicates account linking is needed. + */ + FIRAuthInternalErrorCodeAccountExistsWithDifferentCredential = + FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeAccountExistsWithDifferentCredential, + + /** @var FIRAuthInternalErrorCodeProviderAlreadyLinked + @brief Indicates an attempt to link a provider to which we are already linked. + */ + FIRAuthInternalErrorCodeProviderAlreadyLinked = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeProviderAlreadyLinked, + + /** @var FIRAuthInternalErrorCodeNoSuchProvider + @brief Indicates an attempt to unlink a provider that is not is not linked. + */ + FIRAuthInternalErrorCodeNoSuchProvider = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeNoSuchProvider, + + /** @var FIRAuthInternalErrorCodeUserTokenExpired + @brief Indicates the token issue time is older than account's valid_since time. + */ + FIRAuthInternalErrorCodeUserTokenExpired = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeUserTokenExpired, + + /** @var FIRAuthInternalErrorCodeUserNotFound + @brief Indicates the user account was been found. + */ + FIRAuthInternalErrorCodeUserNotFound = FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeUserNotFound, + + /** @var FIRAuthInternalErrorCodeInvalidAPIKey + @brief Indicates an invalid API Key was supplied in the request. + */ + FIRAuthInternalErrorCodeInvalidAPIKey = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeInvalidAPIKey, + + /** @var FIRAuthInternalErrorCodeOperationNotAllowed + @brief Indicates that admin disabled sign-in with the specified IDP. + */ + FIRAuthInternalErrorCodeOperationNotAllowed = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeOperationNotAllowed, + + /** @var FIRAuthInternalErrorCodeUserMismatch + @brief Indicates that user attempted to reauthenticate with a user other than the current + user. + */ + FIRAuthInternalErrorCodeUserMismatch = FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeUserMismatch, + + /** @var FIRAuthInternalErrorCodeCredentialAlreadyInUse + @brief Indicates an attempt to link with a credential that has already been linked with a + different Firebase account. + */ + FIRAuthInternalErrorCodeCredentialAlreadyInUse = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeCredentialAlreadyInUse, + + /** @var FIRAuthInternalErrorCodeWeakPassword + @brief Indicates an attempt to set a password that is considered too weak. + */ + FIRAuthInternalErrorCodeWeakPassword = FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeWeakPassword, + + /** @var FIRAuthInternalErrorCodeAppNotAuthorized + @brief Indicates the App is not authorized to use Firebase Authentication with the + provided API Key. + */ + FIRAuthInternalErrorCodeAppNotAuthorized = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeAppNotAuthorized, + + /** @var FIRAuthInternalErrorCodeExpiredActionCode + @brief Indicates the OOB code is expired. + */ + FIRAuthInternalErrorCodeExpiredActionCode = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeExpiredActionCode, + + /** @var FIRAuthInternalErrorCodeInvalidActionCode + @brief Indicates the OOB code is invalid. + */ + FIRAuthInternalErrorCodeInvalidActionCode = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeInvalidActionCode, + + /** Indicates that there are invalid parameters in the payload during a "send password reset email + * " attempt. + */ + FIRAuthInternalErrorCodeInvalidMessagePayload = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeInvalidMessagePayload, + + /** Indicates that the sender email is invalid during a "send password reset email" attempt. + */ + FIRAuthInternalErrorCodeInvalidSender = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeInvalidSender, + + /** Indicates that the recipient email is invalid. + */ + FIRAuthInternalErrorCodeInvalidRecipientEmail = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeInvalidRecipientEmail, + + /** Indicates that the iOS bundle ID is missing when a iOS App Store ID is provided. + */ + FIRAuthinternalErrorCodeMissingIosBundleID = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeMissingIosBundleID, + + /** Indicates that the android package name is missing when the @c androidInstallApp flag is set + to true. + */ + FIRAuthInternalErrorCodeMissingAndroidPackageName = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeMissingAndroidPackageName, + + /** Indicates that the domain specified in the continue URL is not allowlisted in the Firebase + console. + */ + FIRAuthInternalErrorCodeUnauthorizedDomain = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeUnauthorizedDomain, + + /** Indicates that the domain specified in the continue URI is not valid. + */ + FIRAuthInternalErrorCodeInvalidContinueURI = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeInvalidContinueURI, + + /** Indicates that a continue URI was not provided in a request to the backend which requires + one. + */ + FIRAuthInternalErrorCodeMissingContinueURI = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeMissingContinueURI, + + /** Indicates that an email address was expected but one was not provided. + */ + FIRAuthInternalErrorCodeMissingEmail = FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeMissingEmail, + + /** Indicates that a phone number was not provided in a call to @c verifyPhoneNumber:completion:. + */ + FIRAuthInternalErrorCodeMissingPhoneNumber = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeMissingPhoneNumber, + + /** Indicates that an invalid phone number was provided in a call to @c + verifyPhoneNumber:completion:. + */ + FIRAuthInternalErrorCodeInvalidPhoneNumber = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeInvalidPhoneNumber, + + /** Indicates that the phone auth credential was created with an empty verification code. + */ + FIRAuthInternalErrorCodeMissingVerificationCode = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeMissingVerificationCode, + + /** Indicates that an invalid verification code was used in the verifyPhoneNumber request. + */ + FIRAuthInternalErrorCodeInvalidVerificationCode = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeInvalidVerificationCode, + + /** Indicates that the phone auth credential was created with an empty verification ID. + */ + FIRAuthInternalErrorCodeMissingVerificationID = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeMissingVerificationID, + + /** Indicates that the APNS device token is missing in the verifyClient request. + */ + FIRAuthInternalErrorCodeMissingAppCredential = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeMissingAppCredential, + + /** Indicates that an invalid APNS device token was used in the verifyClient request. + */ + FIRAuthInternalErrorCodeInvalidAppCredential = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeInvalidAppCredential, + + /** Indicates that the reCAPTCHA token is not valid. + */ + FIRAuthInternalErrorCodeCaptchaCheckFailed = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeCaptchaCheckFailed, + + /** Indicates that an invalid verification ID was used in the verifyPhoneNumber request. + */ + FIRAuthInternalErrorCodeInvalidVerificationID = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeInvalidVerificationID, + + /** Indicates that the quota of SMS messages for a given project has been exceeded. + */ + FIRAuthInternalErrorCodeQuotaExceeded = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeQuotaExceeded, + + /** Indicates that an attempt was made to present a new web context while one was already being + presented. + */ + FIRAuthInternalErrorCodeWebContextAlreadyPresented = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeWebContextAlreadyPresented, + + /** Indicates that the URL presentation was cancelled prematurely by the user. + */ + FIRAuthInternalErrorCodeWebContextCancelled = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeWebContextCancelled, + + /** Indicates a general failure during the app verification flow. + */ + FIRAuthInternalErrorCodeAppVerificationUserInteractionFailure = + FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeAppVerificationUserInteractionFailure, + + /** Indicates that the clientID used to invoke a web flow is invalid. + */ + FIRAuthInternalErrorCodeInvalidClientID = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeInvalidClientID, + + /** Indicates that a network request within a SFSafariViewController or WKWebView failed. + */ + FIRAuthInternalErrorCodeWebNetworkRequestFailed = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeWebNetworkRequestFailed, + + /** Indicates that an internal error occurred within a SFSafariViewController or WKWebView. + */ + FIRAuthInternalErrorCodeWebInternalError = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeWebInternalError, + + /** Indicates that an internal error occurred within a SFSafariViewController or WKWebView. + */ + FIRAuthInternalErrorCodeWebSignInUserInteractionFailure = + FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeWebSignInUserInteractionFailure, + + // The enum values between 17046 and 17051 are reserved and should NOT be used for new error + // codes. + + /** Indicates that the SMS code has expired + */ + FIRAuthInternalErrorCodeSessionExpired = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeSessionExpired, + + FIRAuthInternalErrorCodeMissingAppToken = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeMissingAppToken, + + FIRAuthInternalErrorCodeNotificationNotForwarded = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeNotificationNotForwarded, + + FIRAuthInternalErrorCodeAppNotVerified = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeAppNotVerified, + + /** Indicates that the Game Center local player was not authenticated. + */ + FIRAuthInternalErrorCodeLocalPlayerNotAuthenticated = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeLocalPlayerNotAuthenticated, + + /** Indicates that the Game Center local player was not authenticated. + */ + FIRAuthInternalErrorCodeGameKitNotLinked = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeGameKitNotLinked, + + /** Indicates that the second factor is required for sign in. + */ + FIRAuthInternalErrorCodeSecondFactorRequired = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeSecondFactorRequired, + + /** Indicates that the multi factor session is missing. + */ + FIRAuthInternalErrorCodeMissingMultiFactorSession = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeMissingMultiFactorSession, + + /** Indicates that the multi factor info is missing. + */ + FIRAuthInternalErrorCodeMissingMultiFactorInfo = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeMissingMultiFactorInfo, + + /** Indicates that the multi factor session is invalid. + */ + FIRAuthInternalErrorCodeInvalidMultiFactorSession = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeInvalidMultiFactorSession, + + /** Indicates that the multi factor info is not found. + */ + FIRAuthInternalErrorCodeMultiFactorInfoNotFound = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeMultiFactorInfoNotFound, + + /** Indicates that the operation is admin only. + */ + FIRAuthInternalErrorCodeAdminRestrictedOperation = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeAdminRestrictedOperation, + + /** Indicates that the email is unverified. + */ + FIRAuthInternalErrorCodeUnverifiedEmail = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeUnverifiedEmail, + + /** Indicates that the second factor is already enrolled. + */ + FIRAuthInternalErrorCodeSecondFactorAlreadyEnrolled = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeSecondFactorAlreadyEnrolled, + + /** Indicates that the number of multi factors reached the limit. + */ + FIRAuthInternalErrorCodeMaximumSecondFactorCountExceeded = + FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeMaximumSecondFactorCountExceeded, + + /** Indicates that the first factor is not supportted. + */ + FIRAuthInternalErrorCodeUnsupportedFirstFactor = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeUnsupportedFirstFactor, + + /** Indicates that the email needs to be verified before changed. + */ + FIRAuthInternalErrorCodeEmailChangeNeedsVerification = + FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeEmailChangeNeedsVerification, + + /** Indicates that the nonce is missing or invalid. + */ + FIRAuthInternalErrorCodeMissingOrInvalidNonce = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeMissingOrInvalidNonce, + + /** Indicates that a non-null user was expected as an argmument to the operation but a null + user was provided. + */ + FIRAuthInternalErrorCodeNullUser = FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeNullUser, + + /** Indicates that the provider id given for the web operation is invalid. + */ + FIRAuthInternalErrorCodeInvalidProviderID = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeInvalidProviderID, + + /** @var FIRAuthInternalErrorCodeTenantIDMismatch + @brief Indicates an error occurred when an attempt is made to update the current user with a + tenantId that differs from the current FirebaseAuth instance's tenantId. + */ + FIRAuthInternalErrorCodeTenantIDMismatch = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeTenantIDMismatch, + + /** @var FIRAuthInternalErrorCodeUnsupportedTenantOperation + @brief Indicates an error occurred when operation is not supported in a multi-tenant context. + */ + FIRAuthInternalErrorCodeUnsupportedTenantOperation = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeUnsupportedTenantOperation, + + /** Indicates that the Firebase Dynamic Link domain used is either not configured or is + unauthorized for the current project. + */ + FIRAuthInternalErrorCodeInvalidDynamicLinkDomain = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeInvalidDynamicLinkDomain, + + FIRAuthInternalErrorCodeMalformedJWT = FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeMalformedJWT, + + /** Indicates that an authentication blocking cloud function returned an error. + */ + FIRAuthInternalErrorBlockingCloudFunctionError = FIRAuthPublicErrorCodeFlag | + FIRAuthErrorCodeBlockingCloudFunctionError, + + /** @var FIRAuthInternalErrorCodeRPCRequestEncodingError + @brief Indicates an error encoding the RPC request. + @remarks This is typically due to some sort of unexpected input value. + + See the @c NSUnderlyingError value in the @c NSError.userInfo dictionary for details. + */ + FIRAuthInternalErrorCodeRPCRequestEncodingError = 1, + + /** @var FIRAuthInternalErrorCodeJSONSerializationError + @brief Indicates an error serializing an RPC request. + @remarks This is typically due to some sort of unexpected input value. + + If an @c NSJSONSerialization.isValidJSONObject: check fails, the error will contain no + @c NSUnderlyingError key in the @c NSError.userInfo dictionary. If an error was + encountered calling @c NSJSONSerialization.dataWithJSONObject:options:error:, the + resulting error will be associated with the @c NSUnderlyingError key in the + @c NSError.userInfo dictionary. + */ + FIRAuthInternalErrorCodeJSONSerializationError = 2, + + /** @var FIRAuthInternalErrorCodeUnexpectedErrorResponse + @brief Indicates an HTTP error occurred and the data returned either couldn't be deserialized + or couldn't be decoded. + @remarks See the @c NSUnderlyingError value in the @c NSError.userInfo dictionary for details + about the HTTP error which occurred. + + If the response could be deserialized as JSON then the @c NSError.userInfo dictionary will + contain a value for the key @c FIRAuthErrorUserInfoDeserializedResponseKey which is the + deserialized response value. + + If the response could not be deserialized as JSON then the @c NSError.userInfo dictionary + will contain values for the @c NSUnderlyingErrorKey and @c FIRAuthErrorUserInfoDataKey + keys. + */ + FIRAuthInternalErrorCodeUnexpectedErrorResponse = 3, + + /** @var FIRAuthInternalErrorCodeUnexpectedResponse + @brief Indicates the HTTP response indicated the request was a successes, but the response + contains something other than a JSON-encoded dictionary, or the data type of the response + indicated it is different from the type of response we expected. + @remarks See the @c NSUnderlyingError value in the @c NSError.userInfo dictionary. + If this key is present in the dictionary, it may contain an error from + @c NSJSONSerialization error (indicating the response received was of the wrong data + type). + + See the @c FIRAuthErrorUserInfoDeserializedResponseKey value in the @c NSError.userInfo + dictionary. If the response could be deserialized, it's deserialized representation will + be associated with this key. If the @c NSUnderlyingError value in the @c NSError.userInfo + dictionary is @c nil, this indicates the JSON didn't represent a dictionary. + */ + FIRAuthInternalErrorCodeUnexpectedResponse = 4, + + /** @var FIRAuthInternalErrorCodeRPCResponseDecodingError + @brief Indicates an error decoding the RPC response. + This is typically due to some sort of unexpected response value from the server. + @remarks See the @c NSUnderlyingError value in the @c NSError.userInfo dictionary for details. + + See the @c FIRErrorUserInfoDecodedResponseKey value in the @c NSError.userInfo dictionary. + The deserialized representation of the response will be associated with this key. + */ + FIRAuthInternalErrorCodeRPCResponseDecodingError = 5, +}; + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthURLPresenter.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthURLPresenter.h new file mode 100644 index 0000000..9201305 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthURLPresenter.h @@ -0,0 +1,69 @@ +/* + * 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 +#if TARGET_OS_IOS + +#import + +NS_ASSUME_NONNULL_BEGIN + +@protocol FIRAuthUIDelegate; + +/** @typedef FIRAuthURLPresentationCompletion + @brief The type of block invoked when the URLPresentation completes. + @param callbackURL The callback URL if the presentation ends with a matching callback. + @param error The error if the presentation fails to start or ends with an error. + */ +typedef void (^FIRAuthURLPresentationCompletion)(NSURL *_Nullable callbackURL, + NSError *_Nullable error); + +/** @typedef FIRAuthCallbackMatcher + @brief The type of block invoked for checking whether a callback URL matches. + @param callbackURL The callback URL to check for match. + @return Whether or not the specific callback URL matches or not. + */ +typedef BOOL (^FIRAuthURLCallbackMatcher)(NSURL *_Nullable callbackURL); + +/** @class FIRAuthURLPresenter + @brief A Class responsible for presenting URL via SFSafariViewController or WKWebView. + */ +@interface FIRAuthURLPresenter : NSObject + +/** @fn presentURL:UIDelegate:callbackMatcher:completion: + @brief Presents an URL to interact with user. + @param URL The URL to present. + @param UIDelegate The UI delegate to present view controller. + @param completion A block to be called either synchronously if the presentation fails to start, + or asynchronously in future on an unspecified thread once the presentation finishes. + */ +- (void)presentURL:(NSURL *)URL + UIDelegate:(nullable id)UIDelegate + callbackMatcher:(FIRAuthURLCallbackMatcher)callbackMatcher + completion:(FIRAuthURLPresentationCompletion)completion; + +/** @fn canHandleURL: + @brief Determines if a URL was produced by the currently presented URL. + @param URL The URL to handle. + @return Whether the URL could be handled or not. + */ +- (BOOL)canHandleURL:(NSURL *)URL; + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthURLPresenter.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthURLPresenter.m new file mode 100644 index 0000000..2defaf0 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthURLPresenter.m @@ -0,0 +1,208 @@ +/* + * 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 +#if TARGET_OS_IOS + +#import +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthUIDelegate.h" + +#import "FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthDefaultUIDelegate.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthURLPresenter.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthWebViewController.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRAuthURLPresenter () +@end + +// Disable unguarded availability warnings because SFSafariViewController is been used throughout +// the code, including as an iVar, which cannot be simply excluded by @available check. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunguarded-availability" + +@implementation FIRAuthURLPresenter { + /** @var _isPresenting + @brief Whether or not some web-based content is being presented. + Accesses to this property are serialized on the global Auth work queue + and thus this variable should not be read or written outside of the work queue. + */ + BOOL _isPresenting; + + /** @var _callbackMatcher + @brief The callback URL matcher for the current presentation, if one is active. + */ + FIRAuthURLCallbackMatcher _Nullable _callbackMatcher; + + /** @var _safariViewController + @brief The SFSafariViewController used for the current presentation, if any. + */ + SFSafariViewController *_Nullable _safariViewController; + + /** @var _webViewController + @brief The FIRAuthWebViewController used for the current presentation, if any. + */ + FIRAuthWebViewController *_Nullable _webViewController; + + /** @var _UIDelegate + @brief The UIDelegate used to present the SFSafariViewController. + */ + id _UIDelegate; + + /** @var _completion + @brief The completion handler for the current presentation, if one is active. + Accesses to this variable are serialized on the global Auth work queue + and thus this variable should not be read or written outside of the work queue. + @remarks This variable is also used as a flag to indicate a presentation is active. + */ + FIRAuthURLPresentationCompletion _Nullable _completion; +} + +- (void)presentURL:(NSURL *)URL + UIDelegate:(nullable id)UIDelegate + callbackMatcher:(FIRAuthURLCallbackMatcher)callbackMatcher + completion:(FIRAuthURLPresentationCompletion)completion { + if (_isPresenting) { + // Unable to start a new presentation on top of another. + // Invoke the new completion closure and leave the old one as-is + // to be invoked when the presentation finishes. + dispatch_async(dispatch_get_main_queue(), ^() { + completion(nil, [FIRAuthErrorUtils webContextAlreadyPresentedErrorWithMessage:nil]); + }); + return; + } + _isPresenting = YES; + _callbackMatcher = callbackMatcher; + _completion = [completion copy]; + dispatch_async(dispatch_get_main_queue(), ^() { + self->_UIDelegate = UIDelegate ?: [FIRAuthDefaultUIDelegate defaultUIDelegate]; +#if TARGET_OS_MACCATALYST + self->_webViewController = [[FIRAuthWebViewController alloc] initWithURL:URL delegate:self]; + UINavigationController *navController = + [[UINavigationController alloc] initWithRootViewController:self->_webViewController]; + [self->_UIDelegate presentViewController:navController animated:YES completion:nil]; +#else + if ([SFSafariViewController class]) { + self->_safariViewController = [[SFSafariViewController alloc] initWithURL:URL]; + self->_safariViewController.delegate = self; + [self->_UIDelegate presentViewController:self->_safariViewController + animated:YES + completion:nil]; + return; + } else { + self->_webViewController = [[FIRAuthWebViewController alloc] initWithURL:URL delegate:self]; + UINavigationController *navController = + [[UINavigationController alloc] initWithRootViewController:self->_webViewController]; + [self->_UIDelegate presentViewController:navController animated:YES completion:nil]; + } +#endif + }); +} + +- (BOOL)canHandleURL:(NSURL *)URL { + if (_isPresenting && _callbackMatcher && _callbackMatcher(URL)) { + [self finishPresentationWithURL:URL error:nil]; + return YES; + } + return NO; +} + +#pragma mark - SFSafariViewControllerDelegate + +- (void)safariViewControllerDidFinish:(SFSafariViewController *)controller { + dispatch_async(FIRAuthGlobalWorkQueue(), ^() { + if (controller == self->_safariViewController) { + self->_safariViewController = nil; + // TODO:Ensure that the SFSafariViewController is actually removed from the screen before + // invoking finishPresentationWithURL:error: + [self finishPresentationWithURL:nil + error:[FIRAuthErrorUtils webContextCancelledErrorWithMessage:nil]]; + } + }); +} + +#pragma mark - FIRAuthwebViewControllerDelegate + +- (BOOL)webViewController:(FIRAuthWebViewController *)webViewController canHandleURL:(NSURL *)URL { + __block BOOL result = NO; + dispatch_sync(FIRAuthGlobalWorkQueue(), ^() { + if (webViewController == self->_webViewController) { + result = [self canHandleURL:URL]; + } + }); + return result; +} + +- (void)webViewControllerDidCancel:(FIRAuthWebViewController *)webViewController { + dispatch_async(FIRAuthGlobalWorkQueue(), ^() { + if (webViewController == self->_webViewController) { + [self finishPresentationWithURL:nil + error:[FIRAuthErrorUtils webContextCancelledErrorWithMessage:nil]]; + } + }); +} + +- (void)webViewController:(FIRAuthWebViewController *)webViewController + didFailWithError:(NSError *)error { + dispatch_async(FIRAuthGlobalWorkQueue(), ^() { + if (webViewController == self->_webViewController) { + [self finishPresentationWithURL:nil error:error]; + } + }); +} + +#pragma mark - Private methods + +/** @fn finishPresentationWithURL:error: + @brief Finishes the presentation for a given URL, if any. + @param URL The URL to finish presenting. + @param error The error with which to finish presenting, if any. + */ +- (void)finishPresentationWithURL:(nullable NSURL *)URL error:(nullable NSError *)error { + _callbackMatcher = nil; + id UIDelegate = _UIDelegate; + _UIDelegate = nil; + FIRAuthURLPresentationCompletion completion = [_completion copy]; + _completion = NULL; + void (^finishBlock)(void) = ^() { + self->_isPresenting = NO; + completion(URL, error); + }; + SFSafariViewController *safariViewController = _safariViewController; + _safariViewController = nil; + FIRAuthWebViewController *webViewController = _webViewController; + _webViewController = nil; + if (safariViewController || webViewController) { + dispatch_async(dispatch_get_main_queue(), ^() { + [UIDelegate dismissViewControllerAnimated:YES + completion:^() { + dispatch_async(FIRAuthGlobalWorkQueue(), finishBlock); + }]; + }); + } else { + finishBlock(); + } +} + +#pragma clang diagnostic pop // ignored "-Wunguarded-availability" + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebUtils.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebUtils.h new file mode 100644 index 0000000..7a3d080 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebUtils.h @@ -0,0 +1,102 @@ +/* + * 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. + */ + +#import + +@class FIRAuthRequestConfiguration; + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRFetchAuthDomainCallback + @brief The callback invoked at the end of the flow to fetch the Auth domain. + @param authDomain The Auth domain. + @param error The error that occurred while fetching the auth domain, if any. + */ +typedef void (^FIRFetchAuthDomainCallback)(NSString *_Nullable authDomain, + NSError *_Nullable error); + +/** @class FIRAuthURLUtils + @brief A utility class used to facilitate the creation of auth related URLs. + */ +@interface FIRAuthWebUtils : NSObject + +/** @fn randomStringWithLength: + @brief Generates a random string of a specified length. + */ ++ (NSString *)randomStringWithLength:(NSUInteger)length; + +/** @fn isCallbackSchemeRegisteredForCustomURLScheme: + @brief Checks whether or not the provided custom URL scheme has been registered by the app. + @param URLScheme The custom URL scheme to be checked against all custom URL schemes registered + by the app. + @return whether or not the provided custom URL scheme has been registered by the app. + */ ++ (BOOL)isCallbackSchemeRegisteredForCustomURLScheme:(NSString *)URLScheme; + +/** @fn isExpectedCallbackURL:eventID:authType + @brief Parses a URL into all available query items. + @param URL The actual callback URL. + @param eventID The expected event ID. + @param authType The expected auth type. + @param callbackScheme The expected callback custom scheme. + @return Whether or not the actual callback URL matches the expected callback URL. + */ ++ (BOOL)isExpectedCallbackURL:(nullable NSURL *)URL + eventID:(NSString *)eventID + authType:(NSString *)authType + callbackScheme:(NSString *)callbackScheme; + +/** @fn fetchAuthDomainWithCompletion:completion: + @brief Fetches the auth domain associated with the Firebase Project. + @param completion The callback invoked after the auth domain has been constructed or an error + has been encountered. + */ ++ (void)fetchAuthDomainWithRequestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + completion:(FIRFetchAuthDomainCallback)completion; + +/** @fn queryItemValue:from: + @brief Utility function to get a value from a NSURLQueryItem array. + @param name The key. + @param queryList The NSURLQueryItem array. + @return The value for the key. + */ + ++ (nullable NSString *)queryItemValue:(NSString *)name from:(NSArray *)queryList; + +/** @fn dictionaryWithHttpArgumentsString: + @brief Utility function to get a dictionary from a http argument string. + @param argString The http argument string. + @return The resulting dictionary of query arguments. + */ ++ (NSDictionary *)dictionaryWithHttpArgumentsString:(NSString *)argString; + +/** @fn stringByUnescapingFromURLArgument:from: + @brief Utility function to get a string by unescapting URL arguments. + @param argument The argument string. + @return The resulting string after unescaping URL argument. + */ ++ (NSString *)stringByUnescapingFromURLArgument:(NSString *)argument; + +/** @fn parseURL: + @brief Parses an incoming URL into all available query items. + @param urlString The url to be parsed. + @return A dictionary of available query items in the target URL. + */ ++ (NSDictionary *)parseURL:(NSString *)urlString; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebUtils.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebUtils.m new file mode 100644 index 0000000..d3029c0 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebUtils.m @@ -0,0 +1,211 @@ +/* + * 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. + */ + +#import "FirebaseAuth/Sources/Utilities/FIRAuthWebUtils.h" + +#import "FirebaseAuth/Sources/Backend/FIRAuthBackend.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigResponse.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRAuthWebUtils + ++ (NSArray *)supportedAuthDomains { + return @[ @"firebaseapp.com", @"web.app" ]; +} + ++ (NSString *)randomStringWithLength:(NSUInteger)length { + NSMutableString *randomString = [[NSMutableString alloc] init]; + for (int i = 0; i < length; i++) { + [randomString + appendString:[NSString stringWithFormat:@"%c", 'a' + arc4random_uniform('z' - 'a' + 1)]]; + } + return randomString; +} + ++ (BOOL)isCallbackSchemeRegisteredForCustomURLScheme:(NSString *)URLScheme { + NSString *expectedCustomScheme = [URLScheme lowercaseString]; + NSArray *urlTypes = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleURLTypes"]; + for (NSDictionary *urlType in urlTypes) { + NSArray *urlTypeSchemes = urlType[@"CFBundleURLSchemes"]; + for (NSString *urlTypeScheme in urlTypeSchemes) { + if ([urlTypeScheme.lowercaseString isEqualToString:expectedCustomScheme]) { + return YES; + } + } + } + return NO; +} + ++ (BOOL)isExpectedCallbackURL:(nullable NSURL *)URL + eventID:(NSString *)eventID + authType:(NSString *)authType + callbackScheme:(NSString *)callbackScheme { + if (!URL) { + return NO; + } + NSURLComponents *actualURLComponents = [NSURLComponents componentsWithURL:URL + resolvingAgainstBaseURL:NO]; + actualURLComponents.query = nil; + actualURLComponents.fragment = nil; + + NSURLComponents *expectedURLComponents = [[NSURLComponents alloc] init]; + expectedURLComponents.scheme = callbackScheme; + expectedURLComponents.host = @"firebaseauth"; + expectedURLComponents.path = @"/link"; + + if (![expectedURLComponents.URL isEqual:actualURLComponents.URL]) { + return NO; + } + NSDictionary *URLQueryItems = + [self dictionaryWithHttpArgumentsString:URL.query]; + NSURL *deeplinkURL = [NSURL URLWithString:URLQueryItems[@"deep_link_id"]]; + NSDictionary *deeplinkQueryItems = + [self dictionaryWithHttpArgumentsString:deeplinkURL.query]; + if ([deeplinkQueryItems[@"authType"] isEqualToString:authType] && + [deeplinkQueryItems[@"eventId"] isEqualToString:eventID]) { + return YES; + } + return NO; +} + ++ (void)fetchAuthDomainWithRequestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + completion:(FIRFetchAuthDomainCallback)completion { + if (requestConfiguration.emulatorHostAndPort) { + // If we are using the auth emulator, we do not want to call the GetProjectConfig endpoint. The + // widget is hosted on the emulator host and port, so we can return that directly. + completion(requestConfiguration.emulatorHostAndPort, nil); + return; + } + FIRGetProjectConfigRequest *request = + [[FIRGetProjectConfigRequest alloc] initWithRequestConfiguration:requestConfiguration]; + + [FIRAuthBackend + getProjectConfig:request + callback:^(FIRGetProjectConfigResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + completion(nil, error); + return; + } + // Look up an authorized domain ends with one of the supportedAuthDomains. + // The sequence of supportedAuthDomains matters. ("firebaseapp.com", "web.app") + // The searching ends once the first valid suportedAuthDomain is found. + NSString *authDomain; + for (NSString *domain in response.authorizedDomains) { + for (NSString *suportedAuthDomain in [self supportedAuthDomains]) { + NSInteger index = domain.length - suportedAuthDomain.length; + if (index >= 2) { + if ([domain hasSuffix:suportedAuthDomain] && + domain.length >= suportedAuthDomain.length + 2) { + authDomain = domain; + break; + } + } + } + if (authDomain != nil) { + break; + } + } + if (!authDomain.length) { + completion(nil, [FIRAuthErrorUtils + unexpectedErrorResponseWithDeserializedResponse:response]); + return; + } + completion(authDomain, nil); + }]; +} + +/** @fn queryItemValue:from: + @brief Utility function to get a value from a NSURLQueryItem array. + @param name The key. + @param queryList The NSURLQueryItem array. + @return The value for the key. + */ ++ (nullable NSString *)queryItemValue:(NSString *)name from:(NSArray *)queryList { + for (NSURLQueryItem *item in queryList) { + if ([item.name isEqualToString:name]) { + return item.value; + } + } + return nil; +} + ++ (NSDictionary *)dictionaryWithHttpArgumentsString:(NSString *)argString { + NSMutableDictionary *ret = [NSMutableDictionary dictionary]; + NSArray *components = [argString componentsSeparatedByString:@"&"]; + NSString *component; + // Use reverse order so that the first occurrence of a key replaces + // those subsequent. + for (component in [components reverseObjectEnumerator]) { + if (component.length == 0) continue; + NSRange pos = [component rangeOfString:@"="]; + NSString *key; + NSString *val; + if (pos.location == NSNotFound) { + key = [self stringByUnescapingFromURLArgument:component]; + val = @""; + } else { + key = [self stringByUnescapingFromURLArgument:[component substringToIndex:pos.location]]; + val = [self stringByUnescapingFromURLArgument:[component substringFromIndex:pos.location + + pos.length]]; + } + // returns nil on invalid UTF8 and NSMutableDictionary raises an exception when passed nil + // values. + if (!key) key = @""; + if (!val) val = @""; + [ret setObject:val forKey:key]; + } + return ret; +} + ++ (NSString *)stringByUnescapingFromURLArgument:(NSString *)argument { + NSMutableString *resultString = [NSMutableString stringWithString:argument]; + [resultString replaceOccurrencesOfString:@"+" + withString:@" " + options:NSLiteralSearch + range:NSMakeRange(0, [resultString length])]; + return [resultString stringByRemovingPercentEncoding]; +} + ++ (NSDictionary *)parseURL:(NSString *)urlString { + NSString *linkURL = [NSURLComponents componentsWithString:urlString].query; + if (!linkURL) { + return @{}; + } + NSArray *URLComponents = [linkURL componentsSeparatedByString:@"&"]; + NSMutableDictionary *queryItems = + [[NSMutableDictionary alloc] initWithCapacity:URLComponents.count]; + for (NSString *component in URLComponents) { + NSRange equalRange = [component rangeOfString:@"="]; + if (equalRange.location != NSNotFound) { + NSString *queryItemKey = + [[component substringToIndex:equalRange.location] stringByRemovingPercentEncoding]; + NSString *queryItemValue = + [[component substringFromIndex:equalRange.location + 1] stringByRemovingPercentEncoding]; + if (queryItemKey && queryItemValue) { + queryItems[queryItemKey] = queryItemValue; + } + } + } + return queryItems; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebView.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebView.h new file mode 100644 index 0000000..1a837c2 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebView.h @@ -0,0 +1,44 @@ +/* + * 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 +#if TARGET_OS_IOS + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRAuthWebView + @brief A class reponsible for creating a WKWebView for use within Firebase Auth. + */ +@interface FIRAuthWebView : UIView + +/** @property webView + * @brief The web view. + */ +@property(nonatomic, weak) WKWebView *webView; + +/** @property spinner + * @brief The spinner that indicates web view loading. + */ +@property(nonatomic, weak) UIActivityIndicatorView *spinner; + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebView.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebView.m new file mode 100644 index 0000000..2ea8df8 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebView.m @@ -0,0 +1,104 @@ +/* + * 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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Utilities/FIRAuthWebView.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FIRAuthWebView + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + self.backgroundColor = [UIColor whiteColor]; + [self initializeSubviews]; + } + return self; +} + +/** @fn initializeSubviews + @brief Initializes the subviews of this view. + */ +- (void)initializeSubviews { + WKWebView *webView = [self createWebView]; + UIActivityIndicatorView *spinner = [self createSpinner]; + + // The order of the following controls z-order. + [self addSubview:webView]; + [self addSubview:spinner]; + + [self layoutSubviews]; + _webView = webView; + _spinner = spinner; +} + +- (void)layoutSubviews { + CGFloat height = self.bounds.size.height; + CGFloat width = self.bounds.size.width; + _webView.frame = CGRectMake(0, 0, width, height); + _spinner.center = _webView.center; +} + +/** @fn createWebView + @brief Creates a web view to be used by this view. + @return The newly created web view. + */ +- (WKWebView *)createWebView { + WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectZero]; + // Trickery to make the web view not do weird things (like showing a black background when + // the prompt in the navigation bar animates changes.) + webView.opaque = NO; + webView.backgroundColor = [UIColor clearColor]; + webView.scrollView.opaque = NO; + webView.scrollView.backgroundColor = [UIColor clearColor]; + webView.scrollView.bounces = NO; + webView.scrollView.alwaysBounceVertical = NO; + webView.scrollView.alwaysBounceHorizontal = NO; + return webView; +} + +/** @fn createSpinner + @brief Creates a spinner to be used by this view. + @return The newly created spinner. + */ +- (UIActivityIndicatorView *)createSpinner { + UIActivityIndicatorViewStyle spinnerStyle; +#if defined(TARGET_OS_MACCATALYST) + if (@available(iOS 13.0, *)) { + spinnerStyle = UIActivityIndicatorViewStyleMedium; + } else { +// iOS 13 deprecation +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + spinnerStyle = UIActivityIndicatorViewStyleGray; +#pragma clang diagnostic pop + } +#else + spinnerStyle = UIActivityIndicatorViewStyleGray; +#endif + UIActivityIndicatorView *spinner = + [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:spinnerStyle]; + return spinner; +} + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebViewController.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebViewController.h new file mode 100644 index 0000000..2f01ed2 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebViewController.h @@ -0,0 +1,78 @@ +/* + * 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 +#if TARGET_OS_IOS + +#import + +@class FIRAuthWebViewController; + +NS_ASSUME_NONNULL_BEGIN + +/** @protocol FIRAuthWebViewControllerDelegate + @brief Defines a delegate for FIRAuthWebViewController + */ +@protocol FIRAuthWebViewControllerDelegate + +/** @fn webViewController:canHandleURL: + @brief Determines if a URL should be handled by the delegate. + @param URL The URL to handle. + @return Whether the URL could be handled or not. + */ +- (BOOL)webViewController:(FIRAuthWebViewController *)webViewController canHandleURL:(NSURL *)URL; + +/** @fn webViewControllerDidCancel: + @brief Notifies the delegate that the web view controller is being cancelled by the user. + @param webViewController The web view controller in question. + */ +- (void)webViewControllerDidCancel:(FIRAuthWebViewController *)webViewController; + +/** @fn webViewController:didFailWithError: + @brief Notifies the delegate that the web view controller failed to load a page. + @param webViewController The web view controller in question. + @param error The error that has occurred. + */ +- (void)webViewController:(FIRAuthWebViewController *)webViewController + didFailWithError:(NSError *)error; + +@end + +/** @class FIRAuthWebViewController + @brief Reponsible for creating a UIViewController for presenting a FIRAutWebView. + */ +@interface FIRAuthWebViewController : UIViewController + +/** @fn initWithNibName:bundle: + * @brief Please call initWithURL:delegate: + */ +- (instancetype)initWithNibName:(nullable NSString *)nibNameOrNil + bundle:(nullable NSBundle *)nibBundleOrNil NS_UNAVAILABLE; + +/** @fn initWithCoder: + * @brief Please call initWithURL:delegate: + */ +- (instancetype)initWithCoder:(NSCoder *)aDecoder NS_UNAVAILABLE; + +- (instancetype)initWithURL:(NSURL *)URL + delegate:(__weak id)delegate + NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebViewController.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebViewController.m new file mode 100644 index 0000000..acedd12 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/FIRAuthWebViewController.m @@ -0,0 +1,118 @@ +/* + * 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 +#if TARGET_OS_IOS + +#import "FirebaseAuth/Sources/Utilities/FIRAuthWebView.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthWebViewController.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRAuthWebViewController () +@end + +@implementation FIRAuthWebViewController { + /** @var _URL + @brief The initial URL to display. + */ + NSURL *_URL; + + /** @var _delegate + @brief The delegate to call. + */ + __weak id _delegate; + + /** @var _webView; + @brief The web view instance for easier access. + */ + __weak FIRAuthWebView *_webView; +} + +- (instancetype)initWithURL:(NSURL *)URL + delegate:(__weak id)delegate { + self = [super initWithNibName:nil bundle:nil]; + if (self) { + _URL = URL; + _delegate = delegate; + } + return self; +} + +#pragma mark - Lifecycle + +- (void)loadView { + FIRAuthWebView *webView = [[FIRAuthWebView alloc] initWithFrame:[UIScreen mainScreen].bounds]; + webView.webView.navigationDelegate = self; + self.view = webView; + _webView = webView; + self.navigationItem.leftBarButtonItem = + [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel + target:self + action:@selector(cancel)]; +} + +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + + // Loads the requested URL in the web view. + [_webView.webView loadRequest:[NSURLRequest requestWithURL:_URL]]; +} + +#pragma mark - UI Targets + +- (void)cancel { + [_delegate webViewControllerDidCancel:self]; +} + +#pragma mark - WKNavigationDelegate + +- (void)webView:(WKWebView *)webView + decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction + decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler { + [_delegate webViewController:self canHandleURL:navigationAction.request.URL]; + decisionHandler(WKNavigationActionPolicyAllow); +} + +- (void)webView:(WKWebView *)webView + didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation { + _webView.spinner.hidden = NO; + [_webView.spinner startAnimating]; +} + +- (void)webView:(WKWebView *)webView + didFinishNavigation:(null_unspecified WKNavigation *)navigation { + _webView.spinner.hidden = YES; + [_webView.spinner stopAnimating]; +} + +- (void)webView:(WKWebView *)webView + didFailNavigation:(null_unspecified WKNavigation *)navigation + withError:(NSError *)error { + if ([error.domain isEqualToString:NSURLErrorDomain] && error.code == NSURLErrorCancelled) { + // It's okay for the page to be redirected before it is completely loaded. See b/32028062 . + return; + } + // Forward notification to our delegate. + [self webView:webView didFinishNavigation:navigation]; + [_delegate webViewController:self didFailWithError:error]; +} + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/NSData+FIRBase64.h b/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/NSData+FIRBase64.h new file mode 100644 index 0000000..114cbfd --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/NSData+FIRBase64.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface NSData (FIRBase64) + +/** @fn fir_base64URLEncodedStringWithOptions: + @brief Get a web safe base64 encoded string + @param options The base64 encoding options + */ +- (NSString *)fir_base64URLEncodedStringWithOptions:(NSDataBase64EncodingOptions)options; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/NSData+FIRBase64.m b/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/NSData+FIRBase64.m new file mode 100644 index 0000000..0afc53b --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseAuth/Sources/Utilities/NSData+FIRBase64.m @@ -0,0 +1,33 @@ +/* + * 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. + */ + +#import "FirebaseAuth/Sources/Utilities/NSData+FIRBase64.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation NSData (FIRBase64) + +- (NSString *)fir_base64URLEncodedStringWithOptions:(NSDataBase64EncodingOptions)options { + NSString *string = [self base64EncodedStringWithOptions:options]; + string = [string stringByReplacingOccurrencesOfString:@"/" withString:@"_"]; + string = [string stringByReplacingOccurrencesOfString:@"+" withString:@"-"]; + string = [string stringByReplacingOccurrencesOfString:@"=" withString:@""]; + return string; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseCore/Extension/FIRAppInternal.h b/Pods/FirebaseAuth/FirebaseCore/Extension/FIRAppInternal.h new file mode 100644 index 0000000..49104f0 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseCore/Extension/FIRAppInternal.h @@ -0,0 +1,159 @@ +/* + * 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 + +@class FIRComponentContainer; +@class FIRHeartbeatLogger; +@protocol FIRLibrary; + +/** + * The internal interface to `FirebaseApp`. This is meant for first-party integrators, who need to + * receive `FirebaseApp` notifications, log info about the success or failure of their + * configuration, and access other internal functionality of `FirebaseApp`. + */ +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(NSInteger, FIRConfigType) { + FIRConfigTypeCore = 1, + FIRConfigTypeSDK = 2, +}; + +extern NSString *const kFIRDefaultAppName; +extern NSString *const kFIRAppReadyToConfigureSDKNotification; +extern NSString *const kFIRAppDeleteNotification; +extern NSString *const kFIRAppIsDefaultAppKey; +extern NSString *const kFIRAppNameKey; +extern NSString *const kFIRGoogleAppIDKey; +extern NSString *const kFirebaseCoreErrorDomain; + +/** The `UserDefaults` suite name for `FirebaseCore`, for those storage locations that use it. */ +extern NSString *const kFirebaseCoreDefaultsSuiteName; + +/** + * The format string for the `UserDefaults` key used for storing the data collection enabled flag. + * This includes formatting to append the `FirebaseApp`'s name. + */ +extern NSString *const kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat; + +/** + * The plist key used for storing the data collection enabled flag. + */ +extern NSString *const kFIRGlobalAppDataCollectionEnabledPlistKey; + +/** @var FirebaseAuthStateDidChangeInternalNotification + @brief The name of the @c NotificationCenter notification which is posted when the auth state + changes (e.g. a new token has been produced, a user logs in or out). The object parameter of + the notification is a dictionary possibly containing the key: + @c FirebaseAuthStateDidChangeInternalNotificationTokenKey (the new access token.) If it does not + contain this key it indicates a sign-out event took place. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotification; + +/** @var FirebaseAuthStateDidChangeInternalNotificationTokenKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the new access token. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationTokenKey; + +/** @var FirebaseAuthStateDidChangeInternalNotificationAppKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the FirebaseApp associated with the auth instance. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationAppKey; + +/** @var FirebaseAuthStateDidChangeInternalNotificationUIDKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the new user's UID (or nil if there is no longer a user signed in). + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationUIDKey; + +@interface FIRApp () + +/** + * A flag indicating if this is the default app (has the default app name). + */ +@property(nonatomic, readonly) BOOL isDefaultApp; + +/** + * The container of interop SDKs for this app. + */ +@property(nonatomic) FIRComponentContainer *container; + +/** + * The heartbeat logger associated with this app. + * + * Firebase apps have a 1:1 relationship with heartbeat loggers. + */ +@property(readonly) FIRHeartbeatLogger *heartbeatLogger; + +/** + * Checks if the default app is configured without trying to configure it. + */ ++ (BOOL)isDefaultAppConfigured; + +/** + * Registers a given third-party library with the given version number to be reported for + * analytics. + * + * @param name Name of the library. + * @param version Version of the library. + */ ++ (void)registerLibrary:(nonnull NSString *)name withVersion:(nonnull NSString *)version; + +/** + * Registers a given internal library to be reported for analytics. + * + * @param library Optional parameter for component registration. + * @param name Name of the library. + */ ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name; + +/** + * Registers a given internal library with the given version number to be reported for + * analytics. This should only be used for non-Firebase libraries that have their own versioning + * scheme. + * + * @param library Optional parameter for component registration. + * @param name Name of the library. + * @param version Version of the library. + */ ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name + withVersion:(nonnull NSString *)version; + +/** + * A concatenated string representing all the third-party libraries and version numbers. + */ ++ (NSString *)firebaseUserAgent; + +/** + * Can be used by the unit tests in each SDK to reset `FirebaseApp`. This method is thread unsafe. + */ ++ (void)resetApps; + +/** + * Can be used by the unit tests in each SDK to set customized options. + */ +- (instancetype)initInstanceWithName:(NSString *)name options:(FIROptions *)options; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseCore/Extension/FIRComponent.h b/Pods/FirebaseAuth/FirebaseCore/Extension/FIRComponent.h new file mode 100644 index 0000000..e4c8a27 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseCore/Extension/FIRComponent.h @@ -0,0 +1,91 @@ +/* + * 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. + */ + +#import + +@class FIRApp; +@class FIRComponentContainer; + +NS_ASSUME_NONNULL_BEGIN + +/// Provides a system to clean up cached instances returned from the component system. +NS_SWIFT_NAME(ComponentLifecycleMaintainer) +@protocol FIRComponentLifecycleMaintainer +/// The associated app will be deleted, clean up any resources as they are about to be deallocated. +- (void)appWillBeDeleted:(FIRApp *)app; +@end + +typedef _Nullable id (^FIRComponentCreationBlock)(FIRComponentContainer *container, + BOOL *isCacheable) + NS_SWIFT_NAME(ComponentCreationBlock); + +@class FIRDependency; + +/// Describes the timing of instantiation. Note: new components should default to lazy unless there +/// is a strong reason to be eager. +typedef NS_ENUM(NSInteger, FIRInstantiationTiming) { + FIRInstantiationTimingLazy, + FIRInstantiationTimingAlwaysEager, + FIRInstantiationTimingEagerInDefaultApp +} NS_SWIFT_NAME(InstantiationTiming); + +/// A component that can be used from other Firebase SDKs. +NS_SWIFT_NAME(Component) +@interface FIRComponent : NSObject + +/// The protocol describing functionality provided from the `Component`. +@property(nonatomic, strong, readonly) Protocol *protocol; + +/// The timing of instantiation. +@property(nonatomic, readonly) FIRInstantiationTiming instantiationTiming; + +/// An array of dependencies for the component. +@property(nonatomic, copy, readonly) NSArray *dependencies; + +/// A block to instantiate an instance of the component with the appropriate dependencies. +@property(nonatomic, copy, readonly) FIRComponentCreationBlock creationBlock; + +// There's an issue with long NS_SWIFT_NAMES that causes compilation to fail, disable clang-format +// for the next two methods. +// clang-format off + +/// Creates a component with no dependencies that will be lazily initialized. ++ (instancetype)componentWithProtocol:(Protocol *)protocol + creationBlock:(FIRComponentCreationBlock)creationBlock +NS_SWIFT_NAME(init(_:creationBlock:)); + +/// Creates a component to be registered with the component container. +/// +/// @param protocol - The protocol describing functionality provided by the component. +/// @param instantiationTiming - When the component should be initialized. Use .lazy unless there's +/// a good reason to be instantiated earlier. +/// @param dependencies - Any dependencies the `implementingClass` has, optional or required. +/// @param creationBlock - A block to instantiate the component with a container, and if +/// @return A component that can be registered with the component container. ++ (instancetype)componentWithProtocol:(Protocol *)protocol + instantiationTiming:(FIRInstantiationTiming)instantiationTiming + dependencies:(NSArray *)dependencies + creationBlock:(FIRComponentCreationBlock)creationBlock +NS_SWIFT_NAME(init(_:instantiationTiming:dependencies:creationBlock:)); + +// clang-format on + +/// Unavailable. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseCore/Extension/FIRComponentContainer.h b/Pods/FirebaseAuth/FirebaseCore/Extension/FIRComponentContainer.h new file mode 100644 index 0000000..6ec6147 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseCore/Extension/FIRComponentContainer.h @@ -0,0 +1,45 @@ +/* + * 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. + */ +#import + +NS_ASSUME_NONNULL_BEGIN + +/// A type-safe macro to retrieve a component from a container. This should be used to retrieve +/// components instead of using the container directly. +#define FIR_COMPONENT(type, container) \ + [FIRComponentType> instanceForProtocol:@protocol(type) inContainer:container] + +@class FIRApp; + +/// A container that holds different components that are registered via the +/// `registerAsComponentRegistrant` call. These classes should conform to `ComponentRegistrant` +/// in order to properly register components for Core. +NS_SWIFT_NAME(FirebaseComponentContainer) +@interface FIRComponentContainer : NSObject + +/// A weak reference to the app that an instance of the container belongs to. +@property(nonatomic, weak, readonly) FIRApp *app; + +// TODO: See if we can get improved type safety here. +/// A Swift only API for fetching an instance since the top macro isn't available. +- (nullable id)__instanceForProtocol:(Protocol *)protocol NS_SWIFT_NAME(instance(for:)); + +/// Unavailable. Use the `container` property on `FirebaseApp`. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseCore/Extension/FIRComponentType.h b/Pods/FirebaseAuth/FirebaseCore/Extension/FIRComponentType.h new file mode 100644 index 0000000..6f2aca7 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseCore/Extension/FIRComponentType.h @@ -0,0 +1,34 @@ +/* + * 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. + */ + +#import + +@class FIRComponentContainer; + +NS_ASSUME_NONNULL_BEGIN + +/// Do not use directly. A placeholder type in order to provide a macro that will warn users of +/// mis-matched protocols. +NS_SWIFT_NAME(ComponentType) +@interface FIRComponentType<__covariant T> : NSObject + +/// Do not use directly. A factory method to retrieve an instance that provides a specific +/// functionality. ++ (T)instanceForProtocol:(Protocol *)protocol inContainer:(FIRComponentContainer *)container; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseCore/Extension/FIRDependency.h b/Pods/FirebaseAuth/FirebaseCore/Extension/FIRDependency.h new file mode 100644 index 0000000..a070557 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseCore/Extension/FIRDependency.h @@ -0,0 +1,45 @@ +/* + * 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. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/// A dependency on a specific protocol's functionality. +NS_SWIFT_NAME(Dependency) +@interface FIRDependency : NSObject + +/// The protocol describing functionality being depended on. +@property(nonatomic, strong, readonly) Protocol *protocol; + +/// A flag to specify if the dependency is required or not. +@property(nonatomic, readonly) BOOL isRequired; + +/// Initializes a dependency that is required. Calls `init(protocol:isRequired:)` with true for +/// the required parameter. +/// Creates a required dependency on the specified protocol's functionality. ++ (instancetype)dependencyWithProtocol:(Protocol *)protocol; + +/// Creates a dependency on the specified protocol's functionality and specify if it's required for +/// the class's functionality. ++ (instancetype)dependencyWithProtocol:(Protocol *)protocol isRequired:(BOOL)required; + +/// Use `init(withProtocol:isRequired:)` instead. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseCore/Extension/FIRHeartbeatLogger.h b/Pods/FirebaseAuth/FirebaseCore/Extension/FIRHeartbeatLogger.h new file mode 100644 index 0000000..0f39ad9 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseCore/Extension/FIRHeartbeatLogger.h @@ -0,0 +1,90 @@ +// Copyright 2021 Google LLC +// +// 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 + +NS_ASSUME_NONNULL_BEGIN + +#ifndef FIREBASE_BUILD_CMAKE +@class FIRHeartbeatsPayload; +#endif // FIREBASE_BUILD_CMAKE + +/// Enum representing different daily heartbeat codes. +/// This enum is only used by clients using platform logging V1. This is because +/// the V1 payload only supports a single daily heartbeat. +typedef NS_ENUM(NSInteger, FIRDailyHeartbeatCode) { + /// Represents the absence of a daily heartbeat. + FIRDailyHeartbeatCodeNone = 0, + /// Represents the presence of a daily heartbeat. + FIRDailyHeartbeatCodeSome = 2, +}; + +@protocol FIRHeartbeatLoggerProtocol + +/// Asynchronously logs a heartbeat. +- (void)log; + +#ifndef FIREBASE_BUILD_CMAKE +/// Flushes heartbeats from storage into a structured payload of heartbeats. +- (FIRHeartbeatsPayload *)flushHeartbeatsIntoPayload; +#endif // FIREBASE_BUILD_CMAKE + +/// Gets the heartbeat code for today. +- (FIRDailyHeartbeatCode)heartbeatCodeForToday; + +@end + +#ifndef FIREBASE_BUILD_CMAKE +/// Returns a nullable string header value from a given heartbeats payload. +/// +/// This API returns `nil` when the given heartbeats payload is considered empty. +/// +/// @param heartbeatsPayload The heartbeats payload. +NSString *_Nullable FIRHeaderValueFromHeartbeatsPayload(FIRHeartbeatsPayload *heartbeatsPayload); +#endif // FIREBASE_BUILD_CMAKE + +/// A thread safe, synchronized object that logs and flushes platform logging info. +@interface FIRHeartbeatLogger : NSObject + +/// Designated initializer. +/// +/// @param appID The app ID that this heartbeat logger corresponds to. +- (instancetype)initWithAppID:(NSString *)appID; + +/// Asynchronously logs a new heartbeat corresponding to the Firebase User Agent, if needed. +/// +/// @note This API is thread-safe. +- (void)log; + +#ifndef FIREBASE_BUILD_CMAKE +/// Flushes heartbeats from storage into a structured payload of heartbeats. +/// +/// This API is for clients using platform logging V2. +/// +/// @note This API is thread-safe. +/// @return A payload of heartbeats. +- (FIRHeartbeatsPayload *)flushHeartbeatsIntoPayload; +#endif // FIREBASE_BUILD_CMAKE + +/// Gets today's corresponding heartbeat code. +/// +/// This API is for clients using platform logging V1. +/// +/// @note This API is thread-safe. +/// @return Heartbeat code indicating whether or not there is an unsent global heartbeat. +- (FIRDailyHeartbeatCode)heartbeatCodeForToday; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseCore/Extension/FIRLibrary.h b/Pods/FirebaseAuth/FirebaseCore/Extension/FIRLibrary.h new file mode 100644 index 0000000..15e2865 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseCore/Extension/FIRLibrary.h @@ -0,0 +1,44 @@ +/* + * 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 FIRLibrary_h +#define FIRLibrary_h + +#import + +@class FIRApp; +@class FIRComponent; + +NS_ASSUME_NONNULL_BEGIN + +/// Provide an interface to register a library for userAgent logging and availability to others. +NS_SWIFT_NAME(Library) +@protocol FIRLibrary + +/// Returns one or more Components that will be registered in +/// FirebaseApp and participate in dependency resolution and injection. ++ (NSArray *)componentsToRegister; + +@optional +/// Implement this method if the library needs notifications for lifecycle events. This method is +/// called when the developer calls `FirebaseApp.configure()`. ++ (void)configureWithApp:(FIRApp *)app; + +@end + +NS_ASSUME_NONNULL_END + +#endif /* FIRLibrary_h */ diff --git a/Pods/FirebaseAuth/FirebaseCore/Extension/FIRLogger.h b/Pods/FirebaseAuth/FirebaseCore/Extension/FIRLogger.h new file mode 100644 index 0000000..0a287f5 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseCore/Extension/FIRLogger.h @@ -0,0 +1,188 @@ +/* + * 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 + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * The Firebase services used in Firebase logger. + */ +typedef NSString *const FIRLoggerService; + +extern FIRLoggerService kFIRLoggerAnalytics; +extern FIRLoggerService kFIRLoggerCrash; +extern FIRLoggerService kFIRLoggerCore; +extern FIRLoggerService kFIRLoggerRemoteConfig; + +/** + * The key used to store the logger's error count. + */ +extern NSString *const kFIRLoggerErrorCountKey; + +/** + * The key used to store the logger's warning count. + */ +extern NSString *const kFIRLoggerWarningCountKey; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** + * Enables or disables Analytics debug mode. + * If set to true, the logging level for Analytics will be set to FirebaseLoggerLevelDebug. + * Enabling the debug mode has no effect if the app is running from App Store. + * (required) analytics debug mode flag. + */ +void FIRSetAnalyticsDebugMode(BOOL analyticsDebugMode); + +/** + * Changes the default logging level of FirebaseLoggerLevelNotice to a user-specified level. + * The default level cannot be set above FirebaseLoggerLevelNotice if the app is running from App + * Store. (required) log level (one of the FirebaseLoggerLevel enum values). + */ +void FIRSetLoggerLevel(FIRLoggerLevel loggerLevel); + +/** + * Checks if the specified logger level is loggable given the current settings. + * (required) log level (one of the FirebaseLoggerLevel enum values). + * (required) whether or not this function is called from the Analytics component. + */ +BOOL FIRIsLoggableLevel(FIRLoggerLevel loggerLevel, BOOL analyticsComponent); + +/** + * Logs a message to the Xcode console and the device log. If running from AppStore, will + * not log any messages with a level higher than FirebaseLoggerLevelNotice to avoid log spamming. + * (required) log level (one of the FirebaseLoggerLevel enum values). + * (required) service name of type FirebaseLoggerService. + * (required) message code starting with "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique + * within the service. + * An example of the message code is @"I-COR000001". + * (required) message string which can be a format string. + * (optional) variable arguments list obtained from calling va_start, used when message is a format + * string. + */ +extern void FIRLogBasic(FIRLoggerLevel level, + FIRLoggerService service, + NSString *messageCode, + NSString *message, +// On 64-bit simulators, va_list is not a pointer, so cannot be marked nullable +// See: http://stackoverflow.com/q/29095469 +#if __LP64__ && TARGET_OS_SIMULATOR || TARGET_OS_OSX + va_list args_ptr +#else + va_list _Nullable args_ptr +#endif +); + +/** + * The following functions accept the following parameters in order: + * (required) service name of type FirebaseLoggerService. + * (required) message code starting from "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique + * within the service. + * An example of the message code is @"I-COR000001". + * See go/firebase-log-proposal for details. + * (required) message string which can be a format string. + * (optional) the list of arguments to substitute into the format string. + * Example usage: + * FirebaseLogError(kFirebaseLoggerCore, @"I-COR000001", @"Configuration of %@ failed.", app.name); + */ +extern void FIRLogError(FIRLoggerService service, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogWarning(FIRLoggerService service, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogNotice(FIRLoggerService service, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogInfo(FIRLoggerService service, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogDebug(FIRLoggerService service, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); + +// TODO: Come up with a better logging scheme for Swift. +/** + * Logs a debug message to the Xcode console and the device log. If running from AppStore, will + * not log any messages with a level higher than FirebaseLoggerLevelNotice to avoid log spamming. + * This function is intended to be used by Swift clients that do not support variadic parameters. + * + * @param service The service name of type `FirebaseLoggerService`. + * @param messageCode The mesage code. starting with "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique within the + * service. An example of the message code is @"I-COR000001". + * @param message The message string. + */ +extern void FIRLogDebugSwift(FIRLoggerService service, NSString *messageCode, NSString *message); + +/** + * Logs a warning message to the Xcode console and the device log. If running from AppStore, will + * not log any messages with a level higher than FirebaseLoggerLevelNotice to avoid log spamming. + * This function is intended to be used by Swift clients that do not support variadic parameters. + * + * @param service The service name of type `FirebaseLoggerService`. + * @param messageCode The mesage code. starting with "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique within the + * service. An example of the message code is @"I-COR000001". + * @param message The message string. + */ +extern void FIRLogWarningSwift(FIRLoggerService service, NSString *messageCode, NSString *message); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +NS_SWIFT_NAME(FirebaseLogger) +@interface FIRLoggerWrapper : NSObject + +/// Logs a given message at a given log level. This API is effectively a wrapper for the +/// `FIRLogBasic` C API. +/// +/// - Parameters: +/// - level: The log level to use (defined by `FirebaseLoggerLevel` enum values). +/// - service: The service name of type `FirebaseLoggerService`. +/// - code: The mesage code. Starting with "I-" which means iOS, followed by a capitalized +/// three-character service identifier and a six digit integer message ID that is unique within +/// the service. An example of the message code is @"I-COR000001". +/// - message: Formatted string to be used as the log's message. +/// - args: Arguments list obtained from calling `va_start`, used when message is a format string. ++ (void)logWithLevel:(FIRLoggerLevel)level + withService:(FIRLoggerService)service + withCode:(NSString *)messageCode + withMessage:(NSString *)message + withArgs:(va_list)args; + +/// Logs a given message at a given log level. +/// +/// - Parameters: +/// - level: The log level to use (defined by `FirebaseLoggerLevel` enum values). +/// - service: The service name of type `FirebaseLoggerService`. +/// - code: The mesage code. Starting with "I-" which means iOS, followed by a capitalized +/// three-character service identifier and a six digit integer message ID that is unique within +/// the service. An example of the message code is @"I-COR000001". +/// - message: Formatted string to be used as the log's message. +/// - args: Arguments list obtained from calling `va_start`, used when message is a format string. ++ (void)logWithLevel:(FIRLoggerLevel)level + service:(FIRLoggerService)service + code:(NSString *)code + message:(NSString *)message + __attribute__((__swift_name__("log(level:service:code:message:)"))); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAuth/FirebaseCore/Extension/FIROptionsInternal.h b/Pods/FirebaseAuth/FirebaseCore/Extension/FIROptionsInternal.h new file mode 100644 index 0000000..93a03d6 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseCore/Extension/FIROptionsInternal.h @@ -0,0 +1,106 @@ +/* + * 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 + +/** + * Keys for the strings in the plist file. + */ +extern NSString *const kFIRAPIKey; +extern NSString *const kFIRTrackingID; +extern NSString *const kFIRGoogleAppID; +extern NSString *const kFIRClientID; +extern NSString *const kFIRGCMSenderID; +extern NSString *const kFIRAndroidClientID; +extern NSString *const kFIRDatabaseURL; +extern NSString *const kFIRStorageBucket; +extern NSString *const kFIRBundleID; +extern NSString *const kFIRProjectID; + +/** + * Keys for the plist file name + */ +extern NSString *const kServiceInfoFileName; + +extern NSString *const kServiceInfoFileType; + +/** + * This header file exposes the initialization of FirebaseOptions to internal use. + */ +@interface FIROptions () + +/** + * `resetDefaultOptions` and `initInternalWithOptionsDictionary` are exposed only for unit tests. + */ ++ (void)resetDefaultOptions; + +/** + * Initializes the options with dictionary. The above strings are the keys of the dictionary. + * This is the designated initializer. + */ +- (instancetype)initInternalWithOptionsDictionary:(NSDictionary *)serviceInfoDictionary + NS_DESIGNATED_INITIALIZER; + +/** + * `defaultOptions` and `defaultOptionsDictionary` are exposed in order to be used in FirebaseApp + * and other first party services. + */ ++ (FIROptions *)defaultOptions; + ++ (NSDictionary *)defaultOptionsDictionary; + +/** + * Indicates whether or not Analytics collection was explicitly enabled via a plist flag or at + * runtime. + */ +@property(nonatomic, readonly) BOOL isAnalyticsCollectionExplicitlySet; + +/** + * Whether or not Analytics Collection was enabled. Analytics Collection is enabled unless + * explicitly disabled in GoogleService-Info.plist. + */ +@property(nonatomic, readonly) BOOL isAnalyticsCollectionEnabled; + +/** + * Whether or not Analytics Collection was completely disabled. If true, then + * isAnalyticsCollectionEnabled will be false. + */ +@property(nonatomic, readonly) BOOL isAnalyticsCollectionDeactivated; + +/** + * The version ID of the client library, e.g. @"1100000". + */ +@property(nonatomic, readonly, copy) NSString *libraryVersionID; + +/** + * The flag indicating whether this object was constructed with the values in the default plist + * file. + */ +@property(nonatomic) BOOL usingOptionsFromDefaultPlist; + +/** + * Whether or not Measurement was enabled. Measurement is enabled unless explicitly disabled in + * GoogleService-Info.plist. + */ +@property(nonatomic, readonly) BOOL isMeasurementEnabled; + +/** + * Whether or not editing is locked. This should occur after `FirebaseOptions` has been set on a + * `FirebaseApp`. + */ +@property(nonatomic, getter=isEditingLocked) BOOL editingLocked; + +@end diff --git a/Pods/FirebaseAuth/FirebaseCore/Extension/FirebaseCoreInternal.h b/Pods/FirebaseAuth/FirebaseCore/Extension/FirebaseCoreInternal.h new file mode 100644 index 0000000..0669ae6 --- /dev/null +++ b/Pods/FirebaseAuth/FirebaseCore/Extension/FirebaseCoreInternal.h @@ -0,0 +1,25 @@ +// Copyright 2020 Google LLC +// +// 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 FirebaseCore; + +#import "FIRAppInternal.h" +#import "FIRComponent.h" +#import "FIRComponentContainer.h" +#import "FIRComponentType.h" +#import "FIRDependency.h" +#import "FIRHeartbeatLogger.h" +#import "FIRLibrary.h" +#import "FIRLogger.h" +#import "FIROptionsInternal.h" diff --git a/Pods/FirebaseAuth/LICENSE b/Pods/FirebaseAuth/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/Pods/FirebaseAuth/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/Pods/FirebaseAuth/README.md b/Pods/FirebaseAuth/README.md new file mode 100644 index 0000000..85a23bd --- /dev/null +++ b/Pods/FirebaseAuth/README.md @@ -0,0 +1,281 @@ +

+ + + + + + + + +
+ + + + + + +

+ +# Firebase Apple Open Source Development + +This repository contains all Apple platform Firebase SDK source except FirebaseAnalytics. + +Firebase is an app development platform with tools to help you build, grow and +monetize your app. More information about Firebase can be found on the +[official Firebase website](https://firebase.google.com). + +## Installation + +See the subsections below for details about the different installation methods. Where +available, it's recommended to install any libraries with a `Swift` suffix to get the +best experience when writing your app in Swift. +1. [Standard pod install](#standard-pod-install) +1. [Swift Package Manager](#swift-package-manager) +1. [Installing from the GitHub repo](#installing-from-github) +1. [Experimental Carthage](#carthage-ios-only) + +### Standard pod install + +Go to +[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup). + +### Swift Package Manager + +Instructions for [Swift Package Manager](https://swift.org/package-manager/) support can be +found at [SwiftPackageManager](SwiftPackageManager.md) Markdown file. + +### Installing from GitHub + +These instructions can be used to access the Firebase repo at other branches, +tags, or commits. + +#### Background + +See +[the Podfile Syntax Reference](https://guides.cocoapods.org/syntax/podfile.html#pod) +for instructions and options about overriding pod source locations. + +#### Accessing Firebase Source Snapshots + +All of the official releases are tagged in this repo and available via CocoaPods. To access a local +source snapshot or unreleased branch, use Podfile directives like the following: + +To access FirebaseFirestore via a branch: +```ruby +pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master' +pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master' +``` + +To access FirebaseMessaging via a checked out version of the firebase-ios-sdk repo do: + +```ruby +pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk' +pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk' +``` + +### Carthage (iOS only) + +Instructions for the experimental Carthage distribution are at +[Carthage](Carthage.md). + +### Using Firebase from a Framework or a library + +[Using Firebase from a Framework or a library](docs/firebase_in_libraries.md) + +## Development + +To develop Firebase software in this repository, ensure that you have at least +the following software: + + * Xcode 14.1 (or later) + +CocoaPods is still the canonical way to develop, but much of the repo now supports +development with Swift Package Manager. + +### CocoaPods + +Install + * CocoaPods 1.10.0 (or later) + * [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +```ruby +pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios +``` + +Note: If the CocoaPods cache is out of date, you may need to run +`pod repo update` before the `pod gen` command. + +Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for +those platforms. Since 10.2, Xcode does not properly handle multi-platform +CocoaPods workspaces. + +Firestore has a self contained Xcode project. See +[Firestore/README](Firestore/README.md) Markdown file. + +#### Development for Catalyst +* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios` +* Check the Mac box in the App-iOS Build Settings +* Sign the App in the Settings Signing & Capabilities tab +* Click Pods in the Project Manager +* Add Signing to the iOS host app and unit test targets +* Select the Unit-unit scheme +* Run it to build and test + +Alternatively disable signing in each target: +* Go to Build Settings tab +* Click `+` +* Select `Add User-Defined Setting` +* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO` + +### Swift Package Manager +* To enable test schemes: `./scripts/setup_spm_tests.sh` +* `open Package.swift` or double click `Package.swift` in Finder. +* Xcode will open the project + * Choose a scheme for a library to build or test suite to run + * Choose a target platform by selecting the run destination along with the scheme + +### Adding a New Firebase Pod + +See [AddNewPod](AddNewPod.md) Markdown file. + +### Managing Headers and Imports + +See [HeadersImports](HeadersImports.md) Markdown file. + +### Code Formatting + +To ensure that the code is formatted consistently, run the script +[./scripts/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/master/scripts/check.sh) +before creating a PR. + +GitHub Actions will verify that any code changes are done in a style compliant +way. Install `clang-format` and `mint`: + +```console +brew install clang-format@16 +brew install mint +``` + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +### Running Sample Apps +In order to run the sample apps and integration tests, you'll need a valid +`GoogleService-Info.plist` file. The Firebase Xcode project contains dummy plist +files without real values, but can be replaced with real plist files. To get your own +`GoogleService-Info.plist` files: + +1. Go to the [Firebase Console](https://console.firebase.google.com/) +2. Create a new Firebase project, if you don't already have one +3. For each sample app you want to test, create a new Firebase app with the sample app's bundle +identifier (e.g. `com.google.Database-Example`) +4. Download the resulting `GoogleService-Info.plist` and add it to the Xcode project. + +### Coverage Report Generation + +See [scripts/code_coverage_report/README](scripts/code_coverage_report/README.md) Markdown file. + +## Specific Component Instructions +See the sections below for any special instructions for those components. + +### Firebase Auth + +If you're doing specific Firebase Auth development, see +[the Auth Sample README](FirebaseAuth/Tests/Sample/README.md) for instructions about +building and running the FirebaseAuth pod along with various samples and tests. + +### Firebase Database + +The Firebase Database Integration tests can be run against a locally running Database Emulator +or against a production instance. + +To run against a local emulator instance, invoke `./scripts/run_database_emulator.sh start` before +running the integration test. + +To run against a production instance, provide a valid GoogleServices-Info.plist and copy it to +`FirebaseDatabase/Tests/Resources/GoogleService-Info.plist`. Your Security Rule must be set to +[public](https://firebase.google.com/docs/database/security/quickstart) while your tests are +running. + +### Firebase Performance Monitoring +If you're doing specific Firebase Performance Monitoring development, see +[the Performance README](FirebasePerformance/README.md) for instructions about building the SDK +and [the Performance TestApp README](FirebasePerformance/Tests/TestApp/README.md) for instructions about +integrating Performance with the dev test App. + +### Firebase Storage + +To run the Storage Integration tests, follow the instructions in +[StorageIntegration.swift](FirebaseStorage/Tests/Integration/StorageIntegration.swift). + +#### Push Notifications + +Push notifications can only be delivered to specially provisioned App IDs in the developer portal. +In order to actually test receiving push notifications, you will need to: + +1. Change the bundle identifier of the sample app to something you own in your Apple Developer +account, and enable that App ID for push notifications. +2. You'll also need to +[upload your APNs Provider Authentication Key or certificate to the +Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs) +at **Project Settings > Cloud Messaging > [Your Firebase App]**. +3. Ensure your iOS device is added to your Apple Developer portal as a test device. + +#### iOS Simulator + +The iOS Simulator cannot register for remote notifications, and will not receive push notifications. +In order to receive push notifications, you'll have to follow the steps above and run the app on a +physical device. + +## Building with Firebase on Apple platforms + +Firebase 8.9.0 introduced official beta support for macOS, Catalyst, and tvOS. watchOS continues +to be community supported. Thanks to community contributions for many of the multi-platform PRs. + +At this time, most of Firebase's products are available across Apple platforms. There are still +a few gaps, especially on watchOS. For details about the current support matrix, see +[this chart](https://firebase.google.com/docs/ios/learn-more#firebase_library_support_by_platform) +in Firebase's documentation. + +### watchOS +Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and +work on watchOS. See the [Independent Watch App Sample](Example/watchOSSample). + +Keep in mind that watchOS is not officially supported by Firebase. While we can catch basic unit +test issues with GitHub Actions, there may be some changes where the SDK no longer works as expected +on watchOS. If you encounter this, please +[file an issue](https://github.com/firebase/firebase-ios-sdk/issues). + +During app setup in the console, you may get to a step that mentions something like "Checking if the +app has communicated with our servers". This relies on Analytics and will not work on watchOS. +**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected. + +#### Additional Crashlytics Notes +* watchOS has limited support. Due to watchOS restrictions, mach exceptions and signal crashes are +not recorded. (Crashes in SwiftUI are generated as mach exceptions, so will not be recorded) + +## Combine +Thanks to contributions from the community, _FirebaseCombineSwift_ contains support for Apple's Combine +framework. This module is currently under development, and not yet supported for use in production +environments. Fore more details, please refer to the [docs](FirebaseCombineSwift/README.md). + +## Roadmap + +See [Roadmap](ROADMAP.md) for more about the Firebase Apple SDK Open Source +plans and directions. + +## Contributing + +See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase +Apple SDK. + +## License + +The contents of this repository are licensed under the +[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). + +Your use of Firebase is governed by the +[Terms of Service for Firebase Services](https://firebase.google.com/terms/). diff --git a/Pods/FirebaseCore/FirebaseCore/Extension/FIRAppInternal.h b/Pods/FirebaseCore/FirebaseCore/Extension/FIRAppInternal.h new file mode 100644 index 0000000..49104f0 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Extension/FIRAppInternal.h @@ -0,0 +1,159 @@ +/* + * 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 + +@class FIRComponentContainer; +@class FIRHeartbeatLogger; +@protocol FIRLibrary; + +/** + * The internal interface to `FirebaseApp`. This is meant for first-party integrators, who need to + * receive `FirebaseApp` notifications, log info about the success or failure of their + * configuration, and access other internal functionality of `FirebaseApp`. + */ +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(NSInteger, FIRConfigType) { + FIRConfigTypeCore = 1, + FIRConfigTypeSDK = 2, +}; + +extern NSString *const kFIRDefaultAppName; +extern NSString *const kFIRAppReadyToConfigureSDKNotification; +extern NSString *const kFIRAppDeleteNotification; +extern NSString *const kFIRAppIsDefaultAppKey; +extern NSString *const kFIRAppNameKey; +extern NSString *const kFIRGoogleAppIDKey; +extern NSString *const kFirebaseCoreErrorDomain; + +/** The `UserDefaults` suite name for `FirebaseCore`, for those storage locations that use it. */ +extern NSString *const kFirebaseCoreDefaultsSuiteName; + +/** + * The format string for the `UserDefaults` key used for storing the data collection enabled flag. + * This includes formatting to append the `FirebaseApp`'s name. + */ +extern NSString *const kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat; + +/** + * The plist key used for storing the data collection enabled flag. + */ +extern NSString *const kFIRGlobalAppDataCollectionEnabledPlistKey; + +/** @var FirebaseAuthStateDidChangeInternalNotification + @brief The name of the @c NotificationCenter notification which is posted when the auth state + changes (e.g. a new token has been produced, a user logs in or out). The object parameter of + the notification is a dictionary possibly containing the key: + @c FirebaseAuthStateDidChangeInternalNotificationTokenKey (the new access token.) If it does not + contain this key it indicates a sign-out event took place. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotification; + +/** @var FirebaseAuthStateDidChangeInternalNotificationTokenKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the new access token. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationTokenKey; + +/** @var FirebaseAuthStateDidChangeInternalNotificationAppKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the FirebaseApp associated with the auth instance. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationAppKey; + +/** @var FirebaseAuthStateDidChangeInternalNotificationUIDKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the new user's UID (or nil if there is no longer a user signed in). + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationUIDKey; + +@interface FIRApp () + +/** + * A flag indicating if this is the default app (has the default app name). + */ +@property(nonatomic, readonly) BOOL isDefaultApp; + +/** + * The container of interop SDKs for this app. + */ +@property(nonatomic) FIRComponentContainer *container; + +/** + * The heartbeat logger associated with this app. + * + * Firebase apps have a 1:1 relationship with heartbeat loggers. + */ +@property(readonly) FIRHeartbeatLogger *heartbeatLogger; + +/** + * Checks if the default app is configured without trying to configure it. + */ ++ (BOOL)isDefaultAppConfigured; + +/** + * Registers a given third-party library with the given version number to be reported for + * analytics. + * + * @param name Name of the library. + * @param version Version of the library. + */ ++ (void)registerLibrary:(nonnull NSString *)name withVersion:(nonnull NSString *)version; + +/** + * Registers a given internal library to be reported for analytics. + * + * @param library Optional parameter for component registration. + * @param name Name of the library. + */ ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name; + +/** + * Registers a given internal library with the given version number to be reported for + * analytics. This should only be used for non-Firebase libraries that have their own versioning + * scheme. + * + * @param library Optional parameter for component registration. + * @param name Name of the library. + * @param version Version of the library. + */ ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name + withVersion:(nonnull NSString *)version; + +/** + * A concatenated string representing all the third-party libraries and version numbers. + */ ++ (NSString *)firebaseUserAgent; + +/** + * Can be used by the unit tests in each SDK to reset `FirebaseApp`. This method is thread unsafe. + */ ++ (void)resetApps; + +/** + * Can be used by the unit tests in each SDK to set customized options. + */ +- (instancetype)initInstanceWithName:(NSString *)name options:(FIROptions *)options; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCore/FirebaseCore/Extension/FIRComponent.h b/Pods/FirebaseCore/FirebaseCore/Extension/FIRComponent.h new file mode 100644 index 0000000..e4c8a27 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Extension/FIRComponent.h @@ -0,0 +1,91 @@ +/* + * 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. + */ + +#import + +@class FIRApp; +@class FIRComponentContainer; + +NS_ASSUME_NONNULL_BEGIN + +/// Provides a system to clean up cached instances returned from the component system. +NS_SWIFT_NAME(ComponentLifecycleMaintainer) +@protocol FIRComponentLifecycleMaintainer +/// The associated app will be deleted, clean up any resources as they are about to be deallocated. +- (void)appWillBeDeleted:(FIRApp *)app; +@end + +typedef _Nullable id (^FIRComponentCreationBlock)(FIRComponentContainer *container, + BOOL *isCacheable) + NS_SWIFT_NAME(ComponentCreationBlock); + +@class FIRDependency; + +/// Describes the timing of instantiation. Note: new components should default to lazy unless there +/// is a strong reason to be eager. +typedef NS_ENUM(NSInteger, FIRInstantiationTiming) { + FIRInstantiationTimingLazy, + FIRInstantiationTimingAlwaysEager, + FIRInstantiationTimingEagerInDefaultApp +} NS_SWIFT_NAME(InstantiationTiming); + +/// A component that can be used from other Firebase SDKs. +NS_SWIFT_NAME(Component) +@interface FIRComponent : NSObject + +/// The protocol describing functionality provided from the `Component`. +@property(nonatomic, strong, readonly) Protocol *protocol; + +/// The timing of instantiation. +@property(nonatomic, readonly) FIRInstantiationTiming instantiationTiming; + +/// An array of dependencies for the component. +@property(nonatomic, copy, readonly) NSArray *dependencies; + +/// A block to instantiate an instance of the component with the appropriate dependencies. +@property(nonatomic, copy, readonly) FIRComponentCreationBlock creationBlock; + +// There's an issue with long NS_SWIFT_NAMES that causes compilation to fail, disable clang-format +// for the next two methods. +// clang-format off + +/// Creates a component with no dependencies that will be lazily initialized. ++ (instancetype)componentWithProtocol:(Protocol *)protocol + creationBlock:(FIRComponentCreationBlock)creationBlock +NS_SWIFT_NAME(init(_:creationBlock:)); + +/// Creates a component to be registered with the component container. +/// +/// @param protocol - The protocol describing functionality provided by the component. +/// @param instantiationTiming - When the component should be initialized. Use .lazy unless there's +/// a good reason to be instantiated earlier. +/// @param dependencies - Any dependencies the `implementingClass` has, optional or required. +/// @param creationBlock - A block to instantiate the component with a container, and if +/// @return A component that can be registered with the component container. ++ (instancetype)componentWithProtocol:(Protocol *)protocol + instantiationTiming:(FIRInstantiationTiming)instantiationTiming + dependencies:(NSArray *)dependencies + creationBlock:(FIRComponentCreationBlock)creationBlock +NS_SWIFT_NAME(init(_:instantiationTiming:dependencies:creationBlock:)); + +// clang-format on + +/// Unavailable. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCore/FirebaseCore/Extension/FIRComponentContainer.h b/Pods/FirebaseCore/FirebaseCore/Extension/FIRComponentContainer.h new file mode 100644 index 0000000..6ec6147 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Extension/FIRComponentContainer.h @@ -0,0 +1,45 @@ +/* + * 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. + */ +#import + +NS_ASSUME_NONNULL_BEGIN + +/// A type-safe macro to retrieve a component from a container. This should be used to retrieve +/// components instead of using the container directly. +#define FIR_COMPONENT(type, container) \ + [FIRComponentType> instanceForProtocol:@protocol(type) inContainer:container] + +@class FIRApp; + +/// A container that holds different components that are registered via the +/// `registerAsComponentRegistrant` call. These classes should conform to `ComponentRegistrant` +/// in order to properly register components for Core. +NS_SWIFT_NAME(FirebaseComponentContainer) +@interface FIRComponentContainer : NSObject + +/// A weak reference to the app that an instance of the container belongs to. +@property(nonatomic, weak, readonly) FIRApp *app; + +// TODO: See if we can get improved type safety here. +/// A Swift only API for fetching an instance since the top macro isn't available. +- (nullable id)__instanceForProtocol:(Protocol *)protocol NS_SWIFT_NAME(instance(for:)); + +/// Unavailable. Use the `container` property on `FirebaseApp`. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCore/FirebaseCore/Extension/FIRComponentType.h b/Pods/FirebaseCore/FirebaseCore/Extension/FIRComponentType.h new file mode 100644 index 0000000..6f2aca7 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Extension/FIRComponentType.h @@ -0,0 +1,34 @@ +/* + * 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. + */ + +#import + +@class FIRComponentContainer; + +NS_ASSUME_NONNULL_BEGIN + +/// Do not use directly. A placeholder type in order to provide a macro that will warn users of +/// mis-matched protocols. +NS_SWIFT_NAME(ComponentType) +@interface FIRComponentType<__covariant T> : NSObject + +/// Do not use directly. A factory method to retrieve an instance that provides a specific +/// functionality. ++ (T)instanceForProtocol:(Protocol *)protocol inContainer:(FIRComponentContainer *)container; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCore/FirebaseCore/Extension/FIRDependency.h b/Pods/FirebaseCore/FirebaseCore/Extension/FIRDependency.h new file mode 100644 index 0000000..a070557 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Extension/FIRDependency.h @@ -0,0 +1,45 @@ +/* + * 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. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/// A dependency on a specific protocol's functionality. +NS_SWIFT_NAME(Dependency) +@interface FIRDependency : NSObject + +/// The protocol describing functionality being depended on. +@property(nonatomic, strong, readonly) Protocol *protocol; + +/// A flag to specify if the dependency is required or not. +@property(nonatomic, readonly) BOOL isRequired; + +/// Initializes a dependency that is required. Calls `init(protocol:isRequired:)` with true for +/// the required parameter. +/// Creates a required dependency on the specified protocol's functionality. ++ (instancetype)dependencyWithProtocol:(Protocol *)protocol; + +/// Creates a dependency on the specified protocol's functionality and specify if it's required for +/// the class's functionality. ++ (instancetype)dependencyWithProtocol:(Protocol *)protocol isRequired:(BOOL)required; + +/// Use `init(withProtocol:isRequired:)` instead. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCore/FirebaseCore/Extension/FIRHeartbeatLogger.h b/Pods/FirebaseCore/FirebaseCore/Extension/FIRHeartbeatLogger.h new file mode 100644 index 0000000..0f39ad9 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Extension/FIRHeartbeatLogger.h @@ -0,0 +1,90 @@ +// Copyright 2021 Google LLC +// +// 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 + +NS_ASSUME_NONNULL_BEGIN + +#ifndef FIREBASE_BUILD_CMAKE +@class FIRHeartbeatsPayload; +#endif // FIREBASE_BUILD_CMAKE + +/// Enum representing different daily heartbeat codes. +/// This enum is only used by clients using platform logging V1. This is because +/// the V1 payload only supports a single daily heartbeat. +typedef NS_ENUM(NSInteger, FIRDailyHeartbeatCode) { + /// Represents the absence of a daily heartbeat. + FIRDailyHeartbeatCodeNone = 0, + /// Represents the presence of a daily heartbeat. + FIRDailyHeartbeatCodeSome = 2, +}; + +@protocol FIRHeartbeatLoggerProtocol + +/// Asynchronously logs a heartbeat. +- (void)log; + +#ifndef FIREBASE_BUILD_CMAKE +/// Flushes heartbeats from storage into a structured payload of heartbeats. +- (FIRHeartbeatsPayload *)flushHeartbeatsIntoPayload; +#endif // FIREBASE_BUILD_CMAKE + +/// Gets the heartbeat code for today. +- (FIRDailyHeartbeatCode)heartbeatCodeForToday; + +@end + +#ifndef FIREBASE_BUILD_CMAKE +/// Returns a nullable string header value from a given heartbeats payload. +/// +/// This API returns `nil` when the given heartbeats payload is considered empty. +/// +/// @param heartbeatsPayload The heartbeats payload. +NSString *_Nullable FIRHeaderValueFromHeartbeatsPayload(FIRHeartbeatsPayload *heartbeatsPayload); +#endif // FIREBASE_BUILD_CMAKE + +/// A thread safe, synchronized object that logs and flushes platform logging info. +@interface FIRHeartbeatLogger : NSObject + +/// Designated initializer. +/// +/// @param appID The app ID that this heartbeat logger corresponds to. +- (instancetype)initWithAppID:(NSString *)appID; + +/// Asynchronously logs a new heartbeat corresponding to the Firebase User Agent, if needed. +/// +/// @note This API is thread-safe. +- (void)log; + +#ifndef FIREBASE_BUILD_CMAKE +/// Flushes heartbeats from storage into a structured payload of heartbeats. +/// +/// This API is for clients using platform logging V2. +/// +/// @note This API is thread-safe. +/// @return A payload of heartbeats. +- (FIRHeartbeatsPayload *)flushHeartbeatsIntoPayload; +#endif // FIREBASE_BUILD_CMAKE + +/// Gets today's corresponding heartbeat code. +/// +/// This API is for clients using platform logging V1. +/// +/// @note This API is thread-safe. +/// @return Heartbeat code indicating whether or not there is an unsent global heartbeat. +- (FIRDailyHeartbeatCode)heartbeatCodeForToday; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCore/FirebaseCore/Extension/FIRLibrary.h b/Pods/FirebaseCore/FirebaseCore/Extension/FIRLibrary.h new file mode 100644 index 0000000..15e2865 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Extension/FIRLibrary.h @@ -0,0 +1,44 @@ +/* + * 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 FIRLibrary_h +#define FIRLibrary_h + +#import + +@class FIRApp; +@class FIRComponent; + +NS_ASSUME_NONNULL_BEGIN + +/// Provide an interface to register a library for userAgent logging and availability to others. +NS_SWIFT_NAME(Library) +@protocol FIRLibrary + +/// Returns one or more Components that will be registered in +/// FirebaseApp and participate in dependency resolution and injection. ++ (NSArray *)componentsToRegister; + +@optional +/// Implement this method if the library needs notifications for lifecycle events. This method is +/// called when the developer calls `FirebaseApp.configure()`. ++ (void)configureWithApp:(FIRApp *)app; + +@end + +NS_ASSUME_NONNULL_END + +#endif /* FIRLibrary_h */ diff --git a/Pods/FirebaseCore/FirebaseCore/Extension/FIRLogger.h b/Pods/FirebaseCore/FirebaseCore/Extension/FIRLogger.h new file mode 100644 index 0000000..0a287f5 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Extension/FIRLogger.h @@ -0,0 +1,188 @@ +/* + * 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 + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * The Firebase services used in Firebase logger. + */ +typedef NSString *const FIRLoggerService; + +extern FIRLoggerService kFIRLoggerAnalytics; +extern FIRLoggerService kFIRLoggerCrash; +extern FIRLoggerService kFIRLoggerCore; +extern FIRLoggerService kFIRLoggerRemoteConfig; + +/** + * The key used to store the logger's error count. + */ +extern NSString *const kFIRLoggerErrorCountKey; + +/** + * The key used to store the logger's warning count. + */ +extern NSString *const kFIRLoggerWarningCountKey; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** + * Enables or disables Analytics debug mode. + * If set to true, the logging level for Analytics will be set to FirebaseLoggerLevelDebug. + * Enabling the debug mode has no effect if the app is running from App Store. + * (required) analytics debug mode flag. + */ +void FIRSetAnalyticsDebugMode(BOOL analyticsDebugMode); + +/** + * Changes the default logging level of FirebaseLoggerLevelNotice to a user-specified level. + * The default level cannot be set above FirebaseLoggerLevelNotice if the app is running from App + * Store. (required) log level (one of the FirebaseLoggerLevel enum values). + */ +void FIRSetLoggerLevel(FIRLoggerLevel loggerLevel); + +/** + * Checks if the specified logger level is loggable given the current settings. + * (required) log level (one of the FirebaseLoggerLevel enum values). + * (required) whether or not this function is called from the Analytics component. + */ +BOOL FIRIsLoggableLevel(FIRLoggerLevel loggerLevel, BOOL analyticsComponent); + +/** + * Logs a message to the Xcode console and the device log. If running from AppStore, will + * not log any messages with a level higher than FirebaseLoggerLevelNotice to avoid log spamming. + * (required) log level (one of the FirebaseLoggerLevel enum values). + * (required) service name of type FirebaseLoggerService. + * (required) message code starting with "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique + * within the service. + * An example of the message code is @"I-COR000001". + * (required) message string which can be a format string. + * (optional) variable arguments list obtained from calling va_start, used when message is a format + * string. + */ +extern void FIRLogBasic(FIRLoggerLevel level, + FIRLoggerService service, + NSString *messageCode, + NSString *message, +// On 64-bit simulators, va_list is not a pointer, so cannot be marked nullable +// See: http://stackoverflow.com/q/29095469 +#if __LP64__ && TARGET_OS_SIMULATOR || TARGET_OS_OSX + va_list args_ptr +#else + va_list _Nullable args_ptr +#endif +); + +/** + * The following functions accept the following parameters in order: + * (required) service name of type FirebaseLoggerService. + * (required) message code starting from "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique + * within the service. + * An example of the message code is @"I-COR000001". + * See go/firebase-log-proposal for details. + * (required) message string which can be a format string. + * (optional) the list of arguments to substitute into the format string. + * Example usage: + * FirebaseLogError(kFirebaseLoggerCore, @"I-COR000001", @"Configuration of %@ failed.", app.name); + */ +extern void FIRLogError(FIRLoggerService service, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogWarning(FIRLoggerService service, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogNotice(FIRLoggerService service, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogInfo(FIRLoggerService service, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogDebug(FIRLoggerService service, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); + +// TODO: Come up with a better logging scheme for Swift. +/** + * Logs a debug message to the Xcode console and the device log. If running from AppStore, will + * not log any messages with a level higher than FirebaseLoggerLevelNotice to avoid log spamming. + * This function is intended to be used by Swift clients that do not support variadic parameters. + * + * @param service The service name of type `FirebaseLoggerService`. + * @param messageCode The mesage code. starting with "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique within the + * service. An example of the message code is @"I-COR000001". + * @param message The message string. + */ +extern void FIRLogDebugSwift(FIRLoggerService service, NSString *messageCode, NSString *message); + +/** + * Logs a warning message to the Xcode console and the device log. If running from AppStore, will + * not log any messages with a level higher than FirebaseLoggerLevelNotice to avoid log spamming. + * This function is intended to be used by Swift clients that do not support variadic parameters. + * + * @param service The service name of type `FirebaseLoggerService`. + * @param messageCode The mesage code. starting with "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique within the + * service. An example of the message code is @"I-COR000001". + * @param message The message string. + */ +extern void FIRLogWarningSwift(FIRLoggerService service, NSString *messageCode, NSString *message); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +NS_SWIFT_NAME(FirebaseLogger) +@interface FIRLoggerWrapper : NSObject + +/// Logs a given message at a given log level. This API is effectively a wrapper for the +/// `FIRLogBasic` C API. +/// +/// - Parameters: +/// - level: The log level to use (defined by `FirebaseLoggerLevel` enum values). +/// - service: The service name of type `FirebaseLoggerService`. +/// - code: The mesage code. Starting with "I-" which means iOS, followed by a capitalized +/// three-character service identifier and a six digit integer message ID that is unique within +/// the service. An example of the message code is @"I-COR000001". +/// - message: Formatted string to be used as the log's message. +/// - args: Arguments list obtained from calling `va_start`, used when message is a format string. ++ (void)logWithLevel:(FIRLoggerLevel)level + withService:(FIRLoggerService)service + withCode:(NSString *)messageCode + withMessage:(NSString *)message + withArgs:(va_list)args; + +/// Logs a given message at a given log level. +/// +/// - Parameters: +/// - level: The log level to use (defined by `FirebaseLoggerLevel` enum values). +/// - service: The service name of type `FirebaseLoggerService`. +/// - code: The mesage code. Starting with "I-" which means iOS, followed by a capitalized +/// three-character service identifier and a six digit integer message ID that is unique within +/// the service. An example of the message code is @"I-COR000001". +/// - message: Formatted string to be used as the log's message. +/// - args: Arguments list obtained from calling `va_start`, used when message is a format string. ++ (void)logWithLevel:(FIRLoggerLevel)level + service:(FIRLoggerService)service + code:(NSString *)code + message:(NSString *)message + __attribute__((__swift_name__("log(level:service:code:message:)"))); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCore/FirebaseCore/Extension/FIROptionsInternal.h b/Pods/FirebaseCore/FirebaseCore/Extension/FIROptionsInternal.h new file mode 100644 index 0000000..93a03d6 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Extension/FIROptionsInternal.h @@ -0,0 +1,106 @@ +/* + * 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 + +/** + * Keys for the strings in the plist file. + */ +extern NSString *const kFIRAPIKey; +extern NSString *const kFIRTrackingID; +extern NSString *const kFIRGoogleAppID; +extern NSString *const kFIRClientID; +extern NSString *const kFIRGCMSenderID; +extern NSString *const kFIRAndroidClientID; +extern NSString *const kFIRDatabaseURL; +extern NSString *const kFIRStorageBucket; +extern NSString *const kFIRBundleID; +extern NSString *const kFIRProjectID; + +/** + * Keys for the plist file name + */ +extern NSString *const kServiceInfoFileName; + +extern NSString *const kServiceInfoFileType; + +/** + * This header file exposes the initialization of FirebaseOptions to internal use. + */ +@interface FIROptions () + +/** + * `resetDefaultOptions` and `initInternalWithOptionsDictionary` are exposed only for unit tests. + */ ++ (void)resetDefaultOptions; + +/** + * Initializes the options with dictionary. The above strings are the keys of the dictionary. + * This is the designated initializer. + */ +- (instancetype)initInternalWithOptionsDictionary:(NSDictionary *)serviceInfoDictionary + NS_DESIGNATED_INITIALIZER; + +/** + * `defaultOptions` and `defaultOptionsDictionary` are exposed in order to be used in FirebaseApp + * and other first party services. + */ ++ (FIROptions *)defaultOptions; + ++ (NSDictionary *)defaultOptionsDictionary; + +/** + * Indicates whether or not Analytics collection was explicitly enabled via a plist flag or at + * runtime. + */ +@property(nonatomic, readonly) BOOL isAnalyticsCollectionExplicitlySet; + +/** + * Whether or not Analytics Collection was enabled. Analytics Collection is enabled unless + * explicitly disabled in GoogleService-Info.plist. + */ +@property(nonatomic, readonly) BOOL isAnalyticsCollectionEnabled; + +/** + * Whether or not Analytics Collection was completely disabled. If true, then + * isAnalyticsCollectionEnabled will be false. + */ +@property(nonatomic, readonly) BOOL isAnalyticsCollectionDeactivated; + +/** + * The version ID of the client library, e.g. @"1100000". + */ +@property(nonatomic, readonly, copy) NSString *libraryVersionID; + +/** + * The flag indicating whether this object was constructed with the values in the default plist + * file. + */ +@property(nonatomic) BOOL usingOptionsFromDefaultPlist; + +/** + * Whether or not Measurement was enabled. Measurement is enabled unless explicitly disabled in + * GoogleService-Info.plist. + */ +@property(nonatomic, readonly) BOOL isMeasurementEnabled; + +/** + * Whether or not editing is locked. This should occur after `FirebaseOptions` has been set on a + * `FirebaseApp`. + */ +@property(nonatomic, getter=isEditingLocked) BOOL editingLocked; + +@end diff --git a/Pods/FirebaseCore/FirebaseCore/Extension/FirebaseCoreInternal.h b/Pods/FirebaseCore/FirebaseCore/Extension/FirebaseCoreInternal.h new file mode 100644 index 0000000..0669ae6 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Extension/FirebaseCoreInternal.h @@ -0,0 +1,25 @@ +// Copyright 2020 Google LLC +// +// 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 FirebaseCore; + +#import "FIRAppInternal.h" +#import "FIRComponent.h" +#import "FIRComponentContainer.h" +#import "FIRComponentType.h" +#import "FIRDependency.h" +#import "FIRHeartbeatLogger.h" +#import "FIRLibrary.h" +#import "FIRLogger.h" +#import "FIROptionsInternal.h" diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/FIRAnalyticsConfiguration.h b/Pods/FirebaseCore/FirebaseCore/Sources/FIRAnalyticsConfiguration.h new file mode 100644 index 0000000..6429ac7 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/FIRAnalyticsConfiguration.h @@ -0,0 +1,56 @@ +/* + * 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 + +/// Values stored in analyticsEnabledState. Never alter these constants since they must match with +/// values persisted to disk. +typedef NS_ENUM(int64_t, FIRAnalyticsEnabledState) { + // 0 is the default value for keys not found stored in persisted config, so it cannot represent + // kFIRAnalyticsEnabledStateSetNo. It must represent kFIRAnalyticsEnabledStateNotSet. + kFIRAnalyticsEnabledStateNotSet = 0, + kFIRAnalyticsEnabledStateSetYes = 1, + kFIRAnalyticsEnabledStateSetNo = 2, +}; + +/// The user defaults key for the persisted measurementEnabledState value. FIRAPersistedConfig reads +/// measurementEnabledState using this same key. +static NSString *const kFIRAPersistedConfigMeasurementEnabledStateKey = + @"/google/measurement/measurement_enabled_state"; + +static NSString *const kFIRAnalyticsConfigurationSetEnabledNotification = + @"FIRAnalyticsConfigurationSetEnabledNotification"; +static NSString *const kFIRAnalyticsConfigurationSetMinimumSessionIntervalNotification = + @"FIRAnalyticsConfigurationSetMinimumSessionIntervalNotification"; +static NSString *const kFIRAnalyticsConfigurationSetSessionTimeoutIntervalNotification = + @"FIRAnalyticsConfigurationSetSessionTimeoutIntervalNotification"; + +@interface FIRAnalyticsConfiguration : NSObject + +/// Returns the shared instance of FIRAnalyticsConfiguration. ++ (FIRAnalyticsConfiguration *)sharedInstance; + +// Sets whether analytics collection is enabled for this app on this device. This setting is +// persisted across app sessions. By default it is enabled. +- (void)setAnalyticsCollectionEnabled:(BOOL)analyticsCollectionEnabled; + +/// Sets whether analytics collection is enabled for this app on this device, and a flag to persist +/// the value or not. The setting should not be persisted if being set by the global data collection +/// flag. +- (void)setAnalyticsCollectionEnabled:(BOOL)analyticsCollectionEnabled + persistSetting:(BOOL)shouldPersist; + +@end diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/FIRAnalyticsConfiguration.m b/Pods/FirebaseCore/FirebaseCore/Sources/FIRAnalyticsConfiguration.m new file mode 100644 index 0000000..07c786c --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/FIRAnalyticsConfiguration.m @@ -0,0 +1,62 @@ +// 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 + +#import "FirebaseCore/Sources/FIRAnalyticsConfiguration.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" +@implementation FIRAnalyticsConfiguration +#pragma clang diagnostic pop + ++ (FIRAnalyticsConfiguration *)sharedInstance { + static FIRAnalyticsConfiguration *sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[FIRAnalyticsConfiguration alloc] init]; + }); + return sharedInstance; +} + +- (void)postNotificationName:(NSString *)name value:(id)value { + if (!name.length || !value) { + return; + } + [[NSNotificationCenter defaultCenter] postNotificationName:name + object:self + userInfo:@{name : value}]; +} + +- (void)setAnalyticsCollectionEnabled:(BOOL)analyticsCollectionEnabled { + [self setAnalyticsCollectionEnabled:analyticsCollectionEnabled persistSetting:YES]; +} + +- (void)setAnalyticsCollectionEnabled:(BOOL)analyticsCollectionEnabled + persistSetting:(BOOL)shouldPersist { + // Persist the measurementEnabledState. Use FIRAnalyticsEnabledState values instead of YES/NO. + FIRAnalyticsEnabledState analyticsEnabledState = + analyticsCollectionEnabled ? kFIRAnalyticsEnabledStateSetYes : kFIRAnalyticsEnabledStateSetNo; + if (shouldPersist) { + NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; + [userDefaults setObject:@(analyticsEnabledState) + forKey:kFIRAPersistedConfigMeasurementEnabledStateKey]; + [userDefaults synchronize]; + } + + [self postNotificationName:kFIRAnalyticsConfigurationSetEnabledNotification + value:@(analyticsCollectionEnabled)]; +} + +@end diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/FIRApp.m b/Pods/FirebaseCore/FirebaseCore/Sources/FIRApp.m new file mode 100644 index 0000000..922d93f --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/FIRApp.m @@ -0,0 +1,917 @@ +// 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. + +#include + +#if __has_include() +#import +#endif + +#if __has_include() +#import +#endif + +#if __has_include() +#import +#endif + +#import "FirebaseCore/Sources/Public/FirebaseCore/FIRApp.h" + +#import "FirebaseCore/Sources/FIRAnalyticsConfiguration.h" +#import "FirebaseCore/Sources/FIRBundleUtil.h" +#import "FirebaseCore/Sources/FIRComponentContainerInternal.h" +#import "FirebaseCore/Sources/FIRConfigurationInternal.h" +#import "FirebaseCore/Sources/FIRFirebaseUserAgent.h" + +#import "FirebaseCore/Extension/FIRAppInternal.h" +#import "FirebaseCore/Extension/FIRHeartbeatLogger.h" +#import "FirebaseCore/Extension/FIRLibrary.h" +#import "FirebaseCore/Extension/FIRLogger.h" +#import "FirebaseCore/Extension/FIROptionsInternal.h" +#import "FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h" + +#import + +#import + +NSString *const kFIRDefaultAppName = @"__FIRAPP_DEFAULT"; +NSString *const kFIRAppReadyToConfigureSDKNotification = @"FIRAppReadyToConfigureSDKNotification"; +NSString *const kFIRAppDeleteNotification = @"FIRAppDeleteNotification"; +NSString *const kFIRAppIsDefaultAppKey = @"FIRAppIsDefaultAppKey"; +NSString *const kFIRAppNameKey = @"FIRAppNameKey"; +NSString *const kFIRGoogleAppIDKey = @"FIRGoogleAppIDKey"; + +NSString *const kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat = + @"/google/firebase/global_data_collection_enabled:%@"; +NSString *const kFIRGlobalAppDataCollectionEnabledPlistKey = + @"FirebaseDataCollectionDefaultEnabled"; + +NSString *const kFIRAppDiagnosticsConfigurationTypeKey = @"ConfigType"; +NSString *const kFIRAppDiagnosticsErrorKey = @"Error"; +NSString *const kFIRAppDiagnosticsFIRAppKey = @"FIRApp"; +NSString *const kFIRAppDiagnosticsSDKNameKey = @"SDKName"; +NSString *const kFIRAppDiagnosticsSDKVersionKey = @"SDKVersion"; +NSString *const kFIRAppDiagnosticsApplePlatformPrefix = @"apple-platform"; + +// Auth internal notification notification and key. +NSString *const FIRAuthStateDidChangeInternalNotification = + @"FIRAuthStateDidChangeInternalNotification"; +NSString *const FIRAuthStateDidChangeInternalNotificationAppKey = + @"FIRAuthStateDidChangeInternalNotificationAppKey"; +NSString *const FIRAuthStateDidChangeInternalNotificationTokenKey = + @"FIRAuthStateDidChangeInternalNotificationTokenKey"; +NSString *const FIRAuthStateDidChangeInternalNotificationUIDKey = + @"FIRAuthStateDidChangeInternalNotificationUIDKey"; + +/** + * Error domain for exceptions and NSError construction. + */ +NSString *const kFirebaseCoreErrorDomain = @"com.firebase.core"; + +/** The NSUserDefaults suite name for FirebaseCore, for those storage locations that use it. */ +NSString *const kFirebaseCoreDefaultsSuiteName = @"com.firebase.core"; + +/** + * The URL to download plist files. + */ +static NSString *const kPlistURL = @"https://console.firebase.google.com/"; + +/** + * An array of all classes that registered as `FIRCoreConfigurable` in order to receive lifecycle + * events from Core. + */ +static NSMutableArray> *sRegisteredAsConfigurable; + +@interface FIRApp () + +#ifdef DEBUG +@property(nonatomic) BOOL alreadyOutputDataCollectionFlag; +#endif // DEBUG + +@end + +@implementation FIRApp + +// This is necessary since our custom getter prevents `_options` from being created. +@synthesize options = _options; + +static NSMutableDictionary *sAllApps; +static FIRApp *sDefaultApp; + ++ (void)configure { + FIROptions *options = [FIROptions defaultOptions]; + if (!options) { +#if DEBUG + [self findMisnamedGoogleServiceInfoPlist]; +#endif // DEBUG + [NSException raise:kFirebaseCoreErrorDomain + format:@"`FirebaseApp.configure()` could not find " + @"a valid GoogleService-Info.plist in your project. Please download one " + @"from %@.", + kPlistURL]; + } + [FIRApp configureWithOptions:options]; +} + ++ (void)configureWithOptions:(FIROptions *)options { + if (!options) { + [NSException raise:kFirebaseCoreErrorDomain + format:@"Options is nil. Please pass a valid options."]; + } + [FIRApp configureWithName:kFIRDefaultAppName options:options]; +} + ++ (NSCharacterSet *)applicationNameAllowedCharacters { + static NSCharacterSet *applicationNameAllowedCharacters; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSMutableCharacterSet *allowedNameCharacters = [NSMutableCharacterSet alphanumericCharacterSet]; + [allowedNameCharacters addCharactersInString:@"-_"]; + applicationNameAllowedCharacters = [allowedNameCharacters copy]; + }); + return applicationNameAllowedCharacters; +} + ++ (void)configureWithName:(NSString *)name options:(FIROptions *)options { + if (!name || !options) { + [NSException raise:kFirebaseCoreErrorDomain format:@"Neither name nor options can be nil."]; + } + if (name.length == 0) { + [NSException raise:kFirebaseCoreErrorDomain format:@"Name cannot be empty."]; + } + + if ([name isEqualToString:kFIRDefaultAppName]) { + if (sDefaultApp) { + // The default app already exists. Handle duplicate `configure` calls and return. + [self appWasConfiguredTwice:sDefaultApp usingOptions:options]; + return; + } + + FIRLogDebug(kFIRLoggerCore, @"I-COR000001", @"Configuring the default app."); + } else { + // Validate the app name and ensure it hasn't been configured already. + NSCharacterSet *nameCharacters = [NSCharacterSet characterSetWithCharactersInString:name]; + + if (![[self applicationNameAllowedCharacters] isSupersetOfSet:nameCharacters]) { + [NSException raise:kFirebaseCoreErrorDomain + format:@"App name can only contain alphanumeric, " + @"hyphen (-), and underscore (_) characters"]; + } + + @synchronized(self) { + if (sAllApps && sAllApps[name]) { + // The app already exists. Handle a duplicate `configure` call and return. + [self appWasConfiguredTwice:sAllApps[name] usingOptions:options]; + return; + } + } + + FIRLogDebug(kFIRLoggerCore, @"I-COR000002", @"Configuring app named %@", name); + } + + // Default instantiation, make sure we populate with Swift SDKs that can't register in time. + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + [self registerSwiftComponents]; + }); + + @synchronized(self) { + FIRApp *app = [[FIRApp alloc] initInstanceWithName:name options:options]; + if (app.isDefaultApp) { + sDefaultApp = app; + } + + [FIRApp addAppToAppDictionary:app]; + + // The FIRApp instance is ready to go, `sDefaultApp` is assigned, other SDKs are now ready to be + // instantiated. + [app.container instantiateEagerComponents]; + [FIRApp sendNotificationsToSDKs:app]; + } +} + +/// Called when `configure` has been called multiple times for the same app. This can either throw +/// an exception (most cases) or ignore the duplicate configuration in situations where it's allowed +/// like an extension. ++ (void)appWasConfiguredTwice:(FIRApp *)app usingOptions:(FIROptions *)options { + // Only extensions should potentially be able to call `configure` more than once. + if (![GULAppEnvironmentUtil isAppExtension]) { + // Throw an exception since this is now an invalid state. + if (app.isDefaultApp) { + [NSException raise:kFirebaseCoreErrorDomain + format:@"Default app has already been configured."]; + } else { + [NSException raise:kFirebaseCoreErrorDomain + format:@"App named %@ has already been configured.", app.name]; + } + } + + // In an extension, the entry point could be called multiple times. As long as the options are + // identical we should allow multiple `configure` calls. + if ([options isEqual:app.options]) { + // Everything is identical but the extension's lifecycle triggered `configure` twice. + // Ignore duplicate calls and return since everything should still be in a valid state. + FIRLogDebug(kFIRLoggerCore, @"I-COR000035", + @"Ignoring second `configure` call in an extension."); + return; + } else { + [NSException raise:kFirebaseCoreErrorDomain + format:@"App named %@ has already been configured.", app.name]; + } +} + ++ (FIRApp *)defaultApp { + if (sDefaultApp) { + return sDefaultApp; + } + FIRLogError(kFIRLoggerCore, @"I-COR000003", + @"The default Firebase app has not yet been " + @"configured. Add `FirebaseApp.configure()` to your " + @"application initialization. This can be done in " + @"in the App Delegate's application(_:didFinishLaunchingWithOptions:)` " + @"(or the `@main` struct's initializer in SwiftUI). " + @"Read more: https://goo.gl/ctyzm8."); + return nil; +} + ++ (FIRApp *)appNamed:(NSString *)name { + @synchronized(self) { + if (sAllApps) { + FIRApp *app = sAllApps[name]; + if (app) { + return app; + } + } + FIRLogError(kFIRLoggerCore, @"I-COR000004", @"App with name %@ does not exist.", name); + return nil; + } +} + ++ (NSDictionary *)allApps { + @synchronized(self) { + if (!sAllApps) { + FIRLogError(kFIRLoggerCore, @"I-COR000005", @"No app has been configured yet."); + } + return [sAllApps copy]; + } +} + +// Public only for tests ++ (void)resetApps { + @synchronized(self) { + sDefaultApp = nil; + [sAllApps removeAllObjects]; + sAllApps = nil; + [[self userAgent] reset]; + } +} + +- (void)deleteApp:(FIRAppVoidBoolCallback)completion { + @synchronized([self class]) { + if (sAllApps && sAllApps[self.name]) { + FIRLogDebug(kFIRLoggerCore, @"I-COR000006", @"Deleting app named %@", self.name); + + // Remove all registered libraries from the container to avoid creating new instances. + [self.container removeAllComponents]; + // Remove all cached instances from the container before deleting the app. + [self.container removeAllCachedInstances]; + + [sAllApps removeObjectForKey:self.name]; + [self clearDataCollectionSwitchFromUserDefaults]; + if ([self.name isEqualToString:kFIRDefaultAppName]) { + sDefaultApp = nil; + } + NSDictionary *appInfoDict = @{kFIRAppNameKey : self.name}; + [[NSNotificationCenter defaultCenter] postNotificationName:kFIRAppDeleteNotification + object:[self class] + userInfo:appInfoDict]; + completion(YES); + } else { + FIRLogError(kFIRLoggerCore, @"I-COR000007", @"App does not exist."); + completion(NO); + } + } +} + ++ (void)addAppToAppDictionary:(FIRApp *)app { + if (!sAllApps) { + sAllApps = [NSMutableDictionary dictionary]; + } + if ([app configureCore]) { + sAllApps[app.name] = app; + } else { + [NSException raise:kFirebaseCoreErrorDomain + format:@"Configuration fails. It may be caused by an invalid GOOGLE_APP_ID in " + @"GoogleService-Info.plist or set in the customized options."]; + } +} + +- (instancetype)initInstanceWithName:(NSString *)name options:(FIROptions *)options { + self = [super init]; + if (self) { + _name = [name copy]; + _options = [options copy]; + _options.editingLocked = YES; + _isDefaultApp = [name isEqualToString:kFIRDefaultAppName]; + _container = [[FIRComponentContainer alloc] initWithApp:self]; + _heartbeatLogger = [[FIRHeartbeatLogger alloc] initWithAppID:self.options.googleAppID]; + } + return self; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +- (BOOL)configureCore { + [self checkExpectedBundleID]; + if (![self isAppIDValid]) { + return NO; + } + + // Initialize the Analytics once there is a valid options under default app. Analytics should + // always initialize first by itself before the other SDKs. + if ([self.name isEqualToString:kFIRDefaultAppName]) { + Class firAnalyticsClass = NSClassFromString(@"FIRAnalytics"); + if (firAnalyticsClass) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wundeclared-selector" + SEL startWithConfigurationSelector = @selector(startWithConfiguration:options:); +#pragma clang diagnostic pop + if ([firAnalyticsClass respondsToSelector:startWithConfigurationSelector]) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + [firAnalyticsClass performSelector:startWithConfigurationSelector + withObject:[FIRConfiguration sharedInstance].analyticsConfiguration + withObject:_options]; +#pragma clang diagnostic pop + } + } + } + + [self subscribeForAppDidBecomeActiveNotifications]; + + return YES; +} + +- (FIROptions *)options { + return [_options copy]; +} + +- (void)setDataCollectionDefaultEnabled:(BOOL)dataCollectionDefaultEnabled { +#ifdef DEBUG + FIRLogDebug(kFIRLoggerCore, @"I-COR000034", @"Explicitly %@ data collection flag.", + dataCollectionDefaultEnabled ? @"enabled" : @"disabled"); + self.alreadyOutputDataCollectionFlag = YES; +#endif // DEBUG + + NSString *key = + [NSString stringWithFormat:kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat, self.name]; + [[NSUserDefaults standardUserDefaults] setBool:dataCollectionDefaultEnabled forKey:key]; + + // Core also controls the FirebaseAnalytics flag, so check if the Analytics flags are set + // within FIROptions and change the Analytics value if necessary. Analytics only works with the + // default app, so return if this isn't the default app. + if (!self.isDefaultApp) { + return; + } + + // Check if the Analytics flag is explicitly set. If so, no further actions are necessary. + if ([self.options isAnalyticsCollectionExplicitlySet]) { + return; + } + + // The Analytics flag has not been explicitly set, so update with the value being set. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + [[FIRAnalyticsConfiguration sharedInstance] + setAnalyticsCollectionEnabled:dataCollectionDefaultEnabled + persistSetting:NO]; +#pragma clang diagnostic pop +} + +- (BOOL)isDataCollectionDefaultEnabled { + // Check if it's been manually set before in code, and use that as the higher priority value. + NSNumber *defaultsObject = [[self class] readDataCollectionSwitchFromUserDefaultsForApp:self]; + if (defaultsObject != nil) { +#ifdef DEBUG + if (!self.alreadyOutputDataCollectionFlag) { + FIRLogDebug(kFIRLoggerCore, @"I-COR000031", @"Data Collection flag is %@ in user defaults.", + [defaultsObject boolValue] ? @"enabled" : @"disabled"); + self.alreadyOutputDataCollectionFlag = YES; + } +#endif // DEBUG + return [defaultsObject boolValue]; + } + + // Read the Info.plist to see if the flag is set. If it's not set, it should default to `YES`. + // As per the implementation of `readDataCollectionSwitchFromPlist`, it's a cached value and has + // no performance impact calling multiple times. + NSNumber *collectionEnabledPlistValue = [[self class] readDataCollectionSwitchFromPlist]; + if (collectionEnabledPlistValue != nil) { +#ifdef DEBUG + if (!self.alreadyOutputDataCollectionFlag) { + FIRLogDebug(kFIRLoggerCore, @"I-COR000032", @"Data Collection flag is %@ in plist.", + [collectionEnabledPlistValue boolValue] ? @"enabled" : @"disabled"); + self.alreadyOutputDataCollectionFlag = YES; + } +#endif // DEBUG + return [collectionEnabledPlistValue boolValue]; + } + +#ifdef DEBUG + if (!self.alreadyOutputDataCollectionFlag) { + FIRLogDebug(kFIRLoggerCore, @"I-COR000033", @"Data Collection flag is not set."); + self.alreadyOutputDataCollectionFlag = YES; + } +#endif // DEBUG + return YES; +} + +#pragma mark - private + ++ (void)sendNotificationsToSDKs:(FIRApp *)app { + // TODO: Remove this notification once all SDKs are registered with `FIRCoreConfigurable`. + NSNumber *isDefaultApp = [NSNumber numberWithBool:app.isDefaultApp]; + NSDictionary *appInfoDict = @{ + kFIRAppNameKey : app.name, + kFIRAppIsDefaultAppKey : isDefaultApp, + kFIRGoogleAppIDKey : app.options.googleAppID + }; + [[NSNotificationCenter defaultCenter] postNotificationName:kFIRAppReadyToConfigureSDKNotification + object:self + userInfo:appInfoDict]; + + // This is the new way of sending information to SDKs. + // TODO: Do we want this on a background thread, maybe? + @synchronized(self) { + for (Class library in sRegisteredAsConfigurable) { + [library configureWithApp:app]; + } + } +} + ++ (NSError *)errorForMissingOptions { + NSDictionary *errorDict = @{ + NSLocalizedDescriptionKey : + @"Unable to parse GoogleService-Info.plist in order to configure services.", + NSLocalizedRecoverySuggestionErrorKey : + @"Check formatting and location of GoogleService-Info.plist." + }; + return [NSError errorWithDomain:kFirebaseCoreErrorDomain code:-100 userInfo:errorDict]; +} + ++ (NSError *)errorForInvalidAppID { + NSDictionary *errorDict = @{ + NSLocalizedDescriptionKey : @"Unable to validate Google App ID", + NSLocalizedRecoverySuggestionErrorKey : + @"Check formatting and location of GoogleService-Info.plist or GoogleAppID set in the " + @"customized options." + }; + return [NSError errorWithDomain:kFirebaseCoreErrorDomain code:-101 userInfo:errorDict]; +} + ++ (BOOL)isDefaultAppConfigured { + return (sDefaultApp != nil); +} + ++ (void)registerLibrary:(nonnull NSString *)name withVersion:(nonnull NSString *)version { + // Create the set of characters which aren't allowed, only if this feature is used. + NSMutableCharacterSet *allowedSet = [NSMutableCharacterSet alphanumericCharacterSet]; + [allowedSet addCharactersInString:@"-_."]; + NSCharacterSet *disallowedSet = [allowedSet invertedSet]; + // Make sure the library name and version strings do not contain unexpected characters, and + // add the name/version pair to the dictionary. + if ([name rangeOfCharacterFromSet:disallowedSet].location == NSNotFound && + [version rangeOfCharacterFromSet:disallowedSet].location == NSNotFound) { + [[self userAgent] setValue:version forComponent:name]; + } else { + FIRLogError(kFIRLoggerCore, @"I-COR000027", + @"The library name (%@) or version number (%@) contain invalid characters. " + @"Only alphanumeric, dash, underscore and period characters are allowed.", + name, version); + } +} + ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name { + [self registerInternalLibrary:library withName:name withVersion:FIRFirebaseVersion()]; +} + ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name + withVersion:(nonnull NSString *)version { + // This is called at +load time, keep the work to a minimum. + + // Ensure the class given conforms to the proper protocol. + if (![(Class)library conformsToProtocol:@protocol(FIRLibrary)] || + ![(Class)library respondsToSelector:@selector(componentsToRegister)]) { + [NSException raise:NSInvalidArgumentException + format:@"Class %@ attempted to register components, but it does not conform to " + @"`FIRLibrary or provide a `componentsToRegister:` method.", + library]; + } + + [FIRComponentContainer registerAsComponentRegistrant:library]; + if ([(Class)library respondsToSelector:@selector(configureWithApp:)]) { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sRegisteredAsConfigurable = [[NSMutableArray alloc] init]; + }); + @synchronized(self) { + [sRegisteredAsConfigurable addObject:library]; + } + } + [self registerLibrary:name withVersion:version]; +} + ++ (FIRFirebaseUserAgent *)userAgent { + static dispatch_once_t onceToken; + static FIRFirebaseUserAgent *_userAgent; + dispatch_once(&onceToken, ^{ + _userAgent = [[FIRFirebaseUserAgent alloc] init]; + [_userAgent setValue:FIRFirebaseVersion() forComponent:@"fire-ios"]; + }); + return _userAgent; +} + ++ (NSString *)firebaseUserAgent { + return [[self userAgent] firebaseUserAgent]; +} + +- (void)checkExpectedBundleID { + NSArray *bundles = [FIRBundleUtil relevantBundles]; + NSString *expectedBundleID = [self expectedBundleID]; + // The checking is only done when the bundle ID is provided in the serviceInfo dictionary for + // backward compatibility. + if (expectedBundleID != nil && ![FIRBundleUtil hasBundleIdentifierPrefix:expectedBundleID + inBundles:bundles]) { + FIRLogError(kFIRLoggerCore, @"I-COR000008", + @"The project's Bundle ID is inconsistent with " + @"either the Bundle ID in '%@.%@', or the Bundle ID in the options if you are " + @"using a customized options. To ensure that everything can be configured " + @"correctly, you may need to make the Bundle IDs consistent. To continue with this " + @"plist file, you may change your app's bundle identifier to '%@'. Or you can " + @"download a new configuration file that matches your bundle identifier from %@ " + @"and replace the current one.", + kServiceInfoFileName, kServiceInfoFileType, expectedBundleID, kPlistURL); + } +} + +#pragma mark - private - App ID Validation + +/** + * Validates the format and fingerprint of the app ID contained in GOOGLE_APP_ID in the plist file. + * This is the main method for validating app ID. + * + * @return YES if the app ID fulfills the expected format and fingerprint, NO otherwise. + */ +- (BOOL)isAppIDValid { + NSString *appID = _options.googleAppID; + BOOL isValid = [FIRApp validateAppID:appID]; + if (!isValid) { + NSString *expectedBundleID = [self expectedBundleID]; + FIRLogError(kFIRLoggerCore, @"I-COR000009", + @"The GOOGLE_APP_ID either in the plist file " + @"'%@.%@' or the one set in the customized options is invalid. If you are using " + @"the plist file, use the iOS version of bundle identifier to download the file, " + @"and do not manually edit the GOOGLE_APP_ID. You may change your app's bundle " + @"identifier to '%@'. Or you can download a new configuration file that matches " + @"your bundle identifier from %@ and replace the current one.", + kServiceInfoFileName, kServiceInfoFileType, expectedBundleID, kPlistURL); + }; + return isValid; +} + ++ (BOOL)validateAppID:(NSString *)appID { + // Failing validation only occurs when we are sure we are looking at a V2 app ID and it does not + // have a valid fingerprint, otherwise we just warn about the potential issue. + if (!appID.length) { + return NO; + } + + NSScanner *stringScanner = [NSScanner scannerWithString:appID]; + stringScanner.charactersToBeSkipped = nil; + + NSString *appIDVersion; + if (![stringScanner scanCharactersFromSet:[NSCharacterSet decimalDigitCharacterSet] + intoString:&appIDVersion]) { + return NO; + } + + if (![stringScanner scanString:@":" intoString:NULL]) { + // appIDVersion must be separated by ":" + return NO; + } + + NSArray *knownVersions = @[ @"1" ]; + if (![knownVersions containsObject:appIDVersion]) { + // Permit unknown yet properly formatted app ID versions. + FIRLogInfo(kFIRLoggerCore, @"I-COR000010", @"Unknown GOOGLE_APP_ID version: %@", appIDVersion); + return YES; + } + + if (![self validateAppIDFormat:appID withVersion:appIDVersion]) { + return NO; + } + + if (![self validateAppIDFingerprint:appID withVersion:appIDVersion]) { + return NO; + } + + return YES; +} + ++ (NSString *)actualBundleID { + return [[NSBundle mainBundle] bundleIdentifier]; +} + +/** + * Validates that the format of the app ID string is what is expected based on the supplied version. + * The version must end in ":". + * + * For v1 app ids the format is expected to be + * '::ios:'. + * + * This method does not verify that the contents of the app id are correct, just that they fulfill + * the expected format. + * + * @param appID Contents of GOOGLE_APP_ID from the plist file. + * @param version Indicates what version of the app id format this string should be. + * @return YES if provided string fufills the expected format, NO otherwise. + */ ++ (BOOL)validateAppIDFormat:(NSString *)appID withVersion:(NSString *)version { + if (!appID.length || !version.length) { + return NO; + } + + NSScanner *stringScanner = [NSScanner scannerWithString:appID]; + stringScanner.charactersToBeSkipped = nil; + + // Skip version part + // '**::ios:' + if (![stringScanner scanString:version intoString:NULL]) { + // The version part is missing or mismatched + return NO; + } + + // Validate version part (see part between '*' symbols below) + // '*:*:ios:' + if (![stringScanner scanString:@":" intoString:NULL]) { + // appIDVersion must be separated by ":" + return NO; + } + + // Validate version part (see part between '*' symbols below) + // ':**:ios:'. + NSInteger projectNumber = NSNotFound; + if (![stringScanner scanInteger:&projectNumber]) { + // NO project number found. + return NO; + } + + // Validate version part (see part between '*' symbols below) + // ':*:*ios:'. + if (![stringScanner scanString:@":" intoString:NULL]) { + // The project number must be separated by ":" + return NO; + } + + // Validate version part (see part between '*' symbols below) + // '::*ios*:'. + NSString *platform; + if (![stringScanner scanUpToString:@":" intoString:&platform]) { + return NO; + } + + if (![platform isEqualToString:@"ios"]) { + // The platform must be @"ios" + return NO; + } + + // Validate version part (see part between '*' symbols below) + // '::ios*:*'. + if (![stringScanner scanString:@":" intoString:NULL]) { + // The platform must be separated by ":" + return NO; + } + + // Validate version part (see part between '*' symbols below) + // '::ios:**'. + unsigned long long fingerprint = NSNotFound; + if (![stringScanner scanHexLongLong:&fingerprint]) { + // Fingerprint part is missing + return NO; + } + + if (!stringScanner.isAtEnd) { + // There are not allowed characters in the fingerprint part + return NO; + } + + return YES; +} + +/** + * Validates that the fingerprint of the app ID string is what is expected based on the supplied + * version. + * + * Note that the v1 hash algorithm is not permitted on the client and cannot be fully validated. + * + * @param appID Contents of GOOGLE_APP_ID from the plist file. + * @param version Indicates what version of the app id format this string should be. + * @return YES if provided string fufills the expected fingerprint and the version is known, NO + * otherwise. + */ ++ (BOOL)validateAppIDFingerprint:(NSString *)appID withVersion:(NSString *)version { + // Extract the supplied fingerprint from the supplied app ID. + // This assumes the app ID format is the same for all known versions below. If the app ID format + // changes in future versions, the tokenizing of the app ID format will need to take into account + // the version of the app ID. + NSArray *components = [appID componentsSeparatedByString:@":"]; + if (components.count != 4) { + return NO; + } + + NSString *suppliedFingerprintString = components[3]; + if (!suppliedFingerprintString.length) { + return NO; + } + + uint64_t suppliedFingerprint; + NSScanner *scanner = [NSScanner scannerWithString:suppliedFingerprintString]; + if (![scanner scanHexLongLong:&suppliedFingerprint]) { + return NO; + } + + if ([version isEqual:@"1"]) { + // The v1 hash algorithm is not permitted on the client so the actual hash cannot be validated. + return YES; + } + + // Unknown version. + return NO; +} + +- (NSString *)expectedBundleID { + return _options.bundleID; +} + +// end App ID validation + +#pragma mark - Reading From Plist & User Defaults + +/** + * Clears the data collection switch from the standard NSUserDefaults for easier testing and + * readability. + */ +- (void)clearDataCollectionSwitchFromUserDefaults { + NSString *key = + [NSString stringWithFormat:kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat, self.name]; + [[NSUserDefaults standardUserDefaults] removeObjectForKey:key]; +} + +/** + * Reads the data collection switch from the standard NSUserDefaults for easier testing and + * readability. + */ ++ (nullable NSNumber *)readDataCollectionSwitchFromUserDefaultsForApp:(FIRApp *)app { + // Read the object in user defaults, and only return if it's an NSNumber. + NSString *key = + [NSString stringWithFormat:kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat, app.name]; + id collectionEnabledDefaultsObject = [[NSUserDefaults standardUserDefaults] objectForKey:key]; + if ([collectionEnabledDefaultsObject isKindOfClass:[NSNumber class]]) { + return collectionEnabledDefaultsObject; + } + + return nil; +} + +/** + * Reads the data collection switch from the Info.plist for easier testing and readability. Will + * only read once from the plist and return the cached value. + */ ++ (nullable NSNumber *)readDataCollectionSwitchFromPlist { + static NSNumber *collectionEnabledPlistObject; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + // Read the data from the `Info.plist`, only assign it if it's there and an NSNumber. + id plistValue = [[NSBundle mainBundle] + objectForInfoDictionaryKey:kFIRGlobalAppDataCollectionEnabledPlistKey]; + if (plistValue && [plistValue isKindOfClass:[NSNumber class]]) { + collectionEnabledPlistObject = (NSNumber *)plistValue; + } + }); + + return collectionEnabledPlistObject; +} + +#pragma mark - Swift Components. + ++ (void)registerSwiftComponents { + SEL componentsToRegisterSEL = @selector(componentsToRegister); + // Dictionary of class names that conform to `FIRLibrary` and their user agents. These should only + // be SDKs that are written in Swift but still visible to ObjC. + NSDictionary *swiftComponents = @{ + @"FIRSessions" : @"fire-ses", + @"FIRFunctionsComponent" : @"fire-fun", + @"FIRStorageComponent" : @"fire-str", + }; + for (NSString *className in swiftComponents.allKeys) { + Class klass = NSClassFromString(className); + if (klass && [klass respondsToSelector:componentsToRegisterSEL]) { + [FIRApp registerInternalLibrary:klass withName:swiftComponents[className]]; + } + } + + // Swift libraries that don't need component behaviour + NSDictionary *swiftLibraries = @{ + @"FIRCombineAuthLibrary" : @"comb-auth", + @"FIRCombineFirestoreLibrary" : @"comb-firestore", + @"FIRCombineFunctionsLibrary" : @"comb-functions", + @"FIRCombineStorageLibrary" : @"comb-storage", + }; + for (NSString *className in swiftLibraries.allKeys) { + Class klass = NSClassFromString(className); + if (klass) { + [FIRApp registerLibrary:swiftLibraries[className] withVersion:FIRFirebaseVersion()]; + } + } +} + +#pragma mark - App Life Cycle + +- (void)subscribeForAppDidBecomeActiveNotifications { +#if TARGET_OS_IOS || TARGET_OS_TV + NSNotificationName notificationName = UIApplicationDidBecomeActiveNotification; +#elif TARGET_OS_OSX + NSNotificationName notificationName = NSApplicationDidBecomeActiveNotification; +#elif TARGET_OS_WATCH + // TODO(ncooke3): Remove when minimum supported watchOS version is watchOS 7.0. + // On watchOS 7.0+, heartbeats are logged when the watch app becomes active. + // On watchOS 6.0, heartbeats are logged when the Firebase app is configuring. + // While it does not cover all use cases, logging when the Firebase app is + // configuring is done because watchOS lifecycle notifications are a + // watchOS 7.0+ feature. + NSNotificationName notificationName = kFIRAppReadyToConfigureSDKNotification; + if (@available(watchOS 7.0, *)) { + notificationName = WKApplicationDidBecomeActiveNotification; + } +#endif + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(appDidBecomeActive:) + name:notificationName + object:nil]; +} + +- (void)appDidBecomeActive:(NSNotification *)notification { + if ([self isDataCollectionDefaultEnabled]) { + // If changing the below line, consult with the Games team to ensure they + // are not negatively impacted. For more details, see + // go/firebase-game-sdk-user-agent-register-timing. + [self.heartbeatLogger log]; + } +} + +#if DEBUG ++ (void)findMisnamedGoogleServiceInfoPlist { + for (NSBundle *bundle in [NSBundle allBundles]) { + // Not recursive, but we're looking for misnames, not people accidentally + // hiding their config file in a subdirectory of their bundle. + NSArray *plistPaths = [bundle pathsForResourcesOfType:@"plist" inDirectory:nil]; + for (NSString *path in plistPaths) { + @autoreleasepool { + NSDictionary *contents = [NSDictionary dictionaryWithContentsOfFile:path]; + if (contents == nil) { + continue; + } + + NSString *projectID = contents[@"PROJECT_ID"]; + if (projectID != nil) { + [NSException raise:kFirebaseCoreErrorDomain + format:@"`FirebaseApp.configure()` could not find the default " + @"configuration plist in your project, but did find one at " + @"%@. Please rename this file to GoogleService-Info.plist to " + @"use it as the default configuration.", + path]; + } + } + } + } +} +#endif // DEBUG + +@end diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/FIRBundleUtil.h b/Pods/FirebaseCore/FirebaseCore/Sources/FIRBundleUtil.h new file mode 100644 index 0000000..d9475dd --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/FIRBundleUtil.h @@ -0,0 +1,53 @@ +/* + * 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 + +/** + * This class provides utilities for accessing resources in bundles. + */ +@interface FIRBundleUtil : NSObject + +/** + * Finds all relevant bundles, starting with [NSBundle mainBundle]. + */ ++ (NSArray *)relevantBundles; + +/** + * Reads the options dictionary from one of the provided bundles. + * + * @param resourceName The resource name, e.g. @"GoogleService-Info". + * @param fileType The file type (extension), e.g. @"plist". + * @param bundles The bundles to expect, in priority order. See also + * +[FIRBundleUtil relevantBundles]. + */ ++ (NSString *)optionsDictionaryPathWithResourceName:(NSString *)resourceName + andFileType:(NSString *)fileType + inBundles:(NSArray *)bundles; + +/** + * Finds URL schemes defined in all relevant bundles, starting with those from + * [NSBundle mainBundle]. + */ ++ (NSArray *)relevantURLSchemes; + +/** + * Checks if any of the given bundles have a matching bundle identifier prefix (removing extension + * suffixes). + */ ++ (BOOL)hasBundleIdentifierPrefix:(NSString *)bundleIdentifier inBundles:(NSArray *)bundles; + +@end diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/FIRBundleUtil.m b/Pods/FirebaseCore/FirebaseCore/Sources/FIRBundleUtil.m new file mode 100644 index 0000000..de2c295 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/FIRBundleUtil.m @@ -0,0 +1,79 @@ +// 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 "FirebaseCore/Sources/FIRBundleUtil.h" + +#import + +@implementation FIRBundleUtil + ++ (NSArray *)relevantBundles { + return @[ [NSBundle mainBundle], [NSBundle bundleForClass:[self class]] ]; +} + ++ (NSString *)optionsDictionaryPathWithResourceName:(NSString *)resourceName + andFileType:(NSString *)fileType + inBundles:(NSArray *)bundles { + // Loop through all bundles to find the config dict. + for (NSBundle *bundle in bundles) { + NSString *path = [bundle pathForResource:resourceName ofType:fileType]; + // Use the first one we find. + if (path) { + return path; + } + } + return nil; +} + ++ (NSArray *)relevantURLSchemes { + NSMutableArray *result = [[NSMutableArray alloc] init]; + for (NSBundle *bundle in [[self class] relevantBundles]) { + NSArray *urlTypes = [bundle objectForInfoDictionaryKey:@"CFBundleURLTypes"]; + for (NSDictionary *urlType in urlTypes) { + [result addObjectsFromArray:urlType[@"CFBundleURLSchemes"]]; + } + } + return result; +} + ++ (BOOL)hasBundleIdentifierPrefix:(NSString *)bundleIdentifier inBundles:(NSArray *)bundles { + for (NSBundle *bundle in bundles) { + if ([bundle.bundleIdentifier isEqualToString:bundleIdentifier]) { + return YES; + } + + if ([GULAppEnvironmentUtil isAppExtension]) { + // A developer could be using the same `FIROptions` for both their app and extension. Since + // extensions have a suffix added to the bundleID, we consider a matching prefix as valid. + NSString *appBundleIDFromExtension = + [self bundleIdentifierByRemovingLastPartFrom:bundle.bundleIdentifier]; + if ([appBundleIDFromExtension isEqualToString:bundleIdentifier]) { + return YES; + } + } + } + return NO; +} + ++ (NSString *)bundleIdentifierByRemovingLastPartFrom:(NSString *)bundleIdentifier { + NSString *bundleIDComponentsSeparator = @"."; + + NSMutableArray *bundleIDComponents = + [[bundleIdentifier componentsSeparatedByString:bundleIDComponentsSeparator] mutableCopy]; + [bundleIDComponents removeLastObject]; + + return [bundleIDComponents componentsJoinedByString:bundleIDComponentsSeparator]; +} + +@end diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponent.m b/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponent.m new file mode 100644 index 0000000..d64d296 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponent.m @@ -0,0 +1,65 @@ +/* + * 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. + */ + +#import "FirebaseCore/Extension/FIRComponent.h" + +#import "FirebaseCore/Extension/FIRComponentContainer.h" +#import "FirebaseCore/Extension/FIRDependency.h" + +@interface FIRComponent () + +- (instancetype)initWithProtocol:(Protocol *)protocol + instantiationTiming:(FIRInstantiationTiming)instantiationTiming + dependencies:(NSArray *)dependencies + creationBlock:(FIRComponentCreationBlock)creationBlock; + +@end + +@implementation FIRComponent + ++ (instancetype)componentWithProtocol:(Protocol *)protocol + creationBlock:(FIRComponentCreationBlock)creationBlock { + return [[FIRComponent alloc] initWithProtocol:protocol + instantiationTiming:FIRInstantiationTimingLazy + dependencies:@[] + creationBlock:creationBlock]; +} + ++ (instancetype)componentWithProtocol:(Protocol *)protocol + instantiationTiming:(FIRInstantiationTiming)instantiationTiming + dependencies:(NSArray *)dependencies + creationBlock:(FIRComponentCreationBlock)creationBlock { + return [[FIRComponent alloc] initWithProtocol:protocol + instantiationTiming:instantiationTiming + dependencies:dependencies + creationBlock:creationBlock]; +} + +- (instancetype)initWithProtocol:(Protocol *)protocol + instantiationTiming:(FIRInstantiationTiming)instantiationTiming + dependencies:(NSArray *)dependencies + creationBlock:(FIRComponentCreationBlock)creationBlock { + self = [super init]; + if (self) { + _protocol = protocol; + _instantiationTiming = instantiationTiming; + _dependencies = [dependencies copy]; + _creationBlock = creationBlock; + } + return self; +} + +@end diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentContainer.m b/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentContainer.m new file mode 100644 index 0000000..771d03d --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentContainer.m @@ -0,0 +1,219 @@ +/* + * 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. + */ + +#import "FirebaseCore/Extension/FIRComponentContainer.h" + +#import "FirebaseCore/Extension/FIRAppInternal.h" +#import "FirebaseCore/Extension/FIRComponent.h" +#import "FirebaseCore/Extension/FIRLibrary.h" +#import "FirebaseCore/Extension/FIRLogger.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRComponentContainer () + +/// The dictionary of components that are registered for a particular app. The key is an `NSString` +/// of the protocol. +@property(nonatomic, strong) NSMutableDictionary *components; + +/// Cached instances of components that requested to be cached. +@property(nonatomic, strong) NSMutableDictionary *cachedInstances; + +/// Protocols of components that have requested to be eagerly instantiated. +@property(nonatomic, strong, nullable) NSMutableArray *eagerProtocolsToInstantiate; + +@end + +@implementation FIRComponentContainer + +// Collection of all classes that register to provide components. +static NSMutableSet *sFIRComponentRegistrants; + +#pragma mark - Public Registration + ++ (void)registerAsComponentRegistrant:(Class)klass { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sFIRComponentRegistrants = [[NSMutableSet alloc] init]; + }); + + [self registerAsComponentRegistrant:klass inSet:sFIRComponentRegistrants]; +} + ++ (void)registerAsComponentRegistrant:(Class)klass + inSet:(NSMutableSet *)allRegistrants { + [allRegistrants addObject:klass]; +} + +#pragma mark - Internal Initialization + +- (instancetype)initWithApp:(FIRApp *)app { + return [self initWithApp:app registrants:sFIRComponentRegistrants]; +} + +- (instancetype)initWithApp:(FIRApp *)app registrants:(NSMutableSet *)allRegistrants { + self = [super init]; + if (self) { + _app = app; + _cachedInstances = [NSMutableDictionary dictionary]; + _components = [NSMutableDictionary dictionary]; + + [self populateComponentsFromRegisteredClasses:allRegistrants forApp:app]; + } + return self; +} + +- (void)populateComponentsFromRegisteredClasses:(NSSet *)classes forApp:(FIRApp *)app { + // Keep track of any components that need to eagerly instantiate after all components are added. + self.eagerProtocolsToInstantiate = [[NSMutableArray alloc] init]; + + // Loop through the verified component registrants and populate the components array. + for (Class klass in classes) { + // Loop through all the components being registered and store them as appropriate. + // Classes which do not provide functionality should use a dummy FIRComponentRegistrant + // protocol. + for (FIRComponent *component in [klass componentsToRegister]) { + // Check if the component has been registered before, and error out if so. + NSString *protocolName = NSStringFromProtocol(component.protocol); + if (self.components[protocolName]) { + FIRLogError(kFIRLoggerCore, @"I-COR000029", + @"Attempted to register protocol %@, but it already has an implementation.", + protocolName); + continue; + } + + // Store the creation block for later usage. + self.components[protocolName] = component.creationBlock; + + // Queue any protocols that should be eagerly instantiated. Don't instantiate them yet + // because they could depend on other components that haven't been added to the components + // array yet. + BOOL shouldInstantiateEager = + (component.instantiationTiming == FIRInstantiationTimingAlwaysEager); + BOOL shouldInstantiateDefaultEager = + (component.instantiationTiming == FIRInstantiationTimingEagerInDefaultApp && + [app isDefaultApp]); + if (shouldInstantiateEager || shouldInstantiateDefaultEager) { + [self.eagerProtocolsToInstantiate addObject:component.protocol]; + } + } + } +} + +#pragma mark - Instance Creation + +- (void)instantiateEagerComponents { + // After all components are registered, instantiate the ones that are requesting eager + // instantiation. + @synchronized(self) { + for (Protocol *protocol in self.eagerProtocolsToInstantiate) { + // Get an instance for the protocol, which will instantiate it since it couldn't have been + // cached yet. Ignore the instance coming back since we don't need it. + __unused id unusedInstance = [self instanceForProtocol:protocol]; + } + + // All eager instantiation is complete, clear the stored property now. + self.eagerProtocolsToInstantiate = nil; + } +} + +/// Instantiate an instance of a class that conforms to the specified protocol. +/// This will: +/// - Call the block to create an instance if possible, +/// - Validate that the instance returned conforms to the protocol it claims to, +/// - Cache the instance if the block requests it +/// +/// Note that this method assumes the caller already has @sychronized on self. +- (nullable id)instantiateInstanceForProtocol:(Protocol *)protocol + withBlock:(FIRComponentCreationBlock)creationBlock { + if (!creationBlock) { + return nil; + } + + // Create an instance using the creation block. + BOOL shouldCache = NO; + id instance = creationBlock(self, &shouldCache); + if (!instance) { + return nil; + } + + // An instance was created, validate that it conforms to the protocol it claims to. + NSString *protocolName = NSStringFromProtocol(protocol); + if (![instance conformsToProtocol:protocol]) { + FIRLogError(kFIRLoggerCore, @"I-COR000030", + @"An instance conforming to %@ was requested, but the instance provided does not " + @"conform to the protocol", + protocolName); + } + + // The instance is ready to be returned, but check if it should be cached first before returning. + if (shouldCache) { + self.cachedInstances[protocolName] = instance; + } + + return instance; +} + +#pragma mark - Internal Retrieval + +// Redirected for Swift users. +- (nullable id)__instanceForProtocol:(Protocol *)protocol { + return [self instanceForProtocol:protocol]; +} + +- (nullable id)instanceForProtocol:(Protocol *)protocol { + // Check if there is a cached instance, and return it if so. + NSString *protocolName = NSStringFromProtocol(protocol); + + id cachedInstance; + @synchronized(self) { + cachedInstance = self.cachedInstances[protocolName]; + if (!cachedInstance) { + // Use the creation block to instantiate an instance and return it. + FIRComponentCreationBlock creationBlock = self.components[protocolName]; + cachedInstance = [self instantiateInstanceForProtocol:protocol withBlock:creationBlock]; + } + } + return cachedInstance; +} + +#pragma mark - Lifecycle + +- (void)removeAllCachedInstances { + @synchronized(self) { + // Loop through the cache and notify each instance that is a maintainer to clean up after + // itself. + for (id instance in self.cachedInstances.allValues) { + if ([instance conformsToProtocol:@protocol(FIRComponentLifecycleMaintainer)] && + [instance respondsToSelector:@selector(appWillBeDeleted:)]) { + [instance appWillBeDeleted:self.app]; + } + } + + // Empty the cache. + [self.cachedInstances removeAllObjects]; + } +} + +- (void)removeAllComponents { + @synchronized(self) { + [self.components removeAllObjects]; + } +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentContainerInternal.h b/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentContainerInternal.h new file mode 100644 index 0000000..169e181 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentContainerInternal.h @@ -0,0 +1,50 @@ +/* + * 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. + */ +#import + +#import "FirebaseCore/Extension/FIRComponentContainer.h" +#import "FirebaseCore/Extension/FIRLibrary.h" + +@class FIRApp; + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRComponentContainer (Private) + +/// Initializes a container for a given app. This should only be called by the app itself. +- (instancetype)initWithApp:(FIRApp *)app; + +/// Retrieves an instance that conforms to the specified protocol. This will return `nil` if the +/// protocol wasn't registered, or if the instance couldn't be instantiated for the provided app. +- (nullable id)instanceForProtocol:(Protocol *)protocol + NS_SWIFT_UNAVAILABLE("Use `instance(for:)` from the FirebaseCoreExtension module instead."); + +/// Instantiates all the components that have registered as "eager" after initialization. +- (void)instantiateEagerComponents; + +/// Remove all of the cached instances stored and allow them to clean up after themselves. +- (void)removeAllCachedInstances; + +/// Removes all the components. After calling this method no new instances will be created. +- (void)removeAllComponents; + +/// Register a class to provide components for the interoperability system. The class should conform +/// to `FIRComponentRegistrant` and provide an array of `FIRComponent` objects. ++ (void)registerAsComponentRegistrant:(Class)klass; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentType.m b/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentType.m new file mode 100644 index 0000000..c9cd2ad --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentType.m @@ -0,0 +1,28 @@ +/* + * 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. + */ + +#import "FirebaseCore/Extension/FIRComponentType.h" + +#import "FirebaseCore/Sources/FIRComponentContainerInternal.h" + +@implementation FIRComponentType + ++ (id)instanceForProtocol:(Protocol *)protocol inContainer:(FIRComponentContainer *)container { + // Forward the call to the container. + return [container instanceForProtocol:protocol]; +} + +@end diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/FIRConfiguration.m b/Pods/FirebaseCore/FirebaseCore/Sources/FIRConfiguration.m new file mode 100644 index 0000000..83b3248 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/FIRConfiguration.m @@ -0,0 +1,46 @@ +// 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 "FirebaseCore/Sources/FIRConfigurationInternal.h" + +#import "FirebaseCore/Sources/FIRAnalyticsConfiguration.h" + +extern void FIRSetLoggerLevel(FIRLoggerLevel loggerLevel); + +@implementation FIRConfiguration + ++ (instancetype)sharedInstance { + static FIRConfiguration *sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[FIRConfiguration alloc] init]; + }); + return sharedInstance; +} + +- (instancetype)init { + self = [super init]; + if (self) { + _analyticsConfiguration = [FIRAnalyticsConfiguration sharedInstance]; + } + return self; +} + +- (void)setLoggerLevel:(FIRLoggerLevel)loggerLevel { + NSAssert(loggerLevel <= FIRLoggerLevelMax && loggerLevel >= FIRLoggerLevelMin, + @"Invalid logger level, %ld", (long)loggerLevel); + FIRSetLoggerLevel(loggerLevel); +} + +@end diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/FIRConfigurationInternal.h b/Pods/FirebaseCore/FirebaseCore/Sources/FIRConfigurationInternal.h new file mode 100644 index 0000000..9361e73 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/FIRConfigurationInternal.h @@ -0,0 +1,29 @@ +/* + * Copyright 2019 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 "FirebaseCore/Sources/Public/FirebaseCore/FIRConfiguration.h" + +@class FIRAnalyticsConfiguration; + +@interface FIRConfiguration () + +/** + * The configuration class for Firebase Analytics. This should be removed once the logic for + * enabling and disabling Analytics is moved to Analytics. + */ +@property(nonatomic, readwrite) FIRAnalyticsConfiguration *analyticsConfiguration; + +@end diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/FIRDependency.m b/Pods/FirebaseCore/FirebaseCore/Sources/FIRDependency.m new file mode 100644 index 0000000..5c5bf7c --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/FIRDependency.m @@ -0,0 +1,44 @@ +/* + * 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. + */ + +#import "FirebaseCore/Extension/FIRDependency.h" + +@interface FIRDependency () + +- (instancetype)initWithProtocol:(Protocol *)protocol isRequired:(BOOL)required; + +@end + +@implementation FIRDependency + ++ (instancetype)dependencyWithProtocol:(Protocol *)protocol { + return [[self alloc] initWithProtocol:protocol isRequired:YES]; +} + ++ (instancetype)dependencyWithProtocol:(Protocol *)protocol isRequired:(BOOL)required { + return [[self alloc] initWithProtocol:protocol isRequired:required]; +} + +- (instancetype)initWithProtocol:(Protocol *)protocol isRequired:(BOOL)required { + self = [super init]; + if (self) { + _protocol = protocol; + _isRequired = required; + } + return self; +} + +@end diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/FIRFirebaseUserAgent.h b/Pods/FirebaseCore/FirebaseCore/Sources/FIRFirebaseUserAgent.h new file mode 100644 index 0000000..ffb11fb --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/FIRFirebaseUserAgent.h @@ -0,0 +1,36 @@ +/* + * Copyright 2020 Google LLC + * + * 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 + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRFirebaseUserAgent : NSObject + +/** Returns the firebase user agent which consists of environment part and the components added via + * `setValue:forComponent` method. */ +- (NSString *)firebaseUserAgent; + +/** Sets value associated with the specified component. If value is `nil` then the component is + * removed. */ +- (void)setValue:(nullable NSString *)value forComponent:(NSString *)componentName; + +/** Resets manually added components. */ +- (void)reset; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/FIRFirebaseUserAgent.m b/Pods/FirebaseCore/FirebaseCore/Sources/FIRFirebaseUserAgent.m new file mode 100644 index 0000000..04e7566 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/FIRFirebaseUserAgent.m @@ -0,0 +1,107 @@ +/* + * Copyright 2020 Google LLC + * + * 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 "FirebaseCore/Sources/FIRFirebaseUserAgent.h" + +#import + +@interface FIRFirebaseUserAgent () + +@property(nonatomic, readonly) NSMutableDictionary *valuesByComponent; +@property(nonatomic, readonly) NSDictionary *environmentComponents; +@property(nonatomic, readonly) NSString *firebaseUserAgent; + +@end + +@implementation FIRFirebaseUserAgent + +@synthesize firebaseUserAgent = _firebaseUserAgent; +@synthesize environmentComponents = _environmentComponents; + +- (instancetype)init { + self = [super init]; + if (self) { + _valuesByComponent = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (NSString *)firebaseUserAgent { + @synchronized(self) { + if (_firebaseUserAgent == nil) { + NSMutableDictionary *allComponents = + [self.valuesByComponent mutableCopy]; + [allComponents setValuesForKeysWithDictionary:self.environmentComponents]; + + __block NSMutableArray *components = + [[NSMutableArray alloc] initWithCapacity:self.valuesByComponent.count]; + [allComponents enumerateKeysAndObjectsUsingBlock:^( + NSString *_Nonnull name, NSString *_Nonnull value, BOOL *_Nonnull stop) { + [components addObject:[NSString stringWithFormat:@"%@/%@", name, value]]; + }]; + [components sortUsingSelector:@selector(localizedCaseInsensitiveCompare:)]; + _firebaseUserAgent = [components componentsJoinedByString:@" "]; + } + return _firebaseUserAgent; + } +} + +- (void)setValue:(nullable NSString *)value forComponent:(NSString *)componentName { + @synchronized(self) { + self.valuesByComponent[componentName] = value; + // Reset cached user agent string. + _firebaseUserAgent = nil; + } +} + +- (void)reset { + @synchronized(self) { + // Reset components. + _valuesByComponent = [[[self class] environmentComponents] mutableCopy]; + // Reset cached user agent string. + _firebaseUserAgent = nil; + } +} + +#pragma mark - Environment components + +- (NSDictionary *)environmentComponents { + if (_environmentComponents == nil) { + _environmentComponents = [[self class] environmentComponents]; + } + return _environmentComponents; +} + ++ (NSDictionary *)environmentComponents { + NSMutableDictionary *components = [NSMutableDictionary dictionary]; + + NSDictionary *info = [[NSBundle mainBundle] infoDictionary]; + NSString *xcodeVersion = info[@"DTXcodeBuild"]; + NSString *appleSdkVersion = info[@"DTSDKBuild"]; + NSString *isFromAppstoreFlagValue = [GULAppEnvironmentUtil isFromAppStore] ? @"true" : @"false"; + + components[@"apple-platform"] = [GULAppEnvironmentUtil applePlatform]; + components[@"apple-sdk"] = appleSdkVersion; + components[@"appstore"] = isFromAppstoreFlagValue; + components[@"deploy"] = [GULAppEnvironmentUtil deploymentType]; + components[@"device"] = [GULAppEnvironmentUtil deviceModel]; + components[@"os-version"] = [GULAppEnvironmentUtil systemVersion]; + components[@"xcode"] = xcodeVersion; + + return [components copy]; +} + +@end diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/FIRHeartbeatLogger.m b/Pods/FirebaseCore/FirebaseCore/Sources/FIRHeartbeatLogger.m new file mode 100644 index 0000000..5b0c309 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/FIRHeartbeatLogger.m @@ -0,0 +1,93 @@ +// Copyright 2021 Google LLC +// +// 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 + +#ifndef FIREBASE_BUILD_CMAKE +@import FirebaseCoreInternal; +#endif // FIREBASE_BUILD_CMAKE + +#import "FirebaseCore/Extension/FIRAppInternal.h" +#import "FirebaseCore/Extension/FIRHeartbeatLogger.h" + +#ifndef FIREBASE_BUILD_CMAKE +NSString *_Nullable FIRHeaderValueFromHeartbeatsPayload(FIRHeartbeatsPayload *heartbeatsPayload) { + if ([heartbeatsPayload isEmpty]) { + return nil; + } + + return [heartbeatsPayload headerValue]; +} +#endif // FIREBASE_BUILD_CMAKE + +@interface FIRHeartbeatLogger () +#ifndef FIREBASE_BUILD_CMAKE +@property(nonatomic, readonly) FIRHeartbeatController *heartbeatController; +#endif // FIREBASE_BUILD_CMAKE +@property(copy, readonly) NSString * (^userAgentProvider)(void); +@end + +@implementation FIRHeartbeatLogger + +- (instancetype)initWithAppID:(NSString *)appID { + return [self initWithAppID:appID userAgentProvider:[[self class] currentUserAgentProvider]]; +} + +- (instancetype)initWithAppID:(NSString *)appID + userAgentProvider:(NSString * (^)(void))userAgentProvider { + self = [super init]; + if (self) { +#ifndef FIREBASE_BUILD_CMAKE + _heartbeatController = [[FIRHeartbeatController alloc] initWithId:[appID copy]]; +#endif // FIREBASE_BUILD_CMAKE + _userAgentProvider = [userAgentProvider copy]; + } + return self; +} + ++ (NSString * (^)(void))currentUserAgentProvider { + return ^NSString * { + return [FIRApp firebaseUserAgent]; + }; +} + +- (void)log { + NSString *userAgent = _userAgentProvider(); +#ifndef FIREBASE_BUILD_CMAKE + [_heartbeatController log:userAgent]; +#endif // FIREBASE_BUILD_CMAKE +} + +#ifndef FIREBASE_BUILD_CMAKE +- (FIRHeartbeatsPayload *)flushHeartbeatsIntoPayload { + FIRHeartbeatsPayload *payload = [_heartbeatController flush]; + return payload; +} +#endif // FIREBASE_BUILD_CMAKE + +- (FIRDailyHeartbeatCode)heartbeatCodeForToday { +#ifndef FIREBASE_BUILD_CMAKE + FIRHeartbeatsPayload *todaysHeartbeatPayload = [_heartbeatController flushHeartbeatFromToday]; + + if ([todaysHeartbeatPayload isEmpty]) { + return FIRDailyHeartbeatCodeNone; + } else { + return FIRDailyHeartbeatCodeSome; + } +#else + return FIRDailyHeartbeatCodeNone; +#endif // FIREBASE_BUILD_CMAKE +} + +@end diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/FIRLogger.m b/Pods/FirebaseCore/FirebaseCore/Sources/FIRLogger.m new file mode 100644 index 0000000..cefb07d --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/FIRLogger.m @@ -0,0 +1,181 @@ +// 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 "FirebaseCore/Extension/FIRLogger.h" + +#import +#import +#import "FirebaseCore/Sources/Public/FirebaseCore/FIRLoggerLevel.h" + +#import "FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h" + +FIRLoggerService kFIRLoggerCore = @"[FirebaseCore]"; + +// All the FIRLoggerService definitions should be migrated to clients. Do not add new ones! +FIRLoggerService kFIRLoggerAnalytics = @"[FirebaseAnalytics]"; +FIRLoggerService kFIRLoggerCrash = @"[FirebaseCrash]"; +FIRLoggerService kFIRLoggerRemoteConfig = @"[FirebaseRemoteConfig]"; + +/// Arguments passed on launch. +NSString *const kFIRDisableDebugModeApplicationArgument = @"-FIRDebugDisabled"; +NSString *const kFIREnableDebugModeApplicationArgument = @"-FIRDebugEnabled"; +NSString *const kFIRLoggerForceSDTERRApplicationArgument = @"-FIRLoggerForceSTDERR"; + +/// Key for the debug mode bit in NSUserDefaults. +NSString *const kFIRPersistedDebugModeKey = @"/google/firebase/debug_mode"; + +/// NSUserDefaults that should be used to store and read variables. If nil, `standardUserDefaults` +/// will be used. +static NSUserDefaults *sFIRLoggerUserDefaults; + +static dispatch_once_t sFIRLoggerOnceToken; + +// The sFIRAnalyticsDebugMode flag is here to support the -FIRDebugEnabled/-FIRDebugDisabled +// flags used by Analytics. Users who use those flags expect Analytics to log verbosely, +// while the rest of Firebase logs at the default level. This flag is introduced to support +// that behavior. +static BOOL sFIRAnalyticsDebugMode; + +#ifdef DEBUG +/// The regex pattern for the message code. +static NSString *const kMessageCodePattern = @"^I-[A-Z]{3}[0-9]{6}$"; +static NSRegularExpression *sMessageCodeRegex; +#endif + +void FIRLoggerInitializeASL(void) { + dispatch_once(&sFIRLoggerOnceToken, ^{ + // Register Firebase Version with GULLogger. + GULLoggerRegisterVersion(FIRFirebaseVersion()); + + // Override the aslOptions to ASL_OPT_STDERR if the override argument is passed in. + NSArray *arguments = [NSProcessInfo processInfo].arguments; + BOOL overrideSTDERR = [arguments containsObject:kFIRLoggerForceSDTERRApplicationArgument]; + + // Use the standard NSUserDefaults if it hasn't been explicitly set. + if (sFIRLoggerUserDefaults == nil) { + sFIRLoggerUserDefaults = [NSUserDefaults standardUserDefaults]; + } + + BOOL forceDebugMode = NO; + BOOL debugMode = [sFIRLoggerUserDefaults boolForKey:kFIRPersistedDebugModeKey]; + if ([arguments containsObject:kFIRDisableDebugModeApplicationArgument]) { // Default mode + [sFIRLoggerUserDefaults removeObjectForKey:kFIRPersistedDebugModeKey]; + } else if ([arguments containsObject:kFIREnableDebugModeApplicationArgument] || + debugMode) { // Debug mode + [sFIRLoggerUserDefaults setBool:YES forKey:kFIRPersistedDebugModeKey]; + forceDebugMode = YES; + } + GULLoggerInitializeASL(); + if (overrideSTDERR) { + GULLoggerEnableSTDERR(); + } + if (forceDebugMode) { + GULLoggerForceDebug(); + } + }); +} + +__attribute__((no_sanitize("thread"))) void FIRSetAnalyticsDebugMode(BOOL analyticsDebugMode) { + sFIRAnalyticsDebugMode = analyticsDebugMode; +} + +void FIRSetLoggerLevel(FIRLoggerLevel loggerLevel) { + FIRLoggerInitializeASL(); + GULSetLoggerLevel((GULLoggerLevel)loggerLevel); +} + +#ifdef DEBUG +void FIRResetLogger(void) { + extern void GULResetLogger(void); + sFIRLoggerOnceToken = 0; + [sFIRLoggerUserDefaults removeObjectForKey:kFIRPersistedDebugModeKey]; + sFIRLoggerUserDefaults = nil; + GULResetLogger(); +} + +void FIRSetLoggerUserDefaults(NSUserDefaults *defaults) { + sFIRLoggerUserDefaults = defaults; +} +#endif + +/** + * Check if the level is high enough to be loggable. + * + * Analytics can override the log level with an intentional race condition. + * Add the attribute to get a clean thread sanitizer run. + */ +__attribute__((no_sanitize("thread"))) BOOL FIRIsLoggableLevel(FIRLoggerLevel loggerLevel, + BOOL analyticsComponent) { + FIRLoggerInitializeASL(); + if (sFIRAnalyticsDebugMode && analyticsComponent) { + return YES; + } + return GULIsLoggableLevel((GULLoggerLevel)loggerLevel); +} + +void FIRLogBasic(FIRLoggerLevel level, + FIRLoggerService service, + NSString *messageCode, + NSString *message, + va_list args_ptr) { + FIRLoggerInitializeASL(); + GULLogBasic((GULLoggerLevel)level, service, + sFIRAnalyticsDebugMode && [kFIRLoggerAnalytics isEqualToString:service], messageCode, + message, args_ptr); +} + +/** + * Generates the logging functions using macros. + * + * Calling FIRLogError(kFIRLoggerCore, @"I-COR000001", @"Configure %@ failed.", @"blah") shows: + * yyyy-mm-dd hh:mm:ss.SSS sender[PID] [Firebase/Core][I-COR000001] Configure blah failed. + * Calling FIRLogDebug(kFIRLoggerCore, @"I-COR000001", @"Configure succeed.") shows: + * yyyy-mm-dd hh:mm:ss.SSS sender[PID] [Firebase/Core][I-COR000001] Configure succeed. + */ +#define FIR_LOGGING_FUNCTION(level) \ + void FIRLog##level(FIRLoggerService service, NSString *messageCode, NSString *message, ...) { \ + va_list args_ptr; \ + va_start(args_ptr, message); \ + FIRLogBasic(FIRLoggerLevel##level, service, messageCode, message, args_ptr); \ + va_end(args_ptr); \ + } + +FIR_LOGGING_FUNCTION(Error) +FIR_LOGGING_FUNCTION(Warning) +FIR_LOGGING_FUNCTION(Notice) +FIR_LOGGING_FUNCTION(Info) +FIR_LOGGING_FUNCTION(Debug) + +#undef FIR_MAKE_LOGGER + +#pragma mark - FIRLoggerWrapper + +@implementation FIRLoggerWrapper + ++ (void)logWithLevel:(FIRLoggerLevel)level + withService:(FIRLoggerService)service + withCode:(NSString *)messageCode + withMessage:(NSString *)message + withArgs:(va_list)args { + FIRLogBasic(level, service, messageCode, message, args); +} + ++ (void)logWithLevel:(FIRLoggerLevel)level + service:(FIRLoggerService)service + code:(NSString *)code + message:(NSString *)message { + FIRLogBasic(level, service, code, message, NULL); +} + +@end diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/FIROptions.m b/Pods/FirebaseCore/FirebaseCore/Sources/FIROptions.m new file mode 100644 index 0000000..d46b657 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/FIROptions.m @@ -0,0 +1,487 @@ +// 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 "FirebaseCore/Extension/FIRAppInternal.h" +#import "FirebaseCore/Extension/FIRLogger.h" +#import "FirebaseCore/Extension/FIROptionsInternal.h" +#import "FirebaseCore/Sources/FIRBundleUtil.h" +#import "FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h" + +// Keys for the strings in the plist file. +NSString *const kFIRAPIKey = @"API_KEY"; +NSString *const kFIRTrackingID = @"TRACKING_ID"; +NSString *const kFIRGoogleAppID = @"GOOGLE_APP_ID"; +NSString *const kFIRClientID = @"CLIENT_ID"; +NSString *const kFIRGCMSenderID = @"GCM_SENDER_ID"; +NSString *const kFIRAndroidClientID = @"ANDROID_CLIENT_ID"; +NSString *const kFIRDatabaseURL = @"DATABASE_URL"; +NSString *const kFIRStorageBucket = @"STORAGE_BUCKET"; +// The key to locate the expected bundle identifier in the plist file. +NSString *const kFIRBundleID = @"BUNDLE_ID"; +// The key to locate the project identifier in the plist file. +NSString *const kFIRProjectID = @"PROJECT_ID"; + +NSString *const kFIRIsMeasurementEnabled = @"IS_MEASUREMENT_ENABLED"; +NSString *const kFIRIsAnalyticsCollectionEnabled = @"FIREBASE_ANALYTICS_COLLECTION_ENABLED"; +NSString *const kFIRIsAnalyticsCollectionDeactivated = @"FIREBASE_ANALYTICS_COLLECTION_DEACTIVATED"; + +// Library version ID formatted like: +// @"5" // Major version (one or more digits) +// @"04" // Minor version (exactly 2 digits) +// @"01" // Build number (exactly 2 digits) +// @"000"; // Fixed "000" +NSString *kFIRLibraryVersionID; + +// Plist file name. +NSString *const kServiceInfoFileName = @"GoogleService-Info"; +// Plist file type. +NSString *const kServiceInfoFileType = @"plist"; + +// Exception raised from attempting to modify a FIROptions after it's been copied to a FIRApp. +NSString *const kFIRExceptionBadModification = + @"Attempted to modify options after it's set on FIRApp. Please modify all properties before " + @"initializing FIRApp."; + +@interface FIROptions () + +/** + * This property maintains the actual configuration key-value pairs. + */ +@property(nonatomic, readwrite) NSMutableDictionary *optionsDictionary; + +/** + * Calls `analyticsOptionsDictionaryWithInfoDictionary:` using [NSBundle mainBundle].infoDictionary. + * It combines analytics options from both the infoDictionary and the GoogleService-Info.plist. + * Values which are present in the main plist override values from the GoogleService-Info.plist. + */ +@property(nonatomic, readonly) NSDictionary *analyticsOptionsDictionary; + +/** + * Combination of analytics options from both the infoDictionary and the GoogleService-Info.plist. + * Values which are present in the infoDictionary override values from the GoogleService-Info.plist. + */ +- (NSDictionary *)analyticsOptionsDictionaryWithInfoDictionary:(NSDictionary *)infoDictionary; + +/** + * Throw exception if editing is locked when attempting to modify an option. + */ +- (void)checkEditingLocked; + +@end + +@implementation FIROptions { + /// Backing variable for self.analyticsOptionsDictionary. + NSDictionary *_analyticsOptionsDictionary; +} + +static FIROptions *sDefaultOptions = nil; +static NSDictionary *sDefaultOptionsDictionary = nil; +static dispatch_once_t sDefaultOptionsOnceToken; +static dispatch_once_t sDefaultOptionsDictionaryOnceToken; + +#pragma mark - Public only for internal class methods + ++ (FIROptions *)defaultOptions { + dispatch_once(&sDefaultOptionsOnceToken, ^{ + NSDictionary *defaultOptionsDictionary = [self defaultOptionsDictionary]; + if (defaultOptionsDictionary != nil) { + sDefaultOptions = + [[FIROptions alloc] initInternalWithOptionsDictionary:defaultOptionsDictionary]; + } + }); + + return sDefaultOptions; +} + +#pragma mark - Private class methods + ++ (NSDictionary *)defaultOptionsDictionary { + dispatch_once(&sDefaultOptionsDictionaryOnceToken, ^{ + NSString *plistFilePath = [FIROptions plistFilePathWithName:kServiceInfoFileName]; + if (plistFilePath == nil) { + return; + } + sDefaultOptionsDictionary = [NSDictionary dictionaryWithContentsOfFile:plistFilePath]; + if (sDefaultOptionsDictionary == nil) { + FIRLogError(kFIRLoggerCore, @"I-COR000011", + @"The configuration file is not a dictionary: " + @"'%@.%@'.", + kServiceInfoFileName, kServiceInfoFileType); + } + }); + + return sDefaultOptionsDictionary; +} + +// Returns the path of the plist file with a given file name. ++ (NSString *)plistFilePathWithName:(NSString *)fileName { + NSArray *bundles = [FIRBundleUtil relevantBundles]; + NSString *plistFilePath = + [FIRBundleUtil optionsDictionaryPathWithResourceName:fileName + andFileType:kServiceInfoFileType + inBundles:bundles]; + if (plistFilePath == nil) { + FIRLogError(kFIRLoggerCore, @"I-COR000012", @"Could not locate configuration file: '%@.%@'.", + fileName, kServiceInfoFileType); + } + return plistFilePath; +} + ++ (void)resetDefaultOptions { + sDefaultOptions = nil; + sDefaultOptionsDictionary = nil; + sDefaultOptionsOnceToken = 0; + sDefaultOptionsDictionaryOnceToken = 0; +} + +#pragma mark - Private instance methods + +- (instancetype)initInternalWithOptionsDictionary:(NSDictionary *)optionsDictionary { + self = [super init]; + if (self) { + _optionsDictionary = [optionsDictionary mutableCopy]; + _usingOptionsFromDefaultPlist = YES; + } + return self; +} + +- (id)copyWithZone:(NSZone *)zone { + FIROptions *newOptions = [(FIROptions *)[[self class] allocWithZone:zone] + initInternalWithOptionsDictionary:self.optionsDictionary]; + if (newOptions) { + newOptions.deepLinkURLScheme = self.deepLinkURLScheme; + newOptions.appGroupID = self.appGroupID; + newOptions.editingLocked = self.isEditingLocked; + newOptions.usingOptionsFromDefaultPlist = self.usingOptionsFromDefaultPlist; + } + return newOptions; +} + +#pragma mark - Public instance methods + +- (instancetype)init { + // Unavailable. + [self doesNotRecognizeSelector:_cmd]; + return nil; +} + +- (instancetype)initWithContentsOfFile:(NSString *)plistPath { + self = [super init]; + if (self) { + if (plistPath == nil) { + FIRLogError(kFIRLoggerCore, @"I-COR000013", @"The plist file path is nil."); + return nil; + } + _optionsDictionary = [[NSDictionary dictionaryWithContentsOfFile:plistPath] mutableCopy]; + if (_optionsDictionary == nil) { + FIRLogError(kFIRLoggerCore, @"I-COR000014", + @"The configuration file at %@ does not exist or " + @"is not a well-formed plist file.", + plistPath); + return nil; + } + // TODO: Do we want to validate the dictionary here? It says we do that already in + // the public header. + } + return self; +} + +- (instancetype)initWithGoogleAppID:(NSString *)googleAppID GCMSenderID:(NSString *)GCMSenderID { + self = [super init]; + if (self) { + NSMutableDictionary *mutableOptionsDict = [NSMutableDictionary dictionary]; + [mutableOptionsDict setValue:googleAppID forKey:kFIRGoogleAppID]; + [mutableOptionsDict setValue:GCMSenderID forKey:kFIRGCMSenderID]; + [mutableOptionsDict setValue:[[NSBundle mainBundle] bundleIdentifier] forKey:kFIRBundleID]; + self.optionsDictionary = mutableOptionsDict; + } + return self; +} + +- (NSString *)APIKey { + return self.optionsDictionary[kFIRAPIKey]; +} + +- (void)checkEditingLocked { + if (self.isEditingLocked) { + [NSException raise:kFirebaseCoreErrorDomain format:kFIRExceptionBadModification]; + } +} + +- (void)setAPIKey:(NSString *)APIKey { + [self checkEditingLocked]; + _optionsDictionary[kFIRAPIKey] = [APIKey copy]; +} + +- (NSString *)clientID { + return self.optionsDictionary[kFIRClientID]; +} + +- (void)setClientID:(NSString *)clientID { + [self checkEditingLocked]; + _optionsDictionary[kFIRClientID] = [clientID copy]; +} + +- (NSString *)trackingID { + return self.optionsDictionary[kFIRTrackingID]; +} + +- (void)setTrackingID:(NSString *)trackingID { + [self checkEditingLocked]; + _optionsDictionary[kFIRTrackingID] = [trackingID copy]; +} + +- (NSString *)GCMSenderID { + return self.optionsDictionary[kFIRGCMSenderID]; +} + +- (void)setGCMSenderID:(NSString *)GCMSenderID { + [self checkEditingLocked]; + _optionsDictionary[kFIRGCMSenderID] = [GCMSenderID copy]; +} + +- (NSString *)projectID { + return self.optionsDictionary[kFIRProjectID]; +} + +- (void)setProjectID:(NSString *)projectID { + [self checkEditingLocked]; + _optionsDictionary[kFIRProjectID] = [projectID copy]; +} + +- (NSString *)androidClientID { + return self.optionsDictionary[kFIRAndroidClientID]; +} + +- (void)setAndroidClientID:(NSString *)androidClientID { + [self checkEditingLocked]; + _optionsDictionary[kFIRAndroidClientID] = [androidClientID copy]; +} + +- (NSString *)googleAppID { + return self.optionsDictionary[kFIRGoogleAppID]; +} + +- (void)setGoogleAppID:(NSString *)googleAppID { + [self checkEditingLocked]; + _optionsDictionary[kFIRGoogleAppID] = [googleAppID copy]; +} + +- (NSString *)libraryVersionID { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + // The unit tests are set up to catch anything that does not properly convert. + NSString *version = FIRFirebaseVersion(); + NSArray *components = [version componentsSeparatedByString:@"."]; + NSString *major = [components objectAtIndex:0]; + NSString *minor = [NSString stringWithFormat:@"%02d", [[components objectAtIndex:1] intValue]]; + NSString *patch = [NSString stringWithFormat:@"%02d", [[components objectAtIndex:2] intValue]]; + kFIRLibraryVersionID = [NSString stringWithFormat:@"%@%@%@000", major, minor, patch]; + }); + return kFIRLibraryVersionID; +} + +- (void)setLibraryVersionID:(NSString *)libraryVersionID { + _optionsDictionary[kFIRLibraryVersionID] = [libraryVersionID copy]; +} + +- (NSString *)databaseURL { + return self.optionsDictionary[kFIRDatabaseURL]; +} + +- (void)setDatabaseURL:(NSString *)databaseURL { + [self checkEditingLocked]; + + _optionsDictionary[kFIRDatabaseURL] = [databaseURL copy]; +} + +- (NSString *)storageBucket { + return self.optionsDictionary[kFIRStorageBucket]; +} + +- (void)setStorageBucket:(NSString *)storageBucket { + [self checkEditingLocked]; + _optionsDictionary[kFIRStorageBucket] = [storageBucket copy]; +} + +- (void)setDeepLinkURLScheme:(NSString *)deepLinkURLScheme { + [self checkEditingLocked]; + _deepLinkURLScheme = [deepLinkURLScheme copy]; +} + +- (NSString *)bundleID { + return self.optionsDictionary[kFIRBundleID]; +} + +- (void)setBundleID:(NSString *)bundleID { + [self checkEditingLocked]; + _optionsDictionary[kFIRBundleID] = [bundleID copy]; +} + +- (void)setAppGroupID:(NSString *)appGroupID { + [self checkEditingLocked]; + _appGroupID = [appGroupID copy]; +} + +#pragma mark - Equality + +- (BOOL)isEqual:(id)object { + if (!object || ![object isKindOfClass:[FIROptions class]]) { + return NO; + } + + return [self isEqualToOptions:(FIROptions *)object]; +} + +- (BOOL)isEqualToOptions:(FIROptions *)options { + // Skip any non-FIROptions classes. + if (![options isKindOfClass:[FIROptions class]]) { + return NO; + } + + // Check the internal dictionary and custom properties for differences. + if (![options.optionsDictionary isEqualToDictionary:self.optionsDictionary]) { + return NO; + } + + // Validate extra properties not contained in the dictionary. Only validate it if one of the + // objects has the property set. + if ((options.deepLinkURLScheme != nil || self.deepLinkURLScheme != nil) && + ![options.deepLinkURLScheme isEqualToString:self.deepLinkURLScheme]) { + return NO; + } + + if ((options.appGroupID != nil || self.appGroupID != nil) && + ![options.appGroupID isEqualToString:self.appGroupID]) { + return NO; + } + + // Validate the Analytics options haven't changed with the Info.plist. + if (![options.analyticsOptionsDictionary isEqualToDictionary:self.analyticsOptionsDictionary]) { + return NO; + } + + // We don't care about the `editingLocked` or `usingOptionsFromDefaultPlist` properties since + // those relate to lifecycle and construction, we only care if the contents of the options + // themselves are equal. + return YES; +} + +- (NSUInteger)hash { + // This is strongly recommended for any object that implements a custom `isEqual:` method to + // ensure that dictionary and set behavior matches other `isEqual:` checks. + // Note: `self.analyticsOptionsDictionary` was left out here since it solely relies on the + // contents of the main bundle's `Info.plist`. We should avoid reading that file and the contents + // should be identical. + return self.optionsDictionary.hash ^ self.deepLinkURLScheme.hash ^ self.appGroupID.hash; +} + +#pragma mark - Internal instance methods + +- (NSDictionary *)analyticsOptionsDictionaryWithInfoDictionary:(NSDictionary *)infoDictionary { + if (_analyticsOptionsDictionary == nil) { + NSMutableDictionary *tempAnalyticsOptions = [[NSMutableDictionary alloc] init]; + NSArray *measurementKeys = @[ + kFIRIsMeasurementEnabled, kFIRIsAnalyticsCollectionEnabled, + kFIRIsAnalyticsCollectionDeactivated + ]; + for (NSString *key in measurementKeys) { + id value = infoDictionary[key] ?: self.optionsDictionary[key] ?: nil; + if (!value) { + continue; + } + tempAnalyticsOptions[key] = value; + } + _analyticsOptionsDictionary = tempAnalyticsOptions; + } + return _analyticsOptionsDictionary; +} + +- (NSDictionary *)analyticsOptionsDictionary { + return [self analyticsOptionsDictionaryWithInfoDictionary:[NSBundle mainBundle].infoDictionary]; +} + +/** + * Whether or not Measurement was enabled. Measurement is enabled unless explicitly disabled in + * GoogleService-Info.plist. This uses the old plist flag IS_MEASUREMENT_ENABLED, which should still + * be supported. + */ +- (BOOL)isMeasurementEnabled { + if (self.isAnalyticsCollectionDeactivated) { + return NO; + } + NSNumber *value = self.analyticsOptionsDictionary[kFIRIsMeasurementEnabled]; + if (value == nil) { + // TODO: This could probably be cleaned up since FIROptions shouldn't know about FIRApp or have + // to check if it's the default app. The FIROptions instance can't be modified after + // `+configure` is called, so it's not a good place to copy it either in case the flag is + // changed at runtime. + + // If no values are set for Analytics, fall back to the global collection switch in FIRApp. + // Analytics only supports the default FIRApp, so check that first. + if (![FIRApp isDefaultAppConfigured]) { + return NO; + } + + // Fall back to the default app's collection switch when the key is not in the dictionary. + return [FIRApp defaultApp].isDataCollectionDefaultEnabled; + } + return [value boolValue]; +} + +- (BOOL)isAnalyticsCollectionExplicitlySet { + // If it's de-activated, it classifies as explicity set. If not, it's not a good enough indication + // that the developer wants FirebaseAnalytics enabled so continue checking. + if (self.isAnalyticsCollectionDeactivated) { + return YES; + } + + // Check if the current Analytics flag is set. + id collectionEnabledObject = self.analyticsOptionsDictionary[kFIRIsAnalyticsCollectionEnabled]; + if (collectionEnabledObject && [collectionEnabledObject isKindOfClass:[NSNumber class]]) { + // It doesn't matter what the value is, it's explicitly set. + return YES; + } + + // Check if the old measurement flag is set. + id measurementEnabledObject = self.analyticsOptionsDictionary[kFIRIsMeasurementEnabled]; + if (measurementEnabledObject && [measurementEnabledObject isKindOfClass:[NSNumber class]]) { + // It doesn't matter what the value is, it's explicitly set. + return YES; + } + + // No flags are set to explicitly enable or disable FirebaseAnalytics. + return NO; +} + +- (BOOL)isAnalyticsCollectionEnabled { + if (self.isAnalyticsCollectionDeactivated) { + return NO; + } + NSNumber *value = self.analyticsOptionsDictionary[kFIRIsAnalyticsCollectionEnabled]; + if (value == nil) { + return self.isMeasurementEnabled; // Fall back to older plist flag. + } + return [value boolValue]; +} + +- (BOOL)isAnalyticsCollectionDeactivated { + NSNumber *value = self.analyticsOptionsDictionary[kFIRIsAnalyticsCollectionDeactivated]; + if (value == nil) { + return NO; // Analytics Collection is not deactivated when the key is not in the dictionary. + } + return [value boolValue]; +} + +@end diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/FIRVersion.m b/Pods/FirebaseCore/FirebaseCore/Sources/FIRVersion.m new file mode 100644 index 0000000..f458a3a --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/FIRVersion.m @@ -0,0 +1,32 @@ +/* + * 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 "FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h" + +#ifndef Firebase_VERSION +#error "Firebase_VERSION is not defined: add -DFirebase_VERSION=... to the build invocation" +#endif + +// The following two macros supply the incantation so that the C +// preprocessor does not try to parse the version as a floating +// point number. See +// https://www.guyrutenberg.com/2008/12/20/expanding-macros-into-string-constants-in-c/ +#define STR(x) STR_EXPAND(x) +#define STR_EXPAND(x) #x + +NSString* FIRFirebaseVersion(void) { + return @STR(Firebase_VERSION); +} diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRApp.h b/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRApp.h new file mode 100644 index 0000000..58ef2a6 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRApp.h @@ -0,0 +1,129 @@ +/* + * 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 + +@class FIROptions; + +NS_ASSUME_NONNULL_BEGIN + +/** A block that takes a BOOL and has no return value. */ +typedef void (^FIRAppVoidBoolCallback)(BOOL success) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/** + * The entry point of Firebase SDKs. + * + * Initialize and configure `FirebaseApp` using `FirebaseApp.configure()` + * or other customized ways as shown below. + * + * The logging system has two modes: default mode and debug mode. In default mode, only logs with + * log level Notice, Warning and Error will be sent to device. In debug mode, all logs will be sent + * to device. The log levels that Firebase uses are consistent with the ASL log levels. + * + * Enable debug mode by passing the `-FIRDebugEnabled` argument to the application. You can add this + * argument in the application's Xcode scheme. When debug mode is enabled via `-FIRDebugEnabled`, + * further executions of the application will also be in debug mode. In order to return to default + * mode, you must explicitly disable the debug mode with the application argument + * `-FIRDebugDisabled`. + * + * It is also possible to change the default logging level in code by calling + * `FirebaseConfiguration.shared.setLoggerLevel(_:)` with the desired level. + */ +NS_SWIFT_NAME(FirebaseApp) +@interface FIRApp : NSObject + +/** + * Configures a default Firebase app. Raises an exception if any configuration step fails. The + * default app is named "__FIRAPP_DEFAULT". This method should be called after the app is launched + * and before using Firebase services. This method should be called from the main thread and + * contains synchronous file I/O (reading GoogleService-Info.plist from disk). + */ ++ (void)configure; + +/** + * Configures the default Firebase app with the provided options. The default app is named + * "__FIRAPP_DEFAULT". Raises an exception if any configuration step fails. This method should be + * called from the main thread. + * + * @param options The Firebase application options used to configure the service. + */ ++ (void)configureWithOptions:(FIROptions *)options NS_SWIFT_NAME(configure(options:)); + +/** + * Configures a Firebase app with the given name and options. Raises an exception if any + * configuration step fails. This method should be called from the main thread. + * + * @param name The application's name given by the developer. The name should should only contain + Letters, Numbers and Underscore. + * @param options The Firebase application options used to configure the services. + */ +// clang-format off ++ (void)configureWithName:(NSString *)name + options:(FIROptions *)options NS_SWIFT_NAME(configure(name:options:)); +// clang-format on + +/** + * Returns the default app, or `nil` if the default app does not exist. + */ ++ (nullable FIRApp *)defaultApp NS_SWIFT_NAME(app()); + +/** + * Returns a previously created `FirebaseApp` instance with the given name, or `nil` if no such app + * exists. This method is thread safe. + */ ++ (nullable FIRApp *)appNamed:(NSString *)name NS_SWIFT_NAME(app(name:)); + +/** + * Returns the set of all extant `FirebaseApp` instances, or `nil` if there are no `FirebaseApp` + * instances. This method is thread safe. + */ +@property(class, readonly, nullable) NSDictionary *allApps; + +/** + * Cleans up the current `FirebaseApp`, freeing associated data and returning its name to the pool + * for future use. This method is thread safe. + */ +- (void)deleteApp:(void (^)(BOOL success))completion; + +/** + * `FirebaseApp` instances should not be initialized directly. Call `FirebaseApp.configure()`, + * `FirebaseApp.configure(options:)`, or `FirebaseApp.configure(name:options:)` directly. + */ +- (instancetype)init NS_UNAVAILABLE; + +/** + * Gets the name of this app. + */ +@property(nonatomic, copy, readonly) NSString *name; + +/** + * Gets a copy of the options for this app. These are non-modifiable. + */ +@property(nonatomic, copy, readonly) FIROptions *options; + +/** + * Gets or sets whether automatic data collection is enabled for all products. Defaults to `true` + * unless `FirebaseDataCollectionDefaultEnabled` is set to `NO` in your app's Info.plist. This value + * is persisted across runs of the app so that it can be set once when users have consented to + * collection. + */ +@property(nonatomic, readwrite, getter=isDataCollectionDefaultEnabled) + BOOL dataCollectionDefaultEnabled; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRConfiguration.h b/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRConfiguration.h new file mode 100644 index 0000000..408bcad --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRConfiguration.h @@ -0,0 +1,45 @@ +/* + * 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 + +#import "FIRLoggerLevel.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * This interface provides global level properties that the developer can tweak. + */ +NS_SWIFT_NAME(FirebaseConfiguration) +@interface FIRConfiguration : NSObject + +/** Returns the shared configuration object. */ +@property(class, nonatomic, readonly) FIRConfiguration *sharedInstance NS_SWIFT_NAME(shared); + +/** + * Sets the logging level for internal Firebase logging. Firebase will only log messages + * that are logged at or below `loggerLevel`. The messages are logged both to the Xcode + * console and to the device's log. Note that if an app is running from AppStore, it will + * never log above `.notice` even if `loggerLevel` is set to a higher (more verbose) + * setting. + * + * @param loggerLevel The maximum logging level. The default level is set to FIRLoggerLevelNotice. + */ +- (void)setLoggerLevel:(FIRLoggerLevel)loggerLevel; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRLoggerLevel.h b/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRLoggerLevel.h new file mode 100644 index 0000000..dca3aa0 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRLoggerLevel.h @@ -0,0 +1,38 @@ +/* + * 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. + */ + +// Note that importing GULLoggerLevel.h will lead to a non-modular header +// import error. + +/** + * The log levels used by internal logging. + */ +typedef NS_ENUM(NSInteger, FIRLoggerLevel) { + /** Error level, matches ASL_LEVEL_ERR. */ + FIRLoggerLevelError = 3, + /** Warning level, matches ASL_LEVEL_WARNING. */ + FIRLoggerLevelWarning = 4, + /** Notice level, matches ASL_LEVEL_NOTICE. */ + FIRLoggerLevelNotice = 5, + /** Info level, matches ASL_LEVEL_INFO. */ + FIRLoggerLevelInfo = 6, + /** Debug level, matches ASL_LEVEL_DEBUG. */ + FIRLoggerLevelDebug = 7, + /** Minimum log level. */ + FIRLoggerLevelMin = FIRLoggerLevelError, + /** Maximum log level. */ + FIRLoggerLevelMax = FIRLoggerLevelDebug +} NS_SWIFT_NAME(FirebaseLoggerLevel); diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h b/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h new file mode 100644 index 0000000..8f8d945 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h @@ -0,0 +1,131 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** + * This class provides constant fields of Google APIs. + */ +NS_SWIFT_NAME(FirebaseOptions) +@interface FIROptions : NSObject + +/** + * Returns the default options. The first time this is called it synchronously reads + * GoogleService-Info.plist from disk. + */ ++ (nullable FIROptions *)defaultOptions NS_SWIFT_NAME(defaultOptions()); + +/** + * An API key used for authenticating requests from your Apple app, e.g. + * The key must begin with "A" and contain exactly 39 alphanumeric characters, used to identify your + * app to Google servers. + */ +@property(nonatomic, copy, nullable) NSString *APIKey NS_SWIFT_NAME(apiKey); + +/** + * The bundle ID for the application. Defaults to `Bundle.main.bundleIdentifier` when not set + * manually or in a plist. + */ +@property(nonatomic, copy) NSString *bundleID; + +/** + * The OAuth2 client ID for Apple applications used to authenticate Google users, for example + * @"12345.apps.googleusercontent.com", used for signing in with Google. + */ +@property(nonatomic, copy, nullable) NSString *clientID; + +/** + * Unused. + */ +@property(nonatomic, copy, nullable) NSString *trackingID DEPRECATED_ATTRIBUTE; + +/** + * The Project Number from the Google Developer's console, for example @"012345678901", used to + * configure Firebase Cloud Messaging. + */ +@property(nonatomic, copy) NSString *GCMSenderID NS_SWIFT_NAME(gcmSenderID); + +/** + * The Project ID from the Firebase console, for example @"abc-xyz-123". + */ +@property(nonatomic, copy, nullable) NSString *projectID; + +/** + * Unused. + */ +@property(nonatomic, copy, nullable) NSString *androidClientID DEPRECATED_ATTRIBUTE; + +/** + * The Google App ID that is used to uniquely identify an instance of an app. + */ +@property(nonatomic, copy) NSString *googleAppID; + +/** + * The database root URL, e.g. @"http://abc-xyz-123.firebaseio.com". + */ +@property(nonatomic, copy, nullable) NSString *databaseURL; + +/** + * The URL scheme used to set up Durable Deep Link service. + */ +@property(nonatomic, copy, nullable) NSString *deepLinkURLScheme; + +/** + * The Google Cloud Storage bucket name, e.g. @"abc-xyz-123.storage.firebase.com". + */ +@property(nonatomic, copy, nullable) NSString *storageBucket; + +/** + * The App Group identifier to share data between the application and the application extensions. + * The App Group must be configured in the application and on the Apple Developer Portal. Default + * value `nil`. + */ +@property(nonatomic, copy, nullable) NSString *appGroupID; + +/** + * Initializes a customized instance of FirebaseOptions from the file at the given plist file path. + * This will read the file synchronously from disk. + * For example: + * ```swift + * if let path = Bundle.main.path(forResource:"GoogleServices-Info", ofType:"plist") { + * let options = FirebaseOptions(contentsOfFile: path) + * } + * ``` + * Note that it is not possible to customize `FirebaseOptions` for Firebase Analytics which expects + * a static file named `GoogleServices-Info.plist` - + * https://github.com/firebase/firebase-ios-sdk/issues/230. + * Returns `nil` if the plist file does not exist or is invalid. + */ +- (nullable instancetype)initWithContentsOfFile:(NSString *)plistPath NS_DESIGNATED_INITIALIZER; + +/** + * Initializes a customized instance of `FirebaseOptions` with required fields. Use the mutable + * properties to modify fields for configuring specific services. Note that it is not possible to + * customize `FirebaseOptions` for Firebase Analytics which expects a static file named + * `GoogleServices-Info.plist` - https://github.com/firebase/firebase-ios-sdk/issues/230. + */ +- (instancetype)initWithGoogleAppID:(NSString *)googleAppID + GCMSenderID:(NSString *)GCMSenderID + NS_SWIFT_NAME(init(googleAppID:gcmSenderID:))NS_DESIGNATED_INITIALIZER; + +/** Unavailable. Please use `init(contentsOfFile:)` or `init(googleAppID:gcmSenderID:)` instead. */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h b/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h new file mode 100644 index 0000000..651edaf --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h @@ -0,0 +1,25 @@ +/* + * Copyright 2020 Google LLC + * + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** Returns the current version of Firebase. */ +NS_SWIFT_NAME(FirebaseVersion()) +NSString* FIRFirebaseVersion(void); + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FirebaseCore.h b/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FirebaseCore.h new file mode 100644 index 0000000..680d604 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FirebaseCore.h @@ -0,0 +1,21 @@ +/* + * 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 "FIRApp.h" +#import "FIRConfiguration.h" +#import "FIRLoggerLevel.h" +#import "FIROptions.h" +#import "FIRVersion.h" diff --git a/Pods/FirebaseCore/LICENSE b/Pods/FirebaseCore/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/Pods/FirebaseCore/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/Pods/FirebaseCore/README.md b/Pods/FirebaseCore/README.md new file mode 100644 index 0000000..85a23bd --- /dev/null +++ b/Pods/FirebaseCore/README.md @@ -0,0 +1,281 @@ +

+ + + + + + + + +
+ + + + + + +

+ +# Firebase Apple Open Source Development + +This repository contains all Apple platform Firebase SDK source except FirebaseAnalytics. + +Firebase is an app development platform with tools to help you build, grow and +monetize your app. More information about Firebase can be found on the +[official Firebase website](https://firebase.google.com). + +## Installation + +See the subsections below for details about the different installation methods. Where +available, it's recommended to install any libraries with a `Swift` suffix to get the +best experience when writing your app in Swift. +1. [Standard pod install](#standard-pod-install) +1. [Swift Package Manager](#swift-package-manager) +1. [Installing from the GitHub repo](#installing-from-github) +1. [Experimental Carthage](#carthage-ios-only) + +### Standard pod install + +Go to +[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup). + +### Swift Package Manager + +Instructions for [Swift Package Manager](https://swift.org/package-manager/) support can be +found at [SwiftPackageManager](SwiftPackageManager.md) Markdown file. + +### Installing from GitHub + +These instructions can be used to access the Firebase repo at other branches, +tags, or commits. + +#### Background + +See +[the Podfile Syntax Reference](https://guides.cocoapods.org/syntax/podfile.html#pod) +for instructions and options about overriding pod source locations. + +#### Accessing Firebase Source Snapshots + +All of the official releases are tagged in this repo and available via CocoaPods. To access a local +source snapshot or unreleased branch, use Podfile directives like the following: + +To access FirebaseFirestore via a branch: +```ruby +pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master' +pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master' +``` + +To access FirebaseMessaging via a checked out version of the firebase-ios-sdk repo do: + +```ruby +pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk' +pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk' +``` + +### Carthage (iOS only) + +Instructions for the experimental Carthage distribution are at +[Carthage](Carthage.md). + +### Using Firebase from a Framework or a library + +[Using Firebase from a Framework or a library](docs/firebase_in_libraries.md) + +## Development + +To develop Firebase software in this repository, ensure that you have at least +the following software: + + * Xcode 14.1 (or later) + +CocoaPods is still the canonical way to develop, but much of the repo now supports +development with Swift Package Manager. + +### CocoaPods + +Install + * CocoaPods 1.10.0 (or later) + * [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +```ruby +pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios +``` + +Note: If the CocoaPods cache is out of date, you may need to run +`pod repo update` before the `pod gen` command. + +Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for +those platforms. Since 10.2, Xcode does not properly handle multi-platform +CocoaPods workspaces. + +Firestore has a self contained Xcode project. See +[Firestore/README](Firestore/README.md) Markdown file. + +#### Development for Catalyst +* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios` +* Check the Mac box in the App-iOS Build Settings +* Sign the App in the Settings Signing & Capabilities tab +* Click Pods in the Project Manager +* Add Signing to the iOS host app and unit test targets +* Select the Unit-unit scheme +* Run it to build and test + +Alternatively disable signing in each target: +* Go to Build Settings tab +* Click `+` +* Select `Add User-Defined Setting` +* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO` + +### Swift Package Manager +* To enable test schemes: `./scripts/setup_spm_tests.sh` +* `open Package.swift` or double click `Package.swift` in Finder. +* Xcode will open the project + * Choose a scheme for a library to build or test suite to run + * Choose a target platform by selecting the run destination along with the scheme + +### Adding a New Firebase Pod + +See [AddNewPod](AddNewPod.md) Markdown file. + +### Managing Headers and Imports + +See [HeadersImports](HeadersImports.md) Markdown file. + +### Code Formatting + +To ensure that the code is formatted consistently, run the script +[./scripts/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/master/scripts/check.sh) +before creating a PR. + +GitHub Actions will verify that any code changes are done in a style compliant +way. Install `clang-format` and `mint`: + +```console +brew install clang-format@16 +brew install mint +``` + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +### Running Sample Apps +In order to run the sample apps and integration tests, you'll need a valid +`GoogleService-Info.plist` file. The Firebase Xcode project contains dummy plist +files without real values, but can be replaced with real plist files. To get your own +`GoogleService-Info.plist` files: + +1. Go to the [Firebase Console](https://console.firebase.google.com/) +2. Create a new Firebase project, if you don't already have one +3. For each sample app you want to test, create a new Firebase app with the sample app's bundle +identifier (e.g. `com.google.Database-Example`) +4. Download the resulting `GoogleService-Info.plist` and add it to the Xcode project. + +### Coverage Report Generation + +See [scripts/code_coverage_report/README](scripts/code_coverage_report/README.md) Markdown file. + +## Specific Component Instructions +See the sections below for any special instructions for those components. + +### Firebase Auth + +If you're doing specific Firebase Auth development, see +[the Auth Sample README](FirebaseAuth/Tests/Sample/README.md) for instructions about +building and running the FirebaseAuth pod along with various samples and tests. + +### Firebase Database + +The Firebase Database Integration tests can be run against a locally running Database Emulator +or against a production instance. + +To run against a local emulator instance, invoke `./scripts/run_database_emulator.sh start` before +running the integration test. + +To run against a production instance, provide a valid GoogleServices-Info.plist and copy it to +`FirebaseDatabase/Tests/Resources/GoogleService-Info.plist`. Your Security Rule must be set to +[public](https://firebase.google.com/docs/database/security/quickstart) while your tests are +running. + +### Firebase Performance Monitoring +If you're doing specific Firebase Performance Monitoring development, see +[the Performance README](FirebasePerformance/README.md) for instructions about building the SDK +and [the Performance TestApp README](FirebasePerformance/Tests/TestApp/README.md) for instructions about +integrating Performance with the dev test App. + +### Firebase Storage + +To run the Storage Integration tests, follow the instructions in +[StorageIntegration.swift](FirebaseStorage/Tests/Integration/StorageIntegration.swift). + +#### Push Notifications + +Push notifications can only be delivered to specially provisioned App IDs in the developer portal. +In order to actually test receiving push notifications, you will need to: + +1. Change the bundle identifier of the sample app to something you own in your Apple Developer +account, and enable that App ID for push notifications. +2. You'll also need to +[upload your APNs Provider Authentication Key or certificate to the +Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs) +at **Project Settings > Cloud Messaging > [Your Firebase App]**. +3. Ensure your iOS device is added to your Apple Developer portal as a test device. + +#### iOS Simulator + +The iOS Simulator cannot register for remote notifications, and will not receive push notifications. +In order to receive push notifications, you'll have to follow the steps above and run the app on a +physical device. + +## Building with Firebase on Apple platforms + +Firebase 8.9.0 introduced official beta support for macOS, Catalyst, and tvOS. watchOS continues +to be community supported. Thanks to community contributions for many of the multi-platform PRs. + +At this time, most of Firebase's products are available across Apple platforms. There are still +a few gaps, especially on watchOS. For details about the current support matrix, see +[this chart](https://firebase.google.com/docs/ios/learn-more#firebase_library_support_by_platform) +in Firebase's documentation. + +### watchOS +Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and +work on watchOS. See the [Independent Watch App Sample](Example/watchOSSample). + +Keep in mind that watchOS is not officially supported by Firebase. While we can catch basic unit +test issues with GitHub Actions, there may be some changes where the SDK no longer works as expected +on watchOS. If you encounter this, please +[file an issue](https://github.com/firebase/firebase-ios-sdk/issues). + +During app setup in the console, you may get to a step that mentions something like "Checking if the +app has communicated with our servers". This relies on Analytics and will not work on watchOS. +**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected. + +#### Additional Crashlytics Notes +* watchOS has limited support. Due to watchOS restrictions, mach exceptions and signal crashes are +not recorded. (Crashes in SwiftUI are generated as mach exceptions, so will not be recorded) + +## Combine +Thanks to contributions from the community, _FirebaseCombineSwift_ contains support for Apple's Combine +framework. This module is currently under development, and not yet supported for use in production +environments. Fore more details, please refer to the [docs](FirebaseCombineSwift/README.md). + +## Roadmap + +See [Roadmap](ROADMAP.md) for more about the Firebase Apple SDK Open Source +plans and directions. + +## Contributing + +See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase +Apple SDK. + +## License + +The contents of this repository are licensed under the +[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). + +Your use of Firebase is governed by the +[Terms of Service for Firebase Services](https://firebase.google.com/terms/). diff --git a/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/Heartbeat.swift b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/Heartbeat.swift new file mode 100644 index 0000000..ea92f6f --- /dev/null +++ b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/Heartbeat.swift @@ -0,0 +1,74 @@ +// Copyright 2021 Google LLC +// +// 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 Foundation + +/// An enumeration of time periods. +enum TimePeriod: Int, CaseIterable, Codable { + /// The raw value is the number of calendar days within each time period. + /// More types can be enabled in future iterations (i.e. `weekly = 7, monthly = 28`). + case daily = 1 + + /// The number of seconds in a given time period. + var timeInterval: TimeInterval { + Double(rawValue) * 86400 /* seconds in day */ + } +} + +/// A structure representing SDK usage. +struct Heartbeat: Codable, Equatable { + /// The version of the heartbeat. + private static let version: Int = 0 + + /// An anonymous string of information (i.e. user agent) to associate the heartbeat with. + let agent: String + + /// The date when the heartbeat was recorded. + let date: Date + + /// The heartbeat's model version. + let version: Int + + /// An array of `TimePeriod`s that the heartbeat is tagged with. See `TimePeriod`. + /// + /// Heartbeats represent anonymous data points that measure SDK usage in moving averages for + /// various time periods. Because a single heartbeat can help calculate moving averages for multiple + /// time periods, this property serves to capture all the time periods that the heartbeat can represent in + /// a moving average. + let timePeriods: [TimePeriod] + + /// Designated initializer. + /// - Parameters: + /// - agent: An anonymous string of information to associate the heartbeat with. + /// - date: The date when the heartbeat was recorded. + /// - version: The heartbeat's version. Defaults to the current version. + init(agent: String, + date: Date, + timePeriods: [TimePeriod] = [], + version: Int = version) { + self.agent = agent + self.date = date + self.timePeriods = timePeriods + self.version = version + } +} + +extension Heartbeat: HeartbeatsPayloadConvertible { + func makeHeartbeatsPayload() -> HeartbeatsPayload { + let userAgentPayloads = [ + HeartbeatsPayload.UserAgentPayload(agent: agent, dates: [date]), + ] + return HeartbeatsPayload(userAgentPayloads: userAgentPayloads) + } +} diff --git a/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatController.swift b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatController.swift new file mode 100644 index 0000000..fa3bb23 --- /dev/null +++ b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatController.swift @@ -0,0 +1,146 @@ +// Copyright 2021 Google LLC +// +// 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 Foundation + +/// An object that provides API to log and flush heartbeats from a synchronized storage container. +public final class HeartbeatController { + /// The thread-safe storage object to log and flush heartbeats from. + private let storage: HeartbeatStorageProtocol + /// The max capacity of heartbeats to store in storage. + private let heartbeatsStorageCapacity: Int = 30 + /// Current date provider. It is used for testability. + private let dateProvider: () -> Date + /// Used for standardizing dates for calendar-day comparision. + static let dateStandardizer: (Date) -> (Date) = { + var calendar = Calendar(identifier: .iso8601) + calendar.locale = Locale(identifier: "en_US_POSIX") + calendar.timeZone = TimeZone(secondsFromGMT: 0)! + return calendar.startOfDay(for:) + }() + + /// Public initializer. + /// - Parameter id: The `id` to associate this controller's heartbeat storage with. + public convenience init(id: String) { + self.init(id: id, dateProvider: Date.init) + } + + /// Convenience initializer. Mirrors the semantics of the public initializer with the added benefit of + /// injecting a custom date provider for improved testability. + /// - Parameters: + /// - id: The id to associate this controller's heartbeat storage with. + /// - dateProvider: A date provider. + convenience init(id: String, dateProvider: @escaping () -> Date) { + let storage = HeartbeatStorage.getInstance(id: id) + self.init(storage: storage, dateProvider: dateProvider) + } + + /// Designated initializer. + /// - Parameters: + /// - storage: A heartbeat storage container. + /// - dateProvider: A date provider. Defaults to providing the current date. + init(storage: HeartbeatStorageProtocol, + dateProvider: @escaping () -> Date = Date.init) { + self.storage = storage + self.dateProvider = { Self.dateStandardizer(dateProvider()) } + } + + /// Asynchronously logs a new heartbeat, if needed. + /// + /// - Note: This API is thread-safe. + /// - Parameter agent: The string agent (i.e. Firebase User Agent) to associate the logged heartbeat with. + public func log(_ agent: String) { + let date = dateProvider() + + storage.readAndWriteAsync { heartbeatsBundle in + var heartbeatsBundle = heartbeatsBundle ?? + HeartbeatsBundle(capacity: self.heartbeatsStorageCapacity) + + // Filter for the time periods where the last heartbeat to be logged for + // that time period was logged more than one time period (i.e. day) ago. + let timePeriods = heartbeatsBundle.lastAddedHeartbeatDates.filter { timePeriod, lastDate in + date.timeIntervalSince(lastDate) >= timePeriod.timeInterval + } + .map { timePeriod, _ in timePeriod } + + if !timePeriods.isEmpty { + // A heartbeat should only be logged if there is a time period(s) to + // associate it with. + let heartbeat = Heartbeat(agent: agent, date: date, timePeriods: timePeriods) + heartbeatsBundle.append(heartbeat) + } + + return heartbeatsBundle + } + } + + /// Synchronously flushes heartbeats from storage into a heartbeats payload. + /// + /// - Note: This API is thread-safe. + /// - Returns: The flushed heartbeats in the form of `HeartbeatsPayload`. + @discardableResult + public func flush() -> HeartbeatsPayload { + let resetTransform = { (heartbeatsBundle: HeartbeatsBundle?) -> HeartbeatsBundle? in + guard let oldHeartbeatsBundle = heartbeatsBundle else { + return nil // Storage was empty. + } + // The new value that's stored will use the old's cache to prevent the + // logging of duplicates after flushing. + return HeartbeatsBundle( + capacity: self.heartbeatsStorageCapacity, + cache: oldHeartbeatsBundle.lastAddedHeartbeatDates + ) + } + + do { + // Synchronously gets and returns the stored heartbeats, resetting storage + // using the given transform. + let heartbeatsBundle = try storage.getAndSet(using: resetTransform) + // If no heartbeats bundle was stored, return an empty payload. + return heartbeatsBundle?.makeHeartbeatsPayload() ?? HeartbeatsPayload.emptyPayload + } catch { + // If the operation throws, assume no heartbeat(s) were retrieved or set. + return HeartbeatsPayload.emptyPayload + } + } + + /// Synchronously flushes the heartbeat for today. + /// + /// If no heartbeat was logged today, the returned payload is empty. + /// + /// - Note: This API is thread-safe. + /// - Returns: A heartbeats payload for the flushed heartbeat. + @discardableResult + public func flushHeartbeatFromToday() -> HeartbeatsPayload { + let todaysDate = dateProvider() + var todaysHeartbeat: Heartbeat? + + storage.readAndWriteSync { heartbeatsBundle in + guard var heartbeatsBundle = heartbeatsBundle else { + return nil // Storage was empty. + } + + todaysHeartbeat = heartbeatsBundle.removeHeartbeat(from: todaysDate) + + return heartbeatsBundle + } + + // Note that `todaysHeartbeat` is updated in the above read/write block. + if todaysHeartbeat != nil { + return todaysHeartbeat!.makeHeartbeatsPayload() + } else { + return HeartbeatsPayload.emptyPayload + } + } +} diff --git a/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatLoggingTestUtils.swift b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatLoggingTestUtils.swift new file mode 100644 index 0000000..96dbcf8 --- /dev/null +++ b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatLoggingTestUtils.swift @@ -0,0 +1,140 @@ +// Copyright 2021 Google LLC +// +// 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. + +#if DEBUG + + import Foundation + + /// A utility class intended to be used only in testing contexts. + @objc(FIRHeartbeatLoggingTestUtils) + @objcMembers + public class HeartbeatLoggingTestUtils: NSObject { + /// This should mirror the `Constants` enum in the `HeartbeatLogging` module. + /// See `HeartbeatLogging/Sources/StorageFactory.swift`. + public enum Constants { + /// The name of the file system directory where heartbeat data is stored. + public static let heartbeatFileStorageDirectoryPath = "google-heartbeat-storage" + /// The name of the user defaults suite where heartbeat data is stored. + public static let heartbeatUserDefaultsSuiteName = "com.google.heartbeat.storage" + } + + public static var dateFormatter: DateFormatter { + HeartbeatsPayload.dateFormatter + } + + public static var emptyHeartbeatsPayload: _ObjC_HeartbeatsPayload { + let literalData = """ + { + "version": 2, + "heartbeats": [] + } + """ + .data(using: .utf8)! + + let decoder = JSONDecoder() + decoder.dateDecodingStrategy = .formatted(HeartbeatsPayload.dateFormatter) + + let heartbeatsPayload = try! decoder.decode(HeartbeatsPayload.self, from: literalData) + return _ObjC_HeartbeatsPayload(heartbeatsPayload) + } + + public static var nonEmptyHeartbeatsPayload: _ObjC_HeartbeatsPayload { + let literalData = """ + { + "version": 2, + "heartbeats": [ + { + "agent": "dummy_agent_1", + "dates": ["2021-11-01", "2021-11-02"] + }, + { + "agent": "dummy_agent_2", + "dates": ["2021-11-03"] + } + ] + } + """ + .data(using: .utf8)! + + let decoder = JSONDecoder() + decoder.dateDecodingStrategy = .formatted(HeartbeatsPayload.dateFormatter) + + let heartbeatsPayload = try! decoder.decode(HeartbeatsPayload.self, from: literalData) + return _ObjC_HeartbeatsPayload(heartbeatsPayload) + } + + @objc(assertEncodedPayloadString:isEqualToLiteralString:withError:) + public static func assertEqualPayloadStrings(_ encoded: String, _ literal: String) throws { + var encodedData = Data(base64URLEncoded: encoded)! + if encodedData.count > 0 { + encodedData = try! encodedData.unzipped() + } + + let literalData = literal.data(using: .utf8)! + + let decoder = JSONDecoder() + decoder.dateDecodingStrategy = .formatted(HeartbeatsPayload.dateFormatter) + + let payloadFromEncoded = try? decoder.decode(HeartbeatsPayload.self, from: encodedData) + + let payloadFromLiteral = try? decoder.decode(HeartbeatsPayload.self, from: literalData) + + let encoder = JSONEncoder() + encoder.dateEncodingStrategy = .formatted(HeartbeatsPayload.dateFormatter) + encoder.outputFormatting = .prettyPrinted + + let payloadDataFromEncoded = try! encoder.encode(payloadFromEncoded) + let payloadDataFromLiteral = try! encoder.encode(payloadFromLiteral) + + assert( + payloadFromEncoded == payloadFromLiteral, + """ + Mismatched payloads! + + Payload 1: + \(String(data: payloadDataFromEncoded, encoding: .utf8) ?? "") + + Payload 2: + \(String(data: payloadDataFromLiteral, encoding: .utf8) ?? "") + + """ + ) + } + + /// Removes all underlying storage containers used by the module. + /// - Throws: An error if the storage container could not be removed. + public static func removeUnderlyingHeartbeatStorageContainers() throws { + #if os(tvOS) + UserDefaults().removePersistentDomain(forName: Constants.heartbeatUserDefaultsSuiteName) + #else + + let applicationSupportDirectory = FileManager.default + .urls(for: .applicationSupportDirectory, in: .userDomainMask).first! + + let heartbeatsDirectoryURL = applicationSupportDirectory + .appendingPathComponent( + Constants.heartbeatFileStorageDirectoryPath, isDirectory: true + ) + do { + try FileManager.default.removeItem(at: heartbeatsDirectoryURL) + } catch CocoaError.fileNoSuchFile { + // Do nothing. + } catch { + throw error + } + #endif // os(tvOS) + } + } + +#endif // ENABLE_FIREBASE_CORE_INTERNAL_TESTING_UTILS diff --git a/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatStorage.swift b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatStorage.swift new file mode 100644 index 0000000..742bcb5 --- /dev/null +++ b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatStorage.swift @@ -0,0 +1,178 @@ +// Copyright 2021 Google LLC +// +// 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 Foundation + +/// A type that can perform atomic operations using block-based transformations. +protocol HeartbeatStorageProtocol { + func readAndWriteSync(using transform: (HeartbeatsBundle?) -> HeartbeatsBundle?) + func readAndWriteAsync(using transform: @escaping (HeartbeatsBundle?) -> HeartbeatsBundle?) + func getAndSet(using transform: (HeartbeatsBundle?) -> HeartbeatsBundle?) throws + -> HeartbeatsBundle? +} + +/// Thread-safe storage object designed for transforming heartbeat data that is persisted to disk. +final class HeartbeatStorage: HeartbeatStorageProtocol { + /// The identifier used to differentiate instances. + private let id: String + /// The underlying storage container to read from and write to. + private let storage: Storage + /// The encoder used for encoding heartbeat data. + private let encoder: JSONEncoder = .init() + /// The decoder used for decoding heartbeat data. + private let decoder: JSONDecoder = .init() + /// The queue for synchronizing storage operations. + private let queue: DispatchQueue + + /// Designated initializer. + /// - Parameters: + /// - id: A string identifer. + /// - storage: The underlying storage container where heartbeat data is stored. + init(id: String, + storage: Storage) { + self.id = id + self.storage = storage + queue = DispatchQueue(label: "com.heartbeat.storage.\(id)") + } + + // MARK: - Instance Management + + /// Statically allocated cache of `HeartbeatStorage` instances keyed by string IDs. + private static var cachedInstances: [String: WeakContainer] = [:] + + /// Gets an existing `HeartbeatStorage` instance with the given `id` if one exists. Otherwise, + /// makes a new instance with the given `id`. + /// + /// - Parameter id: A string identifier. + /// - Returns: A `HeartbeatStorage` instance. + static func getInstance(id: String) -> HeartbeatStorage { + if let cachedInstance = cachedInstances[id]?.object { + return cachedInstance + } else { + let newInstance = HeartbeatStorage.makeHeartbeatStorage(id: id) + cachedInstances[id] = WeakContainer(object: newInstance) + return newInstance + } + } + + /// Makes a `HeartbeatStorage` instance using a given `String` identifier. + /// + /// The created persistent storage object is platform dependent. For tvOS, user defaults + /// is used as the underlying storage container due to system storage limits. For all other platforms, + /// the file system is used. + /// + /// - Parameter id: A `String` identifier used to create the `HeartbeatStorage`. + /// - Returns: A `HeartbeatStorage` instance. + private static func makeHeartbeatStorage(id: String) -> HeartbeatStorage { + #if os(tvOS) + let storage = UserDefaultsStorage.makeStorage(id: id) + #else + let storage = FileStorage.makeStorage(id: id) + #endif // os(tvOS) + return HeartbeatStorage(id: id, storage: storage) + } + + deinit { + // Removes the instance if it was cached. + Self.cachedInstances.removeValue(forKey: id) + } + + // MARK: - HeartbeatStorageProtocol + + /// Synchronously reads from and writes to storage using the given transform block. + /// - Parameter transform: A block to transform the currently stored heartbeats bundle to a new + /// heartbeats bundle value. + func readAndWriteSync(using transform: (HeartbeatsBundle?) -> HeartbeatsBundle?) { + queue.sync { + let oldHeartbeatsBundle = try? load(from: storage) + let newHeartbeatsBundle = transform(oldHeartbeatsBundle) + try? save(newHeartbeatsBundle, to: storage) + } + } + + /// Asynchronously reads from and writes to storage using the given transform block. + /// - Parameter transform: A block to transform the currently stored heartbeats bundle to a new + /// heartbeats bundle value. + func readAndWriteAsync(using transform: @escaping (HeartbeatsBundle?) -> HeartbeatsBundle?) { + queue.async { [self] in + let oldHeartbeatsBundle = try? load(from: storage) + let newHeartbeatsBundle = transform(oldHeartbeatsBundle) + try? save(newHeartbeatsBundle, to: storage) + } + } + + /// Synchronously gets the current heartbeat data from storage and resets the storage using the + /// given transform block. + /// + /// This API is like any `getAndSet`-style API in that it gets (and returns) the current value and uses + /// a block to transform the current value (or, soon-to-be old value) to a new value. + /// + /// - Parameter transform: An optional block used to reset the currently stored heartbeat. + /// - Returns: The heartbeat data that was stored (before the `transform` was applied). + @discardableResult + func getAndSet(using transform: (HeartbeatsBundle?) -> HeartbeatsBundle?) throws + -> HeartbeatsBundle? { + let heartbeatsBundle: HeartbeatsBundle? = try queue.sync { + let oldHeartbeatsBundle = try? load(from: storage) + let newHeartbeatsBundle = transform(oldHeartbeatsBundle) + try save(newHeartbeatsBundle, to: storage) + return oldHeartbeatsBundle + } + return heartbeatsBundle + } + + /// Loads and decodes the stored heartbeats bundle from a given storage object. + /// - Parameter storage: The storage container to read from. + /// - Returns: The decoded `HeartbeatsBundle` loaded from storage; `nil` if storage is empty. + /// - Throws: An error if storage could not be read or the data could not be decoded. + private func load(from storage: Storage) throws -> HeartbeatsBundle? { + let data = try storage.read() + if data.isEmpty { + return nil + } else { + let heartbeatData = try data.decoded(using: decoder) as HeartbeatsBundle + return heartbeatData + } + } + + /// Saves the encoding of the given value to the given storage container. + /// - Parameters: + /// - heartbeatsBundle: The heartbeats bundle to encode and save. + /// - storage: The storage container to write to. + private func save(_ heartbeatsBundle: HeartbeatsBundle?, to storage: Storage) throws { + if let heartbeatsBundle = heartbeatsBundle { + let data = try heartbeatsBundle.encoded(using: encoder) + try storage.write(data) + } else { + try storage.write(nil) + } + } +} + +private extension Data { + /// Returns the decoded value of this `Data` using the given decoder. Defaults to `JSONDecoder`. + /// - Returns: The decoded value. + func decoded(using decoder: JSONDecoder = .init()) throws -> T where T: Decodable { + try decoder.decode(T.self, from: self) + } +} + +private extension Encodable { + /// Returns the `Data` encoding of this value using the given encoder. + /// - Parameter encoder: An encoder used to encode the value. Defaults to `JSONEncoder`. + /// - Returns: The data encoding of the value. + func encoded(using encoder: JSONEncoder = .init()) throws -> Data { + try encoder.encode(self) + } +} diff --git a/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatsBundle.swift b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatsBundle.swift new file mode 100644 index 0000000..ef84f7c --- /dev/null +++ b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatsBundle.swift @@ -0,0 +1,147 @@ +// Copyright 2021 Google LLC +// +// 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 Foundation + +/// A type that can be converted to a `HeartbeatsPayload`. +protocol HeartbeatsPayloadConvertible { + func makeHeartbeatsPayload() -> HeartbeatsPayload +} + +/// A codable collection of heartbeats that has a fixed capacity and optimizations for storing heartbeats of +/// multiple time periods. +struct HeartbeatsBundle: Codable, HeartbeatsPayloadConvertible { + /// The maximum number of heartbeats that can be stored in the buffer. + let capacity: Int + /// A cache used for keeping track of the last heartbeat date recorded for a given time period. + /// + /// The cache contains the last added date for each time period. The reason only the date is cached is + /// because it's the only piece of information that should be used by clients to determine whether or not + /// to append a new heartbeat. + private(set) var lastAddedHeartbeatDates: [TimePeriod: Date] + /// A ring buffer of heartbeats. + private var buffer: RingBuffer + + /// A default cache provider that provides a dictionary of all time periods mapping to a default date. + static var cacheProvider: () -> [TimePeriod: Date] { + let timePeriodsAndDates = TimePeriod.allCases.map { ($0, Date.distantPast) } + return { Dictionary(uniqueKeysWithValues: timePeriodsAndDates) } + } + + /// Designated initializer. + /// - Parameters: + /// - capacity: The heartbeat capacity of the inititialized collection. + /// - cache: A cache of time periods mapping to dates. Defaults to using static `cacheProvider`. + init(capacity: Int, + cache: [TimePeriod: Date] = cacheProvider()) { + buffer = RingBuffer(capacity: capacity) + self.capacity = capacity + lastAddedHeartbeatDates = cache + } + + /// Appends a heartbeat to this collection. + /// - Parameter heartbeat: The heartbeat to append. + mutating func append(_ heartbeat: Heartbeat) { + guard capacity > 0 else { + return // Do not append if capacity is non-positive. + } + + do { + // Push the heartbeat to the back of the buffer. + if let overwrittenHeartbeat = try buffer.push(heartbeat) { + // If a heartbeat was overwritten, update the cache to ensure it's date + // is removed. + lastAddedHeartbeatDates = lastAddedHeartbeatDates.mapValues { date in + overwrittenHeartbeat.date == date ? .distantPast : date + } + } + + // Update cache with the new heartbeat's date. + heartbeat.timePeriods.forEach { + lastAddedHeartbeatDates[$0] = heartbeat.date + } + + } catch let error as RingBuffer.Error { + // A ring buffer error occurred while pushing to the buffer so the bundle + // is reset. + self = HeartbeatsBundle(capacity: capacity) + + // Create a diagnostic heartbeat to capture the failure and add it to the + // buffer. The failure is added as a key/value pair to the agent string. + // Given that the ring buffer has been reset, it is not expected for the + // second push attempt to fail. + let errorDescription = error.errorDescription.replacingOccurrences(of: " ", with: "-") + let diagnosticHeartbeat = Heartbeat( + agent: "\(heartbeat.agent) error/\(errorDescription)", + date: heartbeat.date, + timePeriods: heartbeat.timePeriods + ) + + let secondPushAttempt = Result { + try buffer.push(diagnosticHeartbeat) + } + + if case .success = secondPushAttempt { + // Update cache with the new heartbeat's date. + diagnosticHeartbeat.timePeriods.forEach { + lastAddedHeartbeatDates[$0] = diagnosticHeartbeat.date + } + } + } catch { + // Ignore other error. + } + } + + /// Removes the heartbeat associated with the given date. + /// - Parameter date: The date of the heartbeat needing removal. + /// - Returns: The heartbeat that was removed or `nil` if there was no heartbeat to remove. + @discardableResult + mutating func removeHeartbeat(from date: Date) -> Heartbeat? { + var removedHeartbeat: Heartbeat? + + var poppedHeartbeats: [Heartbeat] = [] + + while let poppedHeartbeat = buffer.pop() { + if poppedHeartbeat.date == date { + removedHeartbeat = poppedHeartbeat + break + } + poppedHeartbeats.append(poppedHeartbeat) + } + + poppedHeartbeats.reversed().forEach { + do { + try buffer.push($0) + } catch { + // Ignore error. + } + } + + return removedHeartbeat + } + + /// Makes and returns a `HeartbeatsPayload` from this heartbeats bundle. + /// - Returns: A heartbeats payload. + func makeHeartbeatsPayload() -> HeartbeatsPayload { + let agentAndDates = buffer.map { heartbeat in + (heartbeat.agent, [heartbeat.date]) + } + + let userAgentPayloads = [String: [Date]](agentAndDates, uniquingKeysWith: +) + .map(HeartbeatsPayload.UserAgentPayload.init) + .sorted { $0.agent < $1.agent } // Sort payloads by user agent. + + return HeartbeatsPayload(userAgentPayloads: userAgentPayloads) + } +} diff --git a/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatsPayload.swift b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatsPayload.swift new file mode 100644 index 0000000..8e18bde --- /dev/null +++ b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatsPayload.swift @@ -0,0 +1,176 @@ +// Copyright 2021 Google LLC +// +// 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 Foundation + +#if SWIFT_PACKAGE + import GoogleUtilities_NSData +#else + import GoogleUtilities +#endif // SWIFT_PACKAGE + +/// A type that provides a string representation for use in an HTTP header. +public protocol HTTPHeaderRepresentable { + func headerValue() -> String +} + +/// A value type representing a payload of heartbeat data intended for sending in network requests. +/// +/// This type's structure is optimized for type-safe encoding into a HTTP payload format. +/// The current encoding format for the payload's current version is: +/// +/// { +/// "version": 2, +/// "heartbeats": [ +/// { +/// "agent": "dummy_agent_1", +/// "dates": ["2021-11-01", "2021-11-02"] +/// }, +/// { +/// "agent": "dummy_agent_2", +/// "dates": ["2021-11-03"] +/// } +/// ] +/// } +/// +public struct HeartbeatsPayload: Codable { + /// The version of the payload. See go/firebase-apple-heartbeats for details regarding current version. + static let version: Int = 2 + + /// A payload component composed of a user agent and array of dates (heartbeats). + struct UserAgentPayload: Codable { + /// An anonymous agent string. + let agent: String + /// An array of dates where each date represents a "heartbeat". + let dates: [Date] + } + + /// An array of user agent payloads. + let userAgentPayloads: [UserAgentPayload] + /// The version of the payload structure. + let version: Int + + /// Alternative keys for properties so encoding follows platform-wide payload structure. + enum CodingKeys: String, CodingKey { + case userAgentPayloads = "heartbeats" + case version + } + + /// Designated initializer. + /// - Parameters: + /// - userAgentPayloads: An array of payloads containing heartbeat data corresponding to a + /// given user agent. + /// - version: A version of the payload. Defaults to the static default. + init(userAgentPayloads: [UserAgentPayload] = [], version: Int = version) { + self.userAgentPayloads = userAgentPayloads + self.version = version + } + + /// A Boolean value indicating whether the payload is empty. + public var isEmpty: Bool { + userAgentPayloads.isEmpty + } +} + +// MARK: - HTTPHeaderRepresentable + +extension HeartbeatsPayload: HTTPHeaderRepresentable { + /// Returns a processed payload string intended for use in a HTTP header. + /// - Returns: A string value from the heartbeats payload. + public func headerValue() -> String { + let encoder = JSONEncoder() + encoder.dateEncodingStrategy = .formatted(Self.dateFormatter) + + guard let data = try? encoder.encode(self) else { + // If encoding fails, fall back to encoding with an empty payload. + return Self.emptyPayload.headerValue() + } + + do { + let gzippedData = try data.zipped() + return gzippedData.base64URLEncodedString() + } catch { + // If gzipping fails, fall back to encoding with base64URL. + return data.base64URLEncodedString() + } + } +} + +// MARK: - Static Defaults + +extension HeartbeatsPayload { + /// Convenience instance that represents an empty payload. + static let emptyPayload = HeartbeatsPayload() + + /// A default date formatter that uses `YYYY-MM-dd` format. + public static let dateFormatter: DateFormatter = { + let formatter = DateFormatter() + formatter.dateFormat = "YYYY-MM-dd" + formatter.locale = Locale(identifier: "en_US_POSIX") + formatter.timeZone = TimeZone(secondsFromGMT: 0) + return formatter + }() +} + +// MARK: - Equatable + +extension HeartbeatsPayload: Equatable {} +extension HeartbeatsPayload.UserAgentPayload: Equatable {} + +// MARK: - Data + +public extension Data { + /// Returns a Base-64 URL-safe encoded string. + /// + /// - parameter options: The options to use for the encoding. Default value is `[]`. + /// - returns: The Base-64 URL-safe encoded string. + func base64URLEncodedString(options: Data.Base64EncodingOptions = []) -> String { + base64EncodedString() + .replacingOccurrences(of: "/", with: "_") + .replacingOccurrences(of: "+", with: "-") + .replacingOccurrences(of: "=", with: "") + } + + /// Initialize a `Data` from a Base-64 URL encoded String using the given options. + /// + /// Returns nil when the input is not recognized as valid Base-64. + /// - parameter base64URLString: The string to parse. + /// - parameter options: Encoding options. Default value is `[]`. + init?(base64URLEncoded base64URLString: String, options: Data.Base64DecodingOptions = []) { + var base64Encoded = base64URLString + .replacingOccurrences(of: "_", with: "/") + .replacingOccurrences(of: "-", with: "+") + + // Pad the string with "=" signs until the string's length is a multiple of 4. + while !base64Encoded.count.isMultiple(of: 4) { + base64Encoded.append("=") + } + + self.init(base64Encoded: base64Encoded, options: options) + } + + /// Returns the compressed data. + /// - Returns: The compressed data. + /// - Throws: An error if compression failed. + func zipped() throws -> Data { + try NSData.gul_data(byGzippingData: self) + } + + /// Returns the uncompressed data. + /// - Returns: The decompressed data. + /// - Throws: An error if decompression failed. + func unzipped() throws -> Data { + try NSData.gul_data(byInflatingGzippedData: self) + } +} diff --git a/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/RingBuffer.swift b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/RingBuffer.swift new file mode 100644 index 0000000..2b9565c --- /dev/null +++ b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/RingBuffer.swift @@ -0,0 +1,109 @@ +// Copyright 2021 Google LLC +// +// 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 Foundation + +/// A generic circular queue structure. +struct RingBuffer: Sequence { + /// An array of heartbeats treated as a circular queue and intialized with a fixed capacity. + private var circularQueue: [Element?] + /// The current "tail" and insert point for the `circularQueue`. + private var tailIndex: Array.Index + + /// Error types for `RingBuffer` operations. + enum Error: LocalizedError { + case outOfBoundsPush(pushIndex: Array.Index, endIndex: Array.Index) + + var errorDescription: String { + switch self { + case let .outOfBoundsPush(pushIndex, endIndex): + return "Out-of-bounds push at index \(pushIndex) to ring buffer with" + + "end index of \(endIndex)." + } + } + } + + /// Designated initializer. + /// - Parameter capacity: An `Int` representing the capacity. + init(capacity: Int) { + circularQueue = Array(repeating: nil, count: capacity) + tailIndex = circularQueue.startIndex + } + + /// Pushes an element to the back of the buffer, returning the element (`Element?`) that was overwritten. + /// - Parameter element: The element to push to the back of the buffer. + /// - Returns: The element that was overwritten or `nil` if nothing was overwritten. + /// - Complexity: O(1) + @discardableResult + mutating func push(_ element: Element) throws -> Element? { + guard circularQueue.count > 0 else { + // Do not push if `circularQueue` is a fixed empty array. + return nil + } + + guard circularQueue.indices.contains(tailIndex) else { + // We have somehow entered an invalid state (#10025). + throw Self.Error.outOfBoundsPush( + pushIndex: tailIndex, + endIndex: circularQueue.endIndex + ) + } + + let replaced = circularQueue[tailIndex] + circularQueue[tailIndex] = element + + // Increment index, wrapping around to the start if needed. + tailIndex += 1 + if tailIndex >= circularQueue.endIndex { + tailIndex = circularQueue.startIndex + } + + return replaced + } + + /// Pops an element from the back of the buffer, returning the element (`Element?`) that was popped. + /// - Returns: The element that was popped or `nil` if there was no element to pop. + /// - Complexity: O(1) + @discardableResult + mutating func pop() -> Element? { + guard circularQueue.count > 0 else { + // Do not pop if `circularQueue` is a fixed empty array. + return nil + } + + // Decrement index, wrapping around to the back if needed. + tailIndex -= 1 + if tailIndex < circularQueue.startIndex { + tailIndex = circularQueue.endIndex - 1 + } + + guard let popped = circularQueue[tailIndex] else { + return nil // There is no element to pop. + } + + circularQueue[tailIndex] = nil + + return popped + } + + func makeIterator() -> IndexingIterator<[Element]> { + circularQueue + .compactMap { $0 } // Remove `nil` elements. + .makeIterator() + } +} + +// MARK: - Codable + +extension RingBuffer: Codable where Element: Codable {} diff --git a/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/Storage.swift b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/Storage.swift new file mode 100644 index 0000000..2b2959c --- /dev/null +++ b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/Storage.swift @@ -0,0 +1,144 @@ +// Copyright 2021 Google LLC +// +// 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 Foundation + +/// A type that reads from and writes to an underlying storage container. +protocol Storage { + /// Reads and returns the data stored by this storage type. + /// - Returns: The data read from storage. + /// - Throws: An error if the read failed. + func read() throws -> Data + + /// Writes the given data to this storage type. + /// - Throws: An error if the write failed. + func write(_ data: Data?) throws +} + +/// Error types for `Storage` operations. +enum StorageError: Error { + case readError + case writeError +} + +// MARK: - FileStorage + +/// A object that provides API for reading and writing to a file system resource. +final class FileStorage: Storage { + /// A file system URL to the underlying file resource. + private let url: URL + /// The file manager used to perform file system operations. + private let fileManager: FileManager + + /// Designated initializer. + /// - Parameters: + /// - url: A file system URL for the underlying file resource. + /// - fileManager: A file manager. Defaults to `default` manager. + init(url: URL, fileManager: FileManager = .default) { + self.url = url + self.fileManager = fileManager + } + + /// Reads and returns the data from this object's associated file resource. + /// + /// - Returns: The data stored on disk. + /// - Throws: An error if reading the contents of the file resource fails (i.e. file doesn't exist). + func read() throws -> Data { + do { + return try Data(contentsOf: url) + } catch { + throw StorageError.readError + } + } + + /// Writes the given data to this object's associated file resource. + /// + /// When the given `data` is `nil`, this object's associated file resource is emptied. + /// + /// - Parameter data: The `Data?` to write to this object's associated file resource. + func write(_ data: Data?) throws { + do { + try createDirectories(in: url.deletingLastPathComponent()) + if let data = data { + try data.write(to: url, options: .atomic) + } else { + let emptyData = Data() + try emptyData.write(to: url, options: .atomic) + } + } catch { + throw StorageError.writeError + } + } + + /// Creates all directories in the given file system URL. + /// + /// If the directory for the given URL already exists, the error is ignored because the directory + /// has already been created. + /// + /// - Parameter url: The URL to create directories in. + private func createDirectories(in url: URL) throws { + do { + try fileManager.createDirectory( + at: url, + withIntermediateDirectories: true + ) + } catch CocoaError.fileWriteFileExists { + // Directory already exists. + } catch { throw error } + } +} + +// MARK: - UserDefaultsStorage + +/// A object that provides API for reading and writing to a user defaults resource. +final class UserDefaultsStorage: Storage { + /// The underlying defaults container. + private let defaults: UserDefaults + /// The key mapping to the object's associated resource in `defaults`. + private let key: String + + /// Designated initializer. + /// - Parameters: + /// - defaults: The defaults container. + /// - key: The key mapping to the value stored in the defaults container. + init(defaults: UserDefaults, key: String) { + self.defaults = defaults + self.key = key + } + + /// Reads and returns the data from this object's associated defaults resource. + /// + /// - Returns: The data stored on disk. + /// - Throws: An error if no data has been stored to the defaults container. + func read() throws -> Data { + if let data = defaults.data(forKey: key) { + return data + } else { + throw StorageError.readError + } + } + + /// Writes the given data to this object's associated defaults. + /// + /// When the given `data` is `nil`, the associated default is removed. + /// + /// - Parameter data: The `Data?` to write to this object's associated defaults. + func write(_ data: Data?) throws { + if let data = data { + defaults.set(data, forKey: key) + } else { + defaults.removeObject(forKey: key) + } + } +} diff --git a/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/StorageFactory.swift b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/StorageFactory.swift new file mode 100644 index 0000000..6552a31 --- /dev/null +++ b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/StorageFactory.swift @@ -0,0 +1,66 @@ +// Copyright 2021 Google LLC +// +// 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 Foundation + +private enum Constants { + /// The name of the file system directory where heartbeat data is stored. + static let heartbeatFileStorageDirectoryPath = "google-heartbeat-storage" + /// The name of the user defaults suite where heartbeat data is stored. + static let heartbeatUserDefaultsSuiteName = "com.google.heartbeat.storage" +} + +/// A factory type for `Storage`. +protocol StorageFactory { + static func makeStorage(id: String) -> Storage +} + +// MARK: - FileStorage + StorageFactory + +extension FileStorage: StorageFactory { + static func makeStorage(id: String) -> Storage { + let rootDirectory = FileManager.default.applicationSupportDirectory + let heartbeatDirectoryPath = Constants.heartbeatFileStorageDirectoryPath + + // Sanitize the `id` so the heartbeat file name does not include a ":". + let sanitizedID = id.replacingOccurrences(of: ":", with: "_") + let heartbeatFilePath = "heartbeats-\(sanitizedID)" + + let storageURL = rootDirectory + .appendingPathComponent(heartbeatDirectoryPath, isDirectory: true) + .appendingPathComponent(heartbeatFilePath, isDirectory: false) + + return FileStorage(url: storageURL) + } +} + +extension FileManager { + var applicationSupportDirectory: URL { + urls(for: .applicationSupportDirectory, in: .userDomainMask).first! + } +} + +// MARK: - UserDefaultsStorage + StorageFactory + +extension UserDefaultsStorage: StorageFactory { + static func makeStorage(id: String) -> Storage { + let suiteName = Constants.heartbeatUserDefaultsSuiteName + // It's safe to force unwrap the below defaults instance because the + // initializer only returns `nil` when the bundle id or `globalDomain` + // is passed in as the `suiteName`. + let defaults = UserDefaults(suiteName: suiteName)! + let key = "heartbeats-\(id)" + return UserDefaultsStorage(defaults: defaults, key: key) + } +} diff --git a/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/WeakContainer.swift b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/WeakContainer.swift new file mode 100644 index 0000000..f1dd177 --- /dev/null +++ b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/WeakContainer.swift @@ -0,0 +1,20 @@ +// Copyright 2021 Google LLC +// +// 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 Foundation + +/// A structure used to weakly box reference types. +struct WeakContainer { + weak var object: Object? +} diff --git a/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/_ObjC_HeartbeatController.swift b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/_ObjC_HeartbeatController.swift new file mode 100644 index 0000000..a00c283 --- /dev/null +++ b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/_ObjC_HeartbeatController.swift @@ -0,0 +1,57 @@ +// Copyright 2021 Google LLC +// +// 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 Foundation + +/// An object that provides API to log and flush heartbeats from a synchronized storage container. +@objc(FIRHeartbeatController) +@objcMembers +public class _ObjC_HeartbeatController: NSObject { + /// The underlying Swift object. + private let heartbeatController: HeartbeatController + + /// Public initializer. + /// - Parameter id: The `id` to associate this controller's heartbeat storage with. + public init(id: String) { + heartbeatController = HeartbeatController(id: id) + } + + /// Asynchronously logs a new heartbeat, if needed. + /// + /// - Note: This API is thread-safe. + /// - Parameter agent: The string agent (i.e. Firebase User Agent) to associate the logged heartbeat with. + public func log(_ agent: String) { + heartbeatController.log(agent) + } + + /// Synchronously flushes heartbeats from storage into a heartbeats payload. + /// + /// - Note: This API is thread-safe. + /// - Returns: A heartbeats payload for the flushed heartbeat(s). + public func flush() -> _ObjC_HeartbeatsPayload { + let heartbeatsPayload = heartbeatController.flush() + return _ObjC_HeartbeatsPayload(heartbeatsPayload) + } + + /// Synchronously flushes the heartbeat for today. + /// + /// If no heartbeat was logged today, the returned payload is empty. + /// + /// - Note: This API is thread-safe. + /// - Returns: A heartbeats payload for the flushed heartbeat. + public func flushHeartbeatFromToday() -> _ObjC_HeartbeatsPayload { + let heartbeatsPayload = heartbeatController.flushHeartbeatFromToday() + return _ObjC_HeartbeatsPayload(heartbeatsPayload) + } +} diff --git a/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/_ObjC_HeartbeatsPayload.swift b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/_ObjC_HeartbeatsPayload.swift new file mode 100644 index 0000000..fdf00ed --- /dev/null +++ b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/_ObjC_HeartbeatsPayload.swift @@ -0,0 +1,39 @@ +// Copyright 2021 Google LLC +// +// 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 Foundation + +/// A model object representing a payload of heartbeat data intended for sending in network requests. +@objc(FIRHeartbeatsPayload) +public class _ObjC_HeartbeatsPayload: NSObject, HTTPHeaderRepresentable { + /// The underlying Swift structure. + private let heartbeatsPayload: HeartbeatsPayload + + /// Designated initializer. + /// - Parameter heartbeatsPayload: A native-Swift heartbeats payload. + public init(_ heartbeatsPayload: HeartbeatsPayload) { + self.heartbeatsPayload = heartbeatsPayload + } + + /// Returns a processed payload string intended for use in a HTTP header. + /// - Returns: A string value from the heartbeats payload. + @objc public func headerValue() -> String { + heartbeatsPayload.headerValue() + } + + /// A Boolean value indicating whether the payload is empty. + @objc public var isEmpty: Bool { + heartbeatsPayload.isEmpty + } +} diff --git a/Pods/FirebaseCoreInternal/LICENSE b/Pods/FirebaseCoreInternal/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/Pods/FirebaseCoreInternal/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/Pods/FirebaseCoreInternal/README.md b/Pods/FirebaseCoreInternal/README.md new file mode 100644 index 0000000..85a23bd --- /dev/null +++ b/Pods/FirebaseCoreInternal/README.md @@ -0,0 +1,281 @@ +

+ + + + + + + + +
+ + + + + + +

+ +# Firebase Apple Open Source Development + +This repository contains all Apple platform Firebase SDK source except FirebaseAnalytics. + +Firebase is an app development platform with tools to help you build, grow and +monetize your app. More information about Firebase can be found on the +[official Firebase website](https://firebase.google.com). + +## Installation + +See the subsections below for details about the different installation methods. Where +available, it's recommended to install any libraries with a `Swift` suffix to get the +best experience when writing your app in Swift. +1. [Standard pod install](#standard-pod-install) +1. [Swift Package Manager](#swift-package-manager) +1. [Installing from the GitHub repo](#installing-from-github) +1. [Experimental Carthage](#carthage-ios-only) + +### Standard pod install + +Go to +[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup). + +### Swift Package Manager + +Instructions for [Swift Package Manager](https://swift.org/package-manager/) support can be +found at [SwiftPackageManager](SwiftPackageManager.md) Markdown file. + +### Installing from GitHub + +These instructions can be used to access the Firebase repo at other branches, +tags, or commits. + +#### Background + +See +[the Podfile Syntax Reference](https://guides.cocoapods.org/syntax/podfile.html#pod) +for instructions and options about overriding pod source locations. + +#### Accessing Firebase Source Snapshots + +All of the official releases are tagged in this repo and available via CocoaPods. To access a local +source snapshot or unreleased branch, use Podfile directives like the following: + +To access FirebaseFirestore via a branch: +```ruby +pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master' +pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master' +``` + +To access FirebaseMessaging via a checked out version of the firebase-ios-sdk repo do: + +```ruby +pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk' +pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk' +``` + +### Carthage (iOS only) + +Instructions for the experimental Carthage distribution are at +[Carthage](Carthage.md). + +### Using Firebase from a Framework or a library + +[Using Firebase from a Framework or a library](docs/firebase_in_libraries.md) + +## Development + +To develop Firebase software in this repository, ensure that you have at least +the following software: + + * Xcode 14.1 (or later) + +CocoaPods is still the canonical way to develop, but much of the repo now supports +development with Swift Package Manager. + +### CocoaPods + +Install + * CocoaPods 1.10.0 (or later) + * [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +```ruby +pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios +``` + +Note: If the CocoaPods cache is out of date, you may need to run +`pod repo update` before the `pod gen` command. + +Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for +those platforms. Since 10.2, Xcode does not properly handle multi-platform +CocoaPods workspaces. + +Firestore has a self contained Xcode project. See +[Firestore/README](Firestore/README.md) Markdown file. + +#### Development for Catalyst +* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios` +* Check the Mac box in the App-iOS Build Settings +* Sign the App in the Settings Signing & Capabilities tab +* Click Pods in the Project Manager +* Add Signing to the iOS host app and unit test targets +* Select the Unit-unit scheme +* Run it to build and test + +Alternatively disable signing in each target: +* Go to Build Settings tab +* Click `+` +* Select `Add User-Defined Setting` +* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO` + +### Swift Package Manager +* To enable test schemes: `./scripts/setup_spm_tests.sh` +* `open Package.swift` or double click `Package.swift` in Finder. +* Xcode will open the project + * Choose a scheme for a library to build or test suite to run + * Choose a target platform by selecting the run destination along with the scheme + +### Adding a New Firebase Pod + +See [AddNewPod](AddNewPod.md) Markdown file. + +### Managing Headers and Imports + +See [HeadersImports](HeadersImports.md) Markdown file. + +### Code Formatting + +To ensure that the code is formatted consistently, run the script +[./scripts/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/master/scripts/check.sh) +before creating a PR. + +GitHub Actions will verify that any code changes are done in a style compliant +way. Install `clang-format` and `mint`: + +```console +brew install clang-format@16 +brew install mint +``` + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +### Running Sample Apps +In order to run the sample apps and integration tests, you'll need a valid +`GoogleService-Info.plist` file. The Firebase Xcode project contains dummy plist +files without real values, but can be replaced with real plist files. To get your own +`GoogleService-Info.plist` files: + +1. Go to the [Firebase Console](https://console.firebase.google.com/) +2. Create a new Firebase project, if you don't already have one +3. For each sample app you want to test, create a new Firebase app with the sample app's bundle +identifier (e.g. `com.google.Database-Example`) +4. Download the resulting `GoogleService-Info.plist` and add it to the Xcode project. + +### Coverage Report Generation + +See [scripts/code_coverage_report/README](scripts/code_coverage_report/README.md) Markdown file. + +## Specific Component Instructions +See the sections below for any special instructions for those components. + +### Firebase Auth + +If you're doing specific Firebase Auth development, see +[the Auth Sample README](FirebaseAuth/Tests/Sample/README.md) for instructions about +building and running the FirebaseAuth pod along with various samples and tests. + +### Firebase Database + +The Firebase Database Integration tests can be run against a locally running Database Emulator +or against a production instance. + +To run against a local emulator instance, invoke `./scripts/run_database_emulator.sh start` before +running the integration test. + +To run against a production instance, provide a valid GoogleServices-Info.plist and copy it to +`FirebaseDatabase/Tests/Resources/GoogleService-Info.plist`. Your Security Rule must be set to +[public](https://firebase.google.com/docs/database/security/quickstart) while your tests are +running. + +### Firebase Performance Monitoring +If you're doing specific Firebase Performance Monitoring development, see +[the Performance README](FirebasePerformance/README.md) for instructions about building the SDK +and [the Performance TestApp README](FirebasePerformance/Tests/TestApp/README.md) for instructions about +integrating Performance with the dev test App. + +### Firebase Storage + +To run the Storage Integration tests, follow the instructions in +[StorageIntegration.swift](FirebaseStorage/Tests/Integration/StorageIntegration.swift). + +#### Push Notifications + +Push notifications can only be delivered to specially provisioned App IDs in the developer portal. +In order to actually test receiving push notifications, you will need to: + +1. Change the bundle identifier of the sample app to something you own in your Apple Developer +account, and enable that App ID for push notifications. +2. You'll also need to +[upload your APNs Provider Authentication Key or certificate to the +Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs) +at **Project Settings > Cloud Messaging > [Your Firebase App]**. +3. Ensure your iOS device is added to your Apple Developer portal as a test device. + +#### iOS Simulator + +The iOS Simulator cannot register for remote notifications, and will not receive push notifications. +In order to receive push notifications, you'll have to follow the steps above and run the app on a +physical device. + +## Building with Firebase on Apple platforms + +Firebase 8.9.0 introduced official beta support for macOS, Catalyst, and tvOS. watchOS continues +to be community supported. Thanks to community contributions for many of the multi-platform PRs. + +At this time, most of Firebase's products are available across Apple platforms. There are still +a few gaps, especially on watchOS. For details about the current support matrix, see +[this chart](https://firebase.google.com/docs/ios/learn-more#firebase_library_support_by_platform) +in Firebase's documentation. + +### watchOS +Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and +work on watchOS. See the [Independent Watch App Sample](Example/watchOSSample). + +Keep in mind that watchOS is not officially supported by Firebase. While we can catch basic unit +test issues with GitHub Actions, there may be some changes where the SDK no longer works as expected +on watchOS. If you encounter this, please +[file an issue](https://github.com/firebase/firebase-ios-sdk/issues). + +During app setup in the console, you may get to a step that mentions something like "Checking if the +app has communicated with our servers". This relies on Analytics and will not work on watchOS. +**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected. + +#### Additional Crashlytics Notes +* watchOS has limited support. Due to watchOS restrictions, mach exceptions and signal crashes are +not recorded. (Crashes in SwiftUI are generated as mach exceptions, so will not be recorded) + +## Combine +Thanks to contributions from the community, _FirebaseCombineSwift_ contains support for Apple's Combine +framework. This module is currently under development, and not yet supported for use in production +environments. Fore more details, please refer to the [docs](FirebaseCombineSwift/README.md). + +## Roadmap + +See [Roadmap](ROADMAP.md) for more about the Firebase Apple SDK Open Source +plans and directions. + +## Contributing + +See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase +Apple SDK. + +## License + +The contents of this repository are licensed under the +[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). + +Your use of Firebase is governed by the +[Terms of Service for Firebase Services](https://firebase.google.com/terms/). diff --git a/Pods/FirebaseDatabase/FirebaseAppCheck/Interop/FIRAppCheckInterop.h b/Pods/FirebaseDatabase/FirebaseAppCheck/Interop/FIRAppCheckInterop.h new file mode 100644 index 0000000..11ade09 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseAppCheck/Interop/FIRAppCheckInterop.h @@ -0,0 +1,56 @@ +/* + * Copyright 2020 Google LLC + * + * 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 + +@protocol FIRAppCheckTokenResultInterop; + +NS_ASSUME_NONNULL_BEGIN + +NS_SWIFT_NAME(AppCheckTokenHandlerInterop) +typedef void (^FIRAppCheckTokenHandlerInterop)(id tokenResult); + +NS_SWIFT_NAME(AppCheckInterop) @protocol FIRAppCheckInterop + +/// Retrieve a cached or generate a new FAA Token. If forcingRefresh == YES always generates a new +/// token and updates the cache. +- (void)getTokenForcingRefresh:(BOOL)forcingRefresh + completion:(FIRAppCheckTokenHandlerInterop)handler + NS_SWIFT_NAME(getToken(forcingRefresh:completion:)); + +/// A notification with the specified name is sent to the default notification center +/// (`NotificationCenter.default`) each time a Firebase app check token is refreshed. +/// The user info dictionary contains `-[self notificationTokenKey]` and +/// `-[self notificationAppNameKey]` keys. +- (NSString *)tokenDidChangeNotificationName; + +/// `userInfo` key for the FAC token in a notification for `tokenDidChangeNotificationName`. +- (NSString *)notificationTokenKey; +/// `userInfo` key for the `FirebaseApp.name` in a notification for +/// `tokenDidChangeNotificationName`. +- (NSString *)notificationAppNameKey; + +// MARK: - Optional API + +@optional + +/// Retrieve a new limited-use Firebase App Check token +- (void)getLimitedUseTokenWithCompletion:(FIRAppCheckTokenHandlerInterop)handler + NS_SWIFT_NAME(getLimitedUseToken(completion:)); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseDatabase/FirebaseAppCheck/Interop/FIRAppCheckTokenResultInterop.h b/Pods/FirebaseDatabase/FirebaseAppCheck/Interop/FIRAppCheckTokenResultInterop.h new file mode 100644 index 0000000..cb86a1b --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseAppCheck/Interop/FIRAppCheckTokenResultInterop.h @@ -0,0 +1,32 @@ +/* + * Copyright 2020 Google LLC + * + * 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 + +NS_ASSUME_NONNULL_BEGIN + +@protocol FIRAppCheckTokenResultInterop + +/// App Check token in the case of success or a dummy token in the case of a failure. +/// In general, the value of the token should always be set to the request header. +@property(nonatomic, readonly) NSString *token; + +/// A token fetch error in the case of a failure or `nil` in the case of success. +@property(nonatomic, readonly, nullable) NSError *error; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseDatabase/FirebaseAuth/Interop/FIRAuthInterop.h b/Pods/FirebaseDatabase/FirebaseAuth/Interop/FIRAuthInterop.h new file mode 100644 index 0000000..f710e39 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseAuth/Interop/FIRAuthInterop.h @@ -0,0 +1,47 @@ +/* + * 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 FIRAuthInterop_h +#define FIRAuthInterop_h + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** @typedef FIRTokenCallback + @brief The type of block which gets called when a token is ready. + */ +typedef void (^FIRTokenCallback)(NSString *_Nullable token, NSError *_Nullable error) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/// Common methods for Auth interoperability. +NS_SWIFT_NAME(AuthInterop) +@protocol FIRAuthInterop + +/// Retrieves the Firebase authentication token, possibly refreshing it if it has expired. +- (void)getTokenForcingRefresh:(BOOL)forceRefresh + withCallback: + (void (^)(NSString *_Nullable token, NSError *_Nullable error))callback + NS_SWIFT_NAME(getToken(forcingRefresh:completion:)); + +/// Get the current Auth user's UID. Returns nil if there is no user signed in. +- (nullable NSString *)getUserID; + +@end + +NS_ASSUME_NONNULL_END + +#endif /* FIRAuthInterop_h */ diff --git a/Pods/FirebaseDatabase/FirebaseCore/Extension/FIRAppInternal.h b/Pods/FirebaseDatabase/FirebaseCore/Extension/FIRAppInternal.h new file mode 100644 index 0000000..49104f0 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseCore/Extension/FIRAppInternal.h @@ -0,0 +1,159 @@ +/* + * 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 + +@class FIRComponentContainer; +@class FIRHeartbeatLogger; +@protocol FIRLibrary; + +/** + * The internal interface to `FirebaseApp`. This is meant for first-party integrators, who need to + * receive `FirebaseApp` notifications, log info about the success or failure of their + * configuration, and access other internal functionality of `FirebaseApp`. + */ +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(NSInteger, FIRConfigType) { + FIRConfigTypeCore = 1, + FIRConfigTypeSDK = 2, +}; + +extern NSString *const kFIRDefaultAppName; +extern NSString *const kFIRAppReadyToConfigureSDKNotification; +extern NSString *const kFIRAppDeleteNotification; +extern NSString *const kFIRAppIsDefaultAppKey; +extern NSString *const kFIRAppNameKey; +extern NSString *const kFIRGoogleAppIDKey; +extern NSString *const kFirebaseCoreErrorDomain; + +/** The `UserDefaults` suite name for `FirebaseCore`, for those storage locations that use it. */ +extern NSString *const kFirebaseCoreDefaultsSuiteName; + +/** + * The format string for the `UserDefaults` key used for storing the data collection enabled flag. + * This includes formatting to append the `FirebaseApp`'s name. + */ +extern NSString *const kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat; + +/** + * The plist key used for storing the data collection enabled flag. + */ +extern NSString *const kFIRGlobalAppDataCollectionEnabledPlistKey; + +/** @var FirebaseAuthStateDidChangeInternalNotification + @brief The name of the @c NotificationCenter notification which is posted when the auth state + changes (e.g. a new token has been produced, a user logs in or out). The object parameter of + the notification is a dictionary possibly containing the key: + @c FirebaseAuthStateDidChangeInternalNotificationTokenKey (the new access token.) If it does not + contain this key it indicates a sign-out event took place. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotification; + +/** @var FirebaseAuthStateDidChangeInternalNotificationTokenKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the new access token. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationTokenKey; + +/** @var FirebaseAuthStateDidChangeInternalNotificationAppKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the FirebaseApp associated with the auth instance. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationAppKey; + +/** @var FirebaseAuthStateDidChangeInternalNotificationUIDKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the new user's UID (or nil if there is no longer a user signed in). + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationUIDKey; + +@interface FIRApp () + +/** + * A flag indicating if this is the default app (has the default app name). + */ +@property(nonatomic, readonly) BOOL isDefaultApp; + +/** + * The container of interop SDKs for this app. + */ +@property(nonatomic) FIRComponentContainer *container; + +/** + * The heartbeat logger associated with this app. + * + * Firebase apps have a 1:1 relationship with heartbeat loggers. + */ +@property(readonly) FIRHeartbeatLogger *heartbeatLogger; + +/** + * Checks if the default app is configured without trying to configure it. + */ ++ (BOOL)isDefaultAppConfigured; + +/** + * Registers a given third-party library with the given version number to be reported for + * analytics. + * + * @param name Name of the library. + * @param version Version of the library. + */ ++ (void)registerLibrary:(nonnull NSString *)name withVersion:(nonnull NSString *)version; + +/** + * Registers a given internal library to be reported for analytics. + * + * @param library Optional parameter for component registration. + * @param name Name of the library. + */ ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name; + +/** + * Registers a given internal library with the given version number to be reported for + * analytics. This should only be used for non-Firebase libraries that have their own versioning + * scheme. + * + * @param library Optional parameter for component registration. + * @param name Name of the library. + * @param version Version of the library. + */ ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name + withVersion:(nonnull NSString *)version; + +/** + * A concatenated string representing all the third-party libraries and version numbers. + */ ++ (NSString *)firebaseUserAgent; + +/** + * Can be used by the unit tests in each SDK to reset `FirebaseApp`. This method is thread unsafe. + */ ++ (void)resetApps; + +/** + * Can be used by the unit tests in each SDK to set customized options. + */ +- (instancetype)initInstanceWithName:(NSString *)name options:(FIROptions *)options; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseDatabase/FirebaseCore/Extension/FIRComponent.h b/Pods/FirebaseDatabase/FirebaseCore/Extension/FIRComponent.h new file mode 100644 index 0000000..e4c8a27 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseCore/Extension/FIRComponent.h @@ -0,0 +1,91 @@ +/* + * 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. + */ + +#import + +@class FIRApp; +@class FIRComponentContainer; + +NS_ASSUME_NONNULL_BEGIN + +/// Provides a system to clean up cached instances returned from the component system. +NS_SWIFT_NAME(ComponentLifecycleMaintainer) +@protocol FIRComponentLifecycleMaintainer +/// The associated app will be deleted, clean up any resources as they are about to be deallocated. +- (void)appWillBeDeleted:(FIRApp *)app; +@end + +typedef _Nullable id (^FIRComponentCreationBlock)(FIRComponentContainer *container, + BOOL *isCacheable) + NS_SWIFT_NAME(ComponentCreationBlock); + +@class FIRDependency; + +/// Describes the timing of instantiation. Note: new components should default to lazy unless there +/// is a strong reason to be eager. +typedef NS_ENUM(NSInteger, FIRInstantiationTiming) { + FIRInstantiationTimingLazy, + FIRInstantiationTimingAlwaysEager, + FIRInstantiationTimingEagerInDefaultApp +} NS_SWIFT_NAME(InstantiationTiming); + +/// A component that can be used from other Firebase SDKs. +NS_SWIFT_NAME(Component) +@interface FIRComponent : NSObject + +/// The protocol describing functionality provided from the `Component`. +@property(nonatomic, strong, readonly) Protocol *protocol; + +/// The timing of instantiation. +@property(nonatomic, readonly) FIRInstantiationTiming instantiationTiming; + +/// An array of dependencies for the component. +@property(nonatomic, copy, readonly) NSArray *dependencies; + +/// A block to instantiate an instance of the component with the appropriate dependencies. +@property(nonatomic, copy, readonly) FIRComponentCreationBlock creationBlock; + +// There's an issue with long NS_SWIFT_NAMES that causes compilation to fail, disable clang-format +// for the next two methods. +// clang-format off + +/// Creates a component with no dependencies that will be lazily initialized. ++ (instancetype)componentWithProtocol:(Protocol *)protocol + creationBlock:(FIRComponentCreationBlock)creationBlock +NS_SWIFT_NAME(init(_:creationBlock:)); + +/// Creates a component to be registered with the component container. +/// +/// @param protocol - The protocol describing functionality provided by the component. +/// @param instantiationTiming - When the component should be initialized. Use .lazy unless there's +/// a good reason to be instantiated earlier. +/// @param dependencies - Any dependencies the `implementingClass` has, optional or required. +/// @param creationBlock - A block to instantiate the component with a container, and if +/// @return A component that can be registered with the component container. ++ (instancetype)componentWithProtocol:(Protocol *)protocol + instantiationTiming:(FIRInstantiationTiming)instantiationTiming + dependencies:(NSArray *)dependencies + creationBlock:(FIRComponentCreationBlock)creationBlock +NS_SWIFT_NAME(init(_:instantiationTiming:dependencies:creationBlock:)); + +// clang-format on + +/// Unavailable. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseDatabase/FirebaseCore/Extension/FIRComponentContainer.h b/Pods/FirebaseDatabase/FirebaseCore/Extension/FIRComponentContainer.h new file mode 100644 index 0000000..6ec6147 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseCore/Extension/FIRComponentContainer.h @@ -0,0 +1,45 @@ +/* + * 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. + */ +#import + +NS_ASSUME_NONNULL_BEGIN + +/// A type-safe macro to retrieve a component from a container. This should be used to retrieve +/// components instead of using the container directly. +#define FIR_COMPONENT(type, container) \ + [FIRComponentType> instanceForProtocol:@protocol(type) inContainer:container] + +@class FIRApp; + +/// A container that holds different components that are registered via the +/// `registerAsComponentRegistrant` call. These classes should conform to `ComponentRegistrant` +/// in order to properly register components for Core. +NS_SWIFT_NAME(FirebaseComponentContainer) +@interface FIRComponentContainer : NSObject + +/// A weak reference to the app that an instance of the container belongs to. +@property(nonatomic, weak, readonly) FIRApp *app; + +// TODO: See if we can get improved type safety here. +/// A Swift only API for fetching an instance since the top macro isn't available. +- (nullable id)__instanceForProtocol:(Protocol *)protocol NS_SWIFT_NAME(instance(for:)); + +/// Unavailable. Use the `container` property on `FirebaseApp`. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseDatabase/FirebaseCore/Extension/FIRComponentType.h b/Pods/FirebaseDatabase/FirebaseCore/Extension/FIRComponentType.h new file mode 100644 index 0000000..6f2aca7 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseCore/Extension/FIRComponentType.h @@ -0,0 +1,34 @@ +/* + * 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. + */ + +#import + +@class FIRComponentContainer; + +NS_ASSUME_NONNULL_BEGIN + +/// Do not use directly. A placeholder type in order to provide a macro that will warn users of +/// mis-matched protocols. +NS_SWIFT_NAME(ComponentType) +@interface FIRComponentType<__covariant T> : NSObject + +/// Do not use directly. A factory method to retrieve an instance that provides a specific +/// functionality. ++ (T)instanceForProtocol:(Protocol *)protocol inContainer:(FIRComponentContainer *)container; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseDatabase/FirebaseCore/Extension/FIRDependency.h b/Pods/FirebaseDatabase/FirebaseCore/Extension/FIRDependency.h new file mode 100644 index 0000000..a070557 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseCore/Extension/FIRDependency.h @@ -0,0 +1,45 @@ +/* + * 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. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/// A dependency on a specific protocol's functionality. +NS_SWIFT_NAME(Dependency) +@interface FIRDependency : NSObject + +/// The protocol describing functionality being depended on. +@property(nonatomic, strong, readonly) Protocol *protocol; + +/// A flag to specify if the dependency is required or not. +@property(nonatomic, readonly) BOOL isRequired; + +/// Initializes a dependency that is required. Calls `init(protocol:isRequired:)` with true for +/// the required parameter. +/// Creates a required dependency on the specified protocol's functionality. ++ (instancetype)dependencyWithProtocol:(Protocol *)protocol; + +/// Creates a dependency on the specified protocol's functionality and specify if it's required for +/// the class's functionality. ++ (instancetype)dependencyWithProtocol:(Protocol *)protocol isRequired:(BOOL)required; + +/// Use `init(withProtocol:isRequired:)` instead. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseDatabase/FirebaseCore/Extension/FIRHeartbeatLogger.h b/Pods/FirebaseDatabase/FirebaseCore/Extension/FIRHeartbeatLogger.h new file mode 100644 index 0000000..0f39ad9 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseCore/Extension/FIRHeartbeatLogger.h @@ -0,0 +1,90 @@ +// Copyright 2021 Google LLC +// +// 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 + +NS_ASSUME_NONNULL_BEGIN + +#ifndef FIREBASE_BUILD_CMAKE +@class FIRHeartbeatsPayload; +#endif // FIREBASE_BUILD_CMAKE + +/// Enum representing different daily heartbeat codes. +/// This enum is only used by clients using platform logging V1. This is because +/// the V1 payload only supports a single daily heartbeat. +typedef NS_ENUM(NSInteger, FIRDailyHeartbeatCode) { + /// Represents the absence of a daily heartbeat. + FIRDailyHeartbeatCodeNone = 0, + /// Represents the presence of a daily heartbeat. + FIRDailyHeartbeatCodeSome = 2, +}; + +@protocol FIRHeartbeatLoggerProtocol + +/// Asynchronously logs a heartbeat. +- (void)log; + +#ifndef FIREBASE_BUILD_CMAKE +/// Flushes heartbeats from storage into a structured payload of heartbeats. +- (FIRHeartbeatsPayload *)flushHeartbeatsIntoPayload; +#endif // FIREBASE_BUILD_CMAKE + +/// Gets the heartbeat code for today. +- (FIRDailyHeartbeatCode)heartbeatCodeForToday; + +@end + +#ifndef FIREBASE_BUILD_CMAKE +/// Returns a nullable string header value from a given heartbeats payload. +/// +/// This API returns `nil` when the given heartbeats payload is considered empty. +/// +/// @param heartbeatsPayload The heartbeats payload. +NSString *_Nullable FIRHeaderValueFromHeartbeatsPayload(FIRHeartbeatsPayload *heartbeatsPayload); +#endif // FIREBASE_BUILD_CMAKE + +/// A thread safe, synchronized object that logs and flushes platform logging info. +@interface FIRHeartbeatLogger : NSObject + +/// Designated initializer. +/// +/// @param appID The app ID that this heartbeat logger corresponds to. +- (instancetype)initWithAppID:(NSString *)appID; + +/// Asynchronously logs a new heartbeat corresponding to the Firebase User Agent, if needed. +/// +/// @note This API is thread-safe. +- (void)log; + +#ifndef FIREBASE_BUILD_CMAKE +/// Flushes heartbeats from storage into a structured payload of heartbeats. +/// +/// This API is for clients using platform logging V2. +/// +/// @note This API is thread-safe. +/// @return A payload of heartbeats. +- (FIRHeartbeatsPayload *)flushHeartbeatsIntoPayload; +#endif // FIREBASE_BUILD_CMAKE + +/// Gets today's corresponding heartbeat code. +/// +/// This API is for clients using platform logging V1. +/// +/// @note This API is thread-safe. +/// @return Heartbeat code indicating whether or not there is an unsent global heartbeat. +- (FIRDailyHeartbeatCode)heartbeatCodeForToday; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseDatabase/FirebaseCore/Extension/FIRLibrary.h b/Pods/FirebaseDatabase/FirebaseCore/Extension/FIRLibrary.h new file mode 100644 index 0000000..15e2865 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseCore/Extension/FIRLibrary.h @@ -0,0 +1,44 @@ +/* + * 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 FIRLibrary_h +#define FIRLibrary_h + +#import + +@class FIRApp; +@class FIRComponent; + +NS_ASSUME_NONNULL_BEGIN + +/// Provide an interface to register a library for userAgent logging and availability to others. +NS_SWIFT_NAME(Library) +@protocol FIRLibrary + +/// Returns one or more Components that will be registered in +/// FirebaseApp and participate in dependency resolution and injection. ++ (NSArray *)componentsToRegister; + +@optional +/// Implement this method if the library needs notifications for lifecycle events. This method is +/// called when the developer calls `FirebaseApp.configure()`. ++ (void)configureWithApp:(FIRApp *)app; + +@end + +NS_ASSUME_NONNULL_END + +#endif /* FIRLibrary_h */ diff --git a/Pods/FirebaseDatabase/FirebaseCore/Extension/FIRLogger.h b/Pods/FirebaseDatabase/FirebaseCore/Extension/FIRLogger.h new file mode 100644 index 0000000..0a287f5 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseCore/Extension/FIRLogger.h @@ -0,0 +1,188 @@ +/* + * 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 + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * The Firebase services used in Firebase logger. + */ +typedef NSString *const FIRLoggerService; + +extern FIRLoggerService kFIRLoggerAnalytics; +extern FIRLoggerService kFIRLoggerCrash; +extern FIRLoggerService kFIRLoggerCore; +extern FIRLoggerService kFIRLoggerRemoteConfig; + +/** + * The key used to store the logger's error count. + */ +extern NSString *const kFIRLoggerErrorCountKey; + +/** + * The key used to store the logger's warning count. + */ +extern NSString *const kFIRLoggerWarningCountKey; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** + * Enables or disables Analytics debug mode. + * If set to true, the logging level for Analytics will be set to FirebaseLoggerLevelDebug. + * Enabling the debug mode has no effect if the app is running from App Store. + * (required) analytics debug mode flag. + */ +void FIRSetAnalyticsDebugMode(BOOL analyticsDebugMode); + +/** + * Changes the default logging level of FirebaseLoggerLevelNotice to a user-specified level. + * The default level cannot be set above FirebaseLoggerLevelNotice if the app is running from App + * Store. (required) log level (one of the FirebaseLoggerLevel enum values). + */ +void FIRSetLoggerLevel(FIRLoggerLevel loggerLevel); + +/** + * Checks if the specified logger level is loggable given the current settings. + * (required) log level (one of the FirebaseLoggerLevel enum values). + * (required) whether or not this function is called from the Analytics component. + */ +BOOL FIRIsLoggableLevel(FIRLoggerLevel loggerLevel, BOOL analyticsComponent); + +/** + * Logs a message to the Xcode console and the device log. If running from AppStore, will + * not log any messages with a level higher than FirebaseLoggerLevelNotice to avoid log spamming. + * (required) log level (one of the FirebaseLoggerLevel enum values). + * (required) service name of type FirebaseLoggerService. + * (required) message code starting with "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique + * within the service. + * An example of the message code is @"I-COR000001". + * (required) message string which can be a format string. + * (optional) variable arguments list obtained from calling va_start, used when message is a format + * string. + */ +extern void FIRLogBasic(FIRLoggerLevel level, + FIRLoggerService service, + NSString *messageCode, + NSString *message, +// On 64-bit simulators, va_list is not a pointer, so cannot be marked nullable +// See: http://stackoverflow.com/q/29095469 +#if __LP64__ && TARGET_OS_SIMULATOR || TARGET_OS_OSX + va_list args_ptr +#else + va_list _Nullable args_ptr +#endif +); + +/** + * The following functions accept the following parameters in order: + * (required) service name of type FirebaseLoggerService. + * (required) message code starting from "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique + * within the service. + * An example of the message code is @"I-COR000001". + * See go/firebase-log-proposal for details. + * (required) message string which can be a format string. + * (optional) the list of arguments to substitute into the format string. + * Example usage: + * FirebaseLogError(kFirebaseLoggerCore, @"I-COR000001", @"Configuration of %@ failed.", app.name); + */ +extern void FIRLogError(FIRLoggerService service, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogWarning(FIRLoggerService service, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogNotice(FIRLoggerService service, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogInfo(FIRLoggerService service, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogDebug(FIRLoggerService service, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); + +// TODO: Come up with a better logging scheme for Swift. +/** + * Logs a debug message to the Xcode console and the device log. If running from AppStore, will + * not log any messages with a level higher than FirebaseLoggerLevelNotice to avoid log spamming. + * This function is intended to be used by Swift clients that do not support variadic parameters. + * + * @param service The service name of type `FirebaseLoggerService`. + * @param messageCode The mesage code. starting with "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique within the + * service. An example of the message code is @"I-COR000001". + * @param message The message string. + */ +extern void FIRLogDebugSwift(FIRLoggerService service, NSString *messageCode, NSString *message); + +/** + * Logs a warning message to the Xcode console and the device log. If running from AppStore, will + * not log any messages with a level higher than FirebaseLoggerLevelNotice to avoid log spamming. + * This function is intended to be used by Swift clients that do not support variadic parameters. + * + * @param service The service name of type `FirebaseLoggerService`. + * @param messageCode The mesage code. starting with "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique within the + * service. An example of the message code is @"I-COR000001". + * @param message The message string. + */ +extern void FIRLogWarningSwift(FIRLoggerService service, NSString *messageCode, NSString *message); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +NS_SWIFT_NAME(FirebaseLogger) +@interface FIRLoggerWrapper : NSObject + +/// Logs a given message at a given log level. This API is effectively a wrapper for the +/// `FIRLogBasic` C API. +/// +/// - Parameters: +/// - level: The log level to use (defined by `FirebaseLoggerLevel` enum values). +/// - service: The service name of type `FirebaseLoggerService`. +/// - code: The mesage code. Starting with "I-" which means iOS, followed by a capitalized +/// three-character service identifier and a six digit integer message ID that is unique within +/// the service. An example of the message code is @"I-COR000001". +/// - message: Formatted string to be used as the log's message. +/// - args: Arguments list obtained from calling `va_start`, used when message is a format string. ++ (void)logWithLevel:(FIRLoggerLevel)level + withService:(FIRLoggerService)service + withCode:(NSString *)messageCode + withMessage:(NSString *)message + withArgs:(va_list)args; + +/// Logs a given message at a given log level. +/// +/// - Parameters: +/// - level: The log level to use (defined by `FirebaseLoggerLevel` enum values). +/// - service: The service name of type `FirebaseLoggerService`. +/// - code: The mesage code. Starting with "I-" which means iOS, followed by a capitalized +/// three-character service identifier and a six digit integer message ID that is unique within +/// the service. An example of the message code is @"I-COR000001". +/// - message: Formatted string to be used as the log's message. +/// - args: Arguments list obtained from calling `va_start`, used when message is a format string. ++ (void)logWithLevel:(FIRLoggerLevel)level + service:(FIRLoggerService)service + code:(NSString *)code + message:(NSString *)message + __attribute__((__swift_name__("log(level:service:code:message:)"))); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseDatabase/FirebaseCore/Extension/FIROptionsInternal.h b/Pods/FirebaseDatabase/FirebaseCore/Extension/FIROptionsInternal.h new file mode 100644 index 0000000..93a03d6 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseCore/Extension/FIROptionsInternal.h @@ -0,0 +1,106 @@ +/* + * 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 + +/** + * Keys for the strings in the plist file. + */ +extern NSString *const kFIRAPIKey; +extern NSString *const kFIRTrackingID; +extern NSString *const kFIRGoogleAppID; +extern NSString *const kFIRClientID; +extern NSString *const kFIRGCMSenderID; +extern NSString *const kFIRAndroidClientID; +extern NSString *const kFIRDatabaseURL; +extern NSString *const kFIRStorageBucket; +extern NSString *const kFIRBundleID; +extern NSString *const kFIRProjectID; + +/** + * Keys for the plist file name + */ +extern NSString *const kServiceInfoFileName; + +extern NSString *const kServiceInfoFileType; + +/** + * This header file exposes the initialization of FirebaseOptions to internal use. + */ +@interface FIROptions () + +/** + * `resetDefaultOptions` and `initInternalWithOptionsDictionary` are exposed only for unit tests. + */ ++ (void)resetDefaultOptions; + +/** + * Initializes the options with dictionary. The above strings are the keys of the dictionary. + * This is the designated initializer. + */ +- (instancetype)initInternalWithOptionsDictionary:(NSDictionary *)serviceInfoDictionary + NS_DESIGNATED_INITIALIZER; + +/** + * `defaultOptions` and `defaultOptionsDictionary` are exposed in order to be used in FirebaseApp + * and other first party services. + */ ++ (FIROptions *)defaultOptions; + ++ (NSDictionary *)defaultOptionsDictionary; + +/** + * Indicates whether or not Analytics collection was explicitly enabled via a plist flag or at + * runtime. + */ +@property(nonatomic, readonly) BOOL isAnalyticsCollectionExplicitlySet; + +/** + * Whether or not Analytics Collection was enabled. Analytics Collection is enabled unless + * explicitly disabled in GoogleService-Info.plist. + */ +@property(nonatomic, readonly) BOOL isAnalyticsCollectionEnabled; + +/** + * Whether or not Analytics Collection was completely disabled. If true, then + * isAnalyticsCollectionEnabled will be false. + */ +@property(nonatomic, readonly) BOOL isAnalyticsCollectionDeactivated; + +/** + * The version ID of the client library, e.g. @"1100000". + */ +@property(nonatomic, readonly, copy) NSString *libraryVersionID; + +/** + * The flag indicating whether this object was constructed with the values in the default plist + * file. + */ +@property(nonatomic) BOOL usingOptionsFromDefaultPlist; + +/** + * Whether or not Measurement was enabled. Measurement is enabled unless explicitly disabled in + * GoogleService-Info.plist. + */ +@property(nonatomic, readonly) BOOL isMeasurementEnabled; + +/** + * Whether or not editing is locked. This should occur after `FirebaseOptions` has been set on a + * `FirebaseApp`. + */ +@property(nonatomic, getter=isEditingLocked) BOOL editingLocked; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseCore/Extension/FirebaseCoreInternal.h b/Pods/FirebaseDatabase/FirebaseCore/Extension/FirebaseCoreInternal.h new file mode 100644 index 0000000..0669ae6 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseCore/Extension/FirebaseCoreInternal.h @@ -0,0 +1,25 @@ +// Copyright 2020 Google LLC +// +// 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 FirebaseCore; + +#import "FIRAppInternal.h" +#import "FIRComponent.h" +#import "FIRComponentContainer.h" +#import "FIRComponentType.h" +#import "FIRDependency.h" +#import "FIRHeartbeatLogger.h" +#import "FIRLibrary.h" +#import "FIRLogger.h" +#import "FIROptionsInternal.h" diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/LICENSE b/Pods/FirebaseDatabase/FirebaseDatabase/LICENSE new file mode 100644 index 0000000..3a43759 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/LICENSE @@ -0,0 +1,337 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. + + +-------------------------- +FImmutableSortedDictionary +-------------------------- + Copyright (c) 2012 Mads Hartmann Jensen + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +-------------------------- +Wrap-leveldb +-------------------------- +Created by Adam Preble on 1/23/12. +Copyright (c) 2012 Adam Preble. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +Portions of APLevelDB are based on LevelDB-ObjC: + https:github.com/hoisie/LevelDB-ObjC +Specifically the SliceFromString/StringFromSlice macros, and the structure of +the enumeration methods. License for those potions follows: + +Copyright (c) 2011 Pave Labs + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +-------------------------- +SocketRocket +-------------------------- +Copyright 2012 Square Inc. + +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. + +$OpenBSD: base64.c,v 1.5 2006/10/21 09:55:03 otto Exp $ + +Copyright (c) 1996 by Internet Software Consortium. + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS +ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE +CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL +DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +Portions Copyright (c) 1995 by International Business Machines, Inc. + +International Business Machines, Inc. (hereinafter called IBM) grants +permission under its copyrights to use, copy, modify, and distribute this +Software with or without fee, provided that the above copyright notice and +all paragraphs of this notice appear in all copies, and that the name of IBM +not be used in connection with the marketing of any product incorporating +the Software or modifications thereof, without specific, written prior +permission. + +To the extent it has a right to do so, IBM grants an immunity from suit +under its patents, if any, for the use, sale or manufacture of products to +the extent that such products are used for performing Domain Name System +dynamic updates in TCP/IP networks by means of the Software. No immunity is +granted for any product per se or for any other function of any product. + +THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, +DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING +OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN +IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDataSnapshot.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDataSnapshot.m new file mode 100644 index 0000000..8801534 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDataSnapshot.m @@ -0,0 +1,105 @@ +/* + * 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 "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDataSnapshot.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDataSnapshot_Private.h" +#import "FirebaseDatabase/Sources/FTransformedEnumerator.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseReference.h" +#import "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h" +#import "FirebaseDatabase/Sources/Utilities/FValidation.h" + +@interface FIRDataSnapshot () +@property(nonatomic, strong) FIRDatabaseReference *ref; +@end + +@implementation FIRDataSnapshot + +- (id)initWithRef:(FIRDatabaseReference *)ref indexedNode:(FIndexedNode *)node { + self = [super init]; + if (self != nil) { + self->_ref = ref; + self->_node = node; + } + return self; +} + +- (id)value { + return [self.node.node val]; +} + +- (id)valueInExportFormat { + return [self.node.node valForExport:YES]; +} + +- (FIRDataSnapshot *)childSnapshotForPath:(NSString *)childPathString { + [FValidation validateFrom:@"child:" validPathString:childPathString]; + FPath *childPath = [[FPath alloc] initWith:childPathString]; + FIRDatabaseReference *childRef = [self.ref child:childPathString]; + + id childNode = [self.node.node getChild:childPath]; + return [[FIRDataSnapshot alloc] + initWithRef:childRef + indexedNode:[FIndexedNode indexedNodeWithNode:childNode]]; +} + +- (BOOL)hasChild:(NSString *)childPathString { + [FValidation validateFrom:@"hasChild:" validPathString:childPathString]; + FPath *childPath = [[FPath alloc] initWith:childPathString]; + return ![[self.node.node getChild:childPath] isEmpty]; +} + +- (id)priority { + id priority = [self.node.node getPriority]; + return priority.val; +} + +- (BOOL)hasChildren { + if ([self.node.node isLeafNode]) { + return false; + } else { + return ![self.node.node isEmpty]; + } +} + +- (BOOL)exists { + return ![self.node.node isEmpty]; +} + +- (NSString *)key { + return [self.ref key]; +} + +- (NSUInteger)childrenCount { + return [self.node.node numChildren]; +} + +- (NSEnumerator *)children { + return [[FTransformedEnumerator alloc] + initWithEnumerator:self.node.childEnumerator + andTransform:^id(FNamedNode *node) { + FIRDatabaseReference *childRef = [self.ref child:node.name]; + return [[FIRDataSnapshot alloc] + initWithRef:childRef + indexedNode:[FIndexedNode indexedNodeWithNode:node.node]]; + }]; +} + +- (NSString *)description { + return + [NSString stringWithFormat:@"Snap (%@) %@", self.key, self.node.node]; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabase.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabase.m new file mode 100644 index 0000000..f90e318 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabase.m @@ -0,0 +1,261 @@ +/* + * 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 + +#import "FirebaseAuth/Interop/FIRAuthInterop.h" +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" + +#import "FirebaseDatabase/Sources/Api/FIRDatabaseComponent.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDatabaseReference_Private.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDatabase_Private.h" +#import "FirebaseDatabase/Sources/Core/FRepoInfo.h" +#import "FirebaseDatabase/Sources/FIRDatabaseConfig_Private.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabase.h" +#import "FirebaseDatabase/Sources/Utilities/FValidation.h" + +@implementation FIRDatabase + ++ (FIRDatabase *)database { + if (![FIRApp isDefaultAppConfigured]) { + [NSException + raise:@"FIRAppNotConfigured" + format:@"The default FirebaseApp instance must be " + @"configured before the default Database instance " + @"can be initialized. One way to ensure this is to " + @"call `FirebaseApp.configure()` in the App Delegate's " + @"`application(_:didFinishLaunchingWithOptions:)` " + @"(or the `@main` struct's initializer in SwiftUI)."]; + } + return [FIRDatabase databaseForApp:[FIRApp defaultApp]]; +} + ++ (FIRDatabase *)databaseWithURL:(NSString *)url { + FIRApp *app = [FIRApp defaultApp]; + if (app == nil) { + [NSException + raise:@"FIRAppNotConfigured" + format: + @"Failed to get default Firebase Database instance. " + @"Must call `[FIRApp configure]` (`FirebaseApp.configure()` in " + @"Swift) before using Firebase Database."]; + } + return [FIRDatabase databaseForApp:app URL:url]; +} + ++ (FIRDatabase *)databaseForApp:(FIRApp *)app { + if (app == nil) { + [NSException raise:@"InvalidFIRApp" + format:@"nil FIRApp instance passed to databaseForApp."]; + } + NSString *url = app.options.databaseURL; + if (!url) { + if (!app.options.projectID) { + [NSException + raise:@"MissingProjectId" + format:@"Can't determine Firebase Database URL. Be sure to " + @"include a Project ID when calling " + @"`FirebaseApp.configure()`."]; + } + FFLog(@"I-RDB024002", @"Using default host for project %@", + app.options.projectID); + url = [NSString + stringWithFormat:@"https://%@-default-rtdb.firebaseio.com", + app.options.projectID]; + } + return [FIRDatabase databaseForApp:app URL:url]; +} + ++ (FIRDatabase *)databaseForApp:(FIRApp *)app URL:(NSString *)url { + if (app == nil) { + [NSException raise:@"InvalidFIRApp" + format:@"nil FIRApp instance passed to databaseForApp."]; + } + if (url == nil) { + [NSException raise:@"MissingDatabaseURL" + format:@"Failed to get FirebaseDatabase instance: " + @"Specify DatabaseURL within FIRApp or from your " + @"databaseForApp:URL: call."]; + } + id provider = + FIR_COMPONENT(FIRDatabaseProvider, app.container); + return [provider databaseForApp:app URL:url]; +} + ++ (NSString *)buildVersion { + return [NSString stringWithFormat:@"%@_%s", FIRFirebaseVersion(), __DATE__]; +} + ++ (FIRDatabase *)createDatabaseForTests:(FRepoInfo *)repoInfo + config:(FIRDatabaseConfig *)config { + FIRDatabase *db = [[FIRDatabase alloc] initWithApp:nil + repoInfo:repoInfo + config:config]; + [db ensureRepo]; + return db; +} + ++ (NSString *)sdkVersion { + return FIRFirebaseVersion(); +} + ++ (void)setLoggingEnabled:(BOOL)enabled { + [FUtilities setLoggingEnabled:enabled]; + FFLog(@"I-RDB024001", @"BUILD Version: %@", [FIRDatabase buildVersion]); +} + +- (id)initWithApp:(FIRApp *)app + repoInfo:(FRepoInfo *)info + config:(FIRDatabaseConfig *)config { + self = [super init]; + if (self != nil) { + self->_repoInfo = info; + self->_config = config; + self->_app = app; + } + return self; +} + +- (FIRDatabaseReference *)reference { + [self ensureRepo]; + + return [[FIRDatabaseReference alloc] initWithRepo:self.repo + path:[FPath empty]]; +} + +- (FIRDatabaseReference *)referenceWithPath:(NSString *)path { + [self ensureRepo]; + + [FValidation validateFrom:@"referenceWithPath" validRootPathString:path]; + FPath *childPath = [[FPath alloc] initWith:path]; + return [[FIRDatabaseReference alloc] initWithRepo:self.repo path:childPath]; +} + +- (FIRDatabaseReference *)referenceFromURL:(NSString *)databaseUrl { + [self ensureRepo]; + + if (databaseUrl == nil) { + [NSException raise:@"InvalidDatabaseURL" + format:@"Invalid nil url passed to referenceFromURL:"]; + } + FParsedUrl *parsedUrl = [FUtilities parseUrl:databaseUrl]; + [FValidation validateFrom:@"referenceFromURL:" validURL:parsedUrl]; + + BOOL isInvalidHost = + !parsedUrl.repoInfo.isCustomHost && + ![_repoInfo.host isEqualToString:parsedUrl.repoInfo.host]; + if (isInvalidHost) { + [NSException raise:@"InvalidDatabaseURL" + format:@"Invalid URL (%@) passed to getReference(). URL " + @"was expected to match configured Database URL: %@", + databaseUrl, _repoInfo.host]; + } + return [[FIRDatabaseReference alloc] initWithRepo:self.repo + path:parsedUrl.path]; +} + +- (void)purgeOutstandingWrites { + [self ensureRepo]; + + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self.repo purgeOutstandingWrites]; + }); +} + +- (void)useEmulatorWithHost:(NSString *)host port:(NSInteger)port { + if (host.length == 0) { + [NSException raise:NSInvalidArgumentException + format:@"Cannot connect to nil or empty host."]; + } + if (self.repo != nil) { + [NSException + raise:NSInternalInconsistencyException + format:@"Cannot connect to emulator after database initialization. " + @"Call useEmulator(host:port:) before creating a database " + @"reference or trying to load data."]; + } + NSString *fullHost = + [NSString stringWithFormat:@"%@:%li", host, (long)port]; + FRepoInfo *emulatorInfo = [[FRepoInfo alloc] initWithInfo:self.repoInfo + emulatedHost:fullHost]; + self->_repoInfo = emulatorInfo; +} + +- (void)goOnline { + [self ensureRepo]; + + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self.repo resume]; + }); +} + +- (void)goOffline { + [self ensureRepo]; + + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self.repo interrupt]; + }); +} + +- (void)setPersistenceEnabled:(BOOL)persistenceEnabled { + [self assertUnfrozen:@"setPersistenceEnabled"]; + self->_config.persistenceEnabled = persistenceEnabled; +} + +- (BOOL)persistenceEnabled { + return self->_config.persistenceEnabled; +} + +- (void)setPersistenceCacheSizeBytes:(NSUInteger)persistenceCacheSizeBytes { + [self assertUnfrozen:@"setPersistenceCacheSizeBytes"]; + self->_config.persistenceCacheSizeBytes = persistenceCacheSizeBytes; +} + +- (NSUInteger)persistenceCacheSizeBytes { + return self->_config.persistenceCacheSizeBytes; +} + +- (void)setCallbackQueue:(dispatch_queue_t)callbackQueue { + [self assertUnfrozen:@"setCallbackQueue"]; + self->_config.callbackQueue = callbackQueue; +} + +- (dispatch_queue_t)callbackQueue { + return self->_config.callbackQueue; +} + +- (void)assertUnfrozen:(NSString *)methodName { + if (self.repo != nil) { + [NSException + raise:@"FIRDatabaseAlreadyInUse" + format:@"Calls to %@ must be made before any other usage of " + "FIRDatabase instance.", + methodName]; + } +} + +- (void)ensureRepo { + @synchronized(self) { + if (self.repo == nil) { + self.repo = [FRepoManager createRepo:self.repoInfo + config:self.config + database:self]; + } + } +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabaseComponent.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabaseComponent.h new file mode 100644 index 0000000..9d8bdb2 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabaseComponent.h @@ -0,0 +1,46 @@ +/* + * 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. + */ + +#import + +@class FIRApp; +@class FIRDatabase; + +NS_ASSUME_NONNULL_BEGIN + +/// This protocol is used in the interop registration process to register an +/// instance provider for individual FIRApps. +@protocol FIRDatabaseProvider + +/// Gets a FirebaseDatabase instance for the specified URL, using the specified +/// FirebaseApp. +- (FIRDatabase *)databaseForApp:(FIRApp *)app URL:(NSString *)url; + +@end + +/// A concrete implementation for FIRDatabaseProvider to create Database +/// instances. +@interface FIRDatabaseComponent : NSObject + +/// The FIRApp that instances will be set up with. +@property(nonatomic, weak, readonly) FIRApp *app; + +/// Unavailable, use `databaseForApp:URL:` instead. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabaseComponent.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabaseComponent.m new file mode 100644 index 0000000..8e68d5f --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabaseComponent.m @@ -0,0 +1,172 @@ +/* + * 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. + */ + +#import "FirebaseDatabase/Sources/Api/FIRDatabaseComponent.h" + +#import "FirebaseDatabase/Sources/Api/Private/FIRDatabase_Private.h" +#import "FirebaseDatabase/Sources/Core/FRepoManager.h" +#import "FirebaseDatabase/Sources/FIRDatabaseConfig_Private.h" + +#import "FirebaseAppCheck/Interop/FIRAppCheckInterop.h" +#import "FirebaseAuth/Interop/FIRAuthInterop.h" +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" + +NS_ASSUME_NONNULL_BEGIN + +/** A NSMutableDictionary of FirebaseApp name and FRepoInfo to FirebaseDatabase + * instance. */ +typedef NSMutableDictionary FIRDatabaseDictionary; + +@interface FIRDatabaseComponent () +@property(nonatomic) FIRDatabaseDictionary *instances; +/// Internal initializer. +- (instancetype)initWithApp:(FIRApp *)app; +@end + +@implementation FIRDatabaseComponent + +#pragma mark - Initialization + +- (instancetype)initWithApp:(FIRApp *)app { + self = [super init]; + if (self) { + _app = app; + _instances = [NSMutableDictionary dictionary]; + } + return self; +} + +#pragma mark - Lifecycle + ++ (void)load { + [FIRApp registerInternalLibrary:(Class)self + withName:@"fire-db"]; +} + +#pragma mark - FIRComponentRegistrant + ++ (NSArray *)componentsToRegister { + FIRDependency *authDep = + [FIRDependency dependencyWithProtocol:@protocol(FIRAuthInterop) + isRequired:NO]; + FIRComponentCreationBlock creationBlock = + ^id _Nullable(FIRComponentContainer *container, BOOL *isCacheable) { + *isCacheable = YES; + return [[FIRDatabaseComponent alloc] initWithApp:container.app]; + }; + FIRComponent *databaseProvider = + [FIRComponent componentWithProtocol:@protocol(FIRDatabaseProvider) + instantiationTiming:FIRInstantiationTimingLazy + dependencies:@[ authDep ] + creationBlock:creationBlock]; + return @[ databaseProvider ]; +} + +#pragma mark - Instance management. + +- (void)appWillBeDeleted:(FIRApp *)app { + NSString *appName = app.name; + if (appName == nil) { + return; + } + FIRDatabaseDictionary *instances = [self instances]; + @synchronized(instances) { + // Clean up the deleted instance in an effort to remove any resources + // still in use. Note: Any leftover instances of this exact database + // will be invalid. + for (FIRDatabase *database in [instances allValues]) { + [FRepoManager disposeRepos:database.config]; + } + [instances removeAllObjects]; + } +} + +#pragma mark - FIRDatabaseProvider Conformance + +- (FIRDatabase *)databaseForApp:(FIRApp *)app URL:(NSString *)url { + if (app == nil) { + [NSException raise:@"InvalidFIRApp" + format:@"nil FIRApp instance passed to databaseForApp."]; + } + + if (url == nil) { + [NSException raise:@"MissingDatabaseURL" + format:@"Failed to get FirebaseDatabase instance: " + "Specify DatabaseURL within FIRApp or from your " + "databaseForApp:URL: call."]; + } + + NSURL *databaseUrl = [NSURL URLWithString:url]; + + if (databaseUrl == nil) { + [NSException raise:@"InvalidDatabaseURL" + format:@"The Database URL '%@' cannot be parsed. " + "Specify a valid DatabaseURL within FIRApp or from " + "your databaseForApp:URL: call.", + url]; + } else if (![databaseUrl.path isEqualToString:@""] && + ![databaseUrl.path isEqualToString:@"/"]) { + [NSException + raise:@"InvalidDatabaseURL" + format:@"Configured Database URL '%@' is invalid. It should point " + "to the root of a Firebase Database but it includes a " + "path: %@", + databaseUrl, databaseUrl.path]; + } + + FIRDatabaseDictionary *instances = [self instances]; + @synchronized(instances) { + FParsedUrl *parsedUrl = + [FUtilities parseUrl:databaseUrl.absoluteString]; + NSString *urlIndex = + [NSString stringWithFormat:@"%@:%@", parsedUrl.repoInfo.host, + [parsedUrl.path toString]]; + FIRDatabase *database = instances[urlIndex]; + if (!database) { + id contextProvider = + [FIRDatabaseConnectionContextProvider + contextProviderWithAuth:FIR_COMPONENT(FIRAuthInterop, + app.container) + appCheck:FIR_COMPONENT(FIRAppCheckInterop, + app.container)]; + + // If this is the default app, don't set the session persistence key + // so that we use our default ("default") instead of the FIRApp + // default ("[DEFAULT]") so that we preserve the default location + // used by the legacy Firebase SDK. + NSString *sessionIdentifier = @"default"; + if (![FIRApp isDefaultAppConfigured] || + app != [FIRApp defaultApp]) { + sessionIdentifier = app.name; + } + + FIRDatabaseConfig *config = [[FIRDatabaseConfig alloc] + initWithSessionIdentifier:sessionIdentifier + googleAppID:app.options.googleAppID + contextProvider:contextProvider]; + database = [[FIRDatabase alloc] initWithApp:app + repoInfo:parsedUrl.repoInfo + config:config]; + instances[urlIndex] = database; + } + + return database; + } +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabaseConfig.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabaseConfig.h new file mode 100644 index 0000000..6e3ad25 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabaseConfig.h @@ -0,0 +1,72 @@ +/* + * 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 + +@protocol FIRDatabaseConnectionContextProvider; + +NS_ASSUME_NONNULL_BEGIN + +/** + * TODO: Merge FIRDatabaseConfig into FIRDatabase. + */ +@interface FIRDatabaseConfig : NSObject + +- (id)initWithSessionIdentifier:(NSString *)identifier + googleAppID:(NSString *)googleAppID + contextProvider: + (id)contextProvider; + +/** + * By default the Firebase Database client will keep data in memory while your + * application is running, but not when it is restarted. By setting this value + * to YES, the data will be persisted to on-device (disk) storage and will thus + * be available again when the app is restarted (even when there is no network + * connectivity at that time). Note that this property must be set before + * creating your first FIRDatabaseReference and only needs to be called once per + * application. + * + * If your app uses Firebase Authentication, the client will automatically + * persist the user's authentication token across restarts, even without + * persistence enabled. But if the auth token expired while offline and you've + * enabled persistence, the client will pause write operations until you + * successfully re-authenticate (or explicitly unauthenticate) to prevent your + * writes from being sent unauthenticated and failing due to security rules. + */ +@property(nonatomic) BOOL persistenceEnabled; + +/** + * By default the Firebase Database client will use up to 10MB of disk space to + * cache data. If the cache grows beyond this size, the client will start + * removing data that hasn't been recently used. If you find that your + * application caches too little or too much data, call this method to change + * the cache size. This property must be set before creating your first + * FIRDatabaseReference and only needs to be called once per application. + * + * Note that the specified cache size is only an approximation and the size on + * disk may temporarily exceed it at times. + */ +@property(nonatomic) NSUInteger persistenceCacheSizeBytes; + +/** + * Sets the dispatch queue on which all events are raised. The default queue is + * the main queue. + */ +@property(nonatomic, strong) dispatch_queue_t callbackQueue; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabaseConfig.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabaseConfig.m new file mode 100644 index 0000000..ad6202d --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabaseConfig.m @@ -0,0 +1,96 @@ +/* + * 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 "FirebaseDatabase/Sources/Api/FIRDatabaseConfig.h" + +#import "FirebaseDatabase/Sources/FIRDatabaseConfig_Private.h" +#import "FirebaseDatabase/Sources/Login/FIRDatabaseConnectionContextProvider.h" + +@interface FIRDatabaseConfig (Private) + +@property(nonatomic, strong, readwrite) NSString *sessionIdentifier; +@property(nonatomic, strong, readwrite) NSString *googleAppID; + +@end + +@implementation FIRDatabaseConfig + +- (id)init { + [NSException raise:NSInvalidArgumentException + format:@"Can't create config objects!"]; + return nil; +} + +- (id)initWithSessionIdentifier:(NSString *)identifier + googleAppID:(NSString *)googleAppID + contextProvider: + (id)contextProvider { + self = [super init]; + if (self != nil) { + self->_sessionIdentifier = identifier; + self->_callbackQueue = dispatch_get_main_queue(); + self->_googleAppID = googleAppID; + self->_persistenceCacheSizeBytes = + 10 * 1024 * 1024; // Default cache size is 10MB + self->_contextProvider = contextProvider; + } + return self; +} + +- (void)assertUnfrozen { + if (self.isFrozen) { + [NSException raise:NSGenericException + format:@"Can't modify config objects after they are in use " + @"for FIRDatabaseReferences."]; + } +} + +- (void)setContextProvider: + (id)contextProvider { + [self assertUnfrozen]; + self->_contextProvider = contextProvider; +} + +- (void)setPersistenceEnabled:(BOOL)persistenceEnabled { + [self assertUnfrozen]; + self->_persistenceEnabled = persistenceEnabled; +} + +- (void)setPersistenceCacheSizeBytes:(NSUInteger)persistenceCacheSizeBytes { + [self assertUnfrozen]; + // Can't be less than 1MB + if (persistenceCacheSizeBytes < 1024 * 1024) { + [NSException raise:NSInvalidArgumentException + format:@"The minimum cache size must be at least 1MB"]; + } + if (persistenceCacheSizeBytes > 100 * 1024 * 1024) { + [NSException raise:NSInvalidArgumentException + format:@"Firebase Database currently doesn't support a " + @"cache size larger than 100MB"]; + } + self->_persistenceCacheSizeBytes = persistenceCacheSizeBytes; +} + +- (void)setCallbackQueue:(dispatch_queue_t)callbackQueue { + [self assertUnfrozen]; + self->_callbackQueue = callbackQueue; +} + +- (void)freeze { + self->_isFrozen = YES; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabaseQuery.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabaseQuery.m new file mode 100644 index 0000000..d354a08 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRDatabaseQuery.m @@ -0,0 +1,767 @@ +/* + * 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 "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseQuery.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h" +#import "FirebaseDatabase/Sources/Constants/FConstants.h" +#import "FirebaseDatabase/Sources/Core/FQueryParams.h" +#import "FirebaseDatabase/Sources/Core/FQuerySpec.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Core/View/FChildEventRegistration.h" +#import "FirebaseDatabase/Sources/Core/View/FValueEventRegistration.h" +#import "FirebaseDatabase/Sources/FKeyIndex.h" +#import "FirebaseDatabase/Sources/FPathIndex.h" +#import "FirebaseDatabase/Sources/FPriorityIndex.h" +#import "FirebaseDatabase/Sources/FValueIndex.h" +#import "FirebaseDatabase/Sources/Snapshot/FLeafNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FNextPushId.h" +#import "FirebaseDatabase/Sources/Utilities/FValidation.h" + +@implementation FIRDatabaseQuery + +@synthesize repo; +@synthesize path; +@synthesize queryParams; + +#define INVALID_QUERY_PARAM_ERROR @"InvalidQueryParameter" + ++ (dispatch_queue_t)sharedQueue { + // We use this shared queue across all of the FQueries so things happen FIFO + // (as opposed to dispatch_get_global_queue(0, 0) which is concurrent) + static dispatch_once_t pred; + static dispatch_queue_t sharedDispatchQueue; + + dispatch_once(&pred, ^{ + sharedDispatchQueue = dispatch_queue_create("FirebaseWorker", NULL); + }); + + return sharedDispatchQueue; +} + +- (id)initWithRepo:(FRepo *)theRepo path:(FPath *)thePath { + return [self initWithRepo:theRepo + path:thePath + params:nil + orderByCalled:NO + priorityMethodCalled:NO]; +} + +- (id)initWithRepo:(FRepo *)theRepo + path:(FPath *)thePath + params:(FQueryParams *)theParams + orderByCalled:(BOOL)orderByCalled + priorityMethodCalled:(BOOL)priorityMethodCalled { + self = [super init]; + if (self) { + self.repo = theRepo; + self.path = thePath; + if (!theParams) { + theParams = [FQueryParams defaultInstance]; + } + if (![theParams isValid]) { + @throw [[NSException alloc] + initWithName:@"InvalidArgumentError" + reason:@"Queries are limited to two constraints" + userInfo:nil]; + } + self.queryParams = theParams; + self.orderByCalled = orderByCalled; + self.priorityMethodCalled = priorityMethodCalled; + } + return self; +} + +- (FQuerySpec *)querySpec { + return [[FQuerySpec alloc] initWithPath:self.path params:self.queryParams]; +} + +- (void)validateQueryEndpointsForParams:(FQueryParams *)params { + if ([params.index isEqual:[FKeyIndex keyIndex]]) { + if ([params hasStart]) { + if (params.indexStartKey != [FUtilities minName] && + params.indexStartKey != [FUtilities maxName]) { + [NSException raise:INVALID_QUERY_PARAM_ERROR + format:@"Can't use queryStartingAtValue:childKey:, " + @"queryStartingAfterValue:childKey:, " + @"or queryEqualTo:andChildKey: in " + @"combination with queryOrderedByKey"]; + } + if (![params.indexStartValue.val isKindOfClass:[NSString class]]) { + [NSException raise:INVALID_QUERY_PARAM_ERROR + format:@"Can't use queryStartingAtValue: or " + @"queryStartingAfterValue: " + @"with non-string types when used with " + @"queryOrderedByKey"]; + } + } + if ([params hasEnd]) { + if (params.indexEndKey != [FUtilities maxName] && + params.indexEndKey != [FUtilities minName]) { + [NSException raise:INVALID_QUERY_PARAM_ERROR + format:@"Can't use queryEndingAtValue:childKey: or " + @"queryEndingBeforeValue:childKey: " + @"queryEqualToValue:childKey: in " + @"combination with queryOrderedByKey"]; + } + if (![params.indexEndValue.val isKindOfClass:[NSString class]]) { + [NSException + raise:INVALID_QUERY_PARAM_ERROR + format:@"Can't use queryEndingAtValue: or " + @"queryEndingBeforeValue: " + @"with other types than string in combination with " + @"queryOrderedByKey"]; + } + } + } else if ([params.index isEqual:[FPriorityIndex priorityIndex]]) { + if (([params hasStart] && + ![FValidation validatePriorityValue:params.indexStartValue.val]) || + ([params hasEnd] && + ![FValidation validatePriorityValue:params.indexEndValue.val])) { + [NSException + raise:INVALID_QUERY_PARAM_ERROR + format:@"When using queryOrderedByPriority, values provided to " + @"queryStartingAtValue:, queryStartingAfterValue:, " + @"queryEndingAtValue:, queryEndingBeforeValue:, or " + @"queryEqualToValue: must be valid priorities."]; + } + } +} + +- (void)validateEqualToCall { + if ([self.queryParams hasStart]) { + [NSException + raise:INVALID_QUERY_PARAM_ERROR + format: + @"Cannot combine queryEqualToValue: and queryStartingAtValue: " + @"or queryStartingAfterValue:"]; + } + if ([self.queryParams hasEnd]) { + [NSException + raise:INVALID_QUERY_PARAM_ERROR + format:@"Cannot combine queryEqualToValue: and queryEndingAtValue: " + @"or queryEndingBeforeValue:"]; + } +} + +- (void)validateNoPreviousOrderByCalled { + if (self.orderByCalled) { + [NSException raise:INVALID_QUERY_PARAM_ERROR + format:@"Cannot use multiple queryOrderedBy calls!"]; + } +} + +- (void)validateIndexValueType:(id)type fromMethod:(NSString *)method { + if (type != nil && ![type isKindOfClass:[NSNumber class]] && + ![type isKindOfClass:[NSString class]] && + ![type isKindOfClass:[NSNull class]]) { + [NSException raise:INVALID_QUERY_PARAM_ERROR + format:@"You can only pass nil, NSString or NSNumber to %@", + method]; + } +} + +- (FIRDatabaseQuery *)queryStartingAtValue:(id)startValue { + return [self queryStartingAtInternal:startValue + childKey:nil + from:@"queryStartingAtValue:" + priorityMethod:NO]; +} + +- (FIRDatabaseQuery *)queryStartingAtValue:(id)startValue + childKey:(NSString *)childKey { + if ([self.queryParams.index isEqual:[FKeyIndex keyIndex]]) { + @throw [[NSException alloc] + initWithName:INVALID_QUERY_PARAM_ERROR + reason:@"You must use queryStartingAtValue: instead of " + @"queryStartingAtValue:childKey: when using " + @"queryOrderedByKey:" + userInfo:nil]; + } + NSString *methodName = @"queryStartingAtValue:childKey:"; + if (childKey != nil) { + [FValidation validateFrom:methodName validKey:childKey]; + } + return [self queryStartingAtInternal:startValue + childKey:childKey + from:methodName + priorityMethod:NO]; +} + +- (FIRDatabaseQuery *)queryStartingAfterValue:(id)startAfterValue { + return [self queryStartingAfterValue:startAfterValue childKey:nil]; +} + +- (FIRDatabaseQuery *)queryStartingAfterValue:(id)startAfterValue + childKey:(NSString *)childKey { + NSString *methodName = @"queryStartingAfterValue:childKey:"; + if ([self.queryParams.index isEqual:[FKeyIndex keyIndex]]) { + if (childKey != nil) { + @throw [[NSException alloc] + initWithName:INVALID_QUERY_PARAM_ERROR + reason: + @"You must use queryStartingAfterValue: instead of " + @"queryStartingAfterValue:childKey: when using " + @"queryOrderedByKey:" + userInfo:nil]; + } + if ([startAfterValue isKindOfClass:[NSString class]]) { + startAfterValue = [FNextPushId from:methodName + successor:startAfterValue]; + } + } else { + if (childKey == nil) { + childKey = [FUtilities maxName]; + } else { + childKey = [FNextPushId from:methodName successor:childKey]; + } + } + if (childKey != nil && ![childKey isEqual:[FUtilities maxName]]) { + [FValidation validateFrom:methodName validKey:childKey]; + } + return [self queryStartingAtInternal:startAfterValue + childKey:childKey + from:methodName + priorityMethod:NO]; +} + +- (FIRDatabaseQuery *)queryStartingAtInternal:(id)startValue + childKey:(NSString *)childKey + from:(NSString *)methodName + priorityMethod:(BOOL)priorityMethod { + [self validateIndexValueType:startValue fromMethod:methodName]; + if ([self.queryParams hasStart]) { + [NSException raise:INVALID_QUERY_PARAM_ERROR + format:@"Can't call %@ after queryStartingAtValue, " + @"queryStartingAfterValue, or " + @"queryEqualToValue was previously called", + methodName]; + } + id startNode = [FSnapshotUtilities nodeFrom:startValue]; + FQueryParams *params = [self.queryParams startAt:startNode + childKey:childKey]; + [self validateQueryEndpointsForParams:params]; + return [[FIRDatabaseQuery alloc] + initWithRepo:self.repo + path:self.path + params:params + orderByCalled:self.orderByCalled + priorityMethodCalled:priorityMethod || self.priorityMethodCalled]; +} + +- (FIRDatabaseQuery *)queryEndingAtValue:(id)endValue { + return [self queryEndingAtInternal:endValue + childKey:nil + from:@"queryEndingAtValue:" + priorityMethod:NO]; +} + +- (FIRDatabaseQuery *)queryEndingAtValue:(id)endValue + childKey:(NSString *)childKey { + if ([self.queryParams.index isEqual:[FKeyIndex keyIndex]]) { + @throw [[NSException alloc] + initWithName:INVALID_QUERY_PARAM_ERROR + reason:@"You must use queryEndingAtValue: instead of " + @"queryEndingAtValue:childKey: when using " + @"queryOrderedByKey:" + userInfo:nil]; + } + NSString *methodName = @"queryEndingAtValue:childKey:"; + if (childKey != nil) { + [FValidation validateFrom:methodName validKey:childKey]; + } + return [self queryEndingAtInternal:endValue + childKey:childKey + from:methodName + priorityMethod:NO]; +} + +- (FIRDatabaseQuery *)queryEndingBeforeValue:(id)endValue { + return [self queryEndingBeforeValue:endValue childKey:nil]; +} + +- (FIRDatabaseQuery *)queryEndingBeforeValue:(id)endValue + childKey:(NSString *)childKey { + NSString *methodName = @"queryEndingBeforeValue:childKey:"; + if ([self.queryParams.index isEqual:[FKeyIndex keyIndex]]) { + if (childKey != nil) { + @throw [[NSException alloc] + initWithName:INVALID_QUERY_PARAM_ERROR + reason:@"You must use queryEndingBeforeValue: instead of " + @"queryEndingBeforeValue:childKey: when using " + @"queryOrderedByKey:" + userInfo:nil]; + } + if ([endValue isKindOfClass:[NSString class]]) { + endValue = [FNextPushId from:methodName predecessor:endValue]; + } + } else { + if (childKey == nil) { + childKey = [FUtilities minName]; + } else { + childKey = [FNextPushId from:methodName predecessor:childKey]; + } + } + if (childKey != nil && ![childKey isEqual:[FUtilities minName]]) { + [FValidation validateFrom:methodName validKey:childKey]; + } + return [self queryEndingAtInternal:endValue + childKey:childKey + from:methodName + priorityMethod:NO]; +} + +- (FIRDatabaseQuery *)queryEndingAtInternal:(id)endValue + childKey:(NSString *)childKey + from:(NSString *)methodName + priorityMethod:(BOOL)priorityMethod { + [self validateIndexValueType:endValue fromMethod:methodName]; + if ([self.queryParams hasEnd]) { + [NSException raise:INVALID_QUERY_PARAM_ERROR + format:@"Can't call %@ after queryEndingAtValue or " + @"queryEqualToValue was previously called", + methodName]; + } + id endNode = [FSnapshotUtilities nodeFrom:endValue]; + FQueryParams *params = [self.queryParams endAt:endNode childKey:childKey]; + [self validateQueryEndpointsForParams:params]; + return [[FIRDatabaseQuery alloc] + initWithRepo:self.repo + path:self.path + params:params + orderByCalled:self.orderByCalled + priorityMethodCalled:priorityMethod || self.priorityMethodCalled]; +} + +- (FIRDatabaseQuery *)queryEqualToValue:(id)value { + return [self queryEqualToInternal:value + childKey:nil + from:@"queryEqualToValue:" + priorityMethod:NO]; +} + +- (FIRDatabaseQuery *)queryEqualToValue:(id)value + childKey:(NSString *)childKey { + if ([self.queryParams.index isEqual:[FKeyIndex keyIndex]]) { + @throw [[NSException alloc] + initWithName:INVALID_QUERY_PARAM_ERROR + reason:@"You must use queryEqualToValue: instead of " + @"queryEqualTo:childKey: when using queryOrderedByKey:" + userInfo:nil]; + } + return [self queryEqualToInternal:value + childKey:childKey + from:@"queryEqualToValue:childKey:" + priorityMethod:NO]; +} + +- (FIRDatabaseQuery *)queryEqualToInternal:(id)value + childKey:(NSString *)childKey + from:(NSString *)methodName + priorityMethod:(BOOL)priorityMethod { + [self validateIndexValueType:value fromMethod:methodName]; + if (childKey != nil) { + [FValidation validateFrom:methodName validKey:childKey]; + } + if ([self.queryParams hasEnd] || [self.queryParams hasStart]) { + [NSException raise:INVALID_QUERY_PARAM_ERROR + format:@"Can't call %@ after queryStartingAtValue, " + @"queryStartingAfterValue, queryEndingAtValue, " + @"queryEndingBeforeValue or queryEqualToValue " + @"was previously called", + methodName]; + } + id node = [FSnapshotUtilities nodeFrom:value]; + FQueryParams *params = [[self.queryParams startAt:node + childKey:childKey] endAt:node + childKey:childKey]; + [self validateQueryEndpointsForParams:params]; + return [[FIRDatabaseQuery alloc] + initWithRepo:self.repo + path:self.path + params:params + orderByCalled:self.orderByCalled + priorityMethodCalled:priorityMethod || self.priorityMethodCalled]; +} + +- (void)validateLimitRange:(NSUInteger)limit { + // No need to check for negative ranges, since limit is unsigned + if (limit == 0) { + [NSException raise:INVALID_QUERY_PARAM_ERROR + format:@"Limit can't be zero"]; + } + if (limit >= 1ul << 31) { + [NSException raise:INVALID_QUERY_PARAM_ERROR + format:@"Limit must be less than 2,147,483,648"]; + } +} + +- (FIRDatabaseQuery *)queryLimitedToFirst:(NSUInteger)limit { + if (self.queryParams.limitSet) { + [NSException raise:INVALID_QUERY_PARAM_ERROR + format:@"Can't call queryLimitedToFirst: if a limit was " + @"previously set"]; + } + [self validateLimitRange:limit]; + FQueryParams *params = [self.queryParams limitToFirst:limit]; + return [[FIRDatabaseQuery alloc] initWithRepo:self.repo + path:self.path + params:params + orderByCalled:self.orderByCalled + priorityMethodCalled:self.priorityMethodCalled]; +} + +- (FIRDatabaseQuery *)queryLimitedToLast:(NSUInteger)limit { + if (self.queryParams.limitSet) { + [NSException raise:INVALID_QUERY_PARAM_ERROR + format:@"Can't call queryLimitedToLast: if a limit was " + @"previously set"]; + } + [self validateLimitRange:limit]; + FQueryParams *params = [self.queryParams limitToLast:limit]; + return [[FIRDatabaseQuery alloc] initWithRepo:self.repo + path:self.path + params:params + orderByCalled:self.orderByCalled + priorityMethodCalled:self.priorityMethodCalled]; +} + +- (FIRDatabaseQuery *)queryOrderedByChild:(NSString *)indexPathString { + if ([indexPathString isEqualToString:@"$key"] || + [indexPathString isEqualToString:@".key"]) { + @throw [[NSException alloc] + initWithName:INVALID_QUERY_PARAM_ERROR + reason:[NSString stringWithFormat: + @"(queryOrderedByChild:) %@ is invalid. " + @" Use queryOrderedByKey: instead.", + indexPathString] + userInfo:nil]; + } else if ([indexPathString isEqualToString:@"$priority"] || + [indexPathString isEqualToString:@".priority"]) { + @throw [[NSException alloc] + initWithName:INVALID_QUERY_PARAM_ERROR + reason:[NSString stringWithFormat: + @"(queryOrderedByChild:) %@ is invalid. " + @" Use queryOrderedByPriority: instead.", + indexPathString] + userInfo:nil]; + } else if ([indexPathString isEqualToString:@"$value"] || + [indexPathString isEqualToString:@".value"]) { + @throw [[NSException alloc] + initWithName:INVALID_QUERY_PARAM_ERROR + reason:[NSString stringWithFormat: + @"(queryOrderedByChild:) %@ is invalid. " + @" Use queryOrderedByValue: instead.", + indexPathString] + userInfo:nil]; + } + [self validateNoPreviousOrderByCalled]; + + [FValidation validateFrom:@"queryOrderedByChild:" + validPathString:indexPathString]; + FPath *indexPath = [FPath pathWithString:indexPathString]; + if (indexPath.isEmpty) { + @throw [[NSException alloc] + initWithName:INVALID_QUERY_PARAM_ERROR + reason:[NSString + stringWithFormat:@"(queryOrderedByChild:) with an " + @"empty path is invalid. Use " + @"queryOrderedByValue: instead."] + userInfo:nil]; + } + id index = [[FPathIndex alloc] initWithPath:indexPath]; + + FQueryParams *params = [self.queryParams orderBy:index]; + [self validateQueryEndpointsForParams:params]; + return [[FIRDatabaseQuery alloc] initWithRepo:self.repo + path:self.path + params:params + orderByCalled:YES + priorityMethodCalled:self.priorityMethodCalled]; +} + +- (FIRDatabaseQuery *)queryOrderedByKey { + [self validateNoPreviousOrderByCalled]; + FQueryParams *params = [self.queryParams orderBy:[FKeyIndex keyIndex]]; + [self validateQueryEndpointsForParams:params]; + return [[FIRDatabaseQuery alloc] initWithRepo:self.repo + path:self.path + params:params + orderByCalled:YES + priorityMethodCalled:self.priorityMethodCalled]; +} + +- (FIRDatabaseQuery *)queryOrderedByValue { + [self validateNoPreviousOrderByCalled]; + FQueryParams *params = [self.queryParams orderBy:[FValueIndex valueIndex]]; + return [[FIRDatabaseQuery alloc] initWithRepo:self.repo + path:self.path + params:params + orderByCalled:YES + priorityMethodCalled:self.priorityMethodCalled]; +} + +- (FIRDatabaseQuery *)queryOrderedByPriority { + [self validateNoPreviousOrderByCalled]; + FQueryParams *params = + [self.queryParams orderBy:[FPriorityIndex priorityIndex]]; + return [[FIRDatabaseQuery alloc] initWithRepo:self.repo + path:self.path + params:params + orderByCalled:YES + priorityMethodCalled:self.priorityMethodCalled]; +} + +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + withBlock:(void (^)(FIRDataSnapshot *))block { + [FValidation validateFrom:@"observeEventType:withBlock:" + knownEventType:eventType]; + return [self observeEventType:eventType + withBlock:block + withCancelBlock:nil]; +} + +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock:(fbt_void_datasnapshot_nsstring)block { + [FValidation + validateFrom:@"observeEventType:andPreviousSiblingKeyWithBlock:" + knownEventType:eventType]; + return [self observeEventType:eventType + andPreviousSiblingKeyWithBlock:block + withCancelBlock:nil]; +} + +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + withBlock:(fbt_void_datasnapshot)block + withCancelBlock:(fbt_void_nserror)cancelBlock { + [FValidation validateFrom:@"observeEventType:withBlock:withCancelBlock:" + knownEventType:eventType]; + + if (eventType == FIRDataEventTypeValue) { + // Handle FIRDataEventTypeValue specially because they shouldn't have + // prevName callbacks + NSUInteger handle = [[FUtilities LUIDGenerator] integerValue]; + [self observeValueEventWithHandle:handle + withBlock:block + cancelCallback:cancelBlock]; + return handle; + } else { + // Wrap up the userCallback so we can treat everything as a callback + // that has a prevName + fbt_void_datasnapshot userCallback = [block copy]; + return [self observeEventType:eventType + andPreviousSiblingKeyWithBlock:^(FIRDataSnapshot *snapshot, + NSString *prevName) { + if (userCallback != nil) { + userCallback(snapshot); + } + } + withCancelBlock:cancelBlock]; + } +} + +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock:(fbt_void_datasnapshot_nsstring)block + withCancelBlock:(fbt_void_nserror)cancelBlock { + [FValidation validateFrom:@"observeEventType:" + @"andPreviousSiblingKeyWithBlock:withCancelBlock:" + knownEventType:eventType]; + + if (eventType == FIRDataEventTypeValue) { + // TODO: This gets hit by observeSingleEventOfType. Need to fix. + /* + @throw [[NSException alloc] initWithName:@"InvalidEventTypeForObserver" + reason:@"(observeEventType:andPreviousSiblingKeyWithBlock:withCancelBlock:) + Cannot use + observeEventType:andPreviousSiblingKeyWithBlock:withCancelBlock: with + FIRDataEventTypeValue. Use observeEventType:withBlock:withCancelBlock: + instead." userInfo:nil]; + */ + } + + NSUInteger handle = [[FUtilities LUIDGenerator] integerValue]; + NSDictionary *callbacks = + @{[NSNumber numberWithInteger:eventType] : [block copy]}; + [self observeChildEventWithHandle:handle + withCallbacks:callbacks + cancelCallback:cancelBlock]; + + return handle; +} + +// If we want to distinguish between value event listeners and child event +// listeners, like in the Java client, we can consider exporting this. If we do, +// add argument validation. Otherwise, arguments are validated in the +// public-facing portions of the API. Also, move the FIRDatabaseHandle logic. +- (void)observeValueEventWithHandle:(FIRDatabaseHandle)handle + withBlock:(fbt_void_datasnapshot)block + cancelCallback:(fbt_void_nserror)cancelBlock { + // Note that we don't need to copy the callbacks here, FEventRegistration + // callback properties set to copy + FValueEventRegistration *registration = + [[FValueEventRegistration alloc] initWithRepo:self.repo + handle:handle + callback:block + cancelCallback:cancelBlock]; + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self.repo addEventRegistration:registration forQuery:self.querySpec]; + }); +} + +// Note: as with the above method, we may wish to expose this at some point. +- (void)observeChildEventWithHandle:(FIRDatabaseHandle)handle + withCallbacks:(NSDictionary *)callbacks + cancelCallback:(fbt_void_nserror)cancelBlock { + // Note that we don't need to copy the callbacks here, FEventRegistration + // callback properties set to copy + FChildEventRegistration *registration = + [[FChildEventRegistration alloc] initWithRepo:self.repo + handle:handle + callbacks:callbacks + cancelCallback:cancelBlock]; + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self.repo addEventRegistration:registration forQuery:self.querySpec]; + }); +} + +- (void)removeObserverWithHandle:(FIRDatabaseHandle)handle { + FValueEventRegistration *event = + [[FValueEventRegistration alloc] initWithRepo:self.repo + handle:handle + callback:nil + cancelCallback:nil]; + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self.repo removeEventRegistration:event forQuery:self.querySpec]; + }); +} + +- (void)removeAllObservers { + [self removeObserverWithHandle:NSNotFound]; +} + +- (void)keepSynced:(BOOL)keepSynced { + if ([self.path.getFront isEqualToString:kDotInfoPrefix]) { + [NSException raise:NSInvalidArgumentException + format:@"Can't keep query on .info tree synced (this " + @"already is the case)."]; + } + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self.repo keepQuery:self.querySpec synced:keepSynced]; + }); +} + +- (void)getDataWithCompletionBlock: + (void (^)(NSError *__nullable error, + FIRDataSnapshot *__nullable snapshot))block { + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self.repo getData:self withCompletionBlock:block]; + }); +} + +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + withBlock:(fbt_void_datasnapshot)block { + + [self observeSingleEventOfType:eventType + withBlock:block + withCancelBlock:nil]; +} + +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock:(fbt_void_datasnapshot_nsstring)block { + + [self observeSingleEventOfType:eventType + andPreviousSiblingKeyWithBlock:block + withCancelBlock:nil]; +} + +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + withBlock:(fbt_void_datasnapshot)block + withCancelBlock:(fbt_void_nserror)cancelBlock { + + // XXX: user reported memory leak in method + + // "When you copy a block, any references to other blocks from within that + // block are copied if necessary—an entire tree may be copied (from the + // top). If you have block variables and you reference a block from within + // the block, that block will be copied." + // http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/Blocks/Articles/bxVariables.html#//apple_ref/doc/uid/TP40007502-CH6-SW1 + // So... we don't need to do this since inside the on: we copy this block + // off the stack to the heap. + // __block fbt_void_datasnapshot userCallback = [callback copy]; + + [self observeSingleEventOfType:eventType + andPreviousSiblingKeyWithBlock:^(FIRDataSnapshot *snapshot, + NSString *prevName) { + if (block != nil) { + block(snapshot); + } + } + withCancelBlock:cancelBlock]; +} + +/** + * Attaches a listener, waits for the first event, and then removes the listener + */ +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock:(fbt_void_datasnapshot_nsstring)block + withCancelBlock:(fbt_void_nserror)cancelBlock { + + // XXX: user reported memory leak in method + + // "When you copy a block, any references to other blocks from within that + // block are copied if necessary—an entire tree may be copied (from the + // top). If you have block variables and you reference a block from within + // the block, that block will be copied." + // http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/Blocks/Articles/bxVariables.html#//apple_ref/doc/uid/TP40007502-CH6-SW1 + // So... we don't need to do this since inside the on: we copy this block + // off the stack to the heap. + // __block fbt_void_datasnapshot userCallback = [callback copy]; + + __block FIRDatabaseHandle handle; + __block BOOL firstCall = YES; + + fbt_void_datasnapshot_nsstring callback = [block copy]; + fbt_void_datasnapshot_nsstring wrappedCallback = + ^(FIRDataSnapshot *snap, NSString *prevName) { + if (firstCall) { + firstCall = NO; + [self removeObserverWithHandle:handle]; + callback(snap, prevName); + } + }; + + fbt_void_nserror cancelCallback = [cancelBlock copy]; + handle = [self observeEventType:eventType + andPreviousSiblingKeyWithBlock:wrappedCallback + withCancelBlock:^(NSError *error) { + [self removeObserverWithHandle:handle]; + + if (cancelCallback) { + cancelCallback(error); + } + }]; +} + +- (NSString *)description { + return [NSString + stringWithFormat:@"(%@ %@)", self.path, self.queryParams.description]; +} + +- (FIRDatabaseReference *)ref { + return [[FIRDatabaseReference alloc] initWithRepo:self.repo path:self.path]; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRMutableData.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRMutableData.m new file mode 100644 index 0000000..c05e319 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRMutableData.m @@ -0,0 +1,149 @@ +/* + * 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 "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRMutableData.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRMutableData_Private.h" +#import "FirebaseDatabase/Sources/Core/FSnapshotHolder.h" +#import "FirebaseDatabase/Sources/FNamedNode.h" +#import "FirebaseDatabase/Sources/FTransformedEnumerator.h" +#import "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FIndexedNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h" + +@interface FIRMutableData () + +- (id)initWithPrefixPath:(FPath *)path + andSnapshotHolder:(FSnapshotHolder *)snapshotHolder; + +@property(strong, nonatomic) FSnapshotHolder *data; +@property(strong, nonatomic) FPath *prefixPath; + +@end + +@implementation FIRMutableData + +@synthesize data; +@synthesize prefixPath; + +- (id)initWithNode:(id)node { + FSnapshotHolder *holder = [[FSnapshotHolder alloc] init]; + FPath *path = [FPath empty]; + [holder updateSnapshot:path withNewSnapshot:node]; + return [self initWithPrefixPath:path andSnapshotHolder:holder]; +} + +- (id)initWithPrefixPath:(FPath *)path + andSnapshotHolder:(FSnapshotHolder *)snapshotHolder { + self = [super init]; + if (self) { + self.prefixPath = path; + self.data = snapshotHolder; + } + return self; +} + +- (FIRMutableData *)childDataByAppendingPath:(NSString *)path { + FPath *wholePath = [self.prefixPath childFromString:path]; + return [[FIRMutableData alloc] initWithPrefixPath:wholePath + andSnapshotHolder:self.data]; +} + +- (FIRMutableData *)parent { + if ([self.prefixPath isEmpty]) { + return nil; + } else { + FPath *path = [self.prefixPath parent]; + return [[FIRMutableData alloc] initWithPrefixPath:path + andSnapshotHolder:self.data]; + } +} + +- (void)setValue:(id)aValue { + id node = [FSnapshotUtilities nodeFrom:aValue + withValidationFrom:@"setValue:"]; + [self.data updateSnapshot:self.prefixPath withNewSnapshot:node]; +} + +- (void)setPriority:(id)aPriority { + id node = [self.data getNode:self.prefixPath]; + id pri = [FSnapshotUtilities nodeFrom:aPriority]; + node = [node updatePriority:pri]; + [self.data updateSnapshot:self.prefixPath withNewSnapshot:node]; +} + +- (id)value { + return [[self.data getNode:self.prefixPath] val]; +} + +- (id)priority { + return [[[self.data getNode:self.prefixPath] getPriority] val]; +} + +- (BOOL)hasChildren { + id node = [self.data getNode:self.prefixPath]; + return ![node isLeafNode] && ![(FChildrenNode *)node isEmpty]; +} + +- (BOOL)hasChildAtPath:(NSString *)path { + id node = [self.data getNode:self.prefixPath]; + FPath *childPath = [[FPath alloc] initWith:path]; + return ![[node getChild:childPath] isEmpty]; +} + +- (NSUInteger)childrenCount { + return [[self.data getNode:self.prefixPath] numChildren]; +} + +- (NSString *)key { + return [self.prefixPath getBack]; +} + +- (id)nodeValue { + return [self.data getNode:self.prefixPath]; +} + +- (NSEnumerator *)children { + FIndexedNode *indexedNode = + [FIndexedNode indexedNodeWithNode:self.nodeValue]; + return [[FTransformedEnumerator alloc] + initWithEnumerator:[indexedNode childEnumerator] + andTransform:^id(FNamedNode *node) { + FPath *childPath = [self.prefixPath childFromString:node.name]; + FIRMutableData *childData = + [[FIRMutableData alloc] initWithPrefixPath:childPath + andSnapshotHolder:self.data]; + return childData; + }]; +} + +- (BOOL)isEqualToData:(FIRMutableData *)other { + return self.data == other.data && + [[self.prefixPath description] + isEqualToString:[other.prefixPath description]]; +} + +- (NSString *)description { + if (self.key == nil) { + return [NSString + stringWithFormat:@"FIRMutableData (top-most transaction) %@ %@", + self.key, self.value]; + } else { + return [NSString + stringWithFormat:@"FIRMutableData (%@) %@", self.key, self.value]; + } +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRServerValue.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRServerValue.m new file mode 100644 index 0000000..9cbeedd --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRServerValue.m @@ -0,0 +1,33 @@ +/* + * 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 "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRServerValue.h" + +@implementation FIRServerValue + ++ (NSDictionary *)timestamp { + static NSDictionary *timestamp = nil; + if (timestamp == nil) { + timestamp = @{@".sv" : @"timestamp"}; + } + return timestamp; +} + ++ (NSDictionary *)increment:(NSNumber *)delta { + return @{@".sv" : @{@"increment" : delta}}; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRTransactionResult.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRTransactionResult.m new file mode 100644 index 0000000..dcc4e9a --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/FIRTransactionResult.m @@ -0,0 +1,39 @@ +/* + * 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 "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRTransactionResult.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRTransactionResult_Private.h" + +@implementation FIRTransactionResult + +@synthesize update; +@synthesize isSuccess; + ++ (FIRTransactionResult *)successWithValue:(FIRMutableData *)value { + FIRTransactionResult *result = [[FIRTransactionResult alloc] init]; + result.isSuccess = YES; + result.update = value; + return result; +} + ++ (FIRTransactionResult *)abort { + FIRTransactionResult *result = [[FIRTransactionResult alloc] init]; + result.isSuccess = NO; + result.update = nil; + return result; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRDataSnapshot_Private.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRDataSnapshot_Private.h new file mode 100644 index 0000000..bb006ff --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRDataSnapshot_Private.h @@ -0,0 +1,28 @@ +/* + * 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 "FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDataSnapshot.h" +#import "FirebaseDatabase/Sources/Snapshot/FIndexedNode.h" + +@interface FIRDataSnapshot () + +// in _Private for testing purposes +@property(nonatomic, strong) FIndexedNode *node; + +- (id)initWithRef:(FIRDatabaseReference *)ref indexedNode:(FIndexedNode *)node; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h new file mode 100644 index 0000000..0717e05 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h @@ -0,0 +1,43 @@ +/* + * 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 "FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h" +#import "FirebaseDatabase/Sources/Core/FQueryParams.h" +#import "FirebaseDatabase/Sources/Core/FRepo.h" +#import "FirebaseDatabase/Sources/Core/FRepoManager.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseQuery.h" + +@interface FIRDatabaseQuery () + ++ (dispatch_queue_t)sharedQueue; + +- (id)initWithRepo:(FRepo *)repo path:(FPath *)path; +- (id)initWithRepo:(FRepo *)repo + path:(FPath *)path + params:(FQueryParams *)params + orderByCalled:(BOOL)orderByCalled + priorityMethodCalled:(BOOL)priorityMethodCalled; + +@property(nonatomic, strong) FRepo *repo; +@property(nonatomic, strong) FPath *path; +@property(nonatomic, strong) FQueryParams *queryParams; +@property(nonatomic) BOOL orderByCalled; +@property(nonatomic) BOOL priorityMethodCalled; + +- (FQuerySpec *)querySpec; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRDatabaseReference_Private.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRDatabaseReference_Private.h new file mode 100644 index 0000000..fe1f6ee --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRDatabaseReference_Private.h @@ -0,0 +1,27 @@ +/* + * 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 "FirebaseDatabase/Sources/Api/FIRDatabaseConfig.h" +#import "FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h" +#import "FirebaseDatabase/Sources/Core/FRepo.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseReference.h" + +@interface FIRDatabaseReference () + +- (id)initWithConfig:(FIRDatabaseConfig *)config; +- (id)initWithRepo:(FRepo *)repo path:(FPath *)path; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRDatabase_Private.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRDatabase_Private.h new file mode 100644 index 0000000..fb202ec --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRDatabase_Private.h @@ -0,0 +1,37 @@ +/* + * 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 "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabase.h" + +@class FRepo; +@class FRepoInfo; +@class FIRDatabaseConfig; + +@interface FIRDatabase () + +@property(nonatomic, strong) FRepoInfo *repoInfo; +@property(nonatomic, strong) FIRDatabaseConfig *config; +@property(nonatomic, strong) FRepo *repo; + +- (id)initWithApp:(FIRApp *)app + repoInfo:(FRepoInfo *)info + config:(FIRDatabaseConfig *)config; + ++ (NSString *)buildVersion; ++ (FIRDatabase *)createDatabaseForTests:(FRepoInfo *)repoInfo + config:(FIRDatabaseConfig *)config; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRMutableData_Private.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRMutableData_Private.h new file mode 100644 index 0000000..f3bb2c6 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRMutableData_Private.h @@ -0,0 +1,26 @@ +/* + * 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 "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRMutableData.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" + +@interface FIRMutableData () + +- (id)initWithNode:(id)node; +- (id)nodeValue; +- (BOOL)isEqualToData:(FIRMutableData *)other; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRTransactionResult_Private.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRTransactionResult_Private.h new file mode 100644 index 0000000..ef8cd54 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FIRTransactionResult_Private.h @@ -0,0 +1,25 @@ +/* + * 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 "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRMutableData.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRTransactionResult.h" + +@interface FIRTransactionResult () + +@property(nonatomic) BOOL isSuccess; +@property(nonatomic, strong) FIRMutableData *update; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h new file mode 100644 index 0000000..3fe2bf6 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h @@ -0,0 +1,62 @@ +/* + * 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. + */ + +#ifndef __FTYPEDEFS_PRIVATE__ +#define __FTYPEDEFS_PRIVATE__ + +#import + +typedef NS_ENUM(NSInteger, FTransactionStatus) { + FTransactionInitializing, // 0 + FTransactionRun, // 1 + FTransactionSent, // 2 + FTransactionCompleted, // 3 + FTransactionSentNeedsAbort, // 4 + FTransactionNeedsAbort // 5 +}; + +@protocol FNode; +@class FPath; +@class FIRTransactionResult; +@class FIRMutableData; +@class FIRDataSnapshot; +@class FCompoundHash; + +typedef void (^fbt_void_nserror_bool_datasnapshot)(NSError *error, + BOOL committed, + FIRDataSnapshot *snapshot); +typedef FIRTransactionResult * (^fbt_transactionresult_mutabledata)( + FIRMutableData *currentData); +typedef void (^fbt_void_path_node)(FPath *, id); +typedef void (^fbt_void_nsstring)(NSString *); +typedef BOOL (^fbt_bool_nsstring_node)(NSString *, id); +typedef void (^fbt_void_path_node_marray)(FPath *, id, NSMutableArray *); +typedef BOOL (^fbt_bool_void)(void); +typedef void (^fbt_void_nsstring_nsstring)(NSString *str1, NSString *str2); +typedef void (^fbt_void_nsstring_id_nsstring)(NSString *str1, id dict1, + NSString *str2); +typedef void (^fbt_void_nsstring_nserror)(NSString *str, NSError *error); +typedef BOOL (^fbt_bool_path)(FPath *str); +typedef void (^fbt_void_id)(id data); +typedef NSString * (^fbt_nsstring_void)(void); +typedef FCompoundHash * (^fbt_compoundhash_void)(void); +typedef NSArray * (^fbt_nsarray_nsstring_id)(NSString *status, id Data); +typedef NSArray * (^fbt_nsarray_nsstring)(NSString *status); + +// WWDC 2012 session 712 starting in page 83 for saving blocks in properties +// (use @property (strong) type name). + +#endif diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Constants/FConstants.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Constants/FConstants.h new file mode 100644 index 0000000..51ad626 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Constants/FConstants.h @@ -0,0 +1,201 @@ +/* + * 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. + */ + +#ifndef Firebase_FConstants_h +#define Firebase_FConstants_h + +#import + +#pragma mark - +#pragma mark Wire Protocol Envelope Constants + +FOUNDATION_EXPORT NSString *const kFWPRequestType; +FOUNDATION_EXPORT NSString *const kFWPRequestTypeData; +FOUNDATION_EXPORT NSString *const kFWPRequestDataPayload; +FOUNDATION_EXPORT NSString *const kFWPRequestNumber; +FOUNDATION_EXPORT NSString *const kFWPRequestPayloadBody; +FOUNDATION_EXPORT NSString *const kFWPRequestError; +FOUNDATION_EXPORT NSString *const kFWPRequestAction; +FOUNDATION_EXPORT NSString *const kFWPResponseForRNData; +FOUNDATION_EXPORT NSString *const kFWPResponseForActionStatus; +FOUNDATION_EXPORT NSString *const kFWPResponseForActionStatusOk; +FOUNDATION_EXPORT NSString *const kFWPResponseForActionStatusFailed; +FOUNDATION_EXPORT NSString *const kFWPResponseForActionStatusDataStale; +FOUNDATION_EXPORT NSString *const kFWPResponseForActionData; +FOUNDATION_EXPORT NSString *const kFWPResponseDataWarnings; + +FOUNDATION_EXPORT NSString *const kFWPAsyncServerAction; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerPayloadBody; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerDataUpdate; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerDataMerge; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerDataRangeMerge; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerAuthRevoked; +FOUNDATION_EXPORT NSString *const kFWPASyncServerListenCancelled; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerSecurityDebug; +FOUNDATION_EXPORT NSString + *const kFWPAsyncServerDataUpdateBodyPath; // {"a": "d", "b": {"p": "/", "d": + // """}} +FOUNDATION_EXPORT NSString *const kFWPAsyncServerDataUpdateBodyData; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerDataUpdateStartPath; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerDataUpdateEndPath; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerDataUpdateRangeMerge; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerDataUpdateBodyTag; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerDataQueries; + +FOUNDATION_EXPORT NSString *const kFWPAsyncServerEnvelopeType; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerEnvelopeData; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerControlMessage; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerControlMessageType; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerControlMessageData; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerDataMessage; + +FOUNDATION_EXPORT NSString *const kFWPAsyncServerHello; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerHelloTimestamp; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerHelloVersion; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerHelloConnectedHost; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerHelloSession; + +FOUNDATION_EXPORT NSString *const kFWPAsyncServerControlMessageShutdown; +FOUNDATION_EXPORT NSString *const kFWPAsyncServerControlMessageReset; + +#pragma mark - +#pragma mark Wire Protocol Payload Constants + +FOUNDATION_EXPORT NSString *const kFWPRequestActionPut; +FOUNDATION_EXPORT NSString *const kFWPRequestActionMerge; +FOUNDATION_EXPORT NSString *const kFWPRequestActionGet; +FOUNDATION_EXPORT NSString *const kFWPRequestActionTaggedListen; +FOUNDATION_EXPORT NSString *const kFWPRequestActionTaggedUnlisten; +FOUNDATION_EXPORT NSString + *const kFWPRequestActionListen; // {"t": "d", "d": {"r": 1, "a": "l", "b": { + // "p": "/" } } } +FOUNDATION_EXPORT NSString *const kFWPRequestActionUnlisten; +FOUNDATION_EXPORT NSString *const kFWPRequestActionStats; +FOUNDATION_EXPORT NSString *const kFWPRequestActionDisconnectPut; +FOUNDATION_EXPORT NSString *const kFWPRequestActionDisconnectMerge; +FOUNDATION_EXPORT NSString *const kFWPRequestActionDisconnectCancel; +FOUNDATION_EXPORT NSString *const kFWPRequestActionAppCheck; +FOUNDATION_EXPORT NSString *const kFWPRequestActionAuth; +FOUNDATION_EXPORT NSString *const kFWPRequestActionUnauth; +FOUNDATION_EXPORT NSString *const kFWPRequestAppCheckToken; +FOUNDATION_EXPORT NSString *const kFWPRequestCredential; +FOUNDATION_EXPORT NSString *const kFWPRequestPath; +FOUNDATION_EXPORT NSString *const kFWPRequestCounters; +FOUNDATION_EXPORT NSString *const kFWPRequestQueries; +FOUNDATION_EXPORT NSString *const kFWPRequestTag; +FOUNDATION_EXPORT NSString *const kFWPRequestData; +FOUNDATION_EXPORT NSString *const kFWPRequestHash; +FOUNDATION_EXPORT NSString *const kFWPRequestCompoundHash; +FOUNDATION_EXPORT NSString *const kFWPRequestCompoundHashPaths; +FOUNDATION_EXPORT NSString *const kFWPRequestCompoundHashHashes; +FOUNDATION_EXPORT NSString *const kFWPRequestStatus; + +#pragma mark - +#pragma mark Websock Transport Constants + +FOUNDATION_EXPORT NSString *const kWireProtocolVersionParam; +FOUNDATION_EXPORT NSString *const kWebsocketProtocolVersion; +FOUNDATION_EXPORT NSString *const kWebsocketServerKillPacket; +FOUNDATION_EXPORT NSString *const kPersistentConnectionOffline; +FOUNDATION_EXPORT const int kWebsocketMaxFrameSize; +FOUNDATION_EXPORT NSUInteger const kWebsocketKeepaliveInterval; +FOUNDATION_EXPORT NSUInteger const kWebsocketConnectTimeout; +FOUNDATION_EXPORT UInt64 const kPersistentConnectionGetConnectTimeout; + +FOUNDATION_EXPORT float const kPersistentConnReconnectMinDelay; +FOUNDATION_EXPORT float const kPersistentConnReconnectMaxDelay; +FOUNDATION_EXPORT float const kPersistentConnReconnectMultiplier; +FOUNDATION_EXPORT float const + kPersistentConnSuccessfulConnectionEstablishedDelay; + +#pragma mark - +#pragma mark Query / QueryParams constants + +FOUNDATION_EXPORT NSString *const kQueryDefault; +FOUNDATION_EXPORT NSString *const kQueryDefaultObject; +FOUNDATION_EXPORT NSString *const kViewManagerDictConstView; +FOUNDATION_EXPORT NSString *const kFQPIndexStartValue; +FOUNDATION_EXPORT NSString *const kFQPIndexStartName; +FOUNDATION_EXPORT NSString *const kFQPIndexEndValue; +FOUNDATION_EXPORT NSString *const kFQPIndexEndName; +FOUNDATION_EXPORT NSString *const kFQPLimit; +FOUNDATION_EXPORT NSString *const kFQPViewFrom; +FOUNDATION_EXPORT NSString *const kFQPViewFromLeft; +FOUNDATION_EXPORT NSString *const kFQPViewFromRight; +FOUNDATION_EXPORT NSString *const kFQPIndex; + +#pragma mark - +#pragma mark Interrupt Reasons + +FOUNDATION_EXPORT NSString *const kFInterruptReasonServerKill; +FOUNDATION_EXPORT NSString *const kFInterruptReasonWaitingForOpen; +FOUNDATION_EXPORT NSString *const kFInterruptReasonRepoInterrupt; +FOUNDATION_EXPORT NSString *const kFInterruptReasonAuthExpired; + +#pragma mark - +#pragma mark Payload constants + +FOUNDATION_EXPORT NSString *const kPayloadPriority; +FOUNDATION_EXPORT NSString *const kPayloadValue; +FOUNDATION_EXPORT NSString *const kPayloadMetadataPrefix; + +#pragma mark - +#pragma mark ServerValue constants + +FOUNDATION_EXPORT NSString *const kServerValueSubKey; +FOUNDATION_EXPORT NSString *const kServerValuePriority; + +#pragma mark - +#pragma mark.info/ constants + +FOUNDATION_EXPORT NSString *const kDotInfoPrefix; +FOUNDATION_EXPORT NSString *const kDotInfoConnected; +FOUNDATION_EXPORT NSString *const kDotInfoServerTimeOffset; + +#pragma mark - +#pragma mark ObjectiveC to JavaScript type constants + +FOUNDATION_EXPORT NSString *const kJavaScriptObject; +FOUNDATION_EXPORT NSString *const kJavaScriptString; +FOUNDATION_EXPORT NSString *const kJavaScriptBoolean; +FOUNDATION_EXPORT NSString *const kJavaScriptNumber; +FOUNDATION_EXPORT NSString *const kJavaScriptNull; +FOUNDATION_EXPORT NSString *const kJavaScriptTrue; +FOUNDATION_EXPORT NSString *const kJavaScriptFalse; + +#pragma mark - +#pragma mark Error handling constants + +FOUNDATION_EXPORT NSString *const kFErrorDomain; +FOUNDATION_EXPORT NSUInteger const kFAuthError; +FOUNDATION_EXPORT NSString *const kFErrorWriteCanceled; + +#pragma mark - +#pragma mark Validation Constants + +FOUNDATION_EXPORT NSUInteger const kFirebaseMaxObjectDepth; +FOUNDATION_EXPORT const unsigned int kFirebaseMaxLeafSize; + +#pragma mark - +#pragma mark Transaction Constants + +FOUNDATION_EXPORT NSUInteger const kFTransactionMaxRetries; +FOUNDATION_EXPORT NSString *const kFTransactionTooManyRetries; +FOUNDATION_EXPORT NSString *const kFTransactionNoData; +FOUNDATION_EXPORT NSString *const kFTransactionSet; +FOUNDATION_EXPORT NSString *const kFTransactionDisconnect; + +#endif diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Constants/FConstants.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Constants/FConstants.m new file mode 100644 index 0000000..08b769c --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Constants/FConstants.m @@ -0,0 +1,191 @@ +/* + * 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 "FirebaseDatabase/Sources/Constants/FConstants.h" + +#pragma mark - +#pragma mark Wire Protocol Envelope Constants + +NSString *const kFWPRequestType = @"t"; +NSString *const kFWPRequestTypeData = @"d"; +NSString *const kFWPRequestDataPayload = @"d"; +NSString *const kFWPRequestNumber = @"r"; +NSString *const kFWPRequestPayloadBody = @"b"; +NSString *const kFWPRequestError = @"error"; +NSString *const kFWPRequestAction = @"a"; +NSString *const kFWPResponseForRNData = @"b"; +NSString *const kFWPResponseForActionStatus = @"s"; +NSString *const kFWPResponseForActionStatusOk = @"ok"; +NSString *const kFWPResponseForActionStatusFailed = @"failed"; +NSString *const kFWPResponseForActionStatusDataStale = @"datastale"; +NSString *const kFWPResponseForActionData = @"d"; +NSString *const kFWPResponseDataWarnings = @"w"; +NSString *const kFWPAsyncServerAction = @"a"; +NSString *const kFWPAsyncServerPayloadBody = @"b"; +NSString *const kFWPAsyncServerDataUpdate = @"d"; +NSString *const kFWPAsyncServerDataMerge = @"m"; +NSString *const kFWPAsyncServerDataRangeMerge = @"rm"; +NSString *const kFWPAsyncServerAuthRevoked = @"ac"; +NSString *const kFWPASyncServerListenCancelled = @"c"; +NSString *const kFWPAsyncServerSecurityDebug = @"sd"; +NSString *const kFWPAsyncServerDataUpdateBodyPath = + @"p"; // {"a": "d", "b": {"p": "/", "d": ""}} +NSString *const kFWPAsyncServerDataUpdateBodyData = @"d"; +NSString *const kFWPAsyncServerDataUpdateStartPath = @"s"; +NSString *const kFWPAsyncServerDataUpdateEndPath = @"e"; +NSString *const kFWPAsyncServerDataUpdateRangeMerge = @"m"; +NSString *const kFWPAsyncServerDataUpdateBodyTag = @"t"; +NSString *const kFWPAsyncServerDataQueries = @"q"; + +NSString *const kFWPAsyncServerEnvelopeType = @"t"; +NSString *const kFWPAsyncServerEnvelopeData = @"d"; +NSString *const kFWPAsyncServerControlMessage = @"c"; +NSString *const kFWPAsyncServerControlMessageType = @"t"; +NSString *const kFWPAsyncServerControlMessageData = @"d"; +NSString *const kFWPAsyncServerDataMessage = @"d"; + +NSString *const kFWPAsyncServerHello = @"h"; +NSString *const kFWPAsyncServerHelloTimestamp = @"ts"; +NSString *const kFWPAsyncServerHelloVersion = @"v"; +NSString *const kFWPAsyncServerHelloConnectedHost = @"h"; +NSString *const kFWPAsyncServerHelloSession = @"s"; + +NSString *const kFWPAsyncServerControlMessageShutdown = @"s"; +NSString *const kFWPAsyncServerControlMessageReset = @"r"; + +#pragma mark - +#pragma mark Wire Protocol Payload Constants + +NSString *const kFWPRequestActionPut = @"p"; +NSString *const kFWPRequestActionMerge = @"m"; +NSString *const kFWPRequestActionGet = @"g"; +NSString *const kFWPRequestActionListen = + @"l"; // {"t": "d", "d": {"r": 1, "a": "l", "b": { "p": "/" } } } +NSString *const kFWPRequestActionUnlisten = @"u"; +NSString *const kFWPRequestActionStats = @"s"; +NSString *const kFWPRequestActionTaggedListen = @"q"; +NSString *const kFWPRequestActionTaggedUnlisten = @"n"; +NSString *const kFWPRequestActionDisconnectPut = @"o"; +NSString *const kFWPRequestActionDisconnectMerge = @"om"; +NSString *const kFWPRequestActionDisconnectCancel = @"oc"; +NSString *const kFWPRequestActionAuth = @"auth"; +NSString *const kFWPRequestActionAppCheck = @"appcheck"; +NSString *const kFWPRequestActionUnauth = @"unauth"; +NSString *const kFWPRequestAppCheckToken = @"token"; +NSString *const kFWPRequestCredential = @"cred"; +NSString *const kFWPRequestPath = @"p"; +NSString *const kFWPRequestCounters = @"c"; +NSString *const kFWPRequestQueries = @"q"; +NSString *const kFWPRequestTag = @"t"; +NSString *const kFWPRequestData = @"d"; +NSString *const kFWPRequestHash = @"h"; +NSString *const kFWPRequestCompoundHash = @"ch"; +NSString *const kFWPRequestCompoundHashPaths = @"ps"; +NSString *const kFWPRequestCompoundHashHashes = @"hs"; +NSString *const kFWPRequestStatus = @"s"; + +#pragma mark - +#pragma mark Websock Transport Constants + +NSString *const kWireProtocolVersionParam = @"v"; +NSString *const kWebsocketProtocolVersion = @"5"; +NSString *const kWebsocketServerKillPacket = @"kill"; +NSString *const kPersistentConnectionOffline = @"Client is offline."; +const int kWebsocketMaxFrameSize = 16384; +NSUInteger const kWebsocketKeepaliveInterval = 45; +NSUInteger const kWebsocketConnectTimeout = 30; +UInt64 const kPersistentConnectionGetConnectTimeout = 3 * NSEC_PER_SEC; + +float const kPersistentConnReconnectMinDelay = 1.0; +float const kPersistentConnReconnectMaxDelay = 30.0; +float const kPersistentConnReconnectMultiplier = 1.3f; +float const kPersistentConnSuccessfulConnectionEstablishedDelay = 30.0; + +#pragma mark - +#pragma mark Query constants + +NSString *const kQueryDefault = @"default"; +NSString *const kQueryDefaultObject = @"{}"; +NSString *const kViewManagerDictConstView = @"view"; +NSString *const kFQPIndexStartValue = @"sp"; +NSString *const kFQPIndexStartName = @"sn"; +NSString *const kFQPIndexEndValue = @"ep"; +NSString *const kFQPIndexEndName = @"en"; +NSString *const kFQPLimit = @"l"; +NSString *const kFQPViewFrom = @"vf"; +NSString *const kFQPViewFromLeft = @"l"; +NSString *const kFQPViewFromRight = @"r"; +NSString *const kFQPIndex = @"i"; + +#pragma mark - +#pragma mark Interrupt Reasons + +NSString *const kFInterruptReasonServerKill = @"server_kill"; +NSString *const kFInterruptReasonWaitingForOpen = @"waiting_for_open"; +NSString *const kFInterruptReasonRepoInterrupt = @"repo_interrupt"; + +#pragma mark - +#pragma mark Payload constants + +NSString *const kPayloadPriority = @".priority"; +NSString *const kPayloadValue = @".value"; +NSString *const kPayloadMetadataPrefix = @"."; + +#pragma mark - +#pragma mark ServerValue constants + +NSString *const kServerValueSubKey = @".sv"; +NSString *const kServerValuePriority = @"timestamp"; + +#pragma mark - +#pragma mark.info/ constants + +NSString *const kDotInfoPrefix = @".info"; +NSString *const kDotInfoConnected = @"connected"; +NSString *const kDotInfoServerTimeOffset = @"serverTimeOffset"; + +#pragma mark - +#pragma mark ObjectiveC to JavaScript type constants + +NSString *const kJavaScriptObject = @"object"; +NSString *const kJavaScriptString = @"string"; +NSString *const kJavaScriptBoolean = @"boolean"; +NSString *const kJavaScriptNumber = @"number"; +NSString *const kJavaScriptNull = @"null"; +NSString *const kJavaScriptTrue = @"true"; +NSString *const kJavaScriptFalse = @"false"; + +#pragma mark - +#pragma mark Error handling constants + +NSString *const kFErrorDomain = @"com.firebase"; +NSUInteger const kFAuthError = 1; +NSString *const kFErrorWriteCanceled = @"write_canceled"; + +#pragma mark - +#pragma mark Validation Constants + +NSUInteger const kFirebaseMaxObjectDepth = 1000; +const unsigned int kFirebaseMaxLeafSize = 1024 * 1024 * 10; // 10 MB + +#pragma mark - +#pragma mark Transaction Constants + +NSUInteger const kFTransactionMaxRetries = 25; +NSString *const kFTransactionTooManyRetries = @"maxretry"; +NSString *const kFTransactionNoData = @"nodata"; +NSString *const kFTransactionSet = @"set"; +NSString *const kFTransactionDisconnect = @"disconnect"; diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FCompoundHash.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FCompoundHash.h new file mode 100644 index 0000000..a144c3e --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FCompoundHash.h @@ -0,0 +1,38 @@ +/* + * 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 + +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" + +@interface FCompoundHashBuilder : NSObject + +- (FPath *)currentPath; + +@end + +typedef BOOL (^FCompoundHashSplitStrategy)(FCompoundHashBuilder *builder); + +@interface FCompoundHash : NSObject + +@property(nonatomic, strong, readonly) NSArray *posts; +@property(nonatomic, strong, readonly) NSArray *hashes; + ++ (FCompoundHash *)fromNode:(id)node; ++ (FCompoundHash *)fromNode:(id)node + splitStrategy:(FCompoundHashSplitStrategy)strategy; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FCompoundHash.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FCompoundHash.m new file mode 100644 index 0000000..dbe6cb9 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FCompoundHash.m @@ -0,0 +1,259 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/FCompoundHash.h" +#import "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FLeafNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FStringUtilities.h" + +@interface FCompoundHashBuilder () + +@property(nonatomic, strong) FCompoundHashSplitStrategy splitStrategy; + +@property(nonatomic, strong) NSMutableArray *currentPaths; +@property(nonatomic, strong) NSMutableArray *currentHashes; + +@end + +@implementation FCompoundHashBuilder { + + // NOTE: We use the existence of this to know if we've started building a + // range (i.e. encountered a leaf node). + NSMutableString *optHashValueBuilder; + + // The current path as a stack. This is used in combination with + // currentPathDepth to simultaneously store the last leaf node path. The + // depth is changed when descending and ascending, at the same time the + // current key is set for the current depth. Because the keys are left + // unchanged for ascending the path will also contain the path of the last + // visited leaf node (using lastLeafDepth elements) + NSMutableArray *currentPath; + NSInteger lastLeafDepth; + NSInteger currentPathDepth; + + BOOL needsComma; +} + +- (instancetype)initWithSplitStrategy:(FCompoundHashSplitStrategy)strategy { + self = [super init]; + if (self != nil) { + self->_splitStrategy = strategy; + self->optHashValueBuilder = nil; + self->currentPath = [NSMutableArray array]; + self->lastLeafDepth = -1; + self->currentPathDepth = 0; + self->needsComma = YES; + self->_currentPaths = [NSMutableArray array]; + self->_currentHashes = [NSMutableArray array]; + } + return self; +} + +- (BOOL)isBuildingRange { + return self->optHashValueBuilder != nil; +} + +- (NSUInteger)currentHashLength { + return self->optHashValueBuilder.length; +} + +- (FPath *)currentPath { + return [self currentPathWithDepth:self->currentPathDepth]; +} + +- (FPath *)currentPathWithDepth:(NSInteger)depth { + NSArray *pieces = + [self->currentPath subarrayWithRange:NSMakeRange(0, depth)]; + return [[FPath alloc] initWithPieces:pieces andPieceNum:0]; +} + +- (void)enumerateCurrentPathToDepth:(NSInteger)depth + withBlock:(void (^)(NSString *key))block { + for (NSInteger i = 0; i < depth; i++) { + block(self->currentPath[i]); + } +} + +- (void)appendKey:(NSString *)key toString:(NSMutableString *)string { + [FSnapshotUtilities appendHashV2RepresentationForString:key + toString:string]; +} + +- (void)ensureRange { + if (![self isBuildingRange]) { + optHashValueBuilder = [NSMutableString string]; + [optHashValueBuilder appendString:@"("]; + [self + enumerateCurrentPathToDepth:self->currentPathDepth + withBlock:^(NSString *key) { + [self appendKey:key + toString:self->optHashValueBuilder]; + [self->optHashValueBuilder appendString:@":("]; + }]; + self->needsComma = NO; + } +} + +- (void)processLeaf:(FLeafNode *)leafNode { + [self ensureRange]; + + self->lastLeafDepth = self->currentPathDepth; + [FSnapshotUtilities + appendHashRepresentationForLeafNode:leafNode + toString:self->optHashValueBuilder + hashVersion:FDataHashVersionV2]; + self->needsComma = YES; + if (self.splitStrategy(self)) { + [self endRange]; + } +} + +- (void)startChild:(NSString *)key { + [self ensureRange]; + + if (self->needsComma) { + [self->optHashValueBuilder appendString:@","]; + } + [self appendKey:key toString:self->optHashValueBuilder]; + [self->optHashValueBuilder appendString:@":("]; + if (self->currentPathDepth == currentPath.count) { + [self->currentPath addObject:key]; + } else { + self->currentPath[self->currentPathDepth] = key; + } + self->currentPathDepth++; + self->needsComma = NO; +} + +- (void)endChild { + self->currentPathDepth--; + if ([self isBuildingRange]) { + [self->optHashValueBuilder appendString:@")"]; + } + self->needsComma = YES; +} + +- (void)finishHashing { + NSAssert(self->currentPathDepth == 0, + @"Can't finish hashing in the middle of processing a child"); + if ([self isBuildingRange]) { + [self endRange]; + } + + // Always close with the empty hash for the remaining range to allow simple + // appending + [self.currentHashes addObject:@""]; +} + +- (void)endRange { + NSAssert([self isBuildingRange], + @"Can't end range without starting a range!"); + // Add closing parenthesis for current depth + for (NSUInteger i = 0; i < currentPathDepth; i++) { + [self->optHashValueBuilder appendString:@")"]; + } + [self->optHashValueBuilder appendString:@")"]; + + FPath *lastLeafPath = [self currentPathWithDepth:self->lastLeafDepth]; + NSString *hash = + [FStringUtilities base64EncodedSha1:self->optHashValueBuilder]; + [self.currentHashes addObject:hash]; + [self.currentPaths addObject:lastLeafPath]; + + self->optHashValueBuilder = nil; +} + +@end + +@interface FCompoundHash () + +@property(nonatomic, strong, readwrite) NSArray *posts; +@property(nonatomic, strong, readwrite) NSArray *hashes; + +@end + +@implementation FCompoundHash + +- (id)initWithPosts:(NSArray *)posts hashes:(NSArray *)hashes { + self = [super init]; + if (self != nil) { + if (posts.count != hashes.count - 1) { + [NSException raise:NSInvalidArgumentException + format:@"Number of posts need to be n-1 for n hashes " + @"in FCompoundHash"]; + } + self.posts = posts; + self.hashes = hashes; + } + return self; +} + ++ (FCompoundHashSplitStrategy)simpleSizeSplitStrategyForNode:(id)node { + NSUInteger estimatedSize = + [FSnapshotUtilities estimateSerializedNodeSize:node]; + + // Splits for + // 1k -> 512 (2 parts) + // 5k -> 715 (7 parts) + // 100k -> 3.2k (32 parts) + // 500k -> 7k (71 parts) + // 5M -> 23k (228 parts) + NSUInteger splitThreshold = MAX(512, (NSUInteger)sqrt(estimatedSize * 100)); + + return ^BOOL(FCompoundHashBuilder *builder) { + // Never split on priorities + return [builder currentHashLength] > splitThreshold && + ![[[builder currentPath] getBack] isEqualToString:@".priority"]; + }; +} + ++ (FCompoundHash *)fromNode:(id)node { + return [FCompoundHash + fromNode:node + splitStrategy:[FCompoundHash simpleSizeSplitStrategyForNode:node]]; +} + ++ (FCompoundHash *)fromNode:(id)node + splitStrategy:(FCompoundHashSplitStrategy)strategy { + if ([node isEmpty]) { + return [[FCompoundHash alloc] initWithPosts:@[] hashes:@[ @"" ]]; + } else { + FCompoundHashBuilder *builder = + [[FCompoundHashBuilder alloc] initWithSplitStrategy:strategy]; + [FCompoundHash processNode:node builder:builder]; + [builder finishHashing]; + return [[FCompoundHash alloc] initWithPosts:builder.currentPaths + hashes:builder.currentHashes]; + } +} + ++ (void)processNode:(id)node builder:(FCompoundHashBuilder *)builder { + if ([node isLeafNode]) { + [builder processLeaf:node]; + } else { + NSAssert(![node isEmpty], @"Can't calculate hash on empty node!"); + FChildrenNode *childrenNode = (FChildrenNode *)node; + [childrenNode enumerateChildrenAndPriorityUsingBlock:^( + NSString *key, id node, BOOL *stop) { + [builder startChild:key]; + [self processNode:node builder:builder]; + [builder endChild]; + }]; + } +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FListenProvider.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FListenProvider.h new file mode 100644 index 0000000..093b6af --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FListenProvider.h @@ -0,0 +1,32 @@ +/* + * 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 "FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h" + +@class FQuerySpec; +@protocol FSyncTreeHash; + +typedef NSArray * (^fbt_startListeningBlock)(FQuerySpec *query, NSNumber *tagId, + id hash, + fbt_nsarray_nsstring onComplete); +typedef void (^fbt_stopListeningBlock)(FQuerySpec *query, NSNumber *tagId); + +@interface FListenProvider : NSObject + +@property(nonatomic, copy) fbt_startListeningBlock startListening; +@property(nonatomic, copy) fbt_stopListeningBlock stopListening; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FListenProvider.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FListenProvider.m new file mode 100644 index 0000000..d0dee79 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FListenProvider.m @@ -0,0 +1,25 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/FListenProvider.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseQuery.h" + +@implementation FListenProvider + +@synthesize startListening; +@synthesize stopListening; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FPersistentConnection.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FPersistentConnection.h new file mode 100644 index 0000000..592b5d0 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FPersistentConnection.h @@ -0,0 +1,103 @@ +/* + * 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 "FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h" +#import "FirebaseDatabase/Sources/Core/FRepoInfo.h" +#import "FirebaseDatabase/Sources/Realtime/FConnection.h" +#import "FirebaseDatabase/Sources/Utilities/FTypedefs.h" +#import + +@protocol FPersistentConnectionDelegate; +@protocol FSyncTreeHash; +@class FQuerySpec; +@class FIRDatabaseConfig; + +@interface FPersistentConnection : NSObject + +@property(nonatomic, weak) id delegate; +@property(nonatomic) BOOL pauseWrites; + +- (id)initWithRepoInfo:(FRepoInfo *)repoInfo + dispatchQueue:(dispatch_queue_t)queue + config:(FIRDatabaseConfig *)config; + +- (void)open; + +- (void)putData:(id)data + forPath:(NSString *)pathString + withHash:(NSString *)hash + withCallback:(fbt_void_nsstring_nsstring)onComplete; +- (void)mergeData:(id)data + forPath:(NSString *)pathString + withCallback:(fbt_void_nsstring_nsstring)onComplete; + +- (void)listen:(FQuerySpec *)query + tagId:(NSNumber *)tagId + hash:(id)hash + onComplete:(fbt_void_nsstring)onComplete; + +- (void)unlisten:(FQuerySpec *)query tagId:(NSNumber *)tagId; +- (void)refreshAuthToken:(NSString *)token; +- (void)refreshAppCheckToken:(NSString *)token; +- (void)onDisconnectPutData:(id)data + forPath:(FPath *)path + withCallback:(fbt_void_nsstring_nsstring)callback; +- (void)onDisconnectMergeData:(id)data + forPath:(FPath *)path + withCallback:(fbt_void_nsstring_nsstring)callback; +- (void)onDisconnectCancelPath:(FPath *)path + withCallback:(fbt_void_nsstring_nsstring)callback; +- (void)ackPuts; +- (void)getDataAtPath:(NSString *)pathString + withParams:(NSDictionary *)queryWireProtocolParams + withCallback:(fbt_void_nsstring_id_nsstring)onComplete; +- (void)purgeOutstandingWrites; + +- (void)interruptForReason:(NSString *)reason; +- (void)resumeForReason:(NSString *)reason; +- (BOOL)isInterruptedForReason:(NSString *)reason; + +// FConnection delegate methods +- (void)onReady:(FConnection *)fconnection + atTime:(NSNumber *)timestamp + sessionID:(NSString *)sessionID; +- (void)onDataMessage:(FConnection *)fconnection + withMessage:(NSDictionary *)message; +- (void)onDisconnect:(FConnection *)fconnection + withReason:(FDisconnectReason)reason; +- (void)onKill:(FConnection *)fconnection withReason:(NSString *)reason; + +// Testing methods +- (NSDictionary *)dumpListens; + +@end + +@protocol FPersistentConnectionDelegate + +- (void)onDataUpdate:(FPersistentConnection *)fpconnection + forPath:(NSString *)pathString + message:(id)message + isMerge:(BOOL)isMerge + tagId:(NSNumber *)tagId; +- (void)onRangeMerge:(NSArray *)ranges + forPath:(NSString *)path + tagId:(NSNumber *)tag; +- (void)onConnect:(FPersistentConnection *)fpconnection; +- (void)onDisconnect:(FPersistentConnection *)fpconnection; +- (void)onServerInfoUpdate:(FPersistentConnection *)fpconnection + updates:(NSDictionary *)updates; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FPersistentConnection.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FPersistentConnection.m new file mode 100644 index 0000000..045405d --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FPersistentConnection.m @@ -0,0 +1,1334 @@ +/* + * 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 + +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" +#import "FirebaseDatabase/Sources/Api/FIRDatabaseConfig.h" +#import "FirebaseDatabase/Sources/Constants/FConstants.h" +#import "FirebaseDatabase/Sources/Core/FCompoundHash.h" +#import "FirebaseDatabase/Sources/Core/FPersistentConnection.h" +#import "FirebaseDatabase/Sources/Core/FQueryParams.h" +#import "FirebaseDatabase/Sources/Core/FQuerySpec.h" +#import "FirebaseDatabase/Sources/Core/FRangeMerge.h" +#import "FirebaseDatabase/Sources/Core/FSyncTree.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FIRRetryHelper.h" +#import "FirebaseDatabase/Sources/FIRDatabaseConfig_Private.h" +#import "FirebaseDatabase/Sources/FIndex.h" +#import "FirebaseDatabase/Sources/Login/FIRDatabaseConnectionContextProvider.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseReference.h" +#import "FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FAtomicNumber.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/Tuples/FTupleCallbackStatus.h" +#import "FirebaseDatabase/Sources/Utilities/Tuples/FTupleOnDisconnect.h" +#if TARGET_OS_WATCH +#import +#else +#import +#endif // TARGET_OS_WATCH +#import +#import + +@interface FOutstandingQuery : NSObject + +@property(nonatomic, strong) FQuerySpec *query; +@property(nonatomic, strong) NSNumber *tagId; +@property(nonatomic, strong) id syncTreeHash; +@property(nonatomic, copy) fbt_void_nsstring onComplete; + +@end + +@implementation FOutstandingQuery + +@end + +@interface FOutstandingPut : NSObject + +@property(nonatomic, strong) NSString *action; +@property(nonatomic, strong) NSDictionary *request; +@property(nonatomic, copy) fbt_void_nsstring_nsstring onCompleteBlock; +@property(nonatomic) BOOL sent; + +@end + +@implementation FOutstandingPut + +@end + +@interface FOutstandingGet : NSObject + +@property(nonatomic, strong) NSDictionary *request; +@property(nonatomic, copy) fbt_void_nsstring_id_nsstring onCompleteBlock; +@property(nonatomic) BOOL sent; + +@end + +@implementation FOutstandingGet + +@end + +typedef enum { + ConnectionStateDisconnected, + ConnectionStateGettingToken, + ConnectionStateConnecting, + ConnectionStateAuthenticating, + ConnectionStateConnected +} ConnectionState; + +@interface FPersistentConnection () { + ConnectionState connectionState; + BOOL firstConnection; + NSTimeInterval reconnectDelay; + NSTimeInterval lastConnectionAttemptTime; + NSTimeInterval lastConnectionEstablishedTime; +#if !TARGET_OS_WATCH + SCNetworkReachabilityRef reachability; +#endif // !TARGET_OS_WATCH +} + +- (int)getNextRequestNumber; +- (void)onDataPushWithAction:(NSString *)action andBody:(NSDictionary *)body; +- (void)handleTimestamp:(NSNumber *)timestamp; +- (void)sendOnDisconnectAction:(NSString *)action + forPath:(NSString *)pathString + withData:(id)data + andCallback:(fbt_void_nsstring_nsstring)callback; + +@property(nonatomic, strong) FConnection *realtime; +@property(nonatomic, strong) NSMutableDictionary *listens; +@property(nonatomic, strong) NSMutableDictionary *outstandingPuts; +@property(nonatomic, strong) NSMutableDictionary *outstandingGets; +@property(nonatomic, strong) NSMutableArray *onDisconnectQueue; +@property(nonatomic, strong) FRepoInfo *repoInfo; +@property(nonatomic, strong) FAtomicNumber *putCounter; +@property(nonatomic, strong) FAtomicNumber *getCounter; +@property(nonatomic, strong) FAtomicNumber *requestNumber; +@property(nonatomic, strong) NSMutableDictionary *requestCBHash; +@property(nonatomic, strong) FIRDatabaseConfig *config; +@property(nonatomic) NSUInteger unackedListensCount; +@property(nonatomic, strong) NSMutableArray *putsToAck; +@property(nonatomic, strong) dispatch_queue_t dispatchQueue; +@property(nonatomic, strong) NSString *lastSessionID; +@property(nonatomic, strong) NSMutableSet *interruptReasons; +@property(nonatomic, strong) FIRRetryHelper *retryHelper; +@property(nonatomic, strong) id + contextProvider; +@property(nonatomic, strong) NSString *authToken; +@property(nonatomic) BOOL forceTokenRefreshes; +@property(nonatomic) NSUInteger currentFetchTokenAttempt; + +@end + +@implementation FPersistentConnection + +- (id)initWithRepoInfo:(FRepoInfo *)repoInfo + dispatchQueue:(dispatch_queue_t)dispatchQueue + config:(FIRDatabaseConfig *)config { + self = [super init]; + if (self) { + self->_config = config; + self->_repoInfo = repoInfo; + self->_dispatchQueue = dispatchQueue; + self->_contextProvider = config.contextProvider; + NSAssert(self->_contextProvider != nil, + @"Expected auth token provider"); + self.interruptReasons = [NSMutableSet set]; + + self.listens = [[NSMutableDictionary alloc] init]; + self.outstandingPuts = [[NSMutableDictionary alloc] init]; + self.outstandingGets = [[NSMutableDictionary alloc] init]; + self.onDisconnectQueue = [[NSMutableArray alloc] init]; + self.putCounter = [[FAtomicNumber alloc] init]; + self.getCounter = [[FAtomicNumber alloc] init]; + self.requestNumber = [[FAtomicNumber alloc] init]; + self.requestCBHash = [[NSMutableDictionary alloc] init]; + self.unackedListensCount = 0; + self.putsToAck = [NSMutableArray array]; + connectionState = ConnectionStateDisconnected; + firstConnection = YES; + reconnectDelay = kPersistentConnReconnectMinDelay; + + self->_retryHelper = [[FIRRetryHelper alloc] + initWithDispatchQueue:dispatchQueue + minRetryDelayAfterFailure:kPersistentConnReconnectMinDelay + maxRetryDelay:kPersistentConnReconnectMaxDelay + retryExponent:kPersistentConnReconnectMultiplier + jitterFactor:0.7]; + + [self setupNotifications]; + // Make sure we don't actually connect until open is called + [self interruptForReason:kFInterruptReasonWaitingForOpen]; + } + // nb: The reason establishConnection isn't called here like the JS version + // is because callers need to set the delegate first. The ctor can be + // modified to accept the delegate but that deviates from normal ios + // conventions. After the delegate has been set, the caller is responsible + // for calling establishConnection: + return self; +} + +- (void)dealloc { +#if !TARGET_OS_WATCH + if (reachability) { + // Unschedule the notifications + SCNetworkReachabilitySetDispatchQueue(reachability, NULL); + CFRelease(reachability); + } +#endif // !TARGET_OS_WATCH +} + +#pragma mark - +#pragma mark Public methods + +- (void)open { + [self resumeForReason:kFInterruptReasonWaitingForOpen]; +} + +/** + * Note that the listens dictionary has a type of Map[String (pathString), + * Map[FQueryParams, FOutstandingQuery]] + * + * This means, for each path we care about, there are sets of queryParams that + * correspond to an FOutstandingQuery object. There can be multiple sets at a + * path since we overlap listens for a short time while adding or removing a + * query from a location in the tree. + */ +- (void)listen:(FQuerySpec *)query + tagId:(NSNumber *)tagId + hash:(id)hash + onComplete:(fbt_void_nsstring)onComplete { + FFLog(@"I-RDB034001", @"Listen called for %@", query); + + NSAssert(self.listens[query] == nil, + @"listen() called twice for the same query"); + NSAssert(query.isDefault || !query.loadsAllData, + @"listen called for non-default but complete query"); + FOutstandingQuery *outstanding = [[FOutstandingQuery alloc] init]; + outstanding.query = query; + outstanding.tagId = tagId; + outstanding.syncTreeHash = hash; + outstanding.onComplete = onComplete; + [self.listens setObject:outstanding forKey:query]; + if ([self connected]) { + [self sendListen:outstanding]; + } +} + +- (void)putData:(id)data + forPath:(NSString *)pathString + withHash:(NSString *)hash + withCallback:(fbt_void_nsstring_nsstring)onComplete { + [self putInternal:data + forAction:kFWPRequestActionPut + forPath:pathString + withHash:hash + withCallback:onComplete]; +} + +- (void)mergeData:(id)data + forPath:(NSString *)pathString + withCallback:(fbt_void_nsstring_nsstring)onComplete { + [self putInternal:data + forAction:kFWPRequestActionMerge + forPath:pathString + withHash:nil + withCallback:onComplete]; +} + +- (void)onDisconnectPutData:(id)data + forPath:(FPath *)path + withCallback:(fbt_void_nsstring_nsstring)callback { + if ([self canSendWrites]) { + [self sendOnDisconnectAction:kFWPRequestActionDisconnectPut + forPath:[path description] + withData:data + andCallback:callback]; + } else { + FTupleOnDisconnect *tuple = [[FTupleOnDisconnect alloc] init]; + tuple.pathString = [path description]; + tuple.action = kFWPRequestActionDisconnectPut; + tuple.data = data; + tuple.onComplete = callback; + [self.onDisconnectQueue addObject:tuple]; + } +} + +- (void)onDisconnectMergeData:(id)data + forPath:(FPath *)path + withCallback:(fbt_void_nsstring_nsstring)callback { + if ([self canSendWrites]) { + [self sendOnDisconnectAction:kFWPRequestActionDisconnectMerge + forPath:[path description] + withData:data + andCallback:callback]; + } else { + FTupleOnDisconnect *tuple = [[FTupleOnDisconnect alloc] init]; + tuple.pathString = [path description]; + tuple.action = kFWPRequestActionDisconnectMerge; + tuple.data = data; + tuple.onComplete = callback; + [self.onDisconnectQueue addObject:tuple]; + } +} + +- (void)onDisconnectCancelPath:(FPath *)path + withCallback:(fbt_void_nsstring_nsstring)callback { + if ([self canSendWrites]) { + [self sendOnDisconnectAction:kFWPRequestActionDisconnectCancel + forPath:[path description] + withData:[NSNull null] + andCallback:callback]; + } else { + FTupleOnDisconnect *tuple = [[FTupleOnDisconnect alloc] init]; + tuple.pathString = [path description]; + tuple.action = kFWPRequestActionDisconnectCancel; + tuple.data = [NSNull null]; + tuple.onComplete = callback; + [self.onDisconnectQueue addObject:tuple]; + } +} + +- (void)unlisten:(FQuerySpec *)query tagId:(NSNumber *)tagId { + FPath *path = query.path; + FFLog(@"I-RDB034002", @"Unlistening for %@", query); + + NSArray *outstanding = [self removeListen:query]; + if (outstanding.count > 0 && [self connected]) { + [self sendUnlisten:path queryParams:query.params tagId:tagId]; + } +} + +- (void)refreshAuthToken:(NSString *)token { + self.authToken = token; + if ([self connected]) { + if (token != nil) { + [self sendAuthAndRestoreStateAfterComplete:NO]; + } else { + [self sendUnauth]; + } + } +} + +#pragma mark - +#pragma mark Connection status + +- (BOOL)connected { + return self->connectionState == ConnectionStateAuthenticating || + self->connectionState == ConnectionStateConnected; +} + +- (BOOL)canSendWrites { + return self->connectionState == ConnectionStateConnected; +} + +- (BOOL)canSendReads { + return self->connectionState == ConnectionStateConnected; +} + +#pragma mark - +#pragma mark FConnection delegate methods + +- (void)onReady:(FConnection *)fconnection + atTime:(NSNumber *)timestamp + sessionID:(NSString *)sessionID { + FFLog(@"I-RDB034003", @"On ready"); + lastConnectionEstablishedTime = [[NSDate date] timeIntervalSince1970]; + [self handleTimestamp:timestamp]; + + if (firstConnection) { + [self sendConnectStats]; + } + + [self restoreAuth]; + firstConnection = NO; + self.lastSessionID = sessionID; + dispatch_async(self.dispatchQueue, ^{ + [self.delegate onConnect:self]; + }); +} + +- (void)onDataMessage:(FConnection *)fconnection + withMessage:(NSDictionary *)message { + if (message[kFWPRequestNumber] != nil) { + // this is a response to a request we sent + NSNumber *rn = [NSNumber + numberWithInt:[[message objectForKey:kFWPRequestNumber] intValue]]; + if ([self.requestCBHash objectForKey:rn]) { + void (^callback)(NSDictionary *) = + [self.requestCBHash objectForKey:rn]; + [self.requestCBHash removeObjectForKey:rn]; + + if (callback) { + // dispatch_async(self.dispatchQueue, ^{ + callback([message objectForKey:kFWPResponseForRNData]); + //}); + } + } + } else if (message[kFWPRequestError] != nil) { + NSString *error = [message objectForKey:kFWPRequestError]; + @throw [[NSException alloc] initWithName:@"FirebaseDatabaseServerError" + reason:error + userInfo:nil]; + } else if (message[kFWPAsyncServerAction] != nil) { + // this is a server push of some sort + NSString *action = [message objectForKey:kFWPAsyncServerAction]; + NSDictionary *body = [message objectForKey:kFWPAsyncServerPayloadBody]; + [self onDataPushWithAction:action andBody:body]; + } +} + +- (void)onDisconnect:(FConnection *)fconnection + withReason:(FDisconnectReason)reason { + FFLog(@"I-RDB034004", @"Got on disconnect due to %s", + (reason == DISCONNECT_REASON_SERVER_RESET) ? "server_reset" + : "other"); + connectionState = ConnectionStateDisconnected; + // Drop the realtime connection + self.realtime = nil; + [self cancelSentTransactions]; + [self.requestCBHash removeAllObjects]; + self.unackedListensCount = 0; + if ([self shouldReconnect]) { + NSTimeInterval timeSinceLastConnectSucceeded = + [[NSDate date] timeIntervalSince1970] - + lastConnectionEstablishedTime; + BOOL lastConnectionWasSuccessful; + if (lastConnectionEstablishedTime > 0) { + lastConnectionWasSuccessful = + timeSinceLastConnectSucceeded > + kPersistentConnSuccessfulConnectionEstablishedDelay; + } else { + lastConnectionWasSuccessful = NO; + } + + if (reason == DISCONNECT_REASON_SERVER_RESET || + lastConnectionWasSuccessful) { + [self.retryHelper signalSuccess]; + } + [self tryScheduleReconnect]; + } + lastConnectionEstablishedTime = 0; + [self.delegate onDisconnect:self]; +} + +- (void)onKill:(FConnection *)fconnection withReason:(NSString *)reason { + FFWarn(@"I-RDB034005", + @"Firebase Database connection was forcefully killed by the server. " + @" Will not attempt reconnect. Reason: %@", + reason); + [self interruptForReason:kFInterruptReasonServerKill]; +} + +#pragma mark - +#pragma mark Connection handling methods + +- (void)interruptForReason:(NSString *)reason { + FFLog(@"I-RDB034006", @"Connection interrupted for: %@", reason); + + [self.interruptReasons addObject:reason]; + if (self.realtime) { + // Will call onDisconnect and set the connection state to Disconnected + [self.realtime close]; + self.realtime = nil; + } else { + [self.retryHelper cancel]; + self->connectionState = ConnectionStateDisconnected; + } + // Reset timeouts + [self.retryHelper signalSuccess]; +} + +- (void)resumeForReason:(NSString *)reason { + FFLog(@"I-RDB034007", @"Connection no longer interrupted for: %@", reason); + [self.interruptReasons removeObject:reason]; + + if ([self shouldReconnect] && + connectionState == ConnectionStateDisconnected) { + [self tryScheduleReconnect]; + } +} + +- (BOOL)shouldReconnect { + return self.interruptReasons.count == 0; +} + +- (BOOL)isInterruptedForReason:(NSString *)reason { + return [self.interruptReasons containsObject:reason]; +} + +#pragma mark - +#pragma mark Private methods + +- (void)tryScheduleReconnect { + if ([self shouldReconnect]) { + NSAssert(self->connectionState == ConnectionStateDisconnected, + @"Not in disconnected state: %d", self->connectionState); + BOOL forceRefresh = self.forceTokenRefreshes; + self.forceTokenRefreshes = NO; + FFLog(@"I-RDB034008", @"Scheduling connection attempt"); + [self.retryHelper retry:^{ + FFLog(@"I-RDB034009", @"Trying to fetch auth token"); + NSAssert(self->connectionState == ConnectionStateDisconnected, + @"Not in disconnected state: %d", self->connectionState); + self->connectionState = ConnectionStateGettingToken; + self.currentFetchTokenAttempt++; + NSUInteger thisFetchTokenAttempt = self.currentFetchTokenAttempt; + [self.contextProvider + fetchContextForcingRefresh:forceRefresh + withCallback:^( + FIRDatabaseConnectionContext *context, + NSError *error) { + if (thisFetchTokenAttempt == + self.currentFetchTokenAttempt) { + if (error != nil) { + self->connectionState = + ConnectionStateDisconnected; + FFLog(@"I-RDB034010", + @"Error fetching token: %@", error); + [self tryScheduleReconnect]; + } else { + // Someone could have interrupted us while + // fetching the token, marking the + // connection as Disconnected + if (self->connectionState == + ConnectionStateGettingToken) { + FFLog(@"I-RDB034011", + @"Successfully fetched token, " + @"opening connection"); + [self + openNetworkConnectionWithContext: + context]; + } else { + NSAssert( + self->connectionState == + ConnectionStateDisconnected, + @"Expected connection state " + @"disconnected, but got %d", + self->connectionState); + FFLog(@"I-RDB034012", + @"Not opening connection after " + @"token refresh, because " + @"connection was set to " + @"disconnected."); + } + } + } else { + FFLog(@"I-RDB034013", + @"Ignoring fetch token result, because " + @"this was not the latest attempt."); + } + }]; + }]; + } +} + +- (void)openNetworkConnectionWithContext: + (FIRDatabaseConnectionContext *)context { + NSAssert(self->connectionState == ConnectionStateGettingToken, + @"Trying to open network connection while in wrong state: %d", + self->connectionState); + // TODO: Save entire context? + self.authToken = context.authToken; + + self->connectionState = ConnectionStateConnecting; + self.realtime = [[FConnection alloc] initWith:self.repoInfo + andDispatchQueue:self.dispatchQueue + googleAppID:self.config.googleAppID + lastSessionID:self.lastSessionID + appCheckToken:context.appCheckToken]; + self.realtime.delegate = self; + [self.realtime open]; +} + +#if !TARGET_OS_WATCH +static void reachabilityCallback(SCNetworkReachabilityRef ref, + SCNetworkReachabilityFlags flags, void *info) { + if (flags & kSCNetworkReachabilityFlagsReachable) { + FFLog(@"I-RDB034014", + @"Network became reachable. Trigger a connection attempt"); + FPersistentConnection *self = (__bridge FPersistentConnection *)info; + // Reset reconnect delay + [self.retryHelper signalSuccess]; + if (self->connectionState == ConnectionStateDisconnected) { + [self tryScheduleReconnect]; + } + } else { + FFLog(@"I-RDB034015", @"Network is not reachable"); + } +} +#endif // !TARGET_OS_WATCH + +- (void)enteringForeground { + dispatch_async(self.dispatchQueue, ^{ + // Reset reconnect delay + [self.retryHelper signalSuccess]; + if (self->connectionState == ConnectionStateDisconnected) { + [self tryScheduleReconnect]; + } + }); +} + +- (void)setupNotifications { +#if TARGET_OS_WATCH + if (@available(watchOS 7.0, *)) { + __weak FPersistentConnection *weakSelf = self; + NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; + [center addObserverForName:WKApplicationWillEnterForegroundNotification + object:nil + queue:nil + usingBlock:^(NSNotification *_Nonnull note) { + [weakSelf enteringForeground]; + }]; + } +#else + NSString *const *foregroundConstant = (NSString *const *)dlsym( + RTLD_DEFAULT, "UIApplicationWillEnterForegroundNotification"); + if (foregroundConstant) { + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(enteringForeground) + name:*foregroundConstant + object:nil]; + } + // An empty address is interpreted a generic internet access + struct sockaddr_in zeroAddress; + bzero(&zeroAddress, sizeof(zeroAddress)); + zeroAddress.sin_len = sizeof(zeroAddress); + zeroAddress.sin_family = AF_INET; + reachability = SCNetworkReachabilityCreateWithAddress( + kCFAllocatorDefault, (const struct sockaddr *)&zeroAddress); + SCNetworkReachabilityContext ctx = {0, (__bridge void *)(self), NULL, NULL, + NULL}; + if (SCNetworkReachabilitySetCallback(reachability, reachabilityCallback, + &ctx)) { + SCNetworkReachabilitySetDispatchQueue(reachability, self.dispatchQueue); + } else { + FFLog(@"I-RDB034016", + @"Failed to set up network reachability monitoring"); + CFRelease(reachability); + reachability = NULL; + } +#endif // !TARGET_OS_WATCH +} + +- (void)sendAuthAndRestoreStateAfterComplete:(BOOL)restoreStateAfterComplete { + NSAssert([self connected], @"Must be connected to send auth"); + NSAssert(self.authToken != nil, + @"Can't send auth if there is no credential"); + + NSDictionary *requestData = @{kFWPRequestCredential : self.authToken}; + [self sendAction:kFWPRequestActionAuth + body:requestData + sensitive:YES + callback:^(NSDictionary *data) { + self->connectionState = ConnectionStateConnected; + NSString *status = + [data objectForKey:kFWPResponseForActionStatus]; + id responseData = [data objectForKey:kFWPResponseForActionData]; + if (responseData == nil) { + responseData = @"error"; + } + + BOOL statusOk = + [status isEqualToString:kFWPResponseForActionStatusOk]; + if (statusOk) { + if (restoreStateAfterComplete) { + [self restoreState]; + } + } else { + self.authToken = nil; + self.forceTokenRefreshes = YES; + if ([status isEqualToString:@"expired_token"]) { + FFLog(@"I-RDB034017", @"Authentication failed: %@ (%@)", + status, responseData); + } else { + FFWarn(@"I-RDB034018", @"Authentication failed: %@ (%@)", + status, responseData); + } + [self.realtime close]; + } + }]; +} + +- (void)sendUnauth { + [self sendAction:kFWPRequestActionUnauth + body:@{} + sensitive:NO + callback:nil]; +} + +- (void)onAuthRevokedWithStatus:(NSString *)status + andReason:(NSString *)reason { + // This might be for an earlier token than we just recently sent. But since + // we need to close the connection anyways, we can set it to null here and + // we will refresh the token later on reconnect + if ([status isEqualToString:@"expired_token"]) { + FFLog(@"I-RDB034019", @"Auth token revoked: %@ (%@)", status, reason); + } else { + FFWarn(@"I-RDB034020", @"Auth token revoked: %@ (%@)", status, reason); + } + self.authToken = nil; + self.forceTokenRefreshes = YES; + // Try reconnecting on auth revocation + [self.realtime close]; +} + +- (void)onListenRevoked:(FPath *)path { + NSArray *queries = [self removeAllListensAtPath:path]; + for (FOutstandingQuery *query in queries) { + query.onComplete(@"permission_denied"); + } +} + +- (void)sendOnDisconnectAction:(NSString *)action + forPath:(NSString *)pathString + withData:(id)data + andCallback:(fbt_void_nsstring_nsstring)callback { + + NSDictionary *request = + @{kFWPRequestPath : pathString, kFWPRequestData : data}; + FFLog(@"I-RDB034021", @"onDisconnect %@: %@", action, request); + + [self sendAction:action + body:request + sensitive:NO + callback:^(NSDictionary *data) { + NSString *status = + [data objectForKey:kFWPResponseForActionStatus]; + NSString *errorReason = + [data objectForKey:kFWPResponseForActionData]; + callback(status, errorReason); + }]; +} + +- (void)sendPut:(NSNumber *)index { + NSAssert([self canSendWrites], + @"sendPut called when not able to send writes"); + FOutstandingPut *put = self.outstandingPuts[index]; + assert(put != nil); + fbt_void_nsstring_nsstring onComplete = put.onCompleteBlock; + + // Do not async this block; copying the block insinde sendAction: doesn't + // happen in time (or something) so coredumps + put.sent = YES; + [self sendAction:put.action + body:put.request + sensitive:NO + callback:^(NSDictionary *data) { + FOutstandingPut *currentPut = self.outstandingPuts[index]; + if (currentPut == put) { + [self.outstandingPuts removeObjectForKey:index]; + + if (onComplete != nil) { + NSString *status = + [data objectForKey:kFWPResponseForActionStatus]; + NSString *errorReason = + [data objectForKey:kFWPResponseForActionData]; + if (self.unackedListensCount == 0) { + onComplete(status, errorReason); + } else { + FTupleCallbackStatus *putToAck = + [[FTupleCallbackStatus alloc] init]; + putToAck.block = onComplete; + putToAck.status = status; + putToAck.errorReason = errorReason; + [self.putsToAck addObject:putToAck]; + } + } + } else { + FFLog(@"I-RDB034022", + @"Ignoring on complete for put %@ because it was " + @"already removed", + index); + } + }]; +} + +- (void)sendGet:(NSNumber *)index { + NSAssert([self canSendReads], + @"sendGet called when not able to send reads"); + FOutstandingGet *get = self.outstandingGets[index]; + NSAssert(get != nil, @"sendGet found no outstanding get at index %@", + index); + if ([get sent]) { + return; + } + get.sent = YES; + [self sendAction:kFWPRequestActionGet + body:get.request + sensitive:NO + callback:^(NSDictionary *data) { + FOutstandingGet *currentGet = self.outstandingGets[index]; + if (currentGet == get) { + [self.outstandingGets removeObjectForKey:index]; + NSString *status = + [data objectForKey:kFWPResponseForActionStatus]; + id resultData = [data objectForKey:kFWPResponseForActionData]; + if (resultData == (id)[NSNull null]) { + resultData = nil; + } + if ([status isEqualToString:kFWPResponseForActionStatusOk]) { + get.onCompleteBlock(status, resultData, nil); + return; + } + get.onCompleteBlock(status, nil, resultData); + } else { + FFLog(@"I-RDB034045", + @"Ignoring on complete for get %@ because it was " + @"already removed", + index); + } + }]; +} + +- (void)sendUnlisten:(FPath *)path + queryParams:(FQueryParams *)queryParams + tagId:(NSNumber *)tagId { + FFLog(@"I-RDB034023", @"Unlisten on %@ for %@", path, queryParams); + + NSMutableDictionary *request = [NSMutableDictionary + dictionaryWithObjectsAndKeys:[path toString], kFWPRequestPath, nil]; + if (tagId != nil) { + [request setObject:queryParams.wireProtocolParams + forKey:kFWPRequestQueries]; + [request setObject:tagId forKey:kFWPRequestTag]; + } + + [self sendAction:kFWPRequestActionTaggedUnlisten + body:request + sensitive:NO + callback:nil]; +} + +- (void)putInternal:(id)data + forAction:(NSString *)action + forPath:(NSString *)pathString + withHash:(NSString *)hash + withCallback:(fbt_void_nsstring_nsstring)onComplete { + + NSMutableDictionary *request = [NSMutableDictionary + dictionaryWithObjectsAndKeys:pathString, kFWPRequestPath, data, + kFWPRequestData, nil]; + if (hash) { + [request setObject:hash forKey:kFWPRequestHash]; + } + + FOutstandingPut *put = [[FOutstandingPut alloc] init]; + put.action = action; + put.request = request; + put.onCompleteBlock = onComplete; + put.sent = NO; + + NSNumber *index = [self.putCounter getAndIncrement]; + self.outstandingPuts[index] = put; + + if ([self canSendWrites]) { + FFLog(@"I-RDB034024", @"Was connected, and added as index: %@", index); + [self sendPut:index]; + } else { + FFLog(@"I-RDB034025", + @"Wasn't connected or writes paused, so added to outstanding " + @"puts only. Path: %@", + pathString); + } +} + +- (void)getDataAtPath:(NSString *)pathString + withParams:(NSDictionary *)queryWireProtocolParams + withCallback:(fbt_void_nsstring_id_nsstring)onComplete { + NSMutableDictionary *request = [NSMutableDictionary + dictionaryWithObjectsAndKeys:pathString, kFWPRequestPath, + queryWireProtocolParams, + kFWPRequestQueries, nil]; + FOutstandingGet *get = [[FOutstandingGet alloc] init]; + get.request = request; + get.onCompleteBlock = onComplete; + get.sent = NO; + + NSNumber *index = [self.getCounter getAndIncrement]; + self.outstandingGets[index] = get; + + if (![self connected]) { + dispatch_after( + dispatch_time(DISPATCH_TIME_NOW, + kPersistentConnectionGetConnectTimeout), + self.dispatchQueue, ^{ + FOutstandingGet *currGet = self.outstandingGets[index]; + if ([currGet sent] || currGet == nil) { + return; + } + FFLog(@"I-RDB034045", + @"get %@ timed out waiting for a connection", index); + currGet.sent = YES; + currGet.onCompleteBlock(kFWPResponseForActionStatusFailed, nil, + kPersistentConnectionOffline); + [self.outstandingGets removeObjectForKey:index]; + }); + return; + } + + if ([self canSendReads]) { + FFLog(@"I-RDB034024", @"Sending get: %@", index); + [self sendGet:index]; + } +} + +- (void)sendListen:(FOutstandingQuery *)listenSpec { + FQuerySpec *query = listenSpec.query; + FFLog(@"I-RDB034026", @"Listen for %@", query); + NSMutableDictionary *request = + [NSMutableDictionary dictionaryWithObject:[query.path toString] + forKey:kFWPRequestPath]; + + // Only bother to send query if it's non-default + if (listenSpec.tagId != nil) { + [request setObject:[query.params wireProtocolParams] + forKey:kFWPRequestQueries]; + [request setObject:listenSpec.tagId forKey:kFWPRequestTag]; + } + + [request setObject:[listenSpec.syncTreeHash simpleHash] + forKey:kFWPRequestHash]; + if ([listenSpec.syncTreeHash includeCompoundHash]) { + FCompoundHash *compoundHash = [listenSpec.syncTreeHash compoundHash]; + NSMutableArray *posts = [NSMutableArray array]; + for (FPath *path in compoundHash.posts) { + [posts addObject:path.wireFormat]; + } + request[kFWPRequestCompoundHash] = @{ + kFWPRequestCompoundHashHashes : compoundHash.hashes, + kFWPRequestCompoundHashPaths : posts + }; + } + + fbt_void_nsdictionary onResponse = ^(NSDictionary *response) { + FFLog(@"I-RDB034027", @"Listen response %@", response); + // warn in any case, even if the listener was removed + [self warnOnListenWarningsForQuery:query + payload:response[kFWPResponseForActionData]]; + + FOutstandingQuery *currentListenSpec = self.listens[query]; + + // only trigger actions if the listen hasn't been removed (and maybe + // readded) + if (currentListenSpec == listenSpec) { + NSString *status = [response objectForKey:kFWPRequestStatus]; + if (![status isEqualToString:@"ok"]) { + [self removeListen:query]; + } + + if (listenSpec.onComplete) { + listenSpec.onComplete(status); + } + } + + self.unackedListensCount--; + NSAssert(self.unackedListensCount >= 0, + @"unackedListensCount decremented to be negative."); + if (self.unackedListensCount == 0) { + [self ackPuts]; + } + }; + + [self sendAction:kFWPRequestActionTaggedListen + body:request + sensitive:NO + callback:onResponse]; + + self.unackedListensCount++; +} + +- (void)warnOnListenWarningsForQuery:(FQuerySpec *)query payload:(id)payload { + if (payload != nil && [payload isKindOfClass:[NSDictionary class]]) { + NSDictionary *payloadDict = payload; + id warnings = payloadDict[kFWPResponseDataWarnings]; + if (warnings != nil && [warnings isKindOfClass:[NSArray class]]) { + NSArray *warningsArr = warnings; + if ([warningsArr containsObject:@"no_index"]) { + NSString *indexSpec = [NSString + stringWithFormat:@"\".indexOn\": \"%@\"", + [query.params.index queryDefinition]]; + NSString *indexPath = [query.path description]; + FFWarn(@"I-RDB034028", + @"Using an unspecified index. Your data will be " + @"downloaded and filtered on the client. " + "Consider adding %@ at %@ to your security rules for " + "better performance", + indexSpec, indexPath); + } + } + } +} + +- (int)getNextRequestNumber { + return [[self.requestNumber getAndIncrement] intValue]; +} + +- (void)sendAction:(NSString *)action + body:(NSDictionary *)message + sensitive:(BOOL)sensitive + callback:(void (^)(NSDictionary *data))onMessage { + // Hold onto the onMessage callback for this request before firing it off + NSNumber *rn = [NSNumber numberWithInt:[self getNextRequestNumber]]; + NSDictionary *msg = [NSDictionary + dictionaryWithObjectsAndKeys:rn, kFWPRequestNumber, action, + kFWPRequestAction, message, + kFWPRequestPayloadBody, nil]; + + [self.realtime sendRequest:msg sensitive:sensitive]; + + if (onMessage) { + // Debug message without a callback; bump the rn, but don't hold onto + // the cb + [self.requestCBHash setObject:[onMessage copy] forKey:rn]; + } +} + +- (void)cancelSentTransactions { + NSMutableDictionary + *cancelledOutstandingPuts = [[NSMutableDictionary alloc] init]; + + for (NSNumber *index in self.outstandingPuts) { + FOutstandingPut *put = self.outstandingPuts[index]; + if (put.request[kFWPRequestHash] && put.sent) { + // This is a sent transaction put. + cancelledOutstandingPuts[index] = put; + } + } + + [cancelledOutstandingPuts + enumerateKeysAndObjectsUsingBlock:^( + NSNumber *index, FOutstandingPut *outstandingPut, BOOL *stop) { + // `onCompleteBlock:` may invoke `rerunTransactionsForPath:` and + // enqueue new writes. We defer calling it until we have finished + // enumerating all existing writes. + outstandingPut.onCompleteBlock( + kFTransactionDisconnect, + @"Client was disconnected while running a transaction"); + [self.outstandingPuts removeObjectForKey:index]; + }]; +} + +- (void)onDataPushWithAction:(NSString *)action andBody:(NSDictionary *)body { + FFLog(@"I-RDB034029", @"handleServerMessage: %@, %@", action, body); + id delegate = self.delegate; + if ([action isEqualToString:kFWPAsyncServerDataUpdate] || + [action isEqualToString:kFWPAsyncServerDataMerge]) { + BOOL isMerge = [action isEqualToString:kFWPAsyncServerDataMerge]; + + if ([body objectForKey:kFWPAsyncServerDataUpdateBodyPath] && + [body objectForKey:kFWPAsyncServerDataUpdateBodyData]) { + NSString *path = + [body objectForKey:kFWPAsyncServerDataUpdateBodyPath]; + id payloadData = + [body objectForKey:kFWPAsyncServerDataUpdateBodyData]; + if (isMerge && [payloadData isKindOfClass:[NSDictionary class]] && + [payloadData count] == 0) { + // ignore empty merge + } else { + [delegate + onDataUpdate:self + forPath:path + message:payloadData + isMerge:isMerge + tagId:[body objectForKey: + kFWPAsyncServerDataUpdateBodyTag]]; + } + } else { + FFLog( + @"I-RDB034030", + @"Malformed data response from server missing path or data: %@", + body); + } + } else if ([action isEqualToString:kFWPAsyncServerDataRangeMerge]) { + NSString *path = body[kFWPAsyncServerDataUpdateBodyPath]; + NSArray *ranges = body[kFWPAsyncServerDataUpdateBodyData]; + NSNumber *tag = body[kFWPAsyncServerDataUpdateBodyTag]; + NSMutableArray *rangeMerges = [NSMutableArray array]; + for (NSDictionary *range in ranges) { + NSString *startString = range[kFWPAsyncServerDataUpdateStartPath]; + NSString *endString = range[kFWPAsyncServerDataUpdateEndPath]; + id updateData = range[kFWPAsyncServerDataUpdateRangeMerge]; + id updates = [FSnapshotUtilities nodeFrom:updateData]; + FPath *start = (startString != nil) + ? [[FPath alloc] initWith:startString] + : nil; + FPath *end = + (endString != nil) ? [[FPath alloc] initWith:endString] : nil; + FRangeMerge *merge = [[FRangeMerge alloc] initWithStart:start + end:end + updates:updates]; + [rangeMerges addObject:merge]; + } + [delegate onRangeMerge:rangeMerges forPath:path tagId:tag]; + } else if ([action isEqualToString:kFWPAsyncServerAuthRevoked]) { + NSString *status = [body objectForKey:kFWPResponseForActionStatus]; + NSString *reason = [body objectForKey:kFWPResponseForActionData]; + [self onAuthRevokedWithStatus:status andReason:reason]; + } else if ([action isEqualToString:kFWPASyncServerListenCancelled]) { + NSString *pathString = + [body objectForKey:kFWPAsyncServerDataUpdateBodyPath]; + [self onListenRevoked:[[FPath alloc] initWith:pathString]]; + } else if ([action isEqualToString:kFWPAsyncServerSecurityDebug]) { + NSString *msg = [body objectForKey:@"msg"]; + if (msg != nil) { + NSArray *msgs = [msg componentsSeparatedByString:@"\n"]; + for (NSString *m in msgs) { + FFWarn(@"I-RDB034031", @"%@", m); + } + } + } else { + // TODO: revoke listens, auth, security debug + FFLog(@"I-RDB034032", @"Unsupported action from server: %@", action); + } +} + +- (void)restoreAuth { + FFLog(@"I-RDB034033", @"Calling restore state"); + + NSAssert(self->connectionState == ConnectionStateConnecting, + @"Wanted to restore auth, but was in wrong state: %d", + self->connectionState); + if (self.authToken == nil) { + FFLog(@"I-RDB034034", @"Not restoring auth because token is nil"); + self->connectionState = ConnectionStateConnected; + [self restoreState]; + } else { + FFLog(@"I-RDB034035", @"Restoring auth"); + self->connectionState = ConnectionStateAuthenticating; + [self sendAuthAndRestoreStateAfterComplete:YES]; + } +} + +- (void)restoreState { + NSAssert(self->connectionState == ConnectionStateConnected, + @"Should be connected if we're restoring state, but we are: %d", + self->connectionState); + + [self.listens enumerateKeysAndObjectsUsingBlock:^( + FQuerySpec *query, FOutstandingQuery *outstandingListen, + BOOL *stop) { + FFLog(@"I-RDB034036", @"Restoring listen for %@", query); + [self sendListen:outstandingListen]; + }]; + + NSArray *putKeys = [[self.outstandingPuts allKeys] + sortedArrayUsingSelector:@selector(compare:)]; + for (int i = 0; i < [putKeys count]; i++) { + if ([self.outstandingPuts objectForKey:[putKeys objectAtIndex:i]] != + nil) { + FFLog(@"I-RDB034037", @"Restoring put: %d", i); + [self sendPut:[putKeys objectAtIndex:i]]; + } else { + FFLog(@"I-RDB034038", @"Restoring put: skipped nil: %d", i); + } + } + + NSArray *getKeys = [[self.outstandingGets allKeys] + sortedArrayUsingSelector:@selector(compare:)]; + for (int i = 0; i < [getKeys count]; i++) { + if ([self.outstandingGets objectForKey:[getKeys objectAtIndex:i]] != + nil) { + FFLog(@"I-RDB034037", @"Restoring get: %d", i); + [self sendGet:[getKeys objectAtIndex:i]]; + } else { + FFLog(@"I-RDB034038", @"Restoring get: skipped nil: %d", i); + } + } + + for (FTupleOnDisconnect *tuple in self.onDisconnectQueue) { + [self sendOnDisconnectAction:tuple.action + forPath:tuple.pathString + withData:tuple.data + andCallback:tuple.onComplete]; + } + [self.onDisconnectQueue removeAllObjects]; +} + +- (NSArray *)removeListen:(FQuerySpec *)query { + NSAssert(query.isDefault || !query.loadsAllData, + @"removeListen called for non-default but complete query"); + + FOutstandingQuery *outstanding = self.listens[query]; + if (!outstanding) { + FFLog(@"I-RDB034039", + @"Trying to remove listener for query %@ but no listener exists", + query); + return @[]; + } else { + [self.listens removeObjectForKey:query]; + return @[ outstanding ]; + } +} + +- (NSArray *)removeAllListensAtPath:(FPath *)path { + FFLog(@"I-RDB034040", @"Removing all listens at path %@", path); + NSMutableArray *removed = [NSMutableArray array]; + NSMutableArray *toRemove = [NSMutableArray array]; + [self.listens + enumerateKeysAndObjectsUsingBlock:^( + FQuerySpec *spec, FOutstandingQuery *outstanding, BOOL *stop) { + if ([spec.path isEqual:path]) { + [removed addObject:outstanding]; + [toRemove addObject:spec]; + } + }]; + [self.listens removeObjectsForKeys:toRemove]; + return removed; +} + +- (void)purgeOutstandingWrites { + // We might have unacked puts in our queue that we need to ack now before we + // send out any cancels... + [self ackPuts]; + // Cancel in order + NSArray *keys = [[self.outstandingPuts allKeys] + sortedArrayUsingSelector:@selector(compare:)]; + for (NSNumber *key in keys) { + FOutstandingPut *put = self.outstandingPuts[key]; + if (put.onCompleteBlock != nil) { + put.onCompleteBlock(kFErrorWriteCanceled, nil); + } + } + for (FTupleOnDisconnect *onDisconnect in self.onDisconnectQueue) { + if (onDisconnect.onComplete != nil) { + onDisconnect.onComplete(kFErrorWriteCanceled, nil); + } + } + [self.outstandingPuts removeAllObjects]; + [self.onDisconnectQueue removeAllObjects]; +} + +- (void)ackPuts { + for (FTupleCallbackStatus *put in self.putsToAck) { + put.block(put.status, put.errorReason); + } + [self.putsToAck removeAllObjects]; +} + +- (void)handleTimestamp:(NSNumber *)timestamp { + FFLog(@"I-RDB034041", @"Handling timestamp: %@", timestamp); + double timestampDeltaMs = [timestamp doubleValue] - + ([[NSDate date] timeIntervalSince1970] * 1000); + [self.delegate onServerInfoUpdate:self + updates:@{ + kDotInfoServerTimeOffset : [NSNumber + numberWithDouble:timestampDeltaMs] + }]; +} + +- (void)sendStats:(NSDictionary *)stats { + if ([stats count] > 0) { + NSDictionary *request = @{kFWPRequestCounters : stats}; + [self sendAction:kFWPRequestActionStats + body:request + sensitive:NO + callback:^(NSDictionary *data) { + NSString *status = + [data objectForKey:kFWPResponseForActionStatus]; + NSString *errorReason = + [data objectForKey:kFWPResponseForActionData]; + BOOL statusOk = + [status isEqualToString:kFWPResponseForActionStatusOk]; + if (!statusOk) { + FFLog(@"I-RDB034042", @"Failed to send stats: %@", + errorReason); + } + }]; + } else { + FFLog(@"I-RDB034043", @"Not sending stats because stats are empty"); + } +} + +- (void)sendConnectStats { + NSMutableDictionary *stats = [NSMutableDictionary dictionary]; + +#if TARGET_OS_IOS || TARGET_OS_TV + if (self.config.persistenceEnabled) { + stats[@"persistence.ios.enabled"] = @1; + } +#elif TARGET_OS_OSX + if (self.config.persistenceEnabled) { + stats[@"persistence.osx.enabled"] = @1; + } +#elif TARGET_OS_WATCH + if (self.config.persistenceEnabled) { + stats[@"persistence.watchos.enabled"] = @1; + } +#endif + NSString *sdkVersion = + [[FIRDatabase sdkVersion] stringByReplacingOccurrencesOfString:@"." + withString:@"-"]; + NSString *sdkStatName = + [NSString stringWithFormat:@"sdk.objc.%@", sdkVersion]; + stats[sdkStatName] = @1; + FFLog(@"I-RDB034044", @"Sending first connection stats"); + [self sendStats:stats]; +} + +- (NSDictionary *)dumpListens { + return self.listens; +} + +#pragma mark - App Check Token update + +// TODO: Add tests! +- (void)refreshAppCheckToken:(NSString *)token { + if (![self connected]) { + // A fresh FAC token will be sent as a part of initial handshake. + return; + } + + if (token.length == 0) { + // No token to send. + return; + } + + // Send updated FAC token to the open connection. + [self sendAppCheckToken:token]; +} + +- (void)sendAppCheckToken:(NSString *)token { + NSDictionary *requestData = @{kFWPRequestAppCheckToken : token}; + [self sendAction:kFWPRequestActionAppCheck + body:requestData + sensitive:YES + callback:^(NSDictionary *data) { + NSString *status = + [data objectForKey:kFWPResponseForActionStatus]; + id responseData = [data objectForKey:kFWPResponseForActionData]; + if (responseData == nil) { + responseData = @"Response data was empty."; + } + + BOOL statusOk = + [status isEqualToString:kFWPResponseForActionStatusOk]; + if (!statusOk) { + self.authToken = nil; + self.forceTokenRefreshes = YES; + if ([status isEqualToString:@"invalid_token"]) { + FFLog(@"I-RDB034045", @"App check failed: %@ (%@)", + status, responseData); + } else { + FFWarn(@"I-RDB034046", @"App check failed: %@ (%@)", + status, responseData); + } + [self.realtime close]; + } + }]; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FQueryParams.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FQueryParams.h new file mode 100644 index 0000000..5d957c5 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FQueryParams.h @@ -0,0 +1,60 @@ +/* + * 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 + +@protocol FIndex +, FNodeFilter, FNode; + +@interface FQueryParams : NSObject + +@property(nonatomic, readonly) BOOL limitSet; +@property(nonatomic, readonly) NSInteger limit; + +@property(nonatomic, strong, readonly) NSString *viewFrom; +@property(nonatomic, strong, readonly) id indexStartValue; +@property(nonatomic, strong, readonly) NSString *indexStartKey; +@property(nonatomic, strong, readonly) id indexEndValue; +@property(nonatomic, strong, readonly) NSString *indexEndKey; + +@property(nonatomic, strong, readonly) id index; + +- (BOOL)loadsAllData; +- (BOOL)isDefault; +- (BOOL)isValid; +- (BOOL)hasAnchoredLimit; + +- (FQueryParams *)limitTo:(NSInteger)limit; +- (FQueryParams *)limitToFirst:(NSInteger)newLimit; +- (FQueryParams *)limitToLast:(NSInteger)newLimit; + +- (FQueryParams *)startAt:(id)indexValue childKey:(NSString *)key; +- (FQueryParams *)startAt:(id)indexValue; +- (FQueryParams *)endAt:(id)indexValue childKey:(NSString *)key; +- (FQueryParams *)endAt:(id)indexValue; + +- (FQueryParams *)orderBy:(id)index; + ++ (FQueryParams *)defaultInstance; ++ (FQueryParams *)fromQueryObject:(NSDictionary *)dict; + +- (BOOL)hasStart; +- (BOOL)hasEnd; + +- (NSDictionary *)wireProtocolParams; +- (BOOL)isViewFromLeft; +- (id)nodeFilter; +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FQueryParams.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FQueryParams.m new file mode 100644 index 0000000..fcef36c --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FQueryParams.m @@ -0,0 +1,393 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/FQueryParams.h" +#import "FirebaseDatabase/Sources/Constants/FConstants.h" +#import "FirebaseDatabase/Sources/Core/View/Filter/FIndexedFilter.h" +#import "FirebaseDatabase/Sources/Core/View/Filter/FLimitedFilter.h" +#import "FirebaseDatabase/Sources/Core/View/Filter/FNodeFilter.h" +#import "FirebaseDatabase/Sources/FIndex.h" +#import "FirebaseDatabase/Sources/FPriorityIndex.h" +#import "FirebaseDatabase/Sources/FRangedFilter.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FValidation.h" + +@interface FQueryParams () + +@property(nonatomic, readwrite) BOOL limitSet; +@property(nonatomic, readwrite) NSInteger limit; + +@property(nonatomic, strong, readwrite) NSString *viewFrom; +/** + * indexStartValue is anything you can store as a priority / value. + */ +@property(nonatomic, strong, readwrite) id indexStartValue; +@property(nonatomic, strong, readwrite) NSString *indexStartKey; +/** + * indexStartValue is anything you can store as a priority / value. + */ +@property(nonatomic, strong, readwrite) id indexEndValue; +@property(nonatomic, strong, readwrite) NSString *indexEndKey; + +@property(nonatomic, strong, readwrite) id index; + +@end + +@implementation FQueryParams + ++ (FQueryParams *)defaultInstance { + static FQueryParams *defaultParams = nil; + static dispatch_once_t defaultParamsToken; + dispatch_once(&defaultParamsToken, ^{ + defaultParams = [[FQueryParams alloc] init]; + }); + return defaultParams; +} + +- (id)init { + self = [super init]; + if (self) { + self->_limitSet = NO; + self->_limit = 0; + + self->_viewFrom = nil; + self->_indexStartValue = nil; + self->_indexStartKey = nil; + self->_indexEndValue = nil; + self->_indexEndKey = nil; + + self->_index = [FPriorityIndex priorityIndex]; + } + return self; +} + +/** + * Only valid if hasStart is true + */ +- (id)indexStartValue { + NSAssert([self hasStart], @"Only valid if start has been set"); + return _indexStartValue; +} + +/** + * Only valid if hasStart is true. + * @return The starting key name for the range defined by these query parameters + */ +- (NSString *)indexStartKey { + NSAssert([self hasStart], @"Only valid if start has been set"); + if (_indexStartKey == nil) { + return [FUtilities minName]; + } else { + return _indexStartKey; + } +} + +/** + * Only valid if hasEnd is true. + */ +- (id)indexEndValue { + NSAssert([self hasEnd], @"Only valid if end has been set"); + return _indexEndValue; +} + +/** + * Only valid if hasEnd is true. + * @return The end key name for the range defined by these query parameters + */ +- (NSString *)indexEndKey { + NSAssert([self hasEnd], @"Only valid if end has been set"); + if (_indexEndKey == nil) { + return [FUtilities maxName]; + } else { + return _indexEndKey; + } +} + +/** + * @return true if a limit has been set and has been explicitly anchored + */ +- (BOOL)hasAnchoredLimit { + return self.limitSet && self.viewFrom != nil; +} + +/** + * Only valid to call if limitSet returns true + */ +- (NSInteger)limit { + NSAssert(self.limitSet, @"Only valid if limit has been set"); + return _limit; +} + +- (BOOL)hasStart { + return self->_indexStartValue != nil; +} + +- (BOOL)hasEnd { + return self->_indexEndValue != nil; +} + +- (id)copyWithZone:(NSZone *)zone { + // Immutable + return self; +} + +- (id)mutableCopy { + FQueryParams *other = [[[self class] alloc] init]; + // Maybe need to do extra copying here + other->_limitSet = _limitSet; + other->_limit = _limit; + other->_indexStartValue = _indexStartValue; + other->_indexStartKey = _indexStartKey; + other->_indexEndValue = _indexEndValue; + other->_indexEndKey = _indexEndKey; + other->_viewFrom = _viewFrom; + other->_index = _index; + return other; +} + +- (FQueryParams *)limitTo:(NSInteger)newLimit { + FQueryParams *newParams = [self mutableCopy]; + newParams->_limitSet = YES; + newParams->_limit = newLimit; + newParams->_viewFrom = nil; + return newParams; +} + +- (FQueryParams *)limitToFirst:(NSInteger)newLimit { + FQueryParams *newParams = [self mutableCopy]; + newParams->_limitSet = YES; + newParams->_limit = newLimit; + newParams->_viewFrom = kFQPViewFromLeft; + return newParams; +} + +- (FQueryParams *)limitToLast:(NSInteger)newLimit { + FQueryParams *newParams = [self mutableCopy]; + newParams->_limitSet = YES; + newParams->_limit = newLimit; + newParams->_viewFrom = kFQPViewFromRight; + return newParams; +} + +- (FQueryParams *)startAt:(id)indexValue childKey:(NSString *)key { + NSAssert([indexValue isLeafNode] || [indexValue isEmpty], nil); + FQueryParams *newParams = [self mutableCopy]; + newParams->_indexStartValue = indexValue; + newParams->_indexStartKey = key; + return newParams; +} + +- (FQueryParams *)startAt:(id)indexValue { + return [self startAt:indexValue childKey:nil]; +} + +- (FQueryParams *)endAt:(id)indexValue childKey:(NSString *)key { + NSAssert([indexValue isLeafNode] || [indexValue isEmpty], nil); + FQueryParams *newParams = [self mutableCopy]; + newParams->_indexEndValue = indexValue; + newParams->_indexEndKey = key; + return newParams; +} + +- (FQueryParams *)endAt:(id)indexValue { + return [self endAt:indexValue childKey:nil]; +} + +- (FQueryParams *)orderBy:(id)newIndex { + FQueryParams *newParams = [self mutableCopy]; + newParams->_index = newIndex; + return newParams; +} + +- (NSDictionary *)wireProtocolParams { + NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; + if ([self hasStart]) { + [dict setObject:[self.indexStartValue valForExport:YES] + forKey:kFQPIndexStartValue]; + + // Don't use property as it will be [MIN-NAME] + if (self->_indexStartKey != nil) { + [dict setObject:self->_indexStartKey forKey:kFQPIndexStartName]; + } + } + + if ([self hasEnd]) { + [dict setObject:[self.indexEndValue valForExport:YES] + forKey:kFQPIndexEndValue]; + + // Don't use property as it will be [MAX-NAME] + if (self->_indexEndKey != nil) { + [dict setObject:self->_indexEndKey forKey:kFQPIndexEndName]; + } + } + + if (self.limitSet) { + [dict setObject:[NSNumber numberWithInteger:self.limit] + forKey:kFQPLimit]; + NSString *vf = self.viewFrom; + if (vf == nil) { + // limit() rather than limitToFirst or limitToLast was called. + // This means that only one of startSet or endSet is true. Use them + // to calculate which side of the view to anchor to. If neither is + // set, Anchor to end + if ([self hasStart]) { + vf = kFQPViewFromLeft; + } else { + vf = kFQPViewFromRight; + } + } + [dict setObject:vf forKey:kFQPViewFrom]; + } + + // For now, priority index is the default, so we only specify if it's some + // other index. + if (![self.index isEqual:[FPriorityIndex priorityIndex]]) { + [dict setObject:[self.index queryDefinition] forKey:kFQPIndex]; + } + + return dict; +} + ++ (FQueryParams *)fromQueryObject:(NSDictionary *)dict { + if (dict.count == 0) { + return [FQueryParams defaultInstance]; + } + + FQueryParams *params = [[FQueryParams alloc] init]; + if (dict[kFQPLimit] != nil) { + params->_limitSet = YES; + params->_limit = [dict[kFQPLimit] integerValue]; + } + + if (dict[kFQPIndexStartValue] != nil) { + params->_indexStartValue = + [FSnapshotUtilities nodeFrom:dict[kFQPIndexStartValue]]; + if (dict[kFQPIndexStartName] != nil) { + params->_indexStartKey = dict[kFQPIndexStartName]; + } + } + + if (dict[kFQPIndexEndValue] != nil) { + params->_indexEndValue = + [FSnapshotUtilities nodeFrom:dict[kFQPIndexEndValue]]; + if (dict[kFQPIndexEndName] != nil) { + params->_indexEndKey = dict[kFQPIndexEndName]; + } + } + + if (dict[kFQPViewFrom] != nil) { + NSString *viewFrom = dict[kFQPViewFrom]; + if (![viewFrom isEqualToString:kFQPViewFromLeft] && + ![viewFrom isEqualToString:kFQPViewFromRight]) { + [NSException raise:NSInvalidArgumentException + format:@"Unknown view from paramter: %@", viewFrom]; + } + params->_viewFrom = viewFrom; + } + + NSString *index = dict[kFQPIndex]; + if (index != nil) { + params->_index = [FIndex indexFromQueryDefinition:index]; + } + + return params; +} + +- (BOOL)isViewFromLeft { + if (self.viewFrom != nil) { + // Not null, we can just check + return [self.viewFrom isEqualToString:kFQPViewFromLeft]; + } else { + // If start is set, it's view from left. Otherwise not. + return self.hasStart; + } +} + +- (id)nodeFilter { + if (self.loadsAllData) { + return [[FIndexedFilter alloc] initWithIndex:self.index]; + } else if (self.limitSet) { + return [[FLimitedFilter alloc] initWithQueryParams:self]; + } else { + return [[FRangedFilter alloc] initWithQueryParams:self]; + } +} + +- (BOOL)isValid { + return !(self.hasStart && self.hasEnd && self.limitSet && + !self.hasAnchoredLimit); +} + +- (BOOL)loadsAllData { + return !(self.hasStart || self.hasEnd || self.limitSet); +} + +- (BOOL)isDefault { + return [self loadsAllData] && + [self.index isEqual:[FPriorityIndex priorityIndex]]; +} + +- (NSString *)description { + return [[self wireProtocolParams] description]; +} + +- (BOOL)isEqual:(id)obj { + if (self == obj) { + return YES; + } + if (![obj isKindOfClass:[self class]]) { + return NO; + } + FQueryParams *other = (FQueryParams *)obj; + if (self->_limitSet != other->_limitSet) + return NO; + if (self->_limit != other->_limit) + return NO; + if ((self->_index != other->_index) && + ![self->_index isEqual:other->_index]) + return NO; + if ((self->_indexStartKey != other->_indexStartKey) && + ![self->_indexStartKey isEqualToString:other->_indexStartKey]) + return NO; + if ((self->_indexStartValue != other->_indexStartValue) && + ![self->_indexStartValue isEqual:other->_indexStartValue]) + return NO; + if ((self->_indexEndKey != other->_indexEndKey) && + ![self->_indexEndKey isEqualToString:other->_indexEndKey]) + return NO; + if ((self->_indexEndValue != other->_indexEndValue) && + ![self->_indexEndValue isEqual:other->_indexEndValue]) + return NO; + if ([self isViewFromLeft] != [other isViewFromLeft]) + return NO; + + return YES; +} + +- (NSUInteger)hash { + NSUInteger result = _limitSet ? _limit : 0; + result = 31 * result + ([self isViewFromLeft] ? 1231 : 1237); + result = 31 * result + [_indexStartKey hash]; + result = 31 * result + [_indexStartValue hash]; + result = 31 * result + [_indexEndKey hash]; + result = 31 * result + [_indexEndValue hash]; + result = 31 * result + [_index hash]; + return result; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FQuerySpec.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FQuerySpec.h new file mode 100644 index 0000000..f3e1882 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FQuerySpec.h @@ -0,0 +1,36 @@ +/* + * 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 + +#import "FirebaseDatabase/Sources/Core/FQueryParams.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/FIndex.h" + +@interface FQuerySpec : NSObject + +@property(nonatomic, strong, readonly) FPath *path; +@property(nonatomic, strong, readonly) FQueryParams *params; + +- (id)initWithPath:(FPath *)path params:(FQueryParams *)params; + ++ (FQuerySpec *)defaultQueryAtPath:(FPath *)path; + +- (id)index; +- (BOOL)isDefault; +- (BOOL)loadsAllData; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FQuerySpec.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FQuerySpec.m new file mode 100644 index 0000000..ea76984 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FQuerySpec.m @@ -0,0 +1,86 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/FQuerySpec.h" + +@interface FQuerySpec () + +@property(nonatomic, strong, readwrite) FPath *path; +@property(nonatomic, strong, readwrite) FQueryParams *params; + +@end + +@implementation FQuerySpec + +- (id)initWithPath:(FPath *)path params:(FQueryParams *)params { + self = [super init]; + if (self != nil) { + self->_path = path; + self->_params = params; + } + return self; +} + ++ (FQuerySpec *)defaultQueryAtPath:(FPath *)path { + return [[FQuerySpec alloc] initWithPath:path + params:[FQueryParams defaultInstance]]; +} + +- (id)copyWithZone:(NSZone *)zone { + // Immutable + return self; +} + +- (id)index { + return self.params.index; +} + +- (BOOL)isDefault { + return self.params.isDefault; +} + +- (BOOL)loadsAllData { + return self.params.loadsAllData; +} + +- (BOOL)isEqual:(id)object { + if (self == object) { + return YES; + } + + if (![object isKindOfClass:[FQuerySpec class]]) { + return NO; + } + + FQuerySpec *other = (FQuerySpec *)object; + + if (![self.path isEqual:other.path]) { + return NO; + } + + return [self.params isEqual:other.params]; +} + +- (NSUInteger)hash { + return self.path.hash * 31 + self.params.hash; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"FQuerySpec (path: %@, params: %@)", + self.path, self.params]; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRangeMerge.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRangeMerge.h new file mode 100644 index 0000000..674f936 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRangeMerge.h @@ -0,0 +1,39 @@ +/* + * 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 + +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" + +/** + * Applies a merge of a snap for a given interval of paths. + * Each leaf in the current node which the relative path lies *after* (the + * optional) start and lies *before or at* (the optional) end will be deleted. + * Each leaf in snap that lies in the interval will be added to the resulting + * node. Nodes outside of the range are ignored. nil for start and end are + * sentinel values that represent -infinity and +infinity respectively (aka + * includes any path). Priorities of children nodes are treated as leaf children + * of that node. + */ +@interface FRangeMerge : NSObject + +- (instancetype)initWithStart:(FPath *)start + end:(FPath *)end + updates:(id)updates; + +- (id)applyToNode:(id)node; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRangeMerge.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRangeMerge.m new file mode 100644 index 0000000..7ec74b2 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRangeMerge.m @@ -0,0 +1,134 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/FRangeMerge.h" + +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" + +@interface FRangeMerge () + +@property(nonatomic, strong) FPath *optExclusiveStart; +@property(nonatomic, strong) FPath *optInclusiveEnd; +@property(nonatomic, strong) id updates; + +@end + +@implementation FRangeMerge + +- (instancetype)initWithStart:(FPath *)start + end:(FPath *)end + updates:(id)updates { + self = [super init]; + if (self != nil) { + self->_optExclusiveStart = start; + self->_optInclusiveEnd = end; + self->_updates = updates; + } + return self; +} + +- (id)applyToNode:(id)node { + return [self updateRangeInNode:[FPath empty] + node:node + updates:self.updates]; +} + +- (id)updateRangeInNode:(FPath *)currentPath + node:(id)node + updates:(id)updates { + NSComparisonResult startComparison = + (self.optExclusiveStart == nil) + ? NSOrderedDescending + : [currentPath compare:self.optExclusiveStart]; + NSComparisonResult endComparison = + (self.optInclusiveEnd == nil) + ? NSOrderedAscending + : [currentPath compare:self.optInclusiveEnd]; + BOOL startInNode = self.optExclusiveStart != nil && + [currentPath contains:self.optExclusiveStart]; + BOOL endInNode = self.optInclusiveEnd != nil && + [currentPath contains:self.optInclusiveEnd]; + if (startComparison == NSOrderedDescending && + endComparison == NSOrderedAscending && !endInNode) { + // child is completly contained + return updates; + } else if (startComparison == NSOrderedDescending && endInNode && + [updates isLeafNode]) { + return updates; + } else if (startComparison == NSOrderedDescending && + endComparison == NSOrderedSame) { + NSAssert(endInNode, @"End not in node"); + NSAssert(![updates isLeafNode], @"Found leaf node update, this case " + @"should have been handled above."); + if ([node isLeafNode]) { + // Update node was not a leaf node, so we can delete it + return [FEmptyNode emptyNode]; + } else { + // Unaffected by range, ignore + return node; + } + } else if (startInNode || endInNode) { + // There is a partial update we need to do, so collect all relevant + // children + NSMutableSet *allChildren = [NSMutableSet set]; + [node enumerateChildrenUsingBlock:^(NSString *key, id node, + BOOL *stop) { + [allChildren addObject:key]; + }]; + [updates enumerateChildrenUsingBlock:^(NSString *key, id node, + BOOL *stop) { + [allChildren addObject:key]; + }]; + + __block id newNode = node; + void (^action)(id, BOOL *) = ^void(NSString *key, BOOL *stop) { + id currentChild = [node getImmediateChild:key]; + id updatedChild = + [self updateRangeInNode:[currentPath childFromString:key] + node:currentChild + updates:[updates getImmediateChild:key]]; + // Only need to update if the node changed + if (updatedChild != currentChild) { + newNode = [newNode updateImmediateChild:key + withNewChild:updatedChild]; + } + }; + + [allChildren enumerateObjectsUsingBlock:action]; + + // Add priority last, so the node is not empty when applying + if (!updates.getPriority.isEmpty || !node.getPriority.isEmpty) { + BOOL stop = NO; + action(@".priority", &stop); + } + return newNode; + } else { + // Unaffected by this range + NSAssert(endComparison == NSOrderedDescending || + startComparison <= NSOrderedSame, + @"Invalid range for update"); + return node; + } +} + +- (NSString *)description { + return [NSString stringWithFormat:@"RangeMerge (optExclusiveStart = %@, " + @"optExclusiveEng = %@, updates = %@)", + self.optExclusiveStart, + self.optInclusiveEnd, self.updates]; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepo.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepo.h new file mode 100644 index 0000000..94adbc2 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepo.h @@ -0,0 +1,102 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/FPersistentConnection.h" +#import "FirebaseDatabase/Sources/Core/FRepoInfo.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDataEventType.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseQuery.h" +#import "FirebaseDatabase/Sources/Utilities/Tuples/FTupleUserCallback.h" +#import + +@class FQuerySpec; +@class FPersistence; +@class FAuthenticationManager; +@class FIRDatabaseConfig; +@protocol FEventRegistration; +@class FCompoundWrite; +@protocol FClock; +@class FIRDatabase; + +@interface FRepo : NSObject + +@property(nonatomic, strong) FIRDatabaseConfig *_Nullable config; + +- (id _Nonnull)initWithRepoInfo:(FRepoInfo *_Nullable)info + config:(FIRDatabaseConfig *_Nullable)config + database:(FIRDatabase *_Nullable)database; + +- (void)set:(FPath *_Nullable)path + withNode:(id _Nullable)node + withCallback:(fbt_void_nserror_ref _Nullable)onComplete; +- (void)update:(FPath *_Nullable)path + withNodes:(FCompoundWrite *_Nullable)compoundWrite + withCallback:(fbt_void_nserror_ref _Nullable)callback; +- (void)purgeOutstandingWrites; + +- (void)getData:(FIRDatabaseQuery *_Nullable)query + withCompletionBlock: + (void (^_Nonnull)(NSError *_Nullable error, + FIRDataSnapshot *_Nullable snapshot))block; + +- (void)addEventRegistration:(id _Nullable)eventRegistration + forQuery:(FQuerySpec *_Nullable)query; +- (void)removeEventRegistration: + (id _Nullable)eventRegistration + forQuery:(FQuerySpec *_Nullable)query; +- (void)keepQuery:(FQuerySpec *_Nullable)query synced:(BOOL)synced; + +- (NSString *_Nullable)name; +- (NSTimeInterval)serverTime; + +- (void)onDataUpdate:(FPersistentConnection *_Nullable)fpconnection + forPath:(NSString *_Nullable)pathString + message:(id _Nullable)message + isMerge:(BOOL)isMerge + tagId:(NSNumber *_Nullable)tagId; +- (void)onConnect:(FPersistentConnection *_Nullable)fpconnection; +- (void)onDisconnect:(FPersistentConnection *_Nullable)fpconnection; + +// Disconnect methods +- (void)onDisconnectCancel:(FPath *_Nullable)path + withCallback:(fbt_void_nserror_ref _Nullable)callback; +- (void)onDisconnectSet:(FPath *_Nullable)path + withNode:(id _Nullable)node + withCallback:(fbt_void_nserror_ref _Nullable)callback; +- (void)onDisconnectUpdate:(FPath *_Nullable)path + withNodes:(FCompoundWrite *_Nullable)compoundWrite + withCallback:(fbt_void_nserror_ref _Nullable)callback; + +// Connection Management. +- (void)interrupt; +- (void)resume; + +// Transactions +- (void)startTransactionOnPath:(FPath *_Nullable)path + update: + (fbt_transactionresult_mutabledata _Nullable)update + onComplete: + (fbt_void_nserror_bool_datasnapshot _Nullable)onComplete + withLocalEvents:(BOOL)applyLocally; + +// Testing methods +- (NSDictionary *_Nullable)dumpListens; +- (void)dispose; +- (void)setHijackHash:(BOOL)hijack; + +@property(nonatomic, strong, readonly) FAuthenticationManager *_Nullable auth; +@property(nonatomic, strong, readonly) FIRDatabase *_Nullable database; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepo.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepo.m new file mode 100644 index 0000000..ee3560e --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepo.m @@ -0,0 +1,1541 @@ +/* + * 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 + +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDataSnapshot_Private.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDatabase_Private.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRMutableData_Private.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRTransactionResult_Private.h" +#import "FirebaseDatabase/Sources/Constants/FConstants.h" +#import "FirebaseDatabase/Sources/Core/FListenProvider.h" +#import "FirebaseDatabase/Sources/Core/FQuerySpec.h" +#import "FirebaseDatabase/Sources/Core/FRepo.h" +#import "FirebaseDatabase/Sources/Core/FRepoManager.h" +#import "FirebaseDatabase/Sources/Core/FRepo_Private.h" +#import "FirebaseDatabase/Sources/Core/FServerValues.h" +#import "FirebaseDatabase/Sources/Core/FSnapshotHolder.h" +#import "FirebaseDatabase/Sources/Core/FSyncTree.h" +#import "FirebaseDatabase/Sources/Core/FWriteRecord.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FTree.h" +#import "FirebaseDatabase/Sources/Core/View/FEventRaiser.h" +#import "FirebaseDatabase/Sources/Core/View/FEventRegistration.h" +#import "FirebaseDatabase/Sources/Core/View/FValueEventRegistration.h" +#import "FirebaseDatabase/Sources/FClock.h" +#import "FirebaseDatabase/Sources/FIRDatabaseConfig_Private.h" +#import "FirebaseDatabase/Sources/Persistence/FCachePolicy.h" +#import "FirebaseDatabase/Sources/Persistence/FLevelDBStorageEngine.h" +#import "FirebaseDatabase/Sources/Persistence/FPersistenceManager.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDataSnapshot.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRMutableData.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRTransactionResult.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FAtomicNumber.h" +#import "FirebaseDatabase/Sources/Utilities/Tuples/FTupleNodePath.h" +#import "FirebaseDatabase/Sources/Utilities/Tuples/FTupleSetIdPath.h" +#import "FirebaseDatabase/Sources/Utilities/Tuples/FTupleTransaction.h" +#import + +#if TARGET_OS_IOS || TARGET_OS_TV +#import +#endif + +@interface FRepo () + +@property(nonatomic, strong) FOffsetClock *serverClock; +@property(nonatomic, strong) FPersistenceManager *persistenceManager; +@property(nonatomic, strong) FIRDatabase *database; +@property(nonatomic, strong, readwrite) FAuthenticationManager *auth; +@property(nonatomic, strong) FSyncTree *infoSyncTree; +@property(nonatomic) NSInteger writeIdCounter; +@property(nonatomic) BOOL hijackHash; +@property(nonatomic, strong) FTree *transactionQueueTree; +@property(nonatomic) BOOL loggedTransactionPersistenceWarning; + +/** + * Test only. For load testing the server. + */ +@property(nonatomic, strong) id (^interceptServerDataCallback) + (NSString *pathString, id data); +@end + +@implementation FRepo + +- (id)initWithRepoInfo:(FRepoInfo *)info + config:(FIRDatabaseConfig *)config + database:(FIRDatabase *)database { + self = [super init]; + if (self) { + self.repoInfo = info; + self.config = config; + self.database = database; + + // Access can occur outside of shared queue, so the clock needs to be + // initialized here + self.serverClock = + [[FOffsetClock alloc] initWithClock:[FSystemClock clock] offset:0]; + + self.connection = [[FPersistentConnection alloc] + initWithRepoInfo:self.repoInfo + dispatchQueue:[FIRDatabaseQuery sharedQueue] + config:self.config]; + + // Needs to be called before authentication manager is instantiated + self.eventRaiser = + [[FEventRaiser alloc] initWithQueue:self.config.callbackQueue]; + + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self deferredInit]; + }); + } + return self; +} + +- (void)deferredInit { + // TODO: cleanup on dealloc + __weak FRepo *weakSelf = self; + [self.config.contextProvider listenForAuthTokenChanges:^(NSString *token) { + [weakSelf.connection refreshAuthToken:token]; + }]; + + [self.config.contextProvider + listenForAppCheckTokenChanges:^(NSString *token) { + [weakSelf.connection refreshAppCheckToken:token]; + }]; + + // Open connection now so that by the time we are connected the deferred + // init has run This relies on the fact that all callbacks run on repos + // queue + self.connection.delegate = self; + [self.connection open]; + + self.dataUpdateCount = 0; + self.rangeMergeUpdateCount = 0; + self.interceptServerDataCallback = nil; + + if (self.config.persistenceEnabled) { + NSString *repoHashString = + [NSString stringWithFormat:@"%@_%@", self.repoInfo.host, + self.repoInfo.namespace]; + NSString *persistencePrefix = + [NSString stringWithFormat:@"%@/%@", self.config.sessionIdentifier, + repoHashString]; + + id cachePolicy = [[FLRUCachePolicy alloc] + initWithMaxSize:self.config.persistenceCacheSizeBytes]; + + id engine; + if (self.config.forceStorageEngine != nil) { + engine = self.config.forceStorageEngine; + } else { + FLevelDBStorageEngine *levelDBEngine = + [[FLevelDBStorageEngine alloc] initWithPath:persistencePrefix]; + // We need the repo info to run the legacy migration. Future + // migrations will be managed by the database itself Remove this + // once we are confident that no-one is using legacy migration + // anymore... + [levelDBEngine runLegacyMigration:self.repoInfo]; + engine = levelDBEngine; + } + + self.persistenceManager = + [[FPersistenceManager alloc] initWithStorageEngine:engine + cachePolicy:cachePolicy]; + } else { + self.persistenceManager = nil; + } + + [self initTransactions]; + + // A list of data pieces and paths to be set when this client disconnects + self.onDisconnect = [[FSparseSnapshotTree alloc] init]; + self.infoData = [[FSnapshotHolder alloc] init]; + + FListenProvider *infoListenProvider = [[FListenProvider alloc] init]; + infoListenProvider.startListening = + ^(FQuerySpec *query, NSNumber *tagId, id hash, + fbt_nsarray_nsstring onComplete) { + NSArray *infoEvents = @[]; + FRepo *strongSelf = weakSelf; + id node = [strongSelf.infoData getNode:query.path]; + // This is possibly a hack, but we have different semantics for .info + // endpoints. We don't raise null events on initial data... + if (![node isEmpty]) { + infoEvents = + [strongSelf.infoSyncTree applyServerOverwriteAtPath:query.path + newData:node]; + [strongSelf.eventRaiser raiseCallback:^{ + onComplete(kFWPResponseForActionStatusOk); + }]; + } + return infoEvents; + }; + infoListenProvider.stopListening = ^(FQuerySpec *query, NSNumber *tagId) { + }; + self.infoSyncTree = + [[FSyncTree alloc] initWithListenProvider:infoListenProvider]; + + FListenProvider *serverListenProvider = [[FListenProvider alloc] init]; + serverListenProvider.startListening = + ^(FQuerySpec *query, NSNumber *tagId, id hash, + fbt_nsarray_nsstring onComplete) { + [weakSelf.connection listen:query + tagId:tagId + hash:hash + onComplete:^(NSString *status) { + NSArray *events = onComplete(status); + [weakSelf.eventRaiser raiseEvents:events]; + }]; + // No synchronous events for network-backed sync trees + return @[]; + }; + serverListenProvider.stopListening = ^(FQuerySpec *query, NSNumber *tag) { + [weakSelf.connection unlisten:query tagId:tag]; + }; + self.serverSyncTree = + [[FSyncTree alloc] initWithPersistenceManager:self.persistenceManager + listenProvider:serverListenProvider]; + + [self restoreWrites]; + + [self updateInfo:kDotInfoConnected withValue:@NO]; + + [self setupNotifications]; +} + +- (void)restoreWrites { + NSArray *writes = self.persistenceManager.userWrites; + + NSDictionary *serverValues = + [FServerValues generateServerValues:self.serverClock]; + __block NSInteger lastWriteId = NSIntegerMin; + [writes enumerateObjectsUsingBlock:^(FWriteRecord *write, NSUInteger idx, + BOOL *stop) { + NSInteger writeId = write.writeId; + fbt_void_nsstring_nsstring callback = + ^(NSString *status, NSString *errorReason) { + [self warnIfWriteFailedAtPath:write.path + status:status + message:@"Persisted write"]; + [self ackWrite:writeId + rerunTransactionsAtPath:write.path + status:status]; + }; + if (lastWriteId >= writeId) { + [NSException raise:NSInternalInconsistencyException + format:@"Restored writes were not in order!"]; + } + lastWriteId = writeId; + self.writeIdCounter = writeId + 1; + + if ([write isOverwrite]) { + FFLog(@"I-RDB038001", @"Restoring overwrite with id %ld", + (long)write.writeId); + [self.connection putData:[write.overwrite valForExport:YES] + forPath:[write.path toString] + withHash:nil + withCallback:callback]; + id resolved = + [FServerValues resolveDeferredValueSnapshot:write.overwrite + withSyncTree:self.serverSyncTree + atPath:write.path + serverValues:serverValues]; + [self.serverSyncTree applyUserOverwriteAtPath:write.path + newData:resolved + writeId:writeId + isVisible:YES]; + } else { + FFLog(@"I-RDB038002", @"Restoring merge with id %ld", + (long)write.writeId); + [self.connection mergeData:[write.merge valForExport:YES] + forPath:[write.path toString] + withCallback:callback]; + FCompoundWrite *resolved = [FServerValues + resolveDeferredValueCompoundWrite:write.merge + withSyncTree:self.serverSyncTree + atPath:write.path + serverValues:serverValues]; + [self.serverSyncTree applyUserMergeAtPath:write.path + changedChildren:resolved + writeId:writeId]; + } + }]; +} + +- (NSString *)name { + return self.repoInfo.namespace; +} + +- (NSString *)description { + return [self.repoInfo description]; +} + +- (void)interrupt { + [self.connection interruptForReason:kFInterruptReasonRepoInterrupt]; +} + +- (void)resume { + [self.connection resumeForReason:kFInterruptReasonRepoInterrupt]; +} + +// NOTE: Typically if you're calling this, you should be in an @autoreleasepool +// block to make sure that ARC kicks in and cleans up things no longer +// referenced (i.e. pendingPutsDB). +- (void)dispose { + [self.connection interruptForReason:kFInterruptReasonRepoInterrupt]; + + // We need to nil out any references to LevelDB, to make sure the + // LevelDB exclusive locks are released. + [self.persistenceManager close]; +} + +- (NSInteger)nextWriteId { + return self->_writeIdCounter++; +} + +- (NSTimeInterval)serverTime { + return [self.serverClock currentTime]; +} + +- (void)set:(FPath *)path + withNode:(id)node + withCallback:(fbt_void_nserror_ref)onComplete { + id value = [node valForExport:YES]; + FFLog(@"I-RDB038003", @"Setting: %@ with %@ pri: %@", [path toString], + [value description], [[node getPriority] val]); + + // TODO: Optimize this behavior to either (a) store flag to skip resolving + // where possible and / or (b) store unresolved paths on JSON parse + NSDictionary *serverValues = + [FServerValues generateServerValues:self.serverClock]; + id existing = [self.serverSyncTree calcCompleteEventCacheAtPath:path + excludeWriteIds:@[]]; + id newNode = + [FServerValues resolveDeferredValueSnapshot:node + withExisting:existing + serverValues:serverValues]; + + NSInteger writeId = [self nextWriteId]; + [self.persistenceManager saveUserOverwrite:node + atPath:path + writeId:writeId]; + NSArray *events = [self.serverSyncTree applyUserOverwriteAtPath:path + newData:newNode + writeId:writeId + isVisible:YES]; + [self.eventRaiser raiseEvents:events]; + + [self.connection putData:value + forPath:[path toString] + withHash:nil + withCallback:^(NSString *status, NSString *errorReason) { + [self warnIfWriteFailedAtPath:path + status:status + message:@"setValue: or removeValue:"]; + [self ackWrite:writeId + rerunTransactionsAtPath:path + status:status]; + [self callOnComplete:onComplete + withStatus:status + errorReason:errorReason + andPath:path]; + }]; + + FPath *affectedPath = [self abortTransactionsAtPath:path + error:kFTransactionSet]; + [self rerunTransactionsForPath:affectedPath]; +} + +- (void)update:(FPath *)path + withNodes:(FCompoundWrite *)nodes + withCallback:(fbt_void_nserror_ref)callback { + NSDictionary *values = [nodes valForExport:YES]; + + FFLog(@"I-RDB038004", @"Updating: %@ with %@", [path toString], + [values description]); + NSDictionary *serverValues = + [FServerValues generateServerValues:self.serverClock]; + FCompoundWrite *resolved = + [FServerValues resolveDeferredValueCompoundWrite:nodes + withSyncTree:self.serverSyncTree + atPath:path + serverValues:serverValues]; + + if (!resolved.isEmpty) { + NSInteger writeId = [self nextWriteId]; + [self.persistenceManager saveUserMerge:nodes + atPath:path + writeId:writeId]; + NSArray *events = [self.serverSyncTree applyUserMergeAtPath:path + changedChildren:resolved + writeId:writeId]; + [self.eventRaiser raiseEvents:events]; + + [self.connection mergeData:values + forPath:[path description] + withCallback:^(NSString *status, NSString *errorReason) { + [self warnIfWriteFailedAtPath:path + status:status + message:@"updateChildValues:"]; + [self ackWrite:writeId + rerunTransactionsAtPath:path + status:status]; + [self callOnComplete:callback + withStatus:status + errorReason:errorReason + andPath:path]; + }]; + + [nodes enumerateWrites:^(FPath *childPath, id node, BOOL *stop) { + FPath *pathFromRoot = [path child:childPath]; + FFLog(@"I-RDB038005", @"Cancelling transactions at path: %@", + pathFromRoot); + FPath *affectedPath = [self abortTransactionsAtPath:pathFromRoot + error:kFTransactionSet]; + [self rerunTransactionsForPath:affectedPath]; + }]; + } else { + FFLog(@"I-RDB038006", @"update called with empty data. Doing nothing"); + // Do nothing, just call the callback + [self callOnComplete:callback + withStatus:@"ok" + errorReason:nil + andPath:path]; + } +} + +- (void)onDisconnectCancel:(FPath *)path + withCallback:(fbt_void_nserror_ref)callback { + [self.connection + onDisconnectCancelPath:path + withCallback:^(NSString *status, NSString *errorReason) { + BOOL success = + [status isEqualToString:kFWPResponseForActionStatusOk]; + if (success) { + [self.onDisconnect forgetPath:path]; + } else { + FFLog(@"I-RDB038007", + @"cancelDisconnectOperations: at %@ failed: %@", + path, status); + } + + [self callOnComplete:callback + withStatus:status + errorReason:errorReason + andPath:path]; + }]; +} + +- (void)onDisconnectSet:(FPath *)path + withNode:(id)node + withCallback:(fbt_void_nserror_ref)callback { + [self.connection + onDisconnectPutData:[node valForExport:YES] + forPath:path + withCallback:^(NSString *status, NSString *errorReason) { + BOOL success = + [status isEqualToString:kFWPResponseForActionStatusOk]; + if (success) { + [self.onDisconnect rememberData:node onPath:path]; + } else { + FFWarn(@"I-RDB038008", + @"onDisconnectSetValue: or " + @"onDisconnectRemoveValue: at %@ failed: %@", + path, status); + } + + [self callOnComplete:callback + withStatus:status + errorReason:errorReason + andPath:path]; + }]; +} + +- (void)onDisconnectUpdate:(FPath *)path + withNodes:(FCompoundWrite *)nodes + withCallback:(fbt_void_nserror_ref)callback { + if (!nodes.isEmpty) { + NSDictionary *values = [nodes valForExport:YES]; + + [self.connection + onDisconnectMergeData:values + forPath:path + withCallback:^(NSString *status, NSString *errorReason) { + BOOL success = [status + isEqualToString:kFWPResponseForActionStatusOk]; + if (success) { + [nodes enumerateWrites:^(FPath *relativePath, + id nodeUnresolved, + BOOL *stop) { + FPath *childPath = [path child:relativePath]; + [self.onDisconnect rememberData:nodeUnresolved + onPath:childPath]; + }]; + } else { + FFWarn(@"I-RDB038009", + @"onDisconnectUpdateChildValues: at %@ " + @"failed %@", + path, status); + } + + [self callOnComplete:callback + withStatus:status + errorReason:errorReason + andPath:path]; + }]; + } else { + // Do nothing, just call the callback + [self callOnComplete:callback + withStatus:@"ok" + errorReason:nil + andPath:path]; + } +} + +- (void)purgeOutstandingWrites { + FFLog(@"I-RDB038010", @"Purging outstanding writes"); + NSArray *events = [self.serverSyncTree removeAllWrites]; + [self.eventRaiser raiseEvents:events]; + // Abort any transactions + [self abortTransactionsAtPath:[FPath empty] error:kFErrorWriteCanceled]; + // Remove outstanding writes from connection + [self.connection purgeOutstandingWrites]; +} + +- (void)getData:(FIRDatabaseQuery *)query + withCompletionBlock:(void (^)(NSError *__nullable error, + FIRDataSnapshot *__nullable snapshot))block { + FQuerySpec *querySpec = [query querySpec]; + id node = [self.serverSyncTree getServerValue:[query querySpec]]; + if (node != nil) { + [self.eventRaiser raiseCallback:^{ + block(nil, [[FIRDataSnapshot alloc] + initWithRef:query.ref + indexedNode:[FIndexedNode + indexedNodeWithNode:node + index:querySpec.index]]); + }]; + return; + } + [self.persistenceManager setQueryActive:querySpec]; + [self.connection + getDataAtPath:[query.path toString] + withParams:querySpec.params.wireProtocolParams + withCallback:^(NSString *status, id data, NSString *errorReason) { + id node; + if (![status isEqualToString:kFWPResponseForActionStatusOk]) { + FFLog(@"I-RDB038024", + @"getValue for query %@ falling back to disk cache", + [querySpec.path toString]); + FIndexedNode *node = + [self.serverSyncTree persistenceServerCache:querySpec]; + if (node == nil) { + NSDictionary *errorDict = @{ + NSLocalizedFailureReasonErrorKey : errorReason, + NSLocalizedDescriptionKey : [NSString + stringWithFormat: + @"Unable to get latest value for query %@, " + @"client offline with no active listeners " + @"and no matching disk cache entries", + querySpec] + }; + [self.eventRaiser raiseCallback:^{ + block([NSError errorWithDomain:kFirebaseCoreErrorDomain + code:1 + userInfo:errorDict], + nil); + }]; + return; + } + [self.eventRaiser raiseCallback:^{ + block(nil, [[FIRDataSnapshot alloc] initWithRef:query.ref + indexedNode:node]); + }]; + } else { + node = [FSnapshotUtilities nodeFrom:data]; + [self.eventRaiser + raiseEvents:[self.serverSyncTree + applyServerOverwriteAtPath:[query path] + newData:node]]; + [self.eventRaiser raiseCallback:^{ + block( + nil, + [[FIRDataSnapshot alloc] + initWithRef:query.ref + indexedNode:[FIndexedNode + indexedNodeWithNode:node + index:querySpec.index]]); + }]; + } + [self.persistenceManager setQueryInactive:querySpec]; + }]; +} + +- (void)addEventRegistration:(id)eventRegistration + forQuery:(FQuerySpec *)query { + NSArray *events = nil; + if ([[query.path getFront] isEqualToString:kDotInfoPrefix]) { + events = [self.infoSyncTree addEventRegistration:eventRegistration + forQuery:query]; + } else { + events = [self.serverSyncTree addEventRegistration:eventRegistration + forQuery:query]; + } + [self.eventRaiser raiseEvents:events]; +} + +- (void)removeEventRegistration:(id)eventRegistration + forQuery:(FQuerySpec *)query { + // These are guaranteed not to raise events, since we're not passing in a + // cancelError. However we can future-proof a little bit by handling the + // return values anyways. + FFLog(@"I-RDB038011", @"Removing event registration with hande: %lu", + (unsigned long)eventRegistration.handle); + NSArray *events = nil; + if ([[query.path getFront] isEqualToString:kDotInfoPrefix]) { + events = [self.infoSyncTree removeEventRegistration:eventRegistration + forQuery:query + cancelError:nil]; + } else { + events = [self.serverSyncTree removeEventRegistration:eventRegistration + forQuery:query + cancelError:nil]; + } + [self.eventRaiser raiseEvents:events]; +} + +- (void)keepQuery:(FQuerySpec *)query synced:(BOOL)synced { + NSAssert(![[query.path getFront] isEqualToString:kDotInfoPrefix], + @"Can't keep .info tree synced!"); + [self.serverSyncTree keepQuery:query synced:synced]; +} + +- (void)updateInfo:(NSString *)pathString withValue:(id)value { + // hack to make serverTimeOffset available in a threadsafe way. Property is + // marked as atomic + if ([pathString isEqualToString:kDotInfoServerTimeOffset]) { + NSTimeInterval offset = [(NSNumber *)value doubleValue] / 1000.0; + self.serverClock = + [[FOffsetClock alloc] initWithClock:[FSystemClock clock] + offset:offset]; + } + + FPath *path = [[FPath alloc] + initWith:[NSString + stringWithFormat:@"%@/%@", kDotInfoPrefix, pathString]]; + id newNode = [FSnapshotUtilities nodeFrom:value]; + [self.infoData updateSnapshot:path withNewSnapshot:newNode]; + NSArray *events = [self.infoSyncTree applyServerOverwriteAtPath:path + newData:newNode]; + [self.eventRaiser raiseEvents:events]; +} + +- (void)callOnComplete:(fbt_void_nserror_ref)onComplete + withStatus:(NSString *)status + errorReason:(NSString *)errorReason + andPath:(FPath *)path { + if (onComplete) { + FIRDatabaseReference *ref = + [[FIRDatabaseReference alloc] initWithRepo:self path:path]; + BOOL statusOk = [status isEqualToString:kFWPResponseForActionStatusOk]; + NSError *err = nil; + if (!statusOk) { + err = [FUtilities errorForStatus:status andReason:errorReason]; + } + [self.eventRaiser raiseCallback:^{ + onComplete(err, ref); + }]; + } +} + +- (void)ackWrite:(NSInteger)writeId + rerunTransactionsAtPath:(FPath *)path + status:(NSString *)status { + if ([status isEqualToString:kFErrorWriteCanceled]) { + // This write was already removed, we just need to ignore it... + } else { + BOOL success = [status isEqualToString:kFWPResponseForActionStatusOk]; + NSArray *clearEvents = + [self.serverSyncTree ackUserWriteWithWriteId:writeId + revert:!success + persist:YES + clock:self.serverClock]; + if ([clearEvents count] > 0) { + [self rerunTransactionsForPath:path]; + } + [self.eventRaiser raiseEvents:clearEvents]; + } +} + +- (void)warnIfWriteFailedAtPath:(FPath *)path + status:(NSString *)status + message:(NSString *)message { + if (!([status isEqualToString:kFWPResponseForActionStatusOk] || + [status isEqualToString:kFErrorWriteCanceled])) { + FFWarn(@"I-RDB038012", @"%@ at %@ failed: %@", message, path, status); + } +} + +#pragma mark - +#pragma mark FPersistentConnectionDelegate methods + +- (void)onDataUpdate:(FPersistentConnection *)fpconnection + forPath:(NSString *)pathString + message:(id)data + isMerge:(BOOL)isMerge + tagId:(NSNumber *)tagId { + FFLog(@"I-RDB038013", @"onDataUpdateForPath: %@ withMessage: %@", + pathString, data); + + // For testing. + self.dataUpdateCount++; + + FPath *path = [[FPath alloc] initWith:pathString]; + data = self.interceptServerDataCallback + ? self.interceptServerDataCallback(pathString, data) + : data; + NSArray *events = nil; + + if (tagId != nil) { + if (isMerge) { + NSDictionary *message = data; + FCompoundWrite *taggedChildren = + [FCompoundWrite compoundWriteWithValueDictionary:message]; + events = + [self.serverSyncTree applyTaggedQueryMergeAtPath:path + changedChildren:taggedChildren + tagId:tagId]; + } else { + id taggedSnap = [FSnapshotUtilities nodeFrom:data]; + events = + [self.serverSyncTree applyTaggedQueryOverwriteAtPath:path + newData:taggedSnap + tagId:tagId]; + } + } else if (isMerge) { + NSDictionary *message = data; + FCompoundWrite *changedChildren = + [FCompoundWrite compoundWriteWithValueDictionary:message]; + events = [self.serverSyncTree applyServerMergeAtPath:path + changedChildren:changedChildren]; + } else { + id snap = [FSnapshotUtilities nodeFrom:data]; + events = [self.serverSyncTree applyServerOverwriteAtPath:path + newData:snap]; + } + + if ([events count] > 0) { + // Since we have a listener outstanding for each transaction, receiving + // any events is a proxy for some change having occurred. + [self rerunTransactionsForPath:path]; + } + + [self.eventRaiser raiseEvents:events]; +} + +- (void)onRangeMerge:(NSArray *)ranges + forPath:(NSString *)pathString + tagId:(NSNumber *)tag { + FFLog(@"I-RDB038014", @"onRangeMerge: %@ => %@", pathString, ranges); + + // For testing + self.rangeMergeUpdateCount++; + + FPath *path = [[FPath alloc] initWith:pathString]; + NSArray *events; + if (tag != nil) { + events = [self.serverSyncTree applyTaggedServerRangeMergeAtPath:path + updates:ranges + tagId:tag]; + } else { + events = [self.serverSyncTree applyServerRangeMergeAtPath:path + updates:ranges]; + } + if (events.count > 0) { + // Since we have a listener outstanding for each transaction, receiving + // any events is a proxy for some change having occurred. + [self rerunTransactionsForPath:path]; + } + + [self.eventRaiser raiseEvents:events]; +} + +- (void)onConnect:(FPersistentConnection *)fpconnection { + [self updateInfo:kDotInfoConnected withValue:@YES]; +} + +- (void)onDisconnect:(FPersistentConnection *)fpconnection { + [self updateInfo:kDotInfoConnected withValue:@NO]; + [self runOnDisconnectEvents]; +} + +- (void)onServerInfoUpdate:(FPersistentConnection *)fpconnection + updates:(NSDictionary *)updates { + for (NSString *key in updates) { + id val = [updates objectForKey:key]; + [self updateInfo:key withValue:val]; + } +} + +- (void)setupNotifications { + NSString *const *backgroundConstant = (NSString *const *)dlsym( + RTLD_DEFAULT, "UIApplicationDidEnterBackgroundNotification"); + if (backgroundConstant) { + FFLog(@"I-RDB038015", @"Registering for background notification."); + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(didEnterBackground) + name:*backgroundConstant + object:nil]; + } else { + FFLog(@"I-RDB038016", + @"Skipped registering for background notification."); + } +} + +- (void)didEnterBackground { + if (!self.config.persistenceEnabled) + return; + +// Targetted compilation is ONLY for testing. UIKit is weak-linked in actual +// release build. +#if TARGET_OS_IOS || TARGET_OS_TV + // The idea is to wait until any outstanding sets get written to disk. Since + // the sets might still be in our dispatch queue, we wait for the dispatch + // queue to catch up and for persistence to catch up. This may be + // undesirable though. The dispatch queue might just be processing a bunch + // of incoming data or something. We might want to keep track of whether + // there are any unpersisted sets or something. + FFLog(@"I-RDB038017", + @"Entering background. Starting background task to finish work."); + Class uiApplicationClass = NSClassFromString(@"UIApplication"); + assert(uiApplicationClass); // If we are here, we should be on iOS and + // UIApplication should be available. + + UIApplication *application = [uiApplicationClass sharedApplication]; + __block UIBackgroundTaskIdentifier bgTask = + [application beginBackgroundTaskWithExpirationHandler:^{ + [application endBackgroundTask:bgTask]; + }]; + + NSDate *start = [NSDate date]; + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + NSTimeInterval finishTime = [start timeIntervalSinceNow] * -1; + FFLog(@"I-RDB038018", @"Background task completed. Queue time: %f", + finishTime); + [application endBackgroundTask:bgTask]; + }); +#endif +} + +#pragma mark - +#pragma mark Internal methods + +/** + * Applies all the changes stored up in the onDisconnect tree + */ +- (void)runOnDisconnectEvents { + FFLog(@"I-RDB038019", @"Running onDisconnectEvents"); + NSDictionary *serverValues = + [FServerValues generateServerValues:self.serverClock]; + NSMutableArray *events = [[NSMutableArray alloc] init]; + + [self.onDisconnect + forEachTreeAtPath:[FPath empty] + do:^(FPath *path, id node) { + id existing = [self.serverSyncTree + calcCompleteEventCacheAtPath:path + excludeWriteIds:@[]]; + id resolved = [FServerValues + resolveDeferredValueSnapshot:node + withExisting:existing + serverValues:serverValues]; + [events addObjectsFromArray: + [self.serverSyncTree + applyServerOverwriteAtPath:path + newData:resolved]]; + FPath *affectedPath = + [self abortTransactionsAtPath:path + error:kFTransactionSet]; + [self rerunTransactionsForPath:affectedPath]; + }]; + + self.onDisconnect = [[FSparseSnapshotTree alloc] init]; + [self.eventRaiser raiseEvents:events]; +} + +- (NSDictionary *)dumpListens { + return [self.connection dumpListens]; +} + +#pragma mark - +#pragma mark Transactions + +/** + * Setup the transaction data structures + */ +- (void)initTransactions { + self.transactionQueueTree = [[FTree alloc] init]; + self.hijackHash = NO; + self.loggedTransactionPersistenceWarning = NO; +} + +/** + * Creates a new transaction, add its to the transactions we're tracking, and + * sends it to the server if possible + */ +- (void)startTransactionOnPath:(FPath *)path + update:(fbt_transactionresult_mutabledata)update + onComplete:(fbt_void_nserror_bool_datasnapshot)onComplete + withLocalEvents:(BOOL)applyLocally { + if (self.config.persistenceEnabled && + !self.loggedTransactionPersistenceWarning) { + self.loggedTransactionPersistenceWarning = YES; + FFInfo(@"I-RDB038020", + @"runTransactionBlock: usage detected while persistence is " + @"enabled. Please be aware that transactions " + @"*will not* be persisted across app restarts. " + @"See " + @"https://www.firebase.com/docs/ios/guide/" + @"offline-capabilities.html#section-handling-transactions-" + @"offline for more details."); + } + + FIRDatabaseReference *watchRef = + [[FIRDatabaseReference alloc] initWithRepo:self path:path]; + // make sure we're listening on this node + // Note: we can't do this asynchronously. To preserve event ordering, it has + // to be done in this block. This is ok, this block is guaranteed to be our + // own event loop + NSUInteger handle = [[FUtilities LUIDGenerator] integerValue]; + fbt_void_datasnapshot cb = ^(FIRDataSnapshot *snapshot) { + }; + FValueEventRegistration *registration = + [[FValueEventRegistration alloc] initWithRepo:self + handle:handle + callback:cb + cancelCallback:nil]; + [watchRef.repo addEventRegistration:registration + forQuery:watchRef.querySpec]; + fbt_void_void unwatcher = ^{ + [watchRef removeObserverWithHandle:handle]; + }; + + // Save all the data that represents this transaction + FTupleTransaction *transaction = [[FTupleTransaction alloc] init]; + transaction.path = path; + transaction.update = update; + transaction.onComplete = onComplete; + transaction.status = FTransactionInitializing; + transaction.order = [FUtilities LUIDGenerator]; + transaction.applyLocally = applyLocally; + transaction.retryCount = 0; + transaction.unwatcher = unwatcher; + transaction.currentWriteId = nil; + transaction.currentInputSnapshot = nil; + transaction.currentOutputSnapshotRaw = nil; + transaction.currentOutputSnapshotResolved = nil; + + // Run transaction initially + id currentState = [self latestStateAtPath:path excludeWriteIds:nil]; + transaction.currentInputSnapshot = currentState; + FIRMutableData *mutableCurrent = + [[FIRMutableData alloc] initWithNode:currentState]; + FIRTransactionResult *result = transaction.update(mutableCurrent); + + if (!result.isSuccess) { + // Abort the transaction + transaction.unwatcher(); + transaction.currentOutputSnapshotRaw = nil; + transaction.currentOutputSnapshotResolved = nil; + if (transaction.onComplete) { + FIRDatabaseReference *ref = + [[FIRDatabaseReference alloc] initWithRepo:self + path:transaction.path]; + FIndexedNode *indexedNode = [FIndexedNode + indexedNodeWithNode:transaction.currentInputSnapshot]; + FIRDataSnapshot *snap = + [[FIRDataSnapshot alloc] initWithRef:ref + indexedNode:indexedNode]; + [self.eventRaiser raiseCallback:^{ + transaction.onComplete(nil, NO, snap); + }]; + } + } else { + // Note: different from js. We don't need to validate, FIRMutableData + // does validation. We also don't have to worry about priorities. Just + // mark as run and add to queue. + transaction.status = FTransactionRun; + FTree *queueNode = [self.transactionQueueTree subTree:transaction.path]; + NSMutableArray *nodeQueue = [queueNode getValue]; + if (nodeQueue == nil) { + nodeQueue = [[NSMutableArray alloc] init]; + } + [nodeQueue addObject:transaction]; + [queueNode setValue:nodeQueue]; + + // Update visibleData and raise events + // Note: We intentionally raise events after updating all of our + // transaction state, since the user could start new transactions from + // the event callbacks + NSDictionary *serverValues = + [FServerValues generateServerValues:self.serverClock]; + id newValUnresolved = [result.update nodeValue]; + id newVal = + [FServerValues resolveDeferredValueSnapshot:newValUnresolved + withExisting:currentState + serverValues:serverValues]; + transaction.currentOutputSnapshotRaw = newValUnresolved; + transaction.currentOutputSnapshotResolved = newVal; + transaction.currentWriteId = + [NSNumber numberWithInteger:[self nextWriteId]]; + + NSArray *events = [self.serverSyncTree + applyUserOverwriteAtPath:path + newData:newVal + writeId:[transaction.currentWriteId integerValue] + isVisible:transaction.applyLocally]; + [self.eventRaiser raiseEvents:events]; + + [self sendAllReadyTransactions]; + } +} + +/** + * @param writeIdsToExclude A specific set to exclude + */ +- (id)latestStateAtPath:(FPath *)path + excludeWriteIds:(NSArray *)writeIdsToExclude { + id latestState = + [self.serverSyncTree calcCompleteEventCacheAtPath:path + excludeWriteIds:writeIdsToExclude]; + return latestState ? latestState : [FEmptyNode emptyNode]; +} + +/** + * Sends any already-run transactions that aren't waiting for outstanding + * transactions to complete. + * + * Externally, call the version with no arguments. + * Internally, calls itself recursively with a particular transactionQueueTree + * node to recurse through the tree + */ +- (void)sendAllReadyTransactions { + FTree *node = self.transactionQueueTree; + + [self pruneCompletedTransactionsBelowNode:node]; + [self sendReadyTransactionsForTree:node]; +} + +- (void)sendReadyTransactionsForTree:(FTree *)node { + NSMutableArray *queue = [node getValue]; + if (queue != nil) { + queue = [self buildTransactionQueueAtNode:node]; + NSAssert([queue count] > 0, @"Sending zero length transaction queue"); + + NSUInteger notRunIndex = [queue + indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) { + return ((FTupleTransaction *)obj).status != FTransactionRun; + }]; + + // If they're all run (and not sent), we can send them. Else, we must + // wait. + if (notRunIndex == NSNotFound) { + [self sendTransactionQueue:queue atPath:node.path]; + } + } else if ([node hasChildren]) { + [node forEachChild:^(FTree *child) { + [self sendReadyTransactionsForTree:child]; + }]; + } +} + +/** + * Given a list of run transactions, send them to the server and then handle the + * result (success or failure). + */ +- (void)sendTransactionQueue:(NSMutableArray *)queue atPath:(FPath *)path { + // Mark transactions as sent and bump the retry count + NSMutableArray *writeIdsToExclude = [[NSMutableArray alloc] init]; + for (FTupleTransaction *transaction in queue) { + [writeIdsToExclude addObject:transaction.currentWriteId]; + } + id latestState = [self latestStateAtPath:path + excludeWriteIds:writeIdsToExclude]; + id snapToSend = latestState; + NSString *latestHash = [latestState dataHash]; + for (FTupleTransaction *transaction in queue) { + NSAssert( + transaction.status == FTransactionRun, + @"[FRepo sendTransactionQueue:] items in queue should all be run."); + FFLog(@"I-RDB038021", @"Transaction at %@ set to SENT", + transaction.path); + transaction.status = FTransactionSent; + transaction.retryCount++; + FPath *relativePath = [FPath relativePathFrom:path to:transaction.path]; + // If we've gotten to this point, the output snapshot must be defined. + snapToSend = + [snapToSend updateChild:relativePath + withNewChild:transaction.currentOutputSnapshotRaw]; + } + + id dataToSend = [snapToSend valForExport:YES]; + NSString *pathToSend = [path description]; + latestHash = self.hijackHash ? @"badhash" : latestHash; + + // Send the put + [self.connection + putData:dataToSend + forPath:pathToSend + withHash:latestHash + withCallback:^(NSString *status, NSString *errorReason) { + FFLog(@"I-RDB038022", @"Transaction put response: %@ : %@", + pathToSend, status); + + NSMutableArray *events = [[NSMutableArray alloc] init]; + if ([status isEqualToString:kFWPResponseForActionStatusOk]) { + // Queue up the callbacks and fire them after cleaning up all of + // our transaction state, since the callback could trigger more + // transactions or sets. + NSMutableArray *callbacks = [[NSMutableArray alloc] init]; + for (FTupleTransaction *transaction in queue) { + transaction.status = FTransactionCompleted; + [events addObjectsFromArray: + [self.serverSyncTree + ackUserWriteWithWriteId: + [transaction.currentWriteId integerValue] + revert:NO + persist:NO + clock:self.serverClock]]; + if (transaction.onComplete) { + // We never unset the output snapshot, and given that this + // transaction is complete, it should be set + id node = + transaction.currentOutputSnapshotResolved; + FIndexedNode *indexedNode = + [FIndexedNode indexedNodeWithNode:node]; + FIRDatabaseReference *ref = [[FIRDatabaseReference alloc] + initWithRepo:self + path:transaction.path]; + FIRDataSnapshot *snapshot = + [[FIRDataSnapshot alloc] initWithRef:ref + indexedNode:indexedNode]; + fbt_void_void cb = ^{ + transaction.onComplete(nil, YES, snapshot); + }; + [callbacks addObject:[cb copy]]; + } + transaction.unwatcher(); + } + + // Now remove the completed transactions. + [self + pruneCompletedTransactionsBelowNode:[self.transactionQueueTree + subTree:path]]; + // There may be pending transactions that we can now send. + [self sendAllReadyTransactions]; + + // Finally, trigger onComplete callbacks + [self.eventRaiser raiseCallbacks:callbacks]; + } else { + // transactions are no longer sent. Update their status + // appropriately. + if ([status + isEqualToString:kFWPResponseForActionStatusDataStale]) { + for (FTupleTransaction *transaction in queue) { + if (transaction.status == FTransactionSentNeedsAbort) { + transaction.status = FTransactionNeedsAbort; + } else { + transaction.status = FTransactionRun; + } + } + } else { + FFWarn(@"I-RDB038023", + @"runTransactionBlock: at %@ failed: %@", path, + status); + for (FTupleTransaction *transaction in queue) { + transaction.status = FTransactionNeedsAbort; + [transaction setAbortStatus:status reason:errorReason]; + } + } + } + + [self rerunTransactionsForPath:path]; + [self.eventRaiser raiseEvents:events]; + }]; +} + +/** + * Finds all transactions dependent on the data at changed Path and reruns them. + * + * Should be called any time cached data changes. + * + * Return the highest path that was affected by rerunning transactions. This is + * the path at which events need to be raised for. + */ +- (FPath *)rerunTransactionsForPath:(FPath *)changedPath { + // For the common case that there are no transactions going on, skip all + // this! + if ([self.transactionQueueTree isEmpty]) { + return changedPath; + } else { + FTree *rootMostTransactionNode = + [self getAncestorTransactionNodeForPath:changedPath]; + FPath *path = rootMostTransactionNode.path; + + NSArray *queue = + [self buildTransactionQueueAtNode:rootMostTransactionNode]; + [self rerunTransactionQueue:queue atPath:path]; + + return path; + } +} + +/** + * Does all the work of rerunning transactions (as well as cleans up aborted + * transactions and whatnot). + */ +- (void)rerunTransactionQueue:(NSArray *)queue atPath:(FPath *)path { + if (queue.count == 0) { + return; // nothing to do + } + + // Queue up the callbacks and fire them after cleaning up all of our + // transaction state, since the callback could trigger more transactions or + // sets. + NSMutableArray *events = [[NSMutableArray alloc] init]; + NSMutableArray *callbacks = [[NSMutableArray alloc] init]; + + // Ignore, by default, all of the sets in this queue, since we're re-running + // all of them. However, we want to include the results of new sets + // triggered as part of this re-run, so we don't want to ignore a range, + // just these specific sets. + NSMutableArray *writeIdsToExclude = [[NSMutableArray alloc] init]; + for (FTupleTransaction *transaction in queue) { + [writeIdsToExclude addObject:transaction.currentWriteId]; + } + + for (FTupleTransaction *transaction in queue) { + FPath *relativePath __unused = + [FPath relativePathFrom:path to:transaction.path]; + BOOL abortTransaction = NO; + NSAssert(relativePath != nil, @"[FRepo rerunTransactionsQueue:] " + @"relativePath should not be null."); + + if (transaction.status == FTransactionNeedsAbort) { + abortTransaction = YES; + if (![transaction.abortStatus + isEqualToString:kFErrorWriteCanceled]) { + NSArray *ackEvents = [self.serverSyncTree + ackUserWriteWithWriteId:[transaction.currentWriteId + integerValue] + revert:YES + persist:NO + clock:self.serverClock]; + [events addObjectsFromArray:ackEvents]; + } + } else if (transaction.status == FTransactionRun) { + if (transaction.retryCount >= kFTransactionMaxRetries) { + abortTransaction = YES; + [transaction setAbortStatus:kFTransactionTooManyRetries + reason:nil]; + [events + addObjectsFromArray: + [self.serverSyncTree + ackUserWriteWithWriteId:[transaction.currentWriteId + integerValue] + revert:YES + persist:NO + clock:self.serverClock]]; + } else { + // This code reruns a transaction + id currentNode = + [self latestStateAtPath:transaction.path + excludeWriteIds:writeIdsToExclude]; + transaction.currentInputSnapshot = currentNode; + FIRMutableData *mutableCurrent = + [[FIRMutableData alloc] initWithNode:currentNode]; + FIRTransactionResult *result = + transaction.update(mutableCurrent); + if (result.isSuccess) { + NSNumber *oldWriteId = transaction.currentWriteId; + NSDictionary *serverValues = + [FServerValues generateServerValues:self.serverClock]; + + id newVal = [result.update nodeValue]; + id newValResolved = [FServerValues + resolveDeferredValueSnapshot:newVal + withExisting:transaction + .currentInputSnapshot + serverValues:serverValues]; + + transaction.currentOutputSnapshotRaw = newVal; + transaction.currentOutputSnapshotResolved = newValResolved; + + transaction.currentWriteId = + [NSNumber numberWithInteger:[self nextWriteId]]; + // Mutates writeIdsToExclude in place + [writeIdsToExclude removeObject:oldWriteId]; + [events + addObjectsFromArray: + [self.serverSyncTree + applyUserOverwriteAtPath:transaction.path + newData: + transaction + .currentOutputSnapshotResolved + writeId: + [transaction.currentWriteId + integerValue] + isVisible:transaction + .applyLocally]]; + [events addObjectsFromArray: + [self.serverSyncTree + ackUserWriteWithWriteId:[oldWriteId + integerValue] + revert:YES + persist:NO + clock:self.serverClock]]; + } else { + abortTransaction = YES; + // The user aborted the transaction. JS treats ths as a + // "nodata" abort, but it's not an error, so we don't send + // them an error. + [transaction setAbortStatus:nil reason:nil]; + [events + addObjectsFromArray: + [self.serverSyncTree + ackUserWriteWithWriteId: + [transaction.currentWriteId integerValue] + revert:YES + persist:NO + clock:self.serverClock]]; + } + } + } + + [self.eventRaiser raiseEvents:events]; + events = nil; + + if (abortTransaction) { + // Abort + transaction.status = FTransactionCompleted; + transaction.unwatcher(); + if (transaction.onComplete) { + FIRDatabaseReference *ref = [[FIRDatabaseReference alloc] + initWithRepo:self + path:transaction.path]; + FIndexedNode *lastInput = [FIndexedNode + indexedNodeWithNode:transaction.currentInputSnapshot]; + FIRDataSnapshot *snap = + [[FIRDataSnapshot alloc] initWithRef:ref + indexedNode:lastInput]; + fbt_void_void cb = ^{ + // Unlike JS, no need to check for "nodata" because ObjC has + // abortError = nil + transaction.onComplete(transaction.abortError, NO, snap); + }; + [callbacks addObject:[cb copy]]; + } + } + } + + // Note: unlike current js client, we don't need to preserve priority. Users + // can set priority via FIRMutableData + + // Clean up completed transactions. + [self pruneCompletedTransactionsBelowNode:self.transactionQueueTree]; + + // Now fire callbacks, now that we're in a good, known state. + [self.eventRaiser raiseCallbacks:callbacks]; + + // Try to send the transaction result to the server + [self sendAllReadyTransactions]; +} + +- (FTree *)getAncestorTransactionNodeForPath:(FPath *)path { + FTree *transactionNode = self.transactionQueueTree; + + while (![path isEmpty] && [transactionNode getValue] == nil) { + NSString *front = [path getFront]; + transactionNode = + [transactionNode subTree:[[FPath alloc] initWith:front]]; + path = [path popFront]; + } + + return transactionNode; +} + +- (NSMutableArray *)buildTransactionQueueAtNode:(FTree *)node { + NSMutableArray *queue = [[NSMutableArray alloc] init]; + [self aggregateTransactionQueuesForNode:node andQueue:queue]; + + [queue sortUsingComparator:^NSComparisonResult(FTupleTransaction *obj1, + FTupleTransaction *obj2) { + return [obj1.order compare:obj2.order]; + }]; + + return queue; +} + +- (void)aggregateTransactionQueuesForNode:(FTree *)node + andQueue:(NSMutableArray *)queue { + NSArray *nodeQueue = [node getValue]; + [queue addObjectsFromArray:nodeQueue]; + + [node forEachChild:^(FTree *child) { + [self aggregateTransactionQueuesForNode:child andQueue:queue]; + }]; +} + +/** + * Remove COMPLETED transactions at or below this node in the + * transactionQueueTree + */ +- (void)pruneCompletedTransactionsBelowNode:(FTree *)node { + NSMutableArray *queue = [node getValue]; + if (queue != nil) { + int i = 0; + // remove all of the completed transactions from the queue + while (i < queue.count) { + FTupleTransaction *transaction = [queue objectAtIndex:i]; + if (transaction.status == FTransactionCompleted) { + [queue removeObjectAtIndex:i]; + } else { + i++; + } + } + if (queue.count > 0) { + [node setValue:queue]; + } else { + [node setValue:nil]; + } + } + + [node forEachChildMutationSafe:^(FTree *child) { + [self pruneCompletedTransactionsBelowNode:child]; + }]; +} + +/** + * Aborts all transactions on ancestors or descendants of the specified path. + * Called when doing a setValue: or updateChildValues: since we consider them + * incompatible with transactions + * + * @param path path for which we want to abort related transactions. + */ +- (FPath *)abortTransactionsAtPath:(FPath *)path error:(NSString *)error { + // For the common case that there are no transactions going on, skip all + // this! + if ([self.transactionQueueTree isEmpty]) { + return path; + } else { + FPath *affectedPath = + [self getAncestorTransactionNodeForPath:path].path; + + FTree *transactionNode = [self.transactionQueueTree subTree:path]; + [transactionNode forEachAncestor:^BOOL(FTree *ancestor) { + [self abortTransactionsAtNode:ancestor error:error]; + return NO; + }]; + + [self abortTransactionsAtNode:transactionNode error:error]; + + [transactionNode forEachDescendant:^(FTree *child) { + [self abortTransactionsAtNode:child error:error]; + }]; + + return affectedPath; + } +} + +/** + * Abort transactions stored in this transactions queue node. + * + * @param node Node to abort transactions for. + */ +- (void)abortTransactionsAtNode:(FTree *)node error:(NSString *)error { + NSMutableArray *queue = [node getValue]; + if (queue != nil) { + + // Queue up the callbacks and fire them after cleaning up all of our + // transaction state, since can be immediately aborted and removed. + NSMutableArray *callbacks = [[NSMutableArray alloc] init]; + + // Go through queue. Any already-sent transactions must be marked for + // abort, while the unsent ones can be immediately aborted and removed + NSMutableArray *events = [[NSMutableArray alloc] init]; + int lastSent = -1; + // Note: all of the sent transactions will be at the front of the queue, + // so safe to increment lastSent + for (FTupleTransaction *transaction in queue) { + if (transaction.status == FTransactionSentNeedsAbort) { + // No-op. already marked. + } else if (transaction.status == FTransactionSent) { + // Mark this transaction for abort when it returns + lastSent++; + transaction.status = FTransactionSentNeedsAbort; + [transaction setAbortStatus:error reason:nil]; + } else { + // we can abort this immediately + transaction.unwatcher(); + if ([error isEqualToString:kFTransactionSet]) { + [events + addObjectsFromArray: + [self.serverSyncTree + ackUserWriteWithWriteId: + [transaction.currentWriteId integerValue] + revert:YES + persist:NO + clock:self.serverClock]]; + } else { + // If it was cancelled it was already removed from the sync + // tree, no need to ack + NSAssert([error isEqualToString:kFErrorWriteCanceled], nil); + } + + if (transaction.onComplete) { + NSError *abortReason = [FUtilities errorForStatus:error + andReason:nil]; + FIRDataSnapshot *snapshot = nil; + fbt_void_void cb = ^{ + transaction.onComplete(abortReason, NO, snapshot); + }; + [callbacks addObject:[cb copy]]; + } + } + } + if (lastSent == -1) { + // We're not waiting for any sent transactions. We can clear the + // queue. + [node setValue:nil]; + } else { + // Remove the transactions we aborted + NSRange theRange; + theRange.location = lastSent + 1; + theRange.length = queue.count - theRange.location; + [queue removeObjectsInRange:theRange]; + } + + // Now fire the callbacks + [self.eventRaiser raiseEvents:events]; + [self.eventRaiser raiseCallbacks:callbacks]; + } +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepoInfo.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepoInfo.h new file mode 100644 index 0000000..4b1e40d --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepoInfo.h @@ -0,0 +1,53 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +@interface FRepoInfo : NSObject + +/// The host that the database should connect to. +@property(nonatomic, readonly, copy) NSString *host; + +@property(nonatomic, readonly, copy) NSString *namespace; +@property(nonatomic, readwrite, copy) NSString *internalHost; +@property(nonatomic, readonly, assign) BOOL secure; + +/// Returns YES if the host is not a *.firebaseio.com host. +@property(nonatomic, readonly) BOOL isCustomHost; + +- (instancetype)initWithHost:(NSString *)host + isSecure:(BOOL)secure + withNamespace:(NSString *)namespace NS_DESIGNATED_INITIALIZER; + +- (instancetype)initWithInfo:(FRepoInfo *)info emulatedHost:(NSString *)host; + +- (NSString *)connectionURLWithLastSessionID:(NSString *_Nullable)lastSessionID; +- (NSString *)connectionURL; +- (void)clearInternalHostCache; +- (BOOL)isDemoHost; +- (BOOL)isCustomHost; + +- (id)copyWithZone:(NSZone *_Nullable)zone; +- (NSUInteger)hash; +- (BOOL)isEqual:(id)anObject; + +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepoInfo.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepoInfo.m new file mode 100644 index 0000000..82ca825 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepoInfo.m @@ -0,0 +1,153 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/FRepoInfo.h" +#import "FirebaseDatabase/Sources/Constants/FConstants.h" + +@interface FRepoInfo () + +@property(nonatomic, strong) NSString *domain; + +@end + +@implementation FRepoInfo + +@synthesize internalHost; + +- (instancetype)init { + [NSException + raise:@"FIRDatabaseInvalidInitializer" + format:@"Invalid initializer invoked. This is probably a bug in RTDB."]; + abort(); +} + +- (instancetype)initWithHost:(NSString *)aHost + isSecure:(BOOL)isSecure + withNamespace:(NSString *)aNamespace { + self = [super init]; + if (self) { + _host = [aHost copy]; + _domain = + [_host containsString:@"."] + ? [_host + substringFromIndex:[_host rangeOfString:@"."].location + + 1] + : _host; + _secure = isSecure; + _namespace = aNamespace; + + // Get cached internal host if it exists + NSString *internalHostKey = + [NSString stringWithFormat:@"firebase:host:%@", _host]; + NSString *cachedInternalHost = [[NSUserDefaults standardUserDefaults] + stringForKey:internalHostKey]; + if (cachedInternalHost != nil) { + internalHost = cachedInternalHost; + } else { + internalHost = [_host copy]; + } + } + return self; +} + +- (instancetype)initWithInfo:(FRepoInfo *)info emulatedHost:(NSString *)host { + self = [self initWithHost:host isSecure:NO withNamespace:info.namespace]; + return self; +} + +- (NSString *)description { + // The namespace is encoded in the hostname, so we can just return this. + return [NSString + stringWithFormat:@"http%@://%@", (_secure ? @"s" : @""), _host]; +} + +- (void)setInternalHost:(NSString *)newHost { + if (![internalHost isEqualToString:newHost]) { + internalHost = newHost; + + // Cache the internal host so we don't need to redirect later on + NSString *internalHostKey = + [NSString stringWithFormat:@"firebase:host:%@", self.host]; + NSUserDefaults *cache = [NSUserDefaults standardUserDefaults]; + [cache setObject:internalHost forKey:internalHostKey]; + [cache synchronize]; + } +} + +- (void)clearInternalHostCache { + self.internalHost = self.host; + + // Remove the cached entry + NSString *internalHostKey = + [NSString stringWithFormat:@"firebase:host:%@", self.host]; + NSUserDefaults *cache = [NSUserDefaults standardUserDefaults]; + [cache removeObjectForKey:internalHostKey]; + [cache synchronize]; +} + +- (BOOL)isDemoHost { + return [self.domain isEqualToString:@"firebaseio-demo.com"]; +} + +- (BOOL)isCustomHost { + return ![self.domain isEqualToString:@"firebaseio-demo.com"] && + ![self.domain isEqualToString:@"firebaseio.com"]; +} + +- (NSString *)connectionURL { + return [self connectionURLWithLastSessionID:nil]; +} + +- (NSString *)connectionURLWithLastSessionID:(NSString *)lastSessionID { + NSString *scheme; + if (self.secure) { + scheme = @"wss"; + } else { + scheme = @"ws"; + } + NSString *url = + [NSString stringWithFormat:@"%@://%@/.ws?%@=%@&ns=%@", scheme, + self.internalHost, kWireProtocolVersionParam, + kWebsocketProtocolVersion, self.namespace]; + + if (lastSessionID != nil) { + url = [NSString stringWithFormat:@"%@&ls=%@", url, lastSessionID]; + } + return url; +} + +- (id)copyWithZone:(NSZone *)zone { + return self; // Immutable +} + +- (NSUInteger)hash { + NSUInteger result = _host.hash; + result = 31 * result + (_secure ? 1 : 0); + result = 31 * result + _namespace.hash; + result = 31 * result + _host.hash; + return result; +} + +- (BOOL)isEqual:(id)anObject { + if (![anObject isKindOfClass:[FRepoInfo class]]) { + return NO; + } + FRepoInfo *other = (FRepoInfo *)anObject; + return _secure == other.secure && [_host isEqualToString:other.host] && + [_namespace isEqualToString:other.namespace]; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepoManager.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepoManager.h new file mode 100644 index 0000000..bebfd0b --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepoManager.h @@ -0,0 +1,34 @@ +/* + * 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 "FirebaseDatabase/Sources/Api/FIRDatabaseConfig.h" +#import "FirebaseDatabase/Sources/Core/FRepo.h" +#import "FirebaseDatabase/Sources/Core/FRepoInfo.h" +#import + +@interface FRepoManager : NSObject + ++ (FRepo *)getRepo:(FRepoInfo *)repoInfo config:(FIRDatabaseConfig *)config; ++ (FRepo *)createRepo:(FRepoInfo *)repoInfo + config:(FIRDatabaseConfig *)config + database:(FIRDatabase *)database; ++ (void)interruptAll; ++ (void)interrupt:(FIRDatabaseConfig *)config; ++ (void)resumeAll; ++ (void)resume:(FIRDatabaseConfig *)config; ++ (void)disposeRepos:(FIRDatabaseConfig *)config; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepoManager.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepoManager.m new file mode 100644 index 0000000..94d5488 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepoManager.m @@ -0,0 +1,148 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/FRepoManager.h" +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDatabase_Private.h" +#import "FirebaseDatabase/Sources/Core/FRepo.h" +#import "FirebaseDatabase/Sources/FIRDatabaseConfig_Private.h" +#import "FirebaseDatabase/Sources/Utilities/FAtomicNumber.h" + +@implementation FRepoManager + +typedef NSMutableDictionary *> + FRepoDictionary; + ++ (FRepoDictionary *)configs { + static dispatch_once_t pred = 0; + static FRepoDictionary *configs; + dispatch_once(&pred, ^{ + configs = [NSMutableDictionary dictionary]; + }); + return configs; +} + +/** + * Used for legacy unit tests. The public API should go through + * FirebaseDatabase which calls createRepo. + */ ++ (FRepo *)getRepo:(FRepoInfo *)repoInfo config:(FIRDatabaseConfig *)config { + [config freeze]; + FRepoDictionary *configs = [FRepoManager configs]; + @synchronized(configs) { + NSMutableDictionary *repos = + configs[config.sessionIdentifier]; + if (!repos || repos[repoInfo] == nil) { + // Calling this should create the repo. + [FIRDatabase createDatabaseForTests:repoInfo config:config]; + } + + return configs[config.sessionIdentifier][repoInfo]; + } +} + ++ (FRepo *)createRepo:(FRepoInfo *)repoInfo + config:(FIRDatabaseConfig *)config + database:(FIRDatabase *)database { + [config freeze]; + FRepoDictionary *configs = [FRepoManager configs]; + @synchronized(configs) { + NSMutableDictionary *repos = + configs[config.sessionIdentifier]; + if (!repos) { + repos = [NSMutableDictionary dictionary]; + configs[config.sessionIdentifier] = repos; + } + FRepo *repo = repos[repoInfo]; + if (repo == nil) { + repo = [[FRepo alloc] initWithRepoInfo:repoInfo + config:config + database:database]; + repos[repoInfo] = repo; + return repo; + } else { + [NSException + raise:@"RepoExists" + format:@"createRepo called for Repo that already exists."]; + return nil; + } + } +} + ++ (void)interrupt:(FIRDatabaseConfig *)config { + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + FRepoDictionary *configs = [FRepoManager configs]; + NSMutableDictionary *repos = + configs[config.sessionIdentifier]; + for (FRepo *repo in [repos allValues]) { + [repo interrupt]; + } + }); +} + ++ (void)interruptAll { + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + FRepoDictionary *configs = [FRepoManager configs]; + for (NSMutableDictionary *repos in + [configs allValues]) { + for (FRepo *repo in [repos allValues]) { + [repo interrupt]; + } + } + }); +} + ++ (void)resume:(FIRDatabaseConfig *)config { + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + FRepoDictionary *configs = [FRepoManager configs]; + NSMutableDictionary *repos = + configs[config.sessionIdentifier]; + for (FRepo *repo in [repos allValues]) { + [repo resume]; + } + }); +} + ++ (void)resumeAll { + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + FRepoDictionary *configs = [FRepoManager configs]; + for (NSMutableDictionary *repos in + [configs allValues]) { + for (FRepo *repo in [repos allValues]) { + [repo resume]; + } + } + }); +} + ++ (void)disposeRepos:(FIRDatabaseConfig *)config { + // Do this synchronously to make sure we release our references to LevelDB + // before returning, allowing LevelDB to close and release its exclusive + // locks. + dispatch_sync([FIRDatabaseQuery sharedQueue], ^{ + FFLog(@"I-RDB040001", @"Disposing all repos for Config with name %@", + config.sessionIdentifier); + NSMutableDictionary *configs = [FRepoManager configs]; + for (FRepo *repo in [configs[config.sessionIdentifier] allValues]) { + [repo dispose]; + } + [configs removeObjectForKey:config.sessionIdentifier]; + }); +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepo_Private.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepo_Private.h new file mode 100644 index 0000000..5d69d96 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FRepo_Private.h @@ -0,0 +1,42 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/FRepo.h" +#import "FirebaseDatabase/Sources/Core/FSparseSnapshotTree.h" + +@class FSyncTree; +@class FAtomicNumber; +@class FEventRaiser; +@class FSnapshotHolder; + +@interface FRepo () + +- (void)runOnDisconnectEvents; + +@property(nonatomic, strong) FRepoInfo *repoInfo; +@property(nonatomic, strong) FPersistentConnection *connection; +@property(nonatomic, strong) FSnapshotHolder *infoData; +@property(nonatomic, strong) FSparseSnapshotTree *onDisconnect; +@property(nonatomic, strong) FEventRaiser *eventRaiser; +@property(nonatomic, strong) FSyncTree *serverSyncTree; + +// For testing. +@property(nonatomic) long dataUpdateCount; +@property(nonatomic) long rangeMergeUpdateCount; + +- (NSInteger)nextWriteId; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FServerValues.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FServerValues.h new file mode 100644 index 0000000..aadd507 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FServerValues.h @@ -0,0 +1,40 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/FSparseSnapshotTree.h" +#import "FirebaseDatabase/Sources/Core/FSyncTree.h" +#import "FirebaseDatabase/Sources/FClock.h" +#import "FirebaseDatabase/Sources/Snapshot/FCompoundWrite.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" +#import + +@interface FServerValues : NSObject + ++ (NSDictionary *)generateServerValues:(id)clock; + ++ (FCompoundWrite *)resolveDeferredValueCompoundWrite:(FCompoundWrite *)write + withSyncTree:(FSyncTree *)tree + atPath:(FPath *)path + serverValues: + (NSDictionary *)serverValues; ++ (id)resolveDeferredValueSnapshot:(id)node + withSyncTree:(FSyncTree *)existing + atPath:(FPath *)path + serverValues:(NSDictionary *)serverValues; ++ (id)resolveDeferredValueSnapshot:(id)node + withExisting:(id)existing + serverValues:(NSDictionary *)serverValues; +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FServerValues.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FServerValues.m new file mode 100644 index 0000000..88aadd3 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FServerValues.m @@ -0,0 +1,269 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/FServerValues.h" +#import "FirebaseDatabase/Sources/Constants/FConstants.h" +#import "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FLeafNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h" + +const NSString *kTimestamp = @"timestamp"; +const NSString *kIncrement = @"increment"; + +BOOL canBeRepresentedAsLong(NSNumber *num) { + switch (num.objCType[0]) { + case 'f': // float; fallthrough + case 'd': // double + return NO; + case 'L': // unsigned long; fallthrough + case 'Q': // unsigned long long; fallthrough + // Only use ulong(long) if there isn't an overflow. + if (num.unsignedLongLongValue > LONG_MAX) { + return NO; + } + } + return YES; +} + +// Running through CompoundWrites for all update paths has been shown to +// be a 20% pessimization in microbenchmarks. This is because it slows +// down by O(N) of the write queue length. To eliminate the performance +// hit, we wrap around existing data of either snapshot or CompoundWrite +// (allowing us to share code) and read from the CompoundWrite only when/where +// we need to calculate an incremented value's prior state. +@protocol ValueProvider +- (id)getChild:(NSString *)pathSegment; +- (id)value; +@end + +@interface DeferredValueProvider : NSObject +- (instancetype)initWithSyncTree:(FSyncTree *)tree atPath:(FPath *)path; +- (id)getChild:(NSString *)pathSegment; +- (id)value; +@property FPath *path; +@property FSyncTree *tree; +@end + +@interface ExistingValueProvider : NSObject +- (instancetype)initWithSnapshot:(id)snapshot; +- (id)getChild:(NSString *)pathSegment; +- (id)value; +@property id snapshot; +@end + +@implementation DeferredValueProvider +- (instancetype)initWithSyncTree:(FSyncTree *)tree atPath:(FPath *)path { + self.tree = tree; + self.path = path; + return self; +} + +- (id)getChild:(NSString *)pathSegment { + FPath *child = [self.path childFromString:pathSegment]; + return [[DeferredValueProvider alloc] initWithSyncTree:self.tree + atPath:child]; +} + +- (id)value { + return [self.tree calcCompleteEventCacheAtPath:self.path + excludeWriteIds:@[]]; +} +@end + +@implementation ExistingValueProvider +- (instancetype)initWithSnapshot:(id)snapshot { + self.snapshot = snapshot; + return self; +} + +- (id)getChild:(NSString *)pathSegment { + return [[ExistingValueProvider alloc] + initWithSnapshot:[self.snapshot getImmediateChild:pathSegment]]; +} + +- (id)value { + return self.snapshot; +} +@end + +@interface FServerValues () ++ (id)resolveScalarServerOp:(NSString *)op + withServerValues:(NSDictionary *)serverValues; ++ (id)resolveComplexServerOp:(NSDictionary *)op + withValueProvider:(id)existing + serverValues:(NSDictionary *)serverValues; ++ (id)resolveDeferredValueSnapshot:(id)node + withValueProvider:(id)existing + serverValues:(NSDictionary *)serverValues; + +@end + +@implementation FServerValues + ++ (NSDictionary *)generateServerValues:(id)clock { + long long millis = (long long)([clock currentTime] * 1000); + return @{kTimestamp : [NSNumber numberWithLongLong:millis]}; +} + ++ (id)resolveDeferredValue:(id)val + withExisting:(id)existing + serverValues:(NSDictionary *)serverValues { + if (![val isKindOfClass:[NSDictionary class]]) { + return val; + } + NSDictionary *dict = val; + id op = dict[kServerValueSubKey]; + + if (op == nil) { + return val; + } else if ([op isKindOfClass:NSString.class]) { + return [FServerValues resolveScalarServerOp:op + withServerValues:serverValues]; + } else if ([op isKindOfClass:NSDictionary.class]) { + return [FServerValues resolveComplexServerOp:op + withValueProvider:existing + serverValues:serverValues]; + } + return val; +} + ++ (id)resolveScalarServerOp:(NSString *)op + withServerValues:(NSDictionary *)serverValues { + return serverValues[op]; +} + ++ (id)resolveComplexServerOp:(NSDictionary *)op + withValueProvider:(id)jitExisting + serverValues:(NSDictionary *)serverValues { + // Only increment is supported as of now + if (op[kIncrement] == nil) { + return nil; + } + + // Incrementing a non-number sets the value to the incremented amount + NSNumber *delta = op[kIncrement]; + id existing = jitExisting.value; + if (![existing isLeafNode]) { + return delta; + } + FLeafNode *existingLeaf = existing; + if (![existingLeaf.value isKindOfClass:NSNumber.class]) { + return delta; + } + + NSNumber *existingNum = existingLeaf.value; + BOOL incrLong = canBeRepresentedAsLong(delta); + BOOL baseLong = canBeRepresentedAsLong(existingNum); + + if (incrLong && baseLong) { + long x = delta.longValue; + long y = existingNum.longValue; + long r = x + y; + + // See "Hacker's Delight" 2-12: Overflow if both arguments have the + // opposite sign of the result + if (((x ^ r) & (y ^ r)) >= 0) { + return @(r); + } + } + return @(delta.doubleValue + existingNum.doubleValue); +} + ++ (FCompoundWrite *)resolveDeferredValueCompoundWrite:(FCompoundWrite *)write + withSyncTree:(FSyncTree *)tree + atPath:(FPath *)path + serverValues: + (NSDictionary *)serverValues { + __block FCompoundWrite *resolved = write; + [write enumerateWrites:^(FPath *subPath, id node, BOOL *stop) { + id existing = + [[DeferredValueProvider alloc] initWithSyncTree:tree + atPath:[path child:subPath]]; + id resolvedNode = + [FServerValues resolveDeferredValueSnapshot:node + withValueProvider:existing + serverValues:serverValues]; + // Node actually changed, use pointer inequality here + if (resolvedNode != node) { + resolved = [resolved addWrite:resolvedNode atPath:subPath]; + } + }]; + return resolved; +} + ++ (id)resolveDeferredValueSnapshot:(id)node + withSyncTree:(FSyncTree *)tree + atPath:(FPath *)path + serverValues:(NSDictionary *)serverValues { + id jitExisting = + [[DeferredValueProvider alloc] initWithSyncTree:tree atPath:path]; + return [FServerValues resolveDeferredValueSnapshot:node + withValueProvider:jitExisting + serverValues:serverValues]; +} + ++ (id)resolveDeferredValueSnapshot:(id)node + withExisting:(id)existing + serverValues:(NSDictionary *)serverValues { + id jitExisting = + [[ExistingValueProvider alloc] initWithSnapshot:existing]; + return [FServerValues resolveDeferredValueSnapshot:node + withValueProvider:jitExisting + serverValues:serverValues]; +} + ++ (id)resolveDeferredValueSnapshot:(id)node + withValueProvider:(id)existing + serverValues:(NSDictionary *)serverValues { + id priorityVal = + [FServerValues resolveDeferredValue:[[node getPriority] val] + withExisting:[existing getChild:@".priority"] + serverValues:serverValues]; + id priority = [FSnapshotUtilities nodeFrom:priorityVal]; + + if ([node isLeafNode]) { + id value = [self resolveDeferredValue:[node val] + withExisting:existing + serverValues:serverValues]; + if (![value isEqual:[node val]] || + ![priority isEqual:[node getPriority]]) { + return [[FLeafNode alloc] initWithValue:value + withPriority:priority]; + } else { + return node; + } + } else { + __block FChildrenNode *newNode = node; + if (![priority isEqual:[node getPriority]]) { + newNode = [newNode updatePriority:priority]; + } + + [node enumerateChildrenUsingBlock:^(NSString *childKey, + id childNode, BOOL *stop) { + id newChildNode = [FServerValues + resolveDeferredValueSnapshot:childNode + withValueProvider:[existing getChild:childKey] + serverValues:serverValues]; + if (![newChildNode isEqual:childNode]) { + newNode = [newNode updateImmediateChild:childKey + withNewChild:newChildNode]; + } + }]; + return newNode; + } +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSnapshotHolder.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSnapshotHolder.h new file mode 100644 index 0000000..34214ab --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSnapshotHolder.h @@ -0,0 +1,27 @@ +/* + * 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 "FirebaseDatabase/Sources/Snapshot/FNode.h" +#import + +@interface FSnapshotHolder : NSObject + +- (id)getNode:(FPath *)path; +- (void)updateSnapshot:(FPath *)path withNewSnapshot:(id)newSnapshotNode; + +@property(nonatomic, strong) id rootNode; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSnapshotHolder.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSnapshotHolder.m new file mode 100644 index 0000000..491ccae --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSnapshotHolder.m @@ -0,0 +1,46 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/FSnapshotHolder.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" + +@interface FSnapshotHolder () + +@end + +@implementation FSnapshotHolder + +@synthesize rootNode; + +- (id)init { + self = [super init]; + if (self) { + self.rootNode = [FEmptyNode emptyNode]; + } + return self; +} + +- (id)getNode:(FPath *)path { + return [self.rootNode getChild:path]; +} + +- (void)updateSnapshot:(FPath *)path + withNewSnapshot:(id)newSnapshotNode { + self.rootNode = [self.rootNode updateChild:path + withNewChild:newSnapshotNode]; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSparseSnapshotTree.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSparseSnapshotTree.h new file mode 100644 index 0000000..8ea9293 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSparseSnapshotTree.h @@ -0,0 +1,34 @@ +/* + * 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 "FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" +#import + +@class FSparseSnapshotTree; + +typedef void (^fbt_void_nsstring_sstree)(NSString *, FSparseSnapshotTree *); + +@interface FSparseSnapshotTree : NSObject + +- (id)findPath:(FPath *)path; +- (void)rememberData:(id)data onPath:(FPath *)path; +- (BOOL)forgetPath:(FPath *)path; +- (void)forEachTreeAtPath:(FPath *)prefixPath do:(fbt_void_path_node)func; +- (void)forEachChild:(fbt_void_nsstring_sstree)func; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSparseSnapshotTree.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSparseSnapshotTree.m new file mode 100644 index 0000000..1b16d51 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSparseSnapshotTree.m @@ -0,0 +1,144 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/FSparseSnapshotTree.h" +#import "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h" + +@interface FSparseSnapshotTree () { + id value; + NSMutableDictionary *children; +} + +@end + +@implementation FSparseSnapshotTree + +- (id)init { + self = [super init]; + if (self) { + value = nil; + children = nil; + } + return self; +} + +- (id)findPath:(FPath *)path { + if (value != nil) { + return [value getChild:path]; + } else if (![path isEmpty] && children != nil) { + NSString *childKey = [path getFront]; + path = [path popFront]; + FSparseSnapshotTree *childTree = children[childKey]; + if (childTree != nil) { + return [childTree findPath:path]; + } else { + return nil; + } + } else { + return nil; + } +} + +- (void)rememberData:(id)data onPath:(FPath *)path { + if ([path isEmpty]) { + value = data; + children = nil; + } else if (value != nil) { + value = [value updateChild:path withNewChild:data]; + } else { + if (children == nil) { + children = [[NSMutableDictionary alloc] init]; + } + + NSString *childKey = [path getFront]; + if (children[childKey] == nil) { + children[childKey] = [[FSparseSnapshotTree alloc] init]; + } + + FSparseSnapshotTree *child = children[childKey]; + path = [path popFront]; + [child rememberData:data onPath:path]; + } +} + +- (BOOL)forgetPath:(FPath *)path { + if ([path isEmpty]) { + value = nil; + children = nil; + return YES; + } else { + if (value != nil) { + if ([value isLeafNode]) { + // non-empty path at leaf. the path leads to nowhere + return NO; + } else { + id tmp = value; + value = nil; + + [tmp enumerateChildrenUsingBlock:^(NSString *key, + id node, BOOL *stop) { + [self rememberData:node onPath:[[FPath alloc] initWith:key]]; + }]; + + // we've cleared out the value and set children. Call ourself + // again to hit the next case + return [self forgetPath:path]; + } + } else if (children != nil) { + NSString *childKey = [path getFront]; + path = [path popFront]; + + if (children[childKey] != nil) { + FSparseSnapshotTree *child = children[childKey]; + BOOL safeToRemove = [child forgetPath:path]; + if (safeToRemove) { + [children removeObjectForKey:childKey]; + } + } + + if ([children count] == 0) { + children = nil; + return YES; + } else { + return NO; + } + } else { + return YES; + } + } +} + +- (void)forEachTreeAtPath:(FPath *)prefixPath do:(fbt_void_path_node)func { + if (value != nil) { + func(prefixPath, value); + } else { + [self forEachChild:^(NSString *key, FSparseSnapshotTree *tree) { + FPath *path = [prefixPath childFromString:key]; + [tree forEachTreeAtPath:path do:func]; + }]; + } +} + +- (void)forEachChild:(fbt_void_nsstring_sstree)func { + if (children != nil) { + for (NSString *key in children) { + FSparseSnapshotTree *tree = [children objectForKey:key]; + func(key, tree); + } + } +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSyncPoint.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSyncPoint.h new file mode 100644 index 0000000..f8f19c1 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSyncPoint.h @@ -0,0 +1,74 @@ +/* + * 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 + +@protocol FOperation; +@class FWriteTreeRef; +@protocol FNode; +@protocol FEventRegistration; +@class FQuerySpec; +@class FChildrenNode; +@class FTupleRemovedQueriesEvents; +@class FView; +@class FPath; +@class FCacheNode; +@class FPersistenceManager; + +@interface FSyncPoint : NSObject + +- (id)initWithPersistenceManager:(FPersistenceManager *)persistence; + +- (BOOL)isEmpty; + +/** + * Returns array of FEvent + */ +- (NSArray *)applyOperation:(id)operation + writesCache:(FWriteTreeRef *)writesCache + serverCache:(id)optCompleteServerCache; + +- (FView *)getView:(FQuerySpec *)query + writesCache:(FWriteTreeRef *)writesCache + serverCache:(FCacheNode *)serverCache; + +/** + * Returns array of FEvent + */ +- (NSArray *)addEventRegistration:(id)eventRegistration + forNonExistingViewForQuery:(FQuerySpec *)query + writesCache:(FWriteTreeRef *)writesCache + serverCache:(FCacheNode *)serverCache; + +- (NSArray *)addEventRegistration:(id)eventRegistration + forExistingViewForQuery:(FQuerySpec *)query; + +- (FTupleRemovedQueriesEvents *)removeEventRegistration: + (id)eventRegistration + forQuery:(FQuerySpec *)query + cancelError:(NSError *)cancelError; +/** + * Returns array of FViews + */ +- (NSArray *)queryViews; +- (id)completeServerCacheAtPath:(FPath *)path; +- (id)completeEventCacheAtPath:(FPath *)path; +- (FView *)viewForQuery:(FQuerySpec *)query; +- (BOOL)viewExistsForQuery:(FQuerySpec *)query; +- (BOOL)hasCompleteView; +- (FView *)completeView; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSyncPoint.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSyncPoint.m new file mode 100644 index 0000000..31d32a6 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSyncPoint.m @@ -0,0 +1,325 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/FSyncPoint.h" +#import "FirebaseDatabase/Sources/Core/FQueryParams.h" +#import "FirebaseDatabase/Sources/Core/FQuerySpec.h" +#import "FirebaseDatabase/Sources/Core/FWriteTreeRef.h" +#import "FirebaseDatabase/Sources/Core/Operation/FOperation.h" +#import "FirebaseDatabase/Sources/Core/Operation/FOperationSource.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Core/View/FCacheNode.h" +#import "FirebaseDatabase/Sources/Core/View/FDataEvent.h" +#import "FirebaseDatabase/Sources/Core/View/FEventRegistration.h" +#import "FirebaseDatabase/Sources/Core/View/FView.h" +#import "FirebaseDatabase/Sources/Core/View/FViewCache.h" +#import "FirebaseDatabase/Sources/Persistence/FPersistenceManager.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseQuery.h" +#import "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" +#import "FirebaseDatabase/Sources/Utilities/Tuples/FTupleRemovedQueriesEvents.h" + +/** + * SyncPoint represents a single location in a SyncTree with 1 or more event + * registrations, meaning we need to maintain 1 or more Views at this location + * to cache server data and raise appropriate events for server changes and user + * writes (set, transaction, update). + * + * It's responsible for: + * - Maintaining the set of 1 or more views necessary at this location (a + * SyncPoint with 0 views should be removed). + * - Proxying user / server operations to the views as appropriate (i.e. + * applyServerOverwrite, applyUserOverwrite, etc.) + */ +@interface FSyncPoint () +/** + * The Views being tracked at this location in the tree, stored as a map where + * the key is a queryParams and the value is the View for that query. + * + * NOTE: This list will be quite small (usually 1, but perhaps 2 or 3; any more + * is an odd use case). + * + * Maps NSString -> FView + */ +@property(nonatomic, strong) NSMutableDictionary *views; + +@property(nonatomic, strong) FPersistenceManager *persistenceManager; +@end + +@implementation FSyncPoint + +- (id)initWithPersistenceManager:(FPersistenceManager *)persistence { + self = [super init]; + if (self) { + self.persistenceManager = persistence; + self.views = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (BOOL)isEmpty { + return [self.views count] == 0; +} + +- (NSArray *)applyOperation:(id)operation + toView:(FView *)view + writesCache:(FWriteTreeRef *)writesCache + serverCache:(id)optCompleteServerCache { + FViewOperationResult *result = [view applyOperation:operation + writesCache:writesCache + serverCache:optCompleteServerCache]; + if (!view.query.loadsAllData) { + NSMutableSet *removed = [NSMutableSet set]; + NSMutableSet *added = [NSMutableSet set]; + [result.changes enumerateObjectsUsingBlock:^( + FChange *change, NSUInteger idx, BOOL *stop) { + if (change.type == FIRDataEventTypeChildAdded) { + [added addObject:change.childKey]; + } else if (change.type == FIRDataEventTypeChildRemoved) { + [removed addObject:change.childKey]; + } + }]; + if ([removed count] > 0 || [added count] > 0) { + [self.persistenceManager + updateTrackedQueryKeysWithAddedKeys:added + removedKeys:removed + forQuery:view.query]; + } + } + return result.events; +} + +- (NSArray *)applyOperation:(id)operation + writesCache:(FWriteTreeRef *)writesCache + serverCache:(id)optCompleteServerCache { + FQueryParams *queryParams = operation.source.queryParams; + if (queryParams != nil) { + FView *view = [self.views objectForKey:queryParams]; + NSAssert(view != nil, @"SyncTree gave us an op for an invalid query."); + return [self applyOperation:operation + toView:view + writesCache:writesCache + serverCache:optCompleteServerCache]; + } else { + NSMutableArray *events = [[NSMutableArray alloc] init]; + [self.views enumerateKeysAndObjectsUsingBlock:^( + FQueryParams *key, FView *view, BOOL *stop) { + NSArray *eventsForView = [self applyOperation:operation + toView:view + writesCache:writesCache + serverCache:optCompleteServerCache]; + [events addObjectsFromArray:eventsForView]; + }]; + return events; + } +} + +- (FView *)getView:(FQuerySpec *)query + writesCache:(FWriteTreeRef *)writesCache + serverCache:(FCacheNode *)serverCache { + FView *view = self.views[query.params]; + if (view != nil) { + return view; + } + id eventCache = [writesCache + calculateCompleteEventCacheWithCompleteServerCache: + serverCache.isFullyInitialized ? serverCache.node : nil]; + BOOL eventCacheComplete; + if (eventCache != nil) { + eventCacheComplete = YES; + } else { + eventCache = [writesCache + calculateCompleteEventChildrenWithCompleteServerChildren: + serverCache.node != nil ? serverCache.node + : [FEmptyNode emptyNode]]; + eventCacheComplete = NO; + } + + FIndexedNode *indexed = [FIndexedNode indexedNodeWithNode:eventCache + index:query.index]; + FCacheNode *eventCacheNode = + [[FCacheNode alloc] initWithIndexedNode:indexed + isFullyInitialized:eventCacheComplete + isFiltered:NO]; + FViewCache *viewCache = + [[FViewCache alloc] initWithEventCache:eventCacheNode + serverCache:serverCache]; + return [[FView alloc] initWithQuery:query initialViewCache:viewCache]; +} + +/** + * Add an event callback for the specified query + * Returns an array of events to raise. + */ +- (NSArray *)addEventRegistration:(id)eventRegistration + forNonExistingViewForQuery:(FQuerySpec *)query + writesCache:(FWriteTreeRef *)writesCache + serverCache:(FCacheNode *)serverCache { + NSAssert(self.views[query.params] == nil, @"Found view for query: %@", + query.params); + // TODO: make writesCache take flag for complete server node + FView *view = [self getView:query + writesCache:writesCache + serverCache:serverCache]; + + // If this is a non-default query we need to tell persistence our current + // view of the data + if (!query.loadsAllData) { + NSMutableSet *allKeys = [NSMutableSet set]; + [view.eventCache enumerateChildrenUsingBlock:^( + NSString *key, id node, BOOL *stop) { + [allKeys addObject:key]; + }]; + [self.persistenceManager setTrackedQueryKeys:allKeys forQuery:query]; + } + self.views[query.params] = view; + return [self addEventRegistration:eventRegistration + forExistingViewForQuery:query]; +} + +- (NSArray *)addEventRegistration:(id)eventRegistration + forExistingViewForQuery:(FQuerySpec *)query { + FView *view = self.views[query.params]; + NSAssert(view != nil, @"No view for query: %@", query); + [view addEventRegistration:eventRegistration]; + return [view initialEvents:eventRegistration]; +} + +/** + * Remove event callback(s). Return cancelEvents if a cancelError is specified. + * + * If query is the default query, we'll check all views for the specified + * eventRegistration. If eventRegistration is nil, we'll remove all callbacks + * for the specified view(s). + * + * @return FTupleRemovedQueriesEvents removed queries and any cancel events + */ +- (FTupleRemovedQueriesEvents *)removeEventRegistration: + (id)eventRegistration + forQuery:(FQuerySpec *)query + cancelError:(NSError *)cancelError { + NSMutableArray *removedQueries = [[NSMutableArray alloc] init]; + __block NSMutableArray *cancelEvents = [[NSMutableArray alloc] init]; + BOOL hadCompleteView = [self hasCompleteView]; + if ([query isDefault]) { + // When you do [ref removeObserverWithHandle:], we search all views for + // the registration to remove. + [self.views enumerateKeysAndObjectsUsingBlock:^( + FQueryParams *viewQueryParams, FView *view, + BOOL *stop) { + [cancelEvents + addObjectsFromArray:[view + removeEventRegistration:eventRegistration + cancelError:cancelError]]; + if ([view isEmpty]) { + [self.views removeObjectForKey:viewQueryParams]; + + // We'll deal with complete views later + if (![view.query loadsAllData]) { + [removedQueries addObject:view.query]; + } + } + }]; + } else { + // remove the callback from the specific view + FView *view = [self.views objectForKey:query.params]; + if (view != nil) { + [cancelEvents addObjectsFromArray: + [view removeEventRegistration:eventRegistration + cancelError:cancelError]]; + + if ([view isEmpty]) { + [self.views removeObjectForKey:query.params]; + + // We'll deal with complete views later + if (![view.query loadsAllData]) { + [removedQueries addObject:view.query]; + } + } + } + } + + if (hadCompleteView && ![self hasCompleteView]) { + // We removed our last complete view + [removedQueries addObject:[FQuerySpec defaultQueryAtPath:query.path]]; + } + + return [[FTupleRemovedQueriesEvents alloc] + initWithRemovedQueries:removedQueries + cancelEvents:cancelEvents]; +} + +- (NSArray *)queryViews { + __block NSMutableArray *filteredViews = [[NSMutableArray alloc] init]; + + [self.views enumerateKeysAndObjectsUsingBlock:^(FQueryParams *key, + FView *view, BOOL *stop) { + if (![view.query loadsAllData]) { + [filteredViews addObject:view]; + } + }]; + + return filteredViews; +} + +- (id)completeServerCacheAtPath:(FPath *)path { + __block id serverCache = nil; + [self.views enumerateKeysAndObjectsUsingBlock:^(FQueryParams *key, + FView *view, BOOL *stop) { + serverCache = [view completeServerCacheFor:path]; + *stop = (serverCache != nil); + }]; + return serverCache; +} + +- (id)completeEventCacheAtPath:(FPath *)path { + __block id eventCache = nil; + [self.views enumerateKeysAndObjectsUsingBlock:^(FQueryParams *key, + FView *view, BOOL *stop) { + eventCache = [view completeEventCacheFor:path]; + *stop = (eventCache != nil); + }]; + return eventCache; +} + +- (FView *)viewForQuery:(FQuerySpec *)query { + return [self.views objectForKey:query.params]; +} + +- (BOOL)viewExistsForQuery:(FQuerySpec *)query { + return [self viewForQuery:query] != nil; +} + +- (BOOL)hasCompleteView { + return [self completeView] != nil; +} + +- (FView *)completeView { + __block FView *completeView = nil; + + [self.views enumerateKeysAndObjectsUsingBlock:^(FQueryParams *key, + FView *view, BOOL *stop) { + if ([view.query loadsAllData]) { + completeView = view; + *stop = YES; + } + }]; + + return completeView; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSyncTree.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSyncTree.h new file mode 100644 index 0000000..62ccf4d --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSyncTree.h @@ -0,0 +1,85 @@ +/* + * 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 + +@class FIndexedNode; +@class FListenProvider; +@protocol FNode; +@class FPath; +@protocol FEventRegistration; +@protocol FPersistedServerCache; +@class FQuerySpec; +@class FCompoundWrite; +@class FPersistenceManager; +@class FCompoundHash; +@protocol FClock; + +@protocol FSyncTreeHash + +- (NSString *)simpleHash; +- (FCompoundHash *)compoundHash; +- (BOOL)includeCompoundHash; + +@end + +@interface FSyncTree : NSObject + +- (id)initWithListenProvider:(FListenProvider *)provider; +- (id)initWithPersistenceManager:(FPersistenceManager *)persistenceManager + listenProvider:(FListenProvider *)provider; + +// These methods all return NSArray of FEvent +- (NSArray *)applyUserOverwriteAtPath:(FPath *)path + newData:(id)newData + writeId:(NSInteger)writeId + isVisible:(BOOL)visible; +- (NSArray *)applyUserMergeAtPath:(FPath *)path + changedChildren:(FCompoundWrite *)changedChildren + writeId:(NSInteger)writeId; +- (NSArray *)ackUserWriteWithWriteId:(NSInteger)writeId + revert:(BOOL)revert + persist:(BOOL)persist + clock:(id)clock; +- (NSArray *)applyServerOverwriteAtPath:(FPath *)path + newData:(id)newData; +- (NSArray *)applyServerMergeAtPath:(FPath *)path + changedChildren:(FCompoundWrite *)changedChildren; +- (NSArray *)applyServerRangeMergeAtPath:(FPath *)path + updates:(NSArray *)ranges; +- (NSArray *)applyTaggedQueryOverwriteAtPath:(FPath *)path + newData:(id)newData + tagId:(NSNumber *)tagId; +- (NSArray *)applyTaggedQueryMergeAtPath:(FPath *)path + changedChildren:(FCompoundWrite *)changedChildren + tagId:(NSNumber *)tagId; +- (NSArray *)applyTaggedServerRangeMergeAtPath:(FPath *)path + updates:(NSArray *)ranges + tagId:(NSNumber *)tagId; +- (NSArray *)addEventRegistration:(id)eventRegistration + forQuery:(FQuerySpec *)query; +- (NSArray *)removeEventRegistration:(id)eventRegistration + forQuery:(FQuerySpec *)query + cancelError:(NSError *)cancelError; +- (void)keepQuery:(FQuerySpec *)query synced:(BOOL)keepSynced; +- (NSArray *)removeAllWrites; + +- (FIndexedNode *)persistenceServerCache:(FQuerySpec *)querySpec; +- (id)getServerValue:(FQuerySpec *)query; +- (id)calcCompleteEventCacheAtPath:(FPath *)path + excludeWriteIds:(NSArray *)writeIdsToExclude; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSyncTree.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSyncTree.m new file mode 100644 index 0000000..07cf036 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FSyncTree.m @@ -0,0 +1,1093 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/FSyncTree.h" +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" +#import "FirebaseDatabase/Sources/Core/FCompoundHash.h" +#import "FirebaseDatabase/Sources/Core/FListenProvider.h" +#import "FirebaseDatabase/Sources/Core/FQueryParams.h" +#import "FirebaseDatabase/Sources/Core/FQuerySpec.h" +#import "FirebaseDatabase/Sources/Core/FRangeMerge.h" +#import "FirebaseDatabase/Sources/Core/FServerValues.h" +#import "FirebaseDatabase/Sources/Core/FSnapshotHolder.h" +#import "FirebaseDatabase/Sources/Core/FSyncPoint.h" +#import "FirebaseDatabase/Sources/Core/FWriteRecord.h" +#import "FirebaseDatabase/Sources/Core/FWriteTree.h" +#import "FirebaseDatabase/Sources/Core/FWriteTreeRef.h" +#import "FirebaseDatabase/Sources/Core/Operation/FAckUserWrite.h" +#import "FirebaseDatabase/Sources/Core/Operation/FMerge.h" +#import "FirebaseDatabase/Sources/Core/Operation/FOperation.h" +#import "FirebaseDatabase/Sources/Core/Operation/FOperationSource.h" +#import "FirebaseDatabase/Sources/Core/Operation/FOverwrite.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FImmutableTree.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Core/View/FCacheNode.h" +#import "FirebaseDatabase/Sources/Core/View/FEventRaiser.h" +#import "FirebaseDatabase/Sources/Core/View/FEventRegistration.h" +#import "FirebaseDatabase/Sources/Core/View/FKeepSyncedEventRegistration.h" +#import "FirebaseDatabase/Sources/Core/View/FView.h" +#import "FirebaseDatabase/Sources/FListenComplete.h" +#import "FirebaseDatabase/Sources/Persistence/FPersistenceManager.h" +#import "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FCompoundWrite.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FAtomicNumber.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/Tuples/FTupleRemovedQueriesEvents.h" + +// Size after which we start including the compound hash +static const NSUInteger kFSizeThresholdForCompoundHash = 1024; + +@interface FListenContainer : NSObject + +@property(nonatomic, strong) FView *view; +@property(nonatomic, copy) fbt_nsarray_nsstring onComplete; + +@end + +@implementation FListenContainer + +- (instancetype)initWithView:(FView *)view + onComplete:(fbt_nsarray_nsstring)onComplete { + self = [super init]; + if (self != nil) { + self->_view = view; + self->_onComplete = onComplete; + } + return self; +} + +- (id)serverCache { + return self.view.serverCache; +} + +- (FCompoundHash *)compoundHash { + return [FCompoundHash fromNode:[self serverCache]]; +} + +- (NSString *)simpleHash { + return [[self serverCache] dataHash]; +} + +- (BOOL)includeCompoundHash { + return [FSnapshotUtilities estimateSerializedNodeSize:[self serverCache]] > + kFSizeThresholdForCompoundHash; +} + +@end + +@interface FSyncTree () + +/** + * Tree of SyncPoints. There's a SyncPoint at any location that has 1 or more + * views. + */ +@property(nonatomic, strong) FImmutableTree *syncPointTree; + +/** + * A tree of all pending user writes (user-initiated set, transactions, updates, + * etc) + */ +@property(nonatomic, strong) FWriteTree *pendingWriteTree; + +/** + * Maps tagId -> FTuplePathQueryParams + */ +@property(nonatomic, strong) NSMutableDictionary *tagToQueryMap; +@property(nonatomic, strong) NSMutableDictionary *queryToTagMap; +@property(nonatomic, strong) FListenProvider *listenProvider; +@property(nonatomic, strong) FPersistenceManager *persistenceManager; +@property(nonatomic, strong) FAtomicNumber *queryTagCounter; +@property(nonatomic, strong) NSMutableSet *keepSyncedQueries; + +@end + +/** + * SyncTree is the central class for managing event callback registration, data + * caching, views (query processing), and event generation. There are typically + * two SyncTree instances for each Repo, one for the normal Firebase data, and + * one for the .info data. + * + * It has a number of responsibilities, including: + * - Tracking all user event callbacks (registered via addEventRegistration: + * and removeEventRegistration:). + * - Applying and caching data changes for user setValue:, + * runTransactionBlock:, and updateChildValues: calls + * (applyUserOverwriteAtPath:, applyUserMergeAtPath:). + * - Applying and caching data changes for server data changes + * (applyServerOverwriteAtPath:, applyServerMergeAtPath:). + * - Generating user-facing events for server and user changes (all of the + * apply* methods return the set of events that need to be raised as a result). + * - Maintaining the appropriate set of server listens to ensure we are always + * subscribed to the correct set of paths and queries to satisfy the current set + * of user event callbacks (listens are started/stopped using the provided + * listenProvider). + * + * NOTE: Although SyncTree tracks event callbacks and calculates events to + * raise, the actual events are returned to the caller rather than raised + * synchronously. + */ +@implementation FSyncTree + +- (id)initWithListenProvider:(FListenProvider *)provider { + return [self initWithPersistenceManager:nil listenProvider:provider]; +} + +- (id)initWithPersistenceManager:(FPersistenceManager *)persistenceManager + listenProvider:(FListenProvider *)provider { + self = [super init]; + if (self) { + self.syncPointTree = [FImmutableTree empty]; + self.pendingWriteTree = [[FWriteTree alloc] init]; + self.tagToQueryMap = [[NSMutableDictionary alloc] init]; + self.queryToTagMap = [[NSMutableDictionary alloc] init]; + self.listenProvider = provider; + self.persistenceManager = persistenceManager; + self.queryTagCounter = [[FAtomicNumber alloc] init]; + self.keepSyncedQueries = [NSMutableSet set]; + } + return self; +} + +#pragma mark - +#pragma mark Apply Operations + +/** + * Apply data changes for a user-generated setValue: runTransactionBlock: + * updateChildValues:, etc. + * @return NSArray of FEvent to raise. + */ +- (NSArray *)applyUserOverwriteAtPath:(FPath *)path + newData:(id)newData + writeId:(NSInteger)writeId + isVisible:(BOOL)visible { + // Record pending write + [self.pendingWriteTree addOverwriteAtPath:path + newData:newData + writeId:writeId + isVisible:visible]; + if (!visible) { + return @[]; + } else { + FOverwrite *operation = + [[FOverwrite alloc] initWithSource:[FOperationSource userInstance] + path:path + snap:newData]; + return [self applyOperationToSyncPoints:operation]; + } +} + +/** + * Apply the data from a user-generated updateChildValues: call + * @return NSArray of FEvent to raise. + */ +- (NSArray *)applyUserMergeAtPath:(FPath *)path + changedChildren:(FCompoundWrite *)changedChildren + writeId:(NSInteger)writeId { + // Record pending merge + [self.pendingWriteTree addMergeAtPath:path + changedChildren:changedChildren + writeId:writeId]; + + FMerge *operation = + [[FMerge alloc] initWithSource:[FOperationSource userInstance] + path:path + children:changedChildren]; + return [self applyOperationToSyncPoints:operation]; +} + +/** + * Acknowledge a pending user write that was previously registered with + * applyUserOverwriteAtPath: or applyUserMergeAtPath: + * TODO[offline]: Taking a serverClock here is awkward, but server values are + * awkward. :-( + * @return NSArray of FEvent to raise. + */ +- (NSArray *)ackUserWriteWithWriteId:(NSInteger)writeId + revert:(BOOL)revert + persist:(BOOL)persist + clock:(id)clock { + FWriteRecord *write = [self.pendingWriteTree writeForId:writeId]; + BOOL needToReevaluate = [self.pendingWriteTree removeWriteId:writeId]; + if (write.visible) { + if (persist) { + [self.persistenceManager removeUserWrite:writeId]; + } + if (!revert) { + NSDictionary *serverValues = + [FServerValues generateServerValues:clock]; + if ([write isOverwrite]) { + id resolvedNode = + [FServerValues resolveDeferredValueSnapshot:write.overwrite + withSyncTree:self + atPath:write.path + serverValues:serverValues]; + [self.persistenceManager applyUserWrite:resolvedNode + toServerCacheAtPath:write.path]; + } else { + FCompoundWrite *resolvedMerge = [FServerValues + resolveDeferredValueCompoundWrite:write.merge + withSyncTree:self + atPath:write.path + serverValues:serverValues]; + [self.persistenceManager applyUserMerge:resolvedMerge + toServerCacheAtPath:write.path]; + } + } + } + if (!needToReevaluate) { + return @[]; + } else { + __block FImmutableTree *affectedTree = [FImmutableTree empty]; + if (write.isOverwrite) { + affectedTree = [affectedTree setValue:@YES atPath:[FPath empty]]; + } else { + [write.merge + enumerateWrites:^(FPath *path, id node, BOOL *stop) { + affectedTree = [affectedTree setValue:@YES atPath:path]; + }]; + } + FAckUserWrite *operation = + [[FAckUserWrite alloc] initWithPath:write.path + affectedTree:affectedTree + revert:revert]; + return [self applyOperationToSyncPoints:operation]; + } +} + +/** + * Apply new server data for the specified path + * @return NSArray of FEvent to raise. + */ +- (NSArray *)applyServerOverwriteAtPath:(FPath *)path + newData:(id)newData { + [self.persistenceManager + updateServerCacheWithNode:newData + forQuery:[FQuerySpec defaultQueryAtPath:path]]; + FOverwrite *operation = + [[FOverwrite alloc] initWithSource:[FOperationSource serverInstance] + path:path + snap:newData]; + return [self applyOperationToSyncPoints:operation]; +} + +/** + * Applied new server data to be merged in at the specified path + * @return NSArray of FEvent to raise. + */ +- (NSArray *)applyServerMergeAtPath:(FPath *)path + changedChildren:(FCompoundWrite *)changedChildren { + [self.persistenceManager updateServerCacheWithMerge:changedChildren + atPath:path]; + FMerge *operation = + [[FMerge alloc] initWithSource:[FOperationSource serverInstance] + path:path + children:changedChildren]; + return [self applyOperationToSyncPoints:operation]; +} + +- (NSArray *)applyServerRangeMergeAtPath:(FPath *)path + updates:(NSArray *)ranges { + FSyncPoint *syncPoint = [self.syncPointTree valueAtPath:path]; + if (syncPoint == nil) { + // Removed view, so it's safe to just ignore this update + return @[]; + } else { + // This could be for any "complete" (unfiltered) view, and if there is + // more than one complete view, they should each have the same cache so + // it doesn't matter which one we use. + FView *view = [syncPoint completeView]; + if (view != nil) { + id serverNode = [view serverCache]; + for (FRangeMerge *merge in ranges) { + serverNode = [merge applyToNode:serverNode]; + } + return [self applyServerOverwriteAtPath:path newData:serverNode]; + } else { + // There doesn't exist a view for this update, so it was removed and + // it's safe to just ignore this range merge + return @[]; + } + } +} + +/** + * Apply a listen complete to a path + * @return NSArray of FEvent to raise. + */ +- (NSArray *)applyListenCompleteAtPath:(FPath *)path { + [self.persistenceManager + setQueryComplete:[FQuerySpec defaultQueryAtPath:path]]; + id operation = [[FListenComplete alloc] + initWithSource:[FOperationSource serverInstance] + path:path]; + return [self applyOperationToSyncPoints:operation]; +} + +/** + * Apply a listen complete to a path + * @return NSArray of FEvent to raise. + */ +- (NSArray *)applyTaggedListenCompleteAtPath:(FPath *)path + tagId:(NSNumber *)tagId { + FQuerySpec *query = [self queryForTag:tagId]; + if (query != nil) { + [self.persistenceManager setQueryComplete:query]; + FPath *relativePath = [FPath relativePathFrom:query.path to:path]; + id op = [[FListenComplete alloc] + initWithSource:[FOperationSource forServerTaggedQuery:query.params] + path:relativePath]; + return [self applyTaggedOperation:op atPath:query.path]; + } else { + // We've already removed the query. No big deal, ignore the update. + return @[]; + } +} + +/** + * Internal helper method to apply tagged operation + */ +- (NSArray *)applyTaggedOperation:(id)operation + atPath:(FPath *)path { + FSyncPoint *syncPoint = [self.syncPointTree valueAtPath:path]; + NSAssert(syncPoint != nil, + @"Missing sync point for query tag that we're tracking."); + FWriteTreeRef *writesCache = + [self.pendingWriteTree childWritesForPath:path]; + return [syncPoint applyOperation:operation + writesCache:writesCache + serverCache:nil]; +} + +/** + * Apply new server data for the specified tagged query + * @return NSArray of FEvent to raise. + */ +- (NSArray *)applyTaggedQueryOverwriteAtPath:(FPath *)path + newData:(id)newData + tagId:(NSNumber *)tagId { + FQuerySpec *query = [self queryForTag:tagId]; + if (query != nil) { + FPath *relativePath = [FPath relativePathFrom:query.path to:path]; + FQuerySpec *queryToOverwrite = + relativePath.isEmpty ? query : [FQuerySpec defaultQueryAtPath:path]; + [self.persistenceManager updateServerCacheWithNode:newData + forQuery:queryToOverwrite]; + FOverwrite *operation = [[FOverwrite alloc] + initWithSource:[FOperationSource forServerTaggedQuery:query.params] + path:relativePath + snap:newData]; + return [self applyTaggedOperation:operation atPath:query.path]; + } else { + // Query must have been removed already + return @[]; + } +} + +/** + * Apply server data to be merged in for the specified tagged query + * @return NSArray of FEvent to raise. + */ +- (NSArray *)applyTaggedQueryMergeAtPath:(FPath *)path + changedChildren:(FCompoundWrite *)changedChildren + tagId:(NSNumber *)tagId { + FQuerySpec *query = [self queryForTag:tagId]; + if (query != nil) { + FPath *relativePath = [FPath relativePathFrom:query.path to:path]; + [self.persistenceManager updateServerCacheWithMerge:changedChildren + atPath:path]; + FMerge *operation = [[FMerge alloc] + initWithSource:[FOperationSource forServerTaggedQuery:query.params] + path:relativePath + children:changedChildren]; + return [self applyTaggedOperation:operation atPath:query.path]; + } else { + // We've already removed the query. No big deal, ignore the update. + return @[]; + } +} + +- (NSArray *)applyTaggedServerRangeMergeAtPath:(FPath *)path + updates:(NSArray *)ranges + tagId:(NSNumber *)tagId { + FQuerySpec *query = [self queryForTag:tagId]; + if (query != nil) { + NSAssert([path isEqual:query.path], + @"Tagged update path and query path must match"); + FSyncPoint *syncPoint = [self.syncPointTree valueAtPath:path]; + NSAssert(syncPoint != nil, + @"Missing sync point for query tag that we're tracking."); + FView *view = [syncPoint viewForQuery:query]; + NSAssert(view != nil, + @"Missing view for query tag that we're tracking"); + id serverNode = [view serverCache]; + for (FRangeMerge *merge in ranges) { + serverNode = [merge applyToNode:serverNode]; + } + return [self applyTaggedQueryOverwriteAtPath:path + newData:serverNode + tagId:tagId]; + } else { + // We've already removed the query. No big deal, ignore the update. + return @[]; + } +} + +/** + * Add an event callback for the specified query + * @return NSArray of FEvent to raise. + */ +- (NSArray *)addEventRegistration:(id)eventRegistration + forQuery:(FQuerySpec *)query { + FPath *path = query.path; + + __block BOOL foundAncestorDefaultView = NO; + [self.syncPointTree + forEachOnPath:query.path + whileBlock:^BOOL(FPath *pathToSyncPoint, FSyncPoint *syncPoint) { + foundAncestorDefaultView = + foundAncestorDefaultView || [syncPoint hasCompleteView]; + return !foundAncestorDefaultView; + }]; + + [self.persistenceManager setQueryActive:query]; + + FSyncPoint *syncPoint = [self.syncPointTree valueAtPath:path]; + if (syncPoint == nil) { + syncPoint = [[FSyncPoint alloc] + initWithPersistenceManager:self.persistenceManager]; + self.syncPointTree = [self.syncPointTree setValue:syncPoint + atPath:path]; + } + + BOOL viewAlreadyExists = [syncPoint viewExistsForQuery:query]; + NSArray *events; + if (viewAlreadyExists) { + events = [syncPoint addEventRegistration:eventRegistration + forExistingViewForQuery:query]; + } else { + if (![query loadsAllData]) { + // We need to track a tag for this query + NSAssert(self.queryToTagMap[query] == nil, + @"View does not exist, but we have a tag"); + NSNumber *tagId = [self.queryTagCounter getAndIncrement]; + self.queryToTagMap[query] = tagId; + self.tagToQueryMap[tagId] = query; + } + + FWriteTreeRef *writesCache = + [self.pendingWriteTree childWritesForPath:path]; + FCacheNode *serverCache = [self serverCacheForQuery:query]; + events = [syncPoint addEventRegistration:eventRegistration + forNonExistingViewForQuery:query + writesCache:writesCache + serverCache:serverCache]; + + // There was no view and no default listen + if (!foundAncestorDefaultView) { + FView *view = [syncPoint viewForQuery:query]; + NSMutableArray *mutableEvents = [events mutableCopy]; + [mutableEvents + addObjectsFromArray:[self setupListenerOnQuery:query + view:view]]; + events = mutableEvents; + } + } + + return events; +} + +- (FCacheNode *)serverCacheForQuery:(FQuerySpec *)query { + __block id serverCacheNode = nil; + + [self.syncPointTree + forEachOnPath:query.path + whileBlock:^BOOL(FPath *pathToSyncPoint, FSyncPoint *syncPoint) { + FPath *relativePath = [FPath relativePathFrom:pathToSyncPoint + to:query.path]; + serverCacheNode = + [syncPoint completeServerCacheAtPath:relativePath]; + return serverCacheNode == nil; + }]; + + FCacheNode *serverCache; + if (serverCacheNode != nil) { + FIndexedNode *indexed = + [FIndexedNode indexedNodeWithNode:serverCacheNode + index:query.index]; + serverCache = [[FCacheNode alloc] initWithIndexedNode:indexed + isFullyInitialized:YES + isFiltered:NO]; + } else { + FCacheNode *persistenceServerCache = + [self.persistenceManager serverCacheForQuery:query]; + if (persistenceServerCache.isFullyInitialized) { + serverCache = persistenceServerCache; + } else { + serverCacheNode = [FEmptyNode emptyNode]; + + FImmutableTree *subtree = + [self.syncPointTree subtreeAtPath:query.path]; + [subtree + forEachChild:^(NSString *childKey, FSyncPoint *childSyncPoint) { + id completeCache = + [childSyncPoint completeServerCacheAtPath:[FPath empty]]; + if (completeCache) { + serverCacheNode = + [serverCacheNode updateImmediateChild:childKey + withNewChild:completeCache]; + } + }]; + // Fill the node with any available children we have + [persistenceServerCache.node + enumerateChildrenUsingBlock:^(NSString *key, id node, + BOOL *stop) { + if (![serverCacheNode hasChild:key]) { + serverCacheNode = + [serverCacheNode updateImmediateChild:key + withNewChild:node]; + } + }]; + FIndexedNode *indexed = + [FIndexedNode indexedNodeWithNode:serverCacheNode + index:query.index]; + serverCache = [[FCacheNode alloc] initWithIndexedNode:indexed + isFullyInitialized:NO + isFiltered:NO]; + } + } + + return serverCache; +} + +/** + * Remove event callback(s). + * + * If query is the default query, we'll check all queries for the specified + * eventRegistration. If eventRegistration is null, we'll remove all callbacks + * for the specified query/queries. + * + * @param eventRegistration if nil, all callbacks are removed + * @param cancelError If provided, appropriate cancel events will be returned + * @return NSArray of FEvent to raise. + */ +- (NSArray *)removeEventRegistration:(id)eventRegistration + forQuery:(FQuerySpec *)query + cancelError:(NSError *)cancelError { + // Find the syncPoint first. Then deal with whether or not it has matching + // listeners + FPath *path = query.path; + FSyncPoint *maybeSyncPoint = [self.syncPointTree valueAtPath:path]; + NSArray *cancelEvents = @[]; + + // A removal on a default query affects all queries at that location. A + // removal on an indexed query, even one without other query constraints, + // does *not* affect all queries at that location. So this check must be for + // 'default', and not loadsAllData: + if (maybeSyncPoint && + ([query isDefault] || [maybeSyncPoint viewExistsForQuery:query])) { + FTupleRemovedQueriesEvents *removedAndEvents = + [maybeSyncPoint removeEventRegistration:eventRegistration + forQuery:query + cancelError:cancelError]; + if ([maybeSyncPoint isEmpty]) { + self.syncPointTree = [self.syncPointTree removeValueAtPath:path]; + } + NSArray *removed = removedAndEvents.removedQueries; + cancelEvents = removedAndEvents.cancelEvents; + + // We may have just removed one of many listeners and can short-circuit + // this whole process We may also not have removed a default listener, + // in which case all of the descendant listeners should already be + // properly set up. + // + // Since indexed queries can shadow if they don't have other query + // constraints, check for loadsAllData: instead of isDefault: + NSUInteger defaultQueryIndex = [removed + indexOfObjectPassingTest:^BOOL(FQuerySpec *q, NSUInteger idx, + BOOL *stop) { + return [q loadsAllData]; + }]; + BOOL removingDefault = defaultQueryIndex != NSNotFound; + [removed enumerateObjectsUsingBlock:^(FQuerySpec *query, NSUInteger idx, + BOOL *stop) { + [self.persistenceManager setQueryInactive:query]; + }]; + NSNumber *covered = [self.syncPointTree + findOnPath:path + andApplyBlock:^id(FPath *relativePath, + FSyncPoint *parentSyncPoint) { + return + [NSNumber numberWithBool:[parentSyncPoint hasCompleteView]]; + }]; + + if (removingDefault && ![covered boolValue]) { + FImmutableTree *subtree = [self.syncPointTree subtreeAtPath:path]; + // There are potentially child listeners. Determine what if any + // listens we need to send before executing the removal + if (![subtree isEmpty]) { + // We need to fold over our subtree and collect the listeners to + // send + NSArray *newViews = + [self collectDistinctViewsForSubTree:subtree]; + + // Ok, we've collected all the listens we need. Set them up. + [newViews enumerateObjectsUsingBlock:^( + FView *view, NSUInteger idx, BOOL *stop) { + FQuerySpec *newQuery = view.query; + FListenContainer *listenContainer = + [self createListenerForView:view]; + self.listenProvider.startListening( + [self queryForListening:newQuery], + [self tagForQuery:newQuery], listenContainer, + listenContainer.onComplete); + }]; + } else { + // There's nothing below us, so nothing we need to start + // listening on + } + } + + // If we removed anything and we're not covered by a higher up listen, + // we need to stop listening on this query. The above block has us + // covered in terms of making sure we're set up on listens lower in the + // tree. Also, note that if we have a cancelError, it's already been + // removed at the provider level. + if (![covered boolValue] && [removed count] > 0 && cancelError == nil) { + // If we removed a default, then we weren't listening on any of the + // other queries here. Just cancel the one default. Otherwise, we + // need to iterate through and cancel each individual query + if (removingDefault) { + // We don't tag default listeners + self.listenProvider.stopListening( + [self queryForListening:query], nil); + } else { + [removed + enumerateObjectsUsingBlock:^(FQuerySpec *queryToRemove, + NSUInteger idx, BOOL *stop) { + NSNumber *tagToRemove = + [self.queryToTagMap objectForKey:queryToRemove]; + self.listenProvider.stopListening( + [self queryForListening:queryToRemove], tagToRemove); + }]; + } + } + // Now, clear all the tags we're tracking for the removed listens. + [self removeTags:removed]; + } else { + // No-op, this listener must've been already removed + } + return cancelEvents; +} + +- (void)keepQuery:(FQuerySpec *)query synced:(BOOL)keepSynced { + // Only do something if we actually need to add/remove an event registration + if (keepSynced && ![self.keepSyncedQueries containsObject:query]) { + [self addEventRegistration:[FKeepSyncedEventRegistration instance] + forQuery:query]; + [self.keepSyncedQueries addObject:query]; + } else if (!keepSynced && [self.keepSyncedQueries containsObject:query]) { + [self removeEventRegistration:[FKeepSyncedEventRegistration instance] + forQuery:query + cancelError:nil]; + [self.keepSyncedQueries removeObject:query]; + } +} + +- (NSArray *)removeAllWrites { + [self.persistenceManager removeAllUserWrites]; + NSArray *removedWrites = [self.pendingWriteTree removeAllWrites]; + if (removedWrites.count > 0) { + FImmutableTree *affectedTree = + [[FImmutableTree empty] setValue:@YES atPath:[FPath empty]]; + return [self applyOperationToSyncPoints:[[FAckUserWrite alloc] + initWithPath:[FPath empty] + affectedTree:affectedTree + revert:YES]]; + } else { + return @[]; + } +} + +/** Returns a non-empty cache node if one exists. Otherwise returns null. */ +- (FIndexedNode *)persistenceServerCache:(FQuerySpec *)querySpec { + FCacheNode *cacheNode = + [self.persistenceManager serverCacheForQuery:querySpec]; + if (cacheNode == nil || cacheNode.node.isEmpty) { + return nil; + } + return cacheNode.indexedNode; +} + +- (id)getServerValue:(FQuerySpec *)query { + __block id serverCacheNode = nil; + __block FSyncPoint *targetSyncPoint = nil; + [self.syncPointTree + forEachOnPath:query.path + whileBlock:^BOOL(FPath *pathToSyncPoint, FSyncPoint *syncPoint) { + FPath *relativePath = [FPath relativePathFrom:pathToSyncPoint + to:query.path]; + serverCacheNode = + [syncPoint completeEventCacheAtPath:relativePath]; + targetSyncPoint = syncPoint; + return serverCacheNode == nil; + }]; + + if (targetSyncPoint == nil) { + targetSyncPoint = [[FSyncPoint alloc] + initWithPersistenceManager:self.persistenceManager]; + self.syncPointTree = [self.syncPointTree setValue:targetSyncPoint + atPath:[query path]]; + } else { + serverCacheNode = + serverCacheNode != nil + ? serverCacheNode + : [targetSyncPoint completeServerCacheAtPath:[FPath empty]]; + } + + FIndexedNode *indexed = [FIndexedNode + indexedNodeWithNode:serverCacheNode != nil ? serverCacheNode + : [FEmptyNode emptyNode] + index:query.index]; + FCacheNode *serverCache = + [[FCacheNode alloc] initWithIndexedNode:indexed + isFullyInitialized:serverCacheNode != nil + isFiltered:NO]; + FView *view = [targetSyncPoint + getView:query + writesCache:[_pendingWriteTree childWritesForPath:[query path]] + serverCache:serverCache]; + return [view completeEventCache]; +} + +/** + * Returns a complete cache, if we have one, of the data at a particular path. + * The location must have a listener above it, but as this is only used by + * transaction code, that should always be the case anyways. + * + * Note: this method will *include* hidden writes from transaction with + * applyLocally set to false. + * @param path The path to the data we want + * @param writeIdsToExclude A specific set to be excluded + */ +- (id)calcCompleteEventCacheAtPath:(FPath *)path + excludeWriteIds:(NSArray *)writeIdsToExclude { + BOOL includeHiddenSets = YES; + FWriteTree *writeTree = self.pendingWriteTree; + id serverCache = [self.syncPointTree + findOnPath:path + andApplyBlock:^id(FPath *pathSoFar, FSyncPoint *syncPoint) { + FPath *relativePath = [FPath relativePathFrom:pathSoFar to:path]; + id serverCache = + [syncPoint completeServerCacheAtPath:relativePath]; + if (serverCache) { + return serverCache; + } else { + return nil; + } + }]; + return [writeTree calculateCompleteEventCacheAtPath:path + completeServerCache:serverCache + excludeWriteIds:writeIdsToExclude + includeHiddenWrites:includeHiddenSets]; +} + +#pragma mark - +#pragma mark Private Methods +/** + * This collapses multiple unfiltered views into a single view, since we only + * need a single listener for them. + * @return NSArray of FView + */ +- (NSArray *)collectDistinctViewsForSubTree:(FImmutableTree *)subtree { + return [subtree foldWithBlock:^NSArray *(FPath *relativePath, + FSyncPoint *maybeChildSyncPoint, + NSDictionary *childMap) { + if (maybeChildSyncPoint && [maybeChildSyncPoint hasCompleteView]) { + FView *completeView = [maybeChildSyncPoint completeView]; + return @[ completeView ]; + } else { + // No complete view here, flatten any deeper listens into an array + NSMutableArray *views = [[NSMutableArray alloc] init]; + if (maybeChildSyncPoint) { + views = [[maybeChildSyncPoint queryViews] mutableCopy]; + } + [childMap enumerateKeysAndObjectsUsingBlock:^( + NSString *childKey, NSArray *childViews, BOOL *stop) { + [views addObjectsFromArray:childViews]; + }]; + return views; + } + }]; +} + +/** + * @param queries NSArray of FQuerySpec + */ +- (void)removeTags:(NSArray *)queries { + [queries enumerateObjectsUsingBlock:^(FQuerySpec *removedQuery, + NSUInteger idx, BOOL *stop) { + if (![removedQuery loadsAllData]) { + // We should have a tag for this + NSNumber *removedQueryTag = self.queryToTagMap[removedQuery]; + [self.queryToTagMap removeObjectForKey:removedQuery]; + [self.tagToQueryMap removeObjectForKey:removedQueryTag]; + } + }]; +} + +- (FQuerySpec *)queryForListening:(FQuerySpec *)query { + if (query.loadsAllData && !query.isDefault) { + // We treat queries that load all data as default queries + return [FQuerySpec defaultQueryAtPath:query.path]; + } else { + return query; + } +} + +/** + * For a given new listen, manage the de-duplication of outstanding + * subscriptions. + * @return NSArray of FEvent events to support synchronous data sources + */ +- (NSArray *)setupListenerOnQuery:(FQuerySpec *)query view:(FView *)view { + FPath *path = query.path; + NSNumber *tagId = [self tagForQuery:query]; + FListenContainer *listenContainer = [self createListenerForView:view]; + + NSArray *events = self.listenProvider.startListening( + [self queryForListening:query], tagId, listenContainer, + listenContainer.onComplete); + + FImmutableTree *subtree = [self.syncPointTree subtreeAtPath:path]; + // The root of this subtree has our query. We're here because we definitely + // need to send a listen for that, but we may need to shadow other listens + // as well. + if (tagId != nil) { + NSAssert(![subtree.value hasCompleteView], + @"If we're adding a query, it shouldn't be shadowed"); + } else { + // Shadow everything at or below this location, this is a default + // listener. + NSArray *queriesToStop = + [subtree foldWithBlock:^id(FPath *relativePath, + FSyncPoint *maybeChildSyncPoint, + NSDictionary *childMap) { + if (![relativePath isEmpty] && maybeChildSyncPoint != nil && + [maybeChildSyncPoint hasCompleteView]) { + return @[ [maybeChildSyncPoint completeView].query ]; + } else { + // No default listener here, flatten any deeper queries into + // an array + NSMutableArray *queries = [[NSMutableArray alloc] init]; + if (maybeChildSyncPoint != nil) { + for (FView *view in [maybeChildSyncPoint queryViews]) { + [queries addObject:view.query]; + } + } + [childMap + enumerateKeysAndObjectsUsingBlock:^( + NSString *key, NSArray *childQueries, BOOL *stop) { + [queries addObjectsFromArray:childQueries]; + }]; + return queries; + } + }]; + for (FQuerySpec *queryToStop in queriesToStop) { + self.listenProvider.stopListening( + [self queryForListening:queryToStop], + [self tagForQuery:queryToStop]); + } + } + return events; +} + +- (FListenContainer *)createListenerForView:(FView *)view { + FQuerySpec *query = view.query; + NSNumber *tagId = [self tagForQuery:query]; + + FListenContainer *listenContainer = [[FListenContainer alloc] + initWithView:view + onComplete:^(NSString *status) { + if ([status isEqualToString:@"ok"]) { + if (tagId != nil) { + return [self applyTaggedListenCompleteAtPath:query.path + tagId:tagId]; + } else { + return [self applyListenCompleteAtPath:query.path]; + } + } else { + // If a listen failed, kill all of the listeners here, not just + // the one that triggered the error. Note that this may need to + // be scoped to just this listener if we change permissions on + // filtered children + NSError *error = [FUtilities errorForStatus:status + andReason:nil]; + FFWarn(@"I-RDB038012", @"Listener at %@ failed: %@", query.path, + status); + return [self removeEventRegistration:nil + forQuery:query + cancelError:error]; + } + }]; + + return listenContainer; +} + +/** + * @return The query associated with the given tag, if we have one + */ +- (FQuerySpec *)queryForTag:(NSNumber *)tagId { + return self.tagToQueryMap[tagId]; +} + +/** + * @return The tag associated with the given query + */ +- (NSNumber *)tagForQuery:(FQuerySpec *)query { + return self.queryToTagMap[query]; +} + +#pragma mark - +#pragma mark applyOperation Helpers + +/** +* A helper method that visits all descendant and ancestor SyncPoints, applying +the operation. +* +* NOTES: +* - Descendant SyncPoints will be visited first (since we raise events +depth-first). + +* - We call applyOperation: on each SyncPoint passing three things: +* 1. A version of the Operation that has been made relative to the SyncPoint +location. +* 2. A WriteTreeRef of any writes we have cached at the SyncPoint location. +* 3. A snapshot Node with cached server data, if we have it. + +* - We concatenate all of the events returned by each SyncPoint and return the +result. +* +* @return Array of FEvent +*/ +- (NSArray *)applyOperationToSyncPoints:(id)operation { + return [self applyOperationHelper:operation + syncPointTree:self.syncPointTree + serverCache:nil + writesCache:[self.pendingWriteTree + childWritesForPath:[FPath empty]]]; +} + +/** + * Recursive helper for applyOperationToSyncPoints_ + */ +- (NSArray *)applyOperationHelper:(id)operation + syncPointTree:(FImmutableTree *)syncPointTree + serverCache:(id)serverCache + writesCache:(FWriteTreeRef *)writesCache { + if ([operation.path isEmpty]) { + return [self applyOperationDescendantsHelper:operation + syncPointTree:syncPointTree + serverCache:serverCache + writesCache:writesCache]; + } else { + FSyncPoint *syncPoint = syncPointTree.value; + + // If we don't have cached server data, see if we can get it from this + // SyncPoint + if (serverCache == nil && syncPoint != nil) { + serverCache = [syncPoint completeServerCacheAtPath:[FPath empty]]; + } + + NSMutableArray *events = [[NSMutableArray alloc] init]; + NSString *childKey = [operation.path getFront]; + id childOperation = [operation operationForChild:childKey]; + FImmutableTree *childTree = [syncPointTree.children get:childKey]; + if (childTree != nil && childOperation != nil) { + id childServerCache = + serverCache ? [serverCache getImmediateChild:childKey] : nil; + FWriteTreeRef *childWritesCache = + [writesCache childWriteTreeRef:childKey]; + [events + addObjectsFromArray:[self + applyOperationHelper:childOperation + syncPointTree:childTree + serverCache:childServerCache + writesCache:childWritesCache]]; + } + + if (syncPoint) { + [events addObjectsFromArray:[syncPoint applyOperation:operation + writesCache:writesCache + serverCache:serverCache]]; + } + + return events; + } +} + +/** + * Recursive helper for applyOperationToSyncPoints: + */ +- (NSArray *)applyOperationDescendantsHelper:(id)operation + syncPointTree:(FImmutableTree *)syncPointTree + serverCache:(id)serverCache + writesCache:(FWriteTreeRef *)writesCache { + FSyncPoint *syncPoint = syncPointTree.value; + + // If we don't have cached server data, see if we can get it from this + // SyncPoint + id resolvedServerCache; + if (serverCache == nil & syncPoint != nil) { + resolvedServerCache = + [syncPoint completeServerCacheAtPath:[FPath empty]]; + } else { + resolvedServerCache = serverCache; + } + + NSMutableArray *events = [[NSMutableArray alloc] init]; + [syncPointTree.children enumerateKeysAndObjectsUsingBlock:^( + NSString *childKey, FImmutableTree *childTree, + BOOL *stop) { + id childServerCache = nil; + if (resolvedServerCache != nil) { + childServerCache = [resolvedServerCache getImmediateChild:childKey]; + } + FWriteTreeRef *childWritesCache = + [writesCache childWriteTreeRef:childKey]; + id childOperation = [operation operationForChild:childKey]; + if (childOperation != nil) { + [events addObjectsFromArray: + [self applyOperationDescendantsHelper:childOperation + syncPointTree:childTree + serverCache:childServerCache + writesCache:childWritesCache]]; + } + }]; + + if (syncPoint) { + [events + addObjectsFromArray:[syncPoint applyOperation:operation + writesCache:writesCache + serverCache:resolvedServerCache]]; + } + + return events; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteRecord.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteRecord.h new file mode 100644 index 0000000..435fb6a --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteRecord.h @@ -0,0 +1,45 @@ +/* + * 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 + +@class FPath; +@class FCompoundWrite; +@protocol FNode; + +@interface FWriteRecord : NSObject + +- initWithPath:(FPath *)path + overwrite:(id)overwrite + writeId:(NSInteger)writeId + visible:(BOOL)isVisible; +- initWithPath:(FPath *)path + merge:(FCompoundWrite *)merge + writeId:(NSInteger)writeId; + +@property(nonatomic, readonly) NSInteger writeId; +@property(nonatomic, strong, readonly) FPath *path; +@property(nonatomic, strong, readonly) id overwrite; +/** + * Maps NSString -> id + */ +@property(nonatomic, strong, readonly) FCompoundWrite *merge; +@property(nonatomic, readonly) BOOL visible; + +- (BOOL)isMerge; +- (BOOL)isOverwrite; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteRecord.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteRecord.m new file mode 100644 index 0000000..3f5e657 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteRecord.m @@ -0,0 +1,139 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/FWriteRecord.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Snapshot/FCompoundWrite.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" + +@interface FWriteRecord () +@property(nonatomic, readwrite) NSInteger writeId; +@property(nonatomic, strong, readwrite) FPath *path; +@property(nonatomic, strong, readwrite) id overwrite; +@property(nonatomic, strong, readwrite) FCompoundWrite *merge; +@property(nonatomic, readwrite) BOOL visible; +@end + +@implementation FWriteRecord + +- (id)initWithPath:(FPath *)path + overwrite:(id)overwrite + writeId:(NSInteger)writeId + visible:(BOOL)isVisible { + self = [super init]; + if (self) { + self.path = path; + if (overwrite == nil) { + [NSException raise:NSInvalidArgumentException + format:@"Can't pass nil as overwrite parameter to an " + @"overwrite write record"]; + } + self.overwrite = overwrite; + self.merge = nil; + self.writeId = writeId; + self.visible = isVisible; + } + return self; +} + +- (id)initWithPath:(FPath *)path + merge:(FCompoundWrite *)merge + writeId:(NSInteger)writeId { + self = [super init]; + if (self) { + self.path = path; + if (merge == nil) { + [NSException raise:NSInvalidArgumentException + format:@"Can't pass nil as merge parameter to an merge " + @"write record"]; + } + self.overwrite = nil; + self.merge = merge; + self.writeId = writeId; + self.visible = YES; + } + return self; +} + +- (id)overwrite { + if (self->_overwrite == nil) { + [NSException raise:NSInvalidArgumentException + format:@"Can't get overwrite for merge write record!"]; + } + return self->_overwrite; +} + +- (FCompoundWrite *)compoundWrite { + if (self->_merge == nil) { + [NSException raise:NSInvalidArgumentException + format:@"Can't get merge for overwrite write record!"]; + } + return self->_merge; +} + +- (BOOL)isMerge { + return self->_merge != nil; +} + +- (BOOL)isOverwrite { + return self->_overwrite != nil; +} + +- (NSString *)description { + if (self.isOverwrite) { + return + [NSString stringWithFormat:@"FWriteRecord { writeId = %lu, path = " + @"%@, overwrite = %@, visible = %d }", + (unsigned long)self.writeId, self.path, + self.overwrite, self.visible]; + } else { + return [NSString + stringWithFormat: + @"FWriteRecord { writeId = %lu, path = %@, merge = %@ }", + (unsigned long)self.writeId, self.path, self.merge]; + } +} + +- (BOOL)isEqual:(id)object { + if (![object isKindOfClass:[self class]]) { + return NO; + } + FWriteRecord *other = (FWriteRecord *)object; + if (self->_writeId != other->_writeId) + return NO; + if (self->_path != other->_path && ![self->_path isEqual:other->_path]) + return NO; + if (self->_overwrite != other->_overwrite && + ![self->_overwrite isEqual:other->_overwrite]) + return NO; + if (self->_merge != other->_merge && ![self->_merge isEqual:other->_merge]) + return NO; + if (self->_visible != other->_visible) + return NO; + + return YES; +} + +- (NSUInteger)hash { + NSUInteger hash = self->_writeId * 17; + hash = hash * 31 + self->_path.hash; + hash = hash * 31 + self->_overwrite.hash; + hash = hash * 31 + self->_merge.hash; + hash = hash * 31 + ((self->_visible) ? 1 : 0); + return hash; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteTree.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteTree.h new file mode 100644 index 0000000..178946b --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteTree.h @@ -0,0 +1,70 @@ +/* + * 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 + +@class FPath; +@protocol FNode; +@class FCompoundWrite; +@class FWriteTreeRef; +@class FChildrenNode; +@class FNamedNode; +@class FWriteRecord; +@protocol FIndex; +@class FCacheNode; + +@interface FWriteTree : NSObject + +- (FWriteTreeRef *)childWritesForPath:(FPath *)path; +- (void)addOverwriteAtPath:(FPath *)path + newData:(id)newData + writeId:(NSInteger)writeId + isVisible:(BOOL)visible; +- (void)addMergeAtPath:(FPath *)path + changedChildren:(FCompoundWrite *)changedChildren + writeId:(NSInteger)writeId; +- (BOOL)removeWriteId:(NSInteger)writeId; +- (NSArray *)removeAllWrites; +- (FWriteRecord *)writeForId:(NSInteger)writeId; + +- (id)calculateCompleteEventCacheAtPath:(FPath *)treePath + completeServerCache:(id)completeServerCache + excludeWriteIds:(NSArray *)writeIdsToExclude + includeHiddenWrites:(BOOL)includeHiddenWrites; + +- (id)calculateCompleteEventChildrenAtPath:(FPath *)treePath + completeServerChildren: + (id)completeServerChildren; + +- (id) + calculateEventCacheAfterServerOverwriteAtPath:(FPath *)treePath + childPath:(FPath *)childPath + existingEventSnap:(id)existingEventSnap + existingServerSnap:(id)existingServerSnap; + +- (id)calculateCompleteChildAtPath:(FPath *)treePath + childKey:(NSString *)childKey + cache:(FCacheNode *)existingServerCache; + +- (id)shadowingWriteAtPath:(FPath *)path; + +- (FNamedNode *)calculateNextNodeAfterPost:(FNamedNode *)post + atPath:(FPath *)path + completeServerData:(id)completeServerData + reverse:(BOOL)reverse + index:(id)index; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteTree.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteTree.m new file mode 100644 index 0000000..9cea890 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteTree.m @@ -0,0 +1,577 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/FWriteTree.h" +#import "FirebaseDatabase/Sources/Core/FWriteRecord.h" +#import "FirebaseDatabase/Sources/Core/FWriteTreeRef.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FImmutableTree.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Core/View/FCacheNode.h" +#import "FirebaseDatabase/Sources/FIndex.h" +#import "FirebaseDatabase/Sources/FNamedNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FCompoundWrite.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" + +@interface FWriteTree () +/** + * A tree tracking the results of applying all visible writes. This does not + * include transactions with applyLocally=false or writes that are completely + * shadowed by other writes. Contains id as values. + */ +@property(nonatomic, strong) FCompoundWrite *visibleWrites; +/** + * A list of pending writes, regardless of visibility and shadowed-ness. Used to + * calcuate arbitrary sets of the changed data, such as hidden writes (from + * transactions) or changes with certain writes excluded (also used by + * transactions). Contains FWriteRecords. + */ +@property(nonatomic, strong) NSMutableArray *allWrites; +@property(nonatomic) NSInteger lastWriteId; +@end + +/** + * FWriteTree tracks all pending user-initiated writes and has methods to + * calcuate the result of merging them with underlying server data (to create + * "event cache" data). Pending writes are added with addOverwriteAtPath: and + * addMergeAtPath: and removed with removeWriteId:. + */ +@implementation FWriteTree + +@synthesize allWrites; +@synthesize lastWriteId; + +- (id)init { + self = [super init]; + if (self) { + self.visibleWrites = [FCompoundWrite emptyWrite]; + self.allWrites = [[NSMutableArray alloc] init]; + self.lastWriteId = -1; + } + return self; +} + +/** + * Create a new WriteTreeRef for the given path. For use with a new sync point + * at the given path. + */ +- (FWriteTreeRef *)childWritesForPath:(FPath *)path { + return [[FWriteTreeRef alloc] initWithPath:path writeTree:self]; +} + +/** + * Record a new overwrite from user code. + * @param visible Is set to false by some transactions. It should be excluded + * from event caches. + */ +- (void)addOverwriteAtPath:(FPath *)path + newData:(id)newData + writeId:(NSInteger)writeId + isVisible:(BOOL)visible { + NSAssert(writeId > self.lastWriteId, + @"Stacking an older write on top of a newer one"); + FWriteRecord *record = [[FWriteRecord alloc] initWithPath:path + overwrite:newData + writeId:writeId + visible:visible]; + [self.allWrites addObject:record]; + + if (visible) { + self.visibleWrites = [self.visibleWrites addWrite:newData atPath:path]; + } + + self.lastWriteId = writeId; +} + +/** + * Record a new merge from user code. + * @param changedChildren maps NSString -> id + */ +- (void)addMergeAtPath:(FPath *)path + changedChildren:(FCompoundWrite *)changedChildren + writeId:(NSInteger)writeId { + NSAssert(writeId > self.lastWriteId, + @"Stacking an older merge on top of newer one"); + FWriteRecord *record = [[FWriteRecord alloc] initWithPath:path + merge:changedChildren + writeId:writeId]; + [self.allWrites addObject:record]; + + self.visibleWrites = [self.visibleWrites addCompoundWrite:changedChildren + atPath:path]; + self.lastWriteId = writeId; +} + +- (FWriteRecord *)writeForId:(NSInteger)writeId { + NSUInteger index = [self.allWrites + indexOfObjectPassingTest:^BOOL(FWriteRecord *write, NSUInteger idx, + BOOL *stop) { + return write.writeId == writeId; + }]; + return (index == NSNotFound) ? nil : self.allWrites[index]; +} + +/** + * Remove a write (either an overwrite or merge) that has been successfully + * acknowledged by the server. Recalculates the tree if necessary. We return the + * path of the write and whether it may have been visible, meaning views need to + * reevaluate. + * + * @return YES if the write may have been visible (meaning we'll need to + * reevaluate / raise events as a result). + */ +- (BOOL)removeWriteId:(NSInteger)writeId { + NSUInteger index = [self.allWrites + indexOfObjectPassingTest:^BOOL(FWriteRecord *record, NSUInteger idx, + BOOL *stop) { + if (record.writeId == writeId) { + return YES; + } else { + return NO; + } + }]; + NSAssert(index != NSNotFound, + @"[FWriteTree removeWriteId:] called with nonexistent writeId."); + FWriteRecord *writeToRemove = self.allWrites[index]; + [self.allWrites removeObjectAtIndex:index]; + + BOOL removedWriteWasVisible = writeToRemove.visible; + BOOL removedWriteOverlapsWithOtherWrites = NO; + NSInteger i = [self.allWrites count] - 1; + + while (removedWriteWasVisible && i >= 0) { + FWriteRecord *currentWrite = [self.allWrites objectAtIndex:i]; + if (currentWrite.visible) { + if (i >= index && [self record:currentWrite + containsPath:writeToRemove.path]) { + // The removed write was completely shadowed by a subsequent + // write. + removedWriteWasVisible = NO; + } else if ([writeToRemove.path contains:currentWrite.path]) { + // Either we're covering some writes or they're covering part of + // us (depending on which came first). + removedWriteOverlapsWithOtherWrites = YES; + } + } + i--; + } + + if (!removedWriteWasVisible) { + return NO; + } else if (removedWriteOverlapsWithOtherWrites) { + // There's some shadowing going on. Just rebuild the visible writes from + // scratch. + [self resetTree]; + return YES; + } else { + // There's no shadowing. We can safely just remove the write(s) from + // visibleWrites. + if ([writeToRemove isOverwrite]) { + self.visibleWrites = + [self.visibleWrites removeWriteAtPath:writeToRemove.path]; + } else { + FCompoundWrite *merge = writeToRemove.merge; + [merge enumerateWrites:^(FPath *path, id node, BOOL *stop) { + self.visibleWrites = [self.visibleWrites + removeWriteAtPath:[writeToRemove.path child:path]]; + }]; + } + return YES; + } +} + +- (NSArray *)removeAllWrites { + NSArray *writes = self.allWrites; + self.visibleWrites = [FCompoundWrite emptyWrite]; + self.allWrites = [NSMutableArray array]; + return writes; +} + +/** + * @return A complete snapshot for the given path if there's visible write data + * at that path, else nil. No server data is considered. + */ +- (id)completeWriteDataAtPath:(FPath *)path { + return [self.visibleWrites completeNodeAtPath:path]; +} + +/** + * Given optional, underlying server data, and an optional set of constraints + * (exclude some sets, include hidden writes), attempt to calculate a complete + * snapshot for the given path + * @param includeHiddenWrites Defaults to false, whether or not to layer on + * writes with visible set to false + */ +- (id)calculateCompleteEventCacheAtPath:(FPath *)treePath + completeServerCache:(id)completeServerCache + excludeWriteIds:(NSArray *)writeIdsToExclude + includeHiddenWrites:(BOOL)includeHiddenWrites { + if (writeIdsToExclude == nil && !includeHiddenWrites) { + id shadowingNode = + [self.visibleWrites completeNodeAtPath:treePath]; + if (shadowingNode != nil) { + return shadowingNode; + } else { + // No cache here. Can't claim complete knowledge. + FCompoundWrite *subMerge = + [self.visibleWrites childCompoundWriteAtPath:treePath]; + if (subMerge.isEmpty) { + return completeServerCache; + } else if (completeServerCache == nil && + ![subMerge hasCompleteWriteAtPath:[FPath empty]]) { + // We wouldn't have a complete snapshot since there's no + // underlying data and no complete shadow + return nil; + } else { + id layeredCache = completeServerCache != nil + ? completeServerCache + : [FEmptyNode emptyNode]; + return [subMerge applyToNode:layeredCache]; + } + } + } else { + FCompoundWrite *merge = + [self.visibleWrites childCompoundWriteAtPath:treePath]; + if (!includeHiddenWrites && merge.isEmpty) { + return completeServerCache; + } else { + // If the server cache is null and we don't have a complete cache, + // we need to return nil + if (!includeHiddenWrites && completeServerCache == nil && + ![merge hasCompleteWriteAtPath:[FPath empty]]) { + return nil; + } else { + BOOL (^filter)(FWriteRecord *) = ^(FWriteRecord *record) { + return (BOOL)((record.visible || includeHiddenWrites) && + (writeIdsToExclude == nil || + ![writeIdsToExclude + containsObject:[NSNumber + numberWithInteger: + record.writeId]]) && + ([record.path contains:treePath] || + [treePath contains:record.path])); + }; + FCompoundWrite *mergeAtPath = + [FWriteTree layerTreeFromWrites:self.allWrites + filter:filter + treeRoot:treePath]; + id layeredCache = completeServerCache + ? completeServerCache + : [FEmptyNode emptyNode]; + return [mergeAtPath applyToNode:layeredCache]; + } + } + } +} + +/** + * With optional, underlying server data, attempt to return a children node of + * children that we have complete data for. Used when creating new views, to + * pre-fill their complete event children snapshot. + */ +- (FChildrenNode *)calculateCompleteEventChildrenAtPath:(FPath *)treePath + completeServerChildren: + (id)completeServerChildren { + __block id completeChildren = [FEmptyNode emptyNode]; + id topLevelSet = [self.visibleWrites completeNodeAtPath:treePath]; + if (topLevelSet != nil) { + if (![topLevelSet isLeafNode]) { + // We're shadowing everything. Return the children. + FChildrenNode *topChildrenNode = topLevelSet; + [topChildrenNode enumerateChildrenUsingBlock:^( + NSString *key, id node, BOOL *stop) { + completeChildren = [completeChildren updateImmediateChild:key + withNewChild:node]; + }]; + } + return completeChildren; + } else { + // Layer any children we have on top of this + // We know we don't have a top-level set, so just enumerate existing + // children, and apply any updates + FCompoundWrite *merge = + [self.visibleWrites childCompoundWriteAtPath:treePath]; + [completeServerChildren enumerateChildrenUsingBlock:^( + NSString *key, id node, BOOL *stop) { + FCompoundWrite *childMerge = + [merge childCompoundWriteAtPath:[[FPath alloc] initWith:key]]; + id newChildNode = [childMerge applyToNode:node]; + completeChildren = + [completeChildren updateImmediateChild:key + withNewChild:newChildNode]; + }]; + // Add any complete children we have from the set. + for (FNamedNode *node in merge.completeChildren) { + completeChildren = + [completeChildren updateImmediateChild:node.name + withNewChild:node.node]; + } + return completeChildren; + } +} + +/** + * Given that the underlying server data has updated, determine what, if + * anything, needs to be applied to the event cache. + * + * Possibilities + * + * 1. No write are shadowing. Events should be raised, the snap to be applied + * comes from the server data. + * + * 2. Some write is completely shadowing. No events to be raised. + * + * 3. Is partially shadowed. Events .. + * + * Either existingEventSnap or existingServerSnap must exist. + */ +- (id)calculateEventCacheAfterServerOverwriteAtPath:(FPath *)treePath + childPath:(FPath *)childPath + existingEventSnap: + (id)existingEventSnap + existingServerSnap: + (id)existingServerSnap { + NSAssert(existingEventSnap != nil || existingServerSnap != nil, + @"Either existingEventSnap or existingServerSanp must exist."); + + FPath *path = [treePath child:childPath]; + if ([self.visibleWrites hasCompleteWriteAtPath:path]) { + // At this point we can probably guarantee that we're in case 2, meaning + // no events May need to check visibility while doing the + // findRootMostValueAndPath call + return nil; + } else { + // This could be more efficient if the serverNode + updates doesn't + // change the eventSnap However this is tricky to find out, since user + // updates don't necessary change the server snap, e.g. priority updates + // on empty nodes, or deep deletes. Another special case is if the + // server adds nodes, but doesn't change any existing writes. It is + // therefore not enough to only check if the updates change the + // serverNode. Maybe check if the merge tree contains these special + // cases and only do a full overwrite in that case? + FCompoundWrite *childMerge = + [self.visibleWrites childCompoundWriteAtPath:path]; + if (childMerge.isEmpty) { + // We're not shadowing at all. Case 1 + return [existingServerSnap getChild:childPath]; + } else { + return [childMerge + applyToNode:[existingServerSnap getChild:childPath]]; + } + } +} + +/** + * Returns a complete child for a given server snap after applying all user + * writes or nil if there is no complete child for this child key. + */ +- (id)calculateCompleteChildAtPath:(FPath *)treePath + childKey:(NSString *)childKey + cache:(FCacheNode *)existingServerCache { + FPath *path = [treePath childFromString:childKey]; + id shadowingNode = [self.visibleWrites completeNodeAtPath:path]; + if (shadowingNode != nil) { + return shadowingNode; + } else { + if ([existingServerCache isCompleteForChild:childKey]) { + FCompoundWrite *childMerge = + [self.visibleWrites childCompoundWriteAtPath:path]; + return [childMerge applyToNode:[existingServerCache.node + getImmediateChild:childKey]]; + } else { + return nil; + } + } +} + +/** + * Returns a node if there is a complete overwrite for this path. More + * specifically, if there is a write at a higher path, this will return the + * child of that write relative to the write and this path. Returns null if + * there is no write at this path. + */ +- (id)shadowingWriteAtPath:(FPath *)path { + return [self.visibleWrites completeNodeAtPath:path]; +} + +/** + * This method is used when processing child remove events on a query. If we + * can, we pull in children that were outside the window, but may now be in the + * window. + */ +- (FNamedNode *)calculateNextNodeAfterPost:(FNamedNode *)post + atPath:(FPath *)treePath + completeServerData:(id)completeServerData + reverse:(BOOL)reverse + index:(id)index { + __block id toIterate; + FCompoundWrite *merge = + [self.visibleWrites childCompoundWriteAtPath:treePath]; + id shadowingNode = [merge completeNodeAtPath:[FPath empty]]; + if (shadowingNode != nil) { + toIterate = shadowingNode; + } else if (completeServerData != nil) { + toIterate = [merge applyToNode:completeServerData]; + } else { + return nil; + } + + __block NSString *currentNextKey = nil; + __block id currentNextNode = nil; + [toIterate enumerateChildrenUsingBlock:^(NSString *key, id node, + BOOL *stop) { + if ([index compareKey:key + andNode:node + toOtherKey:post.name + andNode:post.node + reverse:reverse] > NSOrderedSame && + (!currentNextKey || [index compareKey:key + andNode:node + toOtherKey:currentNextKey + andNode:currentNextNode + reverse:reverse] < NSOrderedSame)) { + currentNextKey = key; + currentNextNode = node; + } + }]; + + if (currentNextKey != nil) { + return [FNamedNode nodeWithName:currentNextKey node:currentNextNode]; + } else { + return nil; + } +} + +#pragma mark - +#pragma mark Private Methods + +- (BOOL)record:(FWriteRecord *)record containsPath:(FPath *)path { + if ([record isOverwrite]) { + return [record.path contains:path]; + } else { + __block BOOL contains = NO; + [record.merge + enumerateWrites:^(FPath *childPath, id node, BOOL *stop) { + contains = [[record.path child:childPath] contains:path]; + *stop = contains; + }]; + return contains; + } +} + +/** + * Re-layer the writes and merges into a tree so we can efficiently calculate + * event snapshots + */ +- (void)resetTree { + self.visibleWrites = + [FWriteTree layerTreeFromWrites:self.allWrites + filter:[FWriteTree defaultFilter] + treeRoot:[FPath empty]]; + if ([self.allWrites count] > 0) { + FWriteRecord *lastRecord = self.allWrites[[self.allWrites count] - 1]; + self.lastWriteId = lastRecord.writeId; + } else { + self.lastWriteId = -1; + } +} + +/** + * The default filter used when constructing the tree. Keep everything that's + * visible. + */ ++ (BOOL (^)(FWriteRecord *record))defaultFilter { + static BOOL (^filter)(FWriteRecord *); + static dispatch_once_t filterToken; + dispatch_once(&filterToken, ^{ + filter = ^(FWriteRecord *record) { + return YES; + }; + }); + return filter; +} + +/** + * Static method. Given an array of WriteRecords, a filter for which ones to + * include, and a path, construct a merge at that path + * @return An FImmutableTree of ids. + */ ++ (FCompoundWrite *)layerTreeFromWrites:(NSArray *)writes + filter:(BOOL (^)(FWriteRecord *record))filter + treeRoot:(FPath *)treeRoot { + __block FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite]; + [writes enumerateObjectsUsingBlock:^(FWriteRecord *record, NSUInteger idx, + BOOL *stop) { + // Theory, a later set will either: + // a) abort a relevant transaction, so no need to worry about excluding it + // from calculating that transaction b) not be relevant to a transaction + // (separate branch), so again will not affect the data for that + // transaction + if (filter(record)) { + FPath *writePath = record.path; + if ([record isOverwrite]) { + if ([treeRoot contains:writePath]) { + FPath *relativePath = [FPath relativePathFrom:treeRoot + to:writePath]; + compoundWrite = [compoundWrite addWrite:record.overwrite + atPath:relativePath]; + } else if ([writePath contains:treeRoot]) { + id child = [record.overwrite + getChild:[FPath relativePathFrom:writePath to:treeRoot]]; + compoundWrite = [compoundWrite addWrite:child + atPath:[FPath empty]]; + } else { + // There is no overlap between root path and write path, + // ignore write + } + } else { + if ([treeRoot contains:writePath]) { + FPath *relativePath = [FPath relativePathFrom:treeRoot + to:writePath]; + compoundWrite = [compoundWrite addCompoundWrite:record.merge + atPath:relativePath]; + } else if ([writePath contains:treeRoot]) { + FPath *relativePath = [FPath relativePathFrom:writePath + to:treeRoot]; + if (relativePath.isEmpty) { + compoundWrite = + [compoundWrite addCompoundWrite:record.merge + atPath:[FPath empty]]; + } else { + id child = + [record.merge completeNodeAtPath:relativePath]; + if (child != nil) { + // There exists a child in this node that matches the + // root path + id deepNode = + [child getChild:[relativePath popFront]]; + compoundWrite = + [compoundWrite addWrite:deepNode + atPath:[FPath empty]]; + } + } + } else { + // There is no overlap between root path and write path, + // ignore write + } + } + } + }]; + return compoundWrite; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteTreeRef.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteTreeRef.h new file mode 100644 index 0000000..962ad5c --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteTreeRef.h @@ -0,0 +1,57 @@ +/* + * 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 + +@protocol FNode; +@class FChildrenNode; +@class FPath; +@class FNamedNode; +@class FWriteRecord; +@class FWriteTree; +@protocol FIndex; +@class FCacheNode; + +@interface FWriteTreeRef : NSObject + +- (id)initWithPath:(FPath *)aPath writeTree:(FWriteTree *)tree; + +- (id)calculateCompleteEventCacheWithCompleteServerCache: + (id)completeServerCache; + +- (FChildrenNode *)calculateCompleteEventChildrenWithCompleteServerChildren: + (FChildrenNode *)completeServerChildren; + +- (id) + calculateEventCacheAfterServerOverwriteWithChildPath:(FPath *)childPath + existingEventSnap: + (id)existingEventSnap + existingServerSnap: + (id)existingServerSnap; + +- (id)shadowingWriteAtPath:(FPath *)path; + +- (FNamedNode *)calculateNextNodeAfterPost:(FNamedNode *)post + completeServerData:(id)completeServerData + reverse:(BOOL)reverse + index:(id)index; + +- (id)calculateCompleteChild:(NSString *)childKey + cache:(FCacheNode *)existingServerCache; + +- (FWriteTreeRef *)childWriteTreeRef:(NSString *)childKey; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteTreeRef.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteTreeRef.m new file mode 100644 index 0000000..6edb684 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/FWriteTreeRef.m @@ -0,0 +1,159 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/FWriteTreeRef.h" +#import "FirebaseDatabase/Sources/Core/FWriteRecord.h" +#import "FirebaseDatabase/Sources/Core/FWriteTree.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Core/View/FCacheNode.h" +#import "FirebaseDatabase/Sources/FIndex.h" +#import "FirebaseDatabase/Sources/FNamedNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" + +@interface FWriteTreeRef () +/** + * The path to this particular FWriteTreeRef. Used for calling methods on + * writeTree while exposing a simpler interface to callers. + */ +@property(nonatomic, strong) FPath *path; +/** + * A reference to the actual tree of the write data. All methods are + * pass-through to the tree, but with the appropriate path prefixed. + * + * This lets us make cheap references to points in the tree for sync points + * without having to copy and maintain all of the data. + */ +@property(nonatomic, strong) FWriteTree *writeTree; +@end + +/** + * A FWriteTreeRef wraps a FWriteTree and a FPath, for convenient access to a + * particular subtree. All the methods just proxy to the underlying FWriteTree. + */ +@implementation FWriteTreeRef +- (id)initWithPath:(FPath *)aPath writeTree:(FWriteTree *)tree { + self = [super init]; + if (self) { + self.path = aPath; + self.writeTree = tree; + } + return self; +} + +/** + * @return If possible, returns a complete event cache, using the underlying + * server data if possible. In addition, can be used to get a cache that + * includes hidden writes, and excludes arbitrary writes. Note that customizing + * the returned node can lead to a more expensive calculation. + */ +- (id)calculateCompleteEventCacheWithCompleteServerCache: + (id)completeServerCache { + return [self.writeTree calculateCompleteEventCacheAtPath:self.path + completeServerCache:completeServerCache + excludeWriteIds:nil + includeHiddenWrites:NO]; +} + +/** + * @return If possible, returns a children node containing all of the complete + * children we have data for. The returned data is a mix of the given server + * data and write data. + */ +- (FChildrenNode *)calculateCompleteEventChildrenWithCompleteServerChildren: + (id)completeServerChildren { + return [self.writeTree + calculateCompleteEventChildrenAtPath:self.path + completeServerChildren:completeServerChildren]; +} + +/** + * Given that either the underlying server data has updated or the outstanding + * writes have been updating, determine what, if anything, needs to be applied + * to the event cache. + * + * Possibilities: + * + * 1. No writes are shadowing. Events should be raised, the snap to be applied + * comes from the server data. + * + * 2. Some writes are completly shadowing. No events to be raised. + * + * 3. Is partially shadowed. Events should be raised. + * + * Either existingEventSnap or existingServerSnap must exist, this is validated + * via an assert. + */ +- (id) + calculateEventCacheAfterServerOverwriteWithChildPath:(FPath *)childPath + existingEventSnap: + (id)existingEventSnap + existingServerSnap: + (id)existingServerSnap { + return [self.writeTree + calculateEventCacheAfterServerOverwriteAtPath:self.path + childPath:childPath + existingEventSnap:existingEventSnap + existingServerSnap:existingServerSnap]; +} + +/** + * Returns a node if there is a complete overwrite for this path. More + * specifically, if there is a write at a higher path, this will return the + * child of that write relative to the write and this path. Returns nil if there + * is no write at this path. + */ +- (id)shadowingWriteAtPath:(FPath *)path { + return [self.writeTree shadowingWriteAtPath:[self.path child:path]]; +} + +/** + * This method is used when processing child remove events on a query. If we + * can, we pull in children that are outside the window, but may now be in the + * window. + */ +- (FNamedNode *)calculateNextNodeAfterPost:(FNamedNode *)post + completeServerData:(id)completeServerData + reverse:(BOOL)reverse + index:(id)index { + return [self.writeTree calculateNextNodeAfterPost:post + atPath:self.path + completeServerData:completeServerData + reverse:reverse + index:index]; +} + +/** + * Returns a complete child for a given server snap after applying all user + * writes or nil if there is no complete child for this child key. + */ +- (id)calculateCompleteChild:(NSString *)childKey + cache:(FCacheNode *)existingServerCache { + return [self.writeTree calculateCompleteChildAtPath:self.path + childKey:childKey + cache:existingServerCache]; +} + +/** + * @return a WriteTreeref for a child. + */ +- (FWriteTreeRef *)childWriteTreeRef:(NSString *)childKey { + return + [[FWriteTreeRef alloc] initWithPath:[self.path childFromString:childKey] + writeTree:self.writeTree]; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FAckUserWrite.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FAckUserWrite.h new file mode 100644 index 0000000..2d1223c --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FAckUserWrite.h @@ -0,0 +1,37 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Operation/FOperation.h" + +@class FPath; +@class FOperationSource; +@class FImmutableTree; + +@interface FAckUserWrite : NSObject + +- initWithPath:(FPath *)operationPath + affectedTree:(FImmutableTree *)affectedTree + revert:(BOOL)shouldRevert; + +@property(nonatomic, strong, readonly) FOperationSource *source; +@property(nonatomic, readonly) FOperationType type; +@property(nonatomic, strong, readonly) FPath *path; +// A FImmutableTree, containing @YES for each affected path. Affected paths +// can't overlap. +@property(nonatomic, strong, readonly) FImmutableTree *affectedTree; +@property(nonatomic, readonly) BOOL revert; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FAckUserWrite.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FAckUserWrite.m new file mode 100644 index 0000000..bf65f4d --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FAckUserWrite.m @@ -0,0 +1,66 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Operation/FAckUserWrite.h" +#import "FirebaseDatabase/Sources/Core/Operation/FOperationSource.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FImmutableTree.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" + +@implementation FAckUserWrite + +- (id)initWithPath:(FPath *)operationPath + affectedTree:(FImmutableTree *)tree + revert:(BOOL)shouldRevert { + self = [super init]; + if (self) { + self->_source = [FOperationSource userInstance]; + self->_type = FOperationTypeAckUserWrite; + self->_path = operationPath; + self->_affectedTree = tree; + self->_revert = shouldRevert; + } + return self; +} + +- (FAckUserWrite *)operationForChild:(NSString *)childKey { + if (![self.path isEmpty]) { + NSAssert([self.path.getFront isEqualToString:childKey], + @"operationForChild called for unrelated child."); + return [[FAckUserWrite alloc] initWithPath:[self.path popFront] + affectedTree:self.affectedTree + revert:self.revert]; + } else if (self.affectedTree.value != nil) { + NSAssert(self.affectedTree.children.isEmpty, + @"affectedTree should not have overlapping affected paths."); + // All child locations are affected as well; just return same operation. + return self; + } else { + FImmutableTree *childTree = + [self.affectedTree subtreeAtPath:[[FPath alloc] initWith:childKey]]; + return [[FAckUserWrite alloc] initWithPath:[FPath empty] + affectedTree:childTree + revert:self.revert]; + } +} + +- (NSString *)description { + return + [NSString stringWithFormat: + @"FAckUserWrite { path=%@, revert=%d, affectedTree=%@ }", + self.path, self.revert, self.affectedTree]; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FMerge.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FMerge.h new file mode 100644 index 0000000..9b6534d --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FMerge.h @@ -0,0 +1,32 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Operation/FOperation.h" + +@class FCompoundWrite; + +@interface FMerge : NSObject + +- (id)initWithSource:(FOperationSource *)aSource + path:(FPath *)aPath + children:(FCompoundWrite *)children; + +@property(nonatomic, strong, readonly) FOperationSource *source; +@property(nonatomic, readonly) FOperationType type; +@property(nonatomic, strong, readonly) FPath *path; +@property(nonatomic, strong, readonly) FCompoundWrite *children; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FMerge.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FMerge.m new file mode 100644 index 0000000..88cee3e --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FMerge.m @@ -0,0 +1,85 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Operation/FMerge.h" +#import "FirebaseDatabase/Sources/Core/Operation/FOperationSource.h" +#import "FirebaseDatabase/Sources/Core/Operation/FOverwrite.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Snapshot/FCompoundWrite.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" + +@interface FMerge () +@property(nonatomic, strong, readwrite) FOperationSource *source; +@property(nonatomic, readwrite) FOperationType type; +@property(nonatomic, strong, readwrite) FPath *path; +@property(nonatomic, strong) FCompoundWrite *children; +@end + +@implementation FMerge + +@synthesize source; +@synthesize type; +@synthesize path; +@synthesize children; + +- (id)initWithSource:(FOperationSource *)aSource + path:(FPath *)aPath + children:(FCompoundWrite *)someChildren { + self = [super init]; + if (self) { + self.source = aSource; + self.type = FOperationTypeMerge; + self.path = aPath; + self.children = someChildren; + } + return self; +} + +- (id)operationForChild:(NSString *)childKey { + if ([self.path isEmpty]) { + FCompoundWrite *childTree = [self.children + childCompoundWriteAtPath:[[FPath alloc] initWith:childKey]]; + if (childTree.isEmpty) { + return nil; + } else if (childTree.rootWrite != nil) { + // We have a snapshot for the child in question. This becomes an + // overwrite of the child. + return [[FOverwrite alloc] initWithSource:self.source + path:[FPath empty] + snap:childTree.rootWrite]; + } else { + // This is a merge at a deeper level + return [[FMerge alloc] initWithSource:self.source + path:[FPath empty] + children:childTree]; + } + } else { + NSAssert( + [self.path.getFront isEqualToString:childKey], + @"Can't get a merge for a child not on the path of the operation"); + return [[FMerge alloc] initWithSource:self.source + path:[self.path popFront] + children:self.children]; + } +} + +- (NSString *)description { + return + [NSString stringWithFormat:@"FMerge { path=%@, soruce=%@ children=%@}", + self.path, self.source, self.children]; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FOperation.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FOperation.h new file mode 100644 index 0000000..41f6054 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FOperation.h @@ -0,0 +1,34 @@ +/* + * 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 + +@class FOperationSource; +@class FPath; + +typedef NS_ENUM(NSInteger, FOperationType) { + FOperationTypeOverwrite = 0, + FOperationTypeMerge = 1, + FOperationTypeAckUserWrite = 2, + FOperationTypeListenComplete = 3 +}; + +@protocol FOperation +@property(nonatomic, strong, readonly) FOperationSource *source; +@property(nonatomic, readonly) FOperationType type; +@property(nonatomic, strong, readonly) FPath *path; +- (id)operationForChild:(NSString *)childKey; +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FOperationSource.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FOperationSource.h new file mode 100644 index 0000000..747487b --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FOperationSource.h @@ -0,0 +1,37 @@ +/* + * 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 + +@class FQueryParams; + +@interface FOperationSource : NSObject + +@property(nonatomic, readonly) BOOL fromUser; +@property(nonatomic, readonly) BOOL fromServer; +@property(nonatomic, readonly) BOOL isTagged; +@property(nonatomic, strong, readonly) FQueryParams *queryParams; + +- initWithFromUser:(BOOL)isFromUser + fromServer:(BOOL)isFromServer + queryParams:(FQueryParams *)params + tagged:(BOOL)isTagged; + ++ (FOperationSource *)userInstance; ++ (FOperationSource *)serverInstance; ++ (FOperationSource *)forServerTaggedQuery:(FQueryParams *)params; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FOperationSource.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FOperationSource.m new file mode 100644 index 0000000..ce23987 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FOperationSource.m @@ -0,0 +1,86 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Operation/FOperationSource.h" +#import "FirebaseDatabase/Sources/Core/FQueryParams.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" + +@interface FOperationSource () +@property(nonatomic, readwrite) BOOL fromUser; +@property(nonatomic, readwrite) BOOL fromServer; +@property(nonatomic, readwrite) BOOL isTagged; +@property(nonatomic, strong, readwrite) FQueryParams *queryParams; +@end + +@implementation FOperationSource + +@synthesize fromUser; +@synthesize fromServer; +@synthesize queryParams; + +- (id)initWithFromUser:(BOOL)isFromUser + fromServer:(BOOL)isFromServer + queryParams:(FQueryParams *)params + tagged:(BOOL)tagged { + self = [super init]; + if (self) { + self.fromUser = isFromUser; + self.fromServer = isFromServer; + self.queryParams = params; + self.isTagged = tagged; + } + return self; +} + ++ (FOperationSource *)userInstance { + static FOperationSource *user = nil; + static dispatch_once_t userToken; + dispatch_once(&userToken, ^{ + user = [[FOperationSource alloc] initWithFromUser:YES + fromServer:NO + queryParams:nil + tagged:NO]; + }); + return user; +} + ++ (FOperationSource *)serverInstance { + static FOperationSource *server = nil; + static dispatch_once_t serverToken; + dispatch_once(&serverToken, ^{ + server = [[FOperationSource alloc] initWithFromUser:NO + fromServer:YES + queryParams:nil + tagged:NO]; + }); + return server; +} + ++ (FOperationSource *)forServerTaggedQuery:(FQueryParams *)params { + return [[FOperationSource alloc] initWithFromUser:NO + fromServer:YES + queryParams:params + tagged:YES]; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"FOperationSource { fromUser=%d, " + @"fromServer=%d, queryId=%@, tagged=%d }", + self.fromUser, self.fromServer, + self.queryParams, self.isTagged]; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FOverwrite.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FOverwrite.h new file mode 100644 index 0000000..a828667 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FOverwrite.h @@ -0,0 +1,32 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Operation/FOperation.h" + +@protocol FNode; + +@interface FOverwrite : NSObject + +- (id)initWithSource:(FOperationSource *)aSource + path:(FPath *)aPath + snap:(id)aSnap; + +@property(nonatomic, strong, readonly) FOperationSource *source; +@property(nonatomic, readonly) FOperationType type; +@property(nonatomic, strong, readonly) FPath *path; +@property(nonatomic, strong, readonly) id snap; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FOverwrite.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FOverwrite.m new file mode 100644 index 0000000..7094028 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Operation/FOverwrite.m @@ -0,0 +1,67 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Operation/FOverwrite.h" +#import "FirebaseDatabase/Sources/Core/Operation/FOperationSource.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" + +@interface FOverwrite () +@property(nonatomic, strong, readwrite) FOperationSource *source; +@property(nonatomic, readwrite) FOperationType type; +@property(nonatomic, strong, readwrite) FPath *path; +@property(nonatomic, strong) id snap; +@end + +@implementation FOverwrite + +@synthesize source; +@synthesize type; +@synthesize path; +@synthesize snap; + +- (id)initWithSource:(FOperationSource *)aSource + path:(FPath *)aPath + snap:(id)aSnap { + self = [super init]; + if (self) { + self.source = aSource; + self.type = FOperationTypeOverwrite; + self.path = aPath; + self.snap = aSnap; + } + return self; +} + +- (FOverwrite *)operationForChild:(NSString *)childKey { + if ([self.path isEmpty]) { + return [[FOverwrite alloc] + initWithSource:self.source + path:[FPath empty] + snap:[self.snap getImmediateChild:childKey]]; + } else { + return [[FOverwrite alloc] initWithSource:self.source + path:[self.path popFront] + snap:self.snap]; + } +} + +- (NSString *)description { + return [NSString + stringWithFormat:@"FOverwrite { path=%@, source=%@, snapshot=%@ }", + self.path, self.source, self.snap]; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FIRRetryHelper.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FIRRetryHelper.h new file mode 100644 index 0000000..a63d0d8 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FIRRetryHelper.h @@ -0,0 +1,33 @@ +/* + * 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 + +@interface FIRRetryHelper : NSObject + +- (instancetype)initWithDispatchQueue:(dispatch_queue_t)dispatchQueue + minRetryDelayAfterFailure:(NSTimeInterval)minRetryDelayAfterFailure + maxRetryDelay:(NSTimeInterval)maxRetryDelay + retryExponent:(double)retryExponent + jitterFactor:(double)jitterFactor; + +- (void)retry:(void (^)(void))block; + +- (void)cancel; + +- (void)signalSuccess; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FIRRetryHelper.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FIRRetryHelper.m new file mode 100644 index 0000000..9accc54 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FIRRetryHelper.m @@ -0,0 +1,140 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Utilities/FIRRetryHelper.h" +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" + +@interface FIRRetryHelperTask : NSObject + +@property(nonatomic, strong) void (^block)(void); + +@end + +@implementation FIRRetryHelperTask + +- (instancetype)initWithBlock:(void (^)(void))block { + self = [super init]; + if (self != nil) { + self->_block = [block copy]; + } + return self; +} + +- (BOOL)isCanceled { + return self.block == nil; +} + +- (void)cancel { + self.block = nil; +} + +- (void)execute { + if (self.block) { + self.block(); + } +} + +@end + +@interface FIRRetryHelper () + +@property(nonatomic, strong) dispatch_queue_t dispatchQueue; +@property(nonatomic) NSTimeInterval minRetryDelayAfterFailure; +@property(nonatomic) NSTimeInterval maxRetryDelay; +@property(nonatomic) double retryExponent; +@property(nonatomic) double jitterFactor; + +@property(nonatomic) BOOL lastWasSuccess; +@property(nonatomic) NSTimeInterval currentRetryDelay; + +@property(nonatomic, strong) FIRRetryHelperTask *scheduledRetry; + +@end + +@implementation FIRRetryHelper + +- (instancetype)initWithDispatchQueue:(dispatch_queue_t)dispatchQueue + minRetryDelayAfterFailure:(NSTimeInterval)minRetryDelayAfterFailure + maxRetryDelay:(NSTimeInterval)maxRetryDelay + retryExponent:(double)retryExponent + jitterFactor:(double)jitterFactor { + self = [super init]; + if (self != nil) { + self->_dispatchQueue = dispatchQueue; + self->_minRetryDelayAfterFailure = minRetryDelayAfterFailure; + self->_maxRetryDelay = maxRetryDelay; + self->_retryExponent = retryExponent; + self->_jitterFactor = jitterFactor; + self->_lastWasSuccess = YES; + } + return self; +} + +- (void)retry:(void (^)(void))block { + if (self.scheduledRetry != nil) { + FFLog(@"I-RDB054001", @"Canceling existing retry attempt"); + [self.scheduledRetry cancel]; + self.scheduledRetry = nil; + } + + NSTimeInterval delay; + if (self.lastWasSuccess) { + delay = 0; + } else { + if (self.currentRetryDelay == 0) { + self.currentRetryDelay = self.minRetryDelayAfterFailure; + } else { + NSTimeInterval newDelay = + (self.currentRetryDelay * self.retryExponent); + self.currentRetryDelay = MIN(newDelay, self.maxRetryDelay); + } + + delay = ((1 - self.jitterFactor) * self.currentRetryDelay) + + (self.jitterFactor * self.currentRetryDelay * + [FUtilities randomDouble]); + FFLog(@"I-RDB054002", @"Scheduling retry in %fs", delay); + } + self.lastWasSuccess = NO; + FIRRetryHelperTask *task = [[FIRRetryHelperTask alloc] initWithBlock:block]; + self.scheduledRetry = task; + dispatch_time_t popTime = + dispatch_time(DISPATCH_TIME_NOW, (long long)(delay * NSEC_PER_SEC)); + dispatch_after(popTime, self.dispatchQueue, ^{ + if (![task isCanceled]) { + self.scheduledRetry = nil; + [task execute]; + } + }); +} + +- (void)signalSuccess { + self.lastWasSuccess = YES; + self.currentRetryDelay = 0; +} + +- (void)cancel { + if (self.scheduledRetry != nil) { + FFLog(@"I-RDB054003", @"Canceling existing retry attempt"); + [self.scheduledRetry cancel]; + self.scheduledRetry = nil; + } else { + FFLog(@"I-RDB054004", @"No existing retry attempt to cancel"); + } + self.currentRetryDelay = 0; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FImmutableTree.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FImmutableTree.h new file mode 100644 index 0000000..a08a440 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FImmutableTree.h @@ -0,0 +1,59 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Utilities/Tuples/FTuplePathValue.h" +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedDictionary.h" + +@interface FImmutableTree : NSObject + +- (id)initWithValue:(id)aValue; +- (id)initWithValue:(id)aValue + children:(FImmutableSortedDictionary *)childrenMap; + ++ (FImmutableTree *)empty; +- (BOOL)isEmpty; + +- (FTuplePathValue *)findRootMostMatchingPath:(FPath *)relativePath + predicate:(BOOL (^)(id))predicate; +- (FTuplePathValue *)findRootMostValueAndPath:(FPath *)relativePath; +- (FImmutableTree *)subtreeAtPath:(FPath *)relativePath; +- (FImmutableTree *)setValue:(id)newValue atPath:(FPath *)relativePath; +- (FImmutableTree *)removeValueAtPath:(FPath *)relativePath; +- (id)valueAtPath:(FPath *)relativePath; +- (id)rootMostValueOnPath:(FPath *)path; +- (id)rootMostValueOnPath:(FPath *)path matching:(BOOL (^)(id))predicate; +- (id)leafMostValueOnPath:(FPath *)path; +- (id)leafMostValueOnPath:(FPath *)relativePath + matching:(BOOL (^)(id))predicate; +- (BOOL)containsValueMatching:(BOOL (^)(id))predicate; +- (FImmutableTree *)setTree:(FImmutableTree *)newTree + atPath:(FPath *)relativePath; +- (id)foldWithBlock:(id (^)(FPath *path, id value, + NSDictionary *foldedChildren))block; +- (id)findOnPath:(FPath *)path + andApplyBlock:(id (^)(FPath *path, id value))block; +- (FPath *)forEachOnPath:(FPath *)path + whileBlock:(BOOL (^)(FPath *path, id value))block; +- (FImmutableTree *)forEachOnPath:(FPath *)path + performBlock:(void (^)(FPath *path, id value))block; +- (void)forEach:(void (^)(FPath *path, id value))block; +- (void)forEachChild:(void (^)(NSString *childKey, id childValue))block; + +@property(nonatomic, strong, readonly) id value; +@property(nonatomic, strong, readonly) FImmutableSortedDictionary *children; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FImmutableTree.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FImmutableTree.m new file mode 100644 index 0000000..fe8a924 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FImmutableTree.m @@ -0,0 +1,486 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Utilities/FImmutableTree.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedDictionary.h" + +@interface FImmutableTree () +@property(nonatomic, strong, readwrite) id value; +/** + * Maps NSString -> FImmutableTree, where is type of value. + */ +@property(nonatomic, strong, readwrite) FImmutableSortedDictionary *children; +@end + +@implementation FImmutableTree +@synthesize value; +@synthesize children; + +- (id)initWithValue:(id)aValue { + self = [super init]; + if (self) { + self.value = aValue; + self.children = [FImmutableTree emptyChildren]; + } + return self; +} + +- (id)initWithValue:(id)aValue + children:(FImmutableSortedDictionary *)childrenMap { + self = [super init]; + if (self) { + self.value = aValue; + self.children = childrenMap; + } + return self; +} + ++ (FImmutableSortedDictionary *)emptyChildren { + static dispatch_once_t emptyChildrenToken; + static FImmutableSortedDictionary *emptyChildren; + dispatch_once(&emptyChildrenToken, ^{ + emptyChildren = [FImmutableSortedDictionary + dictionaryWithComparator:[FUtilities stringComparator]]; + }); + return emptyChildren; +} + ++ (FImmutableTree *)empty { + static dispatch_once_t emptyImmutableTreeToken; + static FImmutableTree *emptyTree = nil; + dispatch_once(&emptyImmutableTreeToken, ^{ + emptyTree = [[FImmutableTree alloc] initWithValue:nil]; + }); + return emptyTree; +} + +- (BOOL)isEmpty { + return self.value == nil && [self.children isEmpty]; +} + +/** + * Given a path and a predicate, return the first node and the path to that node + * where the predicate returns true + * // TODO Do a perf test. If we're creating a bunch of FTuplePathValue objects + * on the way back out, it may be better to pass down a pathSoFar FPath + */ +- (FTuplePathValue *)findRootMostMatchingPath:(FPath *)relativePath + predicate:(BOOL (^)(id value))predicate { + if (self.value != nil && predicate(self.value)) { + return [[FTuplePathValue alloc] initWithPath:[FPath empty] + value:self.value]; + } else { + if ([relativePath isEmpty]) { + return nil; + } else { + NSString *front = [relativePath getFront]; + FImmutableTree *child = [self.children get:front]; + if (child != nil) { + FTuplePathValue *childExistingPathAndValue = + [child findRootMostMatchingPath:[relativePath popFront] + predicate:predicate]; + if (childExistingPathAndValue != nil) { + FPath *fullPath = [[[FPath alloc] initWith:front] + child:childExistingPathAndValue.path]; + return [[FTuplePathValue alloc] + initWithPath:fullPath + value:childExistingPathAndValue.value]; + } else { + return nil; + } + } else { + // No child matching path + return nil; + } + } + } +} + +/** + * Find, if it exists, the shortest subpath of the given path that points a + * defined value in the tree + */ +- (FTuplePathValue *)findRootMostValueAndPath:(FPath *)relativePath { + return [self findRootMostMatchingPath:relativePath + predicate:^BOOL(__unsafe_unretained id value) { + return YES; + }]; +} + +- (id)rootMostValueOnPath:(FPath *)path { + return [self rootMostValueOnPath:path + matching:^BOOL(id value) { + return YES; + }]; +} + +- (id)rootMostValueOnPath:(FPath *)path matching:(BOOL (^)(id))predicate { + if (self.value != nil && predicate(self.value)) { + return self.value; + } else if (path.isEmpty) { + return nil; + } else { + return [[self.children get:path.getFront] + rootMostValueOnPath:[path popFront] + matching:predicate]; + } +} + +- (id)leafMostValueOnPath:(FPath *)path { + return [self leafMostValueOnPath:path + matching:^BOOL(id value) { + return YES; + }]; +} + +- (id)leafMostValueOnPath:(FPath *)relativePath + matching:(BOOL (^)(id))predicate { + __block id currentValue = self.value; + __block FImmutableTree *currentTree = self; + [relativePath enumerateComponentsUsingBlock:^(NSString *key, BOOL *stop) { + currentTree = [currentTree.children get:key]; + if (currentTree == nil) { + *stop = YES; + } else { + id treeValue = currentTree.value; + if (treeValue != nil && predicate(treeValue)) { + currentValue = treeValue; + } + } + }]; + return currentValue; +} + +- (BOOL)containsValueMatching:(BOOL (^)(id))predicate { + if (self.value != nil && predicate(self.value)) { + return YES; + } else { + __block BOOL found = NO; + [self.children enumerateKeysAndObjectsUsingBlock:^( + NSString *key, FImmutableTree *subtree, BOOL *stop) { + found = [subtree containsValueMatching:predicate]; + if (found) + *stop = YES; + }]; + return found; + } +} + +- (FImmutableTree *)subtreeAtPath:(FPath *)relativePath { + if ([relativePath isEmpty]) { + return self; + } else { + NSString *front = [relativePath getFront]; + FImmutableTree *childTree = [self.children get:front]; + if (childTree != nil) { + return [childTree subtreeAtPath:[relativePath popFront]]; + } else { + return [FImmutableTree empty]; + } + } +} + +/** + * Sets a value at the specified path + */ +- (FImmutableTree *)setValue:(id)newValue atPath:(FPath *)relativePath { + if ([relativePath isEmpty]) { + return [[FImmutableTree alloc] initWithValue:newValue + children:self.children]; + } else { + NSString *front = [relativePath getFront]; + FImmutableTree *child = [self.children get:front]; + if (child == nil) { + child = [FImmutableTree empty]; + } + FImmutableTree *newChild = [child setValue:newValue + atPath:[relativePath popFront]]; + FImmutableSortedDictionary *newChildren = + [self.children insertKey:front withValue:newChild]; + return [[FImmutableTree alloc] initWithValue:self.value + children:newChildren]; + } +} + +/** + * Remove the value at the specified path + */ +- (FImmutableTree *)removeValueAtPath:(FPath *)relativePath { + if ([relativePath isEmpty]) { + if ([self.children isEmpty]) { + return [FImmutableTree empty]; + } else { + return [[FImmutableTree alloc] initWithValue:nil + children:self.children]; + } + } else { + NSString *front = [relativePath getFront]; + FImmutableTree *child = [self.children get:front]; + if (child) { + FImmutableTree *newChild = + [child removeValueAtPath:[relativePath popFront]]; + FImmutableSortedDictionary *newChildren; + if ([newChild isEmpty]) { + newChildren = [self.children removeKey:front]; + } else { + newChildren = [self.children insertKey:front + withValue:newChild]; + } + if (self.value == nil && [newChildren isEmpty]) { + return [FImmutableTree empty]; + } else { + return [[FImmutableTree alloc] initWithValue:self.value + children:newChildren]; + } + } else { + return self; + } + } +} + +/** + * Gets a value from the tree + */ +- (id)valueAtPath:(FPath *)relativePath { + if ([relativePath isEmpty]) { + return self.value; + } else { + NSString *front = [relativePath getFront]; + FImmutableTree *child = [self.children get:front]; + if (child) { + return [child valueAtPath:[relativePath popFront]]; + } else { + return nil; + } + } +} + +/** + * Replaces the subtree at the specified path with the given new tree + */ +- (FImmutableTree *)setTree:(FImmutableTree *)newTree + atPath:(FPath *)relativePath { + if ([relativePath isEmpty]) { + return newTree; + } else { + NSString *front = [relativePath getFront]; + FImmutableTree *child = [self.children get:front]; + if (child == nil) { + child = [FImmutableTree empty]; + } + FImmutableTree *newChild = [child setTree:newTree + atPath:[relativePath popFront]]; + FImmutableSortedDictionary *newChildren; + if ([newChild isEmpty]) { + newChildren = [self.children removeKey:front]; + } else { + newChildren = [self.children insertKey:front withValue:newChild]; + } + return [[FImmutableTree alloc] initWithValue:self.value + children:newChildren]; + } +} + +/** + * Performs a depth first fold on this tree. Transforms a tree into a single + * value, given a function that operates on the path to a node, an optional + * current value, and a map of the child names to folded subtrees + */ +- (id)foldWithBlock:(id (^)(FPath *path, id value, + NSDictionary *foldedChildren))block { + return [self foldWithPathSoFar:[FPath empty] withBlock:block]; +} + +/** + * Recursive helper for public facing foldWithBlock: method + */ +- (id)foldWithPathSoFar:(FPath *)pathSoFar + withBlock:(id (^)(FPath *path, id value, + NSDictionary *foldedChildren))block { + __block NSMutableDictionary *accum = [[NSMutableDictionary alloc] init]; + [self.children + enumerateKeysAndObjectsUsingBlock:^( + NSString *childKey, FImmutableTree *childTree, BOOL *stop) { + accum[childKey] = + [childTree foldWithPathSoFar:[pathSoFar childFromString:childKey] + withBlock:block]; + }]; + return block(pathSoFar, self.value, accum); +} + +/** + * Find the first matching value on the given path. Return the result of + * applying block to it. + */ +- (id)findOnPath:(FPath *)path + andApplyBlock:(id (^)(FPath *path, id value))block { + return [self findOnPath:path pathSoFar:[FPath empty] andApplyBlock:block]; +} + +- (id)findOnPath:(FPath *)pathToFollow + pathSoFar:(FPath *)pathSoFar + andApplyBlock:(id (^)(FPath *path, id value))block { + id result = self.value ? block(pathSoFar, self.value) : nil; + if (result != nil) { + return result; + } else { + if ([pathToFollow isEmpty]) { + return nil; + } else { + NSString *front = [pathToFollow getFront]; + FImmutableTree *nextChild = [self.children get:front]; + if (nextChild != nil) { + return [nextChild findOnPath:[pathToFollow popFront] + pathSoFar:[pathSoFar childFromString:front] + andApplyBlock:block]; + } else { + return nil; + } + } + } +} +/** + * Call the block on each value along the path for as long as that function + * returns true + * @return The path to the deepest location inspected + */ +- (FPath *)forEachOnPath:(FPath *)path whileBlock:(BOOL (^)(FPath *, id))block { + return [self forEachOnPath:path pathSoFar:[FPath empty] whileBlock:block]; +} + +- (FPath *)forEachOnPath:(FPath *)pathToFollow + pathSoFar:(FPath *)pathSoFar + whileBlock:(BOOL (^)(FPath *, id))block { + if ([pathToFollow isEmpty]) { + if (self.value) { + block(pathSoFar, self.value); + } + return pathSoFar; + } else { + BOOL shouldContinue = YES; + if (self.value) { + shouldContinue = block(pathSoFar, self.value); + } + if (shouldContinue) { + NSString *front = [pathToFollow getFront]; + FImmutableTree *nextChild = [self.children get:front]; + if (nextChild) { + return + [nextChild forEachOnPath:[pathToFollow popFront] + pathSoFar:[pathSoFar childFromString:front] + whileBlock:block]; + } else { + return pathSoFar; + } + } else { + return pathSoFar; + } + } +} + +- (FImmutableTree *)forEachOnPath:(FPath *)path + performBlock:(void (^)(FPath *path, id value))block { + return [self forEachOnPath:path pathSoFar:[FPath empty] performBlock:block]; +} + +- (FImmutableTree *)forEachOnPath:(FPath *)pathToFollow + pathSoFar:(FPath *)pathSoFar + performBlock:(void (^)(FPath *path, id value))block { + if ([pathToFollow isEmpty]) { + return self; + } else { + if (self.value) { + block(pathSoFar, self.value); + } + NSString *front = [pathToFollow getFront]; + FImmutableTree *nextChild = [self.children get:front]; + if (nextChild) { + return [nextChild forEachOnPath:[pathToFollow popFront] + pathSoFar:[pathSoFar childFromString:front] + performBlock:block]; + } else { + return [FImmutableTree empty]; + } + } +} +/** + * Calls the given block for each node in the tree that has a value. Called in + * depth-first order + */ +- (void)forEach:(void (^)(FPath *path, id value))block { + [self forEachPathSoFar:[FPath empty] withBlock:block]; +} + +- (void)forEachPathSoFar:(FPath *)pathSoFar + withBlock:(void (^)(FPath *path, id value))block { + [self.children + enumerateKeysAndObjectsUsingBlock:^( + NSString *childKey, FImmutableTree *childTree, BOOL *stop) { + [childTree forEachPathSoFar:[pathSoFar childFromString:childKey] + withBlock:block]; + }]; + if (self.value) { + block(pathSoFar, self.value); + } +} + +- (void)forEachChild:(void (^)(NSString *childKey, id childValue))block { + [self.children + enumerateKeysAndObjectsUsingBlock:^( + NSString *childKey, FImmutableTree *childTree, BOOL *stop) { + if (childTree.value) { + block(childKey, childTree.value); + } + }]; +} + +- (BOOL)isEqual:(id)object { + if (![object isKindOfClass:[FImmutableTree class]]) { + return NO; + } + FImmutableTree *other = (FImmutableTree *)object; + return (self.value == other.value || [self.value isEqual:other.value]) && + [self.children isEqual:other.children]; +} + +- (NSUInteger)hash { + return self.children.hash * 31 + [self.value hash]; +} + +- (NSString *)description { + NSMutableString *string = [[NSMutableString alloc] init]; + [string appendString:@"FImmutableTree { value="]; + [string appendString:(self.value ? [self.value description] : @"")]; + [string appendString:@", children={"]; + [self.children + enumerateKeysAndObjectsUsingBlock:^( + NSString *childKey, FImmutableTree *childTree, BOOL *stop) { + [string appendString:@" "]; + [string appendString:childKey]; + [string appendString:@"="]; + [string appendString:[childTree.value description]]; + }]; + [string appendString:@" } }"]; + return [NSString stringWithString:string]; +} + +- (NSString *)debugDescription { + return [self description]; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FPath.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FPath.h new file mode 100644 index 0000000..cfa86aa --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FPath.h @@ -0,0 +1,46 @@ +/* + * 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 + +@interface FPath : NSObject + ++ (FPath *)relativePathFrom:(FPath *)outer to:(FPath *)inner; ++ (FPath *)empty; ++ (FPath *)pathWithString:(NSString *)string; + +- (id)initWith:(NSString *)path; +- (id)initWithPieces:(NSArray *)somePieces andPieceNum:(NSInteger)aPieceNum; + +- (id)copyWithZone:(NSZone *)zone; + +- (void)enumerateComponentsUsingBlock:(void (^)(NSString *key, + BOOL *stop))block; +- (NSString *)getFront; +- (NSUInteger)length; +- (FPath *)popFront; +- (NSString *)getBack; +- (NSString *)toString; +- (NSString *)toStringWithTrailingSlash; +- (NSString *)wireFormat; +- (FPath *)parent; +- (FPath *)child:(FPath *)childPathObj; +- (FPath *)childFromString:(NSString *)childPath; +- (BOOL)isEmpty; +- (BOOL)contains:(FPath *)other; +- (NSComparisonResult)compare:(FPath *)other; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FPath.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FPath.m new file mode 100644 index 0000000..0fa734b --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FPath.m @@ -0,0 +1,304 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Utilities/FPath.h" + +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" + +@interface FPath () + +@property(nonatomic, readwrite, assign) NSInteger pieceNum; +@property(nonatomic, strong) NSArray *pieces; + +@end + +@implementation FPath + +#pragma mark - +#pragma mark Initializers + ++ (FPath *)relativePathFrom:(FPath *)outer to:(FPath *)inner { + NSString *outerFront = [outer getFront]; + NSString *innerFront = [inner getFront]; + if (outerFront == nil) { + return inner; + } else if ([outerFront isEqualToString:innerFront]) { + return [self relativePathFrom:[outer popFront] to:[inner popFront]]; + } else { + @throw [[NSException alloc] + initWithName:@"FirebaseDatabaseInternalError" + reason:[NSString + stringWithFormat: + @"innerPath (%@) is not within outerPath (%@)", + inner, outer] + userInfo:nil]; + } +} + ++ (FPath *)pathWithString:(NSString *)string { + return [[FPath alloc] initWith:string]; +} + +- (id)initWith:(NSString *)path { + self = [super init]; + if (self) { + NSArray *pathPieces = [path componentsSeparatedByString:@"/"]; + NSMutableArray *newPieces = [[NSMutableArray alloc] init]; + for (NSInteger i = 0; i < pathPieces.count; i++) { + NSString *piece = [pathPieces objectAtIndex:i]; + if (piece.length > 0) { + [newPieces addObject:piece]; + } + } + + self.pieces = newPieces; + self.pieceNum = 0; + } + return self; +} + +- (id)initWithPieces:(NSArray *)somePieces andPieceNum:(NSInteger)aPieceNum { + self = [super init]; + if (self) { + self.pieceNum = aPieceNum; + self.pieces = somePieces; + } + return self; +} + +- (id)copyWithZone:(NSZone *)zone { + // Immutable, so it's safe to return self + return self; +} + +- (NSString *)description { + return [self toString]; +} + +#pragma mark - +#pragma mark Public methods + +- (NSString *)getFront { + if (self.pieceNum >= self.pieces.count) { + return nil; + } + return [self.pieces objectAtIndex:self.pieceNum]; +} + +/** + * @return The number of segments in this path + */ +- (NSUInteger)length { + return self.pieces.count - self.pieceNum; +} + +- (FPath *)popFront { + NSInteger newPieceNum = self.pieceNum; + if (newPieceNum < self.pieces.count) { + newPieceNum++; + } + return [[FPath alloc] initWithPieces:self.pieces andPieceNum:newPieceNum]; +} + +- (NSString *)getBack { + if (self.pieceNum < self.pieces.count) { + return [self.pieces lastObject]; + } else { + return nil; + } +} + +- (NSString *)toString { + return [self toStringWithTrailingSlash:NO]; +} + +- (NSString *)toStringWithTrailingSlash { + return [self toStringWithTrailingSlash:YES]; +} + +- (NSString *)toStringWithTrailingSlash:(BOOL)trailingSlash { + NSMutableString *pathString = [[NSMutableString alloc] init]; + for (NSInteger i = self.pieceNum; i < self.pieces.count; i++) { + [pathString appendString:@"/"]; + [pathString appendString:[self.pieces objectAtIndex:i]]; + } + if ([pathString length] == 0) { + return @"/"; + } else { + if (trailingSlash) { + [pathString appendString:@"/"]; + } + return pathString; + } +} + +- (NSString *)wireFormat { + if ([self isEmpty]) { + return @"/"; + } else { + NSMutableString *pathString = [[NSMutableString alloc] init]; + for (NSInteger i = self.pieceNum; i < self.pieces.count; i++) { + if (i > self.pieceNum) { + [pathString appendString:@"/"]; + } + [pathString appendString:[self.pieces objectAtIndex:i]]; + } + return pathString; + } +} + +- (FPath *)parent { + if (self.pieceNum >= self.pieces.count) { + return nil; + } else { + NSMutableArray *newPieces = [[NSMutableArray alloc] init]; + for (NSInteger i = self.pieceNum; i < self.pieces.count - 1; i++) { + [newPieces addObject:[self.pieces objectAtIndex:i]]; + } + return [[FPath alloc] initWithPieces:newPieces andPieceNum:0]; + } +} + +- (FPath *)child:(FPath *)childPathObj { + NSMutableArray *newPieces = [[NSMutableArray alloc] init]; + for (NSInteger i = self.pieceNum; i < self.pieces.count; i++) { + [newPieces addObject:[self.pieces objectAtIndex:i]]; + } + + for (NSInteger i = childPathObj.pieceNum; i < childPathObj.pieces.count; + i++) { + [newPieces addObject:[childPathObj.pieces objectAtIndex:i]]; + } + + return [[FPath alloc] initWithPieces:newPieces andPieceNum:0]; +} + +- (FPath *)childFromString:(NSString *)childPath { + NSMutableArray *newPieces = [[NSMutableArray alloc] init]; + for (NSInteger i = self.pieceNum; i < self.pieces.count; i++) { + [newPieces addObject:[self.pieces objectAtIndex:i]]; + } + + NSArray *pathPieces = [childPath componentsSeparatedByString:@"/"]; + for (unsigned int i = 0; i < pathPieces.count; i++) { + NSString *piece = [pathPieces objectAtIndex:i]; + if (piece.length > 0) { + [newPieces addObject:piece]; + } + } + + return [[FPath alloc] initWithPieces:newPieces andPieceNum:0]; +} + +/** + * @return True if there are no segments in this path + */ +- (BOOL)isEmpty { + return self.pieceNum >= self.pieces.count; +} + +/** + * @return Singleton to represent an empty path + */ ++ (FPath *)empty { + static dispatch_once_t oneEmptyPath; + static FPath *emptyPath; + dispatch_once(&oneEmptyPath, ^{ + emptyPath = [[FPath alloc] initWith:@""]; + }); + return emptyPath; +} + +- (BOOL)contains:(FPath *)other { + if (self.length > other.length) { + return NO; + } + + NSInteger i = self.pieceNum; + NSInteger j = other.pieceNum; + while (i < self.pieces.count) { + NSString *thisSeg = [self.pieces objectAtIndex:i]; + NSString *otherSeg = [other.pieces objectAtIndex:j]; + if (![thisSeg isEqualToString:otherSeg]) { + return NO; + } + ++i; + ++j; + } + return YES; +} + +- (void)enumerateComponentsUsingBlock:(void (^)(NSString *, BOOL *))block { + BOOL stop = NO; + for (NSInteger i = self.pieceNum; !stop && i < self.pieces.count; i++) { + block(self.pieces[i], &stop); + } +} + +- (NSComparisonResult)compare:(FPath *)other { + NSInteger myCount = self.pieces.count; + NSInteger otherCount = other.pieces.count; + for (NSInteger i = self.pieceNum, j = other.pieceNum; + i < myCount && j < otherCount; i++, j++) { + NSComparisonResult comparison = [FUtilities compareKey:self.pieces[i] + toKey:other.pieces[j]]; + if (comparison != NSOrderedSame) { + return comparison; + } + } + if (self.length < other.length) { + return NSOrderedAscending; + } else if (other.length < self.length) { + return NSOrderedDescending; + } else { + NSAssert(self.length == other.length, + @"Paths must be the same lengths"); + return NSOrderedSame; + } +} + +/** + * @return YES if paths are the same + */ +- (BOOL)isEqual:(id)other { + if (other == self) { + return YES; + } + if (!other || ![other isKindOfClass:[self class]]) { + return NO; + } + FPath *otherPath = (FPath *)other; + if (self.length != otherPath.length) { + return NO; + } + for (NSUInteger i = self.pieceNum, j = otherPath.pieceNum; + i < self.pieces.count; i++, j++) { + if (![self.pieces[i] isEqualToString:otherPath.pieces[j]]) { + return NO; + } + } + return YES; +} + +- (NSUInteger)hash { + NSUInteger hashCode = 0; + for (NSInteger i = self.pieceNum; i < self.pieces.count; i++) { + hashCode = hashCode * 37 + [self.pieces[i] hash]; + } + return hashCode; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FTree.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FTree.h new file mode 100644 index 0000000..7eea6bf --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FTree.h @@ -0,0 +1,52 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FTreeNode.h" +#import + +@interface FTree : NSObject + +- (id)init; +- (id)initWithName:(NSString *)aName + withParent:(FTree *)aParent + withNode:(FTreeNode *)aNode; + +- (FTree *)subTree:(FPath *)path; +- (id)getValue; +- (void)setValue:(id)value; +- (void)clear; +- (BOOL)hasChildren; +- (BOOL)isEmpty; +- (void)forEachChildMutationSafe:(void (^)(FTree *))action; +- (void)forEachChild:(void (^)(FTree *))action; +- (void)forEachDescendant:(void (^)(FTree *))action; +- (void)forEachDescendant:(void (^)(FTree *))action + includeSelf:(BOOL)incSelf + childrenFirst:(BOOL)childFirst; +- (BOOL)forEachAncestor:(BOOL (^)(FTree *))action; +- (BOOL)forEachAncestor:(BOOL (^)(FTree *))action includeSelf:(BOOL)incSelf; +- (void)forEachImmediateDescendantWithValue:(void (^)(FTree *))action; +- (BOOL)valueExistsAtOrAbove:(FPath *)path; +- (FPath *)path; +- (void)updateParents; +- (void)updateChild:(NSString *)childName withNode:(FTree *)child; + +@property(nonatomic, strong) NSString *name; +@property(nonatomic, strong) FTree *parent; +@property(nonatomic, strong) FTreeNode *node; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FTree.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FTree.m new file mode 100644 index 0000000..4eabb08 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FTree.m @@ -0,0 +1,193 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Utilities/FTree.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FTreeNode.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" + +@implementation FTree + +@synthesize name; +@synthesize parent; +@synthesize node; + +- (id)init { + self = [super init]; + if (self) { + self.name = @""; + self.parent = nil; + self.node = [[FTreeNode alloc] init]; + } + return self; +} + +- (id)initWithName:(NSString *)aName + withParent:(FTree *)aParent + withNode:(FTreeNode *)aNode { + self = [super init]; + if (self) { + self.name = aName != nil ? aName : @""; + self.parent = aParent != nil ? aParent : nil; + self.node = aNode != nil ? aNode : [[FTreeNode alloc] init]; + } + return self; +} + +- (FTree *)subTree:(FPath *)path { + FTree *child = self; + NSString *next = [path getFront]; + while (next != nil) { + FTreeNode *childNode = child.node.children[next]; + if (childNode == nil) { + childNode = [[FTreeNode alloc] init]; + } + child = [[FTree alloc] initWithName:next + withParent:child + withNode:childNode]; + path = [path popFront]; + next = [path getFront]; + } + return child; +} + +- (id)getValue { + return self.node.value; +} + +- (void)setValue:(id)value { + self.node.value = value; + [self updateParents]; +} + +- (void)clear { + self.node.value = nil; + [self.node.children removeAllObjects]; + self.node.childCount = 0; + [self updateParents]; +} + +- (BOOL)hasChildren { + return self.node.childCount > 0; +} + +- (BOOL)isEmpty { + return [self getValue] == nil && ![self hasChildren]; +} + +- (void)forEachChild:(void (^)(FTree *))action { + for (NSString *key in self.node.children) { + action([[FTree alloc] + initWithName:key + withParent:self + withNode:[self.node.children objectForKey:key]]); + } +} + +- (void)forEachChildMutationSafe:(void (^)(FTree *))action { + for (NSString *key in [self.node.children copy]) { + action([[FTree alloc] + initWithName:key + withParent:self + withNode:[self.node.children objectForKey:key]]); + } +} + +- (void)forEachDescendant:(void (^)(FTree *))action { + [self forEachDescendant:action includeSelf:NO childrenFirst:NO]; +} + +- (void)forEachDescendant:(void (^)(FTree *))action + includeSelf:(BOOL)incSelf + childrenFirst:(BOOL)childFirst { + if (incSelf && !childFirst) { + action(self); + } + + [self forEachChild:^(FTree *child) { + [child forEachDescendant:action includeSelf:YES childrenFirst:childFirst]; + }]; + + if (incSelf && childFirst) { + action(self); + } +} + +- (BOOL)forEachAncestor:(BOOL (^)(FTree *))action { + return [self forEachAncestor:action includeSelf:NO]; +} + +- (BOOL)forEachAncestor:(BOOL (^)(FTree *))action includeSelf:(BOOL)incSelf { + FTree *aNode = (incSelf) ? self : self.parent; + while (aNode != nil) { + if (action(aNode)) { + return YES; + } + aNode = aNode.parent; + } + return NO; +} + +- (void)forEachImmediateDescendantWithValue:(void (^)(FTree *))action { + [self forEachChild:^(FTree *child) { + if ([child getValue] != nil) { + action(child); + } else { + [child forEachImmediateDescendantWithValue:action]; + } + }]; +} + +- (BOOL)valueExistsAtOrAbove:(FPath *)path { + FTreeNode *aNode = self.node; + while (aNode != nil) { + if (aNode.value != nil) { + return YES; + } + aNode = [aNode.children objectForKey:path.getFront]; + path = [path popFront]; + } + // XXX Check with Michael if this is correct; deviates from JS. + return NO; +} + +- (FPath *)path { + return [[FPath alloc] + initWith:(self.parent == nil) + ? self.name + : [NSString stringWithFormat:@"%@/%@", [self.parent path], + self.name]]; +} + +- (void)updateParents { + [self.parent updateChild:self.name withNode:self]; +} + +- (void)updateChild:(NSString *)childName withNode:(FTree *)child { + BOOL childEmpty = [child isEmpty]; + BOOL childExists = self.node.children[childName] != nil; + if (childEmpty && childExists) { + [self.node.children removeObjectForKey:childName]; + self.node.childCount = self.node.childCount - 1; + [self updateParents]; + } else if (!childEmpty && !childExists) { + [self.node.children setObject:child.node forKey:childName]; + self.node.childCount = self.node.childCount + 1; + [self updateParents]; + } +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FTreeNode.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FTreeNode.h new file mode 100644 index 0000000..549f3b1 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FTreeNode.h @@ -0,0 +1,25 @@ +/* + * 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 + +@interface FTreeNode : NSObject + +@property(nonatomic, strong) NSMutableDictionary *children; +@property(nonatomic, readwrite, assign) int childCount; +@property(nonatomic, strong) id value; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FTreeNode.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FTreeNode.m new file mode 100644 index 0000000..cfd3fa4 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/Utilities/FTreeNode.m @@ -0,0 +1,35 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Utilities/FTreeNode.h" + +@implementation FTreeNode + +@synthesize children; +@synthesize childCount; +@synthesize value; + +- (id)init { + self = [super init]; + if (self) { + self.children = [[NSMutableDictionary alloc] init]; + self.childCount = 0; + self.value = nil; + } + return self; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FCacheNode.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FCacheNode.h new file mode 100644 index 0000000..eff0cb0 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FCacheNode.h @@ -0,0 +1,46 @@ +/* + * 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 + +@protocol FNode; +@class FIndexedNode; +@class FPath; + +/** + * A cache node only stores complete children. Additionally it holds a flag + * whether the node can be considered fully initialized in the sense that we + * know at one point in time, this represented a valid state of the world, e.g. + * initialized with data from the server, or a complete overwrite by the client. + * It is not necessarily complete because it may have been from a tagged query. + * The filtered flag also tracks whether a node potentially had children removed + * due to a filter. + */ +@interface FCacheNode : NSObject + +- (id)initWithIndexedNode:(FIndexedNode *)indexedNode + isFullyInitialized:(BOOL)fullyInitialized + isFiltered:(BOOL)filtered; + +- (BOOL)isCompleteForPath:(FPath *)path; +- (BOOL)isCompleteForChild:(NSString *)childKey; + +@property(nonatomic, readonly) BOOL isFullyInitialized; +@property(nonatomic, readonly) BOOL isFiltered; +@property(nonatomic, strong, readonly) FIndexedNode *indexedNode; +@property(nonatomic, strong, readonly) id node; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FCacheNode.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FCacheNode.m new file mode 100644 index 0000000..6129995 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FCacheNode.m @@ -0,0 +1,60 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/FCacheNode.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FIndexedNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" + +@interface FCacheNode () +@property(nonatomic, readwrite) BOOL isFullyInitialized; +@property(nonatomic, readwrite) BOOL isFiltered; +@property(nonatomic, strong, readwrite) FIndexedNode *indexedNode; +@end + +@implementation FCacheNode +- (id)initWithIndexedNode:(FIndexedNode *)indexedNode + isFullyInitialized:(BOOL)fullyInitialized + isFiltered:(BOOL)filtered { + self = [super init]; + if (self) { + self.indexedNode = indexedNode; + self.isFullyInitialized = fullyInitialized; + self.isFiltered = filtered; + } + return self; +} + +- (BOOL)isCompleteForPath:(FPath *)path { + if (path.isEmpty) { + return self.isFullyInitialized && !self.isFiltered; + } else { + NSString *childKey = [path getFront]; + return [self isCompleteForChild:childKey]; + } +} + +- (BOOL)isCompleteForChild:(NSString *)childKey { + return (self.isFullyInitialized && !self.isFiltered) || + [self.node hasChild:childKey]; +} + +- (id)node { + return self.indexedNode.node; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FCancelEvent.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FCancelEvent.h new file mode 100644 index 0000000..bd762b8 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FCancelEvent.h @@ -0,0 +1,31 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/FEvent.h" +#import + +@protocol FEventRegistration; + +@interface FCancelEvent : NSObject + +- initWithEventRegistration:(id)eventRegistration + error:(NSError *)error + path:(FPath *)path; + +@property(nonatomic, strong, readonly) NSError *error; +@property(nonatomic, strong, readonly) FPath *path; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FCancelEvent.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FCancelEvent.m new file mode 100644 index 0000000..1ddd436 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FCancelEvent.m @@ -0,0 +1,57 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/FCancelEvent.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Core/View/FEventRegistration.h" + +@interface FCancelEvent () +@property(nonatomic, strong) id eventRegistration; +@property(nonatomic, strong, readwrite) NSError *error; +@property(nonatomic, strong, readwrite) FPath *path; +@end + +@implementation FCancelEvent + +@synthesize eventRegistration; +@synthesize error; +@synthesize path; + +- (id)initWithEventRegistration:(id)registration + error:(NSError *)anError + path:(FPath *)aPath { + self = [super init]; + if (self) { + self.eventRegistration = registration; + self.error = anError; + self.path = aPath; + } + return self; +} + +- (void)fireEventOnQueue:(dispatch_queue_t)queue { + [self.eventRegistration fireEvent:self queue:queue]; +} + +- (BOOL)isCancelEvent { + return YES; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"%@: cancel", self.path]; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FChange.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FChange.h new file mode 100644 index 0000000..7fbdfbe --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FChange.h @@ -0,0 +1,41 @@ +/* + * 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 "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseReference.h" +#import "FirebaseDatabase/Sources/Snapshot/FIndexedNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" +#import + +@interface FChange : NSObject + +@property(nonatomic, readonly) FIRDataEventType type; +@property(nonatomic, strong, readonly) FIndexedNode *indexedNode; +@property(nonatomic, strong, readonly) NSString *childKey; +@property(nonatomic, strong, readonly) NSString *prevKey; +@property(nonatomic, strong, readonly) FIndexedNode *oldIndexedNode; + +- (id)initWithType:(FIRDataEventType)type + indexedNode:(FIndexedNode *)indexedNode; +- (id)initWithType:(FIRDataEventType)type + indexedNode:(FIndexedNode *)indexedNode + childKey:(NSString *)childKey; +- (id)initWithType:(FIRDataEventType)type + indexedNode:(FIndexedNode *)indexedNode + childKey:(NSString *)childKey + oldIndexedNode:(FIndexedNode *)oldIndexedNode; + +- (FChange *)changeWithPrevKey:(NSString *)prevKey; +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FChange.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FChange.m new file mode 100644 index 0000000..e67d078 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FChange.m @@ -0,0 +1,72 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/FChange.h" + +@interface FChange () + +@property(nonatomic, strong, readwrite) NSString *prevKey; + +@end + +@implementation FChange + +- (id)initWithType:(FIRDataEventType)type + indexedNode:(FIndexedNode *)indexedNode { + return [self initWithType:type + indexedNode:indexedNode + childKey:nil + oldIndexedNode:nil]; +} + +- (id)initWithType:(FIRDataEventType)type + indexedNode:(FIndexedNode *)indexedNode + childKey:(NSString *)childKey { + return [self initWithType:type + indexedNode:indexedNode + childKey:childKey + oldIndexedNode:nil]; +} + +- (id)initWithType:(FIRDataEventType)type + indexedNode:(FIndexedNode *)indexedNode + childKey:(NSString *)childKey + oldIndexedNode:(FIndexedNode *)oldIndexedNode { + self = [super init]; + if (self != nil) { + self->_type = type; + self->_indexedNode = indexedNode; + self->_childKey = childKey; + self->_oldIndexedNode = oldIndexedNode; + } + return self; +} + +- (FChange *)changeWithPrevKey:(NSString *)prevKey { + FChange *newChange = [[FChange alloc] initWithType:self.type + indexedNode:self.indexedNode + childKey:self.childKey + oldIndexedNode:self.oldIndexedNode]; + newChange.prevKey = prevKey; + return newChange; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"event: %d, data: %@", (int)self.type, + [self.indexedNode.node val]]; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FChildEventRegistration.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FChildEventRegistration.h new file mode 100644 index 0000000..d7d200d --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FChildEventRegistration.h @@ -0,0 +1,37 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/FEventRegistration.h" +#import "FirebaseDatabase/Sources/Utilities/FTypedefs.h" +#import + +@class FRepo; + +@interface FChildEventRegistration : NSObject + +- (id)initWithRepo:(FRepo *)repo + handle:(FIRDatabaseHandle)fHandle + callbacks:(NSDictionary *)callbackBlocks + cancelCallback:(fbt_void_nserror)cancelCallbackBlock; + +/** + * Maps FIRDataEventType (as NSNumber) to fbt_void_datasnapshot_nsstring + */ +@property(nonatomic, copy, readonly) NSDictionary *callbacks; +@property(nonatomic, copy, readonly) fbt_void_nserror cancelCallback; +@property(nonatomic, readonly) FIRDatabaseHandle handle; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FChildEventRegistration.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FChildEventRegistration.m new file mode 100644 index 0000000..d3b19f5 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FChildEventRegistration.m @@ -0,0 +1,112 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/FChildEventRegistration.h" +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDataSnapshot_Private.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h" +#import "FirebaseDatabase/Sources/Core/FQueryParams.h" +#import "FirebaseDatabase/Sources/Core/FQuerySpec.h" +#import "FirebaseDatabase/Sources/Core/View/FCancelEvent.h" +#import "FirebaseDatabase/Sources/Core/View/FDataEvent.h" + +@interface FChildEventRegistration () +@property(nonatomic, strong) FRepo *repo; +@property(nonatomic, copy, readwrite) NSDictionary *callbacks; +@property(nonatomic, copy, readwrite) fbt_void_nserror cancelCallback; +@property(nonatomic, readwrite) FIRDatabaseHandle handle; +@end + +@implementation FChildEventRegistration + +- (id)initWithRepo:(id)repo + handle:(FIRDatabaseHandle)fHandle + callbacks:(NSDictionary *)callbackBlocks + cancelCallback:(fbt_void_nserror)cancelCallbackBlock { + self = [super init]; + if (self) { + self.repo = repo; + self.handle = fHandle; + self.callbacks = callbackBlocks; + self.cancelCallback = cancelCallbackBlock; + } + return self; +} + +- (BOOL)responseTo:(FIRDataEventType)eventType { + return self.callbacks != nil && + [self.callbacks + objectForKey:[NSNumber numberWithInteger:eventType]] != nil; +} + +- (FDataEvent *)createEventFrom:(FChange *)change query:(FQuerySpec *)query { + FIRDatabaseReference *ref = [[FIRDatabaseReference alloc] + initWithRepo:self.repo + path:[query.path childFromString:change.childKey]]; + FIRDataSnapshot *snapshot = + [[FIRDataSnapshot alloc] initWithRef:ref + indexedNode:change.indexedNode]; + + FDataEvent *eventData = + [[FDataEvent alloc] initWithEventType:change.type + eventRegistration:self + dataSnapshot:snapshot + prevName:change.prevKey]; + return eventData; +} + +- (void)fireEvent:(id)event queue:(dispatch_queue_t)queue { + if ([event isCancelEvent]) { + FCancelEvent *cancelEvent = event; + FFLog(@"I-RDB061001", @"Raising cancel value event on %@", event.path); + NSAssert( + self.cancelCallback != nil, + @"Raising a cancel event on a listener with no cancel callback"); + dispatch_async(queue, ^{ + self.cancelCallback(cancelEvent.error); + }); + } else if (self.callbacks != nil) { + FDataEvent *dataEvent = event; + FFLog(@"I-RDB061002", @"Raising event callback (%ld) on %@", + (long)dataEvent.eventType, dataEvent.path); + fbt_void_datasnapshot_nsstring callback = [self.callbacks + objectForKey:[NSNumber numberWithInteger:dataEvent.eventType]]; + + if (callback != nil) { + dispatch_async(queue, ^{ + callback(dataEvent.snapshot, dataEvent.prevName); + }); + } + } +} + +- (FCancelEvent *)createCancelEventFromError:(NSError *)error + path:(FPath *)path { + if (self.cancelCallback != nil) { + return [[FCancelEvent alloc] initWithEventRegistration:self + error:error + path:path]; + } else { + return nil; + } +} + +- (BOOL)matches:(id)other { + return self.handle == NSNotFound || other.handle == NSNotFound || + self.handle == other.handle; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FDataEvent.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FDataEvent.h new file mode 100644 index 0000000..360c364 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FDataEvent.h @@ -0,0 +1,41 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/FEvent.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDataSnapshot.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseReference.h" +#import "FirebaseDatabase/Sources/Utilities/Tuples/FTupleUserCallback.h" +#import + +@protocol FEventRegistration; +@protocol FIndex; + +@interface FDataEvent : NSObject + +- initWithEventType:(FIRDataEventType)type + eventRegistration:(id)eventRegistration + dataSnapshot:(FIRDataSnapshot *)dataSnapshot; +- initWithEventType:(FIRDataEventType)type + eventRegistration:(id)eventRegistration + dataSnapshot:(FIRDataSnapshot *)snapshot + prevName:(NSString *)prevName; + +@property(nonatomic, strong, readonly) id eventRegistration; +@property(nonatomic, strong, readonly) FIRDataSnapshot *snapshot; +@property(nonatomic, strong, readonly) NSString *prevName; +@property(nonatomic, readonly) FIRDataEventType eventType; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FDataEvent.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FDataEvent.m new file mode 100644 index 0000000..60a467e --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FDataEvent.m @@ -0,0 +1,83 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/FDataEvent.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h" +#import "FirebaseDatabase/Sources/Core/View/FEventRegistration.h" +#import "FirebaseDatabase/Sources/FIndex.h" + +@interface FDataEvent () +@property(nonatomic, strong, readwrite) id + eventRegistration; +@property(nonatomic, strong, readwrite) FIRDataSnapshot *snapshot; +@property(nonatomic, strong, readwrite) NSString *prevName; +@property(nonatomic, readwrite) FIRDataEventType eventType; +@end + +@implementation FDataEvent + +@synthesize eventRegistration; +@synthesize snapshot; +@synthesize prevName; +@synthesize eventType; + +- (id)initWithEventType:(FIRDataEventType)type + eventRegistration:(id)registration + dataSnapshot:(FIRDataSnapshot *)dataSnapshot { + return [self initWithEventType:type + eventRegistration:registration + dataSnapshot:dataSnapshot + prevName:nil]; +} + +- (id)initWithEventType:(FIRDataEventType)type + eventRegistration:(id)registration + dataSnapshot:(FIRDataSnapshot *)dataSnapshot + prevName:(NSString *)previousName { + self = [super init]; + if (self) { + self.eventRegistration = registration; + self.snapshot = dataSnapshot; + self.prevName = previousName; + self.eventType = type; + } + return self; +} + +- (FPath *)path { + // Used for logging, so delay calculation + FIRDatabaseReference *ref = self.snapshot.ref; + if (self.eventType == FIRDataEventTypeValue) { + return ref.path; + } else { + return ref.parent.path; + } +} + +- (void)fireEventOnQueue:(dispatch_queue_t)queue { + [self.eventRegistration fireEvent:self queue:queue]; +} + +- (BOOL)isCancelEvent { + return NO; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"event %d, data: %@", (int)eventType, + [snapshot value]]; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FEvent.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FEvent.h new file mode 100644 index 0000000..f4fa4d6 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FEvent.h @@ -0,0 +1,27 @@ +/* + * 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 "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDataEventType.h" +#import + +@class FPath; + +@protocol FEvent +- (FPath *)path; +- (void)fireEventOnQueue:(dispatch_queue_t)queue; +- (BOOL)isCancelEvent; +- (NSString *)description; +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FEventRaiser.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FEventRaiser.h new file mode 100644 index 0000000..186bb24 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FEventRaiser.h @@ -0,0 +1,36 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/FTypedefs.h" + +@class FPath; +@class FRepo; +@class FIRDatabaseConfig; + +/** + * Left as instance methods rather than class methods so that we could + * potentially callback on different queues for different repos. This is + * semi-parallel to JS's FEventQueue + */ +@interface FEventRaiser : NSObject + +- (id)initWithQueue:(dispatch_queue_t)queue; + +- (void)raiseEvents:(NSArray *)eventDataList; +- (void)raiseCallback:(fbt_void_void)callback; +- (void)raiseCallbacks:(NSArray *)callbackList; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FEventRaiser.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FEventRaiser.m new file mode 100644 index 0000000..2e6ebe6 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FEventRaiser.m @@ -0,0 +1,74 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/FEventRaiser.h" +#import "FirebaseDatabase/Sources/Core/FRepo.h" +#import "FirebaseDatabase/Sources/Core/FRepoManager.h" +#import "FirebaseDatabase/Sources/Core/View/FDataEvent.h" +#import "FirebaseDatabase/Sources/Utilities/FTypedefs.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/Tuples/FTupleUserCallback.h" + +@interface FEventRaiser () + +@property(nonatomic, strong) dispatch_queue_t queue; + +@end + +/** + * This class exists for symmetry with other clients, but since events are + * async, we don't need to do the complicated stuff the JS client does to + * preserve event order. + */ +@implementation FEventRaiser + +- (id)init { + [NSException raise:NSInternalInconsistencyException + format:@"Can't use default constructor"]; + return nil; +} + +- (id)initWithQueue:(dispatch_queue_t)queue { + self = [super init]; + if (self != nil) { + self->_queue = queue; + } + return self; +} + +- (void)raiseEvents:(NSArray *)eventDataList { + for (id event in eventDataList) { + [event fireEventOnQueue:self.queue]; + } +} + +- (void)raiseCallback:(fbt_void_void)callback { + dispatch_async(self.queue, callback); +} + +- (void)raiseCallbacks:(NSArray *)callbackList { + for (fbt_void_void callback in callbackList) { + dispatch_async(self.queue, callback); + } +} + ++ (void)raiseCallbacks:(NSArray *)callbackList queue:(dispatch_queue_t)queue { + for (fbt_void_void callback in callbackList) { + dispatch_async(queue, callback); + } +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FEventRegistration.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FEventRegistration.h new file mode 100644 index 0000000..a1d9c05 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FEventRegistration.h @@ -0,0 +1,38 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/FChange.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDataEventType.h" +#import + +@protocol FEvent; +@class FDataEvent; +@class FCancelEvent; +@class FQuerySpec; + +@protocol FEventRegistration +- (BOOL)responseTo:(FIRDataEventType)eventType; +- (FDataEvent *)createEventFrom:(FChange *)change query:(FQuerySpec *)query; +- (void)fireEvent:(id)event queue:(dispatch_queue_t)queue; +- (FCancelEvent *)createCancelEventFromError:(NSError *)error + path:(FPath *)path; +/** + * Used to figure out what event registration match the event registration that + * needs to be removed. + */ +- (BOOL)matches:(id)other; +@property(nonatomic, readonly) FIRDatabaseHandle handle; +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FKeepSyncedEventRegistration.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FKeepSyncedEventRegistration.h new file mode 100644 index 0000000..5111b20 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FKeepSyncedEventRegistration.h @@ -0,0 +1,28 @@ +/* + * 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 + +#import "FirebaseDatabase/Sources/Core/View/FEventRegistration.h" + +/** + * A singleton event registration to mark a query as keep synced + */ +@interface FKeepSyncedEventRegistration : NSObject + ++ (FKeepSyncedEventRegistration *)instance; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FKeepSyncedEventRegistration.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FKeepSyncedEventRegistration.m new file mode 100644 index 0000000..9c26f44 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FKeepSyncedEventRegistration.m @@ -0,0 +1,70 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/FKeepSyncedEventRegistration.h" + +@interface FKeepSyncedEventRegistration () + +@end + +@implementation FKeepSyncedEventRegistration + ++ (FKeepSyncedEventRegistration *)instance { + static dispatch_once_t onceToken; + static FKeepSyncedEventRegistration *keepSynced; + dispatch_once(&onceToken, ^{ + keepSynced = [[FKeepSyncedEventRegistration alloc] init]; + }); + return keepSynced; +} + +- (BOOL)responseTo:(FIRDataEventType)eventType { + return NO; +} + +- (FDataEvent *)createEventFrom:(FChange *)change query:(FQuerySpec *)query { + [NSException + raise:NSInternalInconsistencyException + format:@"Should never create event for FKeepSyncedEventRegistration"]; + return nil; +} + +- (void)fireEvent:(id)event queue:(dispatch_queue_t)queue { + [NSException + raise:NSInternalInconsistencyException + format:@"Should never raise event for FKeepSyncedEventRegistration"]; +} + +- (FCancelEvent *)createCancelEventFromError:(NSError *)error + path:(FPath *)path { + // Don't create cancel events.... + return nil; +} + +- (FIRDatabaseHandle)handle { + // TODO[offline]: returning arbitray, can't return NSNotFound since that is + // used to match other event registrations We should really redo this to + // match on different kind of events (single observer, all observers, + // cancelled) rather than on a NSNotFound handle... + return NSNotFound - 1; +} + +- (BOOL)matches:(id)other { + // Only matches singleton instance + return self == other; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FValueEventRegistration.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FValueEventRegistration.h new file mode 100644 index 0000000..dea4736 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FValueEventRegistration.h @@ -0,0 +1,34 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/FEventRegistration.h" +#import "FirebaseDatabase/Sources/Utilities/FTypedefs.h" +#import + +@class FRepo; + +@interface FValueEventRegistration : NSObject + +- (id)initWithRepo:(FRepo *)repo + handle:(FIRDatabaseHandle)fHandle + callback:(fbt_void_datasnapshot)callbackBlock + cancelCallback:(fbt_void_nserror)cancelCallbackBlock; + +@property(nonatomic, copy, readonly) fbt_void_datasnapshot callback; +@property(nonatomic, copy, readonly) fbt_void_nserror cancelCallback; +@property(nonatomic, readonly) FIRDatabaseHandle handle; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FValueEventRegistration.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FValueEventRegistration.m new file mode 100644 index 0000000..726227d --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FValueEventRegistration.m @@ -0,0 +1,102 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/FValueEventRegistration.h" +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDataSnapshot_Private.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h" +#import "FirebaseDatabase/Sources/Core/FQueryParams.h" +#import "FirebaseDatabase/Sources/Core/FQuerySpec.h" +#import "FirebaseDatabase/Sources/Core/View/FCancelEvent.h" +#import "FirebaseDatabase/Sources/Core/View/FDataEvent.h" + +@interface FValueEventRegistration () +@property(nonatomic, strong) FRepo *repo; +@property(nonatomic, copy, readwrite) fbt_void_datasnapshot callback; +@property(nonatomic, copy, readwrite) fbt_void_nserror cancelCallback; +@property(nonatomic, readwrite) FIRDatabaseHandle handle; +@end + +@implementation FValueEventRegistration + +- (id)initWithRepo:(FRepo *)repo + handle:(FIRDatabaseHandle)fHandle + callback:(fbt_void_datasnapshot)callbackBlock + cancelCallback:(fbt_void_nserror)cancelCallbackBlock { + self = [super init]; + if (self) { + self.repo = repo; + self.handle = fHandle; + self.callback = callbackBlock; + self.cancelCallback = cancelCallbackBlock; + } + return self; +} + +- (BOOL)responseTo:(FIRDataEventType)eventType { + return eventType == FIRDataEventTypeValue; +} + +- (FDataEvent *)createEventFrom:(FChange *)change query:(FQuerySpec *)query { + FIRDatabaseReference *ref = + [[FIRDatabaseReference alloc] initWithRepo:self.repo path:query.path]; + FIRDataSnapshot *snapshot = + [[FIRDataSnapshot alloc] initWithRef:ref + indexedNode:change.indexedNode]; + FDataEvent *eventData = + [[FDataEvent alloc] initWithEventType:FIRDataEventTypeValue + eventRegistration:self + dataSnapshot:snapshot]; + return eventData; +} + +- (void)fireEvent:(id)event queue:(dispatch_queue_t)queue { + if ([event isCancelEvent]) { + FCancelEvent *cancelEvent = event; + FFLog(@"I-RDB065001", @"Raising cancel value event on %@", event.path); + NSAssert( + self.cancelCallback != nil, + @"Raising a cancel event on a listener with no cancel callback"); + dispatch_async(queue, ^{ + self.cancelCallback(cancelEvent.error); + }); + } else if (self.callback != nil) { + FDataEvent *dataEvent = event; + FFLog(@"I-RDB065002", @"Raising value event on %@", + dataEvent.snapshot.key); + dispatch_async(queue, ^{ + self.callback(dataEvent.snapshot); + }); + } +} + +- (FCancelEvent *)createCancelEventFromError:(NSError *)error + path:(FPath *)path { + if (self.cancelCallback != nil) { + return [[FCancelEvent alloc] initWithEventRegistration:self + error:error + path:path]; + } else { + return nil; + } +} + +- (BOOL)matches:(id)other { + return self.handle == NSNotFound || other.handle == NSNotFound || + self.handle == other.handle; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FView.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FView.h new file mode 100644 index 0000000..ba31209 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FView.h @@ -0,0 +1,58 @@ +/* + * 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 + +@protocol FNode; +@protocol FOperation; +@protocol FEventRegistration; +@class FWriteTreeRef; +@class FQuerySpec; +@class FChange; +@class FPath; +@class FViewCache; + +@interface FViewOperationResult : NSObject + +@property(nonatomic, strong, readonly) NSArray *changes; +@property(nonatomic, strong, readonly) NSArray *events; + +@end + +@interface FView : NSObject + +@property(nonatomic, strong, readonly) FQuerySpec *query; + +- (id)initWithQuery:(FQuerySpec *)query + initialViewCache:(FViewCache *)initialViewCache; + +- (id)eventCache; +- (id)serverCache; +- (id)completeEventCache; +- (id)completeServerCacheFor:(FPath *)path; +- (id)completeEventCacheFor:(FPath *)path; +- (BOOL)isEmpty; + +- (void)addEventRegistration:(id)eventRegistration; +- (NSArray *)removeEventRegistration:(id)eventRegistration + cancelError:(NSError *)cancelError; + +- (FViewOperationResult *)applyOperation:(id)operation + writesCache:(FWriteTreeRef *)writesCache + serverCache:(id)optCompleteServerCache; +- (NSArray *)initialEvents:(id)registration; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FView.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FView.m new file mode 100644 index 0000000..8612def --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FView.m @@ -0,0 +1,285 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/FView.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h" +#import "FirebaseDatabase/Sources/Core/FQueryParams.h" +#import "FirebaseDatabase/Sources/Core/FQuerySpec.h" +#import "FirebaseDatabase/Sources/Core/FWriteTreeRef.h" +#import "FirebaseDatabase/Sources/Core/Operation/FOperation.h" +#import "FirebaseDatabase/Sources/Core/Operation/FOperationSource.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Core/View/FCacheNode.h" +#import "FirebaseDatabase/Sources/Core/View/FCancelEvent.h" +#import "FirebaseDatabase/Sources/Core/View/FEventRegistration.h" +#import "FirebaseDatabase/Sources/Core/View/FViewCache.h" +#import "FirebaseDatabase/Sources/Core/View/Filter/FIndexedFilter.h" +#import "FirebaseDatabase/Sources/FEventGenerator.h" +#import "FirebaseDatabase/Sources/FViewProcessor.h" +#import "FirebaseDatabase/Sources/FViewProcessorResult.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseQuery.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FIndexedNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" + +@interface FViewOperationResult () + +@property(nonatomic, strong, readwrite) NSArray *changes; +@property(nonatomic, strong, readwrite) NSArray *events; + +@end + +@implementation FViewOperationResult + +- (id)initWithChanges:(NSArray *)changes events:(NSArray *)events { + self = [super init]; + if (self != nil) { + self->_changes = changes; + self->_events = events; + } + return self; +} + +@end + +/** + * A view represents a specific location and query that has 1 or more event + * registrations. + * + * It does several things: + * - Maintains the list of event registration for this location/query. + * - Maintains a cache of the data visible for this location/query. + * - Applies new operations (via applyOperation), updates the cache, and based + * on the event registrations returns the set of events to be raised. + */ +@interface FView () + +@property(nonatomic, strong, readwrite) FQuerySpec *query; +@property(nonatomic, strong) FViewProcessor *processor; +@property(nonatomic, strong) FViewCache *viewCache; +@property(nonatomic, strong) NSMutableArray *eventRegistrations; +@property(nonatomic, strong) FEventGenerator *eventGenerator; + +@end + +@implementation FView +- (id)initWithQuery:(FQuerySpec *)query + initialViewCache:(FViewCache *)initialViewCache { + self = [super init]; + if (self) { + self.query = query; + + FIndexedFilter *indexFilter = + [[FIndexedFilter alloc] initWithIndex:query.index]; + id filter = query.params.nodeFilter; + self.processor = [[FViewProcessor alloc] initWithFilter:filter]; + FCacheNode *initialServerCache = initialViewCache.cachedServerSnap; + FCacheNode *initialEventCache = initialViewCache.cachedEventSnap; + + // Don't filter server node with other filter than index, wait for + // tagged listen + FIndexedNode *emptyIndexedNode = + [FIndexedNode indexedNodeWithNode:[FEmptyNode emptyNode] + index:query.index]; + FIndexedNode *serverSnap = + [indexFilter updateFullNode:emptyIndexedNode + withNewNode:initialServerCache.indexedNode + accumulator:nil]; + FIndexedNode *eventSnap = + [filter updateFullNode:emptyIndexedNode + withNewNode:initialEventCache.indexedNode + accumulator:nil]; + FCacheNode *newServerCache = [[FCacheNode alloc] + initWithIndexedNode:serverSnap + isFullyInitialized:initialServerCache.isFullyInitialized + isFiltered:indexFilter.filtersNodes]; + FCacheNode *newEventCache = [[FCacheNode alloc] + initWithIndexedNode:eventSnap + isFullyInitialized:initialEventCache.isFullyInitialized + isFiltered:filter.filtersNodes]; + + self.viewCache = [[FViewCache alloc] initWithEventCache:newEventCache + serverCache:newServerCache]; + + self.eventRegistrations = [[NSMutableArray alloc] init]; + + self.eventGenerator = [[FEventGenerator alloc] initWithQuery:query]; + } + + return self; +} + +- (id)serverCache { + return self.viewCache.cachedServerSnap.node; +} + +- (id)eventCache { + return self.viewCache.cachedEventSnap.node; +} + +- (id)completeEventCache { + return self.viewCache.completeEventSnap; +} + +- (id)completeServerCacheFor:(FPath *)path { + id cache = self.viewCache.completeServerSnap; + if (cache) { + // If this isn't a "loadsAllData" view, then cache isn't actually a + // complete cache and we need to see if it contains the child we're + // interested in. + if ([self.query loadsAllData] || + (!path.isEmpty && + ![cache getImmediateChild:path.getFront].isEmpty)) { + return [cache getChild:path]; + } + } + return nil; +} + +- (id)completeEventCacheFor:(FPath *)path { + id cache = self.viewCache.completeEventSnap; + if (cache) { + // If this isn't a "loadsAllData" view, then cache isn't actually a + // complete cache and we need to see if it contains the child we're + // interested in. + if ([self.query loadsAllData] || + (!path.isEmpty && + ![cache getImmediateChild:path.getFront].isEmpty)) { + return [cache getChild:path]; + } + } + return nil; +} + +- (BOOL)isEmpty { + return self.eventRegistrations.count == 0; +} + +- (void)addEventRegistration:(id)eventRegistration { + [self.eventRegistrations addObject:eventRegistration]; +} + +/** + * @param eventRegistration If null, remove all callbacks. + * @param cancelError If a cancelError is provided, appropriate cancel events + * will be returned. + * @return Cancel events, if cancelError was provided. + */ +- (NSArray *)removeEventRegistration:(id)eventRegistration + cancelError:(NSError *)cancelError { + NSMutableArray *cancelEvents = [[NSMutableArray alloc] init]; + if (cancelError != nil) { + NSAssert(eventRegistration == nil, + @"A cancel should cancel all event registrations."); + FPath *path = self.query.path; + for (id registration in self.eventRegistrations) { + FCancelEvent *maybeEvent = + [registration createCancelEventFromError:cancelError path:path]; + if (maybeEvent) { + [cancelEvents addObject:maybeEvent]; + } + } + } + + if (eventRegistration) { + NSUInteger i = 0; + while (i < self.eventRegistrations.count) { + id existing = self.eventRegistrations[i]; + if ([existing matches:eventRegistration]) { + [self.eventRegistrations removeObjectAtIndex:i]; + } else { + i++; + } + } + } else { + [self.eventRegistrations removeAllObjects]; + } + return cancelEvents; +} + +/** + * Applies the given Operation, updates our cache, and returns the appropriate + * events and changes + */ +- (FViewOperationResult *)applyOperation:(id)operation + writesCache:(FWriteTreeRef *)writesCache + serverCache:(id)optCompleteServerCache { + if (operation.type == FOperationTypeMerge && + operation.source.queryParams != nil) { + NSAssert(self.viewCache.completeServerSnap != nil, + @"We should always have a full cache before handling merges"); + NSAssert(self.viewCache.completeEventSnap != nil, + @"Missing event cache, even though we have a server cache"); + } + FViewCache *oldViewCache = self.viewCache; + FViewProcessorResult *result = + [self.processor applyOperationOn:oldViewCache + operation:operation + writesCache:writesCache + completeCache:optCompleteServerCache]; + + NSAssert(result.viewCache.cachedServerSnap.isFullyInitialized || + !oldViewCache.cachedServerSnap.isFullyInitialized, + @"Once a server snap is complete, it should never go back."); + + self.viewCache = result.viewCache; + NSArray *events = [self + generateEventsForChanges:result.changes + eventCache:result.viewCache.cachedEventSnap.indexedNode + registration:nil]; + return [[FViewOperationResult alloc] initWithChanges:result.changes + events:events]; +} + +- (NSArray *)initialEvents:(id)registration { + FCacheNode *eventSnap = self.viewCache.cachedEventSnap; + NSMutableArray *initialChanges = [[NSMutableArray alloc] init]; + [eventSnap.indexedNode.node enumerateChildrenUsingBlock:^( + NSString *key, id node, BOOL *stop) { + FIndexedNode *indexed = [FIndexedNode indexedNodeWithNode:node]; + FChange *change = [[FChange alloc] initWithType:FIRDataEventTypeChildAdded + indexedNode:indexed + childKey:key]; + [initialChanges addObject:change]; + }]; + if (eventSnap.isFullyInitialized) { + FChange *change = [[FChange alloc] initWithType:FIRDataEventTypeValue + indexedNode:eventSnap.indexedNode]; + [initialChanges addObject:change]; + } + return [self generateEventsForChanges:initialChanges + eventCache:eventSnap.indexedNode + registration:registration]; +} + +- (NSArray *)generateEventsForChanges:(NSArray *)changes + eventCache:(FIndexedNode *)eventCache + registration:(id)registration { + NSArray *registrations; + if (registration == nil) { + registrations = [[NSArray alloc] initWithArray:self.eventRegistrations]; + } else { + registrations = [[NSArray alloc] initWithObjects:registration, nil]; + } + return [self.eventGenerator generateEventsForChanges:changes + eventCache:eventCache + eventRegistrations:registrations]; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"FView (%@)", self.query]; +} +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FViewCache.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FViewCache.h new file mode 100644 index 0000000..62618d2 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FViewCache.h @@ -0,0 +1,40 @@ +#/* +* 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 + +@protocol FNode; +@class FCacheNode; +@class FIndexedNode; + +@interface FViewCache : NSObject + +- (id)initWithEventCache:(FCacheNode *)eventCache + serverCache:(FCacheNode *)serverCache; + +- (FViewCache *)updateEventSnap:(FIndexedNode *)eventSnap + isComplete:(BOOL)complete + isFiltered:(BOOL)filtered; +- (FViewCache *)updateServerSnap:(FIndexedNode *)serverSnap + isComplete:(BOOL)complete + isFiltered:(BOOL)filtered; + +@property(nonatomic, strong, readonly) FCacheNode *cachedEventSnap; +@property(nonatomic, strong, readonly) id completeEventSnap; +@property(nonatomic, strong, readonly) FCacheNode *cachedServerSnap; +@property(nonatomic, strong, readonly) id completeServerSnap; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FViewCache.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FViewCache.m new file mode 100644 index 0000000..c81be09 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/FViewCache.m @@ -0,0 +1,72 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/FViewCache.h" +#import "FirebaseDatabase/Sources/Core/View/FCacheNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" + +@interface FViewCache () +@property(nonatomic, strong, readwrite) FCacheNode *cachedEventSnap; +@property(nonatomic, strong, readwrite) FCacheNode *cachedServerSnap; +@end + +@implementation FViewCache + +- (id)initWithEventCache:(FCacheNode *)eventCache + serverCache:(FCacheNode *)serverCache { + self = [super init]; + if (self) { + self.cachedEventSnap = eventCache; + self.cachedServerSnap = serverCache; + } + return self; +} + +- (FViewCache *)updateEventSnap:(FIndexedNode *)eventSnap + isComplete:(BOOL)complete + isFiltered:(BOOL)filtered { + FCacheNode *updatedEventCache = + [[FCacheNode alloc] initWithIndexedNode:eventSnap + isFullyInitialized:complete + isFiltered:filtered]; + return [[FViewCache alloc] initWithEventCache:updatedEventCache + serverCache:self.cachedServerSnap]; +} + +- (FViewCache *)updateServerSnap:(FIndexedNode *)serverSnap + isComplete:(BOOL)complete + isFiltered:(BOOL)filtered { + FCacheNode *updatedServerCache = + [[FCacheNode alloc] initWithIndexedNode:serverSnap + isFullyInitialized:complete + isFiltered:filtered]; + return [[FViewCache alloc] initWithEventCache:self.cachedEventSnap + serverCache:updatedServerCache]; +} + +- (id)completeEventSnap { + return (self.cachedEventSnap.isFullyInitialized) ? self.cachedEventSnap.node + : nil; +} + +- (id)completeServerSnap { + return (self.cachedServerSnap.isFullyInitialized) + ? self.cachedServerSnap.node + : nil; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FChildChangeAccumulator.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FChildChangeAccumulator.h new file mode 100644 index 0000000..bf25163 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FChildChangeAccumulator.h @@ -0,0 +1,27 @@ +/* + * 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 + +@class FChange; + +@interface FChildChangeAccumulator : NSObject + +- (id)init; +- (void)trackChildChange:(FChange *)change; +- (NSArray *)changes; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FChildChangeAccumulator.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FChildChangeAccumulator.m new file mode 100644 index 0000000..b39366f --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FChildChangeAccumulator.m @@ -0,0 +1,99 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/Filter/FChildChangeAccumulator.h" +#import "FirebaseDatabase/Sources/Core/View/FChange.h" +#import "FirebaseDatabase/Sources/FIndex.h" + +@interface FChildChangeAccumulator () +@property(nonatomic, strong) NSMutableDictionary *changeMap; +@end + +@implementation FChildChangeAccumulator + +- (id)init { + self = [super init]; + if (self) { + self.changeMap = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (void)trackChildChange:(FChange *)change { + FIRDataEventType type = change.type; + NSString *childKey = change.childKey; + NSAssert(type == FIRDataEventTypeChildAdded || + type == FIRDataEventTypeChildChanged || + type == FIRDataEventTypeChildRemoved, + @"Only child changes supported for tracking."); + NSAssert(![change.childKey isEqualToString:@".priority"], + @"Changes not tracked on priority"); + if (self.changeMap[childKey] != nil) { + FChange *oldChange = [self.changeMap objectForKey:childKey]; + FIRDataEventType oldType = oldChange.type; + if (type == FIRDataEventTypeChildAdded && + oldType == FIRDataEventTypeChildRemoved) { + FChange *newChange = + [[FChange alloc] initWithType:FIRDataEventTypeChildChanged + indexedNode:change.indexedNode + childKey:childKey + oldIndexedNode:oldChange.indexedNode]; + [self.changeMap setObject:newChange forKey:childKey]; + } else if (type == FIRDataEventTypeChildRemoved && + oldType == FIRDataEventTypeChildAdded) { + [self.changeMap removeObjectForKey:childKey]; + } else if (type == FIRDataEventTypeChildRemoved && + oldType == FIRDataEventTypeChildChanged) { + FChange *newChange = + [[FChange alloc] initWithType:FIRDataEventTypeChildRemoved + indexedNode:oldChange.oldIndexedNode + childKey:childKey]; + [self.changeMap setObject:newChange forKey:childKey]; + } else if (type == FIRDataEventTypeChildChanged && + oldType == FIRDataEventTypeChildAdded) { + FChange *newChange = + [[FChange alloc] initWithType:FIRDataEventTypeChildAdded + indexedNode:change.indexedNode + childKey:childKey]; + [self.changeMap setObject:newChange forKey:childKey]; + } else if (type == FIRDataEventTypeChildChanged && + oldType == FIRDataEventTypeChildChanged) { + FChange *newChange = + [[FChange alloc] initWithType:FIRDataEventTypeChildChanged + indexedNode:change.indexedNode + childKey:childKey + oldIndexedNode:oldChange.oldIndexedNode]; + [self.changeMap setObject:newChange forKey:childKey]; + } else { + NSString *reason = [NSString + stringWithFormat: + @"Illegal combination of changes: %@ occurred after %@", + change, oldChange]; + @throw [[NSException alloc] + initWithName:@"FirebaseDatabaseInternalError" + reason:reason + userInfo:nil]; + } + } else { + [self.changeMap setObject:change forKey:childKey]; + } +} + +- (NSArray *)changes { + return [self.changeMap allValues]; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FCompleteChildSource.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FCompleteChildSource.h new file mode 100644 index 0000000..0c04bc1 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FCompleteChildSource.h @@ -0,0 +1,30 @@ +/* + * 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 + +@protocol FNode; +@class FNamedNode; +@protocol FIndex; + +@protocol FCompleteChildSource + +- (id)completeChild:(NSString *)childKey; +- (FNamedNode *)childByIndex:(id)index + afterChild:(FNamedNode *)child + isReverse:(BOOL)reverse; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FIndexedFilter.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FIndexedFilter.h new file mode 100644 index 0000000..c42d228 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FIndexedFilter.h @@ -0,0 +1,26 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/Filter/FNodeFilter.h" +#import + +@protocol FIndex; + +@interface FIndexedFilter : NSObject + +- (id)initWithIndex:(id)theIndex; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FIndexedFilter.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FIndexedFilter.m new file mode 100644 index 0000000..0a5f0ef --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FIndexedFilter.m @@ -0,0 +1,164 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/Filter/FIndexedFilter.h" +#import "FirebaseDatabase/Sources/Core/View/FChange.h" +#import "FirebaseDatabase/Sources/Core/View/Filter/FChildChangeAccumulator.h" +#import "FirebaseDatabase/Sources/FIndex.h" +#import "FirebaseDatabase/Sources/FKeyIndex.h" +#import "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FIndexedNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" + +@interface FIndexedFilter () +@property(nonatomic, strong, readwrite) id index; +@end + +@implementation FIndexedFilter +- (id)initWithIndex:(id)theIndex { + self = [super init]; + if (self) { + self.index = theIndex; + } + return self; +} + +- (FIndexedNode *)updateChildIn:(FIndexedNode *)indexedNode + forChildKey:(NSString *)childKey + newChild:(id)newChildSnap + affectedPath:(FPath *)affectedPath + fromSource:(id)source + accumulator: + (FChildChangeAccumulator *)optChangeAccumulator { + NSAssert([indexedNode hasIndex:self.index], + @"The index in FIndexedNode must match the index of the filter"); + id node = indexedNode.node; + id oldChildSnap = [node getImmediateChild:childKey]; + + // Check if anything actually changed. + if ([[oldChildSnap getChild:affectedPath] + isEqual:[newChildSnap getChild:affectedPath]]) { + // There's an edge case where a child can enter or leave the view + // because affectedPath was set to null. In this case, affectedPath will + // appear null in both the old and new snapshots. So we need to avoid + // treating these cases as "nothing changed." + if (oldChildSnap.isEmpty == newChildSnap.isEmpty) { +// Nothing changed. +#ifdef DEBUG + NSAssert([oldChildSnap isEqual:newChildSnap], + @"Old and new snapshots should be equal."); +#endif + + return indexedNode; + } + } + if (optChangeAccumulator) { + if (newChildSnap.isEmpty) { + if ([node hasChild:childKey]) { + FChange *change = [[FChange alloc] + initWithType:FIRDataEventTypeChildRemoved + indexedNode:[FIndexedNode indexedNodeWithNode:oldChildSnap] + childKey:childKey]; + [optChangeAccumulator trackChildChange:change]; + } else { + NSAssert(node.isLeafNode, + @"A child remove without an old child only makes " + @"sense on a leaf node."); + } + } else if (oldChildSnap.isEmpty) { + FChange *change = [[FChange alloc] + initWithType:FIRDataEventTypeChildAdded + indexedNode:[FIndexedNode indexedNodeWithNode:newChildSnap] + childKey:childKey]; + [optChangeAccumulator trackChildChange:change]; + } else { + FChange *change = [[FChange alloc] + initWithType:FIRDataEventTypeChildChanged + indexedNode:[FIndexedNode indexedNodeWithNode:newChildSnap] + childKey:childKey + oldIndexedNode:[FIndexedNode indexedNodeWithNode:oldChildSnap]]; + [optChangeAccumulator trackChildChange:change]; + } + } + if (node.isLeafNode && newChildSnap.isEmpty) { + return indexedNode; + } else { + return [indexedNode updateChild:childKey withNewChild:newChildSnap]; + } +} + +- (FIndexedNode *)updateFullNode:(FIndexedNode *)oldSnap + withNewNode:(FIndexedNode *)newSnap + accumulator: + (FChildChangeAccumulator *)optChangeAccumulator { + if (optChangeAccumulator) { + [oldSnap.node enumerateChildrenUsingBlock:^( + NSString *childKey, id childNode, BOOL *stop) { + if (![newSnap.node hasChild:childKey]) { + FChange *change = [[FChange alloc] + initWithType:FIRDataEventTypeChildRemoved + indexedNode:[FIndexedNode indexedNodeWithNode:childNode] + childKey:childKey]; + [optChangeAccumulator trackChildChange:change]; + } + }]; + + [newSnap.node enumerateChildrenUsingBlock:^( + NSString *childKey, id childNode, BOOL *stop) { + if ([oldSnap.node hasChild:childKey]) { + id oldChildSnap = + [oldSnap.node getImmediateChild:childKey]; + if (![oldChildSnap isEqual:childNode]) { + FChange *change = [[FChange alloc] + initWithType:FIRDataEventTypeChildChanged + indexedNode:[FIndexedNode + indexedNodeWithNode:childNode] + childKey:childKey + oldIndexedNode:[FIndexedNode + indexedNodeWithNode:oldChildSnap]]; + [optChangeAccumulator trackChildChange:change]; + } + } else { + FChange *change = [[FChange alloc] + initWithType:FIRDataEventTypeChildAdded + indexedNode:[FIndexedNode indexedNodeWithNode:childNode] + childKey:childKey]; + [optChangeAccumulator trackChildChange:change]; + } + }]; + } + return newSnap; +} + +- (FIndexedNode *)updatePriority:(id)priority + forNode:(FIndexedNode *)oldSnap { + if ([oldSnap.node isEmpty]) { + return oldSnap; + } else { + return [oldSnap updatePriority:priority]; + } +} + +- (BOOL)filtersNodes { + return NO; +} + +- (id)indexedFilter { + return self; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FLimitedFilter.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FLimitedFilter.h new file mode 100644 index 0000000..ac0af3e --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FLimitedFilter.h @@ -0,0 +1,25 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/Filter/FNodeFilter.h" +#import + +@class FQueryParams; + +@interface FLimitedFilter : NSObject + +- (id)initWithQueryParams:(FQueryParams *)params; +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FLimitedFilter.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FLimitedFilter.m new file mode 100644 index 0000000..776f9c5 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FLimitedFilter.m @@ -0,0 +1,285 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/Filter/FLimitedFilter.h" +#import "FirebaseDatabase/Sources/Core/FQueryParams.h" +#import "FirebaseDatabase/Sources/Core/View/FChange.h" +#import "FirebaseDatabase/Sources/Core/View/Filter/FChildChangeAccumulator.h" +#import "FirebaseDatabase/Sources/Core/View/Filter/FCompleteChildSource.h" +#import "FirebaseDatabase/Sources/FIndex.h" +#import "FirebaseDatabase/Sources/FNamedNode.h" +#import "FirebaseDatabase/Sources/FRangedFilter.h" +#import "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionary.h" + +@interface FLimitedFilter () +@property(nonatomic, strong) FRangedFilter *rangedFilter; +@property(nonatomic, strong, readwrite) id index; +@property(nonatomic) NSInteger limit; +@property(nonatomic) BOOL reverse; + +@end + +@implementation FLimitedFilter +- (id)initWithQueryParams:(FQueryParams *)params { + self = [super init]; + if (self) { + self.rangedFilter = [[FRangedFilter alloc] initWithQueryParams:params]; + self.index = params.index; + self.limit = params.limit; + self.reverse = !params.isViewFromLeft; + } + return self; +} + +- (FIndexedNode *)updateChildIn:(FIndexedNode *)oldSnap + forChildKey:(NSString *)childKey + newChild:(id)newChildSnap + affectedPath:(FPath *)affectedPath + fromSource:(id)source + accumulator: + (FChildChangeAccumulator *)optChangeAccumulator { + if (![self.rangedFilter matchesKey:childKey andNode:newChildSnap]) { + newChildSnap = [FEmptyNode emptyNode]; + } + if ([[oldSnap.node getImmediateChild:childKey] isEqual:newChildSnap]) { + // No change + return oldSnap; + } else if (oldSnap.node.numChildren < self.limit) { + return [[self.rangedFilter indexedFilter] + updateChildIn:oldSnap + forChildKey:childKey + newChild:newChildSnap + affectedPath:affectedPath + fromSource:source + accumulator:optChangeAccumulator]; + } else { + return [self fullLimitUpdateNode:oldSnap + forChildKey:childKey + newChild:newChildSnap + fromSource:source + accumulator:optChangeAccumulator]; + } +} + +- (FIndexedNode *)fullLimitUpdateNode:(FIndexedNode *)oldIndexed + forChildKey:(NSString *)childKey + newChild:(id)newChildSnap + fromSource:(id)source + accumulator: + (FChildChangeAccumulator *)optChangeAccumulator { + NSAssert(oldIndexed.node.numChildren == self.limit, + @"Should have number of children equal to limit."); + + FNamedNode *windowBoundary = + self.reverse ? oldIndexed.firstChild : oldIndexed.lastChild; + + BOOL inRange = [self.rangedFilter matchesKey:childKey andNode:newChildSnap]; + if ([oldIndexed.node hasChild:childKey]) { + // `childKey` was already in `oldSnap`. Figure out if it remains in the + // window or needs to be replaced. + id oldChildSnap = [oldIndexed.node getImmediateChild:childKey]; + + // In case the `newChildSnap` falls outside the window, get the + // `nextChild` that might replace it. + FNamedNode *nextChild = [source childByIndex:self.index + afterChild:windowBoundary + isReverse:(BOOL)self.reverse]; + if (nextChild != nil && ([nextChild.name isEqualToString:childKey] || + [oldIndexed.node hasChild:nextChild.name])) { + // There is a weird edge case where a node is updated as part of a + // merge in the write tree, but hasn't been applied to the limited + // filter yet. Ignore this next child which will be updated later in + // the limited filter... + nextChild = [source childByIndex:self.index + afterChild:nextChild + isReverse:self.reverse]; + } + + // Figure out if `newChildSnap` is in range and ordered before + // `nextChild` + BOOL remainsInWindow = inRange && !newChildSnap.isEmpty; + remainsInWindow = remainsInWindow && + (!nextChild || [self.index compareKey:nextChild.name + andNode:nextChild.node + toOtherKey:childKey + andNode:newChildSnap + reverse:self.reverse] >= + NSOrderedSame); + if (remainsInWindow) { + // `newChildSnap` is ordered before `nextChild`, so it's a child + // changed event + if (optChangeAccumulator != nil) { + FChange *change = [[FChange alloc] + initWithType:FIRDataEventTypeChildChanged + indexedNode:[FIndexedNode + indexedNodeWithNode:newChildSnap] + childKey:childKey + oldIndexedNode:[FIndexedNode + indexedNodeWithNode:oldChildSnap]]; + [optChangeAccumulator trackChildChange:change]; + } + return [oldIndexed updateChild:childKey withNewChild:newChildSnap]; + } else { + // `newChildSnap` is ordered after `nextChild`, so it's a child + // removed event + if (optChangeAccumulator != nil) { + FChange *change = [[FChange alloc] + initWithType:FIRDataEventTypeChildRemoved + indexedNode:[FIndexedNode indexedNodeWithNode:oldChildSnap] + childKey:childKey]; + [optChangeAccumulator trackChildChange:change]; + } + FIndexedNode *newIndexed = + [oldIndexed updateChild:childKey + withNewChild:[FEmptyNode emptyNode]]; + + // We need to check if the `nextChild` is actually in range before + // adding it + BOOL nextChildInRange = + (nextChild != nil) && + [self.rangedFilter matchesKey:nextChild.name + andNode:nextChild.node]; + if (nextChildInRange) { + if (optChangeAccumulator != nil) { + FChange *change = [[FChange alloc] + initWithType:FIRDataEventTypeChildAdded + indexedNode:[FIndexedNode + indexedNodeWithNode:nextChild.node] + childKey:nextChild.name]; + [optChangeAccumulator trackChildChange:change]; + } + return [newIndexed updateChild:nextChild.name + withNewChild:nextChild.node]; + } else { + return newIndexed; + } + } + } else if (newChildSnap.isEmpty) { + // We're deleting a node, but it was not in the window, so ignore it. + return oldIndexed; + } else if (inRange) { + // `newChildSnap` is in range, but was ordered after `windowBoundary`. + // If this has changed, we bump out the `windowBoundary` and add the + // `newChildSnap` + if ([self.index compareKey:windowBoundary.name + andNode:windowBoundary.node + toOtherKey:childKey + andNode:newChildSnap + reverse:self.reverse] >= NSOrderedSame) { + if (optChangeAccumulator != nil) { + FChange *removedChange = [[FChange alloc] + initWithType:FIRDataEventTypeChildRemoved + indexedNode:[FIndexedNode + indexedNodeWithNode:windowBoundary.node] + childKey:windowBoundary.name]; + FChange *addedChange = [[FChange alloc] + initWithType:FIRDataEventTypeChildAdded + indexedNode:[FIndexedNode indexedNodeWithNode:newChildSnap] + childKey:childKey]; + [optChangeAccumulator trackChildChange:removedChange]; + [optChangeAccumulator trackChildChange:addedChange]; + } + return [[oldIndexed updateChild:childKey withNewChild:newChildSnap] + updateChild:windowBoundary.name + withNewChild:[FEmptyNode emptyNode]]; + } else { + return oldIndexed; + } + } else { + // `newChildSnap` was not in range and remains not in range, so ignore + // it. + return oldIndexed; + } +} + +- (FIndexedNode *)updateFullNode:(FIndexedNode *)oldSnap + withNewNode:(FIndexedNode *)newSnap + accumulator: + (FChildChangeAccumulator *)optChangeAccumulator { + __block FIndexedNode *filtered; + if (newSnap.node.isLeafNode || newSnap.node.isEmpty) { + // Make sure we have a children node with the correct index, not a leaf + // node + filtered = [FIndexedNode indexedNodeWithNode:[FEmptyNode emptyNode] + index:self.index]; + } else { + filtered = newSnap; + // Don't support priorities on queries. + filtered = [filtered updatePriority:[FEmptyNode emptyNode]]; + FNamedNode *startPost = nil; + FNamedNode *endPost = nil; + if (self.reverse) { + startPost = self.rangedFilter.endPost; + endPost = self.rangedFilter.startPost; + } else { + startPost = self.rangedFilter.startPost; + endPost = self.rangedFilter.endPost; + } + __block BOOL foundStartPost = NO; + __block NSUInteger count = 0; + [newSnap + enumerateChildrenReverse:self.reverse + usingBlock:^(NSString *childKey, id childNode, + BOOL *stop) { + if (!foundStartPost && + [self.index + compareKey:startPost.name + andNode:startPost.node + toOtherKey:childKey + andNode:childNode + reverse:self.reverse] <= NSOrderedSame) { + // Start adding + foundStartPost = YES; + } + BOOL inRange = foundStartPost && count < self.limit; + inRange = inRange && + [self.index compareKey:childKey + andNode:childNode + toOtherKey:endPost.name + andNode:endPost.node + reverse:self.reverse] <= + NSOrderedSame; + if (inRange) { + count++; + } else { + filtered = [filtered + updateChild:childKey + withNewChild:[FEmptyNode emptyNode]]; + } + }]; + } + return [self.indexedFilter updateFullNode:oldSnap + withNewNode:filtered + accumulator:optChangeAccumulator]; +} + +- (FIndexedNode *)updatePriority:(id)priority + forNode:(FIndexedNode *)oldSnap { + // Don't support priorities on queries. + return oldSnap; +} + +- (BOOL)filtersNodes { + return YES; +} + +- (id)indexedFilter { + return self.rangedFilter.indexedFilter; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FNodeFilter.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FNodeFilter.h new file mode 100644 index 0000000..d19c6fb --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Core/View/Filter/FNodeFilter.h @@ -0,0 +1,77 @@ +/* + * 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 + +@protocol FNode; +@class FIndexedNode; +@protocol FCompleteChildSource; +@class FChildChangeAccumulator; +@protocol FIndex; +@class FPath; + +/** + * FNodeFilter is used to update nodes and complete children of nodes while + * applying queries on the fly and keeping track of any child changes. This + * class does not track value changes as value changes depend on more than just + * the node itself. Different kind of queries require different kind of + * implementations of this interface. + */ +@protocol FNodeFilter + +/** + * Update a single complete child in the snap. If the child equals the old child + * in the snap, this is a no-op. The method expects an indexed snap. + */ +- (FIndexedNode *)updateChildIn:(FIndexedNode *)oldSnap + forChildKey:(NSString *)childKey + newChild:(id)newChildSnap + affectedPath:(FPath *)affectedPath + fromSource:(id)source + accumulator:(FChildChangeAccumulator *)optChangeAccumulator; + +/** + * Update a node in full and output any resulting change from this complete + * update. + */ +- (FIndexedNode *)updateFullNode:(FIndexedNode *)oldSnap + withNewNode:(FIndexedNode *)newSnap + accumulator: + (FChildChangeAccumulator *)optChangeAccumulator; + +/** + * Update the priority of the root node + */ +- (FIndexedNode *)updatePriority:(id)priority + forNode:(FIndexedNode *)oldSnap; + +/** + * Returns true if children might be filtered due to query critiera + */ +- (BOOL)filtersNodes; + +/** + * Returns the index filter that this filter uses to get a NodeFilter that + * doesn't filter any children. + */ +@property(nonatomic, strong, readonly) id indexedFilter; + +/** + * Returns the index that this filter uses + */ +@property(nonatomic, strong, readonly) id index; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FClock.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FClock.h new file mode 100644 index 0000000..e85cb2a --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FClock.h @@ -0,0 +1,35 @@ +/* + * 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 + +@protocol FClock + +- (NSTimeInterval)currentTime; + +@end + +@interface FSystemClock : NSObject + ++ (FSystemClock *)clock; + +@end + +@interface FOffsetClock : NSObject + +- (id)initWithClock:(id)clock offset:(NSTimeInterval)offset; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FClock.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FClock.m new file mode 100644 index 0000000..0733b6c --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FClock.m @@ -0,0 +1,58 @@ +/* + * 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 "FirebaseDatabase/Sources/FClock.h" + +@implementation FSystemClock + +- (NSTimeInterval)currentTime { + return [[NSDate date] timeIntervalSince1970]; +} + ++ (FSystemClock *)clock { + static dispatch_once_t onceToken; + static FSystemClock *clock; + dispatch_once(&onceToken, ^{ + clock = [[FSystemClock alloc] init]; + }); + return clock; +} + +@end + +@interface FOffsetClock () + +@property(nonatomic, strong) id clock; +@property(nonatomic) NSTimeInterval offset; + +@end + +@implementation FOffsetClock + +- (NSTimeInterval)currentTime { + return [self.clock currentTime] + self.offset; +} + +- (id)initWithClock:(id)clock offset:(NSTimeInterval)offset { + self = [super init]; + if (self != nil) { + self->_clock = clock; + self->_offset = offset; + } + return self; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FEventGenerator.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FEventGenerator.h new file mode 100644 index 0000000..443664e --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FEventGenerator.h @@ -0,0 +1,28 @@ +/* + * 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 + +@class FQuerySpec; +@class FIndexedNode; +@protocol FNode; + +@interface FEventGenerator : NSObject +- (id)initWithQuery:(FQuerySpec *)query; +- (NSArray *)generateEventsForChanges:(NSArray *)changes + eventCache:(FIndexedNode *)eventCache + eventRegistrations:(NSArray *)registrations; +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FEventGenerator.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FEventGenerator.m new file mode 100644 index 0000000..815aed1 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FEventGenerator.m @@ -0,0 +1,169 @@ +/* + * 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 "FirebaseDatabase/Sources/FEventGenerator.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h" +#import "FirebaseDatabase/Sources/Core/FQueryParams.h" +#import "FirebaseDatabase/Sources/Core/FQuerySpec.h" +#import "FirebaseDatabase/Sources/Core/View/FChange.h" +#import "FirebaseDatabase/Sources/Core/View/FDataEvent.h" +#import "FirebaseDatabase/Sources/Core/View/FEvent.h" +#import "FirebaseDatabase/Sources/Core/View/FEventRegistration.h" +#import "FirebaseDatabase/Sources/FNamedNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" + +@interface FEventGenerator () +@property(nonatomic, strong) FQuerySpec *query; +@end + +/** + * An EventGenerator is used to convert "raw" changes (fb.core.view.Change) as + * computed by the CacheDiffer into actual events (fb.core.view.Event) that can + * be raised. See generateEventsForChanges() for details. + */ +@implementation FEventGenerator + +- (id)initWithQuery:(FQuerySpec *)query { + self = [super init]; + if (self) { + self.query = query; + } + return self; +} + +/** + * Given a set of raw changes (no moved events, and prevName not specified yet), + * and a set of EventRegistrations that should be notified of these changes, + * generate the actual events to be raised. + * + * Notes: + * - child_moved events will be synthesized at this time for any child_changed + * events that affect our index + * - prevName will be calculated based on the index ordering + * + * @param changes NSArray of FChange, not necessarily in order. + * @param registrations is NSArray of FEventRegistration. + * @return NSArray of FEvent. + */ +- (NSArray *)generateEventsForChanges:(NSArray *)changes + eventCache:(FIndexedNode *)eventCache + eventRegistrations:(NSArray *)registrations { + NSMutableArray *events = [[NSMutableArray alloc] init]; + + // child_moved is index-specific, so check all our child_changed events to + // see if we need to materialize child_moved events with this view's index + NSMutableArray *moves = [[NSMutableArray alloc] init]; + for (FChange *change in changes) { + if (change.type == FIRDataEventTypeChildChanged && + [self.query.index + indexedValueChangedBetween:change.oldIndexedNode.node + and:change.indexedNode.node]) { + FChange *moveChange = + [[FChange alloc] initWithType:FIRDataEventTypeChildMoved + indexedNode:change.indexedNode + childKey:change.childKey + oldIndexedNode:nil]; + [moves addObject:moveChange]; + } + } + + [self generateEvents:events + forType:FIRDataEventTypeChildRemoved + changes:changes + eventCache:eventCache + eventRegistrations:registrations]; + [self generateEvents:events + forType:FIRDataEventTypeChildAdded + changes:changes + eventCache:eventCache + eventRegistrations:registrations]; + [self generateEvents:events + forType:FIRDataEventTypeChildMoved + changes:moves + eventCache:eventCache + eventRegistrations:registrations]; + [self generateEvents:events + forType:FIRDataEventTypeChildChanged + changes:changes + eventCache:eventCache + eventRegistrations:registrations]; + [self generateEvents:events + forType:FIRDataEventTypeValue + changes:changes + eventCache:eventCache + eventRegistrations:registrations]; + + return events; +} + +- (void)generateEvents:(NSMutableArray *)events + forType:(FIRDataEventType)eventType + changes:(NSArray *)changes + eventCache:(FIndexedNode *)eventCache + eventRegistrations:(NSArray *)registrations { + NSMutableArray *filteredChanges = [[NSMutableArray alloc] init]; + for (FChange *change in changes) { + if (change.type == eventType) { + [filteredChanges addObject:change]; + } + } + + id index = self.query.index; + + [filteredChanges + sortUsingComparator:^NSComparisonResult(FChange *one, FChange *two) { + if (one.childKey == nil || two.childKey == nil) { + @throw [[NSException alloc] + initWithName:@"InternalInconsistencyError" + reason:@"Should only compare child_ events" + userInfo:nil]; + } + return [index compareKey:one.childKey + andNode:one.indexedNode.node + toOtherKey:two.childKey + andNode:two.indexedNode.node]; + }]; + + for (FChange *change in filteredChanges) { + for (id registration in registrations) { + if ([registration responseTo:eventType]) { + id event = [self generateEventForChange:change + registration:registration + eventCache:eventCache]; + [events addObject:event]; + } + } + } +} + +- (id)generateEventForChange:(FChange *)change + registration:(id)registration + eventCache:(FIndexedNode *)eventCache { + FChange *materializedChange; + if (change.type == FIRDataEventTypeValue || + change.type == FIRDataEventTypeChildRemoved) { + materializedChange = change; + } else { + NSString *prevChildKey = + [eventCache predecessorForChildKey:change.childKey + childNode:change.indexedNode.node + index:self.query.index]; + materializedChange = [change changeWithPrevKey:prevChildKey]; + } + return [registration createEventFrom:materializedChange query:self.query]; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FIRDatabaseConfig_Private.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FIRDatabaseConfig_Private.h new file mode 100644 index 0000000..96c57db --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FIRDatabaseConfig_Private.h @@ -0,0 +1,33 @@ +/* + * 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 "FirebaseDatabase/Sources/Api/FIRDatabaseConfig.h" +#import "FirebaseDatabase/Sources/Login/FIRDatabaseConnectionContextProvider.h" + +@protocol FStorageEngine; + +@interface FIRDatabaseConfig () + +@property(nonatomic, readonly) BOOL isFrozen; +@property(nonatomic, strong, readonly) NSString *sessionIdentifier; +@property(nonatomic, strong, readonly) NSString *googleAppID; +@property(nonatomic, strong) id + contextProvider; +@property(nonatomic, strong) id forceStorageEngine; + +- (void)freeze; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FIRDatabaseReference.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FIRDatabaseReference.m new file mode 100644 index 0000000..edb961a --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FIRDatabaseReference.m @@ -0,0 +1,542 @@ +/* + * 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 "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseReference.h" +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" +#import "FirebaseDatabase/Sources/Api/FIRDatabaseConfig.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDatabaseReference_Private.h" +#import "FirebaseDatabase/Sources/Core/FQueryParams.h" +#import "FirebaseDatabase/Sources/FIRDatabaseConfig_Private.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabase.h" +#import "FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FNextPushId.h" +#import "FirebaseDatabase/Sources/Utilities/FStringUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FValidation.h" + +@implementation FIRDatabaseReference + +#pragma mark - +#pragma mark Constructors + +- (id)initWithConfig:(FIRDatabaseConfig *)config { + FParsedUrl *parsedUrl = + [FUtilities parseUrl:[[FIRApp defaultApp] options].databaseURL]; + [FValidation validateFrom:@"initWithUrl:" validURL:parsedUrl]; + return [self initWithRepo:[FRepoManager getRepo:parsedUrl.repoInfo + config:config] + path:parsedUrl.path]; +} + +- (id)initWithRepo:(FRepo *)repo path:(FPath *)path { + return [super initWithRepo:repo + path:path + params:[FQueryParams defaultInstance] + orderByCalled:NO + priorityMethodCalled:NO]; +} + +#pragma mark - +#pragma mark Ancillary methods + +- (nullable NSString *)key { + if ([self.path isEmpty]) { + return nil; + } else { + return [self.path getBack]; + } +} + +- (FIRDatabase *)database { + return self.repo.database; +} + +- (FIRDatabaseReference *)parent { + FPath *parentPath = [self.path parent]; + FIRDatabaseReference *parent = nil; + if (parentPath != nil) { + parent = [[FIRDatabaseReference alloc] initWithRepo:self.repo + path:parentPath]; + } + return parent; +} + +- (NSString *)URL { + FIRDatabaseReference *parent = [self parent]; + return parent == nil + ? [self.repo description] + : [NSString + stringWithFormat:@"%@/%@", [parent description], + [FStringUtilities urlEncoded:self.key]]; +} + +- (NSString *)description { + return [self URL]; +} + +- (FIRDatabaseReference *)root { + return [[FIRDatabaseReference alloc] + initWithRepo:self.repo + path:[[FPath alloc] initWith:@""]]; +} + +#pragma mark - +#pragma mark Child methods + +- (FIRDatabaseReference *)child:(NSString *)pathString { + if ([self.path getFront] == nil) { + // we're at the root + [FValidation validateFrom:@"child:" validRootPathString:pathString]; + } else { + [FValidation validateFrom:@"child:" validPathString:pathString]; + } + FPath *path = [self.path childFromString:pathString]; + FIRDatabaseReference *firebaseRef = + [[FIRDatabaseReference alloc] initWithRepo:self.repo path:path]; + return firebaseRef; +} + +- (FIRDatabaseReference *)childByAutoId { + [FValidation validateFrom:@"childByAutoId:" writablePath:self.path]; + + NSString *name = [FNextPushId get:self.repo.serverTime]; + return [self child:name]; +} + +#pragma mark - +#pragma mark Basic write methods + +- (void)setValue:(id)value { + [self setValueInternal:value + andPriority:nil + withCompletionBlock:nil + from:@"setValue:"]; +} + +- (void)setValue:(id)value withCompletionBlock:(fbt_void_nserror_ref)block { + [self setValueInternal:value + andPriority:nil + withCompletionBlock:block + from:@"setValue:withCompletionBlock:"]; +} + +- (void)setValue:(id)value andPriority:(id)priority { + [self setValueInternal:value + andPriority:priority + withCompletionBlock:nil + from:@"setValue:andPriority:"]; +} + +- (void)setValue:(id)value + andPriority:(id)priority + withCompletionBlock:(fbt_void_nserror_ref)block { + [self setValueInternal:value + andPriority:priority + withCompletionBlock:block + from:@"setValue:andPriority:withCompletionBlock:"]; +} + +- (void)setValueInternal:(id)value + andPriority:(id)priority + withCompletionBlock:(fbt_void_nserror_ref)block + from:(NSString *)fn { + [FValidation validateFrom:fn writablePath:self.path]; + + fbt_void_nserror_ref userCallback = [block copy]; + id newNode = [FSnapshotUtilities nodeFrom:value + priority:priority + withValidationFrom:fn]; + + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self.repo set:self.path withNode:newNode withCallback:userCallback]; + }); +} + +- (void)removeValue { + [self setValueInternal:nil + andPriority:nil + withCompletionBlock:nil + from:@"removeValue:"]; +} + +- (void)removeValueWithCompletionBlock:(fbt_void_nserror_ref)block { + [self setValueInternal:nil + andPriority:nil + withCompletionBlock:block + from:@"removeValueWithCompletionBlock:"]; +} + +- (void)setPriority:(id)priority { + [self setPriorityInternal:priority + withCompletionBlock:nil + from:@"setPriority:"]; +} + +- (void)setPriority:(id)priority + withCompletionBlock:(fbt_void_nserror_ref)block { + + [self setPriorityInternal:priority + withCompletionBlock:block + from:@"setPriority:withCompletionBlock:"]; +} + +- (void)setPriorityInternal:(id)priority + withCompletionBlock:(fbt_void_nserror_ref)block + from:(NSString *)fn { + [FValidation validateFrom:fn writablePath:self.path]; + + fbt_void_nserror_ref userCallback = [block copy]; + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self.repo set:[self.path childFromString:@".priority"] + withNode:[FSnapshotUtilities nodeFrom:priority] + withCallback:userCallback]; + }); +} + +- (void)updateChildValues:(NSDictionary *)values { + [self updateChildValuesInternal:values + withCompletionBlock:nil + from:@"updateChildValues:"]; +} + +- (void)updateChildValues:(NSDictionary *)values + withCompletionBlock:(fbt_void_nserror_ref)block { + [self updateChildValuesInternal:values + withCompletionBlock:block + from:@"updateChildValues:withCompletionBlock:"]; +} + +- (void)updateChildValuesInternal:(NSDictionary *)values + withCompletionBlock:(fbt_void_nserror_ref)block + from:(NSString *)fn { + [FValidation validateFrom:fn writablePath:self.path]; + + FCompoundWrite *merge = + [FSnapshotUtilities compoundWriteFromDictionary:values + withValidationFrom:fn]; + + fbt_void_nserror_ref userCallback = [block copy]; + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self.repo update:self.path withNodes:merge withCallback:userCallback]; + }); +} + +#pragma mark - +#pragma mark Disconnect Operations + +- (void)onDisconnectSetValue:(id)value { + [self onDisconnectSetValueInternal:value + andPriority:nil + withCompletionBlock:nil + from:@"onDisconnectSetValue:"]; +} + +- (void)onDisconnectSetValue:(id)value + withCompletionBlock:(fbt_void_nserror_ref)block { + [self onDisconnectSetValueInternal:value + andPriority:nil + withCompletionBlock:block + from:@"onDisconnectSetValue:" + @"withCompletionBlock:"]; +} + +- (void)onDisconnectSetValue:(id)value andPriority:(id)priority { + [self onDisconnectSetValueInternal:value + andPriority:priority + withCompletionBlock:nil + from:@"onDisconnectSetValue:andPriority:"]; +} + +- (void)onDisconnectSetValue:(id)value + andPriority:(id)priority + withCompletionBlock:(fbt_void_nserror_ref)block { + [self onDisconnectSetValueInternal:value + andPriority:priority + withCompletionBlock:block + from:@"onDisconnectSetValue:andPriority:" + @"withCompletionBlock:"]; +} + +- (void)onDisconnectSetValueInternal:(id)value + andPriority:(id)priority + withCompletionBlock:(fbt_void_nserror_ref)block + from:(NSString *)fn { + [FValidation validateFrom:fn writablePath:self.path]; + + id newNodeUnresolved = [FSnapshotUtilities nodeFrom:value + priority:priority + withValidationFrom:fn]; + + fbt_void_nserror_ref userCallback = [block copy]; + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self.repo onDisconnectSet:self.path + withNode:newNodeUnresolved + withCallback:userCallback]; + }); +} + +- (void)onDisconnectRemoveValue { + [self onDisconnectSetValueInternal:nil + andPriority:nil + withCompletionBlock:nil + from:@"onDisconnectRemoveValue:"]; +} + +- (void)onDisconnectRemoveValueWithCompletionBlock:(fbt_void_nserror_ref)block { + [self onDisconnectSetValueInternal:nil + andPriority:nil + withCompletionBlock:block + from:@"onDisconnectRemoveValueWithCompletionB" + @"lock:"]; +} + +- (void)onDisconnectUpdateChildValues:(NSDictionary *)values { + [self + onDisconnectUpdateChildValuesInternal:values + withCompletionBlock:nil + from: + @"onDisconnectUpdateChildValues:"]; +} + +- (void)onDisconnectUpdateChildValues:(NSDictionary *)values + withCompletionBlock:(fbt_void_nserror_ref)block { + [self onDisconnectUpdateChildValuesInternal:values + withCompletionBlock:block + from:@"onDisconnectUpdateChildValues" + @":withCompletionBlock:"]; +} + +- (void)onDisconnectUpdateChildValuesInternal:(NSDictionary *)values + withCompletionBlock:(fbt_void_nserror_ref)block + from:(NSString *)fn { + [FValidation validateFrom:fn writablePath:self.path]; + + FCompoundWrite *merge = + [FSnapshotUtilities compoundWriteFromDictionary:values + withValidationFrom:fn]; + + fbt_void_nserror_ref userCallback = [block copy]; + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self.repo onDisconnectUpdate:self.path + withNodes:merge + withCallback:userCallback]; + }); +} + +- (void)cancelDisconnectOperations { + [self cancelDisconnectOperationsWithCompletionBlock:nil]; +} + +- (void)cancelDisconnectOperationsWithCompletionBlock: + (fbt_void_nserror_ref)block { + fbt_void_nserror_ref callback = nil; + if (block != nil) { + callback = [block copy]; + } + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self.repo onDisconnectCancel:self.path withCallback:callback]; + }); +} + +#pragma mark - +#pragma mark Connection management methods + ++ (void)goOffline { + [FRepoManager interruptAll]; +} + ++ (void)goOnline { + [FRepoManager resumeAll]; +} + +#pragma mark - +#pragma mark Data reading methods deferred to FQuery + +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + withBlock:(fbt_void_datasnapshot)block { + return [self observeEventType:eventType + withBlock:block + withCancelBlock:nil]; +} + +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock:(fbt_void_datasnapshot_nsstring)block { + return [self observeEventType:eventType + andPreviousSiblingKeyWithBlock:block + withCancelBlock:nil]; +} + +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + withBlock:(fbt_void_datasnapshot)block + withCancelBlock:(fbt_void_nserror)cancelBlock { + return [super observeEventType:eventType + withBlock:block + withCancelBlock:cancelBlock]; +} + +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock:(fbt_void_datasnapshot_nsstring)block + withCancelBlock:(fbt_void_nserror)cancelBlock { + return [super observeEventType:eventType + andPreviousSiblingKeyWithBlock:block + withCancelBlock:cancelBlock]; +} + +- (void)removeObserverWithHandle:(FIRDatabaseHandle)handle { + [super removeObserverWithHandle:handle]; +} + +- (void)removeAllObservers { + [super removeAllObservers]; +} + +- (void)keepSynced:(BOOL)keepSynced { + [super keepSynced:keepSynced]; +} + +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + withBlock:(fbt_void_datasnapshot)block { + [self observeSingleEventOfType:eventType + withBlock:block + withCancelBlock:nil]; +} + +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock:(fbt_void_datasnapshot_nsstring)block { + [self observeSingleEventOfType:eventType + andPreviousSiblingKeyWithBlock:block + withCancelBlock:nil]; +} + +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + withBlock:(fbt_void_datasnapshot)block + withCancelBlock:(fbt_void_nserror)cancelBlock { + [super observeSingleEventOfType:eventType + withBlock:block + withCancelBlock:cancelBlock]; +} + +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock:(fbt_void_datasnapshot_nsstring)block + withCancelBlock:(fbt_void_nserror)cancelBlock { + [super observeSingleEventOfType:eventType + andPreviousSiblingKeyWithBlock:block + withCancelBlock:cancelBlock]; +} + +#pragma mark - +#pragma mark Query methods +// These methods suppress warnings from having method definitions in +// FIRDatabaseReference.h for docs generation. + +- (void)getDataWithCompletionBlock: + (void (^_Nonnull)(NSError *__nullable error, + FIRDataSnapshot *__nullable snapshot))block { + [super getDataWithCompletionBlock:block]; +} + +- (FIRDatabaseQuery *)queryLimitedToFirst:(NSUInteger)limit { + return [super queryLimitedToFirst:limit]; +} + +- (FIRDatabaseQuery *)queryLimitedToLast:(NSUInteger)limit { + return [super queryLimitedToLast:limit]; +} + +- (FIRDatabaseQuery *)queryOrderedByChild:(NSString *)key { + return [super queryOrderedByChild:key]; +} + +- (FIRDatabaseQuery *)queryOrderedByKey { + return [super queryOrderedByKey]; +} + +- (FIRDatabaseQuery *)queryOrderedByPriority { + return [super queryOrderedByPriority]; +} + +- (FIRDatabaseQuery *)queryStartingAtValue:(id)startValue { + return [super queryStartingAtValue:startValue]; +} + +- (FIRDatabaseQuery *)queryStartingAtValue:(id)startValue + childKey:(NSString *)childKey { + return [super queryStartingAtValue:startValue childKey:childKey]; +} + +- (FIRDatabaseQuery *)queryStartingAfterValue:(id)startAfterValue { + return [super queryStartingAfterValue:startAfterValue]; +} + +- (FIRDatabaseQuery *)queryStartingAfterValue:(id)startAfterValue + childKey:(NSString *)childKey { + return [super queryStartingAfterValue:startAfterValue childKey:childKey]; +} + +- (FIRDatabaseQuery *)queryEndingAtValue:(id)endValue { + return [super queryEndingAtValue:endValue]; +} + +- (FIRDatabaseQuery *)queryEndingAtValue:(id)endValue + childKey:(NSString *)childKey { + return [super queryEndingAtValue:endValue childKey:childKey]; +} + +- (FIRDatabaseQuery *)queryEqualToValue:(id)value { + return [super queryEqualToValue:value]; +} + +- (FIRDatabaseQuery *)queryEqualToValue:(id)value + childKey:(NSString *)childKey { + return [super queryEqualToValue:value childKey:childKey]; +} + +#pragma mark - +#pragma mark Transaction methods + +- (void)runTransactionBlock:(fbt_transactionresult_mutabledata)block { + [FValidation validateFrom:@"runTransactionBlock:" writablePath:self.path]; + [self runTransactionBlock:block andCompletionBlock:nil withLocalEvents:YES]; +} + +- (void)runTransactionBlock:(fbt_transactionresult_mutabledata)update + andCompletionBlock: + (fbt_void_nserror_bool_datasnapshot)completionBlock { + [FValidation validateFrom:@"runTransactionBlock:andCompletionBlock:" + writablePath:self.path]; + [self runTransactionBlock:update + andCompletionBlock:completionBlock + withLocalEvents:YES]; +} + +- (void)runTransactionBlock:(fbt_transactionresult_mutabledata)block + andCompletionBlock:(fbt_void_nserror_bool_datasnapshot)completionBlock + withLocalEvents:(BOOL)localEvents { + [FValidation + validateFrom:@"runTransactionBlock:andCompletionBlock:withLocalEvents:" + writablePath:self.path]; + fbt_transactionresult_mutabledata updateCopy = [block copy]; + fbt_void_nserror_bool_datasnapshot onCompleteCopy = [completionBlock copy]; + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self.repo startTransactionOnPath:self.path + update:updateCopy + onComplete:onCompleteCopy + withLocalEvents:localEvents]; + }); +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FIndex.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FIndex.h new file mode 100644 index 0000000..89bec76 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FIndex.h @@ -0,0 +1,51 @@ +/* + * 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 + +@class FImmutableSortedDictionary; +@class FNamedNode; +@protocol FNode; + +@protocol FIndex +- (NSComparisonResult)compareKey:(NSString *)key1 + andNode:(id)node1 + toOtherKey:(NSString *)key2 + andNode:(id)node2; + +- (NSComparisonResult)compareKey:(NSString *)key1 + andNode:(id)node1 + toOtherKey:(NSString *)key2 + andNode:(id)node2 + reverse:(BOOL)reverse; + +- (NSComparisonResult)compareNamedNode:(FNamedNode *)namedNode1 + toNamedNode:(FNamedNode *)namedNode2; + +- (BOOL)isDefinedOn:(id)node; +- (BOOL)indexedValueChangedBetween:(id)oldNode and:(id)newNode; +- (FNamedNode *)minPost; +- (FNamedNode *)maxPost; +- (FNamedNode *)makePost:(id)indexValue name:(NSString *)name; +- (NSString *)queryDefinition; + +@end + +@interface FIndex : NSObject + ++ (id)indexFromQueryDefinition:(NSString *)string; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FIndex.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FIndex.m new file mode 100644 index 0000000..0f6761e --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FIndex.m @@ -0,0 +1,39 @@ +/* + * 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 "FirebaseDatabase/Sources/FIndex.h" + +#import "FirebaseDatabase/Sources/FKeyIndex.h" +#import "FirebaseDatabase/Sources/FPathIndex.h" +#import "FirebaseDatabase/Sources/FPriorityIndex.h" +#import "FirebaseDatabase/Sources/FValueIndex.h" + +@implementation FIndex + ++ (id)indexFromQueryDefinition:(NSString *)string { + if ([string isEqualToString:@".key"]) { + return [FKeyIndex keyIndex]; + } else if ([string isEqualToString:@".value"]) { + return [FValueIndex valueIndex]; + } else if ([string isEqualToString:@".priority"]) { + return [FPriorityIndex priorityIndex]; + } else { + return + [[FPathIndex alloc] initWithPath:[[FPath alloc] initWith:string]]; + } +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FKeyIndex.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FKeyIndex.h new file mode 100644 index 0000000..3a5195b --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FKeyIndex.h @@ -0,0 +1,22 @@ +/* + * 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 "FirebaseDatabase/Sources/FIndex.h" +#import + +@interface FKeyIndex : NSObject ++ (id)keyIndex; +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FKeyIndex.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FKeyIndex.m new file mode 100644 index 0000000..9f5147d --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FKeyIndex.m @@ -0,0 +1,123 @@ +/* + * 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 "FirebaseDatabase/Sources/FKeyIndex.h" +#import "FirebaseDatabase/Sources/FNamedNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" + +@interface FKeyIndex () + +@property(nonatomic, strong) FNamedNode *maxPost; + +@end + +@implementation FKeyIndex + +- (id)init { + self = [super init]; + if (self) { + self.maxPost = [[FNamedNode alloc] initWithName:[FUtilities maxName] + andNode:[FEmptyNode emptyNode]]; + } + return self; +} + +- (NSComparisonResult)compareKey:(NSString *)key1 + andNode:(id)node1 + toOtherKey:(NSString *)key2 + andNode:(id)node2 { + return [FUtilities compareKey:key1 toKey:key2]; +} + +- (NSComparisonResult)compareKey:(NSString *)key1 + andNode:(id)node1 + toOtherKey:(NSString *)key2 + andNode:(id)node2 + reverse:(BOOL)reverse { + if (reverse) { + return [self compareKey:key2 + andNode:node2 + toOtherKey:key1 + andNode:node1]; + } else { + return [self compareKey:key1 + andNode:node1 + toOtherKey:key2 + andNode:node2]; + } +} + +- (NSComparisonResult)compareNamedNode:(FNamedNode *)namedNode1 + toNamedNode:(FNamedNode *)namedNode2 { + return [self compareKey:namedNode1.name + andNode:namedNode1.node + toOtherKey:namedNode2.name + andNode:namedNode2.node]; +} + +- (BOOL)isDefinedOn:(id)node { + return YES; +} + +- (BOOL)indexedValueChangedBetween:(id)oldNode and:(id)newNode { + return NO; // The key for a node never changes. +} + +- (FNamedNode *)minPost { + return [FNamedNode min]; +} + +- (FNamedNode *)makePost:(id)indexValue name:(NSString *)name { + NSString *key = indexValue.val; + NSAssert([key isKindOfClass:[NSString class]], + @"KeyIndex indexValue must always be a string."); + // We just use empty node, but it'll never be compared, since our comparator + // only looks at name. + return [[FNamedNode alloc] initWithName:key andNode:[FEmptyNode emptyNode]]; +} + +- (NSString *)queryDefinition { + return @".key"; +} + +- (NSString *)description { + return @"FKeyIndex"; +} + +- (id)copyWithZone:(NSZone *)zone { + return self; +} + +- (BOOL)isEqual:(id)other { + // since we're a singleton. + return (other == self); +} + +- (NSUInteger)hash { + return [@".key" hash]; +} + ++ (id)keyIndex { + static id keyIndex; + static dispatch_once_t once; + dispatch_once(&once, ^{ + keyIndex = [[FKeyIndex alloc] init]; + }); + return keyIndex; +} +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FListenComplete.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FListenComplete.h new file mode 100644 index 0000000..e3cdd4e --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FListenComplete.h @@ -0,0 +1,28 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Operation/FOperation.h" +#import + +@interface FListenComplete : NSObject + +- (id)initWithSource:(FOperationSource *)aSource path:(FPath *)aPath; + +@property(nonatomic, strong, readonly) FOperationSource *source; +@property(nonatomic, strong, readonly) FPath *path; +@property(nonatomic, readonly) FOperationType type; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FListenComplete.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FListenComplete.m new file mode 100644 index 0000000..70a4c5c --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FListenComplete.m @@ -0,0 +1,55 @@ +/* + * 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 "FirebaseDatabase/Sources/FListenComplete.h" +#import "FirebaseDatabase/Sources/Core/Operation/FOperationSource.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" + +@interface FListenComplete () +@property(nonatomic, strong, readwrite) FOperationSource *source; +@property(nonatomic, strong, readwrite) FPath *path; +@property(nonatomic, readwrite) FOperationType type; +@end + +@implementation FListenComplete +- (id)initWithSource:(FOperationSource *)aSource path:(FPath *)aPath { + NSAssert(!aSource.fromUser, + @"Can't have a listen complete from a user source"); + self = [super init]; + if (self) { + self.source = aSource; + self.path = aPath; + self.type = FOperationTypeListenComplete; + } + return self; +} + +- (id)operationForChild:(NSString *)childKey { + if ([self.path isEmpty]) { + return [[FListenComplete alloc] initWithSource:self.source + path:[FPath empty]]; + } else { + return [[FListenComplete alloc] initWithSource:self.source + path:[self.path popFront]]; + } +} + +- (NSString *)description { + return [NSString stringWithFormat:@"FListenComplete { path=%@, source=%@ }", + self.path, self.source]; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FMaxNode.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FMaxNode.h new file mode 100644 index 0000000..16f3d08 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FMaxNode.h @@ -0,0 +1,22 @@ +/* + * 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 "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h" +#import + +@interface FMaxNode : FChildrenNode ++ (id)maxNode; +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FMaxNode.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FMaxNode.m new file mode 100644 index 0000000..159583e --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FMaxNode.m @@ -0,0 +1,58 @@ +/* + * 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 "FirebaseDatabase/Sources/FMaxNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" + +@implementation FMaxNode { +} +- (id)init { + self = [super init]; + if (self) { + } + return self; +} + ++ (id)maxNode { + static FMaxNode *maxNode = nil; + static dispatch_once_t once; + dispatch_once(&once, ^{ + maxNode = [[FMaxNode alloc] init]; + }); + return maxNode; +} + +- (NSComparisonResult)compare:(id)other { + if (other == self) { + return NSOrderedSame; + } else { + return NSOrderedDescending; + } +} + +- (BOOL)isEqual:(id)other { + return other == self; +} + +- (id)getImmediateChild:(NSString *)childName { + return [FEmptyNode emptyNode]; +} + +- (BOOL)isEmpty { + return NO; +} +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FNamedNode.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FNamedNode.h new file mode 100644 index 0000000..b91e57d --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FNamedNode.h @@ -0,0 +1,31 @@ +/* + * 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 "FirebaseDatabase/Sources/Snapshot/FNode.h" +#import + +@interface FNamedNode : NSObject + +@property(nonatomic, strong, readonly) NSString *name; +@property(nonatomic, strong, readonly) id node; + +- (id)initWithName:(NSString *)name andNode:(id)node; + ++ (FNamedNode *)nodeWithName:(NSString *)name node:(id)node; + ++ (FNamedNode *)min; ++ (FNamedNode *)max; +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FNamedNode.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FNamedNode.m new file mode 100644 index 0000000..d1092e8 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FNamedNode.m @@ -0,0 +1,102 @@ +/* + * 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 "FirebaseDatabase/Sources/FNamedNode.h" +#import "FirebaseDatabase/Sources/FIndex.h" +#import "FirebaseDatabase/Sources/FMaxNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" + +@interface FNamedNode () +@property(nonatomic, strong, readwrite) NSString *name; +@property(nonatomic, strong, readwrite) id node; +@end + +@implementation FNamedNode + ++ (FNamedNode *)nodeWithName:(NSString *)name node:(id)node { + return [[FNamedNode alloc] initWithName:name andNode:node]; +} + +- (id)initWithName:(NSString *)name andNode:(id)node { + self = [super init]; + if (self) { + self.name = name; + self.node = node; + } + return self; +} + +- (id)copy { + return self; +} + +- (id)copyWithZone:(NSZone *)zone { + return self; +} + ++ (FNamedNode *)min { + static FNamedNode *min = nil; + static dispatch_once_t once; + dispatch_once(&once, ^{ + min = [[FNamedNode alloc] initWithName:[FUtilities minName] + andNode:[FEmptyNode emptyNode]]; + }); + return min; +} + ++ (FNamedNode *)max { + static FNamedNode *max = nil; + static dispatch_once_t once; + dispatch_once(&once, ^{ + max = [[FNamedNode alloc] initWithName:[FUtilities maxName] + andNode:[FMaxNode maxNode]]; + }); + return max; +} + +- (NSString *)description { + return + [NSString stringWithFormat:@"NamedNode[%@] %@", self.name, self.node]; +} + +- (BOOL)isEqual:(id)object { + if (self == object) { + return YES; + } + if (object == nil || ![object isKindOfClass:[FNamedNode class]]) { + return NO; + } + + FNamedNode *namedNode = object; + if (![self.name isEqualToString:namedNode.name]) { + return NO; + } + if (![self.node isEqual:namedNode.node]) { + return NO; + } + + return YES; +} + +- (NSUInteger)hash { + NSUInteger nameHash = [self.name hash]; + NSUInteger nodeHash = [self.node hash]; + NSUInteger result = 31 * nameHash + nodeHash; + return result; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FPathIndex.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FPathIndex.h new file mode 100644 index 0000000..20c18a0 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FPathIndex.h @@ -0,0 +1,23 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/FIndex.h" +#import + +@interface FPathIndex : NSObject +- (id)initWithPath:(FPath *)path; +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FPathIndex.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FPathIndex.m new file mode 100644 index 0000000..20e276d --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FPathIndex.m @@ -0,0 +1,135 @@ +/* + * 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 "FirebaseDatabase/Sources/FPathIndex.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/FMaxNode.h" +#import "FirebaseDatabase/Sources/FNamedNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" + +@interface FPathIndex () +@property(nonatomic, strong) FPath *path; +@end + +@implementation FPathIndex + +- (id)initWithPath:(FPath *)path { + self = [super init]; + if (self) { + if (path.isEmpty || [path.getFront isEqualToString:@".priority"]) { + [NSException raise:NSInvalidArgumentException + format:@"Invalid path for PathIndex: %@", path]; + } + _path = path; + } + return self; +} + +- (NSComparisonResult)compareKey:(NSString *)key1 + andNode:(id)node1 + toOtherKey:(NSString *)key2 + andNode:(id)node2 { + id child1 = [node1 getChild:self.path]; + id child2 = [node2 getChild:self.path]; + NSComparisonResult indexCmp = [child1 compare:child2]; + if (indexCmp == NSOrderedSame) { + return [FUtilities compareKey:key1 toKey:key2]; + } else { + return indexCmp; + } +} + +- (NSComparisonResult)compareKey:(NSString *)key1 + andNode:(id)node1 + toOtherKey:(NSString *)key2 + andNode:(id)node2 + reverse:(BOOL)reverse { + if (reverse) { + return [self compareKey:key2 + andNode:node2 + toOtherKey:key1 + andNode:node1]; + } else { + return [self compareKey:key1 + andNode:node1 + toOtherKey:key2 + andNode:node2]; + } +} + +- (NSComparisonResult)compareNamedNode:(FNamedNode *)namedNode1 + toNamedNode:(FNamedNode *)namedNode2 { + return [self compareKey:namedNode1.name + andNode:namedNode1.node + toOtherKey:namedNode2.name + andNode:namedNode2.node]; +} + +- (BOOL)isDefinedOn:(id)node { + return ![node getChild:self.path].isEmpty; +} + +- (BOOL)indexedValueChangedBetween:(id)oldNode and:(id)newNode { + id oldValue = [oldNode getChild:self.path]; + id newValue = [newNode getChild:self.path]; + return [oldValue compare:newValue] != NSOrderedSame; +} + +- (FNamedNode *)minPost { + return FNamedNode.min; +} + +- (FNamedNode *)maxPost { + id maxNode = [[FEmptyNode emptyNode] updateChild:self.path + withNewChild:[FMaxNode maxNode]]; + + return [[FNamedNode alloc] initWithName:[FUtilities maxName] + andNode:maxNode]; +} + +- (FNamedNode *)makePost:(id)indexValue name:(NSString *)name { + id node = [[FEmptyNode emptyNode] updateChild:self.path + withNewChild:indexValue]; + return [[FNamedNode alloc] initWithName:name andNode:node]; +} + +- (NSString *)queryDefinition { + return [self.path wireFormat]; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"FPathIndex(%@)", self.path]; +} + +- (id)copyWithZone:(NSZone *)zone { + // Safe since we're immutable. + return self; +} + +- (BOOL)isEqual:(id)other { + if (![other isKindOfClass:[FPathIndex class]]) { + return NO; + } + return ([self.path isEqual:((FPathIndex *)other).path]); +} + +- (NSUInteger)hash { + return [self.path hash]; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FPriorityIndex.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FPriorityIndex.h new file mode 100644 index 0000000..262f686 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FPriorityIndex.h @@ -0,0 +1,23 @@ +/* + * 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 + +#import "FirebaseDatabase/Sources/FIndex.h" + +@interface FPriorityIndex : NSObject ++ (id)priorityIndex; +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FPriorityIndex.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FPriorityIndex.m new file mode 100644 index 0000000..db3220a --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FPriorityIndex.m @@ -0,0 +1,126 @@ +/* + * 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 "FirebaseDatabase/Sources/FPriorityIndex.h" + +#import "FirebaseDatabase/Sources/FMaxNode.h" +#import "FirebaseDatabase/Sources/FNamedNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FLeafNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" + +// TODO: Abstract into some common base class? + +@implementation FPriorityIndex + +- (NSComparisonResult)compareKey:(NSString *)key1 + andNode:(id)node1 + toOtherKey:(NSString *)key2 + andNode:(id)node2 { + id child1 = [node1 getPriority]; + id child2 = [node2 getPriority]; + NSComparisonResult indexCmp = [child1 compare:child2]; + if (indexCmp == NSOrderedSame) { + return [FUtilities compareKey:key1 toKey:key2]; + } else { + return indexCmp; + } +} + +- (NSComparisonResult)compareKey:(NSString *)key1 + andNode:(id)node1 + toOtherKey:(NSString *)key2 + andNode:(id)node2 + reverse:(BOOL)reverse { + if (reverse) { + return [self compareKey:key2 + andNode:node2 + toOtherKey:key1 + andNode:node1]; + } else { + return [self compareKey:key1 + andNode:node1 + toOtherKey:key2 + andNode:node2]; + } +} + +- (NSComparisonResult)compareNamedNode:(FNamedNode *)namedNode1 + toNamedNode:(FNamedNode *)namedNode2 { + return [self compareKey:namedNode1.name + andNode:namedNode1.node + toOtherKey:namedNode2.name + andNode:namedNode2.node]; +} + +- (BOOL)isDefinedOn:(id)node { + return !node.getPriority.isEmpty; +} + +- (BOOL)indexedValueChangedBetween:(id)oldNode and:(id)newNode { + id oldValue = [oldNode getPriority]; + id newValue = [newNode getPriority]; + return ![oldValue isEqual:newValue]; +} + +- (FNamedNode *)minPost { + return FNamedNode.min; +} + +- (FNamedNode *)maxPost { + return [self makePost:[FMaxNode maxNode] name:[FUtilities maxName]]; +} + +- (FNamedNode *)makePost:(id)indexValue name:(NSString *)name { + id node = [[FLeafNode alloc] initWithValue:@"[PRIORITY-POST]" + withPriority:indexValue]; + return [[FNamedNode alloc] initWithName:name andNode:node]; +} + +- (NSString *)queryDefinition { + return @".priority"; +} + +- (NSString *)description { + return @"FPriorityIndex"; +} + +- (id)copyWithZone:(NSZone *)zone { + // Safe since we're immutable. + return self; +} + +- (BOOL)isEqual:(id)other { + return [other isKindOfClass:[FPriorityIndex class]]; +} + +- (NSUInteger)hash { + // chosen by a fair dice roll. Guaranteed to be random + return 3155577; +} + ++ (id)priorityIndex { + static id index; + static dispatch_once_t once; + dispatch_once(&once, ^{ + index = [[FPriorityIndex alloc] init]; + }); + + return index; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FRangedFilter.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FRangedFilter.h new file mode 100644 index 0000000..4c535ea --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FRangedFilter.h @@ -0,0 +1,31 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/View/Filter/FNodeFilter.h" +#import + +@class FQueryParams; +@class FNamedNode; + +@interface FRangedFilter : NSObject + +- (id)initWithQueryParams:(FQueryParams *)params; +- (BOOL)matchesKey:(NSString *)key andNode:(id)node; + +@property(nonatomic, strong, readonly) FNamedNode *startPost; +@property(nonatomic, strong, readonly) FNamedNode *endPost; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FRangedFilter.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FRangedFilter.m new file mode 100644 index 0000000..99095d8 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FRangedFilter.m @@ -0,0 +1,129 @@ +/* + * 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 "FirebaseDatabase/Sources/FRangedFilter.h" +#import "FirebaseDatabase/Sources/Core/FQueryParams.h" +#import "FirebaseDatabase/Sources/Core/View/Filter/FChildChangeAccumulator.h" +#import "FirebaseDatabase/Sources/Core/View/Filter/FIndexedFilter.h" +#import "FirebaseDatabase/Sources/FNamedNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FIndexedNode.h" + +@interface FRangedFilter () +@property(nonatomic, strong, readwrite) id indexedFilter; +@property(nonatomic, strong, readwrite) id index; +@property(nonatomic, strong, readwrite) FNamedNode *startPost; +@property(nonatomic, strong, readwrite) FNamedNode *endPost; +@end + +@implementation FRangedFilter +- (id)initWithQueryParams:(FQueryParams *)params { + self = [super init]; + if (self) { + self.indexedFilter = + [[FIndexedFilter alloc] initWithIndex:params.index]; + self.index = params.index; + self.startPost = [FRangedFilter startPostFromQueryParams:params]; + self.endPost = [FRangedFilter endPostFromQueryParams:params]; + } + return self; +} + ++ (FNamedNode *)startPostFromQueryParams:(FQueryParams *)params { + if ([params hasStart]) { + NSString *startKey = params.indexStartKey; + return [params.index makePost:params.indexStartValue name:startKey]; + } else { + return params.index.minPost; + } +} + ++ (FNamedNode *)endPostFromQueryParams:(FQueryParams *)params { + if ([params hasEnd]) { + NSString *endKey = params.indexEndKey; + return [params.index makePost:params.indexEndValue name:endKey]; + } else { + return params.index.maxPost; + } +} + +- (BOOL)matchesKey:(NSString *)key andNode:(id)node { + return ([self.index compareKey:self.startPost.name + andNode:self.startPost.node + toOtherKey:key + andNode:node] <= NSOrderedSame && + [self.index compareKey:key + andNode:node + toOtherKey:self.endPost.name + andNode:self.endPost.node] <= NSOrderedSame); +} + +- (FIndexedNode *)updateChildIn:(FIndexedNode *)oldSnap + forChildKey:(NSString *)childKey + newChild:(id)newChildSnap + affectedPath:(FPath *)affectedPath + fromSource:(id)source + accumulator: + (FChildChangeAccumulator *)optChangeAccumulator { + if (![self matchesKey:childKey andNode:newChildSnap]) { + newChildSnap = [FEmptyNode emptyNode]; + } + return [self.indexedFilter updateChildIn:oldSnap + forChildKey:childKey + newChild:newChildSnap + affectedPath:affectedPath + fromSource:source + accumulator:optChangeAccumulator]; +} + +- (FIndexedNode *)updateFullNode:(FIndexedNode *)oldSnap + withNewNode:(FIndexedNode *)newSnap + accumulator: + (FChildChangeAccumulator *)optChangeAccumulator { + __block FIndexedNode *filtered; + if (newSnap.node.isLeafNode) { + // Make sure we have a children node with the correct index, not a leaf + // node + filtered = [FIndexedNode indexedNodeWithNode:[FEmptyNode emptyNode] + index:self.index]; + } else { + // Dont' support priorities on queries + filtered = [newSnap updatePriority:[FEmptyNode emptyNode]]; + [newSnap.node enumerateChildrenUsingBlock:^( + NSString *key, id node, BOOL *stop) { + if (![self matchesKey:key andNode:node]) { + filtered = [filtered updateChild:key + withNewChild:[FEmptyNode emptyNode]]; + } + }]; + } + return [self.indexedFilter updateFullNode:oldSnap + withNewNode:filtered + accumulator:optChangeAccumulator]; +} + +- (FIndexedNode *)updatePriority:(id)priority + forNode:(FIndexedNode *)oldSnap { + // Don't support priorities on queries + return oldSnap; +} + +- (BOOL)filtersNodes { + return YES; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FTransformedEnumerator.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FTransformedEnumerator.h new file mode 100644 index 0000000..25a59b4 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FTransformedEnumerator.h @@ -0,0 +1,24 @@ +/* + * 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 + +@interface FTransformedEnumerator : NSEnumerator +- (id)initWithEnumerator:(NSEnumerator *)enumerator + andTransform:(id (^)(id))transform; +- (id)nextObject; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FTransformedEnumerator.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FTransformedEnumerator.m new file mode 100644 index 0000000..decb980 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FTransformedEnumerator.m @@ -0,0 +1,44 @@ +/* + * 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 "FirebaseDatabase/Sources/FTransformedEnumerator.h" + +@interface FTransformedEnumerator () +@property(nonatomic, strong) NSEnumerator *enumerator; +@property(nonatomic, copy) id (^transform)(id); +@end + +@implementation FTransformedEnumerator +- (id)initWithEnumerator:(NSEnumerator *)enumerator + andTransform:(id (^)(id))transform { + self = [super init]; + if (self) { + self.enumerator = enumerator; + self.transform = transform; + } + return self; +} + +- (id)nextObject { + id next = self.enumerator.nextObject; + if (next != nil) { + return self.transform(next); + } else { + return nil; + } +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FValueIndex.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FValueIndex.h new file mode 100644 index 0000000..260d566 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FValueIndex.h @@ -0,0 +1,22 @@ +/* + * 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 "FirebaseDatabase/Sources/FIndex.h" +#import + +@interface FValueIndex : NSObject ++ (id)valueIndex; +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FValueIndex.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FValueIndex.m new file mode 100644 index 0000000..6dde938 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FValueIndex.m @@ -0,0 +1,112 @@ +/* + * 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 "FirebaseDatabase/Sources/FValueIndex.h" +#import "FirebaseDatabase/Sources/FMaxNode.h" +#import "FirebaseDatabase/Sources/FNamedNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" + +@implementation FValueIndex + +- (NSComparisonResult)compareKey:(NSString *)key1 + andNode:(id)node1 + toOtherKey:(NSString *)key2 + andNode:(id)node2 { + NSComparisonResult indexCmp = [node1 compare:node2]; + if (indexCmp == NSOrderedSame) { + return [FUtilities compareKey:key1 toKey:key2]; + } else { + return indexCmp; + } +} + +- (NSComparisonResult)compareKey:(NSString *)key1 + andNode:(id)node1 + toOtherKey:(NSString *)key2 + andNode:(id)node2 + reverse:(BOOL)reverse { + if (reverse) { + return [self compareKey:key2 + andNode:node2 + toOtherKey:key1 + andNode:node1]; + } else { + return [self compareKey:key1 + andNode:node1 + toOtherKey:key2 + andNode:node2]; + } +} + +- (NSComparisonResult)compareNamedNode:(FNamedNode *)namedNode1 + toNamedNode:(FNamedNode *)namedNode2 { + return [self compareKey:namedNode1.name + andNode:namedNode1.node + toOtherKey:namedNode2.name + andNode:namedNode2.node]; +} + +- (BOOL)isDefinedOn:(id)node { + return YES; +} + +- (BOOL)indexedValueChangedBetween:(id)oldNode and:(id)newNode { + return ![oldNode isEqual:newNode]; +} + +- (FNamedNode *)minPost { + return FNamedNode.min; +} + +- (FNamedNode *)maxPost { + return FNamedNode.max; +} + +- (FNamedNode *)makePost:(id)indexValue name:(NSString *)name { + return [[FNamedNode alloc] initWithName:name andNode:indexValue]; +} + +- (NSString *)queryDefinition { + return @".value"; +} + +- (NSString *)description { + return @"FValueIndex"; +} + +- (id)copyWithZone:(NSZone *)zone { + return self; +} + +- (BOOL)isEqual:(id)other { + // since we're a singleton. + return (other == self); +} + +- (NSUInteger)hash { + return [@".value" hash]; +} + ++ (id)valueIndex { + static id valueIndex; + static dispatch_once_t once; + dispatch_once(&once, ^{ + valueIndex = [[FValueIndex alloc] init]; + }); + return valueIndex; +} +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FViewProcessor.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FViewProcessor.h new file mode 100644 index 0000000..ea6676e --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FViewProcessor.h @@ -0,0 +1,42 @@ +/* + * 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 + +@class FViewCache; +@class FViewProcessorResult; +@class FChildChangeAccumulator; +@protocol FNode; +@class FWriteTreeRef; +@class FPath; +@protocol FOperation; +@protocol FNodeFilter; + +@interface FViewProcessor : NSObject + +- (id)initWithFilter:(id)nodeFilter; + +- (FViewProcessorResult *)applyOperationOn:(FViewCache *)oldViewCache + operation:(id)operation + writesCache:(FWriteTreeRef *)writesCache + completeCache:(id)optCompleteCache; +- (FViewCache *)revertUserWriteOn:(FViewCache *)viewCache + path:(FPath *)path + writesCache:(FWriteTreeRef *)writesCache + completeCache:(id)optCompleteCache + accumulator:(FChildChangeAccumulator *)accumulator; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FViewProcessor.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FViewProcessor.m new file mode 100644 index 0000000..35ec642 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FViewProcessor.m @@ -0,0 +1,831 @@ +/* + * 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 "FirebaseDatabase/Sources/FViewProcessor.h" +#import "FirebaseDatabase/Sources/Core/FWriteTreeRef.h" +#import "FirebaseDatabase/Sources/Core/Operation/FAckUserWrite.h" +#import "FirebaseDatabase/Sources/Core/Operation/FMerge.h" +#import "FirebaseDatabase/Sources/Core/Operation/FOperation.h" +#import "FirebaseDatabase/Sources/Core/Operation/FOperationSource.h" +#import "FirebaseDatabase/Sources/Core/Operation/FOverwrite.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FImmutableTree.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Core/View/FCacheNode.h" +#import "FirebaseDatabase/Sources/Core/View/FChange.h" +#import "FirebaseDatabase/Sources/Core/View/FViewCache.h" +#import "FirebaseDatabase/Sources/Core/View/Filter/FChildChangeAccumulator.h" +#import "FirebaseDatabase/Sources/Core/View/Filter/FCompleteChildSource.h" +#import "FirebaseDatabase/Sources/Core/View/Filter/FNodeFilter.h" +#import "FirebaseDatabase/Sources/FKeyIndex.h" +#import "FirebaseDatabase/Sources/FViewProcessorResult.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDataEventType.h" +#import "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FCompoundWrite.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" + +/** + * An implementation of FCompleteChildSource that never returns any additional + * children + */ +@interface FNoCompleteChildSource : NSObject +@end + +@implementation FNoCompleteChildSource ++ (FNoCompleteChildSource *)instance { + static FNoCompleteChildSource *source = nil; + static dispatch_once_t once; + dispatch_once(&once, ^{ + source = [[FNoCompleteChildSource alloc] init]; + }); + return source; +} + +- (id)completeChild:(NSString *)childKey { + return nil; +} + +- (FNamedNode *)childByIndex:(id)index + afterChild:(FNamedNode *)child + isReverse:(BOOL)reverse { + return nil; +} +@end + +/** + * An implementation of FCompleteChildSource that uses a FWriteTree in addition + * to any other server data or old event caches available to calculate complete + * children. + */ +@interface FWriteTreeCompleteChildSource : NSObject +@property(nonatomic, strong) FWriteTreeRef *writes; +@property(nonatomic, strong) FViewCache *viewCache; +@property(nonatomic, strong) id optCompleteServerCache; +@end + +@implementation FWriteTreeCompleteChildSource +- (id)initWithWrites:(FWriteTreeRef *)writes + viewCache:(FViewCache *)viewCache + serverCache:(id)optCompleteServerCache { + self = [super init]; + if (self) { + self.writes = writes; + self.viewCache = viewCache; + self.optCompleteServerCache = optCompleteServerCache; + } + return self; +} + +- (id)completeChild:(NSString *)childKey { + FCacheNode *node = self.viewCache.cachedEventSnap; + if ([node isCompleteForChild:childKey]) { + return [node.node getImmediateChild:childKey]; + } else { + FCacheNode *serverNode; + if (self.optCompleteServerCache) { + // Since we're only ever getting child nodes, we can use the key + // index here + FIndexedNode *indexed = + [FIndexedNode indexedNodeWithNode:self.optCompleteServerCache + index:[FKeyIndex keyIndex]]; + serverNode = [[FCacheNode alloc] initWithIndexedNode:indexed + isFullyInitialized:YES + isFiltered:NO]; + } else { + serverNode = self.viewCache.cachedServerSnap; + } + return [self.writes calculateCompleteChild:childKey cache:serverNode]; + } +} + +- (FNamedNode *)childByIndex:(id)index + afterChild:(FNamedNode *)child + isReverse:(BOOL)reverse { + id completeServerData = self.optCompleteServerCache != nil + ? self.optCompleteServerCache + : self.viewCache.completeServerSnap; + return [self.writes calculateNextNodeAfterPost:child + completeServerData:completeServerData + reverse:reverse + index:index]; +} + +@end + +@interface FViewProcessor () +@property(nonatomic, strong) id filter; +@end + +@implementation FViewProcessor + +- (id)initWithFilter:(id)nodeFilter { + self = [super init]; + if (self) { + self.filter = nodeFilter; + } + return self; +} + +- (FViewProcessorResult *)applyOperationOn:(FViewCache *)oldViewCache + operation:(id)operation + writesCache:(FWriteTreeRef *)writesCache + completeCache:(id)optCompleteCache { + FChildChangeAccumulator *accumulator = + [[FChildChangeAccumulator alloc] init]; + FViewCache *newViewCache; + + if (operation.type == FOperationTypeOverwrite) { + FOverwrite *overwrite = (FOverwrite *)operation; + if (operation.source.fromUser) { + newViewCache = [self applyUserOverwriteTo:oldViewCache + changePath:overwrite.path + changedSnap:overwrite.snap + writesCache:writesCache + completeCache:optCompleteCache + accumulator:accumulator]; + } else { + NSAssert(operation.source.fromServer, + @"Unknown source for overwrite."); + // We filter the node if it's a tagged update or the node has been + // previously filtered and the update is not at the root in which + // case it is ok (and necessary) to mark the node unfiltered again + BOOL filterServerNode = overwrite.source.isTagged || + (oldViewCache.cachedServerSnap.isFiltered && + !overwrite.path.isEmpty); + newViewCache = [self applyServerOverwriteTo:oldViewCache + changePath:overwrite.path + snap:overwrite.snap + writesCache:writesCache + completeCache:optCompleteCache + filterServerNode:filterServerNode + accumulator:accumulator]; + } + } else if (operation.type == FOperationTypeMerge) { + FMerge *merge = (FMerge *)operation; + if (operation.source.fromUser) { + newViewCache = [self applyUserMergeTo:oldViewCache + path:merge.path + changedChildren:merge.children + writesCache:writesCache + completeCache:optCompleteCache + accumulator:accumulator]; + } else { + NSAssert(operation.source.fromServer, @"Unknown source for merge."); + // We filter the node if it's a tagged update or the node has been + // previously filtered + BOOL filterServerNode = merge.source.isTagged || + oldViewCache.cachedServerSnap.isFiltered; + newViewCache = [self applyServerMergeTo:oldViewCache + path:merge.path + changedChildren:merge.children + writesCache:writesCache + completeCache:optCompleteCache + filterServerNode:filterServerNode + accumulator:accumulator]; + } + } else if (operation.type == FOperationTypeAckUserWrite) { + FAckUserWrite *ackWrite = (FAckUserWrite *)operation; + if (!ackWrite.revert) { + newViewCache = [self ackUserWriteOn:oldViewCache + ackPath:ackWrite.path + affectedTree:ackWrite.affectedTree + writesCache:writesCache + completeCache:optCompleteCache + accumulator:accumulator]; + } else { + newViewCache = [self revertUserWriteOn:oldViewCache + path:ackWrite.path + writesCache:writesCache + completeCache:optCompleteCache + accumulator:accumulator]; + } + } else if (operation.type == FOperationTypeListenComplete) { + newViewCache = [self listenCompleteOldCache:oldViewCache + path:operation.path + writesCache:writesCache + serverCache:optCompleteCache + accumulator:accumulator]; + } else { + [NSException + raise:NSInternalInconsistencyException + format:@"Unknown operation encountered %ld.", (long)operation.type]; + return nil; + } + + NSArray *changes = [self maybeAddValueFromOldViewCache:oldViewCache + newViewCache:newViewCache + changes:accumulator.changes]; + FViewProcessorResult *results = + [[FViewProcessorResult alloc] initWithViewCache:newViewCache + changes:changes]; + return results; +} + +- (NSArray *)maybeAddValueFromOldViewCache:(FViewCache *)oldViewCache + newViewCache:(FViewCache *)newViewCache + changes:(NSArray *)changes { + NSArray *newChanges = changes; + FCacheNode *eventSnap = newViewCache.cachedEventSnap; + if (eventSnap.isFullyInitialized) { + BOOL isLeafOrEmpty = + eventSnap.node.isLeafNode || eventSnap.node.isEmpty; + if ([changes count] > 0 || + !oldViewCache.cachedEventSnap.isFullyInitialized || + (isLeafOrEmpty && + ![eventSnap.node isEqual:oldViewCache.completeEventSnap]) || + ![eventSnap.node.getPriority + isEqual:oldViewCache.completeEventSnap.getPriority]) { + FChange *valueChange = + [[FChange alloc] initWithType:FIRDataEventTypeValue + indexedNode:eventSnap.indexedNode]; + NSMutableArray *mutableChanges = [changes mutableCopy]; + [mutableChanges addObject:valueChange]; + newChanges = mutableChanges; + } + } + return newChanges; +} + +- (FViewCache *) + generateEventCacheAfterServerEvent:(FViewCache *)viewCache + path:(FPath *)changePath + writesCache:(FWriteTreeRef *)writesCache + source:(id)source + accumulator:(FChildChangeAccumulator *)accumulator { + FCacheNode *oldEventSnap = viewCache.cachedEventSnap; + if ([writesCache shadowingWriteAtPath:changePath] != nil) { + // we have a shadowing write, ignore changes. + return viewCache; + } else { + FIndexedNode *newEventCache; + if (changePath.isEmpty) { + // TODO: figure out how this plays with "sliding ack windows" + NSAssert( + viewCache.cachedServerSnap.isFullyInitialized, + @"If change path is empty, we must have complete server data"); + id nodeWithLocalWrites; + if (viewCache.cachedServerSnap.isFiltered) { + // We need to special case this, because we need to only apply + // writes to complete children, or we might end up raising + // events for incomplete children. If the server data is + // filtered deep writes cannot be guaranteed to be complete + id serverCache = viewCache.completeServerSnap; + FChildrenNode *completeChildren = + ([serverCache isKindOfClass:[FChildrenNode class]]) + ? serverCache + : [FEmptyNode emptyNode]; + nodeWithLocalWrites = [writesCache + calculateCompleteEventChildrenWithCompleteServerChildren: + completeChildren]; + } else { + nodeWithLocalWrites = [writesCache + calculateCompleteEventCacheWithCompleteServerCache: + viewCache.completeServerSnap]; + } + FIndexedNode *indexedNode = + [FIndexedNode indexedNodeWithNode:nodeWithLocalWrites + index:self.filter.index]; + newEventCache = [self.filter + updateFullNode:viewCache.cachedEventSnap.indexedNode + withNewNode:indexedNode + accumulator:accumulator]; + } else { + NSString *childKey = [changePath getFront]; + if ([childKey isEqualToString:@".priority"]) { + NSAssert( + changePath.length == 1, + @"Can't have a priority with additional path components"); + id oldEventNode = oldEventSnap.node; + id serverNode = viewCache.cachedServerSnap.node; + // we might have overwrites for this priority + id updatedPriority = [writesCache + calculateEventCacheAfterServerOverwriteWithChildPath: + changePath + existingEventSnap: + oldEventNode + existingServerSnap: + serverNode]; + if (updatedPriority != nil) { + newEventCache = + [self.filter updatePriority:updatedPriority + forNode:oldEventSnap.indexedNode]; + } else { + // priority didn't change, keep old node + newEventCache = oldEventSnap.indexedNode; + } + } else { + FPath *childChangePath = [changePath popFront]; + id newEventChild; + if ([oldEventSnap isCompleteForChild:childKey]) { + id serverNode = viewCache.cachedServerSnap.node; + id eventChildUpdate = [writesCache + calculateEventCacheAfterServerOverwriteWithChildPath: + changePath + existingEventSnap: + oldEventSnap.node + existingServerSnap: + serverNode]; + if (eventChildUpdate != nil) { + newEventChild = + [[oldEventSnap.node getImmediateChild:childKey] + updateChild:childChangePath + withNewChild:eventChildUpdate]; + } else { + // Nothing changed, just keep the old child + newEventChild = + [oldEventSnap.node getImmediateChild:childKey]; + } + } else { + newEventChild = [writesCache + calculateCompleteChild:childKey + cache:viewCache.cachedServerSnap]; + } + if (newEventChild != nil) { + newEventCache = + [self.filter updateChildIn:oldEventSnap.indexedNode + forChildKey:childKey + newChild:newEventChild + affectedPath:childChangePath + fromSource:source + accumulator:accumulator]; + } else { + // No complete children available or no change + newEventCache = oldEventSnap.indexedNode; + } + } + } + return [viewCache updateEventSnap:newEventCache + isComplete:(oldEventSnap.isFullyInitialized || + changePath.isEmpty) + isFiltered:self.filter.filtersNodes]; + } +} + +- (FViewCache *)applyServerOverwriteTo:(FViewCache *)oldViewCache + changePath:(FPath *)changePath + snap:(id)changedSnap + writesCache:(FWriteTreeRef *)writesCache + completeCache:(id)optCompleteCache + filterServerNode:(BOOL)filterServerNode + accumulator:(FChildChangeAccumulator *)accumulator { + FCacheNode *oldServerSnap = oldViewCache.cachedServerSnap; + FIndexedNode *newServerCache; + id serverFilter = + filterServerNode ? self.filter : self.filter.indexedFilter; + + if (changePath.isEmpty) { + FIndexedNode *indexed = + [FIndexedNode indexedNodeWithNode:changedSnap + index:serverFilter.index]; + newServerCache = [serverFilter updateFullNode:oldServerSnap.indexedNode + withNewNode:indexed + accumulator:nil]; + } else if (serverFilter.filtersNodes && !oldServerSnap.isFiltered) { + // We want to filter the server node, but we didn't filter the server + // node yet, so simulate a full update + NSAssert(![changePath isEmpty], + @"An empty path should been caught in the other branch"); + NSString *childKey = [changePath getFront]; + FPath *updatePath = [changePath popFront]; + id newChild = [[oldServerSnap.node getImmediateChild:childKey] + updateChild:updatePath + withNewChild:changedSnap]; + FIndexedNode *indexed = + [oldServerSnap.indexedNode updateChild:childKey + withNewChild:newChild]; + newServerCache = [serverFilter updateFullNode:oldServerSnap.indexedNode + withNewNode:indexed + accumulator:nil]; + } else { + NSString *childKey = [changePath getFront]; + if (![oldServerSnap isCompleteForPath:changePath] && + changePath.length > 1) { + // We don't update incomplete nodes with updates intended for other + // listeners. + return oldViewCache; + } + FPath *childChangePath = [changePath popFront]; + id childNode = [oldServerSnap.node getImmediateChild:childKey]; + id newChildNode = [childNode updateChild:childChangePath + withNewChild:changedSnap]; + if ([childKey isEqualToString:@".priority"]) { + newServerCache = + [serverFilter updatePriority:newChildNode + forNode:oldServerSnap.indexedNode]; + } else { + newServerCache = + [serverFilter updateChildIn:oldServerSnap.indexedNode + forChildKey:childKey + newChild:newChildNode + affectedPath:childChangePath + fromSource:[FNoCompleteChildSource instance] + accumulator:nil]; + } + } + FViewCache *newViewCache = + [oldViewCache updateServerSnap:newServerCache + isComplete:(oldServerSnap.isFullyInitialized || + changePath.isEmpty) + isFiltered:serverFilter.filtersNodes]; + id source = + [[FWriteTreeCompleteChildSource alloc] initWithWrites:writesCache + viewCache:newViewCache + serverCache:optCompleteCache]; + return [self generateEventCacheAfterServerEvent:newViewCache + path:changePath + writesCache:writesCache + source:source + accumulator:accumulator]; +} + +- (FViewCache *)applyUserOverwriteTo:(FViewCache *)oldViewCache + changePath:(FPath *)changePath + changedSnap:(id)changedSnap + writesCache:(FWriteTreeRef *)writesCache + completeCache:(id)optCompleteCache + accumulator:(FChildChangeAccumulator *)accumulator { + FCacheNode *oldEventSnap = oldViewCache.cachedEventSnap; + FViewCache *newViewCache; + id source = + [[FWriteTreeCompleteChildSource alloc] initWithWrites:writesCache + viewCache:oldViewCache + serverCache:optCompleteCache]; + if (changePath.isEmpty) { + FIndexedNode *newIndexed = + [FIndexedNode indexedNodeWithNode:changedSnap + index:self.filter.index]; + FIndexedNode *newEventCache = + [self.filter updateFullNode:oldEventSnap.indexedNode + withNewNode:newIndexed + accumulator:accumulator]; + newViewCache = [oldViewCache updateEventSnap:newEventCache + isComplete:YES + isFiltered:self.filter.filtersNodes]; + } else { + NSString *childKey = [changePath getFront]; + if ([childKey isEqualToString:@".priority"]) { + FIndexedNode *newEventCache = [self.filter + updatePriority:changedSnap + forNode:oldViewCache.cachedEventSnap.indexedNode]; + newViewCache = + [oldViewCache updateEventSnap:newEventCache + isComplete:oldEventSnap.isFullyInitialized + isFiltered:oldEventSnap.isFiltered]; + } else { + FPath *childChangePath = [changePath popFront]; + id oldChild = [oldEventSnap.node getImmediateChild:childKey]; + id newChild; + if (childChangePath.isEmpty) { + // Child overwrite, we can replace the child + newChild = changedSnap; + } else { + id childNode = [source completeChild:childKey]; + if (childNode != nil) { + if ([[childChangePath getBack] + isEqualToString:@".priority"] && + [childNode getChild:[childChangePath parent]].isEmpty) { + // This is a priority update on an empty node. If this + // node exists on the server, the server will send down + // the priority in the update, so ignore for now + newChild = childNode; + } else { + newChild = [childNode updateChild:childChangePath + withNewChild:changedSnap]; + } + } else { + newChild = [FEmptyNode emptyNode]; + } + } + if (![oldChild isEqual:newChild]) { + FIndexedNode *newEventSnap = + [self.filter updateChildIn:oldEventSnap.indexedNode + forChildKey:childKey + newChild:newChild + affectedPath:childChangePath + fromSource:source + accumulator:accumulator]; + newViewCache = [oldViewCache + updateEventSnap:newEventSnap + isComplete:oldEventSnap.isFullyInitialized + isFiltered:self.filter.filtersNodes]; + } else { + newViewCache = oldViewCache; + } + } + } + return newViewCache; +} + ++ (BOOL)cache:(FViewCache *)viewCache hasChild:(NSString *)childKey { + return [viewCache.cachedEventSnap isCompleteForChild:childKey]; +} + +/** + * @param changedChildren NSDictionary of child name (NSString*) to child value + * (id) + */ +- (FViewCache *)applyUserMergeTo:(FViewCache *)viewCache + path:(FPath *)path + changedChildren:(FCompoundWrite *)changedChildren + writesCache:(FWriteTreeRef *)writesCache + completeCache:(id)serverCache + accumulator:(FChildChangeAccumulator *)accumulator { + // HACK: In the case of a limit query, there may be some changes that bump + // things out of the window leaving room for new items. It's important we + // process these changes first, so we iterate the changes twice, first + // processing any that affect items currently in view. + // TODO: I consider an item "in view" if cacheHasChild is true, which checks + // both the server and event snap. I'm not sure if this will result in edge + // cases when a child is in one but not the other. + __block FViewCache *curViewCache = viewCache; + + [changedChildren enumerateWrites:^(FPath *relativePath, id childNode, + BOOL *stop) { + FPath *writePath = [path child:relativePath]; + if ([FViewProcessor cache:viewCache hasChild:[writePath getFront]]) { + curViewCache = [self applyUserOverwriteTo:curViewCache + changePath:writePath + changedSnap:childNode + writesCache:writesCache + completeCache:serverCache + accumulator:accumulator]; + } + }]; + + [changedChildren enumerateWrites:^(FPath *relativePath, id childNode, + BOOL *stop) { + FPath *writePath = [path child:relativePath]; + if (![FViewProcessor cache:viewCache hasChild:[writePath getFront]]) { + curViewCache = [self applyUserOverwriteTo:curViewCache + changePath:writePath + changedSnap:childNode + writesCache:writesCache + completeCache:serverCache + accumulator:accumulator]; + } + }]; + + return curViewCache; +} + +- (FViewCache *)applyServerMergeTo:(FViewCache *)viewCache + path:(FPath *)path + changedChildren:(FCompoundWrite *)changedChildren + writesCache:(FWriteTreeRef *)writesCache + completeCache:(id)serverCache + filterServerNode:(BOOL)filterServerNode + accumulator:(FChildChangeAccumulator *)accumulator { + // If we don't have a cache yet, this merge was intended for a previously + // listen in the same location. Ignore it and wait for the complete data + // update coming soon. + if (viewCache.cachedServerSnap.node.isEmpty && + !viewCache.cachedServerSnap.isFullyInitialized) { + return viewCache; + } + + // HACK: In the case of a limit query, there may be some changes that bump + // things out of the window leaving room for new items. It's important we + // process these changes first, so we iterate the changes twice, first + // processing any that affect items currently in view. + // TODO: I consider an item "in view" if cacheHasChild is true, which checks + // both the server and event snap. I'm not sure if this will result in edge + // cases when a child is in one but not the other. + __block FViewCache *curViewCache = viewCache; + FCompoundWrite *actualMerge; + if (path.isEmpty) { + actualMerge = changedChildren; + } else { + actualMerge = + [[FCompoundWrite emptyWrite] addCompoundWrite:changedChildren + atPath:path]; + } + id serverNode = viewCache.cachedServerSnap.node; + + NSDictionary *childCompoundWrites = actualMerge.childCompoundWrites; + [childCompoundWrites + enumerateKeysAndObjectsUsingBlock:^( + NSString *childKey, FCompoundWrite *childMerge, BOOL *stop) { + if ([serverNode hasChild:childKey]) { + id serverChild = + [viewCache.cachedServerSnap.node getImmediateChild:childKey]; + id newChild = [childMerge applyToNode:serverChild]; + curViewCache = + [self applyServerOverwriteTo:curViewCache + changePath:[[FPath alloc] initWith:childKey] + snap:newChild + writesCache:writesCache + completeCache:serverCache + filterServerNode:filterServerNode + accumulator:accumulator]; + } + }]; + + [childCompoundWrites + enumerateKeysAndObjectsUsingBlock:^( + NSString *childKey, FCompoundWrite *childMerge, BOOL *stop) { + bool isUnknownDeepMerge = + ![viewCache.cachedServerSnap isCompleteForChild:childKey] && + childMerge.rootWrite == nil; + if (![serverNode hasChild:childKey] && !isUnknownDeepMerge) { + id serverChild = + [viewCache.cachedServerSnap.node getImmediateChild:childKey]; + id newChild = [childMerge applyToNode:serverChild]; + curViewCache = + [self applyServerOverwriteTo:curViewCache + changePath:[[FPath alloc] initWith:childKey] + snap:newChild + writesCache:writesCache + completeCache:serverCache + filterServerNode:filterServerNode + accumulator:accumulator]; + } + }]; + + return curViewCache; +} + +- (FViewCache *)ackUserWriteOn:(FViewCache *)viewCache + ackPath:(FPath *)ackPath + affectedTree:(FImmutableTree *)affectedTree + writesCache:(FWriteTreeRef *)writesCache + completeCache:(id)optCompleteCache + accumulator:(FChildChangeAccumulator *)accumulator { + + if ([writesCache shadowingWriteAtPath:ackPath] != nil) { + return viewCache; + } + + // Only filter server node if it is currently filtered + BOOL filterServerNode = viewCache.cachedServerSnap.isFiltered; + + // Essentially we'll just get our existing server cache for the affected + // paths and re-apply it as a server update now that it won't be shadowed. + FCacheNode *serverCache = viewCache.cachedServerSnap; + if (affectedTree.value != nil) { + // This is an overwrite. + if ((ackPath.isEmpty && serverCache.isFullyInitialized) || + [serverCache isCompleteForPath:ackPath]) { + return + [self applyServerOverwriteTo:viewCache + changePath:ackPath + snap:[serverCache.node getChild:ackPath] + writesCache:writesCache + completeCache:optCompleteCache + filterServerNode:filterServerNode + accumulator:accumulator]; + } else if (ackPath.isEmpty) { + // This is a goofy edge case where we are acking data at this + // location but don't have full data. We should just re-apply + // whatever we have in our cache as a merge. + FCompoundWrite *changedChildren = [FCompoundWrite emptyWrite]; + for (FNamedNode *child in serverCache.node.childEnumerator) { + changedChildren = [changedChildren addWrite:child.node + atKey:child.name]; + } + return [self applyServerMergeTo:viewCache + path:ackPath + changedChildren:changedChildren + writesCache:writesCache + completeCache:optCompleteCache + filterServerNode:filterServerNode + accumulator:accumulator]; + } else { + return viewCache; + } + } else { + // This is a merge. + __block FCompoundWrite *changedChildren = [FCompoundWrite emptyWrite]; + [affectedTree forEach:^(FPath *mergePath, id value) { + FPath *serverCachePath = [ackPath child:mergePath]; + if ([serverCache isCompleteForPath:serverCachePath]) { + changedChildren = [changedChildren + addWrite:[serverCache.node getChild:serverCachePath] + atPath:mergePath]; + } + }]; + return [self applyServerMergeTo:viewCache + path:ackPath + changedChildren:changedChildren + writesCache:writesCache + completeCache:optCompleteCache + filterServerNode:filterServerNode + accumulator:accumulator]; + } +} + +- (FViewCache *)revertUserWriteOn:(FViewCache *)viewCache + path:(FPath *)path + writesCache:(FWriteTreeRef *)writesCache + completeCache:(id)optCompleteCache + accumulator:(FChildChangeAccumulator *)accumulator { + if ([writesCache shadowingWriteAtPath:path] != nil) { + return viewCache; + } else { + id source = [[FWriteTreeCompleteChildSource alloc] + initWithWrites:writesCache + viewCache:viewCache + serverCache:optCompleteCache]; + FIndexedNode *oldEventCache = viewCache.cachedEventSnap.indexedNode; + FIndexedNode *newEventCache; + if (path.isEmpty || [[path getFront] isEqualToString:@".priority"]) { + id newNode; + if (viewCache.cachedServerSnap.isFullyInitialized) { + newNode = [writesCache + calculateCompleteEventCacheWithCompleteServerCache: + viewCache.completeServerSnap]; + } else { + newNode = [writesCache + calculateCompleteEventChildrenWithCompleteServerChildren: + viewCache.cachedServerSnap.node]; + } + FIndexedNode *indexedNode = + [FIndexedNode indexedNodeWithNode:newNode + index:self.filter.index]; + newEventCache = [self.filter updateFullNode:oldEventCache + withNewNode:indexedNode + accumulator:accumulator]; + } else { + NSString *childKey = [path getFront]; + id newChild = + [writesCache calculateCompleteChild:childKey + cache:viewCache.cachedServerSnap]; + if (newChild == nil && + [viewCache.cachedServerSnap isCompleteForChild:childKey]) { + newChild = [oldEventCache.node getImmediateChild:childKey]; + } + if (newChild != nil) { + newEventCache = [self.filter updateChildIn:oldEventCache + forChildKey:childKey + newChild:newChild + affectedPath:[path popFront] + fromSource:source + accumulator:accumulator]; + } else if (newChild == nil && + [viewCache.cachedEventSnap.node hasChild:childKey]) { + // No complete child available, delete the existing one, if any + newEventCache = + [self.filter updateChildIn:oldEventCache + forChildKey:childKey + newChild:[FEmptyNode emptyNode] + affectedPath:[path popFront] + fromSource:source + accumulator:accumulator]; + } else { + newEventCache = oldEventCache; + } + if (newEventCache.node.isEmpty && + viewCache.cachedServerSnap.isFullyInitialized) { + // We might have reverted all child writes. Maybe the old event + // was a leaf node. + id complete = [writesCache + calculateCompleteEventCacheWithCompleteServerCache: + viewCache.completeServerSnap]; + if (complete.isLeafNode) { + FIndexedNode *indexed = + [FIndexedNode indexedNodeWithNode:complete]; + newEventCache = [self.filter updateFullNode:newEventCache + withNewNode:indexed + accumulator:accumulator]; + } + } + } + BOOL complete = viewCache.cachedServerSnap.isFullyInitialized || + [writesCache shadowingWriteAtPath:[FPath empty]] != nil; + return [viewCache updateEventSnap:newEventCache + isComplete:complete + isFiltered:self.filter.filtersNodes]; + } +} + +- (FViewCache *)listenCompleteOldCache:(FViewCache *)viewCache + path:(FPath *)path + writesCache:(FWriteTreeRef *)writesCache + serverCache:(id)servercache + accumulator:(FChildChangeAccumulator *)accumulator { + FCacheNode *oldServerNode = viewCache.cachedServerSnap; + FViewCache *newViewCache = [viewCache + updateServerSnap:oldServerNode.indexedNode + isComplete:(oldServerNode.isFullyInitialized || path.isEmpty) + isFiltered:oldServerNode.isFiltered]; + return [self + generateEventCacheAfterServerEvent:newViewCache + path:path + writesCache:writesCache + source:[FNoCompleteChildSource instance] + accumulator:accumulator]; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FViewProcessorResult.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FViewProcessorResult.h new file mode 100644 index 0000000..8d3e2ef --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FViewProcessorResult.h @@ -0,0 +1,29 @@ +/* + * 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 + +@class FViewCache; + +@interface FViewProcessorResult : NSObject +@property(nonatomic, strong, readonly) FViewCache *viewCache; +/** + * List of FChanges. + */ +@property(nonatomic, strong, readonly) NSArray *changes; + +- (id)initWithViewCache:(FViewCache *)viewCache changes:(NSArray *)changes; +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FViewProcessorResult.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FViewProcessorResult.m new file mode 100644 index 0000000..8cfe7f3 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/FViewProcessorResult.m @@ -0,0 +1,35 @@ +/* + * 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 "FirebaseDatabase/Sources/FViewProcessorResult.h" +#import "FirebaseDatabase/Sources/Core/View/FViewCache.h" + +@interface FViewProcessorResult () +@property(nonatomic, strong, readwrite) FViewCache *viewCache; +@property(nonatomic, strong, readwrite) NSArray *changes; +@end + +@implementation FViewProcessorResult +- (id)initWithViewCache:(FViewCache *)viewCache changes:(NSArray *)changes { + self = [super init]; + if (self) { + self.viewCache = viewCache; + self.changes = changes; + } + return self; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Login/FIRDatabaseConnectionContextProvider.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Login/FIRDatabaseConnectionContextProvider.h new file mode 100644 index 0000000..5f025e1 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Login/FIRDatabaseConnectionContextProvider.h @@ -0,0 +1,70 @@ +/* + * Copyright 2021 Google LLC + * + * 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 + +#import "FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h" +#import "FirebaseDatabase/Sources/Utilities/FTypedefs.h" + +@protocol FIRAppCheckInterop; +@protocol FIRAuthInterop; + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRDatabaseConnectionContext : NSObject +/// Auth token if available. +@property(nonatomic, nullable) NSString *authToken; + +/// App check token if available. +@property(nonatomic, nullable) NSString *appCheckToken; + +- (instancetype)initWithAuthToken:(nullable NSString *)authToken + appCheckToken:(nullable NSString *)appCheckToken; + +@end + +@protocol FIRDatabaseConnectionContextProvider + +- (void) + fetchContextForcingRefresh:(BOOL)forceRefresh + withCallback: + (void (^)(FIRDatabaseConnectionContext *_Nullable context, + NSError *_Nullable error))callback; + +/// Adds a listener to the Auth token updates. +/// @param listener A block that will be invoked each time the Auth token is +/// updated. +- (void)listenForAuthTokenChanges:(fbt_void_nsstring)listener; + +/// Adds a listener to the FAC token updates. +/// @param listener A block that will be invoked each time the FAC token is +/// updated. +- (void)listenForAppCheckTokenChanges:(fbt_void_nsstring)listener; + +@end + +@interface FIRDatabaseConnectionContextProvider + : NSObject + ++ (id) + contextProviderWithAuth:(nullable id)auth + appCheck:(nullable id)appCheck; + +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Login/FIRDatabaseConnectionContextProvider.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Login/FIRDatabaseConnectionContextProvider.m new file mode 100644 index 0000000..21b50f2 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Login/FIRDatabaseConnectionContextProvider.m @@ -0,0 +1,225 @@ +/* + * Copyright 2021 Google LLC + * + * 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 "FirebaseDatabase/Sources/Login/FIRDatabaseConnectionContextProvider.h" + +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" + +#import "FirebaseAppCheck/Interop/FIRAppCheckInterop.h" +#import "FirebaseAppCheck/Interop/FIRAppCheckTokenResultInterop.h" +#import "FirebaseAuth/Interop/FIRAuthInterop.h" + +#import "FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FAuthStateListenerWrapper : NSObject + +@property(nonatomic, copy) fbt_void_nsstring listener; +@property(nonatomic, weak) id auth; + +@end + +@implementation FAuthStateListenerWrapper + +- (instancetype)initWithListener:(fbt_void_nsstring)listener + auth:(id)auth { + self = [super init]; + if (self != nil) { + self->_listener = listener; + self->_auth = auth; + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(authStateDidChangeNotification:) + name:FIRAuthStateDidChangeInternalNotification + object:nil]; + } + return self; +} + +- (void)authStateDidChangeNotification:(NSNotification *)notification { + NSDictionary *userInfo = notification.userInfo; + if (notification.object == self.auth) { + NSString *token = + userInfo[FIRAuthStateDidChangeInternalNotificationTokenKey]; + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + self.listener(token); + }); + } +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +@end + +@implementation FIRDatabaseConnectionContext + +- (instancetype)initWithAuthToken:(nullable NSString *)authToken + appCheckToken:(nullable NSString *)appCheckToken { + self = [super init]; + if (self) { + _authToken = [authToken copy]; + _appCheckToken = [appCheckToken copy]; + } + return self; +} + +@end + +@interface FIRDatabaseConnectionContextProvider () + +@property(nonatomic, strong) id appCheck; +@property(nonatomic, strong) id auth; + +/// Strong references to the auth listeners as they are only weak in +/// FIRFirebaseApp. +@property(nonatomic, readonly) NSMutableArray *authListeners; + +/// Observer objects returned by +/// `-[NSNotificationCenter addObserverForName:object:queue:usingBlock:]` +/// method. Required to cleanup the observers on dealloc. +@property(nonatomic, readonly) NSMutableArray *appCheckNotificationObservers; + +/// An NSOperationQueue to call listeners on. +@property(nonatomic, readonly) NSOperationQueue *listenerQueue; + +@end + +@implementation FIRDatabaseConnectionContextProvider + +- (instancetype)initWithAuth:(nullable id)auth + appCheck:(nullable id)appCheck { + self = [super init]; + if (self != nil) { + self->_appCheck = appCheck; + self->_auth = auth; + self->_authListeners = [NSMutableArray array]; + self->_appCheckNotificationObservers = [NSMutableArray array]; + self->_listenerQueue = [[NSOperationQueue alloc] init]; + self->_listenerQueue.underlyingQueue = [FIRDatabaseQuery sharedQueue]; + } + return self; +} + +- (void)dealloc { + @synchronized(self) { + // Make sure notification observers are removed from + // NSNotificationCenter. + for (id notificationObserver in self.appCheckNotificationObservers) { + [NSNotificationCenter.defaultCenter + removeObserver:notificationObserver]; + } + } +} + +- (void) + fetchContextForcingRefresh:(BOOL)forceRefresh + withCallback: + (void (^)(FIRDatabaseConnectionContext *_Nullable context, + NSError *_Nullable error))callback { + + if (self.auth == nil && self.appCheck == nil) { + // Nothing to fetch. Finish straight away. + callback(nil, nil); + return; + } + + // Use dispatch group to call the callback when both Auth and FAC operations + // finished. + dispatch_group_t dispatchGroup = dispatch_group_create(); + + __block NSString *authToken; + __block NSString *appCheckToken; + __block NSError *authError; + + if (self.auth) { + dispatch_group_enter(dispatchGroup); + [self.auth getTokenForcingRefresh:forceRefresh + withCallback:^(NSString *_Nullable token, + NSError *_Nullable error) { + authToken = token; + authError = error; + + dispatch_group_leave(dispatchGroup); + }]; + } + + if (self.appCheck) { + dispatch_group_enter(dispatchGroup); + [self.appCheck + getTokenForcingRefresh:forceRefresh + completion:^( + id _Nonnull tokenResult) { + appCheckToken = tokenResult.token; + if (tokenResult.error) { + FFLog(@"I-RDB096001", + @"Failed to fetch App Check token: %@", + tokenResult.error); + } + dispatch_group_leave(dispatchGroup); + }]; + } + + dispatch_group_notify(dispatchGroup, [FIRDatabaseQuery sharedQueue], ^{ + __auto_type context = [[FIRDatabaseConnectionContext alloc] + initWithAuthToken:authToken + appCheckToken:appCheckToken]; + // Pass only a possible Auth error. App Check errors should not change the + // database SDK behaviour at this point as the App Check enforcement is + // controlled on the backend. + callback(context, authError); + }); +} + +- (void)listenForAuthTokenChanges:(_Nonnull fbt_void_nsstring)listener { + FAuthStateListenerWrapper *wrapper = + [[FAuthStateListenerWrapper alloc] initWithListener:listener + auth:self.auth]; + [self.authListeners addObject:wrapper]; +} + +- (void)listenForAppCheckTokenChanges:(fbt_void_nsstring)listener { + if (self.appCheck == nil) { + return; + } + NSString *appCheckTokenKey = [self.appCheck notificationTokenKey]; + __auto_type notificationObserver = [NSNotificationCenter.defaultCenter + addObserverForName:[self.appCheck tokenDidChangeNotificationName] + object:self.appCheck + queue:self.listenerQueue + usingBlock:^(NSNotification *_Nonnull notification) { + NSString *appCheckToken = + notification.userInfo[appCheckTokenKey]; + listener(appCheckToken); + }]; + + @synchronized(self) { + [self.appCheckNotificationObservers addObject:notificationObserver]; + } +} + ++ (id) + contextProviderWithAuth:(nullable id)auth + appCheck:(nullable id)appCheck { + return [[self alloc] initWithAuth:auth appCheck:appCheck]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FCachePolicy.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FCachePolicy.h new file mode 100644 index 0000000..6305d34 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FCachePolicy.h @@ -0,0 +1,41 @@ +/* + * 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 + +@protocol FCachePolicy + +- (BOOL)shouldPruneCacheWithSize:(NSUInteger)cacheSize + numberOfTrackedQueries:(NSUInteger)numTrackedQueries; +- (BOOL)shouldCheckCacheSize:(NSUInteger)serverUpdatesSinceLastCheck; +- (float)percentOfQueriesToPruneAtOnce; +- (NSUInteger)maxNumberOfQueriesToKeep; + +@end + +@interface FLRUCachePolicy : NSObject + +@property(nonatomic, readonly) NSUInteger maxSize; + +- (id)initWithMaxSize:(NSUInteger)maxSize; + +@end + +@interface FNoCachePolicy : NSObject + ++ (FNoCachePolicy *)noCachePolicy; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FCachePolicy.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FCachePolicy.m new file mode 100644 index 0000000..83ef516 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FCachePolicy.m @@ -0,0 +1,82 @@ +/* + * 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 "FirebaseDatabase/Sources/Persistence/FCachePolicy.h" + +@interface FLRUCachePolicy () + +@property(nonatomic, readwrite) NSUInteger maxSize; + +@end + +static const NSUInteger kFServerUpdatesBetweenCacheSizeChecks = 1000; +static const NSUInteger kFMaxNumberOfPrunableQueriesToKeep = 1000; +static const float kFPercentOfQueriesToPruneAtOnce = 0.2f; + +@implementation FLRUCachePolicy + +- (id)initWithMaxSize:(NSUInteger)maxSize { + self = [super init]; + if (self != nil) { + self->_maxSize = maxSize; + } + return self; +} + +- (BOOL)shouldPruneCacheWithSize:(NSUInteger)cacheSize + numberOfTrackedQueries:(NSUInteger)numTrackedQueries { + return cacheSize > self.maxSize || + numTrackedQueries > kFMaxNumberOfPrunableQueriesToKeep; +} + +- (BOOL)shouldCheckCacheSize:(NSUInteger)serverUpdatesSinceLastCheck { + return serverUpdatesSinceLastCheck > kFServerUpdatesBetweenCacheSizeChecks; +} + +- (float)percentOfQueriesToPruneAtOnce { + return kFPercentOfQueriesToPruneAtOnce; +} + +- (NSUInteger)maxNumberOfQueriesToKeep { + return kFMaxNumberOfPrunableQueriesToKeep; +} + +@end + +@implementation FNoCachePolicy + ++ (FNoCachePolicy *)noCachePolicy { + return [[FNoCachePolicy alloc] init]; +} + +- (BOOL)shouldPruneCacheWithSize:(NSUInteger)cacheSize + numberOfTrackedQueries:(NSUInteger)numTrackedQueries { + return NO; +} + +- (BOOL)shouldCheckCacheSize:(NSUInteger)serverUpdatesSinceLastCheck { + return NO; +} + +- (float)percentOfQueriesToPruneAtOnce { + return 0; +} + +- (NSUInteger)maxNumberOfQueriesToKeep { + return NSUIntegerMax; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FLevelDBStorageEngine.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FLevelDBStorageEngine.h new file mode 100644 index 0000000..82b340e --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FLevelDBStorageEngine.h @@ -0,0 +1,39 @@ +/* + * 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 + +#import "FirebaseDatabase/Sources/Core/FQuerySpec.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Persistence/FStorageEngine.h" +#import "FirebaseDatabase/Sources/Snapshot/FCompoundWrite.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" + +@class FCacheNode; +@class FTrackedQuery; +@class FPruneForest; +@class FRepoInfo; + +@interface FLevelDBStorageEngine : NSObject + ++ (NSString *)firebaseDir; + +- (id)initWithPath:(NSString *)path; + +- (void)runLegacyMigration:(FRepoInfo *)info; +- (void)purgeEverything; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FLevelDBStorageEngine.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FLevelDBStorageEngine.m new file mode 100644 index 0000000..9422d9f --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FLevelDBStorageEngine.m @@ -0,0 +1,1002 @@ +/* + * 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 + +#import "FirebaseDatabase/Sources/Persistence/FLevelDBStorageEngine.h" + +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" +#import "FirebaseDatabase/Sources/Core/FQueryParams.h" +#import "FirebaseDatabase/Sources/Core/FWriteRecord.h" +#import "FirebaseDatabase/Sources/Persistence/FPendingPut.h" +#import "FirebaseDatabase/Sources/Persistence/FPruneForest.h" +#import "FirebaseDatabase/Sources/Persistence/FTrackedQuery.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" +#import "FirebaseDatabase/Sources/third_party/Wrap-leveldb/APLevelDB.h" + +@interface FLevelDBStorageEngine () + +@property(nonatomic, strong) NSString *basePath; +@property(nonatomic, strong) APLevelDB *writesDB; +@property(nonatomic, strong) APLevelDB *serverCacheDB; + +@end + +// WARNING: If you change this, you need to write a migration script +static NSString *const kFPersistenceVersion = @"1"; + +static NSString *const kFServerDBPath = @"server_data"; +static NSString *const kFWritesDBPath = @"writes"; + +static NSString *const kFUserWriteId = @"id"; +static NSString *const kFUserWritePath = @"path"; +static NSString *const kFUserWriteOverwrite = @"o"; +static NSString *const kFUserWriteMerge = @"m"; + +static NSString *const kFTrackedQueryId = @"id"; +static NSString *const kFTrackedQueryPath = @"path"; +static NSString *const kFTrackedQueryParams = @"p"; +static NSString *const kFTrackedQueryLastUse = @"lu"; +static NSString *const kFTrackedQueryIsComplete = @"c"; +static NSString *const kFTrackedQueryIsActive = @"a"; + +static NSString *const kFServerCachePrefix = @"/server_cache/"; +// '~' is the last non-control character in the ASCII table until 127 +// We wan't the entire range of thing stored in the DB +static NSString *const kFServerCacheRangeEnd = @"/server_cache~"; +static NSString *const kFTrackedQueriesPrefix = @"/tracked_queries/"; +static NSString *const kFTrackedQueryKeysPrefix = @"/tracked_query_keys/"; + +// Failed to load JSON because a valid JSON turns out to be NaN while +// deserializing +static const NSInteger kFNanFailureCode = 3840; + +static NSString *writeRecordKey(NSUInteger writeId) { + return [NSString stringWithFormat:@"%lu", (unsigned long)(writeId)]; +} + +static NSString *serverCacheKey(FPath *path) { + return [NSString stringWithFormat:@"%@%@", kFServerCachePrefix, + ([path toStringWithTrailingSlash])]; +} + +static NSString *trackedQueryKey(NSUInteger trackedQueryId) { + return [NSString stringWithFormat:@"%@%lu", kFTrackedQueriesPrefix, + (unsigned long)trackedQueryId]; +} + +static NSString *trackedQueryKeysKeyPrefix(NSUInteger trackedQueryId) { + return [NSString stringWithFormat:@"%@%lu/", kFTrackedQueryKeysPrefix, + (unsigned long)trackedQueryId]; +} + +static NSString *trackedQueryKeysKey(NSUInteger trackedQueryId, NSString *key) { + return [NSString stringWithFormat:@"%@%lu/%@", kFTrackedQueryKeysPrefix, + (unsigned long)trackedQueryId, key]; +} + +@implementation FLevelDBStorageEngine +#pragma mark - Constructors + +- (id)initWithPath:(NSString *)dbPath { + self = [super init]; + if (self) { + self.basePath = [[FLevelDBStorageEngine firebaseDir] + stringByAppendingPathComponent:dbPath]; + /* For reference: + serverDataDB = [aPersistence createDbByName:@"server_data"]; + FPangolinDB *completenessDb = [aPersistence + createDbByName:@"server_complete"]; + */ + [FLevelDBStorageEngine ensureDir:self.basePath markAsDoNotBackup:YES]; + [self runMigration]; + [self openDatabases]; + } + return self; +} + +- (void)runMigration { + // Currently we're at version 1, so all we need to do is write that to a + // file + NSString *versionFile = + [self.basePath stringByAppendingPathComponent:@"version"]; + NSError *error; + NSString *oldVersion = + [NSString stringWithContentsOfFile:versionFile + encoding:NSUTF8StringEncoding + error:&error]; + if (!oldVersion) { + // This is probably fine, we don't have a version file yet + BOOL success = [kFPersistenceVersion writeToFile:versionFile + atomically:NO + encoding:NSUTF8StringEncoding + error:&error]; + if (!success) { + FFWarn(@"I-RDB076001", @"Failed to write version for database: %@", + error); + } + } else if ([oldVersion isEqualToString:kFPersistenceVersion]) { + // Everythings fine no need for migration + } else if ([oldVersion length] == 0) { + FFWarn(@"I-RDB076036", + @"Version file empty. Assuming database version 1."); + } else { + // If we add more versions in the future, we need to run migration here + [NSException raise:NSInternalInconsistencyException + format:@"Unrecognized database version: %@", oldVersion]; + } +} + +- (void)runLegacyMigration:(FRepoInfo *)info { + NSArray *dirPaths = NSSearchPathForDirectoriesInDomains( + NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentsDir = [dirPaths objectAtIndex:0]; + NSString *firebaseDir = + [documentsDir stringByAppendingPathComponent:@"firebase"]; + NSString *repoHashString = + [NSString stringWithFormat:@"%@_%@", info.host, info.namespace]; + NSString *legacyBaseDir = + [NSString stringWithFormat:@"%@/1/%@/v1", firebaseDir, repoHashString]; + if ([[NSFileManager defaultManager] fileExistsAtPath:legacyBaseDir]) { + FFWarn(@"I-RDB076002", @"Legacy database found, migrating..."); + // We only need to migrate writes + NSError *error = nil; + APLevelDB *writes = [APLevelDB + levelDBWithPath:[legacyBaseDir stringByAppendingPathComponent: + @"outstanding_puts"] + error:&error]; + if (writes != nil) { + __block NSUInteger numberOfWritesRestored = 0; + // Maybe we could use write batches, but what the heck, I'm sure + // it'll go fine :P + [writes enumerateKeysAndValuesAsData:^(NSString *key, NSData *data, + BOOL *stop) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + // Update the deprecated API when minimum iOS version is 11+. + id pendingPut = [NSKeyedUnarchiver unarchiveObjectWithData:data]; +#pragma clang diagnostic pop + if ([pendingPut isKindOfClass:[FPendingPut class]]) { + FPendingPut *put = pendingPut; + id newNode = + [FSnapshotUtilities nodeFrom:put.data + priority:put.priority]; + [self saveUserOverwrite:newNode + atPath:put.path + writeId:[key integerValue]]; + numberOfWritesRestored++; + } else if ([pendingPut + isKindOfClass:[FPendingPutPriority class]]) { + // This is for backwards compatibility. Older clients will + // save FPendingPutPriority. New ones will need to read it and + // translate. + FPendingPutPriority *putPriority = pendingPut; + FPath *priorityPath = + [putPriority.path childFromString:@".priority"]; + id newNode = + [FSnapshotUtilities nodeFrom:putPriority.priority + priority:nil]; + [self saveUserOverwrite:newNode + atPath:priorityPath + writeId:[key integerValue]]; + numberOfWritesRestored++; + } else if ([pendingPut isKindOfClass:[FPendingUpdate class]]) { + FPendingUpdate *update = pendingPut; + FCompoundWrite *merge = [FCompoundWrite + compoundWriteWithValueDictionary:update.data]; + [self saveUserMerge:merge + atPath:update.path + writeId:[key integerValue]]; + numberOfWritesRestored++; + } else { + FFWarn(@"I-RDB076003", + @"Failed to migrate legacy write, meh!"); + } + }]; + FFWarn(@"I-RDB076004", @"Migrated %lu writes", + (unsigned long)numberOfWritesRestored); + [writes close]; + FFWarn(@"I-RDB076005", @"Deleting legacy database..."); + BOOL success = + [[NSFileManager defaultManager] removeItemAtPath:legacyBaseDir + error:&error]; + if (!success) { + FFWarn(@"I-RDB076006", @"Failed to delete legacy database: %@", + error); + } else { + FFWarn(@"I-RDB076007", @"Finished migrating legacy database."); + } + } else { + FFWarn(@"I-RDB076008", @"Failed to migrate old database: %@", + error); + } + } +} + +- (void)openDatabases { + self.serverCacheDB = [self createDB:kFServerDBPath]; + self.writesDB = [self createDB:kFWritesDBPath]; +} + +- (void)purgeDatabase:(NSString *)dbPath { + NSString *path = [self.basePath stringByAppendingPathComponent:dbPath]; + NSError *error; + FFWarn(@"I-RDB076009", @"Deleting database at path %@", path); + BOOL success = [[NSFileManager defaultManager] removeItemAtPath:path + error:&error]; + if (!success) { + [NSException raise:NSInternalInconsistencyException + format:@"Failed to delete database files: %@", error]; + } +} + +- (void)purgeEverything { + [self close]; + [@[ kFServerDBPath, kFWritesDBPath ] + enumerateObjectsUsingBlock:^(NSString *dbPath, NSUInteger idx, + BOOL *stop) { + [self purgeDatabase:dbPath]; + }]; + + [self openDatabases]; +} + +- (void)close { + // autoreleasepool will cause deallocation which will close the DB + @autoreleasepool { + [self.serverCacheDB close]; + self.serverCacheDB = nil; + [self.writesDB close]; + self.writesDB = nil; + } +} + ++ (NSString *)firebaseDir { +#if TARGET_OS_IOS || TARGET_OS_WATCH + NSArray *dirPaths = NSSearchPathForDirectoriesInDomains( + NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentsDir = [dirPaths objectAtIndex:0]; + return [documentsDir stringByAppendingPathComponent:@"firebase"]; +#elif TARGET_OS_TV + NSArray *dirPaths = NSSearchPathForDirectoriesInDomains( + NSCachesDirectory, NSUserDomainMask, YES); + NSString *cachesDir = [dirPaths objectAtIndex:0]; + return [cachesDir stringByAppendingPathComponent:@"firebase"]; +#elif TARGET_OS_OSX + return [NSHomeDirectory() stringByAppendingPathComponent:@".firebase"]; +#endif +} + +- (APLevelDB *)createDB:(NSString *)dbName { + NSError *err = nil; + NSString *path = [self.basePath stringByAppendingPathComponent:dbName]; + APLevelDB *db = [APLevelDB levelDBWithPath:path error:&err]; + + if (err) { + FFWarn(@"I-RDB076036", + @"Failed to read database persistence file '%@': %@", dbName, + [err localizedDescription]); + err = nil; + + // Delete the database and try again. + [self purgeDatabase:dbName]; + db = [APLevelDB levelDBWithPath:path error:&err]; + + if (err) { + NSString *reason = [NSString + stringWithFormat:@"Error initializing persistence: %@", + [err description]]; + @throw [NSException + exceptionWithName:@"FirebaseDatabasePersistenceFailure" + reason:reason + userInfo:nil]; + } + } + + return db; +} + +- (void)saveUserOverwrite:(id)node + atPath:(FPath *)path + writeId:(NSUInteger)writeId { + NSDictionary *write = @{ + kFUserWriteId : @(writeId), + kFUserWritePath : [path toStringWithTrailingSlash], + kFUserWriteOverwrite : [node valForExport:YES] + }; + NSError *error = nil; + NSData *data = [NSJSONSerialization dataWithJSONObject:write + options:0 + error:&error]; + NSAssert(data, @"Failed to serialize user overwrite: %@, (Error: %@)", + write, error); + [self.writesDB setData:data forKey:writeRecordKey(writeId)]; +} + +- (void)saveUserMerge:(FCompoundWrite *)merge + atPath:(FPath *)path + writeId:(NSUInteger)writeId { + NSDictionary *write = @{ + kFUserWriteId : @(writeId), + kFUserWritePath : [path toStringWithTrailingSlash], + kFUserWriteMerge : [merge valForExport:YES] + }; + NSError *error = nil; + NSData *data = [NSJSONSerialization dataWithJSONObject:write + options:0 + error:&error]; + NSAssert(data, @"Failed to serialize user merge: %@ (Error: %@)", write, + error); + [self.writesDB setData:data forKey:writeRecordKey(writeId)]; +} + +- (void)removeUserWrite:(NSUInteger)writeId { + [self.writesDB removeKey:writeRecordKey(writeId)]; +} + +- (void)removeAllUserWrites { + __block NSUInteger count = 0; + NSDate *start = [NSDate date]; + id batch = [self.writesDB beginWriteBatch]; + [self.writesDB enumerateKeys:^(NSString *key, BOOL *stop) { + [batch removeKey:key]; + count++; + }]; + BOOL success = [batch commit]; + if (!success) { + FFWarn(@"I-RDB076010", @"Failed to remove all users writes on disk!"); + } else { + FFDebug(@"I-RDB076011", @"Removed %lu writes in %fms", + (unsigned long)count, [start timeIntervalSinceNow] * -1000); + } +} + +- (NSArray *)userWrites { + NSDate *date = [NSDate date]; + NSMutableArray *writes = [NSMutableArray array]; + [self.writesDB enumerateKeysAndValuesAsData:^(NSString *key, NSData *data, + BOOL *stop) { + NSError *error = nil; + NSDictionary *writeJSON = [NSJSONSerialization JSONObjectWithData:data + options:0 + error:&error]; + if (writeJSON == nil) { + if (error.code == kFNanFailureCode) { + FFWarn(@"I-RDB076012", + @"Failed to deserialize write (%@), likely because of out " + @"of range doubles (Error: %@)", + [[NSString alloc] initWithData:data + encoding:NSUTF8StringEncoding], + error); + FFWarn(@"I-RDB076013", @"Removing failed write with key %@", key); + [self.writesDB removeKey:key]; + } else { + [NSException raise:NSInternalInconsistencyException + format:@"Failed to deserialize write: %@", error]; + } + } else { + NSInteger writeId = + ((NSNumber *)writeJSON[kFUserWriteId]).integerValue; + FPath *path = [FPath pathWithString:writeJSON[kFUserWritePath]]; + FWriteRecord *writeRecord; + if (writeJSON[kFUserWriteMerge] != nil) { + // It's a merge + FCompoundWrite *merge = [FCompoundWrite + compoundWriteWithValueDictionary:writeJSON[kFUserWriteMerge]]; + writeRecord = [[FWriteRecord alloc] initWithPath:path + merge:merge + writeId:writeId]; + } else { + // It's an overwrite + NSAssert(writeJSON[kFUserWriteOverwrite] != nil, + @"Persisted write did not contain merge or overwrite!"); + id node = + [FSnapshotUtilities nodeFrom:writeJSON[kFUserWriteOverwrite]]; + writeRecord = [[FWriteRecord alloc] initWithPath:path + overwrite:node + writeId:writeId + visible:YES]; + } + [writes addObject:writeRecord]; + } + }]; + // Make sure writes are sorted + [writes sortUsingComparator:^NSComparisonResult(FWriteRecord *one, + FWriteRecord *two) { + if (one.writeId < two.writeId) { + return NSOrderedAscending; + } else if (one.writeId > two.writeId) { + return NSOrderedDescending; + } else { + return NSOrderedSame; + } + }]; + FFDebug(@"I-RDB076014", @"Loaded %lu writes in %fms", + (unsigned long)writes.count, [date timeIntervalSinceNow] * -1000); + return writes; +} + +- (id)serverCacheAtPath:(FPath *)path { + NSDate *start = [NSDate date]; + id data = [self internalNestedDataForPath:path]; + id node = [FSnapshotUtilities nodeFrom:data]; + FFDebug(@"I-RDB076015", @"Loaded node with %d children at %@ in %fms", + [node numChildren], path, [start timeIntervalSinceNow] * -1000); + return node; +} + +- (id)serverCacheForKeys:(NSSet *)keys atPath:(FPath *)path { + NSDate *start = [NSDate date]; + __block id node = [FEmptyNode emptyNode]; + [keys enumerateObjectsUsingBlock:^(NSString *key, BOOL *stop) { + id data = [self internalNestedDataForPath:[path childFromString:key]]; + node = [node updateImmediateChild:key + withNewChild:[FSnapshotUtilities nodeFrom:data]]; + }]; + FFDebug(@"I-RDB076016", + @"Loaded node with %d children for %lu keys at %@ in %fms", + [node numChildren], (unsigned long)keys.count, path, + [start timeIntervalSinceNow] * -1000); + return node; +} + +- (void)updateServerCache:(id)node + atPath:(FPath *)path + merge:(BOOL)merge { + NSDate *start = [NSDate date]; + id batch = [self.serverCacheDB beginWriteBatch]; + // Remove any leaf nodes that might be higher up + [self removeAllLeafNodesOnPath:path batch:batch]; + __block NSUInteger counter = 0; + if (merge) { + // remove any children that exist + [node enumerateChildrenUsingBlock:^(NSString *childKey, + id childNode, BOOL *stop) { + FPath *childPath = [path childFromString:childKey]; + [self removeAllWithPrefix:serverCacheKey(childPath) + batch:batch + database:self.serverCacheDB]; + [self saveNodeInternal:childNode + atPath:childPath + batch:batch + counter:&counter]; + }]; + } else { + // remove everything + [self removeAllWithPrefix:serverCacheKey(path) + batch:batch + database:self.serverCacheDB]; + [self saveNodeInternal:node atPath:path batch:batch counter:&counter]; + } + BOOL success = [batch commit]; + if (!success) { + FFWarn(@"I-RDB076017", @"Failed to update server cache on disk!"); + } else { + FFDebug(@"I-RDB076018", @"Saved %lu leaf nodes for overwrite in %fms", + (unsigned long)counter, [start timeIntervalSinceNow] * -1000); + } +} + +- (void)updateServerCacheWithMerge:(FCompoundWrite *)merge + atPath:(FPath *)path { + NSDate *start = [NSDate date]; + __block NSUInteger counter = 0; + id batch = [self.serverCacheDB beginWriteBatch]; + // Remove any leaf nodes that might be higher up + [self removeAllLeafNodesOnPath:path batch:batch]; + [merge enumerateWrites:^(FPath *relativePath, id node, BOOL *stop) { + FPath *childPath = [path child:relativePath]; + [self removeAllWithPrefix:serverCacheKey(childPath) + batch:batch + database:self.serverCacheDB]; + [self saveNodeInternal:node + atPath:childPath + batch:batch + counter:&counter]; + }]; + BOOL success = [batch commit]; + if (!success) { + FFWarn(@"I-RDB076019", @"Failed to update server cache on disk!"); + } else { + FFDebug(@"I-RDB076020", @"Saved %lu leaf nodes for merge in %fms", + (unsigned long)counter, [start timeIntervalSinceNow] * -1000); + } +} + +- (void)saveNodeInternal:(id)node + atPath:(FPath *)path + batch:(id)batch + counter:(NSUInteger *)counter { + id data = [node valForExport:YES]; + if (data != nil && ![data isKindOfClass:[NSNull class]]) { + [self internalSetNestedData:data + forKey:serverCacheKey(path) + withBatch:batch + counter:counter]; + } +} + +- (NSUInteger)serverCacheEstimatedSizeInBytes { + // Use the exact size, because for pruning the approximate size can lead to + // weird situations where we prune everything because no compaction is ever + // run + return [self.serverCacheDB exactSizeFrom:kFServerCachePrefix + to:kFServerCacheRangeEnd]; +} + +- (void)pruneCache:(FPruneForest *)pruneForest atPath:(FPath *)path { + // TODO: be more intelligent, don't scan entire database... + + __block NSUInteger pruned = 0; + __block NSUInteger kept = 0; + NSDate *start = [NSDate date]; + + NSString *prefix = serverCacheKey(path); + id batch = [self.serverCacheDB beginWriteBatch]; + + [self.serverCacheDB + enumerateKeysWithPrefix:prefix + usingBlock:^(NSString *dbKey, BOOL *stop) { + NSString *pathStr = + [dbKey substringFromIndex:prefix.length]; + FPath *relativePath = [[FPath alloc] initWith:pathStr]; + if ([pruneForest shouldPruneUnkeptDescendantsAtPath: + relativePath]) { + pruned++; + [batch removeKey:dbKey]; + } else { + kept++; + } + }]; + BOOL success = [batch commit]; + if (!success) { + FFWarn(@"I-RDB076021", @"Failed to prune cache on disk!"); + } else { + FFDebug(@"I-RDB076022", @"Pruned %lu paths, kept %lu paths in %fms", + (unsigned long)pruned, (unsigned long)kept, + [start timeIntervalSinceNow] * -1000); + } +} + +#pragma mark - Tracked Queries + +- (NSArray *)loadTrackedQueries { + NSDate *date = [NSDate date]; + NSMutableArray *trackedQueries = [NSMutableArray array]; + [self.serverCacheDB + enumerateKeysWithPrefix:kFTrackedQueriesPrefix + asData:^(NSString *key, NSData *data, BOOL *stop) { + NSError *error = nil; + NSDictionary *queryJSON = + [NSJSONSerialization JSONObjectWithData:data + options:0 + error:&error]; + if (queryJSON == nil) { + if (error.code == kFNanFailureCode) { + FFWarn( + @"I-RDB076023", + @"Failed to deserialize tracked query " + @"(%@), likely because of out of range " + @"doubles (Error: %@)", + [[NSString alloc] + initWithData:data + encoding:NSUTF8StringEncoding], + error); + FFWarn(@"I-RDB076024", + @"Removing failed tracked query with " + @"key %@", + key); + [self.serverCacheDB removeKey:key]; + } else { + [NSException + raise:NSInternalInconsistencyException + format:@"Failed to deserialize tracked " + @"query: %@", + error]; + } + } else { + NSUInteger queryId = + ((NSNumber *)queryJSON[kFTrackedQueryId]) + .unsignedIntegerValue; + FPath *path = + [FPath pathWithString: + queryJSON[kFTrackedQueryPath]]; + FQueryParams *params = [FQueryParams + fromQueryObject:queryJSON + [kFTrackedQueryParams]]; + FQuerySpec *query = + [[FQuerySpec alloc] initWithPath:path + params:params]; + BOOL isComplete = + [queryJSON[kFTrackedQueryIsComplete] + boolValue]; + BOOL isActive = + [queryJSON[kFTrackedQueryIsActive] + boolValue]; + NSTimeInterval lastUse = + [queryJSON[kFTrackedQueryLastUse] + doubleValue]; + + FTrackedQuery *trackedQuery = + [[FTrackedQuery alloc] + initWithId:queryId + query:query + lastUse:lastUse + isActive:isActive + isComplete:isComplete]; + + [trackedQueries addObject:trackedQuery]; + } + }]; + FFDebug(@"I-RDB076025", @"Loaded %lu tracked queries in %fms", + (unsigned long)trackedQueries.count, + [date timeIntervalSinceNow] * -1000); + return trackedQueries; +} + +- (void)removeTrackedQuery:(NSUInteger)queryId { + NSDate *start = [NSDate date]; + id batch = [self.serverCacheDB beginWriteBatch]; + [batch removeKey:trackedQueryKey(queryId)]; + __block NSUInteger keyCount = 0; + [self.serverCacheDB + enumerateKeysWithPrefix:trackedQueryKeysKeyPrefix(queryId) + usingBlock:^(NSString *key, BOOL *stop) { + [batch removeKey:key]; + keyCount++; + }]; + + BOOL success = [batch commit]; + if (!success) { + FFWarn(@"I-RDB076026", @"Failed to remove tracked query on disk!"); + } else { + FFDebug(@"I-RDB076027", + @"Removed query with id %lu (and removed %lu keys) in %fms", + (unsigned long)queryId, (unsigned long)keyCount, + [start timeIntervalSinceNow] * -1000); + } +} + +- (void)saveTrackedQuery:(FTrackedQuery *)query { + NSDate *start = [NSDate date]; + NSDictionary *trackedQuery = @{ + kFTrackedQueryId : @(query.queryId), + kFTrackedQueryPath : [query.query.path toStringWithTrailingSlash], + kFTrackedQueryParams : [query.query.params wireProtocolParams], + kFTrackedQueryLastUse : @(query.lastUse), + kFTrackedQueryIsComplete : @(query.isComplete), + kFTrackedQueryIsActive : @(query.isActive) + }; + NSError *error = nil; + NSData *data = [NSJSONSerialization dataWithJSONObject:trackedQuery + options:0 + error:&error]; + NSAssert(data, @"Failed to serialize tracked query (Error: %@)", error); + [self.serverCacheDB setData:data forKey:trackedQueryKey(query.queryId)]; + FFDebug(@"I-RDB076028", @"Saved tracked query %lu in %fms", + (unsigned long)query.queryId, [start timeIntervalSinceNow] * -1000); +} + +- (void)setTrackedQueryKeys:(NSSet *)keys forQueryId:(NSUInteger)queryId { + NSDate *start = [NSDate date]; + __block NSUInteger removed = 0; + __block NSUInteger added = 0; + id batch = [self.serverCacheDB beginWriteBatch]; + NSMutableSet *seenKeys = [NSMutableSet set]; + // First, delete any keys that might be stored and are not part of the + // current keys + [self.serverCacheDB + enumerateKeysWithPrefix:trackedQueryKeysKeyPrefix(queryId) + asStrings:^(NSString *dbKey, NSString *actualKey, + BOOL *stop) { + if ([keys containsObject:actualKey]) { + // Already in DB + [seenKeys addObject:actualKey]; + } else { + // Not part of set, delete key + [batch removeKey:dbKey]; + removed++; + } + }]; + + // Next add any keys that are missing in the database + [keys enumerateObjectsUsingBlock:^(NSString *childKey, BOOL *stop) { + if (![seenKeys containsObject:childKey]) { + [batch setString:childKey + forKey:trackedQueryKeysKey(queryId, childKey)]; + added++; + } + }]; + BOOL success = [batch commit]; + if (!success) { + FFWarn(@"I-RDB076029", @"Failed to set tracked queries on disk!"); + } else { + FFDebug(@"I-RDB076030", + @"Set %lu tracked keys (%lu added, %lu removed) for query %lu " + @"in %fms", + (unsigned long)keys.count, (unsigned long)added, + (unsigned long)removed, (unsigned long)queryId, + [start timeIntervalSinceNow] * -1000); + } +} + +- (void)updateTrackedQueryKeysWithAddedKeys:(NSSet *)added + removedKeys:(NSSet *)removed + forQueryId:(NSUInteger)queryId { + NSDate *start = [NSDate date]; + id batch = [self.serverCacheDB beginWriteBatch]; + [removed enumerateObjectsUsingBlock:^(NSString *key, BOOL *stop) { + [batch removeKey:trackedQueryKeysKey(queryId, key)]; + }]; + [added enumerateObjectsUsingBlock:^(NSString *key, BOOL *stop) { + [batch setString:key forKey:trackedQueryKeysKey(queryId, key)]; + }]; + BOOL success = [batch commit]; + if (!success) { + FFWarn(@"I-RDB076031", @"Failed to update tracked queries on disk!"); + } else { + FFDebug(@"I-RDB076032", + @"Added %lu tracked keys, removed %lu for query %lu in %fms", + (unsigned long)added.count, (unsigned long)removed.count, + (unsigned long)queryId, [start timeIntervalSinceNow] * -1000); + } +} + +- (NSSet *)trackedQueryKeysForQuery:(NSUInteger)queryId { + NSDate *start = [NSDate date]; + NSMutableSet *set = [NSMutableSet set]; + [self.serverCacheDB + enumerateKeysWithPrefix:trackedQueryKeysKeyPrefix(queryId) + asStrings:^(NSString *dbKey, NSString *actualKey, + BOOL *stop) { + [set addObject:actualKey]; + }]; + FFDebug(@"I-RDB076033", @"Loaded %lu tracked keys for query %lu in %fms", + (unsigned long)set.count, (unsigned long)queryId, + [start timeIntervalSinceNow] * -1000); + return set; +} + +#pragma mark - Internal methods + +- (void)removeAllLeafNodesOnPath:(FPath *)path + batch:(id)batch { + while (!path.isEmpty) { + [batch removeKey:serverCacheKey(path)]; + path = [path parent]; + } + // Make sure to delete any nodes at the root + [batch removeKey:serverCacheKey([FPath empty])]; +} + +- (void)removeAllWithPrefix:(NSString *)prefix + batch:(id)batch + database:(APLevelDB *)database { + assert(prefix != nil); + + [database enumerateKeysWithPrefix:prefix + usingBlock:^(NSString *key, BOOL *stop) { + [batch removeKey:key]; + }]; +} + +#pragma mark - Internal helper methods + +- (void)internalSetNestedData:(id)value + forKey:(NSString *)key + withBatch:(id)batch + counter:(NSUInteger *)counter { + if ([value isKindOfClass:[NSDictionary class]]) { + NSDictionary *dictionary = value; + [dictionary enumerateKeysAndObjectsUsingBlock:^(id childKey, id obj, + BOOL *stop) { + assert(obj != nil); + NSString *childPath = + [NSString stringWithFormat:@"%@%@/", key, childKey]; + [self internalSetNestedData:obj + forKey:childPath + withBatch:batch + counter:counter]; + }]; + } else { + NSData *data = [self serializePrimitive:value]; + [batch setData:data forKey:key]; + (*counter)++; + } +} + +- (id)internalNestedDataForPath:(FPath *)path { + NSAssert(path != nil, @"Path was nil!"); + + NSString *baseKey = serverCacheKey(path); + + // HACK to make sure iter is freed now to avoid race conditions (if self.db + // is deleted before iter, you get an access violation). + @autoreleasepool { + APLevelDBIterator *iter = + [APLevelDBIterator iteratorWithLevelDB:self.serverCacheDB]; + + [iter seekToKey:baseKey]; + if (iter.key == nil || ![iter.key hasPrefix:baseKey]) { + // No data. + return nil; + } else { + return [self internalNestedDataFromIterator:iter + andKeyPrefix:baseKey]; + } + } +} + +- (id)internalNestedDataFromIterator:(APLevelDBIterator *)iterator + andKeyPrefix:(NSString *)prefix { + NSString *key = iterator.key; + + if ([key isEqualToString:prefix]) { + id result = [self deserializePrimitive:iterator.valueAsData]; + [iterator nextKey]; + return result; + } else { + NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; + while (key != nil && [key hasPrefix:prefix]) { + NSString *relativePath = [key substringFromIndex:prefix.length]; + NSArray *pathPieces = + [relativePath componentsSeparatedByString:@"/"]; + assert(pathPieces.count > 0); + NSString *childName = pathPieces[0]; + NSString *childPath = + [NSString stringWithFormat:@"%@%@/", prefix, childName]; + id childValue = [self internalNestedDataFromIterator:iterator + andKeyPrefix:childPath]; + [dict setValue:childValue forKey:childName]; + + key = iterator.key; + } + return dict; + } +} + +- (NSData *)serializePrimitive:(id)value { + // HACK: The built-in serialization only works on dicts and arrays. So we + // create an array and then strip off the leading / trailing byte (the [ and + // ]). + NSError *error = nil; + NSData *data = [NSJSONSerialization dataWithJSONObject:@[ value ] + options:0 + error:&error]; + NSAssert(data, @"Failed to serialize primitive: %@", error); + + return [data subdataWithRange:NSMakeRange(1, data.length - 2)]; +} + +- (id)fixDoubleParsing:(id)value + __attribute__((no_sanitize("float-cast-overflow"))) { + if ([value isKindOfClass:[NSDecimalNumber class]]) { + // In case the value is an NSDecimalNumber, we may be dealing with + // precisions that are higher than what can be represented in a double. + // In this case it does not suffice to check for integral numbers by + // casting the [value doubleValue] to an int64_t, because this will + // cause the compared values to be rounded to double precision. + // Coupled with a bug in [NSDecimalNumber longLongValue] that triggers + // when converting values with high precision, this would cause + // values of high precision, but with an integral 'doubleValue' + // representation to be converted to bogus values. + // A radar for the NSDecimalNumber issue can be found here: + // http://www.openradar.me/radar?id=5007005597040640 + // Consider the NSDecimalNumber value: 999.9999999999999487 + // This number has a 'doubleValue' of 1000. Using the previous version + // of this method would cause the value to be interpreted to be integral + // and then the resulting value would be based on the longLongValue + // which due to the NSDecimalNumber issue would turn out as -844. + // By using NSDecimal logic to test for integral values, + // 999.9999999999999487 will not be considered integral, and instead + // of triggering the 'longLongValue' issue, it will be returned as + // the 'doubleValue' representation (1000). + // Please note, that even without the NSDecimalNumber issue, the + // 'correct' longLongValue of 999.9999999999999487 is 999 and not 1000, + // so the previous code would cause issues even without the bug + // referenced in the radar. + NSDecimal original = [(NSDecimalNumber *)value decimalValue]; + NSDecimal rounded; + NSDecimalRound(&rounded, &original, 0, NSRoundPlain); + if (NSDecimalCompare(&original, &rounded) != NSOrderedSame) { + NSString *doubleString = [value stringValue]; + return [NSNumber numberWithDouble:[doubleString doubleValue]]; + } else { + return [NSNumber numberWithLongLong:[value longLongValue]]; + } + } else if ([value isKindOfClass:[NSNumber class]]) { + // The parser for double values in JSONSerialization at the root takes + // some short-cuts and delivers wrong results (wrong rounding) for some + // double values, including 2.47. Because we use the exact bytes for + // hashing on the server this will lead to hash mismatches. The parser + // of NSNumber seems to be more in line with what the server expects, so + // we use that here + CFNumberType type = CFNumberGetType((CFNumberRef)value); + if (type == kCFNumberDoubleType || type == kCFNumberFloatType) { + // The NSJSON parser returns all numbers as double values, even + // those that contain no exponent. To make sure that the String + // conversion below doesn't unexpectedly reduce precision, we make + // sure that our number is indeed not an integer. + if ((double)(int64_t)[value doubleValue] != [value doubleValue]) { + NSString *doubleString = [value stringValue]; + return [NSNumber numberWithDouble:[doubleString doubleValue]]; + } else { + return [NSNumber numberWithLongLong:[value longLongValue]]; + } + } + } + return value; +} + +- (id)deserializePrimitive:(NSData *)data { + NSError *error = nil; + id result = + [NSJSONSerialization JSONObjectWithData:data + options:NSJSONReadingAllowFragments + error:&error]; + if (result != nil) { + return [self fixDoubleParsing:result]; + } else { + if (error.code == kFNanFailureCode) { + FFWarn(@"I-RDB076034", + @"Failed to load primitive %@, likely because doubles where " + @"out of range (Error: %@)", + [[NSString alloc] initWithData:data + encoding:NSUTF8StringEncoding], + error); + return [NSNull null]; + } else { + [NSException raise:NSInternalInconsistencyException + format:@"Failed to deserialiaze primitive: %@", error]; + return nil; + } + } +} + ++ (void)ensureDir:(NSString *)path markAsDoNotBackup:(BOOL)markAsDoNotBackup { + NSError *error; + BOOL success = + [[NSFileManager defaultManager] createDirectoryAtPath:path + withIntermediateDirectories:YES + attributes:nil + error:&error]; + if (!success) { + @throw [NSException + exceptionWithName:@"FailedToCreatePersistenceDir" + reason:@"Failed to create persistence directory." + userInfo:@{@"path" : path}]; + } + + if (markAsDoNotBackup) { + NSURL *firebaseDirURL = [NSURL fileURLWithPath:path]; + success = [firebaseDirURL setResourceValue:@YES + forKey:NSURLIsExcludedFromBackupKey + error:&error]; + if (!success) { + FFWarn( + @"I-RDB076035", + @"Failed to mark firebase database folder as do not backup: %@", + error); + [NSException raise:@"Error marking as do not backup" + format:@"Failed to mark folder %@ as do not backup", + firebaseDirURL]; + } + } +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPendingPut.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPendingPut.h new file mode 100644 index 0000000..deeeca2 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPendingPut.h @@ -0,0 +1,53 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import + +// These are all legacy classes and are used to migrate older persistence data +// base to newer ones These classes should not be used in newer code + +@interface FPendingPut : NSObject + +@property(nonatomic, strong) FPath *path; +@property(nonatomic, strong) id data; +@property(nonatomic, strong) id priority; + +- (id)initWithPath:(FPath *)aPath andData:(id)aData andPriority:aPriority; +- (void)encodeWithCoder:(NSCoder *)aCoder; +- (id)initWithCoder:(NSCoder *)aDecoder; +@end + +@interface FPendingPutPriority : NSObject + +@property(nonatomic, strong) FPath *path; +@property(nonatomic, strong) id priority; + +- (id)initWithPath:(FPath *)aPath andPriority:(id)aPriority; +- (void)encodeWithCoder:(NSCoder *)aCoder; +- (id)initWithCoder:(NSCoder *)aDecoder; + +@end + +@interface FPendingUpdate : NSObject + +@property(nonatomic, strong) FPath *path; +@property(nonatomic, strong) NSDictionary *data; + +- (id)initWithPath:(FPath *)aPath andData:(NSDictionary *)aData; +- (void)encodeWithCoder:(NSCoder *)aCoder; +- (id)initWithCoder:(NSCoder *)aDecoder; +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPendingPut.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPendingPut.m new file mode 100644 index 0000000..c596dde --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPendingPut.m @@ -0,0 +1,113 @@ +/* + * 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 "FirebaseDatabase/Sources/Persistence/FPendingPut.h" + +@implementation FPendingPut + +@synthesize path; +@synthesize data; + +- (id)initWithPath:(FPath *)aPath andData:(id)aData andPriority:(id)aPriority { + self = [super init]; + if (self) { + self.path = aPath; + self.data = aData; + self.priority = aPriority; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:[self.path description] forKey:@"path"]; + [aCoder encodeObject:self.data forKey:@"data"]; + [aCoder encodeObject:self.priority forKey:@"priority"]; +} + +- (id)initWithCoder:(NSCoder *)aDecoder { + self = [super init]; + if (self) { + self.path = + [[FPath alloc] initWith:[aDecoder decodeObjectForKey:@"path"]]; + self.data = [aDecoder decodeObjectForKey:@"data"]; + self.priority = [aDecoder decodeObjectForKey:@"priority"]; + } + return self; +} + +@end + +@implementation FPendingPutPriority + +@synthesize path; +@synthesize priority; + +- (id)initWithPath:(FPath *)aPath andPriority:(id)aPriority { + self = [super init]; + if (self) { + self.path = aPath; + self.priority = aPriority; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:[self.path description] forKey:@"path"]; + [aCoder encodeObject:self.priority forKey:@"priority"]; +} + +- (id)initWithCoder:(NSCoder *)aDecoder { + self = [super init]; + if (self) { + self.path = + [[FPath alloc] initWith:[aDecoder decodeObjectForKey:@"path"]]; + self.priority = [aDecoder decodeObjectForKey:@"priority"]; + } + return self; +} + +@end + +@implementation FPendingUpdate + +@synthesize path; +@synthesize data; + +- (id)initWithPath:(FPath *)aPath andData:(id)aData { + self = [super init]; + if (self) { + self.path = aPath; + self.data = aData; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:[self.path description] forKey:@"path"]; + [aCoder encodeObject:self.data forKey:@"data"]; +} + +- (id)initWithCoder:(NSCoder *)aDecoder { + self = [super init]; + if (self) { + self.path = + [[FPath alloc] initWith:[aDecoder decodeObjectForKey:@"path"]]; + self.data = [aDecoder decodeObjectForKey:@"data"]; + } + return self; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPersistenceManager.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPersistenceManager.h new file mode 100644 index 0000000..fb35ec6 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPersistenceManager.h @@ -0,0 +1,60 @@ +/* + * 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 + +#import "FirebaseDatabase/Sources/Core/FQuerySpec.h" +#import "FirebaseDatabase/Sources/Core/FRepoInfo.h" +#import "FirebaseDatabase/Sources/Core/View/FCacheNode.h" +#import "FirebaseDatabase/Sources/Persistence/FCachePolicy.h" +#import "FirebaseDatabase/Sources/Persistence/FStorageEngine.h" +#import "FirebaseDatabase/Sources/Snapshot/FCompoundWrite.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" + +@interface FPersistenceManager : NSObject + +- (id)initWithStorageEngine:(id)storageEngine + cachePolicy:(id)cachePolicy; +- (void)close; + +- (void)saveUserOverwrite:(id)node + atPath:(FPath *)path + writeId:(NSUInteger)writeId; +- (void)saveUserMerge:(FCompoundWrite *)merge + atPath:(FPath *)path + writeId:(NSUInteger)writeId; +- (void)removeUserWrite:(NSUInteger)writeId; +- (void)removeAllUserWrites; +- (NSArray *)userWrites; + +- (FCacheNode *)serverCacheForQuery:(FQuerySpec *)spec; +- (void)updateServerCacheWithNode:(id)node forQuery:(FQuerySpec *)spec; +- (void)updateServerCacheWithMerge:(FCompoundWrite *)merge atPath:(FPath *)path; + +- (void)applyUserWrite:(id)write toServerCacheAtPath:(FPath *)path; +- (void)applyUserMerge:(FCompoundWrite *)merge + toServerCacheAtPath:(FPath *)path; + +- (void)setQueryComplete:(FQuerySpec *)spec; +- (void)setQueryActive:(FQuerySpec *)spec; +- (void)setQueryInactive:(FQuerySpec *)spec; + +- (void)setTrackedQueryKeys:(NSSet *)keys forQuery:(FQuerySpec *)query; +- (void)updateTrackedQueryKeysWithAddedKeys:(NSSet *)added + removedKeys:(NSSet *)removed + forQuery:(FQuerySpec *)query; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPersistenceManager.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPersistenceManager.m new file mode 100644 index 0000000..2610f19 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPersistenceManager.m @@ -0,0 +1,231 @@ +/* + * 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 "FirebaseDatabase/Sources/Persistence/FPersistenceManager.h" +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" +#import "FirebaseDatabase/Sources/Core/View/FCacheNode.h" +#import "FirebaseDatabase/Sources/FClock.h" +#import "FirebaseDatabase/Sources/Persistence/FLevelDBStorageEngine.h" +#import "FirebaseDatabase/Sources/Persistence/FPruneForest.h" +#import "FirebaseDatabase/Sources/Persistence/FTrackedQuery.h" +#import "FirebaseDatabase/Sources/Persistence/FTrackedQueryManager.h" +#import "FirebaseDatabase/Sources/Snapshot/FIndexedNode.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" + +@interface FPersistenceManager () + +@property(nonatomic, strong) id storageEngine; +@property(nonatomic, strong) id cachePolicy; +@property(nonatomic, strong) FTrackedQueryManager *trackedQueryManager; +@property(nonatomic) NSUInteger serverCacheUpdatesSinceLastPruneCheck; + +@end + +@implementation FPersistenceManager + +- (id)initWithStorageEngine:(id)storageEngine + cachePolicy:(id)cachePolicy { + self = [super init]; + if (self != nil) { + self->_storageEngine = storageEngine; + self->_cachePolicy = cachePolicy; + self->_trackedQueryManager = [[FTrackedQueryManager alloc] + initWithStorageEngine:self.storageEngine + clock:[FSystemClock clock]]; + } + return self; +} + +- (void)close { + [self.storageEngine close]; + self.storageEngine = nil; + self.trackedQueryManager = nil; +} + +- (void)saveUserOverwrite:(id)node + atPath:(FPath *)path + writeId:(NSUInteger)writeId { + [self.storageEngine saveUserOverwrite:node atPath:path writeId:writeId]; +} + +- (void)saveUserMerge:(FCompoundWrite *)merge + atPath:(FPath *)path + writeId:(NSUInteger)writeId { + [self.storageEngine saveUserMerge:merge atPath:path writeId:writeId]; +} + +- (void)removeUserWrite:(NSUInteger)writeId { + [self.storageEngine removeUserWrite:writeId]; +} + +- (void)removeAllUserWrites { + [self.storageEngine removeAllUserWrites]; +} + +- (NSArray *)userWrites { + return [self.storageEngine userWrites]; +} + +- (FCacheNode *)serverCacheForQuery:(FQuerySpec *)query { + NSSet *trackedKeys; + BOOL complete; + // TODO[offline]: Should we use trackedKeys to find out if this location is + // a child of a complete query? + if ([self.trackedQueryManager isQueryComplete:query]) { + complete = YES; + FTrackedQuery *trackedQuery = + [self.trackedQueryManager findTrackedQuery:query]; + if (!query.loadsAllData && trackedQuery.isComplete) { + trackedKeys = [self.storageEngine + trackedQueryKeysForQuery:trackedQuery.queryId]; + } else { + trackedKeys = nil; + } + } else { + complete = NO; + trackedKeys = + [self.trackedQueryManager knownCompleteChildrenAtPath:query.path]; + } + + id node; + if (trackedKeys != nil) { + node = [self.storageEngine serverCacheForKeys:trackedKeys + atPath:query.path]; + } else { + node = [self.storageEngine serverCacheAtPath:query.path]; + } + + FIndexedNode *indexedNode = [FIndexedNode indexedNodeWithNode:node + index:query.index]; + return [[FCacheNode alloc] initWithIndexedNode:indexedNode + isFullyInitialized:complete + isFiltered:(trackedKeys != nil)]; +} + +- (void)updateServerCacheWithNode:(id)node forQuery:(FQuerySpec *)query { + BOOL merge = !query.loadsAllData; + [self.storageEngine updateServerCache:node atPath:query.path merge:merge]; + [self setQueryComplete:query]; + [self doPruneCheckAfterServerUpdate]; +} + +- (void)updateServerCacheWithMerge:(FCompoundWrite *)merge + atPath:(FPath *)path { + [self.storageEngine updateServerCacheWithMerge:merge atPath:path]; + [self doPruneCheckAfterServerUpdate]; +} + +- (void)applyUserMerge:(FCompoundWrite *)merge + toServerCacheAtPath:(FPath *)path { + // TODO[offline]: rework this to be more efficient + [merge enumerateWrites:^(FPath *relativePath, id node, BOOL *stop) { + [self applyUserWrite:node toServerCacheAtPath:[path child:relativePath]]; + }]; +} + +- (void)applyUserWrite:(id)write toServerCacheAtPath:(FPath *)path { + // This is a hack to guess whether we already cached this because we got a + // server data update for this write via an existing active default query. + // If we didn't, then we'll manually cache this and add a tracked query to + // mark it complete and keep it cached. Unfortunately this is just a guess + // and it's possible that we *did* get an update (e.g. via a filtered query) + // and by overwriting the cache here, we'll actually store an incorrect + // value (e.g. in the case that we wrote a ServerValue.TIMESTAMP and the + // server resolved it to a different value). + // TODO[offline]: Consider reworking. + if (![self.trackedQueryManager hasActiveDefaultQueryAtPath:path]) { + [self.storageEngine updateServerCache:write atPath:path merge:NO]; + [self.trackedQueryManager ensureCompleteTrackedQueryAtPath:path]; + } +} + +- (void)setQueryComplete:(FQuerySpec *)query { + if (query.loadsAllData) { + [self.trackedQueryManager setQueriesCompleteAtPath:query.path]; + } else { + [self.trackedQueryManager setQueryComplete:query]; + } +} + +- (void)setQueryActive:(FQuerySpec *)spec { + [self.trackedQueryManager setQueryActive:spec]; +} + +- (void)setQueryInactive:(FQuerySpec *)spec { + [self.trackedQueryManager setQueryInactive:spec]; +} + +- (void)doPruneCheckAfterServerUpdate { + self.serverCacheUpdatesSinceLastPruneCheck++; + if ([self.cachePolicy + shouldCheckCacheSize:self.serverCacheUpdatesSinceLastPruneCheck]) { + FFDebug(@"I-RDB078001", @"Reached prune check threshold. Checking..."); + NSDate *date = [NSDate date]; + self.serverCacheUpdatesSinceLastPruneCheck = 0; + BOOL canPrune = YES; + NSUInteger cacheSize = + [self.storageEngine serverCacheEstimatedSizeInBytes]; + FFDebug(@"I-RDB078002", @"Server cache size: %lu", + (unsigned long)cacheSize); + while (canPrune && + [self.cachePolicy + shouldPruneCacheWithSize:cacheSize + numberOfTrackedQueries:self.trackedQueryManager + .numberOfPrunableQueries]) { + FPruneForest *pruneForest = + [self.trackedQueryManager pruneOldQueries:self.cachePolicy]; + if (pruneForest.prunesAnything) { + [self.storageEngine pruneCache:pruneForest + atPath:[FPath empty]]; + } else { + canPrune = NO; + } + cacheSize = [self.storageEngine serverCacheEstimatedSizeInBytes]; + FFDebug(@"I-RDB078003", @"Cache size after pruning: %lu", + (unsigned long)cacheSize); + } + FFDebug(@"I-RDB078004", @"Pruning round took %fms", + [date timeIntervalSinceNow] * -1000); + } +} + +- (void)setTrackedQueryKeys:(NSSet *)keys forQuery:(FQuerySpec *)query { + NSAssert(!query.loadsAllData, + @"We should only track keys for filtered queries"); + FTrackedQuery *trackedQuery = + [self.trackedQueryManager findTrackedQuery:query]; + NSAssert(trackedQuery.isActive, + @"We only expect tracked keys for currently-active queries."); + [self.storageEngine setTrackedQueryKeys:keys + forQueryId:trackedQuery.queryId]; +} + +- (void)updateTrackedQueryKeysWithAddedKeys:(NSSet *)added + removedKeys:(NSSet *)removed + forQuery:(FQuerySpec *)query { + NSAssert(!query.loadsAllData, + @"We should only track keys for filtered queries"); + FTrackedQuery *trackedQuery = + [self.trackedQueryManager findTrackedQuery:query]; + NSAssert(trackedQuery.isActive, + @"We only expect tracked keys for currently-active queries."); + [self.storageEngine + updateTrackedQueryKeysWithAddedKeys:added + removedKeys:removed + forQueryId:trackedQuery.queryId]; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPruneForest.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPruneForest.h new file mode 100644 index 0000000..9e77217 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPruneForest.h @@ -0,0 +1,38 @@ +/* + * 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 + +@class FPath; + +@interface FPruneForest : NSObject + ++ (FPruneForest *)empty; + +- (BOOL)prunesAnything; +- (BOOL)shouldPruneUnkeptDescendantsAtPath:(FPath *)path; +- (BOOL)shouldKeepPath:(FPath *)path; +- (BOOL)affectsPath:(FPath *)path; +- (FPruneForest *)child:(NSString *)childKey; +- (FPruneForest *)childAtPath:(FPath *)childKey; +- (FPruneForest *)prunePath:(FPath *)path; +- (FPruneForest *)keepPath:(FPath *)path; +- (FPruneForest *)keepAll:(NSSet *)children atPath:(FPath *)path; +- (FPruneForest *)pruneAll:(NSSet *)children atPath:(FPath *)path; + +- (void)enumarateKeptNodesUsingBlock:(void (^)(FPath *path))block; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPruneForest.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPruneForest.m new file mode 100644 index 0000000..b777ba9 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FPruneForest.m @@ -0,0 +1,194 @@ +/* + * 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 "FirebaseDatabase/Sources/Persistence/FPruneForest.h" + +#import "FirebaseDatabase/Sources/Core/Utilities/FImmutableTree.h" + +@interface FPruneForest () + +@property(nonatomic, strong) FImmutableTree *pruneForest; + +@end + +@implementation FPruneForest + +static BOOL (^kFPrunePredicate)(id) = ^BOOL(NSNumber *pruneValue) { + return [pruneValue boolValue]; +}; + +static BOOL (^kFKeepPredicate)(id) = ^BOOL(NSNumber *pruneValue) { + return ![pruneValue boolValue]; +}; + ++ (FImmutableTree *)pruneTree { + static dispatch_once_t onceToken; + static FImmutableTree *pruneTree; + dispatch_once(&onceToken, ^{ + pruneTree = [[FImmutableTree alloc] initWithValue:@YES]; + }); + return pruneTree; +} + ++ (FImmutableTree *)keepTree { + static dispatch_once_t onceToken; + static FImmutableTree *keepTree; + dispatch_once(&onceToken, ^{ + keepTree = [[FImmutableTree alloc] initWithValue:@NO]; + }); + return keepTree; +} + +- (id)initWithForest:(FImmutableTree *)tree { + self = [super init]; + if (self != nil) { + self->_pruneForest = tree; + } + return self; +} + ++ (FPruneForest *)empty { + static dispatch_once_t onceToken; + static FPruneForest *forest; + dispatch_once(&onceToken, ^{ + forest = [[FPruneForest alloc] initWithForest:[FImmutableTree empty]]; + }); + return forest; +} + +- (BOOL)prunesAnything { + return [self.pruneForest containsValueMatching:kFPrunePredicate]; +} + +- (BOOL)shouldPruneUnkeptDescendantsAtPath:(FPath *)path { + NSNumber *shouldPrune = [self.pruneForest leafMostValueOnPath:path]; + return shouldPrune != nil && [shouldPrune boolValue]; +} + +- (BOOL)shouldKeepPath:(FPath *)path { + NSNumber *shouldPrune = [self.pruneForest leafMostValueOnPath:path]; + return shouldPrune != nil && ![shouldPrune boolValue]; +} + +- (BOOL)affectsPath:(FPath *)path { + return [self.pruneForest rootMostValueOnPath:path] != nil || + ![[self.pruneForest subtreeAtPath:path] isEmpty]; +} + +- (FPruneForest *)child:(NSString *)childKey { + FImmutableTree *childPruneForest = [self.pruneForest.children get:childKey]; + if (childPruneForest == nil) { + if (self.pruneForest.value != nil) { + childPruneForest = [self.pruneForest.value boolValue] + ? [FPruneForest pruneTree] + : [FPruneForest keepTree]; + } else { + childPruneForest = [FImmutableTree empty]; + } + } else { + if (childPruneForest.value == nil && self.pruneForest.value != nil) { + childPruneForest = [childPruneForest setValue:self.pruneForest.value + atPath:[FPath empty]]; + } + } + return [[FPruneForest alloc] initWithForest:childPruneForest]; +} + +- (FPruneForest *)childAtPath:(FPath *)path { + if (path.isEmpty) { + return self; + } else { + return [[self child:path.getFront] childAtPath:[path popFront]]; + } +} + +- (FPruneForest *)prunePath:(FPath *)path { + if ([self.pruneForest rootMostValueOnPath:path matching:kFKeepPredicate]) { + [NSException raise:NSInvalidArgumentException + format:@"Can't prune path that was kept previously!"]; + } + if ([self.pruneForest rootMostValueOnPath:path matching:kFPrunePredicate]) { + // This path will already be pruned + return self; + } else { + FImmutableTree *newPruneForest = + [self.pruneForest setTree:[FPruneForest pruneTree] atPath:path]; + return [[FPruneForest alloc] initWithForest:newPruneForest]; + } +} + +- (FPruneForest *)keepPath:(FPath *)path { + if ([self.pruneForest rootMostValueOnPath:path matching:kFKeepPredicate]) { + // This path will already be kept + return self; + } else { + FImmutableTree *newPruneForest = + [self.pruneForest setTree:[FPruneForest keepTree] atPath:path]; + return [[FPruneForest alloc] initWithForest:newPruneForest]; + } +} + +- (FPruneForest *)keepAll:(NSSet *)children atPath:(FPath *)path { + if ([self.pruneForest rootMostValueOnPath:path matching:kFKeepPredicate]) { + // This path will already be kept + return self; + } else { + return [self setPruneValue:[FPruneForest keepTree] + forAll:children + atPath:path]; + } +} + +- (FPruneForest *)pruneAll:(NSSet *)children atPath:(FPath *)path { + if ([self.pruneForest rootMostValueOnPath:path matching:kFKeepPredicate]) { + [NSException raise:NSInvalidArgumentException + format:@"Can't prune path that was kept previously!"]; + } + if ([self.pruneForest rootMostValueOnPath:path matching:kFPrunePredicate]) { + // This path will already be pruned + return self; + } else { + return [self setPruneValue:[FPruneForest pruneTree] + forAll:children + atPath:path]; + } +} + +- (FPruneForest *)setPruneValue:(FImmutableTree *)pruneValue + forAll:(NSSet *)children + atPath:(FPath *)path { + FImmutableTree *subtree = [self.pruneForest subtreeAtPath:path]; + __block FImmutableSortedDictionary *childrenDictionary = subtree.children; + [children enumerateObjectsUsingBlock:^(NSString *childKey, BOOL *stop) { + childrenDictionary = [childrenDictionary insertKey:childKey + withValue:pruneValue]; + }]; + FImmutableTree *newSubtree = + [[FImmutableTree alloc] initWithValue:subtree.value + children:childrenDictionary]; + return [[FPruneForest alloc] + initWithForest:[self.pruneForest setTree:newSubtree atPath:path]]; +} + +- (void)enumarateKeptNodesUsingBlock:(void (^)(FPath *))block { + [self.pruneForest forEach:^(FPath *path, id value) { + if (value != nil && ![value boolValue]) { + block(path); + } + }]; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FStorageEngine.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FStorageEngine.h new file mode 100644 index 0000000..5f418b8 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FStorageEngine.h @@ -0,0 +1,60 @@ +/* + * 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 + +@protocol FNode; +@class FPruneForest; +@class FPath; +@class FCompoundWrite; +@class FQuerySpec; +@class FTrackedQuery; + +@protocol FStorageEngine + +- (void)close; + +- (void)saveUserOverwrite:(id)node + atPath:(FPath *)path + writeId:(NSUInteger)writeId; +- (void)saveUserMerge:(FCompoundWrite *)merge + atPath:(FPath *)path + writeId:(NSUInteger)writeId; +- (void)removeUserWrite:(NSUInteger)writeId; +- (void)removeAllUserWrites; +- (NSArray *)userWrites; + +- (id)serverCacheAtPath:(FPath *)path; +- (id)serverCacheForKeys:(NSSet *)keys atPath:(FPath *)path; +- (void)updateServerCache:(id)node + atPath:(FPath *)path + merge:(BOOL)merge; +- (void)updateServerCacheWithMerge:(FCompoundWrite *)merge atPath:(FPath *)path; +- (NSUInteger)serverCacheEstimatedSizeInBytes; + +- (void)pruneCache:(FPruneForest *)pruneForest atPath:(FPath *)path; + +- (NSArray *)loadTrackedQueries; +- (void)removeTrackedQuery:(NSUInteger)queryId; +- (void)saveTrackedQuery:(FTrackedQuery *)query; + +- (void)setTrackedQueryKeys:(NSSet *)keys forQueryId:(NSUInteger)queryId; +- (void)updateTrackedQueryKeysWithAddedKeys:(NSSet *)added + removedKeys:(NSSet *)removed + forQueryId:(NSUInteger)queryId; +- (NSSet *)trackedQueryKeysForQuery:(NSUInteger)queryId; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FTrackedQuery.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FTrackedQuery.h new file mode 100644 index 0000000..7413816 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FTrackedQuery.h @@ -0,0 +1,43 @@ +/* + * 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 + +@class FQuerySpec; + +@interface FTrackedQuery : NSObject + +@property(nonatomic, readonly) NSUInteger queryId; +@property(nonatomic, strong, readonly) FQuerySpec *query; +@property(nonatomic, readonly) NSTimeInterval lastUse; +@property(nonatomic, readonly) BOOL isComplete; +@property(nonatomic, readonly) BOOL isActive; + +- (id)initWithId:(NSUInteger)queryId + query:(FQuerySpec *)query + lastUse:(NSTimeInterval)lastUse + isActive:(BOOL)isActive; +- (id)initWithId:(NSUInteger)queryId + query:(FQuerySpec *)query + lastUse:(NSTimeInterval)lastUse + isActive:(BOOL)isActive + isComplete:(BOOL)isComplete; + +- (FTrackedQuery *)updateLastUse:(NSTimeInterval)lastUse; +- (FTrackedQuery *)setComplete; +- (FTrackedQuery *)setActiveState:(BOOL)isActive; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FTrackedQuery.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FTrackedQuery.m new file mode 100644 index 0000000..2f67dd3 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FTrackedQuery.m @@ -0,0 +1,113 @@ +/* + * 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 "FirebaseDatabase/Sources/Persistence/FTrackedQuery.h" + +#import "FirebaseDatabase/Sources/Core/FQuerySpec.h" + +@interface FTrackedQuery () + +@property(nonatomic, readwrite) NSUInteger queryId; +@property(nonatomic, strong, readwrite) FQuerySpec *query; +@property(nonatomic, readwrite) NSTimeInterval lastUse; +@property(nonatomic, readwrite) BOOL isComplete; +@property(nonatomic, readwrite) BOOL isActive; + +@end + +@implementation FTrackedQuery + +- (id)initWithId:(NSUInteger)queryId + query:(FQuerySpec *)query + lastUse:(NSTimeInterval)lastUse + isActive:(BOOL)isActive + isComplete:(BOOL)isComplete { + self = [super init]; + if (self != nil) { + self->_queryId = queryId; + self->_query = query; + self->_lastUse = lastUse; + self->_isComplete = isComplete; + self->_isActive = isActive; + } + return self; +} + +- (id)initWithId:(NSUInteger)queryId + query:(FQuerySpec *)query + lastUse:(NSTimeInterval)lastUse + isActive:(BOOL)isActive { + return [self initWithId:queryId + query:query + lastUse:lastUse + isActive:isActive + isComplete:NO]; +} + +- (FTrackedQuery *)updateLastUse:(NSTimeInterval)lastUse { + return [[FTrackedQuery alloc] initWithId:self.queryId + query:self.query + lastUse:lastUse + isActive:self.isActive + isComplete:self.isComplete]; +} + +- (FTrackedQuery *)setComplete { + return [[FTrackedQuery alloc] initWithId:self.queryId + query:self.query + lastUse:self.lastUse + isActive:self.isActive + isComplete:YES]; +} + +- (FTrackedQuery *)setActiveState:(BOOL)isActive { + return [[FTrackedQuery alloc] initWithId:self.queryId + query:self.query + lastUse:self.lastUse + isActive:isActive + isComplete:self.isComplete]; +} + +- (BOOL)isEqual:(id)object { + if (![object isKindOfClass:[FTrackedQuery class]]) { + return NO; + } + FTrackedQuery *other = (FTrackedQuery *)object; + if (self.queryId != other.queryId) + return NO; + if (self.query != other.query && ![self.query isEqual:other.query]) + return NO; + if (self.lastUse != other.lastUse) + return NO; + if (self.isComplete != other.isComplete) + return NO; + if (self.isActive != other.isActive) + return NO; + + return YES; +} + +- (NSUInteger)hash { + NSUInteger hash = self.queryId; + hash = hash * 31 + self.query.hash; + hash = hash * 31 + (self.isActive ? 1 : 0); + hash = hash * 31 + (NSUInteger)self.lastUse; + hash = hash * 31 + (self.isComplete ? 1 : 0); + hash = hash * 31 + (self.isActive ? 1 : 0); + return hash; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FTrackedQueryManager.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FTrackedQueryManager.h new file mode 100644 index 0000000..cd7d5a1 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FTrackedQueryManager.h @@ -0,0 +1,52 @@ +/* + * 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 + +@protocol FStorageEngine; +@protocol FClock; +@protocol FCachePolicy; +@class FQuerySpec; +@class FPath; +@class FTrackedQuery; +@class FPruneForest; + +@interface FTrackedQueryManager : NSObject + +- (id)initWithStorageEngine:(id)storageEngine + clock:(id)clock; + +- (FTrackedQuery *)findTrackedQuery:(FQuerySpec *)query; + +- (BOOL)isQueryComplete:(FQuerySpec *)query; + +- (void)removeTrackedQuery:(FQuerySpec *)query; +- (void)setQueryComplete:(FQuerySpec *)query; +- (void)setQueriesCompleteAtPath:(FPath *)path; +- (void)setQueryActive:(FQuerySpec *)query; +- (void)setQueryInactive:(FQuerySpec *)query; + +- (BOOL)hasActiveDefaultQueryAtPath:(FPath *)path; +- (void)ensureCompleteTrackedQueryAtPath:(FPath *)path; + +- (FPruneForest *)pruneOldQueries:(id)cachePolicy; +- (NSUInteger)numberOfPrunableQueries; +- (NSSet *)knownCompleteChildrenAtPath:(FPath *)path; + +// For testing +- (void)verifyCache; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FTrackedQueryManager.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FTrackedQueryManager.m new file mode 100644 index 0000000..311f153 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Persistence/FTrackedQueryManager.m @@ -0,0 +1,375 @@ +/* + * 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 "FirebaseDatabase/Sources/Persistence/FTrackedQueryManager.h" +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FImmutableTree.h" +#import "FirebaseDatabase/Sources/FClock.h" +#import "FirebaseDatabase/Sources/Persistence/FCachePolicy.h" +#import "FirebaseDatabase/Sources/Persistence/FLevelDBStorageEngine.h" +#import "FirebaseDatabase/Sources/Persistence/FPruneForest.h" +#import "FirebaseDatabase/Sources/Persistence/FTrackedQuery.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" + +@interface FTrackedQueryManager () + +@property(nonatomic, strong) FImmutableTree *trackedQueryTree; +@property(nonatomic, strong) id storageEngine; +@property(nonatomic, strong) id clock; +@property(nonatomic) NSUInteger currentQueryId; + +@end + +@implementation FTrackedQueryManager + +- (id)initWithStorageEngine:(id)storageEngine + clock:(id)clock { + self = [super init]; + if (self != nil) { + self->_storageEngine = storageEngine; + self->_clock = clock; + self->_trackedQueryTree = [FImmutableTree empty]; + + NSTimeInterval lastUse = [clock currentTime]; + + NSArray *trackedQueries = [self.storageEngine loadTrackedQueries]; + [trackedQueries enumerateObjectsUsingBlock:^( + FTrackedQuery *trackedQuery, NSUInteger idx, + BOOL *stop) { + self.currentQueryId = + MAX(trackedQuery.queryId + 1, self.currentQueryId); + if (trackedQuery.isActive) { + trackedQuery = + [[trackedQuery setActiveState:NO] updateLastUse:lastUse]; + FFDebug( + @"I-RDB081001", + @"Setting active query %lu from previous app start inactive", + (unsigned long)trackedQuery.queryId); + [self.storageEngine saveTrackedQuery:trackedQuery]; + } + [self cacheTrackedQuery:trackedQuery]; + }]; + } + return self; +} + ++ (void)assertValidTrackedQuery:(FQuerySpec *)query { + NSAssert(!query.loadsAllData || query.isDefault, + @"Can't have tracked non-default query that loads all data"); +} + ++ (FQuerySpec *)normalizeQuery:(FQuerySpec *)query { + return query.loadsAllData ? [FQuerySpec defaultQueryAtPath:query.path] + : query; +} + +- (FTrackedQuery *)findTrackedQuery:(FQuerySpec *)query { + query = [FTrackedQueryManager normalizeQuery:query]; + NSDictionary *set = [self.trackedQueryTree valueAtPath:query.path]; + return set[query.params]; +} + +- (void)removeTrackedQuery:(FQuerySpec *)query { + query = [FTrackedQueryManager normalizeQuery:query]; + FTrackedQuery *trackedQuery = [self findTrackedQuery:query]; + NSAssert(trackedQuery, @"Tracked query must exist to be removed!"); + + [self.storageEngine removeTrackedQuery:trackedQuery.queryId]; + NSMutableDictionary *trackedQueries = + [self.trackedQueryTree valueAtPath:query.path]; + [trackedQueries removeObjectForKey:query.params]; +} + +- (void)setQueryActive:(FQuerySpec *)query { + [self setQueryActive:YES forQuery:query]; +} + +- (void)setQueryInactive:(FQuerySpec *)query { + [self setQueryActive:NO forQuery:query]; +} + +- (void)setQueryActive:(BOOL)isActive forQuery:(FQuerySpec *)query { + query = [FTrackedQueryManager normalizeQuery:query]; + FTrackedQuery *trackedQuery = [self findTrackedQuery:query]; + + // Regardless of whether it's now active or no langer active, we update the + // lastUse time + NSTimeInterval lastUse = [self.clock currentTime]; + if (trackedQuery != nil) { + trackedQuery = + [[trackedQuery updateLastUse:lastUse] setActiveState:isActive]; + [self.storageEngine saveTrackedQuery:trackedQuery]; + } else { + NSAssert(isActive, @"If we're setting the query to inactive, we should " + @"already be tracking it!"); + trackedQuery = [[FTrackedQuery alloc] initWithId:self.currentQueryId++ + query:query + lastUse:lastUse + isActive:isActive]; + [self.storageEngine saveTrackedQuery:trackedQuery]; + } + + [self cacheTrackedQuery:trackedQuery]; +} + +- (void)setQueryComplete:(FQuerySpec *)query { + query = [FTrackedQueryManager normalizeQuery:query]; + FTrackedQuery *trackedQuery = [self findTrackedQuery:query]; + if (!trackedQuery) { + // We might have removed a query and pruned it before we got the + // complete message from the server... + FFWarn(@"I-RDB081002", + @"Trying to set a query complete that is not tracked!"); + } else if (!trackedQuery.isComplete) { + trackedQuery = [trackedQuery setComplete]; + [self.storageEngine saveTrackedQuery:trackedQuery]; + [self cacheTrackedQuery:trackedQuery]; + } else { + // Nothing to do, already marked complete + } +} + +- (void)setQueriesCompleteAtPath:(FPath *)path { + [[self.trackedQueryTree subtreeAtPath:path] + forEach:^(FPath *childPath, NSDictionary *trackedQueries) { + [trackedQueries enumerateKeysAndObjectsUsingBlock:^( + FQueryParams *parms, FTrackedQuery *trackedQuery, + BOOL *stop) { + if (!trackedQuery.isComplete) { + FTrackedQuery *newTrackedQuery = [trackedQuery setComplete]; + [self.storageEngine saveTrackedQuery:newTrackedQuery]; + [self cacheTrackedQuery:newTrackedQuery]; + } + }]; + }]; +} + +- (BOOL)isQueryComplete:(FQuerySpec *)query { + if ([self isIncludedInDefaultCompleteQuery:query]) { + return YES; + } else if (query.loadsAllData) { + // We didn't find a default complete query, so must not be complete. + return NO; + } else { + NSDictionary *trackedQueries = + [self.trackedQueryTree valueAtPath:query.path]; + return [trackedQueries[query.params] isComplete]; + } +} + +- (BOOL)hasActiveDefaultQueryAtPath:(FPath *)path { + return [self.trackedQueryTree + rootMostValueOnPath:path + matching:^BOOL(NSDictionary *trackedQueries) { + return + [trackedQueries[[FQueryParams defaultInstance]] + isActive]; + }] != nil; +} + +- (void)ensureCompleteTrackedQueryAtPath:(FPath *)path { + FQuerySpec *query = [FQuerySpec defaultQueryAtPath:path]; + if (![self isIncludedInDefaultCompleteQuery:query]) { + FTrackedQuery *trackedQuery = [self findTrackedQuery:query]; + if (trackedQuery == nil) { + trackedQuery = + [[FTrackedQuery alloc] initWithId:self.currentQueryId++ + query:query + lastUse:[self.clock currentTime] + isActive:NO + isComplete:YES]; + } else { + NSAssert(!trackedQuery.isComplete, + @"This should have been handled above!"); + trackedQuery = [trackedQuery setComplete]; + } + [self.storageEngine saveTrackedQuery:trackedQuery]; + [self cacheTrackedQuery:trackedQuery]; + } +} + +- (BOOL)isIncludedInDefaultCompleteQuery:(FQuerySpec *)query { + return + [self.trackedQueryTree + findRootMostMatchingPath:query.path + predicate:^BOOL(NSDictionary *trackedQueries) { + return + [trackedQueries[[FQueryParams defaultInstance]] + isComplete]; + }] != nil; +} + +- (void)cacheTrackedQuery:(FTrackedQuery *)query { + [FTrackedQueryManager assertValidTrackedQuery:query.query]; + NSMutableDictionary *trackedDict = + [self.trackedQueryTree valueAtPath:query.query.path]; + if (trackedDict == nil) { + trackedDict = [NSMutableDictionary dictionary]; + self.trackedQueryTree = + [self.trackedQueryTree setValue:trackedDict + atPath:query.query.path]; + } + trackedDict[query.query.params] = query; +} + +- (NSUInteger)numberOfQueriesToPrune:(id)cachePolicy + prunableCount:(NSUInteger)numPrunable { + NSUInteger numPercent = (NSUInteger)ceilf( + numPrunable * [cachePolicy percentOfQueriesToPruneAtOnce]); + NSUInteger maxToKeep = [cachePolicy maxNumberOfQueriesToKeep]; + NSUInteger numMax = (numPrunable > maxToKeep) ? numPrunable - maxToKeep : 0; + // Make sure we get below number of max queries to prune + return MAX(numMax, numPercent); +} + +- (FPruneForest *)pruneOldQueries:(id)cachePolicy { + NSMutableArray *pruneableQueries = [NSMutableArray array]; + NSMutableArray *unpruneableQueries = [NSMutableArray array]; + [self.trackedQueryTree + forEach:^(FPath *path, NSDictionary *trackedQueries) { + [trackedQueries enumerateKeysAndObjectsUsingBlock:^( + FQueryParams *params, FTrackedQuery *trackedQuery, + BOOL *stop) { + if (!trackedQuery.isActive) { + [pruneableQueries addObject:trackedQuery]; + } else { + [unpruneableQueries addObject:trackedQuery]; + } + }]; + }]; + [pruneableQueries sortUsingComparator:^NSComparisonResult( + FTrackedQuery *q1, FTrackedQuery *q2) { + if (q1.lastUse < q2.lastUse) { + return NSOrderedAscending; + } else if (q1.lastUse > q2.lastUse) { + return NSOrderedDescending; + } else { + return NSOrderedSame; + } + }]; + + __block FPruneForest *pruneForest = [FPruneForest empty]; + NSUInteger numToPrune = + [self numberOfQueriesToPrune:cachePolicy + prunableCount:pruneableQueries.count]; + + // TODO: do in transaction + for (NSUInteger i = 0; i < numToPrune; i++) { + FTrackedQuery *toPrune = pruneableQueries[i]; + pruneForest = [pruneForest prunePath:toPrune.query.path]; + [self removeTrackedQuery:toPrune.query]; + } + + // Keep the rest of the prunable queries + for (NSUInteger i = numToPrune; i < pruneableQueries.count; i++) { + FTrackedQuery *toKeep = pruneableQueries[i]; + pruneForest = [pruneForest keepPath:toKeep.query.path]; + } + + // Also keep unprunable queries + [unpruneableQueries enumerateObjectsUsingBlock:^( + FTrackedQuery *toKeep, NSUInteger idx, BOOL *stop) { + pruneForest = [pruneForest keepPath:toKeep.query.path]; + }]; + + return pruneForest; +} + +- (NSUInteger)numberOfPrunableQueries { + __block NSUInteger count = 0; + [self.trackedQueryTree + forEach:^(FPath *path, NSDictionary *trackedQueries) { + [trackedQueries enumerateKeysAndObjectsUsingBlock:^( + FQueryParams *params, FTrackedQuery *trackedQuery, + BOOL *stop) { + if (!trackedQuery.isActive) { + count++; + } + }]; + }]; + return count; +} + +- (NSSet *)filteredQueryIdsAtPath:(FPath *)path { + NSDictionary *queries = [self.trackedQueryTree valueAtPath:path]; + if (queries) { + NSMutableSet *ids = [NSMutableSet set]; + [queries enumerateKeysAndObjectsUsingBlock:^( + FQueryParams *params, FTrackedQuery *query, BOOL *stop) { + if (!query.query.loadsAllData) { + [ids addObject:@(query.queryId)]; + } + }]; + return ids; + } else { + return [NSSet set]; + } +} + +- (NSSet *)knownCompleteChildrenAtPath:(FPath *)path { + NSAssert(![self isQueryComplete:[FQuerySpec defaultQueryAtPath:path]], + @"Path is fully complete"); + + NSMutableSet *completeChildren = [NSMutableSet set]; + // First, get complete children from any queries at this location. + NSSet *queryIds = [self filteredQueryIdsAtPath:path]; + [queryIds enumerateObjectsUsingBlock:^(NSNumber *queryId, BOOL *stop) { + NSSet *keys = [self.storageEngine + trackedQueryKeysForQuery:[queryId unsignedIntegerValue]]; + [completeChildren unionSet:keys]; + }]; + + // Second, get any complete default queries immediately below us. + [[[self.trackedQueryTree subtreeAtPath:path] children] + enumerateKeysAndObjectsUsingBlock:^( + NSString *childKey, FImmutableTree *childTree, BOOL *stop) { + if ([childTree.value[[FQueryParams defaultInstance]] isComplete]) { + [completeChildren addObject:childKey]; + } + }]; + + return completeChildren; +} + +- (void)verifyCache { + NSArray *storedTrackedQueries = [self.storageEngine loadTrackedQueries]; + NSMutableArray *trackedQueries = [NSMutableArray array]; + + [self.trackedQueryTree forEach:^(FPath *path, NSDictionary *queryDict) { + [trackedQueries addObjectsFromArray:queryDict.allValues]; + }]; + NSComparator comparator = + ^NSComparisonResult(FTrackedQuery *q1, FTrackedQuery *q2) { + if (q1.queryId < q2.queryId) { + return NSOrderedAscending; + } else if (q1.queryId > q2.queryId) { + return NSOrderedDescending; + } else { + return NSOrderedSame; + } + }; + [trackedQueries sortUsingComparator:comparator]; + storedTrackedQueries = + [storedTrackedQueries sortedArrayUsingComparator:comparator]; + + if (![trackedQueries isEqualToArray:storedTrackedQueries]) { + [NSException + raise:NSInternalInconsistencyException + format:@"Tracked queries and queries stored on disk don't match"]; + } +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDataEventType.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDataEventType.h new file mode 100644 index 0000000..3aecd81 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDataEventType.h @@ -0,0 +1,39 @@ +/* + * 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. + */ + +#ifndef Firebase_FIRDataEventType_h +#define Firebase_FIRDataEventType_h + +#import + +/** + * This enum is the set of events that you can observe at a Firebase Database + * location. + */ +typedef NS_ENUM(NSInteger, FIRDataEventType) { + /// A new child node is added to a location. + FIRDataEventTypeChildAdded, + /// A child node is removed from a location. + FIRDataEventTypeChildRemoved, + /// A child node at a location changes. + FIRDataEventTypeChildChanged, + /// A child node moves relative to the other child nodes at a location. + FIRDataEventTypeChildMoved, + /// Any data changes at a location or, recursively, at any child node. + FIRDataEventTypeValue +} NS_SWIFT_NAME(DataEventType); + +#endif diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDataSnapshot.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDataSnapshot.h new file mode 100644 index 0000000..4197d26 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDataSnapshot.h @@ -0,0 +1,143 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +@class FIRDatabaseReference; + +/** + * A DataSnapshot contains data from a Firebase Database location. Any time + * you read Firebase data, you receive the data as a DataSnapshot. + * + * DataSnapshots are passed to the blocks you attach with + * `observe(_:with:)` or `observeSingleEvent(of:with:)`. They are + * efficiently-generated immutable copies of the data at a Firebase Database + * location. They can't be modified and will never change. To modify data at a + * location, use a DatabaseReference (e.g. with `setValue(_:)`). + */ +NS_SWIFT_NAME(DataSnapshot) +@interface FIRDataSnapshot : NSObject + +#pragma mark - Navigating and inspecting a snapshot + +/** + * Gets a DataSnapshot for the location at the specified relative path. + * The relative path can either be a simple child key (e.g. 'fred') + * or a deeper slash-separated path (e.g. 'fred/name/first'). If the child + * location has no data, an empty DataSnapshot is returned. + * + * @param childPathString A relative path to the location of child data. + * @return The DataSnapshot for the child location. + */ +- (FIRDataSnapshot *)childSnapshotForPath:(NSString *)childPathString; + +/** + * Return true if the specified child exists. + * + * @param childPathString A relative path to the location of a potential child. + * @return true if data exists at the specified childPathString, else false. + */ +- (BOOL)hasChild:(NSString *)childPathString; + +/** + * Return true if the DataSnapshot has any children. + * + * @return true if this snapshot has any children, else false. + */ +- (BOOL)hasChildren; + +/** + * Return true if the DataSnapshot contains a non-null value. + * + * @return true if this snapshot contains a non-null value, else false. + */ +- (BOOL)exists; + +#pragma mark - Data export + +/** + * Returns the raw value at this location, coupled with any metadata, such as + * priority. + * + * Priorities, where they exist, are accessible under the ".priority" key in + * instances of NSDictionary. For leaf locations with priorities, the value will + * be under the ".value" key. + */ +- (id _Nullable)valueInExportFormat; + +#pragma mark - Properties + +/** + * Returns the contents of this data snapshot as native types. + * + * Data types returned: + * + `Dictionary` + * + `Array` + * + `NSNumber`-bridgeable types, including `Bool` + * + `String` + * + * @return The data as a native object. + */ +@property(strong, readonly, nonatomic, nullable) id value; + +/** + * Gets the number of children for this DataSnapshot. + * + * @return An integer indicating the number of children. + */ +@property(readonly, nonatomic) NSUInteger childrenCount; + +/** + * Gets a DatabaseReference for the location that this data came from. + * + * @return A DatabaseReference instance for the location of this data. + */ +@property(nonatomic, readonly, strong) FIRDatabaseReference *ref; + +/** + * The key of the location that generated this DataSnapshot. + * + * @return A `String` containing the key for the location of this + * DataSnapshot. + */ +@property(strong, readonly, nonatomic) NSString *key; + +/** + * An iterator for snapshots of the child nodes in this snapshot. + * + * ``` + * for var child in snapshot.children { + * // ... + * } + * ``` + * + * @return An NSEnumerator of the children. + */ +@property(strong, readonly, nonatomic) + NSEnumerator *children; + +/** + * The priority of the data in this DataSnapshot. + * + * @return The priority as a `String`, or `nil` if no priority was set. + */ +@property(strong, readonly, nonatomic, nullable) id priority; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabase.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabase.h new file mode 100644 index 0000000..eeab6b0 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabase.h @@ -0,0 +1,191 @@ +/* + * 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 "FIRDatabaseReference.h" +#import + +@class FIRApp; + +NS_ASSUME_NONNULL_BEGIN + +/** + * The entry point for accessing a Firebase Database. You can get an instance + * by calling `Database.database()`. To access a location in the database and + * read or write data, use `FIRDatabase.reference()`. + */ +NS_SWIFT_NAME(Database) __attribute__((availability( + watchos, introduced = 6.0, deprecated = 9.0, + message = "Socket connections are not supported on watchOS 9.0 and higher. " + "Use the Firebase Database REST API instead. See " + "github.com/firebase/firebase-ios-sdk/issues/10195 " + "for more details."))) +@interface FIRDatabase : NSObject + +/** + * The NSObject initializer that has been marked as unavailable. Use the + * `database` class method instead. + */ +- (instancetype)init + __attribute__((unavailable("use the database method instead"))); + +/** + * Gets the instance of `Database` for the default `FirebaseApp`. + * + * @return A `Database` instance. + */ ++ (FIRDatabase *)database NS_SWIFT_NAME(database()); + +/** + * Gets a `Database` instance for the specified URL. + * + * @param url The URL to the Firebase Database instance you want to access. + * @return A `Database` instance. + */ ++ (FIRDatabase *)databaseWithURL:(NSString *)url NS_SWIFT_NAME(database(url:)); + +/** + * Gets a `Database` instance for the specified URL, using the specified + * `FirebaseApp`. + * + * @param app The app to get a `Database` for. + * @param url The URL to the Firebase Database instance you want to access. + * @return A `Database` instance. + */ +// clang-format off ++ (FIRDatabase *)databaseForApp:(FIRApp *)app + URL:(NSString *)url NS_SWIFT_NAME(database(app:url:)); +// clang-format on + +/** + * Gets an instance of `Database` for a specific `FirebaseApp`. + * + * @param app The app to get a `Database` for. + * @return A `Database` instance. + */ ++ (FIRDatabase *)databaseForApp:(FIRApp *)app NS_SWIFT_NAME(database(app:)); + +/** The app instance to which this `Database` belongs. */ +@property(weak, readonly, nonatomic) FIRApp *app; + +/** + * Gets a `DatabaseReference` for the root of your Firebase Database. + */ +- (FIRDatabaseReference *)reference; + +/** + * Gets a `DatabaseReference` for the provided path. + * + * @param path Path to a location in your Firebase Database. + * @return A `DatabaseReference` pointing to the specified path. + */ +- (FIRDatabaseReference *)referenceWithPath:(NSString *)path; + +/** + * Gets a `DatabaseReference` for the provided URL. The URL must be a URL to a + * path within this Firebase Database. To create a `DatabaseReference` to a + * different database, create a `FirebaseApp` with an `Options` object + * configured with the appropriate database URL. + * + * @param databaseUrl A URL to a path within your database. + * @return A `DatabaseReference` for the provided URL. + */ +- (FIRDatabaseReference *)referenceFromURL:(NSString *)databaseUrl; + +/** + * The Firebase Database client automatically queues writes and sends them to + * the server at the earliest opportunity, depending on network connectivity. In + * some cases (e.g. offline usage) there may be a large number of writes waiting + * to be sent. Calling this method will purge all outstanding writes so they are + * abandoned. + * + * All writes will be purged, including transactions and onDisconnect writes. + * The writes will be rolled back locally, perhaps triggering events for + * affected event listeners, and the client will not (re-)send them to the + * Firebase Database backend. + */ +- (void)purgeOutstandingWrites; + +/** + * Shuts down the connection to the Firebase Database backend until `goOnline()` + * is called. + */ +- (void)goOffline; + +/** + * Resumes the connection to the Firebase Database backend after a previous + * goOffline() call. + */ +- (void)goOnline; + +/** + * The Firebase Database client will cache synchronized data and keep track of + * all writes you've initiated while your application is running. It seamlessly + * handles intermittent network connections and re-sends write operations when + * the network connection is restored. + * + * However by default your write operations and cached data are only stored + * in-memory and will be lost when your app restarts. By setting this value to + * `true`, the data will be persisted to on-device (disk) storage and will thus + * be available again when the app is restarted (even when there is no network + * connectivity at that time). Note that this property must be set before + * creating your first `DatabaseReference` and only needs to be called once per + * application. + * + */ +@property(nonatomic) BOOL persistenceEnabled NS_SWIFT_NAME(isPersistenceEnabled) + ; + +/** + * By default the Firebase Database client will use up to 10MB of disk space to + * cache data. If the cache grows beyond this size, the client will start + * removing data that hasn't been recently used. If you find that your + * application caches too little or too much data, call this method to change + * the cache size. This property must be set before creating your first + * `DatabaseReference` and only needs to be called once per application. + * + * Note that the specified cache size is only an approximation and the size on + * disk may temporarily exceed it at times. Cache sizes smaller than 1 MB or + * greater than 100 MB are not supported. + */ +@property(nonatomic) NSUInteger persistenceCacheSizeBytes; + +/** + * Sets the dispatch queue on which all events are raised. The default queue is + * the main queue. + * + * Note that this must be set before creating your first Database reference. + */ +@property(nonatomic, strong) dispatch_queue_t callbackQueue; + +/** + * Enables verbose diagnostic logging. + * + * @param enabled true to enable logging, false to disable. + */ ++ (void)setLoggingEnabled:(BOOL)enabled; + +/** Retrieve the Firebase Database SDK version. */ ++ (NSString *)sdkVersion; + +/** + * Configures the database to use an emulated backend instead of the default + * remote backend. + */ +- (void)useEmulatorWithHost:(NSString *)host port:(NSInteger)port; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseQuery.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseQuery.h new file mode 100644 index 0000000..4143d4f --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseQuery.h @@ -0,0 +1,473 @@ +/* + * 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 "FIRDataEventType.h" +#import "FIRDataSnapshot.h" +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * A `DatabaseHandle` is used to identify listeners of Firebase Database + * events. These handles are returned by `observe(_:with:)` and can later be + * passed to `removeObserver(withHandle:)` to stop receiving updates. + */ +typedef NSUInteger FIRDatabaseHandle NS_SWIFT_NAME(DatabaseHandle); + +/** + * A `DatabaseQuery` instance represents a query over the data at a particular + * location. + * + * You create one by calling one of the query methods (`queryOrdered(byChild:)`, + * `queryStarting(atValue:)`, etc.) on a `DatabaseReference`. The query methods + * can be chained to further specify the data you are interested in observing. + */ +NS_SWIFT_NAME(DatabaseQuery) +@interface FIRDatabaseQuery : NSObject + +#pragma mark - Attach observers to read data + +/** + * This method is used to listen for data changes at a particular location. + * This is the primary way to read data from the Firebase Database. Your + * block will be triggered for the initial data and again whenever the + * data changes. + * + * Use removeObserverWithHandle: to stop receiving updates. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called with initial data and updates. + * It is passed the data as a `DataSnapshot`. + * @return A handle used to unregister this block later using + * `removeObserver(withHandle:)` + */ +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + withBlock: + (void (^)(FIRDataSnapshot *snapshot))block; + +/** + * This method is used to listen for data changes at a particular location. + * This is the primary way to read data from the Firebase Database. Your + * block will be triggered for the initial data and again whenever the data + * changes. In addition, for `DataEventTypeChildAdded`, + * `DataEventTypeChildMoved`, and `DataEventTypeChildChanged` events, your + * block will be passed the key of the previous node by priority order. + * + * Use `removeObserver(withHandle:)` to stop receiving updates. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called with initial data and updates. + * It is passed the data as a `DataSnapshot` and the previous child's key. + * @return A handle used to unregister this block later using + * `removeObserver(withHandle:)` + */ +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock: + (void (^)(FIRDataSnapshot *snapshot, + NSString *__nullable prevKey))block; + +/** + * This method is used to listen for data changes at a particular location. + * This is the primary way to read data from the Firebase Database. Your + * block will be triggered for the initial data and again whenever the data + * changes. + * + * The `cancelBlock` will be called if you will no longer receive new events + * due to no longer having permission. + * + * Use `removeObserver(withHandle:)` to stop receiving updates. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called with initial data and updates. + * It is passed the data as a `DataSnapshot`. + * @param cancelBlock The block that should be called if this client no longer + * has permission to receive these events + * @return A handle used to unregister this block later using + * `removeObserver(withHandle:)` + */ +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + withBlock:(void (^)(FIRDataSnapshot *snapshot))block + withCancelBlock: + (nullable void (^)(NSError *error))cancelBlock; + +/** + * This method is used to listen for data changes at a particular location. + * This is the primary way to read data from the Firebase Database. Your block + * will be triggered for the initial data and again whenever the data changes. + * In addition, for `FIRDataEventTypeChildAdded`, `FIRDataEventTypeChildMoved`, + * and FIRDataEventTypeChildChanged events, your block will be passed the key + * of the previous node by priority order. + * + * The `cancelBlock` will be called if you will no longer receive new events due + * to no longer having permission. + * + * Use `removeObserver(withHandle:)` to stop receiving updates. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called with initial data and updates. + * It is passed the data as a `DataSnapshot` and the previous child's key. + * @param cancelBlock The block that should be called if this client no longer + * has permission to receive these events + * @return A handle used to unregister this block later using + * `removeObserver(withHandle:)` + */ +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock: + (void (^)(FIRDataSnapshot *snapshot, + NSString *__nullable prevKey))block + withCancelBlock: + (nullable void (^)(NSError *error))cancelBlock; + +/** + * This method is used to get the most up-to-date value for this query. This + * method updates the cache and raises events if successful. If + * not connected, it returns a locally-cached value. + * + * @param block The block that should be called with the most up-to-date value + * of this query, or an error if no such value could be retrieved. + */ +- (void)getDataWithCompletionBlock: + (void (^_Nonnull)(NSError *__nullable error, + FIRDataSnapshot *__nullable snapshot))block + NS_SWIFT_NAME(getData(completion:)); + +/** + * This is equivalent to `observe(_:with:)`, except the block is + * immediately canceled after the initial data is returned. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called. It is passed the data as a + * `DataSnapshot`. + */ +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + withBlock:(void (^)(FIRDataSnapshot *snapshot))block; + +/** + * This is equivalent to `observe(_:with:)`, except the block is + * immediately canceled after the initial data is returned. In addition, for + * `DataEventTypeChildAdded`, `DataEventTypeChildMoved`, and + * `DataEventTypeChildChanged` events, your block will be passed the key of the + * previous node by priority order. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called. It is passed the data as a + * `DataSnapshot` and the previous child's key. + */ +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock: + (void (^)(FIRDataSnapshot *snapshot, + NSString *__nullable prevKey))block; + +/** + * This is equivalent to `observe(_:with:)`, except the block is + * immediately canceled after the initial data is returned. + * + * The `cancelBlock` will be called if you do not have permission to read data + * at this location. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called. It is passed the data as a + * `DataSnapshot`. + * @param cancelBlock The block that will be called if you don't have permission + * to access this data + */ +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + withBlock:(void (^)(FIRDataSnapshot *snapshot))block + withCancelBlock:(nullable void (^)(NSError *error))cancelBlock; + +/** + * This is equivalent to `observe(_:with:)`, except the block is + * immediately canceled after the initial data is returned. In addition, for + * `DataEventTypeChildAdded`, `DataEventTypeChildMoved`, and + * `DataEventTypeChildChanged` events, your block will be passed the key of the + * previous node by priority order. + * + * The `cancelBlock` will be called if you do not have permission to read data + * at this location. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called. It is passed the data as a + * `DataSnapshot` and the previous child's key. + * @param cancelBlock The block that will be called if you don't have permission + * to access this data + */ +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock:(void (^)(FIRDataSnapshot *snapshot, + NSString *__nullable prevKey))block + withCancelBlock: + (nullable void (^)(NSError *error))cancelBlock; + +#pragma mark - Detaching observers + +/** + * Detach a block previously attached with `observe(_:with:)`, or another query + * observation method. After this method is called, the associated block + * registered to receive snapshot updates will no longer be invoked. + * + * @param handle The handle returned by the call to `observe(_:with:)` + * which we are trying to remove. + */ +- (void)removeObserverWithHandle:(FIRDatabaseHandle)handle; + +/** + * Detach all blocks previously attached to this Firebase Database location with + * `observe(_:with:)` and other query observation methods. + */ +- (void)removeAllObservers; + +/** + * By calling `keepSynced(true)` on a location, the data for that location will + * automatically be downloaded and kept in sync, even when no listeners are + * attached for that location. Additionally, while a location is kept synced, it + * will not be evicted from the persistent disk cache. + * + * @param keepSynced Pass true to keep this location synchronized, or false to + * stop synchronization. + */ +- (void)keepSynced:(BOOL)keepSynced; + +#pragma mark - Querying and limiting + +/** + * This method is used to generate a reference to a limited view of the + * data at this location. The `DatabaseQuery` instance returned by + * `queryLimited(toFirst:)` will respond to at most the first limit child nodes. + * + * @param limit The upper bound, inclusive, for the number of child nodes to + * receive events for + * @return A `DatabaseQuery` instance, limited to at most limit child nodes. + */ +- (FIRDatabaseQuery *)queryLimitedToFirst:(NSUInteger)limit; + +/** + * `queryLimited(toLast:)` is used to generate a reference to a limited view of + * the data at this location. The `DatabaseQuery` instance returned by + * this method will respond to at most the last limit child nodes. + * + * @param limit The upper bound, inclusive, for the number of child nodes to + * receive events for + * @return A `DatabaseQuery` instance, limited to at most limit child nodes. + */ +- (FIRDatabaseQuery *)queryLimitedToLast:(NSUInteger)limit; + +/** + * This method is used to generate a reference to a view of the data that's + * been sorted by the values of a particular child key. This method is intended + * to be used in combination with `queryStarting(atValue:)`, + * `queryEnding(atValue:)`, or `queryEqual(toValue:)`. + * + * @param key The child key to use in ordering data visible to the returned + * `DatabaseQuery` + * @return A `DatabaseQuery` instance, ordered by the values of the specified + * child key. + */ +- (FIRDatabaseQuery *)queryOrderedByChild:(NSString *)key; + +/** + * `queryOrdered(byKey:) is used to generate a reference to a view of the data + * that's been sorted by child key. This method is intended to be used in + * combination with `queryStarting(atValue:)`, `queryEnding(atValue:)`, or + * `queryEqual(toValue:)`. + * + * @return A `DatabaseQuery` instance, ordered by child keys. + */ +- (FIRDatabaseQuery *)queryOrderedByKey; + +/** + * `queryOrdered(byValue:)` is used to generate a reference to a view of the + * data that's been sorted by child value. This method is intended to be used in + * combination with `queryStarting(atValue:)`, `queryEnding(atValue:)`, or + * `queryEqual(toValue:)`. + * + * @return A `DatabaseQuery` instance, ordered by child value. + */ +- (FIRDatabaseQuery *)queryOrderedByValue; + +/** + * `queryOrdered(byPriority:) is used to generate a reference to a view of the + * data that's been sorted by child priority. This method is intended to be used + * in combination with `queryStarting(atValue:)`, `queryEnding(atValue:)`, or + * `queryEqual(toValue:)`. + * + * @return A `DatabaseQuery` instance, ordered by child priorities. + */ +- (FIRDatabaseQuery *)queryOrderedByPriority; + +/** + * `queryStarting(atValue:)` is used to generate a reference to a limited view + * of the data at this location. The `DatabaseQuery` instance returned by + * `queryStarting(atValue:)` will respond to events at nodes with a value + * greater than or equal to `startValue`. + * + * @param startValue The lower bound, inclusive, for the value of data visible + * to the returned `DatabaseQuery` + * @return A `DatabaseQuery` instance, limited to data with value greater than + * or equal to `startValue` + */ +- (FIRDatabaseQuery *)queryStartingAtValue:(nullable id)startValue; + +/** + * `queryStarting(atValue:childKey:)` is used to generate a reference to a + * limited view of the data at this location. The `DatabaseQuery` instance + * returned by `queryStarting(atValue:childKey:)` will respond to events at + * nodes with a value greater than `startValue`, or equal to `startValue` and + * with a key greater than or equal to `childKey`. This is most useful when + * implementing pagination in a case where multiple nodes can match the + * `startValue`. + * + * @param startValue The lower bound, inclusive, for the value of data visible + * to the returned `DatabaseQuery` + * @param childKey The lower bound, inclusive, for the key of nodes with value + * equal to `startValue` + * @return A `DatabaseQuery` instance, limited to data with value greater than + * or equal to `startValue` + */ +- (FIRDatabaseQuery *)queryStartingAtValue:(nullable id)startValue + childKey:(nullable NSString *)childKey; + +/** + * `queryStarting(afterValue:)` is used to generate a reference to a + * limited view of the data at this location. The `DatabaseQuery` instance + * returned by `queryStarting(afterValue:)` will respond to events at nodes + * with a value greater than startAfterValue. + * + * @param startAfterValue The lower bound, exclusive, for the value of data + * visible to the returned `DatabaseQuery` + * @return A `DatabaseQuery` instance, limited to data with value greater + * `startAfterValue` + */ +- (FIRDatabaseQuery *)queryStartingAfterValue:(nullable id)startAfterValue; + +/** + * `queryStarting(afterValue:childKey:)` is used to generate a reference to a + * limited view of the data at this location. The `DatabaseQuery` instance + * returned by `queryStarting(afterValue:childKey:)` will respond to events at + * nodes with a value greater than `startAfterValue`, or equal to + * `startAfterValue` and with a key greater than `childKey`. This is most useful + * when implementing pagination in a case where multiple nodes can match the + * `startAfterValue`. + * + * @param startAfterValue The lower bound, inclusive, for the value of data + * visible to the returned `DatabaseQuery` + * @param childKey The lower bound, exclusive, for the key of nodes with value + * equal to `startAfterValue` + * @return A `DatabaseQuery` instance, limited to data with value greater than + * `startAfterValue`, or equal to `startAfterValue` with a key greater than + * `childKey` + */ +- (FIRDatabaseQuery *)queryStartingAfterValue:(nullable id)startAfterValue + childKey:(nullable NSString *)childKey; +/** + * `queryEnding(atValue:)` is used to generate a reference to a limited view of + * the data at this location. The DatabaseQuery instance returned by + * `queryEnding(atValue:)` will respond to events at nodes with a value less + * than or equal to `endValue`. + * + * @param endValue The upper bound, inclusive, for the value of data visible to + * the returned `DatabaseQuery` + * @return A `DatabaseQuery` instance, limited to data with value less than or + * equal to `endValue` + */ +- (FIRDatabaseQuery *)queryEndingAtValue:(nullable id)endValue; + +/** + * `queryEnding(atValue:childKey:)` is used to generate a reference to a limited + * view of the data at this location. The `DatabaseQuery` instance returned by + * `queryEnding(atValue:childKey:)` will respond to events at nodes with a value + * less than `endValue`, or equal to `endValue` and with a key less than or + * equal to `childKey`. This is most useful when implementing pagination in a + * case where multiple nodes can match the `endValue`. + * + * @param endValue The upper bound, inclusive, for the value of data visible to + * the returned `DatabaseQuery` + * @param childKey The upper bound, inclusive, for the key of nodes with value + * equal to `endValue` + * @return A `DatabaseQuery` instance, limited to data with value less than or + * equal to `endValue` + */ +- (FIRDatabaseQuery *)queryEndingAtValue:(nullable id)endValue + childKey:(nullable NSString *)childKey; + +/** + * `queryEnding(beforeValue:) is used to generate a reference to a limited view + * of the data at this location. The `DatabaseQuery` instance returned by + * `queryEnding(beforeValue:)` will respond to events at nodes with a value less + * than `endValue`. + * + * @param endValue The upper bound, exclusive, for the value of data visible to + * the returned `DatabaseQuery` + * @return A `DatabaseQuery` instance, limited to data with value less than + * `endValue` + */ +- (FIRDatabaseQuery *)queryEndingBeforeValue:(nullable id)endValue; + +/** + * `queryEnding(beforeValue:childKey:)` is used to generate a reference to a + * limited view of the data at this location. The `DatabaseQuery` instance + * returned by `queryEnding(beforeValue:childKey:)` will respond to events at + * nodes with a value less than `endValue`, or equal to `endValue` and with a + * key less than childKey. + * + * @param endValue The upper bound, inclusive, for the value of data visible to + * the returned `DatabaseQuery` + * @param childKey The upper bound, exclusive, for the key of nodes with value + * equal to endValue + * @return A `DatabaseQuery` instance, limited to data with value less than or + * equal to endValue + */ +- (FIRDatabaseQuery *)queryEndingBeforeValue:(nullable id)endValue + childKey:(nullable NSString *)childKey; + +/** + * `queryEqual(toValue:)` is used to generate a reference to a limited view of + * the data at this location. The `DatabaseQuery` instance returned by + * `queryEqual(toValue:)` will respond to events at nodes with a value equal to + * the supplied argument. + * + * @param value The value that the data returned by this `DatabaseQuery` will + * have + * @return A `DatabaseQuery` instance, limited to data with the supplied value. + */ +- (FIRDatabaseQuery *)queryEqualToValue:(nullable id)value; + +/** + * `queryEqual(toValue:childKey:)` is used to generate a reference to a limited + * view of the data at this location. The `DatabaseQuery` instance returned by + * `queryEqual(toValue:childKey:)` will respond to events at nodes with a value + * equal to the supplied argument and with their key equal to `childKey`. There + * will be at most one node that matches because child keys are unique. + * + * @param value The value that the data returned by this `DatabaseQuery` will + * have + * @param childKey The name of nodes with the right value + * @return A `DatabaseQuery` instance, limited to data with the supplied value + * and the key. + */ +- (FIRDatabaseQuery *)queryEqualToValue:(nullable id)value + childKey:(nullable NSString *)childKey; + +#pragma mark - Properties + +/** + * Gets a `DatabaseReference` for the location of this query. + * + * @return A `DatabaseReference` for the location of this query. + */ +@property(nonatomic, readonly, strong) FIRDatabaseReference *ref; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseReference.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseReference.h new file mode 100644 index 0000000..9dd3585 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseReference.h @@ -0,0 +1,905 @@ +/* + * 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 "FIRDataSnapshot.h" +#import "FIRDatabase.h" +#import "FIRDatabaseQuery.h" +#import "FIRMutableData.h" +#import "FIRServerValue.h" +#import "FIRTransactionResult.h" +#import + +NS_ASSUME_NONNULL_BEGIN + +@class FIRDatabase; + +/** + * A FIRDatabaseReference represents a particular location in your Firebase + * Database and can be used for reading or writing data to that Firebase + * Database location. + * + * This class is the starting point for all Firebase Database operations. After + * you've obtained your first FIRDatabaseReference via [FIRDatabase reference], + * you can use it to read data (ie. observeEventType:withBlock:), write data + * (ie. setValue:), and to create new FIRDatabaseReferences (ie. child:). + */ +NS_SWIFT_NAME(DatabaseReference) +@interface FIRDatabaseReference : FIRDatabaseQuery + +#pragma mark - Getting references to children locations + +/** + * Gets a FIRDatabaseReference for the location at the specified relative path. + * The relative path can either be a simple child key (e.g. 'fred') or a + * deeper slash-separated path (e.g. 'fred/name/first'). + * + * @param pathString A relative path from this location to the desired child + * location. + * @return A FIRDatabaseReference for the specified relative path. + */ +- (FIRDatabaseReference *)child:(NSString *)pathString; + +/** + * childByAutoId generates a new child location using a unique key and returns a + * FIRDatabaseReference to it. This is useful when the children of a Firebase + * Database location represent a list of items. + * + * The unique key generated by childByAutoId: is based on a client-generated + * timestamp so that the resulting list will be chronologically-sorted. + * + * @return A FIRDatabaseReference for the generated location. + */ +- (FIRDatabaseReference *)childByAutoId; + +#pragma mark - Writing data + +/** Write data to this Firebase Database location. + +This will overwrite any data at this location and all child locations. + +Data types that can be set are: + +- NSString -- @"Hello World" +- NSNumber (also includes boolean) -- @YES, @43, @4.333 +- NSDictionary -- @{@"key": @"value", @"nested": @{@"another": @"value"} } +- NSArray + +The effect of the write will be visible immediately and the corresponding +events will be triggered. Synchronization of the data to the Firebase Database +servers will also be started. + +Passing null for the new value is equivalent to calling remove:; +all data at this location or any child location will be deleted. + +Note that setValue: will remove any priority stored at this location, so if +priority is meant to be preserved, you should use setValue:andPriority: instead. + +@param value The value to be written. + */ +- (void)setValue:(nullable id)value; + +/** + * The same as setValue: with a block that gets triggered after the write + * operation has been committed to the Firebase Database servers. + * + * @param value The value to be written. + * @param block The block to be called after the write has been committed to the + * Firebase Database servers. + */ +- (void)setValue:(nullable id)value + withCompletionBlock: + (void (^)(NSError *__nullable error, FIRDatabaseReference *ref))block; + +/** + * The same as setValue: with an additional priority to be attached to the data + * being written. Priorities are used to order items. + * + * @param value The value to be written. + * @param priority The priority to be attached to that data. + */ +- (void)setValue:(nullable id)value andPriority:(nullable id)priority; + +/** + * The same as setValue:andPriority: with a block that gets triggered after the + * write operation has been committed to the Firebase Database servers. + * + * @param value The value to be written. + * @param priority The priority to be attached to that data. + * @param block The block to be called after the write has been committed to the + * Firebase Database servers. + */ +- (void)setValue:(nullable id)value + andPriority:(nullable id)priority + withCompletionBlock: + (void (^)(NSError *__nullable error, FIRDatabaseReference *ref))block; + +/** + * Remove the data at this Firebase Database location. Any data at child + * locations will also be deleted. + * + * The effect of the delete will be visible immediately and the corresponding + * events will be triggered. Synchronization of the delete to the Firebase + * Database servers will also be started. + * + * remove: is equivalent to calling setValue:nil + */ +- (void)removeValue; + +/** + * The same as remove: with a block that gets triggered after the remove + * operation has been committed to the Firebase Database servers. + * + * @param block The block to be called after the remove has been committed to + * the Firebase Database servers. + */ +- (void)removeValueWithCompletionBlock: + (void (^)(NSError *__nullable error, FIRDatabaseReference *ref))block; + +/** + * Sets a priority for the data at this Firebase Database location. + * Priorities can be used to provide a custom ordering for the children at a + * location (if no priorities are specified, the children are ordered by key). + * + * You cannot set a priority on an empty location. For this reason + * setValue:andPriority: should be used when setting initial data with a + * specific priority and setPriority: should be used when updating the priority + * of existing data. + * + * Children are sorted based on this priority using the following rules: + * + * Children with no priority come first. + * Children with a number as their priority come next. They are sorted + * numerically by priority (small to large). Children with a string as their + * priority come last. They are sorted lexicographically by priority. Whenever + * two children have the same priority (including no priority), they are sorted + * by key. Numeric keys come first (sorted numerically), followed by the + * remaining keys (sorted lexicographically). + * + * Note that priorities are parsed and ordered as IEEE 754 double-precision + * floating-point numbers. Keys are always stored as strings and are treated as + * numbers only when they can be parsed as a 32-bit integer + * + * @param priority The priority to set at the specified location. + */ +- (void)setPriority:(nullable id)priority; + +/** + * The same as setPriority: with a block that is called once the priority has + * been committed to the Firebase Database servers. + * + * @param priority The priority to set at the specified location. + * @param block The block that is triggered after the priority has been written + * on the servers. + */ +- (void)setPriority:(nullable id)priority + withCompletionBlock: + (void (^)(NSError *__nullable error, FIRDatabaseReference *ref))block; + +/** + * Updates the values at the specified paths in the dictionary without + * overwriting other keys at this location. + * + * @param values A dictionary of the keys to change and their new values + */ +- (void)updateChildValues:(NSDictionary *)values; + +/** + * The same as update: with a block that is called once the update has been + * committed to the Firebase Database servers + * + * @param values A dictionary of the keys to change and their new values + * @param block The block that is triggered after the update has been written on + * the Firebase Database servers + */ +- (void)updateChildValues:(NSDictionary *)values + withCompletionBlock: + (void (^)(NSError *__nullable error, FIRDatabaseReference *ref))block; + +#pragma mark - Attaching observers to read data + +/** + * observeEventType:withBlock: is used to listen for data changes at a + * particular location. This is the primary way to read data from the Firebase + * Database. Your block will be triggered for the initial data and again + * whenever the data changes. + * + * Use removeObserverWithHandle: to stop receiving updates. + * @param eventType The type of event to listen for. + * @param block The block that should be called with initial data and updates. + * It is passed the data as a FIRDataSnapshot. + * @return A handle used to unregister this block later using + * removeObserverWithHandle: + */ +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + withBlock: + (void (^)(FIRDataSnapshot *snapshot))block; + +/** + * observeEventType:andPreviousSiblingKeyWithBlock: is used to listen for data + * changes at a particular location. This is the primary way to read data from + * the Firebase Database. Your block will be triggered for the initial data and + * again whenever the data changes. In addition, for FIRDataEventTypeChildAdded, + * FIRDataEventTypeChildMoved, and FIRDataEventTypeChildChanged events, your + * block will be passed the key of the previous node by priority order. + * + * Use removeObserverWithHandle: to stop receiving updates. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called with initial data and updates. + * It is passed the data as a FIRDataSnapshot and the previous child's key. + * @return A handle used to unregister this block later using + * removeObserverWithHandle: + */ +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock: + (void (^)(FIRDataSnapshot *snapshot, + NSString *__nullable prevKey))block; + +/** + * observeEventType:withBlock: is used to listen for data changes at a + * particular location. This is the primary way to read data from the Firebase + * Database. Your block will be triggered for the initial data and again + * whenever the data changes. + * + * The cancelBlock will be called if you will no longer receive new events due + * to no longer having permission. + * + * Use removeObserverWithHandle: to stop receiving updates. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called with initial data and updates. + * It is passed the data as a FIRDataSnapshot. + * @param cancelBlock The block that should be called if this client no longer + * has permission to receive these events + * @return A handle used to unregister this block later using + * removeObserverWithHandle: + */ +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + withBlock:(void (^)(FIRDataSnapshot *snapshot))block + withCancelBlock: + (nullable void (^)(NSError *error))cancelBlock; + +/** + * observeEventType:andPreviousSiblingKeyWithBlock: is used to listen for data + * changes at a particular location. This is the primary way to read data from + * the Firebase Database. Your block will be triggered for the initial data and + * again whenever the data changes. In addition, for FIRDataEventTypeChildAdded, + * FIRDataEventTypeChildMoved, and FIRDataEventTypeChildChanged events, your + * block will be passed the key of the previous node by priority order. + * + * The cancelBlock will be called if you will no longer receive new events due + * to no longer having permission. + * + * Use removeObserverWithHandle: to stop receiving updates. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called with initial data and updates. + * It is passed the data as a FIRDataSnapshot and the previous child's key. + * @param cancelBlock The block that should be called if this client no longer + * has permission to receive these events + * @return A handle used to unregister this block later using + * removeObserverWithHandle: + */ +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock: + (void (^)(FIRDataSnapshot *snapshot, + NSString *__nullable prevKey))block + withCancelBlock: + (nullable void (^)(NSError *error))cancelBlock; + +/** + * This is equivalent to observeEventType:withBlock:, except the block is + * immediately canceled after the initial data is returned. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called. It is passed the data as a + * FIRDataSnapshot. + */ +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + withBlock:(void (^)(FIRDataSnapshot *snapshot))block; + +/** + * This is equivalent to observeEventType:withBlock:, except the block is + * immediately canceled after the initial data is returned. In addition, for + * FIRDataEventTypeChildAdded, FIRDataEventTypeChildMoved, and + * FIRDataEventTypeChildChanged events, your block will be passed the key of the + * previous node by priority order. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called. It is passed the data as a + * FIRDataSnapshot and the previous child's key. + */ +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock: + (void (^)(FIRDataSnapshot *snapshot, + NSString *__nullable prevKey))block; + +/** + * This is equivalent to observeEventType:withBlock:, except the block is + * immediately canceled after the initial data is returned. + * + * The cancelBlock will be called if you do not have permission to read data at + * this location. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called. It is passed the data as a + * FIRDataSnapshot. + * @param cancelBlock The block that will be called if you don't have permission + * to access this data + */ +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + withBlock:(void (^)(FIRDataSnapshot *snapshot))block + withCancelBlock:(nullable void (^)(NSError *error))cancelBlock; + +/** + * This is equivalent to observeEventType:withBlock:, except the block is + * immediately canceled after the initial data is returned. In addition, for + * FIRDataEventTypeChildAdded, FIRDataEventTypeChildMoved, and + * FIRDataEventTypeChildChanged events, your block will be passed the key of the + * previous node by priority order. + * + * The cancelBlock will be called if you do not have permission to read data at + * this location. + * + * @param eventType The type of event to listen for. + * @param block The block that should be called. It is passed the data as a + * FIRDataSnapshot and the previous child's key. + * @param cancelBlock The block that will be called if you don't have permission + * to access this data + */ +- (void)observeSingleEventOfType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock:(void (^)(FIRDataSnapshot *snapshot, + NSString *__nullable prevKey))block + withCancelBlock: + (nullable void (^)(NSError *error))cancelBlock; + +/** + * getDataWithCompletionBlock: is used to get the most up-to-date value for + * this query. This method updates the cache and raises events if successful. If + * not connected, falls back to a locally-cached value. + * + * @param block The block that should be called with the most up-to-date value + * of this query, or an error if no such value could be retrieved. + */ +- (void)getDataWithCompletionBlock: + (void (^_Nonnull)(NSError *__nullable error, + FIRDataSnapshot *__nullable snapshot))block + NS_SWIFT_NAME(getData(completion:)); + +#pragma mark - Detaching observers + +/** + * Detach a block previously attached with observeEventType:withBlock:. + * + * @param handle The handle returned by the call to observeEventType:withBlock: + * which we are trying to remove. + */ +- (void)removeObserverWithHandle:(FIRDatabaseHandle)handle; + +/** + * By calling `keepSynced:YES` on a location, the data for that location will + * automatically be downloaded and kept in sync, even when no listeners are + * attached for that location. Additionally, while a location is kept synced, it + * will not be evicted from the persistent disk cache. + * + * @param keepSynced Pass YES to keep this location synchronized, pass NO to + * stop synchronization. + */ +- (void)keepSynced:(BOOL)keepSynced; + +/** + * Removes all observers at the current reference, but does not remove any + * observers at child references. removeAllObservers must be called again for + * each child reference where a listener was established to remove the + * observers. + */ +- (void)removeAllObservers; + +#pragma mark - Querying and limiting + +/** + * queryLimitedToFirst: is used to generate a reference to a limited view of the + * data at this location. The FIRDatabaseQuery instance returned by + * queryLimitedToFirst: will respond to at most the first limit child nodes. + * + * @param limit The upper bound, inclusive, for the number of child nodes to + * receive events for + * @return A FIRDatabaseQuery instance, limited to at most limit child nodes. + */ +- (FIRDatabaseQuery *)queryLimitedToFirst:(NSUInteger)limit; + +/** + * queryLimitedToLast: is used to generate a reference to a limited view of the + * data at this location. The FIRDatabaseQuery instance returned by + * queryLimitedToLast: will respond to at most the last limit child nodes. + * + * @param limit The upper bound, inclusive, for the number of child nodes to + * receive events for + * @return A FIRDatabaseQuery instance, limited to at most limit child nodes. + */ +- (FIRDatabaseQuery *)queryLimitedToLast:(NSUInteger)limit; + +/** + * queryOrderBy: is used to generate a reference to a view of the data that's + * been sorted by the values of a particular child key. This method is intended + * to be used in combination with queryStartingAtValue:, queryEndingAtValue:, or + * queryEqualToValue:. + * + * @param key The child key to use in ordering data visible to the returned + * FIRDatabaseQuery + * @return A FIRDatabaseQuery instance, ordered by the values of the specified + * child key. + */ +- (FIRDatabaseQuery *)queryOrderedByChild:(NSString *)key; + +/** + * queryOrderedByKey: is used to generate a reference to a view of the data + * that's been sorted by child key. This method is intended to be used in + * combination with queryStartingAtValue:, queryEndingAtValue:, or + * queryEqualToValue:. + * + * @return A FIRDatabaseQuery instance, ordered by child keys. + */ +- (FIRDatabaseQuery *)queryOrderedByKey; + +/** + * queryOrderedByPriority: is used to generate a reference to a view of the data + * that's been sorted by child priority. This method is intended to be used in + * combination with queryStartingAtValue:, queryEndingAtValue:, or + * queryEqualToValue:. + * + * @return A FIRDatabaseQuery instance, ordered by child priorities. + */ +- (FIRDatabaseQuery *)queryOrderedByPriority; + +/** + * queryStartingAtValue: is used to generate a reference to a limited view of + * the data at this location. The FIRDatabaseQuery instance returned by + * queryStartingAtValue: will respond to events at nodes with a value greater + * than or equal to startValue. + * + * @param startValue The lower bound, inclusive, for the value of data visible + * to the returned FIRDatabaseQuery + * @return A FIRDatabaseQuery instance, limited to data with value greater than + * or equal to startValue + */ +- (FIRDatabaseQuery *)queryStartingAtValue:(nullable id)startValue; + +/** + * queryStartingAtValue:childKey: is used to generate a reference to a limited + * view of the data at this location. The FIRDatabaseQuery instance returned by + * queryStartingAtValue:childKey will respond to events at nodes with a value + * greater than startValue, or equal to startValue and with a key greater than + * or equal to childKey. + * + * @param startValue The lower bound, inclusive, for the value of data visible + * to the returned FIRDatabaseQuery + * @param childKey The lower bound, inclusive, for the key of nodes with value + * equal to startValue + * @return A FIRDatabaseQuery instance, limited to data with value greater than + * or equal to startValue + */ +- (FIRDatabaseQuery *)queryStartingAtValue:(nullable id)startValue + childKey:(nullable NSString *)childKey; + +/** + * queryStartingAfterValue: is used to generate a reference to a limited view of + * the data at this location. The FIRDatabaseQuery instance returned by + * queryStartingAfterValue: will respond to events at nodes with a value greater + * than startAfterValue. + * + * @param startAfterValue The lower bound, exclusive, for the value of data + * visible to the returned FIRDatabaseQuery + * @return A FIRDatabaseQuery instance, limited to data with value greater than + * startAfterValue + */ +- (FIRDatabaseQuery *)queryStartingAfterValue:(nullable id)startAfterValue; + +/** + * queryStartingAfterValue:childKey: is used to generate a reference to a + * limited view of the data at this location. The FIRDatabaseQuery instance + * returned by queryStartingAfterValue:childKey will respond to events at nodes + * with a value greater than startAfterValue, or equal to startAfterValue and + * with a key greater than childKey. This is most useful when implementing + * pagination in a case where multiple nodes can match the startAfterValue. + * + * @param startAfterValue The lower bound, inclusive, for the value of data + * visible to the returned FIRDatabaseQuery + * @param childKey The lower bound, exclusive, for the key of nodes with value + * equal to startAfterValue + * @return A FIRDatabaseQuery instance, limited to data with value greater than + * or equal to startAfterValue, or equal to startAfterValue and with a key + * greater than childKey. + */ +- (FIRDatabaseQuery *)queryStartingAfterValue:(nullable id)startAfterValue + childKey:(nullable NSString *)childKey; + +/** + * queryEndingAtValue: is used to generate a reference to a limited view of the + * data at this location. The FIRDatabaseQuery instance returned by + * queryEndingAtValue: will respond to events at nodes with a value less than or + * equal to endValue. + * + * @param endValue The upper bound, inclusive, for the value of data visible to + * the returned FIRDatabaseQuery + * @return A FIRDatabaseQuery instance, limited to data with value less than or + * equal to endValue + */ +- (FIRDatabaseQuery *)queryEndingAtValue:(nullable id)endValue; + +/** + * queryEndingAtValue:childKey: is used to generate a reference to a limited + * view of the data at this location. The FIRDatabaseQuery instance returned by + * queryEndingAtValue:childKey will respond to events at nodes with a value less + * than endValue, or equal to endValue and with a key less than or equal to + * childKey. + * + * @param endValue The upper bound, inclusive, for the value of data visible to + * the returned FIRDatabaseQuery + * @param childKey The upper bound, inclusive, for the key of nodes with value + * equal to endValue + * @return A FIRDatabaseQuery instance, limited to data with value less than or + * equal to endValue + */ +- (FIRDatabaseQuery *)queryEndingAtValue:(nullable id)endValue + childKey:(nullable NSString *)childKey; + +/** + * queryEqualToValue: is used to generate a reference to a limited view of the + * data at this location. The FIRDatabaseQuery instance returned by + * queryEqualToValue: will respond to events at nodes with a value equal to the + * supplied argument. + * + * @param value The value that the data returned by this FIRDatabaseQuery will + * have + * @return A FIRDatabaseQuery instance, limited to data with the supplied value. + */ +- (FIRDatabaseQuery *)queryEqualToValue:(nullable id)value; + +/** + * queryEqualToValue:childKey: is used to generate a reference to a limited view + * of the data at this location. The FIRDatabaseQuery instance returned by + * queryEqualToValue:childKey will respond to events at nodes with a value equal + * to the supplied argument with a key equal to childKey. There will be at most + * one node that matches because child keys are unique. + * + * @param value The value that the data returned by this FIRDatabaseQuery will + * have + * @param childKey The key of nodes with the right value + * @return A FIRDatabaseQuery instance, limited to data with the supplied value + * and the key. + */ +- (FIRDatabaseQuery *)queryEqualToValue:(nullable id)value + childKey:(nullable NSString *)childKey; + +#pragma mark - Managing presence + +/** + * Ensure the data at this location is set to the specified value when + * the client is disconnected (due to closing the browser, navigating + * to a new page, or network issues). + * + * onDisconnectSetValue: is especially useful for implementing "presence" + * systems, where a value should be changed or cleared when a user disconnects + * so that he appears "offline" to other users. + * + * @param value The value to be set after the connection is lost. + */ +- (void)onDisconnectSetValue:(nullable id)value; + +/** + * Ensure the data at this location is set to the specified value when + * the client is disconnected (due to closing the browser, navigating + * to a new page, or network issues). + * + * The completion block will be triggered when the operation has been + * successfully queued up on the Firebase Database servers + * + * @param value The value to be set after the connection is lost. + * @param block Block to be triggered when the operation has been queued up on + * the Firebase Database servers + */ +- (void)onDisconnectSetValue:(nullable id)value + withCompletionBlock:(void (^)(NSError *__nullable error, + FIRDatabaseReference *ref))block; + +/** + * Ensure the data at this location is set to the specified value and priority + * when the client is disconnected (due to closing the browser, navigating to a + * new page, or network issues). + * + * @param value The value to be set after the connection is lost. + * @param priority The priority to be set after the connection is lost. + */ +- (void)onDisconnectSetValue:(nullable id)value andPriority:(id)priority; + +/** + * Ensure the data at this location is set to the specified value and priority + * when the client is disconnected (due to closing the browser, navigating to a + * new page, or network issues). + * + * The completion block will be triggered when the operation has been + * successfully queued up on the Firebase Database servers + * + * @param value The value to be set after the connection is lost. + * @param priority The priority to be set after the connection is lost. + * @param block Block to be triggered when the operation has been queued up on + * the Firebase Database servers + */ +- (void)onDisconnectSetValue:(nullable id)value + andPriority:(nullable id)priority + withCompletionBlock:(void (^)(NSError *__nullable error, + FIRDatabaseReference *ref))block; + +/** + * Ensure the data at this location is removed when + * the client is disconnected (due to closing the app, navigating + * to a new page, or network issues). + * + * onDisconnectRemoveValue is especially useful for implementing "presence" + * systems. + */ +- (void)onDisconnectRemoveValue; + +/** + * Ensure the data at this location is removed when + * the client is disconnected (due to closing the app, navigating + * to a new page, or network issues). + * + * onDisconnectRemoveValueWithCompletionBlock: is especially useful for + * implementing "presence" systems. + * + * @param block Block to be triggered when the operation has been queued up on + * the Firebase Database servers + */ +- (void)onDisconnectRemoveValueWithCompletionBlock: + (void (^)(NSError *__nullable error, FIRDatabaseReference *ref))block; + +/** + * Ensure the data has the specified child values updated when + * the client is disconnected (due to closing the browser, navigating + * to a new page, or network issues). + * + * + * @param values A dictionary of child node keys and the values to set them to + * after the connection is lost. + */ +- (void)onDisconnectUpdateChildValues:(NSDictionary *)values; + +/** + * Ensure the data has the specified child values updated when + * the client is disconnected (due to closing the browser, navigating + * to a new page, or network issues). + * + * + * @param values A dictionary of child node keys and the values to set them to + * after the connection is lost. + * @param block A block that will be called once the operation has been queued + * up on the Firebase Database servers + */ +- (void)onDisconnectUpdateChildValues:(NSDictionary *)values + withCompletionBlock: + (void (^)(NSError *__nullable error, + FIRDatabaseReference *ref))block; + +/** + * Cancel any operations that are set to run on disconnect. If you previously + * called onDisconnectSetValue:, onDisconnectRemoveValue:, or + * onDisconnectUpdateChildValues:, and no longer want the values updated when + * the connection is lost, call cancelDisconnectOperations: + */ +- (void)cancelDisconnectOperations; + +/** + * Cancel any operations that are set to run on disconnect. If you previously + * called onDisconnectSetValue:, onDisconnectRemoveValue:, or + * onDisconnectUpdateChildValues:, and no longer want the values updated when + * the connection is lost, call cancelDisconnectOperations: + * + * @param block A block that will be triggered once the Firebase Database + * servers have acknowledged the cancel request. + */ +- (void)cancelDisconnectOperationsWithCompletionBlock: + (nullable void (^)(NSError *__nullable error, + FIRDatabaseReference *ref))block; + +#pragma mark - Manual Connection Management + +/** + * Manually disconnect the Firebase Database client from the server and disable + * automatic reconnection. + * + * The Firebase Database client automatically maintains a persistent connection + * to the Firebase Database server, which will remain active indefinitely and + * reconnect when disconnected. However, the goOffline( ) and goOnline( ) + * methods may be used to manually control the client connection in cases where + * a persistent connection is undesirable. + * + * While offline, the Firebase Database client will no longer receive data + * updates from the server. However, all database operations performed locally + * will continue to immediately fire events, allowing your application to + * continue behaving normally. Additionally, each operation performed locally + * will automatically be queued and retried upon reconnection to the Firebase + * Database server. + * + * To reconnect to the Firebase Database server and begin receiving remote + * events, see goOnline( ). Once the connection is reestablished, the Firebase + * Database client will transmit the appropriate data and fire the appropriate + * events so that your client "catches up" automatically. + * + * Note: Invoking this method will impact all Firebase Database connections. + */ ++ (void)goOffline; + +/** + * Manually reestablish a connection to the Firebase Database server and enable + * automatic reconnection. + * + * The Firebase Database client automatically maintains a persistent connection + * to the Firebase Database server, which will remain active indefinitely and + * reconnect when disconnected. However, the goOffline( ) and goOnline( ) + * methods may be used to manually control the client connection in cases where + * a persistent connection is undesirable. + * + * This method should be used after invoking goOffline( ) to disable the active + * connection. Once reconnected, the Firebase Database client will automatically + * transmit the proper data and fire the appropriate events so that your client + * "catches up" automatically. + * + * To disconnect from the Firebase Database server, see goOffline( ). + * + * Note: Invoking this method will impact all Firebase Database connections. + */ ++ (void)goOnline; + +#pragma mark - Transactions + +/** + * Performs an optimistic-concurrency transactional update to the data at this + * location. Your block will be called with a FIRMutableData instance that + * contains the current data at this location. Your block should update this + * data to the value you wish to write to this location, and then return an + * instance of FIRTransactionResult with the new data. + * + * If, when the operation reaches the server, it turns out that this client had + * stale data, your block will be run again with the latest data from the + * server. + * + * When your block is run, you may decide to abort the transaction by returning + * [FIRTransactionResult abort]. + * + * @param block This block receives the current data at this location and must + * return an instance of FIRTransactionResult + */ +- (void)runTransactionBlock: + (FIRTransactionResult * (^)(FIRMutableData *currentData))block; + +/** + * Performs an optimistic-concurrency transactional update to the data at this + * location. Your block will be called with a FIRMutableData instance that + * contains the current data at this location. Your block should update this + * data to the value you wish to write to this location, and then return an + * instance of FIRTransactionResult with the new data. + * + * If, when the operation reaches the server, it turns out that this client had + * stale data, your block will be run again with the latest data from the + * server. + * + * When your block is run, you may decide to abort the transaction by returning + * [FIRTransactionResult abort]. + * + * @param block This block receives the current data at this location and must + * return an instance of FIRTransactionResult + * @param completionBlock This block will be triggered once the transaction is + * complete, whether it was successful or not. It will indicate if there was an + * error, whether or not the data was committed, and what the current value of + * the data at this location is. + */ +- (void)runTransactionBlock: + (FIRTransactionResult * (^)(FIRMutableData *currentData))block + andCompletionBlock: + (void (^)(NSError *__nullable error, BOOL committed, + FIRDataSnapshot *__nullable snapshot))completionBlock; + +/** + * Performs an optimistic-concurrency transactional update to the data at this + * location. Your block will be called with a FIRMutableData instance that + * contains the current data at this location. Your block should update this + * data to the value you wish to write to this location, and then return an + * instance of FIRTransactionResult with the new data. + * + * If, when the operation reaches the server, it turns out that this client had + * stale data, your block will be run again with the latest data from the + * server. + * + * When your block is run, you may decide to abort the transaction by return + * [FIRTransactionResult abort]. + * + * Since your block may be run multiple times, this client could see several + * immediate states that don't exist on the server. You can suppress those + * immediate states until the server confirms the final state of the + * transaction. + * + * @param block This block receives the current data at this location and must + * return an instance of FIRTransactionResult + * @param completionBlock This block will be triggered once the transaction is + * complete, whether it was successful or not. It will indicate if there was an + * error, whether or not the data was committed, and what the current value of + * the data at this location is. + * @param localEvents Set this to NO to suppress events raised for intermediate + * states, and only get events based on the final state of the transaction. + */ +- (void)runTransactionBlock: + (FIRTransactionResult * (^)(FIRMutableData *currentData))block + andCompletionBlock: + (nullable void (^)(NSError *__nullable error, BOOL committed, + FIRDataSnapshot *__nullable snapshot)) + completionBlock + withLocalEvents:(BOOL)localEvents; + +#pragma mark - Retrieving String Representation + +/** + * Gets the absolute URL of this Firebase Database location. + * + * @return The absolute URL of the referenced Firebase Database location. + */ +- (NSString *)description; + +#pragma mark - Properties + +/** + * Gets a FIRDatabaseReference for the parent location. + * If this instance refers to the root of your Firebase Database, it has no + * parent, and therefore parent( ) will return null. + * + * @return A FIRDatabaseReference for the parent location. + */ +@property(strong, readonly, nonatomic, nullable) FIRDatabaseReference *parent; + +/** + * Gets a FIRDatabaseReference for the root location + * + * @return A new FIRDatabaseReference to root location. + */ +@property(strong, readonly, nonatomic) FIRDatabaseReference *root; + +/** + * Gets the last token in a Firebase Database location (e.g. 'fred' in + * https://SampleChat.firebaseIO-demo.com/users/fred) + * + * @return The key of the location this reference points to. + */ +@property(strong, readonly, nonatomic, nullable) NSString *key; + +/** + * Gets the URL for the Firebase Database location referenced by this + * FIRDatabaseReference. + * + * @return The url of the location this reference points to. + */ +@property(strong, readonly, nonatomic) NSString *URL; + +/** + * Gets the FIRDatabase instance associated with this reference. + * + * @return The FIRDatabase object for this reference. + */ +@property(strong, readonly, nonatomic) FIRDatabase *database; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRMutableData.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRMutableData.h new file mode 100644 index 0000000..bedde7b --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRMutableData.h @@ -0,0 +1,130 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** + * A `MutableData` instance is populated with data from a Firebase Database + * location. When you are using `runTransactionBlock(_:)`, you will be given an + * instance containing the current data at that location. Your block will be + * responsible for updating that instance to the data you wish to save at that + * location, and then returning using `TransactionResult.success(withValue:)`. + * + * To modify the data, set its value property to any of the Objective-C types + * supported by Firebase Database, or any equivalent natively bridgeable Swift + * type: + * + * + `NSNumber` (includes booleans) + * + `NSDictionary` + * + `NSArray` + * + `NSString` + * + `nil` / `NSNull` to remove the data + * + * Note that changes made to a child `MutableData` instance will be visible to + * the parent. + */ +NS_SWIFT_NAME(MutableData) +@interface FIRMutableData : NSObject + +#pragma mark - Inspecting and navigating the data + +/** + * Returns boolean indicating whether this mutable data has children. + * + * @return YES if this data contains child nodes. + */ +- (BOOL)hasChildren; + +/** + * Indicates whether this mutable data has a child at the given path. + * + * @param path A path string, consisting either of a single segment, like + * 'child', or multiple segments, 'a/deeper/child' + * @return YES if this data contains a child at the specified relative path + */ +- (BOOL)hasChildAtPath:(NSString *)path; + +/** + * Used to obtain a `MutableData` instance that encapsulates the data at the + * given relative path. Note that changes made to the child will be visible to + * the parent. + * + * @param path A path string, consisting either of a single segment, like + * 'child', or multiple segments, 'a/deeper/child' + * @return A `MutableData` instance containing the data at the given path + */ +- (FIRMutableData *)childDataByAppendingPath:(NSString *)path; + +#pragma mark - Properties + +/** + * To modify the data contained by this instance of `MutableData`, set this to + * any of the Objective-C types supported by Firebase Database, or any + * equivalent natively bridgeable Swift type: + * + * + `NSNumber` (includes booleans) + * + `NSDictionary` + * + `NSArray` + * + `NSString` + * + `nil` / `NSNull` to remove the data + * + * Note that setting this value will override the priority at this location. + * + * @return The current data at this location as a native object + */ +@property(strong, nonatomic, nullable) id value; + +/** + * Set this property to update the priority of the data at this location. Can be + * set to any of the following Objective-C types supported by Firebase Database, + * or any equivalent natively bridgeable Swift type: + * + * + `NSNumber` (includes booleans) + * + `NSString` + * + `nil` / `NSNull` to remove the data + * + * @return The priority of the data at this location + */ +@property(strong, nonatomic, nullable) id priority; + +/** + * @return The number of child nodes at this location + */ +@property(readonly, nonatomic) NSUInteger childrenCount; + +/** + * An enumeration of the children at this location. + * + * for var child in data.children { + * // ... + * } + * + * Note that this enumerator operates on an immutable copy of the child list. + * So, you can modify the instance during iteration, but the new additions will + * not be visible until you get a new enumerator. + */ +@property(readonly, nonatomic, strong) NSEnumerator *children; + +/** + * @return The key name of this node, or `nil` if it is the top-most location + */ +@property(readonly, nonatomic, strong, nullable) NSString *key; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRServerValue.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRServerValue.h new file mode 100644 index 0000000..5f57094 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRServerValue.h @@ -0,0 +1,53 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** + * Placeholder values you may write into Firebase Database as a value or + * priority that will automatically be populated by the Firebase Database + * server. + */ +NS_SWIFT_NAME(ServerValue) +@interface FIRServerValue : NSObject + +/** + * Placeholder value for the number of milliseconds since the Unix epoch + */ ++ (NSDictionary *)timestamp; + +/** + * Returns a placeholder value that can be used to atomically increment the + * current database value by the provided delta. + * + * The delta must be a long or double value. If the current value is not an + * integer or double, or if the data does not yet exist, the transformation will + * set the data to the delta value. If either of the delta value or the existing + * data are doubles, both values will be interpreted as doubles. Double + * arithmetic and representation of double values follow IEEE 754 semantics. If + * there is positive/negative integer overflow, the sum is calculated as a + * double. + * + * @param delta the amount to modify the current value atomically. + * @return a placeholder value for modifying data atomically server-side. + */ ++ (NSDictionary *)increment:(NSNumber *)delta NS_SWIFT_NAME(increment(_:)); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRTransactionResult.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRTransactionResult.h new file mode 100644 index 0000000..6a97c5c --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRTransactionResult.h @@ -0,0 +1,50 @@ +/* + * 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 "FIRMutableData.h" +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * Used for `runTransactionBlock(_:)`. A `TransactionResult` instance is a + * container for the results of the transaction. + */ +NS_SWIFT_NAME(TransactionResult) +@interface FIRTransactionResult : NSObject + +/** + * Used for `runTransactionBlock(_:)`. Indicates that the new value should be + * saved at this location. + * + * @param value A `MutableData` instance containing the new value to be set + * @return A `TransactionResult` instance that can be used as a return value + * from the block given to `runTransactionBlock(_:)`. + */ ++ (FIRTransactionResult *)successWithValue:(FIRMutableData *)value; + +/** + * Used for `runTransactionBlock(_:)`. Indicates that the current transaction + * should no longer proceed. + * + * @return A `TransactionResult` instance that can be used as a return value + * from the block given to `runTransactionBlock(_:)` + */ ++ (FIRTransactionResult *)abort; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FirebaseDatabase.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FirebaseDatabase.h new file mode 100644 index 0000000..ae6b933 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Public/FirebaseDatabase/FirebaseDatabase.h @@ -0,0 +1,29 @@ +/* + * 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. + */ + +#ifndef FirebaseDatabase_h +#define FirebaseDatabase_h + +#import "FIRDataEventType.h" +#import "FIRDataSnapshot.h" +#import "FIRDatabase.h" +#import "FIRDatabaseQuery.h" +#import "FIRDatabaseReference.h" +#import "FIRMutableData.h" +#import "FIRServerValue.h" +#import "FIRTransactionResult.h" + +#endif /* FirebaseDatabase_h */ diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Realtime/FConnection.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Realtime/FConnection.h new file mode 100644 index 0000000..84bb8df --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Realtime/FConnection.h @@ -0,0 +1,61 @@ +/* + * 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 "FirebaseDatabase/Sources/Realtime/FWebSocketConnection.h" +#import "FirebaseDatabase/Sources/Utilities/FTypedefs.h" +#import + +@protocol FConnectionDelegate; + +@interface FConnection : NSObject + +@property(nonatomic, weak) id delegate; + +- (instancetype)initWith:(FRepoInfo *)aRepoInfo + andDispatchQueue:(dispatch_queue_t)queue + googleAppID:(NSString *)googleAppID + lastSessionID:(NSString *)lastSessionID + appCheckToken:(NSString *)appCheckToken; + +- (void)open; +- (void)close; +- (void)sendRequest:(NSDictionary *)dataMsg sensitive:(BOOL)sensitive; + +// FWebSocketDelegate delegate methods +- (void)onMessage:(FWebSocketConnection *)fwebSocket + withMessage:(NSDictionary *)message; +- (void)onDisconnect:(FWebSocketConnection *)fwebSocket + wasEverConnected:(BOOL)everConnected; + +@end + +typedef enum { + DISCONNECT_REASON_SERVER_RESET = 0, + DISCONNECT_REASON_OTHER = 1 +} FDisconnectReason; + +@protocol FConnectionDelegate + +- (void)onReady:(FConnection *)fconnection + atTime:(NSNumber *)timestamp + sessionID:(NSString *)sessionID; +- (void)onDataMessage:(FConnection *)fconnection + withMessage:(NSDictionary *)message; +- (void)onDisconnect:(FConnection *)fconnection + withReason:(FDisconnectReason)reason; +- (void)onKill:(FConnection *)fconnection withReason:(NSString *)reason; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Realtime/FConnection.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Realtime/FConnection.m new file mode 100644 index 0000000..d5e4bc8 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Realtime/FConnection.m @@ -0,0 +1,238 @@ +/* + * 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 "FirebaseDatabase/Sources/Realtime/FConnection.h" +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" +#import "FirebaseDatabase/Sources/Constants/FConstants.h" + +typedef enum { + REALTIME_STATE_CONNECTING = 0, + REALTIME_STATE_CONNECTED = 1, + REALTIME_STATE_DISCONNECTED = 2, +} FConnectionState; + +@interface FConnection () { + FConnectionState state; +} + +@property(nonatomic, strong) FWebSocketConnection *conn; +@property(nonatomic, strong) FRepoInfo *repoInfo; + +@end + +#pragma mark - +#pragma mark FConnection implementation + +@implementation FConnection + +@synthesize delegate; +@synthesize conn; +@synthesize repoInfo; + +#pragma mark - +#pragma mark Initializers + +- (instancetype)initWith:(FRepoInfo *)aRepoInfo + andDispatchQueue:(dispatch_queue_t)queue + googleAppID:(NSString *)googleAppID + lastSessionID:(NSString *)lastSessionID + appCheckToken:(NSString *)appCheckToken { + self = [super init]; + if (self) { + state = REALTIME_STATE_CONNECTING; + self.repoInfo = aRepoInfo; + self.conn = [[FWebSocketConnection alloc] initWith:self.repoInfo + andQueue:queue + googleAppID:googleAppID + lastSessionID:lastSessionID + appCheckToken:appCheckToken]; + self.conn.delegate = self; + } + return self; +} + +#pragma mark - +#pragma mark Public method implementation + +- (void)open { + FFLog(@"I-RDB082001", @"Calling open in FConnection"); + [self.conn open]; +} + +- (void)closeWithReason:(FDisconnectReason)reason { + if (state != REALTIME_STATE_DISCONNECTED) { + FFLog(@"I-RDB082002", @"Closing realtime connection."); + state = REALTIME_STATE_DISCONNECTED; + + if (self.conn) { + FFLog(@"I-RDB082003", @"Calling close again."); + [self.conn close]; + self.conn = nil; + } + + [self.delegate onDisconnect:self withReason:reason]; + } +} + +- (void)close { + [self closeWithReason:DISCONNECT_REASON_OTHER]; +} + +- (void)sendRequest:(NSDictionary *)dataMsg sensitive:(BOOL)sensitive { + // since this came from the persistent connection, wrap it in a data message + // envelope + NSDictionary *msg = @{ + kFWPRequestType : kFWPRequestTypeData, + kFWPRequestDataPayload : dataMsg + }; + [self sendData:msg sensitive:sensitive]; +} + +#pragma mark - +#pragma mark Helpers + +- (void)sendData:(NSDictionary *)data sensitive:(BOOL)sensitive { + if (state != REALTIME_STATE_CONNECTED) { + @throw [[NSException alloc] + initWithName:@"InvalidConnectionState" + reason:@"Tried to send data on an unconnected FConnection" + userInfo:nil]; + } else { + if (sensitive) { + FFLog(@"I-RDB082004", @"Sending data (contents hidden)"); + } else { + FFLog(@"I-RDB082005", @"Sending: %@", data); + } + [self.conn send:data]; + } +} + +#pragma mark - +#pragma mark FWebSocketConnectinDelegate implementation + +// Corresponds to onConnectionLost in JS +- (void)onDisconnect:(FWebSocketConnection *)fwebSocket + wasEverConnected:(BOOL)everConnected { + + self.conn = nil; + if (!everConnected && state == REALTIME_STATE_CONNECTING) { + FFLog(@"I-RDB082006", @"Realtime connection failed."); + + // Since we failed to connect at all, clear any cached entry for this + // namespace in case the machine went away + [self.repoInfo clearInternalHostCache]; + } else if (state == REALTIME_STATE_CONNECTED) { + FFLog(@"I-RDB082007", @"Realtime connection lost."); + } + + [self close]; +} + +// Corresponds to onMessageReceived in JS +- (void)onMessage:(FWebSocketConnection *)fwebSocket + withMessage:(NSDictionary *)message { + NSString *rawMessageType = + [message objectForKey:kFWPAsyncServerEnvelopeType]; + if (rawMessageType != nil) { + if ([rawMessageType isEqualToString:kFWPAsyncServerDataMessage]) { + [self onDataMessage:[message + objectForKey:kFWPAsyncServerEnvelopeData]]; + } else if ([rawMessageType + isEqualToString:kFWPAsyncServerControlMessage]) { + [self onControl:[message objectForKey:kFWPAsyncServerEnvelopeData]]; + } else { + FFLog(@"I-RDB082008", @"Unrecognized server packet type: %@", + rawMessageType); + } + } else { + FFLog(@"I-RDB082009", @"Unrecognized raw server packet received: %@", + message); + } +} + +- (void)onDataMessage:(NSDictionary *)message { + // we don't do anything with data messages, just kick them up a level + FFLog(@"I-RDB082010", @"Got data message: %@", message); + [self.delegate onDataMessage:self withMessage:message]; +} + +- (void)onControl:(NSDictionary *)message { + FFLog(@"I-RDB082011", @"Got control message: %@", message); + NSString *type = [message objectForKey:kFWPAsyncServerControlMessageType]; + if ([type isEqualToString:kFWPAsyncServerControlMessageShutdown]) { + NSString *reason = + [message objectForKey:kFWPAsyncServerControlMessageData]; + [self onConnectionShutdownWithReason:reason]; + } else if ([type isEqualToString:kFWPAsyncServerControlMessageReset]) { + NSString *host = + [message objectForKey:kFWPAsyncServerControlMessageData]; + [self onReset:host]; + } else if ([type isEqualToString:kFWPAsyncServerHello]) { + NSDictionary *handshakeData = + [message objectForKey:kFWPAsyncServerControlMessageData]; + [self onHandshake:handshakeData]; + } else { + FFLog(@"I-RDB082012", + @"Unknown control message returned from server: %@", message); + } +} + +- (void)onConnectionShutdownWithReason:(NSString *)reason { + FFLog(@"I-RDB082013", + @"Connection shutdown command received. Shutting down..."); + + [self.delegate onKill:self withReason:reason]; + [self close]; +} + +- (void)onHandshake:(NSDictionary *)handshake { + NSNumber *timestamp = + [handshake objectForKey:kFWPAsyncServerHelloTimestamp]; + // NSString* version = [handshake + // objectForKey:kFWPAsyncServerHelloVersion]; + NSString *host = [handshake objectForKey:kFWPAsyncServerHelloConnectedHost]; + NSString *sessionID = [handshake objectForKey:kFWPAsyncServerHelloSession]; + + self.repoInfo.internalHost = host; + + if (state == REALTIME_STATE_CONNECTING) { + [self.conn start]; + [self onConnection:self.conn readyAtTime:timestamp sessionID:sessionID]; + } +} + +- (void)onConnection:(FWebSocketConnection *)conn + readyAtTime:(NSNumber *)timestamp + sessionID:(NSString *)sessionID { + FFLog(@"I-RDB082014", @"Realtime connection established"); + state = REALTIME_STATE_CONNECTED; + + [self.delegate onReady:self atTime:timestamp sessionID:sessionID]; +} + +- (void)onReset:(NSString *)host { + FFLog( + @"I-RDB082015", + @"Got a reset; killing connection to: %@; Updating internalHost to: %@", + repoInfo.internalHost, host); + self.repoInfo.internalHost = host; + + // Explicitly close the connection with SERVER_RESET so calling code knows + // to reconnect immediately. + [self closeWithReason:DISCONNECT_REASON_SERVER_RESET]; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Realtime/FWebSocketConnection.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Realtime/FWebSocketConnection.h new file mode 100644 index 0000000..6769718 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Realtime/FWebSocketConnection.h @@ -0,0 +1,67 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/FUtilities.h" +#if !TARGET_OS_WATCH +#import "FirebaseDatabase/Sources/third_party/SocketRocket/FSRWebSocket.h" +#endif // !TARGET_OS_WATCH +#import + +@protocol FWebSocketDelegate; + +#if !TARGET_OS_WATCH +@interface FWebSocketConnection : NSObject +#else +@interface FWebSocketConnection : NSObject +#endif // else !TARGET_OS_WATCH + +@property(nonatomic, weak) id delegate; + +- (instancetype)initWith:(FRepoInfo *)repoInfo + andQueue:(dispatch_queue_t)queue + googleAppID:(NSString *)googleAppID + lastSessionID:(NSString *)lastSessionID + appCheckToken:(NSString *)appCheckToken; + +- (void)open; +- (void)close; +- (void)start; +- (void)send:(NSDictionary *)dictionary; + +// Ignore FSRWebSocketDelegate calls on watchOS. +#if !TARGET_OS_WATCH +- (void)webSocket:(FSRWebSocket *)webSocket didReceiveMessage:(id)message; + +// Exclude the `webSocket` argument since it isn't used in this codebase and it +// allows for better code sharing with watchOS. +- (void)webSocketDidOpen; +- (void)webSocket:(FSRWebSocket *)webSocket didFailWithError:(NSError *)error; +- (void)webSocket:(FSRWebSocket *)webSocket + didCloseWithCode:(NSInteger)code + reason:(NSString *)reason + wasClean:(BOOL)wasClean; +#endif // !TARGET_OS_WATCH + +@end + +@protocol FWebSocketDelegate + +- (void)onMessage:(FWebSocketConnection *)fwebSocket + withMessage:(NSDictionary *)message; +- (void)onDisconnect:(FWebSocketConnection *)fwebSocket + wasEverConnected:(BOOL)everConnected; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Realtime/FWebSocketConnection.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Realtime/FWebSocketConnection.m new file mode 100644 index 0000000..16cc478 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Realtime/FWebSocketConnection.m @@ -0,0 +1,504 @@ +/* + * 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. + */ + +// Targetted compilation is ONLY for testing. UIKit is weak-linked in actual +// release build. + +#import + +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDatabase_Private.h" +#import "FirebaseDatabase/Sources/Constants/FConstants.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseReference.h" +#import "FirebaseDatabase/Sources/Realtime/FWebSocketConnection.h" +#import "FirebaseDatabase/Sources/Utilities/FStringUtilities.h" + +#if TARGET_OS_IOS || TARGET_OS_TV +#import +#endif // TARGET_OS_IOS || TARGET_OS_TV + +#if TARGET_OS_WATCH +#import +#import +#endif // TARGET_OS_WATCH + +static NSString *const kAppCheckTokenHeader = @"X-Firebase-AppCheck"; +static NSString *const kUserAgentHeader = @"User-Agent"; +static NSString *const kGoogleAppIDHeader = @"X-Firebase-GMPID"; + +@interface FWebSocketConnection () { + NSMutableString *frame; + BOOL everConnected; + BOOL isClosed; + NSTimer *keepAlive; +} + +- (void)shutdown; +- (void)onClosed; +- (void)closeIfNeverConnected; + +#if TARGET_OS_WATCH +@property(nonatomic, strong) NSURLSessionWebSocketTask *webSocketTask; +#else +@property(nonatomic, strong) FSRWebSocket *webSocket; +#endif // TARGET_OS_WATCH +@property(nonatomic, strong) NSNumber *connectionId; +@property(nonatomic, readwrite) int totalFrames; +@property(nonatomic, readonly) BOOL buffering; +@property(nonatomic, readonly) NSString *userAgent; +@property(nonatomic) dispatch_queue_t dispatchQueue; + +- (void)nop:(NSTimer *)timer; + +@end + +@implementation FWebSocketConnection + +@synthesize delegate; +#if !TARGET_OS_WATCH +@synthesize webSocket; +#endif // !TARGET_OS_WATCH +@synthesize connectionId; + +- (instancetype)initWith:(FRepoInfo *)repoInfo + andQueue:(dispatch_queue_t)queue + googleAppID:(NSString *)googleAppID + lastSessionID:(NSString *)lastSessionID + appCheckToken:(nullable NSString *)appCheckToken { + self = [super init]; + if (self) { + everConnected = NO; + isClosed = NO; + self.connectionId = [FUtilities LUIDGenerator]; + self.totalFrames = 0; + self.dispatchQueue = queue; + frame = nil; + + NSString *userAgent = [self userAgent]; + NSString *connectionURL = + [repoInfo connectionURLWithLastSessionID:lastSessionID]; + + FFLog(@"I-RDB083001", @"(wsc:%@) Connecting to: %@ as %@", + self.connectionId, connectionURL, userAgent); + + NSURLRequest *req = [[self class] createRequestWithURL:connectionURL + userAgent:userAgent + googleAppID:googleAppID + appCheckToken:appCheckToken]; +#if TARGET_OS_WATCH + // Regular NSURLSession websocket. + NSOperationQueue *opQueue = [[NSOperationQueue alloc] init]; + opQueue.underlyingQueue = queue; + NSURLSession *session = [NSURLSession + sessionWithConfiguration:[NSURLSessionConfiguration + defaultSessionConfiguration] + delegate:self + delegateQueue:opQueue]; + NSURLSessionWebSocketTask *task = + [session webSocketTaskWithRequest:req]; + self.webSocketTask = task; + + if (@available(watchOS 7.0, *)) { + [[NSNotificationCenter defaultCenter] + addObserverForName:WKApplicationWillResignActiveNotification + object:nil + queue:opQueue + usingBlock:^(NSNotification *_Nonnull note) { + FFLog(@"I-RDB083015", + @"Received watchOS background notification, " + @"closing web socket."); + [self onClosed]; + }]; + } +#else + // TODO(mmaksym): Remove googleAppID and userAgent from FSRWebSocket as + // they are passed via NSURLRequest. + self.webSocket = [[FSRWebSocket alloc] initWithURLRequest:req + queue:queue + googleAppID:googleAppID + andUserAgent:userAgent]; + [self.webSocket setDelegateDispatchQueue:queue]; + self.webSocket.delegate = self; +#endif // TARGET_OS_WATCH + } + return self; +} + +- (NSString *)userAgent { + NSString *systemVersion; + NSString *deviceName; + BOOL hasUiDeviceClass = NO; + +// Targetted compilation is ONLY for testing. UIKit is weak-linked in actual +// release build. +#if TARGET_OS_IOS || TARGET_OS_TV + Class uiDeviceClass = NSClassFromString(@"UIDevice"); + if (uiDeviceClass) { + systemVersion = [uiDeviceClass currentDevice].systemVersion; + deviceName = [uiDeviceClass currentDevice].model; + hasUiDeviceClass = YES; + } +#endif // TARGET_OS_IOS || TARGET_OS_TV + + if (!hasUiDeviceClass) { + NSDictionary *systemVersionDictionary = [NSDictionary + dictionaryWithContentsOfFile: + @"/System/Library/CoreServices/SystemVersion.plist"]; + systemVersion = + [systemVersionDictionary objectForKey:@"ProductVersion"]; + deviceName = [systemVersionDictionary objectForKey:@"ProductName"]; + } + + NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier]; + + // Sanitize '/'s in deviceName and bundleIdentifier for stats + deviceName = [FStringUtilities sanitizedForUserAgent:deviceName]; + bundleIdentifier = + [FStringUtilities sanitizedForUserAgent:bundleIdentifier]; + + // Firebase/5/__//{device model / + // os (Mac OS X, iPhone, etc.}_ + NSString *ua = [NSString + stringWithFormat:@"Firebase/%@/%@/%@/%@_%@", kWebsocketProtocolVersion, + [FIRDatabase buildVersion], systemVersion, deviceName, + bundleIdentifier]; + return ua; +} + +- (BOOL)buffering { + return frame != nil; +} + +#pragma mark - +#pragma mark Public FWebSocketConnection methods + +- (void)open { + FFLog(@"I-RDB083002", @"(wsc:%@) FWebSocketConnection open.", + self.connectionId); + assert(delegate); + everConnected = NO; + // TODO Assert url +#if TARGET_OS_WATCH + [self.webSocketTask resume]; + // We need to request data from the web socket in order for it to start + // sending data. + [self receiveWebSocketData]; +#else + [self.webSocket open]; +#endif // TARGET_OS_WATCH + dispatch_time_t when = dispatch_time( + DISPATCH_TIME_NOW, kWebsocketConnectTimeout * NSEC_PER_SEC); + dispatch_after(when, self.dispatchQueue, ^{ + [self closeIfNeverConnected]; + }); +} + +- (void)close { + FFLog(@"I-RDB083003", @"(wsc:%@) FWebSocketConnection is being closed.", + self.connectionId); + isClosed = YES; +#if TARGET_OS_WATCH + [self.webSocketTask + cancelWithCloseCode:NSURLSessionWebSocketCloseCodeNormalClosure + reason:nil]; +#else + [self.webSocket close]; +#endif // TARGET_OS_WATCH +} + +- (void)start { + // Start is a no-op for websockets. +} + +- (void)send:(NSDictionary *)dictionary { + + [self resetKeepAlive]; + + NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dictionary + options:kNilOptions + error:nil]; + + NSString *data = [[NSString alloc] initWithData:jsonData + encoding:NSUTF8StringEncoding]; + + NSArray *dataSegs = [FUtilities splitString:data + intoMaxSize:kWebsocketMaxFrameSize]; + + // First send the header so the server knows how many segments are + // forthcoming + if (dataSegs.count > 1) { + NSString *formattedData = + [NSString stringWithFormat:@"%u", (unsigned int)dataSegs.count]; + [self sendStringToWebSocket:formattedData]; + } + + // Then, actually send the segments. + for (NSString *segment in dataSegs) { + [self sendStringToWebSocket:segment]; + } +} + +- (void)nop:(NSTimer *)timer { + if (!isClosed) { + FFLog(@"I-RDB083004", @"(wsc:%@) nop", self.connectionId); + // Note: the backend is expecting a string "0" here, not any special + // ping/pong from build in websocket APIs. + [self sendStringToWebSocket:@"0"]; + } else { + FFLog(@"I-RDB083005", + @"(wsc:%@) No more websocket; invalidating nop timer.", + self.connectionId); + [timer invalidate]; + } +} + +- (void)handleNewFrameCount:(int)numFrames { + self.totalFrames = numFrames; + frame = [[NSMutableString alloc] initWithString:@""]; + FFLog(@"I-RDB083006", @"(wsc:%@) handleNewFrameCount: %d", + self.connectionId, self.totalFrames); +} + +- (NSString *)extractFrameCount:(NSString *)message { + if ([message length] <= 4) { + int frameCount = [message intValue]; + if (frameCount > 0) { + [self handleNewFrameCount:frameCount]; + return nil; + } + } + [self handleNewFrameCount:1]; + return message; +} + +- (void)appendFrame:(NSString *)message { + [frame appendString:message]; + self.totalFrames = self.totalFrames - 1; + + if (self.totalFrames == 0) { + // Call delegate and pass an immutable version of the frame + NSDictionary *json = [NSJSONSerialization + JSONObjectWithData:[frame dataUsingEncoding:NSUTF8StringEncoding] + options:kNilOptions + error:nil]; + frame = nil; + FFLog(@"I-RDB083007", + @"(wsc:%@) handleIncomingFrame sending complete frame: %d", + self.connectionId, self.totalFrames); + + @autoreleasepool { + [self.delegate onMessage:self withMessage:json]; + } + } +} + +- (void)handleIncomingFrame:(NSString *)message { + [self resetKeepAlive]; + if (self.buffering) { + [self appendFrame:message]; + } else { + NSString *remaining = [self extractFrameCount:message]; + if (remaining) { + [self appendFrame:remaining]; + } + } +} + +#pragma mark - +#pragma mark URLSessionWebSocketDelegate watchOS implementation +#if TARGET_OS_WATCH + +- (void)URLSession:(NSURLSession *)session + webSocketTask:(NSURLSessionWebSocketTask *)webSocketTask + didOpenWithProtocol:(NSString *)protocol { + [self webSocketDidOpen]; +} + +- (void)URLSession:(NSURLSession *)session + webSocketTask:(NSURLSessionWebSocketTask *)webSocketTask + didCloseWithCode:(NSURLSessionWebSocketCloseCode)closeCode + reason:(NSData *)reason { + FFLog(@"I-RDB083011", @"(wsc:%@) didCloseWithCode: %ld %@", + self.connectionId, (long)closeCode, reason); + [self onClosed]; +} + +- (void)receiveWebSocketData { + __weak __auto_type weakSelf = self; + [self.webSocketTask receiveMessageWithCompletionHandler:^( + NSURLSessionWebSocketMessage *_Nullable message, + NSError *_Nullable error) { + __auto_type strongSelf = weakSelf; + if (strongSelf == nil) { + return; + } + + if (message) { + [strongSelf handleIncomingFrame:message.string]; + } else if (error && !strongSelf->isClosed) { + FFWarn(@"I-RDB083020", + @"Error received from web socket, closing the connection. %@", + error); + [strongSelf shutdown]; + return; + } + + [strongSelf receiveWebSocketData]; + }]; +} + +#else + +#pragma mark SRWebSocketDelegate implementation + +- (void)webSocket:(FSRWebSocket *)webSocket didReceiveMessage:(id)message { + [self handleIncomingFrame:message]; +} + +- (void)webSocket:(FSRWebSocket *)webSocket didFailWithError:(NSError *)error { + FFLog(@"I-RDB083010", @"(wsc:%@) didFailWithError didFailWithError: %@", + self.connectionId, [error description]); + [self onClosed]; +} + +- (void)webSocket:(FSRWebSocket *)webSocket + didCloseWithCode:(NSInteger)code + reason:(NSString *)reason + wasClean:(BOOL)wasClean { + FFLog(@"I-RDB083011", @"(wsc:%@) didCloseWithCode: %ld %@", + self.connectionId, (long)code, reason); + [self onClosed]; +} + +#endif // TARGET_OS_WATCH + +// Common to both SRWebSocketDelegate and URLSessionWebSocketDelegate. + +- (void)webSocketDidOpen { + FFLog(@"I-RDB083008", @"(wsc:%@) webSocketDidOpen", self.connectionId); + + everConnected = YES; + + dispatch_async(dispatch_get_main_queue(), ^{ + self->keepAlive = + [NSTimer scheduledTimerWithTimeInterval:kWebsocketKeepaliveInterval + target:self + selector:@selector(nop:) + userInfo:nil + repeats:YES]; + FFLog(@"I-RDB083009", @"(wsc:%@) nop timer kicked off", + self.connectionId); + }); +} + +#pragma mark - +#pragma mark Private methods + +/** Sends a string through the open web socket. */ +- (void)sendStringToWebSocket:(NSString *)string { +#if TARGET_OS_WATCH + // Use built-in URLSessionWebSocket functionality. + [self.webSocketTask sendMessage:[[NSURLSessionWebSocketMessage alloc] + initWithString:string] + completionHandler:^(NSError *_Nullable error) { + if (error) { + FFWarn(@"I-RDB083016", + @"Error sending web socket data: %@.", error); + return; + } + }]; +#else + // Use existing SocketRocket implementation. + [self.webSocket send:string]; +#endif // TARGET_OS_WATCH +} + +/** + * Note that the close / onClosed / shutdown cycle here is a little different + * from the javascript client. In order to properly handle deallocation, no + * close-related action is taken at a higher level until we have received + * notification from the websocket itself that it is closed. Otherwise, we end + * up deallocating this class and the FConnection class before the websocket has + * a change to call some of its delegate methods. So, since close is the + * external close handler, we just set a flag saying not to call our own + * delegate method and close the websocket. That will trigger a callback into + * this class that can then do things like clean up the keepalive timer. + */ + +- (void)closeIfNeverConnected { + if (!everConnected) { + FFLog(@"I-RDB083012", @"(wsc:%@) Websocket timed out on connect", + self.connectionId); +#if TARGET_OS_WATCH + [self.webSocketTask + cancelWithCloseCode:NSURLSessionWebSocketCloseCodeNoStatusReceived + reason:nil]; +#else + [self.webSocket close]; +#endif // TARGET_OS_WATCH + } +} + +- (void)shutdown { + isClosed = YES; + + // Call delegate methods + [self.delegate onDisconnect:self wasEverConnected:everConnected]; +} + +- (void)onClosed { + if (!isClosed) { + FFLog(@"I-RDB083013", @"Websocket is closing itself"); + [self shutdown]; + } +#if TARGET_OS_WATCH + self.webSocketTask = nil; +#else + self.webSocket = nil; +#endif // TARGET_OS_WATCH + if (keepAlive.isValid) { + [keepAlive invalidate]; + } +} + +- (void)resetKeepAlive { + NSDate *newTime = + [NSDate dateWithTimeIntervalSinceNow:kWebsocketKeepaliveInterval]; + // Calling setFireDate is actually kinda' expensive, so wait at least 5 + // seconds before updating it. + if ([newTime timeIntervalSinceDate:keepAlive.fireDate] > 5) { + FFLog(@"I-RDB083014", @"(wsc:%@) resetting keepalive, to %@ ; old: %@", + self.connectionId, newTime, [keepAlive fireDate]); + [keepAlive setFireDate:newTime]; + } +} + ++ (NSURLRequest *)createRequestWithURL:(NSString *)connectionURL + userAgent:(NSString *)userAgent + googleAppID:(NSString *)googleAppID + appCheckToken:(nullable NSString *)appCheckToken { + + NSMutableURLRequest *request = [[NSMutableURLRequest alloc] + initWithURL:[[NSURL alloc] initWithString:connectionURL]]; + + [request setValue:appCheckToken forHTTPHeaderField:kAppCheckTokenHeader]; + [request setValue:userAgent forHTTPHeaderField:kUserAgentHeader]; + [request setValue:googleAppID forHTTPHeaderField:kGoogleAppIDHeader]; + + return [request copy]; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FChildrenNode.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FChildrenNode.h new file mode 100644 index 0000000..e597dcc --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FChildrenNode.h @@ -0,0 +1,42 @@ +/* + * 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 "FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" +#import "FirebaseDatabase/Sources/Utilities/FTypedefs.h" +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedDictionary.h" +#import + +@class FNamedNode; + +@interface FChildrenNode : NSObject + +- (id)initWithChildren:(FImmutableSortedDictionary *)someChildren; +- (id)initWithPriority:(id)aPriority + children:(FImmutableSortedDictionary *)someChildren; + +// FChildrenNode specific methods + +- (void)enumerateChildrenAndPriorityUsingBlock:(void (^)(NSString *, id, + BOOL *))block; + +- (FNamedNode *)firstChild; +- (FNamedNode *)lastChild; + +@property(nonatomic, strong) FImmutableSortedDictionary *children; +@property(nonatomic, strong) id priorityNode; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FChildrenNode.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FChildrenNode.m new file mode 100644 index 0000000..faa2e06 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FChildrenNode.m @@ -0,0 +1,418 @@ +/* + * 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 "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h" +#import "FirebaseDatabase/Sources/Constants/FConstants.h" +#import "FirebaseDatabase/Sources/FMaxNode.h" +#import "FirebaseDatabase/Sources/FNamedNode.h" +#import "FirebaseDatabase/Sources/FPriorityIndex.h" +#import "FirebaseDatabase/Sources/FTransformedEnumerator.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FStringUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" + +@interface FChildrenNode () +@property(nonatomic, strong) NSString *lazyHash; +@end + +@implementation FChildrenNode + +// Note: The only reason we allow nil priority is to for EmptyNode, since we +// can't use EmptyNode as the priority of EmptyNode. We might want to consider +// making EmptyNode its own class instead of an empty ChildrenNode. + +- (id)init { + return [self + initWithPriority:nil + children:[FImmutableSortedDictionary + dictionaryWithComparator:[FUtilities + keyComparator]]]; +} + +- (id)initWithChildren:(FImmutableSortedDictionary *)someChildren { + return [self initWithPriority:nil children:someChildren]; +} + +- (id)initWithPriority:(id)aPriority + children:(FImmutableSortedDictionary *)someChildren { + if (someChildren.isEmpty && aPriority != nil && ![aPriority isEmpty]) { + [NSException raise:NSInvalidArgumentException + format:@"Can't create empty node with priority!"]; + } + self = [super init]; + if (self) { + self.children = someChildren; + self.priorityNode = aPriority; + } + return self; +} + +- (NSString *)description { + return [[self valForExport:YES] description]; +} + +#pragma mark - +#pragma mark FNode methods + +- (BOOL)isLeafNode { + return NO; +} + +- (id)getPriority { + if (self.priorityNode) { + return self.priorityNode; + } else { + return [FEmptyNode emptyNode]; + } +} + +- (id)updatePriority:(id)aPriority { + if ([self.children isEmpty]) { + return [FEmptyNode emptyNode]; + } else { + return [[FChildrenNode alloc] initWithPriority:aPriority + children:self.children]; + } +} + +- (id)getImmediateChild:(NSString *)childName { + if ([childName isEqualToString:@".priority"]) { + return [self getPriority]; + } else { + id child = [self.children objectForKey:childName]; + return (child == nil) ? [FEmptyNode emptyNode] : child; + } +} + +- (id)getChild:(FPath *)path { + NSString *front = [path getFront]; + if (front == nil) { + return self; + } else { + return [[self getImmediateChild:front] getChild:[path popFront]]; + } +} + +- (BOOL)hasChild:(NSString *)childName { + return ![self getImmediateChild:childName].isEmpty; +} + +- (id)updateImmediateChild:(NSString *)childName + withNewChild:(id)newChildNode { + NSAssert(newChildNode != nil, @"Should always be passing nodes."); + + if ([childName isEqualToString:@".priority"]) { + return [self updatePriority:newChildNode]; + } else { + FImmutableSortedDictionary *newChildren; + if (newChildNode.isEmpty) { + newChildren = [self.children removeObjectForKey:childName]; + } else { + newChildren = [self.children setObject:newChildNode + forKey:childName]; + } + if (newChildren.isEmpty) { + return [FEmptyNode emptyNode]; + } else { + return [[FChildrenNode alloc] initWithPriority:self.getPriority + children:newChildren]; + } + } +} + +- (id)updateChild:(FPath *)path withNewChild:(id)newChildNode { + NSString *front = [path getFront]; + if (front == nil) { + return newChildNode; + } else { + NSAssert(![front isEqualToString:@".priority"] || path.length == 1, + @".priority must be the last token in a path."); + id newImmediateChild = + [[self getImmediateChild:front] updateChild:[path popFront] + withNewChild:newChildNode]; + return [self updateImmediateChild:front withNewChild:newImmediateChild]; + } +} + +- (BOOL)isEmpty { + return [self.children isEmpty]; +} + +- (int)numChildren { + return [self.children count]; +} + +- (id)val { + return [self valForExport:NO]; +} + +- (id)valForExport:(BOOL)exp { + if ([self isEmpty]) { + return [NSNull null]; + } + + __block int numKeys = 0; + __block NSInteger maxKey = 0; + __block BOOL allIntegerKeys = YES; + + NSMutableDictionary *obj = + [[NSMutableDictionary alloc] initWithCapacity:[self.children count]]; + [self enumerateChildrenUsingBlock:^(NSString *key, id childNode, + BOOL *stop) { + [obj setObject:[childNode valForExport:exp] forKey:key]; + + numKeys++; + + // If we already found a string key, don't bother with any of this + if (!allIntegerKeys) { + return; + } + + // Treat leading zeroes that are not exactly "0" as strings + NSString *firstChar = [key substringWithRange:NSMakeRange(0, 1)]; + if ([firstChar isEqualToString:@"0"] && [key length] > 1) { + allIntegerKeys = NO; + } else { + NSNumber *keyAsNum = [FUtilities intForString:key]; + if (keyAsNum != nil) { + NSInteger keyAsInt = [keyAsNum integerValue]; + if (keyAsInt > maxKey) { + maxKey = keyAsInt; + } + } else { + allIntegerKeys = NO; + } + } + }]; + + if (!exp && allIntegerKeys && maxKey < 2 * numKeys) { + // convert to an array + NSMutableArray *array = + [[NSMutableArray alloc] initWithCapacity:maxKey + 1]; + for (int i = 0; i <= maxKey; ++i) { + NSString *keyString = [NSString stringWithFormat:@"%i", i]; + id child = obj[keyString]; + if (child != nil) { + [array addObject:child]; + } else { + [array addObject:[NSNull null]]; + } + } + return array; + } else { + + if (exp && [self getPriority] != nil && !self.getPriority.isEmpty) { + obj[kPayloadPriority] = [self.getPriority val]; + } + + return obj; + } +} + +- (NSString *)dataHash { + if (self.lazyHash == nil) { + NSMutableString *toHash = [[NSMutableString alloc] init]; + + if (!self.getPriority.isEmpty) { + [toHash appendString:@"priority:"]; + [FSnapshotUtilities + appendHashRepresentationForLeafNode:(FLeafNode *) + self.getPriority + toString:toHash + hashVersion:FDataHashVersionV1]; + [toHash appendString:@":"]; + } + + __block BOOL sawPriority = NO; + [self enumerateChildrenUsingBlock:^(NSString *key, id node, + BOOL *stop) { + sawPriority = sawPriority || [[node getPriority] isEmpty]; + *stop = sawPriority; + }]; + if (sawPriority) { + NSMutableArray *array = [NSMutableArray array]; + [self enumerateChildrenUsingBlock:^(NSString *key, id node, + BOOL *stop) { + FNamedNode *namedNode = [[FNamedNode alloc] initWithName:key + andNode:node]; + [array addObject:namedNode]; + }]; + [array sortUsingComparator:^NSComparisonResult( + FNamedNode *namedNode1, FNamedNode *namedNode2) { + return + [[FPriorityIndex priorityIndex] compareNamedNode:namedNode1 + toNamedNode:namedNode2]; + }]; + [array enumerateObjectsUsingBlock:^(FNamedNode *namedNode, + NSUInteger idx, BOOL *stop) { + NSString *childHash = [namedNode.node dataHash]; + if (![childHash isEqualToString:@""]) { + [toHash appendFormat:@":%@:%@", namedNode.name, childHash]; + } + }]; + } else { + [self enumerateChildrenUsingBlock:^(NSString *key, id node, + BOOL *stop) { + NSString *childHash = [node dataHash]; + if (![childHash isEqualToString:@""]) { + [toHash appendFormat:@":%@:%@", key, childHash]; + } + }]; + } + self.lazyHash = [toHash isEqualToString:@""] + ? @"" + : [FStringUtilities base64EncodedSha1:toHash]; + } + return self.lazyHash; +} + +- (NSComparisonResult)compare:(id)other { + // children nodes come last, unless this is actually an empty node, then we + // come first. + if (self.isEmpty) { + if (other.isEmpty) { + return NSOrderedSame; + } else { + return NSOrderedAscending; + } + } else if (other.isLeafNode || other.isEmpty) { + return NSOrderedDescending; + } else if (other == [FMaxNode maxNode]) { + return NSOrderedAscending; + } else { + // Must be another node with children. + return NSOrderedSame; + } +} + +- (BOOL)isEqual:(id)other { + if (other == self) { + return YES; + } else if (other == nil) { + return NO; + } else if (other.isLeafNode) { + return NO; + } else if (self.isEmpty && [other isEmpty]) { + // Empty nodes do not have priority + return YES; + } else { + FChildrenNode *otherChildrenNode = other; + if (![self.getPriority isEqual:other.getPriority]) { + return NO; + } else if (self.children.count == otherChildrenNode.children.count) { + __block BOOL equal = YES; + [self enumerateChildrenUsingBlock:^(NSString *key, id node, + BOOL *stop) { + id child = [otherChildrenNode getImmediateChild:key]; + if (![child isEqual:node]) { + equal = NO; + *stop = YES; + } + }]; + return equal; + } else { + return NO; + } + } +} + +- (NSUInteger)hash { + __block NSUInteger hashCode = 0; + [self enumerateChildrenUsingBlock:^(NSString *key, id node, + BOOL *stop) { + hashCode = 31 * hashCode + key.hash; + hashCode = 17 * hashCode + node.hash; + }]; + return 17 * hashCode + self.priorityNode.hash; +} + +- (void)enumerateChildrenAndPriorityUsingBlock:(void (^)(NSString *, id, + BOOL *))block { + if ([self.getPriority isEmpty]) { + [self enumerateChildrenUsingBlock:block]; + } else { + __block BOOL passedPriorityKey = NO; + [self enumerateChildrenUsingBlock:^(NSString *key, id node, + BOOL *stop) { + if (!passedPriorityKey && + [FUtilities compareKey:key + toKey:@".priority"] == NSOrderedDescending) { + passedPriorityKey = YES; + BOOL stopAfterPriority = NO; + block(@".priority", [self getPriority], &stopAfterPriority); + if (stopAfterPriority) + return; + } + block(key, node, stop); + }]; + } +} + +- (void)enumerateChildrenUsingBlock:(void (^)(NSString *, id, + BOOL *))block { + [self.children enumerateKeysAndObjectsUsingBlock:block]; +} + +- (void)enumerateChildrenReverse:(BOOL)reverse + usingBlock: + (void (^)(NSString *, id, BOOL *))block { + [self.children enumerateKeysAndObjectsReverse:reverse usingBlock:block]; +} + +- (NSEnumerator *)childEnumerator { + return [[FTransformedEnumerator alloc] + initWithEnumerator:self.children.keyEnumerator + andTransform:^id(NSString *key) { + return [FNamedNode nodeWithName:key + node:[self getImmediateChild:key]]; + }]; +} + +- (NSString *)predecessorChildKey:(NSString *)childKey { + return [self.children getPredecessorKey:childKey]; +} + +#pragma mark - +#pragma mark FChildrenNode specific methods + +- (id)childrenGetter:(id)key { + return [self.children objectForKey:key]; +} + +- (FNamedNode *)firstChild { + NSString *childKey = self.children.minKey; + if (childKey) { + return + [[FNamedNode alloc] initWithName:childKey + andNode:[self getImmediateChild:childKey]]; + } else { + return nil; + } +} + +- (FNamedNode *)lastChild { + NSString *childKey = self.children.maxKey; + if (childKey) { + return + [[FNamedNode alloc] initWithName:childKey + andNode:[self getImmediateChild:childKey]]; + } else { + return nil; + } +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FCompoundWrite.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FCompoundWrite.h new file mode 100644 index 0000000..47de66f --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FCompoundWrite.h @@ -0,0 +1,64 @@ +/* + * 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 + +@class FImmutableTree; +@protocol FNode; +@class FPath; + +/** + * This class holds a collection of writes that can be applied to nodes in + * unison. It abstracts away the logic with dealing with priority writes and + * multiple nested writes. At any given path, there is only allowed to be one + * write modifying that path. Any write to an existing path or shadowing an + * existing path will modify that existing write to reflect the write added. + */ +@interface FCompoundWrite : NSObject + +- (id)initWithWriteTree:(FImmutableTree *)tree; + +/** + * Creates a compound write with NSDictionary from path string to object + */ ++ (FCompoundWrite *)compoundWriteWithValueDictionary:(NSDictionary *)dictionary; +/** + * Creates a compound write with NSDictionary from path string to node + */ ++ (FCompoundWrite *)compoundWriteWithNodeDictionary:(NSDictionary *)dictionary; + ++ (FCompoundWrite *)emptyWrite; + +- (FCompoundWrite *)addWrite:(id)node atPath:(FPath *)path; +- (FCompoundWrite *)addWrite:(id)node atKey:(NSString *)key; +- (FCompoundWrite *)addCompoundWrite:(FCompoundWrite *)node + atPath:(FPath *)path; +- (FCompoundWrite *)removeWriteAtPath:(FPath *)path; +- (id)rootWrite; +- (BOOL)hasCompleteWriteAtPath:(FPath *)path; +- (id)completeNodeAtPath:(FPath *)path; +- (NSArray *)completeChildren; +- (NSDictionary *)childCompoundWrites; +- (FCompoundWrite *)childCompoundWriteAtPath:(FPath *)path; +- (id)applyToNode:(id)node; +- (void)enumerateWrites:(void (^)(FPath *path, id node, + BOOL *stop))block; + +- (NSDictionary *)valForExport:(BOOL)exportFormat; + +- (BOOL)isEmpty; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FCompoundWrite.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FCompoundWrite.m new file mode 100644 index 0000000..a7c1b2a --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FCompoundWrite.m @@ -0,0 +1,304 @@ +/* + * 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 "FirebaseDatabase/Sources/Snapshot/FCompoundWrite.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FImmutableTree.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/FNamedNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h" + +@interface FCompoundWrite () +@property(nonatomic, strong) FImmutableTree *writeTree; +@end + +@implementation FCompoundWrite + +- (id)initWithWriteTree:(FImmutableTree *)tree { + self = [super init]; + if (self) { + self.writeTree = tree; + } + return self; +} + ++ (FCompoundWrite *)compoundWriteWithValueDictionary: + (NSDictionary *)dictionary { + __block FImmutableTree *writeTree = [FImmutableTree empty]; + [dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *pathString, + id value, BOOL *stop) { + id node = [FSnapshotUtilities nodeFrom:value]; + FImmutableTree *tree = [[FImmutableTree alloc] initWithValue:node]; + writeTree = [writeTree setTree:tree + atPath:[[FPath alloc] initWith:pathString]]; + }]; + return [[FCompoundWrite alloc] initWithWriteTree:writeTree]; +} + ++ (FCompoundWrite *)compoundWriteWithNodeDictionary:(NSDictionary *)dictionary { + __block FImmutableTree *writeTree = [FImmutableTree empty]; + [dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *pathString, + id node, BOOL *stop) { + FImmutableTree *tree = [[FImmutableTree alloc] initWithValue:node]; + writeTree = [writeTree setTree:tree + atPath:[[FPath alloc] initWith:pathString]]; + }]; + return [[FCompoundWrite alloc] initWithWriteTree:writeTree]; +} + ++ (FCompoundWrite *)emptyWrite { + static dispatch_once_t pred = 0; + static FCompoundWrite *empty = nil; + dispatch_once(&pred, ^{ + empty = [[FCompoundWrite alloc] + initWithWriteTree:[[FImmutableTree alloc] initWithValue:nil]]; + }); + return empty; +} + +- (FCompoundWrite *)addWrite:(id)node atPath:(FPath *)path { + if (path.isEmpty) { + return [[FCompoundWrite alloc] + initWithWriteTree:[[FImmutableTree alloc] initWithValue:node]]; + } else { + FTuplePathValue *rootMost = + [self.writeTree findRootMostValueAndPath:path]; + if (rootMost != nil) { + FPath *relativePath = [FPath relativePathFrom:rootMost.path + to:path]; + id value = [rootMost.value updateChild:relativePath + withNewChild:node]; + return [[FCompoundWrite alloc] + initWithWriteTree:[self.writeTree setValue:value + atPath:rootMost.path]]; + } else { + FImmutableTree *subtree = + [[FImmutableTree alloc] initWithValue:node]; + FImmutableTree *newWriteTree = [self.writeTree setTree:subtree + atPath:path]; + return [[FCompoundWrite alloc] initWithWriteTree:newWriteTree]; + } + } +} + +- (FCompoundWrite *)addWrite:(id)node atKey:(NSString *)key { + return [self addWrite:node atPath:[[FPath alloc] initWith:key]]; +} + +- (FCompoundWrite *)addCompoundWrite:(FCompoundWrite *)compoundWrite + atPath:(FPath *)path { + __block FCompoundWrite *newWrite = self; + [compoundWrite.writeTree forEach:^(FPath *childPath, id value) { + newWrite = [newWrite addWrite:value atPath:[path child:childPath]]; + }]; + return newWrite; +} + +/** + * Will remove a write at the given path and deeper paths. This will + * not modify a write at a higher location, which must be removed by + * calling this method with that path. + * @param path The path at which a write and all deeper writes should be + * removed. + * @return The new FWriteCompound with the removed path. + */ +- (FCompoundWrite *)removeWriteAtPath:(FPath *)path { + if (path.isEmpty) { + return [FCompoundWrite emptyWrite]; + } else { + FImmutableTree *newWriteTree = + [self.writeTree setTree:[FImmutableTree empty] atPath:path]; + return [[FCompoundWrite alloc] initWithWriteTree:newWriteTree]; + } +} + +/** + * Returns whether this FCompoundWrite will fully overwrite a node at a given + * location and can therefore be considered "complete". + * @param path The path to check for + * @return Whether there is a complete write at that path. + */ +- (BOOL)hasCompleteWriteAtPath:(FPath *)path { + return [self completeNodeAtPath:path] != nil; +} + +/** + * Returns a node for a path if and only if the node is a "complete" overwrite + * at that path. This will not aggregate writes from depeer paths, but will + * return child nodes from a more shallow path. + * @param path The path to get a complete write + * @return The node if complete at that path, or nil otherwise. + */ +- (id)completeNodeAtPath:(FPath *)path { + FTuplePathValue *rootMost = [self.writeTree findRootMostValueAndPath:path]; + if (rootMost != nil) { + FPath *relativePath = [FPath relativePathFrom:rootMost.path to:path]; + return [rootMost.value getChild:relativePath]; + } else { + return nil; + } +} + +// TODO: change into traversal method... +- (NSArray *)completeChildren { + NSMutableArray *children = [[NSMutableArray alloc] init]; + if (self.writeTree.value != nil) { + id node = self.writeTree.value; + [node enumerateChildrenUsingBlock:^(NSString *key, id node, + BOOL *stop) { + [children addObject:[[FNamedNode alloc] initWithName:key + andNode:node]]; + }]; + } else { + [self.writeTree.children + enumerateKeysAndObjectsUsingBlock:^( + NSString *childKey, FImmutableTree *childTree, BOOL *stop) { + if (childTree.value != nil) { + [children addObject:[[FNamedNode alloc] + initWithName:childKey + andNode:childTree.value]]; + } + }]; + } + return children; +} + +// TODO: change into enumarate method +- (NSDictionary *)childCompoundWrites { + NSMutableDictionary *dict = [NSMutableDictionary dictionary]; + [self.writeTree.children + enumerateKeysAndObjectsUsingBlock:^( + NSString *key, FImmutableTree *childWrite, BOOL *stop) { + dict[key] = [[FCompoundWrite alloc] initWithWriteTree:childWrite]; + }]; + return dict; +} + +- (FCompoundWrite *)childCompoundWriteAtPath:(FPath *)path { + if (path.isEmpty) { + return self; + } else { + id shadowingNode = [self completeNodeAtPath:path]; + if (shadowingNode != nil) { + return [[FCompoundWrite alloc] + initWithWriteTree:[[FImmutableTree alloc] + initWithValue:shadowingNode]]; + } else { + return [[FCompoundWrite alloc] + initWithWriteTree:[self.writeTree subtreeAtPath:path]]; + } + } +} + +- (id)applySubtreeWrite:(FImmutableTree *)subtreeWrite + atPath:(FPath *)relativePath + toNode:(id)node { + if (subtreeWrite.value != nil) { + // Since a write there is always a leaf, we're done here. + return [node updateChild:relativePath withNewChild:subtreeWrite.value]; + } else { + __block id priorityWrite = nil; + __block id blockNode = node; + [subtreeWrite.children + enumerateKeysAndObjectsUsingBlock:^( + NSString *childKey, FImmutableTree *childTree, BOOL *stop) { + if ([childKey isEqualToString:@".priority"]) { + // Apply priorities at the end so we don't update priorities + // for either empty nodes or forget to apply priorities to + // empty nodes that are later filled. + NSAssert(childTree.value != nil, + @"Priority writes must always be leaf nodes"); + priorityWrite = childTree.value; + } else { + blockNode = [self + applySubtreeWrite:childTree + atPath:[relativePath childFromString:childKey] + toNode:blockNode]; + } + }]; + // If there was a priority write, we only apply it if the node is not + // empty + if (![blockNode getChild:relativePath].isEmpty && + priorityWrite != nil) { + blockNode = [blockNode + updateChild:[relativePath childFromString:@".priority"] + withNewChild:priorityWrite]; + } + return blockNode; + } +} + +- (void)enumerateWrites:(void (^)(FPath *, id, BOOL *))block { + __block BOOL stop = NO; + // TODO: add stop to tree iterator... + [self.writeTree forEach:^(FPath *path, id value) { + if (!stop) { + block(path, value, &stop); + } + }]; +} + +/** + * Applies this FCompoundWrite to a node. The node is returned with all writes + * from this FCompoundWrite applied to the node. + * @param node The node to apply this FCompoundWrite to + * @return The node with all writes applied + */ +- (id)applyToNode:(id)node { + return [self applySubtreeWrite:self.writeTree + atPath:[FPath empty] + toNode:node]; +} + +/** + * Return true if this CompoundWrite is empty and therefore does not modify any + * nodes. + * @return Whether this CompoundWrite is empty + */ +- (BOOL)isEmpty { + return self.writeTree.isEmpty; +} + +- (id)rootWrite { + return self.writeTree.value; +} + +- (BOOL)isEqual:(id)object { + if (![object isKindOfClass:[FCompoundWrite class]]) { + return NO; + } + FCompoundWrite *other = (FCompoundWrite *)object; + return + [[self valForExport:YES] isEqualToDictionary:[other valForExport:YES]]; +} + +- (NSUInteger)hash { + return [[self valForExport:YES] hash]; +} + +- (NSDictionary *)valForExport:(BOOL)exportFormat { + NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; + [self.writeTree forEach:^(FPath *path, id value) { + dictionary[path.wireFormat] = [value valForExport:exportFormat]; + }]; + return dictionary; +} + +- (NSString *)description { + return [[self valForExport:YES] description]; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FEmptyNode.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FEmptyNode.h new file mode 100644 index 0000000..aa67983 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FEmptyNode.h @@ -0,0 +1,24 @@ +/* + * 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 "FirebaseDatabase/Sources/Snapshot/FNode.h" +#import + +@interface FEmptyNode : NSObject + ++ (id)emptyNode; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FEmptyNode.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FEmptyNode.m new file mode 100644 index 0000000..2f9283e --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FEmptyNode.m @@ -0,0 +1,30 @@ +/* + * 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 "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h" + +@implementation FEmptyNode + ++ (id)emptyNode { + static FChildrenNode *empty = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + empty = [[FChildrenNode alloc] init]; + }); + return empty; +} +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FIndexedNode.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FIndexedNode.h new file mode 100644 index 0000000..4434855 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FIndexedNode.h @@ -0,0 +1,55 @@ +/* + * 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 + +#import "FirebaseDatabase/Sources/FIndex.h" +#import "FirebaseDatabase/Sources/FNamedNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" + +/** + * Represents a node together with an index. The index and node are updated in + * unison. In the case where the index does not affect the ordering (i.e. the + * ordering is identical to the key ordering) this class uses a fallback index + * to save memory. Everything operating on the index must special case the + * fallback index. + */ +@interface FIndexedNode : NSObject + +@property(nonatomic, strong, readonly) id node; + ++ (FIndexedNode *)indexedNodeWithNode:(id)node; ++ (FIndexedNode *)indexedNodeWithNode:(id)node index:(id)index; + +- (BOOL)hasIndex:(id)index; +- (FIndexedNode *)updateChild:(NSString *)key + withNewChild:(id)newChildNode; +- (FIndexedNode *)updatePriority:(id)priority; + +- (FNamedNode *)firstChild; +- (FNamedNode *)lastChild; + +- (NSString *)predecessorForChildKey:(NSString *)childKey + childNode:(id)childNode + index:(id)index; + +- (void)enumerateChildrenReverse:(BOOL)reverse + usingBlock:(void (^)(NSString *key, id node, + BOOL *stop))block; + +- (NSEnumerator *)childEnumerator; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FIndexedNode.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FIndexedNode.m new file mode 100644 index 0000000..4f36e67 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FIndexedNode.m @@ -0,0 +1,218 @@ +/* + * 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 "FirebaseDatabase/Sources/Snapshot/FIndexedNode.h" + +#import "FirebaseDatabase/Sources/FIndex.h" +#import "FirebaseDatabase/Sources/FKeyIndex.h" +#import "FirebaseDatabase/Sources/FPriorityIndex.h" +#import "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h" +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedSet.h" + +static FImmutableSortedSet *FALLBACK_INDEX; + +@interface FIndexedNode () + +@property(nonatomic, strong) id node; +/** + * The indexed set is initialized lazily to prevent creation when it is not + * needed + */ +@property(nonatomic, strong) FImmutableSortedSet *indexed; +@property(nonatomic, strong) id index; + +@end + +@implementation FIndexedNode + ++ (FImmutableSortedSet *)fallbackIndex { + static FImmutableSortedSet *fallbackIndex; + static dispatch_once_t once; + dispatch_once(&once, ^{ + fallbackIndex = [[FImmutableSortedSet alloc] init]; + }); + return fallbackIndex; +} + ++ (FIndexedNode *)indexedNodeWithNode:(id)node { + return [[FIndexedNode alloc] initWithNode:node + index:[FPriorityIndex priorityIndex]]; +} + ++ (FIndexedNode *)indexedNodeWithNode:(id)node index:(id)index { + return [[FIndexedNode alloc] initWithNode:node index:index]; +} + +- (id)initWithNode:(id)node index:(id)index { + // Initialize indexed lazily + return [self initWithNode:node index:index indexed:nil]; +} + +- (id)initWithNode:(id)node + index:(id)index + indexed:(FImmutableSortedSet *)indexed { + self = [super init]; + if (self != nil) { + self->_node = node; + self->_index = index; + self->_indexed = indexed; + } + return self; +} + +- (void)ensureIndexed { + if (!self.indexed) { + if ([self.index isEqual:[FKeyIndex keyIndex]]) { + self.indexed = [FIndexedNode fallbackIndex]; + } else { + __block BOOL sawChild = NO; + [self.node enumerateChildrenUsingBlock:^( + NSString *key, id node, BOOL *stop) { + sawChild = sawChild || [self.index isDefinedOn:node]; + *stop = sawChild; + }]; + if (sawChild) { + NSMutableDictionary *dict = [NSMutableDictionary dictionary]; + [self.node enumerateChildrenUsingBlock:^( + NSString *key, id node, BOOL *stop) { + FNamedNode *namedNode = + [[FNamedNode alloc] initWithName:key andNode:node]; + dict[namedNode] = [NSNull null]; + }]; + // Make sure to assign index here, because the comparator will + // be retained and using self will cause a cycle + id index = self.index; + self.indexed = [FImmutableSortedSet + setWithKeysFromDictionary:dict + comparator:^NSComparisonResult( + FNamedNode *namedNode1, + FNamedNode *namedNode2) { + return [index compareNamedNode:namedNode1 + toNamedNode:namedNode2]; + }]; + } else { + self.indexed = [FIndexedNode fallbackIndex]; + } + } + } +} + +- (BOOL)hasIndex:(id)index { + return [self.index isEqual:index]; +} + +- (FIndexedNode *)updateChild:(NSString *)key + withNewChild:(id)newChildNode { + id newNode = [self.node updateImmediateChild:key + withNewChild:newChildNode]; + if (self.indexed == [FIndexedNode fallbackIndex] && + ![self.index isDefinedOn:newChildNode]) { + // doesn't affect the index, no need to create an index + return [[FIndexedNode alloc] initWithNode:newNode + index:self.index + indexed:[FIndexedNode fallbackIndex]]; + } else if (!self.indexed || self.indexed == [FIndexedNode fallbackIndex]) { + // No need to index yet, index lazily + return [[FIndexedNode alloc] initWithNode:newNode index:self.index]; + } else { + id oldChild = [self.node getImmediateChild:key]; + FImmutableSortedSet *newIndexed = [self.indexed + removeObject:[FNamedNode nodeWithName:key node:oldChild]]; + if (![newChildNode isEmpty]) { + newIndexed = [newIndexed + addObject:[FNamedNode nodeWithName:key node:newChildNode]]; + } + return [[FIndexedNode alloc] initWithNode:newNode + index:self.index + indexed:newIndexed]; + } +} + +- (FIndexedNode *)updatePriority:(id)priority { + return + [[FIndexedNode alloc] initWithNode:[self.node updatePriority:priority] + index:self.index + indexed:self.indexed]; +} + +- (FNamedNode *)firstChild { + if (![self.node isKindOfClass:[FChildrenNode class]]) { + return nil; + } else { + [self ensureIndexed]; + if (self.indexed == [FIndexedNode fallbackIndex]) { + return [((FChildrenNode *)self.node) firstChild]; + } else { + return self.indexed.firstObject; + } + } +} + +- (FNamedNode *)lastChild { + if (![self.node isKindOfClass:[FChildrenNode class]]) { + return nil; + } else { + [self ensureIndexed]; + if (self.indexed == [FIndexedNode fallbackIndex]) { + return [((FChildrenNode *)self.node) lastChild]; + } else { + return self.indexed.lastObject; + } + } +} + +- (NSString *)predecessorForChildKey:(NSString *)childKey + childNode:(id)childNode + index:(id)index { + if (![self.index isEqual:index]) { + [NSException raise:NSInvalidArgumentException + format:@"Index not available in IndexedNode!"]; + } + [self ensureIndexed]; + if (self.indexed == [FIndexedNode fallbackIndex]) { + return [self.node predecessorChildKey:childKey]; + } else { + FNamedNode *node = [self.indexed + predecessorEntry:[FNamedNode nodeWithName:childKey node:childNode]]; + return node.name; + } +} + +- (void)enumerateChildrenReverse:(BOOL)reverse + usingBlock: + (void (^)(NSString *, id, BOOL *))block { + [self ensureIndexed]; + if (self.indexed == [FIndexedNode fallbackIndex]) { + [self.node enumerateChildrenReverse:reverse usingBlock:block]; + } else { + [self.indexed + enumerateObjectsReverse:reverse + usingBlock:^(FNamedNode *namedNode, BOOL *stop) { + block(namedNode.name, namedNode.node, stop); + }]; + } +} + +- (NSEnumerator *)childEnumerator { + [self ensureIndexed]; + if (self.indexed == [FIndexedNode fallbackIndex]) { + return [self.node childEnumerator]; + } else { + return [self.indexed objectEnumerator]; + } +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FLeafNode.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FLeafNode.h new file mode 100644 index 0000000..07277ba --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FLeafNode.h @@ -0,0 +1,27 @@ +/* + * 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 "FirebaseDatabase/Sources/Snapshot/FNode.h" +#import + +@interface FLeafNode : NSObject + +- (id)initWithValue:(id)aValue; +- (id)initWithValue:(id)aValue withPriority:(id)aPriority; + +@property(nonatomic, strong) id value; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FLeafNode.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FLeafNode.m new file mode 100644 index 0000000..189cb31 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FLeafNode.m @@ -0,0 +1,266 @@ +/* + * 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 "FirebaseDatabase/Sources/Snapshot/FLeafNode.h" +#import "FirebaseDatabase/Sources/Constants/FConstants.h" +#import "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FStringUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedDictionary.h" + +@interface FLeafNode () +@property(nonatomic, strong) id priorityNode; +@property(nonatomic, strong) NSString *lazyHash; + +@end + +@implementation FLeafNode + +@synthesize value; +@synthesize priorityNode; + +- (id)initWithValue:(id)aValue { + self = [super init]; + if (self) { + self.value = aValue; + self.priorityNode = [FEmptyNode emptyNode]; + } + return self; +} + +- (id)initWithValue:(id)aValue withPriority:(id)aPriority { + self = [super init]; + if (self) { + self.value = aValue; + [FSnapshotUtilities validatePriorityNode:aPriority]; + self.priorityNode = aPriority; + } + return self; +} + +#pragma mark - +#pragma mark FNode methods + +- (BOOL)isLeafNode { + return YES; +} + +- (id)getPriority { + return self.priorityNode; +} + +- (id)updatePriority:(id)aPriority { + return [[FLeafNode alloc] initWithValue:self.value withPriority:aPriority]; +} + +- (id)getImmediateChild:(NSString *)childName { + if ([childName isEqualToString:@".priority"]) { + return self.priorityNode; + } else { + return [FEmptyNode emptyNode]; + } +} + +- (id)getChild:(FPath *)path { + if (path.getFront == nil) { + return self; + } else if ([[path getFront] isEqualToString:@".priority"]) { + return [self getPriority]; + } else { + return [FEmptyNode emptyNode]; + } +} + +- (BOOL)hasChild:(NSString *)childName { + return + [childName isEqualToString:@".priority"] && ![self getPriority].isEmpty; +} + +- (NSString *)predecessorChildKey:(NSString *)childKey { + return nil; +} + +- (id)updateImmediateChild:(NSString *)childName + withNewChild:(id)newChildNode { + if ([childName isEqualToString:@".priority"]) { + return [self updatePriority:newChildNode]; + } else if (newChildNode.isEmpty) { + return self; + } else { + FChildrenNode *childrenNode = [[FChildrenNode alloc] init]; + childrenNode = [childrenNode updateImmediateChild:childName + withNewChild:newChildNode]; + childrenNode = [childrenNode updatePriority:self.priorityNode]; + return childrenNode; + } +} + +- (id)updateChild:(FPath *)path withNewChild:(id)newChildNode { + NSString *front = [path getFront]; + if (front == nil) { + return newChildNode; + } else if (newChildNode.isEmpty && ![front isEqualToString:@".priority"]) { + return self; + } else { + NSAssert(![front isEqualToString:@".priority"] || path.length == 1, + @".priority must be the last token in a path."); + return [self updateImmediateChild:front + withNewChild:[[FEmptyNode emptyNode] + updateChild:[path popFront] + withNewChild:newChildNode]]; + } +} + +- (id)val { + return [self valForExport:NO]; +} + +- (id)valForExport:(BOOL)exp { + if (exp && !self.getPriority.isEmpty) { + return @{ + kPayloadValue : self.value, + kPayloadPriority : [[self getPriority] val] + }; + } else { + return self.value; + } +} + +- (BOOL)isEqual:(id)other { + if (other == self) { + return YES; + } else if (other.isLeafNode) { + FLeafNode *otherLeaf = other; + if ([FUtilities getJavascriptType:self.value] != + [FUtilities getJavascriptType:otherLeaf.value]) { + return NO; + } + return [otherLeaf.value isEqual:self.value] && + [otherLeaf.priorityNode isEqual:self.priorityNode]; + } else { + return NO; + } +} + +- (NSUInteger)hash { + return [self.value hash] * 17 + self.priorityNode.hash; +} + +- (id)withIndex:(id)index { + return self; +} + +- (BOOL)isIndexed:(id)index { + return YES; +} + +- (BOOL)isEmpty { + return NO; +} + +- (int)numChildren { + return 0; +} + +- (void)enumerateChildrenUsingBlock:(void (^)(NSString *, id, + BOOL *))block { + // Nothing to iterate over +} + +- (void)enumerateChildrenReverse:(BOOL)reverse + usingBlock: + (void (^)(NSString *, id, BOOL *))block { + // Nothing to iterate over +} + +- (NSEnumerator *)childEnumerator { + // Nothing to iterate over + return [@[] objectEnumerator]; +} + +- (NSString *)dataHash { + if (self.lazyHash == nil) { + NSMutableString *toHash = [[NSMutableString alloc] init]; + [FSnapshotUtilities + appendHashRepresentationForLeafNode:self + toString:toHash + hashVersion:FDataHashVersionV1]; + + self.lazyHash = [FStringUtilities base64EncodedSha1:toHash]; + } + return self.lazyHash; +} + +- (NSComparisonResult)compare:(id)other { + if (other == [FEmptyNode emptyNode]) { + return NSOrderedDescending; + } else if ([other isKindOfClass:[FChildrenNode class]]) { + return NSOrderedAscending; + } else { + NSAssert(other.isLeafNode, @"Compared against unknown type of node."); + return [self compareToLeafNode:(FLeafNode *)other]; + } +} + ++ (NSArray *)valueTypeOrder { + static NSArray *valueOrder = nil; + static dispatch_once_t once; + dispatch_once(&once, ^{ + valueOrder = @[ + kJavaScriptObject, kJavaScriptBoolean, kJavaScriptNumber, + kJavaScriptString + ]; + }); + return valueOrder; +} + +- (NSComparisonResult)compareToLeafNode:(FLeafNode *)other { + NSString *thisLeafType = [FUtilities getJavascriptType:self.value]; + NSString *otherLeafType = [FUtilities getJavascriptType:other.value]; + NSUInteger thisIndex = + [[FLeafNode valueTypeOrder] indexOfObject:thisLeafType]; + NSUInteger otherIndex = + [[FLeafNode valueTypeOrder] indexOfObject:otherLeafType]; + assert(thisIndex >= 0 && otherIndex >= 0); + if (otherIndex == thisIndex) { + // Same type. Compare values. + if (thisLeafType == kJavaScriptObject) { + // Deferred value nodes are all equal, but we should also never get + // to this point... + return NSOrderedSame; + } else if (thisLeafType == kJavaScriptString) { + return [self.value compare:other.value options:NSLiteralSearch]; + } else { + return [self.value compare:other.value]; + } + } else { + return thisIndex > otherIndex ? NSOrderedDescending + : NSOrderedAscending; + } +} + +- (NSString *)description { + return [[self valForExport:YES] description]; +} + +- (void)forEachChildDo:(fbt_bool_nsstring_node)action { + // There are no children, so there is nothing to do. + return; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FNode.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FNode.h new file mode 100644 index 0000000..eff1986 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FNode.h @@ -0,0 +1,50 @@ +/* + * 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 "FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import + +@protocol FIndex; + +@protocol FNode + +- (BOOL)isLeafNode; +- (id)getPriority; +- (id)updatePriority:(id)priority; +- (id)getImmediateChild:(NSString *)childKey; +- (id)getChild:(FPath *)path; +- (NSString *)predecessorChildKey:(NSString *)childKey; +- (id)updateImmediateChild:(NSString *)childKey + withNewChild:(id)newChildNode; +- (id)updateChild:(FPath *)path withNewChild:(id)newChildNode; +- (BOOL)hasChild:(NSString *)childKey; +- (BOOL)isEmpty; +- (int)numChildren; +- (id)val; +- (id)valForExport:(BOOL)exp; +- (NSString *)dataHash; +- (NSComparisonResult)compare:(id)other; +- (BOOL)isEqual:(id)other; +- (void)enumerateChildrenUsingBlock:(void (^)(NSString *key, id node, + BOOL *stop))block; +- (void)enumerateChildrenReverse:(BOOL)reverse + usingBlock:(void (^)(NSString *key, id node, + BOOL *stop))block; + +- (NSEnumerator *)childEnumerator; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h new file mode 100644 index 0000000..92c25e6 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h @@ -0,0 +1,49 @@ +/* + * 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 "FirebaseDatabase/Sources/Snapshot/FNode.h" +#import + +@class FImmutableSortedDictionary; +@class FCompoundWrite; +@class FLeafNode; +@protocol FNode; + +typedef NS_ENUM(NSInteger, FDataHashVersion) { + FDataHashVersionV1, + FDataHashVersionV2, +}; + +@interface FSnapshotUtilities : NSObject + ++ (id)nodeFrom:(id)val; ++ (id)nodeFrom:(id)val priority:(id)priority; ++ (id)nodeFrom:(id)val withValidationFrom:(NSString *)fn; ++ (id)nodeFrom:(id)val + priority:(id)priority + withValidationFrom:(NSString *)fn; ++ (FCompoundWrite *)compoundWriteFromDictionary:(NSDictionary *)values + withValidationFrom:(NSString *)fn; ++ (void)validatePriorityNode:(id)priorityNode; ++ (void)appendHashRepresentationForLeafNode:(FLeafNode *)val + toString:(NSMutableString *)string + hashVersion:(FDataHashVersion)hashVersion; ++ (void)appendHashV2RepresentationForString:(NSString *)string + toString:(NSMutableString *)mutableString; + ++ (NSUInteger)estimateSerializedNodeSize:(id)node; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.m new file mode 100644 index 0000000..68754c8 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.m @@ -0,0 +1,394 @@ +/* + * 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 "FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h" +#import "FirebaseDatabase/Sources/Constants/FConstants.h" +#import "FirebaseDatabase/Sources/FMaxNode.h" +#import "FirebaseDatabase/Sources/FNamedNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FChildrenNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FCompoundWrite.h" +#import "FirebaseDatabase/Sources/Snapshot/FEmptyNode.h" +#import "FirebaseDatabase/Sources/Snapshot/FLeafNode.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FValidation.h" +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBValueNode.h" + +@implementation FSnapshotUtilities + ++ (id)nodeFrom:(id)val { + return [FSnapshotUtilities nodeFrom:val priority:nil]; +} + ++ (id)nodeFrom:(id)val priority:(id)priority { + return [FSnapshotUtilities nodeFrom:val + priority:priority + withValidationFrom:@"nodeFrom:priority:"]; +} + ++ (id)nodeFrom:(id)val withValidationFrom:(NSString *)fn { + return [FSnapshotUtilities nodeFrom:val priority:nil withValidationFrom:fn]; +} + ++ (id)nodeFrom:(id)val + priority:(id)priority + withValidationFrom:(NSString *)fn { + return [FSnapshotUtilities nodeFrom:val + priority:priority + withValidationFrom:fn + atDepth:0 + path:[[NSMutableArray alloc] init]]; +} + ++ (id)nodeFrom:(id)val + priority:(id)aPriority + withValidationFrom:(NSString *)fn + atDepth:(int)depth + path:(NSMutableArray *)path { + @autoreleasepool { + return [FSnapshotUtilities internalNodeFrom:val + priority:aPriority + withValidationFrom:fn + atDepth:depth + path:path]; + } +} + ++ (id)internalNodeFrom:(id)val + priority:(id)aPriority + withValidationFrom:(NSString *)fn + atDepth:(int)depth + path:(NSMutableArray *)path { + + if (depth > kFirebaseMaxObjectDepth) { + NSRange range; + range.location = 0; + range.length = 100; + NSString *pathString = + [[path subarrayWithRange:range] componentsJoinedByString:@"."]; + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString stringWithFormat: + @"(%@) Max object depth exceeded: %@...", + fn, pathString] + userInfo:nil]; + } + + if (val == nil || val == [NSNull null]) { + // Null is a valid type to store + return [FEmptyNode emptyNode]; + } + + [FValidation validateFrom:fn isValidPriorityValue:aPriority withPath:path]; + id priority = [FSnapshotUtilities nodeFrom:aPriority]; + + id value = val; + BOOL isLeafNode = NO; + + if ([value isKindOfClass:[NSDictionary class]]) { + NSDictionary *dict = val; + if (dict[kPayloadPriority] != nil) { + id rawPriority = [dict objectForKey:kPayloadPriority]; + [FValidation validateFrom:fn + isValidPriorityValue:rawPriority + withPath:path]; + priority = [FSnapshotUtilities nodeFrom:rawPriority]; + } + + if (dict[kPayloadValue] != nil) { + value = [dict objectForKey:kPayloadValue]; + if ([FValidation validateFrom:fn + isValidLeafValue:value + withPath:path]) { + isLeafNode = YES; + } else { + @throw [[NSException alloc] + initWithName:@"InvalidLeafValueType" + reason:[NSString stringWithFormat: + @"(%@) Invalid data type used " + @"with .value. Can only use " + "NSString and NSNumber or be " + "null. Found %@ instead.", + fn, [[value class] description]] + userInfo:nil]; + } + } + } + + if ([FValidation validateFrom:fn isValidLeafValue:value withPath:path]) { + isLeafNode = YES; + } + + if (isLeafNode) { + return [[FLeafNode alloc] initWithValue:value withPriority:priority]; + } + + // Unlike with JS, we have to handle the dictionary and array cases + // separately. + if ([value isKindOfClass:[NSDictionary class]]) { + NSDictionary *dval = (NSDictionary *)value; + NSMutableDictionary *children = + [NSMutableDictionary dictionaryWithCapacity:dval.count]; + + // Avoid creating a million newPaths by appending to old one + for (id keyId in dval) { + [FValidation validateFrom:fn + validDictionaryKey:keyId + withPath:path]; + NSString *key = (NSString *)keyId; + + if (![key hasPrefix:kPayloadMetadataPrefix]) { + [path addObject:key]; + id childNode = [FSnapshotUtilities nodeFrom:dval[key] + priority:nil + withValidationFrom:fn + atDepth:depth + 1 + path:path]; + [path removeLastObject]; + + if (![childNode isEmpty]) { + children[key] = childNode; + } + } + } + + if ([children count] == 0) { + return [FEmptyNode emptyNode]; + } else { + FImmutableSortedDictionary *childrenDict = + [FImmutableSortedDictionary + fromDictionary:children + withComparator:[FUtilities keyComparator]]; + return [[FChildrenNode alloc] initWithPriority:priority + children:childrenDict]; + } + } else if ([value isKindOfClass:[NSArray class]]) { + NSArray *aval = (NSArray *)value; + NSMutableDictionary *children = + [NSMutableDictionary dictionaryWithCapacity:aval.count]; + + for (int i = 0; i < [aval count]; i++) { + NSString *key = [NSString stringWithFormat:@"%i", i]; + [path addObject:key]; + id childNode = + [FSnapshotUtilities nodeFrom:[aval objectAtIndex:i] + priority:nil + withValidationFrom:fn + atDepth:depth + 1 + path:path]; + [path removeLastObject]; + + if (![childNode isEmpty]) { + children[key] = childNode; + } + } + + if ([children count] == 0) { + return [FEmptyNode emptyNode]; + } else { + FImmutableSortedDictionary *childrenDict = + [FImmutableSortedDictionary + fromDictionary:children + withComparator:[FUtilities keyComparator]]; + return [[FChildrenNode alloc] initWithPriority:priority + children:childrenDict]; + } + } else { + NSRange range; + range.location = 0; + range.length = MIN(path.count, 50); + NSString *pathString = + [[path subarrayWithRange:range] componentsJoinedByString:@"."]; + + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString + stringWithFormat: + @"(%@) Cannot store object of type %@ at %@. " + "Can only store objects of type NSNumber, " + "NSString, NSDictionary, and NSArray.", + fn, [[value class] description], pathString] + userInfo:nil]; + } +} + ++ (FCompoundWrite *)compoundWriteFromDictionary:(NSDictionary *)values + withValidationFrom:(NSString *)fn { + FCompoundWrite *compoundWrite = [FCompoundWrite emptyWrite]; + + NSMutableArray *updatePaths = + [NSMutableArray arrayWithCapacity:values.count]; + for (NSString *keyId in values) { + id value = values[keyId]; + [FValidation validateFrom:fn + validUpdateDictionaryKey:keyId + withValue:value]; + + FPath *path = [FPath pathWithString:keyId]; + id node = [FSnapshotUtilities nodeFrom:value + withValidationFrom:fn]; + + [updatePaths addObject:path]; + compoundWrite = [compoundWrite addWrite:node atPath:path]; + } + + // Check that the update paths are not descendants of each other. + [updatePaths + sortUsingComparator:^NSComparisonResult(FPath *left, FPath *right) { + return [left compare:right]; + }]; + FPath *prevPath = nil; + for (FPath *path in updatePaths) { + if (prevPath != nil && [prevPath contains:path]) { + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString stringWithFormat: + @"(%@) Invalid path in object. Path " + @"(%@) is an ancestor of (%@).", + fn, prevPath, path] + userInfo:nil]; + } + prevPath = path; + } + + return compoundWrite; +} + ++ (void)validatePriorityNode:(id)priorityNode { + assert(priorityNode != nil); + if (priorityNode.isLeafNode) { + id val = priorityNode.val; + if ([val isKindOfClass:[NSDictionary class]]) { + NSDictionary *valDict __unused = (NSDictionary *)val; + NSAssert(valDict[kServerValueSubKey] != nil, + @"Priority can't be object unless it's a deferred value"); + } else { + NSString *jsType __unused = [FUtilities getJavascriptType:val]; + NSAssert(jsType == kJavaScriptString || jsType == kJavaScriptNumber, + @"Priority of unexpected type."); + } + } else { + NSAssert(priorityNode == [FMaxNode maxNode] || priorityNode.isEmpty, + @"Priority of unexpected type."); + } + // Don't call getPriority() on MAX_NODE to avoid hitting assertion. + NSAssert(priorityNode == [FMaxNode maxNode] || + priorityNode.getPriority.isEmpty, + @"Priority nodes can't have a priority of their own."); +} + ++ (void)appendHashRepresentationForLeafNode:(FLeafNode *)leafNode + toString:(NSMutableString *)string + hashVersion:(FDataHashVersion)hashVersion { + NSAssert(hashVersion == FDataHashVersionV1 || + hashVersion == FDataHashVersionV2, + @"Unknown hash version: %lu", (unsigned long)hashVersion); + if (!leafNode.getPriority.isEmpty) { + [string appendString:@"priority:"]; + [FSnapshotUtilities + appendHashRepresentationForLeafNode:leafNode.getPriority + toString:string + hashVersion:hashVersion]; + [string appendString:@":"]; + } + + NSString *jsType = [FUtilities getJavascriptType:leafNode.val]; + [string appendString:jsType]; + [string appendString:@":"]; + + if (jsType == kJavaScriptBoolean) { + NSString *boolString = + [leafNode.val boolValue] ? kJavaScriptTrue : kJavaScriptFalse; + [string appendString:boolString]; + } else if (jsType == kJavaScriptNumber) { + NSString *numberString = + [FUtilities ieee754StringForNumber:leafNode.val]; + [string appendString:numberString]; + } else if (jsType == kJavaScriptString) { + if (hashVersion == FDataHashVersionV1) { + [string appendString:leafNode.val]; + } else { + NSAssert(hashVersion == FDataHashVersionV2, + @"Invalid hash version found"); + [FSnapshotUtilities appendHashV2RepresentationForString:leafNode.val + toString:string]; + } + } else { + [NSException raise:NSInvalidArgumentException + format:@"Unknown value for hashing: %@", leafNode]; + } +} + ++ (void)appendHashV2RepresentationForString:(NSString *)string + toString:(NSMutableString *)mutableString { + string = [string stringByReplacingOccurrencesOfString:@"\\" + withString:@"\\\\"]; + string = [string stringByReplacingOccurrencesOfString:@"\"" + withString:@"\\\""]; + [mutableString appendString:@"\""]; + [mutableString appendString:string]; + [mutableString appendString:@"\""]; +} + ++ (NSUInteger)estimateLeafNodeSize:(FLeafNode *)leafNode { + NSString *jsType = [FUtilities getJavascriptType:leafNode.val]; + // These values are somewhat arbitrary, but we don't need an exact value so + // prefer performance over exact value + NSUInteger valueSize; + if (jsType == kJavaScriptNumber) { + valueSize = 8; // estimate each float with 8 bytes + } else if (jsType == kJavaScriptBoolean) { + valueSize = 4; // true or false need roughly 4 bytes + } else if (jsType == kJavaScriptString) { + valueSize = 2 + [leafNode.val length]; // add 2 for quotes + } else { + [NSException raise:NSInvalidArgumentException + format:@"Unknown leaf type: %@", leafNode]; + return 0; + } + + if (leafNode.getPriority.isEmpty) { + return valueSize; + } else { + // Account for extra overhead due to the extra JSON object and the + // ".value" and ".priority" keys, colons, comma + NSUInteger leafPriorityOverhead = 2 + 8 + 11 + 2 + 1; + return leafPriorityOverhead + valueSize + + [FSnapshotUtilities estimateLeafNodeSize:leafNode.getPriority]; + } +} + ++ (NSUInteger)estimateSerializedNodeSize:(id)node { + if ([node isEmpty]) { + return 4; // null keyword + } else if ([node isLeafNode]) { + return [FSnapshotUtilities estimateLeafNodeSize:node]; + } else { + NSAssert([node isKindOfClass:[FChildrenNode class]], + @"Unexpected node type: %@", [node class]); + __block NSUInteger sum = 1; // opening brackets + [((FChildrenNode *)node) enumerateChildrenAndPriorityUsingBlock:^( + NSString *key, id child, + BOOL *stop) { + sum += key.length; + sum += + 4; // quotes around key and colon and (comma or closing bracket) + sum += [FSnapshotUtilities estimateSerializedNodeSize:child]; + }]; + return sum; + } +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FAtomicNumber.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FAtomicNumber.h new file mode 100644 index 0000000..b8668d2 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FAtomicNumber.h @@ -0,0 +1,23 @@ +/* + * 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 + +@interface FAtomicNumber : NSObject + +- (NSNumber *)getAndIncrement; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FAtomicNumber.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FAtomicNumber.m new file mode 100644 index 0000000..2cf54ce --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FAtomicNumber.m @@ -0,0 +1,55 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/FAtomicNumber.h" + +@interface FAtomicNumber () { + unsigned long number; +} + +@property(nonatomic, strong) NSLock *lock; + +@end + +@implementation FAtomicNumber + +@synthesize lock; + +- (id)init { + self = [super init]; + if (self) { + number = 1; + self.lock = [[NSLock alloc] init]; + } + return self; +} + +- (NSNumber *)getAndIncrement { + NSNumber *result; + + // See: + // http://developer.apple.com/library/ios/#DOCUMENTATION/Cocoa/Conceptual/Multithreading/ThreadSafety/ThreadSafety.html#//apple_ref/doc/uid/10000057i-CH8-SW14 + // to improve, etc. + + [self.lock lock]; + result = [NSNumber numberWithUnsignedLong:number]; + number = number + 1; + [self.lock unlock]; + + return result; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FEventEmitter.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FEventEmitter.h new file mode 100644 index 0000000..b4f69b9 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FEventEmitter.h @@ -0,0 +1,36 @@ +/* + * 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 "FirebaseDatabase/Sources/Api/FIRDatabaseConfig.h" +#import "FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseQuery.h" + +@interface FEventEmitter : NSObject + +- (id)initWithAllowedEvents:(NSArray *)theAllowedEvents + queue:(dispatch_queue_t)queue; + +- (id)getInitialEventForType:(NSString *)eventType; +- (void)triggerEventType:(NSString *)eventType data:(id)data; + +- (FIRDatabaseHandle)observeEventType:(NSString *)eventType + withBlock:(fbt_void_id)block; +- (void)removeObserverForEventType:(NSString *)eventType + withHandle:(FIRDatabaseHandle)handle; + +- (void)validateEventType:(NSString *)eventType; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FEventEmitter.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FEventEmitter.m new file mode 100644 index 0000000..977c06c --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FEventEmitter.m @@ -0,0 +1,161 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/FEventEmitter.h" +#import "FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h" +#import "FirebaseDatabase/Sources/Core/FRepoManager.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" + +@interface FEventListener : NSObject + +@property(nonatomic, copy) fbt_void_id userCallback; +@property(nonatomic) FIRDatabaseHandle handle; + +@end + +@implementation FEventListener + +@synthesize userCallback; +@synthesize handle; + +@end + +@interface FEventEmitter () + +@property(nonatomic, strong) NSArray *allowedEvents; +@property(nonatomic, strong) NSMutableDictionary *listeners; +@property(nonatomic, strong) dispatch_queue_t queue; + +@end + +@implementation FEventEmitter + +@synthesize allowedEvents; +@synthesize listeners; + +- (id)initWithAllowedEvents:(NSArray *)theAllowedEvents + queue:(dispatch_queue_t)queue { + if (theAllowedEvents == nil || [theAllowedEvents count] == 0) { + @throw [NSException + exceptionWithName:@"AllowedEventsValidation" + reason:@"FEventEmitters must be initialized with at " + @"least one valid event." + userInfo:nil]; + } + + self = [super init]; + + if (self) { + self.allowedEvents = [theAllowedEvents copy]; + self.listeners = [[NSMutableDictionary alloc] init]; + self.queue = queue; + } + + return self; +} + +- (id)getInitialEventForType:(NSString *)eventType { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:@"You must override getInitialEvent: " + @"when subclassing FEventEmitter" + userInfo:nil]; +} + +- (void)triggerEventType:(NSString *)eventType data:(id)data { + [self validateEventType:eventType]; + NSMutableDictionary *eventTypeListeners = + [self.listeners objectForKey:eventType]; + for (FEventListener *listener in eventTypeListeners) { + [self triggerListener:listener withData:data]; + } +} + +- (void)triggerListener:(FEventListener *)listener withData:(id)data { + // TODO, should probably get this from FRepo or something although it ends + // up being the same. (Except maybe for testing) + if (listener.userCallback) { + dispatch_async(self.queue, ^{ + listener.userCallback(data); + }); + } +} + +- (FIRDatabaseHandle)observeEventType:(NSString *)eventType + withBlock:(fbt_void_id)block { + [self validateEventType:eventType]; + + // Create listener + FEventListener *listener = [[FEventListener alloc] init]; + listener.handle = [[FUtilities LUIDGenerator] integerValue]; + listener.userCallback = block; // copies block automatically + + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self addEventListener:listener forEventType:eventType]; + }); + + return listener.handle; +} + +- (void)addEventListener:(FEventListener *)listener + forEventType:(NSString *)eventType { + // Get or initializer listeners map [FIRDatabaseHandle -> callback block] + // for eventType + NSMutableArray *eventTypeListeners = + [self.listeners objectForKey:eventType]; + if (eventTypeListeners == nil) { + eventTypeListeners = [[NSMutableArray alloc] init]; + [self.listeners setObject:eventTypeListeners forKey:eventType]; + } + + // Add listener and fire the current event for this listener + [eventTypeListeners addObject:listener]; + id initialData = [self getInitialEventForType:eventType]; + [self triggerListener:listener withData:initialData]; +} + +- (void)removeObserverForEventType:(NSString *)eventType + withHandle:(FIRDatabaseHandle)handle { + [self validateEventType:eventType]; + + dispatch_async([FIRDatabaseQuery sharedQueue], ^{ + [self removeEventListenerWithHandle:handle forEventType:eventType]; + }); +} + +- (void)removeEventListenerWithHandle:(FIRDatabaseHandle)handle + forEventType:(NSString *)eventType { + NSMutableArray *eventTypeListeners = + [self.listeners objectForKey:eventType]; + for (FEventListener *listener in [eventTypeListeners copy]) { + if (handle == NSNotFound || handle == listener.handle) { + [eventTypeListeners removeObject:listener]; + } + } +} + +- (void)validateEventType:(NSString *)eventType { + if ([self.allowedEvents indexOfObject:eventType] == NSNotFound) { + @throw [NSException + exceptionWithName:@"InvalidEventType" + reason:[NSString stringWithFormat: + @"%@ is not a valid event type. %@ " + @"is the list of valid events.", + eventType, self.allowedEvents] + userInfo:nil]; + } +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FNextPushId.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FNextPushId.h new file mode 100644 index 0000000..b085593 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FNextPushId.h @@ -0,0 +1,27 @@ +/* + * 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 + +@interface FNextPushId : NSObject + ++ (NSString *)get:(NSTimeInterval)now; + ++ (NSString *)from:(NSString *)fn successor:(NSString *)key; + ++ (NSString *)from:(NSString *)fn predecessor:(NSString *)key; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FNextPushId.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FNextPushId.m new file mode 100644 index 0000000..79398de --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FNextPushId.m @@ -0,0 +1,301 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/FNextPushId.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" +#import "FirebaseDatabase/Sources/Utilities/FValidation.h" + +static NSString *const PUSH_CHARS = + @"-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"; + +static NSString *const MIN_PUSH_CHAR = @" "; + +static NSString *const MAX_PUSH_CHAR = @"\uFFFF"; + +static NSInteger const MAX_KEY_LEN = 786; + +static unichar const LOW_SURROGATE_PAIR_START = 0xDC00; +static unichar const LOW_SURROGATE_PAIR_END = 0xDFFF; +static unichar const HIGH_SURROGATE_PAIR_START = 0xD800; +static unichar const HIGH_SURROGATE_PAIR_END = 0xDBFF; + +@implementation FNextPushId + ++ (NSString *)get:(NSTimeInterval)currentTime { + static long long lastPushTime = 0; + static int lastRandChars[12]; + + long long now = (long long)(currentTime * 1000); + + BOOL duplicateTime = now == lastPushTime; + lastPushTime = now; + + unichar timeStampChars[8]; + for (int i = 7; i >= 0; i--) { + timeStampChars[i] = [PUSH_CHARS characterAtIndex:(now % 64)]; + now = (long long)floor(now / 64); + } + + NSMutableString *id = [[NSMutableString alloc] init]; + [id appendString:[NSString stringWithCharacters:timeStampChars length:8]]; + + if (!duplicateTime) { + for (int i = 0; i < 12; i++) { + lastRandChars[i] = (int)floor(arc4random() % 64); + } + } else { + int i = 0; + for (i = 11; i >= 0 && lastRandChars[i] == 63; i--) { + lastRandChars[i] = 0; + } + lastRandChars[i]++; + } + + for (int i = 0; i < 12; i++) { + [id appendFormat:@"%C", [PUSH_CHARS characterAtIndex:lastRandChars[i]]]; + } + + return [NSString stringWithString:id]; +} + ++ (NSString *)from:(NSString *)fn successor:(NSString *_Nonnull)key { + [FValidation validateFrom:fn validKey:key]; + NSInteger keyAsInt; + if ([FUtilities tryParseString:key asInt:&keyAsInt]) { + if (keyAsInt == [FUtilities int32max]) { + return MIN_PUSH_CHAR; + } + return [NSString stringWithFormat:@"%ld", (long)keyAsInt + 1]; + } + NSMutableString *next = [NSMutableString stringWithString:key]; + if ([next length] < MAX_KEY_LEN) { + [next insertString:MIN_PUSH_CHAR atIndex:[key length]]; + return next; + } + + long i = [next length] - 1; + while (i >= 0) { + if ([next characterAtIndex:i] != [MAX_PUSH_CHAR characterAtIndex:0]) { + break; + } + --i; + } + + // `nextAfter` was called on the largest possible key, so return the + // maxName, which sorts larger than all keys. + if (i == -1) { + return [FUtilities maxName]; + } + + unichar character = [next characterAtIndex:i]; + unichar plusOne = character + 1; + BOOL removePreviousCharacter = NO; + BOOL replaceWithLowestSurrogatePair = NO; + switch (plusOne) { + case 0x23: // '#' + case 0x24: // '$' + plusOne = 0x25; + break; + + case 0x2E: // '.' + case 0x2F: // '/' + plusOne = 0x30; + break; + + case 0x5B: // '[' + plusOne = 0x5C; + break; + + case 0x5D: // ']' + plusOne = 0x5E; + break; + + case 0x7F: // control character: del + plusOne = 0x80; + break; + + case HIGH_SURROGATE_PAIR_START: // 0xD800 + // We added one to 0xD7FF and entered surrogate pair zone + // Replace with the lowest surrogate pair here + replaceWithLowestSurrogatePair = YES; + + case LOW_SURROGATE_PAIR_END + 1: // 0xE000 + // If the previous character is the highest surrogate value + // then we increment to the value 0xE000 by replacing the surrogate + // pair by the single value 0xE000 (the value of plusOne) + // Otherwise we increment the high surrogate value and set the low + // surrogate value to the lowest. + if (i == 0) { + // Error, encountered low surrogate without matching high surrogate + } else { + unichar high = [next characterAtIndex:i - 1]; + if (high == HIGH_SURROGATE_PAIR_END) { /* highest value for the high + part of the pair */ + // Replace pair with 0xE000 (the value of plusOne) + removePreviousCharacter = YES; + } else { + high += 1; + NSString *highStr = [NSString stringWithFormat:@"%C", high]; + + [next replaceCharactersInRange:NSMakeRange(i - 1, i) + withString:highStr]; + plusOne = LOW_SURROGATE_PAIR_START; /* lowest value for the low + part of the pair */ + } + } + break; + } + + NSString *sourcePlusOne = + replaceWithLowestSurrogatePair + ? [NSString stringWithFormat:@"%C%C", HIGH_SURROGATE_PAIR_START, + LOW_SURROGATE_PAIR_START] + : [NSString stringWithFormat:@"%C", plusOne]; + + NSInteger replaceLocation = i; + NSInteger replaceLength = 1; + if (removePreviousCharacter) { + --replaceLocation; + ++replaceLength; + } + + [next replaceCharactersInRange:NSMakeRange(replaceLocation, replaceLength) + withString:sourcePlusOne]; + NSInteger length = i + 1; + if (removePreviousCharacter) { + --length; + } else if (replaceWithLowestSurrogatePair) { + ++length; + } + return [next substringWithRange:NSMakeRange(0, length)]; +} + ++ (NSString *)from:(NSString *)fn predecessor:(NSString *_Nonnull)key { + [FValidation validateFrom:fn validKey:key]; + NSInteger keyAsInt; + if ([FUtilities tryParseString:key asInt:&keyAsInt]) { + if (keyAsInt == [FUtilities int32min]) { + return [FUtilities minName]; + } + return [NSString stringWithFormat:@"%ld", (long)keyAsInt - 1]; + } + NSMutableString *next = [NSMutableString stringWithString:key]; + if ([next characterAtIndex:(next.length - 1)] == + [MIN_PUSH_CHAR characterAtIndex:0]) { + if ([next length] == 1) { + return + [NSString stringWithFormat:@"%ld", (long)[FUtilities int32max]]; + } + // If the last character is the smallest possible character, then the + // next smallest string is the prefix of `key` without it. + [next replaceCharactersInRange:NSMakeRange([next length] - 1, 1) + withString:@""]; + return next; + } + // Replace the last character with its immedate predecessor, and fill the + // suffix of the key with MAX_PUSH_CHAR. This is the lexicographically + // largest possible key smaller than `key`. + NSUInteger i = next.length - 1; + unichar character = [next characterAtIndex:i]; + unichar minusOne = character - 1; + BOOL removePreviousCharacter = NO; + BOOL replaceWithHighestSurrogatePair = NO; + switch (minusOne) { + // NOTE: We already handled the case of min char (0x20) + case 0x23: // '#' + case 0x24: // '$' + minusOne = 0x22; + break; + + case 0x2E: // '.' + case 0x2F: // '/' + minusOne = 0x2D; + break; + + case 0x5B: // '[' + minusOne = 0x5A; + break; + + case 0x5D: // ']' + minusOne = 0x5C; + break; + + case 0x7F: // control character: del + minusOne = 0x7E; + break; + + case LOW_SURROGATE_PAIR_END: // 0xDFFF + // Previously we had 0xE000 which is a single utf16 character, + // this needs to be replaced with the highest surrogate pair: + replaceWithHighestSurrogatePair = YES; + break; + + case HIGH_SURROGATE_PAIR_END: // 0xDBFF + // If the previous character is the lowest high surrogate value + // then we decrement to the non-surrogate value 0xD7FF by replacing the + // surrogate pair by the single value 0xD7FF (HIGH_SURROGATE_PAIR_START + // - 1) Otherwise we decrement the high surrogate value and set the low + // surrogate value to the highest. + if (i == 0) { + // Error, found low surrogate without matching high surrogate + } else { + unichar high = [next characterAtIndex:i - 1]; + if (high == HIGH_SURROGATE_PAIR_START) { /* lowest value for the + high part of the pair */ + // Replace pair with single 0xD7FF value + removePreviousCharacter = YES; + minusOne = HIGH_SURROGATE_PAIR_START - 1; + } else { + high -= 1; + NSString *highStr = [NSString stringWithFormat:@"%C", high]; + + [next replaceCharactersInRange:NSMakeRange(i - 1, i) + withString:highStr]; + minusOne = LOW_SURROGATE_PAIR_END; /* highest value for the low + part of the pair */ + } + } + break; + } + + NSString *sourceMinusOne = + replaceWithHighestSurrogatePair + ? [NSString stringWithFormat:@"%C%C", HIGH_SURROGATE_PAIR_END, + LOW_SURROGATE_PAIR_END] + : [NSString stringWithFormat:@"%C", minusOne]; + + NSInteger replaceLocation = i; + NSInteger replaceLength = 1; + if (removePreviousCharacter) { + --replaceLocation; + ++replaceLength; + } + + [next replaceCharactersInRange:NSMakeRange(replaceLocation, replaceLength) + withString:sourceMinusOne]; + + NSInteger length = i + 1; + if (removePreviousCharacter) { + --length; + } else if (replaceWithHighestSurrogatePair) { + ++length; + } + return [next stringByPaddingToLength:MAX_KEY_LEN + withString:MAX_PUSH_CHAR + startingAtIndex:0]; +}; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FParsedUrl.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FParsedUrl.h new file mode 100644 index 0000000..413e5df --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FParsedUrl.h @@ -0,0 +1,25 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/FRepoInfo.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" + +@interface FParsedUrl : NSObject + +@property(nonatomic, strong) FRepoInfo *repoInfo; +@property(nonatomic, strong) FPath *path; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FParsedUrl.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FParsedUrl.m new file mode 100644 index 0000000..81fa02e --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FParsedUrl.m @@ -0,0 +1,24 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/FParsedUrl.h" + +@implementation FParsedUrl + +@synthesize repoInfo; +@synthesize path; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FStringUtilities.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FStringUtilities.h new file mode 100644 index 0000000..f7d19b6 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FStringUtilities.h @@ -0,0 +1,26 @@ +/* + * 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 + +@interface FStringUtilities : NSObject + ++ (NSString *)base64EncodedSha1:(NSString *)str; ++ (NSString *)urlDecoded:(NSString *)url; ++ (NSString *)urlEncoded:(NSString *)url; ++ (NSString *)sanitizedForUserAgent:(NSString *)str; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FStringUtilities.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FStringUtilities.m new file mode 100644 index 0000000..f4370f2 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FStringUtilities.m @@ -0,0 +1,72 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/FStringUtilities.h" +#import "FirebaseDatabase/Sources/third_party/SocketRocket/NSData+SRB64Additions.h" +#import + +@implementation FStringUtilities + +// http://stackoverflow.com/questions/3468268/objective-c-sha1 +// http://stackoverflow.com/questions/7310457/ios-objective-c-sha-1-and-base64-problem ++ (NSString *)base64EncodedSha1:(NSString *)str { + const char *cstr = [str cStringUsingEncoding:NSUTF8StringEncoding]; + // NSString reports length in characters, but we want it in bytes, which + // strlen will give us. + unsigned long dataLen = strlen(cstr); + NSData *data = [NSData dataWithBytes:cstr length:dataLen]; + uint8_t digest[CC_SHA1_DIGEST_LENGTH]; + CC_SHA1(data.bytes, (unsigned int)data.length, digest); + NSData *output = [[NSData alloc] initWithBytes:digest + length:CC_SHA1_DIGEST_LENGTH]; + return [FSRUtilities base64EncodedStringFromData:output]; +} + ++ (NSString *)urlDecoded:(NSString *)url { + NSString *replaced = [url stringByReplacingOccurrencesOfString:@"+" + withString:@" "]; + NSString *decoded = [replaced stringByRemovingPercentEncoding]; + // This is kind of a hack, but is generally how the js client works. We + // could run into trouble if some piece is a correctly escaped %-sequence, + // and another isn't. But, that's bad input anyways... + if (decoded) { + return decoded; + } else { + return replaced; + } +} + ++ (NSString *)urlEncoded:(NSString *)url { + // Didn't seem like there was an Apple NSCharacterSet that had our version + // of the encoding So I made my own, following RFC 2396 + // https://www.ietf.org/rfc/rfc2396.txt allowedCharacters = alphanum | "-" | + // "_" | "~" + NSCharacterSet *allowedCharacters = [NSCharacterSet + characterSetWithCharactersInString:@"abcdefghijklmnopqrstuvwxyzABCDEFGH" + @"IJKLMNOPQRSTUVWXYZ0123456789-_~"]; + return [url + stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacters]; +} + ++ (NSString *)sanitizedForUserAgent:(NSString *)str { + return + [str stringByReplacingOccurrencesOfString:@"/|_" + withString:@"|" + options:NSRegularExpressionSearch + range:NSMakeRange(0, [str length])]; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FTypedefs.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FTypedefs.h new file mode 100644 index 0000000..56d97ff --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FTypedefs.h @@ -0,0 +1,46 @@ +/* + * 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 + +#ifndef Firebase_FTypedefs_h +#define Firebase_FTypedefs_h + +/** + * Stub... + */ +@class FIRDataSnapshot; +@class FIRDatabaseReference; +@class FAuthData; +@protocol FNode; + +// fbt = Firebase Block Typedef + +typedef void (^fbt_void_void)(void); +typedef void (^fbt_void_datasnapshot_nsstring)(FIRDataSnapshot *snapshot, + NSString *prevName); +typedef void (^fbt_void_datasnapshot)(FIRDataSnapshot *snapshot); +typedef void (^fbt_void_user)(FAuthData *user); +typedef void (^fbt_void_nsstring_id)(NSString *status, id data); +typedef void (^fbt_void_nserror_id)(NSError *error, id data); +typedef void (^fbt_void_nserror)(NSError *error); +typedef void (^fbt_void_nserror_ref)(NSError *error, FIRDatabaseReference *ref); +typedef void (^fbt_void_nserror_user)(NSError *error, FAuthData *user); +typedef void (^fbt_void_nserror_json)(NSError *error, NSDictionary *json); +typedef void (^fbt_void_nsdictionary)(NSDictionary *data); +typedef id (^fbt_id_node_nsstring)(id node, NSString *childName); + +#endif diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FUtilities.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FUtilities.h new file mode 100644 index 0000000..d0718f6 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FUtilities.h @@ -0,0 +1,88 @@ +/* + * 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 "FirebaseCore/Extension/FirebaseCoreInternal.h" +#import + +#import "FirebaseDatabase/Sources/Utilities/FParsedUrl.h" + +@interface FUtilities : NSObject + ++ (NSArray *)splitString:(NSString *)str intoMaxSize:(const unsigned int)size; ++ (NSNumber *)LUIDGenerator; ++ (FParsedUrl *)parseUrl:(NSString *)url; ++ (NSString *)getJavascriptType:(id)obj; ++ (NSError *)errorForStatus:(NSString *)status andReason:(NSString *)reason; ++ (NSNumber *)intForString:(NSString *)string; ++ (NSInteger)int32min; ++ (NSInteger)int32max; ++ (NSString *)ieee754StringForNumber:(NSNumber *)val; ++ (BOOL)tryParseString:(NSString *)string asInt:(NSInteger *)integer; ++ (void)setLoggingEnabled:(BOOL)enabled; ++ (BOOL)getLoggingEnabled; + ++ (NSString *)minName; ++ (NSString *)maxName; ++ (NSComparisonResult)compareKey:(NSString *)a toKey:(NSString *)b; ++ (NSComparator)stringComparator; ++ (NSComparator)keyComparator; + ++ (double)randomDouble; + +@end + +typedef enum { + FLogLevelDebug = 1, + FLogLevelInfo = 2, + FLogLevelWarn = 3, + FLogLevelError = 4, + FLogLevelNone = 5 +} FLogLevel; + +// Log tags +FOUNDATION_EXPORT NSString *const kFPersistenceLogTag; + +#define FFLog(code, format, ...) FFDebug((code), (format), ##__VA_ARGS__) + +#define FFDebug(code, format, ...) \ + do { \ + if (FFIsLoggingEnabled(FLogLevelDebug)) { \ + FIRLogDebug(kFIRLoggerDatabase, (code), (format), ##__VA_ARGS__); \ + } \ + } while (0) + +#define FFInfo(code, format, ...) \ + do { \ + if (FFIsLoggingEnabled(FLogLevelInfo)) { \ + FIRLogError(kFIRLoggerDatabase, (code), (format), ##__VA_ARGS__); \ + } \ + } while (0) + +#define FFWarn(code, format, ...) \ + do { \ + if (FFIsLoggingEnabled(FLogLevelWarn)) { \ + FIRLogWarning(kFIRLoggerDatabase, (code), (format), \ + ##__VA_ARGS__); \ + } \ + } while (0) + +#define INTEGER_32_MIN (-2147483648) +#define INTEGER_32_MAX 2147483647 + +extern FIRLoggerService kFIRLoggerDatabase; +BOOL FFIsLoggingEnabled(FLogLevel logLevel); +void firebaseUncaughtExceptionHandler(NSException *exception); +void firebaseJobsTroll(void); diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FUtilities.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FUtilities.m new file mode 100644 index 0000000..30dedc9 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FUtilities.m @@ -0,0 +1,448 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/FUtilities.h" +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" +#import "FirebaseDatabase/Sources/Constants/FConstants.h" +#import "FirebaseDatabase/Sources/Utilities/FAtomicNumber.h" +#import "FirebaseDatabase/Sources/Utilities/FStringUtilities.h" + +#define ARC4RANDOM_MAX 0x100000000 + +#pragma mark - +#pragma mark C functions + +FIRLoggerService kFIRLoggerDatabase = @"[FirebaseDatabase]"; +static FLogLevel logLevel = FLogLevelInfo; // Default log level is info +static NSMutableDictionary *options = nil; + +BOOL FFIsLoggingEnabled(FLogLevel level) { return level >= logLevel; } + +void firebaseJobsTroll(void) { + FFLog(@"I-RDB095001", + @"password super secret; JFK conspiracy; Hello there! Having fun " + @"digging through Firebase? We're always hiring! jobs@firebase.com"); +} + +#pragma mark - +#pragma mark Private property and singleton specification + +@interface FUtilities () { +} + +@property(nonatomic, strong) FAtomicNumber *localUid; + ++ (FUtilities *)singleton; + +@end + +@implementation FUtilities + +@synthesize localUid; + +- (id)init { + self = [super init]; + if (self) { + self.localUid = [[FAtomicNumber alloc] init]; + } + return self; +} + +// TODO: We really want to be able to set the log level ++ (void)setLoggingEnabled:(BOOL)enabled { + logLevel = enabled ? FLogLevelDebug : FLogLevelInfo; +} + ++ (BOOL)getLoggingEnabled { + return logLevel == FLogLevelDebug; +} + ++ (FUtilities *)singleton { + static dispatch_once_t pred = 0; + __strong static id _sharedObject = nil; + dispatch_once(&pred, ^{ + _sharedObject = [[self alloc] init]; // or some other init method + }); + return _sharedObject; +} + +// Refactor as a category of NSString ++ (NSArray *)splitString:(NSString *)str intoMaxSize:(const unsigned int)size { + if (str.length <= size) { + return [NSArray arrayWithObject:str]; + } + + NSMutableArray *dataSegs = [[NSMutableArray alloc] init]; + for (int c = 0; c < str.length; c += size) { + if (c + size > str.length) { + int rangeStart = c; + unsigned long rangeLength = size - ((c + size) - str.length); + [dataSegs + addObject:[str substringWithRange:NSMakeRange(rangeStart, + rangeLength)]]; + } else { + int rangeStart = c; + int rangeLength = size; + [dataSegs + addObject:[str substringWithRange:NSMakeRange(rangeStart, + rangeLength)]]; + } + } + return dataSegs; +} + ++ (NSNumber *)LUIDGenerator { + FUtilities *f = [FUtilities singleton]; + return [f.localUid getAndIncrement]; +} + ++ (NSString *)decodePath:(NSString *)pathString { + NSMutableArray *decodedPieces = [[NSMutableArray alloc] init]; + NSArray *pieces = [pathString componentsSeparatedByString:@"/"]; + for (NSString *piece in pieces) { + if (piece.length > 0) { + [decodedPieces addObject:[FStringUtilities urlDecoded:piece]]; + } + } + return [NSString + stringWithFormat:@"/%@", [decodedPieces componentsJoinedByString:@"/"]]; +} + ++ (NSString *)extractPathFromUrlString:(NSString *)url { + NSString *path = url; + + NSRange schemeIndex = [path rangeOfString:@"//"]; + if (schemeIndex.location != NSNotFound) { + path = [path substringFromIndex:schemeIndex.location + 2]; + } + + NSUInteger pathIndex = [path rangeOfString:@"/"].location; + if (pathIndex != NSNotFound) { + path = [path substringFromIndex:pathIndex + 1]; + } else { + path = @""; + } + + NSUInteger queryParamIndex = [path rangeOfString:@"?"].location; + if (queryParamIndex != NSNotFound) { + path = [path substringToIndex:queryParamIndex]; + } + + return path; +} + ++ (FParsedUrl *)parseUrl:(NSString *)url { + // For backwards compatibility, support URLs without schemes on iOS. + if (![url containsString:@"://"]) { + url = [@"http://" stringByAppendingString:url]; + } + + NSString *originalPathString = [self extractPathFromUrlString:url]; + + // Sanitize the database URL by removing the path component, which may + // contain invalid URL characters. + NSRange lastMatch = [url rangeOfString:originalPathString + options:NSBackwardsSearch]; + NSString *sanitizedUrlWithoutPath = + (lastMatch.location != NSNotFound) + ? [url substringToIndex:lastMatch.location] + : url; + + NSURLComponents *urlComponents = + [NSURLComponents componentsWithString:sanitizedUrlWithoutPath]; + if (!urlComponents) { + [NSException raise:@"Failed to parse database URL" + format:@"Failed to parse database URL: %@", url]; + } + + NSString *host = [urlComponents.host lowercaseString]; + NSString *namespace; + bool secure; + + if (urlComponents.port != nil) { + secure = [urlComponents.scheme isEqualToString:@"https"] || + [urlComponents.scheme isEqualToString:@"wss"]; + host = [host stringByAppendingFormat:@":%@", urlComponents.port]; + } else { + secure = YES; + }; + + NSArray *parts = [urlComponents.host componentsSeparatedByString:@"."]; + if ([parts count] == 3) { + namespace = [parts[0] lowercaseString]; + } else { + // Attempt to extract namespace from "ns" query param. + NSArray *queryItems = urlComponents.queryItems; + for (NSURLQueryItem *item in queryItems) { + if ([item.name isEqualToString:@"ns"]) { + namespace = item.value; + break; + } + } + + if (!namespace) { + namespace = [parts[0] lowercaseString]; + } + } + + NSString *pathString = [self + decodePath:[NSString stringWithFormat:@"/%@", originalPathString]]; + FPath *path = [[FPath alloc] initWith:pathString]; + FRepoInfo *repoInfo = [[FRepoInfo alloc] initWithHost:host + isSecure:secure + withNamespace:namespace]; + + FFLog(@"I-RDB095002", @"---> Parsed (%@) to: (%@,%@); ns=(%@); path=(%@)", + url, [repoInfo description], [repoInfo connectionURL], + repoInfo.namespace, [path description]); + + FParsedUrl *parsedUrl = [[FParsedUrl alloc] init]; + parsedUrl.repoInfo = repoInfo; + parsedUrl.path = path; + + return parsedUrl; +} + +/* + case str: JString => priString + "string:" + str.s; + case bool: JBool => priString + "boolean:" + bool.value; + case double: JDouble => priString + "number:" + double.num; + case int: JInt => priString + "number:" + int.num; + case _ => { + error("Leaf node has value '" + data.value + "' of invalid type '" + + data.value.getClass.toString + "'"); + ""; + } + */ + ++ (NSString *)getJavascriptType:(id)obj { + if ([obj isKindOfClass:[NSDictionary class]]) { + return kJavaScriptObject; + } else if ([obj isKindOfClass:[NSString class]]) { + return kJavaScriptString; + } else if ([obj isKindOfClass:[NSNumber class]]) { + // We used to just compare to @encode(BOOL) as suggested at + // http://stackoverflow.com/questions/2518761/get-type-of-nsnumber, but + // on arm64, @encode(BOOL) returns "B" instead of "c" even though + // objCType still returns 'c' (signed char). So check both. + if (strcmp([obj objCType], @encode(BOOL)) == 0 || + strcmp([obj objCType], @encode(signed char)) == 0) { + return kJavaScriptBoolean; + } else { + return kJavaScriptNumber; + } + } else { + return kJavaScriptNull; + } +} + ++ (NSError *)errorForStatus:(NSString *)status andReason:(NSString *)reason { + static dispatch_once_t pred = 0; + __strong static NSDictionary *errorMap = nil; + __strong static NSDictionary *errorCodes = nil; + dispatch_once(&pred, ^{ + errorMap = @{ + @"permission_denied" : @"Permission Denied", + @"unavailable" : @"Service is unavailable", + kFErrorWriteCanceled : @"Write cancelled by user" + }; + errorCodes = @{ + @"permission_denied" : @1, + @"unavailable" : @2, + kFErrorWriteCanceled : @3 + }; + }); + + if ([status isEqualToString:kFWPResponseForActionStatusOk]) { + return nil; + } else { + NSInteger code; + NSString *desc = nil; + if (reason) { + desc = reason; + } else if ([errorMap objectForKey:status] != nil) { + desc = [errorMap objectForKey:status]; + } else { + desc = status; + } + + if ([errorCodes objectForKey:status] != nil) { + NSNumber *num = [errorCodes objectForKey:status]; + code = [num integerValue]; + } else { + // XXX what to do here? + code = 9999; + } + + return [[NSError alloc] + initWithDomain:kFErrorDomain + code:code + userInfo:@{NSLocalizedDescriptionKey : desc}]; + } +} + ++ (NSNumber *)intForString:(NSString *)string { + static dispatch_once_t once; + static NSCharacterSet *notDigits; + dispatch_once(&once, ^{ + notDigits = [[NSCharacterSet decimalDigitCharacterSet] invertedSet]; + }); + if ([string rangeOfCharacterFromSet:notDigits].length == 0) { + NSInteger num; + NSScanner *scanner = [NSScanner scannerWithString:string]; + if ([scanner scanInteger:&num]) { + return [NSNumber numberWithInteger:num]; + } + } + return nil; +} + ++ (NSInteger)int32min { + return INTEGER_32_MIN; +} + ++ (NSInteger)int32max { + return INTEGER_32_MAX; +} + ++ (NSString *)ieee754StringForNumber:(NSNumber *)val { + double d = [val doubleValue]; + NSData *data = [NSData dataWithBytes:&d length:sizeof(double)]; + NSMutableString *str = [[NSMutableString alloc] init]; + const unsigned char *buffer = (const unsigned char *)[data bytes]; + for (int i = 0; i < data.length; i++) { + unsigned char byte = buffer[7 - i]; + [str appendFormat:@"%02x", byte]; + } + return str; +} + ++ (BOOL)tryParseString:(NSString *)string asInt:(NSInteger *)integer { + return tryParseStringToInt(string, integer); +} + +static inline BOOL tryParseStringToInt(__unsafe_unretained NSString *str, + NSInteger *integer) { + // First do some cheap checks (NOTE: The below checks are significantly + // faster than an equivalent regex :-( ). + NSUInteger length = str.length; + if (length > 11 || length == 0) { + return NO; + } + long long value = 0; + BOOL negative = NO; + NSUInteger i = 0; + if ([str characterAtIndex:0] == '-') { + if (length == 1) { + return NO; + } + negative = YES; + i = 1; + } + for (; i < length; i++) { + unichar c = [str characterAtIndex:i]; + // Must be a digit, or '-' if it's the first char. + if (c < '0' || c > '9') { + return NO; + } else { + int charValue = c - '0'; + value = value * 10 + charValue; + } + } + + value = (negative) ? -value : value; + + if (value < INTEGER_32_MIN || value > INTEGER_32_MAX) { + return NO; + } else { + *integer = (NSInteger)value; + return YES; + } +} + ++ (NSString *)maxName { + static dispatch_once_t once; + static NSString *maxName; + dispatch_once(&once, ^{ + maxName = [[NSString alloc] initWithFormat:@"[MAX_NAME]"]; + }); + return maxName; +} + ++ (NSString *)minName { + static dispatch_once_t once; + static NSString *minName; + dispatch_once(&once, ^{ + minName = [[NSString alloc] initWithFormat:@"[MIN_NAME]"]; + }); + return minName; +} + ++ (NSComparisonResult)compareKey:(NSString *)a toKey:(NSString *)b { + if (a == b) { + return NSOrderedSame; + } else if (a == [FUtilities minName] || b == [FUtilities maxName]) { + return NSOrderedAscending; + } else if (b == [FUtilities minName] || a == [FUtilities maxName]) { + return NSOrderedDescending; + } else { + NSInteger aAsInt, bAsInt; + if (tryParseStringToInt(a, &aAsInt)) { + if (tryParseStringToInt(b, &bAsInt)) { + if (aAsInt > bAsInt) { + return NSOrderedDescending; + } else if (aAsInt < bAsInt) { + return NSOrderedAscending; + } else if (a.length > b.length) { + return NSOrderedDescending; + } else if (a.length < b.length) { + return NSOrderedAscending; + } else { + return NSOrderedSame; + } + } else { + return (NSComparisonResult)NSOrderedAscending; + } + } else if (tryParseStringToInt(b, &bAsInt)) { + return (NSComparisonResult)NSOrderedDescending; + } else { + // Perform literal character by character search to prevent a > b && + // b > a issues. Note that calling -(NSString + // *)decomposedStringWithCanonicalMapping also works. + return [a compare:b options:NSLiteralSearch]; + } + } +} + ++ (NSComparator)keyComparator { + return ^NSComparisonResult(__unsafe_unretained NSString *a, + __unsafe_unretained NSString *b) { + return [FUtilities compareKey:a toKey:b]; + }; +} + ++ (NSComparator)stringComparator { + return ^NSComparisonResult(__unsafe_unretained NSString *a, + __unsafe_unretained NSString *b) { + return [a compare:b]; + }; +} + ++ (double)randomDouble { + return ((double)arc4random() / ARC4RANDOM_MAX); +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FValidation.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FValidation.h new file mode 100644 index 0000000..02c98a2 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FValidation.h @@ -0,0 +1,55 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDataEventType.h" +#import "FirebaseDatabase/Sources/Utilities/FParsedUrl.h" +#import "FirebaseDatabase/Sources/Utilities/FTypedefs.h" +#import + +@interface FValidation : NSObject + ++ (void)validateFrom:(NSString *)fn writablePath:(FPath *)path; ++ (void)validateFrom:(NSString *)fn knownEventType:(FIRDataEventType)event; ++ (void)validateFrom:(NSString *)fn validPathString:(NSString *)pathString; ++ (void)validateFrom:(NSString *)fn validRootPathString:(NSString *)pathString; ++ (void)validateFrom:(NSString *)fn validKey:(NSString *)key; ++ (void)validateFrom:(NSString *)fn validURL:(FParsedUrl *)parsedUrl; + ++ (void)validateToken:(NSString *)token; + +// Functions for handling passing errors back ++ (void)handleError:(NSError *)error + withUserCallback:(fbt_void_nserror_id)userCallback; ++ (void)handleError:(NSError *)error + withSuccessCallback:(fbt_void_nserror)userCallback; + +// Functions used for validating while creating snapshots in FSnapshotUtilities ++ (BOOL)validateFrom:(NSString *)fn + isValidLeafValue:(id)value + withPath:(NSArray *)path; ++ (void)validateFrom:(NSString *)fn + validDictionaryKey:(id)keyId + withPath:(NSArray *)path; ++ (void)validateFrom:(NSString *)fn + validUpdateDictionaryKey:(id)keyId + withValue:(id)value; ++ (void)validateFrom:(NSString *)fn + isValidPriorityValue:(id)value + withPath:(NSArray *)path; ++ (BOOL)validatePriorityValue:value; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FValidation.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FValidation.m new file mode 100644 index 0000000..6e083ce --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/FValidation.m @@ -0,0 +1,461 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/FValidation.h" +#import "FirebaseDatabase/Sources/Constants/FConstants.h" +#import "FirebaseDatabase/Sources/Utilities/FParsedUrl.h" +#import "FirebaseDatabase/Sources/Utilities/FTypedefs.h" + +// Have to escape: * ? + [ ( ) { } ^ $ | \ . / +// See: +// https://developer.apple.com/library/mac/#documentation/Foundation/Reference/NSRegularExpression_Class/Reference/Reference.html + +NSString *const kInvalidPathCharacters = @"[].#$"; +NSString *const kInvalidKeyCharacters = @"[].#$/"; + +@implementation FValidation + ++ (void)validateFrom:(NSString *)fn writablePath:(FPath *)path { + if ([[path getFront] isEqualToString:kDotInfoPrefix]) { + @throw [[NSException alloc] + initWithName:@"WritablePathValidation" + reason:[NSString + stringWithFormat:@"(%@) failed to path %@: Can't " + @"modify data under %@", + fn, [path description], + kDotInfoPrefix] + userInfo:nil]; + } +} + ++ (void)validateFrom:(NSString *)fn knownEventType:(FIRDataEventType)event { + switch (event) { + case FIRDataEventTypeValue: + case FIRDataEventTypeChildAdded: + case FIRDataEventTypeChildChanged: + case FIRDataEventTypeChildMoved: + case FIRDataEventTypeChildRemoved: + return; + break; + default: + @throw [[NSException alloc] + initWithName:@"KnownEventTypeValidation" + reason:[NSString + stringWithFormat:@"(%@) Unknown event type: %d", + fn, (int)event] + userInfo:nil]; + break; + } +} + ++ (BOOL)isValidPathString:(NSString *)pathString { + static dispatch_once_t token; + static NSCharacterSet *badPathChars = nil; + dispatch_once(&token, ^{ + badPathChars = [NSCharacterSet + characterSetWithCharactersInString:kInvalidPathCharacters]; + }); + return pathString != nil && [pathString length] != 0 && + [pathString rangeOfCharacterFromSet:badPathChars].location == + NSNotFound; +} + ++ (void)validateFrom:(NSString *)fn validPathString:(NSString *)pathString { + if (![self isValidPathString:pathString]) { + @throw [[NSException alloc] + initWithName:@"InvalidPathValidation" + reason:[NSString stringWithFormat: + @"(%@) Must be a non-empty string and " + @"not contain '.' '#' '$' '[' or ']'", + fn] + userInfo:nil]; + } +} + ++ (void)validateFrom:(NSString *)fn validRootPathString:(NSString *)pathString { + static dispatch_once_t token; + static NSRegularExpression *dotInfoRegex = nil; + dispatch_once(&token, ^{ + dotInfoRegex = [NSRegularExpression + regularExpressionWithPattern:@"^\\/*\\.info(\\/|$)" + options:0 + error:nil]; + }); + + NSString *tempPath = pathString; + // HACK: Obj-C regex are kinda' slow. Do a plain string search first before + // bothering with the regex. + if ([pathString rangeOfString:@".info"].location != NSNotFound) { + tempPath = [dotInfoRegex + stringByReplacingMatchesInString:pathString + options:0 + range:NSMakeRange(0, pathString.length) + withTemplate:@"/"]; + } + [self validateFrom:fn validPathString:tempPath]; +} + ++ (BOOL)isValidKey:(NSString *)key { + static dispatch_once_t token; + static NSCharacterSet *badKeyChars = nil; + dispatch_once(&token, ^{ + badKeyChars = [NSCharacterSet + characterSetWithCharactersInString:kInvalidKeyCharacters]; + }); + return key != nil && key.length > 0 && + [key rangeOfCharacterFromSet:badKeyChars].location == NSNotFound; +} + ++ (void)validateFrom:(NSString *)fn validKey:(NSString *)key { + if (![self isValidKey:key]) { + @throw [[NSException alloc] + initWithName:@"InvalidKeyValidation" + reason:[NSString + stringWithFormat: + @"(%@) Must be a non-empty string and not " + @"contain '/' '.' '#' '$' '[' or ']'", + fn] + userInfo:nil]; + } +} + ++ (void)validateFrom:(NSString *)fn validURL:(FParsedUrl *)parsedUrl { + NSString *pathString = [parsedUrl.path description]; + [self validateFrom:fn validRootPathString:pathString]; +} + +#pragma mark - +#pragma mark Authentication validation + ++ (BOOL)stringNonempty:(NSString *)str { + return str != nil && ![str isKindOfClass:[NSNull class]] && str.length > 0; +} + ++ (void)validateToken:(NSString *)token { + if (![FValidation stringNonempty:token]) { + [NSException raise:NSInvalidArgumentException + format:@"Can't have empty string or nil for custom token"]; + } +} + +#pragma mark - +#pragma mark Handling authentication errors + +/** + * This function immediately calls the callback. + * It assumes that it is not on FirebaseWorker thread. + * It assumes it's on a user-controlled thread. + */ ++ (void)handleError:(NSError *)error + withUserCallback:(fbt_void_nserror_id)userCallback { + if (userCallback) { + userCallback(error, nil); + } +} + +/** + * This function immediately calls the callback. + * It assumes that it is not on FirebaseWorker thread. + * It assumes it's on a user-controlled thread. + */ ++ (void)handleError:(NSError *)error + withSuccessCallback:(fbt_void_nserror)userCallback { + if (userCallback) { + userCallback(error); + } +} + +#pragma mark - +#pragma mark Snapshot validation + ++ (BOOL)validateFrom:(NSString *)fn + isValidLeafValue:(id)value + withPath:(NSArray *)path { + if ([value isKindOfClass:[NSString class]]) { + // Try to avoid conversion to bytes if possible + NSString *theString = value; + if ([theString maximumLengthOfBytesUsingEncoding:NSUTF8StringEncoding] > + kFirebaseMaxLeafSize && + [theString lengthOfBytesUsingEncoding:NSUTF8StringEncoding] > + kFirebaseMaxLeafSize) { + NSRange range; + range.location = 0; + range.length = MIN(path.count, 50); + NSString *pathString = + [[path subarrayWithRange:range] componentsJoinedByString:@"."]; + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString + stringWithFormat:@"(%@) String exceeds max " + @"size of %u utf8 bytes: %@", + fn, (int)kFirebaseMaxLeafSize, + pathString] + userInfo:nil]; + } + return YES; + } + + else if ([value isKindOfClass:[NSNumber class]]) { + // Cannot store NaN, but otherwise can store NSNumbers. + if ([[NSDecimalNumber notANumber] isEqualToNumber:value]) { + NSRange range; + range.location = 0; + range.length = MIN(path.count, 50); + NSString *pathString = + [[path subarrayWithRange:range] componentsJoinedByString:@"."]; + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString + stringWithFormat: + @"(%@) Cannot store NaN at path: %@.", fn, + pathString] + userInfo:nil]; + } + return YES; + } + + else if ([value isKindOfClass:[NSDictionary class]]) { + NSDictionary *dval = value; + if (dval[kServerValueSubKey] != nil) { + if ([dval count] > 1) { + NSRange range; + range.location = 0; + range.length = MIN(path.count, 50); + NSString *pathString = [[path subarrayWithRange:range] + componentsJoinedByString:@"."]; + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString stringWithFormat: + @"(%@) Cannot store other keys " + @"with server value keys.%@.", + fn, pathString] + userInfo:nil]; + } + return YES; + } + return NO; + } + + else if (value == [NSNull null] || value == nil) { + // Null is valid type to store at leaf + return YES; + } + + return NO; +} + ++ (NSString *)parseAndValidateKey:(id)keyId + fromFunction:(NSString *)fn + path:(NSArray *)path { + if (![keyId isKindOfClass:[NSString class]]) { + NSRange range; + range.location = 0; + range.length = MIN(path.count, 50); + NSString *pathString = + [[path subarrayWithRange:range] componentsJoinedByString:@"."]; + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString + stringWithFormat:@"(%@) Non-string keys are not " + @"allowed in object at path: %@", + fn, pathString] + userInfo:nil]; + } + return (NSString *)keyId; +} + ++ (void)validateFrom:(NSString *)fn + validDictionaryKey:(id)keyId + withPath:(NSArray *)path { + NSString *key = [self parseAndValidateKey:keyId fromFunction:fn path:path]; + if (![key isEqualToString:kPayloadPriority] && + ![key isEqualToString:kPayloadValue] && + ![key isEqualToString:kServerValueSubKey] && + ![FValidation isValidKey:key]) { + NSRange range; + range.location = 0; + range.length = MIN(path.count, 50); + NSString *pathString = + [[path subarrayWithRange:range] componentsJoinedByString:@"."]; + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString stringWithFormat: + @"(%@) Invalid key in object at path: " + @"%@. Keys must be non-empty and cannot " + @"contain '/' '.' '#' '$' '[' or ']'", + fn, pathString] + userInfo:nil]; + } +} + ++ (void)validateFrom:(NSString *)fn + validUpdateDictionaryKey:(id)keyId + withValue:(id)value { + FPath *path = [FPath pathWithString:[self parseAndValidateKey:keyId + fromFunction:fn + path:@[]]]; + __block NSInteger keyNum = 0; + [path enumerateComponentsUsingBlock:^void(NSString *key, BOOL *stop) { + if ([key isEqualToString:kPayloadPriority] && + keyNum == [path length] - 1) { + [self validateFrom:fn isValidPriorityValue:value withPath:@[]]; + } else { + keyNum++; + + if (![FValidation isValidKey:key]) { + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString + stringWithFormat: + @"(%@) Invalid key in object. Keys must " + @"be non-empty and cannot contain '.' " + @"'#' '$' '[' or ']'", + fn] + userInfo:nil]; + } + } + }]; +} + ++ (void)validateFrom:(NSString *)fn + isValidPriorityValue:(id)value + withPath:(NSArray *)path { + [self validateFrom:fn + isValidPriorityValue:value + withPath:path + throwError:YES]; +} + +/** + * Returns YES if priority is valid. + */ ++ (BOOL)validatePriorityValue:value { + return [self validateFrom:nil + isValidPriorityValue:value + withPath:nil + throwError:NO]; +} + +/** + * Helper for validating priorities. If passed YES for throwError, it'll throw + * descriptive errors on validation problems. Else, it'll just return YES/NO. + */ ++ (BOOL)validateFrom:(NSString *)fn + isValidPriorityValue:(id)value + withPath:(NSArray *)path + throwError:(BOOL)throwError { + if ([value isKindOfClass:[NSNumber class]]) { + if ([[NSDecimalNumber notANumber] isEqualToNumber:value]) { + if (throwError) { + NSRange range; + range.location = 0; + range.length = MIN(path.count, 50); + NSString *pathString = [[path subarrayWithRange:range] + componentsJoinedByString:@"."]; + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString stringWithFormat: + @"(%@) Cannot store NaN as " + @"priority at path: %@.", + fn, pathString] + userInfo:nil]; + } else { + return NO; + } + } else if (value == (id)kCFBooleanFalse || + value == (id)kCFBooleanTrue) { + if (throwError) { + NSRange range; + range.location = 0; + range.length = MIN(path.count, 50); + NSString *pathString = [[path subarrayWithRange:range] + componentsJoinedByString:@"."]; + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString stringWithFormat: + @"(%@) Cannot store true/false " + @"as priority at path: %@.", + fn, pathString] + userInfo:nil]; + } else { + return NO; + } + } + } else if ([value isKindOfClass:[NSDictionary class]]) { + NSDictionary *dval = value; + if (dval[kServerValueSubKey] != nil) { + if ([dval count] > 1) { + if (throwError) { + NSRange range; + range.location = 0; + range.length = MIN(path.count, 50); + NSString *pathString = [[path subarrayWithRange:range] + componentsJoinedByString:@"."]; + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString + stringWithFormat: + @"(%@) Cannot store other keys " + @"with server value keys as " + @"priority at path: %@.", + fn, pathString] + userInfo:nil]; + } else { + return NO; + } + } + } else { + if (throwError) { + NSRange range; + range.location = 0; + range.length = MIN(path.count, 50); + NSString *pathString = [[path subarrayWithRange:range] + componentsJoinedByString:@"."]; + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString + stringWithFormat: + @"(%@) Cannot store an NSDictionary " + @"as priority at path: %@.", + fn, pathString] + userInfo:nil]; + } else { + return NO; + } + } + } else if ([value isKindOfClass:[NSArray class]]) { + if (throwError) { + NSRange range; + range.location = 0; + range.length = MIN(path.count, 50); + NSString *pathString = + [[path subarrayWithRange:range] componentsJoinedByString:@"."]; + @throw [[NSException alloc] + initWithName:@"InvalidFirebaseData" + reason:[NSString stringWithFormat: + @"(%@) Cannot store an NSArray as " + @"priority at path: %@.", + fn, pathString] + userInfo:nil]; + } else { + return NO; + } + } + + // It's valid! + return YES; +} +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleBoolBlock.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleBoolBlock.h new file mode 100644 index 0000000..12714c7 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleBoolBlock.h @@ -0,0 +1,25 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/FTypedefs.h" +#import + +@interface FTupleBoolBlock : NSObject + +@property(nonatomic, readwrite) BOOL boolean; +@property(nonatomic, copy) fbt_void_void block; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleBoolBlock.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleBoolBlock.m new file mode 100644 index 0000000..0e6e9a1 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleBoolBlock.m @@ -0,0 +1,24 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/Tuples/FTupleBoolBlock.h" + +@implementation FTupleBoolBlock + +@synthesize boolean; +@synthesize block; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleCallbackStatus.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleCallbackStatus.h new file mode 100644 index 0000000..7c4cc6c --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleCallbackStatus.h @@ -0,0 +1,24 @@ +/* + * 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 "FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h" +#import + +@interface FTupleCallbackStatus : NSObject +@property(nonatomic, copy) fbt_void_nsstring_nsstring block; +@property(nonatomic) NSString *status; +@property(nonatomic) NSString *errorReason; +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleCallbackStatus.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleCallbackStatus.m new file mode 100644 index 0000000..fee5871 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleCallbackStatus.m @@ -0,0 +1,22 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/Tuples/FTupleCallbackStatus.h" + +@implementation FTupleCallbackStatus +@synthesize block; +@synthesize status; +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleFirebase.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleFirebase.h new file mode 100644 index 0000000..1fad277 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleFirebase.h @@ -0,0 +1,26 @@ +/* + * 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 "FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseReference.h" +#import + +@interface FTupleFirebase : NSObject + +@property(nonatomic, strong) FIRDatabaseReference *one; +@property(nonatomic, strong) FIRDatabaseReference *two; +@property(nonatomic, strong) FIRDatabaseReference *three; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleFirebase.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleFirebase.m new file mode 100644 index 0000000..8060eb3 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleFirebase.m @@ -0,0 +1,25 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/Tuples/FTupleFirebase.h" + +@implementation FTupleFirebase + +@synthesize one; +@synthesize two; +@synthesize three; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleNodePath.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleNodePath.h new file mode 100644 index 0000000..f0a6fb7 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleNodePath.h @@ -0,0 +1,28 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Snapshot/FNode.h" +#import + +@interface FTupleNodePath : NSObject + +@property(nonatomic, strong) FPath *path; +@property(nonatomic, strong) id node; + +- (id)initWithNode:(id)aNode andPath:(FPath *)aPath; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleNodePath.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleNodePath.m new file mode 100644 index 0000000..d4e812b --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleNodePath.m @@ -0,0 +1,33 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/Tuples/FTupleNodePath.h" + +@implementation FTupleNodePath + +@synthesize path; +@synthesize node; + +- (id)initWithNode:(id)aNode andPath:(FPath *)aPath { + self = [super init]; + if (self) { + self.path = aPath; + self.node = aNode; + } + return self; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjectNode.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjectNode.h new file mode 100644 index 0000000..79d769b --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjectNode.h @@ -0,0 +1,27 @@ +/* + * 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 "FirebaseDatabase/Sources/Snapshot/FNode.h" +#import + +@interface FTupleObjectNode : NSObject + +- (id)initWithObject:(id)aObj andNode:(id)aNode; + +@property(nonatomic, strong) id node; +@property(nonatomic, strong) id obj; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjectNode.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjectNode.m new file mode 100644 index 0000000..0cb7226 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjectNode.m @@ -0,0 +1,32 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjectNode.h" + +@implementation FTupleObjectNode + +@synthesize obj; +@synthesize node; + +- (id)initWithObject:(id)aObj andNode:(id)aNode { + self = [super init]; + if (self) { + self.obj = aObj; + self.node = aNode; + } + return self; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjects.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjects.h new file mode 100644 index 0000000..05b3141 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjects.h @@ -0,0 +1,24 @@ +/* + * 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 + +@interface FTupleObjects : NSObject + +@property(nonatomic, strong) id objA; +@property(nonatomic, strong) id objB; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjects.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjects.m new file mode 100644 index 0000000..bb98eb2 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjects.m @@ -0,0 +1,24 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjects.h" + +@implementation FTupleObjects + +@synthesize objA; +@synthesize objB; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleOnDisconnect.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleOnDisconnect.h new file mode 100644 index 0000000..4f4ee05 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleOnDisconnect.h @@ -0,0 +1,27 @@ +/* + * 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 "FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h" +#import + +@interface FTupleOnDisconnect : NSObject + +@property(strong, nonatomic) NSString *pathString; +@property(strong, nonatomic) NSString *action; +@property(strong, nonatomic) id data; +@property(strong, nonatomic) fbt_void_nsstring_nsstring onComplete; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleOnDisconnect.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleOnDisconnect.m new file mode 100644 index 0000000..bb36fd4 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleOnDisconnect.m @@ -0,0 +1,26 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/Tuples/FTupleOnDisconnect.h" + +@implementation FTupleOnDisconnect + +@synthesize pathString; +@synthesize action; +@synthesize data; +@synthesize onComplete; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTuplePathValue.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTuplePathValue.h new file mode 100644 index 0000000..b0a515c --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTuplePathValue.h @@ -0,0 +1,25 @@ +/* + * 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 + +@class FPath; + +@interface FTuplePathValue : NSObject +@property(nonatomic, strong, readonly) FPath *path; +@property(nonatomic, strong, readonly) id value; +- (id)initWithPath:(FPath *)aPath value:(id)aValue; +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTuplePathValue.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTuplePathValue.m new file mode 100644 index 0000000..fbe18c1 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTuplePathValue.m @@ -0,0 +1,38 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/Tuples/FTuplePathValue.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" + +@interface FTuplePathValue () +@property(nonatomic, strong, readwrite) id value; +@property(nonatomic, strong, readwrite) FPath *path; +@end + +@implementation FTuplePathValue +@synthesize path; +@synthesize value; + +- (id)initWithPath:(FPath *)aPath value:(id)aValue { + self = [super init]; + if (self) { + self.value = aValue; + self.path = aPath; + } + return self; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleRemovedQueriesEvents.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleRemovedQueriesEvents.h new file mode 100644 index 0000000..7269c2f --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleRemovedQueriesEvents.h @@ -0,0 +1,30 @@ +/* + * 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 + +@interface FTupleRemovedQueriesEvents : NSObject +/** + * `FIRDatabaseQuery`s removed with [SyncPoint removeEventRegistration:] + */ +@property(nonatomic, strong, readonly) NSArray *removedQueries; +/** + * cancel events as FEvent + */ +@property(nonatomic, strong, readonly) NSArray *cancelEvents; + +- (id)initWithRemovedQueries:(NSArray *)removed cancelEvents:(NSArray *)events; +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleRemovedQueriesEvents.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleRemovedQueriesEvents.m new file mode 100644 index 0000000..786f0cb --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleRemovedQueriesEvents.m @@ -0,0 +1,37 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/Tuples/FTupleRemovedQueriesEvents.h" + +@interface FTupleRemovedQueriesEvents () +@property(nonatomic, strong, readwrite) NSArray *removedQueries; +@property(nonatomic, strong, readwrite) NSArray *cancelEvents; +@end + +@implementation FTupleRemovedQueriesEvents +@synthesize removedQueries; +@synthesize cancelEvents; + +- (id)initWithRemovedQueries:(NSArray *)removed cancelEvents:(NSArray *)events { + self = [super init]; + if (self) { + self.removedQueries = removed; + self.cancelEvents = events; + } + return self; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleSetIdPath.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleSetIdPath.h new file mode 100644 index 0000000..d80730b --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleSetIdPath.h @@ -0,0 +1,27 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import + +@interface FTupleSetIdPath : NSObject + +- (id)initWithSetId:(NSNumber *)aSetId andPath:(FPath *)aPath; + +@property(strong, nonatomic) NSNumber *setId; +@property(strong, nonatomic) FPath *path; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleSetIdPath.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleSetIdPath.m new file mode 100644 index 0000000..1213aaf --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleSetIdPath.m @@ -0,0 +1,33 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/Tuples/FTupleSetIdPath.h" + +@implementation FTupleSetIdPath + +@synthesize path; +@synthesize setId; + +- (id)initWithSetId:(NSNumber *)aSetId andPath:(FPath *)aPath { + self = [super init]; + if (self) { + self.setId = aSetId; + self.path = aPath; + } + return self; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleStringNode.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleStringNode.h new file mode 100644 index 0000000..0873982 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleStringNode.h @@ -0,0 +1,27 @@ +/* + * 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 "FirebaseDatabase/Sources/Snapshot/FNode.h" +#import + +@interface FTupleStringNode : NSObject + +- (id)initWithString:(NSString *)aString andNode:(id)aNode; + +@property(nonatomic, strong) id node; +@property(nonatomic, strong) NSString *string; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleStringNode.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleStringNode.m new file mode 100644 index 0000000..baf1629 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleStringNode.m @@ -0,0 +1,33 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/Tuples/FTupleStringNode.h" + +@implementation FTupleStringNode + +@synthesize string; +@synthesize node; + +- (id)initWithString:(NSString *)aString andNode:(id)aNode { + self = [super init]; + if (self) { + self.string = aString; + self.node = aNode; + } + return self; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleTSN.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleTSN.h new file mode 100644 index 0000000..e3cc372 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleTSN.h @@ -0,0 +1,25 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/Tuples/FTupleStringNode.h" +#import + +@interface FTupleTSN : NSObject + +@property(nonatomic, strong) FTupleStringNode *from; +@property(nonatomic, strong) FTupleStringNode *to; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleTSN.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleTSN.m new file mode 100644 index 0000000..fd4fb32 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleTSN.m @@ -0,0 +1,24 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/Tuples/FTupleTSN.h" + +@implementation FTupleTSN + +@synthesize from; +@synthesize to; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleTransaction.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleTransaction.h new file mode 100644 index 0000000..16ae42e --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleTransaction.h @@ -0,0 +1,75 @@ +/* + * 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 "FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h" +#import "FirebaseDatabase/Sources/Core/Utilities/FPath.h" +#import "FirebaseDatabase/Sources/Utilities/FTypedefs.h" +#import + +@interface FTupleTransaction : NSObject + +@property(nonatomic, strong) FPath *path; +@property(nonatomic, copy) fbt_transactionresult_mutabledata update; +@property(nonatomic, copy) fbt_void_nserror_bool_datasnapshot onComplete; +@property(nonatomic) FTransactionStatus status; + +/** + * Used when combining transaction at different locations to figure out which + * one goes first. + */ +@property(nonatomic, strong) NSNumber *order; +/** + * Whether to raise local events for this transaction + */ +@property(nonatomic) BOOL applyLocally; + +/** + * Count how many times we've retried the transaction + */ +@property(nonatomic) int retryCount; + +/** + * Function to call to clean up our listener + */ +@property(nonatomic, copy) fbt_void_void unwatcher; + +/** + * Stores why a transaction was aborted + */ +@property(nonatomic, strong, readonly) NSString *abortStatus; +@property(nonatomic, strong, readonly) NSString *abortReason; + +- (void)setAbortStatus:(NSString *)abortStatus reason:(NSString *)reason; +- (NSError *)abortError; + +@property(nonatomic, strong) NSNumber *currentWriteId; + +/** + * Stores the input snapshot, before the update + */ +@property(nonatomic, strong) id currentInputSnapshot; + +/** + * Stores the unresolved (for server values) output snapshot, after the update + */ +@property(nonatomic, strong) id currentOutputSnapshotRaw; + +/** + * Stores the resolved (for server values) output snapshot, after the update + */ +@property(nonatomic, strong) id currentOutputSnapshotResolved; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleTransaction.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleTransaction.m new file mode 100644 index 0000000..829912b --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleTransaction.m @@ -0,0 +1,41 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/Tuples/FTupleTransaction.h" +#import "FirebaseDatabase/Sources/Utilities/FUtilities.h" + +@interface FTupleTransaction () + +@property(nonatomic, strong) NSString *abortStatus; +@property(nonatomic, strong) NSString *abortReason; + +@end + +@implementation FTupleTransaction + +- (void)setAbortStatus:(NSString *)abortStatus reason:(NSString *)reason { + self.abortStatus = abortStatus; + self.abortReason = reason; +} + +- (NSError *)abortError { + return (self.abortStatus != nil) + ? [FUtilities errorForStatus:self.abortStatus + andReason:self.abortReason] + : nil; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleUserCallback.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleUserCallback.h new file mode 100644 index 0000000..a14ab33 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleUserCallback.h @@ -0,0 +1,32 @@ +/* + * 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 "FirebaseDatabase/Sources/Core/FQueryParams.h" +#import "FirebaseDatabase/Sources/Utilities/FTypedefs.h" +#import + +@interface FTupleUserCallback : NSObject + +- (id)initWithHandle:(NSUInteger)handle; + +@property(nonatomic, copy) + fbt_void_datasnapshot_nsstring datasnapshotPrevnameCallback; +@property(nonatomic, copy) fbt_void_datasnapshot datasnapshotCallback; +@property(nonatomic, copy) fbt_void_nserror cancelCallback; +@property(nonatomic, copy) FQueryParams *queryParams; +@property(nonatomic) NSUInteger handle; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleUserCallback.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleUserCallback.m new file mode 100644 index 0000000..43e2fdf --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/Utilities/Tuples/FTupleUserCallback.m @@ -0,0 +1,35 @@ +/* + * 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 "FirebaseDatabase/Sources/Utilities/Tuples/FTupleUserCallback.h" + +@implementation FTupleUserCallback + +@synthesize datasnapshotCallback; +@synthesize datasnapshotPrevnameCallback; +@synthesize cancelCallback; +@synthesize queryParams; +@synthesize handle; + +- (id)initWithHandle:(NSUInteger)theHandle { + self = [super init]; + if (self) { + self.handle = theHandle; + } + return self; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FArraySortedDictionary.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FArraySortedDictionary.h new file mode 100644 index 0000000..6354caf --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FArraySortedDictionary.h @@ -0,0 +1,21 @@ +#import +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedDictionary.h" + +/** + * This is an array backed implementation of FImmutableSortedDictionary. It uses arrays and linear lookups to achieve + * good memory efficiency while maintaining good performance for small collections. It also uses less allocations than + * a comparable red black tree. To avoid degrading performance with increasing collection size it will automatically + * convert to a FTreeSortedDictionary after an insert call above a certain threshold. + */ +@interface FArraySortedDictionary : FImmutableSortedDictionary + ++ (FArraySortedDictionary *)fromDictionary:(NSDictionary *)dictionary withComparator:(NSComparator)comparator; + +- (id)initWithComparator:(NSComparator)comparator; + +#pragma mark - +#pragma mark Properties + +@property (nonatomic, copy, readonly) NSComparator comparator; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FArraySortedDictionary.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FArraySortedDictionary.m new file mode 100644 index 0000000..fead532 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FArraySortedDictionary.m @@ -0,0 +1,266 @@ +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FArraySortedDictionary.h" +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionary.h" + +@interface FArraySortedDictionaryEnumerator : NSEnumerator + +- (id)initWithKeys:(NSArray *)keys startPos:(NSInteger)pos isReverse:(BOOL)reverse; +- (id)nextObject; + +@property (nonatomic) NSInteger pos; +@property (nonatomic) BOOL reverse; +@property (nonatomic, strong) NSArray *keys; + +@end + +@implementation FArraySortedDictionaryEnumerator + +- (id)initWithKeys:(NSArray *)keys startPos:(NSInteger)pos isReverse:(BOOL)reverse +{ + self = [super init]; + if (self != nil) { + self->_pos = pos; + self->_reverse = reverse; + self->_keys = keys; + } + return self; +} + +- (id)nextObject +{ + NSInteger pos = self->_pos; + if (pos >= 0 && pos < self.keys.count) { + if (self.reverse) { + self->_pos--; + } else { + self->_pos++; + } + return self.keys[pos]; + } else { + return nil; + } +} + +@end + +@interface FArraySortedDictionary () + +- (id)initWithComparator:(NSComparator)comparator; + +@property (nonatomic, copy, readwrite) NSComparator comparator; +@property (nonatomic, strong) NSArray *keys; +@property (nonatomic, strong) NSArray *values; + +@end + +@implementation FArraySortedDictionary + ++ (FArraySortedDictionary *)fromDictionary:(NSDictionary *)dictionary withComparator:(NSComparator)comparator +{ + NSMutableArray *keys = [NSMutableArray arrayWithCapacity:dictionary.count]; + [dictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + [keys addObject:key]; + }]; + [keys sortUsingComparator:comparator]; + + [keys enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + if (idx > 0) { + if (comparator(keys[idx - 1], obj) != NSOrderedAscending) { + [NSException raise:NSInvalidArgumentException format:@"Can't create FImmutableSortedDictionary with keys with same ordering!"]; + } + } + }]; + + NSMutableArray *values = [NSMutableArray arrayWithCapacity:keys.count]; + NSInteger pos = 0; + for (id key in keys) { + values[pos++] = dictionary[key]; + } + NSAssert(values.count == keys.count, @"We added as many keys as values"); + return [[FArraySortedDictionary alloc] initWithComparator:comparator keys:keys values:values]; +} + +- (id)initWithComparator:(NSComparator)comparator +{ + self = [super init]; + if (self != nil) { + self->_comparator = comparator; + self->_keys = [NSArray array]; + self->_values = [NSArray array]; + } + return self; +} + +- (id)initWithComparator:(NSComparator)comparator keys:(NSArray *)keys values:(NSArray *)values +{ + self = [super init]; + if (self != nil) { + self->_comparator = comparator; + self->_keys = keys; + self->_values = values; + } + return self; +} + +- (NSInteger) findInsertPositionForKey:(id)key +{ + NSInteger newPos = 0; + while (newPos < self.keys.count && self.comparator(self.keys[newPos], key) < NSOrderedSame) { + newPos++; + } + return newPos; +} + +- (NSInteger) findKey:(id)key +{ + if (key == nil) { + return NSNotFound; + } + for (NSInteger pos = 0; pos < self.keys.count; pos++) { + NSComparisonResult result = self.comparator(key, self.keys[pos]); + if (result == NSOrderedSame) { + return pos; + } else if (result == NSOrderedAscending) { + return NSNotFound; + } + } + return NSNotFound; +} + +- (FImmutableSortedDictionary *) insertKey:(id)key withValue:(id)value +{ + NSInteger pos = [self findKey:key]; + + if (pos == NSNotFound) { + /* + * If we're above the threshold we want to convert it to a tree backed implementation to not have + * degrading performance + */ + if (self.count >= SORTED_DICTIONARY_ARRAY_TO_RB_TREE_SIZE_THRESHOLD) { + NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:self.count]; + for (NSInteger i = 0; i < self.keys.count; i++) { + dict[self.keys[i]] = self.values[i]; + } + dict[key] = value; + return [FTreeSortedDictionary fromDictionary:dict withComparator:self.comparator]; + } else { + NSMutableArray *newKeys = [NSMutableArray arrayWithArray:self.keys]; + NSMutableArray *newValues = [NSMutableArray arrayWithArray:self.values]; + NSInteger newPos = [self findInsertPositionForKey:key]; + [newKeys insertObject:key atIndex:newPos]; + [newValues insertObject:value atIndex:newPos]; + return [[FArraySortedDictionary alloc] initWithComparator:self.comparator keys:newKeys values:newValues]; + } + } else { + NSMutableArray *newKeys = [NSMutableArray arrayWithArray:self.keys]; + NSMutableArray *newValues = [NSMutableArray arrayWithArray:self.values]; + newKeys[pos] = key; + newValues[pos] = value; + return [[FArraySortedDictionary alloc] initWithComparator:self.comparator keys:newKeys values:newValues]; + } +} + +- (FImmutableSortedDictionary *) removeKey:(id)key +{ + NSInteger pos = [self findKey:key]; + if (pos == NSNotFound) { + return self; + } else { + NSMutableArray *newKeys = [NSMutableArray arrayWithArray:self.keys]; + NSMutableArray *newValues = [NSMutableArray arrayWithArray:self.values]; + [newKeys removeObjectAtIndex:pos]; + [newValues removeObjectAtIndex:pos]; + return [[FArraySortedDictionary alloc] initWithComparator:self.comparator keys:newKeys values:newValues]; + } +} + +- (id) get:(id)key +{ + NSInteger pos = [self findKey:key]; + if (pos == NSNotFound) { + return nil; + } else { + return self.values[pos]; + } +} + +- (id) getPredecessorKey:(id) key { + NSInteger pos = [self findKey:key]; + if (pos == NSNotFound) { + [NSException raise:NSInternalInconsistencyException format:@"Can't get predecessor key for non-existent key"]; + return nil; + } else if (pos == 0) { + return nil; + } else { + return self.keys[pos - 1]; + } +} + +- (BOOL) isEmpty { + return self.keys.count == 0; +} + +- (int) count +{ + return (int)self.keys.count; +} + +- (id) minKey +{ + return [self.keys firstObject]; +} + +- (id) maxKey +{ + return [self.keys lastObject]; +} + +- (void) enumerateKeysAndObjectsUsingBlock:(void (^)(id, id, BOOL *))block +{ + [self enumerateKeysAndObjectsReverse:NO usingBlock:block]; +} + +- (void) enumerateKeysAndObjectsReverse:(BOOL)reverse usingBlock:(void (^)(id, id, BOOL *))block +{ + if (reverse) { + BOOL stop = NO; + for (NSInteger i = self.keys.count - 1; i >= 0; i--) { + block(self.keys[i], self.values[i], &stop); + if (stop) return; + } + } else { + BOOL stop = NO; + for (NSInteger i = 0; i < self.keys.count; i++) { + block(self.keys[i], self.values[i], &stop); + if (stop) return; + } + } +} + +- (BOOL) contains:(id)key { + return [self findKey:key] != NSNotFound; +} + +- (NSEnumerator *) keyEnumerator { + return [self.keys objectEnumerator]; +} + +- (NSEnumerator *) keyEnumeratorFrom:(id)startKey { + NSInteger startPos = [self findInsertPositionForKey:startKey]; + return [[FArraySortedDictionaryEnumerator alloc] initWithKeys:self.keys startPos:startPos isReverse:NO]; +} + +- (NSEnumerator *) reverseKeyEnumerator { + return [self.keys reverseObjectEnumerator]; +} + +- (NSEnumerator *) reverseKeyEnumeratorFrom:(id)startKey { + NSInteger startPos = [self findInsertPositionForKey:startKey]; + // if there's no exact match, findKeyOrInsertPosition will return the index *after* the closest match, but + // since this is a reverse iterator, we want to start just *before* the closest match. + if (startPos >= self.keys.count || self.comparator(self.keys[startPos], startKey) != NSOrderedSame) { + startPos -= 1; + } + return [[FArraySortedDictionaryEnumerator alloc] initWithKeys:self.keys startPos:startPos isReverse:YES]; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedDictionary.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedDictionary.h new file mode 100644 index 0000000..d6687d8 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedDictionary.h @@ -0,0 +1,54 @@ +/** + * @fileoverview Implementation of an immutable SortedMap using a Left-leaning + * Red-Black Tree, adapted from the implementation in Mugs + * (http://mads379.github.com/mugs/) by Mads Hartmann Jensen + * (mads379@gmail.com). + * + * Original paper on Left-leaning Red-Black Trees: + * http://www.cs.princeton.edu/~rs/talks/LLRB/LLRB.pdf + * + * Invariant 1: No red node has a red child + * Invariant 2: Every leaf path has the same number of black nodes + * Invariant 3: Only the left child can be red (left leaning) + */ + +#import + +/** + * The size threshold where we use a tree backed sorted map instead of an array backed sorted map. + * This is a more or less arbitrary chosen value, that was chosen to be large enough to fit most of object kind + * of Firebase data, but small enough to not notice degradation in performance for inserting and lookups. + * Feel free to empirically determine this constant, but don't expect much gain in real world performance. + */ +#define SORTED_DICTIONARY_ARRAY_TO_RB_TREE_SIZE_THRESHOLD 25 + +@interface FImmutableSortedDictionary : NSObject + ++ (FImmutableSortedDictionary *)dictionaryWithComparator:(NSComparator)comparator; ++ (FImmutableSortedDictionary *)fromDictionary:(NSDictionary *)dictionary withComparator:(NSComparator)comparator; + +- (FImmutableSortedDictionary *) insertKey:(id)aKey withValue:(id)aValue; +- (FImmutableSortedDictionary *) removeKey:(id)aKey; +- (id) get:(id) key; +- (id) getPredecessorKey:(id) key; +- (BOOL) isEmpty; +- (int) count; +- (id) minKey; +- (id) maxKey; +- (void) enumerateKeysAndObjectsUsingBlock:(void(^)(id key, id value, BOOL *stop))block; +- (void) enumerateKeysAndObjectsReverse:(BOOL)reverse usingBlock:(void(^)(id key, id value, BOOL *stop))block; +- (BOOL) contains:(id)key; +- (NSEnumerator *) keyEnumerator; +- (NSEnumerator *) keyEnumeratorFrom:(id)startKey; +- (NSEnumerator *) reverseKeyEnumerator; +- (NSEnumerator *) reverseKeyEnumeratorFrom:(id)startKey; + +#pragma mark - +#pragma mark Methods similar to NSMutableDictionary + +- (FImmutableSortedDictionary *) setObject:(id)anObject forKey:(id)aKey; +- (id) objectForKey:(id)key; +- (FImmutableSortedDictionary *) removeObjectForKey:(id)aKey; + +@end + diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedDictionary.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedDictionary.m new file mode 100644 index 0000000..eb4fa8f --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedDictionary.m @@ -0,0 +1,142 @@ +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedDictionary.h" +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FArraySortedDictionary.h" +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionary.h" + +#define THROW_ABSTRACT_METHOD_EXCEPTION(sel) do { \ + @throw [NSException exceptionWithName:NSInternalInconsistencyException \ + reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(sel)] \ + userInfo:nil]; \ +} while(0) + +@implementation FImmutableSortedDictionary + ++ (FImmutableSortedDictionary *)dictionaryWithComparator:(NSComparator)comparator +{ + return [[FArraySortedDictionary alloc] initWithComparator:comparator]; +} + ++ (FImmutableSortedDictionary *)fromDictionary:(NSDictionary *)dictionary withComparator:(NSComparator)comparator +{ + if (dictionary.count <= SORTED_DICTIONARY_ARRAY_TO_RB_TREE_SIZE_THRESHOLD) { + return [FArraySortedDictionary fromDictionary:dictionary withComparator:comparator]; + } else { + return [FTreeSortedDictionary fromDictionary:dictionary withComparator:comparator]; + } +} + +- (FImmutableSortedDictionary *) insertKey:(id)aKey withValue:(id)aValue { + THROW_ABSTRACT_METHOD_EXCEPTION(@selector(insertKey:withValue:)); +} + +- (FImmutableSortedDictionary *) removeKey:(id)aKey { + THROW_ABSTRACT_METHOD_EXCEPTION(@selector(removeKey:)); +} + +- (id) get:(id) key { + THROW_ABSTRACT_METHOD_EXCEPTION(@selector(get:)); +} + +- (id) getPredecessorKey:(id) key { + THROW_ABSTRACT_METHOD_EXCEPTION(@selector(getPredecessorKey:)); +} + +- (BOOL) isEmpty { + THROW_ABSTRACT_METHOD_EXCEPTION(@selector(isEmpty)); +} + +- (int) count { + THROW_ABSTRACT_METHOD_EXCEPTION(@selector((count))); +} + +- (id) minKey { + THROW_ABSTRACT_METHOD_EXCEPTION(@selector(minKey)); +} + +- (id) maxKey { + THROW_ABSTRACT_METHOD_EXCEPTION(@selector(maxKey)); +} + +- (void) enumerateKeysAndObjectsUsingBlock:(void (^)(id, id, BOOL *))block { + THROW_ABSTRACT_METHOD_EXCEPTION(@selector(enumerateKeysAndObjectsUsingBlock:)); +} + +- (void) enumerateKeysAndObjectsReverse:(BOOL)reverse usingBlock:(void (^)(id, id, BOOL *))block { + THROW_ABSTRACT_METHOD_EXCEPTION(@selector(enumerateKeysAndObjectsReverse:usingBlock:)); +} + +- (BOOL) contains:(id)key { + THROW_ABSTRACT_METHOD_EXCEPTION(@selector(contains:)); +} + +- (NSEnumerator *) keyEnumerator { + THROW_ABSTRACT_METHOD_EXCEPTION(@selector(keyEnumerator)); +} + +- (NSEnumerator *) keyEnumeratorFrom:(id)startKey { + THROW_ABSTRACT_METHOD_EXCEPTION(@selector(keyEnumeratorFrom:)); +} + +- (NSEnumerator *) reverseKeyEnumerator { + THROW_ABSTRACT_METHOD_EXCEPTION(@selector(reverseKeyEnumerator)); +} + +- (NSEnumerator *) reverseKeyEnumeratorFrom:(id)startKey { + THROW_ABSTRACT_METHOD_EXCEPTION(@selector(reverseKeyEnumeratorFrom:)); +} + +- (BOOL)isEqual:(id)object { + if (![object isKindOfClass:[FImmutableSortedDictionary class]]) { + return NO; + } + FImmutableSortedDictionary *other = (FImmutableSortedDictionary *)object; + if (self.count != other.count) { + return NO; + } + __block BOOL isEqual = YES; + [self enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) { + id otherValue = [other objectForKey:key]; + isEqual = isEqual && (value == otherValue || [value isEqual:otherValue]); + *stop = !isEqual; + }]; + return isEqual; +} + +- (NSUInteger)hash { + __block NSUInteger hash = 0; + [self enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) { + hash = (hash * 31 + [key hash]) * 17 + [value hash]; + }]; + return hash; +} + +- (NSString *)description { + NSMutableString *str = [[NSMutableString alloc] init]; + __block BOOL first = YES; + [str appendString:@"{ "]; + [self enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) { + if (!first) { + [str appendString:@", "]; + } + first = NO; + [str appendString:[NSString stringWithFormat:@"%@: %@", key, value]]; + }]; + [str appendString:@" }"]; + return str; +} + +#pragma mark - +#pragma mark Methods similar to NSMutableDictionary + +- (FImmutableSortedDictionary *) setObject:(__unsafe_unretained id)anObject forKey:(__unsafe_unretained id)aKey { + return [self insertKey:aKey withValue:anObject]; +} + +- (FImmutableSortedDictionary *) removeObjectForKey:(__unsafe_unretained id)aKey { + return [self removeKey:aKey]; +} + +- (id) objectForKey:(__unsafe_unretained id)key { + return [self get:key]; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedSet.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedSet.h new file mode 100644 index 0000000..ac15c2f --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedSet.h @@ -0,0 +1,22 @@ +#import + +@interface FImmutableSortedSet : NSObject + ++ (FImmutableSortedSet *)setWithKeysFromDictionary:(NSDictionary *)array comparator:(NSComparator)comparator; + +- (BOOL)containsObject:(id)object; +- (FImmutableSortedSet *)addObject:(id)object; +- (FImmutableSortedSet *)removeObject:(id)object; +- (id)firstObject; +- (id)lastObject; +- (NSUInteger)count; +- (BOOL)isEmpty; + +- (id)predecessorEntry:(id)entry; + +- (void)enumerateObjectsUsingBlock:(void (^)(id obj, BOOL *stop))block; +- (void)enumerateObjectsReverse:(BOOL)reverse usingBlock:(void (^)(id obj, BOOL *stop))block; + +- (NSEnumerator *)objectEnumerator; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedSet.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedSet.m new file mode 100644 index 0000000..f284637 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedSet.m @@ -0,0 +1,115 @@ +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedSet.h" +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedDictionary.h" + +@interface FImmutableSortedSet () + +@property (nonatomic, strong) FImmutableSortedDictionary *dictionary; + +@end + +@implementation FImmutableSortedSet + ++ (FImmutableSortedSet *)setWithKeysFromDictionary:(NSDictionary *)dictionary comparator:(NSComparator)comparator +{ + FImmutableSortedDictionary *setDict = [FImmutableSortedDictionary fromDictionary:dictionary withComparator:comparator]; + return [[FImmutableSortedSet alloc] initWithDictionary:setDict]; +} + +- (id)initWithDictionary:(FImmutableSortedDictionary *)dictionary +{ + self = [super init]; + if (self != nil) { + self->_dictionary = dictionary; + } + return self; +} + +- (BOOL)contains:(id)object +{ + return [self.dictionary contains:object]; +} + +- (FImmutableSortedSet *)addObject:(id)object +{ + FImmutableSortedDictionary *newDictionary = [self.dictionary insertKey:object withValue:[NSNull null]]; + if (newDictionary != self.dictionary) { + return [[FImmutableSortedSet alloc] initWithDictionary:newDictionary]; + } else { + return self; + } +} + +- (FImmutableSortedSet *)removeObject:(id)object +{ + FImmutableSortedDictionary *newDictionary = [self.dictionary removeObjectForKey:object]; + if (newDictionary != self.dictionary) { + return [[FImmutableSortedSet alloc] initWithDictionary:newDictionary]; + } else { + return self; + } +} + +- (BOOL)containsObject:(id)object +{ + return [self.dictionary contains:object]; +} + +- (id)firstObject +{ + return [self.dictionary minKey]; +} + +- (id)lastObject +{ + return [self.dictionary maxKey]; +} + +- (id)predecessorEntry:(id)entry +{ + return [self.dictionary getPredecessorKey:entry]; +} + +- (NSUInteger)count +{ + return [self.dictionary count]; +} + +- (BOOL)isEmpty +{ + return [self.dictionary isEmpty]; +} + +- (void)enumerateObjectsUsingBlock:(void (^)(id, BOOL *))block +{ + [self enumerateObjectsReverse:NO usingBlock:block]; +} + +- (void)enumerateObjectsReverse:(BOOL)reverse usingBlock:(void (^)(id, BOOL *))block +{ + [self.dictionary enumerateKeysAndObjectsReverse:reverse usingBlock:^(id key, id value, BOOL *stop) { + block(key, stop); + }]; +} + +- (NSEnumerator *)objectEnumerator +{ + return [self.dictionary keyEnumerator]; +} + +- (NSString *)description +{ + NSMutableString *str = [[NSMutableString alloc] init]; + __block BOOL first = YES; + [str appendString:@"FImmutableSortedSet ( "]; + [self enumerateObjectsUsingBlock:^(id obj, BOOL *stop) { + if (!first) { + [str appendString:@", "]; + } + first = NO; + [str appendString:[NSString stringWithFormat:@"%@", obj]]; + }]; + [str appendString:@" )"]; + return str; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBEmptyNode.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBEmptyNode.h new file mode 100644 index 0000000..4cad969 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBEmptyNode.h @@ -0,0 +1,27 @@ +#import +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBNode.h" + +@interface FLLRBEmptyNode : NSObject + ++ (id)emptyNode; + +- (id)copyWith:(id) aKey withValue:(id) aValue withColor:(FLLRBColor*) aColor withLeft:(id)aLeft withRight:(id)aRight; +- (id) insertKey:(id) aKey forValue:(id)aValue withComparator:(NSComparator)aComparator; +- (id) remove:(id) aKey withComparator:(NSComparator)aComparator; +- (int) count; +- (BOOL) isEmpty; +- (BOOL) inorderTraversal:(BOOL (^)(id key, id value))action; +- (BOOL) reverseTraversal:(BOOL (^)(id key, id value))action; +- (id) min; +- (id) minKey; +- (id) maxKey; +- (BOOL) isRed; +- (int) check; + +@property (nonatomic, strong) id key; +@property (nonatomic, strong) id value; +@property (nonatomic, strong) FLLRBColor* color; +@property (nonatomic, strong) id left; +@property (nonatomic, strong) id right; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBEmptyNode.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBEmptyNode.m new file mode 100644 index 0000000..0de01e6 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBEmptyNode.m @@ -0,0 +1,72 @@ +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBEmptyNode.h" +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBValueNode.h" + +@implementation FLLRBEmptyNode + +@synthesize key, value, color, left, right; + +- (NSString *) description { + return [NSString stringWithFormat:@"[key=%@ val=%@ color=%@]", key, value, + (color != nil ? @"true" : @"false")]; +} + ++ (id)emptyNode +{ + static dispatch_once_t pred = 0; + __strong static id _sharedObject = nil; + dispatch_once(&pred, ^{ + _sharedObject = [[self alloc] init]; // or some other init method + }); + return _sharedObject; +} + +- (id)copyWith:(id) aKey withValue:(id) aValue withColor:(FLLRBColor*) aColor withLeft:(id)aLeft withRight:(id)aRight { + return self; +} + +- (id) insertKey:(id) aKey forValue:(id)aValue withComparator:(NSComparator)aComparator { + FLLRBValueNode* result = [[FLLRBValueNode alloc] initWithKey:aKey withValue:aValue withColor:nil withLeft:nil withRight:nil]; + return result; +} + +- (id) remove:(id) key withComparator:(NSComparator)aComparator { + return self; +} + +- (int) count { + return 0; +} + +- (BOOL) isEmpty { + return YES; +} + +- (BOOL) inorderTraversal:(BOOL (^)(id key, id value))action { + return NO; +} + +- (BOOL) reverseTraversal:(BOOL (^)(id key, id value))action { + return NO; +} + +- (id) min { + return self; +} + +- (id) minKey { + return nil; +} + +- (id) maxKey { + return nil; +} + +- (BOOL) isRed { + return NO; +} + +- (int) check { + return 0; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBNode.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBNode.h new file mode 100644 index 0000000..09b234c --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBNode.h @@ -0,0 +1,29 @@ +#import + +#define RED @true +#define BLACK @false + +typedef NSNumber FLLRBColor; + +@protocol FLLRBNode + +- (id)copyWith:(id) aKey withValue:(id) aValue withColor:(FLLRBColor*) aColor withLeft:(id)aLeft withRight:(id)aRight; +- (id) insertKey:(id) aKey forValue:(id)aValue withComparator:(NSComparator)aComparator; +- (id) remove:(id) key withComparator:(NSComparator)aComparator; +- (int) count; +- (BOOL) isEmpty; +- (BOOL) inorderTraversal:(BOOL (^)(id key, id value))action; +- (BOOL) reverseTraversal:(BOOL (^)(id key, id value))action; +- (id) min; +- (id) minKey; +- (id) maxKey; +- (BOOL) isRed; +- (int) check; + +@property (nonatomic, strong) id key; +@property (nonatomic, strong) id value; +@property (nonatomic, strong) FLLRBColor* color; +@property (nonatomic, strong) id left; +@property (nonatomic, strong) id right; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBValueNode.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBValueNode.h new file mode 100644 index 0000000..04eef4f --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBValueNode.h @@ -0,0 +1,29 @@ +#import +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBNode.h" + +@interface FLLRBValueNode : NSObject + + +- (id)initWithKey:(id) key withValue:(id) value withColor:(FLLRBColor*) color withLeft:(id)left withRight:(id)right; +- (id)copyWith:(id) aKey withValue:(id) aValue withColor:(FLLRBColor*) aColor withLeft:(id)aLeft withRight:(id)aRight; +- (id) insertKey:(id) aKey forValue:(id)aValue withComparator:(NSComparator)aComparator; +- (id) remove:(id) aKey withComparator:(NSComparator)aComparator; +- (int) count; +- (BOOL) isEmpty; +- (BOOL) inorderTraversal:(BOOL (^)(id key, id value))action; +- (BOOL) reverseTraversal:(BOOL (^)(id key, id value))action; +- (id) min; +- (id) minKey; +- (id) maxKey; +- (BOOL) isRed; +- (int) check; + +- (BOOL) checkMaxDepth; + +@property (nonatomic, strong) id key; +@property (nonatomic, strong) id value; +@property (nonatomic, strong) FLLRBColor* color; +@property (nonatomic, strong) id left; +@property (nonatomic, strong) id right; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBValueNode.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBValueNode.m new file mode 100644 index 0000000..da2c871 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBValueNode.m @@ -0,0 +1,230 @@ +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBValueNode.h" +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBEmptyNode.h" + +@implementation FLLRBValueNode + +@synthesize key, value, color, left, right; + +- (NSString *) description { + return [NSString stringWithFormat:@"[key=%@ val=%@ color=%@]", key, value, + (color != nil ? @"true" : @"false")]; +} + +- (id)initWithKey:(__unsafe_unretained id) aKey withValue:(__unsafe_unretained id) aValue withColor:(__unsafe_unretained FLLRBColor*) aColor withLeft:(__unsafe_unretained id)aLeft withRight:(__unsafe_unretained id)aRight +{ + self = [super init]; + if (self) { + self.key = aKey; + self.value = aValue; + self.color = aColor != nil ? aColor : RED; + self.left = aLeft != nil ? aLeft : [FLLRBEmptyNode emptyNode]; + self.right = aRight != nil ? aRight : [FLLRBEmptyNode emptyNode]; + } + return self; +} + +- (id)copyWith:(__unsafe_unretained id) aKey withValue:(__unsafe_unretained id) aValue withColor:(__unsafe_unretained FLLRBColor*) aColor withLeft:(__unsafe_unretained id)aLeft withRight:(__unsafe_unretained id)aRight { + return [[FLLRBValueNode alloc] initWithKey:(aKey != nil) ? aKey : self.key + withValue:(aValue != nil) ? aValue : self.value + withColor:(aColor != nil) ? aColor : self.color + withLeft:(aLeft != nil) ? aLeft : self.left + withRight:(aRight != nil) ? aRight : self.right]; +} + +- (int) count { + return [self.left count] + 1 + [self.right count]; +} + +- (BOOL) isEmpty { + return NO; +} + +/** +* Early terminates if aciton returns YES. +* @return The first truthy value returned by action, or the last falsey value returned by action. +*/ +- (BOOL) inorderTraversal:(BOOL (^)(id key, id value))action { + return [self.left inorderTraversal:action] || + action(self.key, self.value) || + [self.right inorderTraversal:action]; +} + +- (BOOL) reverseTraversal:(BOOL (^)(id key, id value))action { + return [self.right reverseTraversal:action] || + action(self.key, self.value) || + [self.left reverseTraversal:action]; +} + +- (id) min { + if([self.left isEmpty]) { + return self; + } + else { + return [self.left min]; + } +} + +- (id) minKey { + return [[self min] key]; +} + +- (id) maxKey { + if([self.right isEmpty]) { + return self.key; + } + else { + return [self.right maxKey]; + } +} + +- (id) insertKey:(__unsafe_unretained id) aKey forValue:(__unsafe_unretained id)aValue withComparator:(NSComparator)aComparator { + NSComparisonResult cmp = aComparator(aKey, self.key); + FLLRBValueNode* n = self; + + if(cmp == NSOrderedAscending) { + n = [n copyWith:nil withValue:nil withColor:nil withLeft:[n.left insertKey:aKey forValue:aValue withComparator:aComparator] withRight:nil]; + } + else if(cmp == NSOrderedSame) { + n = [n copyWith:nil withValue:aValue withColor:nil withLeft:nil withRight:nil]; + } + else { + n = [n copyWith:nil withValue:nil withColor:nil withLeft:nil withRight:[n.right insertKey:aKey forValue:aValue withComparator:aComparator]]; + } + + return [n fixUp]; +} + +- (id) removeMin { + + if([self.left isEmpty]) { + return [FLLRBEmptyNode emptyNode]; + } + + FLLRBValueNode* n = self; + if(! [n.left isRed] && ! [n.left.left isRed]) { + n = [n moveRedLeft]; + } + + n = [n copyWith:nil withValue:nil withColor:nil withLeft:[(FLLRBValueNode*)n.left removeMin] withRight:nil]; + return [n fixUp]; +} + + +- (id) fixUp { + FLLRBValueNode* n = self; + if([n.right isRed] && ! [n.left isRed]) n = [n rotateLeft]; + if([n.left isRed] && [n.left.left isRed]) n = [n rotateRight]; + if([n.left isRed] && [n.right isRed]) n = [n colorFlip]; + return n; +} + +- (FLLRBValueNode*) moveRedLeft { + FLLRBValueNode* n = [self colorFlip]; + if([n.right.left isRed]) { + n = [n copyWith:nil withValue:nil withColor:nil withLeft:nil withRight:[(FLLRBValueNode*)n.right rotateRight]]; + n = [n rotateLeft]; + n = [n colorFlip]; + } + return n; +} + +- (FLLRBValueNode*) moveRedRight { + FLLRBValueNode* n = [self colorFlip]; + if([n.left.left isRed]) { + n = [n rotateRight]; + n = [n colorFlip]; + } + return n; +} + +- (id) rotateLeft { + id nl = [self copyWith:nil withValue:nil withColor:RED withLeft:nil withRight:self.right.left]; + return [self.right copyWith:nil withValue:nil withColor:self.color withLeft:nl withRight:nil];; +} + +- (id) rotateRight { + id nr = [self copyWith:nil withValue:nil withColor:RED withLeft:self.left.right withRight:nil]; + return [self.left copyWith:nil withValue:nil withColor:self.color withLeft:nil withRight:nr]; +} + +- (id) colorFlip { + id nleft = [self.left copyWith:nil withValue:nil withColor:[NSNumber numberWithBool:![self.left.color boolValue]] withLeft:nil withRight:nil]; + id nright = [self.right copyWith:nil withValue:nil withColor:[NSNumber numberWithBool:![self.right.color boolValue]] withLeft:nil withRight:nil]; + + return [self copyWith:nil withValue:nil withColor:[NSNumber numberWithBool:![self.color boolValue]] withLeft:nleft withRight:nright]; +} + +- (id) remove:(__unsafe_unretained id) aKey withComparator:(NSComparator)comparator { + id smallest; + FLLRBValueNode* n = self; + + if(comparator(aKey, n.key) == NSOrderedAscending) { + if(![n.left isEmpty] && ![n.left isRed] && ![n.left.left isRed]) { + n = [n moveRedLeft]; + } + n = [n copyWith:nil withValue:nil withColor:nil withLeft:[n.left remove:aKey withComparator:comparator] withRight:nil]; + } + else { + if([n.left isRed]) { + n = [n rotateRight]; + } + + if(![n.right isEmpty] && ![n.right isRed] && ![n.right.left isRed]) { + n = [n moveRedRight]; + } + + if(comparator(aKey, n.key) == NSOrderedSame) { + if([n.right isEmpty]) { + return [FLLRBEmptyNode emptyNode]; + } + else { + smallest = [n.right min]; + n = [n copyWith:smallest.key withValue:smallest.value withColor:nil withLeft:nil withRight:[(FLLRBValueNode*)n.right removeMin]]; + } + } + n = [n copyWith:nil withValue:nil withColor:nil withLeft:nil withRight:[n.right remove:aKey withComparator:comparator]]; + } + return [n fixUp]; +} + +- (BOOL) isRed { + return [self.color boolValue]; +} + +- (BOOL) checkMaxDepth { + int blackDepth = [self check]; + if(pow(2.0, blackDepth) <= ([self count] + 1)) { + return YES; + } + else { + return NO; + } +} + +- (int) check { + int blackDepth = 0; + + if([self isRed] && [self.left isRed]) { + @throw [[NSException alloc] initWithName:@"check" reason:@"Red node has a red child" userInfo:nil]; + } + + if([self.right isRed]) { + @throw [[NSException alloc] initWithName:@"check" reason:@"Right child is red" userInfo:nil]; + } + + blackDepth = [self.left check]; +// NSLog(err); + if(blackDepth != [self.right check]) { + NSString* err = [NSString stringWithFormat:@"(%@ -> %@)blackDepth: %d ; self.right check: %d", self.value, [self.color boolValue] ? @"red" : @"black", blackDepth, [self.right check]]; +// return 10; + @throw [[NSException alloc] initWithName:@"check" reason:err userInfo:nil]; + } + else { + int ret = blackDepth + ([self isRed] ? 0 : 1); +// NSLog(@"black depth is: %d; other is: %d, ret is: %d", blackDepth, ([self isRed] ? 0 : 1), ret); + return ret; + } +} + + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionary.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionary.h new file mode 100644 index 0000000..395fad6 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionary.h @@ -0,0 +1,30 @@ +/** + * @fileoverview Implementation of an immutable SortedMap using a Left-leaning + * Red-Black Tree, adapted from the implementation in Mugs + * (http://mads379.github.com/mugs/) by Mads Hartmann Jensen + * (mads379@gmail.com). + * + * Original paper on Left-leaning Red-Black Trees: + * http://www.cs.princeton.edu/~rs/talks/LLRB/LLRB.pdf + * + * Invariant 1: No red node has a red child + * Invariant 2: Every leaf path has the same number of black nodes + * Invariant 3: Only the left child can be red (left leaning) + */ + +#import +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedDictionary.h" +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBNode.h" + +@interface FTreeSortedDictionary : FImmutableSortedDictionary + +@property (nonatomic, copy, readonly) NSComparator comparator; +@property (nonatomic, strong, readonly) id root; + +- (id)initWithComparator:(NSComparator)aComparator; + +// Override methods to return subtype +- (FTreeSortedDictionary *) insertKey:(id)aKey withValue:(id)aValue; +- (FTreeSortedDictionary *) removeKey:(id)aKey; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionary.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionary.m new file mode 100644 index 0000000..d80b5cb --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionary.m @@ -0,0 +1,326 @@ +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionary.h" +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBEmptyNode.h" +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBValueNode.h" +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionaryEnumerator.h" + +typedef void (^fbt_void_nsnumber_int)(NSNumber* color, NSUInteger chunkSize); + +@interface FTreeSortedDictionary () + +@property (nonatomic, strong) id root; +@property (nonatomic, copy, readwrite) NSComparator comparator; + +@end + +@implementation FTreeSortedDictionary + +- (id)initWithComparator:(NSComparator)aComparator { + self = [super init]; + if (self) { + self.root = [FLLRBEmptyNode emptyNode]; + self.comparator = aComparator; + } + return self; +} + +- (id)initWithComparator:(NSComparator)aComparator withRoot:(__unsafe_unretained id)aRoot { + self = [super init]; + if (self) { + self.root = aRoot; + self.comparator = aComparator; + } + return self; +} + +/** + * Returns a copy of the map, with the specified key/value added or replaced. + */ +- (FTreeSortedDictionary *) insertKey:(__unsafe_unretained id)aKey withValue:(__unsafe_unretained id)aValue { + return [[FTreeSortedDictionary alloc] initWithComparator:self.comparator + withRoot:[[self.root insertKey:aKey forValue:aValue withComparator:self.comparator] + copyWith:nil + withValue:nil + withColor:BLACK + withLeft:nil + withRight:nil]]; +} + + +- (FTreeSortedDictionary *) removeKey:(__unsafe_unretained id)aKey { + // Remove is somewhat expensive even if the key doesn't exist (the tree does rebalancing and stuff). So avoid it. + if (![self contains:aKey]) { + return self; + } else { + return [[FTreeSortedDictionary alloc] + initWithComparator:self.comparator + withRoot:[[self.root remove:aKey withComparator:self.comparator] + copyWith:nil + withValue:nil + withColor:BLACK + withLeft:nil + withRight:nil]]; + } +} + +- (id) get:(__unsafe_unretained id) key { + if (key == nil) { + return nil; + } + NSComparisonResult cmp; + id node = self.root; + while(![node isEmpty]) { + cmp = self.comparator(key, node.key); + if(cmp == NSOrderedSame) { + return node.value; + } + else if (cmp == NSOrderedAscending) { + node = node.left; + } + else { + node = node.right; + } + } + return nil; +} + +- (id) getPredecessorKey:(__unsafe_unretained id) key { + NSComparisonResult cmp; + id node = self.root; + id rightParent = nil; + while(![node isEmpty]) { + cmp = self.comparator(key, node.key); + if(cmp == NSOrderedSame) { + if(![node.left isEmpty]) { + node = node.left; + while(! [node.right isEmpty]) { + node = node.right; + } + return node.key; + } + else if (rightParent != nil) { + return rightParent.key; + } + else { + return nil; + } + } + else if (cmp == NSOrderedAscending) { + node = node.left; + } + else if (cmp == NSOrderedDescending) { + rightParent = node; + node = node.right; + } + } + @throw [NSException exceptionWithName:@"NonexistentKey" reason:@"getPredecessorKey called with nonexistent key." userInfo:@{@"key": [key description] }]; +} + +- (BOOL) isEmpty { + return [self.root isEmpty]; +} + +- (int) count { + return [self.root count]; +} + +- (id) minKey { + return [self.root minKey]; +} + +- (id) maxKey { + return [self.root maxKey]; +} + +- (void) enumerateKeysAndObjectsUsingBlock:(void (^)(id, id, BOOL *))block +{ + [self enumerateKeysAndObjectsReverse:NO usingBlock:block]; +} + +- (void) enumerateKeysAndObjectsReverse:(BOOL)reverse usingBlock:(void (^)(id, id, BOOL *))block +{ + if (reverse) { + __block BOOL stop = NO; + [self.root reverseTraversal:^BOOL(id key, id value) { + block(key, value, &stop); + return stop; + }]; + } else { + __block BOOL stop = NO; + [self.root inorderTraversal:^BOOL(id key, id value) { + block(key, value, &stop); + return stop; + }]; + } +} + +- (BOOL) contains:(__unsafe_unretained id)key { + return ([self objectForKey:key] != nil); +} + +- (NSEnumerator *) keyEnumerator { + return [[FTreeSortedDictionaryEnumerator alloc] + initWithImmutableSortedDictionary:self startKey:nil isReverse:NO]; +} + +- (NSEnumerator *) keyEnumeratorFrom:(id)startKey { + return [[FTreeSortedDictionaryEnumerator alloc] + initWithImmutableSortedDictionary:self startKey:startKey isReverse:NO]; +} + +- (NSEnumerator *) reverseKeyEnumerator { + return [[FTreeSortedDictionaryEnumerator alloc] + initWithImmutableSortedDictionary:self startKey:nil isReverse:YES]; +} + +- (NSEnumerator *) reverseKeyEnumeratorFrom:(id)startKey { + return [[FTreeSortedDictionaryEnumerator alloc] + initWithImmutableSortedDictionary:self startKey:startKey isReverse:YES]; +} + + +#pragma mark - +#pragma mark Tree Builder + +// Code to efficiently build a RB Tree +typedef struct _base1_2list { + unsigned int bits; + unsigned short count; + unsigned short current; +} Base1_2List; + +Base1_2List *base1_2List_new(unsigned int length); +void base1_2List_free(Base1_2List* list); +unsigned int log_base2(unsigned int num); +BOOL base1_2List_next(Base1_2List* list); + +unsigned int log_base2(unsigned int num) { + return (unsigned int)(log(num) / log(2)); +} + +/** + * Works like an iterator, so it moves to the next bit. Do not call more than list->count times. + * @return whether or not the next bit is a 1 in base {1,2}. + */ +BOOL base1_2List_next(Base1_2List* list) { + BOOL result = !(list->bits & (0x1 << list->current)); + list->current--; + return result; +} + +static inline unsigned bit_mask(int x) { + return (x >= sizeof(unsigned) * CHAR_BIT) ? (unsigned) -1 : (1U << x) - 1; +} + +/** + * We represent the base{1,2} number as the combination of a binary number and a number of bits that we care about + * We iterate backwards, from most significant bit to least, to build up the llrb nodes. 0 base 2 => 1 base {1,2}, 1 base 2 => 2 base {1,2} + */ +Base1_2List *base1_2List_new(unsigned int length) { + size_t sz = sizeof(Base1_2List); + Base1_2List* list = calloc(1, sz); + // Calculate the number of bits that we care about + list->count = (unsigned short)log_base2(length + 1); + unsigned int mask = bit_mask(list->count); + list->bits = (length + 1) & mask; + list->current = list->count - 1; + return list; +} + + +void base1_2List_free(Base1_2List* list) { + free(list); +} + ++ (id) buildBalancedTree:(NSArray *)keys dictionary:(NSDictionary *)dictionary subArrayStartIndex:(NSUInteger)startIndex length:(NSUInteger)length { + length = MIN(keys.count - startIndex, length); // Bound length by the actual length of the array + if (length == 0) { + return nil; + } else if (length == 1) { + id key = keys[startIndex]; + return [[FLLRBValueNode alloc] initWithKey:key withValue:dictionary[key] withColor:BLACK withLeft:nil withRight:nil]; + } else { + NSUInteger middle = length / 2; + id left = [FTreeSortedDictionary buildBalancedTree:keys dictionary:dictionary subArrayStartIndex:startIndex length:middle]; + id right = [FTreeSortedDictionary buildBalancedTree:keys dictionary:dictionary subArrayStartIndex:(startIndex+middle+1) length:middle]; + id key = keys[startIndex + middle]; + return [[FLLRBValueNode alloc] initWithKey:key withValue:dictionary[key] withColor:BLACK withLeft:left withRight:right]; + } +} + ++ (id) rootFrom12List:(Base1_2List *)base1_2List keyList:(NSArray *)keyList dictionary:(NSDictionary *)dictionary { + __block id root = nil; + __block id node = nil; + __block NSUInteger index = keyList.count; + + fbt_void_nsnumber_int buildPennant = ^(NSNumber* color, NSUInteger chunkSize) { + NSUInteger startIndex = index - chunkSize + 1; + index -= chunkSize; + id key = keyList[index]; + id childTree = [self buildBalancedTree:keyList dictionary:dictionary subArrayStartIndex:startIndex length:(chunkSize - 1)]; + id pennant = [[FLLRBValueNode alloc] initWithKey:key withValue:dictionary[key] withColor:color withLeft:nil withRight:childTree]; + //attachPennant(pennant); + if (node) { + node.left = pennant; + node = pennant; + } else { + root = pennant; + node = pennant; + } + }; + + for (int i = 0; i < base1_2List->count; ++i) { + BOOL isOne = base1_2List_next(base1_2List); + NSUInteger chunkSize = (NSUInteger)pow(2.0, base1_2List->count - (i + 1)); + if (isOne) { + buildPennant(BLACK, chunkSize); + } else { + buildPennant(BLACK, chunkSize); + buildPennant(RED, chunkSize); + } + } + return root; +} + +/** + * Uses the algorithm linked here: + * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.46.1458 + */ + ++ (FImmutableSortedDictionary *)fromDictionary:(NSDictionary *)dictionary withComparator:(NSComparator)comparator +{ + // Steps: + // 0. Sort the array + // 1. Calculate the 1-2 number + // 2. Build From 1-2 number + // 0. for each digit in 1-2 number + // 0. calculate chunk size + // 1. build 1 or 2 pennants of that size + // 2. attach pennants and update node pointer + // 1. return root + NSMutableArray *sortedKeyList = [NSMutableArray arrayWithCapacity:dictionary.count]; + [dictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + [sortedKeyList addObject:key]; + }]; + [sortedKeyList sortUsingComparator:comparator]; + + [sortedKeyList enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + if (idx > 0) { + if (comparator(sortedKeyList[idx - 1], obj) != NSOrderedAscending) { + [NSException raise:NSInvalidArgumentException format:@"Can't create FImmutableSortedDictionary with keys with same ordering!"]; + } + } + }]; + + Base1_2List* list = base1_2List_new((unsigned int)sortedKeyList.count); + id root = [self rootFrom12List:list keyList:sortedKeyList dictionary:dictionary]; + base1_2List_free(list); + + if (root != nil) { + return [[FTreeSortedDictionary alloc] initWithComparator:comparator withRoot:root]; + } else { + return [[FTreeSortedDictionary alloc] initWithComparator:comparator]; + } +} + +@end + diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionaryEnumerator.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionaryEnumerator.h new file mode 100644 index 0000000..a582e14 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionaryEnumerator.h @@ -0,0 +1,9 @@ +#import +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionary.h" + +@interface FTreeSortedDictionaryEnumerator : NSEnumerator + +- (id)initWithImmutableSortedDictionary:(FTreeSortedDictionary *)aDict startKey:(id)startKey isReverse:(BOOL)reverse; +- (id)nextObject; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionaryEnumerator.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionaryEnumerator.m new file mode 100644 index 0000000..473abac --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionaryEnumerator.m @@ -0,0 +1,83 @@ +#import "FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionaryEnumerator.h" + +@interface FTreeSortedDictionaryEnumerator() +@property (nonatomic, strong) FTreeSortedDictionary* immutableSortedDictionary; +@property (nonatomic, strong) NSMutableArray* stack; +@property (nonatomic) BOOL isReverse; + +@end + +@implementation FTreeSortedDictionaryEnumerator + +- (id)initWithImmutableSortedDictionary:(FTreeSortedDictionary *)aDict + startKey:(id)startKey isReverse:(BOOL)reverse { + self = [super init]; + if (self) { + self.immutableSortedDictionary = aDict; + self.stack = [[NSMutableArray alloc] init]; + self.isReverse = reverse; + + NSComparator comparator = aDict.comparator; + id node = self.immutableSortedDictionary.root; + + NSInteger cmp; + while(![node isEmpty]) { + cmp = startKey ? comparator(node.key, startKey) : 1; + // flip the comparison if we're going in reverse + if (self.isReverse) cmp *= -1; + + if (cmp < 0) { + // This node is less than our start key. Ignore it. + if (self.isReverse) { + node = node.left; + } else { + node = node.right; + } + } else if (cmp == 0) { + // This node is exactly equal to our start key. Push it on the stack, but stop iterating: + [self.stack addObject:node]; + break; + } else { + // This node is greater than our start key, add it to the stack and move on to the next one. + [self.stack addObject:node]; + if (self.isReverse) { + node = node.right; + } else { + node = node.left; + } + } + } + } + return self; +} + +- (id)nextObject { + if([self.stack count] == 0) { + return nil; + } + + id node = nil; + @synchronized(self.stack) { + node = [self.stack lastObject]; + [self.stack removeLastObject]; + } + id result = node.key; + + if (self.isReverse) { + node = node.left; + while (![node isEmpty]) { + [self.stack addObject:node]; + node = node.right; + } + } else { + node = node.right; + while (![node isEmpty]) { + [self.stack addObject:node]; + node = node.left; + } + } + + return result; +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/FSRWebSocket.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/FSRWebSocket.h new file mode 100644 index 0000000..876677d --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/FSRWebSocket.h @@ -0,0 +1,112 @@ +// +// Copyright 2012 Square Inc. +// +// 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. +// + +#if !TARGET_OS_WATCH +#import +#import + +typedef enum { + SR_CONNECTING = 0, + SR_OPEN = 1, + SR_CLOSING = 2, + SR_CLOSED = 3, + +} FSRReadyState; + +@class FSRWebSocket; + +extern NSString *const FSRWebSocketErrorDomain; + +@protocol FSRWebSocketDelegate; + +@interface FSRWebSocket : NSObject + +@property (nonatomic, weak) id delegate; + +@property (nonatomic, readonly) FSRReadyState readyState; +@property (nonatomic, readonly, retain) NSURL *url; + +// This returns the negotiated protocol. +// It will be niluntil after the handshake completes. +@property (nonatomic, readonly, copy) NSString *protocol; + +// Protocols should be an array of strings that turn into Sec-WebSocket-Protocol +- (id)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray *)protocols queue:(dispatch_queue_t)queue googleAppID:(NSString*)googleAppID andUserAgent:(NSString *)userAgent; +- (id)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray *)protocols; +- (id)initWithURLRequest:(NSURLRequest *)request queue:(dispatch_queue_t)queue googleAppID:(NSString*)googleAppID andUserAgent:(NSString *)userAgent; +- (id)initWithURLRequest:(NSURLRequest *)request; + +// Some helper constructors +- (id)initWithURL:(NSURL *)url protocols:(NSArray *)protocols; +- (id)initWithURL:(NSURL *)url; + +// Delegate queue will be dispatch_main_queue by default. +// You cannot set both OperationQueue and dispatch_queue. +- (void)setDelegateOperationQueue:(NSOperationQueue*) queue; +- (void)setDelegateDispatchQueue:(dispatch_queue_t)queue; + +// By default, it will schedule itself on +[NSRunLoop SR_networkRunLoop] using defaultModes. +- (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode; +- (void)unscheduleFromRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode; + +// SRWebSockets are intended one-time-use only. Open should be called once and only once +- (void)open; + +- (void)close; +- (void)closeWithCode:(NSInteger)code reason:(NSString *)reason; + +// Send a UTF8 String or Data +- (void)send:(id)data; + +@end + +@protocol FSRWebSocketDelegate + +// message will either be an NSString if the server is using text +// or NSData if the server is using binary +- (void)webSocket:(FSRWebSocket *)webSocket didReceiveMessage:(id)message; + +@optional + +// Exclude the `webSocket` argument since it isn't used in this codebase and it allows for better +// code sharing with watchOS. +- (void)webSocketDidOpen; +- (void)webSocket:(FSRWebSocket *)webSocket didFailWithError:(NSError *)error; +- (void)webSocket:(FSRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean; + +@end + + +@interface NSURLRequest (FCertificateAdditions) + +@property (nonatomic, retain, readonly) NSArray *FSR_SSLPinnedCertificates; + +@end + + +@interface NSMutableURLRequest (FCertificateAdditions) + +@property (nonatomic, retain) NSArray *FSR_SSLPinnedCertificates; + +@end + +@interface NSRunLoop (FSRWebSocket) + ++ (NSRunLoop *)FSR_networkRunLoop; + +@end + +#endif // TARGET_OS_WATCH diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/FSRWebSocket.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/FSRWebSocket.m new file mode 100644 index 0000000..6e0e2c1 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/FSRWebSocket.m @@ -0,0 +1,1884 @@ +// +// Copyright 2012 Square Inc. +// +// 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 + +#import "FirebaseDatabase/Sources/third_party/SocketRocket/FSRWebSocket.h" + +#if __has_include() +#define HAS_ICU +#endif + +#import + +#ifdef HAS_ICU +#import +#endif + +#if __has_include() +#import +#else +#import +#endif + +#import +#import +#import "FirebaseDatabase/Sources/third_party/SocketRocket/fbase64.h" +#import "FirebaseDatabase/Sources/third_party/SocketRocket/NSData+SRB64Additions.h" + +#if OS_OBJECT_USE_OBJC_RETAIN_RELEASE +#define sr_dispatch_retain(x) +#define sr_dispatch_release(x) +#define maybe_bridge(x) ((__bridge void *) x) +#else +#define sr_dispatch_retain(x) dispatch_retain(x) +#define sr_dispatch_release(x) dispatch_release(x) +#define maybe_bridge(x) (x) +#endif + +#if !TARGET_OS_WATCH +typedef enum { + SROpCodeTextFrame = 0x1, + SROpCodeBinaryFrame = 0x2, + //3-7Reserved + SROpCodeConnectionClose = 0x8, + SROpCodePing = 0x9, + SROpCodePong = 0xA, + //B-F reserved +} FSROpCode; + +typedef enum { + SRStatusCodeNormal = 1000, + SRStatusCodeGoingAway = 1001, + SRStatusCodeProtocolError = 1002, + SRStatusCodeUnhandledType = 1003, + // 1004 reserved + SRStatusNoStatusReceived = 1005, + // 1004-1006 reserved + SRStatusCodeInvalidUTF8 = 1007, + SRStatusCodePolicyViolated = 1008, + SRStatusCodeMessageTooBig = 1009, +} FSRStatusCode; + +typedef struct { + BOOL fin; +// BOOL rsv1; +// BOOL rsv2; +// BOOL rsv3; + uint8_t opcode; + BOOL masked; + uint64_t payload_length; +} frame_header; + +static NSString *const SRWebSocketAppendToSecKeyString = @"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; + +static inline int32_t validate_dispatch_data_partial_string(NSData *data); +static inline void SRFastLog(NSString *format, ...); + +@interface NSData (FSRWebSocket) + +- (NSString *)stringBySHA1ThenBase64Encoding; + +@end + + +@interface NSString (FSRWebSocket) + +- (NSString *)stringBySHA1ThenBase64Encoding; + +@end + + +@interface NSURL (FSRWebSocket) + +// The origin isn't really applicable for a native application +// So instead, just map ws -> http and wss -> https +- (NSString *)SR_origin; + +@end + +@interface _FSRRunLoopThread : NSThread + +@property (nonatomic, readonly) NSRunLoop *runLoop; + +@end + +static NSString *newSHA1String(const char *bytes, size_t length) { + uint8_t md[CC_SHA1_DIGEST_LENGTH]; + + CC_SHA1(bytes, (int)length, md); + + size_t buffer_size = ((sizeof(md) * 3 + 2) / 2); + + char *buffer = (char *)malloc(buffer_size); + + int len = f_b64_ntop(md, CC_SHA1_DIGEST_LENGTH, buffer, buffer_size); + if (len == -1) { + free(buffer); + return nil; + } else{ + return [[NSString alloc] initWithBytesNoCopy:buffer length:len encoding:NSASCIIStringEncoding freeWhenDone:YES]; + } +} + +@implementation NSData (FSRWebSocket) + +- (NSString *)stringBySHA1ThenBase64Encoding; +{ + return newSHA1String(self.bytes, self.length); +} + +@end + + +@implementation NSString (FSRWebSocket) + +- (NSString *)stringBySHA1ThenBase64Encoding; +{ + return newSHA1String(self.UTF8String, self.length); +} + +@end + +NSString *const FSRWebSocketErrorDomain = @"FSRWebSocketErrorDomain"; + +// Returns number of bytes consumed. returning 0 means you didn't match. +// Sends bytes to callback handler; +typedef size_t (^stream_scanner)(NSData *collected_data); + +typedef void (^data_callback)(FSRWebSocket *webSocket, NSData *data); + +@interface FSRIOConsumer : NSObject { + stream_scanner _scanner; + data_callback _handler; + size_t _bytesNeeded; + BOOL _readToCurrentFrame; + BOOL _unmaskBytes; +} +@property (nonatomic, copy, readonly) stream_scanner consumer; +@property (nonatomic, copy, readonly) data_callback handler; +@property (nonatomic, assign) size_t bytesNeeded; +@property (nonatomic, assign, readonly) BOOL readToCurrentFrame; +@property (nonatomic, assign, readonly) BOOL unmaskBytes; + +@end + +// This class is not thread-safe, and is expected to always be run on the same queue. +@interface FSRIOConsumerPool : NSObject + +- (id)initWithBufferCapacity:(NSUInteger)poolSize; + +- (FSRIOConsumer *)consumerWithScanner:(stream_scanner)scanner handler:(data_callback)handler bytesNeeded:(size_t)bytesNeeded readToCurrentFrame:(BOOL)readToCurrentFrame unmaskBytes:(BOOL)unmaskBytes; +- (void)returnConsumer:(FSRIOConsumer *)consumer; + +@end + +@interface FSRWebSocket () + +- (void)_writeData:(NSData *)data; +- (void)_closeWithProtocolError:(NSString *)message; +- (void)_failWithError:(NSError *)error; + +- (void)_disconnect; + +- (void)_readFrameNew; +- (void)_readFrameContinue; + +- (void)_pumpScanner; + +- (void)_pumpWriting; + +- (void)_addConsumerWithScanner:(stream_scanner)consumer callback:(data_callback)callback; +- (void)_addConsumerWithDataLength:(size_t)dataLength callback:(data_callback)callback readToCurrentFrame:(BOOL)readToCurrentFrame unmaskBytes:(BOOL)unmaskBytes; +- (void)_addConsumerWithScanner:(stream_scanner)consumer callback:(data_callback)callback dataLength:(size_t)dataLength; +- (void)_readUntilBytes:(const void *)bytes length:(size_t)length callback:(data_callback)dataHandler; +- (void)_readUntilHeaderCompleteWithCallback:(data_callback)dataHandler; + +- (void)_sendFrameWithOpcode:(FSROpCode)opcode data:(id)data; + +- (BOOL)_checkHandshake:(CFHTTPMessageRef)httpMessage; +- (void)_SR_commonInit; + +- (void)_initializeStreams; +- (void)_connect; + +@property (nonatomic) FSRReadyState readyState; + +@property (nonatomic) NSOperationQueue *delegateOperationQueue; +@property (nonatomic) dispatch_queue_t delegateDispatchQueue; + +@end + + +@implementation FSRWebSocket { + NSInteger _webSocketVersion; + + NSOperationQueue *_delegateOperationQueue; + dispatch_queue_t _delegateDispatchQueue; + dispatch_queue_t _workQueue; + NSMutableArray *_consumers; + + NSInputStream *_inputStream; + NSOutputStream *_outputStream; + + NSMutableData *_readBuffer; + NSInteger _readBufferOffset; + + NSMutableData *_outputBuffer; + NSInteger _outputBufferOffset; + + uint8_t _currentFrameOpcode; + size_t _currentFrameCount; + size_t _readOpCount; + uint32_t _currentStringScanPosition; + NSMutableData *_currentFrameData; + + NSString *_closeReason; + + NSString *_secKey; + + BOOL _pinnedCertFound; + + uint8_t _currentReadMaskKey[4]; + size_t _currentReadMaskOffset; + + BOOL _consumerStopped; + + BOOL _closeWhenFinishedWriting; + BOOL _failed; + + BOOL _secure; + NSURLRequest *_urlRequest; + NSString *_userAgent; + NSString *_googleAppID; + + CFHTTPMessageRef _receivedHTTPHeaders; + + BOOL _sentClose; + BOOL _didFail; + BOOL _cleanupScheduled; + int _closeCode; + + BOOL _isPumping; + + NSMutableSet *_scheduledRunloops; + + // We use this to retain ourselves. + __strong FSRWebSocket *_selfRetain; + + NSArray *_requestedProtocols; + FSRIOConsumerPool *_consumerPool; +} + +@synthesize delegate = _delegate; +@synthesize url = _url; +@synthesize readyState = _readyState; +@synthesize protocol = _protocol; + +static __strong NSData *CRLFCRLF; + ++ (void)initialize; +{ + CRLFCRLF = [[NSData alloc] initWithBytes:"\r\n\r\n" length:4]; +} + +- (id)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray *)protocols queue:(dispatch_queue_t)queue + googleAppID:(NSString *)googleAppID andUserAgent:(NSString *)userAgent; +{ + self = [super init]; + if (self) { + assert(request.URL); + _url = request.URL; + NSString *scheme = [_url scheme]; + + _requestedProtocols = [protocols copy]; + _googleAppID = googleAppID; + _userAgent = userAgent; + + assert([scheme isEqualToString:@"ws"] || [scheme isEqualToString:@"http"] || [scheme isEqualToString:@"wss"] || [scheme isEqualToString:@"https"]); + _urlRequest = request; + + if ([scheme isEqualToString:@"wss"] || [scheme isEqualToString:@"https"]) { + _secure = YES; + } + + if (!queue) { + _delegateDispatchQueue = dispatch_get_main_queue(); + } else { + _delegateDispatchQueue = queue; + } + + [self _SR_commonInit]; + } + + return self; +} + +- (id)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray *)protocols; +{ + return [self initWithURLRequest:request protocols:nil queue:nil googleAppID:nil andUserAgent:nil]; +} + +- (id)initWithURLRequest:(NSURLRequest *)request queue:(dispatch_queue_t)queue + googleAppID:(NSString *)googleAppID andUserAgent:(NSString *)userAgent; +{ + return [self initWithURLRequest:request protocols:nil queue:queue googleAppID:googleAppID + andUserAgent:userAgent]; +} + +- (id)initWithURLRequest:(NSURLRequest *)request; +{ + return [self initWithURLRequest:request protocols:nil]; +} + +- (id)initWithURL:(NSURL *)url; +{ + return [self initWithURL:url protocols:nil]; +} + +- (id)initWithURL:(NSURL *)url protocols:(NSArray *)protocols; +{ + NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url]; + return [self initWithURLRequest:request protocols:protocols]; +} + +- (void)_SR_commonInit; +{ + _readyState = SR_CONNECTING; + + _consumerStopped = YES; + + _webSocketVersion = 13; + + _workQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); + + // Going to set a specific on the queue so we can validate we're on the work queue + dispatch_queue_set_specific(_workQueue, (__bridge void *)self, maybe_bridge(_workQueue), NULL); + + sr_dispatch_retain(_delegateDispatchQueue); + + _readBuffer = [[NSMutableData alloc] init]; + _outputBuffer = [[NSMutableData alloc] init]; + + _currentFrameData = [[NSMutableData alloc] init]; + + _consumers = [[NSMutableArray alloc] init]; + + _consumerPool = [[FSRIOConsumerPool alloc] init]; + + _scheduledRunloops = [[NSMutableSet alloc] init]; + + [self _initializeStreams]; + + // default handlers +} + +- (void)assertOnWorkQueue; +{ + assert(dispatch_get_specific((__bridge void *)self) == maybe_bridge(_workQueue)); +} + +- (void)dealloc +{ + _inputStream.delegate = nil; + _outputStream.delegate = nil; + + [_inputStream close]; + [_outputStream close]; + + sr_dispatch_release(_workQueue); + _workQueue = NULL; + + if (_receivedHTTPHeaders) { + CFRelease(_receivedHTTPHeaders); + _receivedHTTPHeaders = NULL; + } + + if (_delegateDispatchQueue) { + sr_dispatch_release(_delegateDispatchQueue); + _delegateDispatchQueue = NULL; + } +} + +#ifndef NDEBUG + +- (void)setReadyState:(FSRReadyState)aReadyState; +{ + [self willChangeValueForKey:@"readyState"]; + assert(aReadyState > _readyState); + _readyState = aReadyState; + [self didChangeValueForKey:@"readyState"]; +} + +#endif + +- (void)open; +{ + assert(_url); + NSAssert(_readyState == SR_CONNECTING, @"Cannot call -(void)open on SRWebSocket more than once"); + + _selfRetain = self; + + [self _connect]; +} + +// Calls block on delegate queue +- (void)_performDelegateBlock:(dispatch_block_t)block; +{ + if (_delegateOperationQueue) { + [_delegateOperationQueue addOperationWithBlock:block]; + } else { + assert(_delegateDispatchQueue); + dispatch_async(_delegateDispatchQueue, block); + } +} + +- (void)setDelegateDispatchQueue:(dispatch_queue_t)queue; +{ + if (queue) { + sr_dispatch_retain(queue); + } + + if (_delegateDispatchQueue) { + sr_dispatch_release(_delegateDispatchQueue); + } + + _delegateDispatchQueue = queue; +} + +- (BOOL)_checkHandshake:(CFHTTPMessageRef)httpMessage; +{ + NSString *acceptHeader = CFBridgingRelease(CFHTTPMessageCopyHeaderFieldValue(httpMessage, CFSTR("Sec-WebSocket-Accept"))); + + if (acceptHeader == nil) { + return NO; + } + + NSString *concattedString = [_secKey stringByAppendingString:SRWebSocketAppendToSecKeyString]; + NSString *expectedAccept = [concattedString stringBySHA1ThenBase64Encoding]; + + return [acceptHeader isEqualToString:expectedAccept]; +} + +- (void)_HTTPHeadersDidFinish; +{ + NSInteger responseCode = CFHTTPMessageGetResponseStatusCode(_receivedHTTPHeaders); + + if (responseCode >= 400) { + SRFastLog(@"Request failed with response code %d", responseCode); + [self _failWithError:[NSError errorWithDomain:@"org.lolrus.SocketRocket" code:2132 userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"received bad response code from server %u", (int)responseCode] forKey:NSLocalizedDescriptionKey]]]; + return; + + } + + if(![self _checkHandshake:_receivedHTTPHeaders]) { + [self _failWithError:[NSError errorWithDomain:FSRWebSocketErrorDomain code:2133 userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"Invalid Sec-WebSocket-Accept response"] forKey:NSLocalizedDescriptionKey]]]; + return; + } + + NSString *negotiatedProtocol = CFBridgingRelease(CFHTTPMessageCopyHeaderFieldValue(_receivedHTTPHeaders, CFSTR("Sec-WebSocket-Protocol"))); + if (negotiatedProtocol) { + // Make sure we requested the protocol + if ([_requestedProtocols indexOfObject:negotiatedProtocol] == NSNotFound) { + [self _failWithError:[NSError errorWithDomain:FSRWebSocketErrorDomain code:2133 userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"Server specified Sec-WebSocket-Protocol that wasn't requested"] forKey:NSLocalizedDescriptionKey]]]; + return; + } + + _protocol = negotiatedProtocol; + } + + self.readyState = SR_OPEN; + + if (!_didFail) { + [self _readFrameNew]; + } + + [self _performDelegateBlock:^{ + if ([self.delegate respondsToSelector:@selector(webSocketDidOpen)]) { + [self.delegate webSocketDidOpen]; + }; + }]; +} + + +- (void)_readHTTPHeader; +{ + if (_receivedHTTPHeaders == NULL) { + _receivedHTTPHeaders = CFHTTPMessageCreateEmpty(NULL, NO); + } + + [self _readUntilHeaderCompleteWithCallback:^(FSRWebSocket *self, NSData *data) { + CFHTTPMessageAppendBytes(self->_receivedHTTPHeaders, (const UInt8 *)data.bytes, data.length); + + if (CFHTTPMessageIsHeaderComplete(self->_receivedHTTPHeaders)) { + SRFastLog(@"Finished reading headers %@", CFBridgingRelease(CFHTTPMessageCopyAllHeaderFields(self->_receivedHTTPHeaders))); + [self _HTTPHeadersDidFinish]; + } else { + [self _readHTTPHeader]; + } + }]; +} + +- (void)didConnect +{ + SRFastLog(@"Connected"); + CFHTTPMessageRef request = CFHTTPMessageCreateRequest(NULL, CFSTR("GET"), (__bridge CFURLRef)_url, kCFHTTPVersion1_1); + + // Set host first so it defaults + CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Host"), (__bridge CFStringRef) + (_url.port != nil ? [NSString stringWithFormat:@"%@:%@", + _url.host, _url.port] : _url.host)); + + NSMutableData *keyBytes = [[NSMutableData alloc] initWithLength:16]; + int __unused result = + SecRandomCopyBytes(kSecRandomDefault, keyBytes.length, keyBytes.mutableBytes); + assert(result == 0); + _secKey = [FSRUtilities base64EncodedStringFromData:keyBytes]; + assert([_secKey length] == 24); + + CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Upgrade"), CFSTR("websocket")); + CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Connection"), CFSTR("Upgrade")); + if (_userAgent) { + CFHTTPMessageSetHeaderFieldValue(request, CFSTR("User-Agent"), (__bridge CFStringRef)_userAgent); + } + + if (_googleAppID) { + CFHTTPMessageSetHeaderFieldValue(request, CFSTR("X-Firebase-GMPID"), (__bridge CFStringRef)_googleAppID); + } + + CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Sec-WebSocket-Key"), (__bridge CFStringRef)_secKey); + CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Sec-WebSocket-Version"), (__bridge CFStringRef)[NSString stringWithFormat:@"%u", (int)_webSocketVersion]); + + CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Origin"), (__bridge CFStringRef)_url.SR_origin); + + if (_requestedProtocols) { + CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Sec-WebSocket-Protocol"), (__bridge CFStringRef)[_requestedProtocols componentsJoinedByString:@", "]); + } + + [_urlRequest.allHTTPHeaderFields enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + CFHTTPMessageSetHeaderFieldValue(request, (__bridge CFStringRef)key, (__bridge CFStringRef)obj); + }]; + + NSData *message = CFBridgingRelease(CFHTTPMessageCopySerializedMessage(request)); + + CFRelease(request); + + [self _writeData:message]; + [self _readHTTPHeader]; +} + +//- (void)_connectToHost:(NSString *)host port:(NSInteger)port; +- (void)_initializeStreams; +{ + NSInteger port = _url.port.integerValue; + if (port == 0) { + if (!_secure) { + port = 80; + } else { + port = 443; + } + } + NSString *host = _url.host; + + CFReadStreamRef readStream = NULL; + CFWriteStreamRef writeStream = NULL; + + CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)host, (int)port, &readStream, &writeStream); + + // XXX + CFReadStreamSetProperty(readStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeBackground); + CFWriteStreamSetProperty(writeStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeBackground); + + _outputStream = CFBridgingRelease(writeStream); + _inputStream = CFBridgingRelease(readStream); + + + if (_secure) { + NSMutableDictionary *SSLOptions = [[NSMutableDictionary alloc] init]; + + [_outputStream setProperty:(__bridge id)kCFStreamSocketSecurityLevelNegotiatedSSL forKey:(__bridge id)kCFStreamPropertySocketSecurityLevel]; + + // If we're using pinned certs, don't validate the certificate chain + if ([_urlRequest FSR_SSLPinnedCertificates].count) { + [SSLOptions setValue:[NSNumber numberWithBool:NO] forKey:(__bridge id)kCFStreamSSLValidatesCertificateChain]; + } + + [_outputStream setProperty:SSLOptions + forKey:(__bridge id)kCFStreamPropertySSLSettings]; + } + + _inputStream.delegate = self; + _outputStream.delegate = self; + + [_outputStream open]; + [_inputStream open]; +} + +- (void)_connect; +{ + if (!_scheduledRunloops.count) { + [self scheduleInRunLoop:[NSRunLoop FSR_networkRunLoop] forMode:NSDefaultRunLoopMode]; + } + + + [_outputStream open]; + [_inputStream open]; +} + +- (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode; +{ + [_outputStream scheduleInRunLoop:aRunLoop forMode:mode]; + [_inputStream scheduleInRunLoop:aRunLoop forMode:mode]; + + [_scheduledRunloops addObject:@[aRunLoop, mode]]; +} + +- (void)unscheduleFromRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode; +{ + [_outputStream removeFromRunLoop:aRunLoop forMode:mode]; + [_inputStream removeFromRunLoop:aRunLoop forMode:mode]; + + [_scheduledRunloops removeObject:@[aRunLoop, mode]]; +} + +- (void)close; +{ + [self closeWithCode:-1 reason:nil]; +} + +- (void)closeWithCode:(NSInteger)code reason:(NSString *)reason; +{ + assert(code); + dispatch_async(_workQueue, ^{ + if (self.readyState == SR_CLOSING || self.readyState == SR_CLOSED) { + return; + } + + BOOL wasConnecting = self.readyState == SR_CONNECTING; + + self.readyState = SR_CLOSING; + + SRFastLog(@"Closing with code %d reason %@", code, reason); + + if (wasConnecting) { + [self _disconnect]; + return; + } + + size_t maxMsgSize = [reason maximumLengthOfBytesUsingEncoding:NSUTF8StringEncoding]; + NSMutableData *mutablePayload = [[NSMutableData alloc] initWithLength:sizeof(uint16_t) + maxMsgSize]; + NSData *payload = mutablePayload; + + ((uint16_t *)mutablePayload.mutableBytes)[0] = EndianU16_BtoN(code); + + if (reason) { + NSRange remainingRange = {0}; + + NSUInteger usedLength = 0; + + BOOL __unused success = + [reason getBytes:(char *)mutablePayload.mutableBytes + sizeof(uint16_t) + maxLength:payload.length - sizeof(uint16_t) + usedLength:&usedLength + encoding:NSUTF8StringEncoding + options:NSStringEncodingConversionExternalRepresentation + range:NSMakeRange(0, reason.length) + remainingRange:&remainingRange]; + + assert(success); + assert(remainingRange.length == 0); + + if (usedLength != maxMsgSize) { + payload = [payload subdataWithRange:NSMakeRange(0, usedLength + sizeof(uint16_t))]; + } + } + + + [self _sendFrameWithOpcode:SROpCodeConnectionClose data:payload]; + }); +} + +- (void)_closeWithProtocolError:(NSString *)message; +{ + // Need to shunt this on the _callbackQueue first to see if they received any messages + [self _performDelegateBlock:^{ + [self closeWithCode:SRStatusCodeProtocolError reason:message]; + dispatch_async(self->_workQueue, ^{ + [self _disconnect]; + }); + }]; +} + +- (void)_failWithError:(NSError *)error; +{ + dispatch_async(_workQueue, ^{ + if (self.readyState != SR_CLOSED) { + self->_failed = YES; + [self _performDelegateBlock:^{ + if ([self.delegate respondsToSelector:@selector(webSocket:didFailWithError:)]) { + [self.delegate webSocket:self didFailWithError:error]; + } + }]; + + self.readyState = SR_CLOSED; + + SRFastLog(@"Failing with error %@", error.localizedDescription); + + [self _disconnect]; + [self _scheduleCleanup]; + } + }); +} + +- (void)_writeData:(NSData *)data; +{ + [self assertOnWorkQueue]; + + if (_closeWhenFinishedWriting) { + return; + } + [_outputBuffer appendData:data]; + [self _pumpWriting]; +} +- (void)send:(id)data; +{ + SRFastLog(@"Sending data %@", data); + NSAssert(self.readyState != SR_CONNECTING, @"Invalid State: Cannot call send: until connection is open"); + // TODO: maybe not copy this for performance + data = [data copy]; + dispatch_async(_workQueue, ^{ + if ([data isKindOfClass:[NSString class]]) { + [self _sendFrameWithOpcode:SROpCodeTextFrame data:[(NSString *)data dataUsingEncoding:NSUTF8StringEncoding]]; + } else if ([data isKindOfClass:[NSData class]]) { + [self _sendFrameWithOpcode:SROpCodeBinaryFrame data:data]; + } else if (data == nil) { + [self _sendFrameWithOpcode:SROpCodeTextFrame data:data]; + } else { + assert(NO); + } + }); +} + +- (void)handlePing:(NSData *)pingData; +{ + // Need to pingpong this off _callbackQueue first to make sure messages happen in order + [self _performDelegateBlock:^{ + dispatch_async(self->_workQueue, ^{ + [self _sendFrameWithOpcode:SROpCodePong data:pingData]; + }); + }]; +} + +- (void)handlePong; +{ + // NOOP +} + +- (void)_handleMessage:(id)message +{ + SRFastLog(@"Received message"); + [self _performDelegateBlock:^{ + if ([self.delegate respondsToSelector:@selector(webSocket:didReceiveMessage:)]) { + [self.delegate webSocket:self didReceiveMessage:message]; + } + }]; +} + + +static inline BOOL closeCodeIsValid(int closeCode) { + if (closeCode < 1000) { + return NO; + } + + if (closeCode >= 1000 && closeCode <= 1011) { + if (closeCode == 1004 || + closeCode == 1005 || + closeCode == 1006) { + return NO; + } + return YES; + } + + if (closeCode >= 3000 && closeCode <= 3999) { + return YES; + } + + if (closeCode >= 4000 && closeCode <= 4999) { + return YES; + } + + return NO; +} + +// Note from RFC: +// +// If there is a body, the first two +// bytes of the body MUST be a 2-byte unsigned integer (in network byte +// order) representing a status code with value /code/ defined in +// Section 7.4. Following the 2-byte integer the body MAY contain UTF-8 +// encoded data with value /reason/, the interpretation of which is not +// defined by this specification. + +- (void)handleCloseWithData:(NSData *)data; +{ + size_t dataSize = data.length; + __block uint16_t closeCode = 0; + + SRFastLog(@"Received close frame"); + + if (dataSize == 1) { + // TODO handle error + [self _closeWithProtocolError:@"Payload for close must be larger than 2 bytes"]; + return; + } else if (dataSize >= 2) { + [data getBytes:&closeCode length:sizeof(closeCode)]; + _closeCode = EndianU16_BtoN(closeCode); + if (!closeCodeIsValid(_closeCode)) { + [self _closeWithProtocolError:[NSString stringWithFormat:@"Cannot have close code of %d", _closeCode]]; + return; + } + if (dataSize > 2) { + _closeReason = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(2, dataSize - 2)] encoding:NSUTF8StringEncoding]; + if (!_closeReason) { + [self _closeWithProtocolError:@"Close reason MUST be valid UTF-8"]; + return; + } + } + } else { + _closeCode = SRStatusNoStatusReceived; + } + + [self assertOnWorkQueue]; + + if (self.readyState == SR_OPEN) { + [self closeWithCode:1000 reason:nil]; + } + dispatch_async(_workQueue, ^{ + [self _disconnect]; + }); +} + +- (void)_disconnect; +{ + [self assertOnWorkQueue]; + SRFastLog(@"Trying to disconnect"); + _closeWhenFinishedWriting = YES; + [self _pumpWriting]; +} + +- (void)_handleFrameWithData:(NSData *)frameData opCode:(NSInteger)opcode; +{ + // Check that the current data is valid UTF8 + + BOOL isControlFrame = (opcode == SROpCodePing || opcode == SROpCodePong || opcode == SROpCodeConnectionClose); + if (!isControlFrame) { + [self _readFrameNew]; + } else { + dispatch_async(_workQueue, ^{ + [self _readFrameContinue]; + }); + } + + switch (opcode) { + case SROpCodeTextFrame: { + NSString *str = [[NSString alloc] initWithData:frameData encoding:NSUTF8StringEncoding]; + if (str == nil && frameData) { + [self closeWithCode:SRStatusCodeInvalidUTF8 reason:@"Text frames must be valid UTF-8"]; + dispatch_async(_workQueue, ^{ + [self _disconnect]; + }); + + return; + } + [self _handleMessage:str]; + break; + } + case SROpCodeBinaryFrame: + [self _handleMessage:[frameData copy]]; + break; + case SROpCodeConnectionClose: + [self handleCloseWithData:frameData]; + break; + case SROpCodePing: + [self handlePing:frameData]; + break; + case SROpCodePong: + [self handlePong]; + break; + default: + [self _closeWithProtocolError:[NSString stringWithFormat:@"Unknown opcode %u", (int)opcode]]; + // TODO: Handle invalid opcode + break; + } +} + +- (void)_handleFrameHeader:(frame_header)frame_header curData:(NSData *)curData; +{ + assert(frame_header.opcode != 0); + + if (self.readyState != SR_OPEN) { + return; + } + + + BOOL isControlFrame = (frame_header.opcode == SROpCodePing || frame_header.opcode == SROpCodePong || frame_header.opcode == SROpCodeConnectionClose); + + if (isControlFrame && !frame_header.fin) { + [self _closeWithProtocolError:@"Fragmented control frames not allowed"]; + return; + } + + if (isControlFrame && frame_header.payload_length >= 126) { + [self _closeWithProtocolError:@"Control frames cannot have payloads larger than 126 bytes"]; + return; + } + + if (!isControlFrame) { + _currentFrameOpcode = frame_header.opcode; + _currentFrameCount += 1; + } + + if (frame_header.payload_length == 0) { + if (isControlFrame) { + [self _handleFrameWithData:curData opCode:frame_header.opcode]; + } else { + if (frame_header.fin) { + [self _handleFrameWithData:_currentFrameData opCode:frame_header.opcode]; + } else { + // TODO add assert that opcode is not a control; + [self _readFrameContinue]; + } + } + } else { + [self _addConsumerWithDataLength:(size_t)frame_header.payload_length callback:^(FSRWebSocket *self, NSData *newData) { + if (isControlFrame) { + [self _handleFrameWithData:newData opCode:frame_header.opcode]; + } else { + if (frame_header.fin) { + [self _handleFrameWithData:self->_currentFrameData opCode:frame_header.opcode]; + } else { + // TODO add assert that opcode is not a control; + [self _readFrameContinue]; + } + + } + } readToCurrentFrame:!isControlFrame unmaskBytes:frame_header.masked]; + } +} + +/* From RFC: + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-------+-+-------------+-------------------------------+ + |F|R|R|R| opcode|M| Payload len | Extended payload length | + |I|S|S|S| (4) |A| (7) | (16/64) | + |N|V|V|V| |S| | (if payload len==126/127) | + | |1|2|3| |K| | | + +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + + | Extended payload length continued, if payload len == 127 | + + - - - - - - - - - - - - - - - +-------------------------------+ + | |Masking-key, if MASK set to 1 | + +-------------------------------+-------------------------------+ + | Masking-key (continued) | Payload Data | + +-------------------------------- - - - - - - - - - - - - - - - + + : Payload Data continued ... : + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + | Payload Data continued ... | + +---------------------------------------------------------------+ + */ + +static const uint8_t SRFinMask = 0x80; +static const uint8_t SROpCodeMask = 0x0F; +static const uint8_t SRRsvMask = 0x70; +static const uint8_t SRMaskMask = 0x80; +static const uint8_t SRPayloadLenMask = 0x7F; + + +- (void)_readFrameContinue; +{ + assert((_currentFrameCount == 0 && _currentFrameOpcode == 0) || (_currentFrameCount > 0 && _currentFrameOpcode > 0)); + + [self _addConsumerWithDataLength:2 callback:^(FSRWebSocket *self, NSData *data) { + __block frame_header header = {0}; + + const uint8_t *headerBuffer = data.bytes; + assert(data.length >= 2); + + if (headerBuffer[0] & SRRsvMask) { + [self _closeWithProtocolError:@"Server used RSV bits"]; + return; + } + + uint8_t receivedOpcode = (SROpCodeMask & headerBuffer[0]); + + BOOL isControlFrame = (receivedOpcode == SROpCodePing || receivedOpcode == SROpCodePong || receivedOpcode == SROpCodeConnectionClose); + + if (!isControlFrame && receivedOpcode != 0 && self->_currentFrameCount > 0) { + [self _closeWithProtocolError:@"all data frames after the initial data frame must have opcode 0"]; + return; + } + + if (receivedOpcode == 0 && self->_currentFrameCount == 0) { + [self _closeWithProtocolError:@"cannot continue a message"]; + return; + } + + header.opcode = receivedOpcode == 0 ? self->_currentFrameOpcode : receivedOpcode; + + header.fin = !!(SRFinMask & headerBuffer[0]); + + + header.masked = !!(SRMaskMask & headerBuffer[1]); + header.payload_length = SRPayloadLenMask & headerBuffer[1]; + + headerBuffer = NULL; + + if (header.masked) { + [self _closeWithProtocolError:@"Client must receive unmasked data"]; + } + + size_t extra_bytes_needed = header.masked ? sizeof(self->_currentReadMaskKey) : 0; + + if (header.payload_length == 126) { + extra_bytes_needed += sizeof(uint16_t); + } else if (header.payload_length == 127) { + extra_bytes_needed += sizeof(uint64_t); + } + + if (extra_bytes_needed == 0) { + [self _handleFrameHeader:header curData:self->_currentFrameData]; + } else { + [self _addConsumerWithDataLength:extra_bytes_needed callback:^(FSRWebSocket *self, NSData *data) { + size_t __unused mapped_size = data.length; + const void *mapped_buffer = data.bytes; + size_t offset = 0; + + if (header.payload_length == 126) { + assert(mapped_size >= sizeof(uint16_t)); + uint16_t newLen = EndianU16_BtoN(*(uint16_t *)(mapped_buffer)); + header.payload_length = newLen; + offset += sizeof(uint16_t); + } else if (header.payload_length == 127) { + assert(mapped_size >= sizeof(uint64_t)); + header.payload_length = EndianU64_BtoN(*(uint64_t *)(mapped_buffer)); + offset += sizeof(uint64_t); + } else { + assert(header.payload_length < 126 && header.payload_length >= 0); + } + + + if (header.masked) { + assert(mapped_size >= sizeof(self->_currentReadMaskOffset) + offset); + memcpy(self->_currentReadMaskKey, ((uint8_t *)mapped_buffer) + offset, sizeof(self->_currentReadMaskKey)); + } + + [self _handleFrameHeader:header curData:self->_currentFrameData]; + } readToCurrentFrame:NO unmaskBytes:NO]; + } + } readToCurrentFrame:NO unmaskBytes:NO]; +} + +- (void)_readFrameNew; +{ + dispatch_async(_workQueue, ^{ + [self->_currentFrameData setLength:0]; + + self->_currentFrameOpcode = 0; + self->_currentFrameCount = 0; + self->_readOpCount = 0; + self->_currentStringScanPosition = 0; + + [self _readFrameContinue]; + }); +} + +- (void)_pumpWriting; +{ + [self assertOnWorkQueue]; + + NSUInteger dataLength = _outputBuffer.length; + if (dataLength - _outputBufferOffset > 0 && _outputStream.hasSpaceAvailable) { + NSUInteger bytesWritten = [_outputStream write:_outputBuffer.bytes + _outputBufferOffset maxLength:dataLength - _outputBufferOffset]; + if (bytesWritten == -1) { + [self _failWithError:[NSError errorWithDomain:@"org.lolrus.SocketRocket" code:2145 userInfo:[NSDictionary dictionaryWithObject:@"Error writing to stream" forKey:NSLocalizedDescriptionKey]]]; + return; + } + + _outputBufferOffset += bytesWritten; + + if (_outputBufferOffset > 4096 && _outputBufferOffset > (_outputBuffer.length >> 1)) { + _outputBuffer = [[NSMutableData alloc] initWithBytes:(char *)_outputBuffer.bytes + _outputBufferOffset length:_outputBuffer.length - _outputBufferOffset]; + _outputBufferOffset = 0; + } + } + + if (_closeWhenFinishedWriting && + _outputBuffer.length - _outputBufferOffset == 0 && + (_inputStream.streamStatus != NSStreamStatusNotOpen && + _inputStream.streamStatus != NSStreamStatusClosed) && + !_sentClose) { + _sentClose = YES; + + @synchronized (self) { + [_outputStream close]; + [_inputStream close]; + + // TODO: Why are we missing the SocketRocket code to call unscheduleFromRunLoop??? + } + + if (!_failed) { + [self _performDelegateBlock:^{ + if ([self.delegate respondsToSelector:@selector(webSocket:didCloseWithCode:reason:wasClean:)]) { + [self.delegate webSocket:self didCloseWithCode:self->_closeCode reason:self->_closeReason wasClean:YES]; + } + }]; + } + [self _scheduleCleanup]; + } +} + +- (void)_addConsumerWithScanner:(stream_scanner)consumer callback:(data_callback)callback; +{ + [self assertOnWorkQueue]; + [self _addConsumerWithScanner:consumer callback:callback dataLength:0]; +} + +- (void)_addConsumerWithDataLength:(size_t)dataLength callback:(data_callback)callback readToCurrentFrame:(BOOL)readToCurrentFrame unmaskBytes:(BOOL)unmaskBytes; +{ + [self assertOnWorkQueue]; + assert(dataLength); + + [_consumers addObject:[_consumerPool consumerWithScanner:nil handler:callback bytesNeeded:dataLength readToCurrentFrame:readToCurrentFrame unmaskBytes:unmaskBytes]]; + [self _pumpScanner]; +} + +- (void)_addConsumerWithScanner:(stream_scanner)consumer callback:(data_callback)callback dataLength:(size_t)dataLength; +{ + [self assertOnWorkQueue]; + [_consumers addObject:[_consumerPool consumerWithScanner:consumer handler:callback bytesNeeded:dataLength readToCurrentFrame:NO unmaskBytes:NO]]; + [self _pumpScanner]; +} + + +- (void)_scheduleCleanup +{ + @synchronized(self) { + if (_cleanupScheduled) { + return; + } + + _cleanupScheduled = YES; + + // Cleanup NSStream delegate's in the same RunLoop used by the streams themselves: + // This way we'll prevent race conditions between handleEvent and SRWebsocket's dealloc + NSTimer *timer = [NSTimer timerWithTimeInterval:(0.0f) target:self selector:@selector(_cleanupSelfReference:) userInfo:nil repeats:NO]; + [[NSRunLoop FSR_networkRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; + } +} + +- (void)_cleanupSelfReference:(NSTimer *)timer +{ + @synchronized(self) { + // Nuke NSStream delegate's + _inputStream.delegate = nil; + _outputStream.delegate = nil; + + // Remove the streams, right now, from the networkRunLoop + [_inputStream close]; + [_outputStream close]; + } + + // Cleanup selfRetain in the same GCD queue as usual + dispatch_async(_workQueue, ^{ + self->_selfRetain = nil; + }); +} + + +static const char CRLFCRLFBytes[] = {'\r', '\n', '\r', '\n'}; + +- (void)_readUntilHeaderCompleteWithCallback:(data_callback)dataHandler; +{ + [self _readUntilBytes:CRLFCRLFBytes length:sizeof(CRLFCRLFBytes) callback:dataHandler]; +} + +- (void)_readUntilBytes:(const void *)bytes length:(size_t)length callback:(data_callback)dataHandler; +{ + // TODO optimize so this can continue from where we last searched + stream_scanner consumer = ^size_t(NSData *data) { + __block size_t found_size = 0; + __block size_t match_count = 0; + + size_t size = data.length; + const unsigned char *buffer = data.bytes; + for (int i = 0; i < size; i++ ) { + if (((const unsigned char *)buffer)[i] == ((const unsigned char *)bytes)[match_count]) { + match_count += 1; + if (match_count == length) { + found_size = i + 1; + break; + } + } else { + match_count = 0; + } + } + return found_size; + }; + [self _addConsumerWithScanner:consumer callback:dataHandler]; +} + + +// Returns true if did work +- (BOOL)_innerPumpScanner { + + BOOL didWork = NO; + + if (self.readyState >= SR_CLOSING) { + return didWork; + } + + if (!_consumers.count) { + return didWork; + } + + size_t curSize = _readBuffer.length - _readBufferOffset; + if (!curSize) { + return didWork; + } + + FSRIOConsumer *consumer = [_consumers objectAtIndex:0]; + + size_t bytesNeeded = consumer.bytesNeeded; + + size_t foundSize = 0; + if (consumer.consumer) { + NSData *tempView = [NSData dataWithBytesNoCopy:(char *)_readBuffer.bytes + _readBufferOffset length:_readBuffer.length - _readBufferOffset freeWhenDone:NO]; + foundSize = consumer.consumer(tempView); + } else { + assert(consumer.bytesNeeded); + if (curSize >= bytesNeeded) { + foundSize = bytesNeeded; + } else if (consumer.readToCurrentFrame) { + foundSize = curSize; + } + } + + NSData *slice = nil; + if (consumer.readToCurrentFrame || foundSize) { + NSRange sliceRange = NSMakeRange(_readBufferOffset, foundSize); + slice = [_readBuffer subdataWithRange:sliceRange]; + + _readBufferOffset += foundSize; + + if (_readBufferOffset > 4096 && _readBufferOffset > (_readBuffer.length >> 1)) { + _readBuffer = [[NSMutableData alloc] initWithBytes:(char *)_readBuffer.bytes + _readBufferOffset length:_readBuffer.length - _readBufferOffset]; _readBufferOffset = 0; + } + + if (consumer.unmaskBytes) { + NSMutableData *mutableSlice = [slice mutableCopy]; + + NSUInteger len = mutableSlice.length; + uint8_t *bytes = mutableSlice.mutableBytes; + + for (int i = 0; i < len; i++) { + bytes[i] = bytes[i] ^ _currentReadMaskKey[_currentReadMaskOffset % sizeof(_currentReadMaskKey)]; + _currentReadMaskOffset += 1; + } + + slice = mutableSlice; + } + + if (consumer.readToCurrentFrame) { + [_currentFrameData appendData:slice]; + + _readOpCount += 1; + + if (_currentFrameOpcode == SROpCodeTextFrame) { + // Validate UTF8 stuff. + size_t currentDataSize = _currentFrameData.length; + if (_currentFrameOpcode == SROpCodeTextFrame && currentDataSize > 0) { + // TODO: Optimize the crap out of this. Don't really have to copy all the data each time + + size_t scanSize = currentDataSize - _currentStringScanPosition; + + NSData *scan_data = [_currentFrameData subdataWithRange:NSMakeRange(_currentStringScanPosition, scanSize)]; + int32_t valid_utf8_size = validate_dispatch_data_partial_string(scan_data); + + if (valid_utf8_size == -1) { + [self closeWithCode:SRStatusCodeInvalidUTF8 reason:@"Text frames must be valid UTF-8"]; + dispatch_async(_workQueue, ^{ + [self _disconnect]; + }); + return didWork; + } else { + _currentStringScanPosition += valid_utf8_size; + } + } + + } + + consumer.bytesNeeded -= foundSize; + + if (consumer.bytesNeeded == 0) { + [_consumers removeObjectAtIndex:0]; + consumer.handler(self, nil); + didWork = YES; + } + } else if (foundSize) { + [_consumers removeObjectAtIndex:0]; + consumer.handler(self, slice); + didWork = YES; + } + } + return didWork; +} + +-(void)_pumpScanner; +{ + [self assertOnWorkQueue]; + + if (!_isPumping) { + _isPumping = YES; + } else { + return; + } + + while ([self _innerPumpScanner]) { + + } + + _isPumping = NO; +} + +//#define NOMASK + +static const size_t SRFrameHeaderOverhead = 32; + +- (void)_sendFrameWithOpcode:(FSROpCode)opcode data:(id)data; +{ + [self assertOnWorkQueue]; + + if (data == nil) { + return; + } + + NSAssert([data isKindOfClass:[NSData class]] || [data isKindOfClass:[NSString class]], @"Function expects nil, NSString or NSData"); + + size_t payloadLength = [data isKindOfClass:[NSString class]] ? [(NSString *)data lengthOfBytesUsingEncoding:NSUTF8StringEncoding] : [data length]; + + NSMutableData *frame = [[NSMutableData alloc] initWithLength:payloadLength + SRFrameHeaderOverhead]; + if (!frame) { + [self closeWithCode:SRStatusCodeMessageTooBig reason:@"Message too big"]; + return; + } + uint8_t *frame_buffer = (uint8_t *)[frame mutableBytes]; + + // set fin + frame_buffer[0] = SRFinMask | opcode; + + BOOL useMask = YES; + +#endif // !TARGET_OS_WATCH +#ifdef NOMASK + useMask = NO; +#endif +#if !TARGET_OS_WATCH + + if (useMask) { + // set the mask and header + frame_buffer[1] |= SRMaskMask; + } + + size_t frame_buffer_size = 2; + + const uint8_t *unmasked_payload = NULL; + if ([data isKindOfClass:[NSData class]]) { + unmasked_payload = (uint8_t *)[data bytes]; + } else if ([data isKindOfClass:[NSString class]]) { + unmasked_payload = (const uint8_t *)[data UTF8String]; + } else { + assert(NO); + } + + if (payloadLength < 126) { + frame_buffer[1] |= payloadLength; + } else if (payloadLength <= UINT16_MAX) { + frame_buffer[1] |= 126; + *((uint16_t *)(frame_buffer + frame_buffer_size)) = EndianU16_BtoN((uint16_t)payloadLength); + frame_buffer_size += sizeof(uint16_t); + } else { + frame_buffer[1] |= 127; + *((uint64_t *)(frame_buffer + frame_buffer_size)) = EndianU64_BtoN((uint64_t)payloadLength); + frame_buffer_size += sizeof(uint64_t); + } + + if (!useMask) { + for (int i = 0; i < payloadLength; i++) { + frame_buffer[frame_buffer_size] = unmasked_payload[i]; + frame_buffer_size += 1; + } + } else { + uint8_t *mask_key = frame_buffer + frame_buffer_size; + int __unused result = + SecRandomCopyBytes(kSecRandomDefault, sizeof(uint32_t), (uint8_t *)mask_key); + assert(result == 0); + frame_buffer_size += sizeof(uint32_t); + + // TODO: could probably optimize this with SIMD + for (int i = 0; i < payloadLength; i++) { + frame_buffer[frame_buffer_size] = unmasked_payload[i] ^ mask_key[i % sizeof(uint32_t)]; + frame_buffer_size += 1; + } + } + + assert(frame_buffer_size <= [frame length]); + frame.length = frame_buffer_size; + + [self _writeData:frame]; +} + +- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode; +{ + __weak __typeof__(self) weakSelf = self; + + // turn on keep-alive for the output stream. + if (eventCode == NSStreamEventOpenCompleted && aStream == _outputStream) { + CFDataRef socketData = CFWriteStreamCopyProperty((CFWriteStreamRef)_outputStream, kCFStreamPropertySocketNativeHandle); + // In rare cases socketData might be nil (there are crash reports out there), in which case we'll have to just + // live without keep-alive :( + if (socketData != nil) { + CFSocketNativeHandle socket; + CFDataGetBytes(socketData, CFRangeMake(0, sizeof(CFSocketNativeHandle)), (UInt8 *)&socket); + CFRelease(socketData); + + int keepAliveOn = 1; + if (setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, &keepAliveOn, sizeof(keepAliveOn)) == -1) { + SRFastLog(@"Failed to turn on TCP keepalive for websocket"); + } + } + } + + if (_secure && !_pinnedCertFound && (eventCode == NSStreamEventHasBytesAvailable || eventCode == NSStreamEventHasSpaceAvailable)) { + + NSArray *sslCerts = [_urlRequest FSR_SSLPinnedCertificates]; + if (sslCerts) { + SecTrustRef secTrust = (__bridge SecTrustRef)[aStream propertyForKey:(__bridge id)kCFStreamPropertySSLPeerTrust]; + if (secTrust) { + NSInteger numCerts = SecTrustGetCertificateCount(secTrust); + for (NSInteger i = 0; i < numCerts && !_pinnedCertFound; i++) { + SecCertificateRef cert = SecTrustGetCertificateAtIndex(secTrust, i); + NSData *certData = CFBridgingRelease(SecCertificateCopyData(cert)); + + for (id ref in sslCerts) { + SecCertificateRef trustedCert = (__bridge SecCertificateRef)ref; + NSData *trustedCertData = CFBridgingRelease(SecCertificateCopyData(trustedCert)); + + if ([trustedCertData isEqualToData:certData]) { + _pinnedCertFound = YES; + break; + } + } + } + } + + if (!_pinnedCertFound) { + dispatch_async(_workQueue, ^{ + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : @"Invalid server cert" }; + [weakSelf _failWithError:[NSError errorWithDomain:@"org.lolrus.SocketRocket" code:23556 userInfo:userInfo]]; + }); + return; + } + } + } + + // SRFastLog(@"%@ Got stream event %d", aStream, eventCode); + dispatch_async(_workQueue, ^{ + [weakSelf safeHandleEvent:eventCode stream:aStream]; + }); +} + +- (void)safeHandleEvent:(NSStreamEvent)eventCode stream:(NSStream *)aStream +{ + switch (eventCode) { + case NSStreamEventOpenCompleted: { + SRFastLog(@"NSStreamEventOpenCompleted %@", aStream); + if (self.readyState >= SR_CLOSING) { + return; + } + + + assert(_readBuffer); + + if (self.readyState == SR_CONNECTING && aStream == _inputStream) { + [self didConnect]; + } + [self _pumpWriting]; + [self _pumpScanner]; + break; + } + + case NSStreamEventErrorOccurred: { + // Note: The upstream code for SocketRocket logs the error message, but this causes + // crashes on iOS 13 (https://github.com/firebase/firebase-ios-sdk/issues/3950) + SRFastLog(@"NSStreamEventErrorOccurred %@", aStream); + /// TODO specify error better! + [self _failWithError:aStream.streamError]; + _readBufferOffset = 0; + [_readBuffer setLength:0]; + break; + + } + + case NSStreamEventEndEncountered: { + [self _pumpScanner]; + SRFastLog(@"NSStreamEventEndEncountered %@", aStream); + if (aStream.streamError) { + [self _failWithError:aStream.streamError]; + } else { + dispatch_async(_workQueue, ^{ + if (self.readyState != SR_CLOSED) { + self.readyState = SR_CLOSED; + [self _scheduleCleanup]; + } + + if (!self->_sentClose && !self->_failed) { + self->_sentClose = YES; + // If we get closed in this state it's probably not clean because we should be sending this when we send messages + [self _performDelegateBlock:^{ + if ([self.delegate respondsToSelector:@selector(webSocket:didCloseWithCode:reason:wasClean:)]) { + [self.delegate webSocket:self didCloseWithCode:0 reason:@"Stream end encountered" wasClean:NO]; + } + }]; + } + }); + } + + break; + } + + case NSStreamEventHasBytesAvailable: { + SRFastLog(@"NSStreamEventHasBytesAvailable %@", aStream); + + #define FSRWEB_SOCKET_BUFFER_SIZE 2048 + uint8_t buffer[FSRWEB_SOCKET_BUFFER_SIZE]; + + + while (_inputStream.hasBytesAvailable) { + NSInteger bytes_read = [_inputStream read:buffer maxLength:FSRWEB_SOCKET_BUFFER_SIZE]; + + if (bytes_read > 0) { + [_readBuffer appendBytes:buffer length:bytes_read]; + } else if (bytes_read < 0) { + [self _failWithError:_inputStream.streamError]; + } + + if (bytes_read != FSRWEB_SOCKET_BUFFER_SIZE) { + break; + } + }; + [self _pumpScanner]; + break; + } + + case NSStreamEventHasSpaceAvailable: { + SRFastLog(@"NSStreamEventHasSpaceAvailable %@", aStream); + [self _pumpWriting]; + break; + } + + default: + SRFastLog(@"(default) %@", aStream); + break; + } +} + +@end + + +@implementation FSRIOConsumer + +@synthesize bytesNeeded = _bytesNeeded; +@synthesize consumer = _scanner; +@synthesize handler = _handler; +@synthesize readToCurrentFrame = _readToCurrentFrame; +@synthesize unmaskBytes = _unmaskBytes; + +- (void)setupWithScanner:(stream_scanner)scanner handler:(data_callback)handler bytesNeeded:(size_t)bytesNeeded readToCurrentFrame:(BOOL)readToCurrentFrame unmaskBytes:(BOOL)unmaskBytes; +{ + _scanner = [scanner copy]; + _handler = [handler copy]; + _bytesNeeded = bytesNeeded; + _readToCurrentFrame = readToCurrentFrame; + _unmaskBytes = unmaskBytes; + assert(_scanner || _bytesNeeded); +} + +@end + +@implementation FSRIOConsumerPool { + NSUInteger _poolSize; + NSMutableArray *_bufferedConsumers; +} + +- (id)initWithBufferCapacity:(NSUInteger)poolSize; +{ + self = [super init]; + if (self) { + _poolSize = poolSize; + _bufferedConsumers = [[NSMutableArray alloc] initWithCapacity:poolSize]; + } + return self; +} + +- (id)init +{ + return [self initWithBufferCapacity:8]; +} + +- (FSRIOConsumer *)consumerWithScanner:(stream_scanner)scanner handler:(data_callback)handler bytesNeeded:(size_t)bytesNeeded readToCurrentFrame:(BOOL)readToCurrentFrame unmaskBytes:(BOOL)unmaskBytes; +{ + FSRIOConsumer *consumer = nil; + if (_bufferedConsumers.count) { + consumer = [_bufferedConsumers lastObject]; + [_bufferedConsumers removeLastObject]; + } else { + consumer = [[FSRIOConsumer alloc] init]; + } + + [consumer setupWithScanner:scanner handler:handler bytesNeeded:bytesNeeded readToCurrentFrame:readToCurrentFrame unmaskBytes:unmaskBytes]; + + return consumer; +} + +- (void)returnConsumer:(FSRIOConsumer *)consumer; +{ + if (_bufferedConsumers.count < _poolSize) { + [_bufferedConsumers addObject:consumer]; + } +} + +@end + +@implementation NSURLRequest (FCertificateAdditions) + +- (NSArray *)FSR_SSLPinnedCertificates; +{ + return [NSURLProtocol propertyForKey:@"FSR_SSLPinnedCertificates" inRequest:self]; +} + +@end + +@implementation NSMutableURLRequest (FCertificateAdditions) + +- (NSArray *)FSR_SSLPinnedCertificates; +{ + return [NSURLProtocol propertyForKey:@"FSR_SSLPinnedCertificates" inRequest:self]; +} + +- (void)setFSR_SSLPinnedCertificates:(NSArray *)FSR_SSLPinnedCertificates; +{ + [NSURLProtocol setProperty:FSR_SSLPinnedCertificates forKey:@"FSR_SSLPinnedCertificates" inRequest:self]; +} + +@end + +@implementation NSURL (FSRWebSocket) + +- (NSString *)SR_origin; +{ + NSString *scheme = [self.scheme lowercaseString]; + + if ([scheme isEqualToString:@"wss"]) { + scheme = @"https"; + } else if ([scheme isEqualToString:@"ws"]) { + scheme = @"http"; + } + + if (self.port != nil) { + return [NSString stringWithFormat:@"%@://%@:%@/", scheme, self.host, self.port]; + } else { + return [NSString stringWithFormat:@"%@://%@/", scheme, self.host]; + } +} + +@end + +// #define SR_ENABLE_LOG + +static inline void SRFastLog(NSString *format, ...) { +#ifdef SR_ENABLE_LOG + __block va_list arg_list; + va_start (arg_list, format); + + NSString *formattedString = [[NSString alloc] initWithFormat:format arguments:arg_list]; + + va_end(arg_list); + + NSLog(@"[SR] %@", formattedString); +#endif +} + + +#ifdef HAS_ICU + +static inline int32_t validate_dispatch_data_partial_string(NSData *data) { + + const void * contents = [data bytes]; + long size = [data length]; + + const uint8_t *str = (const uint8_t *)contents; + + + UChar32 codepoint = 1; + int32_t offset = 0; + int32_t lastOffset = 0; + while(offset < size && codepoint > 0) { + lastOffset = offset; + U8_NEXT(str, offset, size, codepoint); + } + + if (codepoint == -1) { + // Check to see if the last byte is valid or whether it was just continuing + if (!U8_IS_LEAD(str[lastOffset]) || U8_COUNT_TRAIL_BYTES(str[lastOffset]) + lastOffset < (int32_t)size) { + + size = -1; + } else { + uint8_t leadByte = str[lastOffset]; + U8_MASK_LEAD_BYTE(leadByte, U8_COUNT_TRAIL_BYTES(leadByte)); + + for (int i = lastOffset + 1; i < offset; i++) { + + if (U8_IS_SINGLE(str[i]) || U8_IS_LEAD(str[i]) || !U8_IS_TRAIL(str[i])) { + size = -1; + } + } + + if (size != -1) { + size = lastOffset; + } + } + } + + if (size != -1 && ![[NSString alloc] initWithBytesNoCopy:(char *)[data bytes] length:size encoding:NSUTF8StringEncoding freeWhenDone:NO]) { + size = -1; + } + + return (int32_t)size; +} + +#else + +// This is a hack, and probably not optimal +static inline int32_t validate_dispatch_data_partial_string(NSData *data) { + static const int maxCodepointSize = 3; + + for (int i = 0; i < maxCodepointSize; i++) { + NSString *str = [[NSString alloc] initWithBytesNoCopy:(char *)data.bytes length:data.length - i encoding:NSUTF8StringEncoding freeWhenDone:NO]; + if (str) { + return (int)(data.length - i); + } + } + + return -1; +} + +#endif + +static _FSRRunLoopThread *networkThread = nil; +static NSRunLoop *networkRunLoop = nil; + +@implementation NSRunLoop (FSRWebSocket) + ++ (NSRunLoop *)FSR_networkRunLoop { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + networkThread = [[_FSRRunLoopThread alloc] init]; + networkThread.name = @"com.squareup.SocketRocket.NetworkThread"; + networkThread.qualityOfService = NSQualityOfServiceUserInitiated; + [networkThread start]; + networkRunLoop = networkThread.runLoop; + }); + + return networkRunLoop; +} + +@end + + +@implementation _FSRRunLoopThread { + dispatch_group_t _waitGroup; +} + +@synthesize runLoop = _runLoop; + +- (void)dealloc +{ + sr_dispatch_release(_waitGroup); +} + +- (id)init +{ + self = [super init]; + if (self) { + _waitGroup = dispatch_group_create(); + dispatch_group_enter(_waitGroup); + } + return self; +} + + +/** + * This is the main method of the thread on which the socket events are scheduled in a run loop. + */ +- (void)main; +{ + @autoreleasepool { + _runLoop = [NSRunLoop currentRunLoop]; + dispatch_group_leave(_waitGroup); + + // Add an empty run loop source to prevent runloop from spinning. + CFRunLoopSourceContext sourceCtx = { + .version = 0, + .info = NULL, + .retain = NULL, + .release = NULL, + .copyDescription = NULL, + .equal = NULL, + .hash = NULL, + .schedule = NULL, + .cancel = NULL, + .perform = NULL + }; + CFRunLoopSourceRef source = CFRunLoopSourceCreate(NULL, 0, &sourceCtx); + CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode); + CFRelease(source); + + while ([_runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]) { + + } + assert(NO); + } +} + +- (NSRunLoop *)runLoop; +{ + dispatch_group_wait(_waitGroup, DISPATCH_TIME_FOREVER); + return _runLoop; +} + +@end +#endif // TARGET_OS_WATCH diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/NSData+SRB64Additions.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/NSData+SRB64Additions.h new file mode 100644 index 0000000..bac393b --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/NSData+SRB64Additions.h @@ -0,0 +1,23 @@ +// +// Copyright 2012 Square Inc. +// +// 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 + +@interface FSRUtilities : NSObject + ++ (NSString *)base64EncodedStringFromData:(NSData *)data; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/NSData+SRB64Additions.m b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/NSData+SRB64Additions.m new file mode 100644 index 0000000..7cea4e8 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/NSData+SRB64Additions.m @@ -0,0 +1,37 @@ +// +// Copyright 2012 Square Inc. +// +// 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 "FirebaseDatabase/Sources/third_party/SocketRocket/NSData+SRB64Additions.h" +#import "FirebaseDatabase/Sources/third_party/SocketRocket/fbase64.h" + +@implementation FSRUtilities + ++ (NSString *)base64EncodedStringFromData:(NSData *)data { + size_t buffer_size = ((data.length * 3 + 2) / 2); + + char *buffer = (char *)malloc(buffer_size); + + int len = f_b64_ntop(data.bytes, data.length, buffer, buffer_size); + + if (len == -1) { + free(buffer); + return nil; + } else{ + return [[NSString alloc] initWithBytesNoCopy:buffer length:len encoding:NSUTF8StringEncoding freeWhenDone:YES]; + } +} + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/fbase64.c b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/fbase64.c new file mode 100644 index 0000000..9f77b53 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/fbase64.c @@ -0,0 +1,318 @@ +/* $OpenBSD: base64.c,v 1.5 2006/10/21 09:55:03 otto Exp $ */ + +/* + * Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions Copyright (c) 1995 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * To the extent it has a right to do so, IBM grants an immunity from suit + * under its patents, if any, for the use, sale or manufacture of products to + * the extent that such products are used for performing Domain Name System + * dynamic updates in TCP/IP networks by means of the Software. No immunity is + * granted for any product per se or for any other function of any product. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +/* OPENBSD ORIGINAL: lib/libc/net/base64.c */ + + +// +// Distributed with modifications by Firebase ( https://www.firebase.com ) +// + +#if (!defined(HAVE_B64_NTOP) && !defined(HAVE___B64_NTOP)) || (!defined(HAVE_B64_PTON) && !defined(HAVE___B64_PTON)) + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "FirebaseDatabase/Sources/third_party/SocketRocket/fbase64.h" + +static const char Base64[] = +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char Pad64 = '='; + +/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) + The following encoding technique is taken from RFC 1521 by Borenstein + and Freed. It is reproduced here in a slightly edited form for + convenience. + + A 65-character subset of US-ASCII is used, enabling 6 bits to be + represented per printable character. (The extra 65th character, "=", + is used to signify a special processing function.) + + The encoding process represents 24-bit groups of input bits as output + strings of 4 encoded characters. Proceeding from left to right, a + 24-bit input group is formed by concatenating 3 8-bit input groups. + These 24 bits are then treated as 4 concatenated 6-bit groups, each + of which is translated into a single digit in the base64 alphabet. + + Each 6-bit group is used as an index into an array of 64 printable + characters. The character referenced by the index is placed in the + output string. + + Table 1: The Base64 Alphabet + + Value Encoding Value Encoding Value Encoding Value Encoding + 0 A 17 R 34 i 51 z + 1 B 18 S 35 j 52 0 + 2 C 19 T 36 k 53 1 + 3 D 20 U 37 l 54 2 + 4 E 21 V 38 m 55 3 + 5 F 22 W 39 n 56 4 + 6 G 23 X 40 o 57 5 + 7 H 24 Y 41 p 58 6 + 8 I 25 Z 42 q 59 7 + 9 J 26 a 43 r 60 8 + 10 K 27 b 44 s 61 9 + 11 L 28 c 45 t 62 + + 12 M 29 d 46 u 63 / + 13 N 30 e 47 v + 14 O 31 f 48 w (pad) = + 15 P 32 g 49 x + 16 Q 33 h 50 y + + Special processing is performed if fewer than 24 bits are available + at the end of the data being encoded. A full encoding quantum is + always completed at the end of a quantity. When fewer than 24 input + bits are available in an input group, zero bits are added (on the + right) to form an integral number of 6-bit groups. Padding at the + end of the data is performed using the '=' character. + + Since all base64 input is an integral number of octets, only the + ------------------------------------------------- + following cases can arise: + + (1) the final quantum of encoding input is an integral + multiple of 24 bits; here, the final unit of encoded + output will be an integral multiple of 4 characters + with no "=" padding, + (2) the final quantum of encoding input is exactly 8 bits; + here, the final unit of encoded output will be two + characters followed by two "=" padding characters, or + (3) the final quantum of encoding input is exactly 16 bits; + here, the final unit of encoded output will be three + characters followed by one "=" padding character. + */ + +#if !defined(HAVE_B64_NTOP) && !defined(HAVE___B64_NTOP) +int +f_b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize) +{ + size_t datalength = 0; + u_char input[3]; + u_char output[4]; + u_int i; + + while (2 < srclength) { + input[0] = *src++; + input[1] = *src++; + input[2] = *src++; + srclength -= 3; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + output[3] = input[2] & 0x3f; + + if (datalength + 4 > targsize) + return (-1); + target[datalength++] = Base64[output[0]]; + target[datalength++] = Base64[output[1]]; + target[datalength++] = Base64[output[2]]; + target[datalength++] = Base64[output[3]]; + } + + /* Now we worry about padding. */ + if (0 != srclength) { + /* Get what's left. */ + input[0] = input[1] = input[2] = '\0'; + for (i = 0; i < srclength; i++) + input[i] = *src++; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + + if (datalength + 4 > targsize) + return (-1); + target[datalength++] = Base64[output[0]]; + target[datalength++] = Base64[output[1]]; + if (srclength == 1) + target[datalength++] = Pad64; + else + target[datalength++] = Base64[output[2]]; + target[datalength++] = Pad64; + } + if (datalength >= targsize) + return (-1); + target[datalength] = '\0'; /* Returned value doesn't count \0. */ + return (int)(datalength); +} +#endif /* !defined(HAVE_B64_NTOP) && !defined(HAVE___B64_NTOP) */ + +#if !defined(HAVE_B64_PTON) && !defined(HAVE___B64_PTON) + +/* skips all whitespace anywhere. + converts characters, four at a time, starting at (or after) + src from base - 64 numbers into three 8 bit bytes in the target area. + it returns the number of data bytes stored at the target, or -1 on error. + */ + +int +f_b64_pton(char const *src, u_char *target, size_t targsize) +{ + u_int tarindex, state; + int ch; + char *pos; + + state = 0; + tarindex = 0; + + while ((ch = *src++) != '\0') { + if (isspace(ch)) /* Skip whitespace anywhere. */ + continue; + + if (ch == Pad64) + break; + + pos = strchr(Base64, ch); + if (pos == 0) /* A non-base64 character. */ + return (-1); + + switch (state) { + case 0: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] = (pos - Base64) << 2; + } + state = 1; + break; + case 1: + if (target) { + if (tarindex + 1 >= targsize) + return (-1); + target[tarindex] |= (pos - Base64) >> 4; + target[tarindex+1] = ((pos - Base64) & 0x0f) + << 4 ; + } + tarindex++; + state = 2; + break; + case 2: + if (target) { + if (tarindex + 1 >= targsize) + return (-1); + target[tarindex] |= (pos - Base64) >> 2; + target[tarindex+1] = ((pos - Base64) & 0x03) + << 6; + } + tarindex++; + state = 3; + break; + case 3: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] |= (pos - Base64); + } + tarindex++; + state = 0; + break; + } + } + + /* + * We are done decoding Base-64 chars. Let's see if we ended + * on a byte boundary, and/or with erroneous trailing characters. + */ + + if (ch == Pad64) { /* We got a pad char. */ + ch = *src++; /* Skip it, get next. */ + switch (state) { + case 0: /* Invalid = in first position */ + case 1: /* Invalid = in second position */ + return (-1); + + case 2: /* Valid, means one byte of info */ + /* Skip any number of spaces. */ + for (; ch != '\0'; ch = *src++) + if (!isspace(ch)) + break; + /* Make sure there is another trailing = sign. */ + if (ch != Pad64) + return (-1); + ch = *src++; /* Skip the = */ + /* Fall through to "single trailing =" case. */ + /* FALLTHROUGH */ + + case 3: /* Valid, means two bytes of info */ + /* + * We know this char is an =. Is there anything but + * whitespace after it? + */ + for (; ch != '\0'; ch = *src++) + if (!isspace(ch)) + return (-1); + + /* + * Now make sure for cases 2 and 3 that the "extra" + * bits that slopped past the last full byte were + * zeros. If we don't check them, they become a + * subliminal channel. + */ + if (target && target[tarindex] != 0) + return (-1); + } + } else { + /* + * We ended by seeing the end of the string. Make sure we + * have no partial bytes lying around. + */ + if (state != 0) + return (-1); + } + + return (tarindex); +} + +#endif /* !defined(HAVE_B64_PTON) && !defined(HAVE___B64_PTON) */ +#endif diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/fbase64.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/fbase64.h new file mode 100644 index 0000000..a9bf142 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/SocketRocket/fbase64.h @@ -0,0 +1,33 @@ +// Copyright 2012 Square Inc. +// +// 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 FSocketRocket_base64_h +#define FSocketRocket_base64_h + +#include + +extern int +f_b64_ntop(u_char const *src, + size_t srclength, + char *target, + size_t targsize); + +extern int +f_b64_pton(char const *src, + u_char *target, + size_t targsize); + + +#endif diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/Wrap-leveldb/APLevelDB.h b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/Wrap-leveldb/APLevelDB.h new file mode 100644 index 0000000..c0baa22 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/Wrap-leveldb/APLevelDB.h @@ -0,0 +1,105 @@ +// +// APLevelDB.h +// +// Created by Adam Preble on 1/23/12. +// Copyright (c) 2012 Adam Preble. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + +extern NSString * const APLevelDBErrorDomain; + +@class APLevelDBIterator; +@protocol APLevelDBWriteBatch; + +@interface APLevelDB : NSObject + +@property (nonatomic, readonly, strong) NSString *path; + ++ (APLevelDB *)levelDBWithPath:(NSString *)path error:(NSError *__autoreleasing*)errorOut; +- (void)close; + +- (BOOL)setData:(NSData *)data forKey:(NSString *)key; +- (BOOL)setString:(NSString *)str forKey:(NSString *)key; + +- (NSData *)dataForKey:(NSString *)key; +- (NSString *)stringForKey:(NSString *)key; + +- (BOOL)removeKey:(NSString *)key; + +- (NSArray *)allKeys; + +- (void)enumerateKeys:(void (^)(NSString *key, BOOL *stop))block; +- (void)enumerateKeysWithPrefix:(NSString *)prefix usingBlock:(void (^)(NSString *key, BOOL *stop))block; + +- (void)enumerateKeysAndValuesAsStrings:(void (^)(NSString *key, NSString *value, BOOL *stop))block; +- (void)enumerateKeysWithPrefix:(NSString *)prefix asStrings:(void (^)(NSString *key, NSString *value, BOOL *stop))block; + +- (void)enumerateKeysAndValuesAsData:(void (^)(NSString *key, NSData *value, BOOL *stop))block; +- (void)enumerateKeysWithPrefix:(NSString *)prefix asData:(void (^)(NSString *key, NSData *value, BOOL *stop))block; + +- (NSUInteger)approximateSizeFrom:(NSString *)from to:(NSString *)to; +- (NSUInteger)exactSizeFrom:(NSString *)from to:(NSString *)to; + +// Objective-C Subscripting Support: +// The database object supports subscripting for string-string and string-data key-value access and assignment. +// Examples: +// db[@"key"] = @"value"; +// db[@"key"] = [NSData data]; +// NSString *s = db[@"key"]; +// An NSInvalidArgumentException is raised if the key is not an NSString, or if the assigned object is not an +// instance of NSString or NSData. +- (id)objectForKeyedSubscript:(id)key; +- (void)setObject:(id)object forKeyedSubscript:(id)key; + +// Batch write/atomic update support: +- (id)beginWriteBatch; + +@end + + +@interface APLevelDBIterator : NSObject + ++ (id)iteratorWithLevelDB:(APLevelDB *)db; + +// Designated initializer: +- (id)initWithLevelDB:(APLevelDB *)db; + +- (BOOL)seekToKey:(NSString *)key; +- (NSString *)nextKey; +- (NSString *)key; +- (NSString *)valueAsString; +- (NSData *)valueAsData; + +@end + + +@protocol APLevelDBWriteBatch + +- (void)setData:(NSData *)data forKey:(NSString *)key; +- (void)setString:(NSString *)str forKey:(NSString *)key; + +- (void)removeKey:(NSString *)key; + +// Remove all of the buffered sets and removes: +- (void)clear; +- (BOOL)commit; + +@end diff --git a/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/Wrap-leveldb/APLevelDB.mm b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/Wrap-leveldb/APLevelDB.mm new file mode 100644 index 0000000..14b5c93 --- /dev/null +++ b/Pods/FirebaseDatabase/FirebaseDatabase/Sources/third_party/Wrap-leveldb/APLevelDB.mm @@ -0,0 +1,500 @@ +// +// APLevelDB.m +// +// Created by Adam Preble on 1/23/12. +// Copyright (c) 2012 Adam Preble. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// +// Portions of APLevelDB are based on LevelDB-ObjC: +// https://github.com/hoisie/LevelDB-ObjC +// Specifically the SliceFromString/StringFromSlice macros, and the structure of +// the enumeration methods. License for those potions follows: +// +// Copyright (c) 2011 Pave Labs +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#import "FirebaseDatabase/Sources/third_party/Wrap-leveldb/APLevelDB.h" + +#import "leveldb/db.h" +#import "leveldb/options.h" +#import "leveldb/write_batch.h" + +NSString * const APLevelDBErrorDomain = @"APLevelDBErrorDomain"; + +#define SliceFromString(_string_) (leveldb::Slice((char *)[_string_ UTF8String], [_string_ lengthOfBytesUsingEncoding:NSUTF8StringEncoding])) +#define StringFromSlice(_slice_) ([[NSString alloc] initWithBytes:_slice_.data() length:_slice_.size() encoding:NSUTF8StringEncoding]) + + +@interface APLevelDBWriteBatch : NSObject { + @package + leveldb::WriteBatch _batch; +} + +@property (nonatomic, strong) APLevelDB *levelDB; + +- (id)initWithLevelDB:(APLevelDB *)levelDB; +@end + + +#pragma mark - APLevelDB + +@interface APLevelDB () { + leveldb::DB *_db; + leveldb::ReadOptions _readOptions; + leveldb::WriteOptions _writeOptions; +} +- (id)initWithPath:(NSString *)path error:(NSError **)errorOut; ++ (leveldb::Options)defaultCreateOptions; +@property (nonatomic, readonly) leveldb::DB *db; +@end + + +@implementation APLevelDB + +@synthesize path = _path; +@synthesize db = _db; + ++ (APLevelDB *)levelDBWithPath:(NSString *)path error:(NSError *__autoreleasing *)errorOut +{ + return [[APLevelDB alloc] initWithPath:path error:errorOut]; +} + +- (id)initWithPath:(NSString *)path error:(NSError *__autoreleasing *)errorOut +{ + if ((self = [super init])) + { + _path = path; + + leveldb::Options options = [[self class] defaultCreateOptions]; + + leveldb::Status status = leveldb::DB::Open(options, [_path UTF8String], &_db); + + if (!status.ok()) + { + if (errorOut) + { + NSString *statusString = [[NSString alloc] initWithCString:status.ToString().c_str() encoding:NSUTF8StringEncoding]; + *errorOut = [NSError errorWithDomain:APLevelDBErrorDomain + code:0 + userInfo:[NSDictionary dictionaryWithObjectsAndKeys:statusString, NSLocalizedDescriptionKey, nil]]; + } + return nil; + } + + _writeOptions.sync = false; + } + return self; +} + +- (void)close { + if (_db != NULL) { + delete _db; + _db = NULL; + } +} + +- (void)dealloc +{ + if (_db != NULL) { + delete _db; + _db = NULL; + } +} + ++ (leveldb::Options)defaultCreateOptions +{ + leveldb::Options options; + options.create_if_missing = true; + return options; +} + +- (BOOL)setData:(NSData *)data forKey:(NSString *)key +{ + leveldb::Slice keySlice = SliceFromString(key); + leveldb::Slice valueSlice = leveldb::Slice((const char *)[data bytes], (size_t)[data length]); + leveldb::Status status = _db->Put(_writeOptions, keySlice, valueSlice); + return (status.ok() == true); +} + +- (BOOL)setString:(NSString *)str forKey:(NSString *)key +{ + // This could have been based on + leveldb::Slice keySlice = SliceFromString(key); + leveldb::Slice valueSlice = SliceFromString(str); + leveldb::Status status = _db->Put(_writeOptions, keySlice, valueSlice); + return (status.ok() == true); +} + +- (NSData *)dataForKey:(NSString *)key +{ + leveldb::Slice keySlice = SliceFromString(key); + std::string valueCPPString; + leveldb::Status status = _db->Get(_readOptions, keySlice, &valueCPPString); + + if (!status.ok()) + return nil; + else + return [NSData dataWithBytes:valueCPPString.data() length:valueCPPString.size()]; +} + +- (NSString *)stringForKey:(NSString *)key +{ + leveldb::Slice keySlice = SliceFromString(key); + std::string valueCPPString; + leveldb::Status status = _db->Get(_readOptions, keySlice, &valueCPPString); + + // We assume (dangerously?) UTF-8 string encoding: + if (!status.ok()) + return nil; + else + return [[NSString alloc] initWithBytes:valueCPPString.data() length:valueCPPString.size() encoding:NSUTF8StringEncoding]; +} + +- (BOOL)removeKey:(NSString *)key +{ + leveldb::Slice keySlice = SliceFromString(key); + leveldb::Status status = _db->Delete(_writeOptions, keySlice); + return (status.ok() == true); +} + +- (NSArray *)allKeys +{ + NSMutableArray *keys = [NSMutableArray array]; + [self enumerateKeys:^(NSString *key, BOOL *stop) { + [keys addObject:key]; + }]; + return keys; +} + +- (void)enumerateKeysAndValuesAsStrings:(void (^)(NSString *key, NSString *value, BOOL *stop))block +{ + [self enumerateKeysWithPrefix:@"" asStrings:block]; +} + +- (void)enumerateKeysWithPrefix:(NSString *)prefixString asStrings:(void (^)(NSString *, NSString *, BOOL *))block +{ + @autoreleasepool { + BOOL stop = NO; + leveldb::Iterator* iter = _db->NewIterator(leveldb::ReadOptions()); + leveldb::Slice prefix = SliceFromString(prefixString); + for (iter->Seek(prefix); iter->Valid(); iter->Next()) { + leveldb::Slice key = iter->key(), value = iter->value(); + if (key.starts_with(prefix)) { + NSString *k = StringFromSlice(key); + NSString *v = [[NSString alloc] initWithBytes:value.data() length:value.size() encoding:NSUTF8StringEncoding]; + block(k, v, &stop); + if (stop) + break; + } else { + break; + } + } + + delete iter; + } +} + +- (void)enumerateKeys:(void (^)(NSString *key, BOOL *stop))block +{ + [self enumerateKeysWithPrefix:@"" usingBlock:block]; +} + +- (void)enumerateKeysWithPrefix:(NSString *)prefixString usingBlock:(void (^)(NSString *key, BOOL *stop))block; +{ + @autoreleasepool { + BOOL stop = NO; + leveldb::Slice prefix = SliceFromString(prefixString); + leveldb::Iterator* iter = _db->NewIterator(leveldb::ReadOptions()); + for (iter->Seek(prefix); iter->Valid(); iter->Next()) { + leveldb::Slice key = iter->key(); + if (key.starts_with(prefix)) { + NSString *k = StringFromSlice(key); + block(k, &stop); + if (stop) + break; + } else { + break; + } + } + + delete iter; + } +} + +- (void)enumerateKeysAndValuesAsData:(void (^)(NSString *key, NSData *data, BOOL *stop))block +{ + [self enumerateKeysWithPrefix:@"" asData:block]; +} + +- (void)enumerateKeysWithPrefix:(NSString *)prefixString asData:(void (^)(NSString *, NSData *, BOOL *))block +{ + @autoreleasepool { + BOOL stop = NO; + leveldb::Iterator* iter = _db->NewIterator(leveldb::ReadOptions()); + leveldb::Slice prefix = SliceFromString(prefixString); + for (iter->Seek(prefix); iter->Valid(); iter->Next()) { + leveldb::Slice key = iter->key(), value = iter->value(); + if (key.starts_with(prefix)) { + NSString *k = StringFromSlice(key); + NSData *data = [NSData dataWithBytes:value.data() length:value.size()]; + block(k, data, &stop); + if (stop) + break; + } else { + break; + } + } + + delete iter; + } +} + +- (NSUInteger)exactSizeFrom:(NSString *)from to:(NSString *)to { + NSUInteger size = 0; + leveldb::Iterator* iter = _db->NewIterator(leveldb::ReadOptions()); + leveldb::Slice fromSlice = SliceFromString(from); + leveldb::Slice toSlice = SliceFromString(to); + iter->Seek(fromSlice); + while (iter->Valid() && iter->key().compare(toSlice) <= 0) { + size += iter->value().size(); + iter->Next(); + } + delete iter; + return size; +} + + +- (NSUInteger)approximateSizeFrom:(NSString *)from to:(NSString *)to { + leveldb::Range ranges[1]; + leveldb::Slice fromSlice = SliceFromString(from); + leveldb::Slice toSlice = SliceFromString(to); + ranges[0] = leveldb::Range(fromSlice, toSlice); + uint64_t sizes[1]; + _db->GetApproximateSizes(ranges, 1, sizes); + return (NSUInteger)sizes[0]; +} + +#pragma mark - Subscripting Support + +- (id)objectForKeyedSubscript:(id)key +{ + if (![key respondsToSelector: @selector(componentsSeparatedByString:)]) + { + [NSException raise:NSInvalidArgumentException format:@"key must be an NSString"]; + } + return [self stringForKey:key]; +} +- (void)setObject:(id)thing forKeyedSubscript:(id)key +{ + id idKey = (id) key; + if (![idKey respondsToSelector: @selector(componentsSeparatedByString:)]) + { + [NSException raise:NSInvalidArgumentException format:@"key must be NSString or NSData"]; + } + + if ([thing respondsToSelector:@selector(componentsSeparatedByString:)]) + [self setString:thing forKey:(NSString *)key]; + else if ([thing respondsToSelector:@selector(subdataWithRange:)]) + [self setData:thing forKey:(NSString *)key]; + else + [NSException raise:NSInvalidArgumentException format:@"object must be NSString or NSData"]; +} + +#pragma mark - Atomic Updates + +- (id)beginWriteBatch +{ + APLevelDBWriteBatch *batch = [[APLevelDBWriteBatch alloc] initWithLevelDB:self]; + return batch; +} + +- (BOOL)commitWriteBatch:(id)theBatch +{ + if (!theBatch) + return NO; + + APLevelDBWriteBatch *batch = theBatch; + + leveldb::Status status; + status = _db->Write(_writeOptions, &batch->_batch); + return (status.ok() == true); +} + +@end + + +#pragma mark - APLevelDBIterator + +@interface APLevelDBIterator () { + leveldb::Iterator *_iter; +} + +@property (nonatomic, strong) APLevelDB *levelDB; +@end + + + +@implementation APLevelDBIterator + ++ (id)iteratorWithLevelDB:(APLevelDB *)db +{ + APLevelDBIterator *iter = [[[self class] alloc] initWithLevelDB:db]; + return iter; +} + +- (id)initWithLevelDB:(APLevelDB *)db +{ + if ((self = [super init])) + { + // Hold on to the database so it doesn't get deallocated before the iterator is deallocated + self->_levelDB = db; + _iter = db.db->NewIterator(leveldb::ReadOptions()); + _iter->SeekToFirst(); + if (!_iter->Valid()) + return nil; + } + return self; +} + +- (id)init +{ + [NSException raise:@"BadInitializer" format:@"Use the designated initializer, -initWithLevelDB:, instead."]; + return nil; +} + +- (void)dealloc +{ + self->_levelDB = nil; + delete _iter; + _iter = NULL; +} + +- (BOOL)seekToKey:(NSString *)key +{ + leveldb::Slice target = SliceFromString(key); + _iter->Seek(target); + return _iter->Valid() == true; +} + +- (void)seekToFirst +{ + _iter->SeekToFirst(); +} + +- (void)seekToLast +{ + _iter->SeekToLast(); +} + +- (NSString *)nextKey +{ + _iter->Next(); + return [self key]; +} + +- (NSString *)key +{ + if (_iter->Valid() == false) + return nil; + leveldb::Slice value = _iter->key(); + return StringFromSlice(value); +} + +- (NSString *)valueAsString +{ + if (_iter->Valid() == false) + return nil; + leveldb::Slice value = _iter->value(); + return StringFromSlice(value); +} + +- (NSData *)valueAsData +{ + if (_iter->Valid() == false) + return nil; + leveldb::Slice value = _iter->value(); + return [NSData dataWithBytes:value.data() length:value.size()]; +} + +@end + + + +#pragma mark - APLevelDBWriteBatch + +@implementation APLevelDBWriteBatch + +- (id)initWithLevelDB:(APLevelDB *)levelDB { + self = [super init]; + if (self != nil) { + self->_levelDB = levelDB; + } + return self; +} + +- (void)setData:(NSData *)data forKey:(NSString *)key +{ + leveldb::Slice keySlice = SliceFromString(key); + leveldb::Slice valueSlice = leveldb::Slice((const char *)[data bytes], (size_t)[data length]); + _batch.Put(keySlice, valueSlice); +} +- (void)setString:(NSString *)str forKey:(NSString *)key +{ + leveldb::Slice keySlice = SliceFromString(key); + leveldb::Slice valueSlice = SliceFromString(str); + _batch.Put(keySlice, valueSlice); +} + +- (void)removeKey:(NSString *)key +{ + leveldb::Slice keySlice = SliceFromString(key); + _batch.Delete(keySlice); +} + +- (void)clear +{ + _batch.Clear(); +} + +- (BOOL)commit { + return [self.levelDB commitWriteBatch:self]; +} + +@end + diff --git a/Pods/FirebaseDatabase/README.md b/Pods/FirebaseDatabase/README.md new file mode 100644 index 0000000..85a23bd --- /dev/null +++ b/Pods/FirebaseDatabase/README.md @@ -0,0 +1,281 @@ +

+ + + + + + + + +
+ + + + + + +

+ +# Firebase Apple Open Source Development + +This repository contains all Apple platform Firebase SDK source except FirebaseAnalytics. + +Firebase is an app development platform with tools to help you build, grow and +monetize your app. More information about Firebase can be found on the +[official Firebase website](https://firebase.google.com). + +## Installation + +See the subsections below for details about the different installation methods. Where +available, it's recommended to install any libraries with a `Swift` suffix to get the +best experience when writing your app in Swift. +1. [Standard pod install](#standard-pod-install) +1. [Swift Package Manager](#swift-package-manager) +1. [Installing from the GitHub repo](#installing-from-github) +1. [Experimental Carthage](#carthage-ios-only) + +### Standard pod install + +Go to +[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup). + +### Swift Package Manager + +Instructions for [Swift Package Manager](https://swift.org/package-manager/) support can be +found at [SwiftPackageManager](SwiftPackageManager.md) Markdown file. + +### Installing from GitHub + +These instructions can be used to access the Firebase repo at other branches, +tags, or commits. + +#### Background + +See +[the Podfile Syntax Reference](https://guides.cocoapods.org/syntax/podfile.html#pod) +for instructions and options about overriding pod source locations. + +#### Accessing Firebase Source Snapshots + +All of the official releases are tagged in this repo and available via CocoaPods. To access a local +source snapshot or unreleased branch, use Podfile directives like the following: + +To access FirebaseFirestore via a branch: +```ruby +pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master' +pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master' +``` + +To access FirebaseMessaging via a checked out version of the firebase-ios-sdk repo do: + +```ruby +pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk' +pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk' +``` + +### Carthage (iOS only) + +Instructions for the experimental Carthage distribution are at +[Carthage](Carthage.md). + +### Using Firebase from a Framework or a library + +[Using Firebase from a Framework or a library](docs/firebase_in_libraries.md) + +## Development + +To develop Firebase software in this repository, ensure that you have at least +the following software: + + * Xcode 14.1 (or later) + +CocoaPods is still the canonical way to develop, but much of the repo now supports +development with Swift Package Manager. + +### CocoaPods + +Install + * CocoaPods 1.10.0 (or later) + * [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +```ruby +pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios +``` + +Note: If the CocoaPods cache is out of date, you may need to run +`pod repo update` before the `pod gen` command. + +Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for +those platforms. Since 10.2, Xcode does not properly handle multi-platform +CocoaPods workspaces. + +Firestore has a self contained Xcode project. See +[Firestore/README](Firestore/README.md) Markdown file. + +#### Development for Catalyst +* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios` +* Check the Mac box in the App-iOS Build Settings +* Sign the App in the Settings Signing & Capabilities tab +* Click Pods in the Project Manager +* Add Signing to the iOS host app and unit test targets +* Select the Unit-unit scheme +* Run it to build and test + +Alternatively disable signing in each target: +* Go to Build Settings tab +* Click `+` +* Select `Add User-Defined Setting` +* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO` + +### Swift Package Manager +* To enable test schemes: `./scripts/setup_spm_tests.sh` +* `open Package.swift` or double click `Package.swift` in Finder. +* Xcode will open the project + * Choose a scheme for a library to build or test suite to run + * Choose a target platform by selecting the run destination along with the scheme + +### Adding a New Firebase Pod + +See [AddNewPod](AddNewPod.md) Markdown file. + +### Managing Headers and Imports + +See [HeadersImports](HeadersImports.md) Markdown file. + +### Code Formatting + +To ensure that the code is formatted consistently, run the script +[./scripts/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/master/scripts/check.sh) +before creating a PR. + +GitHub Actions will verify that any code changes are done in a style compliant +way. Install `clang-format` and `mint`: + +```console +brew install clang-format@16 +brew install mint +``` + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +### Running Sample Apps +In order to run the sample apps and integration tests, you'll need a valid +`GoogleService-Info.plist` file. The Firebase Xcode project contains dummy plist +files without real values, but can be replaced with real plist files. To get your own +`GoogleService-Info.plist` files: + +1. Go to the [Firebase Console](https://console.firebase.google.com/) +2. Create a new Firebase project, if you don't already have one +3. For each sample app you want to test, create a new Firebase app with the sample app's bundle +identifier (e.g. `com.google.Database-Example`) +4. Download the resulting `GoogleService-Info.plist` and add it to the Xcode project. + +### Coverage Report Generation + +See [scripts/code_coverage_report/README](scripts/code_coverage_report/README.md) Markdown file. + +## Specific Component Instructions +See the sections below for any special instructions for those components. + +### Firebase Auth + +If you're doing specific Firebase Auth development, see +[the Auth Sample README](FirebaseAuth/Tests/Sample/README.md) for instructions about +building and running the FirebaseAuth pod along with various samples and tests. + +### Firebase Database + +The Firebase Database Integration tests can be run against a locally running Database Emulator +or against a production instance. + +To run against a local emulator instance, invoke `./scripts/run_database_emulator.sh start` before +running the integration test. + +To run against a production instance, provide a valid GoogleServices-Info.plist and copy it to +`FirebaseDatabase/Tests/Resources/GoogleService-Info.plist`. Your Security Rule must be set to +[public](https://firebase.google.com/docs/database/security/quickstart) while your tests are +running. + +### Firebase Performance Monitoring +If you're doing specific Firebase Performance Monitoring development, see +[the Performance README](FirebasePerformance/README.md) for instructions about building the SDK +and [the Performance TestApp README](FirebasePerformance/Tests/TestApp/README.md) for instructions about +integrating Performance with the dev test App. + +### Firebase Storage + +To run the Storage Integration tests, follow the instructions in +[StorageIntegration.swift](FirebaseStorage/Tests/Integration/StorageIntegration.swift). + +#### Push Notifications + +Push notifications can only be delivered to specially provisioned App IDs in the developer portal. +In order to actually test receiving push notifications, you will need to: + +1. Change the bundle identifier of the sample app to something you own in your Apple Developer +account, and enable that App ID for push notifications. +2. You'll also need to +[upload your APNs Provider Authentication Key or certificate to the +Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs) +at **Project Settings > Cloud Messaging > [Your Firebase App]**. +3. Ensure your iOS device is added to your Apple Developer portal as a test device. + +#### iOS Simulator + +The iOS Simulator cannot register for remote notifications, and will not receive push notifications. +In order to receive push notifications, you'll have to follow the steps above and run the app on a +physical device. + +## Building with Firebase on Apple platforms + +Firebase 8.9.0 introduced official beta support for macOS, Catalyst, and tvOS. watchOS continues +to be community supported. Thanks to community contributions for many of the multi-platform PRs. + +At this time, most of Firebase's products are available across Apple platforms. There are still +a few gaps, especially on watchOS. For details about the current support matrix, see +[this chart](https://firebase.google.com/docs/ios/learn-more#firebase_library_support_by_platform) +in Firebase's documentation. + +### watchOS +Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and +work on watchOS. See the [Independent Watch App Sample](Example/watchOSSample). + +Keep in mind that watchOS is not officially supported by Firebase. While we can catch basic unit +test issues with GitHub Actions, there may be some changes where the SDK no longer works as expected +on watchOS. If you encounter this, please +[file an issue](https://github.com/firebase/firebase-ios-sdk/issues). + +During app setup in the console, you may get to a step that mentions something like "Checking if the +app has communicated with our servers". This relies on Analytics and will not work on watchOS. +**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected. + +#### Additional Crashlytics Notes +* watchOS has limited support. Due to watchOS restrictions, mach exceptions and signal crashes are +not recorded. (Crashes in SwiftUI are generated as mach exceptions, so will not be recorded) + +## Combine +Thanks to contributions from the community, _FirebaseCombineSwift_ contains support for Apple's Combine +framework. This module is currently under development, and not yet supported for use in production +environments. Fore more details, please refer to the [docs](FirebaseCombineSwift/README.md). + +## Roadmap + +See [Roadmap](ROADMAP.md) for more about the Firebase Apple SDK Open Source +plans and directions. + +## Contributing + +See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase +Apple SDK. + +## License + +The contents of this repository are licensed under the +[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). + +Your use of Firebase is governed by the +[Terms of Service for Firebase Services](https://firebase.google.com/terms/). diff --git a/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRAppInternal.h b/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRAppInternal.h new file mode 100644 index 0000000..49104f0 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRAppInternal.h @@ -0,0 +1,159 @@ +/* + * 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 + +@class FIRComponentContainer; +@class FIRHeartbeatLogger; +@protocol FIRLibrary; + +/** + * The internal interface to `FirebaseApp`. This is meant for first-party integrators, who need to + * receive `FirebaseApp` notifications, log info about the success or failure of their + * configuration, and access other internal functionality of `FirebaseApp`. + */ +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(NSInteger, FIRConfigType) { + FIRConfigTypeCore = 1, + FIRConfigTypeSDK = 2, +}; + +extern NSString *const kFIRDefaultAppName; +extern NSString *const kFIRAppReadyToConfigureSDKNotification; +extern NSString *const kFIRAppDeleteNotification; +extern NSString *const kFIRAppIsDefaultAppKey; +extern NSString *const kFIRAppNameKey; +extern NSString *const kFIRGoogleAppIDKey; +extern NSString *const kFirebaseCoreErrorDomain; + +/** The `UserDefaults` suite name for `FirebaseCore`, for those storage locations that use it. */ +extern NSString *const kFirebaseCoreDefaultsSuiteName; + +/** + * The format string for the `UserDefaults` key used for storing the data collection enabled flag. + * This includes formatting to append the `FirebaseApp`'s name. + */ +extern NSString *const kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat; + +/** + * The plist key used for storing the data collection enabled flag. + */ +extern NSString *const kFIRGlobalAppDataCollectionEnabledPlistKey; + +/** @var FirebaseAuthStateDidChangeInternalNotification + @brief The name of the @c NotificationCenter notification which is posted when the auth state + changes (e.g. a new token has been produced, a user logs in or out). The object parameter of + the notification is a dictionary possibly containing the key: + @c FirebaseAuthStateDidChangeInternalNotificationTokenKey (the new access token.) If it does not + contain this key it indicates a sign-out event took place. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotification; + +/** @var FirebaseAuthStateDidChangeInternalNotificationTokenKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the new access token. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationTokenKey; + +/** @var FirebaseAuthStateDidChangeInternalNotificationAppKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the FirebaseApp associated with the auth instance. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationAppKey; + +/** @var FirebaseAuthStateDidChangeInternalNotificationUIDKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the new user's UID (or nil if there is no longer a user signed in). + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationUIDKey; + +@interface FIRApp () + +/** + * A flag indicating if this is the default app (has the default app name). + */ +@property(nonatomic, readonly) BOOL isDefaultApp; + +/** + * The container of interop SDKs for this app. + */ +@property(nonatomic) FIRComponentContainer *container; + +/** + * The heartbeat logger associated with this app. + * + * Firebase apps have a 1:1 relationship with heartbeat loggers. + */ +@property(readonly) FIRHeartbeatLogger *heartbeatLogger; + +/** + * Checks if the default app is configured without trying to configure it. + */ ++ (BOOL)isDefaultAppConfigured; + +/** + * Registers a given third-party library with the given version number to be reported for + * analytics. + * + * @param name Name of the library. + * @param version Version of the library. + */ ++ (void)registerLibrary:(nonnull NSString *)name withVersion:(nonnull NSString *)version; + +/** + * Registers a given internal library to be reported for analytics. + * + * @param library Optional parameter for component registration. + * @param name Name of the library. + */ ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name; + +/** + * Registers a given internal library with the given version number to be reported for + * analytics. This should only be used for non-Firebase libraries that have their own versioning + * scheme. + * + * @param library Optional parameter for component registration. + * @param name Name of the library. + * @param version Version of the library. + */ ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name + withVersion:(nonnull NSString *)version; + +/** + * A concatenated string representing all the third-party libraries and version numbers. + */ ++ (NSString *)firebaseUserAgent; + +/** + * Can be used by the unit tests in each SDK to reset `FirebaseApp`. This method is thread unsafe. + */ ++ (void)resetApps; + +/** + * Can be used by the unit tests in each SDK to set customized options. + */ +- (instancetype)initInstanceWithName:(NSString *)name options:(FIROptions *)options; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRComponent.h b/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRComponent.h new file mode 100644 index 0000000..e4c8a27 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRComponent.h @@ -0,0 +1,91 @@ +/* + * 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. + */ + +#import + +@class FIRApp; +@class FIRComponentContainer; + +NS_ASSUME_NONNULL_BEGIN + +/// Provides a system to clean up cached instances returned from the component system. +NS_SWIFT_NAME(ComponentLifecycleMaintainer) +@protocol FIRComponentLifecycleMaintainer +/// The associated app will be deleted, clean up any resources as they are about to be deallocated. +- (void)appWillBeDeleted:(FIRApp *)app; +@end + +typedef _Nullable id (^FIRComponentCreationBlock)(FIRComponentContainer *container, + BOOL *isCacheable) + NS_SWIFT_NAME(ComponentCreationBlock); + +@class FIRDependency; + +/// Describes the timing of instantiation. Note: new components should default to lazy unless there +/// is a strong reason to be eager. +typedef NS_ENUM(NSInteger, FIRInstantiationTiming) { + FIRInstantiationTimingLazy, + FIRInstantiationTimingAlwaysEager, + FIRInstantiationTimingEagerInDefaultApp +} NS_SWIFT_NAME(InstantiationTiming); + +/// A component that can be used from other Firebase SDKs. +NS_SWIFT_NAME(Component) +@interface FIRComponent : NSObject + +/// The protocol describing functionality provided from the `Component`. +@property(nonatomic, strong, readonly) Protocol *protocol; + +/// The timing of instantiation. +@property(nonatomic, readonly) FIRInstantiationTiming instantiationTiming; + +/// An array of dependencies for the component. +@property(nonatomic, copy, readonly) NSArray *dependencies; + +/// A block to instantiate an instance of the component with the appropriate dependencies. +@property(nonatomic, copy, readonly) FIRComponentCreationBlock creationBlock; + +// There's an issue with long NS_SWIFT_NAMES that causes compilation to fail, disable clang-format +// for the next two methods. +// clang-format off + +/// Creates a component with no dependencies that will be lazily initialized. ++ (instancetype)componentWithProtocol:(Protocol *)protocol + creationBlock:(FIRComponentCreationBlock)creationBlock +NS_SWIFT_NAME(init(_:creationBlock:)); + +/// Creates a component to be registered with the component container. +/// +/// @param protocol - The protocol describing functionality provided by the component. +/// @param instantiationTiming - When the component should be initialized. Use .lazy unless there's +/// a good reason to be instantiated earlier. +/// @param dependencies - Any dependencies the `implementingClass` has, optional or required. +/// @param creationBlock - A block to instantiate the component with a container, and if +/// @return A component that can be registered with the component container. ++ (instancetype)componentWithProtocol:(Protocol *)protocol + instantiationTiming:(FIRInstantiationTiming)instantiationTiming + dependencies:(NSArray *)dependencies + creationBlock:(FIRComponentCreationBlock)creationBlock +NS_SWIFT_NAME(init(_:instantiationTiming:dependencies:creationBlock:)); + +// clang-format on + +/// Unavailable. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRComponentContainer.h b/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRComponentContainer.h new file mode 100644 index 0000000..6ec6147 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRComponentContainer.h @@ -0,0 +1,45 @@ +/* + * 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. + */ +#import + +NS_ASSUME_NONNULL_BEGIN + +/// A type-safe macro to retrieve a component from a container. This should be used to retrieve +/// components instead of using the container directly. +#define FIR_COMPONENT(type, container) \ + [FIRComponentType> instanceForProtocol:@protocol(type) inContainer:container] + +@class FIRApp; + +/// A container that holds different components that are registered via the +/// `registerAsComponentRegistrant` call. These classes should conform to `ComponentRegistrant` +/// in order to properly register components for Core. +NS_SWIFT_NAME(FirebaseComponentContainer) +@interface FIRComponentContainer : NSObject + +/// A weak reference to the app that an instance of the container belongs to. +@property(nonatomic, weak, readonly) FIRApp *app; + +// TODO: See if we can get improved type safety here. +/// A Swift only API for fetching an instance since the top macro isn't available. +- (nullable id)__instanceForProtocol:(Protocol *)protocol NS_SWIFT_NAME(instance(for:)); + +/// Unavailable. Use the `container` property on `FirebaseApp`. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRComponentType.h b/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRComponentType.h new file mode 100644 index 0000000..6f2aca7 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRComponentType.h @@ -0,0 +1,34 @@ +/* + * 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. + */ + +#import + +@class FIRComponentContainer; + +NS_ASSUME_NONNULL_BEGIN + +/// Do not use directly. A placeholder type in order to provide a macro that will warn users of +/// mis-matched protocols. +NS_SWIFT_NAME(ComponentType) +@interface FIRComponentType<__covariant T> : NSObject + +/// Do not use directly. A factory method to retrieve an instance that provides a specific +/// functionality. ++ (T)instanceForProtocol:(Protocol *)protocol inContainer:(FIRComponentContainer *)container; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRDependency.h b/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRDependency.h new file mode 100644 index 0000000..a070557 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRDependency.h @@ -0,0 +1,45 @@ +/* + * 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. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/// A dependency on a specific protocol's functionality. +NS_SWIFT_NAME(Dependency) +@interface FIRDependency : NSObject + +/// The protocol describing functionality being depended on. +@property(nonatomic, strong, readonly) Protocol *protocol; + +/// A flag to specify if the dependency is required or not. +@property(nonatomic, readonly) BOOL isRequired; + +/// Initializes a dependency that is required. Calls `init(protocol:isRequired:)` with true for +/// the required parameter. +/// Creates a required dependency on the specified protocol's functionality. ++ (instancetype)dependencyWithProtocol:(Protocol *)protocol; + +/// Creates a dependency on the specified protocol's functionality and specify if it's required for +/// the class's functionality. ++ (instancetype)dependencyWithProtocol:(Protocol *)protocol isRequired:(BOOL)required; + +/// Use `init(withProtocol:isRequired:)` instead. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRHeartbeatLogger.h b/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRHeartbeatLogger.h new file mode 100644 index 0000000..0f39ad9 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRHeartbeatLogger.h @@ -0,0 +1,90 @@ +// Copyright 2021 Google LLC +// +// 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 + +NS_ASSUME_NONNULL_BEGIN + +#ifndef FIREBASE_BUILD_CMAKE +@class FIRHeartbeatsPayload; +#endif // FIREBASE_BUILD_CMAKE + +/// Enum representing different daily heartbeat codes. +/// This enum is only used by clients using platform logging V1. This is because +/// the V1 payload only supports a single daily heartbeat. +typedef NS_ENUM(NSInteger, FIRDailyHeartbeatCode) { + /// Represents the absence of a daily heartbeat. + FIRDailyHeartbeatCodeNone = 0, + /// Represents the presence of a daily heartbeat. + FIRDailyHeartbeatCodeSome = 2, +}; + +@protocol FIRHeartbeatLoggerProtocol + +/// Asynchronously logs a heartbeat. +- (void)log; + +#ifndef FIREBASE_BUILD_CMAKE +/// Flushes heartbeats from storage into a structured payload of heartbeats. +- (FIRHeartbeatsPayload *)flushHeartbeatsIntoPayload; +#endif // FIREBASE_BUILD_CMAKE + +/// Gets the heartbeat code for today. +- (FIRDailyHeartbeatCode)heartbeatCodeForToday; + +@end + +#ifndef FIREBASE_BUILD_CMAKE +/// Returns a nullable string header value from a given heartbeats payload. +/// +/// This API returns `nil` when the given heartbeats payload is considered empty. +/// +/// @param heartbeatsPayload The heartbeats payload. +NSString *_Nullable FIRHeaderValueFromHeartbeatsPayload(FIRHeartbeatsPayload *heartbeatsPayload); +#endif // FIREBASE_BUILD_CMAKE + +/// A thread safe, synchronized object that logs and flushes platform logging info. +@interface FIRHeartbeatLogger : NSObject + +/// Designated initializer. +/// +/// @param appID The app ID that this heartbeat logger corresponds to. +- (instancetype)initWithAppID:(NSString *)appID; + +/// Asynchronously logs a new heartbeat corresponding to the Firebase User Agent, if needed. +/// +/// @note This API is thread-safe. +- (void)log; + +#ifndef FIREBASE_BUILD_CMAKE +/// Flushes heartbeats from storage into a structured payload of heartbeats. +/// +/// This API is for clients using platform logging V2. +/// +/// @note This API is thread-safe. +/// @return A payload of heartbeats. +- (FIRHeartbeatsPayload *)flushHeartbeatsIntoPayload; +#endif // FIREBASE_BUILD_CMAKE + +/// Gets today's corresponding heartbeat code. +/// +/// This API is for clients using platform logging V1. +/// +/// @note This API is thread-safe. +/// @return Heartbeat code indicating whether or not there is an unsent global heartbeat. +- (FIRDailyHeartbeatCode)heartbeatCodeForToday; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRLibrary.h b/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRLibrary.h new file mode 100644 index 0000000..15e2865 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRLibrary.h @@ -0,0 +1,44 @@ +/* + * 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 FIRLibrary_h +#define FIRLibrary_h + +#import + +@class FIRApp; +@class FIRComponent; + +NS_ASSUME_NONNULL_BEGIN + +/// Provide an interface to register a library for userAgent logging and availability to others. +NS_SWIFT_NAME(Library) +@protocol FIRLibrary + +/// Returns one or more Components that will be registered in +/// FirebaseApp and participate in dependency resolution and injection. ++ (NSArray *)componentsToRegister; + +@optional +/// Implement this method if the library needs notifications for lifecycle events. This method is +/// called when the developer calls `FirebaseApp.configure()`. ++ (void)configureWithApp:(FIRApp *)app; + +@end + +NS_ASSUME_NONNULL_END + +#endif /* FIRLibrary_h */ diff --git a/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRLogger.h b/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRLogger.h new file mode 100644 index 0000000..0a287f5 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRLogger.h @@ -0,0 +1,188 @@ +/* + * 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 + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * The Firebase services used in Firebase logger. + */ +typedef NSString *const FIRLoggerService; + +extern FIRLoggerService kFIRLoggerAnalytics; +extern FIRLoggerService kFIRLoggerCrash; +extern FIRLoggerService kFIRLoggerCore; +extern FIRLoggerService kFIRLoggerRemoteConfig; + +/** + * The key used to store the logger's error count. + */ +extern NSString *const kFIRLoggerErrorCountKey; + +/** + * The key used to store the logger's warning count. + */ +extern NSString *const kFIRLoggerWarningCountKey; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** + * Enables or disables Analytics debug mode. + * If set to true, the logging level for Analytics will be set to FirebaseLoggerLevelDebug. + * Enabling the debug mode has no effect if the app is running from App Store. + * (required) analytics debug mode flag. + */ +void FIRSetAnalyticsDebugMode(BOOL analyticsDebugMode); + +/** + * Changes the default logging level of FirebaseLoggerLevelNotice to a user-specified level. + * The default level cannot be set above FirebaseLoggerLevelNotice if the app is running from App + * Store. (required) log level (one of the FirebaseLoggerLevel enum values). + */ +void FIRSetLoggerLevel(FIRLoggerLevel loggerLevel); + +/** + * Checks if the specified logger level is loggable given the current settings. + * (required) log level (one of the FirebaseLoggerLevel enum values). + * (required) whether or not this function is called from the Analytics component. + */ +BOOL FIRIsLoggableLevel(FIRLoggerLevel loggerLevel, BOOL analyticsComponent); + +/** + * Logs a message to the Xcode console and the device log. If running from AppStore, will + * not log any messages with a level higher than FirebaseLoggerLevelNotice to avoid log spamming. + * (required) log level (one of the FirebaseLoggerLevel enum values). + * (required) service name of type FirebaseLoggerService. + * (required) message code starting with "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique + * within the service. + * An example of the message code is @"I-COR000001". + * (required) message string which can be a format string. + * (optional) variable arguments list obtained from calling va_start, used when message is a format + * string. + */ +extern void FIRLogBasic(FIRLoggerLevel level, + FIRLoggerService service, + NSString *messageCode, + NSString *message, +// On 64-bit simulators, va_list is not a pointer, so cannot be marked nullable +// See: http://stackoverflow.com/q/29095469 +#if __LP64__ && TARGET_OS_SIMULATOR || TARGET_OS_OSX + va_list args_ptr +#else + va_list _Nullable args_ptr +#endif +); + +/** + * The following functions accept the following parameters in order: + * (required) service name of type FirebaseLoggerService. + * (required) message code starting from "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique + * within the service. + * An example of the message code is @"I-COR000001". + * See go/firebase-log-proposal for details. + * (required) message string which can be a format string. + * (optional) the list of arguments to substitute into the format string. + * Example usage: + * FirebaseLogError(kFirebaseLoggerCore, @"I-COR000001", @"Configuration of %@ failed.", app.name); + */ +extern void FIRLogError(FIRLoggerService service, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogWarning(FIRLoggerService service, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogNotice(FIRLoggerService service, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogInfo(FIRLoggerService service, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogDebug(FIRLoggerService service, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); + +// TODO: Come up with a better logging scheme for Swift. +/** + * Logs a debug message to the Xcode console and the device log. If running from AppStore, will + * not log any messages with a level higher than FirebaseLoggerLevelNotice to avoid log spamming. + * This function is intended to be used by Swift clients that do not support variadic parameters. + * + * @param service The service name of type `FirebaseLoggerService`. + * @param messageCode The mesage code. starting with "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique within the + * service. An example of the message code is @"I-COR000001". + * @param message The message string. + */ +extern void FIRLogDebugSwift(FIRLoggerService service, NSString *messageCode, NSString *message); + +/** + * Logs a warning message to the Xcode console and the device log. If running from AppStore, will + * not log any messages with a level higher than FirebaseLoggerLevelNotice to avoid log spamming. + * This function is intended to be used by Swift clients that do not support variadic parameters. + * + * @param service The service name of type `FirebaseLoggerService`. + * @param messageCode The mesage code. starting with "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique within the + * service. An example of the message code is @"I-COR000001". + * @param message The message string. + */ +extern void FIRLogWarningSwift(FIRLoggerService service, NSString *messageCode, NSString *message); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +NS_SWIFT_NAME(FirebaseLogger) +@interface FIRLoggerWrapper : NSObject + +/// Logs a given message at a given log level. This API is effectively a wrapper for the +/// `FIRLogBasic` C API. +/// +/// - Parameters: +/// - level: The log level to use (defined by `FirebaseLoggerLevel` enum values). +/// - service: The service name of type `FirebaseLoggerService`. +/// - code: The mesage code. Starting with "I-" which means iOS, followed by a capitalized +/// three-character service identifier and a six digit integer message ID that is unique within +/// the service. An example of the message code is @"I-COR000001". +/// - message: Formatted string to be used as the log's message. +/// - args: Arguments list obtained from calling `va_start`, used when message is a format string. ++ (void)logWithLevel:(FIRLoggerLevel)level + withService:(FIRLoggerService)service + withCode:(NSString *)messageCode + withMessage:(NSString *)message + withArgs:(va_list)args; + +/// Logs a given message at a given log level. +/// +/// - Parameters: +/// - level: The log level to use (defined by `FirebaseLoggerLevel` enum values). +/// - service: The service name of type `FirebaseLoggerService`. +/// - code: The mesage code. Starting with "I-" which means iOS, followed by a capitalized +/// three-character service identifier and a six digit integer message ID that is unique within +/// the service. An example of the message code is @"I-COR000001". +/// - message: Formatted string to be used as the log's message. +/// - args: Arguments list obtained from calling `va_start`, used when message is a format string. ++ (void)logWithLevel:(FIRLoggerLevel)level + service:(FIRLoggerService)service + code:(NSString *)code + message:(NSString *)message + __attribute__((__swift_name__("log(level:service:code:message:)"))); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseCore/Extension/FIROptionsInternal.h b/Pods/FirebaseInstallations/FirebaseCore/Extension/FIROptionsInternal.h new file mode 100644 index 0000000..93a03d6 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseCore/Extension/FIROptionsInternal.h @@ -0,0 +1,106 @@ +/* + * 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 + +/** + * Keys for the strings in the plist file. + */ +extern NSString *const kFIRAPIKey; +extern NSString *const kFIRTrackingID; +extern NSString *const kFIRGoogleAppID; +extern NSString *const kFIRClientID; +extern NSString *const kFIRGCMSenderID; +extern NSString *const kFIRAndroidClientID; +extern NSString *const kFIRDatabaseURL; +extern NSString *const kFIRStorageBucket; +extern NSString *const kFIRBundleID; +extern NSString *const kFIRProjectID; + +/** + * Keys for the plist file name + */ +extern NSString *const kServiceInfoFileName; + +extern NSString *const kServiceInfoFileType; + +/** + * This header file exposes the initialization of FirebaseOptions to internal use. + */ +@interface FIROptions () + +/** + * `resetDefaultOptions` and `initInternalWithOptionsDictionary` are exposed only for unit tests. + */ ++ (void)resetDefaultOptions; + +/** + * Initializes the options with dictionary. The above strings are the keys of the dictionary. + * This is the designated initializer. + */ +- (instancetype)initInternalWithOptionsDictionary:(NSDictionary *)serviceInfoDictionary + NS_DESIGNATED_INITIALIZER; + +/** + * `defaultOptions` and `defaultOptionsDictionary` are exposed in order to be used in FirebaseApp + * and other first party services. + */ ++ (FIROptions *)defaultOptions; + ++ (NSDictionary *)defaultOptionsDictionary; + +/** + * Indicates whether or not Analytics collection was explicitly enabled via a plist flag or at + * runtime. + */ +@property(nonatomic, readonly) BOOL isAnalyticsCollectionExplicitlySet; + +/** + * Whether or not Analytics Collection was enabled. Analytics Collection is enabled unless + * explicitly disabled in GoogleService-Info.plist. + */ +@property(nonatomic, readonly) BOOL isAnalyticsCollectionEnabled; + +/** + * Whether or not Analytics Collection was completely disabled. If true, then + * isAnalyticsCollectionEnabled will be false. + */ +@property(nonatomic, readonly) BOOL isAnalyticsCollectionDeactivated; + +/** + * The version ID of the client library, e.g. @"1100000". + */ +@property(nonatomic, readonly, copy) NSString *libraryVersionID; + +/** + * The flag indicating whether this object was constructed with the values in the default plist + * file. + */ +@property(nonatomic) BOOL usingOptionsFromDefaultPlist; + +/** + * Whether or not Measurement was enabled. Measurement is enabled unless explicitly disabled in + * GoogleService-Info.plist. + */ +@property(nonatomic, readonly) BOOL isMeasurementEnabled; + +/** + * Whether or not editing is locked. This should occur after `FirebaseOptions` has been set on a + * `FirebaseApp`. + */ +@property(nonatomic, getter=isEditingLocked) BOOL editingLocked; + +@end diff --git a/Pods/FirebaseInstallations/FirebaseCore/Extension/FirebaseCoreInternal.h b/Pods/FirebaseInstallations/FirebaseCore/Extension/FirebaseCoreInternal.h new file mode 100644 index 0000000..0669ae6 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseCore/Extension/FirebaseCoreInternal.h @@ -0,0 +1,25 @@ +// Copyright 2020 Google LLC +// +// 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 FirebaseCore; + +#import "FIRAppInternal.h" +#import "FIRComponent.h" +#import "FIRComponentContainer.h" +#import "FIRComponentType.h" +#import "FIRDependency.h" +#import "FIRHeartbeatLogger.h" +#import "FIRLibrary.h" +#import "FIRLogger.h" +#import "FIROptionsInternal.h" diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h new file mode 100644 index 0000000..8aed7b1 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h @@ -0,0 +1,65 @@ +/* + * Copyright 2019 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 + +#import "FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallationsErrors.h" + +@class FIRInstallationsHTTPError; +@class FBLPromise; + +NS_ASSUME_NONNULL_BEGIN + +void FIRInstallationsItemSetErrorToPointer(NSError *error, NSError **pointer); + +@interface FIRInstallationsErrorUtil : NSObject + ++ (NSError *)keyedArchiverErrorWithException:(NSException *)exception; ++ (NSError *)keyedArchiverErrorWithError:(NSError *)error; + ++ (NSError *)keychainErrorWithFunction:(NSString *)keychainFunction status:(OSStatus)status; + ++ (NSError *)installationItemNotFoundForAppID:(NSString *)appID appName:(NSString *)appName; + ++ (NSError *)JSONSerializationError:(NSError *)error; + ++ (NSError *)networkErrorWithError:(NSError *)error; + ++ (NSError *)FIDRegistrationErrorWithResponseMissingField:(NSString *)missingFieldName; + ++ (NSError *)corruptedIIDTokenData; + ++ (FIRInstallationsHTTPError *)APIErrorWithHTTPResponse:(NSHTTPURLResponse *)HTTPResponse + data:(nullable NSData *)data; ++ (BOOL)isAPIError:(NSError *)error withHTTPCode:(NSInteger)HTTPCode; + ++ (NSError *)backoffIntervalWaitError; + +/** + * Returns the passed error if it is already in the public domain or a new error with the passed + * error at `NSUnderlyingErrorKey`. + */ ++ (NSError *)publicDomainErrorWithError:(NSError *)error; + ++ (FBLPromise *)rejectedPromiseWithError:(NSError *)error; + ++ (NSError *)installationsErrorWithCode:(FIRInstallationsErrorCode)code + failureReason:(nullable NSString *)failureReason + underlyingError:(nullable NSError *)underlyingError; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.m b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.m new file mode 100644 index 0000000..5673600 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.m @@ -0,0 +1,145 @@ +/* + * Copyright 2019 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 "FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h" + +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsHTTPError.h" + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +NSString *const kFirebaseInstallationsErrorDomain = @"com.firebase.installations"; + +void FIRInstallationsItemSetErrorToPointer(NSError *error, NSError **pointer) { + if (pointer != NULL) { + *pointer = error; + } +} + +@implementation FIRInstallationsErrorUtil + ++ (NSError *)keyedArchiverErrorWithException:(NSException *)exception { + NSString *failureReason = [NSString + stringWithFormat:@"NSKeyedArchiver exception with name: %@, reason: %@, userInfo: %@", + exception.name, exception.reason, exception.userInfo]; + return [self installationsErrorWithCode:FIRInstallationsErrorCodeUnknown + failureReason:failureReason + underlyingError:nil]; +} + ++ (NSError *)keyedArchiverErrorWithError:(NSError *)error { + NSString *failureReason = [NSString stringWithFormat:@"NSKeyedArchiver error."]; + return [self installationsErrorWithCode:FIRInstallationsErrorCodeUnknown + failureReason:failureReason + underlyingError:error]; +} + ++ (NSError *)keychainErrorWithFunction:(NSString *)keychainFunction status:(OSStatus)status { + NSString *failureReason = [NSString stringWithFormat:@"%@ (%li)", keychainFunction, (long)status]; + return [self installationsErrorWithCode:FIRInstallationsErrorCodeKeychain + failureReason:failureReason + underlyingError:nil]; +} + ++ (NSError *)installationItemNotFoundForAppID:(NSString *)appID appName:(NSString *)appName { + NSString *failureReason = + [NSString stringWithFormat:@"Installation for appID %@ appName %@ not found", appID, appName]; + return [self installationsErrorWithCode:FIRInstallationsErrorCodeUnknown + failureReason:failureReason + underlyingError:nil]; +} + ++ (NSError *)corruptedIIDTokenData { + NSString *failureReason = + @"IID token data stored in Keychain is corrupted or in an incompatible format."; + return [self installationsErrorWithCode:FIRInstallationsErrorCodeUnknown + failureReason:failureReason + underlyingError:nil]; +} + ++ (FIRInstallationsHTTPError *)APIErrorWithHTTPResponse:(NSHTTPURLResponse *)HTTPResponse + data:(nullable NSData *)data { + return [[FIRInstallationsHTTPError alloc] initWithHTTPResponse:HTTPResponse data:data]; +} + ++ (BOOL)isAPIError:(NSError *)error withHTTPCode:(NSInteger)HTTPCode { + if (![error isKindOfClass:[FIRInstallationsHTTPError class]]) { + return NO; + } + + return [(FIRInstallationsHTTPError *)error HTTPResponse].statusCode == HTTPCode; +} + ++ (NSError *)JSONSerializationError:(NSError *)error { + NSString *failureReason = [NSString stringWithFormat:@"Failed to serialize JSON data."]; + return [self installationsErrorWithCode:FIRInstallationsErrorCodeUnknown + failureReason:failureReason + underlyingError:nil]; +} + ++ (NSError *)FIDRegistrationErrorWithResponseMissingField:(NSString *)missingFieldName { + NSString *failureReason = [NSString + stringWithFormat:@"A required response field with name %@ is missing", missingFieldName]; + return [self installationsErrorWithCode:FIRInstallationsErrorCodeUnknown + failureReason:failureReason + underlyingError:nil]; +} + ++ (NSError *)networkErrorWithError:(NSError *)error { + return [self installationsErrorWithCode:FIRInstallationsErrorCodeServerUnreachable + failureReason:@"Network connection error." + underlyingError:error]; +} + ++ (NSError *)backoffIntervalWaitError { + return [self installationsErrorWithCode:FIRInstallationsErrorCodeServerUnreachable + failureReason:@"Too many server requests." + underlyingError:nil]; +} + ++ (NSError *)publicDomainErrorWithError:(NSError *)error { + if ([error.domain isEqualToString:kFirebaseInstallationsErrorDomain]) { + return error; + } + + return [self installationsErrorWithCode:FIRInstallationsErrorCodeUnknown + failureReason:nil + underlyingError:error]; +} + ++ (NSError *)installationsErrorWithCode:(FIRInstallationsErrorCode)code + failureReason:(nullable NSString *)failureReason + underlyingError:(nullable NSError *)underlyingError { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + userInfo[NSUnderlyingErrorKey] = underlyingError; + userInfo[NSLocalizedFailureReasonErrorKey] = + failureReason + ?: [NSString + stringWithFormat:@"Underlying error: %@", underlyingError.localizedDescription]; + + return [NSError errorWithDomain:kFirebaseInstallationsErrorDomain code:code userInfo:userInfo]; +} + ++ (FBLPromise *)rejectedPromiseWithError:(NSError *)error { + FBLPromise *rejectedPromise = [FBLPromise pendingPromise]; + [rejectedPromise reject:error]; + return rejectedPromise; +} + +@end diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Errors/FIRInstallationsHTTPError.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Errors/FIRInstallationsHTTPError.h new file mode 100644 index 0000000..b978b77 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Errors/FIRInstallationsHTTPError.h @@ -0,0 +1,53 @@ +/* + * Copyright 2019 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 + +NS_ASSUME_NONNULL_BEGIN + +/** Represents an error caused by an unexpected API response. */ +@interface FIRInstallationsHTTPError : NSError + +@property(nonatomic, readonly) NSHTTPURLResponse *HTTPResponse; +@property(nonatomic, readonly, nonnull) NSData *data; + +- (instancetype)init NS_UNAVAILABLE; + +- (instancetype)initWithHTTPResponse:(NSHTTPURLResponse *)HTTPResponse data:(nullable NSData *)data; + +@end + +NS_ASSUME_NONNULL_END + +typedef NS_ENUM(NSInteger, FIRInstallationsHTTPCodes) { + FIRInstallationsHTTPCodesTooManyRequests = 429, + FIRInstallationsHTTPCodesServerInternalError = 500, +}; + +/** Possible response HTTP codes for `CreateInstallation` API request. */ +typedef NS_ENUM(NSInteger, FIRInstallationsRegistrationHTTPCode) { + FIRInstallationsRegistrationHTTPCodeSuccess = 201, + FIRInstallationsRegistrationHTTPCodeInvalidArgument = 400, + FIRInstallationsRegistrationHTTPCodeAPIKeyToProjectIDMismatch = 403, + FIRInstallationsRegistrationHTTPCodeProjectNotFound = 404, + FIRInstallationsRegistrationHTTPCodeTooManyRequests = 429, + FIRInstallationsRegistrationHTTPCodeServerInternalError = 500 +}; + +typedef NS_ENUM(NSInteger, FIRInstallationsAuthTokenHTTPCode) { + FIRInstallationsAuthTokenHTTPCodeInvalidAuthentication = 401, + FIRInstallationsAuthTokenHTTPCodeFIDNotFound = 404, +}; diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Errors/FIRInstallationsHTTPError.m b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Errors/FIRInstallationsHTTPError.m new file mode 100644 index 0000000..4236f45 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Errors/FIRInstallationsHTTPError.m @@ -0,0 +1,79 @@ +/* + * Copyright 2019 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 "FirebaseInstallations/Source/Library/Errors/FIRInstallationsHTTPError.h" +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h" + +@implementation FIRInstallationsHTTPError + +- (instancetype)initWithHTTPResponse:(NSHTTPURLResponse *)HTTPResponse + data:(nullable NSData *)data { + NSDictionary *userInfo = [FIRInstallationsHTTPError userInfoWithHTTPResponse:HTTPResponse + data:data]; + self = [super + initWithDomain:kFirebaseInstallationsErrorDomain + code:[FIRInstallationsHTTPError errorCodeWithHTTPCode:HTTPResponse.statusCode] + userInfo:userInfo]; + if (self) { + _HTTPResponse = HTTPResponse; + _data = data; + } + return self; +} + ++ (FIRInstallationsErrorCode)errorCodeWithHTTPCode:(NSInteger)HTTPCode { + return FIRInstallationsErrorCodeUnknown; +} + ++ (NSDictionary *)userInfoWithHTTPResponse:(NSHTTPURLResponse *)HTTPResponse + data:(nullable NSData *)data { + NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + NSString *failureReason = + [NSString stringWithFormat:@"The server responded with an error: \n - URL: %@ \n - HTTP " + @"status code: %ld \n - Response body: %@", + HTTPResponse.URL, (long)HTTPResponse.statusCode, responseString]; + return @{NSLocalizedFailureReasonErrorKey : failureReason}; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone { + return [[FIRInstallationsHTTPError alloc] initWithHTTPResponse:self.HTTPResponse data:self.data]; +} + +#pragma mark - NSSecureCoding + +- (nullable instancetype)initWithCoder:(NSCoder *)coder { + NSHTTPURLResponse *HTTPResponse = [coder decodeObjectOfClass:[NSHTTPURLResponse class] + forKey:@"HTTPResponse"]; + if (!HTTPResponse) { + return nil; + } + NSData *data = [coder decodeObjectOfClass:[NSData class] forKey:@"data"]; + + return [self initWithHTTPResponse:HTTPResponse data:data]; +} + +- (void)encodeWithCoder:(NSCoder *)coder { + [coder encodeObject:self.HTTPResponse forKey:@"HTTPResponse"]; + [coder encodeObject:self.data forKey:@"data"]; +} + ++ (BOOL)supportsSecureCoding { + return YES; +} + +@end diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallations.m b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallations.m new file mode 100644 index 0000000..4748f4f --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallations.m @@ -0,0 +1,273 @@ +/* + * Copyright 2019 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 "FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallations.h" + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" + +#import "FirebaseInstallations/Source/Library/FIRInstallationsAuthTokenResultInternal.h" + +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h" +#import "FirebaseInstallations/Source/Library/FIRInstallationsItem.h" +#import "FirebaseInstallations/Source/Library/FIRInstallationsLogger.h" +#import "FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsIDController.h" +#import "FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.h" + +NS_ASSUME_NONNULL_BEGIN + +static const NSUInteger kExpectedAPIKeyLength = 39; + +@protocol FIRInstallationsInstanceProvider +@end + +@interface FIRInstallations () +@property(nonatomic, readonly) FIROptions *appOptions; +@property(nonatomic, readonly) NSString *appName; + +@property(nonatomic, readonly) FIRInstallationsIDController *installationsIDController; + +@end + +@implementation FIRInstallations + +#pragma mark - Firebase component + ++ (void)load { + [FIRApp registerInternalLibrary:(Class)self withName:@"fire-install"]; +} + ++ (nonnull NSArray *)componentsToRegister { + FIRComponentCreationBlock creationBlock = + ^id _Nullable(FIRComponentContainer *container, BOOL *isCacheable) { + *isCacheable = YES; + FIRInstallations *installations = [[FIRInstallations alloc] initWithApp:container.app]; + return installations; + }; + + FIRComponent *installationsProvider = + [FIRComponent componentWithProtocol:@protocol(FIRInstallationsInstanceProvider) + instantiationTiming:FIRInstantiationTimingAlwaysEager + dependencies:@[] + creationBlock:creationBlock]; + return @[ installationsProvider ]; +} + +- (instancetype)initWithApp:(FIRApp *)app { + FIRInstallationsIDController *IDController = + [[FIRInstallationsIDController alloc] initWithApp:app]; + + // `prefetchAuthToken` is disabled due to b/156746574. + return [self initWithAppOptions:app.options + appName:app.name + installationsIDController:IDController + prefetchAuthToken:NO]; +} + +/// This designated initializer can be exposed for testing. +- (instancetype)initWithAppOptions:(FIROptions *)appOptions + appName:(NSString *)appName + installationsIDController:(FIRInstallationsIDController *)installationsIDController + prefetchAuthToken:(BOOL)prefetchAuthToken { + self = [super init]; + if (self) { + [[self class] validateAppOptions:appOptions appName:appName]; + [[self class] assertCompatibleIIDVersion]; + + _appOptions = [appOptions copy]; + _appName = [appName copy]; + _installationsIDController = installationsIDController; + + // Pre-fetch auth token. + if (prefetchAuthToken) { + [self authTokenWithCompletion:^(FIRInstallationsAuthTokenResult *_Nullable tokenResult, + NSError *_Nullable error){ + }]; + } + } + return self; +} + ++ (void)validateAppOptions:(FIROptions *)appOptions appName:(NSString *)appName { + NSMutableArray *missingFields = [NSMutableArray array]; + if (appName.length < 1) { + [missingFields addObject:@"`FirebaseApp.name`"]; + } + if (appOptions.APIKey.length < 1) { + [missingFields addObject:@"`FirebaseOptions.APIKey`"]; + } + if (appOptions.googleAppID.length < 1) { + [missingFields addObject:@"`FirebaseOptions.googleAppID`"]; + } + + if (appOptions.projectID.length < 1) { + [missingFields addObject:@"`FirebaseOptions.projectID`"]; + } + + if (missingFields.count > 0) { + [NSException + raise:kFirebaseInstallationsErrorDomain + format: + @"%@[%@] Could not configure Firebase Installations due to invalid FirebaseApp " + @"options. The following parameters are nil or empty: %@. If you use " + @"GoogleServices-Info.plist please download the most recent version from the Firebase " + @"Console. If you configure Firebase in code, please make sure you specify all " + @"required parameters.", + kFIRLoggerInstallations, kFIRInstallationsMessageCodeInvalidFirebaseAppOptions, + [missingFields componentsJoinedByString:@", "]]; + } + + [self validateAPIKey:appOptions.APIKey]; +} + ++ (void)validateAPIKey:(nullable NSString *)APIKey { + NSMutableArray *validationIssues = [[NSMutableArray alloc] init]; + + if (APIKey.length != kExpectedAPIKeyLength) { + [validationIssues addObject:[NSString stringWithFormat:@"API Key length must be %lu characters", + (unsigned long)kExpectedAPIKeyLength]]; + } + + if (![[APIKey substringToIndex:1] isEqualToString:@"A"]) { + [validationIssues addObject:@"API Key must start with `A`"]; + } + + NSMutableCharacterSet *allowedCharacters = [NSMutableCharacterSet alphanumericCharacterSet]; + [allowedCharacters + formUnionWithCharacterSet:[NSCharacterSet characterSetWithCharactersInString:@"-_"]]; + + NSCharacterSet *characters = [NSCharacterSet characterSetWithCharactersInString:APIKey]; + if (![allowedCharacters isSupersetOfSet:characters]) { + [validationIssues addObject:@"API Key must contain only base64 url-safe characters characters"]; + } + + if (validationIssues.count > 0) { + [NSException + raise:kFirebaseInstallationsErrorDomain + format: + @"%@[%@] Could not configure Firebase Installations due to invalid FirebaseApp " + @"options. `FirebaseOptions.APIKey` doesn't match the expected format: %@. If you use " + @"GoogleServices-Info.plist please download the most recent version from the Firebase " + @"Console. If you configure Firebase in code, please make sure you specify all " + @"required parameters.", + kFIRLoggerInstallations, kFIRInstallationsMessageCodeInvalidFirebaseAppOptions, + [validationIssues componentsJoinedByString:@", "]]; + } +} + +#pragma mark - Public + ++ (FIRInstallations *)installations { + FIRApp *defaultApp = [FIRApp defaultApp]; + if (!defaultApp) { + [NSException raise:kFirebaseInstallationsErrorDomain + format:@"The default FirebaseApp instance must be configured before the default" + @"FirebaseApp instance can be initialized. One way to ensure this is to " + @"call `FirebaseApp.configure()` in the App Delegate's " + @"`application(_:didFinishLaunchingWithOptions:)` " + @"(or the `@main` struct's initializer in SwiftUI)."]; + } + + return [self installationsWithApp:defaultApp]; +} + ++ (FIRInstallations *)installationsWithApp:(FIRApp *)app { + id installations = + FIR_COMPONENT(FIRInstallationsInstanceProvider, app.container); + return (FIRInstallations *)installations; +} + +- (void)installationIDWithCompletion:(FIRInstallationsIDHandler)completion { + [self.installationsIDController getInstallationItem] + .then(^id(FIRInstallationsItem *installation) { + completion(installation.firebaseInstallationID, nil); + return nil; + }) + .catch(^(NSError *error) { + completion(nil, [FIRInstallationsErrorUtil publicDomainErrorWithError:error]); + }); +} + +- (void)authTokenWithCompletion:(FIRInstallationsTokenHandler)completion { + [self authTokenForcingRefresh:NO completion:completion]; +} + +- (void)authTokenForcingRefresh:(BOOL)forceRefresh + completion:(FIRInstallationsTokenHandler)completion { + [self.installationsIDController getAuthTokenForcingRefresh:forceRefresh] + .then(^FIRInstallationsAuthTokenResult *(FIRInstallationsItem *installation) { + FIRInstallationsAuthTokenResult *result = [[FIRInstallationsAuthTokenResult alloc] + initWithToken:installation.authToken.token + expirationDate:installation.authToken.expirationDate]; + return result; + }) + .then(^id(FIRInstallationsAuthTokenResult *token) { + completion(token, nil); + return nil; + }) + .catch(^void(NSError *error) { + completion(nil, [FIRInstallationsErrorUtil publicDomainErrorWithError:error]); + }); +} + +- (void)deleteWithCompletion:(void (^)(NSError *__nullable error))completion { + [self.installationsIDController deleteInstallation] + .then(^id(id result) { + completion(nil); + return nil; + }) + .catch(^void(NSError *error) { + completion([FIRInstallationsErrorUtil publicDomainErrorWithError:error]); + }); +} + +#pragma mark - IID version compatibility + ++ (void)assertCompatibleIIDVersion { + // We use this flag to disable IID compatibility exception for unit tests. +#ifdef FIR_INSTALLATIONS_ALLOWS_INCOMPATIBLE_IID_VERSION + return; +#else + if (![self isIIDVersionCompatible]) { + [NSException + raise:kFirebaseInstallationsErrorDomain + format:@"Firebase Instance ID is not compatible with Firebase 8.x+. Please remove the " + @"dependency from the app. See the documentation at " + @"https://firebase.google.com/docs/cloud-messaging/ios/" + @"client#fetching-the-current-registration-token."]; + } +#endif +} + ++ (BOOL)isIIDVersionCompatible { + Class IIDClass = NSClassFromString(@"FIRInstanceID"); + if (IIDClass == nil) { + // It is OK if there is no IID at all. + return YES; + } + // We expect a compatible version having the method `+[FIRInstanceID usesFIS]` defined. + BOOL isCompatibleVersion = [IIDClass respondsToSelector:NSSelectorFromString(@"usesFIS")]; + return isCompatibleVersion; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsAuthTokenResult.m b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsAuthTokenResult.m new file mode 100644 index 0000000..47a71e8 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsAuthTokenResult.m @@ -0,0 +1,30 @@ +/* + * Copyright 2019 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 "FirebaseInstallations/Source/Library/FIRInstallationsAuthTokenResultInternal.h" + +@implementation FIRInstallationsAuthTokenResult + +- (instancetype)initWithToken:(NSString *)token expirationDate:(NSDate *)expirationDate { + self = [super init]; + if (self) { + _authToken = [token copy]; + _expirationDate = expirationDate; + } + return self; +} + +@end diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsAuthTokenResultInternal.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsAuthTokenResultInternal.h new file mode 100644 index 0000000..662802e --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsAuthTokenResultInternal.h @@ -0,0 +1,27 @@ +/* + * Copyright 2019 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 "FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallationsAuthTokenResult.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRInstallationsAuthTokenResult (Internal) + +- (instancetype)initWithToken:(NSString *)token expirationDate:(NSDate *)expirationTime; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsItem.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsItem.h new file mode 100644 index 0000000..8aa3a5e --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsItem.h @@ -0,0 +1,93 @@ +/* + * Copyright 2019 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 + +#import "FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsStatus.h" + +@class FIRInstallationsStoredItem; +@class FIRInstallationsStoredAuthToken; +@class FIRInstallationsStoredIIDCheckin; + +NS_ASSUME_NONNULL_BEGIN + +/** + * The class represents the required installation ID and auth token data including possible states. + * The data is stored to Keychain via `FIRInstallationsStoredItem` which has only the storage + * relevant data and does not contain any logic. `FIRInstallationsItem` must be used on the logic + * level (not `FIRInstallationsStoredItem`). + */ +@interface FIRInstallationsItem : NSObject + +/// A `FirebaseApp` identifier. +@property(nonatomic, readonly) NSString *appID; +/// A `FirebaseApp` name. +@property(nonatomic, readonly) NSString *firebaseAppName; +/// A stable identifier that uniquely identifies the app instance. +@property(nonatomic, copy, nullable) NSString *firebaseInstallationID; +/// The `refreshToken` is used to authorize the auth token requests. +@property(nonatomic, copy, nullable) NSString *refreshToken; + +@property(nonatomic, nullable) FIRInstallationsStoredAuthToken *authToken; +@property(nonatomic, assign) FIRInstallationsStatus registrationStatus; + +/// Instance ID default token imported from IID store as a part of IID migration. +@property(nonatomic, nullable) NSString *IIDDefaultToken; + +- (instancetype)initWithAppID:(NSString *)appID firebaseAppName:(NSString *)firebaseAppName; + +/** + * Populates `FIRInstallationsItem` properties with data from `FIRInstallationsStoredItem`. + * @param item An instance of `FIRInstallationsStoredItem` to get data from. + */ +- (void)updateWithStoredItem:(FIRInstallationsStoredItem *)item; + +/** + * Creates a stored item with data from the object. + * @return Returns a `FIRInstallationsStoredItem` instance with the data from the object. + */ +- (FIRInstallationsStoredItem *)storedItem; + +/** + * The installation identifier. + * @return Returns a string uniquely identifying the installation. + */ +- (NSString *)identifier; + +/** Validates if all the required item fields are populated and values don't explicitly conflict + * with each other. + * @param outError A reference to be populated with an error containing validation failure details. + * @return `YES` if the item it valid, `NO` otherwise. + */ +- (BOOL)isValid:(NSError *_Nullable *)outError; + +/** + * The installation identifier. + * @param appID A `FirebaseApp` identifier. + * @param appName A `FirebaseApp` name. + * @return Returns a string uniquely identifying the installation. + */ ++ (NSString *)identifierWithAppID:(NSString *)appID appName:(NSString *)appName; + +/** + * Generate a new Firebase Installation Identifier. + * @return Returns a 22 characters long globally unique string created based on UUID. + */ ++ (NSString *)generateFID; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsItem.m b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsItem.m new file mode 100644 index 0000000..0316e45 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsItem.m @@ -0,0 +1,161 @@ +/* + * Copyright 2019 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 "FirebaseInstallations/Source/Library/FIRInstallationsItem.h" + +#import "FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.h" +#import "FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredItem.h" + +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h" + +@implementation FIRInstallationsItem + +- (instancetype)initWithAppID:(NSString *)appID firebaseAppName:(NSString *)firebaseAppName { + self = [super init]; + if (self) { + _appID = [appID copy]; + _firebaseAppName = [firebaseAppName copy]; + } + return self; +} + +- (nonnull id)copyWithZone:(nullable NSZone *)zone { + FIRInstallationsItem *clone = [[FIRInstallationsItem alloc] initWithAppID:self.appID + firebaseAppName:self.firebaseAppName]; + clone.firebaseInstallationID = [self.firebaseInstallationID copy]; + clone.refreshToken = [self.refreshToken copy]; + clone.authToken = [self.authToken copy]; + clone.registrationStatus = self.registrationStatus; + clone.IIDDefaultToken = [self.IIDDefaultToken copy]; + + return clone; +} + +- (void)updateWithStoredItem:(FIRInstallationsStoredItem *)item { + self.firebaseInstallationID = item.firebaseInstallationID; + self.refreshToken = item.refreshToken; + self.authToken = item.authToken; + self.registrationStatus = item.registrationStatus; + self.IIDDefaultToken = item.IIDDefaultToken; +} + +- (FIRInstallationsStoredItem *)storedItem { + FIRInstallationsStoredItem *storedItem = [[FIRInstallationsStoredItem alloc] init]; + storedItem.firebaseInstallationID = self.firebaseInstallationID; + storedItem.refreshToken = self.refreshToken; + storedItem.authToken = self.authToken; + storedItem.registrationStatus = self.registrationStatus; + storedItem.IIDDefaultToken = self.IIDDefaultToken; + return storedItem; +} + +- (nonnull NSString *)identifier { + return [[self class] identifierWithAppID:self.appID appName:self.firebaseAppName]; +} + +- (BOOL)isValid:(NSError *_Nullable *)outError { + NSMutableArray *validationIssues = [NSMutableArray array]; + + if (self.appID.length == 0) { + [validationIssues addObject:@"`appID` must not be empty"]; + } + + if (self.firebaseAppName.length == 0) { + [validationIssues addObject:@"`firebaseAppName` must not be empty"]; + } + + if (self.firebaseInstallationID.length == 0) { + [validationIssues addObject:@"`firebaseInstallationID` must not be empty"]; + } + + switch (self.registrationStatus) { + case FIRInstallationStatusUnknown: + [validationIssues addObject:@"invalid `registrationStatus`"]; + break; + + case FIRInstallationStatusRegistered: + if (self.refreshToken == 0) { + [validationIssues addObject:@"registered installation must have non-empty `refreshToken`"]; + } + + if (self.authToken.token == 0) { + [validationIssues + addObject:@"registered installation must have non-empty `authToken.token`"]; + } + + if (self.authToken.expirationDate == nil) { + [validationIssues + addObject:@"registered installation must have non-empty `authToken.expirationDate`"]; + } + + case FIRInstallationStatusUnregistered: + break; + } + + BOOL isValid = validationIssues.count == 0; + + if (!isValid && outError) { + NSString *failureReason = + [NSString stringWithFormat:@"FIRInstallationsItem validation errors: %@", + [validationIssues componentsJoinedByString:@", "]]; + *outError = + [FIRInstallationsErrorUtil installationsErrorWithCode:FIRInstallationsErrorCodeUnknown + failureReason:failureReason + underlyingError:nil]; + } + + return isValid; +} + ++ (NSString *)identifierWithAppID:(NSString *)appID appName:(NSString *)appName { + return [appID stringByAppendingString:appName]; +} + ++ (NSString *)generateFID { + NSUUID *UUID = [NSUUID UUID]; + uuid_t UUIDBytes; + [UUID getUUIDBytes:UUIDBytes]; + + NSUInteger UUIDLength = sizeof(uuid_t); + NSData *UUIDData = [NSData dataWithBytes:UUIDBytes length:UUIDLength]; + + uint8_t UUIDLast4Bits = UUIDBytes[UUIDLength - 1] & 0b00001111; + + // FID first 4 bits must be `0111`. The last 4 UUID bits will be cut later to form a proper FID. + // To keep 16 random bytes we copy these last 4 UUID to the FID 1st byte after `0111` prefix. + uint8_t FIDPrefix = 0b01110000 | UUIDLast4Bits; + NSMutableData *FIDData = [NSMutableData dataWithBytes:&FIDPrefix length:1]; + + [FIDData appendData:UUIDData]; + NSString *FIDString = [self base64URLEncodedStringWithData:FIDData]; + + // A valid FID has exactly 22 base64 characters, which is 132 bits, or 16.5 bytes. + // Our generated ID has 16 bytes UUID + 1 byte prefix which after encoding with base64 will become + // 23 characters plus 1 character for "=" padding. + + // Remove the 23rd character that was added because of the extra 4 bits at the + // end of our 17 byte data and the '=' padding. + return [FIDString substringWithRange:NSMakeRange(0, 22)]; +} + ++ (NSString *)base64URLEncodedStringWithData:(NSData *)data { + NSString *string = [data base64EncodedStringWithOptions:0]; + string = [string stringByReplacingOccurrencesOfString:@"/" withString:@"_"]; + string = [string stringByReplacingOccurrencesOfString:@"+" withString:@"-"]; + return string; +} + +@end diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsLogger.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsLogger.h new file mode 100644 index 0000000..7ad9967 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsLogger.h @@ -0,0 +1,52 @@ +/* + * Copyright 2019 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 + +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" + +extern FIRLoggerService kFIRLoggerInstallations; + +// FIRInstallationsAPIService.m +extern NSString *const kFIRInstallationsMessageCodeSendAPIRequest; +extern NSString *const kFIRInstallationsMessageCodeAPIRequestNetworkError; +extern NSString *const kFIRInstallationsMessageCodeAPIRequestResponse; +extern NSString *const kFIRInstallationsMessageCodeUnexpectedAPIRequestResponse; +extern NSString *const kFIRInstallationsMessageCodeParsingAPIResponse; +extern NSString *const kFIRInstallationsMessageCodeAPIResponseParsingInstallationFailed; +extern NSString *const kFIRInstallationsMessageCodeAPIResponseParsingInstallationSucceed; +extern NSString *const kFIRInstallationsMessageCodeAPIResponseParsingAuthTokenFailed; +extern NSString *const kFIRInstallationsMessageCodeAPIResponseParsingAuthTokenSucceed; + +// FIRInstallationsIDController.m +extern NSString *const kFIRInstallationsMessageCodeNewGetInstallationOperationCreated; +extern NSString *const kFIRInstallationsMessageCodeNewGetAuthTokenOperationCreated; +extern NSString *const kFIRInstallationsMessageCodeNewDeleteInstallationOperationCreated; +extern NSString *const kFIRInstallationsMessageCodeInvalidFirebaseConfiguration; +extern NSString *const kFIRInstallationsMessageCodeCorruptedStoredInstallation; + +// FIRInstallationsStoredItem.m +extern NSString *const kFIRInstallationsMessageCodeInstallationCoderVersionMismatch; + +// FIRInstallationsStoredAuthToken.m +extern NSString *const kFIRInstallationsMessageCodeAuthTokenCoderVersionMismatch; + +// FIRInstallationsStoredIIDCheckin.m +extern NSString *const kFIRInstallationsMessageCodeIIDCheckinCoderVersionMismatch; +extern NSString *const kFIRInstallationsMessageCodeIIDCheckinFailedToDecode; + +// FIRInstallations.m +extern NSString *const kFIRInstallationsMessageCodeInvalidFirebaseAppOptions; diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsLogger.m b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsLogger.m new file mode 100644 index 0000000..5187f97 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsLogger.m @@ -0,0 +1,50 @@ +/* + * Copyright 2019 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 "FirebaseInstallations/Source/Library/FIRInstallationsLogger.h" + +FIRLoggerService kFIRLoggerInstallations = @"[FirebaseInstallations]"; + +// FIRInstallationsAPIService.m +NSString *const kFIRInstallationsMessageCodeSendAPIRequest = @"I-FIS001001"; +NSString *const kFIRInstallationsMessageCodeAPIRequestNetworkError = @"I-FIS001002"; +NSString *const kFIRInstallationsMessageCodeAPIRequestResponse = @"I-FIS001003"; +NSString *const kFIRInstallationsMessageCodeUnexpectedAPIRequestResponse = @"I-FIS001004"; +NSString *const kFIRInstallationsMessageCodeParsingAPIResponse = @"I-FIS001005"; +NSString *const kFIRInstallationsMessageCodeAPIResponseParsingInstallationFailed = @"I-FIS001006"; +NSString *const kFIRInstallationsMessageCodeAPIResponseParsingInstallationSucceed = @"I-FIS001007"; +NSString *const kFIRInstallationsMessageCodeAPIResponseParsingAuthTokenFailed = @"I-FIS001008"; +NSString *const kFIRInstallationsMessageCodeAPIResponseParsingAuthTokenSucceed = @"I-FIS001009"; + +// FIRInstallationsIDController.m +NSString *const kFIRInstallationsMessageCodeNewGetInstallationOperationCreated = @"I-FIS002000"; +NSString *const kFIRInstallationsMessageCodeNewGetAuthTokenOperationCreated = @"I-FIS002001"; +NSString *const kFIRInstallationsMessageCodeNewDeleteInstallationOperationCreated = @"I-FIS002002"; +NSString *const kFIRInstallationsMessageCodeInvalidFirebaseConfiguration = @"I-FIS002003"; +NSString *const kFIRInstallationsMessageCodeCorruptedStoredInstallation = @"I-FIS002004"; + +// FIRInstallationsStoredItem.m +NSString *const kFIRInstallationsMessageCodeInstallationCoderVersionMismatch = @"I-FIS003000"; + +// FIRInstallationsStoredAuthToken.m +NSString *const kFIRInstallationsMessageCodeAuthTokenCoderVersionMismatch = @"I-FIS004000"; + +// FIRInstallationsStoredIIDCheckin.m +NSString *const kFIRInstallationsMessageCodeIIDCheckinCoderVersionMismatch = @"I-FIS007000"; +NSString *const kFIRInstallationsMessageCodeIIDCheckinFailedToDecode = @"I-FIS007001"; + +// FIRInstallations.m +NSString *const kFIRInstallationsMessageCodeInvalidFirebaseAppOptions = @"I-FIS008000"; diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDStore.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDStore.h new file mode 100644 index 0000000..e2408ca --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDStore.h @@ -0,0 +1,48 @@ +/* + * Copyright 2019 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 + +@class FBLPromise; + +NS_ASSUME_NONNULL_BEGIN + +/** The class encapsulates a port of a piece FirebaseInstanceID logic required to migrate IID. */ +@interface FIRInstallationsIIDStore : NSObject + +/** + * Retrieves existing IID if present. + * @return Returns a promise that is resolved with IID string if IID has been found or rejected with + * an error otherwise. + */ +- (FBLPromise *)existingIID; + +/** + * Deletes existing IID if present. + * @return Returns a promise that is resolved with `[NSNull null]` if the IID was successfully. + * deleted or was not found. The promise is rejected otherwise. + */ +- (FBLPromise *)deleteExistingIID; + +#if TARGET_OS_OSX +/// If not `nil`, then only this keychain will be used to save and read data (see +/// `kSecMatchSearchList` and `kSecUseKeychain`. It is mostly intended to be used by unit tests. +@property(nonatomic, nullable) SecKeychainRef keychainRef; +#endif // TARGET_OSX + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDStore.m b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDStore.m new file mode 100644 index 0000000..1c2f5d3 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDStore.m @@ -0,0 +1,242 @@ +/* + * Copyright 2019 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 "FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDStore.h" + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +#import +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h" + +static NSString *const kFIRInstallationsIIDKeyPairPublicTagPrefix = + @"com.google.iid.keypair.public-"; +static NSString *const kFIRInstallationsIIDKeyPairPrivateTagPrefix = + @"com.google.iid.keypair.private-"; +static NSString *const kFIRInstallationsIIDCreationTimePlistKey = @"|S|cre"; + +@implementation FIRInstallationsIIDStore + +- (FBLPromise *)existingIID { + return [FBLPromise onQueue:dispatch_get_global_queue(QOS_CLASS_UTILITY, 0) + do:^id _Nullable { + if (![self hasPlistIIDFlag]) { + return nil; + } + + NSData *IIDPublicKeyData = [self IIDPublicKeyData]; + return [self IIDWithPublicKeyData:IIDPublicKeyData]; + }] + .validate(^BOOL(NSString *_Nullable IID) { + return IID.length > 0; + }); +} + +- (FBLPromise *)deleteExistingIID { + return [FBLPromise onQueue:dispatch_get_global_queue(QOS_CLASS_UTILITY, 0) + do:^id _Nullable { + NSError *error; + if (![self deleteIIDFlagFromPlist:&error]) { + return error; + } + + if (![self deleteIID:&error]) { + return error; + } + + return [NSNull null]; + }]; +} + +#pragma mark - IID decoding + +- (NSString *)IIDWithPublicKeyData:(NSData *)publicKeyData { + NSData *publicKeySHA1 = [self sha1WithData:publicKeyData]; + + const uint8_t *bytes = publicKeySHA1.bytes; + NSMutableData *identityData = [NSMutableData dataWithData:publicKeySHA1]; + + uint8_t b0 = bytes[0]; + // Take the first byte and make the initial four 7 by initially making the initial 4 bits 0 + // and then adding 0x70 to it. + b0 = 0x70 + (0xF & b0); + // failsafe should give you back b0 itself + b0 = (b0 & 0xFF); + [identityData replaceBytesInRange:NSMakeRange(0, 1) withBytes:&b0]; + NSData *data = [identityData subdataWithRange:NSMakeRange(0, 8 * sizeof(Byte))]; + return [self base64URLEncodedStringWithData:data]; +} + +/** FirebaseInstallations SDK uses the SHA1 hash for backwards compatibility with the legacy + * FirebaseInstanceID SDK. The SHA1 hash is used to access Instance IDs stored on the device and not + * for any security-relevant process. This is a one-time step that allows migration of old client + * identifiers. Cryptographic security is not needed here, so potential hash collisions are not a + * problem. + */ +- (NSData *)sha1WithData:(NSData *)data { + unsigned char output[CC_SHA1_DIGEST_LENGTH]; + unsigned int length = (unsigned int)[data length]; + + CC_SHA1(data.bytes, length, output); + return [NSData dataWithBytes:output length:CC_SHA1_DIGEST_LENGTH]; +} + +- (NSString *)base64URLEncodedStringWithData:(NSData *)data { + NSString *string = [data base64EncodedStringWithOptions:0]; + string = [string stringByReplacingOccurrencesOfString:@"/" withString:@"_"]; + string = [string stringByReplacingOccurrencesOfString:@"+" withString:@"-"]; + string = [string stringByReplacingOccurrencesOfString:@"=" withString:@""]; + return string; +} + +#pragma mark - Keychain + +- (NSData *)IIDPublicKeyData { + NSString *tag = [self keychainKeyTagWithPrefix:kFIRInstallationsIIDKeyPairPublicTagPrefix]; + NSDictionary *query = [self keyPairQueryWithTag:tag returnData:YES]; + + CFTypeRef keyRef = NULL; + OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&keyRef); + + if (status != noErr) { + if (keyRef) { + CFRelease(keyRef); + } + return nil; + } + + return (__bridge NSData *)keyRef; +} + +- (BOOL)deleteIID:(NSError **)outError { + if (![self deleteKeychainKeyWithTagPrefix:kFIRInstallationsIIDKeyPairPublicTagPrefix + error:outError]) { + return NO; + } + + if (![self deleteKeychainKeyWithTagPrefix:kFIRInstallationsIIDKeyPairPrivateTagPrefix + error:outError]) { + return NO; + } + + return YES; +} + +- (BOOL)deleteKeychainKeyWithTagPrefix:(NSString *)tagPrefix error:(NSError **)outError { + NSString *keyTag = [self keychainKeyTagWithPrefix:kFIRInstallationsIIDKeyPairPublicTagPrefix]; + NSDictionary *keyQuery = [self keyPairQueryWithTag:keyTag returnData:NO]; + + OSStatus status = SecItemDelete((__bridge CFDictionaryRef)keyQuery); + + // When item is not found, it should NOT be considered as an error. The operation should + // continue. + if (status != noErr && status != errSecItemNotFound) { + FIRInstallationsItemSetErrorToPointer( + [FIRInstallationsErrorUtil keychainErrorWithFunction:@"SecItemDelete" status:status], + outError); + return NO; + } + + return YES; +} + +- (NSDictionary *)keyPairQueryWithTag:(NSString *)tag returnData:(BOOL)shouldReturnData { + NSMutableDictionary *query = [NSMutableDictionary dictionary]; + NSData *tagData = [tag dataUsingEncoding:NSUTF8StringEncoding]; + + query[(__bridge id)kSecClass] = (__bridge id)kSecClassKey; + query[(__bridge id)kSecAttrApplicationTag] = tagData; + query[(__bridge id)kSecAttrKeyType] = (__bridge id)kSecAttrKeyTypeRSA; + if (shouldReturnData) { + query[(__bridge id)kSecReturnData] = @(YES); + } + +#if TARGET_OS_OSX + if (self.keychainRef) { + query[(__bridge NSString *)kSecMatchSearchList] = @[ (__bridge id)(self.keychainRef) ]; + } +#endif // TARGET_OSX + + return query; +} + +- (NSString *)keychainKeyTagWithPrefix:(NSString *)prefix { + NSString *mainAppBundleID = [[NSBundle mainBundle] bundleIdentifier]; + if (mainAppBundleID.length == 0) { + return nil; + } + return [NSString stringWithFormat:@"%@%@", prefix, mainAppBundleID]; +} + +- (NSString *)mainbundleIdentifier { + NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier]; + if (!bundleIdentifier.length) { + return nil; + } + return bundleIdentifier; +} + +#pragma mark - Plist + +- (BOOL)deleteIIDFlagFromPlist:(NSError **)outError { + NSString *path = [self plistPath]; + if (![[NSFileManager defaultManager] fileExistsAtPath:path]) { + return YES; + } + + NSMutableDictionary *plistContent = [[NSMutableDictionary alloc] initWithContentsOfFile:path]; + plistContent[kFIRInstallationsIIDCreationTimePlistKey] = nil; + + if (@available(macOS 10.13, iOS 11.0, tvOS 11.0, *)) { + return [plistContent writeToURL:[NSURL fileURLWithPath:path] error:outError]; + } + + return [plistContent writeToFile:path atomically:YES]; +} + +- (BOOL)hasPlistIIDFlag { + NSString *path = [self plistPath]; + if (![[NSFileManager defaultManager] fileExistsAtPath:path]) { + return NO; + } + + NSDictionary *plistContent = [[NSDictionary alloc] initWithContentsOfFile:path]; + return plistContent[kFIRInstallationsIIDCreationTimePlistKey] != nil; +} + +- (NSString *)plistPath { + NSString *plistNameWithExtension = @"com.google.iid-keypair.plist"; + NSString *_subDirectoryName = @"Google/FirebaseInstanceID"; + + NSArray *directoryPaths = + NSSearchPathForDirectoriesInDomains([self supportedDirectory], NSUserDomainMask, YES); + NSArray *components = @[ directoryPaths.lastObject, _subDirectoryName, plistNameWithExtension ]; + + return [NSString pathWithComponents:components]; +} + +- (NSSearchPathDirectory)supportedDirectory { +#if TARGET_OS_TV + return NSCachesDirectory; +#else + return NSApplicationSupportDirectory; +#endif +} + +@end diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDTokenStore.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDTokenStore.h new file mode 100644 index 0000000..ed98e3d --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDTokenStore.h @@ -0,0 +1,36 @@ +/* + * Copyright 2019 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 + +@class FBLPromise; + +NS_ASSUME_NONNULL_BEGIN + +/** + * The class reads a default IID token from IID store if available. + */ +@interface FIRInstallationsIIDTokenStore : NSObject + +- (instancetype)init NS_UNAVAILABLE; + +- (instancetype)initWithGCMSenderID:(NSString *)GCMSenderID; + +- (FBLPromise *)existingIIDDefaultToken; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDTokenStore.m b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDTokenStore.m new file mode 100644 index 0000000..5ef3331 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDTokenStore.m @@ -0,0 +1,158 @@ +/* + * Copyright 2019 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 "FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDTokenStore.h" + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +#import + +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h" + +static NSString *const kFIRInstallationsIIDTokenKeychainId = @"com.google.iid-tokens"; + +@interface FIRInstallationsIIDTokenInfo : NSObject +@property(nonatomic, nullable, copy) NSString *token; +@end + +@implementation FIRInstallationsIIDTokenInfo + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (void)encodeWithCoder:(nonnull NSCoder *)coder { +} + +- (nullable instancetype)initWithCoder:(nonnull NSCoder *)coder { + self = [super init]; + if (self) { + _token = [coder decodeObjectOfClass:[NSString class] forKey:@"token"]; + } + return self; +} + +@end + +@interface FIRInstallationsIIDTokenStore () +@property(nonatomic, readonly) NSString *GCMSenderID; +@end + +@implementation FIRInstallationsIIDTokenStore + +- (instancetype)initWithGCMSenderID:(NSString *)GCMSenderID { + self = [super init]; + if (self) { + _GCMSenderID = GCMSenderID; + } + return self; +} + +- (FBLPromise *)existingIIDDefaultToken { + return [[FBLPromise onQueue:dispatch_get_global_queue(QOS_CLASS_UTILITY, 0) + do:^id _Nullable { + return [self IIDDefaultTokenData]; + }] onQueue:dispatch_get_global_queue(QOS_CLASS_UTILITY, 0) + then:^id _Nullable(NSData *_Nullable keychainData) { + return [self IIDCheckinWithData:keychainData]; + }]; +} + +- (FBLPromise *)IIDCheckinWithData:(NSData *)data { + FBLPromise *resultPromise = [FBLPromise pendingPromise]; + + NSError *archiverError; + NSKeyedUnarchiver *unarchiver; + if (@available(iOS 11.0, tvOS 11.0, macOS 10.13, *)) { + unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:data error:&archiverError]; + } else { + @try { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; +#pragma clang diagnostic pop + } @catch (NSException *exception) { + archiverError = [FIRInstallationsErrorUtil keyedArchiverErrorWithException:exception]; + } + } + + if (!unarchiver) { + NSError *error = archiverError ?: [FIRInstallationsErrorUtil corruptedIIDTokenData]; + [resultPromise reject:error]; + return resultPromise; + } + + [unarchiver setClass:[FIRInstallationsIIDTokenInfo class] forClassName:@"FIRInstanceIDTokenInfo"]; + FIRInstallationsIIDTokenInfo *IIDTokenInfo = + [unarchiver decodeObjectOfClass:[FIRInstallationsIIDTokenInfo class] + forKey:NSKeyedArchiveRootObjectKey]; + + if (IIDTokenInfo.token.length < 1) { + [resultPromise reject:[FIRInstallationsErrorUtil corruptedIIDTokenData]]; + return resultPromise; + } + + [resultPromise fulfill:IIDTokenInfo.token]; + + return resultPromise; +} + +- (FBLPromise *)IIDDefaultTokenData { + FBLPromise *resultPromise = [FBLPromise pendingPromise]; + + NSMutableDictionary *keychainQuery = [self IIDDefaultTokenDataKeychainQuery]; + NSError *error; + NSData *data = [GULKeychainUtils getItemWithQuery:keychainQuery error:&error]; + + if (data) { + [resultPromise fulfill:data]; + return resultPromise; + } else { + NSError *outError = error ?: [FIRInstallationsErrorUtil corruptedIIDTokenData]; + [resultPromise reject:outError]; + return resultPromise; + } +} + +- (NSMutableDictionary *)IIDDefaultTokenDataKeychainQuery { + NSDictionary *query = @{(__bridge id)kSecClass : (__bridge id)kSecClassGenericPassword}; + + NSMutableDictionary *finalQuery = [NSMutableDictionary dictionaryWithDictionary:query]; + finalQuery[(__bridge NSString *)kSecAttrGeneric] = kFIRInstallationsIIDTokenKeychainId; + + NSString *account = [self IIDAppIdentifier]; + if ([account length]) { + finalQuery[(__bridge NSString *)kSecAttrAccount] = account; + } + + finalQuery[(__bridge NSString *)kSecAttrService] = + [self serviceKeyForAuthorizedEntity:self.GCMSenderID scope:@"*"]; + return finalQuery; +} + +- (NSString *)IIDAppIdentifier { + return [[NSBundle mainBundle] bundleIdentifier] ?: @""; +} + +- (NSString *)serviceKeyForAuthorizedEntity:(NSString *)authorizedEntity scope:(NSString *)scope { + return [NSString stringWithFormat:@"%@:%@", authorizedEntity, scope]; +} + +@end diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsAPIService.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsAPIService.h new file mode 100644 index 0000000..1601bdc --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsAPIService.h @@ -0,0 +1,65 @@ +/* + * Copyright 2019 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 + +@class FBLPromise; +@class FIRInstallationsItem; + +@protocol FIRHeartbeatLoggerProtocol; + +NS_ASSUME_NONNULL_BEGIN + +FOUNDATION_EXPORT NSString *const kFIRInstallationsHeartbeatKey; + +/** + * The class is responsible for interacting with HTTP REST API for Installations. + */ +@interface FIRInstallationsAPIService : NSObject + +/** + * The default initializer. + * @param APIKey The Firebase project API key (see `FIROptions.APIKey`). + * @param projectID The Firebase project ID (see `FIROptions.projectID`). + * @param heartbeatLogger The heartbeat logger used to populate heartbeat data in request headers. + */ +- (instancetype)initWithAPIKey:(NSString *)APIKey + projectID:(NSString *)projectID + heartbeatLogger:(id)heartbeatLogger; + +/** + * Sends a request to register a new FID to get auth and refresh tokens. + * @param installation The `FIRInstallationsItem` instance with the FID to register. + * @return A promise that is resolved with a new `FIRInstallationsItem` instance with valid tokens. + * It is rejected with an error in case of a failure. + */ +- (FBLPromise *)registerInstallation:(FIRInstallationsItem *)installation; + +- (FBLPromise *)refreshAuthTokenForInstallation: + (FIRInstallationsItem *)installation; + +/** + * Sends a request to delete the installation, related auth tokens and all related data from the + * server. + * @param installation The installation to delete. + * @return Returns a promise that is resolved with the passed installation on successful deletion or + * is rejected with an error otherwise. + */ +- (FBLPromise *)deleteInstallation:(FIRInstallationsItem *)installation; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsAPIService.m b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsAPIService.m new file mode 100644 index 0000000..77408bb --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsAPIService.m @@ -0,0 +1,383 @@ +/* + * Copyright 2019 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 "FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsAPIService.h" + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h" +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsHTTPError.h" +#import "FirebaseInstallations/Source/Library/FIRInstallationsLogger.h" +#import "FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsItem+RegisterInstallationAPI.h" + +NSString *const kFIRInstallationsAPIBaseURL = @"https://firebaseinstallations.googleapis.com"; +NSString *const kFIRInstallationsAPIKey = @"X-Goog-Api-Key"; +NSString *const kFIRInstallationsBundleId = @"X-Ios-Bundle-Identifier"; +NSString *const kFIRInstallationsIIDMigrationAuthHeader = @"x-goog-fis-ios-iid-migration-auth"; +NSString *const kFIRInstallationsHeartbeatKey = @"X-firebase-client"; + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRInstallationsURLSessionResponse : NSObject +@property(nonatomic) NSHTTPURLResponse *HTTPResponse; +@property(nonatomic) NSData *data; + +- (instancetype)initWithResponse:(NSHTTPURLResponse *)response data:(nullable NSData *)data; +@end + +@implementation FIRInstallationsURLSessionResponse + +- (instancetype)initWithResponse:(NSHTTPURLResponse *)response data:(nullable NSData *)data { + self = [super init]; + if (self) { + _HTTPResponse = response; + _data = data ?: [NSData data]; + } + return self; +} + +@end + +@interface FIRInstallationsAPIService () +@property(nonatomic, readonly) NSURLSession *URLSession; +@property(nonatomic, readonly) NSString *APIKey; +@property(nonatomic, readonly) NSString *projectID; +@property(readonly) id heartbeatLogger; +@end + +NS_ASSUME_NONNULL_END + +@implementation FIRInstallationsAPIService + +- (instancetype)initWithAPIKey:(NSString *)APIKey + projectID:(NSString *)projectID + heartbeatLogger:(id)heartbeatLogger { + NSURLSession *URLSession = [NSURLSession + sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration]]; + return [self initWithURLSession:URLSession + APIKey:APIKey + projectID:projectID + heartbeatLogger:heartbeatLogger]; +} + +/// The initializer for tests. +- (instancetype)initWithURLSession:(NSURLSession *)URLSession + APIKey:(NSString *)APIKey + projectID:(NSString *)projectID + heartbeatLogger:(id)heartbeatLogger { + self = [super init]; + if (self) { + _URLSession = URLSession; + _APIKey = [APIKey copy]; + _projectID = [projectID copy]; + _heartbeatLogger = heartbeatLogger; + } + return self; +} + +#pragma mark - Public + +- (FBLPromise *)registerInstallation:(FIRInstallationsItem *)installation { + return [self validateInstallation:installation] + .then(^id _Nullable(FIRInstallationsItem *_Nullable validInstallation) { + return [self registerRequestWithInstallation:validInstallation]; + }) + .then(^id _Nullable(NSURLRequest *_Nullable request) { + return [self sendURLRequest:request]; + }) + .then(^id _Nullable(FIRInstallationsURLSessionResponse *response) { + return [self registeredInstallationWithInstallation:installation serverResponse:response]; + }); +} + +- (FBLPromise *)refreshAuthTokenForInstallation: + (FIRInstallationsItem *)installation { + return [self authTokenRequestWithInstallation:installation] + .then(^id _Nullable(NSURLRequest *_Nullable request) { + return [self sendURLRequest:request]; + }) + .then(^FBLPromise *( + FIRInstallationsURLSessionResponse *response) { + return [self authTokenWithServerResponse:response]; + }) + .then(^FIRInstallationsItem *(FIRInstallationsStoredAuthToken *authToken) { + FIRInstallationsItem *updatedInstallation = [installation copy]; + updatedInstallation.authToken = authToken; + return updatedInstallation; + }); +} + +- (FBLPromise *)deleteInstallation:(FIRInstallationsItem *)installation { + return [self deleteInstallationRequestWithInstallation:installation] + .then(^id _Nullable(NSURLRequest *_Nullable request) { + return [self sendURLRequest:request]; + }) + .then(^id _Nullable(FIRInstallationsURLSessionResponse *_Nullable value) { + // Return the original installation on success. + return installation; + }); +} + +#pragma mark - Register Installation + +- (FBLPromise *)registerRequestWithInstallation: + (FIRInstallationsItem *)installation { + NSString *URLString = [NSString stringWithFormat:@"%@/v1/projects/%@/installations/", + kFIRInstallationsAPIBaseURL, self.projectID]; + NSURL *URL = [NSURL URLWithString:URLString]; + + NSDictionary *bodyDict = @{ + // `firebaseInstallationID` is validated before but let's make sure it is not `nil` one more + // time to prevent a crash. + @"fid" : installation.firebaseInstallationID ?: @"", + @"authVersion" : @"FIS_v2", + @"appId" : installation.appID, + @"sdkVersion" : [self SDKVersion] + }; + + NSDictionary *headers; + if (installation.IIDDefaultToken) { + headers = @{kFIRInstallationsIIDMigrationAuthHeader : installation.IIDDefaultToken}; + } + + return [self requestWithURL:URL + HTTPMethod:@"POST" + bodyDict:bodyDict + refreshToken:nil + additionalHeaders:headers]; +} + +- (FBLPromise *) + registeredInstallationWithInstallation:(FIRInstallationsItem *)installation + serverResponse:(FIRInstallationsURLSessionResponse *)response { + return [FBLPromise do:^id { + FIRLogDebug(kFIRLoggerInstallations, kFIRInstallationsMessageCodeParsingAPIResponse, + @"Parsing server response for %@.", response.HTTPResponse.URL); + NSError *error; + FIRInstallationsItem *registeredInstallation = + [installation registeredInstallationWithJSONData:response.data + date:[NSDate date] + error:&error]; + if (registeredInstallation == nil) { + FIRLogDebug(kFIRLoggerInstallations, + kFIRInstallationsMessageCodeAPIResponseParsingInstallationFailed, + @"Failed to parse FIRInstallationsItem: %@.", error); + return error; + } + + FIRLogDebug(kFIRLoggerInstallations, + kFIRInstallationsMessageCodeAPIResponseParsingInstallationSucceed, + @"FIRInstallationsItem parsed successfully."); + return registeredInstallation; + }]; +} + +#pragma mark - Auth token + +- (FBLPromise *)authTokenRequestWithInstallation: + (FIRInstallationsItem *)installation { + NSString *URLString = + [NSString stringWithFormat:@"%@/v1/projects/%@/installations/%@/authTokens:generate", + kFIRInstallationsAPIBaseURL, self.projectID, + installation.firebaseInstallationID]; + NSURL *URL = [NSURL URLWithString:URLString]; + + NSDictionary *bodyDict = @{@"installation" : @{@"sdkVersion" : [self SDKVersion]}}; + return [self requestWithURL:URL + HTTPMethod:@"POST" + bodyDict:bodyDict + refreshToken:installation.refreshToken]; +} + +- (FBLPromise *)authTokenWithServerResponse: + (FIRInstallationsURLSessionResponse *)response { + return [FBLPromise do:^id { + FIRLogDebug(kFIRLoggerInstallations, kFIRInstallationsMessageCodeParsingAPIResponse, + @"Parsing server response for %@.", response.HTTPResponse.URL); + NSError *error; + FIRInstallationsStoredAuthToken *token = + [FIRInstallationsItem authTokenWithGenerateTokenAPIJSONData:response.data + date:[NSDate date] + error:&error]; + if (token == nil) { + FIRLogDebug(kFIRLoggerInstallations, + kFIRInstallationsMessageCodeAPIResponseParsingAuthTokenFailed, + @"Failed to parse FIRInstallationsStoredAuthToken: %@.", error); + return error; + } + + FIRLogDebug(kFIRLoggerInstallations, + kFIRInstallationsMessageCodeAPIResponseParsingAuthTokenSucceed, + @"FIRInstallationsStoredAuthToken parsed successfully."); + return token; + }]; +} + +#pragma mark - Delete Installation + +- (FBLPromise *)deleteInstallationRequestWithInstallation: + (FIRInstallationsItem *)installation { + NSString *URLString = [NSString stringWithFormat:@"%@/v1/projects/%@/installations/%@/", + kFIRInstallationsAPIBaseURL, self.projectID, + installation.firebaseInstallationID]; + NSURL *URL = [NSURL URLWithString:URLString]; + + return [self requestWithURL:URL + HTTPMethod:@"DELETE" + bodyDict:@{} + refreshToken:installation.refreshToken]; +} + +#pragma mark - URL Request +- (FBLPromise *)requestWithURL:(NSURL *)requestURL + HTTPMethod:(NSString *)HTTPMethod + bodyDict:(NSDictionary *)bodyDict + refreshToken:(nullable NSString *)refreshToken { + return [self requestWithURL:requestURL + HTTPMethod:HTTPMethod + bodyDict:bodyDict + refreshToken:refreshToken + additionalHeaders:nil]; +} + +- (FBLPromise *)requestWithURL:(NSURL *)requestURL + HTTPMethod:(NSString *)HTTPMethod + bodyDict:(NSDictionary *)bodyDict + refreshToken:(nullable NSString *)refreshToken + additionalHeaders:(nullable NSDictionary *) + additionalHeaders { + return [FBLPromise + onQueue:dispatch_get_global_queue(QOS_CLASS_UTILITY, 0) + do:^id _Nullable { + __block NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:requestURL]; + request.HTTPMethod = HTTPMethod; + NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier]; + [request addValue:self.APIKey forHTTPHeaderField:kFIRInstallationsAPIKey]; + [request addValue:bundleIdentifier forHTTPHeaderField:kFIRInstallationsBundleId]; + [self setJSONHTTPBody:bodyDict forRequest:request]; + if (refreshToken) { + NSString *authHeader = [NSString stringWithFormat:@"FIS_v2 %@", refreshToken]; + [request setValue:authHeader forHTTPHeaderField:@"Authorization"]; + } + // Heartbeat Header. + [request setValue:FIRHeaderValueFromHeartbeatsPayload( + [self.heartbeatLogger flushHeartbeatsIntoPayload]) + forHTTPHeaderField:kFIRInstallationsHeartbeatKey]; + + [additionalHeaders + enumerateKeysAndObjectsUsingBlock:^(NSString *_Nonnull key, NSString *_Nonnull obj, + BOOL *_Nonnull stop) { + [request setValue:obj forHTTPHeaderField:key]; + }]; + + return [request copy]; + }]; +} + +- (FBLPromise *)URLRequestPromise:(NSURLRequest *)request { + return [[FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + FIRLogDebug(kFIRLoggerInstallations, kFIRInstallationsMessageCodeSendAPIRequest, + @"Sending request: %@, body:%@, headers: %@.", request, + [[NSString alloc] initWithData:request.HTTPBody encoding:NSUTF8StringEncoding], + request.allHTTPHeaderFields); + [[self.URLSession + dataTaskWithRequest:request + completionHandler:^(NSData *_Nullable data, NSURLResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + FIRLogDebug(kFIRLoggerInstallations, + kFIRInstallationsMessageCodeAPIRequestNetworkError, + @"Request failed: %@, error: %@.", request, error); + reject(error); + } else { + FIRLogDebug(kFIRLoggerInstallations, kFIRInstallationsMessageCodeAPIRequestResponse, + @"Request response received: %@, error: %@, body: %@.", request, error, + [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]); + fulfill([[FIRInstallationsURLSessionResponse alloc] + initWithResponse:(NSHTTPURLResponse *)response + data:data]); + } + }] resume]; + }] then:^id _Nullable(FIRInstallationsURLSessionResponse *response) { + return [self validateHTTPResponseStatusCode:response]; + }]; +} + +- (FBLPromise *)validateHTTPResponseStatusCode: + (FIRInstallationsURLSessionResponse *)response { + NSInteger statusCode = response.HTTPResponse.statusCode; + return [FBLPromise do:^id _Nullable { + if (statusCode < 200 || statusCode >= 300) { + FIRLogDebug(kFIRLoggerInstallations, kFIRInstallationsMessageCodeUnexpectedAPIRequestResponse, + @"Unexpected API response: %@, body: %@.", response.HTTPResponse, + [[NSString alloc] initWithData:response.data encoding:NSUTF8StringEncoding]); + return [FIRInstallationsErrorUtil APIErrorWithHTTPResponse:response.HTTPResponse + data:response.data]; + } + return response; + }]; +} + +- (FBLPromise *)sendURLRequest:(NSURLRequest *)request { + return [FBLPromise attempts:1 + delay:1 + condition:^BOOL(NSInteger remainingAttempts, NSError *_Nonnull error) { + return [FIRInstallationsErrorUtil isAPIError:error + withHTTPCode:FIRInstallationsHTTPCodesServerInternalError]; + } + retry:^id _Nullable { + return [self URLRequestPromise:request]; + }]; +} + +- (NSString *)SDKVersion { + return [NSString stringWithFormat:@"i:%@", FIRFirebaseVersion()]; +} + +#pragma mark - Validation + +- (FBLPromise *)validateInstallation:(FIRInstallationsItem *)installation { + FBLPromise *result = [FBLPromise pendingPromise]; + + NSError *validationError; + if ([installation isValid:&validationError]) { + [result fulfill:installation]; + } else { + [result reject:validationError]; + } + return result; +} + +#pragma mark - JSON + +- (void)setJSONHTTPBody:(NSDictionary *)body + forRequest:(NSMutableURLRequest *)request { + [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; + + NSError *error; + NSData *JSONData = [NSJSONSerialization dataWithJSONObject:body options:0 error:&error]; + if (JSONData == nil) { + // TODO: Log or return an error. + } + request.HTTPBody = JSONData; +} + +@end diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsItem+RegisterInstallationAPI.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsItem+RegisterInstallationAPI.h new file mode 100644 index 0000000..ec0217f --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsItem+RegisterInstallationAPI.h @@ -0,0 +1,53 @@ +/* + * Copyright 2019 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 "FirebaseInstallations/Source/Library/FIRInstallationsItem.h" + +@class FIRInstallationsStoredAuthToken; + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRInstallationsItem (RegisterInstallationAPI) + +/** + * Parses and validates the Register Installation API response and returns a corresponding + * `FIRInstallationsItem` instance on success. + * @param JSONData The data with JSON encoded API response. + * @param date The installation auth token expiration date will be calculated as `date` + + * `response.authToken.expiresIn`. For most of the cases `[NSDate date]` should be passed there. A + * different value may be passed e.g. for unit tests. + * @param outError A pointer to assign a specific `NSError` instance in case of failure. No error is + * assigned in case of success. + * @return Returns a new `FIRInstallationsItem` instance in the success case or `nil` otherwise. + */ +- (nullable FIRInstallationsItem *)registeredInstallationWithJSONData:(NSData *)JSONData + date:(NSDate *)date + error: + (NSError *_Nullable *)outError; + ++ (nullable FIRInstallationsStoredAuthToken *)authTokenWithGenerateTokenAPIJSONData:(NSData *)data + date:(NSDate *)date + error:(NSError **) + outError; + ++ (nullable FIRInstallationsStoredAuthToken *)authTokenWithJSONDict: + (NSDictionary *)dict + date:(NSDate *)date + error:(NSError **)outError; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsItem+RegisterInstallationAPI.m b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsItem+RegisterInstallationAPI.m new file mode 100644 index 0000000..e5c7360 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsItem+RegisterInstallationAPI.m @@ -0,0 +1,142 @@ +/* + * Copyright 2019 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 "FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsItem+RegisterInstallationAPI.h" + +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h" +#import "FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.h" + +@implementation FIRInstallationsItem (RegisterInstallationAPI) + +- (nullable FIRInstallationsItem *) + registeredInstallationWithJSONData:(NSData *)data + date:(NSDate *)date + error:(NSError *__autoreleasing _Nullable *_Nullable)outError { + NSDictionary *responseJSON = [FIRInstallationsItem dictionaryFromJSONData:data error:outError]; + if (!responseJSON) { + return nil; + } + + NSString *refreshToken = [FIRInstallationsItem validStringOrNilForKey:@"refreshToken" + fromDict:responseJSON]; + if (refreshToken == nil) { + FIRInstallationsItemSetErrorToPointer( + [FIRInstallationsErrorUtil FIDRegistrationErrorWithResponseMissingField:@"refreshToken"], + outError); + return nil; + } + + NSDictionary *authTokenDict = responseJSON[@"authToken"]; + if (![authTokenDict isKindOfClass:[NSDictionary class]]) { + FIRInstallationsItemSetErrorToPointer( + [FIRInstallationsErrorUtil FIDRegistrationErrorWithResponseMissingField:@"authToken"], + outError); + return nil; + } + + FIRInstallationsStoredAuthToken *authToken = + [FIRInstallationsItem authTokenWithJSONDict:authTokenDict date:date error:outError]; + if (authToken == nil) { + return nil; + } + + FIRInstallationsItem *installation = + [[FIRInstallationsItem alloc] initWithAppID:self.appID firebaseAppName:self.firebaseAppName]; + NSString *installationID = [FIRInstallationsItem validStringOrNilForKey:@"fid" + fromDict:responseJSON]; + installation.firebaseInstallationID = installationID ?: self.firebaseInstallationID; + installation.refreshToken = refreshToken; + installation.authToken = authToken; + installation.registrationStatus = FIRInstallationStatusRegistered; + + return installation; +} + +#pragma mark - Auth token + ++ (nullable FIRInstallationsStoredAuthToken *)authTokenWithGenerateTokenAPIJSONData:(NSData *)data + date:(NSDate *)date + error:(NSError **) + outError { + NSDictionary *dict = [self dictionaryFromJSONData:data error:outError]; + if (!dict) { + return nil; + } + + return [self authTokenWithJSONDict:dict date:date error:outError]; +} + ++ (nullable FIRInstallationsStoredAuthToken *)authTokenWithJSONDict: + (NSDictionary *)dict + date:(NSDate *)date + error:(NSError **)outError { + NSString *token = [self validStringOrNilForKey:@"token" fromDict:dict]; + if (token == nil) { + FIRInstallationsItemSetErrorToPointer( + [FIRInstallationsErrorUtil FIDRegistrationErrorWithResponseMissingField:@"authToken.token"], + outError); + return nil; + } + + NSString *expiresInString = [self validStringOrNilForKey:@"expiresIn" fromDict:dict]; + if (expiresInString == nil) { + FIRInstallationsItemSetErrorToPointer( + [FIRInstallationsErrorUtil + FIDRegistrationErrorWithResponseMissingField:@"authToken.expiresIn"], + outError); + return nil; + } + + // The response should contain the string in format like "604800s". + // The server should never response with anything else except seconds. + // Just drop the last character and parse a number from string. + NSString *expiresInSeconds = [expiresInString substringToIndex:expiresInString.length - 1]; + NSTimeInterval expiresIn = [expiresInSeconds doubleValue]; + NSDate *expirationDate = [date dateByAddingTimeInterval:expiresIn]; + + FIRInstallationsStoredAuthToken *authToken = [[FIRInstallationsStoredAuthToken alloc] init]; + authToken.status = FIRInstallationsAuthTokenStatusTokenReceived; + authToken.token = token; + authToken.expirationDate = expirationDate; + + return authToken; +} + +#pragma mark - JSON + ++ (nullable NSDictionary *)dictionaryFromJSONData:(NSData *)data + error:(NSError **)outError { + NSError *error; + NSDictionary *responseJSON = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; + + if (![responseJSON isKindOfClass:[NSDictionary class]]) { + FIRInstallationsItemSetErrorToPointer([FIRInstallationsErrorUtil JSONSerializationError:error], + outError); + return nil; + } + + return responseJSON; +} + ++ (NSString *)validStringOrNilForKey:(NSString *)key fromDict:(NSDictionary *)dict { + NSString *string = dict[key]; + if ([string isKindOfClass:[NSString class]] && string.length > 0) { + return string; + } + return nil; +} + +@end diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRCurrentDateProvider.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRCurrentDateProvider.h new file mode 100644 index 0000000..4d40338 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRCurrentDateProvider.h @@ -0,0 +1,27 @@ +/* + * Copyright 2020 Google LLC + * + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** A block returning current date. */ +typedef NSDate *_Nonnull (^FIRCurrentDateProvider)(void); + +/** The function returns a `FIRCurrentDateProvider` block that returns a real current date. */ +FIRCurrentDateProvider FIRRealCurrentDateProvider(void); + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRCurrentDateProvider.m b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRCurrentDateProvider.m new file mode 100644 index 0000000..d2a1d40 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRCurrentDateProvider.m @@ -0,0 +1,23 @@ +/* + * Copyright 2020 Google LLC + * + * 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 "FirebaseInstallations/Source/Library/InstallationsIDController/FIRCurrentDateProvider.h" + +FIRCurrentDateProvider FIRRealCurrentDateProvider(void) { + return ^NSDate *(void) { + return [NSDate date]; + }; +} diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsBackoffController.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsBackoffController.h new file mode 100644 index 0000000..5760618 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsBackoffController.h @@ -0,0 +1,54 @@ +/* + * Copyright 2020 Google LLC + * + * 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 + +#import "FirebaseInstallations/Source/Library/InstallationsIDController/FIRCurrentDateProvider.h" + +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(NSInteger, FIRInstallationsBackoffEvent) { + FIRInstallationsBackoffEventSuccess, + FIRInstallationsBackoffEventRecoverableFailure, + FIRInstallationsBackoffEventUnrecoverableFailure +}; + +/** The protocol defines API for a class that encapsulates backoff logic that prevents the SDK from + * sending unnecessary server requests. See API docs for the methods for more details. */ + +@protocol FIRInstallationsBackoffControllerProtocol + +/** The client must call the method each time a protected server request succeeds of fails. It will + * affect the `isNextRequestAllowed` method result for the current time, e.g. when 3 recoverable + * errors were logged in a row, then `isNextRequestAllowed` will return `YES` only in `pow(2, 3)` + * seconds. */ +- (void)registerEvent:(FIRInstallationsBackoffEvent)event; + +/** Returns if sending a next protected is recommended based on the time and the sequence of logged + * events and the current time. See also `registerEvent:`. */ +- (BOOL)isNextRequestAllowed; + +@end + +/** An implementation of `FIRInstallationsBackoffControllerProtocol` with exponential backoff for + * recoverable errors and constant backoff for recoverable errors. */ +@interface FIRInstallationsBackoffController : NSObject + +- (instancetype)initWithCurrentDateProvider:(FIRCurrentDateProvider)currentDateProvider; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsBackoffController.m b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsBackoffController.m new file mode 100644 index 0000000..1835d08 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsBackoffController.m @@ -0,0 +1,132 @@ +/* + * Copyright 2020 Google LLC + * + * 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 "FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsBackoffController.h" + +static const NSTimeInterval k24Hours = 24 * 60 * 60; +static const NSTimeInterval k30Minutes = 30 * 60; + +/** The class represents `FIRInstallationsBackoffController` sate required to calculate next allowed + request time. The properties of the class are intentionally immutable because changing them + separately leads to an inconsistent state. */ +@interface FIRInstallationsBackoffEventData : NSObject + +@property(nonatomic, readonly) FIRInstallationsBackoffEvent eventType; +@property(nonatomic, readonly) NSDate *lastEventDate; +@property(nonatomic, readonly) NSInteger eventCount; + +@property(nonatomic, readonly) NSTimeInterval backoffTimeInterval; + +@end + +@implementation FIRInstallationsBackoffEventData + +- (instancetype)initWithEvent:(FIRInstallationsBackoffEvent)eventType + lastEventDate:(NSDate *)lastEventDate + eventCount:(NSInteger)eventCount { + self = [super init]; + if (self) { + _eventType = eventType; + _lastEventDate = lastEventDate; + _eventCount = eventCount; + + _backoffTimeInterval = [[self class] backoffTimeIntervalWithEvent:eventType + eventCount:eventCount]; + } + return self; +} + ++ (NSTimeInterval)backoffTimeIntervalWithEvent:(FIRInstallationsBackoffEvent)eventType + eventCount:(NSInteger)eventCount { + switch (eventType) { + case FIRInstallationsBackoffEventSuccess: + return 0; + break; + + case FIRInstallationsBackoffEventRecoverableFailure: + return [self recoverableErrorBackoffTimeForAttemptNumber:eventCount]; + break; + + case FIRInstallationsBackoffEventUnrecoverableFailure: + return k24Hours; + break; + } +} + ++ (NSTimeInterval)recoverableErrorBackoffTimeForAttemptNumber:(NSInteger)attemptNumber { + NSTimeInterval exponentialInterval = pow(2, attemptNumber) + [self randomMilliseconds]; + return MIN(exponentialInterval, k30Minutes); +} + ++ (NSTimeInterval)randomMilliseconds { + int32_t random_millis = ABS(arc4random() % 1000); + return (double)random_millis * 0.001; +} + +@end + +@interface FIRInstallationsBackoffController () + +@property(nonatomic, readonly) FIRCurrentDateProvider currentDateProvider; + +@property(nonatomic, nullable) FIRInstallationsBackoffEventData *lastEventData; + +@end + +@implementation FIRInstallationsBackoffController + +- (instancetype)init { + return [self initWithCurrentDateProvider:FIRRealCurrentDateProvider()]; +} + +- (instancetype)initWithCurrentDateProvider:(FIRCurrentDateProvider)currentDateProvider { + self = [super init]; + if (self) { + _currentDateProvider = [currentDateProvider copy]; + } + return self; +} + +- (BOOL)isNextRequestAllowed { + @synchronized(self) { + if (self.lastEventData == nil) { + return YES; + } + + NSTimeInterval timeSinceLastEvent = + [self.currentDateProvider() timeIntervalSinceDate:self.lastEventData.lastEventDate]; + return timeSinceLastEvent >= self.lastEventData.backoffTimeInterval; + } +} + +- (void)registerEvent:(FIRInstallationsBackoffEvent)event { + @synchronized(self) { + // Event of the same type as was registered before. + if (self.lastEventData && self.lastEventData.eventType == event) { + self.lastEventData = [[FIRInstallationsBackoffEventData alloc] + initWithEvent:event + lastEventDate:self.currentDateProvider() + eventCount:self.lastEventData.eventCount + 1]; + } else { // A different event. + self.lastEventData = + [[FIRInstallationsBackoffEventData alloc] initWithEvent:event + lastEventDate:self.currentDateProvider() + eventCount:1]; + } + } +} + +@end diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsIDController.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsIDController.h new file mode 100644 index 0000000..8e66af9 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsIDController.h @@ -0,0 +1,40 @@ +/* + * Copyright 2019 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 + +NS_ASSUME_NONNULL_BEGIN + +@class FBLPromise; +@class FIRApp; +@class FIRInstallationsItem; + +/** + * The class is responsible for managing FID for a given `FIRApp`. + */ +@interface FIRInstallationsIDController : NSObject + +- (instancetype)initWithApp:(FIRApp *)app; + +- (FBLPromise *)getInstallationItem; + +- (FBLPromise *)getAuthTokenForcingRefresh:(BOOL)forceRefresh; + +- (FBLPromise *)deleteInstallation; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsIDController.m b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsIDController.m new file mode 100644 index 0000000..6ade8cc --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsIDController.m @@ -0,0 +1,530 @@ +/* + * Copyright 2019 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 "FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsIDController.h" + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +#import +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" + +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h" +#import "FirebaseInstallations/Source/Library/FIRInstallationsItem.h" +#import "FirebaseInstallations/Source/Library/FIRInstallationsLogger.h" +#import "FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDStore.h" +#import "FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDTokenStore.h" +#import "FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsAPIService.h" +#import "FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsBackoffController.h" +#import "FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsSingleOperationPromiseCache.h" +#import "FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStore.h" + +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsHTTPError.h" +#import "FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.h" + +const NSNotificationName FIRInstallationIDDidChangeNotification = + @"FIRInstallationIDDidChangeNotification"; +NSString *const kFIRInstallationIDDidChangeNotificationAppNameKey = + @"FIRInstallationIDDidChangeNotification"; + +NSTimeInterval const kFIRInstallationsTokenExpirationThreshold = 60 * 60; // 1 hour. + +static NSString *const kKeychainService = @"com.firebase.FIRInstallations.installations"; + +@interface FIRInstallationsIDController () +@property(nonatomic, readonly) NSString *appID; +@property(nonatomic, readonly) NSString *appName; + +@property(nonatomic, readonly) FIRInstallationsStore *installationsStore; +@property(nonatomic, readonly) FIRInstallationsIIDStore *IIDStore; +@property(nonatomic, readonly) FIRInstallationsIIDTokenStore *IIDTokenStore; + +@property(nonatomic, readonly) FIRInstallationsAPIService *APIService; + +@property(nonatomic, readonly) id backoffController; + +@property(nonatomic, readonly) FIRInstallationsSingleOperationPromiseCache + *getInstallationPromiseCache; +@property(nonatomic, readonly) + FIRInstallationsSingleOperationPromiseCache *authTokenPromiseCache; +@property(nonatomic, readonly) FIRInstallationsSingleOperationPromiseCache + *authTokenForcingRefreshPromiseCache; +@property(nonatomic, readonly) + FIRInstallationsSingleOperationPromiseCache *deleteInstallationPromiseCache; +@end + +@implementation FIRInstallationsIDController + +- (instancetype)initWithApp:(FIRApp *)app { + NSString *serviceName = + [FIRInstallationsIDController keychainServiceWithAppID:app.options.googleAppID]; + GULKeychainStorage *secureStorage = [[GULKeychainStorage alloc] initWithService:serviceName]; + FIRInstallationsStore *installationsStore = + [[FIRInstallationsStore alloc] initWithSecureStorage:secureStorage + accessGroup:app.options.appGroupID]; + + FIRInstallationsAPIService *apiService = + [[FIRInstallationsAPIService alloc] initWithAPIKey:app.options.APIKey + projectID:app.options.projectID + heartbeatLogger:app.heartbeatLogger]; + + FIRInstallationsIIDStore *IIDStore = [[FIRInstallationsIIDStore alloc] init]; + FIRInstallationsIIDTokenStore *IIDCheckingStore = + [[FIRInstallationsIIDTokenStore alloc] initWithGCMSenderID:app.options.GCMSenderID]; + + FIRInstallationsBackoffController *backoffController = + [[FIRInstallationsBackoffController alloc] init]; + + return [self initWithGoogleAppID:app.options.googleAppID + appName:app.name + installationsStore:installationsStore + APIService:apiService + IIDStore:IIDStore + IIDTokenStore:IIDCheckingStore + backoffController:backoffController]; +} + +/// The initializer is supposed to be used by tests to inject `installationsStore`. +- (instancetype)initWithGoogleAppID:(NSString *)appID + appName:(NSString *)appName + installationsStore:(FIRInstallationsStore *)installationsStore + APIService:(FIRInstallationsAPIService *)APIService + IIDStore:(FIRInstallationsIIDStore *)IIDStore + IIDTokenStore:(FIRInstallationsIIDTokenStore *)IIDTokenStore + backoffController: + (id)backoffController { + self = [super init]; + if (self) { + _appID = appID; + _appName = appName; + _installationsStore = installationsStore; + _APIService = APIService; + _IIDStore = IIDStore; + _IIDTokenStore = IIDTokenStore; + _backoffController = backoffController; + + __weak FIRInstallationsIDController *weakSelf = self; + + _getInstallationPromiseCache = [[FIRInstallationsSingleOperationPromiseCache alloc] + initWithNewOperationHandler:^FBLPromise *_Nonnull { + FIRInstallationsIDController *strongSelf = weakSelf; + return [strongSelf createGetInstallationItemPromise]; + }]; + + _authTokenPromiseCache = [[FIRInstallationsSingleOperationPromiseCache alloc] + initWithNewOperationHandler:^FBLPromise *_Nonnull { + FIRInstallationsIDController *strongSelf = weakSelf; + return [strongSelf installationWithValidAuthTokenForcingRefresh:NO]; + }]; + + _authTokenForcingRefreshPromiseCache = [[FIRInstallationsSingleOperationPromiseCache alloc] + initWithNewOperationHandler:^FBLPromise *_Nonnull { + FIRInstallationsIDController *strongSelf = weakSelf; + return [strongSelf installationWithValidAuthTokenForcingRefresh:YES]; + }]; + + _deleteInstallationPromiseCache = [[FIRInstallationsSingleOperationPromiseCache alloc] + initWithNewOperationHandler:^FBLPromise *_Nonnull { + FIRInstallationsIDController *strongSelf = weakSelf; + return [strongSelf createDeleteInstallationPromise]; + }]; + } + return self; +} + +#pragma mark - Get Installation. + +- (FBLPromise *)getInstallationItem { + return [self.getInstallationPromiseCache getExistingPendingOrCreateNewPromise]; +} + +- (FBLPromise *)createGetInstallationItemPromise { + FIRLogDebug(kFIRLoggerInstallations, + kFIRInstallationsMessageCodeNewGetInstallationOperationCreated, @"%s, appName: %@", + __PRETTY_FUNCTION__, self.appName); + + FBLPromise *installationItemPromise = + [self getStoredInstallation].recover(^id(NSError *error) { + return [self createAndSaveFID]; + }); + + // Initiate registration process on success if needed, but return the installation without waiting + // for it. + installationItemPromise.then(^id(FIRInstallationsItem *installation) { + [self getAuthTokenForcingRefresh:NO]; + return nil; + }); + + return installationItemPromise; +} + +- (FBLPromise *)getStoredInstallation { + return [self.installationsStore installationForAppID:self.appID appName:self.appName].validate( + ^BOOL(FIRInstallationsItem *installation) { + NSError *validationError; + BOOL isValid = [installation isValid:&validationError]; + + if (!isValid) { + FIRLogWarning( + kFIRLoggerInstallations, kFIRInstallationsMessageCodeCorruptedStoredInstallation, + @"Stored installation validation error: %@", validationError.localizedDescription); + } + + return isValid; + }); +} + +- (FBLPromise *)createAndSaveFID { + return [self migrateOrGenerateInstallation] + .then(^FBLPromise *(FIRInstallationsItem *installation) { + return [self saveInstallation:installation]; + }) + .then(^FIRInstallationsItem *(FIRInstallationsItem *installation) { + [self postFIDDidChangeNotification]; + return installation; + }); +} + +- (FBLPromise *)saveInstallation:(FIRInstallationsItem *)installation { + return [self.installationsStore saveInstallation:installation].then( + ^FIRInstallationsItem *(NSNull *result) { + return installation; + }); +} + +/** + * Tries to migrate IID data stored by FirebaseInstanceID SDK or generates a new Installation ID if + * not found. + */ +- (FBLPromise *)migrateOrGenerateInstallation { + if (![self isDefaultApp]) { + // Existing IID should be used only for default FirebaseApp. + FIRInstallationsItem *installation = + [self createInstallationWithFID:[FIRInstallationsItem generateFID] IIDDefaultToken:nil]; + return [FBLPromise resolvedWith:installation]; + } + + return [[[FBLPromise + all:@[ [self.IIDStore existingIID], [self.IIDTokenStore existingIIDDefaultToken] ]] + then:^id _Nullable(NSArray *_Nullable results) { + NSString *existingIID = results[0]; + NSString *IIDDefaultToken = results[1]; + + return [self createInstallationWithFID:existingIID IIDDefaultToken:IIDDefaultToken]; + }] recover:^id _Nullable(NSError *_Nonnull error) { + return [self createInstallationWithFID:[FIRInstallationsItem generateFID] IIDDefaultToken:nil]; + }]; +} + +- (FIRInstallationsItem *)createInstallationWithFID:(NSString *)FID + IIDDefaultToken:(nullable NSString *)IIDDefaultToken { + FIRInstallationsItem *installation = [[FIRInstallationsItem alloc] initWithAppID:self.appID + firebaseAppName:self.appName]; + installation.firebaseInstallationID = FID; + installation.IIDDefaultToken = IIDDefaultToken; + installation.registrationStatus = FIRInstallationStatusUnregistered; + return installation; +} + +#pragma mark - FID registration + +- (FBLPromise *)registerInstallationIfNeeded: + (FIRInstallationsItem *)installation { + switch (installation.registrationStatus) { + case FIRInstallationStatusRegistered: + // Already registered. Do nothing. + return [FBLPromise resolvedWith:installation]; + + case FIRInstallationStatusUnknown: + case FIRInstallationStatusUnregistered: + // Registration required. Proceed. + break; + } + + // Check for backoff. + if (![self.backoffController isNextRequestAllowed]) { + return [FIRInstallationsErrorUtil + rejectedPromiseWithError:[FIRInstallationsErrorUtil backoffIntervalWaitError]]; + } + + return [self.APIService registerInstallation:installation] + .catch(^(NSError *_Nonnull error) { + [self updateBackoffWithSuccess:NO APIError:error]; + + if ([self doesRegistrationErrorRequireConfigChange:error]) { + FIRLogError(kFIRLoggerInstallations, + kFIRInstallationsMessageCodeInvalidFirebaseConfiguration, + @"Firebase Installation registration failed for app with name: %@, error:\n" + @"%@\nPlease make sure you use valid GoogleService-Info.plist", + self.appName, error.userInfo[NSLocalizedFailureReasonErrorKey]); + } + }) + .then(^id(FIRInstallationsItem *registeredInstallation) { + [self updateBackoffWithSuccess:YES APIError:nil]; + return [self saveInstallation:registeredInstallation]; + }) + .then(^FIRInstallationsItem *(FIRInstallationsItem *registeredInstallation) { + // Server may respond with a different FID if the sent one cannot be accepted. + if (![registeredInstallation.firebaseInstallationID + isEqualToString:installation.firebaseInstallationID]) { + [self postFIDDidChangeNotification]; + } + return registeredInstallation; + }); +} + +- (BOOL)doesRegistrationErrorRequireConfigChange:(NSError *)error { + FIRInstallationsHTTPError *HTTPError = (FIRInstallationsHTTPError *)error; + if (![HTTPError isKindOfClass:[FIRInstallationsHTTPError class]]) { + return NO; + } + + switch (HTTPError.HTTPResponse.statusCode) { + // These are the errors that require Firebase configuration change. + case FIRInstallationsRegistrationHTTPCodeInvalidArgument: + case FIRInstallationsRegistrationHTTPCodeAPIKeyToProjectIDMismatch: + case FIRInstallationsRegistrationHTTPCodeProjectNotFound: + return YES; + + default: + return NO; + } +} + +#pragma mark - Auth Token + +- (FBLPromise *)getAuthTokenForcingRefresh:(BOOL)forceRefresh { + if (forceRefresh || [self.authTokenForcingRefreshPromiseCache getExistingPendingPromise] != nil) { + return [self.authTokenForcingRefreshPromiseCache getExistingPendingOrCreateNewPromise]; + } else { + return [self.authTokenPromiseCache getExistingPendingOrCreateNewPromise]; + } +} + +- (FBLPromise *)installationWithValidAuthTokenForcingRefresh: + (BOOL)forceRefresh { + FIRLogDebug(kFIRLoggerInstallations, kFIRInstallationsMessageCodeNewGetAuthTokenOperationCreated, + @"-[FIRInstallationsIDController installationWithValidAuthTokenForcingRefresh:%@], " + @"appName: %@", + @(forceRefresh), self.appName); + + return [self getInstallationItem] + .then(^FBLPromise *(FIRInstallationsItem *installation) { + return [self registerInstallationIfNeeded:installation]; + }) + .then(^id(FIRInstallationsItem *registeredInstallation) { + BOOL isTokenExpiredOrExpiresSoon = + [registeredInstallation.authToken.expirationDate timeIntervalSinceDate:[NSDate date]] < + kFIRInstallationsTokenExpirationThreshold; + if (forceRefresh || isTokenExpiredOrExpiresSoon) { + return [self refreshAuthTokenForInstallation:registeredInstallation]; + } else { + return registeredInstallation; + } + }) + .recover(^id(NSError *error) { + return [self regenerateFIDOnRefreshTokenErrorIfNeeded:error]; + }); +} + +- (FBLPromise *)refreshAuthTokenForInstallation: + (FIRInstallationsItem *)installation { + // Check for backoff. + if (![self.backoffController isNextRequestAllowed]) { + return [FIRInstallationsErrorUtil + rejectedPromiseWithError:[FIRInstallationsErrorUtil backoffIntervalWaitError]]; + } + + return [[[self.APIService refreshAuthTokenForInstallation:installation] + then:^id _Nullable(FIRInstallationsItem *_Nullable refreshedInstallation) { + [self updateBackoffWithSuccess:YES APIError:nil]; + return [self saveInstallation:refreshedInstallation]; + }] recover:^id _Nullable(NSError *_Nonnull error) { + // Pass the error to the backoff controller. + [self updateBackoffWithSuccess:NO APIError:error]; + return error; + }]; +} + +- (id)regenerateFIDOnRefreshTokenErrorIfNeeded:(NSError *)error { + if (![error isKindOfClass:[FIRInstallationsHTTPError class]]) { + // No recovery possible. Return the same error. + return error; + } + + FIRInstallationsHTTPError *HTTPError = (FIRInstallationsHTTPError *)error; + switch (HTTPError.HTTPResponse.statusCode) { + case FIRInstallationsAuthTokenHTTPCodeInvalidAuthentication: + case FIRInstallationsAuthTokenHTTPCodeFIDNotFound: + // The stored installation was damaged or blocked by the server. + // Delete the stored installation then generate and register a new one. + return [self getInstallationItem] + .then(^FBLPromise *(FIRInstallationsItem *installation) { + return [self deleteInstallationLocally:installation]; + }) + .then(^FBLPromise *(id result) { + return [self installationWithValidAuthTokenForcingRefresh:NO]; + }); + + default: + // No recovery possible. Return the same error. + return error; + } +} + +#pragma mark - Delete FID + +- (FBLPromise *)deleteInstallation { + return [self.deleteInstallationPromiseCache getExistingPendingOrCreateNewPromise]; +} + +- (FBLPromise *)createDeleteInstallationPromise { + FIRLogDebug(kFIRLoggerInstallations, + kFIRInstallationsMessageCodeNewDeleteInstallationOperationCreated, @"%s, appName: %@", + __PRETTY_FUNCTION__, self.appName); + + // Check for ongoing requests first, if there is no a request, then check local storage for + // existing installation. + FBLPromise *currentInstallationPromise = + [self mostRecentInstallationOperation] ?: [self getStoredInstallation]; + + return currentInstallationPromise + .then(^id(FIRInstallationsItem *installation) { + return [self sendDeleteInstallationRequestIfNeeded:installation]; + }) + .then(^id(FIRInstallationsItem *installation) { + // Remove the installation from the local storage. + return [self deleteInstallationLocally:installation]; + }); +} + +- (FBLPromise *)deleteInstallationLocally:(FIRInstallationsItem *)installation { + return [self.installationsStore removeInstallationForAppID:installation.appID + appName:installation.firebaseAppName] + .then(^FBLPromise *(NSNull *result) { + return [self deleteExistingIIDIfNeeded]; + }) + .then(^NSNull *(NSNull *result) { + [self postFIDDidChangeNotification]; + return result; + }); +} + +- (FBLPromise *)sendDeleteInstallationRequestIfNeeded: + (FIRInstallationsItem *)installation { + switch (installation.registrationStatus) { + case FIRInstallationStatusUnknown: + case FIRInstallationStatusUnregistered: + // The installation is not registered, so it is safe to be deleted as is, so return early. + return [FBLPromise resolvedWith:installation]; + break; + + case FIRInstallationStatusRegistered: + // Proceed to de-register the installation on the server. + break; + } + + return [self.APIService deleteInstallation:installation].recover(^id(NSError *APIError) { + if ([FIRInstallationsErrorUtil isAPIError:APIError withHTTPCode:404]) { + // The installation was not found on the server. + // Return success. + return installation; + } else { + // Re-throw the error otherwise. + return APIError; + } + }); +} + +- (FBLPromise *)deleteExistingIIDIfNeeded { + if ([self isDefaultApp]) { + return [self.IIDStore deleteExistingIID]; + } else { + return [FBLPromise resolvedWith:[NSNull null]]; + } +} + +- (nullable FBLPromise *)mostRecentInstallationOperation { + return [self.authTokenForcingRefreshPromiseCache getExistingPendingPromise] + ?: [self.authTokenPromiseCache getExistingPendingPromise] + ?: [self.getInstallationPromiseCache getExistingPendingPromise]; +} + +#pragma mark - Backoff + +- (void)updateBackoffWithSuccess:(BOOL)success APIError:(nullable NSError *)APIError { + if (success) { + [self.backoffController registerEvent:FIRInstallationsBackoffEventSuccess]; + } else if ([APIError isKindOfClass:[FIRInstallationsHTTPError class]]) { + FIRInstallationsHTTPError *HTTPResponseError = (FIRInstallationsHTTPError *)APIError; + NSInteger statusCode = HTTPResponseError.HTTPResponse.statusCode; + + if (statusCode == FIRInstallationsAuthTokenHTTPCodeInvalidAuthentication || + statusCode == FIRInstallationsAuthTokenHTTPCodeFIDNotFound) { + // These errors are explicitly excluded because they are handled by FIS SDK itself so don't + // require backoff. + } else if (statusCode == 400 || statusCode == 403) { // Explicitly unrecoverable errors. + [self.backoffController registerEvent:FIRInstallationsBackoffEventUnrecoverableFailure]; + } else if (statusCode == 429 || + (statusCode >= 500 && statusCode < 600)) { // Explicitly recoverable errors. + [self.backoffController registerEvent:FIRInstallationsBackoffEventRecoverableFailure]; + } else { // Treat all unknown errors as recoverable. + [self.backoffController registerEvent:FIRInstallationsBackoffEventRecoverableFailure]; + } + } + + // If the error class is not `FIRInstallationsHTTPError` it indicates a connection error. Such + // errors should not change backoff interval. +} + +#pragma mark - Notifications + +- (void)postFIDDidChangeNotification { + [[NSNotificationCenter defaultCenter] + postNotificationName:FIRInstallationIDDidChangeNotification + object:nil + userInfo:@{kFIRInstallationIDDidChangeNotificationAppNameKey : self.appName}]; +} + +#pragma mark - Default App + +- (BOOL)isDefaultApp { + return [self.appName isEqualToString:kFIRDefaultAppName]; +} + +#pragma mark - Keychain + ++ (NSString *)keychainServiceWithAppID:(NSString *)appID { +#if TARGET_OS_MACCATALYST || TARGET_OS_OSX + // We need to keep service name unique per application on macOS. + // Applications on macOS may request access to Keychain items stored by other applications. It + // means that when the app looks up for a relevant Keychain item in the service scope it will + // request user password to grant access to the Keychain if there are other Keychain items from + // other applications stored under the same Keychain Service. + return [kKeychainService stringByAppendingFormat:@".%@", appID]; +#else + // Use a constant Keychain service for non-macOS because: + // 1. Keychain items cannot be shared between apps until configured specifically so the service + // name collisions are not a concern + // 2. We don't want to change the service name to avoid doing a migration. + return kKeychainService; +#endif +} + +@end diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsSingleOperationPromiseCache.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsSingleOperationPromiseCache.h new file mode 100644 index 0000000..aeb54e5 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsSingleOperationPromiseCache.h @@ -0,0 +1,58 @@ +/* + * Copyright 2019 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 + +@class FBLPromise; + +NS_ASSUME_NONNULL_BEGIN + +/** + * The class makes sure the a single operation (represented by a promise) is performed at a time. If + * there is an ongoing operation, then its existing corresponding promise will be returned instead + * of starting a new operation. + */ +@interface FIRInstallationsSingleOperationPromiseCache<__covariant ResultType> : NSObject + +- (instancetype)init NS_UNAVAILABLE; + +/** + * The designated initializer. + * @param newOperationHandler The block that must return a new promise representing the + * single-at-a-time operation. The promise should be fulfilled when the operation is completed. The + * factory block will be used to create a new promise when needed. + */ +- (instancetype)initWithNewOperationHandler: + (FBLPromise *_Nonnull (^)(void))newOperationHandler NS_DESIGNATED_INITIALIZER; + +/** + * Creates a new promise or returns an existing pending one. + * @return Returns and existing pending promise if exists. If the pending promise does not exist + * then a new one will be created using the `factory` block passed in the initializer. Once the + * pending promise gets resolved, it is removed, so calling the method again will lead to creating + * and caching another promise. + */ +- (FBLPromise *)getExistingPendingOrCreateNewPromise; + +/** + * Returns an existing pending promise or `nil`. + * @return Returns an existing pending promise if there is one or `nil` otherwise. + */ +- (nullable FBLPromise *)getExistingPendingPromise; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsSingleOperationPromiseCache.m b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsSingleOperationPromiseCache.m new file mode 100644 index 0000000..7ae8781 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsSingleOperationPromiseCache.m @@ -0,0 +1,75 @@ +/* + * Copyright 2019 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 "FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsSingleOperationPromiseCache.h" + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +@interface FIRInstallationsSingleOperationPromiseCache () +@property(nonatomic, readonly) FBLPromise *_Nonnull (^newOperationHandler)(void); +@property(nonatomic, nullable) FBLPromise *pendingPromise; +@end + +@implementation FIRInstallationsSingleOperationPromiseCache + +- (instancetype)initWithNewOperationHandler: + (FBLPromise *_Nonnull (^)(void))newOperationHandler { + if (newOperationHandler == nil) { + [NSException raise:NSInvalidArgumentException + format:@"`newOperationHandler` must not be `nil`."]; + } + + self = [super init]; + if (self) { + _newOperationHandler = [newOperationHandler copy]; + } + return self; +} + +- (FBLPromise *)getExistingPendingOrCreateNewPromise { + @synchronized(self) { + if (!self.pendingPromise) { + self.pendingPromise = self.newOperationHandler(); + + self.pendingPromise + .then(^id(id result) { + @synchronized(self) { + self.pendingPromise = nil; + return nil; + } + }) + .catch(^void(NSError *error) { + @synchronized(self) { + self.pendingPromise = nil; + } + }); + } + + return self.pendingPromise; + } +} + +- (nullable FBLPromise *)getExistingPendingPromise { + @synchronized(self) { + return self.pendingPromise; + } +} + +@end diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsStatus.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsStatus.h new file mode 100644 index 0000000..3edc692 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsStatus.h @@ -0,0 +1,35 @@ +/* + * Copyright 2019 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 + +/** + * The enum represent possible states of the installation ID. + * + * WARNING: The enum is stored to Keychain as a part of `FIRInstallationsStoredItem`. Modification + * of it can lead to incompatibility with previous version. Any modification must be evaluated and, + * if it is really needed, the `storageVersion` must be bumped and proper migration code added. + */ +typedef NS_ENUM(NSInteger, FIRInstallationsStatus) { + /** Represents either an initial status when a FIRInstallationsItem instance was created but not + * stored to Keychain or an undefined status (e.g. when the status failed to deserialize). + */ + FIRInstallationStatusUnknown, + /// The Firebase Installation has not yet been registered with FIS. + FIRInstallationStatusUnregistered, + /// The Firebase Installation has successfully been registered with FIS. + FIRInstallationStatusRegistered, +}; diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStore.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStore.h new file mode 100644 index 0000000..b86fb39 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStore.h @@ -0,0 +1,71 @@ +/* + * Copyright 2019 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 + +@class FBLPromise; +@class FIRInstallationsItem; +@class GULKeychainStorage; + +NS_ASSUME_NONNULL_BEGIN + +/// The user defaults suite name used to store data. +extern NSString *const kFIRInstallationsStoreUserDefaultsID; + +/// The class is responsible for storing and accessing the installations data. +@interface FIRInstallationsStore : NSObject + +/** + * The default initializer. + * @param storage The secure storage to save installations data. + * @param accessGroup The Keychain Access Group to store and request the installations data. + */ +- (instancetype)initWithSecureStorage:(GULKeychainStorage *)storage + accessGroup:(nullable NSString *)accessGroup; + +/** + * Retrieves existing installation ID if there is. + * @param appID The Firebase(Google) Application ID. + * @param appName The Firebase Application Name. + * + * @return Returns a `FBLPromise` instance. The promise is resolved with a FIRInstallationsItem + * instance if there is a valid installation stored for `appID` and `appName`. The promise is + * rejected with a specific error when the installation has not been found or with another possible + * error. + */ +- (FBLPromise *)installationForAppID:(NSString *)appID + appName:(NSString *)appName; + +/** + * Saves the given installation. + * + * @param installationItem The installation data. + * @return Returns a promise that is resolved with `[NSNull null]` on success. + */ +- (FBLPromise *)saveInstallation:(FIRInstallationsItem *)installationItem; + +/** + * Removes installation data for the given app parameters. + * @param appID The Firebase(Google) Application ID. + * @param appName The Firebase Application Name. + * + * @return Returns a promise that is resolved with `[NSNull null]` on success. + */ +- (FBLPromise *)removeInstallationForAppID:(NSString *)appID appName:(NSString *)appName; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStore.m b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStore.m new file mode 100644 index 0000000..40cd5fb --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStore.m @@ -0,0 +1,126 @@ +/* + * Copyright 2019 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 "FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStore.h" + +#import + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +#import + +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h" +#import "FirebaseInstallations/Source/Library/FIRInstallationsItem.h" +#import "FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredItem.h" + +NSString *const kFIRInstallationsStoreUserDefaultsID = @"com.firebase.FIRInstallations"; + +@interface FIRInstallationsStore () +@property(nonatomic, readonly) GULKeychainStorage *secureStorage; +@property(nonatomic, readonly, nullable) NSString *accessGroup; +@property(nonatomic, readonly) dispatch_queue_t queue; +@property(nonatomic, readonly) GULUserDefaults *userDefaults; +@end + +@implementation FIRInstallationsStore + +- (instancetype)initWithSecureStorage:(GULKeychainStorage *)storage + accessGroup:(NSString *)accessGroup { + self = [super init]; + if (self) { + _secureStorage = storage; + _accessGroup = [accessGroup copy]; + _queue = dispatch_queue_create("com.firebase.FIRInstallationsStore", DISPATCH_QUEUE_SERIAL); + + NSString *userDefaultsSuiteName = _accessGroup ?: kFIRInstallationsStoreUserDefaultsID; + _userDefaults = [[GULUserDefaults alloc] initWithSuiteName:userDefaultsSuiteName]; + } + return self; +} + +- (FBLPromise *)installationForAppID:(NSString *)appID + appName:(NSString *)appName { + NSString *itemID = [FIRInstallationsItem identifierWithAppID:appID appName:appName]; + return [self installationExistsForAppID:appID appName:appName] + .then(^id(id result) { + return [self.secureStorage getObjectForKey:itemID + objectClass:[FIRInstallationsStoredItem class] + accessGroup:self.accessGroup]; + }) + .then(^id(FIRInstallationsStoredItem *_Nullable storedItem) { + if (storedItem == nil) { + return [FIRInstallationsErrorUtil installationItemNotFoundForAppID:appID appName:appName]; + } + + FIRInstallationsItem *item = [[FIRInstallationsItem alloc] initWithAppID:appID + firebaseAppName:appName]; + [item updateWithStoredItem:storedItem]; + return item; + }); +} + +- (FBLPromise *)saveInstallation:(FIRInstallationsItem *)installationItem { + FIRInstallationsStoredItem *storedItem = [installationItem storedItem]; + NSString *identifier = [installationItem identifier]; + + return + [self.secureStorage setObject:storedItem forKey:identifier accessGroup:self.accessGroup].then( + ^id(id result) { + return [self setInstallationExists:YES forItemWithIdentifier:identifier]; + }); +} + +- (FBLPromise *)removeInstallationForAppID:(NSString *)appID appName:(NSString *)appName { + NSString *identifier = [FIRInstallationsItem identifierWithAppID:appID appName:appName]; + return [self.secureStorage removeObjectForKey:identifier accessGroup:self.accessGroup].then( + ^id(id result) { + return [self setInstallationExists:NO forItemWithIdentifier:identifier]; + }); +} + +#pragma mark - User defaults + +- (FBLPromise *)installationExistsForAppID:(NSString *)appID appName:(NSString *)appName { + NSString *identifier = [FIRInstallationsItem identifierWithAppID:appID appName:appName]; + return [FBLPromise onQueue:self.queue + do:^id _Nullable { + return [[self userDefaults] objectForKey:identifier] != nil + ? [NSNull null] + : [FIRInstallationsErrorUtil + installationItemNotFoundForAppID:appID + appName:appName]; + }]; +} + +- (FBLPromise *)setInstallationExists:(BOOL)exists + forItemWithIdentifier:(NSString *)identifier { + return [FBLPromise onQueue:self.queue + do:^id _Nullable { + if (exists) { + [[self userDefaults] setBool:YES forKey:identifier]; + } else { + [[self userDefaults] removeObjectForKey:identifier]; + } + + return [NSNull null]; + }]; +} + +@end diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.h new file mode 100644 index 0000000..4da2337 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.h @@ -0,0 +1,58 @@ +/* + * Copyright 2019 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 + +NS_ASSUME_NONNULL_BEGIN + +/** + * The enum represent possible states of the installation auth token. + * + * WARNING: The enum is stored to Keychain as a part of `FIRInstallationsStoredAuthToken`. + * Modification of it can lead to incompatibility with previous version. Any modification must be + * evaluated and, if it is really needed, the `storageVersion` must be bumped and proper migration + * code added. + */ +typedef NS_ENUM(NSInteger, FIRInstallationsAuthTokenStatus) { + /// An initial status or an undefined value. + FIRInstallationsAuthTokenStatusUnknown, + /// The auth token has been received from the server. + FIRInstallationsAuthTokenStatusTokenReceived +}; + +/** + * This class serializes and deserializes the installation data into/from `NSData` to be stored in + * Keychain. This class is primarily used by `FIRInstallationsStore`. It is also used on the logic + * level as a data object (see `FIRInstallationsItem.authToken`). + * + * WARNING: Modification of the class properties can lead to incompatibility with the stored data + * encoded by the previous class versions. Any modification must be evaluated and, if it is really + * needed, the `storageVersion` must be bumped and proper migration code added. + */ +@interface FIRInstallationsStoredAuthToken : NSObject +@property FIRInstallationsAuthTokenStatus status; + +/// The installation auth token string that can be used to authorize requests to Firebase backend. +@property(nullable, copy) NSString *token; +/// The installation auth token expiration date. +@property(nullable, copy) NSDate *expirationDate; + +/// The version of local storage. +@property(nonatomic, readonly) NSInteger storageVersion; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.m b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.m new file mode 100644 index 0000000..8236f2a --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.m @@ -0,0 +1,77 @@ +/* + * Copyright 2019 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 "FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.h" + +#import "FirebaseInstallations/Source/Library/FIRInstallationsLogger.h" + +NSString *const kFIRInstallationsStoredAuthTokenStatusKey = @"status"; +NSString *const kFIRInstallationsStoredAuthTokenTokenKey = @"token"; +NSString *const kFIRInstallationsStoredAuthTokenExpirationDateKey = @"expirationDate"; +NSString *const kFIRInstallationsStoredAuthTokenStorageVersionKey = @"storageVersion"; + +NSInteger const kFIRInstallationsStoredAuthTokenStorageVersion = 1; + +@implementation FIRInstallationsStoredAuthToken + +- (NSInteger)storageVersion { + return kFIRInstallationsStoredAuthTokenStorageVersion; +} + +- (nonnull id)copyWithZone:(nullable NSZone *)zone { + FIRInstallationsStoredAuthToken *clone = [[FIRInstallationsStoredAuthToken alloc] init]; + clone.status = self.status; + clone.token = [self.token copy]; + clone.expirationDate = self.expirationDate; + return clone; +} + +- (void)encodeWithCoder:(nonnull NSCoder *)aCoder { + [aCoder encodeInteger:self.status forKey:kFIRInstallationsStoredAuthTokenStatusKey]; + [aCoder encodeObject:self.token forKey:kFIRInstallationsStoredAuthTokenTokenKey]; + [aCoder encodeObject:self.expirationDate + forKey:kFIRInstallationsStoredAuthTokenExpirationDateKey]; + [aCoder encodeInteger:self.storageVersion + forKey:kFIRInstallationsStoredAuthTokenStorageVersionKey]; +} + +- (nullable instancetype)initWithCoder:(nonnull NSCoder *)aDecoder { + NSInteger storageVersion = + [aDecoder decodeIntegerForKey:kFIRInstallationsStoredAuthTokenStorageVersionKey]; + if (storageVersion > kFIRInstallationsStoredAuthTokenStorageVersion) { + FIRLogWarning(kFIRLoggerInstallations, + kFIRInstallationsMessageCodeAuthTokenCoderVersionMismatch, + @"FIRInstallationsStoredAuthToken was encoded by a newer coder version %ld. " + @"Current coder version is %ld. Some auth token data may be lost.", + (long)storageVersion, (long)kFIRInstallationsStoredAuthTokenStorageVersion); + } + + FIRInstallationsStoredAuthToken *object = [[FIRInstallationsStoredAuthToken alloc] init]; + object.status = [aDecoder decodeIntegerForKey:kFIRInstallationsStoredAuthTokenStatusKey]; + object.token = [aDecoder decodeObjectOfClass:[NSString class] + forKey:kFIRInstallationsStoredAuthTokenTokenKey]; + object.expirationDate = + [aDecoder decodeObjectOfClass:[NSDate class] + forKey:kFIRInstallationsStoredAuthTokenExpirationDateKey]; + + return object; +} + ++ (BOOL)supportsSecureCoding { + return YES; +} + +@end diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredItem.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredItem.h new file mode 100644 index 0000000..0126eb0 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredItem.h @@ -0,0 +1,51 @@ +/* + * Copyright 2019 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 + +#import "FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsStatus.h" + +@class FIRInstallationsStoredAuthToken; +@class FIRInstallationsStoredIIDCheckin; + +NS_ASSUME_NONNULL_BEGIN + +/** + * The class is supposed to be used by `FIRInstallationsStore` only. It is required to + * serialize/deserialize the installation data into/from `NSData` to be stored in Keychain. + * + * WARNING: Modification of the class properties can lead to incompatibility with the stored data + * encoded by the previous class versions. Any modification must be evaluated and, if it is really + * needed, the `storageVersion` must be bumped and proper migration code added. + */ +@interface FIRInstallationsStoredItem : NSObject + +/// A stable identifier that uniquely identifies the app instance. +@property(nonatomic, copy, nullable) NSString *firebaseInstallationID; +/// The `refreshToken` is used to authorize the installation auth token requests. +@property(nonatomic, copy, nullable) NSString *refreshToken; + +@property(nonatomic, nullable) FIRInstallationsStoredAuthToken *authToken; +@property(nonatomic) FIRInstallationsStatus registrationStatus; + +/// Instance ID default auth token imported from IID store as a part of IID migration. +@property(nonatomic, nullable) NSString *IIDDefaultToken; + +/// The version of local storage. +@property(nonatomic, readonly) NSInteger storageVersion; +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredItem.m b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredItem.m new file mode 100644 index 0000000..4e19955 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredItem.m @@ -0,0 +1,80 @@ +/* + * Copyright 2019 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 "FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredItem.h" + +#import "FirebaseInstallations/Source/Library/FIRInstallationsLogger.h" +#import "FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.h" + +NSString *const kFIRInstallationsStoredItemFirebaseInstallationIDKey = @"firebaseInstallationID"; +NSString *const kFIRInstallationsStoredItemRefreshTokenKey = @"refreshToken"; +NSString *const kFIRInstallationsStoredItemAuthTokenKey = @"authToken"; +NSString *const kFIRInstallationsStoredItemRegistrationStatusKey = @"registrationStatus"; +NSString *const kFIRInstallationsStoredItemIIDDefaultTokenKey = @"IIDDefaultToken"; +NSString *const kFIRInstallationsStoredItemStorageVersionKey = @"storageVersion"; + +NSInteger const kFIRInstallationsStoredItemStorageVersion = 1; + +@implementation FIRInstallationsStoredItem + +- (NSInteger)storageVersion { + return kFIRInstallationsStoredItemStorageVersion; +} + +- (void)encodeWithCoder:(nonnull NSCoder *)aCoder { + [aCoder encodeObject:self.firebaseInstallationID + forKey:kFIRInstallationsStoredItemFirebaseInstallationIDKey]; + [aCoder encodeObject:self.refreshToken forKey:kFIRInstallationsStoredItemRefreshTokenKey]; + [aCoder encodeObject:self.authToken forKey:kFIRInstallationsStoredItemAuthTokenKey]; + [aCoder encodeInteger:self.registrationStatus + forKey:kFIRInstallationsStoredItemRegistrationStatusKey]; + [aCoder encodeObject:self.IIDDefaultToken forKey:kFIRInstallationsStoredItemIIDDefaultTokenKey]; + [aCoder encodeInteger:self.storageVersion forKey:kFIRInstallationsStoredItemStorageVersionKey]; +} + +- (nullable instancetype)initWithCoder:(nonnull NSCoder *)aDecoder { + NSInteger storageVersion = + [aDecoder decodeIntegerForKey:kFIRInstallationsStoredItemStorageVersionKey]; + if (storageVersion > self.storageVersion) { + FIRLogWarning(kFIRLoggerInstallations, + kFIRInstallationsMessageCodeInstallationCoderVersionMismatch, + @"FIRInstallationsStoredItem was encoded by a newer coder version %ld. Current " + @"coder version is %ld. Some installation data may be lost.", + (long)storageVersion, (long)kFIRInstallationsStoredItemStorageVersion); + } + + FIRInstallationsStoredItem *item = [[FIRInstallationsStoredItem alloc] init]; + item.firebaseInstallationID = + [aDecoder decodeObjectOfClass:[NSString class] + forKey:kFIRInstallationsStoredItemFirebaseInstallationIDKey]; + item.refreshToken = [aDecoder decodeObjectOfClass:[NSString class] + forKey:kFIRInstallationsStoredItemRefreshTokenKey]; + item.authToken = [aDecoder decodeObjectOfClass:[FIRInstallationsStoredAuthToken class] + forKey:kFIRInstallationsStoredItemAuthTokenKey]; + item.registrationStatus = + [aDecoder decodeIntegerForKey:kFIRInstallationsStoredItemRegistrationStatusKey]; + item.IIDDefaultToken = + [aDecoder decodeObjectOfClass:[NSString class] + forKey:kFIRInstallationsStoredItemIIDDefaultTokenKey]; + + return item; +} + ++ (BOOL)supportsSecureCoding { + return YES; +} + +@end diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h new file mode 100644 index 0000000..0c850e9 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h @@ -0,0 +1,19 @@ +// Copyright 2020 Google LLC +// +// 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. + +// An umbrella header, for any other libraries in this repo to access Firebase +// Installations Public headers. Any package manager complexity should be +// handled here. + +#import diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallations.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallations.h new file mode 100644 index 0000000..1811d2b --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallations.h @@ -0,0 +1,127 @@ +/* + * Copyright 2019 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 + +@class FIRApp; +@class FIRInstallationsAuthTokenResult; + +NS_ASSUME_NONNULL_BEGIN + +/** A notification with this name is sent each time an installation is created or deleted. */ +// clang-format off +// clang-format12 merges the next two lines. +FOUNDATION_EXPORT const NSNotificationName FIRInstallationIDDidChangeNotification + NS_SWIFT_NAME(InstallationIDDidChange); +/** `userInfo` key for the `FirebaseApp.name` in `InstallationIDDidChangeNotification`. */ +FOUNDATION_EXPORT NSString *const kFIRInstallationIDDidChangeNotificationAppNameKey + NS_SWIFT_NAME(InstallationIDDidChangeAppNameKey); +// clang-format on + +/** + * An installation ID handler block. + * @param identifier The installation ID string if exists or `nil` otherwise. + * @param error The error when `identifier == nil` or `nil` otherwise. + */ +typedef void (^FIRInstallationsIDHandler)(NSString *__nullable identifier, + NSError *__nullable error) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/** + * An authorization token handler block. + * @param tokenResult An instance of `InstallationsAuthTokenResult` in case of success or `nil` + * otherwise. + * @param error The error when `tokenResult == nil` or `nil` otherwise. + */ +typedef void (^FIRInstallationsTokenHandler)( + FIRInstallationsAuthTokenResult *__nullable tokenResult, NSError *__nullable error) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/** + * The class provides API for Firebase Installations. + * Each configured `FirebaseApp` has a corresponding single instance of `Installations`. + * An instance of the class provides access to the installation info for the `FirebaseApp` as well + * as the ability to delete it. A Firebase Installation is unique by `FirebaseApp.name` and + * `FirebaseApp.options.googleAppID` . + */ +NS_SWIFT_NAME(Installations) +@interface FIRInstallations : NSObject + +- (instancetype)init NS_UNAVAILABLE; + +/** + * Returns a default instance of `Installations`. + * @return An instance of `Installations` for `FirebaseApp.defaultApp(). + * @throw Throws an exception if the default app is not configured yet or required `FirebaseApp` + * options are missing. + */ ++ (FIRInstallations *)installations NS_SWIFT_NAME(installations()); + +/** + * Returns an instance of `Installations` for an application. + * @param application A configured `FirebaseApp` instance. + * @return An instance of `Installations` corresponding to the passed application. + * @throw Throws an exception if required `FirebaseApp` options are missing. + */ ++ (FIRInstallations *)installationsWithApp:(FIRApp *)application NS_SWIFT_NAME(installations(app:)); + +/** + * The method creates or retrieves an installation ID. The installation ID is a stable identifier + * that uniquely identifies the app instance. NOTE: If the application already has an existing + * FirebaseInstanceID then the InstanceID identifier will be used. + * @param completion A completion handler which is invoked when the operation completes. + */ +- (void)installationIDWithCompletion:(void (^)(NSString *__nullable identifier, + NSError *__nullable error))completion; + +/** + * Retrieves (locally if it exists or from the server) a valid installation auth token. An existing + * token may be invalidated or expired, so it is recommended to fetch the installation auth token + * before each server request. The method does the same as + * `Installations.authToken(forcingRefresh:completion:)` with forcing refresh `false`. + * @param completion A completion handler which is invoked when the operation completes. + */ +- (void)authTokenWithCompletion:(void (^)(FIRInstallationsAuthTokenResult *__nullable tokenResult, + NSError *__nullable error))completion; + +/** + * Retrieves (locally or from the server depending on `forceRefresh` value) a valid installation + * auth token. An existing token may be invalidated or expire, so it is recommended to fetch the + * installation auth token before each server request. This method should be used with `forceRefresh + * == true` when e.g. a request with the previously fetched installation auth token failed with "Not + * Authorized" error. + * @param forceRefresh If `true` then the locally cached installation auth token will be ignored and + * a new one will be requested from the server. If `false`, then the locally cached installation + * auth token will be returned if exists and has not expired yet. + * @param completion A completion handler which is invoked when the operation completes. See + * `InstallationsTokenHandler` for additional details. + */ +- (void)authTokenForcingRefresh:(BOOL)forceRefresh + completion:(void (^)(FIRInstallationsAuthTokenResult *__nullable tokenResult, + NSError *__nullable error))completion; + +/** + * Deletes all the installation data including the unique identifier, auth tokens and + * all related data on the server side. A network connection is required for the method to + * succeed. If fails, the existing installation data remains untouched. + * @param completion A completion handler which is invoked when the operation completes. `error == + * nil` indicates success. + */ +- (void)deleteWithCompletion:(void (^)(NSError *__nullable error))completion; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallationsAuthTokenResult.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallationsAuthTokenResult.h new file mode 100644 index 0000000..501ac4e --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallationsAuthTokenResult.h @@ -0,0 +1,33 @@ +/* + * Copyright 2019 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 + +NS_ASSUME_NONNULL_BEGIN + +/** The class represents a result of the installation auth token request. */ +NS_SWIFT_NAME(InstallationsAuthTokenResult) +@interface FIRInstallationsAuthTokenResult : NSObject + +/** The installation auth token string. */ +@property(nonatomic, readonly) NSString *authToken; + +/** The installation auth token expiration date. */ +@property(nonatomic, readonly) NSDate *expirationDate; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallationsErrors.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallationsErrors.h new file mode 100644 index 0000000..939ca0a --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallationsErrors.h @@ -0,0 +1,35 @@ +/* + * Copyright 2019 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 + +extern NSString *const kFirebaseInstallationsErrorDomain NS_SWIFT_NAME(InstallationsErrorDomain); + +typedef NS_ERROR_ENUM(kFirebaseInstallationsErrorDomain, FIRInstallationsErrorCode){ + /** Unknown error. See `userInfo` for details. */ + FIRInstallationsErrorCodeUnknown = 0, + + /** Keychain error. See `userInfo` for details. */ + FIRInstallationsErrorCodeKeychain = 1, + + /** Server unreachable. A network error or server is unavailable. See `userInfo` for details. */ + FIRInstallationsErrorCodeServerUnreachable = 2, + + /** FirebaseApp configuration issues e.g. invalid GMP-App-ID, etc. See `userInfo` for details. + */ + FIRInstallationsErrorCodeInvalidConfiguration = 3, + +} NS_SWIFT_NAME(InstallationsErrorCode); diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FirebaseInstallations.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FirebaseInstallations.h new file mode 100644 index 0000000..8a9b3c1 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FirebaseInstallations.h @@ -0,0 +1,19 @@ +/* + * Copyright 2019 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 "FIRInstallations.h" +#import "FIRInstallationsAuthTokenResult.h" +#import "FIRInstallationsErrors.h" diff --git a/Pods/FirebaseInstallations/LICENSE b/Pods/FirebaseInstallations/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/Pods/FirebaseInstallations/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/Pods/FirebaseInstallations/README.md b/Pods/FirebaseInstallations/README.md new file mode 100644 index 0000000..85a23bd --- /dev/null +++ b/Pods/FirebaseInstallations/README.md @@ -0,0 +1,281 @@ +

+ + + + + + + + +
+ + + + + + +

+ +# Firebase Apple Open Source Development + +This repository contains all Apple platform Firebase SDK source except FirebaseAnalytics. + +Firebase is an app development platform with tools to help you build, grow and +monetize your app. More information about Firebase can be found on the +[official Firebase website](https://firebase.google.com). + +## Installation + +See the subsections below for details about the different installation methods. Where +available, it's recommended to install any libraries with a `Swift` suffix to get the +best experience when writing your app in Swift. +1. [Standard pod install](#standard-pod-install) +1. [Swift Package Manager](#swift-package-manager) +1. [Installing from the GitHub repo](#installing-from-github) +1. [Experimental Carthage](#carthage-ios-only) + +### Standard pod install + +Go to +[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup). + +### Swift Package Manager + +Instructions for [Swift Package Manager](https://swift.org/package-manager/) support can be +found at [SwiftPackageManager](SwiftPackageManager.md) Markdown file. + +### Installing from GitHub + +These instructions can be used to access the Firebase repo at other branches, +tags, or commits. + +#### Background + +See +[the Podfile Syntax Reference](https://guides.cocoapods.org/syntax/podfile.html#pod) +for instructions and options about overriding pod source locations. + +#### Accessing Firebase Source Snapshots + +All of the official releases are tagged in this repo and available via CocoaPods. To access a local +source snapshot or unreleased branch, use Podfile directives like the following: + +To access FirebaseFirestore via a branch: +```ruby +pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master' +pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'master' +``` + +To access FirebaseMessaging via a checked out version of the firebase-ios-sdk repo do: + +```ruby +pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk' +pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk' +``` + +### Carthage (iOS only) + +Instructions for the experimental Carthage distribution are at +[Carthage](Carthage.md). + +### Using Firebase from a Framework or a library + +[Using Firebase from a Framework or a library](docs/firebase_in_libraries.md) + +## Development + +To develop Firebase software in this repository, ensure that you have at least +the following software: + + * Xcode 14.1 (or later) + +CocoaPods is still the canonical way to develop, but much of the repo now supports +development with Swift Package Manager. + +### CocoaPods + +Install + * CocoaPods 1.10.0 (or later) + * [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +```ruby +pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios +``` + +Note: If the CocoaPods cache is out of date, you may need to run +`pod repo update` before the `pod gen` command. + +Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for +those platforms. Since 10.2, Xcode does not properly handle multi-platform +CocoaPods workspaces. + +Firestore has a self contained Xcode project. See +[Firestore/README](Firestore/README.md) Markdown file. + +#### Development for Catalyst +* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios` +* Check the Mac box in the App-iOS Build Settings +* Sign the App in the Settings Signing & Capabilities tab +* Click Pods in the Project Manager +* Add Signing to the iOS host app and unit test targets +* Select the Unit-unit scheme +* Run it to build and test + +Alternatively disable signing in each target: +* Go to Build Settings tab +* Click `+` +* Select `Add User-Defined Setting` +* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO` + +### Swift Package Manager +* To enable test schemes: `./scripts/setup_spm_tests.sh` +* `open Package.swift` or double click `Package.swift` in Finder. +* Xcode will open the project + * Choose a scheme for a library to build or test suite to run + * Choose a target platform by selecting the run destination along with the scheme + +### Adding a New Firebase Pod + +See [AddNewPod](AddNewPod.md) Markdown file. + +### Managing Headers and Imports + +See [HeadersImports](HeadersImports.md) Markdown file. + +### Code Formatting + +To ensure that the code is formatted consistently, run the script +[./scripts/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/master/scripts/check.sh) +before creating a PR. + +GitHub Actions will verify that any code changes are done in a style compliant +way. Install `clang-format` and `mint`: + +```console +brew install clang-format@16 +brew install mint +``` + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +### Running Sample Apps +In order to run the sample apps and integration tests, you'll need a valid +`GoogleService-Info.plist` file. The Firebase Xcode project contains dummy plist +files without real values, but can be replaced with real plist files. To get your own +`GoogleService-Info.plist` files: + +1. Go to the [Firebase Console](https://console.firebase.google.com/) +2. Create a new Firebase project, if you don't already have one +3. For each sample app you want to test, create a new Firebase app with the sample app's bundle +identifier (e.g. `com.google.Database-Example`) +4. Download the resulting `GoogleService-Info.plist` and add it to the Xcode project. + +### Coverage Report Generation + +See [scripts/code_coverage_report/README](scripts/code_coverage_report/README.md) Markdown file. + +## Specific Component Instructions +See the sections below for any special instructions for those components. + +### Firebase Auth + +If you're doing specific Firebase Auth development, see +[the Auth Sample README](FirebaseAuth/Tests/Sample/README.md) for instructions about +building and running the FirebaseAuth pod along with various samples and tests. + +### Firebase Database + +The Firebase Database Integration tests can be run against a locally running Database Emulator +or against a production instance. + +To run against a local emulator instance, invoke `./scripts/run_database_emulator.sh start` before +running the integration test. + +To run against a production instance, provide a valid GoogleServices-Info.plist and copy it to +`FirebaseDatabase/Tests/Resources/GoogleService-Info.plist`. Your Security Rule must be set to +[public](https://firebase.google.com/docs/database/security/quickstart) while your tests are +running. + +### Firebase Performance Monitoring +If you're doing specific Firebase Performance Monitoring development, see +[the Performance README](FirebasePerformance/README.md) for instructions about building the SDK +and [the Performance TestApp README](FirebasePerformance/Tests/TestApp/README.md) for instructions about +integrating Performance with the dev test App. + +### Firebase Storage + +To run the Storage Integration tests, follow the instructions in +[StorageIntegration.swift](FirebaseStorage/Tests/Integration/StorageIntegration.swift). + +#### Push Notifications + +Push notifications can only be delivered to specially provisioned App IDs in the developer portal. +In order to actually test receiving push notifications, you will need to: + +1. Change the bundle identifier of the sample app to something you own in your Apple Developer +account, and enable that App ID for push notifications. +2. You'll also need to +[upload your APNs Provider Authentication Key or certificate to the +Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs) +at **Project Settings > Cloud Messaging > [Your Firebase App]**. +3. Ensure your iOS device is added to your Apple Developer portal as a test device. + +#### iOS Simulator + +The iOS Simulator cannot register for remote notifications, and will not receive push notifications. +In order to receive push notifications, you'll have to follow the steps above and run the app on a +physical device. + +## Building with Firebase on Apple platforms + +Firebase 8.9.0 introduced official beta support for macOS, Catalyst, and tvOS. watchOS continues +to be community supported. Thanks to community contributions for many of the multi-platform PRs. + +At this time, most of Firebase's products are available across Apple platforms. There are still +a few gaps, especially on watchOS. For details about the current support matrix, see +[this chart](https://firebase.google.com/docs/ios/learn-more#firebase_library_support_by_platform) +in Firebase's documentation. + +### watchOS +Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and +work on watchOS. See the [Independent Watch App Sample](Example/watchOSSample). + +Keep in mind that watchOS is not officially supported by Firebase. While we can catch basic unit +test issues with GitHub Actions, there may be some changes where the SDK no longer works as expected +on watchOS. If you encounter this, please +[file an issue](https://github.com/firebase/firebase-ios-sdk/issues). + +During app setup in the console, you may get to a step that mentions something like "Checking if the +app has communicated with our servers". This relies on Analytics and will not work on watchOS. +**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected. + +#### Additional Crashlytics Notes +* watchOS has limited support. Due to watchOS restrictions, mach exceptions and signal crashes are +not recorded. (Crashes in SwiftUI are generated as mach exceptions, so will not be recorded) + +## Combine +Thanks to contributions from the community, _FirebaseCombineSwift_ contains support for Apple's Combine +framework. This module is currently under development, and not yet supported for use in production +environments. Fore more details, please refer to the [docs](FirebaseCombineSwift/README.md). + +## Roadmap + +See [Roadmap](ROADMAP.md) for more about the Firebase Apple SDK Open Source +plans and directions. + +## Contributing + +See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase +Apple SDK. + +## License + +The contents of this repository are licensed under the +[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). + +Your use of Firebase is governed by the +[Terms of Service for Firebase Services](https://firebase.google.com/terms/). diff --git a/Pods/GTMSessionFetcher/LICENSE b/Pods/GTMSessionFetcher/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/Pods/GTMSessionFetcher/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/Pods/GTMSessionFetcher/README.md b/Pods/GTMSessionFetcher/README.md new file mode 100644 index 0000000..ae1b941 --- /dev/null +++ b/Pods/GTMSessionFetcher/README.md @@ -0,0 +1,28 @@ +# Google Toolbox for Mac - Session Fetcher + +**Project site**
+**Discussion group** + +[![SwiftPM](https://github.com/google/gtm-session-fetcher/actions/workflows/swiftpm.yml/badge.svg?branch=main)](https://github.com/google/gtm-session-fetcher/actions/workflows/swiftpm.yml) +[![CocoaPods](https://github.com/google/gtm-session-fetcher/actions/workflows/cocoapods.yml/badge.svg?branch=main)](https://github.com/google/gtm-session-fetcher/actions/workflows/cocoapods.yml) + +`GTMSessionFetcher` makes it easy for Cocoa applications to perform http +operations. The fetcher is implemented as a wrapper on `NSURLSession`, so its +behavior is asynchronous and uses operating-system settings. + +Features include: +- Simple to build; only one source/header file pair is required +- Simple to use: takes just two lines of code to fetch a request +- Supports upload and download sessions +- Flexible cookie storage +- Automatic retry on errors, with exponential backoff +- Support for generating multipart MIME upload streams +- Easy, convenient logging of http requests and responses +- Supports plug-in authentication such as with GTMAppAuth +- Easily testable; self-mocking +- Automatic rate limiting when created by the `GTMSessionFetcherService` factory class +- Fully independent of other projects + +**To get started** please read +[USING.md](https://github.com/google/google-api-objectivec-client-for-rest/blob/main/USING.md) +for detailed information. \ No newline at end of file diff --git a/Pods/GTMSessionFetcher/Sources/Core/GTMSessionFetcher.m b/Pods/GTMSessionFetcher/Sources/Core/GTMSessionFetcher.m new file mode 100644 index 0000000..6ed610d --- /dev/null +++ b/Pods/GTMSessionFetcher/Sources/Core/GTMSessionFetcher.m @@ -0,0 +1,4814 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * 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. + */ + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "GTMSessionFetcher/GTMSessionFetcher.h" +#import "GTMSessionFetcher/GTMSessionFetcherService.h" +#import "GTMSessionFetcherService+Internal.h" + +#if TARGET_OS_OSX && GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH +// To reconnect background sessions on Mac outside +load requires importing and linking +// AppKit to access the NSApplicationDidFinishLaunching symbol. +#import +#endif + +#include + +#ifndef STRIP_GTM_FETCH_LOGGING +#error GTMSessionFetcher headers should have defaulted this if it wasn't already defined. +#endif + +NS_ASSUME_NONNULL_BEGIN + +NSString *const kGTMSessionFetcherStartedNotification = @"kGTMSessionFetcherStartedNotification"; +NSString *const kGTMSessionFetcherStoppedNotification = @"kGTMSessionFetcherStoppedNotification"; +NSString *const kGTMSessionFetcherRetryDelayStartedNotification = + @"kGTMSessionFetcherRetryDelayStartedNotification"; +NSString *const kGTMSessionFetcherRetryDelayStoppedNotification = + @"kGTMSessionFetcherRetryDelayStoppedNotification"; + +NSString *const kGTMSessionFetcherCompletionInvokedNotification = + @"kGTMSessionFetcherCompletionInvokedNotification"; +NSString *const kGTMSessionFetcherCompletionDataKey = @"data"; +NSString *const kGTMSessionFetcherCompletionErrorKey = @"error"; + +NSString *const kGTMSessionFetcherErrorDomain = @"com.google.GTMSessionFetcher"; +NSString *const kGTMSessionFetcherStatusDomain = @"com.google.HTTPStatus"; +NSString *const kGTMSessionFetcherStatusDataKey = + @"data"; // data returned with a kGTMSessionFetcherStatusDomain error +NSString *const kGTMSessionFetcherStatusDataContentTypeKey = @"data_content_type"; + +NSString *const kGTMSessionFetcherNumberOfRetriesDoneKey = + @"kGTMSessionFetcherNumberOfRetriesDoneKey"; +NSString *const kGTMSessionFetcherElapsedIntervalWithRetriesKey = + @"kGTMSessionFetcherElapsedIntervalWithRetriesKey"; + +static NSString *const kGTMSessionIdentifierPrefix = @"com.google.GTMSessionFetcher"; +static NSString *const kGTMSessionIdentifierDestinationFileURLMetadataKey = @"_destURL"; +static NSString *const kGTMSessionIdentifierBodyFileURLMetadataKey = @"_bodyURL"; +static NSString *const kGTMSessionIdentifierClientReconnectMetadataKey = @"_clientWillReconnect"; + +// The default max retry interview is 10 minutes for uploads (POST/PUT/PATCH), +// 1 minute for downloads. +static const NSTimeInterval kUnsetMaxRetryInterval = -1.0; +static const NSTimeInterval kDefaultMaxDownloadRetryInterval = 60.0; +static const NSTimeInterval kDefaultMaxUploadRetryInterval = 60.0 * 10.; + +// The maximum data length that can be loaded to the error userInfo +static const int64_t kMaximumDownloadErrorDataLength = 20000; + +#ifdef GTMSESSION_PERSISTED_DESTINATION_KEY +// Projects using unique class names should also define a unique persisted destination key. +static NSString *const kGTMSessionFetcherPersistedDestinationKey = + GTMSESSION_PERSISTED_DESTINATION_KEY; +#else +static NSString *const kGTMSessionFetcherPersistedDestinationKey = + @"com.google.GTMSessionFetcher.downloads"; +#endif + +NS_ASSUME_NONNULL_END + +// +// GTMSessionFetcher +// + +#if 0 +#define GTM_LOG_BACKGROUND_SESSION(...) GTMSESSION_LOG_DEBUG(__VA_ARGS__) +#else +#define GTM_LOG_BACKGROUND_SESSION(...) +#endif + +#ifndef GTM_TARGET_SUPPORTS_APP_TRANSPORT_SECURITY +#define GTM_TARGET_SUPPORTS_APP_TRANSPORT_SECURITY 1 +#endif + +#if ((defined(TARGET_OS_MACCATALYST) && TARGET_OS_MACCATALYST) || \ + (TARGET_OS_OSX && defined(__MAC_10_15) && __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_15) || \ + (TARGET_OS_IOS && defined(__IPHONE_13_0) && \ + __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_13_0) || \ + (TARGET_OS_WATCH && defined(__WATCHOS_6_0) && \ + __WATCH_OS_VERSION_MIN_REQUIRED >= __WATCHOS_6_0) || \ + (TARGET_OS_TV && defined(__TVOS_13_0) && __TVOS_VERSION_MIN_REQUIRED >= __TVOS_13_0)) +#define GTM_SDK_REQUIRES_TLSMINIMUMSUPPORTEDPROTOCOLVERSION 1 +#define GTM_SDK_SUPPORTS_TLSMINIMUMSUPPORTEDPROTOCOLVERSION 1 +#elif ((TARGET_OS_OSX && defined(__MAC_10_15) && __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_15) || \ + (TARGET_OS_IOS && defined(__IPHONE_13_0) && \ + __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0) || \ + (TARGET_OS_WATCH && defined(__WATCHOS_6_0) && \ + __WATCH_OS_VERSION_MAX_ALLOWED >= __WATCHOS_6_0) || \ + (TARGET_OS_TV && defined(__TVOS_13_0) && __TVOS_VERSION_MAX_ALLOWED >= __TVOS_13_0)) +#define GTM_SDK_REQUIRES_TLSMINIMUMSUPPORTEDPROTOCOLVERSION 0 +#define GTM_SDK_SUPPORTS_TLSMINIMUMSUPPORTEDPROTOCOLVERSION 1 +#else +#define GTM_SDK_REQUIRES_TLSMINIMUMSUPPORTEDPROTOCOLVERSION 0 +#define GTM_SDK_SUPPORTS_TLSMINIMUMSUPPORTEDPROTOCOLVERSION 0 +#endif + +#if ((defined(TARGET_OS_MACCATALYST) && TARGET_OS_MACCATALYST) || \ + (TARGET_OS_OSX && defined(__MAC_10_15) && __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_15) || \ + (TARGET_OS_IOS && defined(__IPHONE_13_0) && \ + __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_13_0) || \ + (TARGET_OS_WATCH && defined(__WATCHOS_6_0) && \ + __WATCH_OS_VERSION_MIN_REQUIRED >= __WATCHOS_6_0) || \ + (TARGET_OS_TV && defined(__TVOS_13_0) && __TVOS_VERSION_MIN_REQUIRED >= __TVOS_13_0)) +#define GTM_SDK_REQUIRES_SECTRUSTEVALUATEWITHERROR 1 +#else +#define GTM_SDK_REQUIRES_SECTRUSTEVALUATEWITHERROR 0 +#endif + +#if __has_attribute(swift_async) +// Once Clang 13/Xcode 13 can be assumed, can switch to NS_SWIFT_DISABLE_ASYNC. +#define GTM_SWIFT_DISABLE_ASYNC __attribute__((swift_async(none))) +#else +#define GTM_SWIFT_DISABLE_ASYNC +#endif + +@interface GTMSessionFetcher () + +@property(atomic, strong, readwrite, nullable) NSData *downloadedData; +@property(atomic, strong, readwrite, nullable) NSData *downloadResumeData; + +#if GTM_BACKGROUND_TASK_FETCHING +// Should always be accessed within an @synchronized(self). +@property(assign, nonatomic) UIBackgroundTaskIdentifier backgroundTaskIdentifier; +#endif + +@property(atomic, readwrite, getter=isUsingBackgroundSession) BOOL usingBackgroundSession; + +@end + +#if !GTMSESSION_BUILD_COMBINED_SOURCES +@interface GTMSessionFetcher (GTMSessionFetcherLoggingInternal) +- (void)logFetchWithError:(NSError *)error; +- (void)logNowWithError:(nullable NSError *)error; +- (NSInputStream *)loggedInputStreamForInputStream:(NSInputStream *)inputStream; +- (GTMSessionFetcherBodyStreamProvider)loggedStreamProviderForStreamProvider: + (GTMSessionFetcherBodyStreamProvider)streamProvider; +@end +#endif // !GTMSESSION_BUILD_COMBINED_SOURCES + +NS_ASSUME_NONNULL_BEGIN + +static NSTimeInterval InitialMinRetryInterval(void) { + return 1.0 + ((double)(arc4random_uniform(0x0FFFF)) / (double)0x0FFFF); +} + +static BOOL IsLocalhost(NSString *_Nullable host) { + // We check if there's host, and then make the comparisons. + if (host == nil) return NO; + return ([host caseInsensitiveCompare:@"localhost"] == NSOrderedSame || [host isEqual:@"::1"] || + [host isEqual:@"127.0.0.1"]); +} + +static NSDictionary *_Nullable GTMErrorUserInfoForData(NSData *_Nullable data, + NSDictionary *_Nullable responseHeaders) { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + + if (data.length > 0) { + userInfo[kGTMSessionFetcherStatusDataKey] = data; + + NSString *contentType = responseHeaders[@"Content-Type"]; + if (contentType) { + userInfo[kGTMSessionFetcherStatusDataContentTypeKey] = contentType; + } + } + + return userInfo.count > 0 ? userInfo : nil; +} + +static GTMSessionFetcherTestBlock _Nullable gGlobalTestBlock; + +@implementation GTMSessionFetcher { + NSMutableURLRequest *_request; // after beginFetch, changed only in delegate callbacks + BOOL _useUploadTask; // immutable after beginFetch + NSURL *_bodyFileURL; // immutable after beginFetch + GTMSessionFetcherBodyStreamProvider _bodyStreamProvider; // immutable after beginFetch + NSURLSession *_session; + BOOL _shouldInvalidateSession; // immutable after beginFetch + NSURLSession *_sessionNeedingInvalidation; + NSURLSessionConfiguration *_configuration; + NSURLSessionTask *_sessionTask; + NSString *_taskDescription; + float _taskPriority; + NSURLResponse *_response; + NSString *_sessionIdentifier; + BOOL _wasCreatedFromBackgroundSession; + BOOL _clientWillReconnectBackgroundSession; + BOOL _didCreateSessionIdentifier; + NSString *_sessionIdentifierUUID; + BOOL _userRequestedBackgroundSession; + BOOL _usingBackgroundSession; + NSMutableData *_Nullable _downloadedData; + NSError *_downloadFinishedError; + NSData *_downloadResumeData; // immutable after construction + NSData *_Nullable _downloadTaskErrorData; // Data for when download task fails + NSURL *_destinationFileURL; + int64_t _downloadedLength; + NSURLCredential *_credential; // username & password + NSURLCredential *_proxyCredential; // credential supplied to proxy servers + BOOL _isStopNotificationNeeded; // set when start notification has been sent + BOOL _isUsingTestBlock; // set when a test block was provided (remains set when the block is + // released) + id _userData; // retained, if set by caller + NSMutableDictionary *_properties; // more data retained for caller + dispatch_queue_t _callbackQueue; + dispatch_group_t _callbackGroup; // read-only after creation + NSOperationQueue *_delegateQueue; // immutable after beginFetch + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated" + id _authorizer; // immutable after beginFetch +#pragma clang diagnostic pop + + // The service object that created and monitors this fetcher, if any. + GTMSessionFetcherService *_service; // immutable; set by the fetcher service upon creation + NSString *_serviceHost; + NSInteger _servicePriority; // immutable after beginFetch + BOOL _hasStoppedFetching; // counterpart to _initialBeginFetchDate + BOOL _userStoppedFetching; + + BOOL _isRetryEnabled; // user wants auto-retry + NSTimer *_retryTimer; + NSUInteger _retryCount; + NSTimeInterval _maxRetryInterval; // default 60 (download) or 600 (upload) seconds + NSTimeInterval _minRetryInterval; // random between 1 and 2 seconds + NSTimeInterval _retryFactor; // default interval multiplier is 2 + NSTimeInterval _lastRetryInterval; + NSDate *_initialBeginFetchDate; // date that beginFetch was first invoked; immutable after + // initial beginFetch + NSDate *_initialRequestDate; // date of first request to the target server (ignoring auth) + BOOL _hasAttemptedAuthRefresh; // accessed only in shouldRetryNowForStatus: + + NSString *_comment; // comment for log + NSString *_log; +#if !STRIP_GTM_FETCH_LOGGING + NSMutableData *_loggedStreamData; + NSURL *_redirectedFromURL; + NSString *_logRequestBody; + NSString *_logResponseBody; + BOOL _hasLoggedError; + BOOL _deferResponseBodyLogging; +#endif +} + +#if !GTMSESSION_UNIT_TESTING ++ (void)load { +#if GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH && TARGET_OS_IPHONE + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc addObserver:self + selector:@selector(reconnectFetchersForBackgroundSessionsOnAppLaunch:) + name:UIApplicationDidFinishLaunchingNotification + object:nil]; +#elif GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH && TARGET_OS_OSX + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc addObserver:self + selector:@selector(reconnectFetchersForBackgroundSessionsOnAppLaunch:) + name:NSApplicationDidFinishLaunchingNotification + object:nil]; +#else + [self fetchersForBackgroundSessions]; +#endif +} + ++ (void)reconnectFetchersForBackgroundSessionsOnAppLaunch:(NSNotification *)notification { + // Give all other app-did-launch handlers a chance to complete before + // reconnecting the fetchers. Not doing this may lead to reconnecting + // before the app delegate has a chance to run. + dispatch_async(dispatch_get_main_queue(), ^{ + [self fetchersForBackgroundSessions]; + }); +} +#endif // !GTMSESSION_UNIT_TESTING + ++ (instancetype)fetcherWithRequest:(nullable NSURLRequest *)request { + return [[self alloc] initWithRequest:request configuration:nil]; +} + ++ (instancetype)fetcherWithURL:(NSURL *)requestURL { + return [self fetcherWithRequest:[NSURLRequest requestWithURL:requestURL]]; +} + ++ (instancetype)fetcherWithURLString:(NSString *)requestURLString { + return [self fetcherWithURL:(NSURL *)[NSURL URLWithString:requestURLString]]; +} + ++ (instancetype)fetcherWithDownloadResumeData:(NSData *)resumeData { + GTMSessionFetcher *fetcher = [self fetcherWithRequest:nil]; + fetcher.comment = @"Resuming download"; + fetcher.downloadResumeData = resumeData; + return fetcher; +} + ++ (nullable instancetype)fetcherWithSessionIdentifier:(NSString *)sessionIdentifier { + GTMSESSION_ASSERT_DEBUG(sessionIdentifier != nil, @"Invalid session identifier"); + NSMapTable *sessionIdentifierToFetcherMap = [self sessionIdentifierToFetcherMap]; + GTMSessionFetcher *fetcher = [sessionIdentifierToFetcherMap objectForKey:sessionIdentifier]; + if (!fetcher && [sessionIdentifier hasPrefix:kGTMSessionIdentifierPrefix]) { + fetcher = [self fetcherWithRequest:nil]; + [fetcher setSessionIdentifier:sessionIdentifier]; + [sessionIdentifierToFetcherMap setObject:fetcher forKey:sessionIdentifier]; + fetcher->_wasCreatedFromBackgroundSession = YES; + [fetcher setCommentWithFormat:@"Resuming %@", fetcher && fetcher->_sessionIdentifierUUID + ? fetcher->_sessionIdentifierUUID + : @"?"]; + } + return fetcher; +} + ++ (NSMapTable *)sessionIdentifierToFetcherMap { + // TODO: What if a service is involved in creating the fetcher? Currently, when re-creating + // fetchers, if a service was involved, it is not re-created. Should the service maintain a map? + static NSMapTable *gSessionIdentifierToFetcherMap = nil; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + gSessionIdentifierToFetcherMap = [NSMapTable strongToWeakObjectsMapTable]; + }); + return gSessionIdentifierToFetcherMap; +} + +#if !GTM_ALLOW_INSECURE_REQUESTS ++ (BOOL)appAllowsInsecureRequests { + // If the main bundle Info.plist key NSAppTransportSecurity is present, and it specifies + // NSAllowsArbitraryLoads, then we need to explicitly enforce secure schemes. +#if GTM_TARGET_SUPPORTS_APP_TRANSPORT_SECURITY + static BOOL allowsInsecureRequests; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSBundle *mainBundle = [NSBundle mainBundle]; + NSDictionary *appTransportSecurity = + [mainBundle objectForInfoDictionaryKey:@"NSAppTransportSecurity"]; + allowsInsecureRequests = + [[appTransportSecurity objectForKey:@"NSAllowsArbitraryLoads"] boolValue]; + }); + return allowsInsecureRequests; +#else + // For builds targeting iOS 8 or 10.10 and earlier, we want to require fetcher + // security checks. + return YES; +#endif // GTM_TARGET_SUPPORTS_APP_TRANSPORT_SECURITY +} +#else // GTM_ALLOW_INSECURE_REQUESTS ++ (BOOL)appAllowsInsecureRequests { + return YES; +} +#endif // !GTM_ALLOW_INSECURE_REQUESTS + +- (instancetype)init { + return [self initWithRequest:nil configuration:nil]; +} + +- (instancetype)initWithRequest:(NSURLRequest *)request { + return [self initWithRequest:request configuration:nil]; +} + +- (instancetype)initWithRequest:(nullable NSURLRequest *)request + configuration:(nullable NSURLSessionConfiguration *)configuration { + self = [super init]; + if (self) { +#if GTM_BACKGROUND_TASK_FETCHING + _backgroundTaskIdentifier = UIBackgroundTaskInvalid; +#endif + _request = [request mutableCopy]; + _configuration = configuration; + + NSData *bodyData = request.HTTPBody; + if (bodyData) { + _bodyLength = (int64_t)bodyData.length; + } else { + _bodyLength = NSURLSessionTransferSizeUnknown; + } + + _callbackQueue = dispatch_get_main_queue(); + _callbackGroup = dispatch_group_create(); + _delegateQueue = [NSOperationQueue mainQueue]; + + _minRetryInterval = InitialMinRetryInterval(); + _maxRetryInterval = kUnsetMaxRetryInterval; + + _taskPriority = -1.0f; // Valid values if set are 0.0...1.0. + + _testBlockAccumulateDataChunkCount = 1; + +#if !STRIP_GTM_FETCH_LOGGING + // Encourage developers to set the comment property or use + // setCommentWithFormat: by providing a default string. + _comment = @"(No fetcher comment set)"; +#endif + } + return self; +} + +- (id)copyWithZone:(NSZone *)zone { + // disallow use of fetchers in a copy property + [self doesNotRecognizeSelector:_cmd]; + return nil; +} + +- (NSString *)description { + NSString *requestStr = self.request.URL.description; + if (requestStr.length == 0) { + if (self.downloadResumeData.length > 0) { + requestStr = @""; + } else if (_wasCreatedFromBackgroundSession) { + requestStr = @""; + } else { + requestStr = @""; + } + } + return [NSString stringWithFormat:@"%@ %p (%@)", [self class], self, requestStr]; +} + +- (void)dealloc { + GTMSESSION_ASSERT_DEBUG(!_isStopNotificationNeeded, @"unbalanced fetcher notification for %@", + _request.URL); + [self forgetSessionIdentifierForFetcherWithoutSyncCheck]; + + // Note: if a session task or a retry timer was pending, then this instance + // would be retained by those so it wouldn't be getting dealloc'd, + // hence we don't need to stopFetch here +} + +#pragma mark - + +// Begin fetching the URL (or begin a retry fetch). The delegate is retained +// for the duration of the fetch connection. + +- (void)beginFetchWithCompletionHandler:(nullable GTMSessionFetcherCompletionHandler)handler { + GTMSessionCheckNotSynchronized(self); + _completionHandler = [handler copy]; + + // The user may have called setDelegate: earlier if they want to use other + // delegate-style callbacks during the fetch; otherwise, the delegate is nil, + // which is fine. + [self beginFetchMayDelay:YES mayAuthorize:YES mayDecorate:YES]; +} + +// Begin fetching the URL for a retry fetch. The delegate and completion handler +// are already provided, and do not need to be copied. +- (void)beginFetchForRetry { + GTMSessionCheckNotSynchronized(self); + [self beginFetchMayDelay:YES mayAuthorize:YES mayDecorate:YES]; +} + +- (GTMSessionFetcherCompletionHandler)completionHandlerWithTarget:(nullable id)target + didFinishSelector:(nullable SEL)finishedSelector { + GTMSessionFetcherAssertValidSelector(target, finishedSelector, @encode(GTMSessionFetcher *), + @encode(NSData *), @encode(NSError *), 0); + GTMSessionFetcherCompletionHandler completionHandler = ^(NSData *data, NSError *error) { + if (target && finishedSelector) { + id selfArg = self; // Placate ARC. + NSMethodSignature *sig = [target methodSignatureForSelector:finishedSelector]; + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig]; + [invocation setSelector:(SEL)finishedSelector]; + [invocation setTarget:target]; + [invocation setArgument:&selfArg atIndex:2]; + [invocation setArgument:&data atIndex:3]; + [invocation setArgument:&error atIndex:4]; + [invocation invoke]; + } + }; + return completionHandler; +} + +- (void)beginFetchWithDelegate:(nullable id)target + didFinishSelector:(nullable SEL)finishedSelector { + GTMSessionCheckNotSynchronized(self); + + GTMSessionFetcherCompletionHandler handler = [self completionHandlerWithTarget:target + didFinishSelector:finishedSelector]; + [self beginFetchWithCompletionHandler:handler]; +} + +- (void)beginFetchMayDelay:(BOOL)mayDelay + mayAuthorize:(BOOL)mayAuthorize + mayDecorate:(BOOL)mayDecorate { + // This is the internal entry point for re-starting fetches. + GTMSessionCheckNotSynchronized(self); + + NSMutableURLRequest *fetchRequest = + _request; // The request property is now externally immutable. + NSURL *fetchRequestURL = fetchRequest.URL; + NSString *priorSessionIdentifier = self.sessionIdentifier; + + GTMSESSION_LOG_DEBUG_VERBOSE(@"%@ %p URL:%@ beginFetchMayDelay:%d mayAuthorize:%d mayDecorate:%d", + [self class], self, _request.URL, mayDelay, mayAuthorize, + mayDecorate); + + // A utility block for creating error objects when we fail to start the fetch. + NSError * (^beginFailureError)(NSInteger) = ^(NSInteger code) { + NSString *urlString = fetchRequestURL.absoluteString; + NSDictionary *userInfo = + @{NSURLErrorFailingURLStringErrorKey : (urlString ? urlString : @"(missing URL)")}; + return [NSError errorWithDomain:kGTMSessionFetcherErrorDomain code:code userInfo:userInfo]; + }; + + // Catch delegate queue maxConcurrentOperationCount values other than 1, particularly + // NSOperationQueueDefaultMaxConcurrentOperationCount (-1), to avoid the additional complexity + // of simultaneous or out-of-order delegate callbacks. + GTMSESSION_ASSERT_DEBUG(_delegateQueue.maxConcurrentOperationCount == 1, + @"delegate queue %@ should support one concurrent operation, not %ld", + _delegateQueue.name, (long)_delegateQueue.maxConcurrentOperationCount); + + if (!_initialBeginFetchDate) { + // This ivar is set only here on the initial beginFetch so need not be synchronized. + _initialBeginFetchDate = [[NSDate alloc] init]; + } + + if (self.sessionTask != nil) { + // If cached fetcher returned through fetcherWithSessionIdentifier:, then it's + // already begun, but don't consider this a failure, since the user need not know this. + if (self.sessionIdentifier != nil) { + return; + } + GTMSESSION_ASSERT_DEBUG(NO, @"Fetch object %@ being reused; this should never happen", self); + [self failToBeginFetchWithError:beginFailureError(GTMSessionFetcherErrorDownloadFailed)]; + return; + } + + if (fetchRequestURL == nil && !_downloadResumeData && !priorSessionIdentifier) { + GTMSESSION_ASSERT_DEBUG(NO, @"Beginning a fetch requires a request with a URL"); + [self failToBeginFetchWithError:beginFailureError(GTMSessionFetcherErrorDownloadFailed)]; + return; + } + + // We'll respect the user's request for a background session (unless this is + // an upload fetcher, which does its initial request foreground.) + self.usingBackgroundSession = self.useBackgroundSession && [self canFetchWithBackgroundSession]; + + NSURL *bodyFileURL = self.bodyFileURL; + if (bodyFileURL) { + NSError *fileCheckError; + if (![bodyFileURL checkResourceIsReachableAndReturnError:&fileCheckError]) { + // This assert fires when the file being uploaded no longer exists once + // the fetcher is ready to start the upload. + GTMSESSION_ASSERT_DEBUG_OR_LOG(0, @"Body file is unreachable: %@\n %@", bodyFileURL.path, + fileCheckError); + [self failToBeginFetchWithError:fileCheckError]; + return; + } + } + + NSString *requestScheme = fetchRequestURL.scheme; + BOOL isDataRequest = [requestScheme isEqual:@"data"]; + if (isDataRequest) { + // NSURLSession does not support data URLs in background sessions. +#if DEBUG + if (priorSessionIdentifier || self.sessionIdentifier) { + GTMSESSION_LOG_DEBUG(@"Converting background to foreground session for %@", fetchRequest); + } +#endif + // If priorSessionIdentifier is allowed to stay non-nil, a background session can + // still be created. + priorSessionIdentifier = nil; + [self setSessionIdentifierInternal:nil]; + self.usingBackgroundSession = NO; + } + +#if GTM_ALLOW_INSECURE_REQUESTS + BOOL shouldCheckSecurity = NO; +#else + BOOL shouldCheckSecurity = + (fetchRequestURL != nil && !isDataRequest && [[self class] appAllowsInsecureRequests]); +#endif + + if (shouldCheckSecurity) { + // Allow https only for requests, unless overridden by the client. + // + // Non-https requests may too easily be snooped, so we disallow them by default. + // + // file: and data: schemes are usually safe if they are hardcoded in the client or provided + // by a trusted source, but since it's fairly rare to need them, it's safest to make clients + // explicitly allow them. + BOOL isSecure = + requestScheme != nil && [requestScheme caseInsensitiveCompare:@"https"] == NSOrderedSame; + if (!isSecure) { + BOOL allowRequest = NO; + NSString *host = fetchRequestURL.host; + + // Check schemes first. A file scheme request may be allowed here, or as a localhost request. + for (NSString *allowedScheme in _allowedInsecureSchemes) { + if (requestScheme != nil && + [requestScheme caseInsensitiveCompare:allowedScheme] == NSOrderedSame) { + allowRequest = YES; + break; + } + } + if (!allowRequest) { + // Check for localhost requests. Security checks only occur for non-https requests, so + // this check won't happen for an https request to localhost. + BOOL isLocalhostRequest = + (host.length == 0 && [fetchRequestURL isFileURL]) || IsLocalhost(host); + if (isLocalhostRequest) { + if (self.allowLocalhostRequest) { + allowRequest = YES; + } else { + GTMSESSION_ASSERT_DEBUG(NO, + @"Fetch request for localhost but fetcher" + @" allowLocalhostRequest is not set: %@", + fetchRequestURL); + } + } else { + GTMSESSION_ASSERT_DEBUG(NO, + @"Insecure fetch request has a scheme (%@)" + @" not found in fetcher allowedInsecureSchemes (%@): %@", + requestScheme, _allowedInsecureSchemes ?: @" @[] ", + fetchRequestURL); + } + } + + if (!allowRequest) { +#if !DEBUG + NSLog(@"Insecure fetch disallowed for %@", + fetchRequestURL.description ?: @"nil request URL"); +#endif + [self failToBeginFetchWithError:beginFailureError(GTMSessionFetcherErrorInsecureRequest)]; + return; + } + } // !isSecure + } // (requestURL != nil) && !isDataRequest + + if (self.cookieStorage == nil) { + self.cookieStorage = [[self class] staticCookieStorage]; + } + + BOOL isRecreatingSession = (self.sessionIdentifier != nil) && (fetchRequest == nil); + + self.canShareSession = (_service != nil) && !isRecreatingSession && !self.usingBackgroundSession; + + if (!self.session) { + if (self.canShareSession) { + self.session = [_service + sessionWithCreationBlock:^NSURLSession *(id sessionDelegate) { + return [self createSessionWithDelegate:sessionDelegate + sessionIdentifier:priorSessionIdentifier]; + }]; + } else { + self.session = [self createSessionWithDelegate:self sessionIdentifier:priorSessionIdentifier]; + } + } + + if (isRecreatingSession) { + _shouldInvalidateSession = YES; + + // Let's make sure there are tasks still running or if not that we get a callback from a + // completed one; otherwise, we assume the tasks failed. + // This is the observed behavior perhaps 25% of the time within the Simulator running 7.0.3 on + // exiting the app after starting an upload and relaunching the app if we manage to relaunch + // after the task has completed, but before the system relaunches us in the background. + [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, + NSArray *downloadTasks) { + if (dataTasks.count == 0 && uploadTasks.count == 0 && downloadTasks.count == 0) { + double const kDelayInSeconds = 1.0; // We should get progress indication or completion soon + dispatch_time_t checkForFeedbackDelay = + dispatch_time(DISPATCH_TIME_NOW, (int64_t)(kDelayInSeconds * NSEC_PER_SEC)); + dispatch_after(checkForFeedbackDelay, dispatch_get_main_queue(), ^{ + if (!self.sessionTask && !fetchRequest) { + // If our task and/or request haven't been restored, then we assume task feedback lost. + [self removePersistedBackgroundSessionFromDefaults]; + NSError *sessionError = + [NSError errorWithDomain:kGTMSessionFetcherErrorDomain + code:GTMSessionFetcherErrorBackgroundFetchFailed + userInfo:nil]; + [self failToBeginFetchWithError:sessionError]; + } + }); + } + }]; + return; + } + + self.downloadedData = nil; + self.downloadedLength = 0; + + if (_servicePriority == NSIntegerMin) { + mayDelay = NO; + } + if (mayDelay && _service) { + BOOL shouldFetchNow = [_service fetcherShouldBeginFetching:self]; + if (!shouldFetchNow) { + // The fetch is deferred, but will happen later. + // + // If this session is held by the fetcher service, clear the session now so that we don't + // assume it's still valid after the fetcher is restarted. + if (self.canShareSession) { + self.session = nil; + } + return; + } + } + + NSString *effectiveHTTPMethod = [fetchRequest valueForHTTPHeaderField:@"X-HTTP-Method-Override"]; + if (effectiveHTTPMethod == nil) { + effectiveHTTPMethod = fetchRequest.HTTPMethod; + } + BOOL isEffectiveHTTPGet = (effectiveHTTPMethod == nil || [effectiveHTTPMethod isEqual:@"GET"]); + + BOOL needsUploadTask = (self.useUploadTask || self.bodyFileURL || self.bodyStreamProvider); + if (_bodyData || self.bodyStreamProvider || fetchRequest.HTTPBodyStream) { + if (isEffectiveHTTPGet) { + fetchRequest.HTTPMethod = @"POST"; + isEffectiveHTTPGet = NO; + } + + if (_bodyData) { + if (!needsUploadTask) { + fetchRequest.HTTPBody = _bodyData; + } +#if !STRIP_GTM_FETCH_LOGGING + } else if (fetchRequest.HTTPBodyStream) { + if ([self respondsToSelector:@selector(loggedInputStreamForInputStream:)]) { + fetchRequest.HTTPBodyStream = + [self performSelector:@selector(loggedInputStreamForInputStream:) + withObject:fetchRequest.HTTPBodyStream]; + } +#endif + } + } + + // We authorize after setting up the http method and body in the request + // because OAuth 1 may need to sign the request body + if (mayAuthorize && _authorizer && !isDataRequest) { + BOOL isAuthorized = [_authorizer isAuthorizedRequest:fetchRequest]; + if (!isAuthorized) { + // Authorization needed. + // + // If this session is held by the fetcher service, clear the session now so that we don't + // assume it's still valid after authorization completes. + if (self.canShareSession) { + self.session = nil; + } + + // Authorizing the request will recursively call this beginFetch:mayDelay: + // or failToBeginFetchWithError:. + [self authorizeRequest]; + return; + } + } + + if (mayDecorate && [_service respondsToSelector:@selector(decorators)]) { + NSArray> *decorators = _service.decorators; + if (decorators.count) { + // If this session is held by the fetcher service, clear the session now so that we don't + // assume it's still valid after decoration completes. + // + // The service will still hold on to the session, so as long as decoration doesn't take more + // than 30 seconds since the last request, the service's session will be re-used when the + // fetch actually starts. + if (self.canShareSession) { + self.session = nil; + } + [self applyDecoratorsAtRequestWillStart:decorators startingAtIndex:0]; + return; + } + } + + // set the default upload or download retry interval, if necessary + if ([self isRetryEnabled] && self.maxRetryInterval <= 0) { + if (isEffectiveHTTPGet || [effectiveHTTPMethod isEqual:@"HEAD"]) { + [self setMaxRetryInterval:kDefaultMaxDownloadRetryInterval]; + } else { + [self setMaxRetryInterval:kDefaultMaxUploadRetryInterval]; + } + } + + // finally, start the connection + NSURLSessionTask *newSessionTask; + BOOL needsDataAccumulator = NO; + if (_downloadResumeData) { + newSessionTask = [_session downloadTaskWithResumeData:_downloadResumeData]; + GTMSESSION_ASSERT_DEBUG_OR_LOG( + newSessionTask, @"Failed downloadTaskWithResumeData for %@, resume data %lu bytes", + _session, (unsigned long)_downloadResumeData.length); + } else if (_destinationFileURL && !isDataRequest) { + newSessionTask = [_session downloadTaskWithRequest:fetchRequest]; + GTMSESSION_ASSERT_DEBUG_OR_LOG(newSessionTask, @"Failed downloadTaskWithRequest for %@, %@", + _session, fetchRequest); + } else if (needsUploadTask) { + if (bodyFileURL) { + newSessionTask = [_session uploadTaskWithRequest:fetchRequest fromFile:bodyFileURL]; + GTMSESSION_ASSERT_DEBUG_OR_LOG(newSessionTask, + @"Failed uploadTaskWithRequest for %@, %@, file %@", _session, + fetchRequest, bodyFileURL.path); + } else if (self.bodyStreamProvider) { + newSessionTask = [_session uploadTaskWithStreamedRequest:fetchRequest]; + GTMSESSION_ASSERT_DEBUG_OR_LOG(newSessionTask, + @"Failed uploadTaskWithStreamedRequest for %@, %@", _session, + fetchRequest); + } else { + GTMSESSION_ASSERT_DEBUG_OR_LOG(_bodyData != nil, @"Upload task needs body data, %@", + fetchRequest); + newSessionTask = [_session uploadTaskWithRequest:fetchRequest + fromData:(NSData *_Nonnull)_bodyData]; + GTMSESSION_ASSERT_DEBUG_OR_LOG( + newSessionTask, @"Failed uploadTaskWithRequest for %@, %@, body data %lu bytes", _session, + fetchRequest, (unsigned long)_bodyData.length); + } + needsDataAccumulator = YES; + } else { + newSessionTask = [_session dataTaskWithRequest:fetchRequest]; + needsDataAccumulator = YES; + GTMSESSION_ASSERT_DEBUG_OR_LOG(newSessionTask, @"Failed dataTaskWithRequest for %@, %@", + _session, fetchRequest); + } + self.sessionTask = newSessionTask; + + if (!newSessionTask) { + // We shouldn't get here; if we're here, an earlier assertion should have fired to explain + // which session task creation failed. + [self failToBeginFetchWithError:beginFailureError(GTMSessionFetcherErrorTaskCreationFailed)]; + return; + } + + if (needsDataAccumulator && _accumulateDataBlock == nil) { + self.downloadedData = [NSMutableData data]; + } + if (_taskDescription) { + newSessionTask.taskDescription = _taskDescription; + } + if (_taskPriority >= 0) { + newSessionTask.priority = _taskPriority; + } + +#if GTM_DISABLE_FETCHER_TEST_BLOCK + GTMSESSION_ASSERT_DEBUG(_testBlock == nil && gGlobalTestBlock == nil, @"test blocks disabled"); + _testBlock = nil; +#else + if (!_testBlock) { + if (gGlobalTestBlock) { + // Note that the test block may pass nil for all of its response parameters, + // indicating that the fetch should actually proceed. This is useful when the + // global test block has been set, and the app is only testing a specific + // fetcher. The block simulation code will then resume the task. + _testBlock = gGlobalTestBlock; + } + } + _isUsingTestBlock = (_testBlock != nil); +#endif // GTM_DISABLE_FETCHER_TEST_BLOCK + +#if GTM_BACKGROUND_TASK_FETCHING + id app = [[self class] fetcherUIApplication]; + // Background tasks seem to interfere with out-of-process uploads and downloads. + if (app && !self.skipBackgroundTask && !self.usingBackgroundSession) { + // Tell UIApplication that we want to continue even when the app is in the + // background. +#if DEBUG + NSString *bgTaskName = + [NSString stringWithFormat:@"%@-%@", [self class], fetchRequest.URL.host]; +#else + NSString *bgTaskName = @"GTMSessionFetcher"; +#endif + // Since a request can be started from any thread, we also have to ensure the + // variable for accessing it is safe across the initial thread and the handler + // (incase it gets failed immediately from the app already heading into the + // background). + __block UIBackgroundTaskIdentifier guardedTaskID = UIBackgroundTaskInvalid; + UIBackgroundTaskIdentifier returnedTaskID = + [app beginBackgroundTaskWithName:bgTaskName + expirationHandler:^{ + // Background task expiration callback - this block is always invoked by + // UIApplication on the main thread. + UIBackgroundTaskIdentifier localTaskID; + @synchronized(self) { + localTaskID = guardedTaskID; + } + if (localTaskID != UIBackgroundTaskInvalid) { + @synchronized(self) { + if (localTaskID == self.backgroundTaskIdentifier) { + self.backgroundTaskIdentifier = UIBackgroundTaskInvalid; + } + } + [app endBackgroundTask:localTaskID]; + } + }]; + @synchronized(self) { + guardedTaskID = returnedTaskID; + self.backgroundTaskIdentifier = returnedTaskID; + } + } +#endif + + if (!_initialRequestDate) { + _initialRequestDate = [[NSDate alloc] init]; + } + + // We don't expect to reach here even on retry or auth until a stop notification has been sent + // for the previous task, but we should ensure that we don't unbalance that. + GTMSESSION_ASSERT_DEBUG(!_isStopNotificationNeeded, @"Start notification without a prior stop"); + [self sendStopNotificationIfNeeded]; + + [self addPersistedBackgroundSessionToDefaults]; + + [self setStopNotificationNeeded:YES]; + + [self postNotificationOnMainThreadWithName:kGTMSessionFetcherStartedNotification + userInfo:nil + requireAsync:NO]; + + // The service needs to know our task if it is serving as NSURLSession delegate. + [_service fetcherDidBeginFetching:self]; + + if (_testBlock) { +#if !GTM_DISABLE_FETCHER_TEST_BLOCK + [self simulateFetchForTestBlock]; +#endif + } else { + // We resume the session task after posting the notification since the + // delegate callbacks may happen immediately if the fetch is started off + // the main thread or the session delegate queue is on a background thread, + // and we don't want to post a start notification after a premature finish + // of the session task. + [newSessionTask resume]; + } +} + +// Helper method to create a new NSURLSession for this fetcher. Because the original +// implementation had this code inline, marking direct to avoid any danger of subclasses +// overriding the behavior. +- (NSURLSession *)createSessionWithDelegate:(id)sessionDelegate + sessionIdentifier:(nullable NSString *)priorSessionIdentifier + __attribute__((objc_direct)) { + // Create a session. + if (!_configuration) { + if (priorSessionIdentifier || self.usingBackgroundSession) { + NSString *sessionIdentifier = priorSessionIdentifier; + if (!sessionIdentifier) { + sessionIdentifier = [self createSessionIdentifierWithMetadata:nil]; + } + NSMapTable *sessionIdentifierToFetcherMap = [[self class] sessionIdentifierToFetcherMap]; + [sessionIdentifierToFetcherMap setObject:self forKey:self.sessionIdentifier]; + + _configuration = [NSURLSessionConfiguration + backgroundSessionConfigurationWithIdentifier:sessionIdentifier]; + self.usingBackgroundSession = YES; + self.canShareSession = NO; + } else { + _configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration]; + } +#if !GTM_ALLOW_INSECURE_REQUESTS +#if GTM_SDK_REQUIRES_TLSMINIMUMSUPPORTEDPROTOCOLVERSION + _configuration.TLSMinimumSupportedProtocolVersion = tls_protocol_version_TLSv12; +#elif GTM_SDK_SUPPORTS_TLSMINIMUMSUPPORTEDPROTOCOLVERSION + if (@available(iOS 13, tvOS 13, macOS 10.15, *)) { + _configuration.TLSMinimumSupportedProtocolVersion = tls_protocol_version_TLSv12; + } else { + _configuration.TLSMinimumSupportedProtocol = kTLSProtocol12; + } +#else + _configuration.TLSMinimumSupportedProtocol = kTLSProtocol12; +#endif // GTM_SDK_REQUIRES_TLSMINIMUMSUPPORTEDPROTOCOLVERSION +#endif + } // !_configuration + _configuration.HTTPCookieStorage = self.cookieStorage; + + if (_configurationBlock) { + _configurationBlock(self, _configuration); + } + + id delegate = sessionDelegate; + if (!delegate || !self.canShareSession) { + delegate = self; + } + NSURLSession *session = [NSURLSession sessionWithConfiguration:_configuration + delegate:delegate + delegateQueue:self.sessionDelegateQueue]; + GTMSESSION_ASSERT_DEBUG(session, @"Couldn't create session"); + + // If this assertion fires, the client probably tried to use a session identifier that was + // already used. The solution is to make the client use a unique identifier (or better yet let + // the session fetcher assign the identifier). + GTMSESSION_ASSERT_DEBUG(session.delegate == delegate, @"Couldn't assign delegate."); + + if (session) { + BOOL isUsingSharedDelegate = (delegate != self); + if (!isUsingSharedDelegate) { + _shouldInvalidateSession = YES; + } + } + + return session; +} + +NSData *_Nullable GTMDataFromInputStream(NSInputStream *inputStream, NSError **outError) { + NSMutableData *data = [NSMutableData data]; + + [inputStream open]; + NSInteger numberOfBytesRead = 0; + while ([inputStream hasBytesAvailable]) { + uint8_t buffer[512]; + numberOfBytesRead = [inputStream read:buffer maxLength:sizeof(buffer)]; + if (numberOfBytesRead > 0) { + [data appendBytes:buffer length:(NSUInteger)numberOfBytesRead]; + } else { + break; + } + } + [inputStream close]; + NSError *streamError = inputStream.streamError; + + if (streamError) { + data = nil; + } + if (outError) { + *outError = streamError; + } + return data; +} + +#if !GTM_DISABLE_FETCHER_TEST_BLOCK + +- (void)simulateFetchForTestBlock { + // This is invoked on the same thread as the beginFetch method was. + // + // Callbacks will all occur on the callback queue. + _testBlock(self, ^(NSURLResponse *response, NSData *responseData, NSError *error) { + // Callback from test block. + if (response == nil && responseData == nil && error == nil) { + // Assume the fetcher should execute rather than be tested. + self->_testBlock = nil; + self->_isUsingTestBlock = NO; + [self->_sessionTask resume]; + return; + } + + GTMSessionFetcherBodyStreamProvider bodyStreamProvider = self.bodyStreamProvider; + if (bodyStreamProvider) { + bodyStreamProvider(^(NSInputStream *bodyStream) { + // Read from the input stream into an NSData buffer. We'll drain the stream + // explicitly on a background queue. + [self + invokeOnCallbackQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0) + afterUserStopped:NO + block:^{ + NSError *streamError; + NSData *streamedData = + GTMDataFromInputStream(bodyStream, &streamError); + + dispatch_async(dispatch_get_main_queue(), ^{ + // Continue callbacks on the main thread, since serial behavior + // is more reliable for tests. + [self + simulateDataCallbacksForTestBlockWithBodyData:streamedData + response:response + responseData:responseData + error: + (error + ?: streamError)]; + }); + }]; + }); + } else { + // No input stream; use the supplied data or file URL. + NSURL *bodyFileURL = self.bodyFileURL; + if (bodyFileURL) { + NSError *readError; + self->_bodyData = [NSData dataWithContentsOfURL:bodyFileURL + options:NSDataReadingMappedIfSafe + error:&readError]; + error = readError; + } + + // No stream provider. + + // In real fetches, nothing happens until the run loop spins, so apps have leeway to + // set callbacks after they call beginFetch. We'll mirror that fetcher behavior by + // delaying callbacks here at least to the next spin of the run loop. That keeps + // immediate, synchronous setting of callback blocks after beginFetch working in tests. + dispatch_async(dispatch_get_main_queue(), ^{ + [self simulateDataCallbacksForTestBlockWithBodyData:self->_bodyData + response:response + responseData:responseData + error:error]; + }); + } + }); +} + +- (void)simulateByteTransferReportWithDataLength:(int64_t)totalDataLength + block:(GTMSessionFetcherSendProgressBlock)block { + // This utility method simulates transfer progress with up to three callbacks. + // It is used to call back to any of the progress blocks. + int64_t sendReportSize = totalDataLength / 3 + 1; + int64_t totalSent = 0; + while (totalSent < totalDataLength) { + int64_t bytesRemaining = totalDataLength - totalSent; + sendReportSize = MIN(sendReportSize, bytesRemaining); + totalSent += sendReportSize; + [self invokeOnCallbackQueueUnlessStopped:^{ + block(sendReportSize, totalSent, totalDataLength); + }]; + } +} + +- (void)simulateDataCallbacksForTestBlockWithBodyData:(nullable NSData *)bodyData + response:(NSURLResponse *)response + responseData:(NSData *)suppliedData + error:(NSError *)suppliedError { + __block NSData *responseData = suppliedData; + __block NSError *responseError = suppliedError; + + // This method does the test simulation of callbacks once the upload + // and download data are known. + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // Get copies of ivars we'll access in async invocations. This simulation assumes + // they won't change during fetcher execution. + NSURL *destinationFileURL = _destinationFileURL; + GTMSessionFetcherWillRedirectBlock willRedirectBlock = _willRedirectBlock; + GTMSessionFetcherDidReceiveResponseBlock didReceiveResponseBlock = _didReceiveResponseBlock; + GTMSessionFetcherSendProgressBlock sendProgressBlock = _sendProgressBlock; + GTMSessionFetcherDownloadProgressBlock downloadProgressBlock = _downloadProgressBlock; + GTMSessionFetcherAccumulateDataBlock accumulateDataBlock = _accumulateDataBlock; + GTMSessionFetcherReceivedProgressBlock receivedProgressBlock = _receivedProgressBlock; + GTMSessionFetcherWillCacheURLResponseBlock willCacheURLResponseBlock = + _willCacheURLResponseBlock; + GTMSessionFetcherChallengeBlock challengeBlock = _challengeBlock; + + // Simulate receipt of redirection. + if (willRedirectBlock) { + __auto_type block = ^{ + willRedirectBlock((NSHTTPURLResponse *)response, self->_request, + ^(NSURLRequest *redirectRequest){ + // For simulation, we'll assume + // the app will just continue. + }); + }; + [self invokeOnCallbackUnsynchronizedQueueAfterUserStopped:YES block:block]; + } + + // If the fetcher has a challenge block, simulate a challenge. + // + // It might be nice to eventually let the user determine which testBlock + // fetches get challenged rather than always executing the supplied + // challenge block. + if (challengeBlock) { + __auto_type block = ^{ + NSURL *requestURL = self->_request.URL; + NSString *host = requestURL.host; + NSURLProtectionSpace *pspace = + [[NSURLProtectionSpace alloc] initWithHost:host + port:requestURL.port.integerValue + protocol:requestURL.scheme + realm:nil + authenticationMethod:NSURLAuthenticationMethodHTTPBasic]; + id unusedSender = + (id)[NSNull null]; + NSURLAuthenticationChallenge *challenge = + [[NSURLAuthenticationChallenge alloc] initWithProtectionSpace:pspace + proposedCredential:nil + previousFailureCount:0 + failureResponse:nil + error:nil + sender:unusedSender]; + challengeBlock(self, challenge, + ^(NSURLSessionAuthChallengeDisposition disposition, + NSURLCredential *_Nullable credential){ + // We could change the + // responseData and responseError + // based on the disposition, + // but it's easier for apps to + // just supply the expected data + // and error + // directly to the test block. So + // this simulation ignores the + // disposition. + }); + }; + [self invokeOnCallbackUnsynchronizedQueueAfterUserStopped:YES block:block]; + } + + // Simulate receipt of an initial response. + if (response && didReceiveResponseBlock) { + __auto_type block = ^{ + didReceiveResponseBlock(response, ^(NSURLSessionResponseDisposition desiredDisposition){ + // For simulation, we'll assume + // the disposition is to continue. + }); + }; + [self invokeOnCallbackUnsynchronizedQueueAfterUserStopped:YES block:block]; + } + + // Simulate reporting send progress. + if (sendProgressBlock) { + __auto_type block = + ^(int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend) { + // This is invoked on the callback queue unless + // stopped. + sendProgressBlock(bytesSent, totalBytesSent, totalBytesExpectedToSend); + }; + [self simulateByteTransferReportWithDataLength:(int64_t)bodyData.length block:block]; + } + + if (destinationFileURL) { + // Simulate download to file progress. + if (downloadProgressBlock) { + __auto_type block = ^(int64_t bytesDownloaded, int64_t totalBytesDownloaded, + int64_t totalBytesExpectedToDownload) { + // This is invoked on the callback queue unless + // stopped. + downloadProgressBlock(bytesDownloaded, totalBytesDownloaded, + totalBytesExpectedToDownload); + }; + [self simulateByteTransferReportWithDataLength:(int64_t)responseData.length block:block]; + } + + NSError *writeError; + [responseData writeToURL:destinationFileURL options:NSDataWritingAtomic error:&writeError]; + if (writeError) { + // Tell the test code that writing failed. + responseError = writeError; + } + } else { + // Simulate download to NSData progress. + if ((accumulateDataBlock || receivedProgressBlock) && responseData) { + __auto_type block = ^(NSData *data, int64_t bytesReceived, int64_t totalBytesReceived, + int64_t totalBytesExpectedToReceive) { + // This is invoked on the callback queue unless stopped. + if (accumulateDataBlock) { + accumulateDataBlock(data); + } + + if (receivedProgressBlock) { + receivedProgressBlock(bytesReceived, totalBytesReceived); + } + }; + [self simulateByteTransferWithData:responseData block:block]; + } + + if (!accumulateDataBlock) { + _downloadedData = [responseData mutableCopy]; + } + + if (willCacheURLResponseBlock) { + // Simulate letting the client inspect and alter the cached response. + NSData *cachedData = responseData ?: [[NSData alloc] init]; // Always have non-nil data. + NSCachedURLResponse *cachedResponse = + [[NSCachedURLResponse alloc] initWithResponse:response data:cachedData]; + __auto_type block = ^{ + willCacheURLResponseBlock(cachedResponse, ^(NSCachedURLResponse *responseToCache){ + // The app may provide an + // alternative response, or + // nil to defeat caching. + }); + }; + [self invokeOnCallbackUnsynchronizedQueueAfterUserStopped:YES block:block]; + } + } + _response = response; + } // @synchronized(self) + + NSOperationQueue *queue = self.sessionDelegateQueue; + [queue addOperationWithBlock:^{ + // Rather than invoke failToBeginFetchWithError: we want to simulate completion of + // a connection that started and ended, so we'll call down to finishWithError: + NSInteger status = responseError ? responseError.code : 200; + if (status >= 200 && status <= 399) { + [self finishWithError:nil shouldRetry:NO]; + } else { + [self shouldRetryNowForStatus:status + error:responseError + forceAssumeRetry:NO + response:^(BOOL shouldRetry) { + [self finishWithError:responseError shouldRetry:shouldRetry]; + }]; + } + }]; +} + +- (void)simulateByteTransferWithData:(NSData *)responseData + block:(GTMSessionFetcherSimulateByteTransferBlock)transferBlock { + // This utility method simulates transfering data to the client. It divides the data into at most + // "chunkCount" chunks and then passes each chunk along with a progress update to transferBlock. + // This function can be used with accumulateDataBlock or receivedProgressBlock. + + NSUInteger chunkCount = MAX(self.testBlockAccumulateDataChunkCount, (NSUInteger)1); + NSUInteger totalDataLength = responseData.length; + NSUInteger sendDataSize = totalDataLength / chunkCount + 1; + NSUInteger totalSent = 0; + while (totalSent < totalDataLength) { + NSUInteger bytesRemaining = totalDataLength - totalSent; + sendDataSize = MIN(sendDataSize, bytesRemaining); + NSData *chunkData = [responseData subdataWithRange:NSMakeRange(totalSent, sendDataSize)]; + totalSent += sendDataSize; + [self invokeOnCallbackQueueUnlessStopped:^{ + transferBlock(chunkData, (int64_t)sendDataSize, (int64_t)totalSent, (int64_t)totalDataLength); + }]; + } +} + +#endif // !GTM_DISABLE_FETCHER_TEST_BLOCK + +- (void)setSessionTask:(NSURLSessionTask *)sessionTask { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_sessionTask != sessionTask) { + _sessionTask = sessionTask; + if (_sessionTask) { + // Request could be nil on restoring this fetcher from a background session. + if (!_request) { + _request = [_sessionTask.originalRequest mutableCopy]; + } + } + } + } // @synchronized(self) +} + +- (nullable NSURLSessionTask *)sessionTask { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _sessionTask; + } // @synchronized(self) +} + ++ (NSUserDefaults *)fetcherUserDefaults { + static NSUserDefaults *gFetcherUserDefaults = nil; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + Class fetcherUserDefaultsClass = NSClassFromString(@"GTMSessionFetcherUserDefaultsFactory"); + if (fetcherUserDefaultsClass) { + gFetcherUserDefaults = [fetcherUserDefaultsClass fetcherUserDefaults]; + } else { + gFetcherUserDefaults = [NSUserDefaults standardUserDefaults]; + } + }); + return gFetcherUserDefaults; +} + +- (void)addPersistedBackgroundSessionToDefaults { + NSString *sessionIdentifier = self.sessionIdentifier; + if (!sessionIdentifier) { + return; + } + NSArray *oldBackgroundSessions = [[self class] activePersistedBackgroundSessions]; + if ([oldBackgroundSessions containsObject:_sessionIdentifier]) { + return; + } + NSMutableArray *newBackgroundSessions = [NSMutableArray arrayWithArray:oldBackgroundSessions]; + [newBackgroundSessions addObject:sessionIdentifier]; + GTM_LOG_BACKGROUND_SESSION(@"Add to background sessions: %@", newBackgroundSessions); + + NSUserDefaults *userDefaults = [[self class] fetcherUserDefaults]; + [userDefaults setObject:newBackgroundSessions forKey:kGTMSessionFetcherPersistedDestinationKey]; + [userDefaults synchronize]; +} + +- (void)removePersistedBackgroundSessionFromDefaults { + NSString *sessionIdentifier = self.sessionIdentifier; + if (!sessionIdentifier) return; + + NSArray *oldBackgroundSessions = [[self class] activePersistedBackgroundSessions]; + if (!oldBackgroundSessions) { + return; + } + NSMutableArray *newBackgroundSessions = [NSMutableArray arrayWithArray:oldBackgroundSessions]; + NSUInteger sessionIndex = [newBackgroundSessions indexOfObject:sessionIdentifier]; + if (sessionIndex == NSNotFound) { + return; + } + [newBackgroundSessions removeObjectAtIndex:sessionIndex]; + GTM_LOG_BACKGROUND_SESSION(@"Remove from background sessions: %@", newBackgroundSessions); + + NSUserDefaults *userDefaults = [[self class] fetcherUserDefaults]; + if (newBackgroundSessions.count == 0) { + [userDefaults removeObjectForKey:kGTMSessionFetcherPersistedDestinationKey]; + } else { + [userDefaults setObject:newBackgroundSessions forKey:kGTMSessionFetcherPersistedDestinationKey]; + } + [userDefaults synchronize]; +} + ++ (nullable NSArray *)activePersistedBackgroundSessions { + NSUserDefaults *userDefaults = [[self class] fetcherUserDefaults]; + NSArray *oldBackgroundSessions = + [userDefaults arrayForKey:kGTMSessionFetcherPersistedDestinationKey]; + if (oldBackgroundSessions.count == 0) { + return nil; + } + NSMutableArray *activeBackgroundSessions = nil; + NSMapTable *sessionIdentifierToFetcherMap = [self sessionIdentifierToFetcherMap]; + for (NSString *sessionIdentifier in oldBackgroundSessions) { + GTMSessionFetcher *fetcher = [sessionIdentifierToFetcherMap objectForKey:sessionIdentifier]; + if (fetcher) { + if (!activeBackgroundSessions) { + activeBackgroundSessions = [[NSMutableArray alloc] init]; + } + [activeBackgroundSessions addObject:sessionIdentifier]; + } + } + return activeBackgroundSessions; +} + ++ (NSArray *)fetchersForBackgroundSessions { + NSUserDefaults *userDefaults = [[self class] fetcherUserDefaults]; + NSArray *backgroundSessions = + [userDefaults arrayForKey:kGTMSessionFetcherPersistedDestinationKey]; + NSMapTable *sessionIdentifierToFetcherMap = [self sessionIdentifierToFetcherMap]; + NSMutableArray *fetchers = [NSMutableArray array]; + for (NSString *sessionIdentifier in backgroundSessions) { + GTMSessionFetcher *fetcher = [sessionIdentifierToFetcherMap objectForKey:sessionIdentifier]; + if (!fetcher) { + fetcher = [self fetcherWithSessionIdentifier:sessionIdentifier]; + GTMSESSION_ASSERT_DEBUG(fetcher != nil, @"Unexpected invalid session identifier: %@", + sessionIdentifier); + if (!fetcher.clientWillReconnectBackgroundSession) { + [fetcher beginFetchWithCompletionHandler:nil]; + } + } + GTM_LOG_BACKGROUND_SESSION(@"%@ restoring session %@ by creating fetcher %@ %p", [self class], + sessionIdentifier, fetcher, fetcher); + if (fetcher != nil) { + [fetchers addObject:fetcher]; + } + } + return fetchers; +} + +#if TARGET_OS_IPHONE && !TARGET_OS_WATCH ++ (void)application:(UIApplication *)application + handleEventsForBackgroundURLSession:(NSString *)identifier + completionHandler:(GTMSessionFetcherSystemCompletionHandler)completionHandler + GTM_SWIFT_DISABLE_ASYNC { + GTMSessionFetcher *fetcher = [self fetcherWithSessionIdentifier:identifier]; + if (fetcher != nil) { + fetcher.systemCompletionHandler = completionHandler; + } else { + GTM_LOG_BACKGROUND_SESSION(@"%@ did not create background session identifier: %@", [self class], + identifier); + } +} +#endif + +- (nullable NSString *)sessionIdentifier { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _sessionIdentifier; + } // @synchronized(self) +} + +- (void)setSessionIdentifier:(NSString *)sessionIdentifier { + GTMSESSION_ASSERT_DEBUG(sessionIdentifier != nil, @"Invalid session identifier"); + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + GTMSESSION_ASSERT_DEBUG(!_session, @"Unable to set session identifier after session created"); + _sessionIdentifier = [sessionIdentifier copy]; + _usingBackgroundSession = YES; + _canShareSession = NO; + [self restoreDefaultStateForSessionIdentifierMetadata]; + } // @synchronized(self) +} + +- (void)setSessionIdentifierInternal:(nullable NSString *)sessionIdentifier { + // This internal method only does a synchronized set of the session identifier. + // It does not have side effects on the background session, shared session, or + // session identifier metadata. + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _sessionIdentifier = [sessionIdentifier copy]; + } // @synchronized(self) +} + +- (nullable NSDictionary *)sessionUserInfo { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_sessionUserInfo == nil) { + // We'll return the metadata dictionary with internal keys removed. This avoids the user + // re-using the userInfo dictionary later and accidentally including the internal keys. + NSMutableDictionary *metadata = [[self sessionIdentifierMetadataUnsynchronized] mutableCopy]; + NSSet *keysToRemove = [metadata keysOfEntriesPassingTest:^BOOL(id key, id obj, BOOL *stop) { + return [key hasPrefix:@"_"]; + }]; + [metadata removeObjectsForKeys:[keysToRemove allObjects]]; + if (metadata.count > 0) { + _sessionUserInfo = metadata; + } + } + return _sessionUserInfo; + } // @synchronized(self) +} + +- (void)setSessionUserInfo:(nullable NSDictionary *)dictionary { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + GTMSESSION_ASSERT_DEBUG(_sessionIdentifier == nil, @"Too late to assign userInfo"); + _sessionUserInfo = dictionary; + } // @synchronized(self) +} + +- (nullable NSDictionary *)sessionIdentifierDefaultMetadata { + GTMSessionCheckSynchronized(self); + + NSMutableDictionary *defaultUserInfo = [[NSMutableDictionary alloc] init]; + if (_destinationFileURL) { + defaultUserInfo[kGTMSessionIdentifierDestinationFileURLMetadataKey] = + [_destinationFileURL absoluteString]; + } + if (_bodyFileURL) { + defaultUserInfo[kGTMSessionIdentifierBodyFileURLMetadataKey] = [_bodyFileURL absoluteString]; + } + if (_clientWillReconnectBackgroundSession) { + defaultUserInfo[kGTMSessionIdentifierClientReconnectMetadataKey] = @"YES"; + } + return (defaultUserInfo.count > 0) ? defaultUserInfo : nil; +} + +- (void)restoreDefaultStateForSessionIdentifierMetadata { + GTMSessionCheckSynchronized(self); + + NSDictionary *metadata = [self sessionIdentifierMetadataUnsynchronized]; + NSString *destinationFileURLString = metadata[kGTMSessionIdentifierDestinationFileURLMetadataKey]; + if (destinationFileURLString) { + _destinationFileURL = [NSURL URLWithString:destinationFileURLString]; + GTM_LOG_BACKGROUND_SESSION(@"Restoring destination file URL: %@", _destinationFileURL); + } + NSString *bodyFileURLString = metadata[kGTMSessionIdentifierBodyFileURLMetadataKey]; + if (bodyFileURLString) { + _bodyFileURL = [NSURL URLWithString:bodyFileURLString]; + GTM_LOG_BACKGROUND_SESSION(@"Restoring body file URL: %@", _bodyFileURL); + } + NSString *clientReconnectString = metadata[kGTMSessionIdentifierClientReconnectMetadataKey]; + if (clientReconnectString) { + _clientWillReconnectBackgroundSession = [clientReconnectString boolValue]; + GTM_LOG_BACKGROUND_SESSION(@"Restoring clientWillReconnectBackgroundSession: %@", + (_clientWillReconnectBackgroundSession ? @"YES" : @"NO")); + } +} + +- (nullable NSDictionary *)sessionIdentifierMetadata { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [self sessionIdentifierMetadataUnsynchronized]; + } +} + +- (nullable NSDictionary *)sessionIdentifierMetadataUnsynchronized { + GTMSessionCheckSynchronized(self); + + // Session Identifier format: "com.google.__ + if (!_sessionIdentifier) { + return nil; + } + NSScanner *metadataScanner = [NSScanner scannerWithString:_sessionIdentifier]; + [metadataScanner setCharactersToBeSkipped:nil]; + NSString *metadataString; + NSString *uuid; + if ([metadataScanner scanUpToString:@"_" intoString:NULL] && + [metadataScanner scanString:@"_" intoString:NULL] && + [metadataScanner scanUpToString:@"_" intoString:&uuid] && + [metadataScanner scanString:@"_" intoString:NULL] && + [metadataScanner scanUpToString:@"\n" intoString:&metadataString]) { + _sessionIdentifierUUID = uuid; + NSData *metadataData = [metadataString dataUsingEncoding:NSUTF8StringEncoding]; + NSError *error; + NSDictionary *metadataDict = [NSJSONSerialization JSONObjectWithData:metadataData + options:0 + error:&error]; + GTM_LOG_BACKGROUND_SESSION(@"User Info from session identifier: %@ %@", metadataDict, + error ? error : @""); + return metadataDict; + } + return nil; +} + +- (NSString *)createSessionIdentifierWithMetadata:(nullable NSDictionary *)metadataToInclude { + NSString *result; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // Session Identifier format: "com.google.__ + GTMSESSION_ASSERT_DEBUG(!_sessionIdentifier, @"Session identifier already created"); + _sessionIdentifierUUID = [[NSUUID UUID] UUIDString]; + _sessionIdentifier = + [NSString stringWithFormat:@"%@_%@", kGTMSessionIdentifierPrefix, _sessionIdentifierUUID]; + // Start with user-supplied keys so they cannot accidentally override the fetcher's keys. + NSMutableDictionary *metadataDict = + [NSMutableDictionary dictionaryWithDictionary:(NSDictionary *_Nonnull)_sessionUserInfo]; + + if (metadataToInclude) { + [metadataDict addEntriesFromDictionary:(NSDictionary *)metadataToInclude]; + } + NSDictionary *defaultMetadataDict = [self sessionIdentifierDefaultMetadata]; + if (defaultMetadataDict) { + [metadataDict addEntriesFromDictionary:defaultMetadataDict]; + } + if (metadataDict.count > 0) { + NSData *metadataData = [NSJSONSerialization dataWithJSONObject:metadataDict + options:0 + error:NULL]; + GTMSESSION_ASSERT_DEBUG(metadataData != nil, + @"Session identifier user info failed to convert to JSON"); + if (metadataData.length > 0) { + NSString *metadataString = [[NSString alloc] initWithData:metadataData + encoding:NSUTF8StringEncoding]; + _sessionIdentifier = [_sessionIdentifier stringByAppendingFormat:@"_%@", metadataString]; + } + } + _didCreateSessionIdentifier = YES; + result = _sessionIdentifier; + } // @synchronized(self) + return result; +} + +- (void)failToBeginFetchWithError:(NSError *)error { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _hasStoppedFetching = YES; + } + + if (error == nil) { + error = [NSError errorWithDomain:kGTMSessionFetcherErrorDomain + code:GTMSessionFetcherErrorDownloadFailed + userInfo:nil]; + } + + [self invokeFetchCallbacksOnCallbackQueueWithData:nil + error:error + mayDecorate:YES + shouldReleaseCallbacks:YES]; + + [_service fetcherDidStop:self]; + + self.authorizer = nil; +} + ++ (GTMSessionCookieStorage *)staticCookieStorage { + static GTMSessionCookieStorage *gCookieStorage = nil; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + gCookieStorage = [[GTMSessionCookieStorage alloc] init]; + }); + return gCookieStorage; +} + +#if GTM_BACKGROUND_TASK_FETCHING + +- (void)endBackgroundTask { + // Whenever the connection stops or background execution expires, + // we need to tell UIApplication we're done. + UIBackgroundTaskIdentifier bgTaskID; + @synchronized(self) { + bgTaskID = self.backgroundTaskIdentifier; + if (bgTaskID != UIBackgroundTaskInvalid) { + self.backgroundTaskIdentifier = UIBackgroundTaskInvalid; + } + } + + if (bgTaskID != UIBackgroundTaskInvalid) { + id app = [[self class] fetcherUIApplication]; + [app endBackgroundTask:bgTaskID]; + } +} + +#endif // GTM_BACKGROUND_TASK_FETCHING + +- (void)authorizeRequest { + GTMSessionCheckNotSynchronized(self); + + id authorizer = self.authorizer; + // Prefer the block-based implementation. This *is* a change in behavior, but if authorizers + // previously provided this method they would presumably assume they can be used for the same + // requests as before. + if ([authorizer respondsToSelector:@selector(authorizeRequest:completionHandler:)]) { + // It's unknown how long an authorizer maintains ownership of the provided block, so + // avoid potential retain cycles on self and the authorizer. + __weak __typeof__(self) weakSelf = self; + NSMutableURLRequest *mutableRequest = [self.request mutableCopy]; + [authorizer authorizeRequest:mutableRequest + completionHandler:^(NSError *_Nullable error) { + [weakSelf authorizer:nil request:mutableRequest finishedWithError:error]; + }]; + } else if ([authorizer respondsToSelector:@selector(authorizeRequest: + delegate:didFinishSelector:)]) { + SEL callbackSel = @selector(authorizer:request:finishedWithError:); + NSMutableURLRequest *mutableRequest = [self.request mutableCopy]; + [authorizer authorizeRequest:mutableRequest delegate:self didFinishSelector:callbackSel]; + } else { + GTMSESSION_ASSERT_DEBUG(authorizer == nil, @"invalid authorizer for fetch"); + + // No authorizing possible, and authorizing happens only after any delay; + // just begin fetching + [self beginFetchMayDelay:NO mayAuthorize:NO mayDecorate:YES]; + } +} + +// The authorizer parameter is unused, and the block-based callback will never pass +// non-nil; the field is only for the deprecated selector-based implementation for +// legacy reasons. +- (void)authorizer:(nullable id __unused)auth + request:(nullable NSMutableURLRequest *)authorizedRequest + finishedWithError:(nullable NSError *)error { + GTMSessionCheckNotSynchronized(self); + + if (error != nil) { + // We can't fetch without authorization + [self failToBeginFetchWithError:(NSError *_Nonnull)error]; + } else { + @synchronized(self) { + _request = authorizedRequest; + } + [self beginFetchMayDelay:NO mayAuthorize:NO mayDecorate:YES]; + } +} + +- (void)applyDecoratorsAtRequestWillStart:(NSArray> *)decorators + startingAtIndex:(NSUInteger)index { + GTMSessionCheckNotSynchronized(self); + if (index >= decorators.count) { + GTMSESSION_LOG_DEBUG_VERBOSE( + @"GTMSessionFetcher decorate requestWillStart %zu decorators complete", decorators.count); + [self beginFetchMayDelay:NO mayAuthorize:NO mayDecorate:NO]; + return; + } + + __weak __typeof__(self) weakSelf = self; + id decorator = decorators[index]; + GTMSESSION_LOG_DEBUG_VERBOSE( + @"GTMSessionFetcher decorate requestWillStart %zu decorators, index %zu, " + @"retry count %zu, decorator %@", + decorators.count, index, self.retryCount, decorator); + [decorator fetcherWillStart:self + completionHandler:^(NSURLRequest *_Nullable newRequest, NSError *_Nullable error) { + GTMSESSION_LOG_DEBUG_VERBOSE( + @"GTMSessionFetcher decorator requestWillStart index %zu " + @"complete, newRequest %@, error %@", + index, newRequest, error); + __strong __typeof__(self) strongSelf = weakSelf; + if (!strongSelf) { + GTMSESSION_LOG_DEBUG(@"GTMSessionFetcher destroyed before requestWillStart " + @"decorators completed, ignoring."); + return; + } + if (error) { + [self failToBeginFetchWithError:(NSError *_Nonnull)error]; + return; + } + if (newRequest) { + // Copying `NSURLRequest` should be cheap, but in case profiling shows this + // operation is prohibitively expensive, this API might need to be changed to allow + // clients to manipulate `self.request` directly. + [strongSelf updateMutableRequest:[newRequest mutableCopy]]; + } + [strongSelf applyDecoratorsAtRequestWillStart:decorators startingAtIndex:index + 1]; + }]; +} + +- (void)applyDecoratorsAtRequestDidFinish:(NSArray> *)decorators + withData:(nullable NSData *)data + error:(nullable NSError *)error + startingAtIndex:(NSUInteger)index + shouldReleaseCallbacks:(BOOL)shouldReleaseCallbacks { + GTMSessionCheckNotSynchronized(self); + if (index >= decorators.count) { + GTMSESSION_LOG_DEBUG_VERBOSE( + @"GTMSessionFetcher decorate requestDidFinish %zu decorators complete", decorators.count); + [self invokeFetchCallbacksOnCallbackQueueWithData:data + error:error + mayDecorate:NO + shouldReleaseCallbacks:shouldReleaseCallbacks]; + return; + } + + __weak __typeof__(self) weakSelf = self; + id decorator = decorators[index]; + GTMSESSION_LOG_DEBUG_VERBOSE( + @"GTMSessionFetcher decorate requestDidFinish %zu decorators, index %zu, " + @"retry count %zu, decorator %@", + decorators.count, index, self.retryCount, decorator); + [decorator fetcherDidFinish:self + withData:data + error:error + completionHandler:^{ + GTMSESSION_LOG_DEBUG_VERBOSE( + @"GTMSessionFetcher decorator requestDidFinish index %zu complete", index); + __strong __typeof__(self) strongSelf = weakSelf; + if (!strongSelf) { + GTMSESSION_LOG_DEBUG(@"GTMSessionFetcher destroyed before requestDidFinish " + @"decorators completed, ignoring."); + return; + } + [strongSelf applyDecoratorsAtRequestDidFinish:decorators + withData:data + error:error + startingAtIndex:index + 1 + shouldReleaseCallbacks:shouldReleaseCallbacks]; + }]; +} + +- (BOOL)canFetchWithBackgroundSession { + // Subclasses may override. + return YES; +} + +// Returns YES if the fetcher has been started and has not yet stopped. +// +// Fetching includes waiting for authorization or for retry, waiting to be allowed by the +// service object to start the request, and actually fetching the request. +- (BOOL)isFetching { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [self isFetchingUnsynchronized]; + } +} + +- (BOOL)isFetchingUnsynchronized { + GTMSessionCheckSynchronized(self); + + BOOL hasBegun = (_initialBeginFetchDate != nil); + return hasBegun && !_hasStoppedFetching; +} + +- (nullable NSURLResponse *)response { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSURLResponse *response = [self responseUnsynchronized]; + return response; + } // @synchronized(self) +} + +- (nullable NSURLResponse *)responseUnsynchronized { + GTMSessionCheckSynchronized(self); + + NSURLResponse *response = _sessionTask.response; + if (!response) response = _response; + return response; +} + +- (NSInteger)statusCode { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSInteger statusCode = [self statusCodeUnsynchronized]; + return statusCode; + } // @synchronized(self) +} + +- (NSInteger)statusCodeUnsynchronized { + GTMSessionCheckSynchronized(self); + + NSURLResponse *response = [self responseUnsynchronized]; + NSInteger statusCode; + + if ([response respondsToSelector:@selector(statusCode)]) { + statusCode = [(NSHTTPURLResponse *)response statusCode]; + } else { + // Default to zero, in hopes of hinting "Unknown" (we can't be + // sure that things are OK enough to use 200). + statusCode = 0; + } + return statusCode; +} + +- (nullable NSDictionary *)responseHeaders { + GTMSessionCheckNotSynchronized(self); + + NSURLResponse *response = self.response; + if ([response respondsToSelector:@selector(allHeaderFields)]) { + NSDictionary *headers = [(NSHTTPURLResponse *)response allHeaderFields]; + return headers; + } + return nil; +} + +- (nullable NSDictionary *)responseHeadersUnsynchronized { + GTMSessionCheckSynchronized(self); + + NSURLResponse *response = [self responseUnsynchronized]; + if ([response respondsToSelector:@selector(allHeaderFields)]) { + NSDictionary *headers = [(NSHTTPURLResponse *)response allHeaderFields]; + return headers; + } + return nil; +} + +- (void)releaseCallbacks { + // The clang included with Xcode 13.3 betas added a -Wunused-but-set-variable warning, + // which doesn't (yet) skip variables annotated with objc_precie_lifetime. Since that + // warning is not available in all Xcodes, turn off the -Wunused warning group entirely. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused" + // Avoid releasing blocks in the sync section since objects dealloc'd by + // the blocks being released may call back into the fetcher or fetcher + // service. + dispatch_queue_t NS_VALID_UNTIL_END_OF_SCOPE holdCallbackQueue; + GTMSessionFetcherCompletionHandler NS_VALID_UNTIL_END_OF_SCOPE holdCompletionHandler; +#pragma clang diagnostic pop + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + holdCallbackQueue = _callbackQueue; + holdCompletionHandler = _completionHandler; + + _callbackQueue = nil; + _completionHandler = nil; // Setter overridden in upload. Setter assumed to be used externally. + } + + // Set local callback pointers to nil here rather than let them release at the end of the scope + // to make any problems due to the blocks being released be a bit more obvious in a stack trace. + holdCallbackQueue = nil; + holdCompletionHandler = nil; + + self.configurationBlock = nil; + self.didReceiveResponseBlock = nil; + self.challengeBlock = nil; + self.willRedirectBlock = nil; + self.sendProgressBlock = nil; + self.receivedProgressBlock = nil; + self.downloadProgressBlock = nil; + self.accumulateDataBlock = nil; + self.willCacheURLResponseBlock = nil; + self.retryBlock = nil; + self.testBlock = nil; + self.resumeDataBlock = nil; + if (@available(iOS 10.0, *)) { + self.metricsCollectionBlock = nil; + } +} + +- (void)forgetSessionIdentifierForFetcher { + GTMSessionCheckSynchronized(self); + [self forgetSessionIdentifierForFetcherWithoutSyncCheck]; +} + +- (void)forgetSessionIdentifierForFetcherWithoutSyncCheck { + // This should be called inside a @synchronized block (except during dealloc.) + if (_sessionIdentifier) { + NSMapTable *sessionIdentifierToFetcherMap = [[self class] sessionIdentifierToFetcherMap]; + [sessionIdentifierToFetcherMap removeObjectForKey:_sessionIdentifier]; + _sessionIdentifier = nil; + _didCreateSessionIdentifier = NO; + } +} + +// External stop method +- (void)stopFetching { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // Prevent enqueued callbacks from executing. The completion handler will still execute if + // the property `stopFetchingTriggersCompletionHandler` is `YES`. + _userStoppedFetching = YES; + } // @synchronized(self) + [self stopFetchReleasingCallbacks:!self.stopFetchingTriggersCompletionHandler]; +} + +// Cancel the fetch of the URL that's currently in progress. +// +// If shouldReleaseCallbacks is NO then the fetch will be retried so the callbacks need +// still be retained or `stopFetching` was called and `stopFetchingTriggersCompletionHandler` is +// `YES`. +- (void)stopFetchReleasingCallbacks:(BOOL)shouldReleaseCallbacks { + [self removePersistedBackgroundSessionFromDefaults]; + + GTMSessionFetcherService *service; + NSMutableURLRequest *request; + + // If the task or the retry timer is all that's retaining the fetcher, + // we want to be sure this instance survives stopping at least long enough for + // the stack to unwind. + __autoreleasing GTMSessionFetcher *holdSelf = self; + + BOOL hasCanceledTask = NO; + + [holdSelf destroyRetryTimer]; + + BOOL sendStopNotification = YES; + BOOL callbacksPending = NO; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _hasStoppedFetching = YES; + + service = _service; + request = _request; + + if (_sessionTask) { + // In case cancelling the task or session calls this recursively, we want + // to ensure that we'll only release the task and delegate once, + // so first set _sessionTask to nil + // + // This may be called in a callback from the task, so use autorelease to avoid + // releasing the task in its own callback. + __autoreleasing NSURLSessionTask *oldTask = _sessionTask; + if (!_isUsingTestBlock) { + _response = _sessionTask.response; + } + _sessionTask = nil; + + if ([oldTask state] != NSURLSessionTaskStateCompleted) { + // For download tasks, when the fetch is stopped, we may provide resume data that can + // be used to create a new session. + BOOL mayResume = (_resumeDataBlock && + [oldTask respondsToSelector:@selector(cancelByProducingResumeData:)]); + if (!mayResume) { + [oldTask cancel]; + // A side effect of stopping the task is that URLSession:task:didCompleteWithError: + // will be invoked asynchronously on the delegate queue. + } else { + void (^resumeBlock)(NSData *) = _resumeDataBlock; + _resumeDataBlock = nil; + + // Save callbackQueue since releaseCallbacks clears it. + dispatch_queue_t callbackQueue = _callbackQueue; + dispatch_group_enter(_callbackGroup); + [(NSURLSessionDownloadTask *)oldTask cancelByProducingResumeData:^(NSData *resumeData) { + [self invokeOnCallbackQueue:callbackQueue + afterUserStopped:YES + block:^{ + resumeBlock(resumeData); + dispatch_group_leave(self->_callbackGroup); + }]; + }]; + } + hasCanceledTask = YES; + } + } + + // If the task was canceled, wait until the URLSession:task:didCompleteWithError: to call + // finishTasksAndInvalidate, since calling it immediately tends to crash, see radar 18471901. + if (_session) { + BOOL shouldInvalidate = _shouldInvalidateSession; +#if TARGET_OS_IPHONE + // Don't invalidate if we've got a systemCompletionHandler, since + // URLSessionDidFinishEventsForBackgroundURLSession: won't be called if invalidated. + shouldInvalidate = shouldInvalidate && !self.systemCompletionHandler; +#endif + if (shouldInvalidate) { + __autoreleasing NSURLSession *oldSession = _session; + _session = nil; + + if (!hasCanceledTask) { + [oldSession finishTasksAndInvalidate]; + } else { + sendStopNotification = NO; + _sessionNeedingInvalidation = oldSession; + } + } + } + callbacksPending = _stopFetchingTriggersCompletionHandler && _userStoppedFetching; + } // @synchronized(self) + + // If the NSURLSession needs to be invalidated, but needs to wait until the delegate method + // URLSession:task:didCompleteWithError: is called, delay sending the fetch stopped notification + // until then; otherwise send it now. + if (sendStopNotification) { + [self sendStopNotificationIfNeeded]; + } + + [_authorizer stopAuthorizationForRequest:request]; + + if (shouldReleaseCallbacks) { + [self releaseCallbacks]; + + self.authorizer = nil; + } + + [service fetcherDidStop:self callbacksPending:callbacksPending]; + +#if GTM_BACKGROUND_TASK_FETCHING + [self endBackgroundTask]; +#endif +} + +- (void)setStopNotificationNeeded:(BOOL)flag { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _isStopNotificationNeeded = flag; + } // @synchronized(self) +} + +- (void)sendStopNotificationIfNeeded { + BOOL sendNow = NO; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_isStopNotificationNeeded) { + _isStopNotificationNeeded = NO; + sendNow = YES; + } + } // @synchronized(self) + + if (sendNow) { + [self postNotificationOnMainThreadWithName:kGTMSessionFetcherStoppedNotification + userInfo:nil + requireAsync:NO]; + } +} + +- (void)retryFetch { + [self stopFetchReleasingCallbacks:NO]; + + // A retry will need a configuration with a fresh session identifier. + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_sessionIdentifier && _didCreateSessionIdentifier) { + [self forgetSessionIdentifierForFetcher]; + _configuration = nil; + } + + if (_canShareSession) { + // Force a grab of the current session from the fetcher service in case + // the service's old one has become invalid. + _session = nil; + } + } // @synchronized(self) + + [self beginFetchForRetry]; +} + +- (BOOL)waitForCompletionWithTimeout:(NSTimeInterval)timeoutInSeconds { + // Uncovered in upload fetcher testing, because the chunk fetcher is being waited on, and gets + // released by the upload code. The uploader just holds onto it with an ivar, and that gets + // nilled in the chunk fetcher callback. + // Used once in while loop just to avoid unused variable compiler warning. + __autoreleasing GTMSessionFetcher *holdSelf = self; + + NSDate *giveUpDate = [NSDate dateWithTimeIntervalSinceNow:timeoutInSeconds]; + + BOOL shouldSpinRunLoop = + ([NSThread isMainThread] && + (!self.callbackQueue || self.callbackQueue == dispatch_get_main_queue())); + BOOL expired = NO; + + // Loop until the callbacks have been called and released, and until + // the connection is no longer pending, until there are no callback dispatches + // in flight, or until the timeout has expired. + int64_t delta = (int64_t)(100 * NSEC_PER_MSEC); // 100 ms + while (1) { + BOOL isTaskInProgress = + (holdSelf->_sessionTask && [_sessionTask state] != NSURLSessionTaskStateCompleted); + BOOL needsToCallCompletion = (_completionHandler != nil); + BOOL isCallbackInProgress = + (_callbackGroup && + dispatch_group_wait(_callbackGroup, dispatch_time(DISPATCH_TIME_NOW, delta))); + + if (!isTaskInProgress && !needsToCallCompletion && !isCallbackInProgress) break; + + expired = ([giveUpDate timeIntervalSinceNow] < 0); + if (expired) { + GTMSESSION_LOG_DEBUG(@"GTMSessionFetcher waitForCompletionWithTimeout:%0.1f expired -- " + @"%@%@%@", + timeoutInSeconds, isTaskInProgress ? @"taskInProgress " : @"", + needsToCallCompletion ? @"needsToCallCompletion " : @"", + isCallbackInProgress ? @"isCallbackInProgress" : @""); + break; + } + + // Run the current run loop 1/1000 of a second to give the networking + // code a chance to work + const NSTimeInterval kSpinInterval = 0.001; + if (shouldSpinRunLoop) { + NSDate *stopDate = [NSDate dateWithTimeIntervalSinceNow:kSpinInterval]; + [[NSRunLoop currentRunLoop] runUntilDate:stopDate]; + } else { + [NSThread sleepForTimeInterval:kSpinInterval]; + } + } + return !expired; +} + ++ (void)setGlobalTestBlock:(nullable GTMSessionFetcherTestBlock)block { +#if GTM_DISABLE_FETCHER_TEST_BLOCK + GTMSESSION_ASSERT_DEBUG(block == nil, @"test blocks disabled"); +#endif + gGlobalTestBlock = [block copy]; +} + +#if GTM_BACKGROUND_TASK_FETCHING + +static _Nullable id gSubstituteUIApp; + ++ (void)setSubstituteUIApplication:(nullable id)app { + gSubstituteUIApp = app; +} + ++ (nullable id)substituteUIApplication { + return gSubstituteUIApp; +} + ++ (nullable id)fetcherUIApplication { + id app = gSubstituteUIApp; + if (app) return app; + + // iOS App extensions should not call [UIApplication sharedApplication], even + // if UIApplication responds to it. + + static Class applicationClass = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + BOOL isAppExtension = [[[NSBundle mainBundle] bundlePath] hasSuffix:@".appex"]; + if (!isAppExtension) { + Class cls = NSClassFromString(@"UIApplication"); + if (cls && [cls respondsToSelector:NSSelectorFromString(@"sharedApplication")]) { + applicationClass = cls; + } + } + }); + + if (applicationClass) { + app = (id)[applicationClass sharedApplication]; + } + return app; +} +#endif // GTM_BACKGROUND_TASK_FETCHING + +#pragma mark NSURLSession Delegate Methods + +// NSURLSession documentation indicates that redirectRequest can be passed to the handler +// but empirically redirectRequest lacks the HTTP body, so passing it will break POSTs. +// Instead, we construct a new request, a copy of the original, with overrides from the +// redirect. + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + willPerformHTTPRedirection:(NSHTTPURLResponse *)redirectResponse + newRequest:(NSURLRequest *)redirectRequest + completionHandler:(void (^)(NSURLRequest *_Nullable))handler { + [self setSessionTask:task]; + GTMSESSION_LOG_DEBUG_VERBOSE( + @"%@ %p URLSession:%@ task:%@ willPerformHTTPRedirection:%@ newRequest:%@", [self class], + self, session, task, redirectResponse, redirectRequest); + + if ([self userStoppedFetching]) { + handler(nil); + return; + } + if (redirectRequest && redirectResponse) { + // Copy the original request, including the body. + NSURLRequest *originalRequest = self.request; + NSMutableURLRequest *newRequest = [originalRequest mutableCopy]; + + // The new requests's URL overrides the original's URL. + [newRequest setURL:[GTMSessionFetcher redirectURLWithOriginalRequestURL:originalRequest.URL + redirectRequestURL:redirectRequest.URL]]; + + // Any headers in the redirect override headers in the original. + NSDictionary *redirectHeaders = redirectRequest.allHTTPHeaderFields; + for (NSString *key in redirectHeaders) { + NSString *value = [redirectHeaders objectForKey:key]; + [newRequest setValue:value forHTTPHeaderField:key]; + } + + redirectRequest = newRequest; + + // Log the response we just received + [self setResponse:redirectResponse]; + [self logNowWithError:nil]; + + GTMSessionFetcherWillRedirectBlock willRedirectBlock = self.willRedirectBlock; + if (willRedirectBlock) { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + __auto_type block = ^{ + willRedirectBlock(redirectResponse, redirectRequest, ^(NSURLRequest *clientRequest) { + // Update the request for future logging. + [self updateMutableRequest:[clientRequest mutableCopy]]; + + handler(clientRequest); + }); + }; + [self invokeOnCallbackQueueAfterUserStopped:YES block:block]; + } // @synchronized(self) + return; + } + // Continues here if the client did not provide a redirect block. + + // Update the request for future logging. + [self updateMutableRequest:[redirectRequest mutableCopy]]; + } + handler(redirectRequest); +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + didReceiveResponse:(NSURLResponse *)response + completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))handler { + [self setSessionTask:dataTask]; + GTMSESSION_LOG_DEBUG_VERBOSE(@"%@ %p URLSession:%@ dataTask:%@ didReceiveResponse:%@", + [self class], self, session, dataTask, response); + __auto_type accumulateAndFinish = ^(NSURLSessionResponseDisposition dispositionValue) { + // This method is called when the server has determined that it + // has enough information to create the NSURLResponse + // it can be called multiple times, for example in the case of a + // redirect, so each time we reset the data. + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + BOOL hadPreviousData = self->_downloadedLength > 0; + + [self->_downloadedData setLength:0]; + self->_downloadedLength = 0; + + if (hadPreviousData && (dispositionValue != NSURLSessionResponseCancel)) { + // Tell the accumulate block to discard prior data. + GTMSessionFetcherAccumulateDataBlock accumulateBlock = self->_accumulateDataBlock; + if (accumulateBlock) { + [self invokeOnCallbackQueueUnlessStopped:^{ + accumulateBlock(nil); + }]; + } + } + } // @synchronized(self) + handler(dispositionValue); + }; + + GTMSessionFetcherDidReceiveResponseBlock receivedResponseBlock; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + receivedResponseBlock = _didReceiveResponseBlock; + if (receivedResponseBlock) { + // We will ultimately need to call back to NSURLSession's handler with the disposition value + // for this delegate method even if the user has stopped the fetcher. + __auto_type block = ^{ + receivedResponseBlock(response, ^(NSURLSessionResponseDisposition desiredDisposition) { + accumulateAndFinish(desiredDisposition); + }); + }; + [self invokeOnCallbackQueueAfterUserStopped:YES block:block]; + } + } // @synchronized(self) + + if (receivedResponseBlock == nil) { + accumulateAndFinish(NSURLSessionResponseAllow); + } +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask { + GTMSESSION_LOG_DEBUG_VERBOSE(@"%@ %p URLSession:%@ dataTask:%@ didBecomeDownloadTask:%@", + [self class], self, session, dataTask, downloadTask); + [self setSessionTask:downloadTask]; +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge + completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, + NSURLCredential *_Nullable credential))handler { + [self setSessionTask:task]; + GTMSESSION_LOG_DEBUG_VERBOSE(@"%@ %p URLSession:%@ task:%@ didReceiveChallenge:%@", [self class], + self, session, task, challenge); + + GTMSessionFetcherChallengeBlock challengeBlock = self.challengeBlock; + if (challengeBlock) { + // The fetcher user has provided custom challenge handling. + // + // We will ultimately need to call back to NSURLSession's handler with the disposition value + // for this delegate method even if the user has stopped the fetcher. + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [self invokeOnCallbackQueueAfterUserStopped:YES + block:^{ + challengeBlock(self, challenge, handler); + }]; + } + } else { + // No challenge block was provided by the client. + [self respondToChallenge:challenge completionHandler:handler]; + } +} + +- (void)respondToChallenge:(NSURLAuthenticationChallenge *)challenge + completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, + NSURLCredential *_Nullable credential))handler { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSInteger previousFailureCount = [challenge previousFailureCount]; + if (previousFailureCount <= 2) { + NSURLProtectionSpace *protectionSpace = [challenge protectionSpace]; + NSString *authenticationMethod = [protectionSpace authenticationMethod]; + if ([authenticationMethod isEqual:NSURLAuthenticationMethodServerTrust]) { + // SSL. + // + // Background sessions seem to require an explicit check of the server trust object + // rather than default handling. + SecTrustRef serverTrust = challenge.protectionSpace.serverTrust; + if (serverTrust == NULL) { + // No server trust information is available. + handler(NSURLSessionAuthChallengePerformDefaultHandling, nil); + } else { + // Server trust information is available. + __auto_type callback = ^(SecTrustRef trustRef, BOOL allow) { + if (allow) { + NSURLCredential *trustCredential = [NSURLCredential credentialForTrust:trustRef]; + handler(NSURLSessionAuthChallengeUseCredential, trustCredential); + } else { + GTMSESSION_LOG_DEBUG(@"Cancelling authentication challenge for %@", + self->_request.URL); + handler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil); + } + }; + if (_allowInvalidServerCertificates) { + callback(serverTrust, YES); + } else { + [[self class] evaluateServerTrust:serverTrust + forRequest:_request + completionHandler:callback]; + } + } + return; + } + + NSURLCredential *credential = _credential; + + if ([[challenge protectionSpace] isProxy] && _proxyCredential != nil) { + credential = _proxyCredential; + } + + if (credential) { + handler(NSURLSessionAuthChallengeUseCredential, credential); + } else { + // The credential is still nil; tell the OS to use the default handling. This is needed + // for things that can come out of the keychain (proxies, client certificates, etc.). + // + // Note: Looking up a credential with NSURLCredentialStorage's + // defaultCredentialForProtectionSpace: is *not* the same invoking the handler with + // NSURLSessionAuthChallengePerformDefaultHandling. In the case of + // NSURLAuthenticationMethodClientCertificate, you can get nil back from + // NSURLCredentialStorage, while using this code path instead works. + handler(NSURLSessionAuthChallengePerformDefaultHandling, nil); + } + + } else { + // We've failed auth 3 times. The completion handler will be called with code + // NSURLErrorCancelled. + handler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil); + } + } // @synchronized(self) +} + +// Return redirect URL based on the original request URL and redirect request URL. +// +// Method disallows any scheme changes between the original request URL and redirect request URL +// aside from "http" to "https". If a change in scheme is detected the redirect URL inherits the +// scheme from the original request URL. ++ (nullable NSURL *)redirectURLWithOriginalRequestURL:(nullable NSURL *)originalRequestURL + redirectRequestURL:(nullable NSURL *)redirectRequestURL { + // In the case of an NSURLSession redirect, neither URL should ever be nil; as a sanity check + // if either is nil return the other URL. + if (!redirectRequestURL) return originalRequestURL; + if (!originalRequestURL) return redirectRequestURL; + + NSString *originalScheme = originalRequestURL.scheme; + NSString *redirectScheme = redirectRequestURL.scheme; + BOOL insecureToSecureRedirect = + (originalScheme != nil && [originalScheme caseInsensitiveCompare:@"http"] == NSOrderedSame && + redirectScheme != nil && [redirectScheme caseInsensitiveCompare:@"https"] == NSOrderedSame); + + // This can't really be nil for the inputs, but to keep the analyzer happy + // for the -caseInsensitiveCompare: call below, give it a value if it were. + if (!originalScheme) originalScheme = @"https"; + + // Check for changes to the scheme and disallow any changes except for http to https. + if (!insecureToSecureRedirect && + (redirectScheme.length != originalScheme.length || + [redirectScheme caseInsensitiveCompare:originalScheme] != NSOrderedSame)) { + NSURLComponents *components = + [NSURLComponents componentsWithURL:(NSURL *_Nonnull)redirectRequestURL + resolvingAgainstBaseURL:NO]; + components.scheme = originalScheme; + return components.URL; + } + + return redirectRequestURL; +} + +// Validate the certificate chain. +// +// This may become a public method if it appears to be useful to users. ++ (void)evaluateServerTrust:(SecTrustRef)serverTrust + forRequest:(NSURLRequest *)request + completionHandler:(void (^)(SecTrustRef trustRef, BOOL allow))handler { + // Retain the trust object to avoid a SecTrustEvaluate() crash on iOS 7. + CFRetain(serverTrust); + + // Evaluate the certificate chain. + // + // The delegate queue may be the main thread. Trust evaluation could cause some + // blocking network activity, so we must evaluate async, as documented at + // https://developer.apple.com/library/ios/technotes/tn2232/ + // + // We must also avoid multiple uses of the trust object, per docs: + // "It is not safe to call this function concurrently with any other function that uses + // the same trust management object, or to re-enter this function for the same trust + // management object." + // + // SecTrustEvaluateAsync both does sync execution of Evaluate and calls back on the + // queue passed to it, according to at sources in + // http://www.opensource.apple.com/source/libsecurity_keychain/libsecurity_keychain-55050.9/lib/SecTrust.cpp + // It would require a global serial queue to ensure the evaluate happens only on a + // single thread at a time, so we'll stick with using SecTrustEvaluate on a background + // thread. + dispatch_queue_t evaluateBackgroundQueue = + dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + dispatch_async(evaluateBackgroundQueue, ^{ + // It looks like the implementation of SecTrustEvaluate() on Mac grabs a global lock, + // so it may be redundant for us to also lock, but it's easy to synchronize here + // anyway. + BOOL shouldAllow; +#if GTM_SDK_REQUIRES_SECTRUSTEVALUATEWITHERROR + CFErrorRef errorRef = NULL; + @synchronized([GTMSessionFetcher class]) { + GTMSessionMonitorSynchronized([GTMSessionFetcher class]); + + // SecTrustEvaluateWithError handles both the "proceed" and "unspecified" cases, + // so it is not necessary to check the trust result the evaluation returns true. + shouldAllow = SecTrustEvaluateWithError(serverTrust, &errorRef); + } + + if (errorRef) { + GTMSESSION_LOG_DEBUG(@"Error %d evaluating trust for %@", (int)CFErrorGetCode(errorRef), + request); + CFRelease(errorRef); + } +#else + SecTrustResultType trustEval = kSecTrustResultInvalid; + OSStatus trustError; + @synchronized([GTMSessionFetcher class]) { + GTMSessionMonitorSynchronized([GTMSessionFetcher class]); + + trustError = SecTrustEvaluate(serverTrust, &trustEval); + } + if (trustError != errSecSuccess) { + GTMSESSION_LOG_DEBUG(@"Error %d evaluating trust for %@", + (int)trustError, request); + shouldAllow = NO; + } else { + // Having a trust level "unspecified" by the user is the usual result, described at + // https://developer.apple.com/library/mac/qa/qa1360 + if (trustEval == kSecTrustResultUnspecified + || trustEval == kSecTrustResultProceed) { + shouldAllow = YES; + } else { + shouldAllow = NO; + GTMSESSION_LOG_DEBUG(@"Challenge SecTrustResultType %u for %@, properties: %@", + trustEval, request.URL.host, + CFBridgingRelease(SecTrustCopyProperties(serverTrust))); + } + } +#endif // GTM_SDK_REQUIRES_SECTRUSTEVALUATEWITHERROR + handler(serverTrust, shouldAllow); + + CFRelease(serverTrust); + }); +} + +- (void)invokeOnCallbackQueueUnlessStopped:(void (^)(void))block { + [self invokeOnCallbackQueueAfterUserStopped:NO block:block]; +} + +- (void)invokeOnCallbackQueueAfterUserStopped:(BOOL)afterStopped block:(void (^)(void))block { + GTMSessionCheckSynchronized(self); + + [self invokeOnCallbackUnsynchronizedQueueAfterUserStopped:afterStopped block:block]; +} + +- (void)invokeOnCallbackUnsynchronizedQueueAfterUserStopped:(BOOL)afterStopped + block:(void (^)(void))block { + // testBlock simulation code may not be synchronizing when this is invoked. + [self invokeOnCallbackQueue:_callbackQueue afterUserStopped:afterStopped block:block]; +} + +- (void)invokeOnCallbackQueue:(dispatch_queue_t)callbackQueue + afterUserStopped:(BOOL)afterStopped + block:(void (^)(void))block { + if (callbackQueue) { + dispatch_group_async(_callbackGroup, callbackQueue, ^{ + if (!afterStopped && !self->_stopFetchingTriggersCompletionHandler) { + NSDate *serviceStoppedAllDate = [self->_service stoppedAllFetchersDate]; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // Avoid a race between stopFetching and the callback. + if (self->_userStoppedFetching) { + return; + } + + // Also avoid calling back if the service has stopped all fetchers + // since this one was created. The fetcher may have stopped before + // stopAllFetchers was invoked, so _userStoppedFetching wasn't set, + // but the app still won't expect the callback to fire after + // the service's stopAllFetchers was invoked. + if (serviceStoppedAllDate && + [self->_initialBeginFetchDate compare:serviceStoppedAllDate] != NSOrderedDescending) { + // stopAllFetchers was called after this fetcher began. + return; + } + } // @synchronized(self) + } + block(); + }); + } +} + +- (void)invokeFetchCallbacksOnCallbackQueueWithData:(nullable NSData *)data + error:(nullable NSError *)error + mayDecorate:(BOOL)mayDecorate + shouldReleaseCallbacks:(BOOL)shouldReleaseCallbacks { + if (mayDecorate && [_service respondsToSelector:@selector(decorators)]) { + NSArray> *decorators = _service.decorators; + if (decorators.count) { + [self applyDecoratorsAtRequestDidFinish:decorators + withData:data + error:error + startingAtIndex:0 + shouldReleaseCallbacks:shouldReleaseCallbacks]; + return; + } + } + + GTMSESSION_LOG_DEBUG_VERBOSE( + @"GTMSessionFetcher invoking fetch callbacks, data length %lu, error %@", + (unsigned long)data.length, error); + + // Callbacks will be released in the method stopFetchReleasingCallbacks: + GTMSessionFetcherCompletionHandler handler; + dispatch_queue_t callbackQueue; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // Capture the completion handler and callback queue, and call them only + // after releasing any callbacks to ensure the order of release vs + // callback is deterministic given potential QoS differences between + // callback queue and whatever queue this method eventually executes on. + handler = _completionHandler; + callbackQueue = _callbackQueue; + } + + if (shouldReleaseCallbacks) { + [self releaseCallbacks]; + } + + if (handler) { + [self invokeOnCallbackQueue:callbackQueue + afterUserStopped:NO + block:^{ + handler(data, error); + + // Post a notification, primarily to allow code to collect responses for + // testing. + // + // The observing code is not likely on the fetcher's callback + // queue, so this posts explicitly to the main queue. + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + if (data) { + userInfo[kGTMSessionFetcherCompletionDataKey] = data; + } + if (error) { + userInfo[kGTMSessionFetcherCompletionErrorKey] = error; + } + [self postNotificationOnMainThreadWithName: + kGTMSessionFetcherCompletionInvokedNotification + userInfo:userInfo + requireAsync:NO]; + }]; + } +} + +- (void)postNotificationOnMainThreadWithName:(NSString *)noteName + userInfo:(nullable NSDictionary *)userInfo + requireAsync:(BOOL)requireAsync { + dispatch_block_t postBlock = ^{ + [[NSNotificationCenter defaultCenter] postNotificationName:noteName + object:self + userInfo:userInfo]; + }; + + if ([NSThread isMainThread] && !requireAsync) { + // Post synchronously for compatibility with older code using the fetcher. + + // Avoid calling out to other code from inside a sync block to avoid risk + // of a deadlock or of recursive sync. + GTMSessionCheckNotSynchronized(self); + + postBlock(); + } else { + dispatch_async(dispatch_get_main_queue(), postBlock); + } +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)uploadTask + needNewBodyStream:(void (^)(NSInputStream *_Nullable bodyStream))completionHandler { + [self setSessionTask:uploadTask]; + GTMSESSION_LOG_DEBUG_VERBOSE(@"%@ %p URLSession:%@ task:%@ needNewBodyStream:", [self class], + self, session, uploadTask); + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + GTMSessionFetcherBodyStreamProvider provider = _bodyStreamProvider; +#if !STRIP_GTM_FETCH_LOGGING + if ([self respondsToSelector:@selector(loggedStreamProviderForStreamProvider:)]) { + provider = [self performSelector:@selector(loggedStreamProviderForStreamProvider:) + withObject:provider]; + } +#endif + if (provider) { + [self invokeOnCallbackQueueUnlessStopped:^{ + provider(completionHandler); + }]; + } else { + GTMSESSION_ASSERT_DEBUG(NO, @"NSURLSession expects a stream provider"); + + completionHandler(nil); + } + } // @synchronized(self) +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didSendBodyData:(int64_t)bytesSent + totalBytesSent:(int64_t)totalBytesSent + totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend { + [self setSessionTask:task]; + GTMSESSION_LOG_DEBUG_VERBOSE(@"%@ %p URLSession:%@ task:%@ didSendBodyData:%lld" + @" totalBytesSent:%lld totalBytesExpectedToSend:%lld", + [self class], self, session, task, bytesSent, totalBytesSent, + totalBytesExpectedToSend); + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (!_sendProgressBlock) { + return; + } + // We won't hold on to send progress block; it's ok to not send it if the upload finishes. + [self invokeOnCallbackQueueUnlessStopped:^{ + GTMSessionFetcherSendProgressBlock progressBlock; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + progressBlock = self->_sendProgressBlock; + } + if (progressBlock) { + progressBlock(bytesSent, totalBytesSent, totalBytesExpectedToSend); + } + }]; + } // @synchronized(self) +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + didReceiveData:(NSData *)data { + [self setSessionTask:dataTask]; + NSUInteger bufferLength = data.length; + GTMSESSION_LOG_DEBUG_VERBOSE(@"%@ %p URLSession:%@ dataTask:%@ didReceiveData:%p (%llu bytes)", + [self class], self, session, dataTask, data, + (unsigned long long)bufferLength); + if (bufferLength == 0) { + // Observed on completing an out-of-process upload. + return; + } + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + GTMSessionFetcherAccumulateDataBlock accumulateBlock = _accumulateDataBlock; + if (accumulateBlock) { + // Let the client accumulate the data. + _downloadedLength += bufferLength; + [self invokeOnCallbackQueueUnlessStopped:^{ + accumulateBlock(data); + }]; + } else if (!_userStoppedFetching) { + // Append to the mutable data buffer unless the fetch has been cancelled. + + // Resumed upload tasks may not yet have a data buffer. + if (_downloadedData == nil) { + // Using NSClassFromString for iOS 6 compatibility. + GTMSESSION_ASSERT_DEBUG( + ![dataTask isKindOfClass:NSClassFromString(@"NSURLSessionDownloadTask")], + @"Resumed download tasks should not receive data bytes"); + _downloadedData = [[NSMutableData alloc] init]; + } + + [_downloadedData appendData:data]; + _downloadedLength = (int64_t)_downloadedData.length; + + // We won't hold on to receivedProgressBlock here; it's ok to not send + // it if the transfer finishes. + if (_receivedProgressBlock) { + [self invokeOnCallbackQueueUnlessStopped:^{ + GTMSessionFetcherReceivedProgressBlock progressBlock; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + progressBlock = self->_receivedProgressBlock; + } + if (progressBlock) { + progressBlock((int64_t)bufferLength, self->_downloadedLength); + } + }]; + } + } + } // @synchronized(self) +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + willCacheResponse:(NSCachedURLResponse *)proposedResponse + completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler + GTM_SWIFT_DISABLE_ASYNC { + GTMSESSION_LOG_DEBUG_VERBOSE(@"%@ %p URLSession:%@ dataTask:%@ willCacheResponse:%@ %@", + [self class], self, session, dataTask, proposedResponse, + proposedResponse.response); + GTMSessionFetcherWillCacheURLResponseBlock callback; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + callback = _willCacheURLResponseBlock; + + if (callback) { + [self invokeOnCallbackQueueAfterUserStopped:YES + block:^{ + callback(proposedResponse, completionHandler); + }]; + } + } // @synchronized(self) + if (!callback) { + completionHandler(proposedResponse); + } +} + +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)downloadTask + didWriteData:(int64_t)bytesWritten + totalBytesWritten:(int64_t)totalBytesWritten + totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite { + GTMSESSION_LOG_DEBUG_VERBOSE(@"%@ %p URLSession:%@ downloadTask:%@ didWriteData:%lld" + @" bytesWritten:%lld totalBytesExpectedToWrite:%lld", + [self class], self, session, downloadTask, bytesWritten, + totalBytesWritten, totalBytesExpectedToWrite); + [self setSessionTask:downloadTask]; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if ((totalBytesExpectedToWrite != NSURLSessionTransferSizeUnknown) && + (totalBytesExpectedToWrite < totalBytesWritten)) { + // Have observed cases were bytesWritten == totalBytesExpectedToWrite, + // but totalBytesWritten > totalBytesExpectedToWrite, so setting to unkown in these cases. + totalBytesExpectedToWrite = NSURLSessionTransferSizeUnknown; + } + + GTMSessionFetcherDownloadProgressBlock progressBlock; + progressBlock = self->_downloadProgressBlock; + if (progressBlock) { + [self invokeOnCallbackQueueUnlessStopped:^{ + progressBlock(bytesWritten, totalBytesWritten, totalBytesExpectedToWrite); + }]; + } + } // @synchronized(self) +} + +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)downloadTask + didResumeAtOffset:(int64_t)fileOffset + expectedTotalBytes:(int64_t)expectedTotalBytes { + GTMSESSION_LOG_DEBUG_VERBOSE(@"%@ %p URLSession:%@ downloadTask:%@ didResumeAtOffset:%lld" + @" expectedTotalBytes:%lld", + [self class], self, session, downloadTask, fileOffset, + expectedTotalBytes); + [self setSessionTask:downloadTask]; +} + +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)downloadTask + didFinishDownloadingToURL:(NSURL *)downloadLocationURL { + // Download may have relaunched app, so update _sessionTask. + [self setSessionTask:downloadTask]; + GTMSESSION_LOG_DEBUG_VERBOSE(@"%@ %p URLSession:%@ downloadTask:%@ didFinishDownloadingToURL:%@", + [self class], self, session, downloadTask, downloadLocationURL); + NSNumber *fileSizeNum; + [downloadLocationURL getResourceValue:&fileSizeNum forKey:NSURLFileSizeKey error:NULL]; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSURL *destinationURL = _destinationFileURL; + + _downloadedLength = fileSizeNum.longLongValue; + + // Overwrite any previous file at the destination URL. + NSFileManager *fileMgr = [NSFileManager defaultManager]; + NSError *removeError; + if (![fileMgr removeItemAtURL:destinationURL error:&removeError] && + removeError.code != NSFileNoSuchFileError) { + GTMSESSION_LOG_DEBUG(@"Could not remove previous file at %@ due to %@", + downloadLocationURL.path, removeError); + } + + NSInteger statusCode = [self statusCodeUnsynchronized]; + if (statusCode < 200 || statusCode > 399) { + // In OS X 10.11, the response body is written to a file even on a server + // status error. For convenience of the fetcher client, we'll skip saving the + // downloaded body to the destination URL so that clients do not need to know + // to delete the file following fetch errors. + GTMSESSION_LOG_DEBUG(@"Abandoning download due to status %ld, file %@", (long)statusCode, + downloadLocationURL.path); + + // On error code, add the contents of the temporary file to _downloadTaskErrorData + // This way fetcher clients have access to error details possibly passed by the server. + if (_downloadedLength > 0 && _downloadedLength <= kMaximumDownloadErrorDataLength) { + _downloadTaskErrorData = [NSData dataWithContentsOfURL:downloadLocationURL]; + } else if (_downloadedLength > kMaximumDownloadErrorDataLength) { + GTMSESSION_LOG_DEBUG(@"Download error data for file %@ not passed to userInfo due to size " + @"%lld", + downloadLocationURL.path, _downloadedLength); + } + } else { + NSError *moveError; + NSURL *destinationFolderURL = [destinationURL URLByDeletingLastPathComponent]; + BOOL didMoveDownload = NO; + if ([fileMgr createDirectoryAtURL:destinationFolderURL + withIntermediateDirectories:YES + attributes:nil + error:&moveError]) { + didMoveDownload = [fileMgr moveItemAtURL:downloadLocationURL + toURL:destinationURL + error:&moveError]; + } + if (!didMoveDownload) { + _downloadFinishedError = moveError; + } + GTM_LOG_BACKGROUND_SESSION(@"%@ %p Moved download from \"%@\" to \"%@\" %@", [self class], + self, downloadLocationURL.path, destinationURL.path, + error ? error : @""); + } + } // @synchronized(self) +} + +/* Sent as the last message related to a specific task. Error may be + * nil, which implies that no error occurred and this task is complete. + */ +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didCompleteWithError:(NSError *)error { + [self setSessionTask:task]; + GTMSESSION_LOG_DEBUG_VERBOSE(@"%@ %p URLSession:%@ task:%@ didCompleteWithError:%@", [self class], + self, session, task, error); + + NSInteger status = self.statusCode; + BOOL forceAssumeRetry = NO; + BOOL succeeded = NO; + BOOL userStoppedTriggerCompletion = NO; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + +#if !GTM_DISABLE_FETCHER_TEST_BLOCK + // The task is never resumed when a testBlock is used. When the session is destroyed, + // we should ignore the callback, since the testBlock support code itself invokes + // shouldRetryNowForStatus: and finishWithError:shouldRetry: + if (_isUsingTestBlock) return; +#endif + userStoppedTriggerCompletion = _userStoppedFetching && _stopFetchingTriggersCompletionHandler; + + if (error == nil) { + error = _downloadFinishedError; + } + succeeded = (error == nil && status >= 0 && status < 300); + if (succeeded && !userStoppedTriggerCompletion) { + // Succeeded. + _bodyLength = task.countOfBytesSent; + } + } // @synchronized(self) + + if (userStoppedTriggerCompletion) { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + [userInfo setObject:@"Operation cancelled" forKey:NSLocalizedDescriptionKey]; + if (error) { + [userInfo setObject:error forKey:NSUnderlyingErrorKey]; + } + NSError *cancelError = [NSError errorWithDomain:kGTMSessionFetcherErrorDomain + code:GTMSessionFetcherErrorUserCancelled + userInfo:userInfo]; + [self finishWithError:cancelError shouldRetry:NO]; + return; + } + + if (succeeded) { + [self finishWithError:nil shouldRetry:NO]; + return; + } + // For background redirects, no delegate method is called, so we cannot restore a stripped + // Authorization header, so if a 403 ("Forbidden") was generated due to a missing OAuth 2 header, + // set the current request's URL to the redirected URL, so we in effect restore the Authorization + // header. + if ((status == 403) && self.usingBackgroundSession) { + NSURL *redirectURL = self.response.URL; + NSURLRequest *request = self.request; + if (![request.URL isEqual:redirectURL]) { + NSString *authorizationHeader = [request.allHTTPHeaderFields objectForKey:@"Authorization"]; + if (authorizationHeader != nil) { + NSMutableURLRequest *mutableRequest = [request mutableCopy]; + mutableRequest.URL = redirectURL; + [self updateMutableRequest:mutableRequest]; + // Avoid assuming the session is still valid. + self.session = nil; + forceAssumeRetry = YES; + } + } + } + + // If invalidating the session was deferred in stopFetchReleasingCallbacks: then do it now. + NSURLSession *oldSession = self.sessionNeedingInvalidation; + if (oldSession) { + [self setSessionNeedingInvalidation:NULL]; + [oldSession finishTasksAndInvalidate]; + } + + // Failed. + [self shouldRetryNowForStatus:status + error:error + forceAssumeRetry:forceAssumeRetry + response:^(BOOL shouldRetry) { + [self finishWithError:error shouldRetry:shouldRetry]; + }]; +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics + API_AVAILABLE(ios(10.0), macosx(10.12), tvos(10.0), watchos(6.0)) { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + GTMSessionFetcherMetricsCollectionBlock metricsCollectionBlock = _metricsCollectionBlock; + if (metricsCollectionBlock) { + [self invokeOnCallbackQueueUnlessStopped:^{ + metricsCollectionBlock(metrics); + }]; + } + } +} + +#if TARGET_OS_IPHONE +- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session { + GTMSESSION_LOG_DEBUG_VERBOSE(@"%@ %p URLSessionDidFinishEventsForBackgroundURLSession:%@", + [self class], self, session); + [self removePersistedBackgroundSessionFromDefaults]; + + GTMSessionFetcherSystemCompletionHandler handler; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + handler = self.systemCompletionHandler; + self.systemCompletionHandler = nil; + } // @synchronized(self) + if (handler) { + GTM_LOG_BACKGROUND_SESSION(@"%@ %p Calling system completionHandler", [self class], self); + handler(); + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSURLSession *oldSession = _session; + _session = nil; + if (_shouldInvalidateSession) { + [oldSession finishTasksAndInvalidate]; + } + } // @synchronized(self) + } +} +#endif + +- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(nullable NSError *)error { + // This may happen repeatedly for retries. On authentication callbacks, the retry + // may begin before the prior session sends the didBecomeInvalid delegate message. + GTMSESSION_LOG_DEBUG_VERBOSE(@"%@ %p URLSession:%@ didBecomeInvalidWithError:%@", [self class], + self, session, error); + if (session == (NSURLSession *)self.session) { + GTMSESSION_LOG_DEBUG_VERBOSE(@" Unexpected retained invalid session: %@", session); + self.session = nil; + } +} + +- (void)finishWithError:(nullable NSError *)error shouldRetry:(BOOL)shouldRetry { + [self removePersistedBackgroundSessionFromDefaults]; + + BOOL shouldStopFetching = YES; + NSData *downloadedData = nil; +#if !STRIP_GTM_FETCH_LOGGING + BOOL shouldDeferLogging = NO; +#endif + BOOL shouldBeginRetryTimer = NO; + NSInteger status = [self statusCode]; + NSURL *destinationURL = self.destinationFileURL; + + BOOL fetchSucceeded = (error == nil && status >= 0 && status < 300); + +#if !STRIP_GTM_FETCH_LOGGING + if (!fetchSucceeded) { + if (!shouldDeferLogging && !self.hasLoggedError) { + [self logNowWithError:error]; + self.hasLoggedError = YES; + } + } +#endif // !STRIP_GTM_FETCH_LOGGING + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + +#if !STRIP_GTM_FETCH_LOGGING + shouldDeferLogging = _deferResponseBodyLogging; +#endif + if (fetchSucceeded) { + // Success + if ((_downloadedData.length > 0) && (destinationURL != nil)) { + // Overwrite any previous file at the destination URL. + NSFileManager *fileMgr = [NSFileManager defaultManager]; + [fileMgr removeItemAtURL:destinationURL error:NULL]; + NSURL *destinationFolderURL = [destinationURL URLByDeletingLastPathComponent]; + BOOL didMoveDownload = NO; + if ([fileMgr createDirectoryAtURL:destinationFolderURL + withIntermediateDirectories:YES + attributes:nil + error:&error]) { + didMoveDownload = [_downloadedData writeToURL:destinationURL + options:NSDataWritingAtomic + error:&error]; + } + if (didMoveDownload) { + _downloadedData = nil; + } else { + _downloadFinishedError = error; + } + } + downloadedData = _downloadedData; + } else { + // Unsuccessful with error or status over 300. Retry or notify the delegate of failure + if (shouldRetry) { + // Retrying. + shouldBeginRetryTimer = YES; + shouldStopFetching = NO; + } else { + if (error == nil) { + // Create an error. + NSDictionary *userInfo = GTMErrorUserInfoForData( + _downloadedData.length > 0 ? _downloadedData : _downloadTaskErrorData, + [self responseHeadersUnsynchronized]); + + error = [NSError errorWithDomain:kGTMSessionFetcherStatusDomain + code:status + userInfo:userInfo]; + } else { + // If the error had resume data, and the client supplied a resume block, pass the + // data to the client. + void (^resumeBlock)(NSData *) = _resumeDataBlock; + _resumeDataBlock = nil; + if (resumeBlock) { + NSData *resumeData = [error.userInfo objectForKey:NSURLSessionDownloadTaskResumeData]; + if (resumeData) { + [self invokeOnCallbackQueueAfterUserStopped:YES + block:^{ + resumeBlock(resumeData); + }]; + } + } + } + if (_downloadedData.length > 0) { + downloadedData = _downloadedData; + } + // If the error occurred after retries, report the number and duration of the + // retries. This provides a clue to a developer looking at the error description + // that the fetcher did retry before failing with this error. + if (_retryCount > 0) { + NSMutableDictionary *userInfoWithRetries = + [NSMutableDictionary dictionaryWithDictionary:(NSDictionary *)error.userInfo]; + NSTimeInterval timeSinceInitialRequest = -[_initialRequestDate timeIntervalSinceNow]; + [userInfoWithRetries setObject:@(timeSinceInitialRequest) + forKey:kGTMSessionFetcherElapsedIntervalWithRetriesKey]; + [userInfoWithRetries setObject:@(_retryCount) + forKey:kGTMSessionFetcherNumberOfRetriesDoneKey]; + error = [NSError errorWithDomain:(NSString *)error.domain + code:error.code + userInfo:userInfoWithRetries]; + } + } + } + } // @synchronized(self) + + if (shouldBeginRetryTimer) { + [self beginRetryTimer]; + } + + // We want to send the stop notification before calling the delegate's + // callback selector, since the callback selector may release all of + // the fetcher properties that the client is using to track the fetches. + // + // We'll also stop now so that, to any observers watching the notifications, + // it doesn't look like our wait for a retry (which may be long, + // 30 seconds or more) is part of the network activity. + [self sendStopNotificationIfNeeded]; + + if (shouldStopFetching) { + // The upload subclass doesn't want to release callbacks until upload chunks have completed. + BOOL shouldRelease = [self shouldReleaseCallbacksUponCompletion]; + [self invokeFetchCallbacksOnCallbackQueueWithData:downloadedData + error:error + mayDecorate:YES + shouldReleaseCallbacks:shouldRelease]; + [self stopFetchReleasingCallbacks:NO]; + } + +#if !STRIP_GTM_FETCH_LOGGING + // _hasLoggedError is only set by this method + if (!shouldDeferLogging && !_hasLoggedError) { + [self logNowWithError:error]; + } +#endif +} + +- (BOOL)shouldReleaseCallbacksUponCompletion { + // A subclass can override this to keep callbacks around after the + // connection has finished successfully + return YES; +} + +- (void)logNowWithError:(nullable NSError *)error { + GTMSessionCheckNotSynchronized(self); + + // If the logging category is available, then log the current request, + // response, data, and error + if ([self respondsToSelector:@selector(logFetchWithError:)]) { + [self performSelector:@selector(logFetchWithError:) withObject:error]; + } +} + +#pragma mark Retries + +- (BOOL)isRetryError:(NSError *)error { + struct RetryRecord { + __unsafe_unretained NSString *const domain; + NSInteger code; + }; + + struct RetryRecord retries[] = { + {kGTMSessionFetcherStatusDomain, 408}, // request timeout + {kGTMSessionFetcherStatusDomain, 502}, // failure gatewaying to another server + {kGTMSessionFetcherStatusDomain, 503}, // service unavailable + {kGTMSessionFetcherStatusDomain, 504}, // request timeout + {NSURLErrorDomain, NSURLErrorTimedOut}, + {NSURLErrorDomain, NSURLErrorNetworkConnectionLost}, + {nil, 0}}; + + // NSError's isEqual always returns false for equal but distinct instances + // of NSError, so we have to compare the domain and code values explicitly + NSString *domain = error.domain; + NSInteger code = error.code; + for (int idx = 0; retries[idx].domain != nil; idx++) { + if (code == retries[idx].code && [domain isEqual:retries[idx].domain]) { + return YES; + } + } + return NO; +} + +// shouldRetryNowForStatus:error: responds with YES if the user has enabled retries +// and the status or error is one that is suitable for retrying. "Suitable" +// means either the isRetryError:'s list contains the status or error, or the +// user's retry block is present and returns YES when called, or the +// authorizer may be able to fix. +- (void)shouldRetryNowForStatus:(NSInteger)status + error:(NSError *)error + forceAssumeRetry:(BOOL)forceAssumeRetry + response:(GTMSessionFetcherRetryResponse)response { + // Determine if a refreshed authorizer may avoid an authorization error + BOOL willRetry = NO; + + // We assume _authorizer is immutable after beginFetch, and _hasAttemptedAuthRefresh is modified + // only in this method, and this method is invoked on the serial delegate queue. + // + // We want to avoid calling the authorizer from inside a sync block. + BOOL isFirstAuthError = (_authorizer != nil && !_hasAttemptedAuthRefresh && + status == GTMSessionFetcherStatusUnauthorized); // 401 + + BOOL hasPrimed = NO; + if (isFirstAuthError) { + if ([_authorizer respondsToSelector:@selector(primeForRefresh)]) { + hasPrimed = [_authorizer primeForRefresh]; + } + } + + BOOL shouldRetryForAuthRefresh = NO; + if (hasPrimed) { + shouldRetryForAuthRefresh = YES; + _hasAttemptedAuthRefresh = YES; + [self updateRequestValue:nil forHTTPHeaderField:@"Authorization"]; + } + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + BOOL shouldDoRetry = [self isRetryEnabledUnsynchronized]; + if (shouldDoRetry && ![self hasRetryAfterInterval]) { + // Determine if we're doing exponential backoff retries + shouldDoRetry = [self nextRetryIntervalUnsynchronized] < _maxRetryInterval; + + if (shouldDoRetry) { + // If an explicit max retry interval was set, we expect repeated backoffs to take + // up to roughly twice that for repeated fast failures. If the initial attempt is + // already more than 3 times the max retry interval, then failures have taken a long time + // (such as from network timeouts) so don't retry again to avoid the app becoming + // unexpectedly unresponsive. + if (_maxRetryInterval > 0) { + NSTimeInterval maxAllowedIntervalBeforeRetry = _maxRetryInterval * 3; + NSTimeInterval timeSinceInitialRequest = -[_initialRequestDate timeIntervalSinceNow]; + if (timeSinceInitialRequest > maxAllowedIntervalBeforeRetry) { + shouldDoRetry = NO; + } + } + } + } + BOOL canRetry = shouldRetryForAuthRefresh || forceAssumeRetry || shouldDoRetry; + if (canRetry) { + NSDictionary *userInfo = + GTMErrorUserInfoForData(_downloadedData, [self responseHeadersUnsynchronized]); + NSError *statusError = [NSError errorWithDomain:kGTMSessionFetcherStatusDomain + code:status + userInfo:userInfo]; + if (error == nil) { + error = statusError; + } + willRetry = shouldRetryForAuthRefresh || forceAssumeRetry || [self isRetryError:error] || + ((error != statusError) && [self isRetryError:statusError]); + + // If the user has installed a retry callback, consult that. + GTMSessionFetcherRetryBlock retryBlock = _retryBlock; + if (retryBlock) { + [self invokeOnCallbackQueueUnlessStopped:^{ + retryBlock(willRetry, error, response); + }]; + return; + } + } + } // @synchronized(self) + response(willRetry); +} + +- (BOOL)hasRetryAfterInterval { + GTMSessionCheckSynchronized(self); + + NSDictionary *responseHeaders = [self responseHeadersUnsynchronized]; + NSString *retryAfterValue = [responseHeaders valueForKey:@"Retry-After"]; + return (retryAfterValue != nil); +} + +- (NSTimeInterval)retryAfterInterval { + GTMSessionCheckSynchronized(self); + + NSDictionary *responseHeaders = [self responseHeadersUnsynchronized]; + NSString *retryAfterValue = [responseHeaders valueForKey:@"Retry-After"]; + if (retryAfterValue == nil) { + return 0; + } + // Retry-After formatted as HTTP-date | delta-seconds + // Reference: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html + NSDateFormatter *rfc1123DateFormatter = [[NSDateFormatter alloc] init]; + rfc1123DateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]; + rfc1123DateFormatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"]; + rfc1123DateFormatter.dateFormat = @"EEE',' dd MMM yyyy HH':'mm':'ss z"; + NSDate *retryAfterDate = [rfc1123DateFormatter dateFromString:retryAfterValue]; + NSTimeInterval retryAfterInterval = + (retryAfterDate != nil) ? retryAfterDate.timeIntervalSinceNow : retryAfterValue.intValue; + retryAfterInterval = MAX(0, retryAfterInterval); + return retryAfterInterval; +} + +- (void)beginRetryTimer { + if (![NSThread isMainThread]) { + // Defer creating and starting the timer until we're on the main thread to ensure it has + // a run loop. + dispatch_group_async(_callbackGroup, dispatch_get_main_queue(), ^{ + [self beginRetryTimer]; + }); + return; + } + + [self destroyRetryTimer]; + +#if GTM_BACKGROUND_TASK_FETCHING + // Don't keep a background task active while awaiting retry, which can lead to the + // app exceeding the allotted time for keeping the background task open, causing the + // system to terminate the app. When the retry starts, a new background task will + // be created. + [self endBackgroundTask]; +#endif // GTM_BACKGROUND_TASK_FETCHING + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSTimeInterval nextInterval = [self nextRetryIntervalUnsynchronized]; + NSTimeInterval maxInterval = _maxRetryInterval; + NSTimeInterval newInterval = MIN(nextInterval, (maxInterval > 0 ? maxInterval : DBL_MAX)); + NSTimeInterval newIntervalTolerance = (newInterval / 10) > 1.0 ?: 1.0; + + _lastRetryInterval = newInterval; + + _retryTimer = [NSTimer timerWithTimeInterval:newInterval + target:self + selector:@selector(retryTimerFired:) + userInfo:nil + repeats:NO]; + _retryTimer.tolerance = newIntervalTolerance; + [[NSRunLoop mainRunLoop] addTimer:_retryTimer forMode:NSDefaultRunLoopMode]; + } // @synchronized(self) + + [self postNotificationOnMainThreadWithName:kGTMSessionFetcherRetryDelayStartedNotification + userInfo:nil + requireAsync:NO]; +} + +- (void)retryTimerFired:(NSTimer *)timer { + [self destroyRetryTimer]; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _retryCount++; + } // @synchronized(self) + + NSOperationQueue *queue = self.sessionDelegateQueue; + [queue addOperationWithBlock:^{ + [self retryFetch]; + }]; +} + +- (void)destroyRetryTimer { + BOOL shouldNotify = NO; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_retryTimer) { + [_retryTimer invalidate]; + _retryTimer = nil; + shouldNotify = YES; + } + } + + if (shouldNotify) { + [self postNotificationOnMainThreadWithName:kGTMSessionFetcherRetryDelayStoppedNotification + userInfo:nil + requireAsync:NO]; + } +} + +- (NSUInteger)retryCount { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _retryCount; + } // @synchronized(self) +} + +- (NSTimeInterval)nextRetryInterval { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSTimeInterval interval = [self nextRetryIntervalUnsynchronized]; + return interval; + } // @synchronized(self) +} + +- (NSTimeInterval)nextRetryIntervalUnsynchronized { + GTMSessionCheckSynchronized(self); + + NSInteger statusCode = [self statusCodeUnsynchronized]; + if ((statusCode == 503) && [self hasRetryAfterInterval]) { + NSTimeInterval secs = [self retryAfterInterval]; + return secs; + } + // The next wait interval is the factor (2.0) times the last interval, + // but never less than the minimum interval. + NSTimeInterval secs = _lastRetryInterval * _retryFactor; + if (_maxRetryInterval > 0) { + secs = MIN(secs, _maxRetryInterval); + } + secs = MAX(secs, _minRetryInterval); + + return secs; +} + +- (NSTimer *)retryTimer { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _retryTimer; + } // @synchronized(self) +} + +- (BOOL)isRetryEnabled { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _isRetryEnabled; + } // @synchronized(self) +} + +- (BOOL)isRetryEnabledUnsynchronized { + GTMSessionCheckSynchronized(self); + + return _isRetryEnabled; +} + +- (void)setRetryEnabled:(BOOL)flag { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (flag && !_isRetryEnabled) { + // We defer initializing these until the user calls setRetryEnabled + // to avoid using the random number generator if it's not needed. + // However, this means min and max intervals for this fetcher are reset + // as a side effect of calling setRetryEnabled. + // + // Make an initial retry interval random between 1.0 and 2.0 seconds + _minRetryInterval = InitialMinRetryInterval(); + _maxRetryInterval = kUnsetMaxRetryInterval; + _retryFactor = 2.0; + _lastRetryInterval = 0.0; + } + _isRetryEnabled = flag; + } // @synchronized(self) +}; + +- (NSTimeInterval)maxRetryInterval { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _maxRetryInterval; + } // @synchronized(self) +} + +- (void)setMaxRetryInterval:(NSTimeInterval)secs { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (secs > 0) { + _maxRetryInterval = secs; + } else { + _maxRetryInterval = kUnsetMaxRetryInterval; + } + } // @synchronized(self) +} + +- (double)minRetryInterval { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _minRetryInterval; + } // @synchronized(self) +} + +- (void)setMinRetryInterval:(NSTimeInterval)secs { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (secs > 0) { + _minRetryInterval = secs; + } else { + // Set min interval to a random value between 1.0 and 2.0 seconds + // so that if multiple clients start retrying at the same time, they'll + // repeat at different times and avoid overloading the server + _minRetryInterval = InitialMinRetryInterval(); + } + } // @synchronized(self) +} + +#pragma mark iOS System Completion Handlers + +#if TARGET_OS_IPHONE +static NSMutableDictionary *gSystemCompletionHandlers = nil; + +- (nullable GTMSessionFetcherSystemCompletionHandler)systemCompletionHandler { + return [[self class] systemCompletionHandlerForSessionIdentifier:_sessionIdentifier]; +} + +- (void)setSystemCompletionHandler: + (nullable GTMSessionFetcherSystemCompletionHandler)systemCompletionHandler { + [[self class] setSystemCompletionHandler:systemCompletionHandler + forSessionIdentifier:_sessionIdentifier]; +} + ++ (void)setSystemCompletionHandler: + (nullable GTMSessionFetcherSystemCompletionHandler)systemCompletionHandler + forSessionIdentifier:(NSString *)sessionIdentifier { + if (!sessionIdentifier) { + NSLog(@"%s with nil identifier", __PRETTY_FUNCTION__); + return; + } + + @synchronized([GTMSessionFetcher class]) { + if (gSystemCompletionHandlers == nil && systemCompletionHandler != nil) { + gSystemCompletionHandlers = [[NSMutableDictionary alloc] init]; + } + // Use setValue: to remove the object if completionHandler is nil. + [gSystemCompletionHandlers setValue:systemCompletionHandler forKey:sessionIdentifier]; + } +} + ++ (nullable GTMSessionFetcherSystemCompletionHandler)systemCompletionHandlerForSessionIdentifier: + (NSString *)sessionIdentifier { + if (!sessionIdentifier) { + return nil; + } + @synchronized([GTMSessionFetcher class]) { + return [gSystemCompletionHandlers objectForKey:sessionIdentifier]; + } +} +#endif // TARGET_OS_IPHONE + +#pragma mark Getters and Setters + +// clang-format off +// Don't re-format the @synthesize blocks: +@synthesize downloadResumeData = _downloadResumeData, + configuration = _configuration, + configurationBlock = _configurationBlock, + sessionTask = _sessionTask, + wasCreatedFromBackgroundSession = _wasCreatedFromBackgroundSession, + clientWillReconnectBackgroundSession = _clientWillReconnectBackgroundSession, + sessionUserInfo = _sessionUserInfo, + taskDescription = _taskDescription, + taskPriority = _taskPriority, + usingBackgroundSession = _usingBackgroundSession, + canShareSession = _canShareSession, + completionHandler = _completionHandler, + credential = _credential, + proxyCredential = _proxyCredential, + bodyData = _bodyData, + bodyLength = _bodyLength, + service = _service, + serviceHost = _serviceHost, + accumulateDataBlock = _accumulateDataBlock, + receivedProgressBlock = _receivedProgressBlock, + downloadProgressBlock = _downloadProgressBlock, + resumeDataBlock = _resumeDataBlock, + didReceiveResponseBlock = _didReceiveResponseBlock, + challengeBlock = _challengeBlock, + willRedirectBlock = _willRedirectBlock, + sendProgressBlock = _sendProgressBlock, + willCacheURLResponseBlock = _willCacheURLResponseBlock, + retryBlock = _retryBlock, + metricsCollectionBlock = _metricsCollectionBlock, + retryFactor = _retryFactor, + allowedInsecureSchemes = _allowedInsecureSchemes, + allowLocalhostRequest = _allowLocalhostRequest, + allowInvalidServerCertificates = _allowInvalidServerCertificates, + cookieStorage = _cookieStorage, + callbackQueue = _callbackQueue, + initialBeginFetchDate = _initialBeginFetchDate, + testBlock = _testBlock, + testBlockAccumulateDataChunkCount = _testBlockAccumulateDataChunkCount, + comment = _comment, + log = _log, + stopFetchingTriggersCompletionHandler = _stopFetchingTriggersCompletionHandler; + +#if !STRIP_GTM_FETCH_LOGGING +@synthesize redirectedFromURL = _redirectedFromURL, + logRequestBody = _logRequestBody, + logResponseBody = _logResponseBody, + hasLoggedError = _hasLoggedError; +#endif + +#if GTM_BACKGROUND_TASK_FETCHING +@synthesize backgroundTaskIdentifier = _backgroundTaskIdentifier, + skipBackgroundTask = _skipBackgroundTask; +#endif +// clang-format on + +- (nullable NSURLRequest *)request { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [_request copy]; + } // @synchronized(self) +} + +- (void)setRequest:(nullable NSURLRequest *)request { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (![self isFetchingUnsynchronized]) { + _request = [request mutableCopy]; + } else { + GTMSESSION_ASSERT_DEBUG(0, @"request may not be set after beginFetch has been invoked"); + } + } // @synchronized(self) +} + +- (nullable NSMutableURLRequest *)mutableRequestForTesting { + // Allow tests only to modify the request, useful during retries. + return _request; +} + +// Internal method for updating the request property such as on redirects. +- (void)updateMutableRequest:(nullable NSMutableURLRequest *)request { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _request = request; + } // @synchronized(self) +} + +// Set a header field value on the request. Header field value changes will not +// affect a fetch after the fetch has begun. +- (void)setRequestValue:(nullable NSString *)value forHTTPHeaderField:(NSString *)field { + if (![self isFetching]) { + [self updateRequestValue:value forHTTPHeaderField:field]; + } else { + GTMSESSION_ASSERT_DEBUG(0, @"request may not be set after beginFetch has been invoked"); + } +} + +// Internal method for updating request headers. +- (void)updateRequestValue:(nullable NSString *)value forHTTPHeaderField:(NSString *)field { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [_request setValue:value forHTTPHeaderField:field]; + } // @synchronized(self) +} + +- (void)setResponse:(nullable NSURLResponse *)response { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _response = response; + } // @synchronized(self) +} + +- (int64_t)bodyLength { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_bodyLength == NSURLSessionTransferSizeUnknown) { + if (_bodyData) { + _bodyLength = (int64_t)_bodyData.length; + } else if (_bodyFileURL) { + NSNumber *fileSizeNum = nil; + NSError *fileSizeError = nil; + if ([_bodyFileURL getResourceValue:&fileSizeNum + forKey:NSURLFileSizeKey + error:&fileSizeError]) { + _bodyLength = [fileSizeNum longLongValue]; + } + } + } + return _bodyLength; + } // @synchronized(self) +} + +- (BOOL)useUploadTask { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _useUploadTask; + } // @synchronized(self) +} + +- (void)setUseUploadTask:(BOOL)flag { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (flag != _useUploadTask) { + GTMSESSION_ASSERT_DEBUG(![self isFetchingUnsynchronized], + @"useUploadTask should not change after beginFetch has been invoked"); + _useUploadTask = flag; + } + } // @synchronized(self) +} + +- (nullable NSURL *)bodyFileURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _bodyFileURL; + } // @synchronized(self) +} + +- (void)setBodyFileURL:(nullable NSURL *)fileURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // The comparison here is a trivial optimization and forgiveness for any client that + // repeatedly sets the property, so it just uses pointer comparison rather than isEqual:. + if (fileURL != _bodyFileURL) { + GTMSESSION_ASSERT_DEBUG(![self isFetchingUnsynchronized], + @"fileURL should not change after beginFetch has been invoked"); + + _bodyFileURL = fileURL; + } + } // @synchronized(self) +} + +- (nullable GTMSessionFetcherBodyStreamProvider)bodyStreamProvider { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _bodyStreamProvider; + } // @synchronized(self) +} + +- (void)setBodyStreamProvider:(nullable GTMSessionFetcherBodyStreamProvider)block { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + GTMSESSION_ASSERT_DEBUG(![self isFetchingUnsynchronized], + @"stream provider should not change after beginFetch has been invoked"); + + _bodyStreamProvider = [block copy]; + } // @synchronized(self) +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated" +- (nullable id)authorizer { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _authorizer; + } // @synchronized(self) +} + +- (void)setAuthorizer:(nullable id)authorizer { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (authorizer != _authorizer) { + if ([self isFetchingUnsynchronized]) { + GTMSESSION_ASSERT_DEBUG(0, + @"authorizer should not change after beginFetch has been invoked"); + } else { + _authorizer = authorizer; + } + } + } // @synchronized(self) +} +#pragma clang diagnostic pop + +- (nullable NSData *)downloadedData { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _downloadedData; + } // @synchronized(self) +} + +- (void)setDownloadedData:(nullable NSData *)data { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _downloadedData = [data mutableCopy]; + } // @synchronized(self) +} + +- (int64_t)downloadedLength { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _downloadedLength; + } // @synchronized(self) +} + +- (void)setDownloadedLength:(int64_t)length { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _downloadedLength = length; + } // @synchronized(self) +} + +- (nonnull dispatch_queue_t)callbackQueue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _callbackQueue; + } // @synchronized(self) +} + +- (void)setCallbackQueue:(nullable dispatch_queue_t)queue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _callbackQueue = queue ?: dispatch_get_main_queue(); + } // @synchronized(self) +} + +- (nullable NSURLSession *)session { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _session; + } // @synchronized(self) +} + +- (NSInteger)servicePriority { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _servicePriority; + } // @synchronized(self) +} + +- (void)setServicePriority:(NSInteger)value { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (value != _servicePriority) { + GTMSESSION_ASSERT_DEBUG( + ![self isFetchingUnsynchronized], + @"servicePriority should not change after beginFetch has been invoked"); + + _servicePriority = value; + } + } // @synchronized(self) +} + +- (void)setSession:(nullable NSURLSession *)session { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _session = session; + } // @synchronized(self) +} + +- (BOOL)canShareSession { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _canShareSession; + } // @synchronized(self) +} + +- (void)setCanShareSession:(BOOL)flag { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _canShareSession = flag; + } // @synchronized(self) +} + +- (BOOL)useBackgroundSession { + // This reflects if the user requested a background session, not necessarily + // if one was created. That is tracked with _usingBackgroundSession. + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _userRequestedBackgroundSession; + } // @synchronized(self) +} + +- (void)setUseBackgroundSession:(BOOL)flag { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (flag != _userRequestedBackgroundSession) { + GTMSESSION_ASSERT_DEBUG( + ![self isFetchingUnsynchronized], + @"useBackgroundSession should not change after beginFetch has been invoked"); + + _userRequestedBackgroundSession = flag; + } + } // @synchronized(self) +} + +- (BOOL)isUsingBackgroundSession { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _usingBackgroundSession; + } // @synchronized(self) +} + +- (void)setUsingBackgroundSession:(BOOL)flag { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _usingBackgroundSession = flag; + } // @synchronized(self) +} + +- (BOOL)stopFetchingTriggersCompletionHandler { + return _stopFetchingTriggersCompletionHandler; +} + +- (void)setStopFetchingTriggersCompletionHandler:(BOOL)flag { + if (_initialBeginFetchDate == nil) { + _stopFetchingTriggersCompletionHandler = flag; + } else { + GTMSESSION_ASSERT_DEBUG( + 0, @"stopFetchingTriggersCompletionHandler should not change after fetcher starts"); + } +} + +- (nullable NSURLSession *)sessionNeedingInvalidation { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _sessionNeedingInvalidation; + } // @synchronized(self) +} + +- (void)setSessionNeedingInvalidation:(nullable NSURLSession *)session { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _sessionNeedingInvalidation = session; + } // @synchronized(self) +} + +- (nonnull NSOperationQueue *)sessionDelegateQueue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _delegateQueue; + } // @synchronized(self) +} + +- (void)setSessionDelegateQueue:(nullable NSOperationQueue *)queue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (queue != _delegateQueue) { + if ([self isFetchingUnsynchronized]) { + GTMSESSION_ASSERT_DEBUG(0, @"sessionDelegateQueue should not change after fetch begins"); + } else { + _delegateQueue = queue ?: [NSOperationQueue mainQueue]; + } + } + } // @synchronized(self) +} + +- (BOOL)userStoppedFetching { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _userStoppedFetching; + } // @synchronized(self) +} + +- (nullable id)userData { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _userData; + } // @synchronized(self) +} + +- (void)setUserData:(nullable id)theObj { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _userData = theObj; + } // @synchronized(self) +} + +- (nullable NSURL *)destinationFileURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _destinationFileURL; + } // @synchronized(self) +} + +- (void)setDestinationFileURL:(nullable NSURL *)destinationFileURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (((_destinationFileURL == nil) && (destinationFileURL == nil)) || + [_destinationFileURL isEqual:destinationFileURL]) { + return; + } + if (_sessionIdentifier) { + // This is something we don't expect to happen in production. + // However if it ever happen, leave a system log. + NSLog(@"%@: Destination File URL changed from (%@) to (%@) after session identifier has " + @"been created.", + [self class], _destinationFileURL, destinationFileURL); +#if DEBUG + // On both the simulator and devices, the path can change to the download file, but the name + // shouldn't change. Technically, this isn't supported in the fetcher, but the change of + // URL is expected to happen only across development runs through Xcode. + __unused NSString *oldFilename = [_destinationFileURL lastPathComponent]; + __unused NSString *newFilename = [destinationFileURL lastPathComponent]; + GTMSESSION_ASSERT_DEBUG( + [oldFilename isEqualToString:newFilename], + @"Destination File URL cannot be changed after session identifier has been created"); +#endif + } + _destinationFileURL = destinationFileURL; + } // @synchronized(self) +} + +- (void)setProperties:(nullable NSDictionary *)dict { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _properties = [dict mutableCopy]; + } // @synchronized(self) +} + +- (nullable NSDictionary *)properties { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _properties; + } // @synchronized(self) +} + +- (void)setProperty:(nullable id)obj forKey:(NSString *)key { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_properties == nil && obj != nil) { + _properties = [[NSMutableDictionary alloc] init]; + } + [_properties setValue:obj forKey:key]; + } // @synchronized(self) +} + +- (nullable id)propertyForKey:(NSString *)key { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [_properties objectForKey:key]; + } // @synchronized(self) +} + +- (void)addPropertiesFromDictionary:(NSDictionary *)dict { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_properties == nil && dict != nil) { + [self setProperties:[dict mutableCopy]]; + } else { + [_properties addEntriesFromDictionary:dict]; + } + } // @synchronized(self) +} + +- (void)setCommentWithFormat:(id)format, ... { +#if !STRIP_GTM_FETCH_LOGGING + NSString *result = format; + if (format) { + va_list argList; + va_start(argList, format); + + result = [[NSString alloc] initWithFormat:format arguments:argList]; + va_end(argList); + } + [self setComment:result]; +#endif +} + +#if !STRIP_GTM_FETCH_LOGGING +- (NSData *)loggedStreamData { + return _loggedStreamData; +} + +- (void)appendLoggedStreamData:dataToAdd { + if (!_loggedStreamData) { + _loggedStreamData = [NSMutableData data]; + } + [_loggedStreamData appendData:dataToAdd]; +} + +- (void)clearLoggedStreamData { + _loggedStreamData = nil; +} + +- (void)setDeferResponseBodyLogging:(BOOL)deferResponseBodyLogging { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (deferResponseBodyLogging != _deferResponseBodyLogging) { + _deferResponseBodyLogging = deferResponseBodyLogging; + if (!deferResponseBodyLogging && !self.hasLoggedError) { + [_delegateQueue addOperationWithBlock:^{ + [self logNowWithError:nil]; + }]; + } + } + } // @synchronized(self) +} + +- (BOOL)deferResponseBodyLogging { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _deferResponseBodyLogging; + } // @synchronized(self) +} + +#else ++ (void)setLoggingEnabled:(BOOL)flag { +} + ++ (BOOL)isLoggingEnabled { + return NO; +} +#endif // STRIP_GTM_FETCH_LOGGING + +@end + +@implementation GTMSessionCookieStorage { + NSMutableArray *_cookies; + NSHTTPCookieAcceptPolicy _policy; +} + +- (id)init { + self = [super init]; + if (self != nil) { + _cookies = [[NSMutableArray alloc] init]; + } + return self; +} + +- (nullable NSArray *)cookies { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [_cookies copy]; + } // @synchronized(self) +} + +- (void)setCookie:(NSHTTPCookie *)cookie { + if (!cookie) return; + if (_policy == NSHTTPCookieAcceptPolicyNever) return; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [self internalSetCookie:cookie]; + } // @synchronized(self) +} + +// Note: this should only be called from inside a @synchronized(self) block. +- (void)internalSetCookie:(NSHTTPCookie *)newCookie { + GTMSessionCheckSynchronized(self); + + if (_policy == NSHTTPCookieAcceptPolicyNever) return; + + BOOL isValidCookie = + (newCookie.name.length > 0 && newCookie.domain.length > 0 && newCookie.path.length > 0); + GTMSESSION_ASSERT_DEBUG(isValidCookie, @"invalid cookie: %@", newCookie); + + if (isValidCookie) { + // Remove the cookie if it's currently in the array. + NSHTTPCookie *oldCookie = [self cookieMatchingCookie:newCookie]; + if (oldCookie) { + [_cookies removeObjectIdenticalTo:oldCookie]; + } + + if (![[self class] hasCookieExpired:newCookie]) { + [_cookies addObject:newCookie]; + } + } +} + +// Add all cookies in the new cookie array to the storage, +// replacing stored cookies as appropriate. +// +// Side effect: removes expired cookies from the storage array. +- (void)setCookies:(nullable NSArray *)newCookies { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [self removeExpiredCookies]; + + for (NSHTTPCookie *newCookie in newCookies) { + [self internalSetCookie:newCookie]; + } + } // @synchronized(self) +} + +- (void)setCookies:(NSArray *)cookies + forURL:(nullable NSURL *)URL + mainDocumentURL:(nullable NSURL *)mainDocumentURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_policy == NSHTTPCookieAcceptPolicyNever) { + return; + } + + if (_policy == NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain) { + NSString *mainHost = mainDocumentURL.host; + NSString *associatedHost = URL.host; + if (!mainHost || ![associatedHost hasSuffix:mainHost]) { + return; + } + } + } // @synchronized(self) + [self setCookies:cookies]; +} + +- (void)deleteCookie:(NSHTTPCookie *)cookie { + if (!cookie) return; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSHTTPCookie *foundCookie = [self cookieMatchingCookie:cookie]; + if (foundCookie) { + [_cookies removeObjectIdenticalTo:foundCookie]; + } + } // @synchronized(self) +} + +// Retrieve all cookies appropriate for the given URL, considering +// domain, path, cookie name, expiration, security setting. +// Side effect: removed expired cookies from the storage array. +- (nullable NSArray *)cookiesForURL:(NSURL *)theURL { + NSMutableArray *foundCookies = nil; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [self removeExpiredCookies]; + + // We'll prepend "." to the desired domain, since we want the + // actual domain "nytimes.com" to still match the cookie domain + // ".nytimes.com" when we check it below with hasSuffix. + NSString *host = theURL.host.lowercaseString; + NSString *path = theURL.path; + NSString *scheme = [theURL scheme]; + + NSString *requestingDomain = nil; + BOOL isLocalhostRetrieval = NO; + + if (IsLocalhost(host)) { + isLocalhostRetrieval = YES; + } else { + if (host.length > 0) { + requestingDomain = [@"." stringByAppendingString:host]; + } + } + + for (NSHTTPCookie *storedCookie in _cookies) { + NSString *cookieDomain = storedCookie.domain.lowercaseString; + NSString *cookiePath = storedCookie.path; + BOOL cookieIsSecure = [storedCookie isSecure]; + + BOOL isDomainOK; + + if (isLocalhostRetrieval) { + // Prior to 10.5.6, the domain stored into NSHTTPCookies for localhost + // is "localhost.local" + isDomainOK = (IsLocalhost(cookieDomain) || [cookieDomain isEqual:@"localhost.local"]); + } else { + // Ensure we're matching exact domain names. We prepended a dot to the + // requesting domain, so we can also prepend one here if needed before + // checking if the request contains the cookie domain. + if (![cookieDomain hasPrefix:@"."]) { + cookieDomain = [@"." stringByAppendingString:cookieDomain]; + } + isDomainOK = [requestingDomain hasSuffix:cookieDomain]; + } + + BOOL isPathOK = [cookiePath isEqual:@"/"] || [path hasPrefix:cookiePath]; + BOOL isSecureOK = + (!cookieIsSecure || [scheme caseInsensitiveCompare:@"https"] == NSOrderedSame); + + if (isDomainOK && isPathOK && isSecureOK) { + if (foundCookies == nil) { + foundCookies = [NSMutableArray array]; + } + [foundCookies addObject:storedCookie]; + } + } + } // @synchronized(self) + return foundCookies; +} + +// Override methods from the NSHTTPCookieStorage (NSURLSessionTaskAdditions) category. +- (void)storeCookies:(NSArray *)cookies forTask:(NSURLSessionTask *)task { + NSURLRequest *currentRequest = task.currentRequest; + [self setCookies:cookies forURL:currentRequest.URL mainDocumentURL:nil]; +} + +- (void)getCookiesForTask:(NSURLSessionTask *)task + completionHandler:(void (^)(NSArray *))completionHandler { + if (completionHandler) { + NSURLRequest *currentRequest = task.currentRequest; + NSURL *currentRequestURL = currentRequest.URL; + NSArray *cookies = [self cookiesForURL:currentRequestURL]; + completionHandler(cookies); + } +} + +// Return a cookie from the array with the same name, domain, and path as the +// given cookie, or else return nil if none found. +// +// Both the cookie being tested and all cookies in the storage array should +// be valid (non-nil name, domains, paths). +// +// Note: this should only be called from inside a @synchronized(self) block +- (nullable NSHTTPCookie *)cookieMatchingCookie:(NSHTTPCookie *)cookie { + GTMSessionCheckSynchronized(self); + + NSString *name = cookie.name; + NSString *domain = cookie.domain; + NSString *path = cookie.path; + + GTMSESSION_ASSERT_DEBUG(name && domain && path, + @"Invalid stored cookie (name:%@ domain:%@ path:%@)", name, domain, path); + + for (NSHTTPCookie *storedCookie in _cookies) { + if ([storedCookie.name isEqual:name] && [storedCookie.domain isEqual:domain] && + [storedCookie.path isEqual:path]) { + return storedCookie; + } + } + return nil; +} + +// Internal routine to remove any expired cookies from the array, excluding +// cookies with nil expirations. +// +// Note: this should only be called from inside a @synchronized(self) block +- (void)removeExpiredCookies { + GTMSessionCheckSynchronized(self); + + // Count backwards since we're deleting items from the array + for (NSInteger idx = (NSInteger)_cookies.count - 1; idx >= 0; idx--) { + NSHTTPCookie *storedCookie = [_cookies objectAtIndex:(NSUInteger)idx]; + if ([[self class] hasCookieExpired:storedCookie]) { + [_cookies removeObjectAtIndex:(NSUInteger)idx]; + } + } +} + ++ (BOOL)hasCookieExpired:(NSHTTPCookie *)cookie { + NSDate *expiresDate = [cookie expiresDate]; + if (expiresDate == nil) { + // Cookies seem to have a Expires property even when the expiresDate method returns nil. + id expiresVal = [[cookie properties] objectForKey:NSHTTPCookieExpires]; + if ([expiresVal isKindOfClass:[NSDate class]]) { + expiresDate = expiresVal; + } + } + BOOL hasExpired = (expiresDate != nil && [expiresDate timeIntervalSinceNow] < 0); + return hasExpired; +} + +- (void)removeAllCookies { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [_cookies removeAllObjects]; + } // @synchronized(self) +} + +- (NSHTTPCookieAcceptPolicy)cookieAcceptPolicy { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _policy; + } // @synchronized(self) +} + +- (void)setCookieAcceptPolicy:(NSHTTPCookieAcceptPolicy)cookieAcceptPolicy { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _policy = cookieAcceptPolicy; + } // @synchronized(self) +} + +@end + +void GTMSessionFetcherAssertValidSelector(id _Nullable obj, SEL _Nullable sel, ...) { + // Verify that the object's selector is implemented with the proper + // number and type of arguments +#if DEBUG + va_list argList; + va_start(argList, sel); + + if (obj && sel) { + // Check that the selector is implemented + if (![obj respondsToSelector:sel]) { + NSLog(@"\"%@\" selector \"%@\" is unimplemented or misnamed", + NSStringFromClass([(id)obj class]), NSStringFromSelector((SEL)sel)); + NSCAssert(0, @"callback selector unimplemented or misnamed"); + } else { + const char *expectedArgType; + unsigned int argCount = 2; // skip self and _cmd + NSMethodSignature *sig = [obj methodSignatureForSelector:sel]; + + // Check that each expected argument is present and of the correct type + while ((expectedArgType = va_arg(argList, const char *)) != 0) { + if ([sig numberOfArguments] > argCount) { + const char *foundArgType = [sig getArgumentTypeAtIndex:argCount]; + + if (0 != strncmp(foundArgType, expectedArgType, strlen(expectedArgType))) { + NSLog(@"\"%@\" selector \"%@\" argument %d should be type %s", + NSStringFromClass([(id)obj class]), NSStringFromSelector((SEL)sel), + (argCount - 2), expectedArgType); + NSCAssert(0, @"callback selector argument type mistake"); + } + } + argCount++; + } + + // Check that the proper number of arguments are present in the selector + if (argCount != [sig numberOfArguments]) { + NSLog(@"\"%@\" selector \"%@\" should have %d arguments", + NSStringFromClass([(id)obj class]), NSStringFromSelector((SEL)sel), (argCount - 2)); + NSCAssert(0, @"callback selector arguments incorrect"); + } + } + } + + va_end(argList); +#endif +} + +NSString *GTMFetcherCleanedUserAgentString(NSString *str) { + // Reference http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html + // and http://www-archive.mozilla.org/build/user-agent-strings.html + + if (str == nil) return @""; + + NSMutableString *result = [NSMutableString stringWithString:str]; + + // Replace spaces and commas with underscores + [result replaceOccurrencesOfString:@" " + withString:@"_" + options:0 + range:NSMakeRange(0, result.length)]; + [result replaceOccurrencesOfString:@"," + withString:@"_" + options:0 + range:NSMakeRange(0, result.length)]; + + // Delete http token separators and remaining whitespace + static NSCharacterSet *charsToDelete = nil; + if (charsToDelete == nil) { + // Make a set of unwanted characters + NSString *const kSeparators = @"()<>@;:\\\"/[]?={}"; + + NSMutableCharacterSet *mutableChars = + [[NSCharacterSet whitespaceAndNewlineCharacterSet] mutableCopy]; + [mutableChars addCharactersInString:kSeparators]; + charsToDelete = [mutableChars copy]; // hang on to an immutable copy + } + + while (1) { + NSRange separatorRange = [result rangeOfCharacterFromSet:charsToDelete]; + if (separatorRange.location == NSNotFound) break; + + [result deleteCharactersInRange:separatorRange]; + }; + + return result; +} + +NSString *GTMFetcherSystemVersionString(void) { + static NSString *sSavedSystemString; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ +#if TARGET_OS_WATCH + // watchOS - WKInterfaceDevice + + WKInterfaceDevice *currentDevice = [WKInterfaceDevice currentDevice]; + + NSString *rawModel = [currentDevice model]; + NSString *model = GTMFetcherCleanedUserAgentString(rawModel); + + NSString *systemVersion = [currentDevice systemVersion]; + +#if TARGET_OS_SIMULATOR + NSString *hardwareModel = @"sim"; +#else + NSString *hardwareModel; + struct utsname unameRecord; + if (uname(&unameRecord) == 0) { + NSString *machineName = @(unameRecord.machine); + hardwareModel = GTMFetcherCleanedUserAgentString(machineName); + } + if (hardwareModel.length == 0) { + hardwareModel = @"unk"; + } +#endif + + sSavedSystemString = + [[NSString alloc] initWithFormat:@"%@/%@ hw/%@", model, systemVersion, hardwareModel]; + // Example: Apple_Watch/3.0 hw/Watch1_2 +#elif TARGET_OS_TV || TARGET_OS_IOS + // iOS and tvOS have UIDevice, use that. + UIDevice *currentDevice = [UIDevice currentDevice]; + + NSString *rawModel = [currentDevice model]; + NSString *model = GTMFetcherCleanedUserAgentString(rawModel); + + NSString *systemVersion = [currentDevice systemVersion]; + +#if TARGET_OS_SIMULATOR + NSString *hardwareModel = @"sim"; +#else + NSString *hardwareModel; + struct utsname unameRecord; + if (uname(&unameRecord) == 0) { + NSString *machineName = @(unameRecord.machine); + hardwareModel = GTMFetcherCleanedUserAgentString(machineName); + } + if (hardwareModel.length == 0) { + hardwareModel = @"unk"; + } +#endif + + sSavedSystemString = [[NSString alloc] initWithFormat:@"%@/%@ hw/%@", + model, systemVersion, hardwareModel]; + // Example: iPod_Touch/2.2 hw/iPod1_1 + // Example: Apple_TV/9.2 hw/AppleTV5,3 +#elif TARGET_OS_OSX + // Mac build + NSProcessInfo *procInfo = [NSProcessInfo processInfo]; + NSString *versString; + NSOperatingSystemVersion version = procInfo.operatingSystemVersion; + versString = [NSString stringWithFormat:@"%ld.%ld.%ld", (long)version.majorVersion, + (long)version.minorVersion, (long)version.patchVersion]; + + sSavedSystemString = [[NSString alloc] initWithFormat:@"MacOSX/%@", versString]; +#elif defined(_SYS_UTSNAME_H) + // Foundation-only build + struct utsname unameRecord; + uname(&unameRecord); + + sSavedSystemString = [NSString stringWithFormat:@"%s/%s", + unameRecord.sysname, unameRecord.release]; // "Darwin/8.11.1" +#else +#error No branch taken for a default user agent +#endif + }); + return sSavedSystemString; +} + +NSString *GTMFetcherStandardUserAgentString(NSBundle *_Nullable bundle) { + NSString *result = [NSString stringWithFormat:@"%@ %@", GTMFetcherApplicationIdentifier(bundle), + GTMFetcherSystemVersionString()]; + return result; +} + +NSString *GTMFetcherApplicationIdentifier(NSBundle *_Nullable bundle) { + @synchronized([GTMSessionFetcher class]) { + static NSMutableDictionary *sAppIDMap = nil; + + // If there's a bundle ID, use that; otherwise, use the process name + if (bundle == nil) { + bundle = [NSBundle mainBundle]; + } + NSString *bundleID = [bundle bundleIdentifier]; + if (bundleID == nil) { + bundleID = @""; + } + + NSString *identifier = [sAppIDMap objectForKey:bundleID]; + if (identifier) return identifier; + + // Apps may add a string to the info.plist to uniquely identify different builds. + identifier = [bundle objectForInfoDictionaryKey:@"GTMUserAgentID"]; + if (identifier.length == 0) { + if (bundleID.length > 0) { + identifier = bundleID; + } else { + // Fall back on the procname, prefixed by "proc" to flag that it's + // autogenerated and perhaps unreliable + NSString *procName = [[NSProcessInfo processInfo] processName]; + identifier = [NSString stringWithFormat:@"proc_%@", procName]; + } + } + + // Clean up whitespace and special characters + identifier = GTMFetcherCleanedUserAgentString(identifier); + + // If there's a version number, append that + NSString *version = [bundle objectForInfoDictionaryKey:@"GTMUserAgentVersion"]; + if (version.length == 0) { + version = [bundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; + if (version.length == 0) { + version = [bundle objectForInfoDictionaryKey:@"CFBundleVersion"]; + } + } + + // Clean up whitespace and special characters + version = GTMFetcherCleanedUserAgentString(version); + + // Glue the two together (cleanup done above or else cleanup would strip the + // slash) + if (version.length > 0) { + identifier = [identifier stringByAppendingFormat:@"/%@", version]; + } + + if (sAppIDMap == nil) { + sAppIDMap = [[NSMutableDictionary alloc] init]; + } + [sAppIDMap setObject:identifier forKey:bundleID]; + return identifier; + } +} + +#if DEBUG && (!defined(NS_BLOCK_ASSERTIONS) || GTMSESSION_ASSERT_AS_LOG) +@implementation GTMSessionSyncMonitorInternal { + NSValue *_objectKey; // The synchronize target object. + const char *_functionName; // The function containing the monitored sync block. +} + +- (instancetype)initWithSynchronizationObject:(id)object + allowRecursive:(BOOL)allowRecursive + functionName:(const char *)functionName { + self = [super init]; + if (self) { + Class threadKey = [GTMSessionSyncMonitorInternal class]; + _objectKey = [NSValue valueWithNonretainedObject:object]; + _functionName = functionName; + + NSMutableDictionary *threadDict = [NSThread currentThread].threadDictionary; + NSMutableDictionary *counters = threadDict[threadKey]; + if (counters == nil) { + counters = [NSMutableDictionary dictionary]; + threadDict[(id)threadKey] = counters; + } + NSCountedSet *functionNamesCounter = counters[_objectKey]; + NSUInteger numberOfSyncingFunctions = functionNamesCounter.count; + + if (!allowRecursive) { + BOOL isTopLevelSyncScope = (numberOfSyncingFunctions == 0); + NSArray *stack = [NSThread callStackSymbols]; + GTMSESSION_ASSERT_DEBUG(isTopLevelSyncScope, + @"*** Recursive sync on %@ at %s; previous sync at %@\n%@", + [object class], functionName, functionNamesCounter.allObjects, + [stack subarrayWithRange:NSMakeRange(1, stack.count - 1)]); + } + + if (!functionNamesCounter) { + functionNamesCounter = [NSCountedSet set]; + counters[_objectKey] = functionNamesCounter; + } + [functionNamesCounter addObject:(id _Nonnull) @(functionName)]; + } + return self; +} + +- (void)dealloc { + Class threadKey = [GTMSessionSyncMonitorInternal class]; + + NSMutableDictionary *threadDict = [NSThread currentThread].threadDictionary; + NSMutableDictionary *counters = threadDict[threadKey]; + NSCountedSet *functionNamesCounter = counters[_objectKey]; + NSString *functionNameStr = @(_functionName); + NSUInteger numberOfSyncsByThisFunction = [functionNamesCounter countForObject:functionNameStr]; + NSArray *stack = [NSThread callStackSymbols]; + GTMSESSION_ASSERT_DEBUG(numberOfSyncsByThisFunction > 0, @"Sync not found on %@ at %s\n%@", + [_objectKey.nonretainedObjectValue class], _functionName, + [stack subarrayWithRange:NSMakeRange(1, stack.count - 1)]); + [functionNamesCounter removeObject:functionNameStr]; + if (functionNamesCounter.count == 0) { + [counters removeObjectForKey:_objectKey]; + } +} + ++ (nullable NSArray *)functionsHoldingSynchronizationOnObject:(id)object { + Class threadKey = [GTMSessionSyncMonitorInternal class]; + NSValue *localObjectKey = [NSValue valueWithNonretainedObject:object]; + + NSMutableDictionary *threadDict = [NSThread currentThread].threadDictionary; + NSMutableDictionary *counters = threadDict[threadKey]; + NSCountedSet *functionNamesCounter = counters[localObjectKey]; + return functionNamesCounter.count > 0 ? functionNamesCounter.allObjects : nil; +} +@end +#endif // DEBUG && (!defined(NS_BLOCK_ASSERTIONS) || GTMSESSION_ASSERT_AS_LOG) +NS_ASSUME_NONNULL_END diff --git a/Pods/GTMSessionFetcher/Sources/Core/GTMSessionFetcherLogging.m b/Pods/GTMSessionFetcher/Sources/Core/GTMSessionFetcherLogging.m new file mode 100644 index 0000000..ca853c5 --- /dev/null +++ b/Pods/GTMSessionFetcher/Sources/Core/GTMSessionFetcherLogging.m @@ -0,0 +1,917 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * 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. + */ + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#include +#include + +#import "GTMSessionFetcher/GTMSessionFetcherLogging.h" + +#ifndef STRIP_GTM_FETCH_LOGGING +#error GTMSessionFetcher headers should have defaulted this if it wasn't already defined. +#endif + +#if !STRIP_GTM_FETCH_LOGGING + +// Sensitive credential strings are replaced in logs with _snip_ +// +// Apps that must see the contents of sensitive tokens can set this to 1 +#ifndef SKIP_GTM_FETCH_LOGGING_SNIPPING +#define SKIP_GTM_FETCH_LOGGING_SNIPPING 0 +#endif + +// If GTMReadMonitorInputStream is available, it can be used for +// capturing uploaded streams of data +// +// We locally declare methods of GTMReadMonitorInputStream so we +// do not need to import the header, as some projects may not have it available +#if !GTMSESSION_BUILD_COMBINED_SOURCES +@interface GTMReadMonitorInputStream : NSInputStream + ++ (instancetype)inputStreamWithStream:(NSInputStream *)input; + +@property(assign) id readDelegate; +@property(assign) SEL readSelector; + +@end +#else +@class GTMReadMonitorInputStream; +#endif // !GTMSESSION_BUILD_COMBINED_SOURCES + +@interface GTMSessionFetcher (GTMSessionFetcherLoggingUtilities) + ++ (NSString *)headersStringForDictionary:(NSDictionary *)dict; ++ (NSString *)snipSubstringOfString:(NSString *)originalStr + betweenStartString:(NSString *)startStr + endString:(NSString *)endStr; +- (void)inputStream:(GTMReadMonitorInputStream *)stream + readIntoBuffer:(void *)buffer + length:(int64_t)length; + +@end + +@implementation GTMSessionFetcher (GTMSessionFetcherLogging) + +// fetchers come and fetchers go, but statics are forever +static BOOL gIsLoggingEnabled = NO; +static BOOL gIsLoggingToFile = YES; +static NSString *gLoggingDirectoryPath = nil; +static NSString *gLogDirectoryForCurrentRun = nil; +static NSString *gLoggingDateStamp = nil; +static NSString *gLoggingProcessName = nil; + ++ (void)setLoggingDirectory:(NSString *)path { + gLoggingDirectoryPath = [path copy]; +} + ++ (NSString *)loggingDirectory { + if (!gLoggingDirectoryPath) { + NSArray *paths = nil; +#if TARGET_IPHONE_SIMULATOR + // default to a directory called GTMHTTPDebugLogs into a sandbox-safe + // directory that a developer can find easily, the application home + paths = @[ NSHomeDirectory() ]; +#elif TARGET_OS_IPHONE + // Neither ~/Desktop nor ~/Home is writable on an actual iOS, watchOS, or tvOS device. + // Put it in ~/Documents. + paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); +#else + // default to a directory called GTMHTTPDebugLogs in the desktop folder + paths = NSSearchPathForDirectoriesInDomains(NSDesktopDirectory, NSUserDomainMask, YES); +#endif + + NSString *desktopPath = paths.firstObject; + if (desktopPath) { + NSString *const kGTMLogFolderName = @"GTMHTTPDebugLogs"; + NSString *logsFolderPath = [desktopPath stringByAppendingPathComponent:kGTMLogFolderName]; + + NSFileManager *fileMgr = [NSFileManager defaultManager]; + BOOL isDir; + BOOL doesFolderExist = [fileMgr fileExistsAtPath:logsFolderPath isDirectory:&isDir]; + if (!doesFolderExist) { + // make the directory + doesFolderExist = [fileMgr createDirectoryAtPath:logsFolderPath + withIntermediateDirectories:YES + attributes:nil + error:NULL]; + if (doesFolderExist) { + // The directory has been created. Exclude it from backups. + NSURL *pathURL = [NSURL fileURLWithPath:logsFolderPath isDirectory:YES]; + [pathURL setResourceValue:@YES forKey:NSURLIsExcludedFromBackupKey error:NULL]; + } + } + + if (doesFolderExist) { + // it's there; store it in the global + gLoggingDirectoryPath = [logsFolderPath copy]; + } + } + } + return gLoggingDirectoryPath; +} + ++ (void)setLogDirectoryForCurrentRun:(NSString *)logDirectoryForCurrentRun { + // Set the path for this run's logs. + gLogDirectoryForCurrentRun = [logDirectoryForCurrentRun copy]; +} + ++ (NSString *)logDirectoryForCurrentRun { + // make a directory for this run's logs, like SyncProto_logs_10-16_01-56-58PM + if (gLogDirectoryForCurrentRun) return gLogDirectoryForCurrentRun; + + NSString *parentDir = [self loggingDirectory]; + NSString *logNamePrefix = [self processNameLogPrefix]; + NSString *dateStamp = [self loggingDateStamp]; + NSString *dirName = [NSString stringWithFormat:@"%@%@", logNamePrefix, dateStamp]; + NSString *logDirectory = [parentDir stringByAppendingPathComponent:dirName]; + + if (gIsLoggingToFile) { + NSFileManager *fileMgr = [NSFileManager defaultManager]; + // Be sure that the first time this app runs, it's not writing to a preexisting folder + static BOOL gShouldReuseFolder = NO; + if (!gShouldReuseFolder) { + gShouldReuseFolder = YES; + NSString *origLogDir = logDirectory; + for (int ctr = 2; ctr < 20; ++ctr) { + if (![fileMgr fileExistsAtPath:logDirectory]) break; + + // append a digit + logDirectory = [origLogDir stringByAppendingFormat:@"_%d", ctr]; + } + } + if (![fileMgr createDirectoryAtPath:logDirectory + withIntermediateDirectories:YES + attributes:nil + error:NULL]) + return nil; + } + gLogDirectoryForCurrentRun = logDirectory; + + return gLogDirectoryForCurrentRun; +} + ++ (void)setLoggingEnabled:(BOOL)isLoggingEnabled { + gIsLoggingEnabled = isLoggingEnabled; +} + ++ (BOOL)isLoggingEnabled { + return gIsLoggingEnabled; +} + ++ (void)setLoggingToFileEnabled:(BOOL)isLoggingToFileEnabled { + gIsLoggingToFile = isLoggingToFileEnabled; +} + ++ (BOOL)isLoggingToFileEnabled { + return gIsLoggingToFile; +} + ++ (void)setLoggingProcessName:(NSString *)processName { + gLoggingProcessName = [processName copy]; +} + ++ (NSString *)loggingProcessName { + // get the process name (once per run) replacing spaces with underscores + if (!gLoggingProcessName) { + NSString *procName = [[NSProcessInfo processInfo] processName]; + gLoggingProcessName = [procName stringByReplacingOccurrencesOfString:@" " withString:@"_"]; + } + return gLoggingProcessName; +} + ++ (void)setLoggingDateStamp:(NSString *)dateStamp { + gLoggingDateStamp = [dateStamp copy]; +} + ++ (NSString *)loggingDateStamp { + // We'll pick one date stamp per run, so a run that starts at a later second + // will get a unique results html file + if (!gLoggingDateStamp) { + // produce a string like 08-21_01-41-23PM + + NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; + [formatter setFormatterBehavior:NSDateFormatterBehavior10_4]; + [formatter setDateFormat:@"M-dd_hh-mm-ssa"]; + + gLoggingDateStamp = [formatter stringFromDate:[NSDate date]]; + } + return gLoggingDateStamp; +} + ++ (NSString *)processNameLogPrefix { + static NSString *gPrefix = nil; + if (!gPrefix) { + NSString *processName = [self loggingProcessName]; + gPrefix = [[NSString alloc] initWithFormat:@"%@_log_", processName]; + } + return gPrefix; +} + ++ (NSString *)symlinkNameSuffix { + return @"_log_newest.html"; +} + ++ (NSString *)htmlFileName { + return @"aperçu_http_log.html"; +} + ++ (void)deleteLogDirectoriesOlderThanDate:(NSDate *)cutoffDate { + NSFileManager *fileMgr = [NSFileManager defaultManager]; + NSURL *parentDir = [NSURL fileURLWithPath:[[self class] loggingDirectory]]; + NSURL *logDirectoryForCurrentRun = + [NSURL fileURLWithPath:[[self class] logDirectoryForCurrentRun]]; + NSError *error; + NSArray *contents = [fileMgr contentsOfDirectoryAtURL:parentDir + includingPropertiesForKeys:@[ NSURLContentModificationDateKey ] + options:0 + error:&error]; + for (NSURL *itemURL in contents) { + if ([itemURL isEqual:logDirectoryForCurrentRun]) continue; + + NSDate *modDate; + if ([itemURL getResourceValue:&modDate forKey:NSURLContentModificationDateKey error:&error]) { + if ([modDate compare:cutoffDate] == NSOrderedAscending) { + if (![fileMgr removeItemAtURL:itemURL error:&error]) { + NSLog(@"deleteLogDirectoriesOlderThanDate failed to delete %@: %@", itemURL.path, error); + } + } + } else { + NSLog(@"deleteLogDirectoriesOlderThanDate failed to get mod date of %@: %@", itemURL.path, + error); + } + } +} + +// formattedStringFromData returns a prettyprinted string for JSON input, +// and a plain string for other input data +- (NSString *)formattedStringFromData:(NSData *)inputData + contentType:(NSString *)contentType + JSON:(NSDictionary **)outJSON { + if (!inputData) return nil; + + // if the content type is JSON and we have the parsing class available, use that + if ([contentType hasPrefix:@"application/json"] && inputData.length > 5) { + // convert from JSON string to NSObjects and back to a formatted string + NSMutableDictionary *obj = + [NSJSONSerialization JSONObjectWithData:inputData + options:NSJSONReadingMutableContainers + error:NULL]; + if (obj) { + if (outJSON) *outJSON = obj; + if ([obj isKindOfClass:[NSMutableDictionary class]]) { + // for security and privacy, omit OAuth 2 response access and refresh tokens + if ([obj valueForKey:@"refresh_token"] != nil) { + [obj setObject:@"_snip_" forKey:@"refresh_token"]; + } + if ([obj valueForKey:@"access_token"] != nil) { + [obj setObject:@"_snip_" forKey:@"access_token"]; + } + } + NSData *data = [NSJSONSerialization dataWithJSONObject:obj + options:NSJSONWritingPrettyPrinted + error:NULL]; + if (data) { + NSString *jsonStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + return jsonStr; + } + } + } + + NSString *dataStr = [[NSString alloc] initWithData:inputData encoding:NSUTF8StringEncoding]; + return dataStr; +} + +// stringFromStreamData creates a string given the supplied data +// +// If NSString can create a UTF-8 string from the data, then that is returned. +// +// Otherwise, this routine tries to find a MIME boundary at the beginning of the data block, and +// uses that to break up the data into parts. Each part will be used to try to make a UTF-8 string. +// For parts that fail, a replacement string showing the part header and <> is supplied +// in place of the binary data. + +- (NSString *)stringFromStreamData:(NSData *)data contentType:(NSString *)contentType { + if (!data) return nil; + + // optimistically, see if the whole data block is UTF-8 + NSString *streamDataStr = [self formattedStringFromData:data contentType:contentType JSON:NULL]; + if (streamDataStr) return streamDataStr; + + // Munge a buffer by replacing non-ASCII bytes with underscores, and turn that munged buffer an + // NSString. That gives us a string we can use with NSScanner. + NSMutableData *mutableData = [NSMutableData dataWithData:data]; + unsigned char *bytes = (unsigned char *)mutableData.mutableBytes; + + for (unsigned int idx = 0; idx < mutableData.length; ++idx) { + if (bytes[idx] > 0x7F || bytes[idx] == 0) { + bytes[idx] = '_'; + } + } + + NSString *mungedStr = [[NSString alloc] initWithData:mutableData encoding:NSUTF8StringEncoding]; + if (mungedStr) { + // scan for the boundary string + NSString *boundary = nil; + NSScanner *scanner = [NSScanner scannerWithString:mungedStr]; + + if ([scanner scanUpToString:@"\r\n" intoString:&boundary] && [boundary hasPrefix:@"--"]) { + // we found a boundary string; use it to divide the string into parts + NSArray *mungedParts = [mungedStr componentsSeparatedByString:boundary]; + + // look at each munged part in the original string, and try to convert those into UTF-8 + NSMutableArray *origParts = [NSMutableArray array]; + NSUInteger offset = 0; + for (NSString *mungedPart in mungedParts) { + NSUInteger partSize = mungedPart.length; + NSData *origPartData = [data subdataWithRange:NSMakeRange(offset, partSize)]; + NSString *origPartStr = [[NSString alloc] initWithData:origPartData + encoding:NSUTF8StringEncoding]; + if (origPartStr) { + // we could make this original part into UTF-8; use the string + [origParts addObject:origPartStr]; + } else { + // this part can't be made into UTF-8; scan the header, if we can + NSString *header = nil; + NSScanner *headerScanner = [NSScanner scannerWithString:mungedPart]; + if (![headerScanner scanUpToString:@"\r\n\r\n" intoString:&header]) { + // we couldn't find a header + header = @""; + } + // make a part string with the header and <> + NSString *binStr = [NSString + stringWithFormat:@"\r%@\r<<%lu bytes>>\r", header, (long)(partSize - header.length)]; + [origParts addObject:binStr]; + } + offset += partSize + boundary.length; + } + // rejoin the original parts + streamDataStr = [origParts componentsJoinedByString:boundary]; + } + } + if (!streamDataStr) { + // give up; just make a string showing the uploaded bytes + streamDataStr = [NSString stringWithFormat:@"<<%u bytes>>", (unsigned int)data.length]; + } + return streamDataStr; +} + +// logFetchWithError is called following a successful or failed fetch attempt +// +// This method does all the work for appending to and creating log files + +- (void)logFetchWithError:(NSError *)error { + if (![[self class] isLoggingEnabled]) return; + NSString *logDirectory = [[self class] logDirectoryForCurrentRun]; + if (!logDirectory) return; + NSString *processName = [[self class] loggingProcessName]; + + // TODO: add Javascript to display response data formatted in hex + + // each response's NSData goes into its own xml or txt file, though all responses for this run of + // the app share a main html file. This counter tracks all fetch responses for this app run. + // + // we'll use a local variable since this routine may be reentered while waiting for formatting + // to be completed. + static int gResponseCounter = 0; + int responseCounter = ++gResponseCounter; + + NSURLResponse *response = [self response]; + NSDictionary *responseHeaders = [self responseHeaders]; + NSString *responseDataStr = nil; + NSDictionary *responseJSON = nil; + + // if there's response data, decide what kind of file to put it in based on the first bytes of the + // file or on the mime type supplied by the server + NSString *responseMIMEType = [response MIMEType]; + BOOL isResponseImage = NO; + + // file name for an image data file + NSString *responseDataFileName = nil; + + int64_t responseDataLength = self.downloadedLength; + if (responseDataLength > 0) { + NSData *downloadedData = self.downloadedData; + if (downloadedData == nil && responseDataLength > 0 && responseDataLength < 20000 && + self.destinationFileURL) { + // There's a download file that's not too big, so get the data to display from the downloaded + // file. + NSURL *destinationURL = self.destinationFileURL; + downloadedData = [NSData dataWithContentsOfURL:destinationURL]; + } + NSString *responseType = [responseHeaders valueForKey:@"Content-Type"]; + responseDataStr = [self formattedStringFromData:downloadedData + contentType:responseType + JSON:&responseJSON]; + NSString *responseDataExtn = nil; + NSData *dataToWrite = nil; + if ([responseMIMEType isEqual:@"application/atom+xml"] || + [responseMIMEType hasSuffix:@"/xml"]) { + responseDataExtn = @"xml"; + dataToWrite = downloadedData; + } else if ([responseMIMEType isEqual:@"image/jpeg"]) { + responseDataExtn = @"jpg"; + dataToWrite = downloadedData; + isResponseImage = YES; + } else if ([responseMIMEType isEqual:@"image/gif"]) { + responseDataExtn = @"gif"; + dataToWrite = downloadedData; + isResponseImage = YES; + } else if ([responseMIMEType isEqual:@"image/png"]) { + responseDataExtn = @"png"; + dataToWrite = downloadedData; + isResponseImage = YES; + } else { + // add more non-text types here + } + // if we have an extension, save the raw data in a file with that extension + if (responseDataExtn && dataToWrite) { + // generate a response file base name like + NSString *responseBaseName = + [NSString stringWithFormat:@"fetch_%d_response", responseCounter]; + responseDataFileName = [responseBaseName stringByAppendingPathExtension:responseDataExtn]; + NSString *responseDataFilePath = + [logDirectory stringByAppendingPathComponent:responseDataFileName]; + + NSError *downloadedError = nil; + if (gIsLoggingToFile && ![dataToWrite writeToFile:responseDataFilePath + options:0 + error:&downloadedError]) { + NSLog(@"%@ logging write error:%@ (%@)", [self class], downloadedError, + responseDataFileName); + } + } + } + // we'll have one main html file per run of the app + NSString *htmlName = [[self class] htmlFileName]; + NSString *htmlPath = [logDirectory stringByAppendingPathComponent:htmlName]; + + // if the html file exists (from logging previous fetches) we don't need + // to re-write the header or the scripts + NSFileManager *fileMgr = [NSFileManager defaultManager]; + BOOL didFileExist = [fileMgr fileExistsAtPath:htmlPath]; + + NSMutableString *outputHTML = [NSMutableString string]; + + // we need a header to say we'll have UTF-8 text + if (!didFileExist) { + [outputHTML + appendFormat:@"%@ HTTP fetch log %@", + processName, [[self class] loggingDateStamp]]; + } + // now write the visible html elements + NSString *copyableFileName = [NSString stringWithFormat:@"fetch_%d.txt", responseCounter]; + + NSDate *now = [NSDate date]; + // write the date & time, the comment, and the link to the plain-text (copyable) log + [outputHTML appendFormat:@"%@      ", now]; + + NSString *comment = [self comment]; + if (comment.length > 0) { + [outputHTML appendFormat:@"%@      ", comment]; + } + [outputHTML + appendFormat:@"request/response log
", copyableFileName]; + NSTimeInterval elapsed = -self.initialBeginFetchDate.timeIntervalSinceNow; + [outputHTML appendFormat:@"elapsed: %5.3fsec
", elapsed]; + + // write the request URL + NSURLRequest *request = self.request; + NSString *requestMethod = request.HTTPMethod; + NSURL *requestURL = request.URL; + + // Save the request URL for next time in case this redirects. + NSString *redirectedFromURLString = [self.redirectedFromURL absoluteString]; + self.redirectedFromURL = [requestURL copy]; + if (redirectedFromURLString) { + [outputHTML appendFormat:@"redirected from %@
", + redirectedFromURLString]; + } + [outputHTML appendFormat:@"request: %@ %@
\n", requestMethod, requestURL]; + + // write the request headers + NSDictionary *requestHeaders = request.allHTTPHeaderFields; + NSUInteger numberOfRequestHeaders = requestHeaders.count; + if (numberOfRequestHeaders > 0) { + // Indicate if the request is authorized; warn if the request is authorized but non-SSL + NSString *auth = [requestHeaders objectForKey:@"Authorization"]; + NSString *headerDetails = @""; + if (auth) { + BOOL isInsecure = [[requestURL scheme] isEqual:@"http"]; + if (isInsecure) { + // 26A0 = ⚠ + headerDetails = + @"   authorized, non-SSL "; + } else { + headerDetails = @"   authorized"; + } + } + NSString *cookiesHdr = [requestHeaders objectForKey:@"Cookie"]; + if (cookiesHdr) { + headerDetails = [headerDetails stringByAppendingString:@"   cookies"]; + } + NSString *matchHdr = [requestHeaders objectForKey:@"If-Match"]; + if (matchHdr) { + headerDetails = [headerDetails stringByAppendingString:@"   if-match"]; + } + matchHdr = [requestHeaders objectForKey:@"If-None-Match"]; + if (matchHdr) { + headerDetails = + [headerDetails stringByAppendingString:@"   if-none-match"]; + } + [outputHTML appendFormat:@"   headers: %d %@
", (int)numberOfRequestHeaders, + headerDetails]; + } else { + [outputHTML appendFormat:@"   headers: none
"]; + } + // write the request post data + NSData *bodyData = nil; + NSData *loggedStreamData = self.loggedStreamData; + if (loggedStreamData) { + bodyData = loggedStreamData; + } else { + bodyData = self.bodyData; + if (bodyData == nil) { + bodyData = self.request.HTTPBody; + } + } + uint64_t bodyDataLength = bodyData.length; + + if (bodyData.length == 0) { + // If the data is in a body upload file URL, read that in if it's not huge. + NSURL *bodyFileURL = self.bodyFileURL; + if (bodyFileURL) { + NSNumber *fileSizeNum = nil; + NSError *fileSizeError = nil; + if ([bodyFileURL getResourceValue:&fileSizeNum + forKey:NSURLFileSizeKey + error:&fileSizeError]) { + bodyDataLength = [fileSizeNum unsignedLongLongValue]; + if (bodyDataLength > 0 && bodyDataLength < 50000) { + bodyData = [NSData dataWithContentsOfURL:bodyFileURL + options:NSDataReadingUncached + error:&fileSizeError]; + } + } + } + } + NSString *bodyDataStr = nil; + NSString *postType = [requestHeaders valueForKey:@"Content-Type"]; + + if (bodyDataLength > 0) { + [outputHTML appendFormat:@"   data: %llu bytes, %@
\n", + bodyDataLength, postType ? postType : @"(no type)"]; + NSString *logRequestBody = self.logRequestBody; + if (logRequestBody) { + bodyDataStr = [logRequestBody copy]; + self.logRequestBody = nil; + } else { + bodyDataStr = [self stringFromStreamData:bodyData contentType:postType]; + if (bodyDataStr) { + // remove OAuth 2 client secret and refresh token + bodyDataStr = [[self class] snipSubstringOfString:bodyDataStr + betweenStartString:@"client_secret=" + endString:@"&"]; + bodyDataStr = [[self class] snipSubstringOfString:bodyDataStr + betweenStartString:@"refresh_token=" + endString:@"&"]; + // remove ClientLogin password + bodyDataStr = [[self class] snipSubstringOfString:bodyDataStr + betweenStartString:@"&Passwd=" + endString:@"&"]; + } + } + } else { + // no post data + } + // write the response status, MIME type, URL + NSInteger status = [self statusCode]; + if (response) { + NSString *statusString = @""; + if (status != 0) { + if (status == 200 || status == 201) { + statusString = [NSString stringWithFormat:@"%ld", (long)status]; + + // report any JSON-RPC error + if ([responseJSON isKindOfClass:[NSDictionary class]]) { + NSDictionary *jsonError = [responseJSON objectForKey:@"error"]; + if ([jsonError isKindOfClass:[NSDictionary class]]) { + NSString *jsonCode = [[jsonError valueForKey:@"code"] description]; + NSString *jsonMessage = [jsonError valueForKey:@"message"]; + if (jsonCode || jsonMessage) { + // 2691 = ⚑ + NSString *const jsonErrFmt = @"   JSON error: %@ %@  ⚑"; + statusString = + [statusString stringByAppendingFormat:jsonErrFmt, jsonCode ? jsonCode : @"", + jsonMessage ? jsonMessage : @""]; + } + } + } + } else { + // purple for anything other than 200 or 201 + NSString *flag = status >= 400 ? @" ⚑" : @""; // 2691 = ⚑ + NSString *explanation = [NSHTTPURLResponse localizedStringForStatusCode:status]; + NSString *const statusFormat = @"%ld %@ %@"; + statusString = [NSString stringWithFormat:statusFormat, (long)status, explanation, flag]; + } + } + // show the response URL only if it's different from the request URL + NSString *responseURLStr = @""; + NSURL *responseURL = response.URL; + + if (responseURL && ![responseURL isEqual:request.URL]) { + NSString *const responseURLFormat = + @"response URL: %@
\n"; + responseURLStr = [NSString stringWithFormat:responseURLFormat, [responseURL absoluteString]]; + } + [outputHTML appendFormat:@"response:  status %@
\n%@", statusString, + responseURLStr]; + // Write the response headers + NSUInteger numberOfResponseHeaders = responseHeaders.count; + if (numberOfResponseHeaders > 0) { + // Indicate if the server is setting cookies + NSString *cookiesSet = [responseHeaders valueForKey:@"Set-Cookie"]; + NSString *cookiesStr = + cookiesSet ? @"  sets cookies" : @""; + // Indicate if the server is redirecting + NSString *location = [responseHeaders valueForKey:@"Location"]; + BOOL isRedirect = status >= 300 && status <= 399 && location != nil; + NSString *redirectsStr = + isRedirect ? @"  redirects" : @""; + [outputHTML appendFormat:@"   headers: %d %@ %@
\n", + (int)numberOfResponseHeaders, cookiesStr, redirectsStr]; + } else { + [outputHTML appendString:@"   headers: none
\n"]; + } + } + // error + if (error) { + [outputHTML appendFormat:@"Error: %@
\n", error.description]; + } + // Write the response data + if (responseDataFileName) { + if (isResponseImage) { + // Make a small inline image that links to the full image file + [outputHTML appendFormat:@"   data: %lld bytes, %@
", + responseDataLength, responseMIMEType]; + NSString *const fmt = @"image\n"; + [outputHTML appendFormat:fmt, responseDataFileName, responseDataFileName]; + } else { + // The response data was XML; link to the xml file + NSString *const fmt = @"   data: %lld bytes, " + @"%@   %@\n"; + [outputHTML appendFormat:fmt, responseDataLength, responseMIMEType, responseDataFileName, + [responseDataFileName pathExtension]]; + } + } else { + // The response data was not an image; just show the length and MIME type + [outputHTML appendFormat:@"   data: %lld bytes, %@\n", + responseDataLength, + responseMIMEType ? responseMIMEType : @"(no response type)"]; + } + // Make a single string of the request and response, suitable for copying + // to the clipboard and pasting into a bug report + NSMutableString *copyable = [NSMutableString string]; + if (comment) { + [copyable appendFormat:@"%@\n\n", comment]; + } + [copyable appendFormat:@"%@ elapsed: %5.3fsec\n", now, elapsed]; + if (redirectedFromURLString) { + [copyable appendFormat:@"Redirected from %@\n", redirectedFromURLString]; + } + [copyable appendFormat:@"Request: %@ %@\n", requestMethod, requestURL]; + if (requestHeaders.count > 0) { + [copyable appendFormat:@"Request headers:\n%@\n", + [[self class] headersStringForDictionary:requestHeaders]]; + } + if (bodyDataLength > 0) { + [copyable appendFormat:@"Request body: (%llu bytes)\n", bodyDataLength]; + if (bodyDataStr) { + [copyable appendFormat:@"%@\n", bodyDataStr]; + } + [copyable appendString:@"\n"]; + } + if (response) { + [copyable appendFormat:@"Response: status %d\n", (int)status]; + [copyable appendFormat:@"Response headers:\n%@\n", + [[self class] headersStringForDictionary:responseHeaders]]; + [copyable appendFormat:@"Response body: (%lld bytes)\n", responseDataLength]; + if (responseDataLength > 0) { + NSString *logResponseBody = self.logResponseBody; + if (logResponseBody) { + // The user has provided the response body text. + responseDataStr = [logResponseBody copy]; + self.logResponseBody = nil; + } + if (responseDataStr != nil) { + [copyable appendFormat:@"%@\n", responseDataStr]; + } else { + // Even though it's redundant, we'll put in text to indicate that all the bytes are binary. + if (self.destinationFileURL) { + [copyable appendFormat:@"<<%lld bytes>> to file %@\n", responseDataLength, + self.destinationFileURL.path]; + } else { + [copyable appendFormat:@"<<%lld bytes>>\n", responseDataLength]; + } + } + } + } + if (error) { + [copyable appendFormat:@"Error: %@\n", error]; + } + // Save to log property before adding the separator + self.log = copyable; + + [copyable appendString:@"-----------------------------------------------------------\n"]; + + // Write the copyable version to another file (linked to at the top of the html file, above) + // + // Ideally, something to just copy this to the clipboard like + // Copy here." + // would work everywhere, but it only works in Safari as of 8/2010 + if (gIsLoggingToFile) { + NSString *parentDir = [[self class] loggingDirectory]; + NSString *copyablePath = [logDirectory stringByAppendingPathComponent:copyableFileName]; + NSError *copyableError = nil; + if (![copyable writeToFile:copyablePath + atomically:NO + encoding:NSUTF8StringEncoding + error:©ableError]) { + // Error writing to file + NSLog(@"%@ logging write error:%@ (%@)", [self class], copyableError, copyablePath); + } + [outputHTML appendString:@"

"]; + + // Append the HTML to the main output file + const char *htmlBytes = outputHTML.UTF8String; + NSOutputStream *stream = [NSOutputStream outputStreamToFileAtPath:htmlPath append:YES]; + [stream open]; + [stream write:(const uint8_t *)htmlBytes maxLength:strlen(htmlBytes)]; + [stream close]; + + // Make a symlink to the latest html + NSString *const symlinkNameSuffix = [[self class] symlinkNameSuffix]; + NSString *symlinkName = [processName stringByAppendingString:symlinkNameSuffix]; + NSString *symlinkPath = [parentDir stringByAppendingPathComponent:symlinkName]; + + [fileMgr removeItemAtPath:symlinkPath error:NULL]; + [fileMgr createSymbolicLinkAtPath:symlinkPath withDestinationPath:htmlPath error:NULL]; +#if TARGET_OS_IPHONE + static BOOL gReportedLoggingPath = NO; + if (!gReportedLoggingPath) { + gReportedLoggingPath = YES; + NSLog(@"GTMSessionFetcher logging to \"%@\"", parentDir); + } +#endif + } +} + +- (NSInputStream *)loggedInputStreamForInputStream:(NSInputStream *)inputStream { + if (!inputStream) return nil; + if (![GTMSessionFetcher isLoggingEnabled]) return inputStream; + + [self clearLoggedStreamData]; // Clear any previous data. + Class monitorClass = NSClassFromString(@"GTMReadMonitorInputStream"); + if (!monitorClass) { + NSString const *str = @"<>"; + NSData *stringData = [str dataUsingEncoding:NSUTF8StringEncoding]; + [self appendLoggedStreamData:stringData]; + return inputStream; + } + inputStream = [monitorClass inputStreamWithStream:inputStream]; + + GTMReadMonitorInputStream *readMonitorInputStream = (GTMReadMonitorInputStream *)inputStream; + [readMonitorInputStream setReadDelegate:self]; + SEL readSel = @selector(inputStream:readIntoBuffer:length:); + [readMonitorInputStream setReadSelector:readSel]; + + return inputStream; +} + +- (GTMSessionFetcherBodyStreamProvider)loggedStreamProviderForStreamProvider: + (GTMSessionFetcherBodyStreamProvider)streamProvider { + if (!streamProvider) return nil; + if (![GTMSessionFetcher isLoggingEnabled]) return streamProvider; + + [self clearLoggedStreamData]; // Clear any previous data. + Class monitorClass = NSClassFromString(@"GTMReadMonitorInputStream"); + if (!monitorClass) { + NSString const *str = @"<>"; + NSData *stringData = [str dataUsingEncoding:NSUTF8StringEncoding]; + [self appendLoggedStreamData:stringData]; + return streamProvider; + } + GTMSessionFetcherBodyStreamProvider loggedStreamProvider = + ^(GTMSessionFetcherBodyStreamProviderResponse response) { + streamProvider(^(NSInputStream *bodyStream) { + bodyStream = [self loggedInputStreamForInputStream:bodyStream]; + response(bodyStream); + }); + }; + return loggedStreamProvider; +} + +@end + +@implementation GTMSessionFetcher (GTMSessionFetcherLoggingUtilities) + +- (void)inputStream:(GTMReadMonitorInputStream *)stream + readIntoBuffer:(void *)buffer + length:(int64_t)length { + // append the captured data + NSData *data = [NSData dataWithBytesNoCopy:buffer length:(NSUInteger)length freeWhenDone:NO]; + [self appendLoggedStreamData:data]; +} + +#pragma mark Fomatting Utilities + ++ (NSString *)snipSubstringOfString:(NSString *)originalStr + betweenStartString:(NSString *)startStr + endString:(NSString *)endStr { +#if SKIP_GTM_FETCH_LOGGING_SNIPPING + return originalStr; +#else + if (!originalStr) return nil; + + // Find the start string, and replace everything between it + // and the end string (or the end of the original string) with "_snip_" + NSRange startRange = [originalStr rangeOfString:startStr]; + if (startRange.location == NSNotFound) return originalStr; + + // We found the start string + NSUInteger originalLength = originalStr.length; + NSUInteger startOfTarget = NSMaxRange(startRange); + NSRange targetAndRest = NSMakeRange(startOfTarget, originalLength - startOfTarget); + NSRange endRange = [originalStr rangeOfString:endStr options:0 range:targetAndRest]; + NSRange replaceRange; + if (endRange.location == NSNotFound) { + // Found no end marker so replace to end of string + replaceRange = targetAndRest; + } else { + // Replace up to the endStr + replaceRange = NSMakeRange(startOfTarget, endRange.location - startOfTarget); + } + NSString *result = [originalStr stringByReplacingCharactersInRange:replaceRange + withString:@"_snip_"]; + return result; +#endif // SKIP_GTM_FETCH_LOGGING_SNIPPING +} + ++ (NSString *)headersStringForDictionary:(NSDictionary *)dict { + // Format the dictionary in http header style, like + // Accept: application/json + // Cache-Control: no-cache + // Content-Type: application/json; charset=utf-8 + // + // Pad the key names, but not beyond 16 chars, since long custom header + // keys just create too much whitespace + NSArray *keys = [dict.allKeys sortedArrayUsingSelector:@selector(compare:)]; + + NSMutableString *str = [NSMutableString string]; + for (NSString *key in keys) { + NSString *value = [dict valueForKey:key]; + if ([key isEqual:@"Authorization"]) { + // Remove OAuth 1 token + value = [[self class] snipSubstringOfString:value + betweenStartString:@"oauth_token=\"" + endString:@"\""]; + + // Remove OAuth 2 bearer token (draft 16, and older form) + value = [[self class] snipSubstringOfString:value + betweenStartString:@"Bearer " + endString:@"\n"]; + value = [[self class] snipSubstringOfString:value + betweenStartString:@"OAuth " + endString:@"\n"]; + + // Remove Google ClientLogin + value = [[self class] snipSubstringOfString:value + betweenStartString:@"GoogleLogin auth=" + endString:@"\n"]; + } + [str appendFormat:@" %@: %@\n", key, value]; + } + return str; +} + +@end + +#endif // !STRIP_GTM_FETCH_LOGGING diff --git a/Pods/GTMSessionFetcher/Sources/Core/GTMSessionFetcherService+Internal.h b/Pods/GTMSessionFetcher/Sources/Core/GTMSessionFetcherService+Internal.h new file mode 100644 index 0000000..9708edf --- /dev/null +++ b/Pods/GTMSessionFetcher/Sources/Core/GTMSessionFetcherService+Internal.h @@ -0,0 +1,30 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * 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 "GTMSessionFetcher/GTMSessionFetcherService.h" + +// Internal methods from GTMSessionFetcherService, not intended for public use. + +@interface GTMSessionFetcherService (Internal) + +// Methods for use by the fetcher class only. +- (nullable NSURLSession *)session; +- (nullable NSURLSession *)sessionWithCreationBlock: + (nonnull NS_NOESCAPE GTMSessionFetcherSessionCreationBlock)creationBlock; +- (nullable id)sessionDelegate; +- (nullable NSDate *)stoppedAllFetchersDate; +- (void)fetcherDidStop:(nonnull GTMSessionFetcher *)fetcher callbacksPending: (BOOL)callbacksPending; + +@end diff --git a/Pods/GTMSessionFetcher/Sources/Core/GTMSessionFetcherService.m b/Pods/GTMSessionFetcher/Sources/Core/GTMSessionFetcherService.m new file mode 100644 index 0000000..3d2c6ff --- /dev/null +++ b/Pods/GTMSessionFetcher/Sources/Core/GTMSessionFetcherService.m @@ -0,0 +1,1380 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * 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. + */ + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "GTMSessionFetcher/GTMSessionFetcherService.h" +#import "GTMSessionFetcherService+Internal.h" + +#include + +NSString *const kGTMSessionFetcherServiceSessionBecameInvalidNotification = + @"kGTMSessionFetcherServiceSessionBecameInvalidNotification"; +NSString *const kGTMSessionFetcherServiceSessionKey = @"kGTMSessionFetcherServiceSessionKey"; + +#if !GTMSESSION_BUILD_COMBINED_SOURCES +@interface GTMSessionFetcher (ServiceMethods) +- (BOOL)beginFetchMayDelay:(BOOL)mayDelay + mayAuthorize:(BOOL)mayAuthorize + mayDecorate:(BOOL)mayDecorate; +@end +#endif // !GTMSESSION_BUILD_COMBINED_SOURCES + +@interface GTMSessionFetcherService () + +@property(atomic, strong, readwrite) NSDictionary *delayedFetchersByHost; +@property(atomic, strong, readwrite) NSDictionary *runningFetchersByHost; + +// Ordered collection of id, held weakly. +@property(atomic, strong, readonly) NSPointerArray *decoratorsPointerArray; + +@end + +// Since NSURLSession doesn't support a separate delegate per task (!), instances of this +// class serve as a session delegate trampoline. +// +// This class maps a session's tasks to fetchers, and resends delegate messages to the task's +// fetcher. +@interface GTMSessionFetcherSessionDelegateDispatcher : NSObject + +// The session for the tasks in this dispatcher's task-to-fetcher map. +@property(atomic) NSURLSession *session; + +// The timer interval for invalidating a session that has no active tasks. +@property(atomic) NSTimeInterval discardInterval; + +// The current discard timer. +@property(atomic, readonly) NSTimer *discardTimer; + +- (instancetype)initWithParentService:(GTMSessionFetcherService *)parentService + sessionDiscardInterval:(NSTimeInterval)discardInterval; + +- (void)setFetcher:(GTMSessionFetcher *)fetcher forTask:(NSURLSessionTask *)task; +- (void)removeFetcher:(GTMSessionFetcher *)fetcher; + +// Before using a session, tells the delegate dispatcher to stop the discard timer. +- (void)startSessionUsage; + +// When abandoning a delegate dispatcher, we want to avoid the session retaining +// the delegate after tasks complete. +- (void)abandon; + +@end + +@implementation GTMSessionFetcherService { + NSMutableDictionary *_delayedFetchersByHost; + NSMutableDictionary *_runningFetchersByHost; + NSUInteger _maxRunningFetchersPerHost; + + // When this ivar is nil, the service will not reuse sessions. + GTMSessionFetcherSessionDelegateDispatcher *_delegateDispatcher; + + // Fetchers will wait on this if another fetcher is creating the shared NSURLSession. + os_unfair_lock _sessionCreationLock; + + BOOL _callbackQueueIsConcurrent; + dispatch_queue_t _callbackQueue; + NSOperationQueue *_delegateQueue; + NSHTTPCookieStorage *_cookieStorage; + NSString *_userAgent; + NSTimeInterval _timeout; + + NSURLCredential *_credential; // Username & password. + NSURLCredential *_proxyCredential; // Credential supplied to proxy servers. + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated" + id _authorizer; +#pragma clang diagnostic pop + + // For waitForCompletionOfAllFetchersWithTimeout: we need to wait on stopped fetchers since + // they've not yet finished invoking their queued callbacks. This array is nil except when + // waiting on fetchers. + NSMutableArray *_stoppedFetchersToWaitFor; + + // For fetchers that enqueued their callbacks before stopAllFetchers was called on the service, + // set a barrier so the callbacks know to bail out. + NSDate *_stoppedAllFetchersDate; +} + +// Clang-format likes to cram all @synthesize items onto the fewest lines, rather than one-per. +// clang-format off +@synthesize maxRunningFetchersPerHost = _maxRunningFetchersPerHost, + configuration = _configuration, + configurationBlock = _configurationBlock, + cookieStorage = _cookieStorage, + userAgent = _userAgent, + challengeBlock = _challengeBlock, + credential = _credential, + proxyCredential = _proxyCredential, + allowedInsecureSchemes = _allowedInsecureSchemes, + allowLocalhostRequest = _allowLocalhostRequest, + allowInvalidServerCertificates = _allowInvalidServerCertificates, + retryEnabled = _retryEnabled, + retryBlock = _retryBlock, + maxRetryInterval = _maxRetryInterval, + minRetryInterval = _minRetryInterval, + metricsCollectionBlock = _metricsCollectionBlock, + properties = _properties, + unusedSessionTimeout = _unusedSessionTimeout, + decoratorsPointerArray = _decoratorsPointerArray, + testBlock = _testBlock; +// clang-format on + +#if GTM_BACKGROUND_TASK_FETCHING +@synthesize skipBackgroundTask = _skipBackgroundTask; +#endif + +- (instancetype)init { + self = [super init]; + if (self) { + _delayedFetchersByHost = [[NSMutableDictionary alloc] init]; + _runningFetchersByHost = [[NSMutableDictionary alloc] init]; + _maxRunningFetchersPerHost = 10; + _unusedSessionTimeout = 60.0; + _delegateDispatcher = [[GTMSessionFetcherSessionDelegateDispatcher alloc] + initWithParentService:self + sessionDiscardInterval:_unusedSessionTimeout]; + _callbackQueue = dispatch_get_main_queue(); + + _delegateQueue = [[NSOperationQueue alloc] init]; + _delegateQueue.maxConcurrentOperationCount = 1; + _delegateQueue.name = @"com.google.GTMSessionFetcher.NSURLSessionDelegateQueue"; + + _sessionCreationLock = OS_UNFAIR_LOCK_INIT; + + // Starting with the SDKs for OS X 10.11/iOS 9, the service has a default useragent. + // Apps can remove this and get the default system "CFNetwork" useragent by setting the + // fetcher service's userAgent property to nil. + _userAgent = GTMFetcherStandardUserAgentString(nil); + } + return self; +} + +- (void)dealloc { + [self detachAuthorizer]; + [_delegateDispatcher abandon]; +} + +#pragma mark Generate a new fetcher + +// Creates a serial queue targetting the service's callback, meant to be provided to a new +// GTMSessionFetcher instance. +// +// This method is not intended to be overrideable by clients. +- (nonnull dispatch_queue_t)serialQueueForNewFetcher:(GTMSessionFetcher *)fetcher { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (!_callbackQueueIsConcurrent) return _callbackQueue; + + static const char *kQueueLabel = "com.google.GTMSessionFetcher.serialCallbackQueue"; + return dispatch_queue_create_with_target(kQueueLabel, DISPATCH_QUEUE_SERIAL, _callbackQueue); + } +} + +// Clients may override this method. Clients should not override any other library methods. +- (id)fetcherWithRequest:(NSURLRequest *)request fetcherClass:(Class)fetcherClass { + GTMSessionFetcher *fetcher = [[fetcherClass alloc] initWithRequest:request + configuration:self.configuration]; + fetcher.callbackQueue = [self serialQueueForNewFetcher:fetcher]; + fetcher.sessionDelegateQueue = self.sessionDelegateQueue; + fetcher.challengeBlock = self.challengeBlock; + fetcher.credential = self.credential; + fetcher.proxyCredential = self.proxyCredential; + fetcher.authorizer = self.authorizer; + fetcher.cookieStorage = self.cookieStorage; + fetcher.allowedInsecureSchemes = self.allowedInsecureSchemes; + fetcher.allowLocalhostRequest = self.allowLocalhostRequest; + fetcher.allowInvalidServerCertificates = self.allowInvalidServerCertificates; + fetcher.configurationBlock = self.configurationBlock; + fetcher.retryEnabled = self.retryEnabled; + fetcher.retryBlock = self.retryBlock; + fetcher.maxRetryInterval = self.maxRetryInterval; + fetcher.minRetryInterval = self.minRetryInterval; + if (@available(iOS 10.0, *)) { + fetcher.metricsCollectionBlock = self.metricsCollectionBlock; + } + fetcher.properties = self.properties; + fetcher.service = self; + +#if GTM_BACKGROUND_TASK_FETCHING + fetcher.skipBackgroundTask = self.skipBackgroundTask; +#endif + + NSString *userAgent = self.userAgent; + if (userAgent.length > 0 && [request valueForHTTPHeaderField:@"User-Agent"] == nil) { + [fetcher setRequestValue:userAgent forHTTPHeaderField:@"User-Agent"]; + } + fetcher.testBlock = self.testBlock; + + return fetcher; +} + +- (GTMSessionFetcher *)fetcherWithRequest:(NSURLRequest *)request { + return [self fetcherWithRequest:request fetcherClass:[GTMSessionFetcher class]]; +} + +- (GTMSessionFetcher *)fetcherWithURL:(NSURL *)requestURL { + return [self fetcherWithRequest:[NSURLRequest requestWithURL:requestURL]]; +} + +- (GTMSessionFetcher *)fetcherWithURLString:(NSString *)requestURLString { + NSURL *url = [NSURL URLWithString:requestURLString]; + return [self fetcherWithURL:url]; +} + +- (void)addDecorator:(id)decorator { + @synchronized(self) { + if (!_decoratorsPointerArray) { + _decoratorsPointerArray = [NSPointerArray weakObjectsPointerArray]; + } + [_decoratorsPointerArray addPointer:(__bridge void *)decorator]; + } +} + +- (nullable NSArray> *)decorators { + @synchronized(self) { + return _decoratorsPointerArray.allObjects; + } +} + +- (void)removeDecorator:(id)decorator { + @synchronized(self) { + NSUInteger i = 0; + for (id decoratorCandidate in _decoratorsPointerArray) { + if (decoratorCandidate == decorator) { + break; + } + ++i; + } + GTMSESSION_ASSERT_DEBUG(i < _decoratorsPointerArray.count, + @"decorator %@ must be passed to -addDecorator: before removing", + decorator); + if (i < _decoratorsPointerArray.count) { + [_decoratorsPointerArray removePointerAtIndex:i]; + } + } +} + +// Returns a session for the fetcher's host, or nil. +- (NSURLSession *)session { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSURLSession *session = _delegateDispatcher.session; + return session; + } +} + +- (NSURLSession *)sessionWithCreationBlock: + (NS_NOESCAPE GTMSessionFetcherSessionCreationBlock)creationBlock { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + if (!_delegateDispatcher) { + // This fetcher is creating a non-shared session, so skip locking. + return creationBlock(nil); + } + } + + @try { + NSURLSession *session; + // Wait if another fetcher is currently creating a session; avoid waiting inside the + // @synchronized block as that could deadlock. + os_unfair_lock_lock(&_sessionCreationLock); + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // Before getting the NSURLSession for task creation, it is + // important to invalidate and nil out the session discard timer; otherwise + // the session can be invalidated between when it is returned to the + // fetcher, and when the fetcher attempts to create its NSURLSessionTask. + [_delegateDispatcher startSessionUsage]; + + session = _delegateDispatcher.session; + if (!session) { + session = creationBlock(_delegateDispatcher); + _delegateDispatcher.session = session; + } + } + return session; + } @finally { + // Ensure the lock is always released, even if creationBlock throws. + os_unfair_lock_unlock(&_sessionCreationLock); + } +} + +- (id)sessionDelegate { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _delegateDispatcher; + } +} + +#pragma mark Queue Management + +- (void)addRunningFetcher:(GTMSessionFetcher *)fetcher forHost:(NSString *)host { + // Add to the array of running fetchers for this host, creating the array if needed. + NSMutableArray *runningForHost = [_runningFetchersByHost objectForKey:host]; + if (runningForHost == nil) { + runningForHost = [NSMutableArray arrayWithObject:fetcher]; + [_runningFetchersByHost setObject:runningForHost forKey:host]; + } else { + [runningForHost addObject:fetcher]; + } +} + +- (void)addDelayedFetcher:(GTMSessionFetcher *)fetcher forHost:(NSString *)host { + // Add to the array of delayed fetchers for this host, creating the array if needed. + NSMutableArray *delayedForHost = [_delayedFetchersByHost objectForKey:host]; + if (delayedForHost == nil) { + delayedForHost = [NSMutableArray arrayWithObject:fetcher]; + [_delayedFetchersByHost setObject:delayedForHost forKey:host]; + } else { + [delayedForHost addObject:fetcher]; + } +} + +- (BOOL)isDelayingFetcher:(GTMSessionFetcher *)fetcher { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSString *host = fetcher.request.URL.host; + if (host == nil) { + return NO; + } + NSArray *delayedForHost = [_delayedFetchersByHost objectForKey:host]; + NSUInteger idx = [delayedForHost indexOfObjectIdenticalTo:fetcher]; + BOOL isDelayed = (delayedForHost != nil) && (idx != NSNotFound); + return isDelayed; + } +} + +- (BOOL)fetcherShouldBeginFetching:(GTMSessionFetcher *)fetcher { + // Entry point from the fetcher + NSURL *requestURL = fetcher.request.URL; + NSString *host = requestURL.host; + + // Addresses "file:///path" case where localhost is the implicit host. + if (host.length == 0 && [requestURL isFileURL]) { + host = @"localhost"; + } + + if (host.length == 0) { + // Data URIs legitimately have no host, reject other hostless URLs. + GTMSESSION_ASSERT_DEBUG([[requestURL scheme] isEqual:@"data"], @"%@ lacks host", fetcher); + return YES; + } + + BOOL shouldBeginResult; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSMutableArray *runningForHost = [_runningFetchersByHost objectForKey:host]; + if (runningForHost != nil && [runningForHost indexOfObjectIdenticalTo:fetcher] != NSNotFound) { + GTMSESSION_ASSERT_DEBUG(NO, @"%@ was already running", fetcher); + return YES; + } + + BOOL shouldRunNow = (fetcher.usingBackgroundSession || _maxRunningFetchersPerHost == 0 || + _maxRunningFetchersPerHost > + [[self class] numberOfNonBackgroundSessionFetchers:runningForHost]); + if (shouldRunNow) { + [self addRunningFetcher:fetcher forHost:host]; + shouldBeginResult = YES; + } else { + [self addDelayedFetcher:fetcher forHost:host]; + shouldBeginResult = NO; + } + } // @synchronized(self) + + // We'll save the host that serves as the key for this fetcher's array + // to avoid any chance of the underlying request changing, stranding + // the fetcher in the wrong array + fetcher.serviceHost = host; + + return shouldBeginResult; +} + +- (void)startFetcher:(GTMSessionFetcher *)fetcher { + [fetcher beginFetchMayDelay:NO mayAuthorize:YES mayDecorate:YES]; +} + +// Internal utility. Returns a fetcher's delegate if it's a dispatcher, or nil if the fetcher +// is its own delegate (possibly via proxy) and has no dispatcher. +- (GTMSessionFetcherSessionDelegateDispatcher *)delegateDispatcherForFetcher: + (GTMSessionFetcher *)fetcher { + GTMSessionCheckNotSynchronized(self); + + NSURLSession *fetcherSession = fetcher.session; + if (fetcherSession) { + id fetcherDelegate = fetcherSession.delegate; + // If the delegate is non-nil and claims to be a GTMSessionFetcher, there is no dispatcher; + // assume the fetcher is the delegate or has been proxied (some third-party frameworks + // are known to swizzle NSURLSession to proxy its delegate). + BOOL hasDispatcher = + (fetcherDelegate != nil && ![fetcherDelegate isKindOfClass:[GTMSessionFetcher class]]); + if (hasDispatcher) { + GTMSESSION_ASSERT_DEBUG( + [fetcherDelegate isKindOfClass:[GTMSessionFetcherSessionDelegateDispatcher class]], + @"Fetcher delegate class: %@", [fetcherDelegate class]); + return (GTMSessionFetcherSessionDelegateDispatcher *)fetcherDelegate; + } + } + return nil; +} + +- (void)fetcherDidBeginFetching:(GTMSessionFetcher *)fetcher { + // If this fetcher has a separate delegate with a shared session, then + // this fetcher should be added to the delegate's map of tasks to fetchers. + GTMSessionFetcherSessionDelegateDispatcher *delegateDispatcher = + [self delegateDispatcherForFetcher:fetcher]; + if (delegateDispatcher) { + GTMSESSION_ASSERT_DEBUG(fetcher.canShareSession, @"Inappropriate shared session: %@", fetcher); + + // There should already be a session, from this or a previous fetcher. + // + // Sanity check that the fetcher's session is the delegate's shared session. + NSURLSession *sharedSession = delegateDispatcher.session; + NSURLSession *fetcherSession = fetcher.session; + GTMSESSION_ASSERT_DEBUG(sharedSession != nil, @"Missing delegate session: %@", fetcher); + GTMSESSION_ASSERT_DEBUG(fetcherSession == sharedSession, + @"Inconsistent session: %@ %@ (shared: %@)", fetcher, fetcherSession, + sharedSession); + + if (sharedSession != nil && fetcherSession == sharedSession) { + NSURLSessionTask *task = fetcher.sessionTask; + GTMSESSION_ASSERT_DEBUG(task != nil, @"Missing session task: %@", fetcher); + + if (task) { + [delegateDispatcher setFetcher:fetcher forTask:task]; + } + } + } +} + +- (void)stopFetcher:(GTMSessionFetcher *)fetcher { + [fetcher stopFetching]; +} + +- (void)fetcherDidStop:(GTMSessionFetcher *)fetcher { + [self fetcherDidStop:fetcher callbacksPending:false]; +} + +- (void)fetcherDidStop:(GTMSessionFetcher *)fetcher callbacksPending:(BOOL) callbacksPending { + // Entry point from the fetcher + NSString *host = fetcher.serviceHost; + if (!host) { + // fetcher has been stopped previously + return; + } + + // This removeFetcher: invocation is a fallback; typically, fetchers are removed from the task + // map when the task completes. + if (!callbacksPending) { + GTMSessionFetcherSessionDelegateDispatcher *delegateDispatcher = + [self delegateDispatcherForFetcher:fetcher]; + [delegateDispatcher removeFetcher:fetcher]; + } + + NSMutableArray *fetchersToStart; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // If a test is waiting for all fetchers to stop, it needs to wait for this one + // to invoke its callbacks on the callback queue. + [_stoppedFetchersToWaitFor addObject:fetcher]; + + NSMutableArray *runningForHost = [_runningFetchersByHost objectForKey:host]; + [runningForHost removeObject:fetcher]; + + NSMutableArray *delayedForHost = [_delayedFetchersByHost objectForKey:host]; + [delayedForHost removeObject:fetcher]; + + while (delayedForHost.count > 0 && + [[self class] numberOfNonBackgroundSessionFetchers:runningForHost] < + _maxRunningFetchersPerHost) { + // Start another delayed fetcher running, scanning for the minimum + // priority value, defaulting to FIFO for equal priorities + GTMSessionFetcher *nextFetcher = nil; + for (GTMSessionFetcher *delayedFetcher in delayedForHost) { + if (nextFetcher == nil || delayedFetcher.servicePriority < nextFetcher.servicePriority) { + nextFetcher = delayedFetcher; + } + } + + if (nextFetcher) { + [self addRunningFetcher:nextFetcher forHost:host]; + runningForHost = [_runningFetchersByHost objectForKey:host]; + + [delayedForHost removeObjectIdenticalTo:nextFetcher]; + + if (!fetchersToStart) { + fetchersToStart = [NSMutableArray array]; + } + [fetchersToStart addObject:nextFetcher]; + } + } + + if (runningForHost.count == 0) { + // None left; remove the empty array + [_runningFetchersByHost removeObjectForKey:host]; + } + + if (delayedForHost.count == 0) { + [_delayedFetchersByHost removeObjectForKey:host]; + } + } // @synchronized(self) + + // Start fetchers outside of the synchronized block to avoid a deadlock. + for (GTMSessionFetcher *nextFetcher in fetchersToStart) { + [self startFetcher:nextFetcher]; + } + + // The fetcher is no longer in the running or the delayed array, + // so remove its host and thread properties + fetcher.serviceHost = nil; +} + +- (NSUInteger)numberOfFetchers { + NSUInteger running = [self numberOfRunningFetchers]; + NSUInteger delayed = [self numberOfDelayedFetchers]; + return running + delayed; +} + +- (NSUInteger)numberOfRunningFetchers { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSUInteger sum = 0; + for (NSString *host in _runningFetchersByHost) { + NSArray *fetchers = [_runningFetchersByHost objectForKey:host]; + sum += fetchers.count; + } + return sum; + } +} + +- (NSUInteger)numberOfDelayedFetchers { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSUInteger sum = 0; + for (NSString *host in _delayedFetchersByHost) { + NSArray *fetchers = [_delayedFetchersByHost objectForKey:host]; + sum += fetchers.count; + } + return sum; + } +} + +- (NSArray *)issuedFetchers { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSMutableArray *allFetchers = [NSMutableArray array]; + void (^accumulateFetchers)(id, id, BOOL *) = + ^(NSString *host, NSArray *fetchersForHost, BOOL *stop) { + [allFetchers addObjectsFromArray:fetchersForHost]; + }; + [_runningFetchersByHost enumerateKeysAndObjectsUsingBlock:accumulateFetchers]; + [_delayedFetchersByHost enumerateKeysAndObjectsUsingBlock:accumulateFetchers]; + + GTMSESSION_ASSERT_DEBUG(allFetchers.count == [NSSet setWithArray:allFetchers].count, + @"Fetcher appears multiple times\n running: %@\n delayed: %@", + _runningFetchersByHost, _delayedFetchersByHost); + + return allFetchers.count > 0 ? allFetchers : nil; + } +} + +- (NSArray *)issuedFetchersWithRequestURL:(NSURL *)requestURL { + NSString *host = requestURL.host; + if (host.length == 0) return nil; + + NSURL *targetURL = [requestURL absoluteURL]; + + NSArray *allFetchers = [self issuedFetchers]; + NSIndexSet *indexes = [allFetchers + indexesOfObjectsPassingTest:^BOOL(GTMSessionFetcher *fetcher, NSUInteger idx, BOOL *stop) { + NSURL *fetcherURL = [fetcher.request.URL absoluteURL]; + return [fetcherURL isEqual:targetURL]; + }]; + + NSArray *result = nil; + if (indexes.count > 0) { + result = [allFetchers objectsAtIndexes:indexes]; + } + return result; +} + +- (void)stopAllFetchers { + NSArray *delayedFetchersByHost; + NSArray *runningFetchersByHost; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // Set the time barrier so fetchers know not to call back even if + // the stop calls below occur after the fetchers naturally + // stopped and so were removed from _runningFetchersByHost, + // but while the callbacks were already enqueued before stopAllFetchers + // was invoked. + _stoppedAllFetchersDate = [[NSDate alloc] init]; + + // Remove fetchers from the delayed list to avoid fetcherDidStop: from + // starting more fetchers running as a side effect of stopping one + delayedFetchersByHost = _delayedFetchersByHost.allValues; + [_delayedFetchersByHost removeAllObjects]; + + runningFetchersByHost = _runningFetchersByHost.allValues; + [_runningFetchersByHost removeAllObjects]; + } + + for (NSArray *delayedForHost in delayedFetchersByHost) { + for (GTMSessionFetcher *fetcher in delayedForHost) { + [self stopFetcher:fetcher]; + } + } + + for (NSArray *runningForHost in runningFetchersByHost) { + for (GTMSessionFetcher *fetcher in runningForHost) { + [self stopFetcher:fetcher]; + } + } +} + +- (NSDate *)stoppedAllFetchersDate { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _stoppedAllFetchersDate; + } +} + +#pragma mark Accessors + +- (BOOL)reuseSession { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _delegateDispatcher != nil; + } +} + +- (void)setReuseSession:(BOOL)shouldReuse { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + BOOL wasReusing = (_delegateDispatcher != nil); + if (shouldReuse != wasReusing) { + [self abandonDispatcher]; + if (shouldReuse) { + _delegateDispatcher = [[GTMSessionFetcherSessionDelegateDispatcher alloc] + initWithParentService:self + sessionDiscardInterval:_unusedSessionTimeout]; + } else { + _delegateDispatcher = nil; + } + } + } +} + +- (void)resetSession { + GTMSessionCheckNotSynchronized(self); + os_unfair_lock_lock(&_sessionCreationLock); + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + [self resetSessionInternal]; + } + + os_unfair_lock_unlock(&_sessionCreationLock); +} + +- (void)resetSessionInternal { + GTMSessionCheckSynchronized(self); + + // The old dispatchers may be retained as delegates of any ongoing sessions by those sessions. + if (_delegateDispatcher) { + [self abandonDispatcher]; + _delegateDispatcher = [[GTMSessionFetcherSessionDelegateDispatcher alloc] + initWithParentService:self + sessionDiscardInterval:_unusedSessionTimeout]; + } +} + +- (void)resetSessionForDispatcherDiscardTimer:(NSTimer *)timer { + GTMSessionCheckNotSynchronized(self); + + os_unfair_lock_lock(&_sessionCreationLock); + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_delegateDispatcher.discardTimer == timer) { + // If the delegate dispatcher's current discardTimer is the same object as the timer + // that fired, no fetcher has recently attempted to start using the session by calling + // startSessionUsage, which invalidates and nils out the timer. + [self resetSessionInternal]; + } else { + // A fetcher has invalidated the timer between its triggering and now, potentially + // meaning a fetcher has requested access to the NSURLSession, and may be in the process + // of starting a new task. The dispatcher should not be abandoned, as this can lead + // to a race condition between calling -finishTasksAndInvalidate on the NSURLSession + // and the fetcher attempting to create a new task. + } + } + + os_unfair_lock_unlock(&_sessionCreationLock); +} + +- (NSTimeInterval)unusedSessionTimeout { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _unusedSessionTimeout; + } +} + +- (void)setUnusedSessionTimeout:(NSTimeInterval)timeout { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _unusedSessionTimeout = timeout; + _delegateDispatcher.discardInterval = timeout; + } +} + +// This method should be called inside of @synchronized(self) +- (void)abandonDispatcher { + GTMSessionCheckSynchronized(self); + [_delegateDispatcher abandon]; +} + +- (NSDictionary *)runningFetchersByHost { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [_runningFetchersByHost copy]; + } +} + +- (void)setRunningFetchersByHost:(NSDictionary *)dict { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _runningFetchersByHost = [dict mutableCopy]; + } +} + +- (NSDictionary *)delayedFetchersByHost { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [_delayedFetchersByHost copy]; + } +} + +- (void)setDelayedFetchersByHost:(NSDictionary *)dict { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _delayedFetchersByHost = [dict mutableCopy]; + } +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated" +- (id)authorizer { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _authorizer; + } +} + +- (void)setAuthorizer:(id)obj { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (obj != _authorizer) { + [self detachAuthorizer]; + } + + _authorizer = obj; + } + + // Use the fetcher service for the authorization fetches if the auth + // object supports fetcher services + if ([obj respondsToSelector:@selector(setFetcherService:)]) { + [obj setFetcherService:self]; + } +} +#pragma clang diagnostic pop + +// This should be called inside a @synchronized(self) block except during dealloc. +- (void)detachAuthorizer { + // This method is called by the fetcher service's dealloc and setAuthorizer: + // methods; do not override. + // + // The fetcher service retains the authorizer, and the authorizer has a + // weak pointer to the fetcher service (a non-zeroing pointer for + // compatibility with iOS 4 and Mac OS X 10.5/10.6.) + // + // When this fetcher service no longer uses the authorizer, we want to remove + // the authorizer's dependence on the fetcher service. Authorizers can still + // function without a fetcher service. + if ([_authorizer respondsToSelector:@selector(fetcherService)]) { + id authFetcherService = [_authorizer fetcherService]; + if (authFetcherService == self) { + [_authorizer setFetcherService:nil]; + } + } +} + +- (nonnull dispatch_queue_t)callbackQueue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _callbackQueue; + } // @synchronized(self) +} + +- (void)setCallbackQueue:(dispatch_queue_t)queue { + [self setCallbackQueue:queue isConcurrent:NO]; +} + +- (void)setConcurrentCallbackQueue:(dispatch_queue_t)queue { + [self setCallbackQueue:queue isConcurrent:YES]; +} + +- (void)setCallbackQueue:(dispatch_queue_t)queue isConcurrent:(BOOL)isConcurrent { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + +#if DEBUG + // Warn when changing from a concurrent queue to a serial queue. + if (_callbackQueueIsConcurrent && (!isConcurrent || !queue)) { + GTMSESSION_LOG_DEBUG( + @"WARNING: Resetting the service callback queue from concurrent to serial"); + } +#endif // DEBUG + + _callbackQueue = queue ?: dispatch_get_main_queue(); + _callbackQueueIsConcurrent = queue ? isConcurrent : NO; + } // @synchronized(self) +} + +- (NSOperationQueue *)sessionDelegateQueue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _delegateQueue; + } // @synchronized(self) +} + +- (void)setSessionDelegateQueue:(NSOperationQueue *)queue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _delegateQueue = queue ?: [NSOperationQueue mainQueue]; + } // @synchronized(self) +} + +- (NSOperationQueue *)delegateQueue { + // Provided for compatibility with the old fetcher service. The gtm-oauth2 code respects + // any custom delegate queue for calling the app. + return nil; +} + ++ (NSUInteger)numberOfNonBackgroundSessionFetchers:(NSArray *)fetchers { + NSUInteger sum = 0; + for (GTMSessionFetcher *fetcher in fetchers) { + if (!fetcher.usingBackgroundSession) { + ++sum; + } + } + return sum; +} + +@end + +@implementation GTMSessionFetcherService (TestingSupport) + ++ (instancetype)mockFetcherServiceWithFakedData:(NSData *)fakedDataOrNil + fakedError:(NSError *)fakedErrorOrNil { +#if !GTM_DISABLE_FETCHER_TEST_BLOCK + NSURL *url = [NSURL URLWithString:@"http://example.invalid"]; + NSHTTPURLResponse *fakedResponse = + [[NSHTTPURLResponse alloc] initWithURL:url + statusCode:(fakedErrorOrNil ? 500 : 200)HTTPVersion:@"HTTP/1.1" + headerFields:nil]; + return [self mockFetcherServiceWithFakedData:fakedDataOrNil + fakedResponse:fakedResponse + fakedError:fakedErrorOrNil]; +#else + GTMSESSION_ASSERT_DEBUG(0, @"Test blocks disabled"); + return nil; +#endif // GTM_DISABLE_FETCHER_TEST_BLOCK +} + ++ (instancetype)mockFetcherServiceWithFakedData:(NSData *)fakedDataOrNil + fakedResponse:(NSHTTPURLResponse *)fakedResponse + fakedError:(NSError *)fakedErrorOrNil { +#if !GTM_DISABLE_FETCHER_TEST_BLOCK + GTMSessionFetcherService *service = [[self alloc] init]; + service.allowedInsecureSchemes = @[ @"http" ]; + service.testBlock = + ^(GTMSessionFetcher *fetcherToTest, GTMSessionFetcherTestResponse testResponse) { + testResponse(fakedResponse, fakedDataOrNil, fakedErrorOrNil); + }; + return service; +#else + GTMSESSION_ASSERT_DEBUG(0, @"Test blocks disabled"); + return nil; +#endif // GTM_DISABLE_FETCHER_TEST_BLOCK +} + +#pragma mark Synchronous Wait for Unit Testing + +- (BOOL)waitForCompletionOfAllFetchersWithTimeout:(NSTimeInterval)timeoutInSeconds { + NSDate *giveUpDate = [NSDate dateWithTimeIntervalSinceNow:timeoutInSeconds]; + _stoppedFetchersToWaitFor = [NSMutableArray array]; + + BOOL shouldSpinRunLoop = [NSThread isMainThread]; + const NSTimeInterval kSpinInterval = 0.001; + BOOL didTimeOut = NO; + while (([self numberOfFetchers] > 0 || _stoppedFetchersToWaitFor.count > 0)) { + didTimeOut = [giveUpDate timeIntervalSinceNow] < 0; + if (didTimeOut) break; + + GTMSessionFetcher *stoppedFetcher = _stoppedFetchersToWaitFor.firstObject; + if (stoppedFetcher) { + [_stoppedFetchersToWaitFor removeObject:stoppedFetcher]; + [stoppedFetcher waitForCompletionWithTimeout:10.0 * kSpinInterval]; + } + + if (shouldSpinRunLoop) { + NSDate *stopDate = [NSDate dateWithTimeIntervalSinceNow:kSpinInterval]; + [[NSRunLoop currentRunLoop] runUntilDate:stopDate]; + } else { + [NSThread sleepForTimeInterval:kSpinInterval]; + } + } + _stoppedFetchersToWaitFor = nil; + + return !didTimeOut; +} + +@end + +@implementation GTMSessionFetcherSessionDelegateDispatcher { + __weak GTMSessionFetcherService *_parentService; + NSURLSession *_session; + + // The task map maps NSURLSessionTasks to GTMSessionFetchers + NSMutableDictionary *_taskToFetcherMap; + // The discard timer will invalidate sessions after the session's last task completes. + NSTimer *_discardTimer; + NSTimeInterval _discardInterval; +} + +@synthesize discardInterval = _discardInterval, session = _session; + +- (instancetype)init { + [self doesNotRecognizeSelector:_cmd]; + return nil; +} + +- (instancetype)initWithParentService:(GTMSessionFetcherService *)parentService + sessionDiscardInterval:(NSTimeInterval)discardInterval { + self = [super init]; + if (self) { + _discardInterval = discardInterval; + _parentService = parentService; + } + return self; +} + +- (NSString *)description { + return + [NSString stringWithFormat:@"%@ %p %@ %@", [self class], self, _session ?: @"", + _taskToFetcherMap.count > 0 ? _taskToFetcherMap : @""]; +} + +- (NSTimer *)discardTimer { + GTMSessionCheckNotSynchronized(self); + @synchronized(self) { + return _discardTimer; + } +} + +// This method should be called inside of a @synchronized(self) block. +- (void)startDiscardTimer { + GTMSessionCheckSynchronized(self); + [_discardTimer invalidate]; + _discardTimer = nil; + if (_discardInterval > 0) { + _discardTimer = [NSTimer timerWithTimeInterval:_discardInterval + target:self + selector:@selector(discardTimerFired:) + userInfo:nil + repeats:NO]; + [_discardTimer setTolerance:(_discardInterval / 10)]; + [[NSRunLoop mainRunLoop] addTimer:_discardTimer forMode:NSRunLoopCommonModes]; + } +} + +// This method should be called inside of a @synchronized(self) block. +- (void)destroyDiscardTimer { + GTMSessionCheckSynchronized(self); + [_discardTimer invalidate]; + _discardTimer = nil; +} + +- (void)discardTimerFired:(NSTimer *)timer { + GTMSessionFetcherService *service; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSUInteger numberOfTasks = _taskToFetcherMap.count; + if (numberOfTasks == 0) { + service = _parentService; + } + } + + // Inform the service that the discard timer has fired, and should check whether the + // service can abandon us. -resetSession cannot be called directly, as there is a + // race condition that must be guarded against with the NSURLSession being returned + // from sessionForFetcherCreation outside other locks. The service can take steps + // to prevent resetting the session if that has occurred. + // + // The service must be called from outside the @synchronized block. + [service resetSessionForDispatcherDiscardTimer:timer]; +} + +- (void)abandon { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [self destroySessionAndTimer]; + } +} + +- (void)startSessionUsage { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [self destroyDiscardTimer]; + } +} + +// This method should be called inside of a @synchronized(self) block. +- (void)destroySessionAndTimer { + GTMSessionCheckSynchronized(self); + [self destroyDiscardTimer]; + + // Break any retain cycle from the session holding the delegate. + [_session finishTasksAndInvalidate]; + + // Immediately clear the session so no new task may be issued with it. + // + // The _taskToFetcherMap needs to stay valid until the outstanding tasks finish. + _session = nil; +} + +- (void)setFetcher:(GTMSessionFetcher *)fetcher forTask:(NSURLSessionTask *)task { + GTMSESSION_ASSERT_DEBUG(fetcher != nil, @"missing fetcher"); + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_taskToFetcherMap == nil) { + _taskToFetcherMap = [[NSMutableDictionary alloc] init]; + } + + if (fetcher) { + [_taskToFetcherMap setObject:fetcher forKey:task]; + [self destroyDiscardTimer]; + } + } +} + +- (void)removeFetcher:(GTMSessionFetcher *)fetcher { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + // Typically, a fetcher should be removed when its task invokes + // URLSession:task:didCompleteWithError:. + // + // When fetching with a testBlock, though, the task completed delegate + // method may not be invoked, requiring cleanup here. + NSArray *tasks = [_taskToFetcherMap allKeysForObject:fetcher]; + GTMSESSION_ASSERT_DEBUG(tasks.count <= 1, @"fetcher task not unmapped: %@", tasks); + [_taskToFetcherMap removeObjectsForKeys:tasks]; + + if (_taskToFetcherMap.count == 0) { + [self startDiscardTimer]; + } + } +} + +// This helper method provides synchronized access to the task map for the delegate +// methods below. +- (id)fetcherForTask:(NSURLSessionTask *)task { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return [_taskToFetcherMap objectForKey:task]; + } +} + +- (void)removeTaskFromMap:(NSURLSessionTask *)task { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + [_taskToFetcherMap removeObjectForKey:task]; + } +} + +- (void)setSession:(NSURLSession *)session { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _session = session; + } +} + +- (NSURLSession *)session { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _session; + } +} + +- (NSTimeInterval)discardInterval { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _discardInterval; + } +} + +- (void)setDiscardInterval:(NSTimeInterval)interval { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _discardInterval = interval; + } +} + +// NSURLSessionDelegate protocol methods. + +// - (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session; +// +// TODO(seh): How do we route this to an appropriate fetcher? + +- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(NSError *)error { + GTMSESSION_LOG_DEBUG_VERBOSE(@"%@ %p URLSession:%@ didBecomeInvalidWithError:%@", [self class], + self, session, error); + NSDictionary *localTaskToFetcherMap; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _session = nil; + + localTaskToFetcherMap = [_taskToFetcherMap copy]; + } + + // Any "suspended" tasks may not have received callbacks from NSURLSession when the session + // completes; we'll call them now. + [localTaskToFetcherMap enumerateKeysAndObjectsUsingBlock:^( + NSURLSessionTask *task, GTMSessionFetcher *fetcher, BOOL *stop) { + if (fetcher.session == session) { + // Our delegate method URLSession:task:didCompleteWithError: will rely on + // _taskToFetcherMap so that should still contain this fetcher. + NSError *canceledError = [NSError errorWithDomain:NSURLErrorDomain + code:NSURLErrorCancelled + userInfo:nil]; + [self URLSession:session task:task didCompleteWithError:canceledError]; + } else { + GTMSESSION_ASSERT_DEBUG(0, @"Unexpected session in fetcher: %@ has %@ (expected %@)", fetcher, + fetcher.session, session); + } + }]; + + // Our tests rely on this notification to know the session discard timer fired. + NSDictionary *userInfo = @{kGTMSessionFetcherServiceSessionKey : session}; + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc postNotificationName:kGTMSessionFetcherServiceSessionBecameInvalidNotification + object:_parentService + userInfo:userInfo]; +} + +#pragma mark - NSURLSessionTaskDelegate + +// NSURLSessionTaskDelegate protocol methods. +// +// We won't test here if the fetcher responds to these since we only want this +// class to implement the same delegate methods the fetcher does (so NSURLSession's +// tests for respondsToSelector: will have the same result whether the session +// delegate is the fetcher or this dispatcher.) + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + willPerformHTTPRedirection:(NSHTTPURLResponse *)response + newRequest:(NSURLRequest *)request + completionHandler:(void (^)(NSURLRequest *))completionHandler { + id fetcher = [self fetcherForTask:task]; + [fetcher URLSession:session + task:task + willPerformHTTPRedirection:response + newRequest:request + completionHandler:completionHandler]; +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge + completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))handler { + id fetcher = [self fetcherForTask:task]; + [fetcher URLSession:session task:task didReceiveChallenge:challenge completionHandler:handler]; +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + needNewBodyStream:(void (^)(NSInputStream *bodyStream))handler { + id fetcher = [self fetcherForTask:task]; + [fetcher URLSession:session task:task needNewBodyStream:handler]; +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didSendBodyData:(int64_t)bytesSent + totalBytesSent:(int64_t)totalBytesSent + totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend { + id fetcher = [self fetcherForTask:task]; + [fetcher URLSession:session + task:task + didSendBodyData:bytesSent + totalBytesSent:totalBytesSent + totalBytesExpectedToSend:totalBytesExpectedToSend]; +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didCompleteWithError:(NSError *)error { + id fetcher = [self fetcherForTask:task]; + + // This is the usual way tasks are removed from the task map. + [self removeTaskFromMap:task]; + + [fetcher URLSession:session task:task didCompleteWithError:error]; +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics + API_AVAILABLE(ios(10.0), macosx(10.12), tvos(10.0), watchos(6.0)) { + id fetcher = [self fetcherForTask:task]; + [fetcher URLSession:session task:task didFinishCollectingMetrics:metrics]; +} + +// NSURLSessionDataDelegate protocol methods. + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + didReceiveResponse:(NSURLResponse *)response + completionHandler:(void (^)(NSURLSessionResponseDisposition))handler { + id fetcher = [self fetcherForTask:dataTask]; + [fetcher URLSession:session + dataTask:dataTask + didReceiveResponse:response + completionHandler:handler]; +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask { + id fetcher = [self fetcherForTask:dataTask]; + GTMSESSION_ASSERT_DEBUG(fetcher != nil, @"Missing fetcher for %@", dataTask); + [self removeTaskFromMap:dataTask]; + if (fetcher) { + GTMSESSION_ASSERT_DEBUG([fetcher isKindOfClass:[GTMSessionFetcher class]], + @"Expecting GTMSessionFetcher"); + [self setFetcher:(GTMSessionFetcher *)fetcher forTask:downloadTask]; + } + + [fetcher URLSession:session dataTask:dataTask didBecomeDownloadTask:downloadTask]; +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + didReceiveData:(NSData *)data { + id fetcher = [self fetcherForTask:dataTask]; + [fetcher URLSession:session dataTask:dataTask didReceiveData:data]; +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + willCacheResponse:(NSCachedURLResponse *)proposedResponse + completionHandler:(void (^)(NSCachedURLResponse *))handler { + id fetcher = [self fetcherForTask:dataTask]; + [fetcher URLSession:session + dataTask:dataTask + willCacheResponse:proposedResponse + completionHandler:handler]; +} + +// NSURLSessionDownloadDelegate protocol methods. + +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)downloadTask + didFinishDownloadingToURL:(NSURL *)location { + id fetcher = [self fetcherForTask:downloadTask]; + [fetcher URLSession:session downloadTask:downloadTask didFinishDownloadingToURL:location]; +} + +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)downloadTask + didWriteData:(int64_t)bytesWritten + totalBytesWritten:(int64_t)totalWritten + totalBytesExpectedToWrite:(int64_t)totalExpected { + id fetcher = [self fetcherForTask:downloadTask]; + [fetcher URLSession:session + downloadTask:downloadTask + didWriteData:bytesWritten + totalBytesWritten:totalWritten + totalBytesExpectedToWrite:totalExpected]; +} + +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)downloadTask + didResumeAtOffset:(int64_t)fileOffset + expectedTotalBytes:(int64_t)expectedTotalBytes { + id fetcher = [self fetcherForTask:downloadTask]; + [fetcher URLSession:session + downloadTask:downloadTask + didResumeAtOffset:fileOffset + expectedTotalBytes:expectedTotalBytes]; +} + +@end diff --git a/Pods/GTMSessionFetcher/Sources/Core/GTMSessionUploadFetcher.m b/Pods/GTMSessionFetcher/Sources/Core/GTMSessionUploadFetcher.m new file mode 100644 index 0000000..73f720f --- /dev/null +++ b/Pods/GTMSessionFetcher/Sources/Core/GTMSessionUploadFetcher.m @@ -0,0 +1,2171 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * 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. + */ + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "GTMSessionFetcher/GTMSessionUploadFetcher.h" + +#if TARGET_OS_OSX && GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH +// To reconnect background sessions on Mac outside +load requires importing and linking +// AppKit to access the NSApplicationDidFinishLaunching symbol. +#import +#endif + +static NSString *const kGTMSessionIdentifierIsUploadChunkFetcherMetadataKey = @"_upChunk"; +static NSString *const kGTMSessionIdentifierUploadFileURLMetadataKey = @"_upFileURL"; +static NSString *const kGTMSessionIdentifierUploadFileLengthMetadataKey = @"_upFileLen"; +static NSString *const kGTMSessionIdentifierUploadLocationURLMetadataKey = @"_upLocURL"; +static NSString *const kGTMSessionIdentifierUploadMIMETypeMetadataKey = @"_uploadMIME"; +static NSString *const kGTMSessionIdentifierUploadChunkSizeMetadataKey = @"_upChSize"; +static NSString *const kGTMSessionIdentifierUploadCurrentOffsetMetadataKey = @"_upOffset"; +static NSString *const kGTMSessionIdentifierUploadAllowsCellularAccess = @"_upAllowsCellularAccess"; + +static NSString *const kGTMSessionHeaderXGoogUploadChunkGranularity = + @"X-Goog-Upload-Chunk-Granularity"; +static NSString *const kGTMSessionHeaderXGoogUploadCommand = @"X-Goog-Upload-Command"; +static NSString *const kGTMSessionHeaderXGoogUploadContentLength = @"X-Goog-Upload-Content-Length"; +static NSString *const kGTMSessionHeaderXGoogUploadContentType = @"X-Goog-Upload-Content-Type"; +static NSString *const kGTMSessionHeaderXGoogUploadOffset = @"X-Goog-Upload-Offset"; +static NSString *const kGTMSessionHeaderXGoogUploadProtocol = @"X-Goog-Upload-Protocol"; +static NSString *const kGTMSessionXGoogUploadProtocolResumable = @"resumable"; +static NSString *const kGTMSessionHeaderXGoogUploadSizeReceived = @"X-Goog-Upload-Size-Received"; +static NSString *const kGTMSessionHeaderXGoogUploadStatus = @"X-Goog-Upload-Status"; +static NSString *const kGTMSessionHeaderXGoogUploadURL = @"X-Goog-Upload-URL"; +static const NSTimeInterval kDefaultMaxUploadRetryInterval = 60.0 * 10.; +static const NSTimeInterval kDefaultMinUploadRetryInterval = 1.0; + +// Property of chunk fetchers identifying the parent upload fetcher. Non-retained NSValue. +static NSString *const kGTMSessionUploadFetcherChunkParentKey = @"_uploadFetcherChunkParent"; + +int64_t const kGTMSessionUploadFetcherUnknownFileSize = -1; + +int64_t const kGTMSessionUploadFetcherStandardChunkSize = (int64_t)LLONG_MAX; + +#if TARGET_OS_IPHONE +int64_t const kGTMSessionUploadFetcherMaximumDemandBufferSize = + 10 * 1024 * 1024; // 10 MB for iOS, watchOS, tvOS +#else +int64_t const kGTMSessionUploadFetcherMaximumDemandBufferSize = + 100 * 1024 * 1024; // 100 MB for macOS +#endif + +typedef NS_ENUM(NSUInteger, GTMSessionUploadFetcherStatus) { + kStatusUnknown, + kStatusActive, + kStatusFinal, + kStatusCancelled, +}; + +NSString *const kGTMSessionFetcherUploadLocationObtainedNotification = + @"kGTMSessionFetcherUploadLocationObtainedNotification"; +NSString *const kGTMSessionFetcherUploadInitialBackoffStartedNotification = + @"kGTMSessionFetcherUploadInitialBackoffStartedNotification"; + +#if !GTMSESSION_BUILD_COMBINED_SOURCES +@interface GTMSessionFetcher (ProtectedMethods) + +// Access to non-public method on the parent fetcher class. +- (void)stopFetchReleasingCallbacks:(BOOL)shouldReleaseCallbacks; +- (void)createSessionIdentifierWithMetadata:(NSDictionary *)metadata; +- (GTMSessionFetcherCompletionHandler)completionHandlerWithTarget:(id)target + didFinishSelector:(SEL)finishedSelector; +- (void)invokeOnCallbackQueue:(dispatch_queue_t)callbackQueue + afterUserStopped:(BOOL)afterStopped + block:(void (^)(void))block; +- (NSTimer *)retryTimer; +- (void)beginFetchForRetry; + +@property(readwrite, strong) NSData *downloadedData; +- (void)releaseCallbacks; + +- (NSInteger)statusCodeUnsynchronized; + +- (BOOL)userStoppedFetching; + +@end +#endif // !GTMSESSION_BUILD_COMBINED_SOURCES + +@interface GTMSessionUploadFetcher () + +// Changing readonly to readwrite. +@property(atomic, strong, readwrite) NSURLRequest *lastChunkRequest; +@property(atomic, readwrite, assign) int64_t currentOffset; + +// Internal properties. +@property(strong, atomic, nullable) GTMSessionFetcher *fetcherInFlight; // Synchronized on self. + +@property(assign, atomic, getter=isSubdataGenerating) BOOL subdataGenerating; +@property(assign, atomic) BOOL shouldInitiateOffsetQuery; +@property(assign, atomic) int64_t uploadGranularity; +@property(assign, atomic) BOOL allowsCellularAccess; + +@end + +@implementation GTMSessionUploadFetcher { + GTMSessionFetcher *_chunkFetcher; + + // We'll call through to the delegate's completion handler. + GTMSessionFetcherCompletionHandler _delegateCompletionHandler; + dispatch_queue_t _delegateCallbackQueue; + + // The initial fetch's body length and bytes actually sent are + // needed for calculating progress during subsequent chunk uploads + int64_t _initialBodyLength; + int64_t _initialBodySent; + + // The upload server address for the chunks of this upload session. + NSURL *_uploadLocationURL; + + // _uploadData, _uploadDataProvider, or _uploadFileHandle may be set, but only one. + NSData *_uploadData; + NSFileHandle *_uploadFileHandle; + GTMSessionUploadFetcherDataProvider _uploadDataProvider; + NSURL *_uploadFileURL; + int64_t _uploadFileLength; + NSString *_uploadMIMEType; + int64_t _chunkSize; + int64_t _uploadGranularity; + double _uploadRetryFactor; + NSTimeInterval _nextUploadRetryInterval; + NSTimeInterval _maxUploadRetryInterval; + NSTimeInterval _minUploadRetryInterval; + BOOL _isPaused; + BOOL _isRestartedUpload; + BOOL _shouldInitiateOffsetQuery; + + NSTimer *_uploadRetryTimer; + // Tied to useBackgroundSession property, since this property is applicable to chunk fetchers. + BOOL _useBackgroundSessionOnChunkFetchers; + + // We keep the latest offset into the upload data just for progress reporting. + int64_t _currentOffset; + + NSDictionary *_recentChunkReponseHeaders; + NSInteger _recentChunkStatusCode; + + // For waiting, we need to know the fetcher in flight, if any, and if subdata generation + // is in progress. + GTMSessionFetcher *_fetcherInFlight; + BOOL _isSubdataGenerating; + BOOL _isCancelInFlight; + + GTMSessionUploadFetcherCancellationHandler _cancellationHandler; +} + +- (NSTimeInterval)nextUploadRetryIntervalUnsynchronized { + GTMSessionCheckSynchronized(self); + + // The next wait interval is the factor (2.0) times the last interval, + // but never less than the minimum interval. + NSTimeInterval secs = _nextUploadRetryInterval * _uploadRetryFactor; + if (_maxUploadRetryInterval > 0) { + secs = MIN(secs, _maxUploadRetryInterval); + } + secs = MAX(secs, _minUploadRetryInterval); + + return secs; +} + ++ (void)load { +#if GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH && TARGET_OS_IPHONE + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc addObserver:self + selector:@selector(reconnectFetchersForBackgroundSessionsOnAppLaunch:) + name:UIApplicationDidFinishLaunchingNotification + object:nil]; +#elif GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH && TARGET_OS_OSX + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc addObserver:self + selector:@selector(reconnectFetchersForBackgroundSessionsOnAppLaunch:) + name:NSApplicationDidFinishLaunchingNotification + object:nil]; +#else + [self uploadFetchersForBackgroundSessions]; +#endif +} + ++ (void)reconnectFetchersForBackgroundSessionsOnAppLaunch:(NSNotification *)notification { + // Give all other app-did-launch handlers a chance to complete before + // reconnecting the fetchers. Not doing this may lead to reconnecting + // before the app delegate has a chance to run. + dispatch_async(dispatch_get_main_queue(), ^{ + [self uploadFetchersForBackgroundSessions]; + }); +} + ++ (instancetype)uploadFetcherWithRequest:(NSURLRequest *)request + uploadMIMEType:(NSString *)uploadMIMEType + chunkSize:(int64_t)chunkSize + fetcherService:(GTMSessionFetcherService *)fetcherService { + GTMSessionUploadFetcher *fetcher = [self uploadFetcherWithRequest:request + fetcherService:fetcherService]; + [fetcher setLocationURL:nil + uploadMIMEType:uploadMIMEType + chunkSize:chunkSize + allowsCellularAccess:request.allowsCellularAccess]; + return fetcher; +} + ++ (instancetype)uploadFetcherWithLocation:(nullable NSURL *)uploadLocationURL + uploadMIMEType:(NSString *)uploadMIMEType + chunkSize:(int64_t)chunkSize + fetcherService:(nullable GTMSessionFetcherService *)fetcherServiceOrNil { + return [self uploadFetcherWithLocation:uploadLocationURL + uploadMIMEType:uploadMIMEType + chunkSize:chunkSize + allowsCellularAccess:YES + fetcherService:fetcherServiceOrNil]; +} + ++ (instancetype)uploadFetcherWithLocation:(nullable NSURL *)uploadLocationURL + uploadMIMEType:(NSString *)uploadMIMEType + chunkSize:(int64_t)chunkSize + allowsCellularAccess:(BOOL)allowsCellularAccess + fetcherService:(GTMSessionFetcherService *)fetcherService { + GTMSessionUploadFetcher *fetcher = [self uploadFetcherWithRequest:nil + fetcherService:fetcherService]; + [fetcher setLocationURL:uploadLocationURL + uploadMIMEType:uploadMIMEType + chunkSize:chunkSize + allowsCellularAccess:allowsCellularAccess]; + return fetcher; +} + ++ (instancetype)uploadFetcherForSessionIdentifierMetadata:(NSDictionary *)metadata { + GTMSESSION_ASSERT_DEBUG( + [metadata[kGTMSessionIdentifierIsUploadChunkFetcherMetadataKey] boolValue], + @"Session identifier metadata is not for an upload fetcher: %@", metadata); + + NSNumber *uploadFileLengthNum = metadata[kGTMSessionIdentifierUploadFileLengthMetadataKey]; + GTMSESSION_ASSERT_DEBUG(uploadFileLengthNum != nil, + @"Session metadata missing an UploadFileSize"); + if (uploadFileLengthNum == nil) return nil; + + int64_t uploadFileLength = [uploadFileLengthNum longLongValue]; + GTMSESSION_ASSERT_DEBUG(uploadFileLength >= 0, @"Session metadata UploadFileSize is unknown"); + + NSString *uploadFileURLString = metadata[kGTMSessionIdentifierUploadFileURLMetadataKey]; + GTMSESSION_ASSERT_DEBUG(uploadFileURLString, @"Session metadata missing an UploadFileURL"); + if (uploadFileURLString == nil) return nil; + + NSURL *uploadFileURL = [NSURL URLWithString:uploadFileURLString]; + // There used to be a call here to NSURL checkResourceIsReachableAndReturnError: to check for the + // existence of the file (also tried NSFileManager fileExistsAtPath:). We've determined + // empirically that the check can fail at startup even when the upload file does in fact exist. + // For now, we'll go ahead and restore the background upload fetcher. If the file doesn't exist, + // it will fail later. + + NSString *uploadLocationURLString = metadata[kGTMSessionIdentifierUploadLocationURLMetadataKey]; + NSURL *uploadLocationURL = + uploadLocationURLString ? [NSURL URLWithString:uploadLocationURLString] : nil; + + NSString *uploadMIMEType = metadata[kGTMSessionIdentifierUploadMIMETypeMetadataKey]; + int64_t uploadChunkSize = + [metadata[kGTMSessionIdentifierUploadChunkSizeMetadataKey] longLongValue]; + if (uploadChunkSize <= 0) { + uploadChunkSize = kGTMSessionUploadFetcherStandardChunkSize; + } + int64_t currentOffset = + [metadata[kGTMSessionIdentifierUploadCurrentOffsetMetadataKey] longLongValue]; + + BOOL allowsCellularAccess = YES; + if (metadata[kGTMSessionIdentifierUploadAllowsCellularAccess]) { + allowsCellularAccess = [metadata[kGTMSessionIdentifierUploadAllowsCellularAccess] boolValue]; + } + + GTMSESSION_ASSERT_DEBUG(currentOffset <= uploadFileLength, + @"CurrentOffset (%lld) exceeds UploadFileSize (%lld)", currentOffset, + uploadFileLength); + if (currentOffset > uploadFileLength) return nil; + + GTMSessionUploadFetcher *uploadFetcher = [self uploadFetcherWithLocation:uploadLocationURL + uploadMIMEType:uploadMIMEType + chunkSize:uploadChunkSize + allowsCellularAccess:allowsCellularAccess + fetcherService:nil]; + // Set the upload file length before setting the upload file URL tries to determine the length. + [uploadFetcher setUploadFileLength:uploadFileLength]; + + uploadFetcher.uploadFileURL = uploadFileURL; + uploadFetcher.sessionUserInfo = metadata; + uploadFetcher.useBackgroundSession = YES; + uploadFetcher.currentOffset = currentOffset; + uploadFetcher.delegateCallbackQueue = uploadFetcher.callbackQueue; + uploadFetcher.allowedInsecureSchemes = @[ @"http" ]; // Allowed on restored upload fetcher. + return uploadFetcher; +} + ++ (instancetype)uploadFetcherWithRequest:(NSURLRequest *)request + fetcherService:(GTMSessionFetcherService *)fetcherService { + // Internal utility method for instantiating fetchers + GTMSessionUploadFetcher *fetcher; + if ([fetcherService isKindOfClass:[GTMSessionFetcherService class]]) { + fetcher = [fetcherService fetcherWithRequest:request fetcherClass:self]; + } else { + fetcher = [self fetcherWithRequest:request]; + } + fetcher.useBackgroundSession = YES; + return fetcher; +} + ++ (NSPointerArray *)uploadFetcherPointerArrayForBackgroundSessions { + static NSPointerArray *gUploadFetcherPointerArrayForBackgroundSessions = nil; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + gUploadFetcherPointerArrayForBackgroundSessions = [NSPointerArray weakObjectsPointerArray]; + }); + return gUploadFetcherPointerArrayForBackgroundSessions; +} + ++ (instancetype)uploadFetcherForSessionIdentifier:(NSString *)sessionIdentifier { + GTMSESSION_ASSERT_DEBUG(sessionIdentifier != nil, @"Invalid session identifier"); + NSArray *uploadFetchersForBackgroundSessions = [self uploadFetchersForBackgroundSessions]; + for (GTMSessionUploadFetcher *uploadFetcher in uploadFetchersForBackgroundSessions) { + if ([uploadFetcher.chunkFetcher.sessionIdentifier isEqual:sessionIdentifier]) { + return uploadFetcher; + } + } + return nil; +} + ++ (NSArray *)uploadFetchersForBackgroundSessions { + NSMutableSet *restoredSessionIdentifiers = [[NSMutableSet alloc] init]; + NSMutableArray *uploadFetchers = [[NSMutableArray alloc] init]; + NSPointerArray *uploadFetcherPointerArray = [self uploadFetcherPointerArrayForBackgroundSessions]; + + // Collect the background session upload fetchers that are still in memory. + @synchronized(uploadFetcherPointerArray) { + [uploadFetcherPointerArray compact]; + for (GTMSessionUploadFetcher *uploadFetcher in uploadFetcherPointerArray) { + NSString *sessionIdentifier = uploadFetcher.chunkFetcher.sessionIdentifier; + if (sessionIdentifier) { + [restoredSessionIdentifiers addObject:sessionIdentifier]; + [uploadFetchers addObject:uploadFetcher]; + } + } + } // @synchronized(uploadFetcherPointerArray) + + // The system may have other ongoing background upload sessions. Restore upload fetchers for those + // too. + NSArray *fetchers = [GTMSessionFetcher fetchersForBackgroundSessions]; + for (GTMSessionFetcher *fetcher in fetchers) { + NSString *sessionIdentifier = fetcher.sessionIdentifier; + if (!sessionIdentifier || [restoredSessionIdentifiers containsObject:sessionIdentifier]) { + continue; + } + NSDictionary *sessionIdentifierMetadata = [fetcher sessionIdentifierMetadata]; + if (sessionIdentifierMetadata == nil) { + continue; + } + if (![sessionIdentifierMetadata[kGTMSessionIdentifierIsUploadChunkFetcherMetadataKey] + boolValue]) { + continue; + } + GTMSessionUploadFetcher *uploadFetcher = + [self uploadFetcherForSessionIdentifierMetadata:sessionIdentifierMetadata]; + if (uploadFetcher == nil) { + // Something went wrong with this upload fetcher, so kill the restored chunk fetcher. + [fetcher stopFetching]; + continue; + } + [uploadFetchers addObject:uploadFetcher]; + uploadFetcher->_chunkFetcher = fetcher; + uploadFetcher->_fetcherInFlight = fetcher; + [uploadFetcher attachSendProgressBlockToChunkFetcher:fetcher]; + fetcher.completionHandler = + [fetcher completionHandlerWithTarget:uploadFetcher + didFinishSelector:@selector(chunkFetcher:finishedWithData:error:)]; + + GTMSESSION_LOG_DEBUG(@"%@ restoring upload fetcher %@ for chunk fetcher %@", [self class], + uploadFetcher, fetcher); + } + return uploadFetchers; +} + +- (void)setUploadData:(NSData *)data { + BOOL changed = NO; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_uploadData != data) { + _uploadData = data; + changed = YES; + } + } + if (changed) { + [self setupRequestHeaders]; + } +} + +- (NSData *)uploadData { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _uploadData; + } +} + +- (void)setUploadFileHandle:(NSFileHandle *)fh { + BOOL changed = NO; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_uploadFileHandle != fh) { + _uploadFileHandle = fh; + changed = YES; + } + } + if (changed) { + [self setupRequestHeaders]; + } +} + +- (NSFileHandle *)uploadFileHandle { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _uploadFileHandle; + } +} + +- (void)setUploadFileURL:(NSURL *)uploadURL { + BOOL changed = NO; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_uploadFileURL != uploadURL) { + _uploadFileURL = uploadURL; + changed = YES; + } + } + if (changed) { + [self setupRequestHeaders]; + } +} + +- (NSURL *)uploadFileURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _uploadFileURL; + } +} + +- (void)setUploadFileLength:(int64_t)fullLength { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_uploadFileLength == kGTMSessionUploadFetcherUnknownFileSize && + fullLength != kGTMSessionUploadFetcherUnknownFileSize) { + _uploadFileLength = fullLength; + } + } +} + +- (void)setUploadDataLength:(int64_t)fullLength + provider:(GTMSessionUploadFetcherDataProvider)block { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _uploadDataProvider = [block copy]; + _uploadFileLength = fullLength; + } + [self setupRequestHeaders]; +} + +- (GTMSessionUploadFetcherDataProvider)uploadDataProvider { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _uploadDataProvider; + } +} + +- (void)setUploadMIMEType:(NSString *)uploadMIMEType { + GTMSESSION_ASSERT_DEBUG(0, @"TODO: disallow setUploadMIMEType by making declaration readonly"); + // (and uploadMIMEType, chunksize, currentOffset) + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _uploadMIMEType = uploadMIMEType; + } +} + +- (NSString *)uploadMIMEType { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _uploadMIMEType; + } +} + +- (int64_t)chunkSize { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _chunkSize; + } +} + +- (void)setupRequestHeaders { + GTMSessionCheckNotSynchronized(self); + +#if DEBUG + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + int hasData = (_uploadData != nil) ? 1 : 0; + int hasFileHandle = (_uploadFileHandle != nil) ? 1 : 0; + int hasFileURL = (_uploadFileURL != nil) ? 1 : 0; + int hasUploadDataProvider = (_uploadDataProvider != nil) ? 1 : 0; + __unused int numberOfSources = hasData + hasFileHandle + hasFileURL + hasUploadDataProvider; + GTMSESSION_ASSERT_DEBUG(numberOfSources == 1, @"Need just one upload source (%d)", + numberOfSources); + } // @synchronized(self) +#endif + + // Add our custom headers to the initial request indicating the data + // type and total size to be delivered later in the chunk requests. + NSMutableURLRequest *mutableRequest = [self.request mutableCopy]; + + GTMSESSION_ASSERT_DEBUG((mutableRequest == nil) != (_uploadLocationURL == nil), + @"Request and location are mutually exclusive"); + if (!mutableRequest) return; + + [mutableRequest setValue:kGTMSessionXGoogUploadProtocolResumable + forHTTPHeaderField:kGTMSessionHeaderXGoogUploadProtocol]; + [mutableRequest setValue:@"start" forHTTPHeaderField:kGTMSessionHeaderXGoogUploadCommand]; + [mutableRequest setValue:_uploadMIMEType + forHTTPHeaderField:kGTMSessionHeaderXGoogUploadContentType]; + [mutableRequest setValue:@([self fullUploadLength]).stringValue + forHTTPHeaderField:kGTMSessionHeaderXGoogUploadContentLength]; + + NSString *method = mutableRequest.HTTPMethod; + if (method == nil || [method caseInsensitiveCompare:@"GET"] == NSOrderedSame) { + [mutableRequest setHTTPMethod:@"POST"]; + } + + // Ensure the user agent header identifies this to the upload server as a + // GTMSessionUploadFetcher client. The /1 can be incremented in the unlikely circumstance + // we need to make a bug fix in the client that the server can recognize. + NSString *const kUserAgentStub = @"(GTMSUF/1)"; + NSString *userAgent = [mutableRequest valueForHTTPHeaderField:@"User-Agent"]; + if (userAgent == nil || [userAgent rangeOfString:kUserAgentStub].location == NSNotFound) { + if (userAgent.length == 0) { + userAgent = GTMFetcherStandardUserAgentString(nil); + } + userAgent = [userAgent stringByAppendingFormat:@" %@", kUserAgentStub]; + [mutableRequest setValue:userAgent forHTTPHeaderField:@"User-Agent"]; + } + [self setRequest:mutableRequest]; +} + +- (void)setLocationURL:(nullable NSURL *)location + uploadMIMEType:(NSString *)uploadMIMEType + chunkSize:(int64_t)chunkSize + allowsCellularAccess:(BOOL)allowsCellularAccess { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + GTMSESSION_ASSERT_DEBUG(chunkSize > 0, @"chunk size is zero"); + + _allowsCellularAccess = allowsCellularAccess; + + // When resuming an upload, set the known upload target URL. + _uploadLocationURL = location; + + _uploadMIMEType = uploadMIMEType; + _chunkSize = chunkSize; + + // Indicate that we've not yet determined the file handle's length + _uploadFileLength = kGTMSessionUploadFetcherUnknownFileSize; + + // Indicate that we've not yet determined the upload fetcher status + _recentChunkStatusCode = -1; + + // If this is restarting an upload begun by another fetcher, + // the location is specified but the request is nil + _isRestartedUpload = (location != nil); + } // @synchronized(self) +} + +- (int64_t)fullUploadLength { + int64_t result; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_uploadData) { + result = (int64_t)_uploadData.length; + } else { + if (_uploadFileLength == kGTMSessionUploadFetcherUnknownFileSize) { + if (_uploadFileHandle) { + // First time through, seek to end to determine file length + _uploadFileLength = (int64_t)[_uploadFileHandle seekToEndOfFile]; + } else if (_uploadDataProvider) { + // _uploadFileLength is set when the _uploadDataProvider is set. + GTMSESSION_ASSERT_DEBUG(_uploadFileLength >= 0, @"No uploadDataProvider length set"); + } else { + NSNumber *filesizeNum; + NSError *valueError; + if ([_uploadFileURL getResourceValue:&filesizeNum + forKey:NSURLFileSizeKey + error:&valueError]) { + _uploadFileLength = filesizeNum.longLongValue; + } else { + GTMSESSION_ASSERT_DEBUG(NO, @"Cannot get file size: %@\n %@", valueError, + _uploadFileURL.path); + _uploadFileLength = 0; + } + } + } + result = _uploadFileLength; + } + } // @synchronized(self) + return result; +} + +// Make a subdata of the upload data. +- (void)generateChunkSubdataWithOffset:(int64_t)offset + length:(int64_t)length + response:(GTMSessionUploadFetcherDataProviderResponse)response { + GTMSessionUploadFetcherDataProvider uploadDataProvider = self.uploadDataProvider; + if (uploadDataProvider) { + uploadDataProvider(offset, length, response); + return; + } + + NSData *uploadData = self.uploadData; + if (uploadData) { + // NSData provided. + NSData *resultData; + if (offset == 0 && length == (int64_t)uploadData.length) { + resultData = uploadData; + } else { + int64_t dataLength = (int64_t)uploadData.length; + // Ensure our range is valid. b/18007814 + if (offset + length > dataLength) { + NSString *errorMessage = [NSString + stringWithFormat: + @"Range invalid for upload data. offset: %lld\tlength: %lld\tdataLength: %lld", + offset, length, dataLength]; + GTMSESSION_ASSERT_DEBUG(NO, @"%@", errorMessage); + response(nil, kGTMSessionUploadFetcherUnknownFileSize, + [self uploadChunkUnavailableErrorWithDescription:errorMessage]); + return; + } + NSRange range = NSMakeRange((NSUInteger)offset, (NSUInteger)length); + + @try { + resultData = [uploadData subdataWithRange:range]; + } @catch (NSException *exception) { + NSString *errorMessage = exception.description; + GTMSESSION_ASSERT_DEBUG(NO, @"%@", errorMessage); + response(nil, kGTMSessionUploadFetcherUnknownFileSize, + [self uploadChunkUnavailableErrorWithDescription:errorMessage]); + return; + } + } + response(resultData, kGTMSessionUploadFetcherUnknownFileSize, nil); + return; + } + NSURL *uploadFileURL = self.uploadFileURL; + if (uploadFileURL) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [self generateChunkSubdataFromFileURL:uploadFileURL + offset:offset + length:length + response:response]; + }); + return; + } + GTMSESSION_ASSERT_DEBUG(_uploadFileHandle, @"Unexpectedly missing upload data package"); + NSFileHandle *uploadFileHandle = self.uploadFileHandle; + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [self generateChunkSubdataFromFileHandle:uploadFileHandle + offset:offset + length:length + response:response]; + }); +} + +- (void)generateChunkSubdataFromFileHandle:(NSFileHandle *)fileHandle + offset:(int64_t)offset + length:(int64_t)length + response:(GTMSessionUploadFetcherDataProviderResponse)response { + NSData *resultData; + NSError *error; + @try { + [fileHandle seekToFileOffset:(unsigned long long)offset]; + resultData = [fileHandle readDataOfLength:(NSUInteger)length]; + } @catch (NSException *exception) { + GTMSESSION_ASSERT_DEBUG(NO, @"uploadFileHandle failed to read, %@", exception); + error = [self uploadChunkUnavailableErrorWithDescription:exception.description]; + } + // The response always re-dispatches to the main thread, so we skip doing that here. + response(resultData, kGTMSessionUploadFetcherUnknownFileSize, error); +} + +- (void)generateChunkSubdataFromFileURL:(NSURL *)fileURL + offset:(int64_t)offset + length:(int64_t)length + response:(GTMSessionUploadFetcherDataProviderResponse)response { + GTMSessionCheckNotSynchronized(self); + + NSData *resultData; + NSError *error; + int64_t fullUploadLength = [self fullUploadLength]; + NSData *mappedData = + [NSData dataWithContentsOfURL:fileURL + options:NSDataReadingMappedAlways + NSDataReadingUncached + error:&error]; + if (!mappedData) { + // We could not create an NSData by memory-mapping the file. +#if TARGET_IPHONE_SIMULATOR + // NSTemporaryDirectory() can differ in the simulator between app restarts, + // yet the contents for the new path remains unchanged, so try the latest temp path. + if ([error.domain isEqual:NSCocoaErrorDomain] && (error.code == NSFileReadNoSuchFileError)) { + NSString *filename = [fileURL lastPathComponent]; + NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:filename]; + NSURL *newFileURL = [NSURL fileURLWithPath:filePath]; + if (![newFileURL isEqual:fileURL]) { + [self generateChunkSubdataFromFileURL:newFileURL + offset:offset + length:length + response:response]; + return; + } + } +#endif + + // If the file is just too large to create an NSData for, or if for some other reason we can't + // map it, create an NSFileHandle instead to read a subset into an NSData. +#if DEBUG + NSNumber *fileSizeNum; + BOOL hasFileSize = [fileURL getResourceValue:&fileSizeNum forKey:NSURLFileSizeKey error:NULL]; + GTMSESSION_LOG_DEBUG(@"Note: uploadFileURL is falling back to creating upload chunks by reading" + @" an NSFileHandle since uploadFileURL failed to map the upload file," + @" file size %@, %@", + hasFileSize ? fileSizeNum : @"unknown", error); +#endif + + NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingFromURL:fileURL error:&error]; + if (fileHandle != nil) { + [self generateChunkSubdataFromFileHandle:fileHandle + offset:offset + length:length + response:response]; + return; + } + GTMSESSION_ASSERT_DEBUG(NO, @"uploadFileURL failed to read, %@", error); + // Fall through with the error. + } else { + // Successfully created an NSData by memory-mapping the file. + if ((NSUInteger)(offset + length) > mappedData.length) { + NSString *errorMessage = [NSString + stringWithFormat:@"Range invalid for upload data. offset: %lld\tlength: " + @"%lld\tdataLength: %lld\texpected UploadLength: %lld", + offset, length, (long long)mappedData.length, fullUploadLength]; + GTMSESSION_ASSERT_DEBUG(NO, @"%@", errorMessage); + response(nil, kGTMSessionUploadFetcherUnknownFileSize, + [self uploadChunkUnavailableErrorWithDescription:errorMessage]); + return; + } + if (offset > 0 || length < fullUploadLength) { + NSRange range = NSMakeRange((NSUInteger)offset, (NSUInteger)length); + resultData = [mappedData subdataWithRange:range]; + } else { + resultData = mappedData; + } + } + // The response always re-dispatches to the main thread, so we skip re-dispatching here. + response(resultData, kGTMSessionUploadFetcherUnknownFileSize, error); +} + +- (NSError *)uploadChunkUnavailableErrorWithDescription:(NSString *)description { + // The description in the userInfo is intended as a clue to programmers, not + // for client code to examine or rely on. + NSDictionary *userInfo = @{@"description" : description}; + return [NSError errorWithDomain:kGTMSessionFetcherErrorDomain + code:GTMSessionFetcherErrorUploadChunkUnavailable + userInfo:userInfo]; +} + +- (NSError *)prematureFailureErrorWithUserInfo:(NSDictionary *)userInfo { + // An error for if we get an unexpected status from the upload server or + // otherwise cannot continue. This is an issue beyond the upload protocol; + // there's no way the client can do anything useful except give up. + NSError *error = [NSError errorWithDomain:kGTMSessionFetcherStatusDomain + code:501 // Not implemented + userInfo:userInfo]; + return error; +} + ++ (GTMSessionUploadFetcherStatus)uploadStatusFromResponseHeaders:(NSDictionary *)responseHeaders { + NSString *statusString = [responseHeaders objectForKey:kGTMSessionHeaderXGoogUploadStatus]; + if ([statusString isEqual:@"active"]) { + return kStatusActive; + } + if ([statusString isEqual:@"final"]) { + return kStatusFinal; + } + if ([statusString isEqual:@"cancelled"]) { + return kStatusCancelled; + } + return kStatusUnknown; +} + +#pragma mark Method overrides affecting the initial fetch only + +- (void)setCompletionHandler:(GTMSessionFetcherCompletionHandler)handler { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _delegateCompletionHandler = handler; + } +} + +- (void)setDelegateCallbackQueue:(nullable dispatch_queue_t)queue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _delegateCallbackQueue = queue; + } +} + +- (nullable dispatch_queue_t)delegateCallbackQueue { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _delegateCallbackQueue; + } +} + +- (BOOL)isRestartedUpload { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _isRestartedUpload; + } +} + +- (nullable GTMSessionFetcher *)chunkFetcher { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _chunkFetcher; + } +} + +- (void)setChunkFetcher:(nullable GTMSessionFetcher *)fetcher { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _chunkFetcher = fetcher; + } +} + +- (void)setFetcherInFlight:(nullable GTMSessionFetcher *)fetcher { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _fetcherInFlight = fetcher; + } +} + +- (nullable GTMSessionFetcher *)fetcherInFlight { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _fetcherInFlight; + } +} + +- (void)setCancellationHandler: + (nullable GTMSessionUploadFetcherCancellationHandler)cancellationHandler { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _cancellationHandler = cancellationHandler; + } +} + +- (nullable GTMSessionUploadFetcherCancellationHandler)cancellationHandler { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _cancellationHandler; + } +} + +- (void)beginFetchForRetry { + GTMSessionCheckNotSynchronized(self); + + // Override the superclass to reset the initial body length and fetcher-in-flight, + // then call the superclass implementation. + [self setInitialBodyLength:[self bodyLength]]; + + GTMSESSION_ASSERT_DEBUG(self.fetcherInFlight == nil, @"unexpected fetcher in flight: %@", + self.fetcherInFlight); + self.fetcherInFlight = self; + [super beginFetchForRetry]; +} + +- (void)destroyUploadRetryTimer { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + [_uploadRetryTimer invalidate]; + _uploadRetryTimer = nil; + } +} + +- (void)beginFetchWithCompletionHandler:(GTMSessionFetcherCompletionHandler)handler { + GTMSessionCheckNotSynchronized(self); + + [self setInitialBodyLength:[self bodyLength]]; + if (_minUploadRetryInterval <= 0.0) { + _minUploadRetryInterval = kDefaultMinUploadRetryInterval; + } + if (_maxUploadRetryInterval <= 0.0) { + _maxUploadRetryInterval = kDefaultMaxUploadRetryInterval; + } + if (_uploadRetryFactor <= 0.0) { + _uploadRetryFactor = 2.0; + } + + // We'll hold onto the superclass's callback queue so we can invoke the handler + // even after the superclass has released the queue and its callback handler, as + // happens during auth failure. + [self setDelegateCallbackQueue:self.callbackQueue]; + self.completionHandler = handler; + + if ([self isRestartedUpload]) { + // When restarting an upload, we know the destination location for chunk fetches, + // but we need to query to find the initial offset. + if (![self isPaused]) { + [self sendQueryForUploadOffsetWithFetcherProperties:self.properties]; + } + return; + } + // We don't want to call into the client's completion block immediately + // after the finish of the initial connection (the delegate is called only + // when uploading finishes), so we substitute our own completion block to be + // called when the initial connection finishes + GTMSESSION_ASSERT_DEBUG(self.fetcherInFlight == nil, @"unexpected fetcher in flight: %@", + self.fetcherInFlight); + + self.fetcherInFlight = self; + [super beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { + self.fetcherInFlight = nil; + // callback + + BOOL hasTestBlock = (self.testBlock != nil); + if (![self isRestartedUpload] && !hasTestBlock) { + if (error == nil) { + [self beginChunkFetches]; + } else { + if ([self retryTimer] == nil) { + [self invokeFinalCallbackWithData:nil error:error shouldInvalidateLocation:YES]; + } + } + } else { + // If there was no initial request, then this fetch is resuming some + // other uploadFetcher's initial request, and the superclass's connection + // is never used, so at this point we call the user's actual completion + // block. + if (!hasTestBlock) { + [self invokeFinalCallbackWithData:data error:error shouldInvalidateLocation:YES]; + } else { + // There was a test block, so we won't do chunk fetches, but we simulate obtaining + // the data to be uploaded from the upload data provider block or the file handle, + // and then call back. + [self generateChunkSubdataWithOffset:0 + length:[self fullUploadLength] + response:^(NSData *generateData, int64_t fullUploadLength, + NSError *generateError) { + [self invokeFinalCallbackWithData:data + error:error + shouldInvalidateLocation:YES]; + }]; + } + } + }]; +} + +- (void)beginChunkFetches { + GTMSessionCheckNotSynchronized(self); + +#if DEBUG + // The initial response of the resumable upload protocol should have an + // empty body + // + // This assert typically happens because the upload create/edit link URL was + // not supplied with the request, and the server is thus expecting a non- + // resumable request/response. + if (self.downloadedData.length > 0) { + NSData *downloadedData = self.downloadedData; + __unused NSString *str = [[NSString alloc] initWithData:downloadedData + encoding:NSUTF8StringEncoding]; + GTMSESSION_ASSERT_DEBUG(NO, @"unexpected response data (uploading to the wrong URL?)\n%@", str); + } +#endif + + // We need to get the upload URL from the location header to continue. + NSDictionary *responseHeaders = [self responseHeaders]; + + [self retrieveUploadChunkGranularityFromResponseHeaders:responseHeaders]; + + GTMSessionUploadFetcherStatus uploadStatus = + [[self class] uploadStatusFromResponseHeaders:responseHeaders]; + GTMSESSION_ASSERT_DEBUG(uploadStatus != kStatusUnknown, + @"beginChunkFetches has unexpected upload status for headers %@", + responseHeaders); + + BOOL isPrematureStop = (uploadStatus == kStatusFinal) || (uploadStatus == kStatusCancelled); + + NSString *uploadLocationURLStr = [responseHeaders objectForKey:kGTMSessionHeaderXGoogUploadURL]; + BOOL hasUploadLocation = (uploadLocationURLStr.length > 0); + + if (isPrematureStop || !hasUploadLocation) { + GTMSESSION_ASSERT_DEBUG(NO, @"Premature failure: upload-status:\"%@\" location:%@", + [responseHeaders objectForKey:kGTMSessionHeaderXGoogUploadStatus], + uploadLocationURLStr); + // We cannot continue since we do not know the location to use + // as our upload destination. + NSDictionary *userInfo = nil; + NSData *downloadedData = self.downloadedData; + if (downloadedData.length > 0) { + userInfo = @{kGTMSessionFetcherStatusDataKey : downloadedData}; + } + NSError *failureError = [self prematureFailureErrorWithUserInfo:userInfo]; + [self invokeFinalCallbackWithData:nil error:failureError shouldInvalidateLocation:YES]; + return; + } + + self.uploadLocationURL = [NSURL URLWithString:uploadLocationURLStr]; + + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc postNotificationName:kGTMSessionFetcherUploadLocationObtainedNotification object:self]; + + // we've now sent all of the initial post body data, so we need to include + // its size in future progress indicator callbacks + [self setInitialBodySent:[self initialBodyLength]]; + + // just in case the user paused us during the initial fetch... + if (![self isPaused]) { + [self uploadNextChunkWithOffset:0]; + } +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didSendBodyData:(int64_t)bytesSent + totalBytesSent:(int64_t)totalBytesSent + totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend { + // Overrides the superclass. + [self invokeDelegateWithDidSendBytes:bytesSent + totalBytesSent:totalBytesSent + totalBytesExpectedToSend:totalBytesExpectedToSend + [self fullUploadLength]]; +} + +- (BOOL)shouldReleaseCallbacksUponCompletion { + // Overrides the superclass. + + // We don't want the superclass to release the delegate and callback + // blocks once the initial fetch has finished + // + // This is invoked for only successful completion of the connection; + // an error always will invoke and release the callbacks + return NO; +} + +- (void)invokeFinalCallbackWithData:(NSData *)data + error:(NSError *)error + shouldInvalidateLocation:(BOOL)shouldInvalidateLocation { + dispatch_queue_t queue; + GTMSessionFetcherCompletionHandler handler; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (shouldInvalidateLocation) { + _uploadLocationURL = nil; + } + + // Wait to dispatch the completion handler until after releasing callbacks. Because + // action on the upload fetcher often takes place on a background queue, there can + // be issues with CI tests failing due to load making the dispatched callback to + // execute and the tests resume and assert callbacks have been released prior to that + // actually occurring. + // + // However under normal operation this should also be a perfectly fine change. + queue = _delegateCallbackQueue; + handler = _delegateCompletionHandler; + } // @synchronized(self) + + [self releaseUploadAndBaseCallbacks:!self.userStoppedFetching]; + + if (queue && handler) { + [self invokeOnCallbackQueue:queue + afterUserStopped:NO + block:^{ + handler(data, error); + }]; + } +} + +- (void)releaseUploadAndBaseCallbacks:(BOOL)shouldReleaseCancellation { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _delegateCallbackQueue = nil; + _delegateCompletionHandler = nil; + _uploadDataProvider = nil; + if (shouldReleaseCancellation) { + _cancellationHandler = nil; + } + } + + // Release the base class's callbacks, too, if needed. + [self releaseCallbacks]; +} + +- (void)stopFetchReleasingCallbacks:(BOOL)shouldReleaseCallbacks { + GTMSessionCheckNotSynchronized(self); + [self destroyUploadRetryTimer]; + + // Clear _fetcherInFlight when stopped. Moved from stopFetching, since that's a public method, + // where this method does the work. Fixes issue clearing value when retryBlock included. + GTMSessionFetcher *fetcherInFlight = self.fetcherInFlight; + if (fetcherInFlight == self) { + self.fetcherInFlight = nil; + } + + [super stopFetchReleasingCallbacks:shouldReleaseCallbacks]; + + if (shouldReleaseCallbacks) { + [self releaseUploadAndBaseCallbacks:NO]; + } +} + +#pragma mark Chunk fetching methods + +- (void)uploadNextChunkWithOffset:(int64_t)offset { + // use the properties in each chunk fetcher + NSDictionary *props = [self properties]; + + [self uploadNextChunkWithOffset:offset fetcherProperties:props]; +} + +- (void)sendQueryForUploadOffsetWithFetcherProperties:(NSDictionary *)props { + GTMSessionFetcher *queryFetcher = [self uploadFetcherWithProperties:props isQueryFetch:YES]; + queryFetcher.bodyData = [NSData data]; + + NSString *originalComment = self.comment; + [queryFetcher + setCommentWithFormat:@"%@ (query offset)", originalComment ? originalComment : @"upload"]; + + [queryFetcher setRequestValue:@"query" forHTTPHeaderField:kGTMSessionHeaderXGoogUploadCommand]; + + self.fetcherInFlight = queryFetcher; + [queryFetcher beginFetchWithDelegate:self + didFinishSelector:@selector(queryFetcher:finishedWithData:error:)]; +} + +- (void)queryFetcher:(GTMSessionFetcher *)queryFetcher + finishedWithData:(NSData *)data + error:(NSError *)error { + self.fetcherInFlight = nil; + + NSDictionary *responseHeaders = [queryFetcher responseHeaders]; + NSString *sizeReceivedHeader; + + GTMSessionUploadFetcherStatus uploadStatus = + [[self class] uploadStatusFromResponseHeaders:responseHeaders]; + GTMSESSION_ASSERT_DEBUG(uploadStatus != kStatusUnknown || error != nil, + @"query fetcher completion has unexpected upload status for headers %@", + responseHeaders); + + if (error == nil) { + sizeReceivedHeader = [responseHeaders objectForKey:kGTMSessionHeaderXGoogUploadSizeReceived]; + + if (uploadStatus == kStatusCancelled || + (uploadStatus == kStatusActive && sizeReceivedHeader == nil)) { + NSDictionary *userInfo = nil; + if (data.length > 0) { + userInfo = @{kGTMSessionFetcherStatusDataKey : data}; + } + error = [self prematureFailureErrorWithUserInfo:userInfo]; + } + } + + if (error == nil) { + int64_t offset = [sizeReceivedHeader longLongValue]; + int64_t fullUploadLength = [self fullUploadLength]; + if (uploadStatus == kStatusFinal || + (offset >= fullUploadLength && + fullUploadLength != kGTMSessionUploadFetcherUnknownFileSize)) { + // Handle we're done + [self chunkFetcher:queryFetcher finishedWithData:data error:nil]; + } else { + [self retrieveUploadChunkGranularityFromResponseHeaders:responseHeaders]; + [self uploadNextChunkWithOffset:offset]; + } + } else { + // Handle query error + [self chunkFetcher:queryFetcher finishedWithData:data error:error]; + } +} + +- (void)sendCancelUploadWithFetcherProperties:(NSDictionary *)props { + @synchronized(self) { + _isCancelInFlight = YES; + } + GTMSessionFetcher *cancelFetcher = [self uploadFetcherWithProperties:props isQueryFetch:YES]; + cancelFetcher.bodyData = [NSData data]; + + NSString *originalComment = self.comment; + [cancelFetcher + setCommentWithFormat:@"%@ (cancel)", originalComment ? originalComment : @"upload"]; + + [cancelFetcher setRequestValue:@"cancel" forHTTPHeaderField:kGTMSessionHeaderXGoogUploadCommand]; + + self.fetcherInFlight = cancelFetcher; + [cancelFetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { + self.fetcherInFlight = nil; + if (![self triggerCancellationHandlerForFetch:cancelFetcher data:data error:error]) { + if (error) { + GTMSESSION_LOG_DEBUG(@"cancelFetcher %@", error); + } + } + @synchronized(self) { + self->_isCancelInFlight = NO; + } + }]; +} + +- (void)uploadNextChunkWithOffset:(int64_t)offset fetcherProperties:(NSDictionary *)props { + GTMSessionCheckNotSynchronized(self); + + // Example chunk headers: + // X-Goog-Upload-Command: upload, finalize + // X-Goog-Upload-Offset: 0 + // Content-Length: 2000000 + // Content-Type: image/jpeg + // + // {bytes 0-1999999} + + // The chunk upload URL requires no authentication header. + GTMSessionFetcher *chunkFetcher = [self uploadFetcherWithProperties:props isQueryFetch:NO]; + [self attachSendProgressBlockToChunkFetcher:chunkFetcher]; + int64_t chunkSize = [self updateChunkFetcher:chunkFetcher forChunkAtOffset:offset]; + BOOL isUploadingFileURL = (self.uploadFileURL != nil); + int64_t fullUploadLength = [self fullUploadLength]; + + // The chunk size may have changed, so determine again if we're uploading the full file. + BOOL isUploadingFullFile = + (offset == 0 && fullUploadLength != kGTMSessionUploadFetcherUnknownFileSize && + chunkSize >= fullUploadLength); + if (isUploadingFullFile && isUploadingFileURL) { + // The data is the full upload file URL. + chunkFetcher.bodyFileURL = self.uploadFileURL; + [self beginChunkFetcher:chunkFetcher offset:offset]; + } else { + // Make an NSData for the subset for this upload chunk. + self.subdataGenerating = YES; + [self generateChunkSubdataWithOffset:offset + length:chunkSize + response:^(NSData *chunkData, int64_t uploadFileLength, + NSError *chunkError) { + // The subdata methods may leave us on a background thread. + dispatch_async(dispatch_get_main_queue(), ^{ + self.subdataGenerating = NO; + + // dont allow the updating of fileLength for uploads not using a + // data provider as they should know the file length before the + // upload starts. + if (self.uploadDataProvider != nil && uploadFileLength > 0) { + [self setUploadFileLength:uploadFileLength]; + // Update the command and content-length headers if this is + // the last chunk to be sent. + if (offset + chunkSize >= uploadFileLength) { + int64_t updatedChunkSize = + [self updateChunkFetcher:chunkFetcher + forChunkAtOffset:offset]; + if (updatedChunkSize == 0) { + // Calling beginChunkFetcher early when there is no more + // data to send allows us to properly handle nil chunkData + // below without having to account for the case where we + // are just finalizing the file. + chunkFetcher.bodyData = [[NSData alloc] init]; + [self beginChunkFetcher:chunkFetcher offset:offset]; + return; + } + } + } + + if (chunkData == nil) { + NSError *responseError = chunkError; + if (!responseError) { + responseError = + [self uploadChunkUnavailableErrorWithDescription: + @"chunkData is nil"]; + } + [self invokeFinalCallbackWithData:nil + error:responseError + shouldInvalidateLocation:YES]; + return; + } + + BOOL didWriteFile = NO; + if (isUploadingFileURL) { + // Make a temporary file with the data subset. + NSString *tempName = + [NSString stringWithFormat:@"GTMUpload_temp_%@", + [[NSUUID UUID] UUIDString]]; + NSString *tempPath = [NSTemporaryDirectory() + stringByAppendingPathComponent:tempName]; + NSError *writeError; + didWriteFile = [chunkData writeToFile:tempPath + options:NSDataWritingAtomic + error:&writeError]; + if (didWriteFile) { + chunkFetcher.bodyFileURL = [NSURL fileURLWithPath:tempPath]; + } else { + GTMSESSION_LOG_DEBUG(@"writeToFile failed: %@\n%@", + writeError, tempPath); + } + } + if (!didWriteFile) { + chunkFetcher.bodyData = [chunkData copy]; + } + [self beginChunkFetcher:chunkFetcher offset:offset]; + }); + }]; + } +} + +- (void)beginUploadRetryTimer { + if (![NSThread isMainThread]) { + // Defer creating and starting the timer until we're on the main thread to ensure it has + // a run loop. + dispatch_async(dispatch_get_main_queue(), ^{ + [self beginUploadRetryTimer]; + }); + return; + } + + [self destroyUploadRetryTimer]; + + if (_nextUploadRetryInterval == 0.0) { + [self.chunkFetcher beginFetchWithDelegate:self + didFinishSelector:@selector(chunkFetcher:finishedWithData:error:)]; + return; + } + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + NSTimeInterval nextInterval = _nextUploadRetryInterval; + NSTimeInterval maxInterval = _maxUploadRetryInterval; + NSTimeInterval newInterval = MIN(nextInterval, (maxInterval > 0 ? maxInterval : DBL_MAX)); + NSTimeInterval newIntervalTolerance = (newInterval / 10) > 1.0 ?: 1.0; + + _nextUploadRetryInterval = newInterval; + + _uploadRetryTimer = [NSTimer timerWithTimeInterval:newInterval + target:self + selector:@selector(uploadRetryTimerFired:) + userInfo:nil + repeats:NO]; + _uploadRetryTimer.tolerance = newIntervalTolerance; + [[NSRunLoop mainRunLoop] addTimer:_uploadRetryTimer forMode:NSDefaultRunLoopMode]; + } // @synchronized(self) + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc postNotificationName:kGTMSessionFetcherUploadInitialBackoffStartedNotification object:self]; +} + +- (void)uploadRetryTimerFired:(NSTimer *)timer { + [self destroyUploadRetryTimer]; + + NSOperationQueue *queue = self.sessionDelegateQueue; + [queue addOperationWithBlock:^{ + [self.chunkFetcher beginFetchWithDelegate:self + didFinishSelector:@selector(chunkFetcher:finishedWithData:error:)]; + }]; +} + +- (NSTimer *)uploadRetryTimer { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _uploadRetryTimer; + } // @synchronized(self) +} + +- (NSTimeInterval)maxUploadRetryInterval { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _maxUploadRetryInterval; + } // @synchronized(self) +} +- (void)setMaxUploadRetryInterval:(NSTimeInterval)secs { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (secs > 0) { + _maxUploadRetryInterval = secs; + } else { + _maxUploadRetryInterval = kDefaultMaxUploadRetryInterval; + } + } // @synchronized(self) +} +- (void)setMinUploadRetryInterval:(NSTimeInterval)secs { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (secs > 0) { + _minUploadRetryInterval = secs; + } else { + _minUploadRetryInterval = kDefaultMinUploadRetryInterval; + } + } // @synchronized(self) +} + +- (NSTimeInterval)minUploadRetryInterval { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _minUploadRetryInterval; + } // @synchronized(self) +} + +- (void)beginChunkFetcher:(GTMSessionFetcher *)chunkFetcher offset:(int64_t)offset { + // Track the current offset for progress reporting + self.currentOffset = offset; + + // Hang on to the fetcher in case we need to cancel it. We set these before beginning the + // chunk fetch so the observers notified of chunk fetches can inspect the upload fetcher to + // match to the chunk. + self.chunkFetcher = chunkFetcher; + self.fetcherInFlight = chunkFetcher; + + // Update the last chunk request, including any request headers. + self.lastChunkRequest = chunkFetcher.request; + + if (_nextUploadRetryInterval < _maxUploadRetryInterval) { + [self beginUploadRetryTimer]; + + } else { + NSError *responseError = + [self uploadChunkUnavailableErrorWithDescription:@"Retry Limit Reached"]; + [self invokeFinalCallbackWithData:nil error:responseError shouldInvalidateLocation:NO]; + } +} + +- (void)attachSendProgressBlockToChunkFetcher:(GTMSessionFetcher *)chunkFetcher { + chunkFetcher.sendProgressBlock = + ^(int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend) { + // The total bytes expected include the initial body and the full chunked + // data, independent of how big this fetcher's chunk is. + int64_t initialBodySent = [self bodyLength]; // TODO(grobbins) use [self initialBodySent] + int64_t totalSent = initialBodySent + self.currentOffset + totalBytesSent; + int64_t totalExpected = initialBodySent + [self fullUploadLength]; + + [self invokeDelegateWithDidSendBytes:bytesSent + totalBytesSent:totalSent + totalBytesExpectedToSend:totalExpected]; + }; +} + +- (NSDictionary *)uploadSessionIdentifierMetadata { + NSMutableDictionary *metadata = [NSMutableDictionary dictionary]; + metadata[kGTMSessionIdentifierIsUploadChunkFetcherMetadataKey] = @YES; + GTMSESSION_ASSERT_DEBUG(self.uploadFileURL, + @"Invalid upload fetcher to create session identifier for metadata"); + metadata[kGTMSessionIdentifierUploadFileURLMetadataKey] = [self.uploadFileURL absoluteString]; + metadata[kGTMSessionIdentifierUploadFileLengthMetadataKey] = @([self fullUploadLength]); + + if (self.uploadLocationURL) { + metadata[kGTMSessionIdentifierUploadLocationURLMetadataKey] = + [self.uploadLocationURL absoluteString]; + } + if (self.uploadMIMEType) { + metadata[kGTMSessionIdentifierUploadMIMETypeMetadataKey] = self.uploadMIMEType; + } + metadata[kGTMSessionIdentifierUploadChunkSizeMetadataKey] = @(self.chunkSize); + metadata[kGTMSessionIdentifierUploadCurrentOffsetMetadataKey] = @(self.currentOffset); + metadata[kGTMSessionIdentifierUploadAllowsCellularAccess] = @(self.request.allowsCellularAccess); + + return metadata; +} + +- (GTMSessionFetcher *)uploadFetcherWithProperties:(NSDictionary *)properties + isQueryFetch:(BOOL)isQueryFetch { + GTMSessionCheckNotSynchronized(self); + + // Common code to make a request for a query command or for a chunk upload. + NSURL *uploadLocationURL = self.uploadLocationURL; + NSMutableURLRequest *chunkRequest = [NSMutableURLRequest requestWithURL:uploadLocationURL]; + [chunkRequest setHTTPMethod:@"PUT"]; + + // copy the user-agent from the original connection + // n.b. that self.request is nil for upload fetchers created with an existing upload location + // URL. + NSURLRequest *origRequest = self.request; + + chunkRequest.allowsCellularAccess = origRequest.allowsCellularAccess; + if (!origRequest) { + chunkRequest.allowsCellularAccess = _allowsCellularAccess; + } + NSString *userAgent = [origRequest valueForHTTPHeaderField:@"User-Agent"]; + if (userAgent.length > 0) { + [chunkRequest setValue:userAgent forHTTPHeaderField:@"User-Agent"]; + } + + [chunkRequest setValue:kGTMSessionXGoogUploadProtocolResumable + forHTTPHeaderField:kGTMSessionHeaderXGoogUploadProtocol]; + + // To avoid timeouts when debugging, copy the timeout of the initial fetcher. + NSTimeInterval origTimeout = [origRequest timeoutInterval]; + [chunkRequest setTimeoutInterval:origTimeout]; + + // + // Make a new chunk fetcher. + // + GTMSessionFetcher *chunkFetcher = [GTMSessionFetcher fetcherWithRequest:chunkRequest]; + chunkFetcher.callbackQueue = self.callbackQueue; + chunkFetcher.sessionUserInfo = self.sessionUserInfo; + chunkFetcher.configurationBlock = self.configurationBlock; + chunkFetcher.allowedInsecureSchemes = self.allowedInsecureSchemes; + chunkFetcher.allowLocalhostRequest = self.allowLocalhostRequest; + chunkFetcher.allowInvalidServerCertificates = self.allowInvalidServerCertificates; + chunkFetcher.stopFetchingTriggersCompletionHandler = self.stopFetchingTriggersCompletionHandler; + chunkFetcher.useUploadTask = !isQueryFetch; + + if (self.uploadFileURL && !isQueryFetch && self.useBackgroundSession) { + [chunkFetcher createSessionIdentifierWithMetadata:[self uploadSessionIdentifierMetadata]]; + } + + // Give the chunk fetcher the same properties as the previous chunk fetcher + chunkFetcher.properties = [properties mutableCopy]; + [chunkFetcher setProperty:[NSValue valueWithNonretainedObject:self] + forKey:kGTMSessionUploadFetcherChunkParentKey]; + + // copy other fetcher settings to the new fetcher + chunkFetcher.retryEnabled = self.retryEnabled; + chunkFetcher.maxRetryInterval = self.maxRetryInterval; + + if ([self isRetryEnabled]) { + // We interpose our own retry method both so we can change the request to ask the server to + // tell us where to resume the chunk. + chunkFetcher.retryBlock = + ^(BOOL suggestedWillRetry, NSError *chunkError, GTMSessionFetcherRetryResponse response) { + void (^finish)(BOOL) = ^(BOOL shouldRetry) { + // We'll retry by sending an offset query. + if (shouldRetry) { + self.shouldInitiateOffsetQuery = !isQueryFetch; + + // We don't know what our actual offset is anymore, but the server will tell us. + self.currentOffset = 0; + } + // We don't actually want to retry this specific fetcher. + response(NO); + }; + + GTMSessionFetcherRetryBlock retryBlock = self.retryBlock; + if (retryBlock) { + // Ask the client, then call the finish block above. + retryBlock(suggestedWillRetry, chunkError, finish); + } else { + finish(suggestedWillRetry); + } + }; + } + + return chunkFetcher; +} + +- (void)chunkFetcher:(GTMSessionFetcher *)chunkFetcher + finishedWithData:(NSData *)data + error:(NSError *)error { + BOOL hasDestroyedOldChunkFetcher = NO; + self.fetcherInFlight = nil; + + NSDictionary *responseHeaders = [chunkFetcher responseHeaders]; + GTMSessionUploadFetcherStatus uploadStatus = + [[self class] uploadStatusFromResponseHeaders:responseHeaders]; + GTMSESSION_ASSERT_DEBUG( + uploadStatus != kStatusUnknown || error != nil || self.wasCreatedFromBackgroundSession, + @"chunk fetcher completion has kStatusUnknown upload status for headers %@ fetcher %@", + responseHeaders, self); + BOOL isUploadStatusStopped = (uploadStatus == kStatusFinal || uploadStatus == kStatusCancelled); + + // Check if the fetcher was actually querying. If it failed, do not retry, + // as it would enter an infinite retry loop. + NSString *uploadCommand = + chunkFetcher.request.allHTTPHeaderFields[kGTMSessionHeaderXGoogUploadCommand]; + BOOL isQueryFetch = [uploadCommand isEqual:@"query"]; + + // TODO + // Maybe here we can check to see if the request had x goog content length set. (the file length + // one). + NSString *previousContentLengthValue = + [chunkFetcher.request valueForHTTPHeaderField:@"Content-Length"]; + // The Content-Length header may not be present if the chunk fetcher was recreated from + // a background session. + BOOL hasKnownChunkSize = (previousContentLengthValue != nil); + int64_t previousContentLength = [previousContentLengthValue longLongValue]; + + BOOL needsQuery = (!hasKnownChunkSize && !isUploadStatusStopped); + + if (error || (needsQuery && !isQueryFetch)) { + NSInteger status = error.code; + + // Status 4xx indicates a bad offset in the Google upload protocol. However, do not retry status + // 404 per spec, nor if the upload size appears to have been zero (since the server will just + // keep asking us to retry.) + if (self.shouldInitiateOffsetQuery || (needsQuery && !isQueryFetch) || + ([error.domain isEqual:kGTMSessionFetcherStatusDomain] && status >= 400 && status <= 499 && + status != 404 && uploadStatus == kStatusActive && previousContentLength > 0)) { + self.shouldInitiateOffsetQuery = NO; + [self destroyChunkFetcher]; + hasDestroyedOldChunkFetcher = YES; + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + _nextUploadRetryInterval = self.nextUploadRetryIntervalUnsynchronized; + } + + [self sendQueryForUploadOffsetWithFetcherProperties:chunkFetcher.properties]; + } else { + // Some unexpected status has occurred; handle it as we would a regular + // object fetcher failure. + [self invokeFinalCallbackWithData:data error:error shouldInvalidateLocation:NO]; + } + } else { + int64_t newOffset; + // The chunk has uploaded successfully. + NSString *uploadSizeReceived = + [chunkFetcher.responseHeaders objectForKey:kGTMSessionHeaderXGoogUploadSizeReceived]; + + if (uploadSizeReceived) { + newOffset = [uploadSizeReceived longLongValue]; + } else { + newOffset = self.currentOffset + previousContentLength; + } +#if DEBUG + // Verify that if we think all of the uploading data has been sent, the server responded with + // the "final" upload status. + __unused BOOL hasUploadAllData = (newOffset == [self fullUploadLength]); + __unused BOOL isFinalStatus = (uploadStatus == kStatusFinal); + GTMSESSION_ASSERT_DEBUG(hasUploadAllData == isFinalStatus || !hasKnownChunkSize, + @"uploadStatus:%@ newOffset:%lld (%lld + %lld) fullUploadLength:%lld" + @" chunkFetcher:%@ requestHeaders:%@ responseHeaders:%@", + [responseHeaders objectForKey:kGTMSessionHeaderXGoogUploadStatus], + newOffset, self.currentOffset, previousContentLength, + [self fullUploadLength], chunkFetcher, + chunkFetcher.request.allHTTPHeaderFields, responseHeaders); +#endif + if (isUploadStatusStopped || (!_uploadData && _uploadFileLength == 0) || + (_currentOffset > _uploadFileLength && _uploadFileLength > 0)) { + // This was the last chunk. + if (error == nil && uploadStatus == kStatusCancelled) { + // Report cancelled status as an error. + NSDictionary *userInfo = nil; + if (data.length > 0) { + userInfo = @{kGTMSessionFetcherStatusDataKey : data}; + } + data = nil; + error = [self prematureFailureErrorWithUserInfo:userInfo]; + } else { + // The upload is in final status. + // + // Take the chunk fetcher's data as the superclass data. + self.downloadedData = data; + self.statusCode = chunkFetcher.statusCode; + } + + // we're done + [self invokeFinalCallbackWithData:data error:error shouldInvalidateLocation:YES]; + } else { + // Start the next chunk. + self.currentOffset = newOffset; + + // We want to destroy this chunk fetcher before creating the next one, but + // we want to pass on its properties + NSDictionary *props = [chunkFetcher properties]; + + // We no longer need to be able to cancel this chunkFetcher. Destroy it + // before we create a new chunk fetcher. + [self destroyChunkFetcher]; + hasDestroyedOldChunkFetcher = YES; + [self uploadNextChunkWithOffset:newOffset fetcherProperties:props]; + } + } + if (!hasDestroyedOldChunkFetcher) { + [self destroyChunkFetcher]; + } +} + +- (void)destroyChunkFetcher { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_fetcherInFlight == _chunkFetcher) { + _fetcherInFlight = nil; + } + + [_chunkFetcher stopFetching]; + + NSURL *chunkFileURL = _chunkFetcher.bodyFileURL; + BOOL wasTemporaryUploadFile = ![chunkFileURL isEqual:_uploadFileURL]; + if (wasTemporaryUploadFile) { + NSError *error; + [[NSFileManager defaultManager] removeItemAtURL:chunkFileURL error:&error]; + if (error) { + GTMSESSION_LOG_DEBUG(@"removingItemAtURL failed: %@\n%@", error, chunkFileURL); + } + } + + _recentChunkReponseHeaders = _chunkFetcher.responseHeaders; + + // To avoid retain cycles, remove all properties except the parent identifier. + _chunkFetcher.properties = + @{kGTMSessionUploadFetcherChunkParentKey : [NSValue valueWithNonretainedObject:self]}; + + _chunkFetcher.retryBlock = nil; + _chunkFetcher.sendProgressBlock = nil; + _chunkFetcher = nil; + } // @synchronized(self) +} + +// This method calculates the proper values to pass to the client's send progress block. +// +// The actual total bytes sent include the initial body sent, plus the +// offset into the batched data prior to the current chunk fetcher + +- (void)invokeDelegateWithDidSendBytes:(int64_t)bytesSent + totalBytesSent:(int64_t)totalBytesSent + totalBytesExpectedToSend:(int64_t)totalBytesExpected { + GTMSessionCheckNotSynchronized(self); + + // The clang included with Xcode 13.3 betas added a -Wunused-but-set-variable warning, + // which doesn't (yet) skip variables annotated with objc_precie_lifetime. Since that + // warning is not available in all Xcodes, turn off the -Wunused warning group entirely. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused" + // Ensure the chunk fetcher survives the callback in case the user pauses the upload process. + __block GTMSessionFetcher *holdFetcher = self.chunkFetcher; +#pragma clang diagnostic pop + + [self invokeOnCallbackQueue:self.delegateCallbackQueue + afterUserStopped:NO + block:^{ + GTMSessionFetcherSendProgressBlock sendProgressBlock = + self.sendProgressBlock; + if (sendProgressBlock) { + sendProgressBlock(bytesSent, totalBytesSent, totalBytesExpected); + } + holdFetcher = nil; + }]; +} + +- (void)retrieveUploadChunkGranularityFromResponseHeaders:(NSDictionary *)responseHeaders { + GTMSessionCheckNotSynchronized(self); + + // Standard granularity for Google uploads is 256K. + NSString *chunkGranularityHeader = + [responseHeaders objectForKey:kGTMSessionHeaderXGoogUploadChunkGranularity]; + self.uploadGranularity = chunkGranularityHeader.longLongValue; +} + +#pragma mark - + +- (BOOL)isPaused { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _isPaused; + } // @synchronized(self) +} + +- (void)pauseFetching { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _isPaused = YES; + } // @synchronized(self) + + // Pausing just means stopping the current chunk from uploading; + // when we resume, we will send a query request to the server to + // figure out what bytes to resume sending. + // + // We won't try to cancel the initial data upload, but rather will check + // for being paused in beginChunkFetches. + [self destroyChunkFetcher]; +} + +- (void)resumeFetching { + BOOL wasPaused; + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + wasPaused = _isPaused; + _isPaused = NO; + } // @synchronized(self) + + if (wasPaused) { + [self sendQueryForUploadOffsetWithFetcherProperties:self.properties]; + } +} + +- (void)stopFetching { + // Overrides the superclass + [self destroyChunkFetcher]; + + // If we think the server is waiting for more data, then tell it there won't be more. + if (self.uploadLocationURL) { + [self sendCancelUploadWithFetcherProperties:[self properties]]; + self.uploadLocationURL = nil; + } else { + [self invokeOnCallbackQueue:self.callbackQueue + afterUserStopped:YES + block:^{ + // Repeated calls to stopFetching may cause this path to be reached + // despite having sent a real cancel request, check here to ensure that + // the cancellation handler invocation which fires will definitely be + // for the real request sent previously. + @synchronized(self) { + if (self->_isCancelInFlight) { + return; + } + } + [self triggerCancellationHandlerForFetch:nil data:nil error:nil]; + }]; + } + + [super stopFetching]; +} + +// Fires the cancellation handler, returning whether there was a handler to be fired. +- (BOOL)triggerCancellationHandlerForFetch:(GTMSessionFetcher *)fetcher + data:(NSData *)data + error:(NSError *)error { + GTMSessionUploadFetcherCancellationHandler handler = self.cancellationHandler; + if (handler) { + handler(fetcher, data, error); + self.cancellationHandler = nil; + return YES; + } + return NO; +} + +#pragma mark - + +- (int64_t)updateChunkFetcher:(GTMSessionFetcher *)chunkFetcher forChunkAtOffset:(int64_t)offset { + BOOL isUploadingFileURL = (self.uploadFileURL != nil); + + // Upload another chunk, meeting server-required granularity. + int64_t chunkSize = self.chunkSize; + + int64_t fullUploadLength = [self fullUploadLength]; + BOOL isFileLengthKnown = fullUploadLength >= 0; + + BOOL isUploadingFullFile = (offset == 0 && isFileLengthKnown && chunkSize >= fullUploadLength); + if (!isUploadingFileURL || !isUploadingFullFile) { + // We're not uploading the entire file and given the file URL. Since we'll be + // allocating a subdata block for a chunk, we need to bound it to something that + // won't blow the process's memory. + if (chunkSize > kGTMSessionUploadFetcherMaximumDemandBufferSize) { + chunkSize = kGTMSessionUploadFetcherMaximumDemandBufferSize; + } + } + + int64_t granularity = self.uploadGranularity; + if (granularity > 0) { + if (chunkSize < granularity) { + chunkSize = granularity; + } else { + chunkSize = chunkSize - (chunkSize % granularity); + } + } + + GTMSESSION_ASSERT_DEBUG(offset <= fullUploadLength || fullUploadLength == 0, + @"offset %lld exceeds data length %lld", offset, fullUploadLength); + + if (granularity > 0 && offset < fullUploadLength) { + offset = offset - (offset % granularity); + } + + // If the chunk size is bigger than the remaining data, or else + // it's close enough in size to the remaining data that we'd rather + // avoid having a whole extra http fetch for the leftover bit, then make + // this chunk size exactly match the remaining data size + NSString *command; + int64_t thisChunkSize = chunkSize; + + BOOL isChunkTooBig = (thisChunkSize >= (fullUploadLength - offset)); + BOOL isChunkAlmostBigEnough = (fullUploadLength - offset - 2500 < thisChunkSize); + BOOL isFinalChunk = (isChunkTooBig || isChunkAlmostBigEnough) && isFileLengthKnown; + if (isFinalChunk) { + thisChunkSize = fullUploadLength - offset; + if (thisChunkSize > 0) { + command = @"upload, finalize"; + } else { + command = @"finalize"; + } + } else { + command = @"upload"; + } + NSString *lengthStr = @(thisChunkSize).stringValue; + NSString *offsetStr = @(offset).stringValue; + + [chunkFetcher setRequestValue:command forHTTPHeaderField:kGTMSessionHeaderXGoogUploadCommand]; + [chunkFetcher setRequestValue:lengthStr forHTTPHeaderField:@"Content-Length"]; + [chunkFetcher setRequestValue:offsetStr forHTTPHeaderField:kGTMSessionHeaderXGoogUploadOffset]; + if (_uploadFileLength != kGTMSessionUploadFetcherUnknownFileSize) { + [chunkFetcher setRequestValue:@([self fullUploadLength]).stringValue + forHTTPHeaderField:kGTMSessionHeaderXGoogUploadContentLength]; + } + + // Append the range of bytes in this chunk to the fetcher comment. + NSString *baseComment = self.comment; + [chunkFetcher setCommentWithFormat:@"%@ (%lld-%lld)", baseComment ? baseComment : @"upload", + offset, MAX(0, offset + thisChunkSize - 1)]; + + return thisChunkSize; +} + +// Public properties. +// clang-format off +@synthesize currentOffset = _currentOffset, + allowsCellularAccess = _allowsCellularAccess, + delegateCompletionHandler = _delegateCompletionHandler, + chunkFetcher = _chunkFetcher, + lastChunkRequest = _lastChunkRequest, + subdataGenerating = _subdataGenerating, + shouldInitiateOffsetQuery = _shouldInitiateOffsetQuery, + uploadGranularity = _uploadGranularity, + uploadRetryFactor = _uploadRetryFactor; +// clang-format on + +// Internal properties. +@dynamic fetcherInFlight; +@dynamic activeFetcher; +@dynamic statusCode; +@dynamic delegateCallbackQueue; + ++ (void)removePointer:(void *)pointer fromPointerArray:(NSPointerArray *)pointerArray { + for (NSUInteger index = 0, count = pointerArray.count; index < count; ++index) { + void *pointerAtIndex = [pointerArray pointerAtIndex:index]; + if (pointerAtIndex == pointer) { + [pointerArray removePointerAtIndex:index]; + return; + } + } +} + +- (BOOL)useBackgroundSession { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _useBackgroundSessionOnChunkFetchers; + } // @synchronized(self +} + +- (void)setUseBackgroundSession:(BOOL)useBackgroundSession { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_useBackgroundSessionOnChunkFetchers != useBackgroundSession) { + _useBackgroundSessionOnChunkFetchers = useBackgroundSession; + NSPointerArray *uploadFetcherPointerArrayForBackgroundSessions = + [[self class] uploadFetcherPointerArrayForBackgroundSessions]; + @synchronized(uploadFetcherPointerArrayForBackgroundSessions) { + if (_useBackgroundSessionOnChunkFetchers) { + [uploadFetcherPointerArrayForBackgroundSessions addPointer:(__bridge void *)self]; + } else { + [[self class] removePointer:(__bridge void *)self + fromPointerArray:uploadFetcherPointerArrayForBackgroundSessions]; + } + } // @synchronized(uploadFetcherPointerArrayForBackgroundSessions) + } + } // @synchronized(self) +} + +- (BOOL)canFetchWithBackgroundSession { + // The initial upload fetcher is always a foreground session; the + // useBackgroundSession property will apply only to chunk fetchers, + // not to queries. + return NO; +} + +- (NSDictionary *)responseHeaders { + GTMSessionCheckNotSynchronized(self); + // Overrides the superclass + + // If asked for the fetcher's response, use the most recent chunk fetcher's response, + // since the original request's response lacks useful information like the actual + // Content-Type. + NSDictionary *dict = self.chunkFetcher.responseHeaders; + if (dict) { + return dict; + } + + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + if (_recentChunkReponseHeaders) { + return _recentChunkReponseHeaders; + } + } // @synchronized(self + + // No chunk fetcher yet completed, so return whatever we have from the initial fetch. + return [super responseHeaders]; +} + +- (NSInteger)statusCodeUnsynchronized { + GTMSessionCheckSynchronized(self); + + if (_recentChunkStatusCode != -1) { + // Overrides the superclass to indicate status appropriate to the initial + // or latest chunk fetch + return _recentChunkStatusCode; + } else { + return [super statusCodeUnsynchronized]; + } +} + +- (void)setStatusCode:(NSInteger)val { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _recentChunkStatusCode = val; + } +} + +- (int64_t)initialBodyLength { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _initialBodyLength; + } +} + +- (void)setInitialBodyLength:(int64_t)length { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _initialBodyLength = length; + } +} + +- (int64_t)initialBodySent { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _initialBodySent; + } +} + +- (void)setInitialBodySent:(int64_t)length { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _initialBodySent = length; + } +} + +- (NSURL *)uploadLocationURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + return _uploadLocationURL; + } +} + +- (void)setUploadLocationURL:(NSURL *)locationURL { + @synchronized(self) { + GTMSessionMonitorSynchronized(self); + + _uploadLocationURL = locationURL; + } +} + +- (GTMSessionFetcher *)activeFetcher { + GTMSessionFetcher *result = self.fetcherInFlight; + if (result) return result; + + return self; +} + +- (BOOL)isFetching { + // If there is an active chunk fetcher, then the upload fetcher is considered + // to still be fetching. + if (self.fetcherInFlight != nil) return YES; + + return [super isFetching]; +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" +- (BOOL)waitForCompletionWithTimeout:(NSTimeInterval)timeoutInSeconds { + NSDate *timeoutDate = [NSDate dateWithTimeIntervalSinceNow:timeoutInSeconds]; + + while (self.fetcherInFlight || self.subdataGenerating) { + if ([timeoutDate timeIntervalSinceNow] < 0) return NO; + + if (self.subdataGenerating) { + // Allow time for subdata generation. + NSDate *stopDate = [NSDate dateWithTimeIntervalSinceNow:0.001]; + [[NSRunLoop currentRunLoop] runUntilDate:stopDate]; + } else { + // Wait for any chunk or query fetchers that still have pending callbacks or + // notifications. + BOOL timedOut; + + if (self.fetcherInFlight == self) { + timedOut = ![super waitForCompletionWithTimeout:timeoutInSeconds]; + } else { + timedOut = ![self.fetcherInFlight waitForCompletionWithTimeout:timeoutInSeconds]; + } + if (timedOut) return NO; + } + } + return YES; +} +#pragma clang diagnostic pop + +@end + +@implementation GTMSessionFetcher (GTMSessionUploadFetcherMethods) + +- (GTMSessionUploadFetcher *)parentUploadFetcher { + NSValue *property = [self propertyForKey:kGTMSessionUploadFetcherChunkParentKey]; + if (!property) return nil; + + GTMSessionUploadFetcher *uploadFetcher = property.nonretainedObjectValue; + + GTMSESSION_ASSERT_DEBUG([uploadFetcher isKindOfClass:[GTMSessionUploadFetcher class]], + @"Unexpected parent upload fetcher class: %@", [uploadFetcher class]); + return uploadFetcher; +} + +@end diff --git a/Pods/GTMSessionFetcher/Sources/Core/Public/GTMSessionFetcher/GTMSessionFetcher.h b/Pods/GTMSessionFetcher/Sources/Core/Public/GTMSessionFetcher/GTMSessionFetcher.h new file mode 100644 index 0000000..c5a9fdd --- /dev/null +++ b/Pods/GTMSessionFetcher/Sources/Core/Public/GTMSessionFetcher/GTMSessionFetcher.h @@ -0,0 +1,1370 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * 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. + */ + +// GTMSessionFetcher is a wrapper around NSURLSession for http operations. +// +// What does this offer on top of of NSURLSession? +// +// - Block-style callbacks for useful functionality like progress rather +// than delegate methods. +// - Out-of-process uploads and downloads using NSURLSession, including +// management of fetches after relaunch. +// - Integration with GTMAppAuth for invisible management and refresh of +// authorization tokens. +// - Pretty-printed http logging. +// - Cookies handling that does not interfere with or get interfered with +// by WebKit cookies or on Mac by Safari and other apps. +// - Credentials handling for the http operation. +// - Rate-limiting and cookie grouping when fetchers are created with +// GTMSessionFetcherService. +// +// If the bodyData or bodyFileURL property is set, then a POST request is assumed. +// +// Each fetcher is assumed to be for a one-shot fetch request; don't reuse the object +// for a second fetch. +// +// The fetcher will be self-retained as long as a connection is pending. +// +// To keep user activity private, URLs must have an https scheme (unless the property +// allowedInsecureSchemes is set to permit the scheme.) +// +// Callbacks will be released when the fetch completes or is stopped, so there is no need +// to use weak self references in the callback blocks. +// +// Sample usage: +// +// _fetcherService = [[GTMSessionFetcherService alloc] init]; +// +// GTMSessionFetcher *myFetcher = [_fetcherService fetcherWithURLString:myURLString]; +// myFetcher.retryEnabled = YES; +// myFetcher.comment = @"First profile image"; +// +// // Optionally specify a file URL or NSData for the request body to upload. +// myFetcher.bodyData = [postString dataUsingEncoding:NSUTF8StringEncoding]; +// +// [myFetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { +// if (error != nil) { +// // Server status code or network error. +// // +// // If the domain is kGTMSessionFetcherStatusDomain then the error code +// // is a failure status from the server. +// } else { +// // Fetch succeeded. +// } +// }]; +// +// There is also a beginFetch call that takes a pointer and selector for the completion handler; +// a pointer and selector is a better style when the callback is a substantial, separate method. +// +// NOTE: Fetches may retrieve data from the server even though the server +// returned an error, so the criteria for success is a non-nil error. +// The completion handler is called when the server status is >= 300 with an NSError +// having domain kGTMSessionFetcherStatusDomain and code set to the server status. +// +// Status codes are at +// +// +// Background session support: +// +// Out-of-process uploads and downloads may be created by setting the fetcher's +// useBackgroundSession property. Data to be uploaded should be provided via +// the uploadFileURL property; the download destination should be specified with +// the destinationFileURL. NOTE: Background upload files should be in a location +// that will be valid even after the device is restarted, so the file should not +// be uploaded from a system temporary or cache directory. +// +// Background session transfers are slower, and should typically be used only +// for very large downloads or uploads (hundreds of megabytes). +// +// When background sessions are used in iOS apps, the application delegate must +// pass through the parameters from UIApplicationDelegate's +// application:handleEventsForBackgroundURLSession:completionHandler: to the +// fetcher class. +// +// When the application has been relaunched, it may also create a new fetcher +// instance to handle completion of the transfers. +// +// - (void)application:(UIApplication *)application +// handleEventsForBackgroundURLSession:(NSString *)identifier +// completionHandler:(void (^)())completionHandler { +// // Application was re-launched on completing an out-of-process download. +// +// // Pass the URLSession info related to this re-launch to the fetcher class. +// [GTMSessionFetcher application:application +// handleEventsForBackgroundURLSession:identifier +// completionHandler:completionHandler]; +// +// // Get a fetcher related to this re-launch and re-hook up a completionHandler to it. +// GTMSessionFetcher *fetcher = [GTMSessionFetcher fetcherWithSessionIdentifier:identifier]; +// NSURL *destinationFileURL = fetcher.destinationFileURL; +// fetcher.completionHandler = ^(NSData *data, NSError *error) { +// [self downloadCompletedToFile:destinationFileURL error:error]; +// }; +// } +// +// +// Threading and queue support: +// +// Networking always happens on a background thread; there is no advantage to +// changing thread or queue to create or start a fetcher. +// +// Callbacks are run on the main thread; alternatively, the app may set the +// fetcher's callbackQueue to a dispatch queue. +// +// Once the fetcher's beginFetch method has been called, the fetcher's methods and +// properties may be accessed from any thread. +// +// Downloading to disk: +// +// To have downloaded data saved directly to disk, specify a file URL for the +// destinationFileURL property. +// +// HTTP methods and headers: +// +// Alternative HTTP methods, like PUT, and custom headers can be specified by +// creating the fetcher with an appropriate NSMutableURLRequest. +// +// Custom headers can also be provided per-request via an instance of `GTMFetcherDecoratorProtocol` +// passed to `-[GTMSessionFetcherService addDecorator:]`. +// +// Caching: +// +// The fetcher avoids caching. That is best for API requests, but may hurt +// repeat fetches of static data. Apps may enable a persistent disk cache by +// customizing the config: +// +// fetcher.configurationBlock = ^(GTMSessionFetcher *configFetcher, +// NSURLSessionConfiguration *config) { +// config.URLCache = [NSURLCache sharedURLCache]; +// }; +// +// Or use the standard system config to share cookie storage with web views +// and to enable disk caching: +// +// fetcher.configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; +// +// +// Cookies: +// +// There are three supported mechanisms for remembering cookies between fetches. +// +// By default, a standalone GTMSessionFetcher uses a mutable array held +// statically to track cookies for all instantiated fetchers. This avoids +// cookies being set by servers for the application from interfering with +// Safari and WebKit cookie settings, and vice versa. +// The fetcher cookies are lost when the application quits. +// +// To rely instead on WebKit's global NSHTTPCookieStorage, set the fetcher's +// cookieStorage property: +// myFetcher.cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; +// +// To share cookies with other apps, use the method introduced in iOS 9/OS X 10.11: +// myFetcher.cookieStorage = +// [NSHTTPCookieStorage sharedCookieStorageForGroupContainerIdentifier:kMyCompanyContainedID]; +// +// To ignore existing cookies and only have cookies related to the single fetch +// be applied, make a temporary cookie storage object: +// myFetcher.cookieStorage = [[GTMSessionCookieStorage alloc] init]; +// +// Note: cookies set while following redirects will be sent to the server, as +// the redirects are followed by the fetcher. +// +// To completely disable cookies, adjust the session configuration appropriately +// in the fetcher or fetcher service: +// fetcher.configurationBlock = ^(GTMSessionFetcher *configFetcher, +// NSURLSessionConfiguration *config) { +// config.HTTPCookieAcceptPolicy = NSHTTPCookieAcceptPolicyNever; +// config.HTTPShouldSetCookies = NO; +// }; +// +// If the fetcher is created from a GTMSessionFetcherService object +// then the cookie storage mechanism is set to use the cookie storage in the +// service object rather than the static storage. Disabling cookies in the +// session configuration set on a service object will disable cookies for all +// fetchers created from that GTMSessionFetcherService object, since the session +// configuration is propagated to the fetcher. +// +// +// Monitoring data transfers. +// +// The fetcher supports a variety of properties for progress monitoring +// progress with callback blocks. +// GTMSessionFetcherSendProgressBlock sendProgressBlock +// GTMSessionFetcherReceivedProgressBlock receivedProgressBlock +// GTMSessionFetcherDownloadProgressBlock downloadProgressBlock +// +// If supplied by the server, the anticipated total download size is available +// as [[myFetcher response] expectedContentLength] (and may be -1 for unknown +// download sizes.) +// +// +// Automatic retrying of fetches +// +// The fetcher can optionally create a timer and reattempt certain kinds of +// fetch failures (status codes 408, request timeout; 502, gateway failure; +// 503, service unavailable; 504, gateway timeout; networking errors +// NSURLErrorTimedOut and NSURLErrorNetworkConnectionLost.) The user may +// set a retry selector to customize the type of errors which will be retried. +// +// Retries are done in an exponential-backoff fashion (that is, after 1 second, +// 2, 4, 8, and so on.) +// +// Enabling automatic retries looks like this: +// myFetcher.retryEnabled = YES; +// +// With retries enabled, the completion callbacks are called only +// when no more retries will be attempted. Calling the fetcher's stopFetching +// method will terminate the retry timer, without the finished or failure +// selectors being invoked. +// +// Optionally, the client may set the maximum retry interval: +// myFetcher.maxRetryInterval = 60.0; // in seconds; default is 60 seconds +// // for downloads, 600 for uploads +// +// Servers should never send a 400 or 500 status for errors that are retryable +// by clients, as those values indicate permanent failures. In nearly all +// cases, the default standard retry behavior is correct for clients, and no +// custom client retry behavior is needed or appropriate. Servers that send +// non-retryable status codes and expect the client to retry the request are +// faulty. +// +// Still, the client may provide a block to determine if a status code or other +// error should be retried. The block returns YES to set the retry timer or NO +// to fail without additional fetch attempts. +// +// The retry method may return the |suggestedWillRetry| argument to get the +// default retry behavior. Server status codes are present in the +// error argument, and have the domain kGTMSessionFetcherStatusDomain. The +// user's method may look something like this: +// +// myFetcher.retryBlock = ^(BOOL suggestedWillRetry, NSError *error, +// GTMSessionFetcherRetryResponse response) { +// // Perhaps examine error.domain and error.code, or fetcher.retryCount +// // +// // Respond with YES to start the retry timer, NO to proceed to the failure +// // callback, or suggestedWillRetry to get default behavior for the +// // current error domain and code values. +// response(suggestedWillRetry); +// }; + +#import + +#if TARGET_OS_IPHONE +#import +#endif +#if TARGET_OS_WATCH +#import +#endif + +// By default it is stripped from non DEBUG builds. Developers can override +// this in their project settings. +#ifndef STRIP_GTM_FETCH_LOGGING +#if !DEBUG +#define STRIP_GTM_FETCH_LOGGING 1 +#else +#define STRIP_GTM_FETCH_LOGGING 0 +#endif +#endif + +// Logs in debug builds. +#ifndef GTMSESSION_LOG_DEBUG +#if DEBUG +#define GTMSESSION_LOG_DEBUG(...) NSLog(__VA_ARGS__) +#else +#define GTMSESSION_LOG_DEBUG(...) \ + do { \ + } while (0) +#endif +#endif + +// Asserts in debug builds (or logs in debug builds if GTMSESSION_ASSERT_AS_LOG +// or NS_BLOCK_ASSERTIONS are defined.) +#ifndef GTMSESSION_ASSERT_DEBUG +#if DEBUG && !defined(NS_BLOCK_ASSERTIONS) && !GTMSESSION_ASSERT_AS_LOG +#undef GTMSESSION_ASSERT_AS_LOG +#define GTMSESSION_ASSERT_AS_LOG 1 +#endif + +#if DEBUG && !GTMSESSION_ASSERT_AS_LOG +#define GTMSESSION_ASSERT_DEBUG(...) NSAssert(__VA_ARGS__) +#elif DEBUG +#define GTMSESSION_ASSERT_DEBUG(pred, ...) \ + if (!(pred)) { \ + NSLog(__VA_ARGS__); \ + } +#else +#define GTMSESSION_ASSERT_DEBUG(pred, ...) \ + do { \ + } while (0) +#endif +#endif + +// Asserts in debug builds, logs in release builds (or logs in debug builds if +// GTMSESSION_ASSERT_AS_LOG is defined.) +#ifndef GTMSESSION_ASSERT_DEBUG_OR_LOG +#if DEBUG && !GTMSESSION_ASSERT_AS_LOG +#define GTMSESSION_ASSERT_DEBUG_OR_LOG(...) NSAssert(__VA_ARGS__) +#else +#define GTMSESSION_ASSERT_DEBUG_OR_LOG(pred, ...) \ + if (!(pred)) { \ + NSLog(__VA_ARGS__); \ + } +#endif +#endif + +// Macro useful for more verbose logging from NSURLSession during debugging. +#if 0 +#define GTMSESSION_LOG_DEBUG_VERBOSE(...) GTMSESSION_LOG_DEBUG(__VA_ARGS__) +#else +#define GTMSESSION_LOG_DEBUG_VERBOSE(...) +#endif + +// For iOS, the fetcher can declare itself a background task to allow fetches +// to finish when the app leaves the foreground. +// +// (This is unrelated to providing a background configuration, which allows +// out-of-process uploads and downloads.) +// +// To disallow use of background tasks during fetches, the target should define +// GTM_BACKGROUND_TASK_FETCHING to 0, or alternatively may set the +// skipBackgroundTask property to YES. +#if !defined(GTM_BACKGROUND_TASK_FETCHING) && \ + (TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_MACCATALYST) +#define GTM_BACKGROUND_TASK_FETCHING 1 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// When creating background sessions to perform out-of-process uploads and +// downloads, on app launch any background sessions must be reconnected in +// order to receive events that occurred while the app was not running. +// +// The fetcher will automatically attempt to recreate the sessions on app +// start, but doing so reads from NSUserDefaults. This may have launch-time +// performance impacts. +// +// To avoid launch performance impacts, on iPhone/iPad with iOS 13+ the +// GTMSessionFetcher class will register for the app launch notification and +// perform the reconnect then. +// +// Apps targeting Mac or older iOS SDKs can opt into the new behavior by defining +// GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH=1. +// +// Apps targeting new SDKs can force the old behavior by defining +// GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH = 0. +#ifndef GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH +// Default to the on-launch behavior for iOS 13+. +#if TARGET_OS_IOS && defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0 +#define GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH 1 +#else +#define GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH 0 +#endif +#endif + +NS_ASSUME_NONNULL_BEGIN + +// Notifications +// +// Fetch started and stopped, and fetch retry delay started and stopped. +extern NSString *const kGTMSessionFetcherStartedNotification; +extern NSString *const kGTMSessionFetcherStoppedNotification; +extern NSString *const kGTMSessionFetcherRetryDelayStartedNotification; +extern NSString *const kGTMSessionFetcherRetryDelayStoppedNotification; + +// Completion handler notification. This is intended for use by code capturing +// and replaying fetch requests and results for testing. For fetches where +// destinationFileURL or accumulateDataBlock is set for the fetcher, the data +// will be nil for successful fetches. +// +// This notification is posted on the main thread. +extern NSString *const kGTMSessionFetcherCompletionInvokedNotification; +extern NSString *const kGTMSessionFetcherCompletionDataKey; +extern NSString *const kGTMSessionFetcherCompletionErrorKey; + +// Constants for NSErrors created by the fetcher (excluding server status errors, +// and error objects originating in the OS.) +extern NSString *const kGTMSessionFetcherErrorDomain; + +// The fetcher turns server error status values (3XX, 4XX, 5XX) into NSErrors +// with domain kGTMSessionFetcherStatusDomain. +// +// Any server response body data accompanying the status error is added to the +// userInfo dictionary with key kGTMSessionFetcherStatusDataKey. +extern NSString *const kGTMSessionFetcherStatusDomain; +extern NSString *const kGTMSessionFetcherStatusDataKey; +extern NSString *const kGTMSessionFetcherStatusDataContentTypeKey; + +// When a fetch fails with an error, these keys are included in the error userInfo +// dictionary if retries were attempted. +extern NSString *const kGTMSessionFetcherNumberOfRetriesDoneKey; +extern NSString *const kGTMSessionFetcherElapsedIntervalWithRetriesKey; + +// Background session support requires access to NSUserDefaults. +// If [NSUserDefaults standardUserDefaults] doesn't yield the correct NSUserDefaults for your usage, +// ie for an App Extension, then implement this class/method to return the correct NSUserDefaults. +// https://developer.apple.com/library/ios/documentation/General/Conceptual/ExtensibilityPG/ExtensionScenarios.html#//apple_ref/doc/uid/TP40014214-CH21-SW6 +@interface GTMSessionFetcherUserDefaultsFactory : NSObject + ++ (NSUserDefaults *)fetcherUserDefaults; + +@end + +#ifdef __cplusplus +} +#endif + +typedef NS_ENUM(NSInteger, GTMSessionFetcherError) { + GTMSessionFetcherErrorDownloadFailed = -1, + GTMSessionFetcherErrorUploadChunkUnavailable = -2, + GTMSessionFetcherErrorBackgroundExpiration = -3, + GTMSessionFetcherErrorBackgroundFetchFailed = -4, + GTMSessionFetcherErrorInsecureRequest = -5, + GTMSessionFetcherErrorTaskCreationFailed = -6, + + // This error is only used if `stopFetchingTriggersCompletionHandler` is + // enabled and `-stopFetching` is called on that fetcher. + GTMSessionFetcherErrorUserCancelled = -7, +}; + +typedef NS_ENUM(NSInteger, GTMSessionFetcherStatus) { + // Standard http status codes. + GTMSessionFetcherStatusNotModified = 304, + GTMSessionFetcherStatusBadRequest = 400, + GTMSessionFetcherStatusUnauthorized = 401, + GTMSessionFetcherStatusForbidden = 403, + GTMSessionFetcherStatusPreconditionFailed = 412 +}; + +#ifdef __cplusplus +extern "C" { +#endif + +@class GTMSessionCookieStorage; +@class GTMSessionFetcher; +@class GTMSessionFetcherService; + +// The configuration block is for modifying the NSURLSessionConfiguration only. +// DO NOT change any fetcher properties in the configuration block. +typedef void (^GTMSessionFetcherConfigurationBlock)(GTMSessionFetcher *fetcher, + NSURLSessionConfiguration *configuration); +typedef void (^GTMSessionFetcherSystemCompletionHandler)(void); +typedef void (^GTMSessionFetcherCompletionHandler)(NSData *_Nullable data, + NSError *_Nullable error); +typedef NSURLSession *_Nullable (^GTMSessionFetcherSessionCreationBlock)( + id _Nullable sessionDelegate); +typedef void (^GTMSessionFetcherBodyStreamProviderResponse)(NSInputStream *bodyStream); +typedef void (^GTMSessionFetcherBodyStreamProvider)( + GTMSessionFetcherBodyStreamProviderResponse response); +typedef void (^GTMSessionFetcherDidReceiveResponseDispositionBlock)( + NSURLSessionResponseDisposition disposition); +typedef void (^GTMSessionFetcherDidReceiveResponseBlock)( + NSURLResponse *response, GTMSessionFetcherDidReceiveResponseDispositionBlock dispositionBlock); +typedef void (^GTMSessionFetcherChallengeDispositionBlock)( + NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *_Nullable credential); +typedef void (^GTMSessionFetcherChallengeBlock)( + GTMSessionFetcher *fetcher, NSURLAuthenticationChallenge *challenge, + GTMSessionFetcherChallengeDispositionBlock dispositionBlock); +typedef void (^GTMSessionFetcherWillRedirectResponse)(NSURLRequest *_Nullable redirectedRequest); +typedef void (^GTMSessionFetcherWillRedirectBlock)(NSHTTPURLResponse *redirectResponse, + NSURLRequest *redirectRequest, + GTMSessionFetcherWillRedirectResponse response); +typedef void (^GTMSessionFetcherAccumulateDataBlock)(NSData *_Nullable buffer); +typedef void (^GTMSessionFetcherSimulateByteTransferBlock)(NSData *_Nullable buffer, + int64_t bytesWritten, + int64_t totalBytesWritten, + int64_t totalBytesExpectedToWrite); +typedef void (^GTMSessionFetcherReceivedProgressBlock)(int64_t bytesWritten, + int64_t totalBytesWritten); +typedef void (^GTMSessionFetcherDownloadProgressBlock)(int64_t bytesWritten, + int64_t totalBytesWritten, + int64_t totalBytesExpectedToWrite); +typedef void (^GTMSessionFetcherSendProgressBlock)(int64_t bytesSent, int64_t totalBytesSent, + int64_t totalBytesExpectedToSend); +typedef void (^GTMSessionFetcherWillCacheURLResponseResponse)( + NSCachedURLResponse *_Nullable cachedResponse); +typedef void (^GTMSessionFetcherWillCacheURLResponseBlock)( + NSCachedURLResponse *proposedResponse, + GTMSessionFetcherWillCacheURLResponseResponse responseBlock); +typedef void (^GTMSessionFetcherRetryResponse)(BOOL shouldRetry); +typedef void (^GTMSessionFetcherRetryBlock)(BOOL suggestedWillRetry, NSError *_Nullable error, + GTMSessionFetcherRetryResponse response); + +API_AVAILABLE(ios(10.0), macosx(10.12), tvos(10.0), watchos(6.0)) +typedef void (^GTMSessionFetcherMetricsCollectionBlock)(NSURLSessionTaskMetrics *metrics); + +typedef void (^GTMSessionFetcherTestResponse)(NSHTTPURLResponse *_Nullable response, + NSData *_Nullable data, NSError *_Nullable error); +typedef void (^GTMSessionFetcherTestBlock)(GTMSessionFetcher *fetcherToTest, + GTMSessionFetcherTestResponse testResponse); + +void GTMSessionFetcherAssertValidSelector(id _Nullable obj, SEL _Nullable sel, ...); + +// Utility functions for applications self-identifying to servers via a +// user-agent header + +// The "standard" user agent includes the application identifier, taken from the bundle, +// followed by a space and the system version string. Pass nil to use +mainBundle as the source +// of the bundle identifier. +// +// Applications may use this as a starting point for their own user agent strings, perhaps +// with additional sections appended. Use GTMFetcherCleanedUserAgentString() below to +// clean up any string being added to the user agent. +NSString *GTMFetcherStandardUserAgentString(NSBundle *_Nullable bundle); + +// Make a generic name and version for the current application, like +// com.example.MyApp/1.2.3 relying on the bundle identifier and the +// CFBundleShortVersionString or CFBundleVersion. +// +// The bundle ID may be overridden as the base identifier string by +// adding to the bundle's Info.plist a "GTMUserAgentID" key. +// +// The application version may be overridden by adding to the bundle's +// Info.plist a "GTMUserAgentVersion" key. +// +// If no bundle ID or override is available, the process name preceded +// by "proc_" is used. +NSString *GTMFetcherApplicationIdentifier(NSBundle *_Nullable bundle); + +// Make an identifier like "MacOSX/10.7.1" or "iPod_Touch/4.1 hw/iPod1_1" +NSString *GTMFetcherSystemVersionString(void); + +// Make a parseable user-agent identifier from the given string, replacing whitespace +// and commas with underscores, and removing other characters that may interfere +// with parsing of the full user-agent string. +// +// For example, @"[My App]" would become @"My_App" +NSString *GTMFetcherCleanedUserAgentString(NSString *str); + +// Grab the data from an input stream. Since streams cannot be assumed to be rewindable, +// this may be destructive; the caller can try to rewind the stream (by setting the +// NSStreamFileCurrentOffsetKey property) or can just use the NSData to make a new +// NSInputStream. This function is intended to facilitate testing rather than be used in +// production. +// +// This function operates synchronously on the current thread. Depending on how the +// input stream is implemented, it may be appropriate to dispatch to a different +// queue before calling this function. +// +// Failure is indicated by a returned data value of nil. +NSData *_Nullable GTMDataFromInputStream(NSInputStream *inputStream, NSError **outError); + +#ifdef __cplusplus +} // extern "C" +#endif + +// Completion handler passed to -[GTMFetcherDecoratorProtocol fetcherWillStart:completionHandler:]. +typedef void (^GTMFetcherDecoratorFetcherWillStartCompletionHandler)(NSURLRequest *_Nullable, + NSError *_Nullable); + +// Allows intercepting a request and optionally modifying it before the request (or a retry) +// is sent. See `-[GTMSessionFetcherService addDecorator:]` and `-[GTMSessionFetcherService +// removeDecorator:]`. +// +// Decorator methods must be thread-safe, as they might be invoked on any queue. +@protocol GTMFetcherDecoratorProtocol + +// Invoked just before a fetcher's request starts. +// +// After the decorator's work is complete, the decorator must invoke `handler(request, error)` +// either synchronously or asynchronously (on any queue). +// +// If no changes are to be made, pass `nil` for both `request` and `error`. +// +// Otherwise, if `error` is non-nil, then the fetcher is stopped with the given error, and any +// further decorators' `-fetcherWillStart:completionHandler:` methods are not invoked. +// +// Otherwise, the decorator may use `[fetcher.request mutableCopy]`, make changes to the mutable +// copy of the request, and pass the result to the handler via the `request` parameter. +// +// To distinguish the initial fetch from retries, the decorator can look at `fetcher.retryCount`. +// +// This method must not block the caller (e.g., performing synchronous I/O). Perform any blocking +// work or I/O on a different queue, then invoke `handler` with the results after the blocking work +// completes. +- (void)fetcherWillStart:(GTMSessionFetcher *)fetcher + completionHandler:(GTMFetcherDecoratorFetcherWillStartCompletionHandler)handler; + +// Invoked just after a fetcher's request finishes (either on success or on failure). +// +// After the decorator's work is complete, the decorator must invoke `handler()` either +// synchronously or asynchronously (on any queue). +// +// To access the result of the fetch, the decorator can look at `fetcher.response`. +// +// This method must not block the caller (e.g., performing synchronous I/O). Perform any blocking +// work or I/O on a different queue, then invoke `handler` with the results after the blocking work +// completes. +- (void)fetcherDidFinish:(GTMSessionFetcher *)fetcher + withData:(nullable NSData *)data + error:(nullable NSError *)error + completionHandler:(void (^)(void))handler; + +@end + +// This protocol allows abstract references to the fetcher service. +// +// Apps should not need to use this protocol. +@protocol GTMSessionFetcherServiceProtocol + +- (GTMSessionFetcher *)fetcherWithRequest:(NSURLRequest *)request; + +@property(atomic, strong, null_resettable, readonly) dispatch_queue_t callbackQueue; + +// These properties are being removed from the protocol; clients should not attempt new +// accesses to them. +@property(atomic, assign) BOOL reuseSession; +@property(atomic, readonly, strong, nullable) NSOperationQueue *delegateQueue; + +@end // @protocol GTMSessionFetcherServiceProtocol + +__deprecated_msg("implement GTMSessionFetcherAuthorizer instead") + @protocol GTMFetcherAuthorizationProtocol +@required +// This protocol allows us to call the authorizer without requiring its sources +// in this project. This protocol is deprecated in favor of GTMSessionFetcherAuthorizer, +// and implementations should move to that protocol in anticipation of +// GTMFetcherAuthorizationProtocol being deleted in a future release. + +// This method is being phased out. While implementing it is necessary to satisfy +// the protocol's @required restrictions, conforming implementations that implement +// authorizeRequest:completionHandler: will have that called instead. +// be removed in a future version when GTMFetcherAuthorizationProtocol is +// also removed. +- (void)authorizeRequest:(nullable NSMutableURLRequest *)request + delegate:(id)delegate + didFinishSelector:(SEL)sel + __deprecated_msg("implement authorizeRequest:completionHandler: instead"); + +- (void)stopAuthorization; + +- (void)stopAuthorizationForRequest:(NSURLRequest *)request; + +- (BOOL)isAuthorizingRequest:(NSURLRequest *)request; + +- (BOOL)isAuthorizedRequest:(NSURLRequest *)request; + +@property(atomic, strong, readonly, nullable) NSString *userEmail; + +@optional + +// This method is prefered over authorizeRequest:delegate:didFinishSelector:, and +// becomes a required method in the GTMSessionFetcherAuthorizer protocol. +- (void)authorizeRequest:(nullable NSMutableURLRequest *)request + completionHandler:(void (^)(NSError *_Nullable error))handler; + +// Indicate if authorization may be attempted. Even if this succeeds, +// authorization may fail if the user's permissions have been revoked. +@property(atomic, readonly) BOOL canAuthorize; + +// For development only, allow authorization of non-SSL requests, allowing +// transmission of the bearer token unencrypted. +@property(atomic, assign) BOOL shouldAuthorizeAllRequests; + +@property(atomic, weak, nullable) id fetcherService; + +- (BOOL)primeForRefresh; + +@end + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated" +// This is the preferred, forward-going protocol for fetcher authorization. it +// currently implements the deprecated GTMFetcherAuthorizationProtocol in order +// to avoid changing the GTMSessionFetcher API surface while implementations +// migrate. In a future release, the non-deprecated method declarations will be +// moved here and the GTMFetcherAuthorizationProtocol and the deprecated methods +// deleted. +@protocol GTMSessionFetcherAuthorizer +// This protocol allows us to call the authorizer without requiring its sources +// in this project. +#pragma clang diagnostic pop +@required + +// Authorizers should implement this method rather than the selector-based +// callback form from the old protocol. +- (void)authorizeRequest:(nullable NSMutableURLRequest *)request + completionHandler:(void (^)(NSError *_Nullable error))handler; + +@optional +// This method is re-declared here as @optional only to quash deprecation warnings +// on the @required declaration from GTMFetcherAuthorizationProtocol, which +// must still be provided by conforming implementations. Once the old protocol has +// been removed, this method will be marked unavailable to trigger implementations +// to stop providing it, and it will eventually be removed. +- (void)authorizeRequest:(nullable NSMutableURLRequest *)request + delegate:(id)delegate + didFinishSelector:(SEL)sel; + +@end + +#if GTM_BACKGROUND_TASK_FETCHING +// A protocol for an alternative target for messages from GTMSessionFetcher to UIApplication. +// Set the target using +[GTMSessionFetcher setSubstituteUIApplication:] +@protocol GTMUIApplicationProtocol +- (UIBackgroundTaskIdentifier)beginBackgroundTaskWithName:(nullable NSString *)taskName + expirationHandler:(void (^__nullable)(void))handler; +- (void)endBackgroundTask:(UIBackgroundTaskIdentifier)identifier; +@end +#endif + +#pragma mark - + +// GTMSessionFetcher objects are used for async retrieval of an http get or post +// +// See additional comments at the beginning of this file +@interface GTMSessionFetcher : NSObject + +// Create a fetcher +// +// fetcherWithRequest will return an autoreleased fetcher, but if +// the connection is successfully created, the connection should retain the +// fetcher for the life of the connection as well. So the caller doesn't have +// to retain the fetcher explicitly unless they want to be able to cancel it. ++ (instancetype)fetcherWithRequest:(nullable NSURLRequest *)request; + +// Convenience methods that make a request, like +fetcherWithRequest ++ (instancetype)fetcherWithURL:(NSURL *)requestURL; ++ (instancetype)fetcherWithURLString:(NSString *)requestURLString; + +// Methods for creating fetchers to continue previous fetches. ++ (instancetype)fetcherWithDownloadResumeData:(NSData *)resumeData; ++ (nullable instancetype)fetcherWithSessionIdentifier:(NSString *)sessionIdentifier; + +// Returns an array of currently active fetchers for background sessions, +// both restarted and newly created ones. ++ (NSArray *)fetchersForBackgroundSessions; + +// Designated initializer. +// +// Applications should create fetchers with a "fetcherWith..." method on a fetcher +// service or a class method, not with this initializer. +// +// The configuration should typically be nil. Applications needing to customize +// the configuration may do so by setting the configurationBlock property. +- (instancetype)initWithRequest:(nullable NSURLRequest *)request + configuration:(nullable NSURLSessionConfiguration *)configuration; + +// The fetcher's request. This may not be set after beginFetch has been invoked. The request +// may change due to redirects. +@property(atomic, strong, nullable) NSURLRequest *request; + +// Set a header field value on the request. Header field value changes will not +// affect a fetch after the fetch has begun. +- (void)setRequestValue:(nullable NSString *)value forHTTPHeaderField:(NSString *)field; + +// Data used for resuming a download task. +@property(atomic, readonly, nullable) NSData *downloadResumeData; + +// The configuration; this must be set before the fetch begins. If no configuration is +// set or inherited from the fetcher service, then the fetcher uses an ephemeral config. +// +// NOTE: This property should typically be nil. Applications needing to customize +// the configuration should do so by setting the configurationBlock property. +// That allows the fetcher to pick an appropriate base configuration, with the +// application setting only the configuration properties it needs to customize. +@property(atomic, strong, nullable) NSURLSessionConfiguration *configuration; + +// A block the client may use to customize the configuration used to create the session. +// +// This is called synchronously, either on the thread that begins the fetch or, during a retry, +// on the main thread. The configuration block may be called repeatedly if multiple fetchers are +// created. +// +// The configuration block is for modifying the NSURLSessionConfiguration only. +// DO NOT change any fetcher properties in the configuration block. Fetcher properties +// may be set in the fetcher service prior to fetcher creation, or on the fetcher prior +// to invoking beginFetch. +@property(atomic, copy, nullable) GTMSessionFetcherConfigurationBlock configurationBlock; + +// A session is created as needed by the fetcher. A fetcher service object +// may maintain sessions for multiple fetches to the same host. +@property(atomic, strong, nullable) NSURLSession *session; + +// The task in flight. +@property(atomic, readonly, nullable) NSURLSessionTask *sessionTask; + +// The background session identifier. +@property(atomic, readonly, nullable) NSString *sessionIdentifier; + +// Indicates a fetcher created to finish a background session task. +@property(atomic, readonly) BOOL wasCreatedFromBackgroundSession; + +// Indicates the client has committed to reconnecting this background session when +// the app restarts. If this value is YES, the session fetcher will not automatically +// call beginFetchWithCompletionHandler: on the restored fetcher on app start, and +// the session will not handle system events until the client explicitly does. +@property(atomic, assign) BOOL clientWillReconnectBackgroundSession; + +// Additional user-supplied data to encode into the session identifier. Since session identifier +// length limits are unspecified, this should be kept small. Key names beginning with an underscore +// are reserved for use by the fetcher. +@property(atomic, strong, nullable) NSDictionary *sessionUserInfo; + +// The human-readable description to be assigned to the task. +@property(atomic, copy, nullable) NSString *taskDescription; + +// The priority assigned to the task, if any. Use NSURLSessionTaskPriorityLow, +// NSURLSessionTaskPriorityDefault, or NSURLSessionTaskPriorityHigh. +@property(atomic, assign) float taskPriority; + +// The fetcher encodes information used to resume a session in the session identifier. +// This method, intended for internal use returns the encoded information. The sessionUserInfo +// dictionary is stored as identifier metadata. +- (nullable NSDictionary *)sessionIdentifierMetadata; + +#if TARGET_OS_IPHONE && !TARGET_OS_WATCH +// The app should pass to this method the completion handler passed in the app delegate method +// application:handleEventsForBackgroundURLSession:completionHandler: ++ (void)application:(UIApplication *)application + handleEventsForBackgroundURLSession:(NSString *)identifier + completionHandler:(GTMSessionFetcherSystemCompletionHandler)completionHandler; +#endif + +// Indicate that a newly created session should be a background session. +// A new session identifier will be created by the fetcher. +// +// Warning: The only thing background sessions are for is rare download +// of huge, batched files of data. And even just for those, there's a lot +// of pain and hackery needed to get transfers to actually happen reliably +// with background sessions. +// +// Don't try to upload or download in many background sessions, since the system +// will impose an exponentially increasing time penalty to prevent the app from +// getting too much background execution time. +// +// References: +// +// "Moving to Fewer, Larger Transfers" +// https://forums.developer.apple.com/thread/14853 +// +// "NSURLSession’s Resume Rate Limiter" +// https://forums.developer.apple.com/thread/14854 +// +// "Background Session Task state persistence" +// https://forums.developer.apple.com/thread/11554 +// +@property(atomic, assign) BOOL useBackgroundSession; + +// Indicates if the fetcher was started using a background session. +@property(atomic, readonly, getter=isUsingBackgroundSession) BOOL usingBackgroundSession; + +// Indicates if uploads should use an upload task. This is always set for file or stream-provider +// bodies, but may be set explicitly for NSData bodies. +@property(atomic, assign) BOOL useUploadTask; + +// Indicates that the fetcher is using a session that may be shared with other fetchers. +@property(atomic, readonly) BOOL canShareSession; + +// By default, the fetcher allows only secure (https) schemes unless this +// property is set, or the GTM_ALLOW_INSECURE_REQUESTS build flag is set. +// +// For example, during debugging when fetching from a development server that lacks SSL support, +// this may be set to @[ @"http" ], or when the fetcher is used to retrieve local files, +// this may be set to @[ @"file" ]. +// +// This should be left as nil for release builds to avoid creating the opportunity for +// leaking private user behavior and data. If a server is providing insecure URLs +// for fetching by the client app, report the problem as server security & privacy bug. +// +// For builds with the iOS 9/OS X 10.11 and later SDKs, this property is required only when +// the app specifies NSAppTransportSecurity/NSAllowsArbitraryLoads in the main bundle's Info.plist. +@property(atomic, copy, nullable) NSArray *allowedInsecureSchemes; + +// By default, the fetcher prohibits localhost requests unless this property is set, +// or the GTM_ALLOW_INSECURE_REQUESTS build flag is set. +// +// For localhost requests, the URL scheme is not checked when this property is set. +// +// For builds with the iOS 9/OS X 10.11 and later SDKs, this property is required only when +// the app specifies NSAppTransportSecurity/NSAllowsArbitraryLoads in the main bundle's Info.plist. +@property(atomic, assign) BOOL allowLocalhostRequest; + +// By default, the fetcher requires valid server certs. This may be bypassed +// temporarily for development against a test server with an invalid cert. +@property(atomic, assign) BOOL allowInvalidServerCertificates; + +// Cookie storage object for this fetcher. If nil, the fetcher will use a static cookie +// storage instance shared among fetchers. If this fetcher was created by a fetcher service +// object, it will be set to use the service object's cookie storage. See Cookies section above for +// the full discussion. +// +// Because as of Jan 2014 standalone instances of NSHTTPCookieStorage do not actually +// store any cookies (Radar 15735276) we use our own subclass, GTMSessionCookieStorage, +// to hold cookies in memory. +@property(atomic, strong, nullable) NSHTTPCookieStorage *cookieStorage; + +// Setting the credential is optional; it is used if the connection receives +// an authentication challenge. +@property(atomic, strong, nullable) NSURLCredential *credential; + +// Setting the proxy credential is optional; it is used if the connection +// receives an authentication challenge from a proxy. +@property(atomic, strong, nullable) NSURLCredential *proxyCredential; + +// If body data, body file URL, or body stream provider is not set, then a GET request +// method is assumed. +@property(atomic, strong, nullable) NSData *bodyData; + +// File to use as the request body. This forces use of an upload task. +@property(atomic, strong, nullable) NSURL *bodyFileURL; + +// Length of body to send, expected or actual. +@property(atomic, readonly) int64_t bodyLength; + +// The body stream provider may be called repeatedly to provide a body. +// Setting a body stream provider forces use of an upload task. +@property(atomic, copy, nullable) GTMSessionFetcherBodyStreamProvider bodyStreamProvider; + +#pragma clang diagnostic push +// For now retain the existing API surface of accepting a GTMFetcherAuthorizationProtocol +// for the authorizer, but the intent is that this will change to take the new +// GTMSessionFetcherAuthorizer protocol instead in a future major version update. +#pragma clang diagnostic ignored "-Wdeprecated" +// Object to add authorization to the request, if needed. +// +// This may not be changed once beginFetch has been invoked. +@property(atomic, strong, nullable) id authorizer; +#pragma clang diagnostic pop + +// The service object that created and monitors this fetcher, if any. +@property(atomic, strong) GTMSessionFetcherService *service; + +// The host, if any, used to classify this fetcher in the fetcher service. +@property(atomic, copy, nullable) NSString *serviceHost; + +// The priority, if any, used for starting fetchers in the fetcher service. +// +// Lower values are higher priority; the default is 0, and values may +// be negative or positive. This priority affects only the start order of +// fetchers that are being delayed by a fetcher service when the running fetchers +// exceeds the service's maxRunningFetchersPerHost. A priority of NSIntegerMin will +// exempt this fetcher from delay. +@property(atomic, assign) NSInteger servicePriority; + +// The delegate's optional didReceiveResponse block may be used to inspect or alter +// the session task response. +// +// This is called on the callback queue. +@property(atomic, copy, nullable) GTMSessionFetcherDidReceiveResponseBlock didReceiveResponseBlock; + +// The delegate's optional challenge block may be used to inspect or alter +// the session task challenge. +// +// If this block is not set, the fetcher's default behavior for the NSURLSessionTask +// didReceiveChallenge: delegate method is to use the fetcher's respondToChallenge: method +// which relies on the fetcher's credential and proxyCredential properties. +// +// Warning: This may be called repeatedly if the challenge fails. Check +// challenge.previousFailureCount to identify repeated invocations. +// +// This is called on the callback queue. +@property(atomic, copy, nullable) GTMSessionFetcherChallengeBlock challengeBlock; + +// The delegate's optional willRedirect block may be used to inspect or alter +// the redirection. +// +// This is called on the callback queue. +@property(atomic, copy, nullable) GTMSessionFetcherWillRedirectBlock willRedirectBlock; + +// The optional send progress block reports body bytes uploaded. +// +// This is called on the callback queue. +@property(atomic, copy, nullable) GTMSessionFetcherSendProgressBlock sendProgressBlock; + +// The optional accumulate block may be set by clients wishing to accumulate data +// themselves rather than let the fetcher append each buffer to an NSData. +// +// When this is called with nil data (such as on redirect) the client +// should empty its accumulation buffer. +// +// This is called on the callback queue. +@property(atomic, copy, nullable) GTMSessionFetcherAccumulateDataBlock accumulateDataBlock; + +// The optional received progress block may be used to monitor data +// received from a data task. +// +// This is called on the callback queue. +@property(atomic, copy, nullable) GTMSessionFetcherReceivedProgressBlock receivedProgressBlock; + +// The delegate's optional downloadProgress block may be used to monitor download +// progress in writing to disk. +// +// This is called on the callback queue. +@property(atomic, copy, nullable) GTMSessionFetcherDownloadProgressBlock downloadProgressBlock; + +// The delegate's optional willCacheURLResponse block may be used to alter the cached +// NSURLResponse. The user may prevent caching by passing nil to the block's response. +// +// This is called on the callback queue. +@property(atomic, copy, nullable) + GTMSessionFetcherWillCacheURLResponseBlock willCacheURLResponseBlock; + +// Enable retrying; see comments at the top of this file. Setting +// retryEnabled=YES resets the min and max retry intervals. +@property(atomic, assign, getter=isRetryEnabled) BOOL retryEnabled; + +// Retry block is optional for retries. +// +// If present, this block should call the response block with YES to cause a retry or NO to end the +// fetch. +// See comments at the top of this file. +@property(atomic, copy, nullable) GTMSessionFetcherRetryBlock retryBlock; + +// The optional block for collecting the metrics of the present session. +// +// This is called on the callback queue. +@property(atomic, copy, nullable) + GTMSessionFetcherMetricsCollectionBlock metricsCollectionBlock API_AVAILABLE( + ios(10.0), macosx(10.12), tvos(10.0), watchos(6.0)); + +// Retry intervals must be strictly less than maxRetryInterval, else +// they will be limited to maxRetryInterval and no further retries will +// be attempted. Setting maxRetryInterval to 0.0 will reset it to the +// default value, 60 seconds for downloads and 600 seconds for uploads. +@property(atomic, assign) NSTimeInterval maxRetryInterval; + +// Starting retry interval. Setting minRetryInterval to 0.0 will reset it +// to a random value between 1.0 and 2.0 seconds. Clients should normally not +// set this except for unit testing. +@property(atomic, assign) NSTimeInterval minRetryInterval; + +// Multiplier used to increase the interval between retries, typically 2.0. +// Clients should not need to set this. +@property(atomic, assign) double retryFactor; + +// Number of retries attempted. +@property(atomic, readonly) NSUInteger retryCount; + +// Interval delay to precede next retry. +@property(atomic, readonly) NSTimeInterval nextRetryInterval; + +#if GTM_BACKGROUND_TASK_FETCHING +// Skip use of a UIBackgroundTask, thus requiring fetches to complete when the app is in the +// foreground. +// +// Targets should define GTM_BACKGROUND_TASK_FETCHING to 0 to avoid use of a UIBackgroundTask +// on iOS to allow fetches to complete in the background. This property is available when +// it's not practical to set the preprocessor define. +@property(atomic, assign) BOOL skipBackgroundTask; +#endif // GTM_BACKGROUND_TASK_FETCHING + +// Begin fetching the request +// +// The delegate may optionally implement the callback or pass nil for the selector or handler. +// +// The delegate and all callback blocks are retained between the beginFetch call until after the +// finish callback, or until the fetch is stopped. +// +// An error is passed to the callback for server statuses 300 or +// higher, with the status stored as the error object's code. +// +// finishedSEL has a signature like: +// - (void)fetcher:(GTMSessionFetcher *)fetcher +// finishedWithData:(NSData *)data +// error:(NSError *)error; +// +// If the application has specified a destinationFileURL or an accumulateDataBlock +// for the fetcher, the data parameter passed to the callback will be nil. + +- (void)beginFetchWithDelegate:(nullable id)delegate didFinishSelector:(nullable SEL)finishedSEL; + +- (void)beginFetchWithCompletionHandler:(nullable GTMSessionFetcherCompletionHandler)handler; + +// Returns YES if this fetcher is in the process of fetching a URL. +@property(atomic, readonly, getter=isFetching) BOOL fetching; + +// Cancel the fetch of the request that's currently in progress. The completion handler +// will be called with `GTMSessionFetcherErrorUserCancelled` if the property +// `stopFetchingTriggersCompletionHandler` is `YES`. +- (void)stopFetching; + +// Call callbacks with `GTMSessionFetcherErrorUserCancelled` after a `stopFetching`. +// It cannot be changed once the fetcher starts. This should be set to `YES` from +// Swift clients before `beginFetch` with `async/await` since the Swift runtime +// requires the completion handler to be called. +@property(atomic, assign) BOOL stopFetchingTriggersCompletionHandler; + +// A block to be called when the fetch completes. +@property(atomic, copy, nullable) GTMSessionFetcherCompletionHandler completionHandler; + +// A block to be called if download resume data becomes available. +@property(atomic, strong, nullable) void (^resumeDataBlock)(NSData *); + +// Return the status code from the server response. +@property(atomic, readonly) NSInteger statusCode; + +// Return the http headers from the response. +@property(atomic, strong, readonly, nullable) NSDictionary *responseHeaders; + +// The response, once it's been received. +@property(atomic, strong, readonly, nullable) NSURLResponse *response; + +// Bytes downloaded so far. +@property(atomic, readonly) int64_t downloadedLength; + +// Buffer of currently-downloaded data, if available. +@property(atomic, readonly, strong, nullable) NSData *downloadedData; + +// Local path to which the downloaded file will be moved. +// +// If a file already exists at the path, it will be overwritten. +// Will create the enclosing folders if they are not present. +@property(atomic, strong, nullable) NSURL *destinationFileURL; + +// The time this fetcher originally began fetching. This is useful as a time +// barrier for ignoring irrelevant fetch notifications or callbacks. +@property(atomic, strong, readonly, nullable) NSDate *initialBeginFetchDate; + +// userData is retained solely for the convenience of the client. +@property(atomic, strong, nullable) id userData; + +// Stored property values are retained solely for the convenience of the client. +@property(atomic, copy, nullable) NSDictionary *properties; + +- (void)setProperty:(nullable id)obj + forKey:(NSString *)key; // Pass nil for obj to remove the property. +- (nullable id)propertyForKey:(NSString *)key; + +- (void)addPropertiesFromDictionary:(NSDictionary *)dict; + +// Comments are useful for logging, so are strongly recommended for each fetcher. +@property(atomic, copy, nullable) NSString *comment; + +- (void)setCommentWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1, 2); + +// Log of request and response, if logging is enabled +@property(atomic, copy, nullable) NSString *log; + +// Callbacks are run on this queue. If none is supplied, the main queue is used. +// +// CAUTION: This block MUST be a serial queue. Setting a concurrent queue can result in callbacks +// being dispatched concurrently, leading events to appear out-of-order. +@property(atomic, strong, null_resettable) dispatch_queue_t callbackQueue; + +// The queue used internally by the session to invoke its delegate methods in the fetcher. +// +// Application callbacks are always called by the fetcher on the callbackQueue above, +// not on this queue. Apps should generally not change this queue. +// +// The default delegate queue is the main queue. +// +// This value is ignored after the session has been created, so this +// property should be set in the fetcher service rather in the fetcher as it applies +// to a shared session. +@property(atomic, strong, null_resettable) NSOperationQueue *sessionDelegateQueue; + +// DEPRECATED: Callers should use XCTestExpectation instead. +// +// Spin the run loop or sleep the thread, discarding events, until the fetch has completed. +// +// This is only for use in testing or in tools without a user interface. +// +// Note: Synchronous fetches should never be used by shipping apps; they are +// sufficient reason for rejection from the app store. +// +// Returns NO if timed out. +- (BOOL)waitForCompletionWithTimeout:(NSTimeInterval)timeoutInSeconds + __deprecated_msg("Use XCTestExpectation instead"); + +// Test block is optional for testing. +// +// If present, this block will cause the fetcher to skip starting the session, and instead +// use the test block response values when calling the completion handler and delegate code. +// +// Test code can set this on the fetcher or on the fetcher service. For testing libraries +// that use a fetcher without exposing either the fetcher or the fetcher service, the global +// method setGlobalTestBlock: will set the block for all fetchers that do not have a test +// block set. +// +// The test code can pass nil for all response parameters to indicate that the fetch +// should proceed. +// +// Applications can exclude test block support by setting GTM_DISABLE_FETCHER_TEST_BLOCK. +@property(atomic, copy, nullable) GTMSessionFetcherTestBlock testBlock; + ++ (void)setGlobalTestBlock:(nullable GTMSessionFetcherTestBlock)block; + +// When using the testBlock, |testBlockAccumulateDataChunkCount| is the desired number of chunks to +// divide the response data into if the client has streaming enabled. The data will be divided up to +// |testBlockAccumulateDataChunkCount| chunks; however, the exact amount may vary depending on the +// size of the response data (e.g. a 1-byte response can only be divided into one chunk). +@property(atomic, readwrite) NSUInteger testBlockAccumulateDataChunkCount; + +#if GTM_BACKGROUND_TASK_FETCHING +// For testing or to override UIApplication invocations, apps may specify an alternative +// target for messages to UIApplication. ++ (void)setSubstituteUIApplication:(nullable id)substituteUIApplication; ++ (nullable id)substituteUIApplication; +#endif // GTM_BACKGROUND_TASK_FETCHING + +// Exposed for testing. ++ (GTMSessionCookieStorage *)staticCookieStorage; ++ (BOOL)appAllowsInsecureRequests; + +#if STRIP_GTM_FETCH_LOGGING +// If logging is stripped, provide a stub for the main method +// for controlling logging. ++ (void)setLoggingEnabled:(BOOL)flag; ++ (BOOL)isLoggingEnabled; + +#else + +// These methods let an application log specific body text, such as the text description of a binary +// request or response. The application should set the fetcher to defer response body logging until +// the response has been received and the log response body has been set by the app. For example: +// +// fetcher.logRequestBody = [binaryObject stringDescription]; +// fetcher.deferResponseBodyLogging = YES; +// [fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { +// if (error == nil) { +// fetcher.logResponseBody = [[[MyThing alloc] initWithData:data] stringDescription]; +// } +// fetcher.deferResponseBodyLogging = NO; +// }]; + +@property(atomic, copy, nullable) NSString *logRequestBody; +@property(atomic, assign) BOOL deferResponseBodyLogging; +@property(atomic, copy, nullable) NSString *logResponseBody; + +// Internal logging support. +@property(atomic, readonly) NSData *loggedStreamData; +@property(atomic, assign) BOOL hasLoggedError; +@property(atomic, strong, nullable) NSURL *redirectedFromURL; +- (void)appendLoggedStreamData:(NSData *)dataToAdd; +- (void)clearLoggedStreamData; + +#endif // STRIP_GTM_FETCH_LOGGING + +@end + +// Until we can just instantiate NSHTTPCookieStorage for local use, we'll +// implement all the public methods ourselves. This stores cookies only in +// memory. Additional methods are provided for testing. +// +// iOS 9/OS X 10.11 added +[NSHTTPCookieStorage sharedCookieStorageForGroupContainerIdentifier:] +// which may also be used to create cookie storage. +@interface GTMSessionCookieStorage : NSHTTPCookieStorage + +// Add the array off cookies to the storage, replacing duplicates. +// Also removes expired cookies from the storage. +- (void)setCookies:(nullable NSArray *)cookies; + +- (void)removeAllCookies; + +@end + +// Macros to monitor synchronization blocks in debug builds. +// These report problems using GTMSessionCheckDebug. +// +// GTMSessionMonitorSynchronized Start monitoring a top-level-only +// @sync scope. +// GTMSessionMonitorRecursiveSynchronized Start monitoring a top-level or +// recursive @sync scope. +// GTMSessionCheckSynchronized Verify that the current execution +// is inside a @sync scope. +// GTMSessionCheckNotSynchronized Verify that the current execution +// is not inside a @sync scope. +// +// Example usage: +// +// - (void)myExternalMethod { +// @synchronized(self) { +// GTMSessionMonitorSynchronized(self) +// +// - (void)myInternalMethod { +// GTMSessionCheckSynchronized(self); +// +// - (void)callMyCallbacks { +// GTMSessionCheckNotSynchronized(self); +// +// GTMSessionCheckNotSynchronized is available for verifying the code isn't +// in a deadlockable @sync state when posting notifications and invoking +// callbacks. Don't use GTMSessionCheckNotSynchronized immediately before a +// @sync scope; the normal recursiveness check of GTMSessionMonitorSynchronized +// can catch those. + +#ifdef __OBJC__ +// If asserts are entirely no-ops, the synchronization monitor is just a bunch +// of counting code that doesn't report exceptional circumstances in any way. +// Only build the synchronization monitor code if NS_BLOCK_ASSERTIONS is not +// defined or asserts are being logged instead. +#if DEBUG && (!defined(NS_BLOCK_ASSERTIONS) || GTMSESSION_ASSERT_AS_LOG) +#define __GTMSessionMonitorSynchronizedVariableInner(varname, counter) varname##counter +#define __GTMSessionMonitorSynchronizedVariable(varname, counter) \ + __GTMSessionMonitorSynchronizedVariableInner(varname, counter) + +#define GTMSessionMonitorSynchronized(obj) \ + NS_VALID_UNTIL_END_OF_SCOPE id __GTMSessionMonitorSynchronizedVariable(__monitor, __COUNTER__) = \ + [[GTMSessionSyncMonitorInternal alloc] initWithSynchronizationObject:obj \ + allowRecursive:NO \ + functionName:__func__] + +#define GTMSessionMonitorRecursiveSynchronized(obj) \ + NS_VALID_UNTIL_END_OF_SCOPE id __GTMSessionMonitorSynchronizedVariable(__monitor, __COUNTER__) = \ + [[GTMSessionSyncMonitorInternal alloc] initWithSynchronizationObject:obj \ + allowRecursive:YES \ + functionName:__func__] + +#define GTMSessionCheckSynchronized(obj) \ + { \ + GTMSESSION_ASSERT_DEBUG( \ + [GTMSessionSyncMonitorInternal functionsHoldingSynchronizationOnObject:obj], \ + @"GTMSessionCheckSynchronized(" #obj ") failed: not sync'd" \ + @" on " #obj " in %s. Call stack:\n%@", \ + __func__, [NSThread callStackSymbols]); \ + } + +#define GTMSessionCheckNotSynchronized(obj) \ + { \ + GTMSESSION_ASSERT_DEBUG( \ + ![GTMSessionSyncMonitorInternal functionsHoldingSynchronizationOnObject:obj], \ + @"GTMSessionCheckNotSynchronized(" #obj ") failed: was sync'd" \ + @" on " #obj " in %s by %@. Call stack:\n%@", \ + __func__, [GTMSessionSyncMonitorInternal functionsHoldingSynchronizationOnObject:obj], \ + [NSThread callStackSymbols]); \ + } + +// GTMSessionSyncMonitorInternal is a private class that keeps track of the +// beginning and end of synchronized scopes. +// +// This class should not be used directly, but only via the +// GTMSessionMonitorSynchronized macro. +@interface GTMSessionSyncMonitorInternal : NSObject +- (instancetype)initWithSynchronizationObject:(id)object + allowRecursive:(BOOL)allowRecursive + functionName:(const char *)functionName; +// Return the names of the functions that hold sync on the object, or nil if none. ++ (nullable NSArray *)functionsHoldingSynchronizationOnObject:(id)object; +@end + +#else +#define GTMSessionMonitorSynchronized(obj) \ + do { \ + } while (0) +#define GTMSessionMonitorRecursiveSynchronized(obj) \ + do { \ + } while (0) +#define GTMSessionCheckSynchronized(obj) \ + do { \ + } while (0) +#define GTMSessionCheckNotSynchronized(obj) \ + do { \ + } while (0) +#endif // !DEBUG +#endif // __OBJC__ + +NS_ASSUME_NONNULL_END diff --git a/Pods/GTMSessionFetcher/Sources/Core/Public/GTMSessionFetcher/GTMSessionFetcherLogging.h b/Pods/GTMSessionFetcher/Sources/Core/Public/GTMSessionFetcher/GTMSessionFetcherLogging.h new file mode 100644 index 0000000..46fdd5b --- /dev/null +++ b/Pods/GTMSessionFetcher/Sources/Core/Public/GTMSessionFetcher/GTMSessionFetcherLogging.h @@ -0,0 +1,109 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * 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 "GTMSessionFetcher/GTMSessionFetcher.h" + +// GTM HTTP Logging +// +// All traffic using GTMSessionFetcher can be easily logged. Call +// +// [GTMSessionFetcher setLoggingEnabled:YES]; +// +// to begin generating log files. +// +// Unless explicitly set by the application using +setLoggingDirectory:, +// logs are put into a default directory, located at: +// * macOS: ~/Desktop/GTMHTTPDebugLogs +// * iOS simulator: ~/GTMHTTPDebugLogs (in application sandbox) +// * iOS device: ~/Documents/GTMHTTPDebugLogs (in application sandbox) +// +// Tip: use the Finder's "Sort By Date" to find the most recent logs. +// +// Each run of an application gets a separate set of log files. An html +// file is generated to simplify browsing the run's http transactions. +// The html file includes javascript links for inline viewing of uploaded +// and downloaded data. +// +// A symlink is created in the logs folder to simplify finding the html file +// for the latest run of the application; the symlink is called +// +// AppName_http_log_newest.html +// +// Each fetcher may be given a comment to be inserted as a label in the logs, +// such as +// [fetcher setCommentWithFormat:@"retrieve item %@", itemName]; +// +// Projects may define STRIP_GTM_FETCH_LOGGING to remove logging code. + +#if !STRIP_GTM_FETCH_LOGGING + +@interface GTMSessionFetcher (GTMSessionFetcherLogging) + +// Note: on macOS the default logs directory is ~/Desktop/GTMHTTPDebugLogs; on +// iOS simulators it will be the ~/GTMHTTPDebugLogs (in the app sandbox); on +// iOS devices it will be in ~/Documents/GTMHTTPDebugLogs (in the app sandbox). +// These directories will be created as needed, and are excluded from backups +// to iCloud and iTunes. +// +// If a custom directory is set, the directory should already exist. It is +// the application's responsibility to exclude any custom directory from +// backups, if desired. ++ (void)setLoggingDirectory:(NSString *)path; ++ (NSString *)loggingDirectory; + +// client apps can turn logging on and off ++ (void)setLoggingEnabled:(BOOL)isLoggingEnabled; ++ (BOOL)isLoggingEnabled; + +// client apps can turn off logging to a file if they want to only check +// the fetcher's log property ++ (void)setLoggingToFileEnabled:(BOOL)isLoggingToFileEnabled; ++ (BOOL)isLoggingToFileEnabled; + +// client apps can optionally specify process name and date string used in +// log file names ++ (void)setLoggingProcessName:(NSString *)processName; ++ (NSString *)loggingProcessName; + ++ (void)setLoggingDateStamp:(NSString *)dateStamp; ++ (NSString *)loggingDateStamp; + +// client apps can specify the directory for the log for this specific run: +// +// [GTMSessionFetcher setLogDirectoryForCurrentRun:logDirectoryPath]; +// +// Setting this overrides the logging directory, process name, and date stamp when writing +// the log file. ++ (void)setLogDirectoryForCurrentRun:(NSString *)logDirectoryForCurrentRun; ++ (NSString *)logDirectoryForCurrentRun; + +// Prunes old log directories that have not been modified since the provided date. +// This will not delete the current run's log directory. ++ (void)deleteLogDirectoriesOlderThanDate:(NSDate *)date; + +// internal; called by fetcher +- (void)logFetchWithError:(NSError *)error; +- (NSInputStream *)loggedInputStreamForInputStream:(NSInputStream *)inputStream; +- (GTMSessionFetcherBodyStreamProvider)loggedStreamProviderForStreamProvider: + (GTMSessionFetcherBodyStreamProvider)streamProvider; + +// internal; accessors useful for viewing logs ++ (NSString *)processNameLogPrefix; ++ (NSString *)symlinkNameSuffix; ++ (NSString *)htmlFileName; + +@end + +#endif // !STRIP_GTM_FETCH_LOGGING diff --git a/Pods/GTMSessionFetcher/Sources/Core/Public/GTMSessionFetcher/GTMSessionFetcherService.h b/Pods/GTMSessionFetcher/Sources/Core/Public/GTMSessionFetcher/GTMSessionFetcherService.h new file mode 100644 index 0000000..e1e457b --- /dev/null +++ b/Pods/GTMSessionFetcher/Sources/Core/Public/GTMSessionFetcher/GTMSessionFetcherService.h @@ -0,0 +1,225 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * 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. + */ + +// For best performance and convenient usage, fetchers should be generated by a common +// GTMSessionFetcherService instance, like +// +// _fetcherService = [[GTMSessionFetcherService alloc] init]; +// GTMSessionFetcher* myFirstFetcher = [_fetcherService fetcherWithRequest:request1]; +// GTMSessionFetcher* mySecondFetcher = [_fetcherService fetcherWithRequest:request2]; + +#import "GTMSessionFetcher/GTMSessionFetcher.h" + +NS_ASSUME_NONNULL_BEGIN + +// Notifications. + +// This notification indicates a reusable session has become invalid. It is intended mainly for the +// service's unit tests. +// +// The notification object is the fetcher service. +// The invalid session is provided via the userInfo kGTMSessionFetcherServiceSessionKey key. +extern NSString *const kGTMSessionFetcherServiceSessionBecameInvalidNotification; +extern NSString *const kGTMSessionFetcherServiceSessionKey; + +@interface GTMSessionFetcherService : NSObject + +// Queues of delayed and running fetchers. Each dictionary contains arrays +// of GTMSessionFetcher *fetchers, keyed by NSString *host +@property(atomic, strong, readonly, nullable) + NSDictionary *delayedFetchersByHost; +@property(atomic, strong, readonly, nullable) + NSDictionary *runningFetchersByHost; + +// A max value of 0 means no fetchers should be delayed. +// The default limit is 10 simultaneous fetchers targeting each host. +// This does not apply to fetchers whose useBackgroundSession property is YES. Since services are +// not resurrected on an app relaunch, delayed fetchers would effectively be abandoned. +@property(atomic, assign) NSUInteger maxRunningFetchersPerHost; + +// Properties to be applied to each fetcher; see GTMSessionFetcher.h for descriptions +@property(atomic, strong, nullable) NSURLSessionConfiguration *configuration; +@property(atomic, copy, nullable) GTMSessionFetcherConfigurationBlock configurationBlock; +@property(atomic, strong, nullable) NSHTTPCookieStorage *cookieStorage; +@property(atomic, strong, null_resettable) dispatch_queue_t callbackQueue; +@property(atomic, copy, nullable) GTMSessionFetcherChallengeBlock challengeBlock; +@property(atomic, strong, nullable) NSURLCredential *credential; +@property(atomic, strong) NSURLCredential *proxyCredential; +@property(atomic, copy, nullable) NSArray *allowedInsecureSchemes; +@property(atomic, assign) BOOL allowLocalhostRequest; +@property(atomic, assign) BOOL allowInvalidServerCertificates; +@property(atomic, assign, getter=isRetryEnabled) BOOL retryEnabled; +@property(atomic, copy, nullable) GTMSessionFetcherRetryBlock retryBlock; +@property(atomic, assign) NSTimeInterval maxRetryInterval; +@property(atomic, assign) NSTimeInterval minRetryInterval; +@property(atomic, copy, nullable) NSDictionary *properties; +@property(atomic, copy, nullable) + GTMSessionFetcherMetricsCollectionBlock metricsCollectionBlock API_AVAILABLE( + ios(10.0), macosx(10.12), tvos(10.0), watchos(6.0)); + +#if GTM_BACKGROUND_TASK_FETCHING +@property(atomic, assign) BOOL skipBackgroundTask; +#endif + +// A default useragent of GTMFetcherStandardUserAgentString(nil) will be given to each fetcher +// created by this service unless the request already has a user-agent header set. +// This default will be added starting with builds with the SDKs for OS X 10.11 and iOS 9. +// +// To use the configuration's default user agent, set this property to nil. +@property(atomic, copy, nullable) NSString *userAgent; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated" +// The authorizer to attach to the created fetchers. If a specific fetcher should +// not authorize its requests, the fetcher's authorizer property may be set to nil +// before the fetch begins. +@property(atomic, strong, nullable) id authorizer; +#pragma clang diagnostic pop + +@property(atomic, readonly, strong, nullable) NSOperationQueue *delegateQueue; + +// Delegate queue used by the session when calling back to the fetcher. The default +// is the main queue. Changing this does not affect the queue used to call back to the +// application; that is specified by the callbackQueue property above. +@property(atomic, strong, null_resettable) NSOperationQueue *sessionDelegateQueue; + +// When enabled, indicates the same session should be used by subsequent fetchers. +// +// This is enabled by default. +@property(atomic, assign) BOOL reuseSession; + +// Sets the delay until an unused session is invalidated. +// The default interval is 60 seconds. +// +// If the interval is set to 0, then any reused session is not invalidated except by +// explicitly invoking -resetSession. Be aware that setting the interval to 0 thus +// causes the session's delegate to be retained until the session is explicitly reset. +@property(atomic, assign) NSTimeInterval unusedSessionTimeout; + +// If shouldReuseSession is enabled, this will force creation of a new session when future +// fetchers begin. +- (void)resetSession; + +// Sets the callback queue, specifying that the provided queue is a concurrent queue. +// +// When a concurrent queue is explicitly provided via this setter, then each new fetcher +// instance created by the service will be provided a new serial queue targeting the +// concurrent callback queue; this will ensure callbacks for each instance are executed +// in order, while callbacks from separate fetcher instances are not blocked by each other. +// +// The service behavior when resetting the callback queue after providing a concurrent +// queue is unspecified. +- (void)setConcurrentCallbackQueue:(dispatch_queue_t)queue; + +// Create a fetcher +// +// These methods will return a fetcher. If successfully created, the connection +// will hold a strong reference to it for the life of the connection as well. +// So the caller doesn't have to hold onto the fetcher explicitly unless they +// want to be able to monitor or cancel it. +- (GTMSessionFetcher *)fetcherWithRequest:(NSURLRequest *)request; +- (GTMSessionFetcher *)fetcherWithURL:(NSURL *)requestURL; +- (GTMSessionFetcher *)fetcherWithURLString:(NSString *)requestURLString; + +// Common method for fetcher creation. +// +// -fetcherWithRequest:fetcherClass: may be overridden to customize creation of +// fetchers. This is the ONLY method in the GTMSessionFetcher library intended to +// be overridden. +- (id)fetcherWithRequest:(NSURLRequest *)request fetcherClass:(Class)fetcherClass; + +- (BOOL)isDelayingFetcher:(GTMSessionFetcher *)fetcher; + +- (NSUInteger)numberOfFetchers; // running + delayed fetchers +- (NSUInteger)numberOfRunningFetchers; +- (NSUInteger)numberOfDelayedFetchers; + +// Return a list of all running or delayed fetchers. This includes fetchers created +// by the service which have been started and have not yet stopped. +// +// Returns an array of fetcher objects, or nil if none. +- (nullable NSArray *)issuedFetchers; + +// Search for running or delayed fetchers with the specified URL. +// +// Returns an array of fetcher objects found, or nil if none found. +- (nullable NSArray *)issuedFetchersWithRequestURL:(NSURL *)requestURL; + +- (void)stopAllFetchers; + +// All decorators added to the service. +@property(atomic, readonly, strong, nullable) NSArray> *decorators; + +// Holds a weak reference to `decorator`. When creating a fetcher via +// `-fetcherWithRequest:fetcherClass:`, each registered `decorator` can inspect and potentially +// change the fetcher's request before it starts. Decorators are invoked in the order in which +// they are passed to this method. +- (void)addDecorator:(id)decorator; + +// Removes a `decorator` previously passed to `-removeDecorator:`. +- (void)removeDecorator:(id)decorator; + +// The testBlock can inspect its fetcher parameter's request property to +// determine which fetcher is being faked. +@property(atomic, copy, nullable) GTMSessionFetcherTestBlock testBlock; + +@end + +@interface GTMSessionFetcherService (FetcherCallbacks) +// Checks whether the fetcher should delay starting to avoid overloading the host. +- (BOOL)fetcherShouldBeginFetching:(nonnull GTMSessionFetcher *)fetcher; + +// Notifies the service that the fetcher did begin fetching. +- (void)fetcherDidBeginFetching:(nonnull GTMSessionFetcher *)fetcher; + +// Notifies the service that the fetcher has stopped fetching. +- (void)fetcherDidStop:(nonnull GTMSessionFetcher *)fetcher; +@end + +@interface GTMSessionFetcherService (TestingSupport) + +// Convenience methods to create a fetcher service for testing. +// +// Fetchers generated by this mock fetcher service will not perform any +// network operation, but will invoke callbacks and provide the supplied data +// or error to the completion handler. +// +// You can make more customized mocks by setting the test block property of the service +// or fetcher; the test block can inspect the fetcher's request or other properties. +// +// See the description of the testBlock property below. ++ (instancetype)mockFetcherServiceWithFakedData:(nullable NSData *)fakedDataOrNil + fakedError:(nullable NSError *)fakedErrorOrNil; ++ (instancetype)mockFetcherServiceWithFakedData:(nullable NSData *)fakedDataOrNil + fakedResponse:(NSHTTPURLResponse *)fakedResponse + fakedError:(nullable NSError *)fakedErrorOrNil; + +// DEPRECATED: Callers should use XCTestExpectation instead. +// +// Spin the run loop and discard events (or, if not on the main thread, just sleep the thread) +// until all running and delayed fetchers have completed. +// +// This is only for use in testing or in tools without a user interface. +// +// Synchronous fetches should never be done by shipping apps; they are +// sufficient reason for rejection from the app store. +// +// Returns NO if timed out. +- (BOOL)waitForCompletionOfAllFetchersWithTimeout:(NSTimeInterval)timeoutInSeconds + __deprecated_msg("Use XCTestExpectation instead"); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GTMSessionFetcher/Sources/Core/Public/GTMSessionFetcher/GTMSessionUploadFetcher.h b/Pods/GTMSessionFetcher/Sources/Core/Public/GTMSessionFetcher/GTMSessionUploadFetcher.h new file mode 100644 index 0000000..3537ccc --- /dev/null +++ b/Pods/GTMSessionFetcher/Sources/Core/Public/GTMSessionFetcher/GTMSessionUploadFetcher.h @@ -0,0 +1,179 @@ +/* Copyright 2014 Google Inc. All rights reserved. + * + * 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. + */ + +// GTMSessionUploadFetcher implements Google's resumable upload protocol. + +// +// This subclass of GTMSessionFetcher simulates the series of fetches +// needed for chunked upload as a single fetch operation. +// +// Protocol document: TBD +// +// To the client, the only fetcher that exists is this class; the subsidiary +// fetchers needed for uploading chunks are not visible (though the most recent +// chunk fetcher may be accessed via the -activeFetcher or -chunkFetcher methods, and +// -responseHeaders and -statusCode reflect results from the most recent chunk +// fetcher.) +// +// Chunk fetchers are discarded as soon as they have completed. +// +// The protocol also allows for a cancellation notification request to be sent to the +// server to allow discarding of the currently uploaded data and this will be sent +// automatically upon calling stopFetching if the upload has already started. +// +// Note: Unlike the fetcher superclass, the methods of GTMSessionUploadFetcher should +// only be used from the main thread until further work is done to make this subclass +// thread-safe. + +#import "GTMSessionFetcher/GTMSessionFetcher.h" +#import "GTMSessionFetcher/GTMSessionFetcherService.h" + +NS_ASSUME_NONNULL_BEGIN + +// The value to use for file size parameters when the file size is not yet known. +extern int64_t const kGTMSessionUploadFetcherUnknownFileSize; + +// Unless an application knows it needs a smaller chunk size, it should use the standard +// chunk size, which sends the entire file as a single chunk to minimize upload overhead. +// Setting an explicit chunk size that comfortably fits in memory is advisable for large +// uploads. +extern int64_t const kGTMSessionUploadFetcherStandardChunkSize; + +// When uploading requires data buffer allocations (such as uploading from an NSData or +// an NSFileHandle) this is the maximum buffer size that will be created by the fetcher. +extern int64_t const kGTMSessionUploadFetcherMaximumDemandBufferSize; + +// Notification that the upload location URL was provided by the server. +extern NSString *const kGTMSessionFetcherUploadLocationObtainedNotification; +// Notification that the exponential backoff for upload has started. +extern NSString *const kGTMSessionFetcherUploadInitialBackoffStartedNotification; + +// Block to provide data during uploads. +// +// Response data may be allocated with dataWithBytesNoCopy:length:freeWhenDone: for efficiency, +// and released after the response block returns. +// +// If the length of the file being uploaded is unknown or already set, send +// kGTMSessionUploadFetcherUnknownFileSize for |fullUploadLength|. Otherwise, set |fullUploadLength| +// to its proper value. +// +// Pass nil as the data (and optionally an NSError) for a failure. +typedef void (^GTMSessionUploadFetcherDataProviderResponse)(NSData *_Nullable data, + int64_t fullUploadLength, + NSError *_Nullable error); +// Do not call the response with an NSData object with less data than the requested length unless +// you are passing the fullUploadLength to the fetcher for the first time and it is the last chunk +// of data in the file being uploaded. +typedef void (^GTMSessionUploadFetcherDataProvider)( + int64_t offset, int64_t length, GTMSessionUploadFetcherDataProviderResponse response); + +// Block to be notified about the final status of the cancellation request started in stopFetching. +// +// |fetcher| will be the cancel request that was sent to the server, or nil if stopFetching is not +// going to send a cancel request. If |fetcher| is provided, the other parameters correspond to the +// completion handler of the cancellation request fetcher. +typedef void (^GTMSessionUploadFetcherCancellationHandler)(GTMSessionFetcher *_Nullable fetcher, + NSData *_Nullable data, + NSError *_Nullable error); + +@interface GTMSessionUploadFetcher : GTMSessionFetcher + +// Create an upload fetcher specifying either the request or the resume location URL, +// then set an upload data source using one of these: +// +// setUploadFileURL: +// setUploadDataLength:provider: +// setUploadFileHandle: +// setUploadData: + ++ (instancetype)uploadFetcherWithRequest:(NSURLRequest *)request + uploadMIMEType:(NSString *)uploadMIMEType + chunkSize:(int64_t)chunkSize + fetcherService:(nullable GTMSessionFetcherService *)fetcherServiceOrNil; + +// Allows cellular access. ++ (instancetype)uploadFetcherWithLocation:(nullable NSURL *)uploadLocationURL + uploadMIMEType:(NSString *)uploadMIMEType + chunkSize:(int64_t)chunkSize + fetcherService:(nullable GTMSessionFetcherService *)fetcherServiceOrNil; + ++ (instancetype)uploadFetcherWithLocation:(nullable NSURL *)uploadLocationURL + uploadMIMEType:(NSString *)uploadMIMEType + chunkSize:(int64_t)chunkSize + allowsCellularAccess:(BOOL)allowsCellularAccess + fetcherService:(nullable GTMSessionFetcherService *)fetcherServiceOrNil; + +// Allows dataProviders for files of unknown length. Pass kGTMSessionUploadFetcherUnknownFileSize as +// |fullLength| if the length is unknown. +- (void)setUploadDataLength:(int64_t)fullLength + provider:(nullable GTMSessionUploadFetcherDataProvider)block; + ++ (NSArray *)uploadFetchersForBackgroundSessions; ++ (nullable instancetype)uploadFetcherForSessionIdentifier:(NSString *)sessionIdentifier; + +- (void)pauseFetching; +- (void)resumeFetching; +- (BOOL)isPaused; + +@property(atomic, strong, nullable) NSURL *uploadLocationURL; +@property(atomic, strong, nullable) NSData *uploadData; +@property(atomic, strong, nullable) NSURL *uploadFileURL; +@property(atomic, strong, nullable) NSFileHandle *uploadFileHandle; +@property(atomic, copy, readonly, nullable) GTMSessionUploadFetcherDataProvider uploadDataProvider; +@property(atomic, copy) NSString *uploadMIMEType; +@property(atomic, readonly, assign) int64_t chunkSize; +@property(atomic, readonly, assign) int64_t currentOffset; +@property(atomic, assign) double uploadRetryFactor; +@property(atomic, assign) NSTimeInterval maxUploadRetryInterval; +@property(atomic, assign) NSTimeInterval minUploadRetryInterval; + +// Reflects the original NSURLRequest's @c allowCellularAccess property. +@property(atomic, readonly, assign) BOOL allowsCellularAccess; + +// The fetcher for the current data chunk, if any +@property(atomic, strong, nullable) GTMSessionFetcher *chunkFetcher; + +// The active fetcher is the current chunk fetcher, or the upload fetcher itself +// if no chunk fetcher has yet been created. +@property(atomic, readonly) GTMSessionFetcher *activeFetcher; + +// The last request made by an active fetcher. Useful for testing. +@property(atomic, readonly, nullable) NSURLRequest *lastChunkRequest; + +// The status code from the most recently-completed fetch. +@property(atomic, assign) NSInteger statusCode; + +// Invoked as part of the stop fetching process. Invoked immediately if there is no upload in +// progress, otherwise invoked with the results of the attempt to notify the server that the +// upload will not continue. +// +// Unlike other callbacks, since this is related specifically to the stopFetching flow it is not +// cleared by stopFetching. It will instead clear itself after it is invoked or if the completion +// has occured before stopFetching is called. +@property(atomic, copy, nullable) GTMSessionUploadFetcherCancellationHandler cancellationHandler; + +// Exposed for testing only. +@property(atomic, readonly, nullable) dispatch_queue_t delegateCallbackQueue; +@property(atomic, readonly, nullable) GTMSessionFetcherCompletionHandler delegateCompletionHandler; + +@end + +@interface GTMSessionFetcher (GTMSessionUploadFetcherMethods) + +@property(readonly, nullable) GTMSessionUploadFetcher *parentUploadFetcher; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/Info.plist b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/Info.plist new file mode 100644 index 0000000..ed48227 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/Info.plist @@ -0,0 +1,95 @@ + + + + + AvailableLibraries + + + LibraryIdentifier + ios-arm64 + LibraryPath + GoogleAppMeasurement.framework + SupportedArchitectures + + arm64 + + SupportedPlatform + ios + + + LibraryIdentifier + ios-arm64_x86_64-maccatalyst + LibraryPath + GoogleAppMeasurement.framework + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + ios + SupportedPlatformVariant + maccatalyst + + + LibraryIdentifier + tvos-arm64_x86_64-simulator + LibraryPath + GoogleAppMeasurement.framework + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + tvos + SupportedPlatformVariant + simulator + + + LibraryIdentifier + tvos-arm64 + LibraryPath + GoogleAppMeasurement.framework + SupportedArchitectures + + arm64 + + SupportedPlatform + tvos + + + LibraryIdentifier + ios-arm64_x86_64-simulator + LibraryPath + GoogleAppMeasurement.framework + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + ios + SupportedPlatformVariant + simulator + + + LibraryIdentifier + macos-arm64_x86_64 + LibraryPath + GoogleAppMeasurement.framework + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + macos + + + CFBundlePackageType + XFWK + XCFrameworkFormatVersion + 1.0 + + diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64/GoogleAppMeasurement.framework/GoogleAppMeasurement b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64/GoogleAppMeasurement.framework/GoogleAppMeasurement new file mode 100644 index 0000000..4800ade Binary files /dev/null and b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64/GoogleAppMeasurement.framework/GoogleAppMeasurement differ diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64/GoogleAppMeasurement.framework/Info.plist b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64/GoogleAppMeasurement.framework/Info.plist new file mode 100644 index 0000000..08c310b --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64/GoogleAppMeasurement.framework/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleExecutable + GoogleAppMeasurement + CFBundleIdentifier + com.firebase.Firebase-GoogleAppMeasurement + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + GoogleAppMeasurement + CFBundlePackageType + FMWK + CFBundleVersion + 10.11.0 + DTSDKName + iphonesimulator11.2 + + diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64/GoogleAppMeasurement.framework/Modules/module.modulemap b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64/GoogleAppMeasurement.framework/Modules/module.modulemap new file mode 100644 index 0000000..d3499f0 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64/GoogleAppMeasurement.framework/Modules/module.modulemap @@ -0,0 +1,10 @@ +framework module GoogleAppMeasurement { +umbrella header "GoogleAppMeasurement-umbrella.h" +export * +module * { export * } + link framework "Security" + link framework "SystemConfiguration" + link "c++" + link "sqlite3" + link "z" +} diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/GoogleAppMeasurement b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/GoogleAppMeasurement new file mode 100644 index 0000000..6ead4b3 Binary files /dev/null and b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/GoogleAppMeasurement differ diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/Info.plist b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/Info.plist new file mode 100644 index 0000000..08c310b --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleExecutable + GoogleAppMeasurement + CFBundleIdentifier + com.firebase.Firebase-GoogleAppMeasurement + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + GoogleAppMeasurement + CFBundlePackageType + FMWK + CFBundleVersion + 10.11.0 + DTSDKName + iphonesimulator11.2 + + diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/Modules/module.modulemap b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/Modules/module.modulemap new file mode 100644 index 0000000..d3499f0 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/Modules/module.modulemap @@ -0,0 +1,10 @@ +framework module GoogleAppMeasurement { +umbrella header "GoogleAppMeasurement-umbrella.h" +export * +module * { export * } + link framework "Security" + link framework "SystemConfiguration" + link "c++" + link "sqlite3" + link "z" +} diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-simulator/GoogleAppMeasurement.framework/GoogleAppMeasurement b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-simulator/GoogleAppMeasurement.framework/GoogleAppMeasurement new file mode 100644 index 0000000..8e740d0 Binary files /dev/null and b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-simulator/GoogleAppMeasurement.framework/GoogleAppMeasurement differ diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-simulator/GoogleAppMeasurement.framework/Info.plist b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-simulator/GoogleAppMeasurement.framework/Info.plist new file mode 100644 index 0000000..08c310b --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-simulator/GoogleAppMeasurement.framework/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleExecutable + GoogleAppMeasurement + CFBundleIdentifier + com.firebase.Firebase-GoogleAppMeasurement + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + GoogleAppMeasurement + CFBundlePackageType + FMWK + CFBundleVersion + 10.11.0 + DTSDKName + iphonesimulator11.2 + + diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-simulator/GoogleAppMeasurement.framework/Modules/module.modulemap b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-simulator/GoogleAppMeasurement.framework/Modules/module.modulemap new file mode 100644 index 0000000..d3499f0 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-simulator/GoogleAppMeasurement.framework/Modules/module.modulemap @@ -0,0 +1,10 @@ +framework module GoogleAppMeasurement { +umbrella header "GoogleAppMeasurement-umbrella.h" +export * +module * { export * } + link framework "Security" + link framework "SystemConfiguration" + link "c++" + link "sqlite3" + link "z" +} diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/macos-arm64_x86_64/GoogleAppMeasurement.framework/GoogleAppMeasurement b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/macos-arm64_x86_64/GoogleAppMeasurement.framework/GoogleAppMeasurement new file mode 100644 index 0000000..3e4559f Binary files /dev/null and b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/macos-arm64_x86_64/GoogleAppMeasurement.framework/GoogleAppMeasurement differ diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/macos-arm64_x86_64/GoogleAppMeasurement.framework/Info.plist b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/macos-arm64_x86_64/GoogleAppMeasurement.framework/Info.plist new file mode 100644 index 0000000..08c310b --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/macos-arm64_x86_64/GoogleAppMeasurement.framework/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleExecutable + GoogleAppMeasurement + CFBundleIdentifier + com.firebase.Firebase-GoogleAppMeasurement + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + GoogleAppMeasurement + CFBundlePackageType + FMWK + CFBundleVersion + 10.11.0 + DTSDKName + iphonesimulator11.2 + + diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/macos-arm64_x86_64/GoogleAppMeasurement.framework/Modules/module.modulemap b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/macos-arm64_x86_64/GoogleAppMeasurement.framework/Modules/module.modulemap new file mode 100644 index 0000000..d3499f0 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/macos-arm64_x86_64/GoogleAppMeasurement.framework/Modules/module.modulemap @@ -0,0 +1,10 @@ +framework module GoogleAppMeasurement { +umbrella header "GoogleAppMeasurement-umbrella.h" +export * +module * { export * } + link framework "Security" + link framework "SystemConfiguration" + link "c++" + link "sqlite3" + link "z" +} diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/tvos-arm64/GoogleAppMeasurement.framework/GoogleAppMeasurement b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/tvos-arm64/GoogleAppMeasurement.framework/GoogleAppMeasurement new file mode 100644 index 0000000..e262639 Binary files /dev/null and b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/tvos-arm64/GoogleAppMeasurement.framework/GoogleAppMeasurement differ diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/tvos-arm64/GoogleAppMeasurement.framework/Info.plist b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/tvos-arm64/GoogleAppMeasurement.framework/Info.plist new file mode 100644 index 0000000..08c310b --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/tvos-arm64/GoogleAppMeasurement.framework/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleExecutable + GoogleAppMeasurement + CFBundleIdentifier + com.firebase.Firebase-GoogleAppMeasurement + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + GoogleAppMeasurement + CFBundlePackageType + FMWK + CFBundleVersion + 10.11.0 + DTSDKName + iphonesimulator11.2 + + diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/tvos-arm64/GoogleAppMeasurement.framework/Modules/module.modulemap b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/tvos-arm64/GoogleAppMeasurement.framework/Modules/module.modulemap new file mode 100644 index 0000000..d3499f0 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/tvos-arm64/GoogleAppMeasurement.framework/Modules/module.modulemap @@ -0,0 +1,10 @@ +framework module GoogleAppMeasurement { +umbrella header "GoogleAppMeasurement-umbrella.h" +export * +module * { export * } + link framework "Security" + link framework "SystemConfiguration" + link "c++" + link "sqlite3" + link "z" +} diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/tvos-arm64_x86_64-simulator/GoogleAppMeasurement.framework/GoogleAppMeasurement b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/tvos-arm64_x86_64-simulator/GoogleAppMeasurement.framework/GoogleAppMeasurement new file mode 100644 index 0000000..6bf415f Binary files /dev/null and b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/tvos-arm64_x86_64-simulator/GoogleAppMeasurement.framework/GoogleAppMeasurement differ diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/tvos-arm64_x86_64-simulator/GoogleAppMeasurement.framework/Info.plist b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/tvos-arm64_x86_64-simulator/GoogleAppMeasurement.framework/Info.plist new file mode 100644 index 0000000..08c310b --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/tvos-arm64_x86_64-simulator/GoogleAppMeasurement.framework/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleExecutable + GoogleAppMeasurement + CFBundleIdentifier + com.firebase.Firebase-GoogleAppMeasurement + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + GoogleAppMeasurement + CFBundlePackageType + FMWK + CFBundleVersion + 10.11.0 + DTSDKName + iphonesimulator11.2 + + diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/tvos-arm64_x86_64-simulator/GoogleAppMeasurement.framework/Modules/module.modulemap b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/tvos-arm64_x86_64-simulator/GoogleAppMeasurement.framework/Modules/module.modulemap new file mode 100644 index 0000000..d3499f0 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/tvos-arm64_x86_64-simulator/GoogleAppMeasurement.framework/Modules/module.modulemap @@ -0,0 +1,10 @@ +framework module GoogleAppMeasurement { +umbrella header "GoogleAppMeasurement-umbrella.h" +export * +module * { export * } + link framework "Security" + link framework "SystemConfiguration" + link "c++" + link "sqlite3" + link "z" +} diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/Info.plist b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/Info.plist new file mode 100644 index 0000000..bba7a41 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/Info.plist @@ -0,0 +1,95 @@ + + + + + AvailableLibraries + + + LibraryIdentifier + ios-arm64_x86_64-maccatalyst + LibraryPath + GoogleAppMeasurementIdentitySupport.framework + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + ios + SupportedPlatformVariant + maccatalyst + + + LibraryIdentifier + macos-arm64_x86_64 + LibraryPath + GoogleAppMeasurementIdentitySupport.framework + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + macos + + + LibraryIdentifier + ios-arm64 + LibraryPath + GoogleAppMeasurementIdentitySupport.framework + SupportedArchitectures + + arm64 + + SupportedPlatform + ios + + + LibraryIdentifier + ios-arm64_x86_64-simulator + LibraryPath + GoogleAppMeasurementIdentitySupport.framework + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + ios + SupportedPlatformVariant + simulator + + + LibraryIdentifier + tvos-arm64 + LibraryPath + GoogleAppMeasurementIdentitySupport.framework + SupportedArchitectures + + arm64 + + SupportedPlatform + tvos + + + LibraryIdentifier + tvos-arm64_x86_64-simulator + LibraryPath + GoogleAppMeasurementIdentitySupport.framework + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + tvos + SupportedPlatformVariant + simulator + + + CFBundlePackageType + XFWK + XCFrameworkFormatVersion + 1.0 + + diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport new file mode 100644 index 0000000..5bbde0a Binary files /dev/null and b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport differ diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64/GoogleAppMeasurementIdentitySupport.framework/Info.plist b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64/GoogleAppMeasurementIdentitySupport.framework/Info.plist new file mode 100644 index 0000000..bbddaa6 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64/GoogleAppMeasurementIdentitySupport.framework/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleExecutable + GoogleAppMeasurementIdentitySupport + CFBundleIdentifier + com.firebase.Firebase-GoogleAppMeasurementIdentitySupport + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + GoogleAppMeasurementIdentitySupport + CFBundlePackageType + FMWK + CFBundleVersion + 10.11.0 + DTSDKName + iphonesimulator11.2 + + diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64/GoogleAppMeasurementIdentitySupport.framework/Modules/module.modulemap b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64/GoogleAppMeasurementIdentitySupport.framework/Modules/module.modulemap new file mode 100644 index 0000000..4a42c5d --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64/GoogleAppMeasurementIdentitySupport.framework/Modules/module.modulemap @@ -0,0 +1,5 @@ +framework module GoogleAppMeasurementIdentitySupport { +umbrella header "GoogleAppMeasurementIdentitySupport-umbrella.h" +export * +module * { export * } +} diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport new file mode 100644 index 0000000..ca7a26e Binary files /dev/null and b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport differ diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/Info.plist b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/Info.plist new file mode 100644 index 0000000..bbddaa6 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleExecutable + GoogleAppMeasurementIdentitySupport + CFBundleIdentifier + com.firebase.Firebase-GoogleAppMeasurementIdentitySupport + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + GoogleAppMeasurementIdentitySupport + CFBundlePackageType + FMWK + CFBundleVersion + 10.11.0 + DTSDKName + iphonesimulator11.2 + + diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/Modules/module.modulemap b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/Modules/module.modulemap new file mode 100644 index 0000000..4a42c5d --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/Modules/module.modulemap @@ -0,0 +1,5 @@ +framework module GoogleAppMeasurementIdentitySupport { +umbrella header "GoogleAppMeasurementIdentitySupport-umbrella.h" +export * +module * { export * } +} diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport new file mode 100644 index 0000000..0c79825 Binary files /dev/null and b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport differ diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/Info.plist b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/Info.plist new file mode 100644 index 0000000..bbddaa6 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleExecutable + GoogleAppMeasurementIdentitySupport + CFBundleIdentifier + com.firebase.Firebase-GoogleAppMeasurementIdentitySupport + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + GoogleAppMeasurementIdentitySupport + CFBundlePackageType + FMWK + CFBundleVersion + 10.11.0 + DTSDKName + iphonesimulator11.2 + + diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/Modules/module.modulemap b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/Modules/module.modulemap new file mode 100644 index 0000000..4a42c5d --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/Modules/module.modulemap @@ -0,0 +1,5 @@ +framework module GoogleAppMeasurementIdentitySupport { +umbrella header "GoogleAppMeasurementIdentitySupport-umbrella.h" +export * +module * { export * } +} diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport new file mode 100644 index 0000000..c0d2f63 Binary files /dev/null and b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport differ diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/Info.plist b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/Info.plist new file mode 100644 index 0000000..bbddaa6 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleExecutable + GoogleAppMeasurementIdentitySupport + CFBundleIdentifier + com.firebase.Firebase-GoogleAppMeasurementIdentitySupport + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + GoogleAppMeasurementIdentitySupport + CFBundlePackageType + FMWK + CFBundleVersion + 10.11.0 + DTSDKName + iphonesimulator11.2 + + diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/Modules/module.modulemap b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/Modules/module.modulemap new file mode 100644 index 0000000..4a42c5d --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/Modules/module.modulemap @@ -0,0 +1,5 @@ +framework module GoogleAppMeasurementIdentitySupport { +umbrella header "GoogleAppMeasurementIdentitySupport-umbrella.h" +export * +module * { export * } +} diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport new file mode 100644 index 0000000..0713d9f Binary files /dev/null and b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport differ diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64/GoogleAppMeasurementIdentitySupport.framework/Info.plist b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64/GoogleAppMeasurementIdentitySupport.framework/Info.plist new file mode 100644 index 0000000..bbddaa6 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64/GoogleAppMeasurementIdentitySupport.framework/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleExecutable + GoogleAppMeasurementIdentitySupport + CFBundleIdentifier + com.firebase.Firebase-GoogleAppMeasurementIdentitySupport + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + GoogleAppMeasurementIdentitySupport + CFBundlePackageType + FMWK + CFBundleVersion + 10.11.0 + DTSDKName + iphonesimulator11.2 + + diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64/GoogleAppMeasurementIdentitySupport.framework/Modules/module.modulemap b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64/GoogleAppMeasurementIdentitySupport.framework/Modules/module.modulemap new file mode 100644 index 0000000..4a42c5d --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64/GoogleAppMeasurementIdentitySupport.framework/Modules/module.modulemap @@ -0,0 +1,5 @@ +framework module GoogleAppMeasurementIdentitySupport { +umbrella header "GoogleAppMeasurementIdentitySupport-umbrella.h" +export * +module * { export * } +} diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport new file mode 100644 index 0000000..e4d9b79 Binary files /dev/null and b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport differ diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/Info.plist b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/Info.plist new file mode 100644 index 0000000..bbddaa6 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleExecutable + GoogleAppMeasurementIdentitySupport + CFBundleIdentifier + com.firebase.Firebase-GoogleAppMeasurementIdentitySupport + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + GoogleAppMeasurementIdentitySupport + CFBundlePackageType + FMWK + CFBundleVersion + 10.11.0 + DTSDKName + iphonesimulator11.2 + + diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/Modules/module.modulemap b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/Modules/module.modulemap new file mode 100644 index 0000000..4a42c5d --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/Modules/module.modulemap @@ -0,0 +1,5 @@ +framework module GoogleAppMeasurementIdentitySupport { +umbrella header "GoogleAppMeasurementIdentitySupport-umbrella.h" +export * +module * { export * } +} diff --git a/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/GULAppDelegateSwizzler.m b/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/GULAppDelegateSwizzler.m new file mode 100644 index 0000000..88ea069 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/GULAppDelegateSwizzler.m @@ -0,0 +1,1070 @@ +// Copyright 2018 Google LLC +// +// 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 + +#import "GoogleUtilities/AppDelegateSwizzler/Internal/GULAppDelegateSwizzler_Private.h" +#import "GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULAppDelegateSwizzler.h" +#import "GoogleUtilities/Common/GULLoggerCodes.h" +#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULAppEnvironmentUtil.h" +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h" + +#import +#import + +// Implementations need to be typed before calling the implementation directly to cast the +// arguments and the return types correctly. Otherwise, it will crash the app. +typedef BOOL (*GULRealOpenURLSourceApplicationAnnotationIMP)( + id, SEL, GULApplication *, NSURL *, NSString *, id); + +typedef BOOL (*GULRealOpenURLOptionsIMP)( + id, SEL, GULApplication *, NSURL *, NSDictionary *); + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wstrict-prototypes" +typedef void (*GULRealHandleEventsForBackgroundURLSessionIMP)( + id, SEL, GULApplication *, NSString *, void (^)()); +#pragma clang diagnostic pop + +typedef BOOL (*GULRealContinueUserActivityIMP)( + id, SEL, GULApplication *, NSUserActivity *, void (^)(NSArray *restorableObjects)); + +typedef void (*GULRealDidRegisterForRemoteNotificationsIMP)(id, SEL, GULApplication *, NSData *); + +typedef void (*GULRealDidFailToRegisterForRemoteNotificationsIMP)(id, + SEL, + GULApplication *, + NSError *); + +typedef void (*GULRealDidReceiveRemoteNotificationIMP)(id, SEL, GULApplication *, NSDictionary *); + +#if !TARGET_OS_WATCH && !TARGET_OS_OSX +typedef void (*GULRealDidReceiveRemoteNotificationWithCompletionIMP)( + id, SEL, GULApplication *, NSDictionary *, void (^)(UIBackgroundFetchResult)); +#endif // !TARGET_OS_WATCH && !TARGET_OS_OSX + +typedef void (^GULAppDelegateInterceptorCallback)(id); + +// The strings below are the keys for associated objects. +static char const *const kGULRealIMPBySelectorKey = "GUL_realIMPBySelector"; +static char const *const kGULRealClassKey = "GUL_realClass"; + +static NSString *const kGULAppDelegateKeyPath = @"delegate"; + +static GULLoggerService kGULLoggerSwizzler = @"[GoogleUtilities/AppDelegateSwizzler]"; + +// Since Firebase SDKs also use this for app delegate proxying, in order to not be a breaking change +// we disable App Delegate proxying when either of these two flags are set to NO. + +/** Plist key that allows Firebase developers to disable App and Scene Delegate Proxying. */ +static NSString *const kGULFirebaseAppDelegateProxyEnabledPlistKey = + @"FirebaseAppDelegateProxyEnabled"; + +/** Plist key that allows developers not using Firebase to disable App and Scene Delegate Proxying. + */ +static NSString *const kGULGoogleUtilitiesAppDelegateProxyEnabledPlistKey = + @"GoogleUtilitiesAppDelegateProxyEnabled"; + +/** The prefix of the App Delegate. */ +static NSString *const kGULAppDelegatePrefix = @"GUL_"; + +/** The original instance of App Delegate. */ +static id gOriginalAppDelegate; + +/** The original App Delegate class */ +static Class gOriginalAppDelegateClass; + +/** The subclass of the original App Delegate. */ +static Class gAppDelegateSubclass; + +/** Remote notification methods selectors + * + * We have to opt out of referencing APNS related App Delegate methods directly to prevent + * an Apple review warning email about missing Push Notification Entitlement + * (like here: https://github.com/firebase/firebase-ios-sdk/issues/2807). From our experience, the + * warning is triggered when any of the symbols is present in the application sent to review, even + * if the code is never executed. Because GULAppDelegateSwizzler may be used by applications that + * are not using APNS we have to refer to the methods indirectly using selector constructed from + * string. + * + * NOTE: None of the methods is proxied unless it is explicitly requested by calling the method + * +[GULAppDelegateSwizzler proxyOriginalDelegateIncludingAPNSMethods] + */ +static NSString *const kGULDidRegisterForRemoteNotificationsSEL = + @"application:didRegisterForRemoteNotificationsWithDeviceToken:"; +static NSString *const kGULDidFailToRegisterForRemoteNotificationsSEL = + @"application:didFailToRegisterForRemoteNotificationsWithError:"; +static NSString *const kGULDidReceiveRemoteNotificationSEL = + @"application:didReceiveRemoteNotification:"; +static NSString *const kGULDidReceiveRemoteNotificationWithCompletionSEL = + @"application:didReceiveRemoteNotification:fetchCompletionHandler:"; + +/** + * This class is necessary to store the delegates in an NSArray without retaining them. + * [NSValue valueWithNonRetainedObject] also provides this functionality, but does not provide a + * zeroing pointer. This will cause EXC_BAD_ACCESS when trying to access the object after it is + * dealloced. Instead, this container stores a weak, zeroing reference to the object, which + * automatically is set to nil by the runtime when the object is dealloced. + */ +@interface GULZeroingWeakContainer : NSObject + +/** Stores a weak object. */ +@property(nonatomic, weak) id object; + +@end + +@implementation GULZeroingWeakContainer +@end + +@interface GULAppDelegateObserver : NSObject +@end + +@implementation GULAppDelegateObserver { + BOOL _isObserving; +} + ++ (GULAppDelegateObserver *)sharedInstance { + static GULAppDelegateObserver *instance; + static dispatch_once_t once; + dispatch_once(&once, ^{ + instance = [[GULAppDelegateObserver alloc] init]; + }); + return instance; +} + +- (void)observeUIApplication { + if (_isObserving) { + return; + } + [[GULAppDelegateSwizzler sharedApplication] + addObserver:self + forKeyPath:kGULAppDelegateKeyPath + options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld + context:nil]; + _isObserving = YES; +} + +- (void)observeValueForKeyPath:(NSString *)keyPath + ofObject:(id)object + change:(NSDictionary *)change + context:(void *)context { + if ([keyPath isEqual:kGULAppDelegateKeyPath]) { + id newValue = change[NSKeyValueChangeNewKey]; + id oldValue = change[NSKeyValueChangeOldKey]; + if ([newValue isEqual:oldValue]) { + return; + } + // Free the stored app delegate instance because it has been changed to a different instance to + // avoid keeping it alive forever. + if ([oldValue isEqual:gOriginalAppDelegate]) { + gOriginalAppDelegate = nil; + // Remove the observer. Parse it to NSObject to avoid warning. + [[GULAppDelegateSwizzler sharedApplication] removeObserver:self + forKeyPath:kGULAppDelegateKeyPath]; + _isObserving = NO; + } + } +} + +@end + +@implementation GULAppDelegateSwizzler + +static dispatch_once_t sProxyAppDelegateOnceToken; +static dispatch_once_t sProxyAppDelegateRemoteNotificationOnceToken; + +#pragma mark - Public methods + ++ (BOOL)isAppDelegateProxyEnabled { + NSDictionary *infoDictionary = [NSBundle mainBundle].infoDictionary; + + id isFirebaseProxyEnabledPlistValue = infoDictionary[kGULFirebaseAppDelegateProxyEnabledPlistKey]; + id isGoogleProxyEnabledPlistValue = + infoDictionary[kGULGoogleUtilitiesAppDelegateProxyEnabledPlistKey]; + + // Enabled by default. + BOOL isFirebaseAppDelegateProxyEnabled = YES; + BOOL isGoogleUtilitiesAppDelegateProxyEnabled = YES; + + if ([isFirebaseProxyEnabledPlistValue isKindOfClass:[NSNumber class]]) { + isFirebaseAppDelegateProxyEnabled = [isFirebaseProxyEnabledPlistValue boolValue]; + } + + if ([isGoogleProxyEnabledPlistValue isKindOfClass:[NSNumber class]]) { + isGoogleUtilitiesAppDelegateProxyEnabled = [isGoogleProxyEnabledPlistValue boolValue]; + } + + // Only deactivate the proxy if it is explicitly disabled by app developers using either one of + // the plist flags. + return isFirebaseAppDelegateProxyEnabled && isGoogleUtilitiesAppDelegateProxyEnabled; +} + ++ (GULAppDelegateInterceptorID)registerAppDelegateInterceptor: + (id)interceptor { + NSAssert(interceptor, @"AppDelegateProxy cannot add nil interceptor"); + NSAssert([interceptor conformsToProtocol:@protocol(GULApplicationDelegate)], + @"AppDelegateProxy interceptor does not conform to UIApplicationDelegate"); + + if (!interceptor) { + GULLogError(kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling000], + @"AppDelegateProxy cannot add nil interceptor."); + return nil; + } + if (![interceptor conformsToProtocol:@protocol(GULApplicationDelegate)]) { + GULLogError(kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling001], + @"AppDelegateProxy interceptor does not conform to UIApplicationDelegate"); + return nil; + } + + // The ID should be the same given the same interceptor object. + NSString *interceptorID = [NSString stringWithFormat:@"%@%p", kGULAppDelegatePrefix, interceptor]; + if (!interceptorID.length) { + GULLogError(kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling002], + @"AppDelegateProxy cannot create Interceptor ID."); + return nil; + } + GULZeroingWeakContainer *weakObject = [[GULZeroingWeakContainer alloc] init]; + weakObject.object = interceptor; + [GULAppDelegateSwizzler interceptors][interceptorID] = weakObject; + return interceptorID; +} + ++ (void)unregisterAppDelegateInterceptorWithID:(GULAppDelegateInterceptorID)interceptorID { + NSAssert(interceptorID, @"AppDelegateProxy cannot unregister nil interceptor ID."); + NSAssert(((NSString *)interceptorID).length != 0, + @"AppDelegateProxy cannot unregister empty interceptor ID."); + + if (!interceptorID) { + GULLogError(kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling003], + @"AppDelegateProxy cannot unregister empty interceptor ID."); + return; + } + + GULZeroingWeakContainer *weakContainer = [GULAppDelegateSwizzler interceptors][interceptorID]; + if (!weakContainer.object) { + GULLogError(kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling004], + @"AppDelegateProxy cannot unregister interceptor that was not registered. " + "Interceptor ID %@", + interceptorID); + return; + } + + [[GULAppDelegateSwizzler interceptors] removeObjectForKey:interceptorID]; +} + ++ (void)proxyOriginalDelegate { + if ([GULAppEnvironmentUtil isAppExtension]) { + return; + } + + dispatch_once(&sProxyAppDelegateOnceToken, ^{ + id originalDelegate = + [GULAppDelegateSwizzler sharedApplication].delegate; + [GULAppDelegateSwizzler proxyAppDelegate:originalDelegate]; + }); +} + ++ (void)proxyOriginalDelegateIncludingAPNSMethods { + if ([GULAppEnvironmentUtil isAppExtension]) { + return; + } + + [self proxyOriginalDelegate]; + + dispatch_once(&sProxyAppDelegateRemoteNotificationOnceToken, ^{ + id appDelegate = [GULAppDelegateSwizzler sharedApplication].delegate; + + NSMutableDictionary *realImplementationsBySelector = + [objc_getAssociatedObject(appDelegate, &kGULRealIMPBySelectorKey) mutableCopy]; + + [self proxyRemoteNotificationsMethodsWithAppDelegateSubClass:gAppDelegateSubclass + realClass:gOriginalAppDelegateClass + appDelegate:appDelegate + realImplementationsBySelector:realImplementationsBySelector]; + + objc_setAssociatedObject(appDelegate, &kGULRealIMPBySelectorKey, + [realImplementationsBySelector copy], OBJC_ASSOCIATION_RETAIN); + [self reassignAppDelegate]; + }); +} + +#pragma mark - Create proxy + ++ (GULApplication *)sharedApplication { + if ([GULAppEnvironmentUtil isAppExtension]) { + return nil; + } + id sharedApplication = nil; + Class uiApplicationClass = NSClassFromString(kGULApplicationClassName); + if (uiApplicationClass && + [uiApplicationClass respondsToSelector:(NSSelectorFromString(@"sharedApplication"))]) { + sharedApplication = [uiApplicationClass sharedApplication]; + } + return sharedApplication; +} + +#pragma mark - Override default methods + +/** Creates a new subclass of the class of the given object and sets the isa value of the given + * object to the new subclass. Additionally this copies methods to that new subclass that allow us + * to intercept UIApplicationDelegate methods. This is better known as isa swizzling. + * + * @param appDelegate The object to which you want to isa swizzle. This has to conform to the + * UIApplicationDelegate subclass. + * @return Returns the new subclass. + */ ++ (nullable Class)createSubclassWithObject:(id)appDelegate { + Class realClass = [appDelegate class]; + + // Create GUL__ + NSString *classNameWithPrefix = + [kGULAppDelegatePrefix stringByAppendingString:NSStringFromClass(realClass)]; + NSString *newClassName = + [NSString stringWithFormat:@"%@-%@", classNameWithPrefix, [NSUUID UUID].UUIDString]; + + if (NSClassFromString(newClassName)) { + GULLogError(kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling005], + @"Cannot create a proxy for App Delegate. Subclass already exists. Original Class: " + @"%@, subclass: %@", + NSStringFromClass(realClass), newClassName); + return nil; + } + + // Register the new class as subclass of the real one. Do not allocate more than the real class + // size. + Class appDelegateSubClass = objc_allocateClassPair(realClass, newClassName.UTF8String, 0); + if (appDelegateSubClass == Nil) { + GULLogError(kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling006], + @"Cannot create a proxy for App Delegate. Subclass already exists. Original Class: " + @"%@, subclass: Nil", + NSStringFromClass(realClass)); + return nil; + } + + NSMutableDictionary *realImplementationsBySelector = + [[NSMutableDictionary alloc] init]; + + // For application:continueUserActivity:restorationHandler: + SEL continueUserActivitySEL = @selector(application:continueUserActivity:restorationHandler:); + [self proxyDestinationSelector:continueUserActivitySEL + implementationsFromSourceSelector:continueUserActivitySEL + fromClass:[GULAppDelegateSwizzler class] + toClass:appDelegateSubClass + realClass:realClass + storeDestinationImplementationTo:realImplementationsBySelector]; + +#if TARGET_OS_IOS || TARGET_OS_TV + // Add the following methods from GULAppDelegate class, and store the real implementation so it + // can forward to the real one. + // For application:openURL:options: + SEL applicationOpenURLOptionsSEL = @selector(application:openURL:options:); + if ([appDelegate respondsToSelector:applicationOpenURLOptionsSEL]) { + // Only add the application:openURL:options: method if the original AppDelegate implements it. + // This fixes a bug if an app only implements application:openURL:sourceApplication:annotation: + // (if we add the `options` method, iOS sees that one exists and does not call the + // `sourceApplication` method, which in this case is the only one the app implements). + + [self proxyDestinationSelector:applicationOpenURLOptionsSEL + implementationsFromSourceSelector:applicationOpenURLOptionsSEL + fromClass:[GULAppDelegateSwizzler class] + toClass:appDelegateSubClass + realClass:realClass + storeDestinationImplementationTo:realImplementationsBySelector]; + } + + // For application:handleEventsForBackgroundURLSession:completionHandler: + SEL handleEventsForBackgroundURLSessionSEL = @selector(application: + handleEventsForBackgroundURLSession:completionHandler:); + [self proxyDestinationSelector:handleEventsForBackgroundURLSessionSEL + implementationsFromSourceSelector:handleEventsForBackgroundURLSessionSEL + fromClass:[GULAppDelegateSwizzler class] + toClass:appDelegateSubClass + realClass:realClass + storeDestinationImplementationTo:realImplementationsBySelector]; +#endif // TARGET_OS_IOS || TARGET_OS_TV + +#if TARGET_OS_IOS + // For application:openURL:sourceApplication:annotation: + SEL openURLSourceApplicationAnnotationSEL = @selector(application: + openURL:sourceApplication:annotation:); + + [self proxyDestinationSelector:openURLSourceApplicationAnnotationSEL + implementationsFromSourceSelector:openURLSourceApplicationAnnotationSEL + fromClass:[GULAppDelegateSwizzler class] + toClass:appDelegateSubClass + realClass:realClass + storeDestinationImplementationTo:realImplementationsBySelector]; +#endif // TARGET_OS_IOS + + // Override the description too so the custom class name will not show up. + [GULAppDelegateSwizzler addInstanceMethodWithDestinationSelector:@selector(description) + withImplementationFromSourceSelector:@selector(fakeDescription) + fromClass:[self class] + toClass:appDelegateSubClass]; + + // Store original implementations to a fake property of the original delegate. + objc_setAssociatedObject(appDelegate, &kGULRealIMPBySelectorKey, + [realImplementationsBySelector copy], OBJC_ASSOCIATION_RETAIN_NONATOMIC); + objc_setAssociatedObject(appDelegate, &kGULRealClassKey, realClass, + OBJC_ASSOCIATION_RETAIN_NONATOMIC); + + // The subclass size has to be exactly the same size with the original class size. The subclass + // cannot have more ivars/properties than its superclass since it will cause an offset in memory + // that can lead to overwriting the isa of an object in the next frame. + if (class_getInstanceSize(realClass) != class_getInstanceSize(appDelegateSubClass)) { + GULLogError(kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling007], + @"Cannot create subclass of App Delegate, because the created subclass is not the " + @"same size. %@", + NSStringFromClass(realClass)); + NSAssert(NO, @"Classes must be the same size to swizzle isa"); + return nil; + } + + // Make the newly created class to be the subclass of the real App Delegate class. + objc_registerClassPair(appDelegateSubClass); + if (object_setClass(appDelegate, appDelegateSubClass)) { + GULLogDebug(kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling008], + @"Successfully created App Delegate Proxy automatically. To disable the " + @"proxy, set the flag %@ to NO (Boolean) in the Info.plist", + [GULAppDelegateSwizzler correctAppDelegateProxyKey]); + } + + return appDelegateSubClass; +} + ++ (void)proxyRemoteNotificationsMethodsWithAppDelegateSubClass:(Class)appDelegateSubClass + realClass:(Class)realClass + appDelegate:(id)appDelegate + realImplementationsBySelector: + (NSMutableDictionary *)realImplementationsBySelector { + if (realClass == nil || appDelegateSubClass == nil || appDelegate == nil || + realImplementationsBySelector == nil) { + // The App Delegate has not been swizzled. + return; + } + + // For application:didRegisterForRemoteNotificationsWithDeviceToken: + SEL didRegisterForRemoteNotificationsSEL = + NSSelectorFromString(kGULDidRegisterForRemoteNotificationsSEL); + SEL didRegisterForRemoteNotificationsDonorSEL = @selector(application: + donor_didRegisterForRemoteNotificationsWithDeviceToken:); + + [self proxyDestinationSelector:didRegisterForRemoteNotificationsSEL + implementationsFromSourceSelector:didRegisterForRemoteNotificationsDonorSEL + fromClass:[GULAppDelegateSwizzler class] + toClass:appDelegateSubClass + realClass:realClass + storeDestinationImplementationTo:realImplementationsBySelector]; + + // For application:didFailToRegisterForRemoteNotificationsWithError: + SEL didFailToRegisterForRemoteNotificationsSEL = + NSSelectorFromString(kGULDidFailToRegisterForRemoteNotificationsSEL); + SEL didFailToRegisterForRemoteNotificationsDonorSEL = @selector(application: + donor_didFailToRegisterForRemoteNotificationsWithError:); + + [self proxyDestinationSelector:didFailToRegisterForRemoteNotificationsSEL + implementationsFromSourceSelector:didFailToRegisterForRemoteNotificationsDonorSEL + fromClass:[GULAppDelegateSwizzler class] + toClass:appDelegateSubClass + realClass:realClass + storeDestinationImplementationTo:realImplementationsBySelector]; + + // For application:didReceiveRemoteNotification: + SEL didReceiveRemoteNotificationSEL = NSSelectorFromString(kGULDidReceiveRemoteNotificationSEL); + SEL didReceiveRemoteNotificationDonotSEL = @selector(application: + donor_didReceiveRemoteNotification:); + + [self proxyDestinationSelector:didReceiveRemoteNotificationSEL + implementationsFromSourceSelector:didReceiveRemoteNotificationDonotSEL + fromClass:[GULAppDelegateSwizzler class] + toClass:appDelegateSubClass + realClass:realClass + storeDestinationImplementationTo:realImplementationsBySelector]; + + // For application:didReceiveRemoteNotification:fetchCompletionHandler: +#if !TARGET_OS_WATCH && !TARGET_OS_OSX + SEL didReceiveRemoteNotificationWithCompletionSEL = + NSSelectorFromString(kGULDidReceiveRemoteNotificationWithCompletionSEL); + SEL didReceiveRemoteNotificationWithCompletionDonorSEL = + @selector(application:donor_didReceiveRemoteNotification:fetchCompletionHandler:); + if ([appDelegate respondsToSelector:didReceiveRemoteNotificationWithCompletionSEL]) { + // Only add the application:didReceiveRemoteNotification:fetchCompletionHandler: method if + // the original AppDelegate implements it. + // This fixes a bug if an app only implements application:didReceiveRemoteNotification: + // (if we add the method with completion, iOS sees that one exists and does not call + // the method without the completion, which in this case is the only one the app implements). + + [self proxyDestinationSelector:didReceiveRemoteNotificationWithCompletionSEL + implementationsFromSourceSelector:didReceiveRemoteNotificationWithCompletionDonorSEL + fromClass:[GULAppDelegateSwizzler class] + toClass:appDelegateSubClass + realClass:realClass + storeDestinationImplementationTo:realImplementationsBySelector]; + } +#endif // !TARGET_OS_WATCH && !TARGET_OS_OSX +} + +/// We have to do this to invalidate the cache that caches the original respondsToSelector of +/// openURL handlers. Without this, it won't call the default implementations because the system +/// checks and caches them. +/// Register KVO only once. Otherwise, the observing method will be called as many times as +/// being registered. ++ (void)reassignAppDelegate { +#if !TARGET_OS_WATCH + id delegate = [self sharedApplication].delegate; + [self sharedApplication].delegate = nil; + [self sharedApplication].delegate = delegate; + gOriginalAppDelegate = delegate; + [[GULAppDelegateObserver sharedInstance] observeUIApplication]; +#endif +} + +#pragma mark - Helper methods + ++ (GULMutableDictionary *)interceptors { + static dispatch_once_t onceToken; + static GULMutableDictionary *sInterceptors; + dispatch_once(&onceToken, ^{ + sInterceptors = [[GULMutableDictionary alloc] init]; + }); + return sInterceptors; +} + ++ (nullable NSValue *)originalImplementationForSelector:(SEL)selector object:(id)object { + NSDictionary *realImplementationBySelector = + objc_getAssociatedObject(object, &kGULRealIMPBySelectorKey); + return realImplementationBySelector[NSStringFromSelector(selector)]; +} + ++ (void)proxyDestinationSelector:(SEL)destinationSelector + implementationsFromSourceSelector:(SEL)sourceSelector + fromClass:(Class)sourceClass + toClass:(Class)destinationClass + realClass:(Class)realClass + storeDestinationImplementationTo: + (NSMutableDictionary *)destinationImplementationsBySelector { + [self addInstanceMethodWithDestinationSelector:destinationSelector + withImplementationFromSourceSelector:sourceSelector + fromClass:sourceClass + toClass:destinationClass]; + IMP sourceImplementation = + [GULAppDelegateSwizzler implementationOfMethodSelector:destinationSelector + fromClass:realClass]; + NSValue *sourceImplementationPointer = [NSValue valueWithPointer:sourceImplementation]; + + NSString *destinationSelectorString = NSStringFromSelector(destinationSelector); + destinationImplementationsBySelector[destinationSelectorString] = sourceImplementationPointer; +} + +/** Copies a method identified by the methodSelector from one class to the other. After this method + * is called, performing [toClassInstance methodSelector] will be similar to calling + * [fromClassInstance methodSelector]. This method does nothing if toClass already has a method + * identified by methodSelector. + * + * @param methodSelector The SEL that identifies both the method on the fromClass as well as the + * one on the toClass. + * @param fromClass The class from which a method is sourced. + * @param toClass The class to which the method is added. If the class already has a method with + * the same selector, this has no effect. + */ ++ (void)addInstanceMethodWithSelector:(SEL)methodSelector + fromClass:(Class)fromClass + toClass:(Class)toClass { + [self addInstanceMethodWithDestinationSelector:methodSelector + withImplementationFromSourceSelector:methodSelector + fromClass:fromClass + toClass:toClass]; +} + +/** Copies a method identified by the sourceSelector from the fromClass as a method for the + * destinationSelector on the toClass. After this method is called, performing + * [toClassInstance destinationSelector] will be similar to calling + * [fromClassInstance sourceSelector]. This method does nothing if toClass already has a method + * identified by destinationSelector. + * + * @param destinationSelector The SEL that identifies the method on the toClass. + * @param sourceSelector The SEL that identifies the method on the fromClass. + * @param fromClass The class from which a method is sourced. + * @param toClass The class to which the method is added. If the class already has a method with + * the same selector, this has no effect. + */ ++ (void)addInstanceMethodWithDestinationSelector:(SEL)destinationSelector + withImplementationFromSourceSelector:(SEL)sourceSelector + fromClass:(Class)fromClass + toClass:(Class)toClass { + Method method = class_getInstanceMethod(fromClass, sourceSelector); + IMP methodIMP = method_getImplementation(method); + const char *types = method_getTypeEncoding(method); + if (!class_addMethod(toClass, destinationSelector, methodIMP, types)) { + GULLogWarning(kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling009], + @"Cannot copy method to destination selector %@ as it already exists", + NSStringFromSelector(destinationSelector)); + } +} + +/** Gets the IMP of the instance method on the class identified by the selector. + * + * @param selector The selector of which the IMP is to be fetched. + * @param aClass The class from which the IMP is to be fetched. + * @return The IMP of the instance method identified by selector and aClass. + */ ++ (IMP)implementationOfMethodSelector:(SEL)selector fromClass:(Class)aClass { + Method aMethod = class_getInstanceMethod(aClass, selector); + return method_getImplementation(aMethod); +} + +/** Enumerates through all the interceptors and if they respond to a given selector, executes a + * GULAppDelegateInterceptorCallback with the interceptor. + * + * @param methodSelector The SEL to check if an interceptor responds to. + * @param callback the GULAppDelegateInterceptorCallback. + */ ++ (void)notifyInterceptorsWithMethodSelector:(SEL)methodSelector + callback:(GULAppDelegateInterceptorCallback)callback { + if (!callback) { + return; + } + + NSDictionary *interceptors = [GULAppDelegateSwizzler interceptors].dictionary; + [interceptors enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + GULZeroingWeakContainer *interceptorContainer = obj; + id interceptor = interceptorContainer.object; + if (!interceptor) { + GULLogWarning( + kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", (long)kGULSwizzlerMessageCodeAppDelegateSwizzling010], + @"AppDelegateProxy cannot find interceptor with ID %@. Removing the interceptor.", key); + [[GULAppDelegateSwizzler interceptors] removeObjectForKey:key]; + return; + } + if ([interceptor respondsToSelector:methodSelector]) { + callback(interceptor); + } + }]; +} + +// The methods below are donor methods which are added to the dynamic subclass of the App Delegate. +// They are called within the scope of the real App Delegate so |self| does not refer to the +// GULAppDelegateSwizzler instance but the real App Delegate instance. + +#pragma mark - [Donor Methods] Overridden instance description method + +- (NSString *)fakeDescription { + Class realClass = objc_getAssociatedObject(self, &kGULRealClassKey); + return [NSString stringWithFormat:@"<%@: %p>", realClass, self]; +} + +#pragma mark - [Donor Methods] URL overridden handler methods +#if TARGET_OS_IOS || TARGET_OS_TV + +- (BOOL)application:(GULApplication *)application + openURL:(NSURL *)url + options:(NSDictionary *)options { + SEL methodSelector = @selector(application:openURL:options:); + // Call the real implementation if the real App Delegate has any. + NSValue *openURLIMPPointer = + [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self]; + GULRealOpenURLOptionsIMP openURLOptionsIMP = [openURLIMPPointer pointerValue]; + + __block BOOL returnedValue = NO; + +// This is needed to for the library to be warning free on iOS versions < 9. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunguarded-availability" + [GULAppDelegateSwizzler + notifyInterceptorsWithMethodSelector:methodSelector + callback:^(id interceptor) { + returnedValue |= [interceptor application:application + openURL:url + options:options]; + }]; +#pragma clang diagnostic pop + if (openURLOptionsIMP) { + returnedValue |= openURLOptionsIMP(self, methodSelector, application, url, options); + } + return returnedValue; +} + +#endif // TARGET_OS_IOS || TARGET_OS_TV + +#if TARGET_OS_IOS + +- (BOOL)application:(GULApplication *)application + openURL:(NSURL *)url + sourceApplication:(NSString *)sourceApplication + annotation:(id)annotation { + SEL methodSelector = @selector(application:openURL:sourceApplication:annotation:); + + // Call the real implementation if the real App Delegate has any. + NSValue *openURLSourceAppAnnotationIMPPointer = + [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self]; + GULRealOpenURLSourceApplicationAnnotationIMP openURLSourceApplicationAnnotationIMP = + [openURLSourceAppAnnotationIMPPointer pointerValue]; + + __block BOOL returnedValue = NO; + [GULAppDelegateSwizzler + notifyInterceptorsWithMethodSelector:methodSelector + callback:^(id interceptor) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + returnedValue |= [interceptor application:application + openURL:url + sourceApplication:sourceApplication + annotation:annotation]; +#pragma clang diagnostic pop + }]; + if (openURLSourceApplicationAnnotationIMP) { + returnedValue |= openURLSourceApplicationAnnotationIMP(self, methodSelector, application, url, + sourceApplication, annotation); + } + return returnedValue; +} + +#endif // TARGET_OS_IOS + +#pragma mark - [Donor Methods] Network overridden handler methods + +#if TARGET_OS_IOS || TARGET_OS_TV + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wstrict-prototypes" +- (void)application:(GULApplication *)application + handleEventsForBackgroundURLSession:(NSString *)identifier + completionHandler:(void (^)())completionHandler API_AVAILABLE(ios(7.0)) { +#pragma clang diagnostic pop + SEL methodSelector = @selector(application: + handleEventsForBackgroundURLSession:completionHandler:); + NSValue *handleBackgroundSessionPointer = + [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self]; + GULRealHandleEventsForBackgroundURLSessionIMP handleBackgroundSessionIMP = + [handleBackgroundSessionPointer pointerValue]; + + // Notify interceptors. + [GULAppDelegateSwizzler + notifyInterceptorsWithMethodSelector:methodSelector + callback:^(id interceptor) { + [interceptor application:application + handleEventsForBackgroundURLSession:identifier + completionHandler:completionHandler]; + }]; + // Call the real implementation if the real App Delegate has any. + if (handleBackgroundSessionIMP) { + handleBackgroundSessionIMP(self, methodSelector, application, identifier, completionHandler); + } +} + +#endif // TARGET_OS_IOS || TARGET_OS_TV + +#pragma mark - [Donor Methods] User Activities overridden handler methods + +- (BOOL)application:(GULApplication *)application + continueUserActivity:(NSUserActivity *)userActivity + restorationHandler:(void (^)(NSArray *restorableObjects))restorationHandler { + SEL methodSelector = @selector(application:continueUserActivity:restorationHandler:); + NSValue *continueUserActivityIMPPointer = + [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self]; + GULRealContinueUserActivityIMP continueUserActivityIMP = + continueUserActivityIMPPointer.pointerValue; + + __block BOOL returnedValue = NO; +#if !TARGET_OS_WATCH + [GULAppDelegateSwizzler + notifyInterceptorsWithMethodSelector:methodSelector + callback:^(id interceptor) { + returnedValue |= [interceptor application:application + continueUserActivity:userActivity + restorationHandler:restorationHandler]; + }]; +#endif + // Call the real implementation if the real App Delegate has any. + if (continueUserActivityIMP) { + returnedValue |= continueUserActivityIMP(self, methodSelector, application, userActivity, + restorationHandler); + } + return returnedValue; +} + +#pragma mark - [Donor Methods] Remote Notifications + +- (void)application:(GULApplication *)application + donor_didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { + SEL methodSelector = NSSelectorFromString(kGULDidRegisterForRemoteNotificationsSEL); + + NSValue *didRegisterForRemoteNotificationsIMPPointer = + [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self]; + GULRealDidRegisterForRemoteNotificationsIMP didRegisterForRemoteNotificationsIMP = + [didRegisterForRemoteNotificationsIMPPointer pointerValue]; + + // Notify interceptors. + [GULAppDelegateSwizzler + notifyInterceptorsWithMethodSelector:methodSelector + callback:^(id interceptor) { + NSInvocation *invocation = [GULAppDelegateSwizzler + appDelegateInvocationForSelector:methodSelector]; + [invocation setTarget:interceptor]; + [invocation setSelector:methodSelector]; + [invocation setArgument:(void *)(&application) atIndex:2]; + [invocation setArgument:(void *)(&deviceToken) atIndex:3]; + [invocation invoke]; + }]; + // Call the real implementation if the real App Delegate has any. + if (didRegisterForRemoteNotificationsIMP) { + didRegisterForRemoteNotificationsIMP(self, methodSelector, application, deviceToken); + } +} + +- (void)application:(GULApplication *)application + donor_didFailToRegisterForRemoteNotificationsWithError:(NSError *)error { + SEL methodSelector = NSSelectorFromString(kGULDidFailToRegisterForRemoteNotificationsSEL); + NSValue *didFailToRegisterForRemoteNotificationsIMPPointer = + [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self]; + GULRealDidFailToRegisterForRemoteNotificationsIMP didFailToRegisterForRemoteNotificationsIMP = + [didFailToRegisterForRemoteNotificationsIMPPointer pointerValue]; + + // Notify interceptors. + [GULAppDelegateSwizzler + notifyInterceptorsWithMethodSelector:methodSelector + callback:^(id interceptor) { + NSInvocation *invocation = [GULAppDelegateSwizzler + appDelegateInvocationForSelector:methodSelector]; + [invocation setTarget:interceptor]; + [invocation setSelector:methodSelector]; + [invocation setArgument:(void *)(&application) atIndex:2]; + [invocation setArgument:(void *)(&error) atIndex:3]; + [invocation invoke]; + }]; + // Call the real implementation if the real App Delegate has any. + if (didFailToRegisterForRemoteNotificationsIMP) { + didFailToRegisterForRemoteNotificationsIMP(self, methodSelector, application, error); + } +} + +#if !TARGET_OS_WATCH && !TARGET_OS_OSX +- (void)application:(GULApplication *)application + donor_didReceiveRemoteNotification:(NSDictionary *)userInfo + fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { + SEL methodSelector = NSSelectorFromString(kGULDidReceiveRemoteNotificationWithCompletionSEL); + NSValue *didReceiveRemoteNotificationWithCompletionIMPPointer = + [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self]; + GULRealDidReceiveRemoteNotificationWithCompletionIMP + didReceiveRemoteNotificationWithCompletionIMP = + [didReceiveRemoteNotificationWithCompletionIMPPointer pointerValue]; + + dispatch_group_t __block callbackGroup = dispatch_group_create(); + NSMutableArray *__block fetchResults = [NSMutableArray array]; + + void (^localCompletionHandler)(UIBackgroundFetchResult) = + ^void(UIBackgroundFetchResult fetchResult) { + [fetchResults addObject:[NSNumber numberWithInt:(int)fetchResult]]; + dispatch_group_leave(callbackGroup); + }; + + // Notify interceptors. + [GULAppDelegateSwizzler + notifyInterceptorsWithMethodSelector:methodSelector + callback:^(id interceptor) { + dispatch_group_enter(callbackGroup); + + NSInvocation *invocation = [GULAppDelegateSwizzler + appDelegateInvocationForSelector:methodSelector]; + [invocation setTarget:interceptor]; + [invocation setSelector:methodSelector]; + [invocation setArgument:(void *)(&application) atIndex:2]; + [invocation setArgument:(void *)(&userInfo) atIndex:3]; + [invocation setArgument:(void *)(&localCompletionHandler) + atIndex:4]; + [invocation invoke]; + }]; + // Call the real implementation if the real App Delegate has any. + if (didReceiveRemoteNotificationWithCompletionIMP) { + dispatch_group_enter(callbackGroup); + + didReceiveRemoteNotificationWithCompletionIMP(self, methodSelector, application, userInfo, + localCompletionHandler); + } + + dispatch_group_notify(callbackGroup, dispatch_get_main_queue(), ^() { + BOOL allFetchesFailed = YES; + BOOL anyFetchHasNewData = NO; + + for (NSNumber *oneResult in fetchResults) { + UIBackgroundFetchResult result = oneResult.intValue; + + switch (result) { + case UIBackgroundFetchResultNoData: + allFetchesFailed = NO; + break; + case UIBackgroundFetchResultNewData: + allFetchesFailed = NO; + anyFetchHasNewData = YES; + break; + case UIBackgroundFetchResultFailed: + + break; + } + } + + UIBackgroundFetchResult finalFetchResult = UIBackgroundFetchResultNoData; + + if (allFetchesFailed) { + finalFetchResult = UIBackgroundFetchResultFailed; + } else if (anyFetchHasNewData) { + finalFetchResult = UIBackgroundFetchResultNewData; + } else { + finalFetchResult = UIBackgroundFetchResultNoData; + } + + completionHandler(finalFetchResult); + }); +} +#endif // !TARGET_OS_WATCH && !TARGET_OS_OSX + +- (void)application:(GULApplication *)application + donor_didReceiveRemoteNotification:(NSDictionary *)userInfo { + SEL methodSelector = NSSelectorFromString(kGULDidReceiveRemoteNotificationSEL); + NSValue *didReceiveRemoteNotificationIMPPointer = + [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self]; + GULRealDidReceiveRemoteNotificationIMP didReceiveRemoteNotificationIMP = + [didReceiveRemoteNotificationIMPPointer pointerValue]; + + // Notify interceptors. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + [GULAppDelegateSwizzler + notifyInterceptorsWithMethodSelector:methodSelector + callback:^(id interceptor) { + NSInvocation *invocation = [GULAppDelegateSwizzler + appDelegateInvocationForSelector:methodSelector]; + [invocation setTarget:interceptor]; + [invocation setSelector:methodSelector]; + [invocation setArgument:(void *)(&application) atIndex:2]; + [invocation setArgument:(void *)(&userInfo) atIndex:3]; + [invocation invoke]; + }]; +#pragma clang diagnostic pop + // Call the real implementation if the real App Delegate has any. + if (didReceiveRemoteNotificationIMP) { + didReceiveRemoteNotificationIMP(self, methodSelector, application, userInfo); + } +} + ++ (nullable NSInvocation *)appDelegateInvocationForSelector:(SEL)selector { + struct objc_method_description methodDescription = + protocol_getMethodDescription(@protocol(GULApplicationDelegate), selector, NO, YES); + if (methodDescription.types == NULL) { + return nil; + } + + NSMethodSignature *signature = [NSMethodSignature signatureWithObjCTypes:methodDescription.types]; + return [NSInvocation invocationWithMethodSignature:signature]; +} + ++ (void)proxyAppDelegate:(id)appDelegate { + if (![appDelegate conformsToProtocol:@protocol(GULApplicationDelegate)]) { + GULLogNotice( + kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzlingInvalidAppDelegate], + @"App Delegate does not conform to UIApplicationDelegate protocol. %@", + [GULAppDelegateSwizzler correctAlternativeWhenAppDelegateProxyNotCreated]); + return; + } + + id originalDelegate = appDelegate; + // Do not create a subclass if it is not enabled. + if (![GULAppDelegateSwizzler isAppDelegateProxyEnabled]) { + GULLogNotice(kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling011], + @"App Delegate Proxy is disabled. %@", + [GULAppDelegateSwizzler correctAlternativeWhenAppDelegateProxyNotCreated]); + return; + } + // Do not accept nil delegate. + if (!originalDelegate) { + GULLogError(kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling012], + @"Cannot create App Delegate Proxy because App Delegate instance is nil. %@", + [GULAppDelegateSwizzler correctAlternativeWhenAppDelegateProxyNotCreated]); + return; + } + + @try { + gOriginalAppDelegateClass = [originalDelegate class]; + gAppDelegateSubclass = [self createSubclassWithObject:originalDelegate]; + [self reassignAppDelegate]; + } @catch (NSException *exception) { + GULLogError(kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling013], + @"Cannot create App Delegate Proxy. %@", + [GULAppDelegateSwizzler correctAlternativeWhenAppDelegateProxyNotCreated]); + return; + } +} + +#pragma mark - Methods to print correct debug logs + ++ (NSString *)correctAppDelegateProxyKey { + return NSClassFromString(@"FIRCore") ? kGULFirebaseAppDelegateProxyEnabledPlistKey + : kGULGoogleUtilitiesAppDelegateProxyEnabledPlistKey; +} + ++ (NSString *)correctAlternativeWhenAppDelegateProxyNotCreated { + return NSClassFromString(@"FIRCore") + ? @"To log deep link campaigns manually, call the methods in " + @"FIRAnalytics+AppDelegate.h." + : @""; +} + +#pragma mark - Private Methods for Testing + ++ (void)clearInterceptors { + [[self interceptors] removeAllObjects]; +} + ++ (void)resetProxyOriginalDelegateOnceToken { + sProxyAppDelegateOnceToken = 0; + sProxyAppDelegateRemoteNotificationOnceToken = 0; +} + ++ (id)originalDelegate { + return gOriginalAppDelegate; +} + +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/GULSceneDelegateSwizzler.m b/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/GULSceneDelegateSwizzler.m new file mode 100644 index 0000000..36ba1ca --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/GULSceneDelegateSwizzler.m @@ -0,0 +1,439 @@ +// Copyright 2019 Google LLC +// +// 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 + +#import "GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULSceneDelegateSwizzler.h" + +#import "GoogleUtilities/AppDelegateSwizzler/Internal/GULSceneDelegateSwizzler_Private.h" +#import "GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULAppDelegateSwizzler.h" +#import "GoogleUtilities/Common/GULLoggerCodes.h" +#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULAppEnvironmentUtil.h" +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h" + +#import + +#if UISCENE_SUPPORTED +API_AVAILABLE(ios(13.0), tvos(13.0)) +typedef void (*GULOpenURLContextsIMP)(id, SEL, UIScene *, NSSet *); + +API_AVAILABLE(ios(13.0), tvos(13.0)) +typedef void (^GULSceneDelegateInterceptorCallback)(id); + +// The strings below are the keys for associated objects. +static char const *const kGULRealIMPBySelectorKey = "GUL_realIMPBySelector"; +static char const *const kGULRealClassKey = "GUL_realClass"; +#endif // UISCENE_SUPPORTED + +static GULLoggerService kGULLoggerSwizzler = @"[GoogleUtilities/SceneDelegateSwizzler]"; + +// Since Firebase SDKs also use this for app delegate proxying, in order to not be a breaking change +// we disable App Delegate proxying when either of these two flags are set to NO. + +/** Plist key that allows Firebase developers to disable App and Scene Delegate Proxying. */ +static NSString *const kGULFirebaseSceneDelegateProxyEnabledPlistKey = + @"FirebaseAppDelegateProxyEnabled"; + +/** Plist key that allows developers not using Firebase to disable App and Scene Delegate Proxying. + */ +static NSString *const kGULGoogleUtilitiesSceneDelegateProxyEnabledPlistKey = + @"GoogleUtilitiesAppDelegateProxyEnabled"; + +/** The prefix of the Scene Delegate. */ +static NSString *const kGULSceneDelegatePrefix = @"GUL_"; + +/** + * This class is necessary to store the delegates in an NSArray without retaining them. + * [NSValue valueWithNonRetainedObject] also provides this functionality, but does not provide a + * zeroing pointer. This will cause EXC_BAD_ACCESS when trying to access the object after it is + * dealloced. Instead, this container stores a weak, zeroing reference to the object, which + * automatically is set to nil by the runtime when the object is dealloced. + */ +@interface GULSceneZeroingWeakContainer : NSObject + +/** Stores a weak object. */ +@property(nonatomic, weak) id object; + +@end + +@implementation GULSceneZeroingWeakContainer +@end + +@implementation GULSceneDelegateSwizzler + +#pragma mark - Public methods + ++ (BOOL)isSceneDelegateProxyEnabled { + return [GULAppDelegateSwizzler isAppDelegateProxyEnabled]; +} + ++ (void)proxyOriginalSceneDelegate { +#if UISCENE_SUPPORTED + if ([GULAppEnvironmentUtil isAppExtension]) { + return; + } + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + if (@available(iOS 13.0, tvOS 13.0, *)) { + if (![GULSceneDelegateSwizzler isSceneDelegateProxyEnabled]) { + return; + } + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(handleSceneWillConnectToNotification:) + name:UISceneWillConnectNotification + object:nil]; + } + }); +#endif // UISCENE_SUPPORTED +} + +#if UISCENE_SUPPORTED ++ (GULSceneDelegateInterceptorID)registerSceneDelegateInterceptor:(id)interceptor { + NSAssert(interceptor, @"SceneDelegateProxy cannot add nil interceptor"); + NSAssert([interceptor conformsToProtocol:@protocol(UISceneDelegate)], + @"SceneDelegateProxy interceptor does not conform to UIApplicationDelegate"); + + if (!interceptor) { + GULLogError(kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeSceneDelegateSwizzling000], + @"SceneDelegateProxy cannot add nil interceptor."); + return nil; + } + if (![interceptor conformsToProtocol:@protocol(UISceneDelegate)]) { + GULLogError(kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeSceneDelegateSwizzling001], + @"SceneDelegateProxy interceptor does not conform to UIApplicationDelegate"); + return nil; + } + + // The ID should be the same given the same interceptor object. + NSString *interceptorID = + [NSString stringWithFormat:@"%@%p", kGULSceneDelegatePrefix, interceptor]; + if (!interceptorID.length) { + GULLogError(kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeSceneDelegateSwizzling002], + @"SceneDelegateProxy cannot create Interceptor ID."); + return nil; + } + GULSceneZeroingWeakContainer *weakObject = [[GULSceneZeroingWeakContainer alloc] init]; + weakObject.object = interceptor; + [GULSceneDelegateSwizzler interceptors][interceptorID] = weakObject; + return interceptorID; +} + ++ (void)unregisterSceneDelegateInterceptorWithID:(GULSceneDelegateInterceptorID)interceptorID { + NSAssert(interceptorID, @"SceneDelegateProxy cannot unregister nil interceptor ID."); + NSAssert(((NSString *)interceptorID).length != 0, + @"SceneDelegateProxy cannot unregister empty interceptor ID."); + + if (!interceptorID) { + GULLogError(kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeSceneDelegateSwizzling003], + @"SceneDelegateProxy cannot unregister empty interceptor ID."); + return; + } + + GULSceneZeroingWeakContainer *weakContainer = + [GULSceneDelegateSwizzler interceptors][interceptorID]; + if (!weakContainer.object) { + GULLogError(kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeSceneDelegateSwizzling004], + @"SceneDelegateProxy cannot unregister interceptor that was not registered. " + "Interceptor ID %@", + interceptorID); + return; + } + + [[GULSceneDelegateSwizzler interceptors] removeObjectForKey:interceptorID]; +} + +#pragma mark - Helper methods + ++ (GULMutableDictionary *)interceptors { + static dispatch_once_t onceToken; + static GULMutableDictionary *sInterceptors; + dispatch_once(&onceToken, ^{ + sInterceptors = [[GULMutableDictionary alloc] init]; + }); + return sInterceptors; +} + ++ (void)clearInterceptors { + [[self interceptors] removeAllObjects]; +} + ++ (nullable NSValue *)originalImplementationForSelector:(SEL)selector object:(id)object { + NSDictionary *realImplementationBySelector = + objc_getAssociatedObject(object, &kGULRealIMPBySelectorKey); + return realImplementationBySelector[NSStringFromSelector(selector)]; +} + ++ (void)proxyDestinationSelector:(SEL)destinationSelector + implementationsFromSourceSelector:(SEL)sourceSelector + fromClass:(Class)sourceClass + toClass:(Class)destinationClass + realClass:(Class)realClass + storeDestinationImplementationTo: + (NSMutableDictionary *)destinationImplementationsBySelector { + [self addInstanceMethodWithDestinationSelector:destinationSelector + withImplementationFromSourceSelector:sourceSelector + fromClass:sourceClass + toClass:destinationClass]; + IMP sourceImplementation = + [GULSceneDelegateSwizzler implementationOfMethodSelector:destinationSelector + fromClass:realClass]; + NSValue *sourceImplementationPointer = [NSValue valueWithPointer:sourceImplementation]; + + NSString *destinationSelectorString = NSStringFromSelector(destinationSelector); + destinationImplementationsBySelector[destinationSelectorString] = sourceImplementationPointer; +} + +/** Copies a method identified by the methodSelector from one class to the other. After this method + * is called, performing [toClassInstance methodSelector] will be similar to calling + * [fromClassInstance methodSelector]. This method does nothing if toClass already has a method + * identified by methodSelector. + * + * @param methodSelector The SEL that identifies both the method on the fromClass as well as the + * one on the toClass. + * @param fromClass The class from which a method is sourced. + * @param toClass The class to which the method is added. If the class already has a method with + * the same selector, this has no effect. + */ ++ (void)addInstanceMethodWithSelector:(SEL)methodSelector + fromClass:(Class)fromClass + toClass:(Class)toClass { + [self addInstanceMethodWithDestinationSelector:methodSelector + withImplementationFromSourceSelector:methodSelector + fromClass:fromClass + toClass:toClass]; +} + +/** Copies a method identified by the sourceSelector from the fromClass as a method for the + * destinationSelector on the toClass. After this method is called, performing + * [toClassInstance destinationSelector] will be similar to calling + * [fromClassInstance sourceSelector]. This method does nothing if toClass already has a method + * identified by destinationSelector. + * + * @param destinationSelector The SEL that identifies the method on the toClass. + * @param sourceSelector The SEL that identifies the method on the fromClass. + * @param fromClass The class from which a method is sourced. + * @param toClass The class to which the method is added. If the class already has a method with + * the same selector, this has no effect. + */ ++ (void)addInstanceMethodWithDestinationSelector:(SEL)destinationSelector + withImplementationFromSourceSelector:(SEL)sourceSelector + fromClass:(Class)fromClass + toClass:(Class)toClass { + Method method = class_getInstanceMethod(fromClass, sourceSelector); + IMP methodIMP = method_getImplementation(method); + const char *types = method_getTypeEncoding(method); + if (!class_addMethod(toClass, destinationSelector, methodIMP, types)) { + GULLogWarning( + kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", (long)kGULSwizzlerMessageCodeSceneDelegateSwizzling009], + @"Cannot copy method to destination selector %@ as it already exists", + NSStringFromSelector(destinationSelector)); + } +} + +/** Gets the IMP of the instance method on the class identified by the selector. + * + * @param selector The selector of which the IMP is to be fetched. + * @param aClass The class from which the IMP is to be fetched. + * @return The IMP of the instance method identified by selector and aClass. + */ ++ (IMP)implementationOfMethodSelector:(SEL)selector fromClass:(Class)aClass { + Method aMethod = class_getInstanceMethod(aClass, selector); + return method_getImplementation(aMethod); +} + +/** Enumerates through all the interceptors and if they respond to a given selector, executes a + * GULSceneDelegateInterceptorCallback with the interceptor. + * + * @param methodSelector The SEL to check if an interceptor responds to. + * @param callback the GULSceneDelegateInterceptorCallback. + */ ++ (void)notifyInterceptorsWithMethodSelector:(SEL)methodSelector + callback:(GULSceneDelegateInterceptorCallback)callback + API_AVAILABLE(ios(13.0)) { + if (!callback) { + return; + } + + NSDictionary *interceptors = [GULSceneDelegateSwizzler interceptors].dictionary; + [interceptors enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + GULSceneZeroingWeakContainer *interceptorContainer = obj; + id interceptor = interceptorContainer.object; + if (!interceptor) { + GULLogWarning( + kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeSceneDelegateSwizzling010], + @"SceneDelegateProxy cannot find interceptor with ID %@. Removing the interceptor.", key); + [[GULSceneDelegateSwizzler interceptors] removeObjectForKey:key]; + return; + } + if ([interceptor respondsToSelector:methodSelector]) { + callback(interceptor); + } + }]; +} + ++ (void)handleSceneWillConnectToNotification:(NSNotification *)notification { + if (@available(iOS 13.0, tvOS 13.0, *)) { + if ([notification.object isKindOfClass:[UIScene class]]) { + UIScene *scene = (UIScene *)notification.object; + [GULSceneDelegateSwizzler proxySceneDelegateIfNeeded:scene]; + } + } +} + +#pragma mark - [Donor Methods] UISceneDelegate URL handler + +- (void)scene:(UIScene *)scene + openURLContexts:(NSSet *)URLContexts API_AVAILABLE(ios(13.0), tvos(13.0)) { + if (@available(iOS 13.0, tvOS 13.0, *)) { + SEL methodSelector = @selector(scene:openURLContexts:); + // Call the real implementation if the real Scene Delegate has any. + NSValue *openURLContextsIMPPointer = + [GULSceneDelegateSwizzler originalImplementationForSelector:methodSelector object:self]; + GULOpenURLContextsIMP openURLContextsIMP = [openURLContextsIMPPointer pointerValue]; + + [GULSceneDelegateSwizzler + notifyInterceptorsWithMethodSelector:methodSelector + callback:^(id interceptor) { + if ([interceptor + conformsToProtocol:@protocol(UISceneDelegate)]) { + id sceneInterceptor = + (id)interceptor; + [sceneInterceptor scene:scene openURLContexts:URLContexts]; + } + }]; + + if (openURLContextsIMP) { + openURLContextsIMP(self, methodSelector, scene, URLContexts); + } + } +} + ++ (void)proxySceneDelegateIfNeeded:(UIScene *)scene { + Class realClass = [scene.delegate class]; + NSString *className = NSStringFromClass(realClass); + + // Skip proxying if failed to get the delegate class name for some reason (e.g. `delegate == nil`) + // or the class has a prefix of kGULAppDelegatePrefix, which means it has been proxied before. + if (className == nil || [className hasPrefix:kGULSceneDelegatePrefix]) { + return; + } + + NSString *classNameWithPrefix = [kGULSceneDelegatePrefix stringByAppendingString:className]; + NSString *newClassName = + [NSString stringWithFormat:@"%@-%@", classNameWithPrefix, [NSUUID UUID].UUIDString]; + + if (NSClassFromString(newClassName)) { + GULLogError( + kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", + (long) + kGULSwizzlerMessageCodeSceneDelegateSwizzlingInvalidSceneDelegate], + @"Cannot create a proxy for Scene Delegate. Subclass already exists. Original Class" + @": %@, subclass: %@", + className, newClassName); + return; + } + + // Register the new class as subclass of the real one. Do not allocate more than the real class + // size. + Class sceneDelegateSubClass = objc_allocateClassPair(realClass, newClassName.UTF8String, 0); + if (sceneDelegateSubClass == Nil) { + GULLogError( + kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", + (long) + kGULSwizzlerMessageCodeSceneDelegateSwizzlingInvalidSceneDelegate], + @"Cannot create a proxy for Scene Delegate. Subclass already exists. Original Class" + @": %@, subclass: Nil", + className); + return; + } + + NSMutableDictionary *realImplementationsBySelector = + [[NSMutableDictionary alloc] init]; + + // For scene:openURLContexts: + SEL openURLContextsSEL = @selector(scene:openURLContexts:); + [self proxyDestinationSelector:openURLContextsSEL + implementationsFromSourceSelector:openURLContextsSEL + fromClass:[GULSceneDelegateSwizzler class] + toClass:sceneDelegateSubClass + realClass:realClass + storeDestinationImplementationTo:realImplementationsBySelector]; + + // Store original implementations to a fake property of the original delegate. + objc_setAssociatedObject(scene.delegate, &kGULRealIMPBySelectorKey, + [realImplementationsBySelector copy], OBJC_ASSOCIATION_RETAIN_NONATOMIC); + objc_setAssociatedObject(scene.delegate, &kGULRealClassKey, realClass, + OBJC_ASSOCIATION_RETAIN_NONATOMIC); + + // The subclass size has to be exactly the same size with the original class size. The subclass + // cannot have more ivars/properties than its superclass since it will cause an offset in memory + // that can lead to overwriting the isa of an object in the next frame. + if (class_getInstanceSize(realClass) != class_getInstanceSize(sceneDelegateSubClass)) { + GULLogError( + kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", + (long) + kGULSwizzlerMessageCodeSceneDelegateSwizzlingInvalidSceneDelegate], + @"Cannot create subclass of Scene Delegate, because the created subclass is not the " + @"same size. %@", + className); + NSAssert(NO, @"Classes must be the same size to swizzle isa"); + return; + } + + // Make the newly created class to be the subclass of the real Scene Delegate class. + objc_registerClassPair(sceneDelegateSubClass); + if (object_setClass(scene.delegate, sceneDelegateSubClass)) { + GULLogDebug( + kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", + (long) + kGULSwizzlerMessageCodeSceneDelegateSwizzlingInvalidSceneDelegate], + @"Successfully created Scene Delegate Proxy automatically. To disable the " + @"proxy, set the flag %@ to NO (Boolean) in the Info.plist", + [GULSceneDelegateSwizzler correctSceneDelegateProxyKey]); + } +} + ++ (NSString *)correctSceneDelegateProxyKey { + return NSClassFromString(@"FIRCore") ? kGULFirebaseSceneDelegateProxyEnabledPlistKey + : kGULGoogleUtilitiesSceneDelegateProxyEnabledPlistKey; +} + +#endif // UISCENE_SUPPORTED + +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Internal/GULAppDelegateSwizzler_Private.h b/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Internal/GULAppDelegateSwizzler_Private.h new file mode 100644 index 0000000..38e9315 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Internal/GULAppDelegateSwizzler_Private.h @@ -0,0 +1,55 @@ +/* + * Copyright 2018 Google LLC + * + * 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 +#import "GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULAppDelegateSwizzler.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h" + +@class GULApplication; + +NS_ASSUME_NONNULL_BEGIN + +@interface GULAppDelegateSwizzler () + +/** ISA Swizzles the given appDelegate as the original app delegate would be. + * + * @param appDelegate The object that needs to be isa swizzled. This should conform to the + * application delegate protocol. + */ ++ (void)proxyAppDelegate:(id)appDelegate; + +/** Returns a dictionary containing interceptor IDs mapped to a GULZeroingWeakContainer. + * + * @return A dictionary of the form {NSString : GULZeroingWeakContainer}, where the NSString is + * the interceptorID. + */ ++ (GULMutableDictionary *)interceptors; + +/** Deletes all the registered interceptors. */ ++ (void)clearInterceptors; + +/** Resets the token that prevents the app delegate proxy from being isa swizzled multiple times. */ ++ (void)resetProxyOriginalDelegateOnceToken; + +/** Returns the original app delegate that was proxied. + * + * @return The original app delegate instance that was proxied. + */ ++ (id)originalDelegate; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Internal/GULSceneDelegateSwizzler_Private.h b/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Internal/GULSceneDelegateSwizzler_Private.h new file mode 100644 index 0000000..89896f7 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Internal/GULSceneDelegateSwizzler_Private.h @@ -0,0 +1,48 @@ +/* + * Copyright 2019 Google LLC + * + * 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 +#import "GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULSceneDelegateSwizzler.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface GULSceneDelegateSwizzler () + +#if UISCENE_SUPPORTED + +/** Returns a dictionary containing interceptor IDs mapped to a GULZeroingWeakContainer. + * + * @return A dictionary of the form {NSString : GULZeroingWeakContainer}, where the NSString is + * the interceptorID. + */ ++ (GULMutableDictionary *)interceptors; + +/** Deletes all the registered interceptors. */ ++ (void)clearInterceptors; + +/** ISA Swizzles the given appDelegate as the original app delegate would be. + * + * @param scene The scene whose delegate needs to be isa swizzled. This should conform to the + * scene delegate protocol. + */ ++ (void)proxySceneDelegateIfNeeded:(UIScene *)scene API_AVAILABLE(ios(13.0), tvos(13.0)); + +#endif // UISCENE_SUPPORTED + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULAppDelegateSwizzler.h b/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULAppDelegateSwizzler.h new file mode 100644 index 0000000..58dec49 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULAppDelegateSwizzler.h @@ -0,0 +1,107 @@ +/* + * Copyright 2018 Google LLC + * + * 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 + +#import "GULApplication.h" + +NS_ASSUME_NONNULL_BEGIN + +typedef NSString *const GULAppDelegateInterceptorID; + +/** This class contains methods that isa swizzle the app delegate. */ +@interface GULAppDelegateSwizzler : NSProxy + +/** Registers an app delegate interceptor whose methods will be invoked as they're invoked on the + * original app delegate. + * + * @param interceptor An instance of a class that conforms to the application delegate protocol. + * The interceptor is NOT retained. + * @return A unique GULAppDelegateInterceptorID if interceptor was successfully registered; nil + * if it fails. + */ ++ (nullable GULAppDelegateInterceptorID)registerAppDelegateInterceptor: + (id)interceptor; + +/** Unregisters an interceptor with the given ID if it exists. + * + * @param interceptorID The object that was generated when the interceptor was registered. + */ ++ (void)unregisterAppDelegateInterceptorWithID:(GULAppDelegateInterceptorID)interceptorID; + +/** This method ensures that the original app delegate has been proxied. Call this before + * registering your interceptor. This method is safe to call multiple times (but it only proxies + * the app delegate once). + * + * This method doesn't proxy APNS related methods: + * @code + * - application:didRegisterForRemoteNotificationsWithDeviceToken: + * - application:didFailToRegisterForRemoteNotificationsWithError: + * - application:didReceiveRemoteNotification:fetchCompletionHandler: + * - application:didReceiveRemoteNotification: + * @endcode + * + * To proxy these methods use +[GULAppDelegateSwizzler + * proxyOriginalDelegateIncludingAPNSMethods]. The methods have to be proxied separately to + * avoid potential warnings from Apple review about missing Push Notification Entitlement (e.g. + * https://github.com/firebase/firebase-ios-sdk/issues/2807) + * + * The method has no effect for extensions. + * + * @see proxyOriginalDelegateIncludingAPNSMethods + */ ++ (void)proxyOriginalDelegate; + +/** This method ensures that the original app delegate has been proxied including APNS related + * methods. Call this before registering your interceptor. This method is safe to call multiple + * times (but it only proxies the app delegate once) or + * after +[GULAppDelegateSwizzler proxyOriginalDelegate] + * + * This method calls +[GULAppDelegateSwizzler proxyOriginalDelegate] under the hood. + * After calling this method the following App Delegate methods will be proxied in addition to + * the methods proxied by proxyOriginalDelegate: + * @code + * - application:didRegisterForRemoteNotificationsWithDeviceToken: + * - application:didFailToRegisterForRemoteNotificationsWithError: + * - application:didReceiveRemoteNotification:fetchCompletionHandler: + * - application:didReceiveRemoteNotification: + * @endcode + * + * The method has no effect for extensions. + * + * @see proxyOriginalDelegate + */ ++ (void)proxyOriginalDelegateIncludingAPNSMethods; + +/** Indicates whether app delegate proxy is explicitly disabled or enabled. Enabled by default. + * + * @return YES if AppDelegateProxy is Enabled, NO otherwise. + */ ++ (BOOL)isAppDelegateProxyEnabled; + +/** Returns the current sharedApplication. + * + * @return the current application instance if in an app, or nil if in extension or if it doesn't + * exist. + */ ++ (nullable GULApplication *)sharedApplication; + +/** Do not initialize this class. */ +- (instancetype)init NS_UNAVAILABLE; + +NS_ASSUME_NONNULL_END + +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULApplication.h b/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULApplication.h new file mode 100644 index 0000000..8067212 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULApplication.h @@ -0,0 +1,50 @@ +/* + * Copyright 2019 Google LLC + * + * 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 + +#if TARGET_OS_IOS || TARGET_OS_TV + +#import + +#define GULApplication UIApplication +#define GULApplicationDelegate UIApplicationDelegate +#define GULUserActivityRestoring UIUserActivityRestoring + +static NSString *const kGULApplicationClassName = @"UIApplication"; + +#elif TARGET_OS_OSX + +#import + +#define GULApplication NSApplication +#define GULApplicationDelegate NSApplicationDelegate +#define GULUserActivityRestoring NSUserActivityRestoring + +static NSString *const kGULApplicationClassName = @"NSApplication"; + +#elif TARGET_OS_WATCH + +#import + +// We match the according watchOS API but swizzling should not work in watch +#define GULApplication WKExtension +#define GULApplicationDelegate WKExtensionDelegate +#define GULUserActivityRestoring NSUserActivityRestoring + +static NSString *const kGULApplicationClassName = @"WKExtension"; + +#endif diff --git a/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULSceneDelegateSwizzler.h b/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULSceneDelegateSwizzler.h new file mode 100644 index 0000000..ed080a3 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULSceneDelegateSwizzler.h @@ -0,0 +1,76 @@ +/* + * Copyright 2019 Google LLC + * + * 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 +#import + +#if !TARGET_OS_OSX +#import +#endif // !TARGET_OS_OSX + +#if ((TARGET_OS_IOS || TARGET_OS_TV) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= 130000)) +#define UISCENE_SUPPORTED 1 +#endif + +NS_ASSUME_NONNULL_BEGIN + +typedef NSString *const GULSceneDelegateInterceptorID; + +/** This class contains methods that isa swizzle the scene delegate. */ +@interface GULSceneDelegateSwizzler : NSProxy + +#if UISCENE_SUPPORTED + +/** Registers a scene delegate interceptor whose methods will be invoked as they're invoked on the + * original scene delegate. + * + * @param interceptor An instance of a class that conforms to the application delegate protocol. + * The interceptor is NOT retained. + * @return A unique GULSceneDelegateInterceptorID if interceptor was successfully registered; nil + * if it fails. + */ ++ (nullable GULSceneDelegateInterceptorID)registerSceneDelegateInterceptor: + (id)interceptor API_AVAILABLE(ios(13.0), tvos(13.0)); + +/** Unregisters an interceptor with the given ID if it exists. + * + * @param interceptorID The object that was generated when the interceptor was registered. + */ ++ (void)unregisterSceneDelegateInterceptorWithID:(GULSceneDelegateInterceptorID)interceptorID + API_AVAILABLE(ios(13.0), tvos(13.0)); + +/** Do not initialize this class. */ +- (instancetype)init NS_UNAVAILABLE; + +#endif // UISCENE_SUPPORTED + +/** This method ensures that the original scene delegate has been proxied. Call this before + * registering your interceptor. This method is safe to call multiple times (but it only proxies + * the scene delegate once). + * + * The method has no effect for extensions. + */ ++ (void)proxyOriginalSceneDelegate; + +/** Indicates whether scene delegate proxy is explicitly disabled or enabled. Enabled by default. + * + * @return YES if SceneDelegateProxy is Enabled, NO otherwise. + */ ++ (BOOL)isSceneDelegateProxyEnabled; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleUtilities/GoogleUtilities/Common/GULLoggerCodes.h b/Pods/GoogleUtilities/GoogleUtilities/Common/GULLoggerCodes.h new file mode 100644 index 0000000..053ce84 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Common/GULLoggerCodes.h @@ -0,0 +1,56 @@ +/* + * Copyright 2018 Google LLC + * + * 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 + +typedef NS_ENUM(NSInteger, GULSwizzlerMessageCode) { + // App Delegate Swizzling. + kGULSwizzlerMessageCodeAppDelegateSwizzling000 = 1000, // I-SWZ001000 + kGULSwizzlerMessageCodeAppDelegateSwizzling001 = 1001, // I-SWZ001001 + kGULSwizzlerMessageCodeAppDelegateSwizzling002 = 1002, // I-SWZ001002 + kGULSwizzlerMessageCodeAppDelegateSwizzling003 = 1003, // I-SWZ001003 + kGULSwizzlerMessageCodeAppDelegateSwizzling004 = 1004, // I-SWZ001004 + kGULSwizzlerMessageCodeAppDelegateSwizzling005 = 1005, // I-SWZ001005 + kGULSwizzlerMessageCodeAppDelegateSwizzling006 = 1006, // I-SWZ001006 + kGULSwizzlerMessageCodeAppDelegateSwizzling007 = 1007, // I-SWZ001007 + kGULSwizzlerMessageCodeAppDelegateSwizzling008 = 1008, // I-SWZ001008 + kGULSwizzlerMessageCodeAppDelegateSwizzling009 = 1009, // I-SWZ001009 + kGULSwizzlerMessageCodeAppDelegateSwizzling010 = 1010, // I-SWZ001010 + kGULSwizzlerMessageCodeAppDelegateSwizzling011 = 1011, // I-SWZ001011 + kGULSwizzlerMessageCodeAppDelegateSwizzling012 = 1012, // I-SWZ001012 + kGULSwizzlerMessageCodeAppDelegateSwizzling013 = 1013, // I-SWZ001013 + kGULSwizzlerMessageCodeAppDelegateSwizzlingInvalidAppDelegate = 1014, // I-SWZ001014 + + // Scene Delegate Swizzling. + kGULSwizzlerMessageCodeSceneDelegateSwizzling000 = 1100, // I-SWZ001100 + kGULSwizzlerMessageCodeSceneDelegateSwizzling001 = 1101, // I-SWZ001101 + kGULSwizzlerMessageCodeSceneDelegateSwizzling002 = 1102, // I-SWZ001102 + kGULSwizzlerMessageCodeSceneDelegateSwizzling003 = 1103, // I-SWZ001103 + kGULSwizzlerMessageCodeSceneDelegateSwizzling004 = 1104, // I-SWZ001104 + kGULSwizzlerMessageCodeSceneDelegateSwizzling005 = 1105, // I-SWZ001105 + kGULSwizzlerMessageCodeSceneDelegateSwizzling006 = 1106, // I-SWZ001106 + kGULSwizzlerMessageCodeSceneDelegateSwizzling007 = 1107, // I-SWZ001107 + kGULSwizzlerMessageCodeSceneDelegateSwizzling008 = 1108, // I-SWZ001108 + kGULSwizzlerMessageCodeSceneDelegateSwizzling009 = 1109, // I-SWZ001109 + kGULSwizzlerMessageCodeSceneDelegateSwizzling010 = 1110, // I-SWZ001110 + kGULSwizzlerMessageCodeSceneDelegateSwizzling011 = 1111, // I-SWZ001111 + kGULSwizzlerMessageCodeSceneDelegateSwizzling012 = 1112, // I-SWZ001112 + kGULSwizzlerMessageCodeSceneDelegateSwizzling013 = 1113, // I-SWZ001113 + kGULSwizzlerMessageCodeSceneDelegateSwizzlingInvalidSceneDelegate = 1114, // I-SWZ001114 + + // Method Swizzling. + kGULSwizzlerMessageCodeMethodSwizzling000 = 2000, // I-SWZ002000 +}; diff --git a/Pods/GoogleUtilities/GoogleUtilities/Environment/GULHeartbeatDateStorage.m b/Pods/GoogleUtilities/GoogleUtilities/Environment/GULHeartbeatDateStorage.m new file mode 100644 index 0000000..f1d8ddc --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Environment/GULHeartbeatDateStorage.m @@ -0,0 +1,153 @@ +/* + * Copyright 2019 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 "GoogleUtilities/Environment/Public/GoogleUtilities/GULHeartbeatDateStorage.h" +#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULSecureCoding.h" + +NSString *const kGULHeartbeatStorageDirectory = @"Google/FIRApp"; + +@interface GULHeartbeatDateStorage () + +/** The name of the file that stores heartbeat information. */ +@property(nonatomic, readonly) NSString *fileName; +@end + +@implementation GULHeartbeatDateStorage + +@synthesize fileURL = _fileURL; + +- (instancetype)initWithFileName:(NSString *)fileName { + if (fileName == nil) return nil; + + self = [super init]; + if (self) { + _fileName = fileName; + } + return self; +} + +/** Lazy getter for fileURL. + * @return fileURL where heartbeat information is stored. + */ +- (NSURL *)fileURL { + if (!_fileURL) { + NSURL *directoryURL = [self directoryPathURL]; + [self checkAndCreateDirectory:directoryURL]; + _fileURL = [directoryURL URLByAppendingPathComponent:_fileName]; + } + return _fileURL; +} + +/** Returns the URL path of the directory for heartbeat storage data. + * @return the URL path of the directory for heartbeat storage data. + */ +- (NSURL *)directoryPathURL { + NSArray *paths; +#if TARGET_OS_TV + paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); +#else + paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); +#endif // TARGET_OS_TV + NSString *rootPath = [paths lastObject]; + NSURL *rootURL = [NSURL fileURLWithPath:rootPath]; + NSURL *directoryURL = [rootURL URLByAppendingPathComponent:kGULHeartbeatStorageDirectory]; + return directoryURL; +} + +/** Check for the existence of the directory specified by the URL, and create it if it does not + * exist. + * @param directoryPathURL The path to the directory that needs to exist. + */ +- (void)checkAndCreateDirectory:(NSURL *)directoryPathURL { + NSError *error; + if (![directoryPathURL checkResourceIsReachableAndReturnError:&error]) { + NSError *error; + [[NSFileManager defaultManager] createDirectoryAtURL:directoryPathURL + withIntermediateDirectories:YES + attributes:nil + error:&error]; + } +} + +- (nullable NSDate *)heartbeatDateForTag:(NSString *)tag { + @synchronized(self.class) { + NSDictionary *heartbeatDictionary = [self heartbeatDictionaryWithFileURL:self.fileURL]; + NSDate *heartbeatDate = heartbeatDictionary[tag]; + + // Validate the value type. If the storage file was corrupted or updated with a different format + // by a newer SDK version the value type may be different. + if (![heartbeatDate isKindOfClass:[NSDate class]]) { + heartbeatDate = nil; + } + + return heartbeatDate; + } +} + +- (BOOL)setHearbeatDate:(NSDate *)date forTag:(NSString *)tag { + // Synchronize on the class to ensure that the different instances of the class will not access + // the same file concurrently. + // TODO: Consider a different synchronization strategy here and in `-heartbeatDateForTag:` method. + // Currently no heartbeats can be read/written concurrently even if they are in different files. + @synchronized(self.class) { + NSMutableDictionary *heartbeatDictionary = + [[self heartbeatDictionaryWithFileURL:self.fileURL] mutableCopy]; + heartbeatDictionary[tag] = date; + NSError *error; + BOOL isSuccess = [self writeDictionary:[heartbeatDictionary copy] + forWritingURL:self.fileURL + error:&error]; + return isSuccess; + } +} + +- (NSDictionary *)heartbeatDictionaryWithFileURL:(NSURL *)readingFileURL { + NSDictionary *heartbeatDictionary; + + NSError *error; + NSData *objectData = [NSData dataWithContentsOfURL:readingFileURL options:0 error:&error]; + + if (objectData.length > 0 && error == nil) { + NSSet *objectClasses = + [NSSet setWithArray:@[ NSDictionary.class, NSDate.class, NSString.class ]]; + heartbeatDictionary = [GULSecureCoding unarchivedObjectOfClasses:objectClasses + fromData:objectData + error:&error]; + } + + if (heartbeatDictionary.count == 0 || error != nil) { + heartbeatDictionary = [NSDictionary dictionary]; + } + + return heartbeatDictionary; +} + +- (BOOL)writeDictionary:(NSDictionary *)dictionary + forWritingURL:(NSURL *)writingFileURL + error:(NSError **)outError { + // Archive a mutable copy `dictionary` for writing to disk. This is done for + // backwards compatibility. See Google Utilities issue #36 for more context. + // TODO: Remove usage of mutable copy in a future version of Google Utilities. + NSData *data = [GULSecureCoding archivedDataWithRootObject:[dictionary mutableCopy] + error:outError]; + if (data.length == 0) { + return NO; + } + + return [data writeToURL:writingFileURL atomically:YES]; +} + +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/Environment/GULHeartbeatDateStorageUserDefaults.m b/Pods/GoogleUtilities/GoogleUtilities/Environment/GULHeartbeatDateStorageUserDefaults.m new file mode 100644 index 0000000..f8f1159 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Environment/GULHeartbeatDateStorageUserDefaults.m @@ -0,0 +1,68 @@ +/* + * Copyright 2021 Google LLC + * + * 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 "GoogleUtilities/Environment/Public/GoogleUtilities/GULHeartbeatDateStorageUserDefaults.h" + +@interface GULHeartbeatDateStorageUserDefaults () + +/** The storage to store the date of the last sent heartbeat. */ +@property(nonatomic, readonly) NSUserDefaults *userDefaults; + +/** The key for user defaults to store heartbeat information. */ +@property(nonatomic, readonly) NSString *key; + +@end + +@implementation GULHeartbeatDateStorageUserDefaults + +- (instancetype)initWithDefaults:(NSUserDefaults *)defaults key:(NSString *)key { + self = [super init]; + if (self) { + _userDefaults = defaults; + _key = key; + } + return self; +} + +- (NSMutableDictionary *)heartbeatDictionaryFromDefaults { + NSDictionary *heartbeatDict = [self.userDefaults objectForKey:self.key]; + if (heartbeatDict != nil) { + return [heartbeatDict mutableCopy]; + } else { + return [NSMutableDictionary dictionary]; + } +} + +- (nullable NSDate *)heartbeatDateForTag:(NSString *)tag { + NSDate *date = nil; + @synchronized(self.userDefaults) { + NSMutableDictionary *dict = [self heartbeatDictionaryFromDefaults]; + date = dict[tag]; + } + + return date; +} + +- (BOOL)setHearbeatDate:(NSDate *)date forTag:(NSString *)tag { + @synchronized(self.userDefaults) { + NSMutableDictionary *dict = [self heartbeatDictionaryFromDefaults]; + dict[tag] = date; + [self.userDefaults setObject:dict forKey:self.key]; + } + return true; +} + +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/Environment/GULSecureCoding.m b/Pods/GoogleUtilities/GoogleUtilities/Environment/GULSecureCoding.m new file mode 100644 index 0000000..21d5c2a --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Environment/GULSecureCoding.m @@ -0,0 +1,103 @@ +// Copyright 2019 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 "GoogleUtilities/Environment/Public/GoogleUtilities/GULSecureCoding.h" + +NSString *const kGULSecureCodingError = @"GULSecureCodingError"; + +@implementation GULSecureCoding + ++ (nullable id)unarchivedObjectOfClasses:(NSSet *)classes + fromData:(NSData *)data + error:(NSError **)outError { + id object; +#if __has_builtin(__builtin_available) + if (@available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *)) { + object = [NSKeyedUnarchiver unarchivedObjectOfClasses:classes fromData:data error:outError]; + } else +#endif // __has_builtin(__builtin_available) + { + @try { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; +#pragma clang diagnostic pop + unarchiver.requiresSecureCoding = YES; + + object = [unarchiver decodeObjectOfClasses:classes forKey:NSKeyedArchiveRootObjectKey]; + } @catch (NSException *exception) { + if (outError) { + *outError = [self archivingErrorWithException:exception]; + } + } + + if (object == nil && outError && *outError == nil) { + NSString *failureReason = @"NSKeyedUnarchiver failed to unarchive data."; + *outError = [NSError errorWithDomain:kGULSecureCodingError + code:-1 + userInfo:@{NSLocalizedFailureReasonErrorKey : failureReason}]; + } + } + + return object; +} + ++ (nullable id)unarchivedObjectOfClass:(Class)class + fromData:(NSData *)data + error:(NSError **)outError { + return [self unarchivedObjectOfClasses:[NSSet setWithObject:class] fromData:data error:outError]; +} + ++ (nullable NSData *)archivedDataWithRootObject:(id)object error:(NSError **)outError { + NSData *archiveData; +#if __has_builtin(__builtin_available) + if (@available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *)) { + archiveData = [NSKeyedArchiver archivedDataWithRootObject:object + requiringSecureCoding:YES + error:outError]; + } else +#endif // __has_builtin(__builtin_available) + { + @try { + NSMutableData *data = [NSMutableData data]; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; +#pragma clang diagnostic pop + archiver.requiresSecureCoding = YES; + + [archiver encodeObject:object forKey:NSKeyedArchiveRootObjectKey]; + [archiver finishEncoding]; + + archiveData = [data copy]; + } @catch (NSException *exception) { + if (outError) { + *outError = [self archivingErrorWithException:exception]; + } + } + } + + return archiveData; +} + ++ (NSError *)archivingErrorWithException:(NSException *)exception { + NSString *failureReason = [NSString + stringWithFormat:@"NSKeyedArchiver exception with name: %@, reason: %@, userInfo: %@", + exception.name, exception.reason, exception.userInfo]; + NSDictionary *errorUserInfo = @{NSLocalizedFailureReasonErrorKey : failureReason}; + + return [NSError errorWithDomain:kGULSecureCodingError code:-1 userInfo:errorUserInfo]; +} + +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/Environment/NetworkInfo/GULNetworkInfo.m b/Pods/GoogleUtilities/GoogleUtilities/Environment/NetworkInfo/GULNetworkInfo.m new file mode 100644 index 0000000..622ae4a --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Environment/NetworkInfo/GULNetworkInfo.m @@ -0,0 +1,138 @@ +// Copyright 2022 Google LLC +// +// 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 "GoogleUtilities/Environment/Public/GoogleUtilities/GULNetworkInfo.h" + +#import + +#import +#if __has_include("CoreTelephony/CTTelephonyNetworkInfo.h") && !TARGET_OS_MACCATALYST && \ + !TARGET_OS_OSX && !TARGET_OS_TV && !TARGET_OS_WATCH +#define TARGET_HAS_MOBILE_CONNECTIVITY +#import +#import +#import +#endif + +@implementation GULNetworkInfo + +#ifdef TARGET_HAS_MOBILE_CONNECTIVITY ++ (CTTelephonyNetworkInfo *)getNetworkInfo { + static CTTelephonyNetworkInfo *networkInfo; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + networkInfo = [[CTTelephonyNetworkInfo alloc] init]; + }); + return networkInfo; +} +#endif + ++ (NSString *_Nullable)getNetworkMobileCountryCode { +#ifdef TARGET_HAS_MOBILE_CONNECTIVITY + CTTelephonyNetworkInfo *networkInfo = [GULNetworkInfo getNetworkInfo]; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + CTCarrier *provider = networkInfo.subscriberCellularProvider; +#pragma clang diagnostic push + return provider.mobileCountryCode; +#endif + return nil; +} + ++ (NSString *_Nullable)getNetworkMobileNetworkCode { +#ifdef TARGET_HAS_MOBILE_CONNECTIVITY + CTTelephonyNetworkInfo *networkInfo = [GULNetworkInfo getNetworkInfo]; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + CTCarrier *provider = networkInfo.subscriberCellularProvider; +#pragma clang diagnostic push + return provider.mobileNetworkCode; +#endif + return nil; +} + +/** + * Returns the formatted MccMnc if the inputs are valid, otherwise nil + * @param mcc The Mobile Country Code returned from `getNetworkMobileCountryCode` + * @param mnc The Mobile Network Code returned from `getNetworkMobileNetworkCode` + * @returns A string with the concatenated mccMnc if both inputs are valid, otherwise nil + */ ++ (NSString *_Nullable)formatMcc:(NSString *)mcc andMNC:(NSString *)mnc { + // These are both nil if the target does not support mobile connectivity + if (mcc == nil && mnc == nil) { + return nil; + } + + if (mcc.length != 3 || mnc.length < 2 || mnc.length > 3) { + return nil; + } + + // If the resulting appended mcc + mnc contains characters that are not + // decimal digits, return nil + static NSCharacterSet *notDigits; + static dispatch_once_t token; + dispatch_once(&token, ^{ + notDigits = [[NSCharacterSet decimalDigitCharacterSet] invertedSet]; + }); + NSString *mccMnc = [mcc stringByAppendingString:mnc]; + if ([mccMnc rangeOfCharacterFromSet:notDigits].location != NSNotFound) { + return nil; + } + + return mccMnc; +} + ++ (GULNetworkType)getNetworkType { + GULNetworkType networkType = GULNetworkTypeNone; + +#ifdef TARGET_HAS_MOBILE_CONNECTIVITY + static SCNetworkReachabilityRef reachabilityRef = 0; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + reachabilityRef = SCNetworkReachabilityCreateWithName(kCFAllocatorSystemDefault, "google.com"); + }); + + if (!reachabilityRef) { + return GULNetworkTypeNone; + } + + SCNetworkReachabilityFlags reachabilityFlags = 0; + SCNetworkReachabilityGetFlags(reachabilityRef, &reachabilityFlags); + + // Parse the network flags to set the network type. + if (reachabilityFlags & kSCNetworkReachabilityFlagsReachable) { + if (reachabilityFlags & kSCNetworkReachabilityFlagsIsWWAN) { + networkType = GULNetworkTypeMobile; + } else { + networkType = GULNetworkTypeWIFI; + } + } +#endif + + return networkType; +} + ++ (NSString *)getNetworkRadioType { +#ifdef TARGET_HAS_MOBILE_CONNECTIVITY + CTTelephonyNetworkInfo *networkInfo = [GULNetworkInfo getNetworkInfo]; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + return networkInfo.currentRadioAccessTechnology; +#pragma clang diagnostic pop +#else + return @""; +#endif +} + +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULAppEnvironmentUtil.h b/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULAppEnvironmentUtil.h new file mode 100644 index 0000000..ad32929 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULAppEnvironmentUtil.h @@ -0,0 +1,68 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +@interface GULAppEnvironmentUtil : NSObject + +/// Indicates whether the app is from Apple Store or not. Returns NO if the app is on simulator, +/// development environment or sideloaded. ++ (BOOL)isFromAppStore; + +/// Indicates whether the app is a Testflight app. Returns YES if the app has sandbox receipt. +/// Returns NO otherwise. ++ (BOOL)isAppStoreReceiptSandbox; + +/// Indicates whether the app is on simulator or not at runtime depending on the device +/// architecture. ++ (BOOL)isSimulator; + +/// The current device model. Returns an empty string if device model cannot be retrieved. ++ (nullable NSString *)deviceModel; + +/// The current device model, with simulator-specific values. Returns an empty string if device +/// model cannot be retrieved. ++ (nullable NSString *)deviceSimulatorModel; + +/// The current operating system version. Returns an empty string if the system version cannot be +/// retrieved. ++ (NSString *)systemVersion; + +/// Indicates whether it is running inside an extension or an app. ++ (BOOL)isAppExtension; + +/// @return Returns @YES when is run on iOS version greater or equal to 7.0 ++ (BOOL)isIOS7OrHigher DEPRECATED_MSG_ATTRIBUTE( + "Always `YES` because only iOS 8 and higher supported. The method will be removed."); + +/// @return YES if Swift runtime detected in the app. ++ (BOOL)hasSwiftRuntime __deprecated; + +/// @return An Apple platform. Possible values "ios", "tvos", "macos", "watchos", "maccatalyst". ++ (NSString *)applePlatform; + +/// @return An Apple Device platform. Same possible values as `applePlatform`, with the addition of +/// "ipados". ++ (NSString *)appleDevicePlatform; + +/// @return The way the library was added to the app, e.g. "swiftpm", "cocoapods", etc. ++ (NSString *)deploymentType; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULHeartbeatDateStorable.h b/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULHeartbeatDateStorable.h new file mode 100644 index 0000000..43d3740 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULHeartbeatDateStorable.h @@ -0,0 +1,40 @@ +/* + * Copyright 2021 Google LLC + * + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** + * Describes an object that can store and fetch heartbeat dates for given tags. + */ +@protocol GULHeartbeatDateStorable + +/** + * Reads the date from the specified file for the given tag. + * @return Returns date if exists, otherwise `nil`. + */ +- (nullable NSDate *)heartbeatDateForTag:(NSString *)tag; + +/** + * Saves the date for the specified tag in the specified file. + * @return YES on success, NO otherwise. + */ +- (BOOL)setHearbeatDate:(NSDate *)date forTag:(NSString *)tag; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULHeartbeatDateStorage.h b/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULHeartbeatDateStorage.h new file mode 100644 index 0000000..245b1a2 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULHeartbeatDateStorage.h @@ -0,0 +1,54 @@ +/* + * Copyright 2019 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 + +#import "GULHeartbeatDateStorable.h" + +NS_ASSUME_NONNULL_BEGIN + +/// The name of the directory where the heartbeat data is stored. +extern NSString *const kGULHeartbeatStorageDirectory; + +/// Stores either a date or a dictionary to a specified file. +@interface GULHeartbeatDateStorage : NSObject + +- (instancetype)init NS_UNAVAILABLE; + +@property(nonatomic, readonly) NSURL *fileURL; + +/** + * Default initializer. + * @param fileName The name of the file to store the date information. + * exist, it will be created if needed. + */ +- (instancetype)initWithFileName:(NSString *)fileName; + +/** + * Reads the date from the specified file for the given tag. + * @return Returns date if exists, otherwise `nil`. + */ +- (nullable NSDate *)heartbeatDateForTag:(NSString *)tag; + +/** + * Saves the date for the specified tag in the specified file. + * @return YES on success, NO otherwise. + */ +- (BOOL)setHearbeatDate:(NSDate *)date forTag:(NSString *)tag; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULHeartbeatDateStorageUserDefaults.h b/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULHeartbeatDateStorageUserDefaults.h new file mode 100644 index 0000000..e6c7dda --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULHeartbeatDateStorageUserDefaults.h @@ -0,0 +1,51 @@ +/* + * Copyright 2021 Google LLC + * + * 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 + +#import "GULHeartbeatDateStorable.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Stores either a date or a dictionary to a specified file. +@interface GULHeartbeatDateStorageUserDefaults : NSObject + +/** + * Default initializer. tvOS can only write to the cache directory and + * there are no guarantees that the directory will persist. User defaults will + * be retained, so that should be used instead. + * @param defaults User defaults instance to store the heartbeat information. + * @param key The key to be used with the user defaults instance. + */ +- (instancetype)initWithDefaults:(NSUserDefaults *)defaults key:(NSString *)key; + +- (instancetype)init NS_UNAVAILABLE; + +/** + * Reads the date from the specified file for the given tag. + * @return Returns date if exists, otherwise `nil`. + */ +- (nullable NSDate *)heartbeatDateForTag:(NSString *)tag; + +/** + * Saves the date for the specified tag in the specified file. + * @return YES on success, NO otherwise. + */ +- (BOOL)setHearbeatDate:(NSDate *)date forTag:(NSString *)tag; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainStorage.h b/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainStorage.h new file mode 100644 index 0000000..af10cb4 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainStorage.h @@ -0,0 +1,82 @@ +/* + * Copyright 2019 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 + +@class FBLPromise; + +NS_ASSUME_NONNULL_BEGIN + +/// The class provides a convenient, multiplatform abstraction of the Keychain. +/// +/// When using this API on macOS, the corresponding target must be signed with a provisioning +/// profile that has the Keychain Sharing capability enabled. +@interface GULKeychainStorage : NSObject + +- (instancetype)init NS_UNAVAILABLE; + +/** Initializes the keychain storage with Keychain Service name. + * @param service A Keychain Service name that will be used to store and retrieve objects. See also + * `kSecAttrService`. + */ +- (instancetype)initWithService:(NSString *)service; + +/** + * Get an object by key. + * @param key The key. + * @param objectClass The expected object class required by `NSSecureCoding`. + * @param accessGroup The Keychain Access Group. + * + * @return Returns a promise. It is resolved with an object stored by key if exists. It is resolved + * with `nil` when the object not found. It fails on a Keychain error. + */ +- (FBLPromise> *)getObjectForKey:(NSString *)key + objectClass:(Class)objectClass + accessGroup:(nullable NSString *)accessGroup; + +/** + * Saves the given object by the given key. + * @param object The object to store. + * @param key The key to store the object. If there is an existing object by the key, it will be + * overridden. + * @param accessGroup The Keychain Access Group. + * + * @return Returns which is resolved with `[NSNull null]` on success. + */ +- (FBLPromise *)setObject:(id)object + forKey:(NSString *)key + accessGroup:(nullable NSString *)accessGroup; + +/** + * Removes the object by the given key. + * @param key The key to store the object. If there is an existing object by the key, it will be + * overridden. + * @param accessGroup The Keychain Access Group. + * + * @return Returns which is resolved with `[NSNull null]` on success. + */ +- (FBLPromise *)removeObjectForKey:(NSString *)key + accessGroup:(nullable NSString *)accessGroup; + +#if TARGET_OS_OSX +/// If not `nil`, then only this keychain will be used to save and read data (see +/// `kSecMatchSearchList` and `kSecUseKeychain`. It is mostly intended to be used by unit tests. +@property(nonatomic, nullable) SecKeychainRef keychainRef; +#endif // TARGET_OS_OSX + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainUtils.h b/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainUtils.h new file mode 100644 index 0000000..9c17356 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainUtils.h @@ -0,0 +1,64 @@ +/* + * Copyright 2019 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 + +NS_ASSUME_NONNULL_BEGIN + +FOUNDATION_EXPORT NSString *const kGULKeychainUtilsErrorDomain; + +/// A collection of helper functions that abstract away common Keychain operations. +/// +/// When using this API on macOS, the corresponding target must be signed with a provisioning +/// profile that has the Keychain Sharing capability enabled. +@interface GULKeychainUtils : NSObject + +/** Fetches a keychain item data matching to the provided query. + * @param query A dictionary with Keychain query parameters. See docs for `SecItemCopyMatching` for + * details. + * @param outError A pointer to `NSError` instance or `NULL`. The instance at `outError` will be + * assigned with an error if there is. + * @returns Data for the first Keychain Item matching the provided query or `nil` if there is not + * such an item (`outError` will be `nil` in this case) or an error occurred. + */ ++ (nullable NSData *)getItemWithQuery:(NSDictionary *)query + error:(NSError *_Nullable *_Nullable)outError; + +/** Stores data to a Keychain Item matching to the provided query. An existing Keychain Item + * matching the query parameters will be updated or a new will be created. + * @param item A Keychain Item data to store. + * @param query A dictionary with Keychain query parameters. See docs for `SecItemAdd` and + * `SecItemUpdate` for details. + * @param outError A pointer to `NSError` instance or `NULL`. The instance at `outError` will be + * assigned with an error if there is. + * @returns `YES` when data was successfully stored, `NO` otherwise. + */ ++ (BOOL)setItem:(NSData *)item + withQuery:(NSDictionary *)query + error:(NSError *_Nullable *_Nullable)outError; + +/** Removes a Keychain Item matching to the provided query. + * @param query A dictionary with Keychain query parameters. See docs for `SecItemDelete` for + * details. + * @param outError A pointer to `NSError` instance or `NULL`. The instance at `outError` will be + * assigned with an error if there is. + * @returns `YES` if the item was removed successfully or doesn't exist, `NO` otherwise. + */ ++ (BOOL)removeItemWithQuery:(NSDictionary *)query error:(NSError *_Nullable *_Nullable)outError; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULNetworkInfo.h b/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULNetworkInfo.h new file mode 100644 index 0000000..d3025cd --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULNetworkInfo.h @@ -0,0 +1,57 @@ +// Copyright 2022 Google LLC +// +// 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 + +NS_ASSUME_NONNULL_BEGIN + +/// The type of network that the device is running with. Values should correspond to the NetworkType +/// values in android/play/playlog/proto/clientanalytics.proto +typedef NS_ENUM(NSInteger, GULNetworkType) { + GULNetworkTypeNone = -1, + GULNetworkTypeMobile = 0, + GULNetworkTypeWIFI = 1, +}; + +/// Collection of utilities to read network status information +@interface GULNetworkInfo : NSObject + +/// Returns the cellular mobile country code (mcc) if CoreTelephony is supported, otherwise nil ++ (NSString *_Nullable)getNetworkMobileCountryCode; + +/// Returns the cellular mobile network code (mnc) if CoreTelephony is supported, otherwise nil ++ (NSString *_Nullable)getNetworkMobileNetworkCode; + +/** + * Returns the formatted MccMnc if the inputs are valid, otherwise nil + * @param mcc The Mobile Country Code returned from `getNetworkMobileCountryCode` + * @param mnc The Mobile Network Code returned from `getNetworkMobileNetworkCode` + * @returns A string with the concatenated mccMnc if both inputs are valid, otherwise nil + */ ++ (NSString *_Nullable)formatMcc:(NSString *_Nullable)mcc andMNC:(NSString *_Nullable)mnc; + +/// Returns an enum indicating the network type. The enum values should be easily transferrable to +/// the NetworkType value in android/play/playlog/proto/clientanalytics.proto. Right now this always +/// returns None on platforms other than iOS. This should be updated in the future to return Wi-Fi +/// values for the other platforms when applicable. ++ (GULNetworkType)getNetworkType; + +/// Returns a string indicating the radio access technology used by the app. The return value will +/// be one of CTRadioAccess constants defined in +/// https://developer.apple.com/documentation/coretelephony/cttelephonynetworkinfo/radio_access_technology_constants ++ (NSString *)getNetworkRadioType; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULSecureCoding.h b/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULSecureCoding.h new file mode 100644 index 0000000..8484b39 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULSecureCoding.h @@ -0,0 +1,36 @@ +// Copyright 2019 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 + +NS_ASSUME_NONNULL_BEGIN + +/** The class wraps `NSKeyedArchiver` and `NSKeyedUnarchiver` API to provide a unified secure coding + * methods for iOS versions before and after 11. + */ +@interface GULSecureCoding : NSObject + ++ (nullable id)unarchivedObjectOfClasses:(NSSet *)classes + fromData:(NSData *)data + error:(NSError **)outError; + ++ (nullable id)unarchivedObjectOfClass:(Class)class + fromData:(NSData *)data + error:(NSError **)outError; + ++ (nullable NSData *)archivedDataWithRootObject:(id)object error:(NSError **)outError; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULURLSessionDataResponse.h b/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULURLSessionDataResponse.h new file mode 100644 index 0000000..e88eb67 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULURLSessionDataResponse.h @@ -0,0 +1,31 @@ +/* + * Copyright 2020 Google LLC + * + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** The class represents HTTP response received from `NSURLSession`. */ +@interface GULURLSessionDataResponse : NSObject + +@property(nonatomic, readonly) NSHTTPURLResponse *HTTPResponse; +@property(nonatomic, nullable, readonly) NSData *HTTPBody; + +- (instancetype)initWithResponse:(NSHTTPURLResponse *)response HTTPBody:(nullable NSData *)body; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/NSURLSession+GULPromises.h b/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/NSURLSession+GULPromises.h new file mode 100644 index 0000000..7bed005 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/NSURLSession+GULPromises.h @@ -0,0 +1,37 @@ +/* + * Copyright 2020 Google LLC + * + * 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 + +@class FBLPromise; +@class GULURLSessionDataResponse; + +NS_ASSUME_NONNULL_BEGIN + +/** Promise based API for `NSURLSession`. */ +@interface NSURLSession (GULPromises) + +/** Creates a promise wrapping `-[NSURLSession dataTaskWithRequest:completionHandler:]` method. + * @param URLRequest The request to create a data task with. + * @return A promise that is fulfilled when an HTTP response is received (with any response code), + * or is rejected with the error passed to the task completion. + */ +- (FBLPromise *)gul_dataTaskPromiseWithRequest: + (NSURLRequest *)URLRequest; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleUtilities/GoogleUtilities/Environment/SecureStorage/GULKeychainStorage.m b/Pods/GoogleUtilities/GoogleUtilities/Environment/SecureStorage/GULKeychainStorage.m new file mode 100644 index 0000000..022c1bf --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Environment/SecureStorage/GULKeychainStorage.m @@ -0,0 +1,198 @@ +/* + * Copyright 2019 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 "GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainStorage.h" +#import + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainUtils.h" +#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULSecureCoding.h" + +@interface GULKeychainStorage () +@property(nonatomic, readonly) dispatch_queue_t keychainQueue; +@property(nonatomic, readonly) dispatch_queue_t inMemoryCacheQueue; +@property(nonatomic, readonly) NSString *service; +@property(nonatomic, readonly) NSCache> *inMemoryCache; +@end + +@implementation GULKeychainStorage + +- (instancetype)initWithService:(NSString *)service { + NSCache *cache = [[NSCache alloc] init]; + // Cache up to 5 installations. + cache.countLimit = 5; + return [self initWithService:service cache:cache]; +} + +- (instancetype)initWithService:(NSString *)service cache:(NSCache *)cache { + self = [super init]; + if (self) { + _keychainQueue = + dispatch_queue_create("com.gul.KeychainStorage.Keychain", DISPATCH_QUEUE_SERIAL); + _inMemoryCacheQueue = + dispatch_queue_create("com.gul.KeychainStorage.InMemoryCache", DISPATCH_QUEUE_SERIAL); + _service = [service copy]; + _inMemoryCache = cache; + } + return self; +} + +#pragma mark - Public + +- (FBLPromise> *)getObjectForKey:(NSString *)key + objectClass:(Class)objectClass + accessGroup:(nullable NSString *)accessGroup { + return [FBLPromise onQueue:self.inMemoryCacheQueue + do:^id _Nullable { + // Return cached object or fail otherwise. + id object = [self.inMemoryCache objectForKey:key]; + return object + ?: [[NSError alloc] + initWithDomain:FBLPromiseErrorDomain + code:FBLPromiseErrorCodeValidationFailure + userInfo:nil]; + }] + .recover(^id _Nullable(NSError *error) { + // Look for the object in the keychain. + return [self getObjectFromKeychainForKey:key + objectClass:objectClass + accessGroup:accessGroup]; + }); +} + +- (FBLPromise *)setObject:(id)object + forKey:(NSString *)key + accessGroup:(nullable NSString *)accessGroup { + return [FBLPromise onQueue:self.inMemoryCacheQueue + do:^id _Nullable { + // Save to the in-memory cache first. + [self.inMemoryCache setObject:object forKey:[key copy]]; + return [NSNull null]; + }] + .thenOn(self.keychainQueue, ^id(id result) { + // Then store the object to the keychain. + NSDictionary *query = [self keychainQueryWithKey:key accessGroup:accessGroup]; + NSError *error; + NSData *encodedObject = [GULSecureCoding archivedDataWithRootObject:object error:&error]; + if (!encodedObject) { + return error; + } + + if (![GULKeychainUtils setItem:encodedObject withQuery:query error:&error]) { + return error; + } + + return [NSNull null]; + }); +} + +- (FBLPromise *)removeObjectForKey:(NSString *)key + accessGroup:(nullable NSString *)accessGroup { + return [FBLPromise onQueue:self.inMemoryCacheQueue + do:^id _Nullable { + [self.inMemoryCache removeObjectForKey:key]; + return nil; + }] + .thenOn(self.keychainQueue, ^id(id result) { + NSDictionary *query = [self keychainQueryWithKey:key accessGroup:accessGroup]; + + NSError *error; + if (![GULKeychainUtils removeItemWithQuery:query error:&error]) { + return error; + } + + return [NSNull null]; + }); +} + +#pragma mark - Private + +- (FBLPromise> *)getObjectFromKeychainForKey:(NSString *)key + objectClass:(Class)objectClass + accessGroup:(nullable NSString *)accessGroup { + // Look for the object in the keychain. + return [FBLPromise + onQueue:self.keychainQueue + do:^id { + NSDictionary *query = [self keychainQueryWithKey:key accessGroup:accessGroup]; + NSError *error; + NSData *encodedObject = [GULKeychainUtils getItemWithQuery:query error:&error]; + + if (error) { + return error; + } + if (!encodedObject) { + return nil; + } + id object = [GULSecureCoding unarchivedObjectOfClass:objectClass + fromData:encodedObject + error:&error]; + if (error) { + return error; + } + + return object; + }] + .thenOn(self.inMemoryCacheQueue, + ^id _Nullable(id _Nullable object) { + // Save object to the in-memory cache if exists and return the object. + if (object) { + [self.inMemoryCache setObject:object forKey:[key copy]]; + } + return object; + }); +} + +- (void)resetInMemoryCache { + [self.inMemoryCache removeAllObjects]; +} + +#pragma mark - Keychain + +- (NSMutableDictionary *)keychainQueryWithKey:(NSString *)key + accessGroup:(nullable NSString *)accessGroup { + NSMutableDictionary *query = [NSMutableDictionary dictionary]; + + query[(__bridge NSString *)kSecClass] = (__bridge NSString *)kSecClassGenericPassword; + query[(__bridge NSString *)kSecAttrService] = self.service; + query[(__bridge NSString *)kSecAttrAccount] = key; + + if (accessGroup) { + query[(__bridge NSString *)kSecAttrAccessGroup] = accessGroup; + } + + if (@available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, watchOS 6.0, *)) { + // Ensures that the keychain query behaves the same across all platforms. + // See go/firebase-macos-keychain-popups for details. + query[(__bridge id)kSecUseDataProtectionKeychain] = (__bridge id)kCFBooleanTrue; + } + +#if TARGET_OS_OSX + if (self.keychainRef) { + query[(__bridge NSString *)kSecUseKeychain] = (__bridge id)(self.keychainRef); + query[(__bridge NSString *)kSecMatchSearchList] = @[ (__bridge id)(self.keychainRef) ]; + } +#endif // TARGET_OS_OSX + + return query; +} + +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/Environment/SecureStorage/GULKeychainUtils.m b/Pods/GoogleUtilities/GoogleUtilities/Environment/SecureStorage/GULKeychainUtils.m new file mode 100644 index 0000000..57855a0 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Environment/SecureStorage/GULKeychainUtils.m @@ -0,0 +1,133 @@ +/* + * Copyright 2019 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 "GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainUtils.h" + +NSString *const kGULKeychainUtilsErrorDomain = @"com.gul.keychain.ErrorDomain"; + +@implementation GULKeychainUtils + ++ (nullable NSData *)getItemWithQuery:(NSDictionary *)query + error:(NSError *_Nullable *_Nullable)outError { + NSMutableDictionary *mutableGetItemQuery = + [[[self class] multiplatformQueryWithQuery:query] mutableCopy]; + + mutableGetItemQuery[(__bridge id)kSecReturnData] = @YES; + mutableGetItemQuery[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitOne; + + CFDataRef result = NULL; + OSStatus status = + SecItemCopyMatching((__bridge CFDictionaryRef)mutableGetItemQuery, (CFTypeRef *)&result); + + if (status == errSecSuccess && result != NULL) { + if (outError) { + *outError = nil; + } + + return (__bridge_transfer NSData *)result; + } + + if (status == errSecItemNotFound) { + if (outError) { + *outError = nil; + } + } else { + if (outError) { + *outError = [self keychainErrorWithFunction:@"SecItemCopyMatching" status:status]; + } + } + return nil; +} + ++ (BOOL)setItem:(NSData *)item + withQuery:(NSDictionary *)query + error:(NSError *_Nullable *_Nullable)outError { + NSDictionary *multiplatformQuery = [[self class] multiplatformQueryWithQuery:query]; + + NSData *existingItem = [self getItemWithQuery:multiplatformQuery error:outError]; + if (outError && *outError) { + return NO; + } + + OSStatus status; + if (!existingItem) { + NSMutableDictionary *mutableAddItemQuery = [multiplatformQuery mutableCopy]; + mutableAddItemQuery[(__bridge id)kSecAttrAccessible] = + (__bridge id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly; + mutableAddItemQuery[(__bridge id)kSecValueData] = item; + + status = SecItemAdd((__bridge CFDictionaryRef)mutableAddItemQuery, NULL); + } else { + NSDictionary *attributes = @{(__bridge id)kSecValueData : item}; + status = SecItemUpdate((__bridge CFDictionaryRef)multiplatformQuery, + (__bridge CFDictionaryRef)attributes); + } + + if (status == noErr) { + if (outError) { + *outError = nil; + } + return YES; + } + + NSString *function = existingItem ? @"SecItemUpdate" : @"SecItemAdd"; + if (outError) { + *outError = [self keychainErrorWithFunction:function status:status]; + } + return NO; +} + ++ (BOOL)removeItemWithQuery:(NSDictionary *)query error:(NSError *_Nullable *_Nullable)outError { + NSDictionary *deleteItemQuery = [[self class] multiplatformQueryWithQuery:query]; + + OSStatus status = SecItemDelete((__bridge CFDictionaryRef)deleteItemQuery); + + if (status == noErr || status == errSecItemNotFound) { + if (outError) { + *outError = nil; + } + return YES; + } + + if (outError) { + *outError = [self keychainErrorWithFunction:@"SecItemDelete" status:status]; + } + return NO; +} + +#pragma mark - Private + +/// Returns a `NSDictionary` query that behaves the same across all platforms. +/// - Note: In practice, this API only makes a difference to keychain queries on macOS. +/// See go/firebase-macos-keychain-popups for details. +/// - Parameter query: A query to create the protected keychain query with. ++ (NSDictionary *)multiplatformQueryWithQuery:(NSDictionary *)query { + NSMutableDictionary *multiplatformQuery = [query mutableCopy]; + if (@available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, watchOS 6.0, *)) { + multiplatformQuery[(__bridge id)kSecUseDataProtectionKeychain] = (__bridge id)kCFBooleanTrue; + } + return [multiplatformQuery copy]; +} + +#pragma mark - Errors + ++ (NSError *)keychainErrorWithFunction:(NSString *)keychainFunction status:(OSStatus)status { + NSString *failureReason = [NSString stringWithFormat:@"%@ (%li)", keychainFunction, (long)status]; + NSDictionary *userInfo = @{NSLocalizedFailureReasonErrorKey : failureReason}; + return [NSError errorWithDomain:kGULKeychainUtilsErrorDomain code:0 userInfo:userInfo]; +} + +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/Environment/URLSessionPromiseWrapper/GULURLSessionDataResponse.m b/Pods/GoogleUtilities/GoogleUtilities/Environment/URLSessionPromiseWrapper/GULURLSessionDataResponse.m new file mode 100644 index 0000000..559875a --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Environment/URLSessionPromiseWrapper/GULURLSessionDataResponse.m @@ -0,0 +1,30 @@ +/* + * Copyright 2020 Google LLC + * + * 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 "GoogleUtilities/Environment/Public/GoogleUtilities/GULURLSessionDataResponse.h" + +@implementation GULURLSessionDataResponse + +- (instancetype)initWithResponse:(NSHTTPURLResponse *)response HTTPBody:(NSData *)body { + self = [super init]; + if (self) { + _HTTPResponse = response; + _HTTPBody = body; + } + return self; +} + +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/Environment/URLSessionPromiseWrapper/NSURLSession+GULPromises.m b/Pods/GoogleUtilities/GoogleUtilities/Environment/URLSessionPromiseWrapper/NSURLSession+GULPromises.m new file mode 100644 index 0000000..6c70310 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Environment/URLSessionPromiseWrapper/NSURLSession+GULPromises.m @@ -0,0 +1,46 @@ +/* + * Copyright 2020 Google LLC + * + * 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 "GoogleUtilities/Environment/Public/GoogleUtilities/NSURLSession+GULPromises.h" + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULURLSessionDataResponse.h" + +@implementation NSURLSession (GULPromises) + +- (FBLPromise *)gul_dataTaskPromiseWithRequest: + (NSURLRequest *)URLRequest { + return [FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + [[self dataTaskWithRequest:URLRequest + completionHandler:^(NSData *_Nullable data, NSURLResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + reject(error); + } else { + fulfill([[GULURLSessionDataResponse alloc] + initWithResponse:(NSHTTPURLResponse *)response + HTTPBody:data]); + } + }] resume]; + }]; +} + +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/Environment/third_party/GULAppEnvironmentUtil.m b/Pods/GoogleUtilities/GoogleUtilities/Environment/third_party/GULAppEnvironmentUtil.m new file mode 100644 index 0000000..84d4f5c --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Environment/third_party/GULAppEnvironmentUtil.m @@ -0,0 +1,392 @@ +// 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 "GoogleUtilities/Environment/Public/GoogleUtilities/GULAppEnvironmentUtil.h" + +#import +#import +#import +#import +#import +#import + +#if TARGET_OS_IOS +#import +#endif + +/// The encryption info struct and constants are missing from the iPhoneSimulator SDK, but not from +/// the iPhoneOS or Mac OS X SDKs. Since one doesn't ever ship a Simulator binary, we'll just +/// provide the definitions here. +#if TARGET_OS_SIMULATOR && !defined(LC_ENCRYPTION_INFO) +#define LC_ENCRYPTION_INFO 0x21 +struct encryption_info_command { + uint32_t cmd; + uint32_t cmdsize; + uint32_t cryptoff; + uint32_t cryptsize; + uint32_t cryptid; +}; +#endif + +@implementation GULAppEnvironmentUtil + +/// A key for the Info.plist to enable or disable checking if the App Store is running in a sandbox. +/// This will affect your data integrity when using Firebase Analytics, as it will disable some +/// necessary checks. +static NSString *const kFIRAppStoreReceiptURLCheckEnabledKey = + @"FirebaseAppStoreReceiptURLCheckEnabled"; + +/// The file name of the sandbox receipt. This is available on iOS >= 8.0 +static NSString *const kFIRAIdentitySandboxReceiptFileName = @"sandboxReceipt"; + +/// The following copyright from Landon J. Fuller applies to the isAppEncrypted function. +/// +/// Copyright (c) 2017 Landon J. Fuller +/// All rights reserved. +/// +/// Permission is hereby granted, free of charge, to any person obtaining a copy of this software +/// and associated documentation files (the "Software"), to deal in the Software without +/// restriction, including without limitation the rights to use, copy, modify, merge, publish, +/// distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in all copies or +/// substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +/// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +/// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +/// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +/// +/// Comment from iPhone Dev Wiki +/// Crack Prevention: +/// App Store binaries are signed by both their developer and Apple. This encrypts the binary so +/// that decryption keys are needed in order to make the binary readable. When iOS executes the +/// binary, the decryption keys are used to decrypt the binary into a readable state where it is +/// then loaded into memory and executed. iOS can tell the encryption status of a binary via the +/// cryptid structure member of LC_ENCRYPTION_INFO MachO load command. If cryptid is a non-zero +/// value then the binary is encrypted. +/// +/// 'Cracking' works by letting the kernel decrypt the binary then siphoning the decrypted data into +/// a new binary file, resigning, and repackaging. This will only work on jailbroken devices as +/// codesignature validation has been removed. Resigning takes place because while the codesignature +/// doesn't have to be valid thanks to the jailbreak, it does have to be in place unless you have +/// AppSync or similar to disable codesignature checks. +/// +/// More information at Landon Fuller's blog +static BOOL IsAppEncrypted(void) { + const struct mach_header *executableHeader = NULL; + for (uint32_t i = 0; i < _dyld_image_count(); i++) { + const struct mach_header *header = _dyld_get_image_header(i); + if (header && header->filetype == MH_EXECUTE) { + executableHeader = header; + break; + } + } + + if (!executableHeader) { + return NO; + } + + BOOL is64bit = (executableHeader->magic == MH_MAGIC_64); + uintptr_t cursor = (uintptr_t)executableHeader + + (is64bit ? sizeof(struct mach_header_64) : sizeof(struct mach_header)); + const struct segment_command *segmentCommand = NULL; + uint32_t i = 0; + + while (i++ < executableHeader->ncmds) { + segmentCommand = (struct segment_command *)cursor; + + if (!segmentCommand) { + continue; + } + + if ((!is64bit && segmentCommand->cmd == LC_ENCRYPTION_INFO) || + (is64bit && segmentCommand->cmd == LC_ENCRYPTION_INFO_64)) { + if (is64bit) { + struct encryption_info_command_64 *cryptCmd = + (struct encryption_info_command_64 *)segmentCommand; + return cryptCmd && cryptCmd->cryptid != 0; + } else { + struct encryption_info_command *cryptCmd = (struct encryption_info_command *)segmentCommand; + return cryptCmd && cryptCmd->cryptid != 0; + } + } + cursor += segmentCommand->cmdsize; + } + + return NO; +} + +static BOOL HasSCInfoFolder(void) { +#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH + NSString *bundlePath = [NSBundle mainBundle].bundlePath; + NSString *scInfoPath = [bundlePath stringByAppendingPathComponent:@"SC_Info"]; + return [[NSFileManager defaultManager] fileExistsAtPath:scInfoPath]; +#elif TARGET_OS_OSX + return NO; +#endif +} + +static BOOL HasEmbeddedMobileProvision(void) { +#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH + return [[NSBundle mainBundle] pathForResource:@"embedded" ofType:@"mobileprovision"].length > 0; +#elif TARGET_OS_OSX + return NO; +#endif +} + ++ (BOOL)isFromAppStore { + static dispatch_once_t isEncryptedOnce; + static BOOL isEncrypted = NO; + + dispatch_once(&isEncryptedOnce, ^{ + isEncrypted = IsAppEncrypted(); + }); + + if ([GULAppEnvironmentUtil isSimulator]) { + return NO; + } + + // If an app contain the sandboxReceipt file, it means its coming from TestFlight + // This must be checked before the SCInfo Folder check below since TestFlight apps may + // also have an SCInfo folder. + if ([GULAppEnvironmentUtil isAppStoreReceiptSandbox]) { + return NO; + } + + if (HasSCInfoFolder()) { + // When iTunes downloads a .ipa, it also gets a customized .sinf file which is added to the + // main SC_Info directory. + return YES; + } + + // For iOS >= 8.0, iTunesMetadata.plist is moved outside of the sandbox. Any attempt to read + // the iTunesMetadata.plist outside of the sandbox will be rejected by Apple. + // If the app does not contain the embedded.mobileprovision which is stripped out by Apple when + // the app is submitted to store, then it is highly likely that it is from Apple Store. + return isEncrypted && !HasEmbeddedMobileProvision(); +} + ++ (BOOL)isAppStoreReceiptSandbox { + // Since checking the App Store's receipt URL can be memory intensive, check the option in the + // Info.plist if developers opted out of this check. + id enableSandboxCheck = + [[NSBundle mainBundle] objectForInfoDictionaryKey:kFIRAppStoreReceiptURLCheckEnabledKey]; + if (enableSandboxCheck && [enableSandboxCheck isKindOfClass:[NSNumber class]] && + ![enableSandboxCheck boolValue]) { + return NO; + } + + NSURL *appStoreReceiptURL = [NSBundle mainBundle].appStoreReceiptURL; + NSString *appStoreReceiptFileName = appStoreReceiptURL.lastPathComponent; + return [appStoreReceiptFileName isEqualToString:kFIRAIdentitySandboxReceiptFileName]; +} + ++ (BOOL)isSimulator { +#if TARGET_OS_SIMULATOR + return YES; +#elif TARGET_OS_MACCATALYST + return NO; +#elif TARGET_OS_IOS || TARGET_OS_TV + NSString *platform = [GULAppEnvironmentUtil deviceModel]; + return [platform isEqual:@"x86_64"] || [platform isEqual:@"i386"]; +#elif TARGET_OS_OSX + return NO; +#endif + return NO; +} + ++ (NSString *)getSysctlEntry:(const char *)sysctlKey { + static NSString *entryValue; + size_t size; + sysctlbyname(sysctlKey, NULL, &size, NULL, 0); + if (size > 0) { + char *entryValueCStr = malloc(size); + sysctlbyname(sysctlKey, entryValueCStr, &size, NULL, 0); + entryValue = [NSString stringWithCString:entryValueCStr encoding:NSUTF8StringEncoding]; + free(entryValueCStr); + return entryValue; + } else { + return nil; + } +} + ++ (NSString *)deviceModel { + static dispatch_once_t once; + static NSString *deviceModel; + +#if TARGET_OS_OSX || TARGET_OS_MACCATALYST + dispatch_once(&once, ^{ + // The `uname` function only returns x86_64 for Macs. Use `sysctlbyname` instead, but fall back + // to the `uname` function if it fails. + deviceModel = [GULAppEnvironmentUtil getSysctlEntry:"hw.model"]; + if (deviceModel.length == 0) { + struct utsname systemInfo; + if (uname(&systemInfo) == 0) { + deviceModel = [NSString stringWithUTF8String:systemInfo.machine]; + } + } + }); +#else + dispatch_once(&once, ^{ + struct utsname systemInfo; + if (uname(&systemInfo) == 0) { + deviceModel = [NSString stringWithUTF8String:systemInfo.machine]; + } + }); +#endif // TARGET_OS_OSX || TARGET_OS_MACCATALYST + return deviceModel; +} + ++ (NSString *)deviceSimulatorModel { + static dispatch_once_t once; + static NSString *model = nil; + + dispatch_once(&once, ^{ +#if TARGET_OS_SIMULATOR +#if TARGET_OS_WATCH + model = @"watchOS Simulator"; +#elif TARGET_OS_TV + model = @"tvOS Simulator"; +#elif TARGET_OS_IPHONE + switch ([[UIDevice currentDevice] userInterfaceIdiom]) { + case UIUserInterfaceIdiomPhone: + model = @"iOS Simulator (iPhone)"; + break; + case UIUserInterfaceIdiomPad: + model = @"iOS Simulator (iPad)"; + break; + default: + model = @"iOS Simulator (Unknown)"; + break; + } +#endif +#elif TARGET_OS_EMBEDDED + model = [GULAppEnvironmentUtil getSysctlEntry:"hw.machine"]; +#else + model = [GULAppEnvironmentUtil getSysctlEntry:"hw.model"]; +#endif + }); + + return model; +} + ++ (NSString *)systemVersion { +#if TARGET_OS_IOS + return [UIDevice currentDevice].systemVersion; +#elif TARGET_OS_OSX || TARGET_OS_TV || TARGET_OS_WATCH + // Assemble the systemVersion, excluding the patch version if it's 0. + NSOperatingSystemVersion osVersion = [NSProcessInfo processInfo].operatingSystemVersion; + NSMutableString *versionString = [[NSMutableString alloc] + initWithFormat:@"%ld.%ld", (long)osVersion.majorVersion, (long)osVersion.minorVersion]; + if (osVersion.patchVersion != 0) { + [versionString appendFormat:@".%ld", (long)osVersion.patchVersion]; + } + return versionString; +#endif +} + ++ (BOOL)isAppExtension { +#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH + // Documented by Apple + BOOL appExtension = [[[NSBundle mainBundle] bundlePath] hasSuffix:@".appex"]; + return appExtension; +#elif TARGET_OS_OSX + return NO; +#endif +} + ++ (BOOL)isIOS7OrHigher { + return YES; +} + ++ (BOOL)hasSwiftRuntime { + // The class + // [Swift._SwiftObject](https://github.com/apple/swift/blob/5eac3e2818eb340b11232aff83edfbd1c307fa03/stdlib/public/runtime/SwiftObject.h#L35) + // is a part of Swift runtime, so it should be present if Swift runtime is available. + + BOOL hasSwiftRuntime = + objc_lookUpClass("Swift._SwiftObject") != nil || + // Swift object class name before + // https://github.com/apple/swift/commit/9637b4a6e11ddca72f5f6dbe528efc7c92f14d01 + objc_getClass("_TtCs12_SwiftObject") != nil; + + return hasSwiftRuntime; +} + ++ (NSString *)applePlatform { + NSString *applePlatform = @"unknown"; + + // When a Catalyst app is run on macOS then both `TARGET_OS_MACCATALYST` and `TARGET_OS_IOS` are + // `true`, which means the condition list is order-sensitive. +#if TARGET_OS_MACCATALYST + applePlatform = @"maccatalyst"; +#elif TARGET_OS_IOS +#if defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000 + if (@available(iOS 14.0, *)) { + // Early iOS 14 betas do not include isiOSAppOnMac (#6969) + applePlatform = ([[NSProcessInfo processInfo] respondsToSelector:@selector(isiOSAppOnMac)] && + [NSProcessInfo processInfo].isiOSAppOnMac) ? @"ios_on_mac" : @"ios"; + } else { + applePlatform = @"ios"; + } +#else // defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000 + applePlatform = @"ios"; +#endif // defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000 + +#elif TARGET_OS_TV + applePlatform = @"tvos"; +#elif TARGET_OS_OSX + applePlatform = @"macos"; +#elif TARGET_OS_WATCH + applePlatform = @"watchos"; +#endif // TARGET_OS_MACCATALYST + + return applePlatform; +} + ++ (NSString *)appleDevicePlatform { + NSString* firebasePlatform = [GULAppEnvironmentUtil applePlatform]; +#if TARGET_OS_IOS + // This check is necessary because iOS-only apps running on iPad + // will report UIUserInterfaceIdiomPhone via UI_USER_INTERFACE_IDIOM(). + if ([firebasePlatform isEqualToString:@"ios"] && + ([[UIDevice currentDevice].model.lowercaseString containsString:@"ipad"] || + [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)) { + return @"ipados"; + } +#endif + + return firebasePlatform; +} + ++ (NSString *)deploymentType { +#if SWIFT_PACKAGE + NSString *deploymentType = @"swiftpm"; +#elif FIREBASE_BUILD_CARTHAGE + NSString *deploymentType = @"carthage"; +#elif FIREBASE_BUILD_ZIP_FILE + NSString *deploymentType = @"zip"; +#elif COCOAPODS + NSString *deploymentType = @"cocoapods"; +#else + NSString *deploymentType = @"unknown"; +#endif + + return deploymentType; +} + +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/Logger/GULLogger.m b/Pods/GoogleUtilities/GoogleUtilities/Logger/GULLogger.m new file mode 100644 index 0000000..df2a937 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Logger/GULLogger.m @@ -0,0 +1,214 @@ +// 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. + +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" + +#include + +#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULAppEnvironmentUtil.h" +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLoggerLevel.h" + +/// ASL client facility name used by GULLogger. +const char *kGULLoggerASLClientFacilityName = "com.google.utilities.logger"; + +static dispatch_once_t sGULLoggerOnceToken; + +static aslclient sGULLoggerClient; + +static dispatch_queue_t sGULClientQueue; + +static BOOL sGULLoggerDebugMode; + +static GULLoggerLevel sGULLoggerMaximumLevel; + +// Allow clients to register a version to include in the log. +static NSString *sVersion = @""; + +static GULLoggerService kGULLoggerLogger = @"[GULLogger]"; + +#ifdef DEBUG +/// The regex pattern for the message code. +static NSString *const kMessageCodePattern = @"^I-[A-Z]{3}[0-9]{6}$"; +static NSRegularExpression *sMessageCodeRegex; +#endif + +void GULLoggerInitializeASL(void) { + dispatch_once(&sGULLoggerOnceToken, ^{ + NSInteger majorOSVersion = [[GULAppEnvironmentUtil systemVersion] integerValue]; + uint32_t aslOptions = ASL_OPT_STDERR; +#if TARGET_OS_SIMULATOR + // The iOS 11 simulator doesn't need the ASL_OPT_STDERR flag. + if (majorOSVersion >= 11) { + aslOptions = 0; + } +#else + // Devices running iOS 10 or higher don't need the ASL_OPT_STDERR flag. + if (majorOSVersion >= 10) { + aslOptions = 0; + } +#endif // TARGET_OS_SIMULATOR + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" // asl is deprecated + // Initialize the ASL client handle. + sGULLoggerClient = asl_open(NULL, kGULLoggerASLClientFacilityName, aslOptions); + sGULLoggerMaximumLevel = GULLoggerLevelNotice; + + // Set the filter used by system/device log. Initialize in default mode. + asl_set_filter(sGULLoggerClient, ASL_FILTER_MASK_UPTO(ASL_LEVEL_NOTICE)); + + sGULClientQueue = dispatch_queue_create("GULLoggingClientQueue", DISPATCH_QUEUE_SERIAL); + dispatch_set_target_queue(sGULClientQueue, + dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)); +#ifdef DEBUG + sMessageCodeRegex = [NSRegularExpression regularExpressionWithPattern:kMessageCodePattern + options:0 + error:NULL]; +#endif + }); +} + +void GULLoggerEnableSTDERR(void) { + asl_add_log_file(sGULLoggerClient, STDERR_FILENO); +} + +void GULLoggerForceDebug(void) { + // We should enable debug mode if we're not running from App Store. + if (![GULAppEnvironmentUtil isFromAppStore]) { + sGULLoggerDebugMode = YES; + GULSetLoggerLevel(GULLoggerLevelDebug); + } +} + +__attribute__((no_sanitize("thread"))) void GULSetLoggerLevel(GULLoggerLevel loggerLevel) { + if (loggerLevel < GULLoggerLevelMin || loggerLevel > GULLoggerLevelMax) { + GULLogError(kGULLoggerLogger, NO, @"I-COR000023", @"Invalid logger level, %ld", + (long)loggerLevel); + return; + } + GULLoggerInitializeASL(); + // We should not raise the logger level if we are running from App Store. + if (loggerLevel >= GULLoggerLevelNotice && [GULAppEnvironmentUtil isFromAppStore]) { + return; + } + + sGULLoggerMaximumLevel = loggerLevel; + dispatch_async(sGULClientQueue, ^{ + asl_set_filter(sGULLoggerClient, ASL_FILTER_MASK_UPTO(loggerLevel)); + }); +} + +/** + * Check if the level is high enough to be loggable. + */ +__attribute__((no_sanitize("thread"))) BOOL GULIsLoggableLevel(GULLoggerLevel loggerLevel) { + GULLoggerInitializeASL(); + if (sGULLoggerDebugMode) { + return YES; + } + return (BOOL)(loggerLevel <= sGULLoggerMaximumLevel); +} + +#ifdef DEBUG +void GULResetLogger(void) { + sGULLoggerOnceToken = 0; + sGULLoggerDebugMode = NO; +} + +aslclient getGULLoggerClient(void) { + return sGULLoggerClient; +} + +dispatch_queue_t getGULClientQueue(void) { + return sGULClientQueue; +} + +BOOL getGULLoggerDebugMode(void) { + return sGULLoggerDebugMode; +} +#endif + +void GULLoggerRegisterVersion(NSString *version) { + sVersion = version; +} + +void GULLogBasic(GULLoggerLevel level, + GULLoggerService service, + BOOL forceLog, + NSString *messageCode, + NSString *message, + va_list args_ptr) { + GULLoggerInitializeASL(); + if (!(level <= sGULLoggerMaximumLevel || sGULLoggerDebugMode || forceLog)) { + return; + } + +#ifdef DEBUG + NSCAssert(messageCode.length == 11, @"Incorrect message code length."); + NSRange messageCodeRange = NSMakeRange(0, messageCode.length); + NSUInteger __unused numberOfMatches = + [sMessageCodeRegex numberOfMatchesInString:messageCode options:0 range:messageCodeRange]; + NSCAssert(numberOfMatches == 1, @"Incorrect message code format."); +#endif + NSString *logMsg; + if (args_ptr == NULL) { + logMsg = message; + } else { + logMsg = [[NSString alloc] initWithFormat:message arguments:args_ptr]; + } + logMsg = [NSString stringWithFormat:@"%@ - %@[%@] %@", sVersion, service, messageCode, logMsg]; + dispatch_async(sGULClientQueue, ^{ + asl_log(sGULLoggerClient, NULL, (int)level, "%s", logMsg.UTF8String); + }); +} +#pragma clang diagnostic pop + +/** + * Generates the logging functions using macros. + * + * Calling GULLogError({service}, @"I-XYZ000001", @"Configure %@ failed.", @"blah") shows: + * yyyy-mm-dd hh:mm:ss.SSS sender[PID] [{service}][I-XYZ000001] Configure blah failed. + * Calling GULLogDebug({service}, @"I-XYZ000001", @"Configure succeed.") shows: + * yyyy-mm-dd hh:mm:ss.SSS sender[PID] [{service}][I-XYZ000001] Configure succeed. + */ +#define GUL_LOGGING_FUNCTION(level) \ + void GULLog##level(GULLoggerService service, BOOL force, NSString *messageCode, \ + NSString *message, ...) { \ + va_list args_ptr; \ + va_start(args_ptr, message); \ + GULLogBasic(GULLoggerLevel##level, service, force, messageCode, message, args_ptr); \ + va_end(args_ptr); \ + } + +GUL_LOGGING_FUNCTION(Error) +GUL_LOGGING_FUNCTION(Warning) +GUL_LOGGING_FUNCTION(Notice) +GUL_LOGGING_FUNCTION(Info) +GUL_LOGGING_FUNCTION(Debug) + +#undef GUL_MAKE_LOGGER + +#pragma mark - GULLoggerWrapper + +@implementation GULLoggerWrapper + ++ (void)logWithLevel:(GULLoggerLevel)level + withService:(GULLoggerService)service + withCode:(NSString *)messageCode + withMessage:(NSString *)message + withArgs:(va_list)args { + GULLogBasic(level, service, NO, messageCode, message, args); +} + +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h b/Pods/GoogleUtilities/GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h new file mode 100644 index 0000000..6797399 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h @@ -0,0 +1,159 @@ +/* + * 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. + */ + +#import + +#import "GULLoggerLevel.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * The services used in the logger. + */ +typedef NSString *const GULLoggerService; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** + * Initialize GULLogger. + */ +extern void GULLoggerInitializeASL(void); + +/** + * Override log level to Debug. + */ +void GULLoggerForceDebug(void); + +/** + * Turn on logging to STDERR. + */ +extern void GULLoggerEnableSTDERR(void); + +/** + * Changes the default logging level of GULLoggerLevelNotice to a user-specified level. + * The default level cannot be set above GULLoggerLevelNotice if the app is running from App Store. + * (required) log level (one of the GULLoggerLevel enum values). + */ +extern void GULSetLoggerLevel(GULLoggerLevel loggerLevel); + +/** + * Checks if the specified logger level is loggable given the current settings. + * (required) log level (one of the GULLoggerLevel enum values). + */ +extern BOOL GULIsLoggableLevel(GULLoggerLevel loggerLevel); + +/** + * Register version to include in logs. + * (required) version + */ +extern void GULLoggerRegisterVersion(NSString *version); + +/** + * Logs a message to the Xcode console and the device log. If running from AppStore, will + * not log any messages with a level higher than GULLoggerLevelNotice to avoid log spamming. + * (required) log level (one of the GULLoggerLevel enum values). + * (required) service name of type GULLoggerService. + * (required) message code starting with "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique + * within the service. + * An example of the message code is @"I-COR000001". + * (required) message string which can be a format string. + * (optional) variable arguments list obtained from calling va_start, used when message is a format + * string. + */ +extern void GULLogBasic(GULLoggerLevel level, + GULLoggerService service, + BOOL forceLog, + NSString *messageCode, + NSString *message, +// On 64-bit simulators, va_list is not a pointer, so cannot be marked nullable +// See: http://stackoverflow.com/q/29095469 +#if __LP64__ && TARGET_OS_SIMULATOR || TARGET_OS_OSX + va_list args_ptr +#else + va_list _Nullable args_ptr +#endif +); + +/** + * The following functions accept the following parameters in order: + * (required) service name of type GULLoggerService. + * (required) message code starting from "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique + * within the service. + * An example of the message code is @"I-COR000001". + * See go/firebase-log-proposal for details. + * (required) message string which can be a format string. + * (optional) the list of arguments to substitute into the format string. + * Example usage: + * GULLogError(kGULLoggerCore, @"I-COR000001", @"Configuration of %@ failed.", app.name); + */ +extern void GULLogError(GULLoggerService service, + BOOL force, + NSString *messageCode, + NSString *message, + ...) NS_FORMAT_FUNCTION(4, 5); +extern void GULLogWarning(GULLoggerService service, + BOOL force, + NSString *messageCode, + NSString *message, + ...) NS_FORMAT_FUNCTION(4, 5); +extern void GULLogNotice(GULLoggerService service, + BOOL force, + NSString *messageCode, + NSString *message, + ...) NS_FORMAT_FUNCTION(4, 5); +extern void GULLogInfo(GULLoggerService service, + BOOL force, + NSString *messageCode, + NSString *message, + ...) NS_FORMAT_FUNCTION(4, 5); +extern void GULLogDebug(GULLoggerService service, + BOOL force, + NSString *messageCode, + NSString *message, + ...) NS_FORMAT_FUNCTION(4, 5); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +@interface GULLoggerWrapper : NSObject + +/** + * Objective-C wrapper for GULLogBasic to allow weak linking to GULLogger + * (required) log level (one of the GULLoggerLevel enum values). + * (required) service name of type GULLoggerService. + * (required) message code starting with "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique + * within the service. + * An example of the message code is @"I-COR000001". + * (required) message string which can be a format string. + * (optional) variable arguments list obtained from calling va_start, used when message is a format + * string. + */ + ++ (void)logWithLevel:(GULLoggerLevel)level + withService:(GULLoggerService)service + withCode:(NSString *)messageCode + withMessage:(NSString *)message + withArgs:(va_list)args; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleUtilities/GoogleUtilities/Logger/Public/GoogleUtilities/GULLoggerLevel.h b/Pods/GoogleUtilities/GoogleUtilities/Logger/Public/GoogleUtilities/GULLoggerLevel.h new file mode 100644 index 0000000..f0ee435 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Logger/Public/GoogleUtilities/GULLoggerLevel.h @@ -0,0 +1,37 @@ +/* + * 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. + */ + +#import + +/** + * The log levels used by internal logging. + */ +typedef NS_ENUM(NSInteger, GULLoggerLevel) { + /** Error level, matches ASL_LEVEL_ERR. */ + GULLoggerLevelError = 3, + /** Warning level, matches ASL_LEVEL_WARNING. */ + GULLoggerLevelWarning = 4, + /** Notice level, matches ASL_LEVEL_NOTICE. */ + GULLoggerLevelNotice = 5, + /** Info level, matches ASL_LEVEL_INFO. */ + GULLoggerLevelInfo = 6, + /** Debug level, matches ASL_LEVEL_DEBUG. */ + GULLoggerLevelDebug = 7, + /** Minimum log level. */ + GULLoggerLevelMin = GULLoggerLevelError, + /** Maximum log level. */ + GULLoggerLevelMax = GULLoggerLevelDebug +} NS_SWIFT_NAME(GoogleLoggerLevel); diff --git a/Pods/GoogleUtilities/GoogleUtilities/MethodSwizzler/GULSwizzler.m b/Pods/GoogleUtilities/GoogleUtilities/MethodSwizzler/GULSwizzler.m new file mode 100644 index 0000000..7f0c82e --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/MethodSwizzler/GULSwizzler.m @@ -0,0 +1,153 @@ +// Copyright 2018 Google LLC +// +// 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 "GoogleUtilities/MethodSwizzler/Public/GoogleUtilities/GULSwizzler.h" + +#import + +#ifdef DEBUG +#import "GoogleUtilities/Common/GULLoggerCodes.h" +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" + +static GULLoggerService kGULLoggerSwizzler = @"[GoogleUtilities/MethodSwizzler]"; +#endif + +dispatch_queue_t GetGULSwizzlingQueue(void) { + static dispatch_queue_t queue; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + queue = dispatch_queue_create("com.google.GULSwizzler", DISPATCH_QUEUE_SERIAL); + }); + return queue; +} + +@implementation GULSwizzler + ++ (void)swizzleClass:(Class)aClass + selector:(SEL)selector + isClassSelector:(BOOL)isClassSelector + withBlock:(nullable id)block { + dispatch_sync(GetGULSwizzlingQueue(), ^{ + NSAssert(selector, @"The selector cannot be NULL"); + NSAssert(aClass, @"The class cannot be Nil"); + Class resolvedClass = aClass; + Method method = nil; + if (isClassSelector) { + method = class_getClassMethod(aClass, selector); + resolvedClass = object_getClass(aClass); + } else { + method = class_getInstanceMethod(aClass, selector); + } + NSAssert(method, @"You're attempting to swizzle a method that doesn't exist. (%@, %@)", + NSStringFromClass(resolvedClass), NSStringFromSelector(selector)); + IMP newImp = imp_implementationWithBlock(block); +#ifdef DEBUG + IMP currentImp = class_getMethodImplementation(resolvedClass, selector); + Class class = NSClassFromString(@"GULSwizzlingCache"); + if (class) { + SEL cacheSelector = NSSelectorFromString(@"cacheCurrentIMP:forNewIMP:forClass:withSelector:"); + NSMethodSignature *methodSignature = [class methodSignatureForSelector:cacheSelector]; + if (methodSignature != nil) { + NSInvocation *inv = [NSInvocation invocationWithMethodSignature:methodSignature]; + [inv setSelector:cacheSelector]; + [inv setTarget:class]; + [inv setArgument:&(currentImp) atIndex:2]; + [inv setArgument:&(newImp) atIndex:3]; + [inv setArgument:&(resolvedClass) atIndex:4]; + [inv setArgument:(void *_Nonnull)&(selector) atIndex:5]; + [inv invoke]; + } + } +#endif + + const char *typeEncoding = method_getTypeEncoding(method); + __unused IMP originalImpOfClass = + class_replaceMethod(resolvedClass, selector, newImp, typeEncoding); + +#ifdef DEBUG + // If !originalImpOfClass, then the IMP came from a superclass. + if (originalImpOfClass) { + SEL selector = NSSelectorFromString(@"originalIMPOfCurrentIMP:"); + NSMethodSignature *methodSignature = [class methodSignatureForSelector:selector]; + if (methodSignature != nil) { + NSInvocation *inv = [NSInvocation invocationWithMethodSignature:methodSignature]; + [inv setSelector:selector]; + [inv setTarget:class]; + [inv setArgument:&(currentImp) atIndex:2]; + [inv invoke]; + IMP testOriginal; + [inv getReturnValue:&testOriginal]; + if (originalImpOfClass != testOriginal) { + GULLogWarning(kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeMethodSwizzling000], + @"Swizzling class: %@ SEL:%@ after it has been previously been swizzled.", + NSStringFromClass(resolvedClass), NSStringFromSelector(selector)); + } + } + } +#endif + }); +} + ++ (nullable IMP)currentImplementationForClass:(Class)aClass + selector:(SEL)selector + isClassSelector:(BOOL)isClassSelector { + NSAssert(selector, @"The selector cannot be NULL"); + NSAssert(aClass, @"The class cannot be Nil"); + if (selector == NULL || aClass == nil) { + return nil; + } + __block IMP currentIMP = nil; + dispatch_sync(GetGULSwizzlingQueue(), ^{ + Method method = nil; + if (isClassSelector) { + method = class_getClassMethod(aClass, selector); + } else { + method = class_getInstanceMethod(aClass, selector); + } + NSAssert(method, @"The Method for this class/selector combo doesn't exist (%@, %@).", + NSStringFromClass(aClass), NSStringFromSelector(selector)); + if (method == nil) { + return; + } + currentIMP = method_getImplementation(method); + NSAssert(currentIMP, @"The IMP for this class/selector combo doesn't exist (%@, %@).", + NSStringFromClass(aClass), NSStringFromSelector(selector)); + }); + return currentIMP; +} + ++ (BOOL)selector:(SEL)selector existsInClass:(Class)aClass isClassSelector:(BOOL)isClassSelector { + Method method = isClassSelector ? class_getClassMethod(aClass, selector) + : class_getInstanceMethod(aClass, selector); + return method != nil; +} + ++ (NSArray *)ivarObjectsForObject:(id)object { + NSMutableArray *array = [NSMutableArray array]; + unsigned int count; + Ivar *vars = class_copyIvarList([object class], &count); + for (NSUInteger i = 0; i < count; i++) { + const char *typeEncoding = ivar_getTypeEncoding(vars[i]); + // Check to see if the ivar is an object. + if (strncmp(typeEncoding, "@", 1) == 0) { + id ivarObject = object_getIvar(object, vars[i]); + [array addObject:ivarObject]; + } + } + free(vars); + return array; +} +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/MethodSwizzler/Public/GoogleUtilities/GULOriginalIMPConvenienceMacros.h b/Pods/GoogleUtilities/GoogleUtilities/MethodSwizzler/Public/GoogleUtilities/GULOriginalIMPConvenienceMacros.h new file mode 100644 index 0000000..a33262a --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/MethodSwizzler/Public/GoogleUtilities/GULOriginalIMPConvenienceMacros.h @@ -0,0 +1,207 @@ +/* + * Copyright 2018 Google LLC + * + * 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. + */ + +/** + * GULOriginalIMPConvenienceMacros.h + * + * This header contains convenience macros for invoking the original IMP of a swizzled method. + */ + +/** + * Invokes original IMP when the original selector takes no arguments. + * + * @param __receivingObject The object on which the IMP is invoked. + * @param __swizzledSEL The selector used for swizzling. + * @param __returnType The return type of the original implementation. + * @param __originalIMP The original IMP. + */ +#define GUL_INVOKE_ORIGINAL_IMP0(__receivingObject, __swizzledSEL, __returnType, __originalIMP) \ + ((__returnType(*)(id, SEL))__originalIMP)(__receivingObject, __swizzledSEL) + +/** + * Invokes original IMP when the original selector takes 1 argument. + * + * @param __receivingObject The object on which the IMP is invoked. + * @param __swizzledSEL The selector used for swizzling. + * @param __returnType The return type of the original implementation. + * @param __originalIMP The original IMP. + * @param __arg1 The first argument. + */ +#define GUL_INVOKE_ORIGINAL_IMP1(__receivingObject, __swizzledSEL, __returnType, __originalIMP, \ + __arg1) \ + ((__returnType(*)(id, SEL, __typeof__(__arg1)))__originalIMP)(__receivingObject, __swizzledSEL, \ + __arg1) + +/** + * Invokes original IMP when the original selector takes 2 arguments. + * + * @param __receivingObject The object on which the IMP is invoked. + * @param __swizzledSEL The selector used for swizzling. + * @param __returnType The return type of the original implementation. + * @param __originalIMP The original IMP. + * @param __arg1 The first argument. + * @param __arg2 The second argument. + */ +#define GUL_INVOKE_ORIGINAL_IMP2(__receivingObject, __swizzledSEL, __returnType, __originalIMP, \ + __arg1, __arg2) \ + ((__returnType(*)(id, SEL, __typeof__(__arg1), __typeof__(__arg2)))__originalIMP)( \ + __receivingObject, __swizzledSEL, __arg1, __arg2) + +/** + * Invokes original IMP when the original selector takes 3 arguments. + * + * @param __receivingObject The object on which the IMP is invoked. + * @param __swizzledSEL The selector used for swizzling. + * @param __returnType The return type of the original implementation. + * @param __originalIMP The original IMP. + * @param __arg1 The first argument. + * @param __arg2 The second argument. + * @param __arg3 The third argument. + */ +#define GUL_INVOKE_ORIGINAL_IMP3(__receivingObject, __swizzledSEL, __returnType, __originalIMP, \ + __arg1, __arg2, __arg3) \ + ((__returnType(*)(id, SEL, __typeof__(__arg1), __typeof__(__arg2), \ + __typeof__(__arg3)))__originalIMP)(__receivingObject, __swizzledSEL, __arg1, \ + __arg2, __arg3) + +/** + * Invokes original IMP when the original selector takes 4 arguments. + * + * @param __receivingObject The object on which the IMP is invoked. + * @param __swizzledSEL The selector used for swizzling. + * @param __returnType The return type of the original implementation. + * @param __originalIMP The original IMP. + * @param __arg1 The first argument. + * @param __arg2 The second argument. + * @param __arg3 The third argument. + * @param __arg4 The fourth argument. + */ +#define GUL_INVOKE_ORIGINAL_IMP4(__receivingObject, __swizzledSEL, __returnType, __originalIMP, \ + __arg1, __arg2, __arg3, __arg4) \ + ((__returnType(*)(id, SEL, __typeof__(__arg1), __typeof__(__arg2), __typeof__(__arg3), \ + __typeof__(__arg4)))__originalIMP)(__receivingObject, __swizzledSEL, __arg1, \ + __arg2, __arg3, __arg4) + +/** + * Invokes original IMP when the original selector takes 5 arguments. + * + * @param __receivingObject The object on which the IMP is invoked. + * @param __swizzledSEL The selector used for swizzling. + * @param __returnType The return type of the original implementation. + * @param __originalIMP The original IMP. + * @param __arg1 The first argument. + * @param __arg2 The second argument. + * @param __arg3 The third argument. + * @param __arg4 The fourth argument. + * @param __arg5 The fifth argument. + */ +#define GUL_INVOKE_ORIGINAL_IMP5(__receivingObject, __swizzledSEL, __returnType, __originalIMP, \ + __arg1, __arg2, __arg3, __arg4, __arg5) \ + ((__returnType(*)(id, SEL, __typeof__(__arg1), __typeof__(__arg2), __typeof__(__arg3), \ + __typeof__(__arg4), __typeof__(__arg5)))__originalIMP)( \ + __receivingObject, __swizzledSEL, __arg1, __arg2, __arg3, __arg4, __arg5) + +/** + * Invokes original IMP when the original selector takes 6 arguments. + * + * @param __receivingObject The object on which the IMP is invoked. + * @param __swizzledSEL The selector used for swizzling. + * @param __returnType The return type of the original implementation. + * @param __originalIMP The original IMP. + * @param __arg1 The first argument. + * @param __arg2 The second argument. + * @param __arg3 The third argument. + * @param __arg4 The fourth argument. + * @param __arg5 The fifth argument. + * @param __arg6 The sixth argument. + */ +#define GUL_INVOKE_ORIGINAL_IMP6(__receivingObject, __swizzledSEL, __returnType, __originalIMP, \ + __arg1, __arg2, __arg3, __arg4, __arg5, __arg6) \ + ((__returnType(*)(id, SEL, __typeof__(__arg1), __typeof__(__arg2), __typeof__(__arg3), \ + __typeof__(__arg4), __typeof__(__arg5), __typeof__(__arg6)))__originalIMP)( \ + __receivingObject, __swizzledSEL, __arg1, __arg2, __arg3, __arg4, __arg5, __arg6) + +/** + * Invokes original IMP when the original selector takes 7 arguments. + * + * @param __receivingObject The object on which the IMP is invoked. + * @param __swizzledSEL The selector used for swizzling. + * @param __returnType The return type of the original implementation. + * @param __originalIMP The original IMP. + * @param __arg1 The first argument. + * @param __arg2 The second argument. + * @param __arg3 The third argument. + * @param __arg4 The fourth argument. + * @param __arg5 The fifth argument. + * @param __arg6 The sixth argument. + * @param __arg7 The seventh argument. + */ +#define GUL_INVOKE_ORIGINAL_IMP7(__receivingObject, __swizzledSEL, __returnType, __originalIMP, \ + __arg1, __arg2, __arg3, __arg4, __arg5, __arg6, __arg7) \ + ((__returnType(*)(id, SEL, __typeof__(__arg1), __typeof__(__arg2), __typeof__(__arg3), \ + __typeof__(__arg4), __typeof__(__arg5), __typeof__(__arg6), \ + __typeof__(__arg7)))__originalIMP)( \ + __receivingObject, __swizzledSEL, __arg1, __arg2, __arg3, __arg4, __arg5, __arg6, __arg7) + +/** + * Invokes original IMP when the original selector takes 8 arguments. + * + * @param __receivingObject The object on which the IMP is invoked. + * @param __swizzledSEL The selector used for swizzling. + * @param __returnType The return type of the original implementation. + * @param __originalIMP The original IMP. + * @param __arg1 The first argument. + * @param __arg2 The second argument. + * @param __arg3 The third argument. + * @param __arg4 The fourth argument. + * @param __arg5 The fifth argument. + * @param __arg6 The sixth argument. + * @param __arg7 The seventh argument. + * @param __arg8 The eighth argument. + */ +#define GUL_INVOKE_ORIGINAL_IMP8(__receivingObject, __swizzledSEL, __returnType, __originalIMP, \ + __arg1, __arg2, __arg3, __arg4, __arg5, __arg6, __arg7, __arg8) \ + ((__returnType(*)(id, SEL, __typeof__(__arg1), __typeof__(__arg2), __typeof__(__arg3), \ + __typeof__(__arg4), __typeof__(__arg5), __typeof__(__arg6), \ + __typeof__(__arg7), __typeof__(__arg8)))__originalIMP)( \ + __receivingObject, __swizzledSEL, __arg1, __arg2, __arg3, __arg4, __arg5, __arg6, __arg7, \ + __arg8) + +/** + * Invokes original IMP when the original selector takes 9 arguments. + * + * @param __receivingObject The object on which the IMP is invoked. + * @param __swizzledSEL The selector used for swizzling. + * @param __returnType The return type of the original implementation. + * @param __originalIMP The original IMP. + * @param __arg1 The first argument. + * @param __arg2 The second argument. + * @param __arg3 The third argument. + * @param __arg4 The fourth argument. + * @param __arg5 The fifth argument. + * @param __arg6 The sixth argument. + * @param __arg7 The seventh argument. + * @param __arg8 The eighth argument. + * @param __arg9 The ninth argument. + */ +#define GUL_INVOKE_ORIGINAL_IMP9(__receivingObject, __swizzledSEL, __returnType, __originalIMP, \ + __arg1, __arg2, __arg3, __arg4, __arg5, __arg6, __arg7, __arg8, \ + __arg9) \ + ((__returnType(*)(id, SEL, __typeof__(__arg1), __typeof__(__arg2), __typeof__(__arg3), \ + __typeof__(__arg4), __typeof__(__arg5), __typeof__(__arg6), \ + __typeof__(__arg7), __typeof__(__arg8), __typeof__(__arg9)))__originalIMP)( \ + __receivingObject, __swizzledSEL, __arg1, __arg2, __arg3, __arg4, __arg5, __arg6, __arg7, \ + __arg8, __arg9) diff --git a/Pods/GoogleUtilities/GoogleUtilities/MethodSwizzler/Public/GoogleUtilities/GULSwizzler.h b/Pods/GoogleUtilities/GoogleUtilities/MethodSwizzler/Public/GoogleUtilities/GULSwizzler.h new file mode 100644 index 0000000..26949c8 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/MethodSwizzler/Public/GoogleUtilities/GULSwizzler.h @@ -0,0 +1,71 @@ +/* + * Copyright 2018 Google LLC + * + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** This class handles the runtime manipulation necessary to instrument selectors. It stores the + * classes and selectors that have been swizzled, and runs all operations on its own queue. + */ +@interface GULSwizzler : NSObject + +/** Manipulates the Objective-C runtime to replace the original IMP with the supplied block. + * + * @param aClass The class to swizzle. + * @param selector The selector of the class to swizzle. + * @param isClassSelector A BOOL specifying whether the selector is a class or instance selector. + * @param block The block that replaces the original IMP. + */ ++ (void)swizzleClass:(Class)aClass + selector:(SEL)selector + isClassSelector:(BOOL)isClassSelector + withBlock:(nullable id)block; + +/** Returns the current IMP for the given class and selector. + * + * @param aClass The class to use. + * @param selector The selector to find the implementation of. + * @param isClassSelector A BOOL specifying whether the selector is a class or instance selector. + * @return The implementation of the selector in the runtime. + */ ++ (nullable IMP)currentImplementationForClass:(Class)aClass + selector:(SEL)selector + isClassSelector:(BOOL)isClassSelector; + +/** Checks the runtime to see if a selector exists on a class. If a property is declared as + * @dynamic, we have a reverse swizzling situation, where the implementation of a method exists + * only in concrete subclasses, and NOT in the superclass. We can detect that situation using + * this helper method. Similarly, we can detect situations where a class doesn't implement a + * protocol method. + * + * @param selector The selector to check for. + * @param aClass The class to check. + * @param isClassSelector A BOOL specifying whether the selector is a class or instance selector. + * @return YES if the method was found in this selector/class combination, NO otherwise. + */ ++ (BOOL)selector:(SEL)selector existsInClass:(Class)aClass isClassSelector:(BOOL)isClassSelector; + +/** Returns a list of all Objective-C (and not primitive) ivars contained by the given object. + * + * @param object The object whose ivars will be iterated. + * @return The list of ivar objects. + */ ++ (NSArray *)ivarObjectsForObject:(id)object; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleUtilities/GoogleUtilities/NSData+zlib/GULNSData+zlib.m b/Pods/GoogleUtilities/GoogleUtilities/NSData+zlib/GULNSData+zlib.m new file mode 100644 index 0000000..e441e36 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/NSData+zlib/GULNSData+zlib.m @@ -0,0 +1,207 @@ +// 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. + +#import "GoogleUtilities/NSData+zlib/Public/GoogleUtilities/GULNSData+zlib.h" + +#import + +#define kChunkSize 1024 +#define Z_DEFAULT_COMPRESSION (-1) + +NSString *const GULNSDataZlibErrorDomain = @"com.google.GULNSDataZlibErrorDomain"; +NSString *const GULNSDataZlibErrorKey = @"GULNSDataZlibErrorKey"; +NSString *const GULNSDataZlibRemainingBytesKey = @"GULNSDataZlibRemainingBytesKey"; + +@implementation NSData (GULGzip) + ++ (NSData *)gul_dataByInflatingGzippedData:(NSData *)data error:(NSError **)error { + const void *bytes = [data bytes]; + NSUInteger length = [data length]; + if (!bytes || !length) { + return nil; + } + +#if defined(__LP64__) && __LP64__ + // Don't support > 32bit length for 64 bit, see note in header. + if (length > UINT_MAX) { + return nil; + } +#endif + + z_stream strm; + bzero(&strm, sizeof(z_stream)); + + // Setup the input. + strm.avail_in = (unsigned int)length; + strm.next_in = (unsigned char *)bytes; + + int windowBits = 15; // 15 to enable any window size + windowBits += 32; // and +32 to enable zlib or gzip header detection. + + int retCode; + if ((retCode = inflateInit2(&strm, windowBits)) != Z_OK) { + if (error) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:retCode] + forKey:GULNSDataZlibErrorKey]; + *error = [NSError errorWithDomain:GULNSDataZlibErrorDomain + code:GULNSDataZlibErrorInternal + userInfo:userInfo]; + } + return nil; + } + + // Hint the size at 4x the input size. + NSMutableData *result = [NSMutableData dataWithCapacity:(length * 4)]; + unsigned char output[kChunkSize]; + + // Loop to collect the data. + do { + // Update what we're passing in. + strm.avail_out = kChunkSize; + strm.next_out = output; + retCode = inflate(&strm, Z_NO_FLUSH); + if ((retCode != Z_OK) && (retCode != Z_STREAM_END)) { + if (error) { + NSMutableDictionary *userInfo = + [NSMutableDictionary dictionaryWithObject:[NSNumber numberWithInt:retCode] + forKey:GULNSDataZlibErrorKey]; + if (strm.msg) { + NSString *message = [NSString stringWithUTF8String:strm.msg]; + if (message) { + [userInfo setObject:message forKey:NSLocalizedDescriptionKey]; + } + } + *error = [NSError errorWithDomain:GULNSDataZlibErrorDomain + code:GULNSDataZlibErrorInternal + userInfo:userInfo]; + } + inflateEnd(&strm); + return nil; + } + // Collect what we got. + unsigned gotBack = kChunkSize - strm.avail_out; + if (gotBack > 0) { + [result appendBytes:output length:gotBack]; + } + + } while (retCode == Z_OK); + + // Make sure there wasn't more data tacked onto the end of a valid compressed stream. + if (strm.avail_in != 0) { + if (error) { + NSDictionary *userInfo = + [NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedInt:strm.avail_in] + forKey:GULNSDataZlibRemainingBytesKey]; + *error = [NSError errorWithDomain:GULNSDataZlibErrorDomain + code:GULNSDataZlibErrorDataRemaining + userInfo:userInfo]; + } + result = nil; + } + // The only way out of the loop was by hitting the end of the stream. + NSAssert(retCode == Z_STREAM_END, + @"Thought we finished inflate w/o getting a result of stream end, code %d", retCode); + + // Clean up. + inflateEnd(&strm); + + return result; +} + ++ (NSData *)gul_dataByGzippingData:(NSData *)data error:(NSError **)error { + const void *bytes = [data bytes]; + NSUInteger length = [data length]; + + int level = Z_DEFAULT_COMPRESSION; + if (!bytes || !length) { + return nil; + } + +#if defined(__LP64__) && __LP64__ + // Don't support > 32bit length for 64 bit, see note in header. + if (length > UINT_MAX) { + if (error) { + *error = [NSError errorWithDomain:GULNSDataZlibErrorDomain + code:GULNSDataZlibErrorGreaterThan32BitsToCompress + userInfo:nil]; + } + return nil; + } +#endif + + z_stream strm; + bzero(&strm, sizeof(z_stream)); + + int memLevel = 8; // Default. + int windowBits = 15 + 16; // Enable gzip header instead of zlib header. + + int retCode; + if ((retCode = deflateInit2(&strm, level, Z_DEFLATED, windowBits, memLevel, + Z_DEFAULT_STRATEGY)) != Z_OK) { + if (error) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:retCode] + forKey:GULNSDataZlibErrorKey]; + *error = [NSError errorWithDomain:GULNSDataZlibErrorDomain + code:GULNSDataZlibErrorInternal + userInfo:userInfo]; + } + return nil; + } + + // Hint the size at 1/4 the input size. + NSMutableData *result = [NSMutableData dataWithCapacity:(length / 4)]; + unsigned char output[kChunkSize]; + + // Setup the input. + strm.avail_in = (unsigned int)length; + strm.next_in = (unsigned char *)bytes; + + // Collect the data. + do { + // update what we're passing in + strm.avail_out = kChunkSize; + strm.next_out = output; + retCode = deflate(&strm, Z_FINISH); + if ((retCode != Z_OK) && (retCode != Z_STREAM_END)) { + if (error) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:retCode] + forKey:GULNSDataZlibErrorKey]; + *error = [NSError errorWithDomain:GULNSDataZlibErrorDomain + code:GULNSDataZlibErrorInternal + userInfo:userInfo]; + } + deflateEnd(&strm); + return nil; + } + // Collect what we got. + unsigned gotBack = kChunkSize - strm.avail_out; + if (gotBack > 0) { + [result appendBytes:output length:gotBack]; + } + + } while (retCode == Z_OK); + + // If the loop exits, it used all input and the stream ended. + NSAssert(strm.avail_in == 0, + @"Should have finished deflating without using all input, %u bytes left", strm.avail_in); + NSAssert(retCode == Z_STREAM_END, + @"thought we finished deflate w/o getting a result of stream end, code %d", retCode); + + // Clean up. + deflateEnd(&strm); + + return result; +} + +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/NSData+zlib/Public/GoogleUtilities/GULNSData+zlib.h b/Pods/GoogleUtilities/GoogleUtilities/NSData+zlib/Public/GoogleUtilities/GULNSData+zlib.h new file mode 100644 index 0000000..36f94a7 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/NSData+zlib/Public/GoogleUtilities/GULNSData+zlib.h @@ -0,0 +1,49 @@ +// 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. + +#import + +/// This is a copy of Google Toolbox for Mac library to avoid creating an extra framework. + +// NOTE: For 64bit, none of these apis handle input sizes >32bits, they will return nil when given +// such data. To handle data of that size you really should be streaming it rather then doing it all +// in memory. + +@interface NSData (GULGzip) + +/// Returns an data as the result of decompressing the payload of |data|.The data to decompress must +/// be a gzipped payloads. ++ (NSData *)gul_dataByInflatingGzippedData:(NSData *)data error:(NSError **)error; + +/// Returns an compressed data with the result of gzipping the payload of |data|. Uses the default +/// compression level. ++ (NSData *)gul_dataByGzippingData:(NSData *)data error:(NSError **)error; + +FOUNDATION_EXPORT NSString *const GULNSDataZlibErrorDomain; +FOUNDATION_EXPORT NSString *const GULNSDataZlibErrorKey; // NSNumber +FOUNDATION_EXPORT NSString *const GULNSDataZlibRemainingBytesKey; // NSNumber + +typedef NS_ENUM(NSInteger, GULNSDataZlibError) { + GULNSDataZlibErrorGreaterThan32BitsToCompress = 1024, + // An internal zlib error. + // GULNSDataZlibErrorKey will contain the error value. + // NSLocalizedDescriptionKey may contain an error string from zlib. + // Look in zlib.h for list of errors. + GULNSDataZlibErrorInternal, + // There was left over data in the buffer that was not used. + // GULNSDataZlibRemainingBytesKey will contain number of remaining bytes. + GULNSDataZlibErrorDataRemaining +}; + +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/Network/GULMutableDictionary.m b/Pods/GoogleUtilities/GoogleUtilities/Network/GULMutableDictionary.m new file mode 100644 index 0000000..7726d15 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Network/GULMutableDictionary.m @@ -0,0 +1,101 @@ +// 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 "GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h" + +@implementation GULMutableDictionary { + /// The mutable dictionary. + NSMutableDictionary *_objects; + + /// Serial synchronization queue. All reads should use dispatch_sync, while writes use + /// dispatch_async. + dispatch_queue_t _queue; +} + +- (instancetype)init { + self = [super init]; + + if (self) { + _objects = [[NSMutableDictionary alloc] init]; + _queue = dispatch_queue_create("GULMutableDictionary", DISPATCH_QUEUE_SERIAL); + } + + return self; +} + +- (NSString *)description { + __block NSString *description; + dispatch_sync(_queue, ^{ + description = self->_objects.description; + }); + return description; +} + +- (id)objectForKey:(id)key { + __block id object; + dispatch_sync(_queue, ^{ + object = [self->_objects objectForKey:key]; + }); + return object; +} + +- (void)setObject:(id)object forKey:(id)key { + dispatch_async(_queue, ^{ + [self->_objects setObject:object forKey:key]; + }); +} + +- (void)removeObjectForKey:(id)key { + dispatch_async(_queue, ^{ + [self->_objects removeObjectForKey:key]; + }); +} + +- (void)removeAllObjects { + dispatch_async(_queue, ^{ + [self->_objects removeAllObjects]; + }); +} + +- (NSUInteger)count { + __block NSUInteger count; + dispatch_sync(_queue, ^{ + count = self->_objects.count; + }); + return count; +} + +- (id)objectForKeyedSubscript:(id)key { + __block id object; + dispatch_sync(_queue, ^{ + object = self->_objects[key]; + }); + return object; +} + +- (void)setObject:(id)obj forKeyedSubscript:(id)key { + dispatch_async(_queue, ^{ + self->_objects[key] = obj; + }); +} + +- (NSDictionary *)dictionary { + __block NSDictionary *dictionary; + dispatch_sync(_queue, ^{ + dictionary = [self->_objects copy]; + }); + return dictionary; +} + +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetwork.m b/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetwork.m new file mode 100644 index 0000000..327a3a0 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetwork.m @@ -0,0 +1,405 @@ +// 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 "GoogleUtilities/Network/Public/GoogleUtilities/GULNetwork.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkMessageCode.h" + +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" +#import "GoogleUtilities/NSData+zlib/Public/GoogleUtilities/GULNSData+zlib.h" +#import "GoogleUtilities/Network/GULNetworkInternal.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkConstants.h" +#import "GoogleUtilities/Reachability/Public/GoogleUtilities/GULReachabilityChecker.h" + +/// Constant string for request header Content-Encoding. +static NSString *const kGULNetworkContentCompressionKey = @"Content-Encoding"; + +/// Constant string for request header Content-Encoding value. +static NSString *const kGULNetworkContentCompressionValue = @"gzip"; + +/// Constant string for request header Content-Length. +static NSString *const kGULNetworkContentLengthKey = @"Content-Length"; + +/// Constant string for request header Content-Type. +static NSString *const kGULNetworkContentTypeKey = @"Content-Type"; + +/// Constant string for request header Content-Type value. +static NSString *const kGULNetworkContentTypeValue = @"application/x-www-form-urlencoded"; + +/// Constant string for GET request method. +static NSString *const kGULNetworkGETRequestMethod = @"GET"; + +/// Constant string for POST request method. +static NSString *const kGULNetworkPOSTRequestMethod = @"POST"; + +/// Default constant string as a prefix for network logger. +static NSString *const kGULNetworkLogTag = @"Google/Utilities/Network"; + +@interface GULNetwork () +@end + +@implementation GULNetwork { + /// Network reachability. + GULReachabilityChecker *_reachability; + + /// The dictionary of requests by session IDs { NSString : id }. + GULMutableDictionary *_requests; +} + +- (instancetype)init { + return [self initWithReachabilityHost:kGULNetworkReachabilityHost]; +} + +- (instancetype)initWithReachabilityHost:(NSString *)reachabilityHost { + self = [super init]; + if (self) { + // Setup reachability. + _reachability = [[GULReachabilityChecker alloc] initWithReachabilityDelegate:self + withHost:reachabilityHost]; + if (![_reachability start]) { + return nil; + } + + _requests = [[GULMutableDictionary alloc] init]; + _timeoutInterval = kGULNetworkTimeOutInterval; + } + return self; +} + +- (void)dealloc { + _reachability.reachabilityDelegate = nil; + [_reachability stop]; +} + +#pragma mark - External Methods + ++ (void)handleEventsForBackgroundURLSessionID:(NSString *)sessionID + completionHandler:(GULNetworkSystemCompletionHandler)completionHandler { + [GULNetworkURLSession handleEventsForBackgroundURLSessionID:sessionID + completionHandler:completionHandler]; +} + +- (NSString *)postURL:(NSURL *)url + payload:(NSData *)payload + queue:(dispatch_queue_t)queue + usingBackgroundSession:(BOOL)usingBackgroundSession + completionHandler:(GULNetworkCompletionHandler)handler { + return [self postURL:url + headers:nil + payload:payload + queue:queue + usingBackgroundSession:usingBackgroundSession + completionHandler:handler]; +} + +- (NSString *)postURL:(NSURL *)url + headers:(NSDictionary *)headers + payload:(NSData *)payload + queue:(dispatch_queue_t)queue + usingBackgroundSession:(BOOL)usingBackgroundSession + completionHandler:(GULNetworkCompletionHandler)handler { + if (!url.absoluteString.length) { + [self handleErrorWithCode:GULErrorCodeNetworkInvalidURL queue:queue withHandler:handler]; + return nil; + } + + NSTimeInterval timeOutInterval = _timeoutInterval ?: kGULNetworkTimeOutInterval; + + NSMutableURLRequest *request = + [[NSMutableURLRequest alloc] initWithURL:url + cachePolicy:NSURLRequestReloadIgnoringLocalCacheData + timeoutInterval:timeOutInterval]; + + if (!request) { + [self handleErrorWithCode:GULErrorCodeNetworkSessionTaskCreation + queue:queue + withHandler:handler]; + return nil; + } + request.allHTTPHeaderFields = headers; + + NSError *compressError = nil; + NSData *compressedData = [NSData gul_dataByGzippingData:payload error:&compressError]; + if (!compressedData || compressError) { + if (compressError || payload.length > 0) { + // If the payload is not empty but it fails to compress the payload, something has been wrong. + [self handleErrorWithCode:GULErrorCodeNetworkPayloadCompression + queue:queue + withHandler:handler]; + return nil; + } + compressedData = [[NSData alloc] init]; + } + + NSString *postLength = @(compressedData.length).stringValue; + + // Set up the request with the compressed data. + [request setValue:postLength forHTTPHeaderField:kGULNetworkContentLengthKey]; + request.HTTPBody = compressedData; + request.HTTPMethod = kGULNetworkPOSTRequestMethod; + [request setValue:kGULNetworkContentTypeValue forHTTPHeaderField:kGULNetworkContentTypeKey]; + [request setValue:kGULNetworkContentCompressionValue + forHTTPHeaderField:kGULNetworkContentCompressionKey]; + + GULNetworkURLSession *fetcher = [[GULNetworkURLSession alloc] initWithNetworkLoggerDelegate:self]; + fetcher.backgroundNetworkEnabled = usingBackgroundSession; + + __weak GULNetwork *weakSelf = self; + NSString *requestID = [fetcher + sessionIDFromAsyncPOSTRequest:request + completionHandler:^(NSHTTPURLResponse *response, NSData *data, + NSString *sessionID, NSError *error) { + GULNetwork *strongSelf = weakSelf; + if (!strongSelf) { + return; + } + dispatch_queue_t queueToDispatch = queue ? queue : dispatch_get_main_queue(); + dispatch_async(queueToDispatch, ^{ + if (sessionID.length) { + [strongSelf->_requests removeObjectForKey:sessionID]; + } + if (handler) { + handler(response, data, error); + } + }); + }]; + if (!requestID) { + [self handleErrorWithCode:GULErrorCodeNetworkSessionTaskCreation + queue:queue + withHandler:handler]; + return nil; + } + + [self GULNetwork_logWithLevel:kGULNetworkLogLevelDebug + messageCode:kGULNetworkMessageCodeNetwork000 + message:@"Uploading data. Host" + context:url]; + _requests[requestID] = fetcher; + return requestID; +} + +- (NSString *)getURL:(NSURL *)url + headers:(NSDictionary *)headers + queue:(dispatch_queue_t)queue + usingBackgroundSession:(BOOL)usingBackgroundSession + completionHandler:(GULNetworkCompletionHandler)handler { + if (!url.absoluteString.length) { + [self handleErrorWithCode:GULErrorCodeNetworkInvalidURL queue:queue withHandler:handler]; + return nil; + } + + NSTimeInterval timeOutInterval = _timeoutInterval ?: kGULNetworkTimeOutInterval; + NSMutableURLRequest *request = + [[NSMutableURLRequest alloc] initWithURL:url + cachePolicy:NSURLRequestReloadIgnoringLocalCacheData + timeoutInterval:timeOutInterval]; + + if (!request) { + [self handleErrorWithCode:GULErrorCodeNetworkSessionTaskCreation + queue:queue + withHandler:handler]; + return nil; + } + + request.HTTPMethod = kGULNetworkGETRequestMethod; + request.allHTTPHeaderFields = headers; + + GULNetworkURLSession *fetcher = [[GULNetworkURLSession alloc] initWithNetworkLoggerDelegate:self]; + fetcher.backgroundNetworkEnabled = usingBackgroundSession; + + __weak GULNetwork *weakSelf = self; + NSString *requestID = [fetcher + sessionIDFromAsyncGETRequest:request + completionHandler:^(NSHTTPURLResponse *response, NSData *data, NSString *sessionID, + NSError *error) { + GULNetwork *strongSelf = weakSelf; + if (!strongSelf) { + return; + } + dispatch_queue_t queueToDispatch = queue ? queue : dispatch_get_main_queue(); + dispatch_async(queueToDispatch, ^{ + if (sessionID.length) { + [strongSelf->_requests removeObjectForKey:sessionID]; + } + if (handler) { + handler(response, data, error); + } + }); + }]; + + if (!requestID) { + [self handleErrorWithCode:GULErrorCodeNetworkSessionTaskCreation + queue:queue + withHandler:handler]; + return nil; + } + + [self GULNetwork_logWithLevel:kGULNetworkLogLevelDebug + messageCode:kGULNetworkMessageCodeNetwork001 + message:@"Downloading data. Host" + context:url]; + _requests[requestID] = fetcher; + return requestID; +} + +- (BOOL)hasUploadInProgress { + return _requests.count > 0; +} + +#pragma mark - Network Reachability + +/// Tells reachability delegate to call reachabilityDidChangeToStatus: to notify the network +/// reachability has changed. +- (void)reachability:(GULReachabilityChecker *)reachability + statusChanged:(GULReachabilityStatus)status { + _networkConnected = (status == kGULReachabilityViaCellular || status == kGULReachabilityViaWifi); + [_reachabilityDelegate reachabilityDidChange]; +} + +#pragma mark - Network logger delegate + +- (void)setLoggerDelegate:(id)loggerDelegate { + // Explicitly check whether the delegate responds to the methods because conformsToProtocol does + // not work correctly even though the delegate does respond to the methods. + if (!loggerDelegate || + ![loggerDelegate respondsToSelector:@selector(GULNetwork_logWithLevel: + messageCode:message:contexts:)] || + ![loggerDelegate respondsToSelector:@selector(GULNetwork_logWithLevel: + messageCode:message:context:)] || + ![loggerDelegate respondsToSelector:@selector(GULNetwork_logWithLevel: + messageCode:message:)]) { + GULLogError(kGULLoggerNetwork, NO, + [NSString stringWithFormat:@"I-NET%06ld", (long)kGULNetworkMessageCodeNetwork002], + @"Cannot set the network logger delegate: delegate does not conform to the network " + "logger protocol."); + return; + } + _loggerDelegate = loggerDelegate; +} + +#pragma mark - Private methods + +/// Handles network error and calls completion handler with the error. +- (void)handleErrorWithCode:(NSInteger)code + queue:(dispatch_queue_t)queue + withHandler:(GULNetworkCompletionHandler)handler { + NSDictionary *userInfo = @{kGULNetworkErrorContext : @"Failed to create network request"}; + NSError *error = [[NSError alloc] initWithDomain:kGULNetworkErrorDomain + code:code + userInfo:userInfo]; + [self GULNetwork_logWithLevel:kGULNetworkLogLevelWarning + messageCode:kGULNetworkMessageCodeNetwork002 + message:@"Failed to create network request. Code, error" + contexts:@[ @(code), error ]]; + if (handler) { + dispatch_queue_t queueToDispatch = queue ? queue : dispatch_get_main_queue(); + dispatch_async(queueToDispatch, ^{ + handler(nil, nil, error); + }); + } +} + +#pragma mark - Network logger + +- (void)GULNetwork_logWithLevel:(GULNetworkLogLevel)logLevel + messageCode:(GULNetworkMessageCode)messageCode + message:(NSString *)message + contexts:(NSArray *)contexts { + // Let the delegate log the message if there is a valid logger delegate. Otherwise, just log + // errors/warnings/info messages to the console log. + if (_loggerDelegate) { + [_loggerDelegate GULNetwork_logWithLevel:logLevel + messageCode:messageCode + message:message + contexts:contexts]; + return; + } + if (_isDebugModeEnabled || logLevel == kGULNetworkLogLevelError || + logLevel == kGULNetworkLogLevelWarning || logLevel == kGULNetworkLogLevelInfo) { + NSString *formattedMessage = GULStringWithLogMessage(message, logLevel, contexts); + NSLog(@"%@", formattedMessage); + GULLogBasic((GULLoggerLevel)logLevel, kGULLoggerNetwork, NO, + [NSString stringWithFormat:@"I-NET%06ld", (long)messageCode], formattedMessage, + NULL); + } +} + +- (void)GULNetwork_logWithLevel:(GULNetworkLogLevel)logLevel + messageCode:(GULNetworkMessageCode)messageCode + message:(NSString *)message + context:(id)context { + if (_loggerDelegate) { + [_loggerDelegate GULNetwork_logWithLevel:logLevel + messageCode:messageCode + message:message + context:context]; + return; + } + NSArray *contexts = context ? @[ context ] : @[]; + [self GULNetwork_logWithLevel:logLevel messageCode:messageCode message:message contexts:contexts]; +} + +- (void)GULNetwork_logWithLevel:(GULNetworkLogLevel)logLevel + messageCode:(GULNetworkMessageCode)messageCode + message:(NSString *)message { + if (_loggerDelegate) { + [_loggerDelegate GULNetwork_logWithLevel:logLevel messageCode:messageCode message:message]; + return; + } + [self GULNetwork_logWithLevel:logLevel messageCode:messageCode message:message contexts:@[]]; +} + +/// Returns a string for the given log level (e.g. kGULNetworkLogLevelError -> @"ERROR"). +static NSString *GULLogLevelDescriptionFromLogLevel(GULNetworkLogLevel logLevel) { + static NSDictionary *levelNames = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + levelNames = @{ + @(kGULNetworkLogLevelError) : @"ERROR", + @(kGULNetworkLogLevelWarning) : @"WARNING", + @(kGULNetworkLogLevelInfo) : @"INFO", + @(kGULNetworkLogLevelDebug) : @"DEBUG" + }; + }); + return levelNames[@(logLevel)]; +} + +/// Returns a formatted string to be used for console logging. +static NSString *GULStringWithLogMessage(NSString *message, + GULNetworkLogLevel logLevel, + NSArray *contexts) { + if (!message) { + message = @"(Message was nil)"; + } else if (!message.length) { + message = @"(Message was empty)"; + } + NSMutableString *result = [[NSMutableString alloc] + initWithFormat:@"<%@/%@> %@", kGULNetworkLogTag, GULLogLevelDescriptionFromLogLevel(logLevel), + message]; + + if (!contexts.count) { + return result; + } + + NSMutableArray *formattedContexts = [[NSMutableArray alloc] init]; + for (id item in contexts) { + [formattedContexts addObject:(item != [NSNull null] ? item : @"(nil)")]; + } + + [result appendString:@": "]; + [result appendString:[formattedContexts componentsJoinedByString:@", "]]; + return result; +} + +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkConstants.m b/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkConstants.m new file mode 100644 index 0000000..e4b8469 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkConstants.m @@ -0,0 +1,41 @@ +// 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 "GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkConstants.h" +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" + +#import + +NSString *const kGULNetworkBackgroundSessionConfigIDPrefix = @"com.gul.network.background-upload"; +NSString *const kGULNetworkApplicationSupportSubdirectory = @"GUL/Network"; +NSString *const kGULNetworkTempDirectoryName = @"GULNetworkTemporaryDirectory"; +const NSTimeInterval kGULNetworkTempFolderExpireTime = 60 * 60; // 1 hour +const NSTimeInterval kGULNetworkTimeOutInterval = 60; // 1 minute. +NSString *const kGULNetworkReachabilityHost = @"app-measurement.com"; +NSString *const kGULNetworkErrorContext = @"Context"; + +const int kGULNetworkHTTPStatusOK = 200; +const int kGULNetworkHTTPStatusNoContent = 204; +const int kGULNetworkHTTPStatusCodeMultipleChoices = 300; +const int kGULNetworkHTTPStatusCodeMovedPermanently = 301; +const int kGULNetworkHTTPStatusCodeFound = 302; +const int kGULNetworkHTTPStatusCodeNotModified = 304; +const int kGULNetworkHTTPStatusCodeMovedTemporarily = 307; +const int kGULNetworkHTTPStatusCodeNotFound = 404; +const int kGULNetworkHTTPStatusCodeCannotAcceptTraffic = 429; +const int kGULNetworkHTTPStatusCodeUnavailable = 503; + +NSString *const kGULNetworkErrorDomain = @"com.gul.network.ErrorDomain"; + +GULLoggerService kGULLoggerNetwork = @"[GULNetwork]"; diff --git a/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkInternal.h b/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkInternal.h new file mode 100644 index 0000000..5aca9fd --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkInternal.h @@ -0,0 +1,24 @@ +/* + * 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 + +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" + +extern NSString *const kGULNetworkErrorDomain; + +/// The logger service for GULNetwork. +extern GULLoggerService kGULLoggerNetwork; diff --git a/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkURLSession.m b/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkURLSession.m new file mode 100644 index 0000000..956abfc --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkURLSession.m @@ -0,0 +1,736 @@ +// 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 + +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkURLSession.h" + +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" +#import "GoogleUtilities/Network/GULNetworkInternal.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkConstants.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkMessageCode.h" + +@interface GULNetworkURLSession () +@end + +@implementation GULNetworkURLSession { + /// The handler to be called when the request completes or error has occurs. + GULNetworkURLSessionCompletionHandler _completionHandler; + + /// Session ID generated randomly with a fixed prefix. + NSString *_sessionID; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunguarded-availability" + /// The session configuration. NSURLSessionConfiguration' is only available on iOS 7.0 or newer. + NSURLSessionConfiguration *_sessionConfig; + + /// The current NSURLSession. + NSURLSession *__weak _Nullable _URLSession; +#pragma clang diagnostic pop + + /// The path to the directory where all temporary files are stored before uploading. + NSURL *_networkDirectoryURL; + + /// The downloaded data from fetching. + NSData *_downloadedData; + + /// The path to the temporary file which stores the uploading data. + NSURL *_uploadingFileURL; + + /// The current request. + NSURLRequest *_request; +} + +#pragma mark - Init + +- (instancetype)initWithNetworkLoggerDelegate:(id)networkLoggerDelegate { + self = [super init]; + if (self) { + // Create URL to the directory where all temporary files to upload have to be stored. +#if TARGET_OS_TV + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); +#else + NSArray *paths = + NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); +#endif + NSString *storageDirectory = paths.firstObject; + NSArray *tempPathComponents = @[ + storageDirectory, kGULNetworkApplicationSupportSubdirectory, kGULNetworkTempDirectoryName + ]; + _networkDirectoryURL = [NSURL fileURLWithPathComponents:tempPathComponents]; + _sessionID = [NSString stringWithFormat:@"%@-%@", kGULNetworkBackgroundSessionConfigIDPrefix, + [[NSUUID UUID] UUIDString]]; + _loggerDelegate = networkLoggerDelegate; + } + return self; +} + +#pragma mark - External Methods + +#pragma mark - To be called from AppDelegate + ++ (void)handleEventsForBackgroundURLSessionID:(NSString *)sessionID + completionHandler: + (GULNetworkSystemCompletionHandler)systemCompletionHandler { + // The session may not be Analytics background. Ignore those that do not have the prefix. + if (![sessionID hasPrefix:kGULNetworkBackgroundSessionConfigIDPrefix]) { + return; + } + GULNetworkURLSession *fetcher = [self fetcherWithSessionIdentifier:sessionID]; + if (fetcher != nil) { + [fetcher addSystemCompletionHandler:systemCompletionHandler forSession:sessionID]; + } else { + GULLogError(kGULLoggerNetwork, NO, + [NSString stringWithFormat:@"I-NET%06ld", (long)kGULNetworkMessageCodeNetwork003], + @"Failed to retrieve background session with ID %@ after app is relaunched.", + sessionID); + } +} + +#pragma mark - External Methods + +/// Sends an async POST request using NSURLSession for iOS >= 7.0, and returns an ID of the +/// connection. +- (nullable NSString *)sessionIDFromAsyncPOSTRequest:(NSURLRequest *)request + completionHandler:(GULNetworkURLSessionCompletionHandler)handler + API_AVAILABLE(ios(7.0)) { + // NSURLSessionUploadTask does not work with NSData in the background. + // To avoid this issue, write the data to a temporary file to upload it. + // Make a temporary file with the data subset. + _uploadingFileURL = [self temporaryFilePathWithSessionID:_sessionID]; + NSError *writeError; + NSURLSessionUploadTask *postRequestTask; + NSURLSession *session; + BOOL didWriteFile = NO; + + // Clean up the entire temp folder to avoid temp files that remain in case the previous session + // crashed and did not clean up. + [self maybeRemoveTempFilesAtURL:_networkDirectoryURL + expiringTime:kGULNetworkTempFolderExpireTime]; + + // If there is no background network enabled, no need to write to file. This will allow default + // network session which runs on the foreground. + if (_backgroundNetworkEnabled && [self ensureTemporaryDirectoryExists]) { + didWriteFile = [request.HTTPBody writeToFile:_uploadingFileURL.path + options:NSDataWritingAtomic + error:&writeError]; + + if (writeError) { + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession000 + message:@"Failed to write request data to file" + context:writeError]; + } + } + + if (didWriteFile) { + // Exclude this file from backing up to iTunes. There are conflicting reports that excluding + // directory from backing up does not exclude files of that directory from backing up. + [self excludeFromBackupForURL:_uploadingFileURL]; + + _sessionConfig = [self backgroundSessionConfigWithSessionID:_sessionID]; + [self populateSessionConfig:_sessionConfig withRequest:request]; + session = [NSURLSession sessionWithConfiguration:_sessionConfig + delegate:self + delegateQueue:[NSOperationQueue mainQueue]]; + postRequestTask = [session uploadTaskWithRequest:request fromFile:_uploadingFileURL]; + } else { + // If we cannot write to file, just send it in the foreground. + _sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration]; + [self populateSessionConfig:_sessionConfig withRequest:request]; + session = [NSURLSession sessionWithConfiguration:_sessionConfig + delegate:self + delegateQueue:[NSOperationQueue mainQueue]]; + postRequestTask = [session uploadTaskWithRequest:request fromData:request.HTTPBody]; + } + + if (!session || !postRequestTask) { + NSError *error = [[NSError alloc] + initWithDomain:kGULNetworkErrorDomain + code:GULErrorCodeNetworkRequestCreation + userInfo:@{kGULNetworkErrorContext : @"Cannot create network session"}]; + [self callCompletionHandler:handler withResponse:nil data:nil error:error]; + return nil; + } + + _URLSession = session; + + // Save the session into memory. + [[self class] setSessionInFetcherMap:self forSessionID:_sessionID]; + + _request = [request copy]; + + // Store completion handler because background session does not accept handler block but custom + // delegate. + _completionHandler = [handler copy]; + [postRequestTask resume]; + + return _sessionID; +} + +/// Sends an async GET request using NSURLSession for iOS >= 7.0, and returns an ID of the session. +- (nullable NSString *)sessionIDFromAsyncGETRequest:(NSURLRequest *)request + completionHandler:(GULNetworkURLSessionCompletionHandler)handler + API_AVAILABLE(ios(7.0)) { + if (_backgroundNetworkEnabled) { + _sessionConfig = [self backgroundSessionConfigWithSessionID:_sessionID]; + } else { + _sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration]; + } + + [self populateSessionConfig:_sessionConfig withRequest:request]; + + // Do not cache the GET request. + _sessionConfig.URLCache = nil; + + NSURLSession *session = [NSURLSession sessionWithConfiguration:_sessionConfig + delegate:self + delegateQueue:[NSOperationQueue mainQueue]]; + NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request]; + + if (!session || !downloadTask) { + NSError *error = [[NSError alloc] + initWithDomain:kGULNetworkErrorDomain + code:GULErrorCodeNetworkRequestCreation + userInfo:@{kGULNetworkErrorContext : @"Cannot create network session"}]; + [self callCompletionHandler:handler withResponse:nil data:nil error:error]; + return nil; + } + + _URLSession = session; + + // Save the session into memory. + [[self class] setSessionInFetcherMap:self forSessionID:_sessionID]; + + _request = [request copy]; + + _completionHandler = [handler copy]; + [downloadTask resume]; + + return _sessionID; +} + +#pragma mark - NSURLSessionDataDelegate + +/// Called by the NSURLSession when the data task has received some of the expected data. +/// Once the session is completed, URLSession:task:didCompleteWithError will be called and the +/// completion handler will be called with the downloaded data. +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + didReceiveData:(NSData *)data { + @synchronized(self) { + NSMutableData *mutableData = [[NSMutableData alloc] init]; + if (_downloadedData) { + mutableData = _downloadedData.mutableCopy; + } + [mutableData appendData:data]; + _downloadedData = mutableData; + } +} + +#pragma mark - NSURLSessionTaskDelegate + +/// Called by the NSURLSession once the download task is completed. The file is saved in the +/// provided URL so we need to read the data and store into _downloadedData. Once the session is +/// completed, URLSession:task:didCompleteWithError will be called and the completion handler will +/// be called with the downloaded data. +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)task + didFinishDownloadingToURL:(NSURL *)url API_AVAILABLE(ios(7.0)) { + if (!url.path) { + [_loggerDelegate + GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession001 + message:@"Unable to read downloaded data from empty temp path"]; + _downloadedData = nil; + return; + } + + NSError *error; + _downloadedData = [NSData dataWithContentsOfFile:url.path options:0 error:&error]; + + if (error) { + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession002 + message:@"Cannot read the content of downloaded data" + context:error]; + _downloadedData = nil; + } +} + +#if TARGET_OS_IOS || TARGET_OS_TV +- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session + API_AVAILABLE(ios(7.0)) { + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelDebug + messageCode:kGULNetworkMessageCodeURLSession003 + message:@"Background session finished" + context:session.configuration.identifier]; + [self callSystemCompletionHandler:session.configuration.identifier]; +} +#endif + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didCompleteWithError:(NSError *)error API_AVAILABLE(ios(7.0)) { + // Avoid any chance of recursive behavior leading to it being used repeatedly. + GULNetworkURLSessionCompletionHandler handler = _completionHandler; + _completionHandler = nil; + + if (task.response) { + // The following assertion should always be true for HTTP requests, see https://goo.gl/gVLxT7. + NSAssert([task.response isKindOfClass:[NSHTTPURLResponse class]], @"URL response must be HTTP"); + + // The server responded so ignore the error created by the system. + error = nil; + } else if (!error) { + error = [[NSError alloc] + initWithDomain:kGULNetworkErrorDomain + code:GULErrorCodeNetworkInvalidResponse + userInfo:@{kGULNetworkErrorContext : @"Network Error: Empty network response"}]; + } + + [self callCompletionHandler:handler + withResponse:(NSHTTPURLResponse *)task.response + data:_downloadedData + error:error]; + + // Remove the temp file to avoid trashing devices with lots of temp files. + [self removeTempItemAtURL:_uploadingFileURL]; + + // Try to clean up stale files again. + [self maybeRemoveTempFilesAtURL:_networkDirectoryURL + expiringTime:kGULNetworkTempFolderExpireTime]; + + // This is called without checking the sessionID here since non-background sessions + // won't have an ID. + [session finishTasksAndInvalidate]; + + // Explicitly remove the session so it won't be reused. The weak map table should + // remove the session on deallocation, but dealloc may not happen immediately after + // calling `finishTasksAndInvalidate`. + NSString *sessionID = session.configuration.identifier; + [[self class] setSessionInFetcherMap:nil forSessionID:sessionID]; +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge + completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, + NSURLCredential *credential))completionHandler + API_AVAILABLE(ios(7.0)) { + // The handling is modeled after GTMSessionFetcher. + if ([challenge.protectionSpace.authenticationMethod + isEqualToString:NSURLAuthenticationMethodServerTrust]) { + SecTrustRef serverTrust = challenge.protectionSpace.serverTrust; + if (serverTrust == NULL) { + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelDebug + messageCode:kGULNetworkMessageCodeURLSession004 + message:@"Received empty server trust for host. Host" + context:_request.URL]; + completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); + return; + } + NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust]; + if (!credential) { + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelWarning + messageCode:kGULNetworkMessageCodeURLSession005 + message:@"Unable to verify server identity. Host" + context:_request.URL]; + completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil); + return; + } + + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelDebug + messageCode:kGULNetworkMessageCodeURLSession006 + message:@"Received SSL challenge for host. Host" + context:_request.URL]; + + void (^callback)(BOOL) = ^(BOOL allow) { + if (allow) { + completionHandler(NSURLSessionAuthChallengeUseCredential, credential); + } else { + [self->_loggerDelegate + GULNetwork_logWithLevel:kGULNetworkLogLevelDebug + messageCode:kGULNetworkMessageCodeURLSession007 + message:@"Cancelling authentication challenge for host. Host" + context:self->_request.URL]; + completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil); + } + }; + + // Retain the trust object to avoid a SecTrustEvaluate() crash on iOS 7. + CFRetain(serverTrust); + + // Evaluate the certificate chain. + // + // The delegate queue may be the main thread. Trust evaluation could cause some + // blocking network activity, so we must evaluate async, as documented at + // https://developer.apple.com/library/ios/technotes/tn2232/ + dispatch_queue_t evaluateBackgroundQueue = + dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + + dispatch_async(evaluateBackgroundQueue, ^{ + SecTrustResultType trustEval = kSecTrustResultInvalid; + BOOL shouldAllow; + OSStatus trustError; + + @synchronized([GULNetworkURLSession class]) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + trustError = SecTrustEvaluate(serverTrust, &trustEval); +#pragma clang diagnostic pop + } + + if (trustError != errSecSuccess) { + [self->_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession008 + message:@"Cannot evaluate server trust. Error, host" + contexts:@[ @(trustError), self->_request.URL ]]; + shouldAllow = NO; + } else { + // Having a trust level "unspecified" by the user is the usual result, described at + // https://developer.apple.com/library/mac/qa/qa1360 + shouldAllow = + (trustEval == kSecTrustResultUnspecified || trustEval == kSecTrustResultProceed); + } + + // Call the call back with the permission. + callback(shouldAllow); + + CFRelease(serverTrust); + }); + return; + } + + // Default handling for other Auth Challenges. + completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); +} + +#pragma mark - Internal Methods + +/// Stores system completion handler with session ID as key. +- (void)addSystemCompletionHandler:(GULNetworkSystemCompletionHandler)handler + forSession:(NSString *)identifier { + if (!handler) { + [_loggerDelegate + GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession009 + message:@"Cannot store nil system completion handler in network"]; + return; + } + + if (!identifier.length) { + [_loggerDelegate + GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession010 + message:@"Cannot store system completion handler with empty network " + "session identifier"]; + return; + } + + GULMutableDictionary *systemCompletionHandlers = + [[self class] sessionIDToSystemCompletionHandlerDictionary]; + if (systemCompletionHandlers[identifier]) { + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelWarning + messageCode:kGULNetworkMessageCodeURLSession011 + message:@"Got multiple system handlers for a single session ID" + context:identifier]; + } + + systemCompletionHandlers[identifier] = handler; +} + +/// Calls the system provided completion handler with the session ID stored in the dictionary. +/// The handler will be removed from the dictionary after being called. +- (void)callSystemCompletionHandler:(NSString *)identifier { + GULMutableDictionary *systemCompletionHandlers = + [[self class] sessionIDToSystemCompletionHandlerDictionary]; + GULNetworkSystemCompletionHandler handler = [systemCompletionHandlers objectForKey:identifier]; + + if (handler) { + [systemCompletionHandlers removeObjectForKey:identifier]; + + dispatch_async(dispatch_get_main_queue(), ^{ + handler(); + }); + } +} + +/// Sets or updates the session ID of this session. +- (void)setSessionID:(NSString *)sessionID { + _sessionID = [sessionID copy]; +} + +/// Creates a background session configuration with the session ID using the supported method. +- (NSURLSessionConfiguration *)backgroundSessionConfigWithSessionID:(NSString *)sessionID { + return [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:sessionID]; +} + +- (void)maybeRemoveTempFilesAtURL:(NSURL *)folderURL expiringTime:(NSTimeInterval)staleTime { + if (!folderURL.absoluteString.length) { + return; + } + + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSError *error = nil; + + NSArray *properties = @[ NSURLCreationDateKey ]; + NSArray *directoryContent = + [fileManager contentsOfDirectoryAtURL:folderURL + includingPropertiesForKeys:properties + options:NSDirectoryEnumerationSkipsSubdirectoryDescendants + error:&error]; + if (error && error.code != NSFileReadNoSuchFileError) { + [_loggerDelegate + GULNetwork_logWithLevel:kGULNetworkLogLevelDebug + messageCode:kGULNetworkMessageCodeURLSession012 + message:@"Cannot get files from the temporary network folder. Error" + context:error]; + return; + } + + if (!directoryContent.count) { + return; + } + + NSTimeInterval now = [NSDate date].timeIntervalSince1970; + for (NSURL *tempFile in directoryContent) { + NSDate *creationDate; + BOOL getCreationDate = [tempFile getResourceValue:&creationDate + forKey:NSURLCreationDateKey + error:NULL]; + if (!getCreationDate) { + continue; + } + NSTimeInterval creationTimeInterval = creationDate.timeIntervalSince1970; + if (fabs(now - creationTimeInterval) > staleTime) { + [self removeTempItemAtURL:tempFile]; + } + } +} + +/// Removes the temporary file written to disk for sending the request. It has to be cleaned up +/// after the session is done. +- (void)removeTempItemAtURL:(NSURL *)fileURL { + if (!fileURL.absoluteString.length) { + return; + } + + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSError *error = nil; + + if (![fileManager removeItemAtURL:fileURL error:&error] && error.code != NSFileNoSuchFileError) { + [_loggerDelegate + GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession013 + message:@"Failed to remove temporary uploading data file. Error" + context:error.localizedDescription]; + } +} + +/// Gets the fetcher with the session ID. ++ (instancetype)fetcherWithSessionIdentifier:(NSString *)sessionIdentifier { + GULNetworkURLSession *session = [self sessionFromFetcherMapForSessionID:sessionIdentifier]; + if (!session && [sessionIdentifier hasPrefix:kGULNetworkBackgroundSessionConfigIDPrefix]) { + session = [[GULNetworkURLSession alloc] initWithNetworkLoggerDelegate:nil]; + [session setSessionID:sessionIdentifier]; + [self setSessionInFetcherMap:session forSessionID:sessionIdentifier]; + } + return session; +} + +/// Returns a map of the fetcher by session ID. Creates a map if it is not created. +/// When reading and writing from/to the session map, don't use this method directly. +/// To avoid thread safety issues, use one of the helper methods at the bottom of the +/// file: setSessionInFetcherMap:forSessionID:, sessionFromFetcherMapForSessionID: ++ (NSMapTable *)sessionIDToFetcherMap { + static NSMapTable *sessionIDToFetcherMap; + + static dispatch_once_t sessionMapOnceToken; + dispatch_once(&sessionMapOnceToken, ^{ + sessionIDToFetcherMap = [NSMapTable strongToWeakObjectsMapTable]; + }); + return sessionIDToFetcherMap; +} + ++ (NSLock *)sessionIDToFetcherMapReadWriteLock { + static NSLock *lock; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + lock = [[NSLock alloc] init]; + }); + return lock; +} + +/// Returns a map of system provided completion handler by session ID. Creates a map if it is not +/// created. ++ (GULMutableDictionary *)sessionIDToSystemCompletionHandlerDictionary { + static GULMutableDictionary *systemCompletionHandlers; + + static dispatch_once_t systemCompletionHandlerOnceToken; + dispatch_once(&systemCompletionHandlerOnceToken, ^{ + systemCompletionHandlers = [[GULMutableDictionary alloc] init]; + }); + return systemCompletionHandlers; +} + +- (NSURL *)temporaryFilePathWithSessionID:(NSString *)sessionID { + NSString *tempName = [NSString stringWithFormat:@"GULUpload_temp_%@", sessionID]; + return [_networkDirectoryURL URLByAppendingPathComponent:tempName]; +} + +/// Makes sure that the directory to store temp files exists. If not, tries to create it and returns +/// YES. If there is anything wrong, returns NO. +- (BOOL)ensureTemporaryDirectoryExists { + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSError *error = nil; + + // Create a temporary directory if it does not exist or was deleted. + if ([_networkDirectoryURL checkResourceIsReachableAndReturnError:&error]) { + return YES; + } + + if (error && error.code != NSFileReadNoSuchFileError) { + [_loggerDelegate + GULNetwork_logWithLevel:kGULNetworkLogLevelWarning + messageCode:kGULNetworkMessageCodeURLSession014 + message:@"Error while trying to access Network temp folder. Error" + context:error]; + } + + NSError *writeError = nil; + + [fileManager createDirectoryAtURL:_networkDirectoryURL + withIntermediateDirectories:YES + attributes:nil + error:&writeError]; + if (writeError) { + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession015 + message:@"Cannot create temporary directory. Error" + context:writeError]; + return NO; + } + + // Set the iCloud exclusion attribute on the Documents URL. + [self excludeFromBackupForURL:_networkDirectoryURL]; + + return YES; +} + +- (void)excludeFromBackupForURL:(NSURL *)url { + if (!url.path) { + return; + } + + // Set the iCloud exclusion attribute on the Documents URL. + NSError *preventBackupError = nil; + [url setResourceValue:@YES forKey:NSURLIsExcludedFromBackupKey error:&preventBackupError]; + if (preventBackupError) { + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession016 + message:@"Cannot exclude temporary folder from iTunes backup"]; + } +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + willPerformHTTPRedirection:(NSHTTPURLResponse *)response + newRequest:(NSURLRequest *)request + completionHandler:(void (^)(NSURLRequest *))completionHandler API_AVAILABLE(ios(7.0)) { + NSArray *nonAllowedRedirectionCodes = @[ + @(kGULNetworkHTTPStatusCodeFound), @(kGULNetworkHTTPStatusCodeMovedPermanently), + @(kGULNetworkHTTPStatusCodeMovedTemporarily), @(kGULNetworkHTTPStatusCodeMultipleChoices) + ]; + + // Allow those not in the non allowed list to be followed. + if (![nonAllowedRedirectionCodes containsObject:@(response.statusCode)]) { + completionHandler(request); + return; + } + + // Do not allow redirection if the response code is in the non-allowed list. + NSURLRequest *newRequest = request; + + if (response) { + newRequest = nil; + } + + completionHandler(newRequest); +} + +#pragma mark - Helper Methods + ++ (void)setSessionInFetcherMap:(GULNetworkURLSession *)session forSessionID:(NSString *)sessionID { + [[self sessionIDToFetcherMapReadWriteLock] lock]; + GULNetworkURLSession *existingSession = + [[[self class] sessionIDToFetcherMap] objectForKey:sessionID]; + if (existingSession) { + if (session) { + NSString *message = [NSString stringWithFormat:@"Discarding session: %@", existingSession]; + [existingSession->_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelInfo + messageCode:kGULNetworkMessageCodeURLSession019 + message:message]; + } + [existingSession->_URLSession finishTasksAndInvalidate]; + } + if (session) { + [[[self class] sessionIDToFetcherMap] setObject:session forKey:sessionID]; + } else { + [[[self class] sessionIDToFetcherMap] removeObjectForKey:sessionID]; + } + [[self sessionIDToFetcherMapReadWriteLock] unlock]; +} + ++ (nullable GULNetworkURLSession *)sessionFromFetcherMapForSessionID:(NSString *)sessionID { + [[self sessionIDToFetcherMapReadWriteLock] lock]; + GULNetworkURLSession *session = [[[self class] sessionIDToFetcherMap] objectForKey:sessionID]; + [[self sessionIDToFetcherMapReadWriteLock] unlock]; + return session; +} + +- (void)callCompletionHandler:(GULNetworkURLSessionCompletionHandler)handler + withResponse:(NSHTTPURLResponse *)response + data:(NSData *)data + error:(NSError *)error { + if (error) { + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession017 + message:@"Encounter network error. Code, error" + contexts:@[ @(error.code), error ]]; + } + + if (handler) { + dispatch_async(dispatch_get_main_queue(), ^{ + handler(response, data, self->_sessionID, error); + }); + } +} + +// Always use the request parameters even if the default session configuration is more restrictive. +- (void)populateSessionConfig:(NSURLSessionConfiguration *)sessionConfig + withRequest:(NSURLRequest *)request API_AVAILABLE(ios(7.0)) { + sessionConfig.HTTPAdditionalHeaders = request.allHTTPHeaderFields; + sessionConfig.timeoutIntervalForRequest = request.timeoutInterval; + sessionConfig.timeoutIntervalForResource = request.timeoutInterval; + sessionConfig.requestCachePolicy = request.cachePolicy; +} + +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h b/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h new file mode 100644 index 0000000..a8cc45b --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h @@ -0,0 +1,46 @@ +/* + * 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 + +/// A mutable dictionary that provides atomic accessor and mutators. +@interface GULMutableDictionary : NSObject + +/// Returns an object given a key in the dictionary or nil if not found. +- (id)objectForKey:(id)key; + +/// Updates the object given its key or adds it to the dictionary if it is not in the dictionary. +- (void)setObject:(id)object forKey:(id)key; + +/// Removes the object given its session ID from the dictionary. +- (void)removeObjectForKey:(id)key; + +/// Removes all objects. +- (void)removeAllObjects; + +/// Returns the number of current objects in the dictionary. +- (NSUInteger)count; + +/// Returns an object given a key in the dictionary or nil if not found. +- (id)objectForKeyedSubscript:(id)key; + +/// Updates the object given its key or adds it to the dictionary if it is not in the dictionary. +- (void)setObject:(id)obj forKeyedSubscript:(id)key; + +/// Returns the immutable dictionary. +- (NSDictionary *)dictionary; + +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetwork.h b/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetwork.h new file mode 100644 index 0000000..8631b8b --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetwork.h @@ -0,0 +1,97 @@ +/* + * 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 + +#import "GULNetworkConstants.h" +#import "GULNetworkLoggerProtocol.h" +#import "GULNetworkURLSession.h" + +/// Delegate protocol for GULNetwork events. +@protocol GULNetworkReachabilityDelegate + +/// Tells the delegate to handle events when the network reachability changes to connected or not +/// connected. +- (void)reachabilityDidChange; + +@end + +/// The Network component that provides network status and handles network requests and responses. +/// This is not thread safe. +/// +/// NOTE: +/// User must add FIRAnalytics handleEventsForBackgroundURLSessionID:completionHandler to the +/// AppDelegate application:handleEventsForBackgroundURLSession:completionHandler: +@interface GULNetwork : NSObject + +/// Indicates if network connectivity is available. +@property(nonatomic, readonly, getter=isNetworkConnected) BOOL networkConnected; + +/// Indicates if there are any uploads in progress. +@property(nonatomic, readonly, getter=hasUploadInProgress) BOOL uploadInProgress; + +/// An optional delegate that can be used in the event when network reachability changes. +@property(nonatomic, weak) id reachabilityDelegate; + +/// An optional delegate that can be used to log messages, warnings or errors that occur in the +/// network operations. +@property(nonatomic, weak) id loggerDelegate; + +/// Indicates whether the logger should display debug messages. +@property(nonatomic, assign) BOOL isDebugModeEnabled; + +/// The time interval in seconds for the network request to timeout. +@property(nonatomic, assign) NSTimeInterval timeoutInterval; + +/// Initializes with the default reachability host. +- (instancetype)init; + +/// Initializes with a custom reachability host. +- (instancetype)initWithReachabilityHost:(NSString *)reachabilityHost; + +/// Handles events when background session with the given ID has finished. ++ (void)handleEventsForBackgroundURLSessionID:(NSString *)sessionID + completionHandler:(GULNetworkSystemCompletionHandler)completionHandler; + +/// Compresses and sends a POST request with the provided data to the URL. The session will be +/// background session if usingBackgroundSession is YES. Otherwise, the POST session is default +/// session. Returns a session ID or nil if an error occurs. +- (NSString *)postURL:(NSURL *)url + payload:(NSData *)payload + queue:(dispatch_queue_t)queue + usingBackgroundSession:(BOOL)usingBackgroundSession + completionHandler:(GULNetworkCompletionHandler)handler; + +/// Compresses and sends a POST request with the provided headers and data to the URL. The session +/// will be background session if usingBackgroundSession is YES. Otherwise, the POST session is +/// default session. Returns a session ID or nil if an error occurs. +- (NSString *)postURL:(NSURL *)url + headers:(NSDictionary *)headers + payload:(NSData *)payload + queue:(dispatch_queue_t)queue + usingBackgroundSession:(BOOL)usingBackgroundSession + completionHandler:(GULNetworkCompletionHandler)handler; + +/// Sends a GET request with the provided data to the URL. The session will be background session +/// if usingBackgroundSession is YES. Otherwise, the GET session is default session. Returns a +/// session ID or nil if an error occurs. +- (NSString *)getURL:(NSURL *)url + headers:(NSDictionary *)headers + queue:(dispatch_queue_t)queue + usingBackgroundSession:(BOOL)usingBackgroundSession + completionHandler:(GULNetworkCompletionHandler)handler; + +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkConstants.h b/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkConstants.h new file mode 100644 index 0000000..1cbedd1 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkConstants.h @@ -0,0 +1,71 @@ +/* + * 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 + +/// Error codes in Firebase Network error domain. +/// Note: these error codes should never change. It would make it harder to decode the errors if +/// we inadvertently altered any of these codes in a future SDK version. +typedef NS_ENUM(NSInteger, GULNetworkErrorCode) { + /// Unknown error. + GULNetworkErrorCodeUnknown = 0, + /// Error occurs when the request URL is invalid. + GULErrorCodeNetworkInvalidURL = 1, + /// Error occurs when request cannot be constructed. + GULErrorCodeNetworkRequestCreation = 2, + /// Error occurs when payload cannot be compressed. + GULErrorCodeNetworkPayloadCompression = 3, + /// Error occurs when session task cannot be created. + GULErrorCodeNetworkSessionTaskCreation = 4, + /// Error occurs when there is no response. + GULErrorCodeNetworkInvalidResponse = 5 +}; + +#pragma mark - Network constants + +/// The prefix of the ID of the background session. +extern NSString *const kGULNetworkBackgroundSessionConfigIDPrefix; + +/// The sub directory to store the files of data that is being uploaded in the background. +extern NSString *const kGULNetworkApplicationSupportSubdirectory; + +/// Name of the temporary directory that stores files for background uploading. +extern NSString *const kGULNetworkTempDirectoryName; + +/// The period when the temporary uploading file can stay. +extern const NSTimeInterval kGULNetworkTempFolderExpireTime; + +/// The default network request timeout interval. +extern const NSTimeInterval kGULNetworkTimeOutInterval; + +/// The host to check the reachability of the network. +extern NSString *const kGULNetworkReachabilityHost; + +/// The key to get the error context of the UserInfo. +extern NSString *const kGULNetworkErrorContext; + +#pragma mark - Network Status Code + +extern const int kGULNetworkHTTPStatusOK; +extern const int kGULNetworkHTTPStatusNoContent; +extern const int kGULNetworkHTTPStatusCodeMultipleChoices; +extern const int kGULNetworkHTTPStatusCodeMovedPermanently; +extern const int kGULNetworkHTTPStatusCodeFound; +extern const int kGULNetworkHTTPStatusCodeNotModified; +extern const int kGULNetworkHTTPStatusCodeMovedTemporarily; +extern const int kGULNetworkHTTPStatusCodeNotFound; +extern const int kGULNetworkHTTPStatusCodeCannotAcceptTraffic; +extern const int kGULNetworkHTTPStatusCodeUnavailable; diff --git a/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkLoggerProtocol.h b/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkLoggerProtocol.h new file mode 100644 index 0000000..425c073 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkLoggerProtocol.h @@ -0,0 +1,49 @@ +/* + * 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 + +#import "GULNetworkMessageCode.h" + +/// The log levels used by GULNetworkLogger. +typedef NS_ENUM(NSInteger, GULNetworkLogLevel) { + kGULNetworkLogLevelError = 3, + kGULNetworkLogLevelWarning = 4, + kGULNetworkLogLevelInfo = 6, + kGULNetworkLogLevelDebug = 7, +}; + +@protocol GULNetworkLoggerDelegate + +@required +/// Tells the delegate to log a message with an array of contexts and the log level. +- (void)GULNetwork_logWithLevel:(GULNetworkLogLevel)logLevel + messageCode:(GULNetworkMessageCode)messageCode + message:(NSString *)message + contexts:(NSArray *)contexts; + +/// Tells the delegate to log a message with a context and the log level. +- (void)GULNetwork_logWithLevel:(GULNetworkLogLevel)logLevel + messageCode:(GULNetworkMessageCode)messageCode + message:(NSString *)message + context:(id)context; + +/// Tells the delegate to log a message with the log level. +- (void)GULNetwork_logWithLevel:(GULNetworkLogLevel)logLevel + messageCode:(GULNetworkMessageCode)messageCode + message:(NSString *)message; + +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkMessageCode.h b/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkMessageCode.h new file mode 100644 index 0000000..507bc5a --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkMessageCode.h @@ -0,0 +1,47 @@ +/* + * 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 + +// Make sure these codes do not overlap with any contained in the FIRAMessageCode enum. +typedef NS_ENUM(NSInteger, GULNetworkMessageCode) { + // GULNetwork.m + kGULNetworkMessageCodeNetwork000 = 900000, // I-NET900000 + kGULNetworkMessageCodeNetwork001 = 900001, // I-NET900001 + kGULNetworkMessageCodeNetwork002 = 900002, // I-NET900002 + kGULNetworkMessageCodeNetwork003 = 900003, // I-NET900003 + // GULNetworkURLSession.m + kGULNetworkMessageCodeURLSession000 = 901000, // I-NET901000 + kGULNetworkMessageCodeURLSession001 = 901001, // I-NET901001 + kGULNetworkMessageCodeURLSession002 = 901002, // I-NET901002 + kGULNetworkMessageCodeURLSession003 = 901003, // I-NET901003 + kGULNetworkMessageCodeURLSession004 = 901004, // I-NET901004 + kGULNetworkMessageCodeURLSession005 = 901005, // I-NET901005 + kGULNetworkMessageCodeURLSession006 = 901006, // I-NET901006 + kGULNetworkMessageCodeURLSession007 = 901007, // I-NET901007 + kGULNetworkMessageCodeURLSession008 = 901008, // I-NET901008 + kGULNetworkMessageCodeURLSession009 = 901009, // I-NET901009 + kGULNetworkMessageCodeURLSession010 = 901010, // I-NET901010 + kGULNetworkMessageCodeURLSession011 = 901011, // I-NET901011 + kGULNetworkMessageCodeURLSession012 = 901012, // I-NET901012 + kGULNetworkMessageCodeURLSession013 = 901013, // I-NET901013 + kGULNetworkMessageCodeURLSession014 = 901014, // I-NET901014 + kGULNetworkMessageCodeURLSession015 = 901015, // I-NET901015 + kGULNetworkMessageCodeURLSession016 = 901016, // I-NET901016 + kGULNetworkMessageCodeURLSession017 = 901017, // I-NET901017 + kGULNetworkMessageCodeURLSession018 = 901018, // I-NET901018 + kGULNetworkMessageCodeURLSession019 = 901019, // I-NET901019 +}; diff --git a/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkURLSession.h b/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkURLSession.h new file mode 100644 index 0000000..3f9f7f9 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkURLSession.h @@ -0,0 +1,62 @@ +/* + * 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 + +#import "GULNetworkLoggerProtocol.h" + +NS_ASSUME_NONNULL_BEGIN + +typedef void (^GULNetworkCompletionHandler)(NSHTTPURLResponse *_Nullable response, + NSData *_Nullable data, + NSError *_Nullable error); +typedef void (^GULNetworkURLSessionCompletionHandler)(NSHTTPURLResponse *_Nullable response, + NSData *_Nullable data, + NSString *sessionID, + NSError *_Nullable error); +typedef void (^GULNetworkSystemCompletionHandler)(void); + +/// The protocol that uses NSURLSession for iOS >= 7.0 to handle requests and responses. +@interface GULNetworkURLSession : NSObject + +/// Indicates whether the background network is enabled. Default value is NO. +@property(nonatomic, getter=isBackgroundNetworkEnabled) BOOL backgroundNetworkEnabled; + +/// The logger delegate to log message, errors or warnings that occur during the network operations. +@property(nonatomic, weak, nullable) id loggerDelegate; + +/// Calls the system provided completion handler after the background session is finished. ++ (void)handleEventsForBackgroundURLSessionID:(NSString *)sessionID + completionHandler:(GULNetworkSystemCompletionHandler)completionHandler; + +/// Initializes with logger delegate. +- (instancetype)initWithNetworkLoggerDelegate: + (nullable id)networkLoggerDelegate NS_DESIGNATED_INITIALIZER; + +- (instancetype)init NS_UNAVAILABLE; + +/// Sends an asynchronous POST request and calls the provided completion handler when the request +/// completes or when errors occur, and returns an ID of the session/connection. +- (nullable NSString *)sessionIDFromAsyncPOSTRequest:(NSURLRequest *)request + completionHandler:(GULNetworkURLSessionCompletionHandler)handler; + +/// Sends an asynchronous GET request and calls the provided completion handler when the request +/// completes or when errors occur, and returns an ID of the session. +- (nullable NSString *)sessionIDFromAsyncGETRequest:(NSURLRequest *)request + completionHandler:(GULNetworkURLSessionCompletionHandler)handler; + +NS_ASSUME_NONNULL_END +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityChecker+Internal.h b/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityChecker+Internal.h new file mode 100644 index 0000000..103ed3b --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityChecker+Internal.h @@ -0,0 +1,48 @@ +/* + * 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 "GoogleUtilities/Reachability/Public/GoogleUtilities/GULReachabilityChecker.h" + +#if !TARGET_OS_WATCH +typedef SCNetworkReachabilityRef (*GULReachabilityCreateWithNameFn)(CFAllocatorRef allocator, + const char *host); + +typedef Boolean (*GULReachabilitySetCallbackFn)(SCNetworkReachabilityRef target, + SCNetworkReachabilityCallBack callback, + SCNetworkReachabilityContext *context); +typedef Boolean (*GULReachabilityScheduleWithRunLoopFn)(SCNetworkReachabilityRef target, + CFRunLoopRef runLoop, + CFStringRef runLoopMode); +typedef Boolean (*GULReachabilityUnscheduleFromRunLoopFn)(SCNetworkReachabilityRef target, + CFRunLoopRef runLoop, + CFStringRef runLoopMode); + +typedef void (*GULReachabilityReleaseFn)(CFTypeRef cf); + +struct GULReachabilityApi { + GULReachabilityCreateWithNameFn createWithNameFn; + GULReachabilitySetCallbackFn setCallbackFn; + GULReachabilityScheduleWithRunLoopFn scheduleWithRunLoopFn; + GULReachabilityUnscheduleFromRunLoopFn unscheduleFromRunLoopFn; + GULReachabilityReleaseFn releaseFn; +}; +#endif +@interface GULReachabilityChecker (Internal) + +- (const struct GULReachabilityApi *)reachabilityApi; +- (void)setReachabilityApi:(const struct GULReachabilityApi *)reachabilityApi; + +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityChecker.m b/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityChecker.m new file mode 100644 index 0000000..f0d1235 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityChecker.m @@ -0,0 +1,263 @@ +// 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 + +#import "GoogleUtilities/Reachability/Public/GoogleUtilities/GULReachabilityChecker.h" + +#import "GoogleUtilities/Reachability/GULReachabilityChecker+Internal.h" +#import "GoogleUtilities/Reachability/GULReachabilityMessageCode.h" + +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" + +static GULLoggerService kGULLoggerReachability = @"[GULReachability]"; +#if !TARGET_OS_WATCH +static void ReachabilityCallback(SCNetworkReachabilityRef reachability, + SCNetworkReachabilityFlags flags, + void *info); + +static const struct GULReachabilityApi kGULDefaultReachabilityApi = { + SCNetworkReachabilityCreateWithName, + SCNetworkReachabilitySetCallback, + SCNetworkReachabilityScheduleWithRunLoop, + SCNetworkReachabilityUnscheduleFromRunLoop, + CFRelease, +}; + +static NSString *const kGULReachabilityUnknownStatus = @"Unknown"; +static NSString *const kGULReachabilityConnectedStatus = @"Connected"; +static NSString *const kGULReachabilityDisconnectedStatus = @"Disconnected"; +#endif +@interface GULReachabilityChecker () + +@property(nonatomic, assign) const struct GULReachabilityApi *reachabilityApi; +@property(nonatomic, assign) GULReachabilityStatus reachabilityStatus; +@property(nonatomic, copy) NSString *host; +#if !TARGET_OS_WATCH +@property(nonatomic, assign) SCNetworkReachabilityRef reachability; +#endif + +@end + +@implementation GULReachabilityChecker + +@synthesize reachabilityApi = reachabilityApi_; +#if !TARGET_OS_WATCH +@synthesize reachability = reachability_; +#endif + +- (const struct GULReachabilityApi *)reachabilityApi { + return reachabilityApi_; +} + +- (void)setReachabilityApi:(const struct GULReachabilityApi *)reachabilityApi { +#if !TARGET_OS_WATCH + if (reachability_) { + GULLogError(kGULLoggerReachability, NO, + [NSString stringWithFormat:@"I-REA%06ld", (long)kGULReachabilityMessageCode000], + @"Cannot change reachability API while reachability is running. " + @"Call stop first."); + return; + } + reachabilityApi_ = reachabilityApi; +#endif +} + +@synthesize reachabilityStatus = reachabilityStatus_; +@synthesize host = host_; +@synthesize reachabilityDelegate = reachabilityDelegate_; + +- (BOOL)isActive { +#if !TARGET_OS_WATCH + return reachability_ != nil; +#else + return NO; +#endif +} + +- (void)setReachabilityDelegate:(id)reachabilityDelegate { + if (reachabilityDelegate && + (![(NSObject *)reachabilityDelegate conformsToProtocol:@protocol(GULReachabilityDelegate)])) { + GULLogError(kGULLoggerReachability, NO, + [NSString stringWithFormat:@"I-NET%06ld", (long)kGULReachabilityMessageCode005], + @"Reachability delegate doesn't conform to Reachability protocol."); + return; + } + reachabilityDelegate_ = reachabilityDelegate; +} + +- (instancetype)initWithReachabilityDelegate:(id)reachabilityDelegate + withHost:(NSString *)host { + self = [super init]; + + if (!host || !host.length) { + GULLogError(kGULLoggerReachability, NO, + [NSString stringWithFormat:@"I-REA%06ld", (long)kGULReachabilityMessageCode001], + @"Invalid host specified"); + return nil; + } + if (self) { +#if !TARGET_OS_WATCH + [self setReachabilityDelegate:reachabilityDelegate]; + reachabilityApi_ = &kGULDefaultReachabilityApi; + reachabilityStatus_ = kGULReachabilityUnknown; + host_ = [host copy]; + reachability_ = nil; +#endif + } + return self; +} + +- (void)dealloc { + reachabilityDelegate_ = nil; + [self stop]; +} + +- (BOOL)start { +#if TARGET_OS_WATCH + return NO; +#else + + if (!reachability_) { + reachability_ = reachabilityApi_->createWithNameFn(kCFAllocatorDefault, [host_ UTF8String]); + if (!reachability_) { + return NO; + } + SCNetworkReachabilityContext context = { + 0, /* version */ + (__bridge void *)(self), /* info (passed as last parameter to reachability callback) */ + NULL, /* retain */ + NULL, /* release */ + NULL /* copyDescription */ + }; + if (!reachabilityApi_->setCallbackFn(reachability_, ReachabilityCallback, &context) || + !reachabilityApi_->scheduleWithRunLoopFn(reachability_, CFRunLoopGetMain(), + kCFRunLoopCommonModes)) { + reachabilityApi_->releaseFn(reachability_); + reachability_ = nil; + + GULLogError(kGULLoggerReachability, NO, + [NSString stringWithFormat:@"I-REA%06ld", (long)kGULReachabilityMessageCode002], + @"Failed to start reachability handle"); + return NO; + } + } + GULLogDebug(kGULLoggerReachability, NO, + [NSString stringWithFormat:@"I-REA%06ld", (long)kGULReachabilityMessageCode003], + @"Monitoring the network status"); + return YES; +#endif +} + +- (void)stop { +#if !TARGET_OS_WATCH + if (reachability_) { + reachabilityStatus_ = kGULReachabilityUnknown; + reachabilityApi_->unscheduleFromRunLoopFn(reachability_, CFRunLoopGetMain(), + kCFRunLoopCommonModes); + reachabilityApi_->releaseFn(reachability_); + reachability_ = nil; + } +#endif +} + +#if !TARGET_OS_WATCH +- (GULReachabilityStatus)statusForFlags:(SCNetworkReachabilityFlags)flags { + GULReachabilityStatus status = kGULReachabilityNotReachable; + // If the Reachable flag is not set, we definitely don't have connectivity. + if (flags & kSCNetworkReachabilityFlagsReachable) { + // Reachable flag is set. Check further flags. + if (!(flags & kSCNetworkReachabilityFlagsConnectionRequired)) { +// Connection required flag is not set, so we have connectivity. +#if TARGET_OS_IOS || TARGET_OS_TV + status = (flags & kSCNetworkReachabilityFlagsIsWWAN) ? kGULReachabilityViaCellular + : kGULReachabilityViaWifi; +#elif TARGET_OS_OSX + status = kGULReachabilityViaWifi; +#endif + } else if ((flags & (kSCNetworkReachabilityFlagsConnectionOnDemand | + kSCNetworkReachabilityFlagsConnectionOnTraffic)) && + !(flags & kSCNetworkReachabilityFlagsInterventionRequired)) { +// If the connection on demand or connection on traffic flag is set, and user intervention +// is not required, we have connectivity. +#if TARGET_OS_IOS || TARGET_OS_TV + status = (flags & kSCNetworkReachabilityFlagsIsWWAN) ? kGULReachabilityViaCellular + : kGULReachabilityViaWifi; +#elif TARGET_OS_OSX + status = kGULReachabilityViaWifi; +#endif + } + } + return status; +} + +- (void)reachabilityFlagsChanged:(SCNetworkReachabilityFlags)flags { + GULReachabilityStatus status = [self statusForFlags:flags]; + if (reachabilityStatus_ != status) { + NSString *reachabilityStatusString; + if (status == kGULReachabilityUnknown) { + reachabilityStatusString = kGULReachabilityUnknownStatus; + } else { + reachabilityStatusString = (status == kGULReachabilityNotReachable) + ? kGULReachabilityDisconnectedStatus + : kGULReachabilityConnectedStatus; + } + + GULLogDebug(kGULLoggerReachability, NO, + [NSString stringWithFormat:@"I-REA%06ld", (long)kGULReachabilityMessageCode004], + @"Network status has changed. Code:%@, status:%@", @(status), + reachabilityStatusString); + reachabilityStatus_ = status; + [reachabilityDelegate_ reachability:self statusChanged:reachabilityStatus_]; + } +} + +#endif +@end + +#if !TARGET_OS_WATCH +static void ReachabilityCallback(SCNetworkReachabilityRef reachability, + SCNetworkReachabilityFlags flags, + void *info) { + GULReachabilityChecker *checker = (__bridge GULReachabilityChecker *)info; + [checker reachabilityFlagsChanged:flags]; +} +#endif + +// This function used to be at the top of the file, but it was moved here +// as a workaround for a suspected compiler bug. When compiled in Release mode +// and run on an iOS device with WiFi disabled, the reachability code crashed +// when calling SCNetworkReachabilityScheduleWithRunLoop, or shortly thereafter. +// After unsuccessfully trying to diagnose the cause of the crash, it was +// discovered that moving this function to the end of the file magically fixed +// the crash. If you are going to edit this file, exercise caution and make sure +// to test thoroughly with an iOS device under various network conditions. +const NSString *GULReachabilityStatusString(GULReachabilityStatus status) { + switch (status) { + case kGULReachabilityUnknown: + return @"Reachability Unknown"; + + case kGULReachabilityNotReachable: + return @"Not reachable"; + + case kGULReachabilityViaWifi: + return @"Reachable via Wifi"; + + case kGULReachabilityViaCellular: + return @"Reachable via Cellular Data"; + + default: + return [NSString stringWithFormat:@"Invalid reachability status %d", (int)status]; + } +} diff --git a/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityMessageCode.h b/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityMessageCode.h new file mode 100644 index 0000000..373e0af --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityMessageCode.h @@ -0,0 +1,29 @@ +/* + * 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 + +// Make sure these codes do not overlap with any contained in the FIRAMessageCode enum. +typedef NS_ENUM(NSInteger, GULReachabilityMessageCode) { + // GULReachabilityChecker.m + kGULReachabilityMessageCode000 = 902000, // I-NET902000 + kGULReachabilityMessageCode001 = 902001, // I-NET902001 + kGULReachabilityMessageCode002 = 902002, // I-NET902002 + kGULReachabilityMessageCode003 = 902003, // I-NET902003 + kGULReachabilityMessageCode004 = 902004, // I-NET902004 + kGULReachabilityMessageCode005 = 902005, // I-NET902005 + kGULReachabilityMessageCode006 = 902006, // I-NET902006 +}; diff --git a/Pods/GoogleUtilities/GoogleUtilities/Reachability/Public/GoogleUtilities/GULReachabilityChecker.h b/Pods/GoogleUtilities/GoogleUtilities/Reachability/Public/GoogleUtilities/GULReachabilityChecker.h new file mode 100644 index 0000000..0c70c05 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Reachability/Public/GoogleUtilities/GULReachabilityChecker.h @@ -0,0 +1,79 @@ +/* + * 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 +#if !TARGET_OS_WATCH +#import +#endif + +/// Reachability Status +typedef enum { + kGULReachabilityUnknown, ///< Have not yet checked or been notified whether host is reachable. + kGULReachabilityNotReachable, ///< Host is not reachable. + kGULReachabilityViaWifi, ///< Host is reachable via Wifi. + kGULReachabilityViaCellular, ///< Host is reachable via cellular. +} GULReachabilityStatus; + +const NSString *GULReachabilityStatusString(GULReachabilityStatus status); + +@class GULReachabilityChecker; + +/// Google Analytics iOS Reachability Checker. +@protocol GULReachabilityDelegate +@required +/// Called when network status has changed. +- (void)reachability:(GULReachabilityChecker *)reachability + statusChanged:(GULReachabilityStatus)status; +@end + +/// Google Analytics iOS Network Status Checker. +@interface GULReachabilityChecker : NSObject + +/// The last known reachability status, or GULReachabilityStatusUnknown if the +/// checker is not active. +@property(nonatomic, readonly) GULReachabilityStatus reachabilityStatus; +/// The host to which reachability status is to be checked. +@property(nonatomic, copy, readonly) NSString *host; +/// The delegate to be notified of reachability status changes. +@property(nonatomic, weak) id reachabilityDelegate; +/// `YES` if the reachability checker is active, `NO` otherwise. +@property(nonatomic, readonly) BOOL isActive; + +/// Initialize the reachability checker. Note that you must call start to begin checking for and +/// receiving notifications about network status changes. +/// +/// @param reachabilityDelegate The delegate to be notified when reachability status to host +/// changes. +/// +/// @param host The name of the host. +/// +- (instancetype)initWithReachabilityDelegate:(id)reachabilityDelegate + withHost:(NSString *)host; + +- (instancetype)init NS_UNAVAILABLE; + +/// Start checking for reachability to the specified host. This has no effect if the status +/// checker is already checking for connectivity. +/// +/// @return `YES` if initiating status checking was successful or the status checking has already +/// been initiated, `NO` otherwise. +- (BOOL)start; + +/// Stop checking for reachability to the specified host. This has no effect if the status +/// checker is not checking for connectivity. +- (void)stop; + +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/UserDefaults/GULUserDefaults.m b/Pods/GoogleUtilities/GoogleUtilities/UserDefaults/GULUserDefaults.m new file mode 100644 index 0000000..1640d6e --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/UserDefaults/GULUserDefaults.m @@ -0,0 +1,213 @@ +// 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. + +#import "GoogleUtilities/UserDefaults/Public/GoogleUtilities/GULUserDefaults.h" + +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" + +NS_ASSUME_NONNULL_BEGIN + +static NSTimeInterval const kGULSynchronizeInterval = 1.0; + +static NSString *const kGULLogFormat = @"I-GUL%06ld"; + +static GULLoggerService kGULLogUserDefaultsService = @"[GoogleUtilities/UserDefaults]"; + +typedef NS_ENUM(NSInteger, GULUDMessageCode) { + GULUDMessageCodeInvalidKeyGet = 1, + GULUDMessageCodeInvalidKeySet = 2, + GULUDMessageCodeInvalidObjectSet = 3, + GULUDMessageCodeSynchronizeFailed = 4, +}; + +@interface GULUserDefaults () + +/// Equivalent to the suite name for NSUserDefaults. +@property(readonly) CFStringRef appNameRef; + +@property(atomic) BOOL isPreferenceFileExcluded; + +@end + +@implementation GULUserDefaults { + // The application name is the same with the suite name of the NSUserDefaults, and it is used for + // preferences. + CFStringRef _appNameRef; +} + ++ (GULUserDefaults *)standardUserDefaults { + static GULUserDefaults *standardUserDefaults; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + standardUserDefaults = [[GULUserDefaults alloc] init]; + }); + return standardUserDefaults; +} + +- (instancetype)init { + return [self initWithSuiteName:nil]; +} + +- (instancetype)initWithSuiteName:(nullable NSString *)suiteName { + self = [super init]; + + NSString *name = [suiteName copy]; + + if (self) { + // `kCFPreferencesCurrentApplication` maps to the same defaults database as + // `[NSUserDefaults standardUserDefaults]`. + _appNameRef = + name.length ? (__bridge_retained CFStringRef)name : kCFPreferencesCurrentApplication; + } + + return self; +} + +- (void)dealloc { + // If we're using a custom `_appNameRef` it needs to be released. If it's a constant, it shouldn't + // need to be released since we don't own it. + if (CFStringCompare(_appNameRef, kCFPreferencesCurrentApplication, 0) != kCFCompareEqualTo) { + CFRelease(_appNameRef); + } + + [NSObject cancelPreviousPerformRequestsWithTarget:self + selector:@selector(synchronize) + object:nil]; +} + +- (nullable id)objectForKey:(NSString *)defaultName { + NSString *key = [defaultName copy]; + if (![key isKindOfClass:[NSString class]] || !key.length) { + GULLogWarning(@"", NO, + [NSString stringWithFormat:kGULLogFormat, (long)GULUDMessageCodeInvalidKeyGet], + @"Cannot get object for invalid user default key."); + return nil; + } + return (__bridge_transfer id)CFPreferencesCopyAppValue((__bridge CFStringRef)key, _appNameRef); +} + +- (void)setObject:(nullable id)value forKey:(NSString *)defaultName { + NSString *key = [defaultName copy]; + if (![key isKindOfClass:[NSString class]] || !key.length) { + GULLogWarning(kGULLogUserDefaultsService, NO, + [NSString stringWithFormat:kGULLogFormat, (long)GULUDMessageCodeInvalidKeySet], + @"Cannot set object for invalid user default key."); + return; + } + if (!value) { + CFPreferencesSetAppValue((__bridge CFStringRef)key, NULL, _appNameRef); + [self scheduleSynchronize]; + return; + } + BOOL isAcceptableValue = + [value isKindOfClass:[NSString class]] || [value isKindOfClass:[NSNumber class]] || + [value isKindOfClass:[NSArray class]] || [value isKindOfClass:[NSDictionary class]] || + [value isKindOfClass:[NSDate class]] || [value isKindOfClass:[NSData class]]; + if (!isAcceptableValue) { + GULLogWarning(kGULLogUserDefaultsService, NO, + [NSString stringWithFormat:kGULLogFormat, (long)GULUDMessageCodeInvalidObjectSet], + @"Cannot set invalid object to user defaults. Must be a string, number, array, " + @"dictionary, date, or data. Value: %@", + value); + return; + } + + CFPreferencesSetAppValue((__bridge CFStringRef)key, (__bridge CFStringRef)value, _appNameRef); + [self scheduleSynchronize]; +} + +- (void)removeObjectForKey:(NSString *)key { + [self setObject:nil forKey:key]; +} + +#pragma mark - Getters + +- (NSInteger)integerForKey:(NSString *)defaultName { + NSNumber *object = [self objectForKey:defaultName]; + return object.integerValue; +} + +- (float)floatForKey:(NSString *)defaultName { + NSNumber *object = [self objectForKey:defaultName]; + return object.floatValue; +} + +- (double)doubleForKey:(NSString *)defaultName { + NSNumber *object = [self objectForKey:defaultName]; + return object.doubleValue; +} + +- (BOOL)boolForKey:(NSString *)defaultName { + NSNumber *object = [self objectForKey:defaultName]; + return object.boolValue; +} + +- (nullable NSString *)stringForKey:(NSString *)defaultName { + return [self objectForKey:defaultName]; +} + +- (nullable NSArray *)arrayForKey:(NSString *)defaultName { + return [self objectForKey:defaultName]; +} + +- (nullable NSDictionary *)dictionaryForKey:(NSString *)defaultName { + return [self objectForKey:defaultName]; +} + +#pragma mark - Setters + +- (void)setInteger:(NSInteger)integer forKey:(NSString *)defaultName { + [self setObject:@(integer) forKey:defaultName]; +} + +- (void)setFloat:(float)value forKey:(NSString *)defaultName { + [self setObject:@(value) forKey:defaultName]; +} + +- (void)setDouble:(double)doubleNumber forKey:(NSString *)defaultName { + [self setObject:@(doubleNumber) forKey:defaultName]; +} + +- (void)setBool:(BOOL)boolValue forKey:(NSString *)defaultName { + [self setObject:@(boolValue) forKey:defaultName]; +} + +#pragma mark - Save data + +- (void)synchronize { + if (!CFPreferencesAppSynchronize(_appNameRef)) { + GULLogError(kGULLogUserDefaultsService, NO, + [NSString stringWithFormat:kGULLogFormat, (long)GULUDMessageCodeSynchronizeFailed], + @"Cannot synchronize user defaults to disk"); + } +} + +#pragma mark - Private methods + +- (void)scheduleSynchronize { + // Synchronize data using a timer so that multiple set... calls can be coalesced under one + // synchronize. + [NSObject cancelPreviousPerformRequestsWithTarget:self + selector:@selector(synchronize) + object:nil]; + // This method may be called on multiple queues (due to set... methods can be called on any queue) + // synchronize can be scheduled on different queues, so make sure that it does not crash. If this + // instance goes away, self will be released also, no one will retain it and the schedule won't be + // called. + [self performSelector:@selector(synchronize) withObject:nil afterDelay:kGULSynchronizeInterval]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleUtilities/GoogleUtilities/UserDefaults/Public/GoogleUtilities/GULUserDefaults.h b/Pods/GoogleUtilities/GoogleUtilities/UserDefaults/Public/GoogleUtilities/GULUserDefaults.h new file mode 100644 index 0000000..0d04781 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/UserDefaults/Public/GoogleUtilities/GULUserDefaults.h @@ -0,0 +1,110 @@ +// 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. + +#import + +NS_ASSUME_NONNULL_BEGIN + +/// A thread-safe user defaults that uses C functions from CFPreferences.h instead of +/// `NSUserDefaults`. This is to avoid sending an `NSNotification` when it's changed from a +/// background thread to avoid crashing. // TODO: Insert radar number here. +@interface GULUserDefaults : NSObject + +/// A shared user defaults similar to +[NSUserDefaults standardUserDefaults] and accesses the same +/// data of the standardUserDefaults. ++ (GULUserDefaults *)standardUserDefaults; + +/// Initializes preferences with a suite name that is the same with the NSUserDefaults' suite name. +/// Both of CFPreferences and NSUserDefaults share the same plist file so their data will exactly +/// the same. +/// +/// @param suiteName The name of the suite of the user defaults. +- (instancetype)initWithSuiteName:(nullable NSString *)suiteName; + +#pragma mark - Getters + +/// Searches the receiver's search list for a default with the key 'defaultName' and return it. If +/// another process has changed defaults in the search list, NSUserDefaults will automatically +/// update to the latest values. If the key in question has been marked as ubiquitous via a Defaults +/// Configuration File, the latest value may not be immediately available, and the registered value +/// will be returned instead. +- (nullable id)objectForKey:(NSString *)defaultName; + +/// Equivalent to -objectForKey:, except that it will return nil if the value is not an NSArray. +- (nullable NSArray *)arrayForKey:(NSString *)defaultName; + +/// Equivalent to -objectForKey:, except that it will return nil if the value +/// is not an NSDictionary. +- (nullable NSDictionary *)dictionaryForKey:(NSString *)defaultName; + +/// Equivalent to -objectForKey:, except that it will convert NSNumber values to their NSString +/// representation. If a non-string non-number value is found, nil will be returned. +- (nullable NSString *)stringForKey:(NSString *)defaultName; + +/// Equivalent to -objectForKey:, except that it converts the returned value to an NSInteger. If the +/// value is an NSNumber, the result of -integerValue will be returned. If the value is an NSString, +/// it will be converted to NSInteger if possible. If the value is a boolean, it will be converted +/// to either 1 for YES or 0 for NO. If the value is absent or can't be converted to an integer, 0 +/// will be returned. +- (NSInteger)integerForKey:(NSString *)defaultName; + +/// Similar to -integerForKey:, except that it returns a float, and boolean values will not be +/// converted. +- (float)floatForKey:(NSString *)defaultName; + +/// Similar to -integerForKey:, except that it returns a double, and boolean values will not be +/// converted. +- (double)doubleForKey:(NSString *)defaultName; + +/// Equivalent to -objectForKey:, except that it converts the returned value to a BOOL. If the value +/// is an NSNumber, NO will be returned if the value is 0, YES otherwise. If the value is an +/// NSString, values of "YES" or "1" will return YES, and values of "NO", "0", or any other string +/// will return NO. If the value is absent or can't be converted to a BOOL, NO will be returned. +- (BOOL)boolForKey:(NSString *)defaultName; + +#pragma mark - Setters + +/// Immediately stores a value (or removes the value if `nil` is passed as the value) for the +/// provided key in the search list entry for the receiver's suite name in the current user and any +/// host, then asynchronously stores the value persistently, where it is made available to other +/// processes. +- (void)setObject:(nullable id)value forKey:(NSString *)defaultName; + +/// Equivalent to -setObject:forKey: except that the value is converted from a float to an NSNumber. +- (void)setFloat:(float)value forKey:(NSString *)defaultName; + +/// Equivalent to -setObject:forKey: except that the value is converted from a double to an +/// NSNumber. +- (void)setDouble:(double)value forKey:(NSString *)defaultName; + +/// Equivalent to -setObject:forKey: except that the value is converted from an NSInteger to an +/// NSNumber. +- (void)setInteger:(NSInteger)value forKey:(NSString *)defaultName; + +/// Equivalent to -setObject:forKey: except that the value is converted from a BOOL to an NSNumber. +- (void)setBool:(BOOL)value forKey:(NSString *)defaultName; + +#pragma mark - Removing Defaults + +/// Equivalent to -[... setObject:nil forKey:defaultName] +- (void)removeObjectForKey:(NSString *)defaultName; + +#pragma mark - Save data + +/// Blocks the calling thread until all in-progress set operations have completed. +- (void)synchronize; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleUtilities/LICENSE b/Pods/GoogleUtilities/LICENSE new file mode 100644 index 0000000..30a8f72 --- /dev/null +++ b/Pods/GoogleUtilities/LICENSE @@ -0,0 +1,247 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. + +================================================================================ + +The following copyright from Landon J. Fuller applies to the isAppEncrypted +function in Environment/third_party/GULAppEnvironmentUtil.m. + +Copyright (c) 2017 Landon J. Fuller +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Comment from +iPhone Dev Wiki +Crack Prevention: App Store binaries are signed by both their developer +and Apple. This encrypts the binary so that decryption keys are needed in order +to make the binary readable. When iOS executes the binary, the decryption keys +are used to decrypt the binary into a readable state where it is then loaded +into memory and executed. iOS can tell the encryption status of a binary via the +cryptid structure member of LC_ENCRYPTION_INFO MachO load command. If cryptid is +a non-zero value then the binary is encrypted. + +'Cracking' works by letting the kernel decrypt the binary then siphoning the +decrypted data into a new binary file, resigning, and repackaging. This will +only work on jailbroken devices as codesignature validation has been removed. +Resigning takes place because while the codesignature doesn't have to be valid +thanks to the jailbreak, it does have to be in place unless you have AppSync or +similar to disable codesignature checks. + +More information at Landon +Fuller's blog diff --git a/Pods/GoogleUtilities/README.md b/Pods/GoogleUtilities/README.md new file mode 100644 index 0000000..e5d0b21 --- /dev/null +++ b/Pods/GoogleUtilities/README.md @@ -0,0 +1,189 @@ +[![Version](https://img.shields.io/cocoapods/v/GoogleUtilities.svg?style=flat)](https://cocoapods.org/pods/GoogleUtilities) +[![License](https://img.shields.io/cocoapods/l/GoogleUtilities.svg?style=flat)](https://cocoapods.org/pods/GoogleUtilities) +[![Platform](https://img.shields.io/cocoapods/p/GoogleUtilities.svg?style=flat)](https://cocoapods.org/pods/GoogleUtilities) + +[![Actions Status][gh-google-utilities-badge]][gh-actions] + +# GoogleUtilities + +GoogleUtilities provides a set of utilities for Firebase and other Google SDKs for Apple platform +development. + +The utilities are not directly supported for non-Google library usage. + +## Integration Testing +These instructions apply to minor and patch version updates. Major versions need +a customized adaptation. + +After the CI is green: +* Determine the next version for release by checking the + [tagged releases](https://github.com/google/GoogleUtilities/tags). + Ensure that the next release version keeps the Swift PM and CocoaPods versions in sync. +* Verify that the releasing version is the latest entry in the [CHANGELOG.md](CHANGELOG.md), + updating it if necessary. +* Update the version in the podspec to match the latest entry in the [CHANGELOG.md](CHANGELOG.md) +* Checkout the `main` branch and ensure it is up to date + ```console + git checkout main + git pull + ``` +* Add the CocoaPods tag (`{version}` will be the latest version in the [podspec](GoogleUtilities.podspec#L3)) + ```console + git tag CocoaPods-{version} + git push origin CocoaPods-{version} + ``` +* Push the podspec to the designated repo + * If this version of GoogleUtilities is intended to launch **before or with** the next Firebase release: +

+ Push to SpecsStaging + + ```console + pod repo push --skip-tests staging GoogleUtilities.podspec + ``` + + If the command fails with `Unable to find the 'staging' repo.`, add the staging repo with: + ```console + pod repo add staging git@github.com:firebase/SpecsStaging.git + ``` +
+ * Otherwise: +
+ Push to SpecsDev + + ```console + pod repo push --skip-tests dev GoogleUtilities.podspec + ``` + + If the command fails with `Unable to find the 'dev' repo.`, add the dev repo with: + ```console + pod repo add dev git@github.com:firebase/SpecsDev.git + ``` +
+* Run Firebase CI by waiting until next nightly or adding a PR that touches `Gemfile`. +* On google3, run copybara using the command below. Then, start a global TAP on the generated CL. Deflake as needed. + ```console + third_party/firebase/ios/Releases/run_copy_bara.py --directory GoogleUtilities --branch main + ``` + +## Publishing +The release process is as follows: +1. [Tag and release for Swift PM](#swift-package-manager) +2. [Publish to CocoaPods](#cocoapods) +3. [Create GitHub Release](#create-github-release) +4. [Perform post release cleanup](#post-release-cleanup) + +### Swift Package Manager + By creating and [pushing a tag](https://github.com/google/GoogleUtilities/tags) + for Swift PM, the newly tagged version will be immediately released for public use. + Given this, please verify the intended time of release for Swift PM. + * Add a version tag for Swift PM + ```console + git tag {version} + git push origin {version} + ``` + *Note: Ensure that any inflight PRs that depend on the new `GoogleUtilities` version are updated to point to the + newly tagged version rather than a checksum.* + +### CocoaPods +* Publish the newly versioned pod to CocoaPods + + It's recommended to point to the `GoogleUtilities.podspec` in `staging` to make sure the correct spec is being published. + ```console + pod trunk push ~/.cocoapods/repos/staging/GoogleUtilities/{version}/GoogleUtilities.podspec + ``` + *Note: In some cases, it may be acceptable to `pod trunk push` with the `--skip-tests` flag. Please double check with + the maintainers before doing so.* + + The pod push was successful if the above command logs: `🚀 GoogleUtilities ({version}) successfully published`. + In addition, a new commit that publishes the new version (co-authored by [CocoaPodsAtGoogle](https://github.com/CocoaPodsAtGoogle)) + should appear in the [CocoaPods specs repo](https://github.com/CocoaPods/Specs). Last, the latest version should be displayed + on [GoogleUtilities's CocoaPods page](https://cocoapods.org/pods/GoogleUtilities). + +### [Create GitHub Release](https://github.com/google/GoogleUtilities/releases/new/) + Update the [release template](https://github.com/google/GoogleUtilities/releases/new/)'s **Tag version** and **Release title** + fields with the latest version. In addition, reference the [Release Notes](./CHANGELOG.md) in the release's description. + + See [this release](https://github.com/google/GoogleUtilities/releases/edit/7.7.0) for an example. + + *Don't forget to perform the [post release cleanup](#post-release-cleanup)!* + +### Post Release Cleanup +
+ Clean up SpecsStaging + + ```console + pwd=$(pwd) + mkdir -p /tmp/release-cleanup && cd $_ + git clone git@github.com:firebase/SpecsStaging.git + cd SpecsStaging/ + git rm -rf GoogleUtilities/ + git commit -m "Post publish cleanup" + git push origin master + rm -rf /tmp/release-cleanup + cd $pwd + ``` +
+ +## Development + +To develop in this repository, ensure that you have at least the following software: + + * Xcode 12.0 (or later) + * CocoaPods 1.10.0 (or later) + * [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +`pod gen GoogleUtilities.podspec --local-sources=./ --auto-open --platforms=ios` + +Note: If the CocoaPods cache is out of date, you may need to run +`pod repo update` before the `pod gen` command. + +Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for +those platforms. Since 10.2, Xcode does not properly handle multi-platform +CocoaPods workspaces. + +### Development for Catalyst +* `pod gen GoogleUtilities.podspec --local-sources=./ --auto-open --platforms=ios` +* Check the Mac box in the App-iOS Build Settings +* Sign the App in the Settings Signing & Capabilities tab +* Click Pods in the Project Manager +* Add Signing to the iOS host app and unit test targets +* Select the Unit-unit scheme +* Run it to build and test + +Alternatively disable signing in each target: +* Go to Build Settings tab +* Click `+` +* Select `Add User-Defined Setting` +* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO` + +### Code Formatting + +To ensure that the code is formatted consistently, run the script +[./scripts/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/master/scripts/check.sh) +before creating a PR. + +GitHub Actions will verify that any code changes are done in a style compliant +way. Install `clang-format` and `mint`: + +```console +brew install clang-format@16 +brew install mint +``` + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +## Contributing + +See [Contributing](CONTRIBUTING.md). + +## License + +The contents of this repository is licensed under the +[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). + +[gh-actions]: https://github.com/firebase/firebase-ios-sdk/actions +[gh-google-utilities-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/google-utilities/badge.svg diff --git a/Pods/Headers/Private/Firebase/Firebase.h b/Pods/Headers/Private/Firebase/Firebase.h new file mode 120000 index 0000000..07ac6eb --- /dev/null +++ b/Pods/Headers/Private/Firebase/Firebase.h @@ -0,0 +1 @@ +../../../Firebase/CoreOnly/Sources/Firebase.h \ No newline at end of file diff --git a/Pods/Headers/Public/Firebase/Firebase.h b/Pods/Headers/Public/Firebase/Firebase.h new file mode 120000 index 0000000..07ac6eb --- /dev/null +++ b/Pods/Headers/Public/Firebase/Firebase.h @@ -0,0 +1 @@ +../../../Firebase/CoreOnly/Sources/Firebase.h \ No newline at end of file diff --git a/Pods/Manifest.lock b/Pods/Manifest.lock new file mode 100644 index 0000000..86b9403 --- /dev/null +++ b/Pods/Manifest.lock @@ -0,0 +1,150 @@ +PODS: + - Firebase/Auth (10.11.0): + - Firebase/CoreOnly + - FirebaseAuth (~> 10.11.0) + - Firebase/Core (10.11.0): + - Firebase/CoreOnly + - FirebaseAnalytics (~> 10.11.0) + - Firebase/CoreOnly (10.11.0): + - FirebaseCore (= 10.11.0) + - Firebase/Database (10.11.0): + - Firebase/CoreOnly + - FirebaseDatabase (~> 10.11.0) + - FirebaseAnalytics (10.11.0): + - FirebaseAnalytics/AdIdSupport (= 10.11.0) + - FirebaseCore (~> 10.0) + - FirebaseInstallations (~> 10.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.11) + - GoogleUtilities/MethodSwizzler (~> 7.11) + - GoogleUtilities/Network (~> 7.11) + - "GoogleUtilities/NSData+zlib (~> 7.11)" + - nanopb (< 2.30910.0, >= 2.30908.0) + - FirebaseAnalytics/AdIdSupport (10.11.0): + - FirebaseCore (~> 10.0) + - FirebaseInstallations (~> 10.0) + - GoogleAppMeasurement (= 10.11.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.11) + - GoogleUtilities/MethodSwizzler (~> 7.11) + - GoogleUtilities/Network (~> 7.11) + - "GoogleUtilities/NSData+zlib (~> 7.11)" + - nanopb (< 2.30910.0, >= 2.30908.0) + - FirebaseAppCheckInterop (10.11.0) + - FirebaseAuth (10.11.0): + - FirebaseAppCheckInterop (~> 10.0) + - FirebaseCore (~> 10.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.8) + - GoogleUtilities/Environment (~> 7.8) + - GTMSessionFetcher/Core (< 4.0, >= 2.1) + - FirebaseCore (10.11.0): + - FirebaseCoreInternal (~> 10.0) + - GoogleUtilities/Environment (~> 7.8) + - GoogleUtilities/Logger (~> 7.8) + - FirebaseCoreInternal (10.11.0): + - "GoogleUtilities/NSData+zlib (~> 7.8)" + - FirebaseDatabase (10.11.0): + - FirebaseCore (~> 10.0) + - leveldb-library (~> 1.22) + - FirebaseInstallations (10.11.0): + - FirebaseCore (~> 10.0) + - GoogleUtilities/Environment (~> 7.8) + - GoogleUtilities/UserDefaults (~> 7.8) + - PromisesObjC (~> 2.1) + - GoogleAppMeasurement (10.11.0): + - GoogleAppMeasurement/AdIdSupport (= 10.11.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.11) + - GoogleUtilities/MethodSwizzler (~> 7.11) + - GoogleUtilities/Network (~> 7.11) + - "GoogleUtilities/NSData+zlib (~> 7.11)" + - nanopb (< 2.30910.0, >= 2.30908.0) + - GoogleAppMeasurement/AdIdSupport (10.11.0): + - GoogleAppMeasurement/WithoutAdIdSupport (= 10.11.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.11) + - GoogleUtilities/MethodSwizzler (~> 7.11) + - GoogleUtilities/Network (~> 7.11) + - "GoogleUtilities/NSData+zlib (~> 7.11)" + - nanopb (< 2.30910.0, >= 2.30908.0) + - GoogleAppMeasurement/WithoutAdIdSupport (10.11.0): + - GoogleUtilities/AppDelegateSwizzler (~> 7.11) + - GoogleUtilities/MethodSwizzler (~> 7.11) + - GoogleUtilities/Network (~> 7.11) + - "GoogleUtilities/NSData+zlib (~> 7.11)" + - nanopb (< 2.30910.0, >= 2.30908.0) + - GoogleUtilities/AppDelegateSwizzler (7.11.1): + - GoogleUtilities/Environment + - GoogleUtilities/Logger + - GoogleUtilities/Network + - GoogleUtilities/Environment (7.11.1): + - PromisesObjC (< 3.0, >= 1.2) + - GoogleUtilities/Logger (7.11.1): + - GoogleUtilities/Environment + - GoogleUtilities/MethodSwizzler (7.11.1): + - GoogleUtilities/Logger + - GoogleUtilities/Network (7.11.1): + - GoogleUtilities/Logger + - "GoogleUtilities/NSData+zlib" + - GoogleUtilities/Reachability + - "GoogleUtilities/NSData+zlib (7.11.1)" + - GoogleUtilities/Reachability (7.11.1): + - GoogleUtilities/Logger + - GoogleUtilities/UserDefaults (7.11.1): + - GoogleUtilities/Logger + - GTMSessionFetcher/Core (3.1.1) + - leveldb-library (1.22.2) + - nanopb (2.30909.0): + - nanopb/decode (= 2.30909.0) + - nanopb/encode (= 2.30909.0) + - nanopb/decode (2.30909.0) + - nanopb/encode (2.30909.0) + - PromisesObjC (2.2.0) + - Realm (10.41.0): + - Realm/Headers (= 10.41.0) + - Realm/Headers (10.41.0) + - RealmSwift (10.41.0): + - Realm (= 10.41.0) + +DEPENDENCIES: + - Firebase/Auth + - Firebase/Core + - Firebase/Database + - RealmSwift (~> 10) + +SPEC REPOS: + trunk: + - Firebase + - FirebaseAnalytics + - FirebaseAppCheckInterop + - FirebaseAuth + - FirebaseCore + - FirebaseCoreInternal + - FirebaseDatabase + - FirebaseInstallations + - GoogleAppMeasurement + - GoogleUtilities + - GTMSessionFetcher + - leveldb-library + - nanopb + - PromisesObjC + - Realm + - RealmSwift + +SPEC CHECKSUMS: + Firebase: 31d9575c124839fb5abc0db6d39511cc1dab1b85 + FirebaseAnalytics: 6c6bf99e8854475bf1fa342028841be8ecd236da + FirebaseAppCheckInterop: 255b6c0292fe5da995c8b2df0c02f6a3ca7f61b4 + FirebaseAuth: 7aabcb00fbf330db49c207c0d645b8b1b62df0e9 + FirebaseCore: 62fd4d549f5e3f3bd52b7998721c5fa0557fb355 + FirebaseCoreInternal: 9e46c82a14a3b3a25be4e1e151ce6d21536b89c0 + FirebaseDatabase: 4e1cb7f44ce6ffa553033913dd0d634b2310ce65 + FirebaseInstallations: 2a2c6859354cbec0a228a863d4daf6de7c74ced4 + GoogleAppMeasurement: d3dabccdb336fc0ae44b633c8abaa26559893cd9 + GoogleUtilities: 9aa0ad5a7bc171f8bae016300bfcfa3fb8425749 + GTMSessionFetcher: e8647203b65cee28c5f73d0f473d096653945e72 + leveldb-library: f03246171cce0484482ec291f88b6d563699ee06 + nanopb: b552cce312b6c8484180ef47159bc0f65a1f0431 + PromisesObjC: 09985d6d70fbe7878040aa746d78236e6946d2ef + Realm: 669efee7dc1ce0aa9f6739a60f8c0df0a3835067 + RealmSwift: 6b7b0e91b79dc66d5cfceeb3b319cacfc9b1a70e + +PODFILE CHECKSUM: aa7d3da7f5d56ddf2ffa51d4d394794236ee6717 + +COCOAPODS: 1.12.1 diff --git a/Pods/Pods.xcodeproj/project.pbxproj b/Pods/Pods.xcodeproj/project.pbxproj new file mode 100644 index 0000000..ae20426 --- /dev/null +++ b/Pods/Pods.xcodeproj/project.pbxproj @@ -0,0 +1,8417 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 56; + objects = { + +/* Begin PBXAggregateTarget section */ + 072CEA044D2EF26F03496D5996BBF59F /* Firebase */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 8EB88B4FC0FC9B16DC04AEB4E446B11D /* Build configuration list for PBXAggregateTarget "Firebase" */; + buildPhases = ( + ); + dependencies = ( + EE5FAD0A2825DCEFCA8DE9122EF93B48 /* PBXTargetDependency */, + E6E557B60C168CACEE6735A71890345A /* PBXTargetDependency */, + AB813BADA5C8B5B5E1AC06E26A0E4072 /* PBXTargetDependency */, + 774B463620166FF8826D78B6C95772B6 /* PBXTargetDependency */, + ); + name = Firebase; + productName = Firebase; + }; + B53D977A951AFC38B21751B706C1DF83 /* GoogleAppMeasurement */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 77A2A922B1E9CABA47FABBE48E70F593 /* Build configuration list for PBXAggregateTarget "GoogleAppMeasurement" */; + buildPhases = ( + 83B95425D2BD5BA4375FA7E7ABB6BD93 /* [CP] Copy XCFrameworks */, + ); + dependencies = ( + D322FD0C2A19F7C28987A7EECEDD22ED /* PBXTargetDependency */, + D11B3AC94525F901567ED83ABDA99EB1 /* PBXTargetDependency */, + ); + name = GoogleAppMeasurement; + productName = GoogleAppMeasurement; + }; + C49E7A4D59E5C8BE8DE9FB1EFB150185 /* FirebaseAnalytics */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 5823FAB140D66B9C27BAAB580E779242 /* Build configuration list for PBXAggregateTarget "FirebaseAnalytics" */; + buildPhases = ( + F1FD9E30F1BAAA93D028A88FBEB9E90F /* [CP] Copy XCFrameworks */, + ); + dependencies = ( + E5CCB3D080BE105847132F88805A855A /* PBXTargetDependency */, + D58FFA70B17AA29C1EBBF258007459DE /* PBXTargetDependency */, + 013E8573996C58ACAAC5E290C08CF0FA /* PBXTargetDependency */, + 5BDE0A3955F4B848ADBF521062D8852D /* PBXTargetDependency */, + A9B4A1AD9D39009794B539EBDE6DD5A1 /* PBXTargetDependency */, + ); + name = FirebaseAnalytics; + productName = FirebaseAnalytics; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 00617798FE5A15909C04A310A21147FF /* FirebaseCoreInternal-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A268D34F1B85A759DE13BDCDF787C6B /* FirebaseCoreInternal-dummy.m */; }; + 00693E81011B4F156A751125E729D2BD /* RLMThreadSafeReference.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 726B5EDE338F3B54A4CF771D23EA5618 /* RLMThreadSafeReference.h */; }; + 009D232C1C36C96BAAD1C29F8D70776D /* FPersistenceManager.m in Sources */ = {isa = PBXBuildFile; fileRef = E5728A1EC7C20549A71D8E4A6D437EC2 /* FPersistenceManager.m */; }; + 00B6A51F66E88F69863C2D92BA6F6562 /* RLMObjectStore.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = D153033C39ED5D472A14A8B145E0434D /* RLMObjectStore.h */; }; + 00CC58E0E5D67FF05E13D15377F3AB80 /* GTMSessionFetcherLogging.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ADBEEDE93688F19E571CE7A74DE23AD /* GTMSessionFetcherLogging.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 00FEC32E8F0A1C904919B1F4F522A0D7 /* FIRVerifyPhoneNumberRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 86A9DD91DF789DEE2B780190291B4392 /* FIRVerifyPhoneNumberRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 01B167FB9B5EE4202F1D7019DFBF1206 /* FIRSetAccountInfoResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = A9C5CAC11B532C8059B2E2040D5A2AE7 /* FIRSetAccountInfoResponse.m */; }; + 01C75D80D822B72FE13911FF8BBBA934 /* iterator.h in Headers */ = {isa = PBXBuildFile; fileRef = 9668070A520556E1157179EFD5675DA2 /* iterator.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 01E38B9CF9813D66B186AAEED4868E4D /* version_edit.h in Headers */ = {isa = PBXBuildFile; fileRef = 44DFA81BB6A42907B0617316BF7476AA /* version_edit.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 01FCD91768C7B43218C3250882812F23 /* FLLRBEmptyNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547375C6508BD409DCDF96AC19B46BD /* FLLRBEmptyNode.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 02153F7E42E3C9AE4AE7C4DBC80F19A9 /* FIRMultiFactorSession.m in Sources */ = {isa = PBXBuildFile; fileRef = A3DBB2AB553DB346C5F9A455867C76A4 /* FIRMultiFactorSession.m */; }; + 02328FAFA4CAC5A88D871C0D4281062A /* FIROptionsInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = B438E42DDF19AE28B09823D0CCEC5714 /* FIROptionsInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 02DA238295776C954EDDF831D7027D24 /* FImmutableTree.h in Headers */ = {isa = PBXBuildFile; fileRef = 972B364EC6AF475E2DD052A2A60FFC2A /* FImmutableTree.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 033B9A14A4E0FD6594EEBDD1C851F467 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEAE96632CC2337ED6A14302B3022EC8 /* SystemConfiguration.framework */; }; + 038242B952D8B42129B77E03E1A519A1 /* FIRUser.h in Headers */ = {isa = PBXBuildFile; fileRef = 0871B1AF60D0FA795C25D0BBC7A6B793 /* FIRUser.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 03C6606D7430D634EDC9A0A0E7C3C327 /* FIREmailAuthProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = BEA7AE33B74AF59CA502D5FDE7DCD982 /* FIREmailAuthProvider.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 03CDC8C7A3DD78EB4A71480159F2EDD2 /* FIRInstallationsSingleOperationPromiseCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BA7C44B9E19D70D498CD1406747C619 /* FIRInstallationsSingleOperationPromiseCache.m */; }; + 03FD460B72E20F8CEB4BAA02B6AB20EE /* FIREmailAuthProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 300EDAC88419BEDA22431274ECF54354 /* FIREmailAuthProvider.m */; }; + 04255801699620ACD92B0118549C4F6B /* GULURLSessionDataResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = C36ACCDE3C319DC975D64D8C09A4CB3C /* GULURLSessionDataResponse.m */; }; + 0442CEDEA4243DD8629F664272A285DE /* KeyPathStrings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 534282AC766172E1738511BDA8F27B1F /* KeyPathStrings.swift */; }; + 04A77BA00EE781F8B02B69EDBB61E959 /* crc32c.h in Headers */ = {isa = PBXBuildFile; fileRef = 2B1A9A9086F5222D113BD0D4C6521882 /* crc32c.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 04C54BD42C853B261EA081931344691B /* FIRAuthProto.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CF57CF9CBA1F70F48ADF8E3845AD4E5 /* FIRAuthProto.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 04CD6531A0F2CD57CD074175471F18B7 /* windows_logger.h in Headers */ = {isa = PBXBuildFile; fileRef = 7671FC7CD2367A77CBAF94D322CD3EA0 /* windows_logger.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 04D7C641B10FBB28AC75BF6A12614002 /* FIROAuthCredential.m in Sources */ = {isa = PBXBuildFile; fileRef = 6F17E4595E3BDA403E8C7DBF3F47B918 /* FIROAuthCredential.m */; }; + 04E0867585C77CDB92E740D5ED5E9DC0 /* FIRStartMFAEnrollmentRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 520F17A85613DE207C7D040EBDD6F8BD /* FIRStartMFAEnrollmentRequest.m */; }; + 04E85FDCD1BF5720CAE73C11B9DECA10 /* FIRDatabaseConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A980800E710A010DF494004C96778B7 /* FIRDatabaseConfig.m */; }; + 0511EE38AFFABD31A9AB86C4D34E7244 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB96318E2CB72DE3CDFEEF1B9E8644AD /* Foundation.framework */; }; + 05D13830C0296C1BC8EED51A2C8AC790 /* FIRDatabaseQuery.m in Sources */ = {isa = PBXBuildFile; fileRef = F1E367B64874B28C5E8947B105E8CB27 /* FIRDatabaseQuery.m */; }; + 061AAAC4865C320B832820C7A28132A5 /* FIRAuthAPNSToken.h in Headers */ = {isa = PBXBuildFile; fileRef = B7817A8A19488A6E5E1F62D68DACF069 /* FIRAuthAPNSToken.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 06304E80795DA749417F68A31C6A4D74 /* Results.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10310C29C4CC4CCC1AC43ECD64772E1C /* Results.swift */; }; + 0632B4C782BDE709D2E6D3F430584653 /* RLMNetworkTransport.h in Headers */ = {isa = PBXBuildFile; fileRef = A57BCC415D3BC94E35EB525E03037615 /* RLMNetworkTransport.h */; }; + 063AEAC2993E1F7E50141FF96012FCBC /* GULNetworkURLSession.m in Sources */ = {isa = PBXBuildFile; fileRef = 7070066373BC8611A2B554BE77E09B2C /* GULNetworkURLSession.m */; }; + 065A10113B63F448EF07DB487BAD18CC /* RLMScheduler.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = B0F9C1B839FB025457D8E24B0D0E8D9A /* RLMScheduler.h */; }; + 069810D5AFB74BAF041B5591C8C284B2 /* FIRGameCenterAuthCredential.h in Headers */ = {isa = PBXBuildFile; fileRef = 4166FCADAD4D4FD1E59EC390EF82F247 /* FIRGameCenterAuthCredential.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 06D0DEC16407DB4731F5EECFD70BB596 /* FIRAuthCredential.m in Sources */ = {isa = PBXBuildFile; fileRef = 5727B0661FF05A9D9CB986B6E82760FB /* FIRAuthCredential.m */; }; + 0722851D136DD19B4DF9F8D7A602E76D /* RLMApp_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 2290A765CE084379675E2DAE6C691B8F /* RLMApp_Private.h */; }; + 075DFF61BE5F0C4C6B1C039BCE9610E2 /* FIRStartMFAEnrollmentRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 92B72A17E56EBF7CEDC7FBB84BF7A1C7 /* FIRStartMFAEnrollmentRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 07BE846F330C6E3CC21666B1689703E3 /* FIRAuthProtoFinalizeMFAPhoneRequestInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = A99DA8352A55CF898457A0B158BB8961 /* FIRAuthProtoFinalizeMFAPhoneRequestInfo.m */; }; + 07C276C1C2CA802328111B82EC042276 /* table.cc in Sources */ = {isa = PBXBuildFile; fileRef = 6A9CA393FA5F4F8BE4BD71ADB0DAE631 /* table.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 07DFFFA39382BF47F87F85F4060411C6 /* FViewProcessor.h in Headers */ = {isa = PBXBuildFile; fileRef = AEB1B3775C7B162C71502AB49434EE36 /* FViewProcessor.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 07F261922769AA1165299B51787D22D6 /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4439B26A132B0978E10DE975AF9F2E70 /* Query.swift */; }; + 082C1131024807CE7E2FBDFF812C3BCB /* FIRStartMFASignInResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = DA41FE18FB4EA2B72D7B4F8366676BC1 /* FIRStartMFASignInResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0885A108D0AE69C45B5DFF90EF4D5404 /* FIRAuthBackend+MultiFactor.h in Headers */ = {isa = PBXBuildFile; fileRef = 6FF141A971FE681D3139DD5BC9039439 /* FIRAuthBackend+MultiFactor.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 08BA761685D424F62253220DBB1F4692 /* FIRLibrary.h in Headers */ = {isa = PBXBuildFile; fileRef = A98F6CF369D6452E984735A431BE0790 /* FIRLibrary.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 09EA6EB381880B689D80C64DA13E8B6F /* FIRMultiFactorInfo+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 043C226E59B26E794E9191331A864A5A /* FIRMultiFactorInfo+Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0A538E60675F1A4A8520BBB3F6A9308C /* FStringUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 56D7C61A84BD3126201E1B693272E5A8 /* FStringUtilities.m */; }; + 0ABE3648A1AC88265A23E66FD8D9AEA4 /* RLMSwiftProperty.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 62DA765EFA6176292C8BB0A39A6430D4 /* RLMSwiftProperty.h */; }; + 0AFD73DED7EB02CEAAFA2B42AAB79A2B /* GULAppEnvironmentUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = D0A9F872C17D0303D7A2EC5BBC973658 /* GULAppEnvironmentUtil.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0B2427765D5FE4486052F9AF50E5B0D5 /* FirebaseCoreInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 03569094005DFF21986290B7A7CCCD84 /* FirebaseCoreInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0B9DC3C5A979E7BDF04CBCA3461FCFB9 /* FTypedefs_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = A9B5783D1DF0F07EC4CC01D3E05F348C /* FTypedefs_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0BD69C8B2A7F56A05EBAA938E35D0A10 /* RLMMongoCollection.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 684B24EBB223FA5F33D00EACC3360AFB /* RLMMongoCollection.h */; }; + 0C14DFEB59A69A6264B9F5AFB91565DF /* FIRAppCheckInterop.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C4CCD297749321D38B4D8E1C0E06675 /* FIRAppCheckInterop.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0C25A01228C9393D350E75A8B2688EC0 /* FIRGetAccountInfoResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 0006371B66B70DA75BA4BAA405CE68B1 /* FIRGetAccountInfoResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0C56480A60541302683296892E8E22F3 /* FIRStartMFASignInResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 16ADD2871F8ACA2789A95C96B1F4FE19 /* FIRStartMFASignInResponse.m */; }; + 0C904DAFBAF94A44772444E05843DA9B /* FIRHeartbeatLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = CFDFCB3E3580BB6BEB1A3231B23289DD /* FIRHeartbeatLogger.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0C912F4D2C555B0D7F78D176F4595827 /* options.h in Headers */ = {isa = PBXBuildFile; fileRef = BB43DCDDF68FDAA8606A46164F080265 /* options.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0C9C133167200A1AC793C5B4F01B2ED8 /* FIRDependency.h in Headers */ = {isa = PBXBuildFile; fileRef = D455DC7451DB6AE120BB8BB269C4F3D9 /* FIRDependency.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0CC18E591907BF6B77BC02E7302E0CEE /* FIRWithdrawMFAResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 67EA9922C35F5F0019B266058D44FF98 /* FIRWithdrawMFAResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0CD9B5FD1CDE92219291ED4E89CC768F /* RLMScheduler.mm in Sources */ = {isa = PBXBuildFile; fileRef = 6E654A0432980B1F063FFDBCA71B4084 /* RLMScheduler.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 0CE8EEEBA36B0D52833A0245A57D9EBE /* FIRTwitterAuthProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 33057FA5EBAC487EC38B2C709F9F5DA6 /* FIRTwitterAuthProvider.m */; }; + 0D013B8100EB7D31F8C637385C307B38 /* FIRSignUpNewUserRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = A2F7F8DB85024F49526953B427B6486B /* FIRSignUpNewUserRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0D57570ED6DA0B24D24B6E96F4F414D4 /* FIRAuthProtoFinalizeMFAPhoneResponseInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 34BB5F58F426BDBCA59A72E52B095E95 /* FIRAuthProtoFinalizeMFAPhoneResponseInfo.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0D79E35CEA44F0952C080D02E834339E /* FPath.h in Headers */ = {isa = PBXBuildFile; fileRef = 266C617256AA4E2CB667A0F9044E7108 /* FPath.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0D980C39895D93AE95B64B87D9D05FA7 /* RLMUser.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B2DC0C4DFDB5B772B4F9B1EB97645E7 /* RLMUser.h */; }; + 0DA668730ACF231E73644A814D74A957 /* FMaxNode.m in Sources */ = {isa = PBXBuildFile; fileRef = B759001AEC2B36BC2B380644FBF8AEE3 /* FMaxNode.m */; }; + 0DA79DE502509F30F6DF82612FF81885 /* FIRCreateAuthURIResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 932C2931560E557D677E5D825DF55FF4 /* FIRCreateAuthURIResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0DE810456153ACAC87B26F587B903E75 /* RLMAsyncTask_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 611073B847128EBBC450AA00B49A5852 /* RLMAsyncTask_Private.h */; }; + 0E9AF13F9D3A60B0D9CEECBFE24B4F16 /* FTupleObjectNode.m in Sources */ = {isa = PBXBuildFile; fileRef = D98C07DBF8AFD2E90F45D95D0BA5E334 /* FTupleObjectNode.m */; }; + 0EBA9EA5EDC9B05CAC03D6A3C8340BA7 /* posix_logger.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A65A260D5E743AF8EF26E0EC4DBB9CA /* posix_logger.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0ECF3C22EF17A827CBB6633E059D3F5F /* FIRAuthWebUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = C97005B66F0BCD1C70222679991C6EF8 /* FIRAuthWebUtils.m */; }; + 0F38CB49C51C49A6AFF68848C37B24DE /* FIRComponentType.h in Headers */ = {isa = PBXBuildFile; fileRef = F5AE5CC06827309EE8FD36857AEEAD93 /* FIRComponentType.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0F4B1CDC7A0FBF93D3CF6DE9E5120356 /* RLMFindOptions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 607673A9F4B2F07F2E2EBB8F530B123D /* RLMFindOptions.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 0F624737C8B25492C886BFC1CC5115E5 /* FWriteRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = FF4E9D78A15423578B14516BCC3D0101 /* FWriteRecord.m */; }; + 0F670C7670C381D6919E9E6EDC010C2A /* FIRAuthProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 32EEA95F0D817AB69D4DD7990267512E /* FIRAuthProvider.m */; }; + 0FDAF73F04F6DBF0ABD393BDE2CC4651 /* c.h in Headers */ = {isa = PBXBuildFile; fileRef = E166A650D7D8C863AB91749CE9A89980 /* c.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0FEC32864EB9E4825B82766A0968B455 /* FValueEventRegistration.m in Sources */ = {isa = PBXBuildFile; fileRef = 9E7451B12E477E50E5B6D057C62C9818 /* FValueEventRegistration.m */; }; + 1020D1695BBA61AE0FCA0561BA37C4F5 /* FIndex.m in Sources */ = {isa = PBXBuildFile; fileRef = 2537AFF1FBBC4757A039581EF92AE608 /* FIndex.m */; }; + 10382ACB48A8FA82118A649D3A8979DC /* arena.h in Headers */ = {isa = PBXBuildFile; fileRef = AE21984D85FCC8A58C4A3DEB607EE9B3 /* arena.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1044D7EB9FFD66F58378B57517E41EFE /* FAtomicNumber.m in Sources */ = {isa = PBXBuildFile; fileRef = F2503973D433D6E9A0D2C052DE9C051C /* FAtomicNumber.m */; }; + 1059F6E4C81D4442F9A0443E56682D22 /* RealmConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 197274F76C7C01DC8B256E11BA3CA173 /* RealmConfiguration.swift */; }; + 108C00BBD7DB265FE04674D64F825F96 /* WeakContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93D1FC7C12423DA20AA334BD7AE69448 /* WeakContainer.swift */; }; + 108EDC903235587BF65B92ECC17761BA /* filter_policy.h in Headers */ = {isa = PBXBuildFile; fileRef = A43C946F25F4088423BBB29BB0D1E82F /* filter_policy.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 10C49AD71798CA4BDBB9F953BAED0CF6 /* FIRGitHubAuthProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 74F7F76D9723E9827EF3AD57738BD660 /* FIRGitHubAuthProvider.m */; }; + 122FB696FFF548CC3C300271E3C85852 /* RLMBSON.mm in Sources */ = {isa = PBXBuildFile; fileRef = DF68E17A2DB79D8E848E4D63DFB990D9 /* RLMBSON.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 1272C08EDBFCEEAB914C7169E258237E /* FIRAuthGlobalWorkQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 5706AC95CB4140FC7CEF869802B2B37A /* FIRAuthGlobalWorkQueue.m */; }; + 13533801B7E1A587D45E709EB8BD6159 /* FSyncPoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 652A3A7D52D06A4AFAE994E85C60432A /* FSyncPoint.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 13B5FCEFE1051075D694B06BD6345BB2 /* Persistable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CFE28636C71B865952B8CBA130E29DE /* Persistable.swift */; }; + 13E9FAFB711C21EDFDE915E77BC98076 /* db_iter.h in Headers */ = {isa = PBXBuildFile; fileRef = 176C38A32F80DAD2F58BA0865F64426A /* db_iter.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1442DE70EF3D59599F5A0C08837389B5 /* FEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 324CE274DE272729DB6F10A4C8C8401A /* FEvent.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 14730F31F1DC012AF4075208DE6B99C3 /* RLMAsymmetricObject.mm in Sources */ = {isa = PBXBuildFile; fileRef = 87F8A8905922D0CF7DAE27789D5EFC50 /* RLMAsymmetricObject.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 15467BBAED5278D8B7FD42E0DC8F5E09 /* RLMCredentials.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 99A3796A766AC39C09D1D998A183ED46 /* RLMCredentials.h */; }; + 1583014E980020AFC5FCFFA20E7E1589 /* FTupleObjectNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 309FE736880C3235DF3887AA58B3C6CE /* FTupleObjectNode.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 15998BE1E8E0F093D62A96474AA11256 /* FSparseSnapshotTree.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A07B044EF3476E89A8934CBC290CDB2 /* FSparseSnapshotTree.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 15A2E78F986153130CC782DE70297984 /* GULNetworkConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 1152AD3AF12FA0DE0A46B04DA8CF3C57 /* GULNetworkConstants.m */; }; + 15C622DC1904FBD6FB918B7832172CEF /* FQueryParams.m in Sources */ = {isa = PBXBuildFile; fileRef = 0751FFB6348E774F561AA56090F02B8E /* FQueryParams.m */; }; + 15EAD31ACB9B27C3A1193121331E7579 /* RLMMongoDatabase.h in Headers */ = {isa = PBXBuildFile; fileRef = CF97E0F164DFA9E0C2AA0BA05C846A5A /* RLMMongoDatabase.h */; }; + 160CB2757087667BBBC83DB6645470A4 /* FIRComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = F85757FC6D0D70EA704FBC21028EDF46 /* FIRComponent.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 16255205935C0EDAD6061E7DC422D451 /* FViewCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 2873E87EC61B34528E6E869AC2DCD567 /* FViewCache.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 164C8171D35E9623BA1D59A6A8BD005D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB96318E2CB72DE3CDFEEF1B9E8644AD /* Foundation.framework */; }; + 173E484A46C45E4E2EAAEBAEB7D19FBB /* FBLPromise+Async.h in Headers */ = {isa = PBXBuildFile; fileRef = CA25B306FFAA76849CE6925F041F4116 /* FBLPromise+Async.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 174FB4CA96ABA27CC7B3F3D233C7458E /* FTupleNodePath.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D885A4F106B62B2C0DB2B5CE2D09E22 /* FTupleNodePath.m */; }; + 176C194122DABDA7F7F2F4F3767E9808 /* table_cache.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2EB81C3B8587730347BDC959EAAC9FA2 /* table_cache.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 17ACA929F7991E272C9A70302E8F470D /* RLMArray.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4017654FAE4B47AA0C9B3F842A344DE0 /* RLMArray.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 17B25894B99C479DE96C344CFBBEFD7F /* FIRComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 24B4007499458D350361A99EE865BC30 /* FIRComponent.m */; }; + 180BF9A8B4FB2EE3D1F2CB2F024F5F85 /* FMerge.h in Headers */ = {isa = PBXBuildFile; fileRef = D7D16DA5AD11F3D6F872D23FA8E6A157 /* FMerge.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 186A9950AD2BC40A5E06896B3F3FFBC4 /* RealmSwift-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 718D25283FCCDB355A59F30C238CDC71 /* RealmSwift-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 186B723BA9635B8C2A44DA292E12B770 /* FTree.m in Sources */ = {isa = PBXBuildFile; fileRef = D3C7869F6D75E8CDC540790526E3F955 /* FTree.m */; }; + 187595E76222B7A73977531CCC6E728E /* FTree.h in Headers */ = {isa = PBXBuildFile; fileRef = A3B0C6C9B2CD46F23B0B57ADFA239899 /* FTree.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 18774A6239D9CE2E626517CA92D04E8F /* testharness.cc in Sources */ = {isa = PBXBuildFile; fileRef = DDC9E831C2A72BB2A398571D8AD3C8EA /* testharness.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 18C6F896810D32D01B3208154D689CEF /* FIRLibrary.h in Headers */ = {isa = PBXBuildFile; fileRef = 97376E6BECB554DDCA9DBDA7C7CB9217 /* FIRLibrary.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 191780B64BD14CA6817038571827C27E /* RLMBSON.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = FCFFDCA51CE25755A9B7C297EF1226FF /* RLMBSON.h */; }; + 19344C97DA033C622B62F40E6650E56E /* FIRPhoneMultiFactorInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 7FFE5FB751622716C89387E428A18B33 /* FIRPhoneMultiFactorInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1955ED863CC66C0EAAE4E38C196A9EBC /* FIRWithdrawMFARequest.h in Headers */ = {isa = PBXBuildFile; fileRef = A800F833AC5404F3FA4FC8CC82716281 /* FIRWithdrawMFARequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1A340BB5ECA742DF70E865839937A42A /* FQueryParams.h in Headers */ = {isa = PBXBuildFile; fileRef = AFB356F5255300E6FB821BAEBE11CEAA /* FQueryParams.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1A41A84E600185E54A9D4A3FFD5177BC /* RLMUserAPIKey.h in Headers */ = {isa = PBXBuildFile; fileRef = 34DE85D047CC7AE8971A383A422D922B /* RLMUserAPIKey.h */; }; + 1A5DBDF8EC79DB739D6F6333801E6E7D /* GULAppEnvironmentUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = E8942392A79DA09DE59AB54A095222B0 /* GULAppEnvironmentUtil.m */; }; + 1A8D3239CD91ED4D979E2061BAE3E994 /* FIRAuthProtoStartMFAPhoneRequestInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 90F49AB280D154511F8828F29429908F /* FIRAuthProtoStartMFAPhoneRequestInfo.m */; }; + 1AE31850261F971BBAE81FA9859C5DBE /* SortDescriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 046758AD33D0FD687DD1AD08DD311250 /* SortDescriptor.swift */; }; + 1B3BCA0AEE5AC15E825670A550338EEF /* FIRServerValue.m in Sources */ = {isa = PBXBuildFile; fileRef = 7CC89F7D738A2A79CA9191BE2FC708E0 /* FIRServerValue.m */; }; + 1B49710EAEC16C9113A9404A4BDC9E3F /* FIRInstallationsIDController.h in Headers */ = {isa = PBXBuildFile; fileRef = C3837D45F314C1B4B6B4AD233C4F06DC /* FIRInstallationsIDController.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1B758413CB8C82D2C26A49A1DF222B4B /* RLMSwiftSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D2AEB4E2CAF4CF35E4F45069EB30D0A6 /* RLMSwiftSupport.m */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 1C0679E65CDB66E90C07A50D045635FC /* table_cache.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C8F9D1F3278289794C00D2F8EC2D354 /* table_cache.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1C292460A5B87AD8C4248AF11B9BADD5 /* FTupleUserCallback.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EC2C755F7459C7D17578604910BA6C9 /* FTupleUserCallback.m */; }; + 1C3CCBA7A56F4B2AE6DC7D4080D085CF /* RLMAsymmetricObject.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 23A3F80698CEECE919C9E022F40AFC28 /* RLMAsymmetricObject.h */; }; + 1C4AD68BD3321CBA37ADFBFBB0EA3A85 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB96318E2CB72DE3CDFEEF1B9E8644AD /* Foundation.framework */; }; + 1C7518A96589FAC93583DA08463ACD30 /* RLMUUID.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3535D8C2C242A80EFE2003ADDADD8EB2 /* RLMUUID.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 1C94C778746A9747B0C9300710ABFF00 /* RLMObject.mm in Sources */ = {isa = PBXBuildFile; fileRef = 77B43A9AB4643A40D2652594DE5E5DFE /* RLMObject.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 1CA0567A035870C832DE6060E1C348A1 /* LinkingObjects.swift in Sources */ = {isa = PBXBuildFile; fileRef = 673C8052EBB7CFC728848688E8635A04 /* LinkingObjects.swift */; }; + 1CA90EEE7B12A5FF6A8BB43FEBB1AB47 /* FIRMultiFactorAssertion.m in Sources */ = {isa = PBXBuildFile; fileRef = A4AE47A83D9419056CA5152B8060EB57 /* FIRMultiFactorAssertion.m */; }; + 1D8397CFAB68F89506B82B8E5DE0E332 /* FIRPhoneMultiFactorGenerator.m in Sources */ = {isa = PBXBuildFile; fileRef = 9533FA4F9B48BB2174C0ED30C78DFE7E /* FIRPhoneMultiFactorGenerator.m */; }; + 1D959CCB6684555C4421436045A397B8 /* GULNSData+zlib.m in Sources */ = {isa = PBXBuildFile; fileRef = FA41946ADC0A1E4F1F07A106A35D5C1A /* GULNSData+zlib.m */; }; + 1DAF869CDE6189F9FA50BC1288038DB4 /* FIRLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = DF47599DCB441F39488B62462C49AB81 /* FIRLogger.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1E43DE43BBB68B7F97D958FFE0D6361C /* FIRComponentType.h in Headers */ = {isa = PBXBuildFile; fileRef = 434FF72C1B06DAFDF7A6F2F790AACEBC /* FIRComponentType.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1E5410EFB9924CC9454BDA535D3F4DEA /* FIRConfigurationInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 67361D46F9488FA1DC95BE85E46CE3ED /* FIRConfigurationInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1E563604E3C43CD98D2CFC150359E536 /* RealmCollectionImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32E4A9F082BFCABE2AD6B32D535E37D8 /* RealmCollectionImpl.swift */; }; + 1E75EC8BC9F736D1C338F9D1F9EAFC7A /* RLMSet.mm in Sources */ = {isa = PBXBuildFile; fileRef = F0E3797522D2DA92B3D9A8D35FFEDFE2 /* RLMSet.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 1E7BA32AA3F6BE570C598689E2BAC9DF /* FIRSecureTokenResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 4FF91AFC3D4E8D5DDE6F76B436ADF093 /* FIRSecureTokenResponse.m */; }; + 1ECDAEF2D8E73A492C15D2FE1ACF3869 /* GULAppDelegateSwizzler_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 7F98669F88B9C95FEB19125B73434800 /* GULAppDelegateSwizzler_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1EDCB680A779A00F4F6662BE40051FFD /* RLMEvent.mm in Sources */ = {isa = PBXBuildFile; fileRef = 501133B694FC9229BA3E4B89DA7124DC /* RLMEvent.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 1F0607B87427A32DE2195E6B3373626A /* FIRAuthTokenResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 356FA68C30464A29EB11FD7CA7521327 /* FIRAuthTokenResult.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1F2FE99E303BEDEE81468398721C5697 /* FSnapshotUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 6547B8C2009B2D61EB11FEC0F64F29F5 /* FSnapshotUtilities.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1F7125A2397241BCD087960ACFA0C8F2 /* APLevelDB.h in Headers */ = {isa = PBXBuildFile; fileRef = DFA09D9997A62037EBBA3F916282D412 /* APLevelDB.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1F8482568311E5D193A3655C8C67F53D /* FIRVersion.h in Headers */ = {isa = PBXBuildFile; fileRef = E2A825F628843CCD72BD31D2F167A274 /* FIRVersion.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1FCDD221A9E732A3CA3D2CDF5BFD85A5 /* FIRFederatedAuthProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = 06CD6D8F5E3BF730BDA839220939A8AA /* FIRFederatedAuthProvider.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 200F9D45C92F76E4D7BCDD330FF456D5 /* RLMSwiftCollectionBase.h in Headers */ = {isa = PBXBuildFile; fileRef = DAC208FD41CE38A2E2E5ABCDABD3D70E /* RLMSwiftCollectionBase.h */; }; + 201D4EB6D2A2AE8B478AAF3D905349FF /* dbformat.cc in Sources */ = {isa = PBXBuildFile; fileRef = ECF825CA7953BF64C51F8BCB314F7A1C /* dbformat.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 206449DF6C6856E7F63C20C7C67283A2 /* RLMObjectId.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = E3B5F7670B5C0CA94B6720CC51510838 /* RLMObjectId.h */; }; + 2089B723FD3543B3A649AC26616550CE /* FIRStartMFASignInRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D3125925FAEC4F82BA1ED3FEDDF2EA /* FIRStartMFASignInRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2091B27B45767BE89BD047867367DF30 /* FLevelDBStorageEngine.h in Headers */ = {isa = PBXBuildFile; fileRef = DF1DFA0E235C7EBFBB0C874CC3FB1BB4 /* FLevelDBStorageEngine.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 209C8610E46A99257A7EA9E79D4CE3A7 /* FIRFinalizeMFASignInResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = DDABA880B080FE3D88806F394D8ECB82 /* FIRFinalizeMFASignInResponse.m */; }; + 20A59DBE2C17C1DB9D63977A2D093606 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4972477850A41A9D9B673C96DEF4168A /* Security.framework */; }; + 21133EAD7666F99E72CB375C737B5F84 /* RLMDecimal128.mm in Sources */ = {isa = PBXBuildFile; fileRef = 6C12879EEF6A505D3CEE089176D6333E /* RLMDecimal128.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 21427BDB68B531D4AFCB02B3D5C0E38B /* RLMSet.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 4CBCF5236A1C6D972EB1E9825C24568D /* RLMSet.h */; }; + 21751DBB5EAA38F1C2BC416F1F0477B4 /* FIRSignInWithGameCenterRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 81252E5CD0EB33B7028F00FADE62A39B /* FIRSignInWithGameCenterRequest.m */; }; + 21A191B2DC557588618AF79120F64B45 /* FIRComponentContainerInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = D3CBF39EB565F7C6E0D1BA08F7C7AC50 /* FIRComponentContainerInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 21C58D39D595DB6E2522245782514F73 /* RLMArray_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = A77530BCB920D9861E25B63BE3E4443E /* RLMArray_Private.h */; }; + 21CFD2B6DC3E36215D9BCC8158B2CAEE /* Pods-PRTYTests-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 0009925C746201D1B1E5D9602FFC6DCA /* Pods-PRTYTests-dummy.m */; }; + 2248B7A0012B9511E4F820D7E9701B3F /* FIRAuthSerialTaskQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 226C88C2143E230C84E42844AF62C9FC /* FIRAuthSerialTaskQueue.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 229802FCEB7A418CD2C5103658823BAA /* FSparseSnapshotTree.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D347E1A64C9ADD432B01EE1CD0EF50B /* FSparseSnapshotTree.m */; }; + 231B82B559FA16389A48B6C0BCA4BA46 /* FIRAuth_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 72B122535CC236E3BC29334CA1639C6E /* FIRAuth_Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2327507B9D5595050D98860F7CC24F63 /* FOverwrite.h in Headers */ = {isa = PBXBuildFile; fileRef = A052E47398426D6826B82AAF3868DAA6 /* FOverwrite.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2389325BD1515692FCF0905C00D4D8A0 /* FIRMutableData.m in Sources */ = {isa = PBXBuildFile; fileRef = 9420AAD5DAC96CCA96AB03E31BD57796 /* FIRMutableData.m */; }; + 23C461911D9808F97D596DDDDD453436 /* FChildChangeAccumulator.h in Headers */ = {isa = PBXBuildFile; fileRef = B50D0C80ED816334D64C4012ABDB6D91 /* FChildChangeAccumulator.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 23E3887CC08BDC547463047B858849BE /* RLMRealm.h in Headers */ = {isa = PBXBuildFile; fileRef = F0BFC6AD06F7FAA34D3238F20D1BDDD3 /* RLMRealm.h */; }; + 23E9879097C598B8AA8A388356C09BE4 /* RLMRealm+Sync.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 0C0CD8603C88F495D0C59CF44AB151EA /* RLMRealm+Sync.h */; }; + 25A2FDE3446D76FAC5F9DA3D4E0A1F08 /* FIRAuthAPNSTokenManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 3939D097FA2B064D8642167CB9C80243 /* FIRAuthAPNSTokenManager.m */; }; + 25BF6CA2126B5CA98749D820B6EE3790 /* pb_decode.h in Headers */ = {isa = PBXBuildFile; fileRef = 7AA4F6AE64EE4FC2D1783D3CDE850753 /* pb_decode.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 25D1EE805A5E8D9B263A2D8B335F6124 /* FIRGetProjectConfigRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = EF35764F03CD24E9BEFF38AB8C6873BF /* FIRGetProjectConfigRequest.m */; }; + 260FCFDE1EE1A0437CDA85BA253F84C8 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4972477850A41A9D9B673C96DEF4168A /* Security.framework */; }; + 263E861581658DF48841CD38DE090E27 /* FEventGenerator.m in Sources */ = {isa = PBXBuildFile; fileRef = B40F9A123AE0840B522636A66050A271 /* FEventGenerator.m */; }; + 266B77BE7D14531F8F80B830618A2322 /* FNextPushId.h in Headers */ = {isa = PBXBuildFile; fileRef = 37151480117365DF172C5574B6D0651C /* FNextPushId.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 267D4C41BB1B461358E2BB57169328F9 /* FIRInstallationsIDController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9FF9B18D901B58F5B274E797ABF8D03C /* FIRInstallationsIDController.m */; }; + 269D36571B40B60D117D163D7B87597B /* FNamedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 6293EEA3422B89FF3E253E3876365114 /* FNamedNode.m */; }; + 270305E8D407E8059D9FFD2D9565DAF6 /* RLMResults.h in Headers */ = {isa = PBXBuildFile; fileRef = D499691A37C194CFC8292C3B66E69060 /* RLMResults.h */; }; + 27110206EA54BA318491514F1E5AC600 /* FIRInstallationsIIDStore.m in Sources */ = {isa = PBXBuildFile; fileRef = BE6CCDBE7A5141FB59661292B11561C0 /* FIRInstallationsIIDStore.m */; }; + 2726B73C90D07E3FC35D1EABAF7B68D1 /* leveldb-library-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = EDFEE8706FA0AF292187CAE8E1EF207B /* leveldb-library-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 275517FAB97156D3F6B8F2CCA588D375 /* RLMDictionary.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 448F758E8949F357C24A8E3D4F0EE6E2 /* RLMDictionary.h */; }; + 27946A092ED65B47834CB76DB96A76D9 /* FIRSetAccountInfoRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = BAA2696F7FBBB1CBD28CC9EE73BA0480 /* FIRSetAccountInfoRequest.m */; }; + 27D9F773AB09ACEA1463B46594D36905 /* RLMSyncSubscription_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 272FB90054BCC4BB95316C5013FC9834 /* RLMSyncSubscription_Private.h */; }; + 280B690F41E4F6156DB9194020820A53 /* FIRAppInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 301C5C7EB56673BEA7FD351C9E864BD8 /* FIRAppInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 28128BF32E810A8678D7171A29F0A477 /* FBLPromises.h in Headers */ = {isa = PBXBuildFile; fileRef = 44FFEBF653DCAA7740DA6A359B3DAC77 /* FBLPromises.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 282B9343DCF3A93E1B5FB83297B1B56F /* RLMPushClient.mm in Sources */ = {isa = PBXBuildFile; fileRef = A74279679B1A5D45438D0DDBFDE0CA14 /* RLMPushClient.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 2838AAEA623CEB269148E955BDD4CE93 /* FMerge.m in Sources */ = {isa = PBXBuildFile; fileRef = DB1010F3237A58009791F7F779E11F1D /* FMerge.m */; }; + 2848C9835FB27AFFE43D089CCD1C9EE7 /* FIRVersion.m in Sources */ = {isa = PBXBuildFile; fileRef = EC208AAD8607F9C59421288F9B50F57D /* FIRVersion.m */; }; + 284B6D6F6370F71E42AEEAB66779B572 /* FConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = 118893944206EA50EB70686CFE24555F /* FConstants.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 29432E2D848A8D5FDC653A470795980F /* FIRAuthSerialTaskQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 66CEFE2624DA20593CC818FF907F46F5 /* FIRAuthSerialTaskQueue.m */; }; + 296F785F9BB7CDD1C9718FE9703701E5 /* FIRGitHubAuthCredential.h in Headers */ = {isa = PBXBuildFile; fileRef = FDF2EFAF7E3BB03DFF3DF33C3AE6D230 /* FIRGitHubAuthCredential.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 29B1483F501DE1434F01C5798A66B54F /* RLMAsymmetricObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 23A3F80698CEECE919C9E022F40AFC28 /* RLMAsymmetricObject.h */; }; + 29F00DB50FF8AA7AD4FCD36D00B6AF5A /* RLMLogger.mm in Sources */ = {isa = PBXBuildFile; fileRef = F37FE4685A93D38F15751D8281B0E889 /* RLMLogger.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 29F08AF3D1535FD26ABAE795B14EDFA8 /* GULLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = DE6EC9F385F7E055E70A09F1EAFA7E4A /* GULLogger.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2A31970FF0E9775502FDAD1367C9A8C3 /* RLMUser.mm in Sources */ = {isa = PBXBuildFile; fileRef = 6DD2A0344579B5A9CAA6BDFFD7B8481F /* RLMUser.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 2A47E42F34E410CB363A42BA8358B0F5 /* FIROAuthCredential_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4EA5A35B9693996DBF681BB5E4ED3AB9 /* FIROAuthCredential_Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2A93CB0B3804F73F214BAC10BEB17616 /* RLMEvent.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 955BE9FC76F7CE1DC6CEC4D0204858EB /* RLMEvent.h */; }; + 2AA16A5788CFD8693903222735840723 /* FIRFinalizeMFAEnrollmentResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = F9C09D85943C666EFF4A7E7FF556468E /* FIRFinalizeMFAEnrollmentResponse.m */; }; + 2AB3F88542B7A1594C161DF518EA7A09 /* HeartbeatsBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C574899E21FF7BC5D52C1B2C2A1FB71 /* HeartbeatsBundle.swift */; }; + 2AC9B914114C83566F0335E463C35CBF /* FIRVerifyPhoneNumberResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D28A3D7BBFED5216A2FCF2D4855B3BE /* FIRVerifyPhoneNumberResponse.m */; }; + 2AFC8AD2E5BE28E28D99F3377D847D05 /* RLMApp_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 2290A765CE084379675E2DAE6C691B8F /* RLMApp_Private.h */; }; + 2B06CE35C5F2F86997A11CCFBB2002C4 /* RLMSyncSession.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 454A4F6087FFA109E2BAAD2E3244848F /* RLMSyncSession.h */; }; + 2B0FDB6E145DC289E4826D8FF4CC7F06 /* FBLPromise+Any.m in Sources */ = {isa = PBXBuildFile; fileRef = F5FC60DFF725AF93166D1B0F9E69A00D /* FBLPromise+Any.m */; }; + 2B11BFEC836C5038F4C1E58BD1A35FCE /* FRepoManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 98B7302B3903DB29AD102B2B4A7C077F /* FRepoManager.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2B1964D3F4B7A4E590DA2D60D42C3263 /* FIRUser_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 251A0FACCAB61BF90F11AAC339D36587 /* FIRUser_Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2B4F071A28E58BF95E34258DE39AD449 /* RLMDictionary.h in Headers */ = {isa = PBXBuildFile; fileRef = 448F758E8949F357C24A8E3D4F0EE6E2 /* RLMDictionary.h */; }; + 2B505A23980039E9504F1854F70DEAC1 /* FIRInstallationsHTTPError.h in Headers */ = {isa = PBXBuildFile; fileRef = 94C405D207D05FB559806347FF4C3110 /* FIRInstallationsHTTPError.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2B66A4B70C36AA4D0DBED20183E3EB4F /* RLMSectionedResults.h in Headers */ = {isa = PBXBuildFile; fileRef = 9011CDAF888185959FCBA517AA3CCD8D /* RLMSectionedResults.h */; }; + 2B7172EBC25CE6B3C2613DA8DAFE7D19 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB96318E2CB72DE3CDFEEF1B9E8644AD /* Foundation.framework */; }; + 2B9D45261AB0F27D7B4FFB0B0B32937F /* FIRAuthOperationType.h in Headers */ = {isa = PBXBuildFile; fileRef = 255C5F38BC053F1E20A8E00981F2D825 /* FIRAuthOperationType.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2BDA434ED438CA7501C58441AA8E58B3 /* FTupleUserCallback.h in Headers */ = {isa = PBXBuildFile; fileRef = 9ADF28900A460B3E7E1AF2D6D862756B /* FTupleUserCallback.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2C25D8B69A7076CC958BAB5BD37FCD8D /* FIRGetOOBConfirmationCodeResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = C221AE887079015A8381423D3733ED04 /* FIRGetOOBConfirmationCodeResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2C476F4F273960B86AC4FB592BC004D6 /* FIRDatabaseConnectionContextProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 2EC642ED48C46A050E79A1F996755054 /* FIRDatabaseConnectionContextProvider.m */; }; + 2C7492344C6598F8514582D5B34F6956 /* ObjectiveCSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F1F7E6A93AAEE1766B72ADAA3E6F62B /* ObjectiveCSupport.swift */; }; + 2C9BB565C846B9E82A7B19A6DEDB0D2A /* FIRAuthCredential.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D0A7F15D7C1C5FAB85E7E8AAA2FED49 /* FIRAuthCredential.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2D12A36D05F856956F5CDA84ECFEC8E8 /* FIRPhoneAuthCredential_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 9FEB68EC6BAB21247A9560C3A523173B /* FIRPhoneAuthCredential_Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2D73F53F12D6DB49131B7A5898BA3651 /* FIRComponentContainer.m in Sources */ = {isa = PBXBuildFile; fileRef = B16EB04DE78E887824E1C8DBFC66B5F5 /* FIRComponentContainer.m */; }; + 2D7E51E790AFE79B85372E8B7030C235 /* FBLPromise+Testing.m in Sources */ = {isa = PBXBuildFile; fileRef = 17586B39950BC2B022A340DD26D64DC0 /* FBLPromise+Testing.m */; }; + 2DA2C2154A6BBEE40B136B1C8854FCA0 /* FIRAuthInterop.h in Headers */ = {isa = PBXBuildFile; fileRef = 3BD63FE4290CDD7BAC1946490F265016 /* FIRAuthInterop.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2DD1FE142741159D79FF695B47D323CD /* RLMSyncSubscription.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = DA74B0436802FE2BDE61D436290670BD /* RLMSyncSubscription.h */; }; + 2DE2E901B48A92BBEEC0DA9F0AC58643 /* FTreeNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 039997D3CBE3F7A0E8AF5CAE8CF8AF49 /* FTreeNode.m */; }; + 2E36EC47A992822A4D670D9A237B8894 /* FIRComponentType.h in Headers */ = {isa = PBXBuildFile; fileRef = C259035AB4864FBC222C048097AEDB6A /* FIRComponentType.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2E536C9ED61E08A9DFC5E8F32A33B60A /* FBLPromise+Validate.m in Sources */ = {isa = PBXBuildFile; fileRef = 59658C383969DFD4CC50A9FB8FE855AB /* FBLPromise+Validate.m */; }; + 2E6AA9AEB8C9A11A88CCC93D3678124D /* RLMManagedArray.mm in Sources */ = {isa = PBXBuildFile; fileRef = D56EC12CC16DD1D834245EB18033364A /* RLMManagedArray.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 2E8BEF00344577175E9103DBF07FD880 /* FLeafNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 89442941AAFEBFBD27360DCA80B0C541 /* FLeafNode.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2E9DCF5DE252DD97076AFC91842225CF /* AnyRealmValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70AF99E224EDF12DFD45951388CF82E3 /* AnyRealmValue.swift */; }; + 2F0B5B4DE3359F3E1EFCBA5955134B94 /* FQuerySpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 6F2297CEDCE776B9F4D682C5BFDFBAF7 /* FQuerySpec.m */; }; + 2F3EDA73AAD29A88A95922DCC6404CF1 /* port_example.h in Headers */ = {isa = PBXBuildFile; fileRef = 35C5CA813B56606F6856DDAC7EC3B552 /* port_example.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2F4BC38B89616077E07A1672A9E23BEC /* FRangedFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 9035019906CFA898627DB9DD54174418 /* FRangedFilter.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2F578C1D7FD3AEF6A55B5625D3502A61 /* FIRDatabaseQuery.h in Headers */ = {isa = PBXBuildFile; fileRef = AEF6388410F1929F5AE36C5D9175EBC3 /* FIRDatabaseQuery.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2F6F852A5CF6FF3C8E791FAE3E555A08 /* GULNetworkInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = A92EF1CA905127F130D1776E993E98FD /* GULNetworkInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2FB72ED3C83C69112786822E6A109B1D /* FIRFinalizeMFASignInRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = FD1024348B7D7F91773F548CC6A4A4B5 /* FIRFinalizeMFASignInRequest.m */; }; + 30370665ED1ABB8568DDEC0A31B1D441 /* coding.cc in Sources */ = {isa = PBXBuildFile; fileRef = 18957DF296CAB6C27B5D971F258E0A01 /* coding.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 30A465DB1D908AF3A1D79C4FCB0BC837 /* FCompoundWrite.h in Headers */ = {isa = PBXBuildFile; fileRef = 72F431CF7352923F85C4AD27477F4B3E /* FCompoundWrite.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 30AC90E398AD1879161358AD52E0440D /* FIRInstallationsIIDTokenStore.h in Headers */ = {isa = PBXBuildFile; fileRef = 32CCE9D44B7DBFAB4EC8193C9E7907EF /* FIRInstallationsIIDTokenStore.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 30AE109E466587FB7257790E9FB5E4EB /* NSError+RLMSync.m in Sources */ = {isa = PBXBuildFile; fileRef = 82144ED3101ECA164213270A3C7A5398 /* NSError+RLMSync.m */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 30BC5B49C4B53971EA7F8689DDF5C8D7 /* FIRAuthAppCredentialManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CD89FAADE3C7B16A0F34D8014E0ECCE /* FIRAuthAppCredentialManager.m */; }; + 30C0073032317A76CDBA70B681414B9D /* FIRBundleUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = B96EBCC46DCBEDE26365D7AC85351CC5 /* FIRBundleUtil.m */; }; + 312CA68E22F5BAF8D5BB7F0538FED1CB /* logging.cc in Sources */ = {isa = PBXBuildFile; fileRef = D17F4CAEA8B1222B41373E48DDB479F8 /* logging.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 3139C4E6340CBE4B22B43096EDB8EB15 /* FIREmailLinkSignInResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 14313C746BD248B51B801D5D0EAB7816 /* FIREmailLinkSignInResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 313FC85C8B36FDF89836E2BF03CFF5C0 /* RLMSyncSubscription.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8FA4AA9362111E7D1B6C89F59C6E425E /* RLMSyncSubscription.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 314291CBDDA8230AE9D787E30CD4087C /* FIRSignUpNewUserRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 6EE3C9DA366E6B7ABA2CD3B139B2BFFC /* FIRSignUpNewUserRequest.m */; }; + 315DB9E13CC8D07BA11C3A6AE9BAB9CC /* FIREmailPasswordAuthCredential.h in Headers */ = {isa = PBXBuildFile; fileRef = FDF715A8163A7748E8D70591288E49C2 /* FIREmailPasswordAuthCredential.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 318AFF729D2DE955120F0BDEC6A58BD6 /* RLMAPIKeyAuth.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 7265EFBF2A684FDD8000FFA1529176CE /* RLMAPIKeyAuth.h */; }; + 328F275F96233AC46D18AE4FC60269F2 /* RLMEmailPasswordAuth.mm in Sources */ = {isa = PBXBuildFile; fileRef = B9DF9F7043C387E6BBD41BFE4E656257 /* RLMEmailPasswordAuth.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 32D55723E434E34412EE79D3ED27F36C /* builder.h in Headers */ = {isa = PBXBuildFile; fileRef = FE30687F11D90C3A5C7F0BC4A4F7C122 /* builder.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 32F5FDC13D8F0F7B9D01D264D7D09D32 /* FIRDataEventType.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B30B908533087573BAB4A4DBFAB691D /* FIRDataEventType.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 33108301DF03DB45D48B8F3889DE5906 /* GULLoggerCodes.h in Headers */ = {isa = PBXBuildFile; fileRef = D8780156F717E510F1DB5FA53ECBEEFC /* GULLoggerCodes.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 3310BD9799F4B3C7E08E8692D785EA41 /* FIREmailLinkSignInRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 78D1E4541AA37C05E37CD3271341EB53 /* FIREmailLinkSignInRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 331287FF32C8BEDC639F7A8D2ED118CC /* NSURLSession+GULPromises.h in Headers */ = {isa = PBXBuildFile; fileRef = 83A7B45E5C8683064DA6B5DAAD5957C0 /* NSURLSession+GULPromises.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 335FA26ACC34E99D04E31985AA681928 /* pb_common.h in Headers */ = {isa = PBXBuildFile; fileRef = E85CC75C83CC5C34C66FEA0792C24588 /* pb_common.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 34A7A9C91800828112A8B3AF6B36D8CE /* memtable.cc in Sources */ = {isa = PBXBuildFile; fileRef = B1383C44D5CC1F593039878620AA112C /* memtable.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 352A47A6F158DBB01933867841790478 /* FirebaseDatabase-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = CF1F64FF1371085F3868BD8A29F1725E /* FirebaseDatabase-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3532C2D4D8F7DE7C4B6028B2533DE424 /* FWriteTreeRef.m in Sources */ = {isa = PBXBuildFile; fileRef = F6D4069FBA41CDF529F7FF7044569873 /* FWriteTreeRef.m */; }; + 355D95383A9CE3130A45726FC2EEF811 /* RLMRealmConfiguration_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D6DEDD58747685647800F21525DEFC8 /* RLMRealmConfiguration_Private.h */; }; + 35C92F88D02F66D3CD811EE747A0D2D1 /* FCacheNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 06304D72C5C2F7A0DB5EC2BD2DBFBB12 /* FCacheNode.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 35CE3B95660A62605924372F4F2161FC /* comparator.cc in Sources */ = {isa = PBXBuildFile; fileRef = BDE9BA49B88ABDE1B7B491F0876E56D6 /* comparator.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 3606144765DE64C83E8ABCF7769E9589 /* FTrackedQueryManager.h in Headers */ = {isa = PBXBuildFile; fileRef = F2348A5807D3DC0C79B38DE2BF5C174B /* FTrackedQueryManager.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 3626BEFF142ABEFB340C17ED85052C4D /* GTMSessionFetcher-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 89B93A8ED3FC12F718397CD71C98EE02 /* GTMSessionFetcher-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3652FD94A1EDA7EC5CE3D584EDEEEB53 /* RLMUpdateChecker.mm in Sources */ = {isa = PBXBuildFile; fileRef = F11CF8FB763A7027E9275814033E4AAA /* RLMUpdateChecker.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 36EAF66821BFB428D34426904FA4CED6 /* GULKeychainStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = 0AC41380A652260C2B824C6DCD0D123B /* GULKeychainStorage.m */; }; + 37938C045A4BF24A92E0C73970A55CCC /* FCancelEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C65A271995DEF7866A8ACEA5248CC93 /* FCancelEvent.m */; }; + 379E03816B0498680EEA825E07B75BAB /* FIRCreateAuthURIResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = E9E24A592D6788921EFF7CD6B07DA3D0 /* FIRCreateAuthURIResponse.m */; }; + 37CDF5442F766E20BD807E2265C6EF55 /* RLMObjectSchema.h in Headers */ = {isa = PBXBuildFile; fileRef = 55971155657172B3C8EE36661224A4CF /* RLMObjectSchema.h */; }; + 3804F8E81CAFD3284E1516A54D6F04B7 /* GTMSessionFetcherService.m in Sources */ = {isa = PBXBuildFile; fileRef = C600859214CB6427CF9C135B659E3AF6 /* GTMSessionFetcherService.m */; }; + 38A7CFB28A653498AC76B3DBD8E872C3 /* FValueIndex.m in Sources */ = {isa = PBXBuildFile; fileRef = 004F83479325FA52B3C2EF9F638F5C2C /* FValueIndex.m */; }; + 38B384070F9EE79308F694D5566C29F8 /* FIRAppInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F849893A149318894D9DDDDDC9FABE5 /* FIRAppInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 38D9942994604B9E407034CDDD612568 /* FBLPromise.h in Headers */ = {isa = PBXBuildFile; fileRef = 14ED6C038781E8190323E214EB7F8D3E /* FBLPromise.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 38F29F91F5CDD2A7690A581BFB0567EE /* FViewProcessorResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 921A7FA65DED7374E8FA5FEF975CD444 /* FViewProcessorResult.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 390166F3C6763F547913436E141CC1E0 /* RLMRealmConfiguration.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 4C4A0D72C0FDAD19E451C2E21BA93B3A /* RLMRealmConfiguration.h */; }; + 3985FF8BAC3C5B2AE2B6808AA80884B1 /* PromisesObjC-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = F4332EC6914A3C94E725975980509BB2 /* PromisesObjC-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 39A44ED1031AABA976280D99FD4337F0 /* GULKeychainUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 85221EA6BE483DC672CBF12305306A3E /* GULKeychainUtils.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 39BC691EE1B9EC37E1F6E5FAD28EDD4B /* FTupleStringNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D4E6BB1FEF2DF20718587A7EE8B8918 /* FTupleStringNode.m */; }; + 39EA99A31B37C65E005202F18FBB2782 /* Aliases.swift in Sources */ = {isa = PBXBuildFile; fileRef = 682683D1FA0D7DFA4BEE25A9AC5C6759 /* Aliases.swift */; }; + 39ED90D10209900AD8F48B6673062030 /* FirebaseAppCheckInterop-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A18DE4B7A84F362E93E76BCAB3882E7 /* FirebaseAppCheckInterop-dummy.m */; }; + 3A05E4136818D9A738393A7C46D4EAFA /* RLMMongoCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = 684B24EBB223FA5F33D00EACC3360AFB /* RLMMongoCollection.h */; }; + 3A973A8CB0DEE9F13BCA66F95AB34C1C /* FBLPromise+Retry.m in Sources */ = {isa = PBXBuildFile; fileRef = F50FD872912D12668F5FF512DB8D6FA2 /* FBLPromise+Retry.m */; }; + 3B728B444B95692D159372CD8462A19A /* GULSceneDelegateSwizzler.m in Sources */ = {isa = PBXBuildFile; fileRef = 257F0A0FBD7080CADA3BD0EF0DAA0156 /* GULSceneDelegateSwizzler.m */; }; + 3B74BA9E808626DD2C5906054F55A87C /* two_level_iterator.cc in Sources */ = {isa = PBXBuildFile; fileRef = B3B9F9E57BAB9DB88B08810413E1BFD7 /* two_level_iterator.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 3C4CB761E2F8364198D4B1309B62510C /* FIRPhoneMultiFactorAssertion.h in Headers */ = {isa = PBXBuildFile; fileRef = 8256334A1BB6D43D6A505A6A754FB9AD /* FIRPhoneMultiFactorAssertion.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3C7D6E44E8B2D1CAD761AE1E52A96E38 /* NSError+RLMSync.h in Headers */ = {isa = PBXBuildFile; fileRef = 40538536D8C20ED7DA137A5713BB459A /* NSError+RLMSync.h */; }; + 3CC55DD6A04CCCD387282A9F4477E0C9 /* FIRVerifyClientRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E959605E1F403D7C14260C76E2C0B48 /* FIRVerifyClientRequest.m */; }; + 3CE18A1F048FB0FCAEB327D11D9F7812 /* FirebaseAuth-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 3365BB0E589B36D213FB9E983F34EF99 /* FirebaseAuth-dummy.m */; }; + 3CEF90A4BF4D698D3C0E6E28F79F8D90 /* FBLPromise+Do.m in Sources */ = {isa = PBXBuildFile; fileRef = 30A03FE1790D4156F8F0C48C9824EE5F /* FBLPromise+Do.m */; }; + 3CFB18B0527BA0AEE99AEF919724A524 /* FListenComplete.h in Headers */ = {isa = PBXBuildFile; fileRef = 1490E33A780917C79C45E316672435C0 /* FListenComplete.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 3D16DDB8C9EBAD7CF2BEB2BF60F08ACC /* FTreeSortedDictionaryEnumerator.h in Headers */ = {isa = PBXBuildFile; fileRef = D4CA33A9E671FF56D957091FF43648C9 /* FTreeSortedDictionaryEnumerator.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 3D1DEC7F7FDA6D8C486B03C1B36475D5 /* FIRAppCheckTokenResultInterop.h in Headers */ = {isa = PBXBuildFile; fileRef = 5974F17EA36C2FB1DFB94CB822008CDB /* FIRAppCheckTokenResultInterop.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 3D3A8614FAF4D83BF0F47714E011D9EE /* FListenProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = A49A8CB71A70BD3B8FB71290DBA32D9F /* FListenProvider.m */; }; + 3D57F293DE68AED8D0A21AC6D76A05EE /* FIRAppInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = F9E888606FE5836F42A73640926AC56C /* FIRAppInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 3D730C9DC0E969B8CB05CD83179E0E24 /* RLMSwiftValueStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = DF49FADD2F521BE21950120B832A1914 /* RLMSwiftValueStorage.h */; }; + 3DE45AD6C793FC5662B38765F089A571 /* FSRWebSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 5273EDBC2A77E71FC4220D15FFD2AC31 /* FSRWebSocket.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 3E036CAA97F279B0C6ABD859726A047A /* CustomPersistable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24CF3FE9F1F63048BE73769786AA32FA /* CustomPersistable.swift */; }; + 3E1B5386B32268FA87A5B13C81242612 /* Sync.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBC36C1DEA1FE665B1571B58B928ED9B /* Sync.swift */; }; + 3E1BCE16271BB78E389F562A312BD2C5 /* RLMLogger_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 57AA2F599A51760A591158FC670C1F2B /* RLMLogger_Private.h */; }; + 3E501C4D318CD0E51008FFEBB5786936 /* GULNetwork.m in Sources */ = {isa = PBXBuildFile; fileRef = B7487725A4319C3CAF8225F0C8F99718 /* GULNetwork.m */; }; + 3EC845F88149384EC83CD47A57F9D374 /* GTMSessionFetcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 703AE36A6535247556EF937C30749277 /* GTMSessionFetcher.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3EEB5CD0432AE4C966A336FE407F4564 /* SyncSubscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1CC4C7FABA96F45EE8B3CD9AAFE20D0 /* SyncSubscription.swift */; }; + 3EF90985FBC0EFC597433890E552681B /* FIRAuthDispatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = C4AEE519BA69496F1FD1C1F661D8E156 /* FIRAuthDispatcher.m */; }; + 3F3A0AE5CD76C9173676C44A0EB816F9 /* FIRFacebookAuthProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = E2DB273917BC7D135A0439291C9C008C /* FIRFacebookAuthProvider.m */; }; + 3F5DC8E1E4127053A92C72E08D27F5D8 /* BSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CEC0913FB88FE9BE18552047F830854 /* BSON.swift */; }; + 3FBC587410256792D44C22FE350580B7 /* RLMObjectBase.mm in Sources */ = {isa = PBXBuildFile; fileRef = EED7AF0F3BBCD3CF75FB429BB1B43A4A /* RLMObjectBase.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 404B52810CF5B35D54D95481794696F8 /* FIRActionCodeSettings.h in Headers */ = {isa = PBXBuildFile; fileRef = 5F42FD92CC45EDFD0C54EE547EE79090 /* FIRActionCodeSettings.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4171658B89120091D032FE97BA262E6C /* FIRComponentContainer.h in Headers */ = {isa = PBXBuildFile; fileRef = 56627901A29601B454E5A4D76045BF54 /* FIRComponentContainer.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 41A3C21316B987FFDBD324926D024C1D /* GULHeartbeatDateStorageUserDefaults.h in Headers */ = {isa = PBXBuildFile; fileRef = 919DFEB9C187FA7EEAAFF1CD6E87C64F /* GULHeartbeatDateStorageUserDefaults.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 41D9BA130C83986F9937FC360681F3BD /* RLMObjectSchema.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 55971155657172B3C8EE36661224A4CF /* RLMObjectSchema.h */; }; + 41E257B3BE577D173F85A8527E26BDB2 /* random.h in Headers */ = {isa = PBXBuildFile; fileRef = 5F3C1CEEBD4F3E655891CC3098279020 /* random.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 42166693E19EE0C7271C40B2D97DC71A /* leveldb-library-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 458BC4E3C00864D5B96FB2C89BE7DED9 /* leveldb-library-dummy.m */; }; + 4312FD62AAF2FB45358D7DF002936519 /* RLMSyncConfiguration.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = FAEFF93C94DDA61320F23FD69CC400B2 /* RLMSyncConfiguration.h */; }; + 4368C42C4F53C03122E577AC4A39A34C /* FIRFirebaseUserAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = D55A3C15FC867492DF0F4DCD8284D6A3 /* FIRFirebaseUserAgent.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 437CCE734A37C465BF1C06785DA8AB4B /* filter_block.cc in Sources */ = {isa = PBXBuildFile; fileRef = CB6CC9C42F657883774DDF1FC12F6B95 /* filter_block.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 43DA1A03E3CA90322A1E2D113F2CEF8D /* FIRAuthTokenResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 975D4CE22FA4C1DA6407E67828831C8E /* FIRAuthTokenResult.m */; }; + 43DEA604571EA56BDD9171DE48C65DB3 /* RLMResults_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 708181884E851CC294593093D3921B23 /* RLMResults_Private.h */; }; + 43E6D5C2FC9D50383B2C39CDA9929534 /* FIRIdentityToolkitRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = DAC5A28E00D22DC13534FA98A6FF1154 /* FIRIdentityToolkitRequest.m */; }; + 44291122DBE8E9AD92E8CC7F49F17A03 /* GTMSessionUploadFetcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 1100DABD72493AA08CE2AC79C1B6E19C /* GTMSessionUploadFetcher.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 442B35CDAB15537B59F5243FD98FFD52 /* GULMutableDictionary.h in Headers */ = {isa = PBXBuildFile; fileRef = CBE5568FBAD64B88E9DEBA7097A70ACB /* GULMutableDictionary.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 44B2925315E8C523225A94DBBD7CBBBA /* RLMEmbeddedObject.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 6D00B53942427419D9F1A394FBEE64F3 /* RLMEmbeddedObject.h */; }; + 44C56B638B17F5B6DCB5FCD503D0174F /* FTypedefs.h in Headers */ = {isa = PBXBuildFile; fileRef = B997ABCC90C9366DF38FDE06D380B2A8 /* FTypedefs.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 458C1FF89558037425722E55EB0B3DBA /* FIRGetAccountInfoResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 55828DC9C361221F1C6E3554B9703949 /* FIRGetAccountInfoResponse.m */; }; + 45DC4DC21EECB903A0AEC26D726A51DF /* FIROAuthCredential.h in Headers */ = {isa = PBXBuildFile; fileRef = 94E05EC88F26D558B547C8E5D72E7792 /* FIROAuthCredential.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4658CF4DF9D5266AFD60AD5B08CDD9FD /* FIRInstallationsStore.m in Sources */ = {isa = PBXBuildFile; fileRef = D80EF8C0A8F6337C6FB4F253C9D82B8E /* FIRInstallationsStore.m */; }; + 46DDFA750D4F8FC1AD257891B13954F7 /* PromisesObjC-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = FCC47F2FBDB65E9C97CEA7B0375E1E50 /* PromisesObjC-dummy.m */; }; + 4722136B0312A5C842F3A30A08A703D8 /* FIRAuthNotificationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E85C3D67C66233F215F077D5D4DBAFB /* FIRAuthNotificationManager.m */; }; + 479B60053A3DD2352139C5F4438BA674 /* FIRInstallationsAPIService.m in Sources */ = {isa = PBXBuildFile; fileRef = F5C7322600CB61912E75AD1BB17BDBA9 /* FIRInstallationsAPIService.m */; }; + 47E84DE98A0BCA4869BB30F4E00A4213 /* RLMNetworkTransport.mm in Sources */ = {isa = PBXBuildFile; fileRef = F3E5068F34D0E92C3F70A3EEFE682CAB /* RLMNetworkTransport.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 48188B5EFF05E24BCBD3BF8A74F5835C /* FIREmailPasswordAuthCredential.m in Sources */ = {isa = PBXBuildFile; fileRef = 344E6FEA72D17152155F2C9C6C56CA92 /* FIREmailPasswordAuthCredential.m */; }; + 481B69706CC4E586BD0C1BF080020D26 /* FChildrenNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 35106334CFDB44A3BF401053F4AB5332 /* FChildrenNode.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4826009A120992E817EFAE9BD91E5E8C /* logging.h in Headers */ = {isa = PBXBuildFile; fileRef = C6275AF2BB6CE62341D7E3633E717BEE /* logging.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 482EAA47E185193C33011CB530672D66 /* RLMMongoClient.mm in Sources */ = {isa = PBXBuildFile; fileRef = 6E1AAF86750B38DE664456E8E4A9C10F /* RLMMongoClient.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 4832A53F299328B249B42F6C13641B38 /* block_builder.cc in Sources */ = {isa = PBXBuildFile; fileRef = 35CB08C83459BF6C53FCF704A67647D6 /* block_builder.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 4843A45A15A4127190085FAEA939E55A /* RLMSectionedResults.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 9011CDAF888185959FCBA517AA3CCD8D /* RLMSectionedResults.h */; }; + 486464C1D84C601D5ABFC53920E4B959 /* HeartbeatLoggingTestUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6EE078C25A16F573B5605E4E7F0BC2E /* HeartbeatLoggingTestUtils.swift */; }; + 4866194CFA963278423EAB19CF0919EB /* RLMMigration.mm in Sources */ = {isa = PBXBuildFile; fileRef = 463CDBD457E0FB4C4ACD2D2BFE1862BE /* RLMMigration.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 486FB1F998459F78D6D2907F7861E8A3 /* FIRAuthAppCredentialManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FFCE5665AD9B43DF0409F6A7B9C97B9 /* FIRAuthAppCredentialManager.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 48A3DD5AB48593E10CC8CC8701045594 /* GULReachabilityChecker+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 78BCFBB3475F1361601C33BBE6B25FFC /* GULReachabilityChecker+Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 491FCEDE5FCD1E4853BC3EC46EB3FB24 /* FBLPromise+Catch.m in Sources */ = {isa = PBXBuildFile; fileRef = 76967898F8101178E562B75A2FE2C7B6 /* FBLPromise+Catch.m */; }; + 496C5E6D646C6F261FB29A676837CA49 /* FBLPromise+Always.h in Headers */ = {isa = PBXBuildFile; fileRef = E3E1C442BA8DDCEEFA65EE0379DAD33E /* FBLPromise+Always.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 49A9A4B4409D9359518456CD7D3156DA /* FIRAuthBackend.h in Headers */ = {isa = PBXBuildFile; fileRef = 7F4F042C307A225AAA16C9601FF316FF /* FIRAuthBackend.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 49EB428C817FA945F9BB6A3995F73FFF /* APLevelDB.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3B81F7B757D1B962385B509729E603BD /* APLevelDB.mm */; }; + 4A449CBD996AF1DD78CA968B1EA4898B /* FCachePolicy.m in Sources */ = {isa = PBXBuildFile; fileRef = 90F4CCD10E8C11477F4BC57D0F8C8E20 /* FCachePolicy.m */; }; + 4A48C495B15B169C2B9828A8BEFFB9DD /* FIRResetPasswordRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = F8D485A35F3C8EC5C1FB4CF802609E6C /* FIRResetPasswordRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4A509D1DADB51A3417913A34B8352F8C /* FTuplePathValue.h in Headers */ = {isa = PBXBuildFile; fileRef = D64B72A8936ECC9C34DA6EA69AD8B336 /* FTuplePathValue.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4A65CBCE0C4CAE31C4559FDF046D5F92 /* RLMMigration.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = AFBE43B2C0C2AF9EBCECCCEBBC8D162B /* RLMMigration.h */; }; + 4A96408EC60E5F1D98C83BB0237A612F /* FServerValues.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B01D60353BAB7668513EE30428048CA /* FServerValues.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4AFFADD4B822947985F6930E6557BF87 /* FIRVerifyAssertionResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = EF93B3CD6E2C57E0A8E985819171A8AD /* FIRVerifyAssertionResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4B608FE2ECE665D165D9F46633E74AF9 /* FirebaseCoreInternal-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 52E34EC8AAB1C8662FC59D8A62F2E08E /* FirebaseCoreInternal-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4B78255CFCE26F89B4FB04D56E46577C /* FIRAuthRequestConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 21F6C74565B78083660C443B41DC95DE /* FIRAuthRequestConfiguration.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4BC450BD29DA1B1F0A6393E89BCAEF67 /* log_reader.h in Headers */ = {isa = PBXBuildFile; fileRef = EAB3A0514E6334B17A71E551EFCEB469 /* log_reader.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4C1DE7029ADD87FB8DCFB376283C5898 /* FIRGameCenterAuthCredential.m in Sources */ = {isa = PBXBuildFile; fileRef = 0F7F3AFAE2A24AD030BDE0A544F117C8 /* FIRGameCenterAuthCredential.m */; }; + 4C3A971EFC4B51F07BF7A2C487073D4D /* RLMSyncManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 2B5BF8D2317897E5636B6D098AAA376C /* RLMSyncManager.h */; }; + 4C51A5D00224D8834489FEC967ED81CC /* GULOriginalIMPConvenienceMacros.h in Headers */ = {isa = PBXBuildFile; fileRef = 1678ACD8E0AF993C082BA2E26E5C9293 /* GULOriginalIMPConvenienceMacros.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4C9439E7A3507B105C4BB4707F0E7334 /* FArraySortedDictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = D5C8BA1EEC0185497B91CE4F4A3EA391 /* FArraySortedDictionary.m */; }; + 4C99278882E436684311D9BFD37937F7 /* FBLPromise+All.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CEDB3566E20E923946312D7CEF69B71 /* FBLPromise+All.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4D2B7517D0813C662A60572D908D65B1 /* FIRInstallationsLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = F1CC9D6836BEB84A834ABB338A080E55 /* FIRInstallationsLogger.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4DA78481AA044CB40BDB1AD282BA35B8 /* RLMMongoCollection_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = D00927971D6B3C1621037BDC2C93FB12 /* RLMMongoCollection_Private.h */; }; + 4DCA1C2000C8709D077527E34A1ACF55 /* FNamedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = C3AB1EF8BE9154067AF395162065B7F7 /* FNamedNode.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4DCEFFB1FBD0DD6F77A3D6CAB6FF6BE5 /* GTMSessionFetcher-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 27A49FDF138880BD7F33CD5008A47C15 /* GTMSessionFetcher-dummy.m */; }; + 4DEDACB8CD42A769352645B89B73201D /* FirebaseCoreInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = FC3CEE71B7D74D3270183AD28E24D9FB /* FirebaseCoreInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4DF7C4E7DE1A2616D895833DA75A1259 /* FIRPhoneAuthProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D3BA8069DBAAD52F0BBD67EF7D95738 /* FIRPhoneAuthProvider.m */; }; + 4E05FA1B2E051ADC104673E3740280D6 /* merger.h in Headers */ = {isa = PBXBuildFile; fileRef = BCD33795AF033DD0357292495050944A /* merger.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4E09CC3E7BFB08BF1D4E9C22246B5114 /* StorageFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC9C364C4160499BF30C6614BB9168B2 /* StorageFactory.swift */; }; + 4E3873B890396CA5576DEADB4D8DA616 /* RLMSchema_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 120853B5C287EB6778D0E6F2CAAC678B /* RLMSchema_Private.h */; }; + 4E6803BAEBD925222351FE9B6885F3DC /* env_posix_test_helper.h in Headers */ = {isa = PBXBuildFile; fileRef = FFDDE3E628D464C5FAF7C60041209C2C /* env_posix_test_helper.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4F06F225D9F08ABDBD0F08524EB8D580 /* FIRPhoneAuthCredential.m in Sources */ = {isa = PBXBuildFile; fileRef = 2EBF4EF9C2EBB9F4610CF7F1990756D8 /* FIRPhoneAuthCredential.m */; }; + 4F51C722E3194985A2C961E89366F2F2 /* FTreeSortedDictionaryEnumerator.m in Sources */ = {isa = PBXBuildFile; fileRef = E9A4687D268F2913AF3361DC3E0DCA57 /* FTreeSortedDictionaryEnumerator.m */; }; + 4FB8F7A00DAC6A8C59492FAA33A6F33A /* pb_common.c in Sources */ = {isa = PBXBuildFile; fileRef = EA10A779E36C2B20E2D2B85D189969F4 /* pb_common.c */; settings = {COMPILER_FLAGS = "-fno-objc-arc -fno-objc-arc -fno-objc-arc"; }; }; + 501CCFC0727924636987808BF71FDA97 /* FIRHeartbeatLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = CBF3DACAC92F02382C074F36C5FF59C1 /* FIRHeartbeatLogger.m */; }; + 5031EDD6D39ABE328F106298097D68CF /* FIREmailLinkSignInRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = F0B54BCD2027EEA2560F04A5F660DF5F /* FIREmailLinkSignInRequest.m */; }; + 50CDD7A792E4F8FBC44618421DD8CF9B /* FirebaseInstallations-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = D93CC25FAAF72AD0E3E8DCA1B38AC5A6 /* FirebaseInstallations-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 50D4D65EE4C1B4EDB3D8B2AA68B1A01D /* block.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4B39E52B0C608DB97C5C4253CF1DF99E /* block.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 51126ABE1EBA39EE201F72B0567BD3BA /* FIRVerifyCustomTokenRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 3ACA02065590E1AFEA516EA287B96AE9 /* FIRVerifyCustomTokenRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 5145A069D3AD0759F1133EFCB5313C00 /* RLMRealm_Dynamic.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B05F3BE2B4BA2F8C84E85EC55902EE0 /* RLMRealm_Dynamic.h */; }; + 517660A661274C4A72A3E7FAE2B9883A /* Pods-PRTY-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 2B738DB0AE5FFD26E7118871882CA3F6 /* Pods-PRTY-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 51CB4CF290C18825C5302621D800DEC2 /* FIRMultiFactorResolver.h in Headers */ = {isa = PBXBuildFile; fileRef = AC261D7B91CBC6A2616EEE91114F83A5 /* FIRMultiFactorResolver.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 51D0DF0757943CCB8BB8413E7949854D /* FIRAppCheckInterop.h in Headers */ = {isa = PBXBuildFile; fileRef = A02ACC5171F5816C4717036ECB8B255C /* FIRAppCheckInterop.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 51F3891D59A4214B173A1EAEBE5F327A /* FIRVerifyAssertionResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 143EB88CB6BF32B3B92E745AED2B8D1F /* FIRVerifyAssertionResponse.m */; }; + 51FBC9718924785B6B4B2827C0569407 /* FIRAuthUIDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = BF274B2900480BCAE368E294B73E5B23 /* FIRAuthUIDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 520DE702E04C513843FE06229BD82259 /* FIRDeleteAccountResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = B98A05D5A1CDC09C8D241FDD9E8942CA /* FIRDeleteAccountResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 521B7AF46A4DA8F73C0FCE98A8652410 /* RLMScheduler.h in Headers */ = {isa = PBXBuildFile; fileRef = B0F9C1B839FB025457D8E24B0D0E8D9A /* RLMScheduler.h */; }; + 5245FD7B67D000DD606C54FF58571B23 /* FSnapshotHolder.h in Headers */ = {isa = PBXBuildFile; fileRef = 97392617A9D0A4229CD0CBA298E78B57 /* FSnapshotHolder.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 52BB88609ECD059EBB11D6B25FD1E313 /* dumpfile.cc in Sources */ = {isa = PBXBuildFile; fileRef = 05B386CDC39EA631D1FAAA7D1F0AB45A /* dumpfile.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 52CCA2C0E0519F7E94D786041FE01870 /* FBLPromise+Await.m in Sources */ = {isa = PBXBuildFile; fileRef = 1173B352316565C062F130D6DF0B2D83 /* FBLPromise+Await.m */; }; + 5313ED256C342664AB3F3F7A45504AC2 /* RLMDictionary_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = F46007BED52B57BCF4843B87E9523D49 /* RLMDictionary_Private.h */; }; + 5337561978B91F1E3E2D06222FD818CA /* FIRInstallationsBackoffController.m in Sources */ = {isa = PBXBuildFile; fileRef = A7136DC79F7CF21A918462EA6BA72D9F /* FIRInstallationsBackoffController.m */; }; + 53502CA8CADE18039E609C3CD3642AF6 /* FIRPhoneAuthProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = F6709A26A6D2B2D009B7AD09AB964714 /* FIRPhoneAuthProvider.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 540B40700F4D887009995777BE969707 /* FListenProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = 52B4AA8267619A715F34030E9D7C8DAF /* FListenProvider.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 5445F07D73D86E557BDFD419CD743D6D /* FBLPromise+Race.h in Headers */ = {isa = PBXBuildFile; fileRef = 122D962CA59AC2D4A82C5178BE4BE260 /* FBLPromise+Race.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 54D1FFB96451C7B3EB31FDAA8D1A93E3 /* FRepo_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = FAB149690E2D664FDECA85D5157CBA67 /* FRepo_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 54F05B51D5819573F1F0C3EE8AEAF5BF /* FIRAuthProtoFinalizeMFAPhoneRequestInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 2102618715F19E54D0AB8FB6593E0326 /* FIRAuthProtoFinalizeMFAPhoneRequestInfo.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 54F62BCFBC519F4FD6C42F437664AC6E /* RLMAccessor.mm in Sources */ = {isa = PBXBuildFile; fileRef = 277D8E8244D2FA29E1317FCC9FB6C696 /* RLMAccessor.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 55284658D32D0CDD85FA37EF35A79238 /* fbase64.h in Headers */ = {isa = PBXBuildFile; fileRef = 92FA39E85E83F2D45F0EFE7ED6AC3E9D /* fbase64.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 555CCCBC50108665AC9117CDB6F576E2 /* FUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 5026DF9D418AC9740AF4DC88D58E0F34 /* FUtilities.m */; }; + 55814156A2B12DE25A5F87842E17DB31 /* FBLPromise+Delay.h in Headers */ = {isa = PBXBuildFile; fileRef = 48F42BAA7BEB6F1D7FB7708D9D26470E /* FBLPromise+Delay.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 55D159558CD752F60B91D48FD16B5B14 /* FLLRBValueNode.h in Headers */ = {isa = PBXBuildFile; fileRef = A777775526F20173795213860C79ADEE /* FLLRBValueNode.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 55D37E587FABDFB9D97DDC35CB8A4A51 /* FBLPromise+Testing.h in Headers */ = {isa = PBXBuildFile; fileRef = E2DDE940DDAC937FC95E2A04A274103D /* FBLPromise+Testing.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 56040CFFA72105E3B95C1D44A8AAD299 /* RealmSwift-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = F11AA3BD3B6733487D7ED153F816289D /* RealmSwift-dummy.m */; }; + 5609685AD9628CB2C95E0110E743CF9D /* FValueIndex.h in Headers */ = {isa = PBXBuildFile; fileRef = 187AAB69D8B2FC133DAAA952E9154DAB /* FValueIndex.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 565750705CA8C90200D9A1EEF7275FD7 /* FIRGetAccountInfoRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 360D283782E2F70E29346574623B578D /* FIRGetAccountInfoRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 568B5B5D2DF06DCD731EDAAA735AFCD0 /* FIRLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = BE904D1FED7D94CEE1F8C3A0FCC83148 /* FIRLogger.m */; }; + 56D6E3DB181AF1B10B1893736E4DE442 /* log_format.h in Headers */ = {isa = PBXBuildFile; fileRef = B7D00F668FCD769C1AF57B80F9EF273E /* log_format.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 56DD497298CFD6B9BE25A7DB188F137A /* FIRAuthErrorUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = BE5EA9BAFBD4C1C39027D404A599B6E0 /* FIRAuthErrorUtils.m */; }; + 5700CD33EC84CEA20B9E8D458063882A /* FIRDataSnapshot_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 7F2816163119D09FACF48BF06C77144F /* FIRDataSnapshot_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 572713FA85012B09A410BEEEF0400B23 /* FIRUserInfoImpl.h in Headers */ = {isa = PBXBuildFile; fileRef = C7A7A909033C8FDAD8F306BF09436C37 /* FIRUserInfoImpl.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 5791C5BE858BE11F3C05A9872B4B40E7 /* FIRInstallationsErrorUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D63A41B92013D355B257E784C3C5D2E /* FIRInstallationsErrorUtil.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 57A3EF3072CC13E10031822BC6C763E2 /* FIRIdentityToolkitRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 28BA89D03A923D6F3645E3792D7B6A85 /* FIRIdentityToolkitRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 57F7C783C5CC5A1BEFFF5ECC67792080 /* log_writer.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F8113D296393D094DD639A535F9873C /* log_writer.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 57FA026564E61B5A7C007FE2B748A227 /* pb_encode.c in Sources */ = {isa = PBXBuildFile; fileRef = F0C021C6E1701A5C89767E23F96F8FB7 /* pb_encode.c */; settings = {COMPILER_FLAGS = "-fno-objc-arc -fno-objc-arc"; }; }; + 5805F658F32743DE99FEAB6A6F4A21D9 /* RLMRealmUtil.mm in Sources */ = {isa = PBXBuildFile; fileRef = 97C24FBADCCD7036078377512D90D4D7 /* RLMRealmUtil.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 580DC037A2A349DE3A5BAF94A36211C5 /* FIRVerifyPasswordRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = F16A7F5529145AB1A4B7E519508ACF72 /* FIRVerifyPasswordRequest.m */; }; + 582154C6ADD5ABA88AE539266498C60A /* FIRAuthDataResult_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 00E78D580C86EE50250D99A09C295403 /* FIRAuthDataResult_Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 585DFEF219F029D15010CD641EF535F8 /* FCacheNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 28F4C70F3E073FC6BA4014DBCBDFC33B /* FCacheNode.m */; }; + 58882B03EECF67F28BEFC616DE13B6EE /* GULSecureCoding.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E042D37247BFBFE5C5FFA198F53B6AA /* GULSecureCoding.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 589E4C484F651A492FBB935FBF740DEB /* memtable.h in Headers */ = {isa = PBXBuildFile; fileRef = 7D790D2DD3CD5C606CCF3B56048A95D6 /* memtable.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 58C96277ECC03358ED0A472DA23F3F53 /* RLMSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E083BCD2610C9F8CD73B0B83C2A3252 /* RLMSupport.swift */; }; + 58DE67C18F2A1D9FE9418218F72B7757 /* Pods-PRTYTests-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 5316165368ABB6512CB6E082B4E2B9C3 /* Pods-PRTYTests-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59172902DE2D04BC0A5E95A22D78E6E4 /* FIRAuthAPNSTokenManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E04B2430253816BA0826684401AB443 /* FIRAuthAPNSTokenManager.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 5964B58BB046CB6CCD8E511CBCAEA80E /* RLMObservation.mm in Sources */ = {isa = PBXBuildFile; fileRef = 50371EE0D5E9B68064DD3B94892A83DD /* RLMObservation.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 5997E8A72EC4756FD9EA0D217A102E56 /* FIRAuthSettings.h in Headers */ = {isa = PBXBuildFile; fileRef = CAA738EABBD697265171DE3DAC8E0C17 /* FIRAuthSettings.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 59A212C68AC67FFFE1BBFFA322B06CEB /* RLMConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C5F2659D020AEC57B6932441441E7E8 /* RLMConstants.m */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 59DBE5D4B7A5CE7E86AAE82D7B242964 /* FTupleCallbackStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = 63554B52614D7D8DF01AB2A87A9CC991 /* FTupleCallbackStatus.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 5A0B815B366922A4474119ADF8C6B944 /* FirebaseInstallationsInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 27947EE5809D5134A30123C3BAD888C7 /* FirebaseInstallationsInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 5A1109D02A51716B3DC2E37A3FC5632E /* FNextPushId.m in Sources */ = {isa = PBXBuildFile; fileRef = CAACC193A9AD2AE454E57F5C3EF6F1D4 /* FNextPushId.m */; }; + 5A112F8271072DE73024CBA8078043AA /* Projection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44140A47AA4C978E372460E01A273CAE /* Projection.swift */; }; + 5AC2DDA73F2100F520FFEB5480E511E7 /* FIROptionsInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 782D131BB42C5CBFD43A47DDC8824422 /* FIROptionsInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 5AE0FC6ECF376011AEBAB1F7C2F04640 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB96318E2CB72DE3CDFEEF1B9E8644AD /* Foundation.framework */; }; + 5B0D2E37D013049C4FDCDF690DA1AEA9 /* cache.h in Headers */ = {isa = PBXBuildFile; fileRef = 50394C30904748E456D4C35922B549B3 /* cache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5B5A896DEF606171FF5CD8478E3129F2 /* FPriorityIndex.m in Sources */ = {isa = PBXBuildFile; fileRef = F62A4B119F14F2DCBA60D4223F2BEDEC /* FPriorityIndex.m */; }; + 5B8A458DC7C87F427A5C463F3CAC517B /* Decimal128.swift in Sources */ = {isa = PBXBuildFile; fileRef = 753ACF5F1365F9D5FD71BE6F829E2F92 /* Decimal128.swift */; }; + 5BDE98E505CAFDBCEED5C84E82F9958B /* RLMError.h in Headers */ = {isa = PBXBuildFile; fileRef = C6B2640364AB64A02A4091061D24152C /* RLMError.h */; }; + 5BECFA895A8912A75721584A238F04F7 /* FIRAuthInterop.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DEC2457D87D238E0CD170552886919 /* FIRAuthInterop.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 5BF4201F4F0D3F3912D7CFEC12CB183E /* pb.h in Headers */ = {isa = PBXBuildFile; fileRef = 3C428F6C9EE7CA9AAF79DA85A514B14A /* pb.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5C34CE6C2A6C7932B3216D2844258313 /* RLMAccessor.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = B508FF5F45501FC204670A03072D40AF /* RLMAccessor.h */; }; + 5C7234476A52BF7C290A0A4395E1CE65 /* FParsedUrl.m in Sources */ = {isa = PBXBuildFile; fileRef = 3590D9904E6E3BCACBF1085443FE45FD /* FParsedUrl.m */; }; + 5CA3A6BE0C3058AFF6CB3EA559809BAF /* FIRCurrentDateProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 40AA7B7AA35DA6F3567044AE67EC3AE3 /* FIRCurrentDateProvider.m */; }; + 5CC62BA3C946FBC25A11AB5778675995 /* RLMObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 780F15D6939A98ACA8F237480C9FDF2E /* RLMObject.h */; }; + 5CD7BEA809F7A6459BE94B7FB8E4E220 /* RLMAsyncTask.mm in Sources */ = {isa = PBXBuildFile; fileRef = 02170472A8C1C88AB10DAC7F8DA66B69 /* RLMAsyncTask.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 5D01CC83D8C2C6D0A0C82588A0B22D96 /* RLMConstants.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 83712E3E12FF5DD9E4CC45C82549DD15 /* RLMConstants.h */; }; + 5D312581A8E49DA56F5A578C9716869C /* FIRSendVerificationCodeRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = A21BE0CCC6934357A32AC861FDF64150 /* FIRSendVerificationCodeRequest.m */; }; + 5D8F3549757CF9CC44FB0D55347EC1E0 /* GULLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 02D7467DDB121A7DEEE46877041066D7 /* GULLogger.m */; }; + 5DECDE1DDD458F2D47F8C641C638E348 /* FirebaseCore-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 254DFE40388CA77868691F69AC5F12D5 /* FirebaseCore-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5E1FC2F73D8BCC5F49BA87CD68F27737 /* FPendingPut.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C58E49372EAEEB8B4514B62243B2D8C /* FPendingPut.m */; }; + 5E4803946556D9427C1E7E569B038C1A /* nanopb-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = D5890EEE293438821271DA021C01DB15 /* nanopb-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5E4B70D26A7E04EF92A34EE613EBFB2A /* FIRDeleteAccountRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 6ECA1090408234F0432AD7A8719CDED2 /* FIRDeleteAccountRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 5F0035F3A7972050FF180F1353B39463 /* FIRGetOOBConfirmationCodeResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 186FA2D4398AA444253D80F690200E1D /* FIRGetOOBConfirmationCodeResponse.m */; }; + 5F0A29426B5289CE22EE51AFE0A28775 /* ObjectiveCSupport+Sync.swift in Sources */ = {isa = PBXBuildFile; fileRef = E355264F8F23BD69A8E6EC8A430817AD /* ObjectiveCSupport+Sync.swift */; }; + 5F0E280A37666ADE8D88D12AF7CE94CD /* GULURLSessionDataResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = A44E4167201C1AB4D63CA58B6C88B7D2 /* GULURLSessionDataResponse.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5F21EF6E74C5254B54F99DF2F37321A1 /* FIRMultiFactorSession+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = D24EAB3656B66CFA3FC4EC757C29A2B0 /* FIRMultiFactorSession+Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 5F8A63633E05A9E7B34F5D31A8989574 /* Pods-PRTY-PRTYUITests-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 69578BBD7CC915AC07C4B3A36276C339 /* Pods-PRTY-PRTYUITests-dummy.m */; }; + 5FAD38ED361CFAFC0E4AF120C95BA013 /* RLMConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = 83712E3E12FF5DD9E4CC45C82549DD15 /* RLMConstants.h */; }; + 5FB06882FB3FFC654DCC1AE26110B315 /* FTupleObjects.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C8C2F327B6662093A84BFDB0321BAFB /* FTupleObjects.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 5FBFE5D037D58A5AFD620C5FDB5E0C7A /* FIRLibrary.h in Headers */ = {isa = PBXBuildFile; fileRef = 6DEADF2D6BCDFA40C7B0F220FE995B41 /* FIRLibrary.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 5FCCD637451B4362B20EF5C1DF4FE27D /* GULUserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = 7E9095E4AA136950BC9BCC00DC4AF244 /* GULUserDefaults.m */; }; + 6036D8DB4C4B7C592FF94E76A7DF8D98 /* GULAppDelegateSwizzler.h in Headers */ = {isa = PBXBuildFile; fileRef = 6F386A0EAC54042F34AD558B82364330 /* GULAppDelegateSwizzler.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 603AB74B5E67811B4D03346CA6FBCADD /* FTupleSetIdPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 0573A17A7335B226B940471176B068EC /* FTupleSetIdPath.m */; }; + 605323DEC358BEE719E4D52B3627DACA /* RLMObjectStore.h in Headers */ = {isa = PBXBuildFile; fileRef = D153033C39ED5D472A14A8B145E0434D /* RLMObjectStore.h */; }; + 609DC9E302A653DA56687D5C92A1CF52 /* FLevelDBStorageEngine.m in Sources */ = {isa = PBXBuildFile; fileRef = E4274F4A59E6D6C77EE43A9264D4726C /* FLevelDBStorageEngine.m */; }; + 609EB115EBE2C1BB25EE2FF2EE67A4BD /* Property.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A3490944EAFC2F4D1E10697E776D942 /* Property.swift */; }; + 60C0157E685DD1F2BAF7D7E47E5FC8F4 /* RLMObjectBase.h in Headers */ = {isa = PBXBuildFile; fileRef = C69F72C06B9F4D036CD7680BFD656FDB /* RLMObjectBase.h */; }; + 6167C40443525D692BA386E55620DD14 /* FRepoInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = FA61EC6075B55FC111B9D7281C25E9CB /* FRepoInfo.m */; }; + 61836E97EC307FE78A3188DC59E80766 /* FIRAuthDefaultUIDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C8C68A38AE16BAFA716CDBF9740AAEE /* FIRAuthDefaultUIDelegate.m */; }; + 61C65BF648375A8DF65199887BA1CC36 /* FEventGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = 312A6319AFA1D25F26944EE1A94437CC /* FEventGenerator.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 623172201F28ACB8537E34B99ABB4E75 /* FBLPromise+Do.h in Headers */ = {isa = PBXBuildFile; fileRef = 74B5118CEAD735734BEAA228AD3D8739 /* FBLPromise+Do.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 62A55B1CA17373B9BFBC6BA6887F22A6 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB96318E2CB72DE3CDFEEF1B9E8644AD /* Foundation.framework */; }; + 633CB270D7455590E3E9E7C0BB61BA0E /* FIRRetryHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = F76CC964DA80E549EEB9C20EB2651EB3 /* FIRRetryHelper.m */; }; + 63D74FBA3A84E9500101C5B32FBAF35C /* FIROptionsInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E2D8E4D702AA7E3958C44B41A68AEF3 /* FIROptionsInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 63FFD179F5B7441B72277FBA17CA7E57 /* FIRAuthDefaultUIDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 38C820D1FF6FACD317F69B7822D4B160 /* FIRAuthDefaultUIDelegate.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 643A7722C9C5049ED385CD61C0D2C74C /* RLMPushClient.h in Headers */ = {isa = PBXBuildFile; fileRef = CC35B50226DE5DE0D691E21CE1CAED70 /* RLMPushClient.h */; }; + 64487BBCCACB841B1DAF3A8FD45CE1C7 /* dbformat.h in Headers */ = {isa = PBXBuildFile; fileRef = 1051F740E13750B942A9EDA85AA602EE /* dbformat.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 64B9E5FB3BC5313C5CB1C7CF70FCD5BF /* FIRPhoneMultiFactorInfo+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 33996B996CB2DA56D97D8237737419AC /* FIRPhoneMultiFactorInfo+Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6534652571843696A0F64F405498D430 /* FEventRegistration.h in Headers */ = {isa = PBXBuildFile; fileRef = 7334D38A0B7D794172B7EDC55F342D71 /* FEventRegistration.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6554025CC0DAA62DA09B3C2E06896D90 /* thread_annotations.h in Headers */ = {isa = PBXBuildFile; fileRef = CB6EC6D167E8A3AB0DFE54EBC765CAA3 /* thread_annotations.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 657FA1B537040FA0900273E09DACF02A /* table.h in Headers */ = {isa = PBXBuildFile; fileRef = AE140AEAF52DA37BEE141D52E151594A /* table.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 665E44FD4B1FD5EB5403D5169D7E56CA /* FIRVerifyCustomTokenResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = B30E8A2EFD646DD32FBF567E54E8FE3A /* FIRVerifyCustomTokenResponse.m */; }; + 668E0B7C95B37D8DFE134D091A0BFAF5 /* FIRResetPasswordResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 9254CCCC55DF6E10A7F6C8019FD5F8B8 /* FIRResetPasswordResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 66E2AA64199527717DA5CA9F0703ABF4 /* env.h in Headers */ = {isa = PBXBuildFile; fileRef = AD80C00D5C4B562AD2F08B823827B159 /* env.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 672CFE0E53EE27776F329249118ACE25 /* FIRMultiFactor.m in Sources */ = {isa = PBXBuildFile; fileRef = 5185F33603CDA2B68194411E0A8EE5FC /* FIRMultiFactor.m */; }; + 67937E2E8F7F37C6511383F05A56B941 /* FTupleTSN.h in Headers */ = {isa = PBXBuildFile; fileRef = D123FAB0A8C5ECD50735F08853562BC3 /* FTupleTSN.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 67D409B2F1E6AAA495FBBD92F5C45E3F /* RLMArray.h in Headers */ = {isa = PBXBuildFile; fileRef = AF4C27BB7CD817442F90B3068C676B6B /* RLMArray.h */; }; + 68005BC2C5F600F7841B5BD2333636EC /* FIRAuth.h in Headers */ = {isa = PBXBuildFile; fileRef = E609518EF2F1803F18D4DF39F3B4FB27 /* FIRAuth.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 682649CEC1CA3CFF6F01C692754E53D5 /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = 221A1EC0D7C56B655A04DE2004063628 /* App.swift */; }; + 68A1D8991B40FF51D86FCA23FD15A401 /* FIRAuthInternalErrors.h in Headers */ = {isa = PBXBuildFile; fileRef = 3F3D7C8AA04555304F587C2EE131762B /* FIRAuthInternalErrors.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6937D13B8FF8AB3A213A5DF4E9219D47 /* RLMSet_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 87B4B54B444CBCE7121C9CC71213A704 /* RLMSet_Private.h */; }; + 69DFDFF0AF88E04E100B31F3B8232C0D /* RLMPredicateUtil.mm in Sources */ = {isa = PBXBuildFile; fileRef = 701AE09D27677AF927D0756A5C7C40B4 /* RLMPredicateUtil.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 6A02A21D71BA4843494A0AF209FB4558 /* RLMLogger.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 8863D1E8CCA754A7C72D9B4890E10EDD /* RLMLogger.h */; }; + 6A3CF6C2BF8B0291E6EDE3A1DD05B00A /* env_posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = AC67D1A683AEF0B1D0C65AE006AFDD82 /* env_posix.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 6A7947EDEF0FD4A230501DEEBA20B426 /* FIRInstallations.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F207504952B0CD5C9F5FE247A248597 /* FIRInstallations.m */; }; + 6AE773CDC43873AD079E95360A32A284 /* RLMSwiftObject.h in Headers */ = {isa = PBXBuildFile; fileRef = F6150C0680A6EE061716FDD32CE733D5 /* RLMSwiftObject.h */; }; + 6B1F6C00D9884BD500BD80BA0A8B562A /* FPruneForest.m in Sources */ = {isa = PBXBuildFile; fileRef = 5BC2453F28988CA912B8C605F9E28277 /* FPruneForest.m */; }; + 6B28A1F6364323D6F1EE3B59DB3A2B3E /* HeartbeatStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F08C4B9A5E6AFBA8D2DDDA90493AB07 /* HeartbeatStorage.swift */; }; + 6B78FBCD579F9C61B65E8B50D8EDD439 /* RLMObjectBase_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 171EC043E8C48B150D6C70B8D3C8551A /* RLMObjectBase_Private.h */; }; + 6B93BE98BFB7A771824B968D139D4451 /* FIRVerifyPasswordRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = F5468F77E33BB89CB6344365C97B2821 /* FIRVerifyPasswordRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6BBB9D3D1E702A56325CA972DAB9C605 /* RLMPushClient.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = CC35B50226DE5DE0D691E21CE1CAED70 /* RLMPushClient.h */; }; + 6C584A75762A7121616EEAEEABA54280 /* FTuplePathValue.m in Sources */ = {isa = PBXBuildFile; fileRef = F8FAD4104C03D65C5550064D9F044480 /* FTuplePathValue.m */; }; + 6C59DE012FACC419CD2F0259DFEFAF40 /* GULHeartbeatDateStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = 3287B3FC8DE790FC3DCEC27D6BA1A7BB /* GULHeartbeatDateStorage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 6C8114A52703DCCBD717A2C65AD5E69C /* GoogleUtilities-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B5CA39A2CE71ED31A7A51A7DEE202E3 /* GoogleUtilities-dummy.m */; }; + 6D2C6F9E260C61A32B0281446400F958 /* GULNetwork.h in Headers */ = {isa = PBXBuildFile; fileRef = 06FE9F21A3BCFA3977FAEECD35474C42 /* GULNetwork.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 6D3B7C2BF20A55C9D460151D79439BEE /* FOperationSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 9CF3F69586BC10D21D82153B4BF2A8E2 /* FOperationSource.m */; }; + 6D5601D8011B68E29F793C2F38E7E339 /* FIRSignInWithGameCenterResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 35E3F5B427B2657E3077368D97033BB2 /* FIRSignInWithGameCenterResponse.m */; }; + 6D980042B490765086010F317F4006E5 /* FIRMultiFactorResolver.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AAC8D7921DC3CFE9D2E4976DAE3040F /* FIRMultiFactorResolver.m */; }; + 6D9CA441C68C8FE9F8B757E9C4C7A34E /* FIRVerifyClientResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 36C43AC2291B2B1D31742EF42B3BFB6D /* FIRVerifyClientResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6DC739B4759D5679D631B2297D2618B6 /* RLMThreadSafeReference.mm in Sources */ = {isa = PBXBuildFile; fileRef = 29CBFE174016502905427BA7B5DBE044 /* RLMThreadSafeReference.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 6E09FC0722B6BBC771CD1C26DD93B664 /* filter_policy.cc in Sources */ = {isa = PBXBuildFile; fileRef = 0BFFC1CBABB5EE6979B7BB6454C1F606 /* filter_policy.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 6EE7668A320D637AD0788EFFFC8E1F67 /* FIROptionsInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = E979A44E4715ED4F43A9136F01012EA5 /* FIROptionsInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6F2488447014917CC4AAF15465543EA3 /* GULNetworkInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 76B21F0B55C360125A29B27794C61933 /* GULNetworkInfo.m */; }; + 6F37A41886CA7FFFBA8576AEF58E2D6F /* RLMUser_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 0E66C7EAAF91F65896E6CC7C4A7B26F4 /* RLMUser_Private.h */; }; + 6F41546A492D5F6448970F4278FF2A07 /* GTMSessionFetcherService+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E46BC3A6CF1D9F1F138BD437FF6E7AA /* GTMSessionFetcherService+Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6F4303D28697F0CD7593FD437D4AEED5 /* FLLRBNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 45DCCB0A7A912B2851D96ECE76C3B6D4 /* FLLRBNode.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6F93BBD384F487594C48556579A2E8ED /* FIndexedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = ABCC74735035AF922CF393EA7C93A204 /* FIndexedNode.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6FB22426B2EB8D375C6730C6742B1133 /* FPersistentConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = C43AF87E49A1E6F9EB9613D7269CD983 /* FPersistentConnection.m */; }; + 6FC16F5639926D99A63C51C6AB855C2D /* PropertyAccessors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74A5A96FBBF716F052FC7FE7E7799B11 /* PropertyAccessors.swift */; }; + 70244986A48B56752A1F63833EFB408C /* FIRResetPasswordResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 6677881A1A790A577070807981ECC661 /* FIRResetPasswordResponse.m */; }; + 7027C8F66273C15566DC87EA976FBBCA /* FIRInstallationsStoredItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 648A0A18D652FE8A5C1DF6848D5864D1 /* FIRInstallationsStoredItem.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 7032415E7E58896C284DAE637501C451 /* FConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = CA3763A5C3BE75A0E0860942F867C9E8 /* FConnection.m */; }; + 703DE9CF4ECC5464EB8C17404FDC70EF /* FIRAuthErrorUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 39B4A3F4F9FF7842FA2A7D4F246719A3 /* FIRAuthErrorUtils.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 705ED32B9CF56B5852CA33C5BCC90233 /* GULNetworkURLSession.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CCBD61D45E1DA5335507549F09ECA06 /* GULNetworkURLSession.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 70665A637908A34422AEA93EED2F7BDF /* FTupleFirebase.m in Sources */ = {isa = PBXBuildFile; fileRef = BE9749E67C035DA4EB9E5F6AB5530370 /* FTupleFirebase.m */; }; + 70EA9C51B91189AC304E612F4998C52D /* nanopb-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 857C5EEC6F7D3F8980BABFC0863E92C8 /* nanopb-dummy.m */; }; + 7158EE753AFBCD149B1110FAEF2E6DCF /* FOverwrite.m in Sources */ = {isa = PBXBuildFile; fileRef = 60E66EB709475B2AE9581154EEAFEF40 /* FOverwrite.m */; }; + 71B2896D03416092358F5EBCF3E2FC14 /* GULLoggerLevel.h in Headers */ = {isa = PBXBuildFile; fileRef = 6829850E183C8570735638BD3F540C47 /* GULLoggerLevel.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 71ED8B725658B0D3E35D4B72106BC615 /* SchemaDiscovery.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5DD6C3F39E0FF0D612E4964A5FD8D45 /* SchemaDiscovery.swift */; }; + 71FEA929BEAAE87FEECC90064CAD12E1 /* FIRSecureTokenService.m in Sources */ = {isa = PBXBuildFile; fileRef = 312C7C07B79F4877B8F6286D00F9C8E8 /* FIRSecureTokenService.m */; }; + 7212BE09C35F4BD336F79AFBC24874A4 /* FKeepSyncedEventRegistration.m in Sources */ = {isa = PBXBuildFile; fileRef = 33F1B68B22D7FE9BC4BA619D1AB5F540 /* FKeepSyncedEventRegistration.m */; }; + 7213E5E3F75461A35E62B98665FED91D /* FIRConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 2B05E83977D207F6BE795A000530F88B /* FIRConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 72326CC926D7729374FCF9260D6CACAF /* FIRInstallationsStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = 46B0CA64A596FDBA487EC8BF5923246E /* FIRInstallationsStatus.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 72AB8DFD21CA1AE084E1FDB7C204A482 /* FIRRevokeTokenResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 93C71DF12581A34115171295278A2235 /* FIRRevokeTokenResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 72BF69AEEB29A843EC0088DFA55979C5 /* RLMCollection_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = F6204AB7B81D89A39B83FE06046A4725 /* RLMCollection_Private.h */; }; + 7346BD05A5E330BD6C4B7DEAB82A087E /* HeartbeatsPayload.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E32862F9DADC43AADD541E3708029A8 /* HeartbeatsPayload.swift */; }; + 73494A7AA13DE730145715BB6C5026AC /* FTupleFirebase.h in Headers */ = {isa = PBXBuildFile; fileRef = 6904D0037830DB80686AB0A6EDFDD815 /* FTupleFirebase.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 73D6DBA39D87023005F7AF6B38244515 /* RLMFindOneAndModifyOptions.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 4831343EA0DCD89549053AB1F3C335F9 /* RLMFindOneAndModifyOptions.h */; }; + 73FE3010502203A12B08BBE54C8E2055 /* RLMAnalytics.mm in Sources */ = {isa = PBXBuildFile; fileRef = 245479B0028A3B41D31BA76DE5EFC18E /* RLMAnalytics.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 7441914D0D9C68B7F20C77230326D22B /* RLMEmbeddedObject.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8C87850C03CB12BC395080AD0C60F63C /* RLMEmbeddedObject.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 745F46C649A9EF4D3EC2810615B87980 /* FIRUserMetadata_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = DA158D7DA802B44F18C94FBD0C6A7A7C /* FIRUserMetadata_Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 74BB146F22D7FF85888EF332589FC2E1 /* FIRInstallationsStoredAuthToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BE10AFF86267C9FDAC00B2AAB63A15D /* FIRInstallationsStoredAuthToken.m */; }; + 74E46733C9F9E9BEED6F791F1E91CEB0 /* FirebaseInstallations.h in Headers */ = {isa = PBXBuildFile; fileRef = CF8428E4E89357A6FCA2D964BE2D2D03 /* FirebaseInstallations.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 752C7184ED4531729174293BFC7AF6E7 /* Migration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03AA740D30B94B0A702C0129205701EE /* Migration.swift */; }; + 753A9063781468314E5535FA51D18770 /* dumpfile.h in Headers */ = {isa = PBXBuildFile; fileRef = ABE3480E6C4EFBD93505A4B57A945898 /* dumpfile.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7554645B7EE80B5C2D1B06F51A523FE5 /* FIRSecureTokenService.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B613C7C1583C7F1F9A167E85A01750A /* FIRSecureTokenService.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 75619E3CA351CC53A27C30DF83812FDA /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB96318E2CB72DE3CDFEEF1B9E8644AD /* Foundation.framework */; }; + 75A82B4A272F013FEF4657F458C9C529 /* RLMSyncConfiguration_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = C9D1BC99201338B767AF74599605CBAB /* RLMSyncConfiguration_Private.h */; }; + 75A9EC193CE5BFDD61D3D32361BC45E3 /* FIRGetProjectConfigResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = DDE80AF0D4D25BFCEFB299B8C17CEE4C /* FIRGetProjectConfigResponse.m */; }; + 7636F152E8794F10E4A36E2753703115 /* builder.cc in Sources */ = {isa = PBXBuildFile; fileRef = AF32F1890AC304CEACE3EC8163C6D595 /* builder.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 76826B9B18013A5F61252F19CF86402D /* RLMUserAPIKey.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5C604635A949AB81B5D5CAB66362D049 /* RLMUserAPIKey.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 76952BFE70A646B85266D3EAE1153876 /* FBLPromise+Validate.h in Headers */ = {isa = PBXBuildFile; fileRef = DE81F36FF24373414B6EC1A426429DDC /* FBLPromise+Validate.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 76F0D6FB31C89BA3CE5CFBAC0FF9F71D /* FIRAuthWebUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = DFF1E8F69B5E593941C2E469879CCF4A /* FIRAuthWebUtils.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 780E30F358C54CC11BC53DEDA85BCDCE /* FirebaseDatabase.h in Headers */ = {isa = PBXBuildFile; fileRef = AA83942C00F87EB03B1859665331F578 /* FirebaseDatabase.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 781671C9525101E2C5AC80A6C3DF54C6 /* Map.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73C0174B2AFCC7AE91A522B22727376A /* Map.swift */; }; + 7836A9112F980071C3771D7D999DE7C4 /* FEventEmitter.h in Headers */ = {isa = PBXBuildFile; fileRef = D887E54D3239CBDA0F3CE1921760C572 /* FEventEmitter.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 790A45A6460CBFA52D094D0D5656D86D /* RLMRealmConfiguration.mm in Sources */ = {isa = PBXBuildFile; fileRef = 851C20472E36ED891170AD12241B66BB /* RLMRealmConfiguration.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 7914264FBFAC55C55120BA3EA55F62B1 /* SafariServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B7D6683BB4B8820F7AFBD61BFB7F6B3 /* SafariServices.framework */; }; + 79956513781565B1B06A201C91893DAA /* FIRVerifyClientRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A93BF76000E48D0F95A516E92CF28E8 /* FIRVerifyClientRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 79D0EC285DCC4DD6DC940F2F040086EB /* FIRAuthRPCResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = A431F7DED716295CBC39AAAC7731B616 /* FIRAuthRPCResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 79DF5164542097A87970D857C22688FD /* SectionedResults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FAAA110C793DEE87DD244F02733834B /* SectionedResults.swift */; }; + 79E3469DC4AED4587DF861AC0BFEBBC1 /* RLMRealm_Dynamic.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 7B05F3BE2B4BA2F8C84E85EC55902EE0 /* RLMRealm_Dynamic.h */; }; + 7A19FB567C9E37705D6FED5A68EEA1F0 /* FStringUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 77FB6AA08E6C71D030AFA0335507B674 /* FStringUtilities.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 7A46E80C28977AA1EAC551BCEACBC631 /* FIRHeartbeatLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = BA97061F190CEDC6C816E99501895270 /* FIRHeartbeatLogger.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 7A53C4BAC24FFF020B3D1C730A195B27 /* FIRUser.m in Sources */ = {isa = PBXBuildFile; fileRef = 9081630104DE8D7CFD31DF7D5426FDF3 /* FIRUser.m */; }; + 7AA5D2ED28C6B278DB39BC615D38ED5B /* EmbeddedObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59727615BE1BBAD30154EEDC7630DB67 /* EmbeddedObject.swift */; }; + 7ABA215D32B0D02167C6FB4BDBDE3398 /* RLMValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 135176A848ECF939C0716D13BD47BFDB /* RLMValue.h */; }; + 7B10CA8D611210BC9AEEA70EE4059A35 /* FWebSocketConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = EA8239410F30B3473F054F4F9AC2D05F /* FWebSocketConnection.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 7B3830BF34B0CD961AFEABBA5A353A30 /* RLMSyncConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = FAEFF93C94DDA61320F23FD69CC400B2 /* RLMSyncConfiguration.h */; }; + 7B4466D42A8889C378D2DAA303B2481E /* FIRStartMFAEnrollmentResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 57E608271810C0DF3502349FA7E1F9AD /* FIRStartMFAEnrollmentResponse.m */; }; + 7B4CD08DF8A36987D9561D1599F82BC1 /* FIRUserInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = E07ED6727EC0704096E3C366CDD15BF8 /* FIRUserInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7C0DC16B7C992AF9C7B3B9221CF12113 /* FWriteTreeRef.h in Headers */ = {isa = PBXBuildFile; fileRef = 0E15FA60DA659491727FFBFD46B27EB7 /* FWriteTreeRef.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 7C41C73363E436830C727DE77EAAE9E4 /* FServerValues.m in Sources */ = {isa = PBXBuildFile; fileRef = 73941508AA91B8C0AC7E08B3C43C974A /* FServerValues.m */; }; + 7C42320EC510AF127E5CC6A35A5FF853 /* RLMUpdateResult.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = CE2E12DEE7E27510B2C96E2C68424DA6 /* RLMUpdateResult.h */; }; + 7C4D567C727D32276A67A4634F5F1F1A /* FIRGetOOBConfirmationCodeRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 3FD194CD3A55CB5AEBE27BCD94D10206 /* FIRGetOOBConfirmationCodeRequest.m */; }; + 7CC2243707E36C7D6999E039DFB5B218 /* FChange.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AF1FEB5A0A42BDF77BD2CE3A7CDE92E /* FChange.m */; }; + 7CEAC0F052AAFD79BEC81BF85E40C111 /* RLMAsyncTask.h in Headers */ = {isa = PBXBuildFile; fileRef = 260BA989E65D1B70F99F3F9464CD1115 /* RLMAsyncTask.h */; }; + 7D3E99D0B5F4097DC8CB6992458604CD /* FIRAuthDataResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A30C75392B91F7A665289F629130CC3 /* FIRAuthDataResult.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7D6B9148BE9AE09E9C01D056DB838238 /* RLMSwiftObject.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = F6150C0680A6EE061716FDD32CE733D5 /* RLMSwiftObject.h */; }; + 7D8719C93C68BAAD9FB94A7B93982AA8 /* GULSwizzler.h in Headers */ = {isa = PBXBuildFile; fileRef = C3FBA578EB9F1A354876E51D1ECFC603 /* GULSwizzler.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7DC2F4C7608BA7017846117B83D6FB2B /* FIRInstallationsAuthTokenResult.h in Headers */ = {isa = PBXBuildFile; fileRef = A2C57AE6DAC312F02E876AD29647C664 /* FIRInstallationsAuthTokenResult.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7E797D6BAC015A9DB1DBF2DCB171996A /* FIRPhoneMultiFactorAssertion+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4480D3ADCD279112EAF94738881E3C65 /* FIRPhoneMultiFactorAssertion+Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 7E869C45F0B7BBA5DC477008646C53E8 /* status.h in Headers */ = {isa = PBXBuildFile; fileRef = D6239ED73C89FD84A2B7E3742D7E015E /* status.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7F7FFEEF9343C454582B565A2D72178F /* FIRAppCheckInterop.h in Headers */ = {isa = PBXBuildFile; fileRef = 6CE6F0F74A2B43DEE1CA48C3DFBC20DA /* FIRAppCheckInterop.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 7FDB7BFDBE90E751FD01DF78A268D99C /* FBLPromise+Timeout.h in Headers */ = {isa = PBXBuildFile; fileRef = 2710FEC0F62930F9443537F90F05D60F /* FBLPromise+Timeout.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7FF8B428E990D7D592F65F6EFBE7D222 /* FRepo.m in Sources */ = {isa = PBXBuildFile; fileRef = 3C4C5034116D73230351A85353B11BBB /* FRepo.m */; }; + 802198BC371E8E13B62E61235B8BD084 /* RLMAPIKeyAuth.h in Headers */ = {isa = PBXBuildFile; fileRef = 7265EFBF2A684FDD8000FFA1529176CE /* RLMAPIKeyAuth.h */; }; + 805DBFE8246CDEC8CFC1CAA007A36CF4 /* RLMFindOptions.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = BD9D20F856B549632C5B821F2B74BCFC /* RLMFindOptions.h */; }; + 80A205DB9FAF20A0C8A635E28A6D167B /* GULHeartbeatDateStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = 9DEFF50571A73345FEF094BB2FEDDBEC /* GULHeartbeatDateStorage.m */; }; + 81172B43F338ED500082F2E012C1CE3B /* RLMMongoCollection.mm in Sources */ = {isa = PBXBuildFile; fileRef = 48D7907809830F1F47820F035D74C78D /* RLMMongoCollection.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 811E4C0162D96D681C927C81A56E8617 /* FPruneForest.h in Headers */ = {isa = PBXBuildFile; fileRef = 6193CC42799E1C407B66E8C95CC11099 /* FPruneForest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 812DE624EF12F8735C6AA3F521034C72 /* RLMLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 8863D1E8CCA754A7C72D9B4890E10EDD /* RLMLogger.h */; }; + 813F3F1E791272CFF8A1F4A11E041408 /* arena.cc in Sources */ = {isa = PBXBuildFile; fileRef = 1ADF76418061CD96E158397CF9BB037B /* arena.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 81C3A0068920FC702FE1488DC104992E /* RLMSchema.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = D6B797734979214911F26CE6964D223D /* RLMSchema.h */; }; + 82336698B7047F4B03FD0A754CE1F0CF /* iterator_wrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 5B906ACE4C08A720ED3DEEE6A58B6D51 /* iterator_wrapper.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8305B8FF0E42EC1E6CC732785D3DF4E3 /* FIRVerifyPasswordResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E4C5C96B5A1265FA9FC149C8C91EC87 /* FIRVerifyPasswordResponse.m */; }; + 83128FD5CDA88B84C9E7C5F0CA0C68F4 /* FIRComponentContainer.h in Headers */ = {isa = PBXBuildFile; fileRef = 0D53DBCD1D5DF2809E0E17C553BF1699 /* FIRComponentContainer.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 831F97CA0784C52918A070E95B0D3735 /* FIRVerifyAssertionRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 97D9C8B87E834414170ABFDA7040DB3C /* FIRVerifyAssertionRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8328BB1B08B1B7D0DCC2C75EE9F36EAB /* FValidation.m in Sources */ = {isa = PBXBuildFile; fileRef = 9E3E4E344F68B74F639CDE095DE89DEE /* FValidation.m */; }; + 838BCB7118626D6D427E87BC53CDDD26 /* FIRMutableData.h in Headers */ = {isa = PBXBuildFile; fileRef = 25D51C61BBC33B3A91740F2EBF9B9F9B /* FIRMutableData.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 839E07D95440A3F636BE770B0DAB0338 /* export.h in Headers */ = {isa = PBXBuildFile; fileRef = EC87252ACE45D15F776E6AB2967A03D1 /* export.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 83A89426A1ECA287F8B9E3CF523604DA /* FIRComponentType.h in Headers */ = {isa = PBXBuildFile; fileRef = 70408AF61F223F44EBED723B80F513A4 /* FIRComponentType.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 83CB9EEA0326A748F65100B246D0DF18 /* RLMRealmConfiguration_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 3D6DEDD58747685647800F21525DEFC8 /* RLMRealmConfiguration_Private.h */; }; + 83FDCCCA6FA59EE3D4C2974A69FB14C8 /* GULHeartbeatDateStorable.h in Headers */ = {isa = PBXBuildFile; fileRef = B58E731F045F472B2AE7CE066F291251 /* GULHeartbeatDateStorable.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 84025BBB96DDE4205F0D9C4C8E095643 /* RLMUser.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 3B2DC0C4DFDB5B772B4F9B1EB97645E7 /* RLMUser.h */; }; + 846A31A1003204664D2D37D032DF4D79 /* hash.cc in Sources */ = {isa = PBXBuildFile; fileRef = B5D5E48B2A9BCFDED384060054046493 /* hash.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 8487D1FF04DE63D5B5FBA89D3D5C6CD7 /* FIRDatabase_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 5F42CD147531578D555111E281D9DB32 /* FIRDatabase_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 848BB8E075B1AE26528D06BBDB2BB918 /* RLMObjectSchema.mm in Sources */ = {isa = PBXBuildFile; fileRef = 75FC8BF03C212294921BDF40A8ACB832 /* RLMObjectSchema.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 848F464B8D76264AAB71B6E9809DD130 /* FIRInstallationsLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A3C948976000104C7FFE044C96214F8 /* FIRInstallationsLogger.m */; }; + 84C158263730504EFA0CBA0928572142 /* FIRMultiFactor+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 23DC2294E824B6B4F959947D89FE4AC0 /* FIRMultiFactor+Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 84C69069142A72AF88B4BB8994E7679B /* RLMProperty_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DD6BDED44B8616A9BECF39BB7B8841F2 /* RLMProperty_Private.h */; }; + 84DF36844DF0F23CD6AE44EB60A4E70F /* FBLPromise+All.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D857BC602EF666E952EE6B1639A9508 /* FBLPromise+All.m */; }; + 84DF7A56FB06C5B144AA1A22C2F6AD36 /* FTupleTransaction.h in Headers */ = {isa = PBXBuildFile; fileRef = 49CEB01CF98BF899E526EC7692849F4B /* FTupleTransaction.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8507E262AF0B917CD3216BE0E1C0015D /* FBLPromise+Await.h in Headers */ = {isa = PBXBuildFile; fileRef = 59B1316F443B4F1AC8F4C103BE9970BD /* FBLPromise+Await.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 854AC47AA62CDBAE18A357DFFB84D80A /* FIRGitHubAuthCredential.m in Sources */ = {isa = PBXBuildFile; fileRef = F1DC45D9BAAB0EF43B79461F9CE85306 /* FIRGitHubAuthCredential.m */; }; + 8563FB6F9023EA1647E0D89264455498 /* FIRLibrary.h in Headers */ = {isa = PBXBuildFile; fileRef = 5218979E6A5F407F3CEDFE2821715668 /* FIRLibrary.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 85660B253CFD7166CDEDE73C9CB1E992 /* version_set.cc in Sources */ = {isa = PBXBuildFile; fileRef = 09B54AFC23373B0CA6F8F53FCAFB8B94 /* version_set.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 8577E7D27B4FAA529100D60E8FE6FCC9 /* RLMFindOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = BD9D20F856B549632C5B821F2B74BCFC /* RLMFindOptions.h */; }; + 8634EB48AFD69C6F560107A205C95B48 /* _ObjC_HeartbeatController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1D686105A5C3AABBDDDB266B062F1C /* _ObjC_HeartbeatController.swift */; }; + 864E5DB771C48AA0E2B10853506C779F /* FIRAuth.m in Sources */ = {isa = PBXBuildFile; fileRef = C21BB75CDBF87E02D19B34054FA40340 /* FIRAuth.m */; }; + 865ABE450423382E3C18852BA9B78BD8 /* FTrackedQueryManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 102E79069AA2B7FA312F4A307CAB61A3 /* FTrackedQueryManager.m */; }; + 867C59EC12A60569E2AB24E1B53247B4 /* FIRVerifyCustomTokenRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BFFCDC8875646C24A0AA7F7C16EAADF /* FIRVerifyCustomTokenRequest.m */; }; + 868EC2D6F5E462D6EC55BCAA99DA1848 /* ObjectiveCSupport+BSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4235F9BE23198AFAE32EBEA9B32A5C18 /* ObjectiveCSupport+BSON.swift */; }; + 869EF688D8253A7B5CE1B53198AED047 /* FPendingPut.h in Headers */ = {isa = PBXBuildFile; fileRef = F2A0CA9C4DCD46B305AFCB09388F8B44 /* FPendingPut.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 86B8E81017D9B71A3C2D750A26EE3943 /* two_level_iterator.h in Headers */ = {isa = PBXBuildFile; fileRef = 81EF26534B7108DEFF43DFD082550D16 /* two_level_iterator.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 86CAE83EE76AFAD891FF538BF7E3F060 /* RLMEmailPasswordAuth.h in Headers */ = {isa = PBXBuildFile; fileRef = B1EE524838C98D6E19AF4CF8DB02D099 /* RLMEmailPasswordAuth.h */; }; + 86F76D1A633F29F914531D3E5BEC31A7 /* FIRRevokeTokenResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 6109B27325309C7DB2F34C877E65CE8E /* FIRRevokeTokenResponse.m */; }; + 875F9A299293C79C833F6A1968117299 /* NSData+SRB64Additions.h in Headers */ = {isa = PBXBuildFile; fileRef = C8756C73EF22A551744BB081DCF4FDEA /* NSData+SRB64Additions.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 876BA4C97CB5877A759607A404CCDCE3 /* RLMSyncSession.h in Headers */ = {isa = PBXBuildFile; fileRef = 454A4F6087FFA109E2BAAD2E3244848F /* RLMSyncSession.h */; }; + 876EE37947934409808939990FBC28D7 /* SwiftUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC3AE1029A198F99DE8B54D835FA231 /* SwiftUI.swift */; }; + 878F4B6FDC69E25ACF2DB1E1524B86D3 /* FQuerySpec.h in Headers */ = {isa = PBXBuildFile; fileRef = 8F40B3B9417B5D4ED968E1E788B3A38E /* FQuerySpec.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 882657E5558E8ACC6634AB9D8FDED37B /* FIRComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 077DD8E014A49337645CEFA1ED433797 /* FIRComponent.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 89073846BCA6670F870B7B137814D47B /* FIRFinalizeMFASignInRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 63618DD550DBA72C753D27AB482CF04E /* FIRFinalizeMFASignInRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8944B8D4A577AF297043ABF9977D7F7B /* env_windows_test_helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 781F45EA0C7D63C20AA65A2ECB8306B9 /* env_windows_test_helper.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 89A78DD0D7EF9512C16FA8A1AD9A9117 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4972477850A41A9D9B673C96DEF4168A /* Security.framework */; }; + 89B7946331B18912484080D3D5650838 /* coding.h in Headers */ = {isa = PBXBuildFile; fileRef = A81FDBBC145D10A1514304C22193715C /* coding.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 89B7CABFA86E84E895B197B32BA81FD5 /* FIRSecureTokenRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = CFB6CCB1B4AF1019876E53953A7D37A8 /* FIRSecureTokenRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 89F5F005CF42FB4F0313CEEF776AD3A5 /* FBLPromise+Wrap.m in Sources */ = {isa = PBXBuildFile; fileRef = B6A729DD21BF2EF3E08B418A6DA898B0 /* FBLPromise+Wrap.m */; }; + 8A59933B92420A17E5E4CAD5C66E7DBB /* FChange.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C46AC75A5F40B157446B74CFDEBDCE4 /* FChange.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8A669A05308CB2ACBE76B0F867562EB7 /* GULNetworkMessageCode.h in Headers */ = {isa = PBXBuildFile; fileRef = 447DCBE2B1131BC09AED15BD4E7E6C38 /* GULNetworkMessageCode.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 8A9025AE4A9232EF04AAFFA2EEA1416F /* ComplexTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A82FDA5AE234681E92A4CF13D383368 /* ComplexTypes.swift */; }; + 8B24E60ABEC3AB8D09B4524EECAA378E /* FTupleOnDisconnect.h in Headers */ = {isa = PBXBuildFile; fileRef = B76E93B48A5797509F56D1C0B9296D4C /* FTupleOnDisconnect.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8B57B7A29A06D531CB4988E8F2492796 /* FIRComponentType.m in Sources */ = {isa = PBXBuildFile; fileRef = 35EBFFB02004349994925EC963A01894 /* FIRComponentType.m */; }; + 8B60F24BB5A70BB9917F6CFE09910EE8 /* FConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 0AA78A5FF346BDCCF63A27E56A597B97 /* FConnection.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8B88E5A9D0C57CCE176581D749719D1B /* RLMApp.h in Headers */ = {isa = PBXBuildFile; fileRef = B553FE0894FC0F9CFAA1014CF6D4F9DC /* RLMApp.h */; }; + 8BA82EA563A0E6460C1C4FFDED4A5CF2 /* FIRAuthWebView.h in Headers */ = {isa = PBXBuildFile; fileRef = 9F876082355922D63035B970213AB0CD /* FIRAuthWebView.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8BBC41C025C20DD3DF7072540D9ACF8D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB96318E2CB72DE3CDFEEF1B9E8644AD /* Foundation.framework */; }; + 8BD86B5E5C4D9040FF6F940A7DDE5B5E /* Events.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF93129186968B01B7B193F2016F8569 /* Events.swift */; }; + 8BF7C00E7B596F069966DB2F0DA0B308 /* FIRDatabaseReference.m in Sources */ = {isa = PBXBuildFile; fileRef = 42E37BEF1DB058A22126DEAE325C8DB8 /* FIRDatabaseReference.m */; }; + 8C42A7A9022BBAFCF982F250E3A7500D /* Schema.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27ECFAE94F84C45208AF513C0E025E9D /* Schema.swift */; }; + 8C5D76997AA50A03C0507ABE81B8EA90 /* FLimitedFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = F1572B79421971BB2F3F25A47639DB2E /* FLimitedFilter.m */; }; + 8D204A8354310BC2EC1FEAB676241A2D /* RLMValue.mm in Sources */ = {isa = PBXBuildFile; fileRef = FDA721544E537F06282FFFFB621FBD30 /* RLMValue.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 8DF4C16DBDD29689C7747E810E814836 /* FIRRevokeTokenRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 3244ADC01679A6C46E66783E3006820A /* FIRRevokeTokenRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8DF758428290968A7A6745B4EF821F36 /* RLMObjectBase_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 171EC043E8C48B150D6C70B8D3C8551A /* RLMObjectBase_Private.h */; }; + 8DF9BFFC1C27B66DF18D7A1A77B20A66 /* log_writer.cc in Sources */ = {isa = PBXBuildFile; fileRef = F387E83A61343EB694A8E28807337949 /* log_writer.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 8E043355D82994E1780D651AB0240B45 /* FIRPhoneAuthCredential.h in Headers */ = {isa = PBXBuildFile; fileRef = 12229C986A2EE4B61CDA11875E871A84 /* FIRPhoneAuthCredential.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 8E7060F11BBBEB03E9D34B7858081729 /* FIRGameCenterAuthProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = F26D7F28656F20339771BBA1D7E42D4A /* FIRGameCenterAuthProvider.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 8EAB6FC18913E8F2528C2B1A94A2678B /* FImmutableSortedDictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = C6C3FF34757A1E2892183B49F5842784 /* FImmutableSortedDictionary.m */; }; + 8EB027297697291D2A6CF957EFC4F9F5 /* FIRSecureTokenResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = E22845731258908F89CCAFAF4476E8E0 /* FIRSecureTokenResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8ED70935C31DEC00D90FDA2DFFAE5A1B /* FTupleRemovedQueriesEvents.h in Headers */ = {isa = PBXBuildFile; fileRef = 55FF929E3B066C69F518521636DBA3DA /* FTupleRemovedQueriesEvents.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8EFC7D5B421515836B695F56A2729CFF /* crc32c.cc in Sources */ = {isa = PBXBuildFile; fileRef = 17848892389DEF304DC3D3D5F8B965A8 /* crc32c.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 8F5C1D74BE2842634974271AE9FC7945 /* FIRAuthDataResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B4C6D7ADDA4ADABDBD392B362DC1F38 /* FIRAuthDataResult.m */; }; + 8F6DFFC393590C52DAC213565722C40D /* FIRAuthProtoStartMFAPhoneRequestInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = A5D259662259C7BE1415453C22210DCA /* FIRAuthProtoStartMFAPhoneRequestInfo.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8F7E464A2CB88BF555C24CEA466463E1 /* testutil.h in Headers */ = {isa = PBXBuildFile; fileRef = 7CA157D50F38EC9E1EDB65A499D536F7 /* testutil.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8FA126ECD66FB79D079893AA823C9575 /* HeartbeatController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9D20F783BE6512E0DE13B7C0C5670BE /* HeartbeatController.swift */; }; + 8FD79265CC7CDFB8FCD8051A8D936CC9 /* RLMMongoCollection_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = D00927971D6B3C1621037BDC2C93FB12 /* RLMMongoCollection_Private.h */; }; + 905BFD0510C4C0ED5C97B3864A25E5B4 /* db_iter.cc in Sources */ = {isa = PBXBuildFile; fileRef = F557FDA3AF2F031583CCC00944047D8A /* db_iter.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 90AF3C42D8F7E3B51C7CE7A5DC2C3407 /* FIRApp.h in Headers */ = {isa = PBXBuildFile; fileRef = BD7537EC51FC4F1A9702E002BC025FDE /* FIRApp.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 90B1D14277BAD1823703CF9E200B39A2 /* FIRAuthExceptionUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = C37804A80D841783D9BF3A30B9F8016A /* FIRAuthExceptionUtils.m */; }; + 90B308AD77D91B69ADDB109CB0D75829 /* NSData+FIRBase64.m in Sources */ = {isa = PBXBuildFile; fileRef = B3FD9E5801F2AD2BD362344F93669102 /* NSData+FIRBase64.m */; }; + 90DF05CC96171E8108A83697467E39C4 /* env.cc in Sources */ = {isa = PBXBuildFile; fileRef = B6AF9354970089CC782E648426B0F62D /* env.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 90F5214A87703025030C79659166F248 /* FIRLoggerLevel.h in Headers */ = {isa = PBXBuildFile; fileRef = EB78CE135800E8CDACBD0AE334B55148 /* FIRLoggerLevel.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 910145FF03824ABFF17CA653C7F0BD5E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB96318E2CB72DE3CDFEEF1B9E8644AD /* Foundation.framework */; }; + 91161FD58138AB0E2C694035C96B5779 /* FIRMultiFactorAssertion.h in Headers */ = {isa = PBXBuildFile; fileRef = C586384ED84D2D56FFBE9589841A7C36 /* FIRMultiFactorAssertion.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 917BC551095B7D467693400C1981BC58 /* FViewProcessor.m in Sources */ = {isa = PBXBuildFile; fileRef = 5ABBB25E158253F6289758734B748297 /* FViewProcessor.m */; }; + 918653E16077446E3228300361F811C7 /* FBLPromise+Recover.m in Sources */ = {isa = PBXBuildFile; fileRef = FCAD24AC225AC807A081C35F3B371DA4 /* FBLPromise+Recover.m */; }; + 9226A945F3D80332E2C4C83115B9F6E3 /* Realm.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 0306EEC425C1FFBD36CA65D3932A6ADC /* Realm.h */; }; + 923D016B51AA47A7F2887DB315161BF9 /* RLMResults_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 708181884E851CC294593093D3921B23 /* RLMResults_Private.h */; }; + 924BE5528A081DEF9AE9D2911A7F3A7C /* FBLPromise+Catch.h in Headers */ = {isa = PBXBuildFile; fileRef = BB799EAE95DCF5C0E5C3CA09470ABA2C /* FBLPromise+Catch.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 928622B3D584F08FB48CCA5357562D6C /* Realm.h in Headers */ = {isa = PBXBuildFile; fileRef = 0306EEC425C1FFBD36CA65D3932A6ADC /* Realm.h */; }; + 9311C57B3CD9E335505406C425678201 /* FIRInstallationsAuthTokenResultInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 95EA0878DF345763F81B3830AECFF356 /* FIRInstallationsAuthTokenResultInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 932580A3057AD248F08F7B62D7F85D47 /* FIRResetPasswordRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A5B34AC3E337EC7014EA2086077DAB9 /* FIRResetPasswordRequest.m */; }; + 93605CBB442A1846671A0B857D5C9A81 /* FIRTwitterAuthCredential.h in Headers */ = {isa = PBXBuildFile; fileRef = 4785776E6B04F0C704ED408714796CCC /* FIRTwitterAuthCredential.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 93BCB3BA76BFD984CA350338DDD1B5AD /* no_destructor.h in Headers */ = {isa = PBXBuildFile; fileRef = 6A1EB85929DB5ABFC8B1B0F7CA908A93 /* no_destructor.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 94019D9BAB6F218A17B853C14ABFA29C /* RLMResults.mm in Sources */ = {isa = PBXBuildFile; fileRef = BAEF988E635365578AACECB2A52620D3 /* RLMResults.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 940B828B191381F6A1A9D40902364630 /* RLMProviderClient.h in Headers */ = {isa = PBXBuildFile; fileRef = A9D715562896C77226A34E182B52AE9E /* RLMProviderClient.h */; }; + 945A33542D7BDB6356AA2442B6601CA6 /* hash.h in Headers */ = {isa = PBXBuildFile; fileRef = B0C804B4546C72B739AD4D126464376F /* hash.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 947AE0004C53D32999ECEC79204D2FE1 /* RLMRealm+Sync.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C0CD8603C88F495D0C59CF44AB151EA /* RLMRealm+Sync.h */; }; + 949AB19E291233083C42BE9ADBFC20D5 /* FIRGameCenterAuthProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AD60D804ED86004AB6ADDF386296D8C /* FIRGameCenterAuthProvider.m */; }; + 949E867236FB69DBCA105E66DFD437A1 /* FWebSocketConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DA1270DF0D5F31B5860D0879C25BFCF /* FWebSocketConnection.m */; }; + 94AC4F19769153CFA401C98A84B99A8A /* GULReachabilityMessageCode.h in Headers */ = {isa = PBXBuildFile; fileRef = 89A1FB094E0C49A6D4987A61F9960B34 /* GULReachabilityMessageCode.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 94BEFCDCEC7A42473FC1D494A29E1CF8 /* FirebaseAuth.h in Headers */ = {isa = PBXBuildFile; fileRef = B36227C53E719CE8182B4FB7ACEEC2DA /* FirebaseAuth.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 94CA0E83F2B89D06241D54A94058B6D5 /* FSRWebSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 09F100EB4B62EBE83645C2D60ED1E078 /* FSRWebSocket.m */; }; + 94E96158433F7455C36D5D1ED2CDE61A /* FIRDeleteAccountResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 35D13F140D3BA97AA0F59CD6D0185A2F /* FIRDeleteAccountResponse.m */; }; + 9609235EF89429B145D15C35CD97B78B /* FIRCurrentDateProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = B13B7BABC1263F4E9BC3D14D6AC1096F /* FIRCurrentDateProvider.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 962C5416547AB875A95DC457450E16C4 /* FIRAuthProtoFinalizeMFAPhoneResponseInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 20527044548AD5FFF595A5E3278C7287 /* FIRAuthProtoFinalizeMFAPhoneResponseInfo.m */; }; + 966C504495609E40E3EAF21EE23244FB /* FImmutableSortedSet.m in Sources */ = {isa = PBXBuildFile; fileRef = AAD3672222B78EF845809BCE176BC39C /* FImmutableSortedSet.m */; }; + 9671A6738BEE91011FDC3399A96B431A /* dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D1D1CE6B410E1BCE80346A09E546722 /* dummy.m */; }; + 9680102310967F59CA76AF4B0301A138 /* FView.m in Sources */ = {isa = PBXBuildFile; fileRef = 10AC127C6D153D12363D963E92010133 /* FView.m */; }; + 969E8E99A97BF0FCEFF6BC5BAED14B58 /* FIRWithdrawMFAResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 1291C14B3AB631F2898B2F8286A070FE /* FIRWithdrawMFAResponse.m */; }; + 96BC606C6F0FE863C7994163F10D96EB /* FIRDatabase.m in Sources */ = {isa = PBXBuildFile; fileRef = B6636FC9D55BA423AE5D31143F16C3C6 /* FIRDatabase.m */; }; + 96D8CF73824E8DFB9D0738674EBE8885 /* FIRCreateAuthURIRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = F0C900FADDD4BE441B1FED142B0B0690 /* FIRCreateAuthURIRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9774D25AD742E9273057E0F008F3830C /* status.cc in Sources */ = {isa = PBXBuildFile; fileRef = FE2C17AB2A7CF72D25F49312B857984E /* status.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 978D74F5AFBE1950843BE1748E2E6BF6 /* repair.cc in Sources */ = {isa = PBXBuildFile; fileRef = ADD8E035121D65CDD6CF8FEC0FE3FBFD /* repair.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 97966CCFF45DDA06DCB4F5C9F7C90460 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB96318E2CB72DE3CDFEEF1B9E8644AD /* Foundation.framework */; }; + 97BE95E381B9FDACEE58261D36045A21 /* RLMObjectBase_Dynamic.h in Headers */ = {isa = PBXBuildFile; fileRef = 3CF270CB5CBFFE011E21EF25448B9646 /* RLMObjectBase_Dynamic.h */; }; + 9881252194046087CFD77E71E63721A1 /* FIRActionCodeSettings.m in Sources */ = {isa = PBXBuildFile; fileRef = 81B38C32D7A56C22344E671F7C0B1AF1 /* FIRActionCodeSettings.m */; }; + 98FB19FDCBF27E03A1228A3F51ED84E9 /* FIRTwitterAuthProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B828DF519503B35B1B1C7893D5F6C1E /* FIRTwitterAuthProvider.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 992233B1F4B40F8B77EA7CC9D7C8E0F1 /* pb_encode.h in Headers */ = {isa = PBXBuildFile; fileRef = FA03DCA390E3B26A7DCD911883F15289 /* pb_encode.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 992270036034484690C0D43686A3352F /* FIROptions.m in Sources */ = {isa = PBXBuildFile; fileRef = B664529372060D95B49A4C4F210AFB3B /* FIROptions.m */; }; + 992B6529BBC99C3FDFA09AEEA0621D39 /* FEventRaiser.m in Sources */ = {isa = PBXBuildFile; fileRef = 507728C48E9B69D1D56C13D2301CDB10 /* FEventRaiser.m */; }; + 99720C62F8883DED73FDE4B2E8C8418C /* FIRInstallations.h in Headers */ = {isa = PBXBuildFile; fileRef = BA4BB1B3E24F76A1197B5722E1A54B84 /* FIRInstallations.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 99B62D32054FE258375BCDD48305CF93 /* FIRDataSnapshot.m in Sources */ = {isa = PBXBuildFile; fileRef = F03959F6EC6AFA8E040BC189C4A27323 /* FIRDataSnapshot.m */; }; + 99BB16964483ACCEFFE2E25131479EAD /* FCachePolicy.h in Headers */ = {isa = PBXBuildFile; fileRef = 3463F8E9265223FD78A8E353D9DBC93A /* FCachePolicy.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9A032416A3664E846492883825B07F3E /* FIRGoogleAuthCredential.m in Sources */ = {isa = PBXBuildFile; fileRef = 8248C935EA50EC5DC7B87FF59C18BCC0 /* FIRGoogleAuthCredential.m */; }; + 9A67A5511310C707DDD90E5FEB47EA41 /* FIRPhoneMultiFactorGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B54381D354957163C76271AA6E11ADA /* FIRPhoneMultiFactorGenerator.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9AC52B23473AE7928D42958AA1841110 /* FIRDependency.h in Headers */ = {isa = PBXBuildFile; fileRef = 5824BEEDD3575E41D0E94856799BCFA8 /* FIRDependency.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9AD0B4DB3C43A0B34DED85DED855CE09 /* FTupleOnDisconnect.m in Sources */ = {isa = PBXBuildFile; fileRef = D65CCF92BADFD9664EB7E03196C8195C /* FTupleOnDisconnect.m */; }; + 9B012A8F604FAA865C6F47354D4E8577 /* FIRDatabaseComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = D8D3F8C07FC1809D6A888E03A8585E72 /* FIRDatabaseComponent.m */; }; + 9B91307547BEDA714941231459B7A8C0 /* FSyncPoint.m in Sources */ = {isa = PBXBuildFile; fileRef = 007B099760AAE9DBA8EC8150D40C88BB /* FSyncPoint.m */; }; + 9B921FB7B1E6CE0D70535CD2ADBFC4C4 /* GULKeychainStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = C8357ED2FAC9005A1B855EDE918C7AF5 /* GULKeychainStorage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9BE0C432C601BAEF9616CDF193E4D493 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1799EDD01F3BDE8A78F8501A99E86879 /* UIKit.framework */; }; + 9CAA1F8F766383E30D4E2EE96E394A9C /* RLMCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = C01A8C68201D99996D349D3CE0CAC1EA /* RLMCollection.h */; }; + 9CAE0CEC8F47B76BE29471EDED2DDC89 /* FIRWithdrawMFARequest.m in Sources */ = {isa = PBXBuildFile; fileRef = ED26D901D7A953FFDFA298223B2EA02C /* FIRWithdrawMFARequest.m */; }; + 9CB06FE748D924EE8F8216D24A4DC2E5 /* FIRAuthSettings.m in Sources */ = {isa = PBXBuildFile; fileRef = 4666F2D0D35E201F414EBF12BB1B75AC /* FIRAuthSettings.m */; }; + 9D14157D94D8AD8E7E4ED65C882441B6 /* FIRAuthProtoMFAEnrollment.h in Headers */ = {isa = PBXBuildFile; fileRef = 3F37469C8502B8AA3CAD193EF4D56E93 /* FIRAuthProtoMFAEnrollment.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9D52E14C4FE9CA72CC28383D5BD51546 /* FSyncTree.m in Sources */ = {isa = PBXBuildFile; fileRef = EADAA6771DED910D18EEE52483AEA223 /* FSyncTree.m */; }; + 9D65E3E660A5810772FD494FF83D786B /* GULNetworkInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = F433C4D3C5A3828AC08AECBC9337940A /* GULNetworkInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9D86DDE6D19CD5509A5ECCF254ED3336 /* FSyncTree.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C0AF19F9C4062998F561DD8F98DECE3 /* FSyncTree.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9D927CE9C76B13599666AE9A345525F3 /* FTreeSortedDictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = D3BC4F854711166760C34ADA038051BA /* FTreeSortedDictionary.m */; }; + 9DA9A1427D2FBE2618C79F8F8ADEC9D9 /* FValueEventRegistration.h in Headers */ = {isa = PBXBuildFile; fileRef = 125863111A1DBB3C7CB2752151C25750 /* FValueEventRegistration.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9E55EC0DF4903FAF9A23AFFB105AAE54 /* FIndexedFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = D5100D25D948326FCCAF410A4BE86046 /* FIndexedFilter.m */; }; + 9E79B559377D95495396E828598C66AB /* FIndex.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C61B12ACA3E421895B038C2C363D156 /* FIndex.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9EB707DA936F64F9FE7139226B5EA01A /* GULSecureCoding.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A45F4A50350CD25215F79F11B696584 /* GULSecureCoding.m */; }; + 9EE4B196ADC91A640E2948C889DE2C2D /* RLMQueryUtil.mm in Sources */ = {isa = PBXBuildFile; fileRef = E75A7FC8166DA36E089D2AD89ACDB3F5 /* RLMQueryUtil.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + 9F46CED3C51DA609AE7C985E0017C920 /* FBLPromise+Any.h in Headers */ = {isa = PBXBuildFile; fileRef = 473C88C5429C1D64A09BB61AB8CF96B8 /* FBLPromise+Any.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9F4CB6E18F78821866985298E819B20A /* FIRAdditionalUserInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = AC8ABFC882AE8D079F88275E0F5AA22D /* FIRAdditionalUserInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9F4D180B838B06FAB57B4062BDACAC16 /* db.h in Headers */ = {isa = PBXBuildFile; fileRef = 581EF75B385FA2FCCBB0497AC0AC8A58 /* db.h */; settings = {ATTRIBUTES = (Public, ); }; }; + A093549452C05981016DDA86E341871A /* RLMRealm_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 8A1CF7A2AB94E939661BF09684D2DF1B /* RLMRealm_Private.h */; }; + A09BE80C5FC981BACED4EA201F7AEACE /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 39B4FEB4B3B91D6CDE38132BAB3BEE14 /* CFNetwork.framework */; }; + A0BA99A9C218794AE29315E27D045246 /* FCompleteChildSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 7FC074C669327E8C8F84CB1E0EF41773 /* FCompleteChildSource.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A0C346DD84D892132E629AE4EE267F14 /* FBLPromise+Wrap.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C8D0EA446BF7DA682A806ED24FE6AFB /* FBLPromise+Wrap.h */; settings = {ATTRIBUTES = (Public, ); }; }; + A10C98239F7AF3C8A45A1F2A33B6038E /* FPersistenceManager.h in Headers */ = {isa = PBXBuildFile; fileRef = A9CB8D94CC94FDEDC76F63707334A585 /* FPersistenceManager.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A11B2EE8A74B25AEB3D6A1807235EB50 /* FBLPromise+Reduce.h in Headers */ = {isa = PBXBuildFile; fileRef = AD0FDF20ADB9C0908115F409C91E242F /* FBLPromise+Reduce.h */; settings = {ATTRIBUTES = (Public, ); }; }; + A173A3BC99B9C858CECE483B60C57951 /* FIRAdditionalUserInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 56DA4B923BA10A0AFF4CBCE4257C2480 /* FIRAdditionalUserInfo.m */; }; + A17CA87BA5842902B638DEE5BFEB2EE2 /* FIRAuthAPNSToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 93E7C59C6BE703966530FFBC723395EF /* FIRAuthAPNSToken.m */; }; + A1BC422359DF11ED2C7B3FE4C5214942 /* RLMObjectStore.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7F1B362D7A8C6E8B43B41DCA9EC82A5B /* RLMObjectStore.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + A1D05B2080062B9F5FE73C57D34B1BF1 /* FIRInstallationsItem+RegisterInstallationAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = 89F626DEF1C52C94294D9723D0C99539 /* FIRInstallationsItem+RegisterInstallationAPI.m */; }; + A20BA28DEF36B1CB3E6E8F9205BD1678 /* FIRSendVerificationCodeResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = D4B2D1F9402DEE3A5695B326EE5FFD8F /* FIRSendVerificationCodeResponse.m */; }; + A2235A3B04B2347E27E03A400BDA8F67 /* FIRComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 6DFB4AE7F11314CE5775A0522693D21C /* FIRComponent.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A2510B92AFE46DCBC196E0E40550856B /* RLMUtil.mm in Sources */ = {isa = PBXBuildFile; fileRef = B0CBE3B4CF9091DD07FE7658445755DA /* RLMUtil.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + A25122EB1C1C87A2AE4F62F9ECE66DCB /* write_batch.cc in Sources */ = {isa = PBXBuildFile; fileRef = 443669EB0193E1FDA50EE1B7C683DA16 /* write_batch.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + A27EA8BE9E88868BB6EDC2BAD5E80820 /* FIRAuthStoredUserManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 733CEDC657436DD895F6CF302461A85D /* FIRAuthStoredUserManager.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A2D241953E4F2DA88EEC3CED7DEDF8B1 /* Realm.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE522E5C99C9F08611559181764D55B9 /* Realm.swift */; }; + A3337A425F2D7098E8E0FF8C7D54A556 /* FTupleTSN.m in Sources */ = {isa = PBXBuildFile; fileRef = CFB945C62972C0C90CE78FE6D174EAD1 /* FTupleTSN.m */; }; + A3578F1E8CBAD2C225AC7D11C9DDA8D9 /* FIRSetAccountInfoRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = F81A1054298CE5C004C4FE464C5DCE2C /* FIRSetAccountInfoRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A35ECF8CDD51CD1085D528816AB97198 /* FIRGitHubAuthProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = 3F4580980FFA6C2CB244BCD3B8BFDE2E /* FIRGitHubAuthProvider.h */; settings = {ATTRIBUTES = (Public, ); }; }; + A3F2ACD414E198365E6ED9AD99D097EC /* FIRSetAccountInfoResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 3239ADF167FDB5AF1EC2F83F1F8DADD3 /* FIRSetAccountInfoResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A3F8479F3A970E032D0A3E07C81EF3A7 /* FIRMutableData_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D2BCDEBF223F71AFF9564E683A322A8 /* FIRMutableData_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A4595E5A026C972FD6829E2A7D698CFB /* FIRInstallationsIIDStore.h in Headers */ = {isa = PBXBuildFile; fileRef = D53299DB70CFB23861357EA947C70688 /* FIRInstallationsIIDStore.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A47149847911B053BB4CE39AE37276E6 /* GULUserDefaults.h in Headers */ = {isa = PBXBuildFile; fileRef = B2750DC4306D28633B3876C5C545F55F /* GULUserDefaults.h */; settings = {ATTRIBUTES = (Public, ); }; }; + A4BB95BC9251977B0A08075C77AA9DC3 /* bloom.cc in Sources */ = {isa = PBXBuildFile; fileRef = 0780A95F429DCE64484BDD78CBA3FE12 /* bloom.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + A527417E86B49E6FE60D3EC555DEE9F2 /* FIRAuthRequestConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 07FFA32CF64DC17468EA57AF8C75CADF /* FIRAuthRequestConfiguration.m */; }; + A5EEE1954FBC0A5798C8992A05C4F717 /* FIRAnalyticsConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = FA4FC112C43350FA23C041B4F4331E68 /* FIRAnalyticsConfiguration.m */; }; + A664E8B743AE58614C1043A9D353359E /* RLMSwiftProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = 62DA765EFA6176292C8BB0A39A6430D4 /* RLMSwiftProperty.h */; }; + A6A5E3C4226D1666D8D40D598EBCFA47 /* RLMUpdateResult.h in Headers */ = {isa = PBXBuildFile; fileRef = CE2E12DEE7E27510B2C96E2C68424DA6 /* RLMUpdateResult.h */; }; + A6AC4CEAEC8C92DC44FD5692E5CFF9F0 /* FChildrenNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 675C0C404FF5EA964785CFC002A6E20D /* FChildrenNode.m */; }; + A6F389E893B67866C913A7CC967BE7EA /* FKeepSyncedEventRegistration.h in Headers */ = {isa = PBXBuildFile; fileRef = 35F20F6EE823992F00BCEBD34542EF0A /* FKeepSyncedEventRegistration.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A717A83405C484FDE5A4D037892343FC /* FKeyIndex.m in Sources */ = {isa = PBXBuildFile; fileRef = D984F82324A6B762CC65B0B8A3D4B26B /* FKeyIndex.m */; }; + A75CCB280339D151D59272139672AEB3 /* RLMBSON.h in Headers */ = {isa = PBXBuildFile; fileRef = FCFFDCA51CE25755A9B7C297EF1226FF /* RLMBSON.h */; }; + A78A12C84F898279D2CF0DEDA0987804 /* RLMUserAPIKey.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 34DE85D047CC7AE8971A383A422D922B /* RLMUserAPIKey.h */; }; + A79571C65BAB139997C9CB1C04E8B395 /* RLMNetworkTransport.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = A57BCC415D3BC94E35EB525E03037615 /* RLMNetworkTransport.h */; }; + A7CE962EF9B775EBC3DF94CB1A10D308 /* RLMProperty_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = DD6BDED44B8616A9BECF39BB7B8841F2 /* RLMProperty_Private.h */; }; + A7D53C0DD6A4F8238BD524B8BD1D7A13 /* FTransformedEnumerator.h in Headers */ = {isa = PBXBuildFile; fileRef = AC3496D1774819DE9FF283E783E8FD57 /* FTransformedEnumerator.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A811DDDB0D93AEFA12BAF266B214D115 /* FClock.m in Sources */ = {isa = PBXBuildFile; fileRef = DC3C5F7564BBF625FA085989C71B0540 /* FClock.m */; }; + A8B023366D664D7D355BF2F5B7970DEF /* FChildEventRegistration.m in Sources */ = {isa = PBXBuildFile; fileRef = A16A5315E18D376E152E91F55B367ED7 /* FChildEventRegistration.m */; }; + A921770EBECAFB9A3BF11619955F6491 /* block_builder.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DB1A365BD7D10214DD2C7AE73A31366 /* block_builder.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A93E2122B31D4B57FEFCA90699A9C6E6 /* RLMObject_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 83B84A215D7F46B8C23EE84B1A5F9CCB /* RLMObject_Private.h */; }; + A9805E610FDB0C5C030851F00172CE23 /* FIRHeartbeatLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E47E99A63C56A34F47752275944340C /* FIRHeartbeatLogger.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A9C59999EAE6BCC341858A32BA288A08 /* RLMAsyncTask_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 611073B847128EBBC450AA00B49A5852 /* RLMAsyncTask_Private.h */; }; + AA5F2686F0E973FBAC628822736DCF5A /* RLMSchema.mm in Sources */ = {isa = PBXBuildFile; fileRef = 43D14090369EEC01BE508BDB88EB84F8 /* RLMSchema.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + AAA3B8C557486D7CAFFC82623BA36A12 /* RLMSet_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 87B4B54B444CBCE7121C9CC71213A704 /* RLMSet_Private.h */; }; + AABB04026DDE6C037FF7496D6B47EBFB /* skiplist.h in Headers */ = {isa = PBXBuildFile; fileRef = D69481ED1553EEC1AC684D6C26C0022D /* skiplist.h */; settings = {ATTRIBUTES = (Project, ); }; }; + AAC54DF236959D637BAAC9D487AB53EB /* FBLPromise+Then.m in Sources */ = {isa = PBXBuildFile; fileRef = CAE042BCC7FF44CC71EC43BF6F7B7CBA /* FBLPromise+Then.m */; }; + AAD9FDCF7389C0EFE67CCD5B9BAF3115 /* Optional.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AA822C47FB8D76517D7B38666F38C1 /* Optional.swift */; }; + AB3D370C50E410078DE6953A09736B13 /* RLMApp.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = B553FE0894FC0F9CFAA1014CF6D4F9DC /* RLMApp.h */; }; + AB3E9EAB71F0B212E143CE8C636F77AA /* RLMLogger_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 57AA2F599A51760A591158FC670C1F2B /* RLMLogger_Private.h */; }; + AB4928353201F4B67A73A0880CA939BC /* FIRAuthAppCredential.m in Sources */ = {isa = PBXBuildFile; fileRef = 80091CE146D230191C846447F22D2BFC /* FIRAuthAppCredential.m */; }; + AB90B36902E786169B8AEF90BABDBB7A /* FBLPromiseError.m in Sources */ = {isa = PBXBuildFile; fileRef = 7055A9FCC22D8FE5674415195AAB67AB /* FBLPromiseError.m */; }; + ABAC3114CDDD664D12B2B33A93063D5C /* FAckUserWrite.h in Headers */ = {isa = PBXBuildFile; fileRef = C4E718B55509A9AA2889EA254EA608CA /* FAckUserWrite.h */; settings = {ATTRIBUTES = (Project, ); }; }; + ABD61BF538B0440B014502E121AD906D /* MongoClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = D403AB05C8E5B8D4D7EC9A9E2C7A971E /* MongoClient.swift */; }; + ABDBC17D9DAC3AB0815997E4EBF8DF34 /* FTupleObjects.m in Sources */ = {isa = PBXBuildFile; fileRef = 692CA72025C2AD94D8AD564A919418FB /* FTupleObjects.m */; }; + AC5C0A72839F72F5CBB97472EF544076 /* FIRAuthBackend+MultiFactor.m in Sources */ = {isa = PBXBuildFile; fileRef = C341B5E37833446B630AF47E00CECF59 /* FIRAuthBackend+MultiFactor.m */; }; + AC856C6E5BEF966B11B0E0135895C487 /* RLMCollection.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = C01A8C68201D99996D349D3CE0CAC1EA /* RLMCollection.h */; }; + AD7BCAB6BE202FF2D009E7E088E3DEC0 /* block.h in Headers */ = {isa = PBXBuildFile; fileRef = 600763BBCBED3F50EE109FA6AB08E882 /* block.h */; settings = {ATTRIBUTES = (Project, ); }; }; + AD82C7808251471F35BA3A73BA03BEDB /* GULSceneDelegateSwizzler_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = C8FAC6B7AC02F097592BE88CD4EABC83 /* GULSceneDelegateSwizzler_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + AD8FA6C3AF584A8AE1983BA729DF3A07 /* FTupleSetIdPath.h in Headers */ = {isa = PBXBuildFile; fileRef = 5FCFC34AFBC4E5C47B62D36842E9D028 /* FTupleSetIdPath.h */; settings = {ATTRIBUTES = (Project, ); }; }; + ADCA32AC2369C90AD2FA2616F7A6DD41 /* RLMSwiftValueStorage.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = DF49FADD2F521BE21950120B832A1914 /* RLMSwiftValueStorage.h */; }; + ADFCE255F5A94F073CA5F5DBF194CB01 /* FIRAdditionalUserInfo_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A9F68773EE5E52B4D5659917D69DBAF /* FIRAdditionalUserInfo_Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + AE2819DF95D7AFDAD05C2ABBC3C0BC06 /* FIROAuthProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = AFF21A3F40FF482B7644277954FE53A4 /* FIROAuthProvider.h */; settings = {ATTRIBUTES = (Public, ); }; }; + AE88A770938D3331DA56158D4149E829 /* FView.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E0B7881254469695A443E9B4ECCF474 /* FView.h */; settings = {ATTRIBUTES = (Project, ); }; }; + AEA62B264E04B2E2B4C3B279D838CD7D /* GTMSessionFetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = B563271FE374CC1858749750DE0541AB /* GTMSessionFetcher.m */; }; + AEBCA3B9E36968494D8EF17CBE7A7946 /* FBLPromisePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 22876DDCA074830528A1B2A90E9096F6 /* FBLPromisePrivate.h */; settings = {ATTRIBUTES = (Private, ); }; }; + AF19A4C6CAE1776A211A41FA60B74540 /* RLMRealm.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0DD02532F284925CB1FC4D2E2108EEA7 /* RLMRealm.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + AF3B946C1C71A75CB204C50E48E36FF7 /* RLMArray_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = A77530BCB920D9861E25B63BE3E4443E /* RLMArray_Private.h */; }; + AF4E7917DEE0C2E522FF4A32FFB50CB7 /* FIndexedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = CA22FD4400AA8E8CB40D6E656136F272 /* FIndexedNode.m */; }; + AFFEB160C9DAC32478B61FCCED14535B /* PersistedProperty.swift in Sources */ = {isa = PBXBuildFile; fileRef = D71BEF9DD1974C9E1B6490E81C32E5B6 /* PersistedProperty.swift */; }; + B0BD0D34D2B49C6F6AF6709C5CD3D2A4 /* filter_block.h in Headers */ = {isa = PBXBuildFile; fileRef = 287C36FAAEDA194E995524403501AB31 /* filter_block.h */; settings = {ATTRIBUTES = (Project, ); }; }; + B0DB6A1D468D898FFF34AB95A7323CC1 /* slice.h in Headers */ = {isa = PBXBuildFile; fileRef = CEBEE94472042794604075BCA211146D /* slice.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B0F831410CB9D0FA3B471C5100EA35F1 /* FIRInstallationsItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 24E342468348506C8B682D5206A317CE /* FIRInstallationsItem.h */; settings = {ATTRIBUTES = (Project, ); }; }; + B0FFC5806A64B5A60CB55230332EC96B /* RLMArray.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = AF4C27BB7CD817442F90B3068C676B6B /* RLMArray.h */; }; + B1AD71A7648B34EB72F5D99152A8E299 /* RLMSyncSubscription_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 272FB90054BCC4BB95316C5013FC9834 /* RLMSyncSubscription_Private.h */; }; + B1D5C5A53BE576222D41A8601FD6333B /* GTMSessionFetcherLogging.m in Sources */ = {isa = PBXBuildFile; fileRef = 2FBD192144F1B9FEFEB202A6CA259781 /* GTMSessionFetcherLogging.m */; }; + B1F7ECE15B477A3F7F9B6417469B5FF9 /* GTMSessionUploadFetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 6046DACC7689D111783C349D3D6D4D73 /* GTMSessionUploadFetcher.m */; }; + B1FF1AF7078C2A4114FAD6976C4B1E57 /* write_batch_internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2F425451E6AF67F3E0D5654E90ED43 /* write_batch_internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + B2388836E5E17F87578AB046A8F9C449 /* NSError+RLMSync.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 40538536D8C20ED7DA137A5713BB459A /* NSError+RLMSync.h */; }; + B26EE4F4E233857BC1A9B1CDFE66657D /* RingBuffer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C892732CFC7F04EDE36414A35202F2F /* RingBuffer.swift */; }; + B284929F06F08C99A8A41B3C444E005F /* FirebaseDatabase-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 73874D1391ABB5D9F840E66D19FC0FDF /* FirebaseDatabase-dummy.m */; }; + B2A567972E2A3A00493F89D63B361337 /* FIRAuthURLPresenter.m in Sources */ = {isa = PBXBuildFile; fileRef = 5BED05889CD6C4477F7E451D6485915E /* FIRAuthURLPresenter.m */; }; + B2B29029DD1D746CE09B3E27066129F9 /* FPriorityIndex.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ECC1E0C372817AC19942A566AB123C1 /* FPriorityIndex.h */; settings = {ATTRIBUTES = (Project, ); }; }; + B2EEC59FABCF5E5C59652196C9A16A39 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEAE96632CC2337ED6A14302B3022EC8 /* SystemConfiguration.framework */; }; + B30F3599D78D2A3A0344C528972F6A5B /* version_edit.cc in Sources */ = {isa = PBXBuildFile; fileRef = 5F51D8C4AC0945BEB82DE5747E45BC96 /* version_edit.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + B3769095DE70D4998B1F2E1A54B058E7 /* FSnapshotUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 70F4CDB8C474983A83FFDA390D5A657A /* FSnapshotUtilities.m */; }; + B38189926FD2265A00099C5F5FDC3884 /* FIRInstallationsErrors.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B2844F303E92ABE8A160DD9F6582F0C /* FIRInstallationsErrors.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B399D68CDF262A8E78D6F4085C479B9A /* FNodeFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = F18ED32B3B8F221BFA6014B394B24828 /* FNodeFilter.h */; settings = {ATTRIBUTES = (Project, ); }; }; + B3D14EE8BE8A3F664067BCCEC7E5C843 /* RLMFindOneAndModifyOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 4831343EA0DCD89549053AB1F3C335F9 /* RLMFindOneAndModifyOptions.h */; }; + B46E52EDBD14DEA140A5EE7F128F7D70 /* RealmProperty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76E8A9B00D0B852C4CBF03F3018E7BA6 /* RealmProperty.swift */; }; + B499873D96BE7E087783337479CECA89 /* FBLPromise+Always.m in Sources */ = {isa = PBXBuildFile; fileRef = C0D3E9D94E45F0CA51973A4FC3F7A77D /* FBLPromise+Always.m */; }; + B4A11489809A67AB70513E3C6064FD0F /* FIRAuthWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6ABE347DB5D72B0A29CB81D058503E94 /* FIRAuthWebViewController.m */; }; + B4AE86E05D286DEE1843DD5344090641 /* RLMError.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = C6B2640364AB64A02A4091061D24152C /* RLMError.h */; }; + B4D51CF0EB25677858925A7E23D6344E /* FIRInstallationsErrorUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = EBBB58C277BED60ECBB0936F62871EA6 /* FIRInstallationsErrorUtil.m */; }; + B4EE276AF7CB12ED9DB48318D8914C2B /* RealmCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C375A35EEAB2E08FC388D263A6209408 /* RealmCollection.swift */; }; + B5115253D4214741AB8DDBC2BF58E222 /* RLMEmbeddedObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 6D00B53942427419D9F1A394FBEE64F3 /* RLMEmbeddedObject.h */; }; + B51D7F506DFEA060C1CB741903F75CF8 /* FConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = A036C3B6F27E62C0413AA1CB052F1E9C /* FConstants.m */; }; + B52D9C6E0E42DEB9798559D08220D332 /* RLMRealm.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = F0BFC6AD06F7FAA34D3238F20D1BDDD3 /* RLMRealm.h */; }; + B59E22971F8D4CE5681BF67535A363F7 /* Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 836372D75ABF46C08BAD5758AD2B8EBF /* Combine.swift */; }; + B625F27E68B1BC1194572B6E3FD04F8B /* mutexlock.h in Headers */ = {isa = PBXBuildFile; fileRef = ADB9AD101FB170D305160E82F1CC2AA3 /* mutexlock.h */; settings = {ATTRIBUTES = (Project, ); }; }; + B6554DE2E058C862C452D40EC7C7D270 /* FIRDeleteAccountRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = B144E5E3A8596BD2FAAEAA56BDD6A884 /* FIRDeleteAccountRequest.m */; }; + B784F4B4A2325A1F719961C174067AE6 /* FSnapshotHolder.m in Sources */ = {isa = PBXBuildFile; fileRef = F4F3CAE474A7B498BF161E01B891F739 /* FSnapshotHolder.m */; }; + B785E35AE212C2CB4C4CD0D84C49B90D /* AsymmetricObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 161AC9CABA773FA8567619A753121850 /* AsymmetricObject.swift */; }; + B787C57C3EF4635A72E630ACD6F40BA3 /* RLMApp.mm in Sources */ = {isa = PBXBuildFile; fileRef = CBF04219BF0CCF068C34ECBB735714FC /* RLMApp.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + B82F8A63C5DC9E69986D4EBA7E7F3876 /* FValidation.h in Headers */ = {isa = PBXBuildFile; fileRef = CE3CC14F5AC1D8BCEC33860FC79E5344 /* FValidation.h */; settings = {ATTRIBUTES = (Project, ); }; }; + B8316E008B646F18A831E0497A8A534F /* FIRFinalizeMFASignInResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 67DA65C65A6DC928597F98BDE85879D6 /* FIRFinalizeMFASignInResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + B837F9BAA1E321E18780F3B8903BC004 /* MutableSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 250E7EC04CADDFF718CBE2F2B949220D /* MutableSet.swift */; }; + B83ABEECDE4D2AF6117282407B441D55 /* RLMAsyncTask.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 260BA989E65D1B70F99F3F9464CD1115 /* RLMAsyncTask.h */; }; + B8751E3FB95E013FB515F455EB018E83 /* _ObjC_HeartbeatsPayload.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEEFE024B53EE0D176146FCC6098D527 /* _ObjC_HeartbeatsPayload.swift */; }; + B89733EC7C564F879DA19FFCE4652F67 /* FIRHeartbeatLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 9FE4A6CCA174E0D63A5A98CABD8EC548 /* FIRHeartbeatLogger.h */; settings = {ATTRIBUTES = (Project, ); }; }; + B8B47B601574BA7BBFD029157CA4E628 /* GULSwizzler.m in Sources */ = {isa = PBXBuildFile; fileRef = A7E4C9186535EBC191900B137507E328 /* GULSwizzler.m */; }; + B8B5CAECF1D4440DA7E242D4D0B09BDA /* FIRVerifyAssertionRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 408F5AC132654E114CB2C4642531A12A /* FIRVerifyAssertionRequest.m */; }; + B8B7329C446F7C0134EAFF904FF52555 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB96318E2CB72DE3CDFEEF1B9E8644AD /* Foundation.framework */; }; + B8E868B2092716E5F89E7A04EF1079EA /* FIRAuthErrors.h in Headers */ = {isa = PBXBuildFile; fileRef = CC6D95242984ED92CFCC5367CC6F5AFE /* FIRAuthErrors.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B9420B1AEF7A229BE322D42494F6A4AD /* FViewCache.m in Sources */ = {isa = PBXBuildFile; fileRef = F545DFF514F5EA358932BB95A431E476 /* FViewCache.m */; }; + B94C1066CCFE8D7C8B902DED4BE9FCE1 /* FIRComponentContainer.h in Headers */ = {isa = PBXBuildFile; fileRef = 8466D70DC12DC21169B9A39EB1BBAF8B /* FIRComponentContainer.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BA057835099158FDFDA0C1F7A35C289F /* RLMObjectSchema_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 82F408B46FDEEDA775BCD20ABA5AEA87 /* RLMObjectSchema_Private.h */; }; + BA7F42CD95B27BD397FF9D3C5E2DB084 /* FDataEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = DE35B94C2CED0E8E9CAE38566E26439E /* FDataEvent.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BA8344D3B25EBACBE20F5A12CEA3DDD9 /* FIRVerifyPasswordResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = C2CC7D967ED5502EA688B2B429A6B2E0 /* FIRVerifyPasswordResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BA9F3E9F989382AC102728F0E867DB7D /* RLMPlatform.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = F44000EA207E28FDA17F50C681374B50 /* RLMPlatform.h */; }; + BB0E71EF9840588153CB86879EAAAEE3 /* RLMRealmConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C4A0D72C0FDAD19E451C2E21BA93B3A /* RLMRealmConfiguration.h */; }; + BB3AC17CF1CBD8C6675F7AB2565239EB /* FIRConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 43100CB1F7F8A6943C13D8F0BFD868C0 /* FIRConfiguration.m */; }; + BB4561A2ED45CC603872EDC873FEA6C1 /* RLMRealm+Sync.mm in Sources */ = {isa = PBXBuildFile; fileRef = 77EF00ECB627D79F06240B748B823EED /* RLMRealm+Sync.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + BB4B91C245873ED03D924E22707518F0 /* FOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 9ECD48B2C579D35E52365ED54C06D7A4 /* FOperation.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BB64E140F2511E1A201B5035D0D94FDA /* FParsedUrl.h in Headers */ = {isa = PBXBuildFile; fileRef = EE55309BF72F93761475501AEEA09218 /* FParsedUrl.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BBCE391F1AC55EFC2A589E550ACCC1B6 /* ObjectiveCSupport+AnyRealmValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = C29E8533FF9AF637113A7A692C0FD27D /* ObjectiveCSupport+AnyRealmValue.swift */; }; + BBE799CAF8880799CDEEDBA765FFC7CA /* histogram.cc in Sources */ = {isa = PBXBuildFile; fileRef = 3E3B8F36375EA3714EC52956048A32C4 /* histogram.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + BC5107C6FE41D614D2E229570FB776E7 /* FIRFacebookAuthCredential.h in Headers */ = {isa = PBXBuildFile; fileRef = D881B7E53154441A4B1D49E8DB0FA3F4 /* FIRFacebookAuthCredential.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BCDB42CD9E4A79B1AE35173F99F002FE /* RLMSwiftCollectionBase.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = DAC208FD41CE38A2E2E5ABCDABD3D70E /* RLMSwiftCollectionBase.h */; }; + BD13356B7C0CAB0D612190773C0480A4 /* FPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 62DBEBE7FDE694DB7230FEAFD3AC7DD6 /* FPath.m */; }; + BD2957E94F11BC2656255B32ED9A4937 /* filename.h in Headers */ = {isa = PBXBuildFile; fileRef = F6EA58853A83F71F9E161BBA885467E3 /* filename.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BD58FB4CADE9D1D06BAA8E61127892D1 /* RLMProviderClient.mm in Sources */ = {isa = PBXBuildFile; fileRef = EA7D71EB92C35DBEB01DB4C6AFBCC6CD /* RLMProviderClient.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + BD5ACB67AB00DBBFB9AAB0297FAC4161 /* FBLPromise+Then.h in Headers */ = {isa = PBXBuildFile; fileRef = BC987A1227156846E08850D86560BDF5 /* FBLPromise+Then.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BD69E327C8A2D5C6F4BA40913755AAD0 /* FIRUserMetadata.m in Sources */ = {isa = PBXBuildFile; fileRef = B5779CA3FF1DD9E71297A3043E11DC63 /* FIRUserMetadata.m */; }; + BDCC5C4B4D01C1885658D5CB3A3AC167 /* FIRInstallationsStore.h in Headers */ = {isa = PBXBuildFile; fileRef = CFEB25BE4BFD56BF6D6D28C7DBF5F9A2 /* FIRInstallationsStore.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BE0802B7354FC89221F4366ECDD35398 /* FTupleTransaction.m in Sources */ = {isa = PBXBuildFile; fileRef = 841716D96ED42D3A9096E922F0A3C8E5 /* FTupleTransaction.m */; }; + BE21697F0A9CCBFFD083CAB673468FFE /* FKeyIndex.h in Headers */ = {isa = PBXBuildFile; fileRef = 668B626E7E6C85D299AFCEA201C42B08 /* FKeyIndex.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BE41A7861D927FA0B900D659EF81BDC9 /* FNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 1BACF9688C6693A62406F49CBC73F486 /* FNode.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BE6E9AAE134ED6EB4353EAFA3D61DCD1 /* FIRAuthStoredUserManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D0DBBFFAC44D74581C242E052AFB80 /* FIRAuthStoredUserManager.m */; }; + BED9922AAC7CEE176632814E91E88EE3 /* FDataEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2ECCA115AD74D654B14B529508C64F3F /* FDataEvent.m */; }; + BEDF46F72C441F3549090A88F01DD917 /* RLMError.mm in Sources */ = {isa = PBXBuildFile; fileRef = 071248C77545C00DFE9E8A50D439E7AA /* RLMError.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + BF5352E6A21E27DB879C2189155F17EA /* BasicTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5506F3E5AA24EDAAE83D9798B944122C /* BasicTypes.swift */; }; + BF6874BB68C6E5D4386E78B11A4E45DA /* version_set.h in Headers */ = {isa = PBXBuildFile; fileRef = 1543F2502D4867CC79A5AFF5A5D871C7 /* version_set.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BF8A055237F1D258F87166BDF415E667 /* FIRLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 1174004659514A219C0CDDF7066B18C2 /* FIRLogger.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BFA7A13A2995D892BC108E0B0D53191D /* FIRVerifyPhoneNumberResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D47FAEFD73B473DF35243384BFA1770 /* FIRVerifyPhoneNumberResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BFECD5D79B67FEA725A2A2160D0D372A /* FIRDataSnapshot.h in Headers */ = {isa = PBXBuildFile; fileRef = B947898B4454551FA9410269740D2F69 /* FIRDataSnapshot.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C046821A21D98EABE254E3F597C87976 /* FIndexedFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 9EC1D2A0AB969A937D8CCD9DA60C7715 /* FIndexedFilter.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C049DE1B6175B99E372E70DF1F9241AB /* RLMCredentials.h in Headers */ = {isa = PBXBuildFile; fileRef = 99A3796A766AC39C09D1D998A183ED46 /* RLMCredentials.h */; }; + C04C00037217D6B0FA21801099283BB9 /* FIRGetProjectConfigRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = F40A7949398CF1B354A45647D63F250E /* FIRGetProjectConfigRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C070A4BC082AEC327BDB69A965E55AF8 /* port.h in Headers */ = {isa = PBXBuildFile; fileRef = D7ADD5B6B5915AEAC85BA95F031C7AAB /* port.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C07A83B6F8272719F207BAE2E077D573 /* GULAppDelegateSwizzler.m in Sources */ = {isa = PBXBuildFile; fileRef = FD47B704335D3B8A2DAF90093BD29570 /* GULAppDelegateSwizzler.m */; }; + C0A2D94BE8E64BD7092E214A3C6DC8F7 /* FirebaseCoreInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 16FEB6A940B78555761BBE1CD7FF27F1 /* FirebaseCoreInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C0B022EB886F9DCE13408F6E3041DBAA /* FIRInstallationsSingleOperationPromiseCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 8724DAAB9ED5D56FA204FF734EE4FD86 /* FIRInstallationsSingleOperationPromiseCache.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C0DF8DA7126E2280ECC00E581633D9D0 /* FIRAuthUserDefaults.h in Headers */ = {isa = PBXBuildFile; fileRef = 96ED84605B32D89346896DDD098C7B7F /* FIRAuthUserDefaults.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C11339074CE5C4A8DF75384CCC987B77 /* ObjectId.swift in Sources */ = {isa = PBXBuildFile; fileRef = 542FC53B9E7ABA035BA8484DB8D865D7 /* ObjectId.swift */; }; + C16F9108587C4D012FBB50DBD8AA5E77 /* RLMEmailPasswordAuth.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = B1EE524838C98D6E19AF4CF8DB02D099 /* RLMEmailPasswordAuth.h */; }; + C1CA135946CA13DF232F8101E13E7B9C /* FUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 05842D32365C92508821DBCFF24949FA /* FUtilities.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C21CC70908ACBEE99F98EEE082AF23F3 /* RLMDecimal128.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = C8CAF3FC639EB612E0500A5FAA2028C6 /* RLMDecimal128.h */; }; + C277A58F5843B31AB8F166E7E342194C /* RLMSwiftValueStorage.mm in Sources */ = {isa = PBXBuildFile; fileRef = 41F5A37DA149DDD896A9588F912417F8 /* RLMSwiftValueStorage.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + C2ADDCDFD0B92BEEC6D449000FB4882E /* FChildChangeAccumulator.m in Sources */ = {isa = PBXBuildFile; fileRef = D8FF4697BD930A161E25C7F50B4FBC63 /* FChildChangeAccumulator.m */; }; + C2B5190B51BE0FAE537831925FF254D3 /* FCancelEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 4310F18485AEFC94D8688C3A803C350B /* FCancelEvent.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C2BD266797A754A6FCAB38E867F6F4B4 /* FBLPromise.m in Sources */ = {isa = PBXBuildFile; fileRef = 1082CC92F4A4AB1688B228846A11F83D /* FBLPromise.m */; }; + C2BDB75DB8DF24B7F2A588E64FBCC466 /* merger.cc in Sources */ = {isa = PBXBuildFile; fileRef = 29924CAAFCB95B7922AD14E3631630E1 /* merger.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + C2BE5C95EDF2CE6BC335C709D6E44067 /* RLMProperty.mm in Sources */ = {isa = PBXBuildFile; fileRef = CF1CF80E33E84E4C4E5880610EEEB26B /* RLMProperty.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + C31C9FA5FD979162E48E1D3972872173 /* FLLRBEmptyNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 9506BA131E3841461239C5D751AD678A /* FLLRBEmptyNode.m */; }; + C357BF9095103609A41D4DD98905D94A /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4972477850A41A9D9B673C96DEF4168A /* Security.framework */; }; + C35D99F8D318ED34EA275C7266752AA9 /* FIRPhoneMultiFactorAssertion.m in Sources */ = {isa = PBXBuildFile; fileRef = 73247FFFFE3299EA4FF88B4C958FCFB2 /* FIRPhoneMultiFactorAssertion.m */; }; + C3BAEF874A581AE9B3E5BF66D5E431E5 /* RLMDictionary_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = F46007BED52B57BCF4843B87E9523D49 /* RLMDictionary_Private.h */; }; + C3DE1ACA5C56880B3AB706DDCF5F15AA /* GULApplication.h in Headers */ = {isa = PBXBuildFile; fileRef = C58E9D971BEAA0B2666855E46772D815 /* GULApplication.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C41D7F7A4FA6DA2FFC5DD86778C06DE1 /* FIRVerifyPhoneNumberRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = F784FF6511E920AAF983C6D82547E28D /* FIRVerifyPhoneNumberRequest.m */; }; + C46671D11B3BEBA872C9888AF8B2DB16 /* FIRFacebookAuthProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = 2BFD21803769DB6C353B3E8AB9C3D04C /* FIRFacebookAuthProvider.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C46AC4E9C3E597F9900ED4D12F934F3B /* RLMSchema.h in Headers */ = {isa = PBXBuildFile; fileRef = D6B797734979214911F26CE6964D223D /* RLMSchema.h */; }; + C479DC41793B5C448FEAE2B131A1AB56 /* FIRLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 58050F9C59254E6D397ADB56DFC128C4 /* FIRLogger.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C47C17432E9D7E48AA716B7B672DE9EC /* FTupleStringNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 91B060AB17825145370421059E87B0CB /* FTupleStringNode.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C49F41A0E496C24E4146A289BC043389 /* RLMSwiftCollectionBase.mm in Sources */ = {isa = PBXBuildFile; fileRef = 739D1EBC2858FD3E444E93BBB800622E /* RLMSwiftCollectionBase.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + C4DEB058FC4697D7845D56FEA4CC8446 /* FIRAuthKeychainServices.h in Headers */ = {isa = PBXBuildFile; fileRef = 73D394BF34BF20845775F8C96C11C552 /* FIRAuthKeychainServices.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C5322C26D74065EC41562C9EEBF78150 /* db_impl.cc in Sources */ = {isa = PBXBuildFile; fileRef = C770CCEDA892E21FD63BD717C4A20708 /* db_impl.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + C5344851C80D3EB6EC78C422351D1862 /* GULHeartbeatDateStorageUserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = 2035F5591F18DB561814028FE3726CF0 /* GULHeartbeatDateStorageUserDefaults.m */; }; + C5D49AFCFB7FAFFDE26F4D088E92FB33 /* FIRComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DA65E275D60CAA4E6577D4B0C1A9DBE /* FIRComponent.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C5ED69C4AA8BF6199DAF2C2BCABBA12F /* FIRAppInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 8353124354524C02C36488028B2F4D02 /* FIRAppInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C61143E52DEA5930248C02F7D44FDBCE /* FEmptyNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 1B5E77D8721F5D8AC2DD4588444F3EFB /* FEmptyNode.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C67E939C044C8C6A96A7F913403D7D12 /* FCompoundWrite.m in Sources */ = {isa = PBXBuildFile; fileRef = 338AECF668DCCB9C64EBE4A69BB6A954 /* FCompoundWrite.m */; }; + C68AA3E3D27F09F3C65E95FE0FA9A773 /* FIRRetryHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = C7A2103476D3B0BEBCA3691034634FDD /* FIRRetryHelper.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C6B76B89A919288D604A47D491FA7EE3 /* FIRSignUpNewUserResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = FF4A31EB3E4294B2F18DC6243AD3116D /* FIRSignUpNewUserResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C6C6AA35F49FCFA34BEF41CFFDD7ACFB /* table_builder.cc in Sources */ = {isa = PBXBuildFile; fileRef = FD32D97423F1C3AD8AD7075D273598CA /* table_builder.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + C78BF0F094DD0D20A1603776BA2888D1 /* FIRRevokeTokenRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 360BEAE8353C4A0D3D79A704073FB4D5 /* FIRRevokeTokenRequest.m */; }; + C7E0AE69B6132CFC359AC4CA35CAC927 /* snapshot.h in Headers */ = {isa = PBXBuildFile; fileRef = E195C7C4C8A627E9BC80CA7047D22DFD /* snapshot.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C820EC6237A1C41121E1F8B8597BBC95 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB96318E2CB72DE3CDFEEF1B9E8644AD /* Foundation.framework */; }; + C8626178E7EE3B1A784C50B1EC4C049B /* FIRAuthTokenResult_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = FDE9B09BD40DEABB8127F587A4BA535E /* FIRAuthTokenResult_Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C88EEA9C29E546AD0D04EE06B3113BDF /* RLMSectionedResults.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1B6E62F259BD798696AC28CA9B61D063 /* RLMSectionedResults.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + C8E2336FEDA5BACB621022D61C185B66 /* format.h in Headers */ = {isa = PBXBuildFile; fileRef = 56824B248662C8E8C141F005C41977B9 /* format.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C8E41AD8618746EC7F633A39328CDAAE /* FirebaseAuth-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A0132002DAF9BF16D277AB0D0C07A5C /* FirebaseAuth-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C92E5DE5B2BC5978D5A60D208FB9A050 /* FIRDependency.m in Sources */ = {isa = PBXBuildFile; fileRef = 61E8141817AC68D5CC9DCF402DC7F433 /* FIRDependency.m */; }; + C93BB8422D8332A3F5684DDC390B946B /* FBLPromise+Race.m in Sources */ = {isa = PBXBuildFile; fileRef = 58E43043367BCAD229609546CB6EF371 /* FBLPromise+Race.m */; }; + C9417F07851A0CF6FC395552A403F362 /* RLMProviderClient.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = A9D715562896C77226A34E182B52AE9E /* RLMProviderClient.h */; }; + C9927E5817F375F4470F9EB4DE12DD83 /* FIRTwitterAuthCredential.m in Sources */ = {isa = PBXBuildFile; fileRef = DDD2DB49347560B7FD71926843CC00F6 /* FIRTwitterAuthCredential.m */; }; + CA8BB025FB57BCC168A9AC80794CFA1D /* FMaxNode.h in Headers */ = {isa = PBXBuildFile; fileRef = BBC0FDBE9BF419C3332954C5D758AE2F /* FMaxNode.h */; settings = {ATTRIBUTES = (Project, ); }; }; + CAFBCA09CF5C2F272C040CF7976F4DEC /* FIRInstallationsBackoffController.h in Headers */ = {isa = PBXBuildFile; fileRef = CDB00D7D033A76284F4C2D94CD218ADA /* FIRInstallationsBackoffController.h */; settings = {ATTRIBUTES = (Project, ); }; }; + CB44D8EE576BFF2CCC5176F139A86EE2 /* Storage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 786F9BDCFBF6DF893D9F253B20AB4509 /* Storage.swift */; }; + CB72164F55028933140BF6E03EC064D1 /* GULMutableDictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = 2ECBE8E8556F51DD2D12C08DE1263BA9 /* GULMutableDictionary.m */; }; + CB735F99DCB6A60A24E6B7C4F3BFD674 /* RLMManagedSet.mm in Sources */ = {isa = PBXBuildFile; fileRef = DFE8D317CAC32D1548639938EE4E02AB /* RLMManagedSet.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + CBD2AD02B6042702A5AC2833AFC1829F /* FIRVerifyClientResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = C6545A3F8EC8ED4010C4BE7D98E69E88 /* FIRVerifyClientResponse.m */; }; + CBDB9BD5C1AD3C89C7FC98CE3E976CAF /* FIRDatabaseConfig_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = AEB6A7434EF1F3E8455BFE975EDDDC33 /* FIRDatabaseConfig_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + CC098CA333DF585D4E53DB5E3541CCD8 /* FIRAuthURLPresenter.h in Headers */ = {isa = PBXBuildFile; fileRef = 2919608BB643C33E664256CA53BB95EB /* FIRAuthURLPresenter.h */; settings = {ATTRIBUTES = (Project, ); }; }; + CC0A2E0CC16606F7F9FED89017360DF6 /* FTupleRemovedQueriesEvents.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BCC07F63582332DF6501B6233E04AD5 /* FTupleRemovedQueriesEvents.m */; }; + CC404F5613533237A8782BCE33094619 /* FIRDatabaseConnectionContextProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = 3FF0C7E3C42C45A71B34F4F0C942A1A7 /* FIRDatabaseConnectionContextProvider.h */; settings = {ATTRIBUTES = (Project, ); }; }; + CC7E403C2DDE4EAA34195F619AB290C7 /* FIRAuthCredential_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = D0B5650C6E0ADF651F660A4F97DB1A67 /* FIRAuthCredential_Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + CCD1C585CE4E9DBE15769F38E06842C2 /* ThreadSafeReference.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB1C8573631EC09896F9F87AF31645E6 /* ThreadSafeReference.swift */; }; + CCF6E8E0CC2205BF731C033CF4AA6810 /* RLMSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CBCF5236A1C6D972EB1E9825C24568D /* RLMSet.h */; }; + CDB19F68F28169453D4C9D9161031D69 /* FRepoInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 09BC0DF6DDAAB485732A09CE78733647 /* FRepoInfo.h */; settings = {ATTRIBUTES = (Project, ); }; }; + CEBED60F230DDDC6E9D71CBFE5D4147F /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4972477850A41A9D9B673C96DEF4168A /* Security.framework */; }; + CF1CA992D8E849D8E071EC1134DB762E /* RLMObjectId.mm in Sources */ = {isa = PBXBuildFile; fileRef = 061851272BBE3FB093703FA3D36BBF67 /* RLMObjectId.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + CFAF28FE3DFEB84A1862B6CCEAE64B88 /* Heartbeat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E953C57A2C1A68306C9ADAEC68C1C99 /* Heartbeat.swift */; }; + CFDA1E348801BB27D286CF747AAF3187 /* RLMSyncManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = 64108C8865FFF2EE03378892DBAA7633 /* RLMSyncManager.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + D03A42EF380D585E615FC9FAF77BA4A9 /* FIRStartMFASignInRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = C4326A02499E82B8CB0C1B52ED00762C /* FIRStartMFASignInRequest.m */; }; + D048FAB5314A168A7C43CCBC16780B5C /* FChildEventRegistration.h in Headers */ = {isa = PBXBuildFile; fileRef = 16A61136124D22967767C62762E11781 /* FChildEventRegistration.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D0ACD95FD5301C5C9E40E3C5DFEB289D /* FirebaseCore-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = A056A0728CEA9D82899D8B1F03886BDA /* FirebaseCore-dummy.m */; }; + D0D9A0D6F301A748E7F89A32C6822393 /* FIRAuthProtoStartMFAPhoneResponseInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A4A2A3F4FEE1B358A1A649FC0C19EEE /* FIRAuthProtoStartMFAPhoneResponseInfo.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D0E5286861360BCB4F7DEB39F5FB9D19 /* FirebaseInstallations-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = F1A63F9946D77AA0988F1947BD912CAC /* FirebaseInstallations-dummy.m */; }; + D0E622E0E6DB90C49606F1C38305F847 /* RLMResults.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = D499691A37C194CFC8292C3B66E69060 /* RLMResults.h */; }; + D10E04ED005166DE728E30E0091434B8 /* FIRComponentContainer.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BE9A4788D908C70DB01791A60D2E8C8 /* FIRComponentContainer.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D12BC2FB1D3DC4592128F923781BE852 /* FClock.h in Headers */ = {isa = PBXBuildFile; fileRef = CED95F9ADEF91DF005475A84C722E6FA /* FClock.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D200DDDDED3ADA6C430CC33566EB7E83 /* FIRDependency.h in Headers */ = {isa = PBXBuildFile; fileRef = D209A08FA1E9922FD310E9BE48FE9AAC /* FIRDependency.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D2173B9C59F3ED7A67431C3AC53CBDBC /* options.cc in Sources */ = {isa = PBXBuildFile; fileRef = B860C210552E04D159F16FAC9529BE68 /* options.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + D2578A9339552C39A0F02C5270FB1CFF /* FImmutableSortedDictionary.h in Headers */ = {isa = PBXBuildFile; fileRef = F2AF3110914F29826DCE78B416523133 /* FImmutableSortedDictionary.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D259A175BA77A4853C3834D57A8D988B /* FIRAuthWebViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 91067448F334D70084120D1E5EC0040C /* FIRAuthWebViewController.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D260ECDDE28A0556DB93E754D43C25F8 /* FAtomicNumber.h in Headers */ = {isa = PBXBuildFile; fileRef = 2345425439383E6C98582C65C0981322 /* FAtomicNumber.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D2BA7AE944BA6CFCFC0A39048D9BB707 /* RLMRealm_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 8A1CF7A2AB94E939661BF09684D2DF1B /* RLMRealm_Private.h */; }; + D2D06F2A49CC6BA3F7425EE460E0EE87 /* FIRAnalyticsConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 7852B5DBDABD1585A09D661182ED0B4F /* FIRAnalyticsConfiguration.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D30A9B44711199CA00581A2201414536 /* FAckUserWrite.m in Sources */ = {isa = PBXBuildFile; fileRef = 2AAAEDE8E70C8C7420323BCE56CECD62 /* FAckUserWrite.m */; }; + D3AB2D43660D45764524F9D018835C2E /* RLMMigration.h in Headers */ = {isa = PBXBuildFile; fileRef = AFBE43B2C0C2AF9EBCECCCEBBC8D162B /* RLMMigration.h */; }; + D42931C1B9778BAE429EB1D3BA1325BF /* FIRBundleUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = C443F6191AE6D9CA89D2B2D541E2329E /* FIRBundleUtil.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D42E8EF287DF8D1299662DCD8D2592ED /* RLMSyncUtil.mm in Sources */ = {isa = PBXBuildFile; fileRef = F927599937411CFC58D678F8486AB0AC /* RLMSyncUtil.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + D48DBD7232BDC3A01578CD4E7D5C95BC /* RLMSyncSubscription.h in Headers */ = {isa = PBXBuildFile; fileRef = DA74B0436802FE2BDE61D436290670BD /* RLMSyncSubscription.h */; }; + D49F99D6E4662F4EE1194AF5CD9FDE5C /* FIRTransactionResult_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = CF81F335A3222C35BAB5B868B46A8AC3 /* FIRTransactionResult_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D4C0E07416FD5F73DD67CB509AD491D1 /* FIRDatabaseReference_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DD63AD9A2170EA8DA1F0CED800B448C /* FIRDatabaseReference_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D4CB9A2EA3601EA9F9897A74B7ECC895 /* FIRAuthExceptionUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 790371766FE16C535A3A6564C2016038 /* FIRAuthExceptionUtils.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D4D154F12A9508D4453FC2E0B1B2A3C1 /* FIRDatabaseComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 296BED686200C06B5795701FF3B5C0AB /* FIRDatabaseComponent.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D4F202A907C8D419AB82200B814F0953 /* FIRGetAccountInfoRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 447F7001F40D564009C8A48A4B7801EA /* FIRGetAccountInfoRequest.m */; }; + D53372B5BBF6015D7925B8BCA6245276 /* FIRLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 59B92BFC2E5FD6370D6AAD2B96F09C54 /* FIRLogger.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D534E5D3B33F23C23AC12827BB2E15D7 /* FImmutableSortedSet.h in Headers */ = {isa = PBXBuildFile; fileRef = B0C06E7081B48799232D89E17EB0A49B /* FImmutableSortedSet.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D5530F56A633ED858516420DDC785BA5 /* FTupleCallbackStatus.m in Sources */ = {isa = PBXBuildFile; fileRef = 9EE5FB69103270807821EFED952A8EA2 /* FTupleCallbackStatus.m */; }; + D58019E41FACCB661850911399D9213B /* FIRFinalizeMFAEnrollmentRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 1BFC4F5515D28AA157359A2FE83628C6 /* FIRFinalizeMFAEnrollmentRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D646F95EC5C99A8C2FB7BB15F8EC6557 /* FListenComplete.m in Sources */ = {isa = PBXBuildFile; fileRef = 94D7FB887A55186658BA2927E263E07E /* FListenComplete.m */; }; + D6B2D211BB9CB9A12D9F2F6D9CAA65FB /* FIRAppCheckTokenResultInterop.h in Headers */ = {isa = PBXBuildFile; fileRef = 303B6E98FABDA657EC15858154A04C4F /* FIRAppCheckTokenResultInterop.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D6C44947FEE40D6011352F10AFF03FC0 /* FIRSendVerificationCodeResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C38BC7996475558BC1B0527BC88087F /* FIRSendVerificationCodeResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D7CAC9227069395CEA958D733F6F448D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB96318E2CB72DE3CDFEEF1B9E8644AD /* Foundation.framework */; }; + D7E0B1ECE4451DA6E3E681AFC9E3CE20 /* FIRMultiFactorResolver+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 88576C105CD8237BE0FC4B763FDF77AF /* FIRMultiFactorResolver+Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D7F425B8A1234098B7CAB015B96896FD /* RLMSyncSession.mm in Sources */ = {isa = PBXBuildFile; fileRef = 944425105FFCFF644DC439575272B712 /* RLMSyncSession.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + D81B797CD2571F21D720DC21E87360F6 /* RLMObject_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B84A215D7F46B8C23EE84B1A5F9CCB /* RLMObject_Private.h */; }; + D82059120A48162DA564D2E2D50DBDEB /* FRangedFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 77CF941717A8A5BD89D10005F3094380 /* FRangedFilter.m */; }; + D82684D89B5905862B5A06E431E4A6F6 /* FIRVerifyCustomTokenResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = DF8D96275E2E2AAC3FD340661C455E7E /* FIRVerifyCustomTokenResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D839B1FFF095A45A6A2C9AFAACD32A91 /* RLMCollection_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = F6204AB7B81D89A39B83FE06046A4725 /* RLMCollection_Private.h */; }; + D8455788A35E4CF431E52B2F7EB76AC0 /* FRangeMerge.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B63FB84EB4C99C9989AE9702E6B5310 /* FRangeMerge.m */; }; + D8BBE5D5E027D5EEEA15CBB9DA279FBD /* FIRInstallationsAPIService.h in Headers */ = {isa = PBXBuildFile; fileRef = 4E026AD30098E7501DEFA64FA8A2B8BF /* FIRInstallationsAPIService.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D8F2A6F3893C0186D0B46233B31A1910 /* FIRMultiFactorSession.h in Headers */ = {isa = PBXBuildFile; fileRef = B6AC0D7DAB5655B6C98E8132C5F02847 /* FIRMultiFactorSession.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D9D8EA266CD7C5885464952BC9B2678D /* ObjcBridgeable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B9C0BA6C40683E28DD6831B3FC7E7F1 /* ObjcBridgeable.swift */; }; + D9DFEE8BBB15E18235DBA274639050DF /* pb_decode.c in Sources */ = {isa = PBXBuildFile; fileRef = F5D281652BF9F2FE685ADC168FB4217F /* pb_decode.c */; settings = {COMPILER_FLAGS = "-fno-objc-arc -fno-objc-arc"; }; }; + D9EDB119313CA2168485F0024FD98B6C /* RLMFindOneAndModifyOptions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8583BB6D970836E5FDF1168BAB878383 /* RLMFindOneAndModifyOptions.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + DA099809CF608E0348A0E308A838BA49 /* GULSceneDelegateSwizzler.h in Headers */ = {isa = PBXBuildFile; fileRef = 707F9FEDC83ABFDAF459079D0BE88C1E /* GULSceneDelegateSwizzler.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DA143FCE1DF739C0493449CE4BA33D7E /* RLMDictionary.mm in Sources */ = {isa = PBXBuildFile; fileRef = 6C7E8CA913852DAEA9F764D022D94B48 /* RLMDictionary.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + DA288525260D987D8F913FF83AF10B2B /* FIRSecureTokenRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 98AA57D4F61DF5CEE54B53D96945100D /* FIRSecureTokenRequest.m */; }; + DB58CCADAD27983D22346E4ED8FDEED7 /* FIRMultiFactorInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = EA1F9E6CD6CEF164872E5EA441957F62 /* FIRMultiFactorInfo.m */; }; + DB7950971D2B42CFF36F27EECF3821A7 /* c.cc in Sources */ = {isa = PBXBuildFile; fileRef = C8BDC147022A51D0ED823DC6230006BB /* c.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + DB9C97512B77301DAB4399FFC26933CC /* FViewProcessorResult.m in Sources */ = {isa = PBXBuildFile; fileRef = E5F8E0CE9018602A1E2F2C90CC6FB33E /* FViewProcessorResult.m */; }; + DBBDEC5D335671836A90EE8DF97EF8A3 /* FIRUserInfoImpl.m in Sources */ = {isa = PBXBuildFile; fileRef = 6081ADA3495E375084C4844160B739B3 /* FIRUserInfoImpl.m */; }; + DC1CC94EA95338783CD4596CF2882942 /* List.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31136171FDDC64178366CD0A6B113B84 /* List.swift */; }; + DC365FBBDC86092EDCF4B284E44FAB47 /* RLMEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 955BE9FC76F7CE1DC6CEC4D0204858EB /* RLMEvent.h */; }; + DC4D87E65DF1801D3AB23D64E9C7584B /* FIRInstallationsStoredAuthToken.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AAEDD3920555DD075FFA6D823419E99 /* FIRInstallationsStoredAuthToken.h */; settings = {ATTRIBUTES = (Project, ); }; }; + DC70FCD19F37D5A2AF1C1FAD1771F031 /* RLMUpdateResult.mm in Sources */ = {isa = PBXBuildFile; fileRef = E7606F26B9DF776AB41E04D3CF6CAE70 /* RLMUpdateResult.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + DC742E247FD28307BFA5C4F97A86B148 /* RLMSyncConfiguration_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = C9D1BC99201338B767AF74599605CBAB /* RLMSyncConfiguration_Private.h */; }; + DD03813A8D27CBD28F61120EE5540A7F /* FBLPromise+Retry.h in Headers */ = {isa = PBXBuildFile; fileRef = 7BD2BA99023096C1DF3C88F2DE465DD2 /* FBLPromise+Retry.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DD2B25557D1C5C7198184E033C9F5E78 /* Pods-PRTY-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 647108F63AEB846763605E0AFE84F78E /* Pods-PRTY-dummy.m */; }; + DD2BC5BD5B99AFCBC34524C557E2C0BF /* RLMObjectBase.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = C69F72C06B9F4D036CD7680BFD656FDB /* RLMObjectBase.h */; }; + DD6533A9C97BB1393002A7590E2B70F2 /* FTupleBoolBlock.m in Sources */ = {isa = PBXBuildFile; fileRef = EA00F4F46EC2CD0F233E301B8D7D3F87 /* FTupleBoolBlock.m */; }; + DD7C92CFAEA3DF3952EF609A42353BB8 /* FIRAuthProtoMFAEnrollment.m in Sources */ = {isa = PBXBuildFile; fileRef = 0E5FD8D39CE43C6B9EF33E3B84B7C417 /* FIRAuthProtoMFAEnrollment.m */; }; + DD8584CBD50A0A5628C32118683454B3 /* RLMClassInfo.mm in Sources */ = {isa = PBXBuildFile; fileRef = E0CB4FCA7F89AD1530D8E842C40E2D1D /* RLMClassInfo.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + DDC1FB1EB139826C6FF10FCB2E91947A /* RLMThreadSafeReference.h in Headers */ = {isa = PBXBuildFile; fileRef = 726B5EDE338F3B54A4CF771D23EA5618 /* RLMThreadSafeReference.h */; }; + DDCC2DC2EEC342615590DEBF5899BCEC /* GULKeychainUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 075A5D7577CF5A3DC2EF3B7C5AB21F9C /* GULKeychainUtils.m */; }; + DDE0BA26BDA6A6C3CE77FFFF9C63C0C4 /* FIRDependency.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C04EE56E5B835BB6F333DCBC55AC442 /* FIRDependency.h */; settings = {ATTRIBUTES = (Project, ); }; }; + DE9AC4D1B35C9E07B979930D5C0B38DF /* CollectionAccess.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5071D4D3329AB8550000CC07BE36AFAB /* CollectionAccess.swift */; }; + DED0DBA57C460BED50AB906959ECADFE /* FIRMultiFactorAssertion+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 2B33ABC19D62233834F6D06F4927B557 /* FIRMultiFactorAssertion+Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + DED8B9BA2D7639B05CA4AF45A83B4A3A /* FPathIndex.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C6F5A54008F5FE3B7C04E60A783FF8F /* FPathIndex.h */; settings = {ATTRIBUTES = (Project, ); }; }; + DEEFD271BF00213BFE8F7D329BD3F5AA /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4972477850A41A9D9B673C96DEF4168A /* Security.framework */; }; + DFB24E24E3F25F5D5F990BF040C8D4DC /* FirebaseCore.h in Headers */ = {isa = PBXBuildFile; fileRef = F7ADFB69059F59EB2245F0730BC4BC72 /* FirebaseCore.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DFE1746A5269BEE6DD306BA59145C307 /* FIRSignInWithGameCenterRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = FE280A7F867E6C75B2562C0E436F53A3 /* FIRSignInWithGameCenterRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + DFEC3309D6492AD8DDE0516E83A3F5D5 /* FWriteTree.m in Sources */ = {isa = PBXBuildFile; fileRef = E1349D5F673D710C9751BEF3BD0990CF /* FWriteTree.m */; }; + E00D22D438AA185BF358A07FF0E0BE19 /* FIRTransactionResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 9D1A70BBED3AA1D1F9152581BE1E35B7 /* FIRTransactionResult.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E05FA77305030016A6C83C4B315FCB15 /* FBLPromise+Delay.m in Sources */ = {isa = PBXBuildFile; fileRef = E372170790901E282DA2178AD64F9AF1 /* FBLPromise+Delay.m */; }; + E0F676F594C65B182748EFC109BF842D /* RLMSyncManager.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 2B5BF8D2317897E5636B6D098AAA376C /* RLMSyncManager.h */; }; + E11EC38CFBC70683F81F2858E8F10439 /* RLMCredentials.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8709E4280FD40FF2D6C51425A4CC4DA8 /* RLMCredentials.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + E1592F441247C0469A674A0E0F738AF2 /* FRangeMerge.h in Headers */ = {isa = PBXBuildFile; fileRef = 3BA23E086F9B885781704FCA48B4BE17 /* FRangeMerge.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E18454DF2F43C51C823BF865A82A3EC1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB96318E2CB72DE3CDFEEF1B9E8644AD /* Foundation.framework */; }; + E22858B989C3D08AC5E7E1ED67468D28 /* FIRSignInWithGameCenterResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = E786BAEFF21D797C4F8294C087E59257 /* FIRSignInWithGameCenterResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E23E882A1005A1B0C8395A1AADE4A815 /* RLMAccessor.h in Headers */ = {isa = PBXBuildFile; fileRef = B508FF5F45501FC204670A03072D40AF /* RLMAccessor.h */; }; + E2565A76FD48280A35B688B7DEA233FC /* FIRAuthNotificationManager.h in Headers */ = {isa = PBXBuildFile; fileRef = D65779CDF02306477DFB2EE59C042724 /* FIRAuthNotificationManager.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E2916C9A40D41E306C7B1CCED8AC8D53 /* FIRAuthGlobalWorkQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = B699CB81D7A551A9BE7FB104B80D114D /* FIRAuthGlobalWorkQueue.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E2A421C6B07D202EC46EBF8FBE4A6C2A /* FIRMultiFactorConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 0FB9ED5CC42FCE28A63013D90A0CE0E3 /* FIRMultiFactorConstants.m */; }; + E2C0ACDE304C8154F8D114D3849C9206 /* FIRAuthDispatcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 063CA7411C06AB807B4B631C3D730ABC /* FIRAuthDispatcher.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E319346F7B9732FD494ECE12C241911B /* FIRGetProjectConfigResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 3023B4F5DDD02CFF5B395E7F490D33CC /* FIRGetProjectConfigResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E34B80A9A8B49857FCD043CAE44D1EC0 /* Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33F49AFBB23402149BEFBFF42FB5ABE /* Util.swift */; }; + E3B3840EAB0F5AAE1FFCEB635A2B5121 /* FCompoundHash.m in Sources */ = {isa = PBXBuildFile; fileRef = 75956E3ED82B4C4C3A8BF491AF04E129 /* FCompoundHash.m */; }; + E3C9567E3F690C2202CB3C1CAA301921 /* FIRAuthUserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D27EA86C69966574F1E107D04DEE758 /* FIRAuthUserDefaults.m */; }; + E51FC18B468CA4DB966243C9DB3A6B91 /* RLMSyncConfiguration.mm in Sources */ = {isa = PBXBuildFile; fileRef = CDCA1EBD36A9944DE635F52ECFC297C6 /* RLMSyncConfiguration.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + E52A2C906C5E2437C3089E99C8BEB9B0 /* FBLPromise+Async.m in Sources */ = {isa = PBXBuildFile; fileRef = 77F0D8AA239C613235E4A219436457D4 /* FBLPromise+Async.m */; }; + E5549CBA417D626744A8617A1735FE49 /* FIROAuthProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = DC183DB0DD726787211F6CDF27F004B0 /* FIROAuthProvider.m */; }; + E5B93B9B88365818621927C4E207BBCE /* FIROptions.h in Headers */ = {isa = PBXBuildFile; fileRef = C71C4ABD7D0982DB872418B5A8E88A5E /* FIROptions.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E5C0EB38B4AB858401C362D87E78DB59 /* FIRServerValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 03DCC5D7969A9F8F2B5976EE2BDCF5FD /* FIRServerValue.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E5DC059D5B0285E2244EC66BC86D982D /* FTreeNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 34182904E0E1E8C02F312847B25E4418 /* FTreeNode.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E60631A799CB4DB0AD96DE179954CDCE /* RLMSchema_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 120853B5C287EB6778D0E6F2CAAC678B /* RLMSchema_Private.h */; }; + E60EA635FFB19BB7C38CA8D88E0CCFB2 /* FIRAppCheckTokenResultInterop.h in Headers */ = {isa = PBXBuildFile; fileRef = FBF69EF961BCBADD5088BF639982EADA /* FIRAppCheckTokenResultInterop.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E6284E908AF5409603CA525094613726 /* FIRSendVerificationCodeRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = A5FF33CC502EBCFB234B8B0CAB937207 /* FIRSendVerificationCodeRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E66B26493E5450BF72C07766E4B210D4 /* FLimitedFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = CA25BAC788742E5802F043AFAF3A8086 /* FLimitedFilter.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E6B4DC0805BA4085AF3E995BCFE0831A /* RLMObject.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 780F15D6939A98ACA8F237480C9FDF2E /* RLMObject.h */; }; + E6B66B5094D16D6C2F439158E68F8453 /* FTrackedQuery.h in Headers */ = {isa = PBXBuildFile; fileRef = 18B260C2BA6AF298BFDD66833B84A7CB /* FTrackedQuery.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E6F7A6A7B2EFBD2AD51F53960EB8E530 /* histogram.h in Headers */ = {isa = PBXBuildFile; fileRef = 57D22D4FC5A856CAA41A5E4B0378EB49 /* histogram.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E728FFC9C06C471B2251C36600FA9637 /* FBLPromiseError.h in Headers */ = {isa = PBXBuildFile; fileRef = E77B5F799945E2A80CEF1ECB60633E49 /* FBLPromiseError.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E74C6FF02E4A9B3DB2C9BFF991C7BBA6 /* RLMMongoClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C642008350A5CF8DEB52E2325A396F1 /* RLMMongoClient.h */; }; + E79D6DB4E78C4F31D33B529C12E3509E /* FTreeSortedDictionary.h in Headers */ = {isa = PBXBuildFile; fileRef = E6B0319BF99F0E5F8A53C708EE2F0FBE /* FTreeSortedDictionary.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E7B389C091FE7D1155C1456195E531F7 /* FIRUserMetadata.h in Headers */ = {isa = PBXBuildFile; fileRef = 78A0CF3F16BA622C5E0A626D56DFAE8A /* FIRUserMetadata.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E7B3B7A549F8566E5D2F59B0FE2020C0 /* comparator.h in Headers */ = {isa = PBXBuildFile; fileRef = B11618F2A39522921E515B9556E49021 /* comparator.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E8CDC21A1379922EFEA8922958C76451 /* log_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = FD617FE550E98264A4A123767CCCB5C9 /* log_reader.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + E8EBA782F6C257A93E8D3A95D9F5C266 /* NSData+FIRBase64.h in Headers */ = {isa = PBXBuildFile; fileRef = 60EE7485A5498FE07A5EBB875A28A6FC /* NSData+FIRBase64.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E8F1FDCEE4DAC3658676B3BD4CCA4DF7 /* FIRInstallationsIIDTokenStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 8ACA29DAD3C62BAB3015BD90E9439CB1 /* FIRInstallationsIIDTokenStore.m */; }; + E96C247FA47305CECFF921819D6B1B32 /* FPersistentConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = BE470ED8559FFF0453FC817C2D585A1F /* FPersistentConnection.h */; settings = {ATTRIBUTES = (Project, ); }; }; + EA03FC54A195BCAD5218701A5B904734 /* FIRDatabaseConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B62A1EFF65D0F7A6EDC00FAB049E14E /* FIRDatabaseConfig.h */; settings = {ATTRIBUTES = (Project, ); }; }; + EA2D0A5C868A11E3A21F053F33E61C73 /* FIRFinalizeMFAEnrollmentRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = E291F2BE395DCAE350627CC2B42FE6E4 /* FIRFinalizeMFAEnrollmentRequest.m */; }; + EA43386142F3A4FA976A68C2D8F9AAEB /* FTupleNodePath.h in Headers */ = {isa = PBXBuildFile; fileRef = 35E2E52AD208369569D961888AD2CD8E /* FTupleNodePath.h */; settings = {ATTRIBUTES = (Project, ); }; }; + EA79854AD3918CA21E7420761A594DBC /* FEventRaiser.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D4B3FEF0D03F93C58C129DDF773C0AC /* FEventRaiser.h */; settings = {ATTRIBUTES = (Project, ); }; }; + EADF5AC8B74DD5106820523572EE7506 /* RLMProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = 94CA7DCE38C9B491A31260A067D071EA /* RLMProperty.h */; }; + EB39DFED44E6B77F023D047F844E1588 /* RLMMongoClient.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 0C642008350A5CF8DEB52E2325A396F1 /* RLMMongoClient.h */; }; + EB586BD5D0A80F02EB2CE9F00D11E5C0 /* FIRDatabaseQuery_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 0A03AE62123483BCC06367C075244AD8 /* FIRDatabaseQuery_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + EBD27DA186C47F37477C4D2FD98AB122 /* FWriteRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = 35220F076E37D3FB4AEFB242DBB9DA87 /* FWriteRecord.h */; settings = {ATTRIBUTES = (Project, ); }; }; + EBD59139C3F995AC17309B4FF3F32751 /* NSData+SRB64Additions.m in Sources */ = {isa = PBXBuildFile; fileRef = DF26D9FD9034751F508E469A65F9DE14 /* NSData+SRB64Additions.m */; }; + EBD66CD12254355FB20A1BA8DEABF253 /* FOperationSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 9020E232EB0972D241D3BF9C28E8BC0B /* FOperationSource.h */; settings = {ATTRIBUTES = (Project, ); }; }; + EC4C9EB9A74BB5447000582F572A5356 /* Realm-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 6287A4A1BAE8862EA2597F0C1383E8FC /* Realm-dummy.m */; }; + EC659275F4A4F5564BD0D55C62FC7CA4 /* GULReachabilityChecker.h in Headers */ = {isa = PBXBuildFile; fileRef = CB623088DFC607EEA6CC6E2C99E661BB /* GULReachabilityChecker.h */; settings = {ATTRIBUTES = (Public, ); }; }; + EC81C960F707C65ACA0D26A4658C15CB /* port_stdcxx.h in Headers */ = {isa = PBXBuildFile; fileRef = 82842089E759BBC3480E5CB007595E93 /* port_stdcxx.h */; settings = {ATTRIBUTES = (Project, ); }; }; + EC992DE9B00DA0F531A2BF0AF67B7D1D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB96318E2CB72DE3CDFEEF1B9E8644AD /* Foundation.framework */; }; + ECCD62448DCA613BA7D1125EF24669F2 /* FTupleBoolBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = 04F3DD0C04BB7E1840D7DD9435C44113 /* FTupleBoolBlock.h */; settings = {ATTRIBUTES = (Project, ); }; }; + ECF384925EB148C037CD4A9EF2366163 /* FIRInstallationsHTTPError.m in Sources */ = {isa = PBXBuildFile; fileRef = 4F4AE0B2518B127D5CFD6A229F918FBE /* FIRInstallationsHTTPError.m */; }; + ED2B4154C90873BF34D9F53C5E66C2D5 /* FIREmailLinkSignInResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B8FA1F7710A719A4A55E7366464BC60 /* FIREmailLinkSignInResponse.m */; }; + ED84D33835D30E2D1BC665C0048784D5 /* FIRFinalizeMFAEnrollmentResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C9BF815DA833EA927104176F6728631 /* FIRFinalizeMFAEnrollmentResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + EDD6148B0C349895A7FB55C60870EA1E /* RLMUser_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 0E66C7EAAF91F65896E6CC7C4A7B26F4 /* RLMUser_Private.h */; }; + EE2B13BBE97EB26F8D122A01EC320175 /* FIRSignUpNewUserResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = B87AF41DF8B5A0C0F400BC9F24C530D1 /* FIRSignUpNewUserResponse.m */; }; + EE7AF6437947FDF718E2A9CFAEBC3737 /* FIRGoogleAuthProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = E33AB87C9E1B8F7F515F0C6C418D8B2B /* FIRGoogleAuthProvider.m */; }; + EF029687EE62CFF7A201138A9A961A2E /* FRepoManager.m in Sources */ = {isa = PBXBuildFile; fileRef = D1FCF70DD745852460CA893C0044F06E /* FRepoManager.m */; }; + EF7D157C0B2D4029FBFBC6E072954952 /* FIRPhoneMultiFactorInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DDE43AA7EDF5492F8787EF6723CE7D5 /* FIRPhoneMultiFactorInfo.m */; }; + EF9183138C397191B5FCC5039411001A /* GoogleUtilities-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 75524D426CC700CE7B7C9E5C62779F88 /* GoogleUtilities-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + EFDA49F8F77C6CA54BA1C56F73B76BF6 /* RLMDecimal128.h in Headers */ = {isa = PBXBuildFile; fileRef = C8CAF3FC639EB612E0500A5FAA2028C6 /* RLMDecimal128.h */; }; + EFE5E6AC5BB761FB55261A9D992293D8 /* FTrackedQuery.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DC9D589442044C7CA61657FE041213C /* FTrackedQuery.m */; }; + F025CF81C5FDDDAC6BD6D31CD9458D18 /* FIRAuthBackend.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B387526B9BE23AC791723076F4BBF0D /* FIRAuthBackend.m */; }; + F03F8775698CB7D3BE31C481977C771B /* iterator.cc in Sources */ = {isa = PBXBuildFile; fileRef = 111F794074A676995CDDD8A9D7065800 /* iterator.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + F0B910E4767D4E42AB5BD44A08FCDB6E /* write_batch.h in Headers */ = {isa = PBXBuildFile; fileRef = B16C94E5F3A025995171BD475489E65F /* write_batch.h */; settings = {ATTRIBUTES = (Public, ); }; }; + F0ED9B20EED8F5046B60DF1BB893E515 /* FIRGoogleAuthProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = 9EED899C7A00C5E6FBC89D92F112061F /* FIRGoogleAuthProvider.h */; settings = {ATTRIBUTES = (Public, ); }; }; + F10EE87B15A28BECC7142627D6CA4BA1 /* FIRInstallationsAuthTokenResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A5426C951D7F583BE4F54AC6D9FDCBE /* FIRInstallationsAuthTokenResult.m */; }; + F1719DA02D57E086A37F581EB6DE31A0 /* FIRFacebookAuthCredential.m in Sources */ = {isa = PBXBuildFile; fileRef = 220EC7D8A2CB38340BCB87DDAF0166CD /* FIRFacebookAuthCredential.m */; }; + F1B335949B234A973FC70F5D9545BBC0 /* FIRAuthWebView.m in Sources */ = {isa = PBXBuildFile; fileRef = BF356E62ADDF306CEFC4B8245B5BCE68 /* FIRAuthWebView.m */; }; + F1D9094B4F5304543CCF8B7134C4CDD9 /* GULReachabilityChecker.m in Sources */ = {isa = PBXBuildFile; fileRef = 542B20DEA26B5C074039A87247015DEF /* GULReachabilityChecker.m */; }; + F1E7D8D5AD985178B7DE1CC0C3905032 /* GULNetworkLoggerProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = C20CAC628237BB9D607750E34695E5FC /* GULNetworkLoggerProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; + F2012DF27E5CCA5800F11829AC6C06D1 /* db_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = AAE0B0D562FECE9B4EA7BD57332F263C /* db_impl.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F20A0BD5B07FC0792FF857189CE7AFB4 /* FIRAuthRPCRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = A3D9BAC3AE5D6F200CE6741CC7D8430A /* FIRAuthRPCRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F23664D576E15E7398BB588D5B2F132A /* FIRStartMFAEnrollmentResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = CC576E1F438D451BD01C77F7B27C65A8 /* FIRStartMFAEnrollmentResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F24A2722E2CC4700F04B1087504EAF7D /* FBLPromise+Timeout.m in Sources */ = {isa = PBXBuildFile; fileRef = BF5A2E32B76BCCEDB11A4CC15B579BBB /* FBLPromise+Timeout.m */; }; + F26374CF411669267DB9B0F79015FD8F /* GULNetworkConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = EB340D31B9671B20F48E9C1D40AEB894 /* GULNetworkConstants.h */; settings = {ATTRIBUTES = (Public, ); }; }; + F2AE5E909E21811FA4F44DA63F7E23C4 /* RLMMongoDatabase.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = CF97E0F164DFA9E0C2AA0BA05C846A5A /* RLMMongoDatabase.h */; }; + F2BD51600D0A5C24260E09ADDF39BF65 /* FLLRBValueNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 657050EAF637F805365C58A8E0BC3601 /* FLLRBValueNode.m */; }; + F2ED3AE79750AFBF23156619FC6DC6B4 /* RLMObjectSchema_Private.h in Copy . Private Headers */ = {isa = PBXBuildFile; fileRef = 82F408B46FDEEDA775BCD20ABA5AEA87 /* RLMObjectSchema_Private.h */; }; + F3117B7CBCA74424D090B0911C96DC89 /* Object.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D5EB8A590366F66FC4D151DF662E315 /* Object.swift */; }; + F31CC2BA137A263D576A36AB0AA40E8A /* FBLPromise+Reduce.m in Sources */ = {isa = PBXBuildFile; fileRef = E00B9C320CCC9F274F7D1867FC7C18E0 /* FBLPromise+Reduce.m */; }; + F3320DB40CFC2F70058E85A452DD3359 /* FArraySortedDictionary.h in Headers */ = {isa = PBXBuildFile; fileRef = 013DBEEBEDDF4A433554616BCBBA997D /* FArraySortedDictionary.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F33E9CE79C80524B7507FFB796BC089B /* FIRGetOOBConfirmationCodeRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 0A6F710CD6390E3FBAEBC393A95FDAE0 /* FIRGetOOBConfirmationCodeRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F3A800D4B3012F97A4482F04FB2F0D26 /* FIRFirebaseUserAgent.m in Sources */ = {isa = PBXBuildFile; fileRef = 1171CF5F6FD906DFE4F386B29FA61D56 /* FIRFirebaseUserAgent.m */; }; + F43E7403F18847664D85B40C4B548801 /* FCompoundHash.h in Headers */ = {isa = PBXBuildFile; fileRef = 689C26D1B7BCCB029AE9A72765C6468E /* FCompoundHash.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F4610C06DBF2174D4B20830E6F9E7618 /* RLMPlatform.h in Headers */ = {isa = PBXBuildFile; fileRef = F44000EA207E28FDA17F50C681374B50 /* RLMPlatform.h */; }; + F4E23CC44884A30B093B217992E074CD /* testharness.h in Headers */ = {isa = PBXBuildFile; fileRef = 136D4F7911367790110F5E9240A6FD95 /* testharness.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F4E7ECDDA22430555FED5B6B5A48CBE6 /* FirebaseCoreInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DAAF670A3A48BEC4510C5D248BC666C /* FirebaseCoreInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F5A9905AFF28A99966232E7EB9274196 /* Pods-PRTY-PRTYUITests-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 8FD2C61EFB4734EA70647A3B77BF8ACF /* Pods-PRTY-PRTYUITests-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + F5C2EF7AC1CA47FE84C3356B7467849E /* format.cc in Sources */ = {isa = PBXBuildFile; fileRef = 25364FCE8A53D06CD550B641C415881F /* format.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + F646D4658110406F996A48C0B448FAB7 /* RLMAPIKeyAuth.mm in Sources */ = {isa = PBXBuildFile; fileRef = 46F03E9D37DE03046046D67857D32E74 /* RLMAPIKeyAuth.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + F67FE7C9AFC88C161332DCD647A9799F /* GTMSessionFetcherService.h in Headers */ = {isa = PBXBuildFile; fileRef = 85A86307CFF228951C1F53BA876D81A8 /* GTMSessionFetcherService.h */; settings = {ATTRIBUTES = (Public, ); }; }; + F7056900C929A66DE9C7C3709D538CF5 /* FRepo.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A337A8352740590C160918A1CC6B71B /* FRepo.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F70F563A55B7BE35625BC0DE69133526 /* FBLPromise+Recover.h in Headers */ = {isa = PBXBuildFile; fileRef = 050B6FE33817741C4489AF2856307BDB /* FBLPromise+Recover.h */; settings = {ATTRIBUTES = (Public, ); }; }; + F74EB5E9CFAC4748D7780350953B940C /* RLMManagedDictionary.mm in Sources */ = {isa = PBXBuildFile; fileRef = 276D23FD6D93BFC03B3E403333FC0C08 /* RLMManagedDictionary.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + F75854BE6F0E74A60701E844DFFBC597 /* filename.cc in Sources */ = {isa = PBXBuildFile; fileRef = E11FC028A82D1763971334635D2617A3 /* filename.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + F776D3E140166311A001DB9FC98853A1 /* FPathIndex.m in Sources */ = {isa = PBXBuildFile; fileRef = 580F4927B5BDF99355238AB3E3B8A646 /* FPathIndex.m */; }; + F77E9BFC320A071D1B0F29A909E1D1C4 /* FirebaseAppCheckInterop-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = A8F9DB69F1C068D0A79E78FF631D2D07 /* FirebaseAppCheckInterop-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + F7C7EB039AE633F1B5C99360FDEC4685 /* FStorageEngine.h in Headers */ = {isa = PBXBuildFile; fileRef = A1352CAA4472E809464D00B49A3A6BA6 /* FStorageEngine.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F80CCCEBF9794DC3E8B4EEB8FAAA2D0B /* ObjectSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7638110F458ECF6341C673A9696D666D /* ObjectSchema.swift */; }; + F81B60944AA404D3DC3B198B886EC053 /* table_builder.h in Headers */ = {isa = PBXBuildFile; fileRef = 795AEE8AFDEC780A0E27DFCCEDCBE103 /* table_builder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + F8E864A9944D645898FEDF5C14BBA609 /* FLeafNode.m in Sources */ = {isa = PBXBuildFile; fileRef = DDDD0E5429AF168AA2D3ED8F2AED36D4 /* FLeafNode.m */; }; + F9269572B7E1F79AD0695542C63253D5 /* FIRGoogleAuthCredential.h in Headers */ = {isa = PBXBuildFile; fileRef = 5F57F13EBD8F6268EA73B2E4176B7FB5 /* FIRGoogleAuthCredential.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F939485D514925747B76EB8FD3A1320A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB96318E2CB72DE3CDFEEF1B9E8644AD /* Foundation.framework */; }; + F94984129D6304129EE220C872F865B4 /* cache.cc in Sources */ = {isa = PBXBuildFile; fileRef = 110E93ABDED0BDC603500CB52BB1E1E5 /* cache.cc */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + F982C8D70D706DD41B1C47052126723E /* FIRDatabaseReference.h in Headers */ = {isa = PBXBuildFile; fileRef = DFB42C998CA9D2337B259FCCF7EF8206 /* FIRDatabaseReference.h */; settings = {ATTRIBUTES = (Public, ); }; }; + F999CFEC9CADE77F5EF855F3AF2C69B8 /* RLMObjectBase_Dynamic.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 3CF270CB5CBFFE011E21EF25448B9646 /* RLMObjectBase_Dynamic.h */; }; + F9D3ADA4C37A1FC124F9959AA8554670 /* FIRMultiFactorInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = BD0338B357A3CDE8F82D07CC33E9666E /* FIRMultiFactorInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; + F9D55B925CB1E274C7E86DADED3C9006 /* NSURLSession+GULPromises.m in Sources */ = {isa = PBXBuildFile; fileRef = EC13AB64AF41FAC54352545976A8CC9A /* NSURLSession+GULPromises.m */; }; + FA0D3093DDC70715973905B191D740CA /* FEmptyNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A141BBDF00F68D384672D09E6C8D5CA /* FEmptyNode.m */; }; + FA8FA0E3B86B3F7A1E20213EF3344C0E /* RLMCollection.mm in Sources */ = {isa = PBXBuildFile; fileRef = B843B5687B1E7F297B8EDE84FB98D92D /* RLMCollection.mm */; settings = {COMPILER_FLAGS = "-DREALM_HAVE_CONFIG -DREALM_COCOA_VERSION='@\"10.41.0\"' -D__ASSERTMACROS__ -DREALM_ENABLE_SYNC"; }; }; + FAA41046BC0FD7DA7F16B3C094B7C7A4 /* FIRInstallationsItem.m in Sources */ = {isa = PBXBuildFile; fileRef = F2DAEC929043E230DBB3692CFC09A1BA /* FIRInstallationsItem.m */; }; + FB2A314ECB8499A987353600D006BDF2 /* FIRTransactionResult.m in Sources */ = {isa = PBXBuildFile; fileRef = B328E2210DE31FBAA889235596BD786D /* FIRTransactionResult.m */; }; + FB665E38D5A479AEEDCFFD011F149A13 /* FIRApp.m in Sources */ = {isa = PBXBuildFile; fileRef = 2F92B76E1A6A4787FF52794D225AEB7B /* FIRApp.m */; }; + FB82B31BA1AFC627C65F9764A7094C8B /* RLMObjectId.h in Headers */ = {isa = PBXBuildFile; fileRef = E3B5F7670B5C0CA94B6720CC51510838 /* RLMObjectId.h */; }; + FBC2AF9B1DFC53B3F1436BF31F7EC9C9 /* RLMValue.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 135176A848ECF939C0716D13BD47BFDB /* RLMValue.h */; }; + FC59AB27D5307BDF740094CC16954F56 /* FIRCreateAuthURIRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 00F472C98AE8DC1A4A60B2718E19B6EE /* FIRCreateAuthURIRequest.m */; }; + FC74AFA3716766723E2B0239EAD3E274 /* FImmutableTree.m in Sources */ = {isa = PBXBuildFile; fileRef = E94ECD3EF54AD47F74DAF000981E3F6D /* FImmutableTree.m */; }; + FC91692EEA460F6AB5A7258EE960ED7D /* FWriteTree.h in Headers */ = {isa = PBXBuildFile; fileRef = 2B3CB3DFA47B93EEDCE11386C1D23DFF /* FWriteTree.h */; settings = {ATTRIBUTES = (Project, ); }; }; + FCE1F976A31B6C03B3B71681B632A40C /* FIRMultiFactor.h in Headers */ = {isa = PBXBuildFile; fileRef = B13E4C7F03E85F82326BD44C4F58BB36 /* FIRMultiFactor.h */; settings = {ATTRIBUTES = (Public, ); }; }; + FD5127CFB41EA3C43F6BC1448CB31135 /* FIRAuthAPNSTokenType.h in Headers */ = {isa = PBXBuildFile; fileRef = EF4313DE4400552722C93B74B967C814 /* FIRAuthAPNSTokenType.h */; settings = {ATTRIBUTES = (Public, ); }; }; + FD69336AE1B542C200DA412FF326EC11 /* FEventEmitter.m in Sources */ = {isa = PBXBuildFile; fileRef = F8E9BD133AFCC06067CDABEEB3220EF1 /* FEventEmitter.m */; }; + FE2BCCBDF39BF523C12F36BE70307E57 /* FIRAuthAppCredential.h in Headers */ = {isa = PBXBuildFile; fileRef = 898ED1F0E51D270602B2D9E712BDFB17 /* FIRAuthAppCredential.h */; settings = {ATTRIBUTES = (Project, ); }; }; + FE2F13D80F1F4B8A605390C3399EF3AD /* RealmKeyedCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA3CA50214CA2C30C735EF15DCFDD00C /* RealmKeyedCollection.swift */; }; + FE5621DEC98FB31AA72B2E7EFCF47E5E /* FIRAuthProtoStartMFAPhoneResponseInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 335DF35A42C03B1C619B15E6AFA1D269 /* FIRAuthProtoStartMFAPhoneResponseInfo.m */; }; + FE7FC652161CB9CBDDBA9E5BE3397011 /* Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4299C7EE17ED3C5658CD46D929754564 /* Error.swift */; }; + FE81A9DEF16D478E586D05E003497B10 /* FIRInstallationsStoredItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 77674F69710E6CF04D1D387F6B6F1F36 /* FIRInstallationsStoredItem.m */; }; + FEC8C3811D02EFF18C682D0103E873D5 /* RLMProperty.h in Copy . Public Headers */ = {isa = PBXBuildFile; fileRef = 94CA7DCE38C9B491A31260A067D071EA /* RLMProperty.h */; }; + FF00FEB45507C13D07486E49219A30A1 /* GULNSData+zlib.h in Headers */ = {isa = PBXBuildFile; fileRef = C8B8699512E125DAF372EB2BA3CFB387 /* GULNSData+zlib.h */; settings = {ATTRIBUTES = (Public, ); }; }; + FF13FD276737DDB7385A0E9C635991F7 /* fbase64.c in Sources */ = {isa = PBXBuildFile; fileRef = DF55A01ECA815A9E60783C3BEAA1609C /* fbase64.c */; }; + FFA2DAEB0C26A15082FF1CF616F37743 /* FIRAuthKeychainServices.m in Sources */ = {isa = PBXBuildFile; fileRef = 47384AF77CA4509C7238A8A3B5F9D3C1 /* FIRAuthKeychainServices.m */; }; + FFA8772FA4A072B867456081598B8E9D /* FIRDatabase.h in Headers */ = {isa = PBXBuildFile; fileRef = FFB04E1B4A84C609969A49C26D4AA88F /* FIRDatabase.h */; settings = {ATTRIBUTES = (Public, ); }; }; + FFACC2D38CD2693E59AA2CE0C74B2B33 /* FTransformedEnumerator.m in Sources */ = {isa = PBXBuildFile; fileRef = B7596BDDECA588FCF52569F283CD745F /* FTransformedEnumerator.m */; }; + FFFC123D47FB74E967FB4F2401D24BE5 /* FIRInstallationsItem+RegisterInstallationAPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 68AE375B41C0795563080D459FDCC110 /* FIRInstallationsItem+RegisterInstallationAPI.h */; settings = {ATTRIBUTES = (Project, ); }; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 04F2B059621A8F52AF612957704DB52F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8D7F5D5DD528D21A72DC87ADA5B12E2D; + remoteInfo = GoogleUtilities; + }; + 0516152CFD505C7F0B0F8A16FCA90AD9 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8D7F5D5DD528D21A72DC87ADA5B12E2D; + remoteInfo = GoogleUtilities; + }; + 098C48605ADC39486758E23BA26539F7 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8D7F5D5DD528D21A72DC87ADA5B12E2D; + remoteInfo = GoogleUtilities; + }; + 14A322A1AC500E74EDF645DC892EA44D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 2BBF7206D7FAC92C82A042A99C4A98F8; + remoteInfo = PromisesObjC; + }; + 1673B004612F96977DBC24524410576C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B53D977A951AFC38B21751B706C1DF83; + remoteInfo = GoogleAppMeasurement; + }; + 1BA286B69860AA1E04F78ABEDF3294A7 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 4402AFF83DBDC4DD07E198685FDC2DF2; + remoteInfo = FirebaseCore; + }; + 2D147F859DDB7890AB63757B2B48D558 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D2B5E7DCCBBFB32341D857D01211A1A3; + remoteInfo = nanopb; + }; + 2DDAB5BB6DECA834588DCE67F913C08F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 2BBF7206D7FAC92C82A042A99C4A98F8; + remoteInfo = PromisesObjC; + }; + 308ABA41B2D29D0D1B37A17A4B12F138 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 782725687624F8665247B84AB581BEB1; + remoteInfo = RealmSwift; + }; + 3108DDC56CCB0CDC4E6BDFE021997DDE /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 6AE4A3D573DED275B034E20506596C62; + remoteInfo = FirebaseAuth; + }; + 318C1A405308D930D20AE22EB1FD4150 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 6AE4A3D573DED275B034E20506596C62; + remoteInfo = FirebaseAuth; + }; + 31E77B69BA9B2AA4BE68E9BFA19F85CC /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 2BBF7206D7FAC92C82A042A99C4A98F8; + remoteInfo = PromisesObjC; + }; + 33D8BFB977D35D03620D1DFF284C88D9 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 736AF68F6527ACF6B4A4C54728824A1C; + remoteInfo = FirebaseDatabase; + }; + 3492D860BE14792B6CCAA6C9F8E4E505 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 87803597EB3F20FC46472B85392EC4FD; + remoteInfo = FirebaseInstallations; + }; + 39A18CEC6FA11024467A2918EC7D6BC6 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 072CEA044D2EF26F03496D5996BBF59F; + remoteInfo = Firebase; + }; + 443F5DC9F3D1DE495A2D326006F980FB /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D676E21115185671D7258A56944ABE98; + remoteInfo = GTMSessionFetcher; + }; + 4C6C3C078CB5C9B18F5BA52C4AF6929C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 68494F30B4A13F8E5E88BCCAEC25B0A4; + remoteInfo = Realm; + }; + 4F6978D24DDD2B673979E92879905610 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 68494F30B4A13F8E5E88BCCAEC25B0A4; + remoteInfo = Realm; + }; + 5BD9ADE5AAA4535686FAAA1C3CC0357D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 6EB67D63E9CBABC9495A7C2F928737F2; + remoteInfo = "Pods-PRTY"; + }; + 61E1F30BB49E1CFA5E47E05FB2CC4945 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 25E9E9A17BC3F670357D7385C521E48E; + remoteInfo = FirebaseCoreInternal; + }; + 6D40EDCF4FADF10C87091425A26E2172 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8D7F5D5DD528D21A72DC87ADA5B12E2D; + remoteInfo = GoogleUtilities; + }; + 6F43C42E7927FD30D223C4082AD1E611 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 25E9E9A17BC3F670357D7385C521E48E; + remoteInfo = FirebaseCoreInternal; + }; + 6FCBD942CDF63E61FE2190400F6CD3FA /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D676E21115185671D7258A56944ABE98; + remoteInfo = GTMSessionFetcher; + }; + 74142478B4FC8B27E39C042BD1E36403 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8D7F5D5DD528D21A72DC87ADA5B12E2D; + remoteInfo = GoogleUtilities; + }; + 78BCAB41F407804D6FC2BD1E2911218D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = C49E7A4D59E5C8BE8DE9FB1EFB150185; + remoteInfo = FirebaseAnalytics; + }; + 7A83C545054283193154F50A0D70E089 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 68494F30B4A13F8E5E88BCCAEC25B0A4; + remoteInfo = Realm; + }; + 7C2DD98B54749B01C52F6F805BCCF988 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 782725687624F8665247B84AB581BEB1; + remoteInfo = RealmSwift; + }; + 7E879050E608976F80175EA65F8BC320 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 072CEA044D2EF26F03496D5996BBF59F; + remoteInfo = Firebase; + }; + 819C09EAE7F010DD612DFBCD69E40FCC /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 4402AFF83DBDC4DD07E198685FDC2DF2; + remoteInfo = FirebaseCore; + }; + 825E5630272C9862D73FDCB626215B14 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D2B5E7DCCBBFB32341D857D01211A1A3; + remoteInfo = nanopb; + }; + 8CB010577E0BE59D2312C3B77669CC8B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8D7F5D5DD528D21A72DC87ADA5B12E2D; + remoteInfo = GoogleUtilities; + }; + 8FED94D31CE78026A377FC87CF489CD5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 4402AFF83DBDC4DD07E198685FDC2DF2; + remoteInfo = FirebaseCore; + }; + 93D09E74D894F9DA140CDFD4CC314A49 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 4402AFF83DBDC4DD07E198685FDC2DF2; + remoteInfo = FirebaseCore; + }; + 9AD642D3BE68B4B2A425E8B6FE438C4C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 87803597EB3F20FC46472B85392EC4FD; + remoteInfo = FirebaseInstallations; + }; + 9DB6502B940BC7A4311340732F4A82FC /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D676E21115185671D7258A56944ABE98; + remoteInfo = GTMSessionFetcher; + }; + A27C3F3F02080EF60222D292BFCA0415 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 736AF68F6527ACF6B4A4C54728824A1C; + remoteInfo = FirebaseDatabase; + }; + A7FCDBA4F6755115DC3CDBE58DCED780 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DD28B439BE8B17D9339D9B526F144347; + remoteInfo = FirebaseAppCheckInterop; + }; + AC814FA86648A9EA9FC2438DCDF553A0 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 6AE4A3D573DED275B034E20506596C62; + remoteInfo = FirebaseAuth; + }; + B02D047C18BA97E1CCED89BDA620C907 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B53D977A951AFC38B21751B706C1DF83; + remoteInfo = GoogleAppMeasurement; + }; + B1EC55D5BFD3FC0E774363F72E4494A6 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DD28B439BE8B17D9339D9B526F144347; + remoteInfo = FirebaseAppCheckInterop; + }; + B55E86A2610B1EF5E73A5410E17D0D95 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 4402AFF83DBDC4DD07E198685FDC2DF2; + remoteInfo = FirebaseCore; + }; + B78518C0F06A7F78C8BA8C29F750E165 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = C49E7A4D59E5C8BE8DE9FB1EFB150185; + remoteInfo = FirebaseAnalytics; + }; + C944FF5406DC8599A20BCFFC8BAA2221 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D2B5E7DCCBBFB32341D857D01211A1A3; + remoteInfo = nanopb; + }; + D2EC79994CB78BF25744580D912EA76B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 2BBF7206D7FAC92C82A042A99C4A98F8; + remoteInfo = PromisesObjC; + }; + D3B2A91186893F85EC9A0D5E8AE3F180 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 9307B7A119490930CF70393AB529AAC1; + remoteInfo = "leveldb-library"; + }; + D5B50C51D354989FF8B1A057EBC1AE3A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B53D977A951AFC38B21751B706C1DF83; + remoteInfo = GoogleAppMeasurement; + }; + D5DC6F9AB94C697099D58DBD7EA567F7 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 9307B7A119490930CF70393AB529AAC1; + remoteInfo = "leveldb-library"; + }; + D6286A89240200BBCDEAA1BDFEFABC96 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8D7F5D5DD528D21A72DC87ADA5B12E2D; + remoteInfo = GoogleUtilities; + }; + D6DFDCFFAD1A3D0821E7CBFDBE773355 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DD28B439BE8B17D9339D9B526F144347; + remoteInfo = FirebaseAppCheckInterop; + }; + D835DB6B3AE8421567C44B91F7E5975E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 87803597EB3F20FC46472B85392EC4FD; + remoteInfo = FirebaseInstallations; + }; + D9DDD885C5F83A9E84C453FF34838738 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 25E9E9A17BC3F670357D7385C521E48E; + remoteInfo = FirebaseCoreInternal; + }; + DFB4583EE4CA5B4263ECD1F9C5633838 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8D7F5D5DD528D21A72DC87ADA5B12E2D; + remoteInfo = GoogleUtilities; + }; + E0EC0F3F3F512E174FCB13C02032280E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D2B5E7DCCBBFB32341D857D01211A1A3; + remoteInfo = nanopb; + }; + E44ACD1C4BCA32274285B332CAEFFC7C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 9307B7A119490930CF70393AB529AAC1; + remoteInfo = "leveldb-library"; + }; + EB91152D34D1393B9475FE1D58A2F496 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = C49E7A4D59E5C8BE8DE9FB1EFB150185; + remoteInfo = FirebaseAnalytics; + }; + F15B1E28F8F656804698054C67A9968D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 736AF68F6527ACF6B4A4C54728824A1C; + remoteInfo = FirebaseDatabase; + }; + FA117A33ECCCB87CC55E174C24B02719 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 4402AFF83DBDC4DD07E198685FDC2DF2; + remoteInfo = FirebaseCore; + }; + FAE09F295913CE5870F2600E737BD884 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 4402AFF83DBDC4DD07E198685FDC2DF2; + remoteInfo = FirebaseCore; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + A7251DEEB84017C53E839EE10B835C9C /* Copy . Private Headers */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "$(PRIVATE_HEADERS_FOLDER_PATH)/."; + dstSubfolderSpec = 16; + files = ( + 5C34CE6C2A6C7932B3216D2844258313 /* RLMAccessor.h in Copy . Private Headers */, + 0722851D136DD19B4DF9F8D7A602E76D /* RLMApp_Private.h in Copy . Private Headers */, + AF3B946C1C71A75CB204C50E48E36FF7 /* RLMArray_Private.h in Copy . Private Headers */, + A9C59999EAE6BCC341858A32BA288A08 /* RLMAsyncTask_Private.h in Copy . Private Headers */, + D839B1FFF095A45A6A2C9AFAACD32A91 /* RLMCollection_Private.h in Copy . Private Headers */, + 5313ED256C342664AB3F3F7A45504AC2 /* RLMDictionary_Private.h in Copy . Private Headers */, + 2A93CB0B3804F73F214BAC10BEB17616 /* RLMEvent.h in Copy . Private Headers */, + AB3E9EAB71F0B212E143CE8C636F77AA /* RLMLogger_Private.h in Copy . Private Headers */, + 8FD79265CC7CDFB8FCD8051A8D936CC9 /* RLMMongoCollection_Private.h in Copy . Private Headers */, + A93E2122B31D4B57FEFCA90699A9C6E6 /* RLMObject_Private.h in Copy . Private Headers */, + 8DF758428290968A7A6745B4EF821F36 /* RLMObjectBase_Private.h in Copy . Private Headers */, + F2ED3AE79750AFBF23156619FC6DC6B4 /* RLMObjectSchema_Private.h in Copy . Private Headers */, + 00B6A51F66E88F69863C2D92BA6F6562 /* RLMObjectStore.h in Copy . Private Headers */, + A7CE962EF9B775EBC3DF94CB1A10D308 /* RLMProperty_Private.h in Copy . Private Headers */, + A093549452C05981016DDA86E341871A /* RLMRealm_Private.h in Copy . Private Headers */, + 83CB9EEA0326A748F65100B246D0DF18 /* RLMRealmConfiguration_Private.h in Copy . Private Headers */, + 923D016B51AA47A7F2887DB315161BF9 /* RLMResults_Private.h in Copy . Private Headers */, + 065A10113B63F448EF07DB487BAD18CC /* RLMScheduler.h in Copy . Private Headers */, + E60631A799CB4DB0AD96DE179954CDCE /* RLMSchema_Private.h in Copy . Private Headers */, + AAA3B8C557486D7CAFFC82623BA36A12 /* RLMSet_Private.h in Copy . Private Headers */, + 0ABE3648A1AC88265A23E66FD8D9AEA4 /* RLMSwiftProperty.h in Copy . Private Headers */, + DC742E247FD28307BFA5C4F97A86B148 /* RLMSyncConfiguration_Private.h in Copy . Private Headers */, + B1AD71A7648B34EB72F5D99152A8E299 /* RLMSyncSubscription_Private.h in Copy . Private Headers */, + EDD6148B0C349895A7FB55C60870EA1E /* RLMUser_Private.h in Copy . Private Headers */, + ); + name = "Copy . Private Headers"; + runOnlyForDeploymentPostprocessing = 0; + }; + C285DFF620C646030E5EBD6B526878CD /* Copy . Public Headers */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "$(PUBLIC_HEADERS_FOLDER_PATH)/."; + dstSubfolderSpec = 16; + files = ( + B2388836E5E17F87578AB046A8F9C449 /* NSError+RLMSync.h in Copy . Public Headers */, + 9226A945F3D80332E2C4C83115B9F6E3 /* Realm.h in Copy . Public Headers */, + 318AFF729D2DE955120F0BDEC6A58BD6 /* RLMAPIKeyAuth.h in Copy . Public Headers */, + AB3D370C50E410078DE6953A09736B13 /* RLMApp.h in Copy . Public Headers */, + B0FFC5806A64B5A60CB55230332EC96B /* RLMArray.h in Copy . Public Headers */, + 1C3CCBA7A56F4B2AE6DC7D4080D085CF /* RLMAsymmetricObject.h in Copy . Public Headers */, + B83ABEECDE4D2AF6117282407B441D55 /* RLMAsyncTask.h in Copy . Public Headers */, + 191780B64BD14CA6817038571827C27E /* RLMBSON.h in Copy . Public Headers */, + AC856C6E5BEF966B11B0E0135895C487 /* RLMCollection.h in Copy . Public Headers */, + 5D01CC83D8C2C6D0A0C82588A0B22D96 /* RLMConstants.h in Copy . Public Headers */, + 15467BBAED5278D8B7FD42E0DC8F5E09 /* RLMCredentials.h in Copy . Public Headers */, + C21CC70908ACBEE99F98EEE082AF23F3 /* RLMDecimal128.h in Copy . Public Headers */, + 275517FAB97156D3F6B8F2CCA588D375 /* RLMDictionary.h in Copy . Public Headers */, + C16F9108587C4D012FBB50DBD8AA5E77 /* RLMEmailPasswordAuth.h in Copy . Public Headers */, + 44B2925315E8C523225A94DBBD7CBBBA /* RLMEmbeddedObject.h in Copy . Public Headers */, + B4AE86E05D286DEE1843DD5344090641 /* RLMError.h in Copy . Public Headers */, + 73D6DBA39D87023005F7AF6B38244515 /* RLMFindOneAndModifyOptions.h in Copy . Public Headers */, + 805DBFE8246CDEC8CFC1CAA007A36CF4 /* RLMFindOptions.h in Copy . Public Headers */, + 6A02A21D71BA4843494A0AF209FB4558 /* RLMLogger.h in Copy . Public Headers */, + 4A65CBCE0C4CAE31C4559FDF046D5F92 /* RLMMigration.h in Copy . Public Headers */, + EB39DFED44E6B77F023D047F844E1588 /* RLMMongoClient.h in Copy . Public Headers */, + 0BD69C8B2A7F56A05EBAA938E35D0A10 /* RLMMongoCollection.h in Copy . Public Headers */, + F2AE5E909E21811FA4F44DA63F7E23C4 /* RLMMongoDatabase.h in Copy . Public Headers */, + A79571C65BAB139997C9CB1C04E8B395 /* RLMNetworkTransport.h in Copy . Public Headers */, + E6B4DC0805BA4085AF3E995BCFE0831A /* RLMObject.h in Copy . Public Headers */, + DD2BC5BD5B99AFCBC34524C557E2C0BF /* RLMObjectBase.h in Copy . Public Headers */, + F999CFEC9CADE77F5EF855F3AF2C69B8 /* RLMObjectBase_Dynamic.h in Copy . Public Headers */, + 206449DF6C6856E7F63C20C7C67283A2 /* RLMObjectId.h in Copy . Public Headers */, + 41D9BA130C83986F9937FC360681F3BD /* RLMObjectSchema.h in Copy . Public Headers */, + BA9F3E9F989382AC102728F0E867DB7D /* RLMPlatform.h in Copy . Public Headers */, + FEC8C3811D02EFF18C682D0103E873D5 /* RLMProperty.h in Copy . Public Headers */, + C9417F07851A0CF6FC395552A403F362 /* RLMProviderClient.h in Copy . Public Headers */, + 6BBB9D3D1E702A56325CA972DAB9C605 /* RLMPushClient.h in Copy . Public Headers */, + B52D9C6E0E42DEB9798559D08220D332 /* RLMRealm.h in Copy . Public Headers */, + 23E9879097C598B8AA8A388356C09BE4 /* RLMRealm+Sync.h in Copy . Public Headers */, + 79E3469DC4AED4587DF861AC0BFEBBC1 /* RLMRealm_Dynamic.h in Copy . Public Headers */, + 390166F3C6763F547913436E141CC1E0 /* RLMRealmConfiguration.h in Copy . Public Headers */, + D0E622E0E6DB90C49606F1C38305F847 /* RLMResults.h in Copy . Public Headers */, + 81C3A0068920FC702FE1488DC104992E /* RLMSchema.h in Copy . Public Headers */, + 4843A45A15A4127190085FAEA939E55A /* RLMSectionedResults.h in Copy . Public Headers */, + 21427BDB68B531D4AFCB02B3D5C0E38B /* RLMSet.h in Copy . Public Headers */, + BCDB42CD9E4A79B1AE35173F99F002FE /* RLMSwiftCollectionBase.h in Copy . Public Headers */, + 7D6B9148BE9AE09E9C01D056DB838238 /* RLMSwiftObject.h in Copy . Public Headers */, + ADCA32AC2369C90AD2FA2616F7A6DD41 /* RLMSwiftValueStorage.h in Copy . Public Headers */, + 4312FD62AAF2FB45358D7DF002936519 /* RLMSyncConfiguration.h in Copy . Public Headers */, + E0F676F594C65B182748EFC109BF842D /* RLMSyncManager.h in Copy . Public Headers */, + 2B06CE35C5F2F86997A11CCFBB2002C4 /* RLMSyncSession.h in Copy . Public Headers */, + 2DD1FE142741159D79FF695B47D323CD /* RLMSyncSubscription.h in Copy . Public Headers */, + 00693E81011B4F156A751125E729D2BD /* RLMThreadSafeReference.h in Copy . Public Headers */, + 7C42320EC510AF127E5CC6A35A5FF853 /* RLMUpdateResult.h in Copy . Public Headers */, + 84025BBB96DDE4205F0D9C4C8E095643 /* RLMUser.h in Copy . Public Headers */, + A78A12C84F898279D2CF0DEDA0987804 /* RLMUserAPIKey.h in Copy . Public Headers */, + FBC2AF9B1DFC53B3F1436BF31F7EC9C9 /* RLMValue.h in Copy . Public Headers */, + ); + name = "Copy . Public Headers"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 0006371B66B70DA75BA4BAA405CE68B1 /* FIRGetAccountInfoResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRGetAccountInfoResponse.h; path = FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoResponse.h; sourceTree = ""; }; + 0009925C746201D1B1E5D9602FFC6DCA /* Pods-PRTYTests-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-PRTYTests-dummy.m"; sourceTree = ""; }; + 004F83479325FA52B3C2EF9F638F5C2C /* FValueIndex.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FValueIndex.m; path = FirebaseDatabase/Sources/FValueIndex.m; sourceTree = ""; }; + 007B099760AAE9DBA8EC8150D40C88BB /* FSyncPoint.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FSyncPoint.m; path = FirebaseDatabase/Sources/Core/FSyncPoint.m; sourceTree = ""; }; + 00AF0142CDFB574A26958CAF911B5C05 /* GTMSessionFetcher-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "GTMSessionFetcher-Info.plist"; sourceTree = ""; }; + 00E78D580C86EE50250D99A09C295403 /* FIRAuthDataResult_Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthDataResult_Internal.h; path = FirebaseAuth/Sources/Auth/FIRAuthDataResult_Internal.h; sourceTree = ""; }; + 00F472C98AE8DC1A4A60B2718E19B6EE /* FIRCreateAuthURIRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRCreateAuthURIRequest.m; path = FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIRequest.m; sourceTree = ""; }; + 013DBEEBEDDF4A433554616BCBBA997D /* FArraySortedDictionary.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FArraySortedDictionary.h; path = FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FArraySortedDictionary.h; sourceTree = ""; }; + 020FDD18BA4ABFA3D61D95E45EFAC4E4 /* FirebaseAuth.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = FirebaseAuth.modulemap; sourceTree = ""; }; + 02170472A8C1C88AB10DAC7F8DA66B69 /* RLMAsyncTask.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMAsyncTask.mm; path = Realm/RLMAsyncTask.mm; sourceTree = ""; }; + 02D7467DDB121A7DEEE46877041066D7 /* GULLogger.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULLogger.m; path = GoogleUtilities/Logger/GULLogger.m; sourceTree = ""; }; + 02F08FE90CA068E63145D504F97EA515 /* Pods-PRTY-PRTYUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-PRTY-PRTYUITests.debug.xcconfig"; sourceTree = ""; }; + 0306EEC425C1FFBD36CA65D3932A6ADC /* Realm.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Realm.h; path = include/Realm.h; sourceTree = ""; }; + 032A6D00D7568C566A9E84523D7F8ED4 /* FirebaseCore.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = FirebaseCore.modulemap; sourceTree = ""; }; + 03569094005DFF21986290B7A7CCCD84 /* FirebaseCoreInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FirebaseCoreInternal.h; path = FirebaseCore/Extension/FirebaseCoreInternal.h; sourceTree = ""; }; + 039997D3CBE3F7A0E8AF5CAE8CF8AF49 /* FTreeNode.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTreeNode.m; path = FirebaseDatabase/Sources/Core/Utilities/FTreeNode.m; sourceTree = ""; }; + 03AA740D30B94B0A702C0129205701EE /* Migration.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Migration.swift; path = RealmSwift/Migration.swift; sourceTree = ""; }; + 03DCC5D7969A9F8F2B5976EE2BDCF5FD /* FIRServerValue.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRServerValue.h; path = FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRServerValue.h; sourceTree = ""; }; + 03E65604EC485B5893B33E6098B32451 /* Realm.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Realm.release.xcconfig; sourceTree = ""; }; + 043C226E59B26E794E9191331A864A5A /* FIRMultiFactorInfo+Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FIRMultiFactorInfo+Internal.h"; path = "FirebaseAuth/Sources/MultiFactor/FIRMultiFactorInfo+Internal.h"; sourceTree = ""; }; + 046758AD33D0FD687DD1AD08DD311250 /* SortDescriptor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SortDescriptor.swift; path = RealmSwift/SortDescriptor.swift; sourceTree = ""; }; + 04B8B77B56D977247170C592E6DE11B9 /* Pods-PRTYTests.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-PRTYTests.modulemap"; sourceTree = ""; }; + 04F3DD0C04BB7E1840D7DD9435C44113 /* FTupleBoolBlock.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTupleBoolBlock.h; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleBoolBlock.h; sourceTree = ""; }; + 050B6FE33817741C4489AF2856307BDB /* FBLPromise+Recover.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Recover.h"; path = "Sources/FBLPromises/include/FBLPromise+Recover.h"; sourceTree = ""; }; + 0573A17A7335B226B940471176B068EC /* FTupleSetIdPath.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTupleSetIdPath.m; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleSetIdPath.m; sourceTree = ""; }; + 05842D32365C92508821DBCFF24949FA /* FUtilities.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FUtilities.h; path = FirebaseDatabase/Sources/Utilities/FUtilities.h; sourceTree = ""; }; + 05B386CDC39EA631D1FAAA7D1F0AB45A /* dumpfile.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = dumpfile.cc; path = db/dumpfile.cc; sourceTree = ""; }; + 061851272BBE3FB093703FA3D36BBF67 /* RLMObjectId.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMObjectId.mm; path = Realm/RLMObjectId.mm; sourceTree = ""; }; + 06304D72C5C2F7A0DB5EC2BD2DBFBB12 /* FCacheNode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FCacheNode.h; path = FirebaseDatabase/Sources/Core/View/FCacheNode.h; sourceTree = ""; }; + 063CA7411C06AB807B4B631C3D730ABC /* FIRAuthDispatcher.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthDispatcher.h; path = FirebaseAuth/Sources/Auth/FIRAuthDispatcher.h; sourceTree = ""; }; + 06CD6D8F5E3BF730BDA839220939A8AA /* FIRFederatedAuthProvider.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRFederatedAuthProvider.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRFederatedAuthProvider.h; sourceTree = ""; }; + 06FC5C9CF96D60C50FCD47D339C91951 /* nanopb */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = nanopb; path = nanopb.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 06FE9F21A3BCFA3977FAEECD35474C42 /* GULNetwork.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULNetwork.h; path = GoogleUtilities/Network/Public/GoogleUtilities/GULNetwork.h; sourceTree = ""; }; + 071248C77545C00DFE9E8A50D439E7AA /* RLMError.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMError.mm; path = Realm/RLMError.mm; sourceTree = ""; }; + 0751FFB6348E774F561AA56090F02B8E /* FQueryParams.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FQueryParams.m; path = FirebaseDatabase/Sources/Core/FQueryParams.m; sourceTree = ""; }; + 075A5D7577CF5A3DC2EF3B7C5AB21F9C /* GULKeychainUtils.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULKeychainUtils.m; path = GoogleUtilities/Environment/SecureStorage/GULKeychainUtils.m; sourceTree = ""; }; + 077DD8E014A49337645CEFA1ED433797 /* FIRComponent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRComponent.h; path = FirebaseCore/Extension/FIRComponent.h; sourceTree = ""; }; + 0780A95F429DCE64484BDD78CBA3FE12 /* bloom.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = bloom.cc; path = util/bloom.cc; sourceTree = ""; }; + 07FFA32CF64DC17468EA57AF8C75CADF /* FIRAuthRequestConfiguration.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthRequestConfiguration.m; path = FirebaseAuth/Sources/Backend/FIRAuthRequestConfiguration.m; sourceTree = ""; }; + 0843F6B3C59457C07E690F4E361631E0 /* Pods-PRTYTests */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = "Pods-PRTYTests"; path = Pods_PRTYTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 086091EC6366134D5C0A260E2ABF57D5 /* Pods-PRTY-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-PRTY-frameworks.sh"; sourceTree = ""; }; + 0871B1AF60D0FA795C25D0BBC7A6B793 /* FIRUser.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRUser.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRUser.h; sourceTree = ""; }; + 09B54AFC23373B0CA6F8F53FCAFB8B94 /* version_set.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = version_set.cc; path = db/version_set.cc; sourceTree = ""; }; + 09BC0DF6DDAAB485732A09CE78733647 /* FRepoInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FRepoInfo.h; path = FirebaseDatabase/Sources/Core/FRepoInfo.h; sourceTree = ""; }; + 09F100EB4B62EBE83645C2D60ED1E078 /* FSRWebSocket.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FSRWebSocket.m; path = FirebaseDatabase/Sources/third_party/SocketRocket/FSRWebSocket.m; sourceTree = ""; }; + 0A03AE62123483BCC06367C075244AD8 /* FIRDatabaseQuery_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDatabaseQuery_Private.h; path = FirebaseDatabase/Sources/Api/Private/FIRDatabaseQuery_Private.h; sourceTree = ""; }; + 0A0CF7B9BAF15535F28A3BC045F60A22 /* FirebaseAppCheckInterop.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FirebaseAppCheckInterop.release.xcconfig; sourceTree = ""; }; + 0A3C948976000104C7FFE044C96214F8 /* FIRInstallationsLogger.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRInstallationsLogger.m; path = FirebaseInstallations/Source/Library/FIRInstallationsLogger.m; sourceTree = ""; }; + 0A6F710CD6390E3FBAEBC393A95FDAE0 /* FIRGetOOBConfirmationCodeRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRGetOOBConfirmationCodeRequest.h; path = FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeRequest.h; sourceTree = ""; }; + 0A9F46A999C47653013D3AD854352507 /* leveldb-library */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = "leveldb-library"; path = leveldb.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 0AA78A5FF346BDCCF63A27E56A597B97 /* FConnection.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FConnection.h; path = FirebaseDatabase/Sources/Realtime/FConnection.h; sourceTree = ""; }; + 0AC41380A652260C2B824C6DCD0D123B /* GULKeychainStorage.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULKeychainStorage.m; path = GoogleUtilities/Environment/SecureStorage/GULKeychainStorage.m; sourceTree = ""; }; + 0B9C0BA6C40683E28DD6831B3FC7E7F1 /* ObjcBridgeable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObjcBridgeable.swift; path = RealmSwift/Impl/ObjcBridgeable.swift; sourceTree = ""; }; + 0BFFC1CBABB5EE6979B7BB6454C1F606 /* filter_policy.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = filter_policy.cc; path = util/filter_policy.cc; sourceTree = ""; }; + 0C0AF19F9C4062998F561DD8F98DECE3 /* FSyncTree.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FSyncTree.h; path = FirebaseDatabase/Sources/Core/FSyncTree.h; sourceTree = ""; }; + 0C0CD8603C88F495D0C59CF44AB151EA /* RLMRealm+Sync.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "RLMRealm+Sync.h"; path = "include/RLMRealm+Sync.h"; sourceTree = ""; }; + 0C5F2659D020AEC57B6932441441E7E8 /* RLMConstants.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RLMConstants.m; path = Realm/RLMConstants.m; sourceTree = ""; }; + 0C642008350A5CF8DEB52E2325A396F1 /* RLMMongoClient.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMMongoClient.h; path = include/RLMMongoClient.h; sourceTree = ""; }; + 0C8C2F327B6662093A84BFDB0321BAFB /* FTupleObjects.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTupleObjects.h; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjects.h; sourceTree = ""; }; + 0C8F9D1F3278289794C00D2F8EC2D354 /* table_cache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = table_cache.h; path = db/table_cache.h; sourceTree = ""; }; + 0D53DBCD1D5DF2809E0E17C553BF1699 /* FIRComponentContainer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRComponentContainer.h; path = FirebaseCore/Extension/FIRComponentContainer.h; sourceTree = ""; }; + 0D5EB8A590366F66FC4D151DF662E315 /* Object.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Object.swift; path = RealmSwift/Object.swift; sourceTree = ""; }; + 0DD02532F284925CB1FC4D2E2108EEA7 /* RLMRealm.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMRealm.mm; path = Realm/RLMRealm.mm; sourceTree = ""; }; + 0DDE43AA7EDF5492F8787EF6723CE7D5 /* FIRPhoneMultiFactorInfo.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRPhoneMultiFactorInfo.m; path = FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorInfo.m; sourceTree = ""; }; + 0E15FA60DA659491727FFBFD46B27EB7 /* FWriteTreeRef.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FWriteTreeRef.h; path = FirebaseDatabase/Sources/Core/FWriteTreeRef.h; sourceTree = ""; }; + 0E5FD8D39CE43C6B9EF33E3B84B7C417 /* FIRAuthProtoMFAEnrollment.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthProtoMFAEnrollment.m; path = FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProtoMFAEnrollment.m; sourceTree = ""; }; + 0E66C7EAAF91F65896E6CC7C4A7B26F4 /* RLMUser_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMUser_Private.h; path = include/RLMUser_Private.h; sourceTree = ""; }; + 0F2F425451E6AF67F3E0D5654E90ED43 /* write_batch_internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = write_batch_internal.h; path = db/write_batch_internal.h; sourceTree = ""; }; + 0F75325E1AFCBB674768EAEE2D817261 /* FirebaseCore.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FirebaseCore.release.xcconfig; sourceTree = ""; }; + 0F7F3AFAE2A24AD030BDE0A544F117C8 /* FIRGameCenterAuthCredential.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRGameCenterAuthCredential.m; path = FirebaseAuth/Sources/AuthProvider/GameCenter/FIRGameCenterAuthCredential.m; sourceTree = ""; }; + 0F8DAE8DAB33858EC467E8C46A252F13 /* FirebaseAuth.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FirebaseAuth.debug.xcconfig; sourceTree = ""; }; + 0FB9ED5CC42FCE28A63013D90A0CE0E3 /* FIRMultiFactorConstants.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMultiFactorConstants.m; path = FirebaseAuth/Sources/MultiFactor/FIRMultiFactorConstants.m; sourceTree = ""; }; + 102E79069AA2B7FA312F4A307CAB61A3 /* FTrackedQueryManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTrackedQueryManager.m; path = FirebaseDatabase/Sources/Persistence/FTrackedQueryManager.m; sourceTree = ""; }; + 10310C29C4CC4CCC1AC43ECD64772E1C /* Results.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Results.swift; path = RealmSwift/Results.swift; sourceTree = ""; }; + 1051F740E13750B942A9EDA85AA602EE /* dbformat.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = dbformat.h; path = db/dbformat.h; sourceTree = ""; }; + 1082CC92F4A4AB1688B228846A11F83D /* FBLPromise.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBLPromise.m; path = Sources/FBLPromises/FBLPromise.m; sourceTree = ""; }; + 10AC127C6D153D12363D963E92010133 /* FView.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FView.m; path = FirebaseDatabase/Sources/Core/View/FView.m; sourceTree = ""; }; + 10D87030427938D0539D5DF4EC4032F1 /* FirebaseCore.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FirebaseCore.debug.xcconfig; sourceTree = ""; }; + 1100DABD72493AA08CE2AC79C1B6E19C /* GTMSessionUploadFetcher.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GTMSessionUploadFetcher.h; path = Sources/Core/Public/GTMSessionFetcher/GTMSessionUploadFetcher.h; sourceTree = ""; }; + 110E93ABDED0BDC603500CB52BB1E1E5 /* cache.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = cache.cc; path = util/cache.cc; sourceTree = ""; }; + 111F794074A676995CDDD8A9D7065800 /* iterator.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = iterator.cc; path = table/iterator.cc; sourceTree = ""; }; + 1152AD3AF12FA0DE0A46B04DA8CF3C57 /* GULNetworkConstants.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULNetworkConstants.m; path = GoogleUtilities/Network/GULNetworkConstants.m; sourceTree = ""; }; + 1153AA0F8C924E8939A0BE0804E5FEEA /* leveldb-library-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "leveldb-library-prefix.pch"; sourceTree = ""; }; + 1171CF5F6FD906DFE4F386B29FA61D56 /* FIRFirebaseUserAgent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRFirebaseUserAgent.m; path = FirebaseCore/Sources/FIRFirebaseUserAgent.m; sourceTree = ""; }; + 1173B352316565C062F130D6DF0B2D83 /* FBLPromise+Await.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Await.m"; path = "Sources/FBLPromises/FBLPromise+Await.m"; sourceTree = ""; }; + 1174004659514A219C0CDDF7066B18C2 /* FIRLogger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRLogger.h; path = FirebaseCore/Extension/FIRLogger.h; sourceTree = ""; }; + 118893944206EA50EB70686CFE24555F /* FConstants.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FConstants.h; path = FirebaseDatabase/Sources/Constants/FConstants.h; sourceTree = ""; }; + 120853B5C287EB6778D0E6F2CAAC678B /* RLMSchema_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMSchema_Private.h; path = include/RLMSchema_Private.h; sourceTree = ""; }; + 12229C986A2EE4B61CDA11875E871A84 /* FIRPhoneAuthCredential.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRPhoneAuthCredential.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthCredential.h; sourceTree = ""; }; + 122D962CA59AC2D4A82C5178BE4BE260 /* FBLPromise+Race.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Race.h"; path = "Sources/FBLPromises/include/FBLPromise+Race.h"; sourceTree = ""; }; + 125863111A1DBB3C7CB2752151C25750 /* FValueEventRegistration.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FValueEventRegistration.h; path = FirebaseDatabase/Sources/Core/View/FValueEventRegistration.h; sourceTree = ""; }; + 1291C14B3AB631F2898B2F8286A070FE /* FIRWithdrawMFAResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRWithdrawMFAResponse.m; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFAResponse.m; sourceTree = ""; }; + 135176A848ECF939C0716D13BD47BFDB /* RLMValue.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMValue.h; path = include/RLMValue.h; sourceTree = ""; }; + 136D4F7911367790110F5E9240A6FD95 /* testharness.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = testharness.h; path = util/testharness.h; sourceTree = ""; }; + 13C8C8B254851998F9289F71229B28A2 /* FirebaseInstallations */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = FirebaseInstallations; path = FirebaseInstallations.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 14313C746BD248B51B801D5D0EAB7816 /* FIREmailLinkSignInResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIREmailLinkSignInResponse.h; path = FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInResponse.h; sourceTree = ""; }; + 143EB88CB6BF32B3B92E745AED2B8D1F /* FIRVerifyAssertionResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRVerifyAssertionResponse.m; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.m; sourceTree = ""; }; + 148D0F9E8C7373FEAF40D800FC5F1BAA /* FirebaseCoreInternal */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = FirebaseCoreInternal; path = FirebaseCoreInternal.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 1490E33A780917C79C45E316672435C0 /* FListenComplete.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FListenComplete.h; path = FirebaseDatabase/Sources/FListenComplete.h; sourceTree = ""; }; + 14ED6C038781E8190323E214EB7F8D3E /* FBLPromise.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBLPromise.h; path = Sources/FBLPromises/include/FBLPromise.h; sourceTree = ""; }; + 1543F2502D4867CC79A5AFF5A5D871C7 /* version_set.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = version_set.h; path = db/version_set.h; sourceTree = ""; }; + 161AC9CABA773FA8567619A753121850 /* AsymmetricObject.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AsymmetricObject.swift; path = RealmSwift/AsymmetricObject.swift; sourceTree = ""; }; + 1678ACD8E0AF993C082BA2E26E5C9293 /* GULOriginalIMPConvenienceMacros.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULOriginalIMPConvenienceMacros.h; path = GoogleUtilities/MethodSwizzler/Public/GoogleUtilities/GULOriginalIMPConvenienceMacros.h; sourceTree = ""; }; + 16A61136124D22967767C62762E11781 /* FChildEventRegistration.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FChildEventRegistration.h; path = FirebaseDatabase/Sources/Core/View/FChildEventRegistration.h; sourceTree = ""; }; + 16ADD2871F8ACA2789A95C96B1F4FE19 /* FIRStartMFASignInResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRStartMFASignInResponse.m; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInResponse.m; sourceTree = ""; }; + 16FEB6A940B78555761BBE1CD7FF27F1 /* FirebaseCoreInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FirebaseCoreInternal.h; path = FirebaseCore/Extension/FirebaseCoreInternal.h; sourceTree = ""; }; + 171EC043E8C48B150D6C70B8D3C8551A /* RLMObjectBase_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMObjectBase_Private.h; path = include/RLMObjectBase_Private.h; sourceTree = ""; }; + 17586B39950BC2B022A340DD26D64DC0 /* FBLPromise+Testing.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Testing.m"; path = "Sources/FBLPromises/FBLPromise+Testing.m"; sourceTree = ""; }; + 176C38A32F80DAD2F58BA0865F64426A /* db_iter.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = db_iter.h; path = db/db_iter.h; sourceTree = ""; }; + 17848892389DEF304DC3D3D5F8B965A8 /* crc32c.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = crc32c.cc; path = util/crc32c.cc; sourceTree = ""; }; + 1799EDD01F3BDE8A78F8501A99E86879 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; }; + 186FA2D4398AA444253D80F690200E1D /* FIRGetOOBConfirmationCodeResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRGetOOBConfirmationCodeResponse.m; path = FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeResponse.m; sourceTree = ""; }; + 187AAB69D8B2FC133DAAA952E9154DAB /* FValueIndex.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FValueIndex.h; path = FirebaseDatabase/Sources/FValueIndex.h; sourceTree = ""; }; + 18957DF296CAB6C27B5D971F258E0A01 /* coding.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = coding.cc; path = util/coding.cc; sourceTree = ""; }; + 18B260C2BA6AF298BFDD66833B84A7CB /* FTrackedQuery.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTrackedQuery.h; path = FirebaseDatabase/Sources/Persistence/FTrackedQuery.h; sourceTree = ""; }; + 197274F76C7C01DC8B256E11BA3CA173 /* RealmConfiguration.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RealmConfiguration.swift; path = RealmSwift/RealmConfiguration.swift; sourceTree = ""; }; + 1A93BF76000E48D0F95A516E92CF28E8 /* FIRVerifyClientRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRVerifyClientRequest.h; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientRequest.h; sourceTree = ""; }; + 1A980800E710A010DF494004C96778B7 /* FIRDatabaseConfig.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRDatabaseConfig.m; path = FirebaseDatabase/Sources/Api/FIRDatabaseConfig.m; sourceTree = ""; }; + 1A9F68773EE5E52B4D5659917D69DBAF /* FIRAdditionalUserInfo_Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAdditionalUserInfo_Internal.h; path = FirebaseAuth/Sources/User/FIRAdditionalUserInfo_Internal.h; sourceTree = ""; }; + 1ADBEEDE93688F19E571CE7A74DE23AD /* GTMSessionFetcherLogging.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GTMSessionFetcherLogging.h; path = Sources/Core/Public/GTMSessionFetcher/GTMSessionFetcherLogging.h; sourceTree = ""; }; + 1ADF76418061CD96E158397CF9BB037B /* arena.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = arena.cc; path = util/arena.cc; sourceTree = ""; }; + 1B387526B9BE23AC791723076F4BBF0D /* FIRAuthBackend.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthBackend.m; path = FirebaseAuth/Sources/Backend/FIRAuthBackend.m; sourceTree = ""; }; + 1B5CA39A2CE71ED31A7A51A7DEE202E3 /* GoogleUtilities-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "GoogleUtilities-dummy.m"; sourceTree = ""; }; + 1B5E77D8721F5D8AC2DD4588444F3EFB /* FEmptyNode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FEmptyNode.h; path = FirebaseDatabase/Sources/Snapshot/FEmptyNode.h; sourceTree = ""; }; + 1B6E62F259BD798696AC28CA9B61D063 /* RLMSectionedResults.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMSectionedResults.mm; path = Realm/RLMSectionedResults.mm; sourceTree = ""; }; + 1BACF9688C6693A62406F49CBC73F486 /* FNode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FNode.h; path = FirebaseDatabase/Sources/Snapshot/FNode.h; sourceTree = ""; }; + 1BFC4F5515D28AA157359A2FE83628C6 /* FIRFinalizeMFAEnrollmentRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRFinalizeMFAEnrollmentRequest.h; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentRequest.h; sourceTree = ""; }; + 1C61B12ACA3E421895B038C2C363D156 /* FIndex.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIndex.h; path = FirebaseDatabase/Sources/FIndex.h; sourceTree = ""; }; + 1D347E1A64C9ADD432B01EE1CD0EF50B /* FSparseSnapshotTree.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FSparseSnapshotTree.m; path = FirebaseDatabase/Sources/Core/FSparseSnapshotTree.m; sourceTree = ""; }; + 1E32862F9DADC43AADD541E3708029A8 /* HeartbeatsPayload.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HeartbeatsPayload.swift; path = FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatsPayload.swift; sourceTree = ""; }; + 1E85C3D67C66233F215F077D5D4DBAFB /* FIRAuthNotificationManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthNotificationManager.m; path = FirebaseAuth/Sources/SystemService/FIRAuthNotificationManager.m; sourceTree = ""; }; + 1EC2C755F7459C7D17578604910BA6C9 /* FTupleUserCallback.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTupleUserCallback.m; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleUserCallback.m; sourceTree = ""; }; + 1F6EBB208A039BAD472B7CB6E7FBCFF4 /* Realm-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Realm-prefix.pch"; sourceTree = ""; }; + 1F849893A149318894D9DDDDDC9FABE5 /* FIRAppInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAppInternal.h; path = FirebaseCore/Extension/FIRAppInternal.h; sourceTree = ""; }; + 1FAA971A08BB9B6B11705EEE9B77BAD5 /* Pods-PRTY-PRTYUITests-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-PRTY-PRTYUITests-Info.plist"; sourceTree = ""; }; + 2035F5591F18DB561814028FE3726CF0 /* GULHeartbeatDateStorageUserDefaults.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULHeartbeatDateStorageUserDefaults.m; path = GoogleUtilities/Environment/GULHeartbeatDateStorageUserDefaults.m; sourceTree = ""; }; + 20527044548AD5FFF595A5E3278C7287 /* FIRAuthProtoFinalizeMFAPhoneResponseInfo.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthProtoFinalizeMFAPhoneResponseInfo.m; path = FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneResponseInfo.m; sourceTree = ""; }; + 2102618715F19E54D0AB8FB6593E0326 /* FIRAuthProtoFinalizeMFAPhoneRequestInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthProtoFinalizeMFAPhoneRequestInfo.h; path = FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneRequestInfo.h; sourceTree = ""; }; + 21F6C74565B78083660C443B41DC95DE /* FIRAuthRequestConfiguration.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthRequestConfiguration.h; path = FirebaseAuth/Sources/Backend/FIRAuthRequestConfiguration.h; sourceTree = ""; }; + 220EC7D8A2CB38340BCB87DDAF0166CD /* FIRFacebookAuthCredential.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRFacebookAuthCredential.m; path = FirebaseAuth/Sources/AuthProvider/Facebook/FIRFacebookAuthCredential.m; sourceTree = ""; }; + 221A1EC0D7C56B655A04DE2004063628 /* App.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = App.swift; path = RealmSwift/App.swift; sourceTree = ""; }; + 226C88C2143E230C84E42844AF62C9FC /* FIRAuthSerialTaskQueue.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthSerialTaskQueue.h; path = FirebaseAuth/Sources/Auth/FIRAuthSerialTaskQueue.h; sourceTree = ""; }; + 22876DDCA074830528A1B2A90E9096F6 /* FBLPromisePrivate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBLPromisePrivate.h; path = Sources/FBLPromises/include/FBLPromisePrivate.h; sourceTree = ""; }; + 2290A765CE084379675E2DAE6C691B8F /* RLMApp_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMApp_Private.h; path = include/RLMApp_Private.h; sourceTree = ""; }; + 229308366B6A55E8735EA3EB6903A228 /* realm-monorepo.xcframework */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = wrapper.xcframework; name = "realm-monorepo.xcframework"; path = "core/realm-monorepo.xcframework"; sourceTree = ""; }; + 2345425439383E6C98582C65C0981322 /* FAtomicNumber.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FAtomicNumber.h; path = FirebaseDatabase/Sources/Utilities/FAtomicNumber.h; sourceTree = ""; }; + 23A3F80698CEECE919C9E022F40AFC28 /* RLMAsymmetricObject.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMAsymmetricObject.h; path = include/RLMAsymmetricObject.h; sourceTree = ""; }; + 23DC2294E824B6B4F959947D89FE4AC0 /* FIRMultiFactor+Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FIRMultiFactor+Internal.h"; path = "FirebaseAuth/Sources/MultiFactor/FIRMultiFactor+Internal.h"; sourceTree = ""; }; + 23EAD188D4983631890D4FE0563517B6 /* GoogleAppMeasurement.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = GoogleAppMeasurement.release.xcconfig; sourceTree = ""; }; + 245479B0028A3B41D31BA76DE5EFC18E /* RLMAnalytics.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMAnalytics.mm; path = Realm/RLMAnalytics.mm; sourceTree = ""; }; + 24B4007499458D350361A99EE865BC30 /* FIRComponent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRComponent.m; path = FirebaseCore/Sources/FIRComponent.m; sourceTree = ""; }; + 24CF3FE9F1F63048BE73769786AA32FA /* CustomPersistable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CustomPersistable.swift; path = RealmSwift/CustomPersistable.swift; sourceTree = ""; }; + 24E342468348506C8B682D5206A317CE /* FIRInstallationsItem.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInstallationsItem.h; path = FirebaseInstallations/Source/Library/FIRInstallationsItem.h; sourceTree = ""; }; + 250E7EC04CADDFF718CBE2F2B949220D /* MutableSet.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MutableSet.swift; path = RealmSwift/MutableSet.swift; sourceTree = ""; }; + 251A0FACCAB61BF90F11AAC339D36587 /* FIRUser_Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRUser_Internal.h; path = FirebaseAuth/Sources/User/FIRUser_Internal.h; sourceTree = ""; }; + 25364FCE8A53D06CD550B641C415881F /* format.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = format.cc; path = table/format.cc; sourceTree = ""; }; + 2537AFF1FBBC4757A039581EF92AE608 /* FIndex.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIndex.m; path = FirebaseDatabase/Sources/FIndex.m; sourceTree = ""; }; + 254DFE40388CA77868691F69AC5F12D5 /* FirebaseCore-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "FirebaseCore-umbrella.h"; sourceTree = ""; }; + 255C5F38BC053F1E20A8E00981F2D825 /* FIRAuthOperationType.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthOperationType.h; path = FirebaseAuth/Sources/Auth/FIRAuthOperationType.h; sourceTree = ""; }; + 257F0A0FBD7080CADA3BD0EF0DAA0156 /* GULSceneDelegateSwizzler.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULSceneDelegateSwizzler.m; path = GoogleUtilities/AppDelegateSwizzler/GULSceneDelegateSwizzler.m; sourceTree = ""; }; + 25D51C61BBC33B3A91740F2EBF9B9F9B /* FIRMutableData.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMutableData.h; path = FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRMutableData.h; sourceTree = ""; }; + 260BA989E65D1B70F99F3F9464CD1115 /* RLMAsyncTask.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMAsyncTask.h; path = include/RLMAsyncTask.h; sourceTree = ""; }; + 266C617256AA4E2CB667A0F9044E7108 /* FPath.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FPath.h; path = FirebaseDatabase/Sources/Core/Utilities/FPath.h; sourceTree = ""; }; + 2710FEC0F62930F9443537F90F05D60F /* FBLPromise+Timeout.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Timeout.h"; path = "Sources/FBLPromises/include/FBLPromise+Timeout.h"; sourceTree = ""; }; + 272FB90054BCC4BB95316C5013FC9834 /* RLMSyncSubscription_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMSyncSubscription_Private.h; path = include/RLMSyncSubscription_Private.h; sourceTree = ""; }; + 276D23FD6D93BFC03B3E403333FC0C08 /* RLMManagedDictionary.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMManagedDictionary.mm; path = Realm/RLMManagedDictionary.mm; sourceTree = ""; }; + 277D8E8244D2FA29E1317FCC9FB6C696 /* RLMAccessor.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMAccessor.mm; path = Realm/RLMAccessor.mm; sourceTree = ""; }; + 27947EE5809D5134A30123C3BAD888C7 /* FirebaseInstallationsInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FirebaseInstallationsInternal.h; path = FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h; sourceTree = ""; }; + 27A49FDF138880BD7F33CD5008A47C15 /* GTMSessionFetcher-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "GTMSessionFetcher-dummy.m"; sourceTree = ""; }; + 27D5D30E3C0372FE553B522497F2D079 /* FirebaseAuth-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "FirebaseAuth-Info.plist"; sourceTree = ""; }; + 27ECFAE94F84C45208AF513C0E025E9D /* Schema.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Schema.swift; path = RealmSwift/Schema.swift; sourceTree = ""; }; + 2873E87EC61B34528E6E869AC2DCD567 /* FViewCache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FViewCache.h; path = FirebaseDatabase/Sources/Core/View/FViewCache.h; sourceTree = ""; }; + 287C36FAAEDA194E995524403501AB31 /* filter_block.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = filter_block.h; path = table/filter_block.h; sourceTree = ""; }; + 28BA89D03A923D6F3645E3792D7B6A85 /* FIRIdentityToolkitRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRIdentityToolkitRequest.h; path = FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h; sourceTree = ""; }; + 28F4C70F3E073FC6BA4014DBCBDFC33B /* FCacheNode.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FCacheNode.m; path = FirebaseDatabase/Sources/Core/View/FCacheNode.m; sourceTree = ""; }; + 2919608BB643C33E664256CA53BB95EB /* FIRAuthURLPresenter.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthURLPresenter.h; path = FirebaseAuth/Sources/Utilities/FIRAuthURLPresenter.h; sourceTree = ""; }; + 296BED686200C06B5795701FF3B5C0AB /* FIRDatabaseComponent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDatabaseComponent.h; path = FirebaseDatabase/Sources/Api/FIRDatabaseComponent.h; sourceTree = ""; }; + 29924CAAFCB95B7922AD14E3631630E1 /* merger.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = merger.cc; path = table/merger.cc; sourceTree = ""; }; + 29CBFE174016502905427BA7B5DBE044 /* RLMThreadSafeReference.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMThreadSafeReference.mm; path = Realm/RLMThreadSafeReference.mm; sourceTree = ""; }; + 2A0132002DAF9BF16D277AB0D0C07A5C /* FirebaseAuth-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "FirebaseAuth-umbrella.h"; sourceTree = ""; }; + 2A07B044EF3476E89A8934CBC290CDB2 /* FSparseSnapshotTree.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FSparseSnapshotTree.h; path = FirebaseDatabase/Sources/Core/FSparseSnapshotTree.h; sourceTree = ""; }; + 2A141BBDF00F68D384672D09E6C8D5CA /* FEmptyNode.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FEmptyNode.m; path = FirebaseDatabase/Sources/Snapshot/FEmptyNode.m; sourceTree = ""; }; + 2AAAEDE8E70C8C7420323BCE56CECD62 /* FAckUserWrite.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FAckUserWrite.m; path = FirebaseDatabase/Sources/Core/Operation/FAckUserWrite.m; sourceTree = ""; }; + 2B05E83977D207F6BE795A000530F88B /* FIRConfiguration.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRConfiguration.h; path = FirebaseCore/Sources/Public/FirebaseCore/FIRConfiguration.h; sourceTree = ""; }; + 2B1A9A9086F5222D113BD0D4C6521882 /* crc32c.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = crc32c.h; path = util/crc32c.h; sourceTree = ""; }; + 2B33ABC19D62233834F6D06F4927B557 /* FIRMultiFactorAssertion+Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FIRMultiFactorAssertion+Internal.h"; path = "FirebaseAuth/Sources/MultiFactor/FIRMultiFactorAssertion+Internal.h"; sourceTree = ""; }; + 2B3CB3DFA47B93EEDCE11386C1D23DFF /* FWriteTree.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FWriteTree.h; path = FirebaseDatabase/Sources/Core/FWriteTree.h; sourceTree = ""; }; + 2B5BF8D2317897E5636B6D098AAA376C /* RLMSyncManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMSyncManager.h; path = include/RLMSyncManager.h; sourceTree = ""; }; + 2B738DB0AE5FFD26E7118871882CA3F6 /* Pods-PRTY-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-PRTY-umbrella.h"; sourceTree = ""; }; + 2BD9A1C4D7C0E01F46C69DCB21ED00B1 /* Pods-PRTY-PRTYUITests-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-PRTY-PRTYUITests-acknowledgements.markdown"; sourceTree = ""; }; + 2BFD21803769DB6C353B3E8AB9C3D04C /* FIRFacebookAuthProvider.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRFacebookAuthProvider.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRFacebookAuthProvider.h; sourceTree = ""; }; + 2D0A7F15D7C1C5FAB85E7E8AAA2FED49 /* FIRAuthCredential.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthCredential.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthCredential.h; sourceTree = ""; }; + 2D47FAEFD73B473DF35243384BFA1770 /* FIRVerifyPhoneNumberResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRVerifyPhoneNumberResponse.h; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberResponse.h; sourceTree = ""; }; + 2D4B3FEF0D03F93C58C129DDF773C0AC /* FEventRaiser.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FEventRaiser.h; path = FirebaseDatabase/Sources/Core/View/FEventRaiser.h; sourceTree = ""; }; + 2DC9D589442044C7CA61657FE041213C /* FTrackedQuery.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTrackedQuery.m; path = FirebaseDatabase/Sources/Persistence/FTrackedQuery.m; sourceTree = ""; }; + 2E083BCD2610C9F8CD73B0B83C2A3252 /* RLMSupport.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RLMSupport.swift; path = Realm/Swift/RLMSupport.swift; sourceTree = ""; }; + 2E0B7881254469695A443E9B4ECCF474 /* FView.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FView.h; path = FirebaseDatabase/Sources/Core/View/FView.h; sourceTree = ""; }; + 2E46BC3A6CF1D9F1F138BD437FF6E7AA /* GTMSessionFetcherService+Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "GTMSessionFetcherService+Internal.h"; path = "Sources/Core/GTMSessionFetcherService+Internal.h"; sourceTree = ""; }; + 2E953C57A2C1A68306C9ADAEC68C1C99 /* Heartbeat.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Heartbeat.swift; path = FirebaseCore/Internal/Sources/HeartbeatLogging/Heartbeat.swift; sourceTree = ""; }; + 2EB81C3B8587730347BDC959EAAC9FA2 /* table_cache.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = table_cache.cc; path = db/table_cache.cc; sourceTree = ""; }; + 2EBF4EF9C2EBB9F4610CF7F1990756D8 /* FIRPhoneAuthCredential.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRPhoneAuthCredential.m; path = FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthCredential.m; sourceTree = ""; }; + 2EC642ED48C46A050E79A1F996755054 /* FIRDatabaseConnectionContextProvider.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRDatabaseConnectionContextProvider.m; path = FirebaseDatabase/Sources/Login/FIRDatabaseConnectionContextProvider.m; sourceTree = ""; }; + 2ECBE8E8556F51DD2D12C08DE1263BA9 /* GULMutableDictionary.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULMutableDictionary.m; path = GoogleUtilities/Network/GULMutableDictionary.m; sourceTree = ""; }; + 2ECCA115AD74D654B14B529508C64F3F /* FDataEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FDataEvent.m; path = FirebaseDatabase/Sources/Core/View/FDataEvent.m; sourceTree = ""; }; + 2F1F7E6A93AAEE1766B72ADAA3E6F62B /* ObjectiveCSupport.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObjectiveCSupport.swift; path = RealmSwift/ObjectiveCSupport.swift; sourceTree = ""; }; + 2F32604D42064F5693F0C5DD948F6D8D /* nanopb.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = nanopb.modulemap; sourceTree = ""; }; + 2F92B76E1A6A4787FF52794D225AEB7B /* FIRApp.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRApp.m; path = FirebaseCore/Sources/FIRApp.m; sourceTree = ""; }; + 2FBD192144F1B9FEFEB202A6CA259781 /* GTMSessionFetcherLogging.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GTMSessionFetcherLogging.m; path = Sources/Core/GTMSessionFetcherLogging.m; sourceTree = ""; }; + 2FFCE5665AD9B43DF0409F6A7B9C97B9 /* FIRAuthAppCredentialManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthAppCredentialManager.h; path = FirebaseAuth/Sources/SystemService/FIRAuthAppCredentialManager.h; sourceTree = ""; }; + 300EDAC88419BEDA22431274ECF54354 /* FIREmailAuthProvider.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIREmailAuthProvider.m; path = FirebaseAuth/Sources/AuthProvider/Email/FIREmailAuthProvider.m; sourceTree = ""; }; + 301C5C7EB56673BEA7FD351C9E864BD8 /* FIRAppInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAppInternal.h; path = FirebaseCore/Extension/FIRAppInternal.h; sourceTree = ""; }; + 301DBE1318BC044C84AA208FD606A887 /* FirebaseCoreInternal-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "FirebaseCoreInternal-Info.plist"; sourceTree = ""; }; + 3023B4F5DDD02CFF5B395E7F490D33CC /* FIRGetProjectConfigResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRGetProjectConfigResponse.h; path = FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigResponse.h; sourceTree = ""; }; + 303B6E98FABDA657EC15858154A04C4F /* FIRAppCheckTokenResultInterop.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAppCheckTokenResultInterop.h; path = FirebaseAppCheck/Interop/FIRAppCheckTokenResultInterop.h; sourceTree = ""; }; + 309FE736880C3235DF3887AA58B3C6CE /* FTupleObjectNode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTupleObjectNode.h; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjectNode.h; sourceTree = ""; }; + 30A03FE1790D4156F8F0C48C9824EE5F /* FBLPromise+Do.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Do.m"; path = "Sources/FBLPromises/FBLPromise+Do.m"; sourceTree = ""; }; + 31136171FDDC64178366CD0A6B113B84 /* List.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = List.swift; path = RealmSwift/List.swift; sourceTree = ""; }; + 312A6319AFA1D25F26944EE1A94437CC /* FEventGenerator.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FEventGenerator.h; path = FirebaseDatabase/Sources/FEventGenerator.h; sourceTree = ""; }; + 312C7C07B79F4877B8F6286D00F9C8E8 /* FIRSecureTokenService.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRSecureTokenService.m; path = FirebaseAuth/Sources/SystemService/FIRSecureTokenService.m; sourceTree = ""; }; + 3239ADF167FDB5AF1EC2F83F1F8DADD3 /* FIRSetAccountInfoResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRSetAccountInfoResponse.h; path = FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoResponse.h; sourceTree = ""; }; + 3244ADC01679A6C46E66783E3006820A /* FIRRevokeTokenRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRRevokeTokenRequest.h; path = FirebaseAuth/Sources/Backend/RPC/FIRRevokeTokenRequest.h; sourceTree = ""; }; + 324CE274DE272729DB6F10A4C8C8401A /* FEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FEvent.h; path = FirebaseDatabase/Sources/Core/View/FEvent.h; sourceTree = ""; }; + 3287B3FC8DE790FC3DCEC27D6BA1A7BB /* GULHeartbeatDateStorage.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULHeartbeatDateStorage.h; path = GoogleUtilities/Environment/Public/GoogleUtilities/GULHeartbeatDateStorage.h; sourceTree = ""; }; + 32B097528C97B06073D7C5C2098FC9BE /* leveldb-library-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "leveldb-library-Info.plist"; sourceTree = ""; }; + 32CCE9D44B7DBFAB4EC8193C9E7907EF /* FIRInstallationsIIDTokenStore.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInstallationsIIDTokenStore.h; path = FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDTokenStore.h; sourceTree = ""; }; + 32D3125925FAEC4F82BA1ED3FEDDF2EA /* FIRStartMFASignInRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStartMFASignInRequest.h; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInRequest.h; sourceTree = ""; }; + 32E4A9F082BFCABE2AD6B32D535E37D8 /* RealmCollectionImpl.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RealmCollectionImpl.swift; path = RealmSwift/Impl/RealmCollectionImpl.swift; sourceTree = ""; }; + 32EEA95F0D817AB69D4DD7990267512E /* FIRAuthProvider.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthProvider.m; path = FirebaseAuth/Sources/AuthProvider/FIRAuthProvider.m; sourceTree = ""; }; + 33057FA5EBAC487EC38B2C709F9F5DA6 /* FIRTwitterAuthProvider.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRTwitterAuthProvider.m; path = FirebaseAuth/Sources/AuthProvider/Twitter/FIRTwitterAuthProvider.m; sourceTree = ""; }; + 3347A1AB6546F0A3977529B8F199DC41 /* PromisesObjC */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = PromisesObjC; path = FBLPromises.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 335DF35A42C03B1C619B15E6AFA1D269 /* FIRAuthProtoStartMFAPhoneResponseInfo.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthProtoStartMFAPhoneResponseInfo.m; path = FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneResponseInfo.m; sourceTree = ""; }; + 3365BB0E589B36D213FB9E983F34EF99 /* FirebaseAuth-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "FirebaseAuth-dummy.m"; sourceTree = ""; }; + 338AECF668DCCB9C64EBE4A69BB6A954 /* FCompoundWrite.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FCompoundWrite.m; path = FirebaseDatabase/Sources/Snapshot/FCompoundWrite.m; sourceTree = ""; }; + 33996B996CB2DA56D97D8237737419AC /* FIRPhoneMultiFactorInfo+Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FIRPhoneMultiFactorInfo+Internal.h"; path = "FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorInfo+Internal.h"; sourceTree = ""; }; + 33F1B68B22D7FE9BC4BA619D1AB5F540 /* FKeepSyncedEventRegistration.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FKeepSyncedEventRegistration.m; path = FirebaseDatabase/Sources/Core/View/FKeepSyncedEventRegistration.m; sourceTree = ""; }; + 34182904E0E1E8C02F312847B25E4418 /* FTreeNode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTreeNode.h; path = FirebaseDatabase/Sources/Core/Utilities/FTreeNode.h; sourceTree = ""; }; + 344E6FEA72D17152155F2C9C6C56CA92 /* FIREmailPasswordAuthCredential.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIREmailPasswordAuthCredential.m; path = FirebaseAuth/Sources/AuthProvider/Email/FIREmailPasswordAuthCredential.m; sourceTree = ""; }; + 3463F8E9265223FD78A8E353D9DBC93A /* FCachePolicy.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FCachePolicy.h; path = FirebaseDatabase/Sources/Persistence/FCachePolicy.h; sourceTree = ""; }; + 34BB5F58F426BDBCA59A72E52B095E95 /* FIRAuthProtoFinalizeMFAPhoneResponseInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthProtoFinalizeMFAPhoneResponseInfo.h; path = FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneResponseInfo.h; sourceTree = ""; }; + 34D0DBBFFAC44D74581C242E052AFB80 /* FIRAuthStoredUserManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthStoredUserManager.m; path = FirebaseAuth/Sources/SystemService/FIRAuthStoredUserManager.m; sourceTree = ""; }; + 34DE85D047CC7AE8971A383A422D922B /* RLMUserAPIKey.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMUserAPIKey.h; path = include/RLMUserAPIKey.h; sourceTree = ""; }; + 35106334CFDB44A3BF401053F4AB5332 /* FChildrenNode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FChildrenNode.h; path = FirebaseDatabase/Sources/Snapshot/FChildrenNode.h; sourceTree = ""; }; + 35220F076E37D3FB4AEFB242DBB9DA87 /* FWriteRecord.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FWriteRecord.h; path = FirebaseDatabase/Sources/Core/FWriteRecord.h; sourceTree = ""; }; + 3535D8C2C242A80EFE2003ADDADD8EB2 /* RLMUUID.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMUUID.mm; path = Realm/RLMUUID.mm; sourceTree = ""; }; + 356FA68C30464A29EB11FD7CA7521327 /* FIRAuthTokenResult.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthTokenResult.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthTokenResult.h; sourceTree = ""; }; + 3590D9904E6E3BCACBF1085443FE45FD /* FParsedUrl.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FParsedUrl.m; path = FirebaseDatabase/Sources/Utilities/FParsedUrl.m; sourceTree = ""; }; + 35C5CA813B56606F6856DDAC7EC3B552 /* port_example.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = port_example.h; path = port/port_example.h; sourceTree = ""; }; + 35CB08C83459BF6C53FCF704A67647D6 /* block_builder.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = block_builder.cc; path = table/block_builder.cc; sourceTree = ""; }; + 35D13F140D3BA97AA0F59CD6D0185A2F /* FIRDeleteAccountResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRDeleteAccountResponse.m; path = FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountResponse.m; sourceTree = ""; }; + 35E2E52AD208369569D961888AD2CD8E /* FTupleNodePath.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTupleNodePath.h; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleNodePath.h; sourceTree = ""; }; + 35E3F5B427B2657E3077368D97033BB2 /* FIRSignInWithGameCenterResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRSignInWithGameCenterResponse.m; path = FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterResponse.m; sourceTree = ""; }; + 35EBFFB02004349994925EC963A01894 /* FIRComponentType.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRComponentType.m; path = FirebaseCore/Sources/FIRComponentType.m; sourceTree = ""; }; + 35F20F6EE823992F00BCEBD34542EF0A /* FKeepSyncedEventRegistration.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FKeepSyncedEventRegistration.h; path = FirebaseDatabase/Sources/Core/View/FKeepSyncedEventRegistration.h; sourceTree = ""; }; + 360BEAE8353C4A0D3D79A704073FB4D5 /* FIRRevokeTokenRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRRevokeTokenRequest.m; path = FirebaseAuth/Sources/Backend/RPC/FIRRevokeTokenRequest.m; sourceTree = ""; }; + 360D283782E2F70E29346574623B578D /* FIRGetAccountInfoRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRGetAccountInfoRequest.h; path = FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoRequest.h; sourceTree = ""; }; + 36C43AC2291B2B1D31742EF42B3BFB6D /* FIRVerifyClientResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRVerifyClientResponse.h; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientResponse.h; sourceTree = ""; }; + 36DA0CC9E409501529A53ABC8F6AA4C9 /* GTMSessionFetcher.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = GTMSessionFetcher.modulemap; sourceTree = ""; }; + 37151480117365DF172C5574B6D0651C /* FNextPushId.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FNextPushId.h; path = FirebaseDatabase/Sources/Utilities/FNextPushId.h; sourceTree = ""; }; + 38C820D1FF6FACD317F69B7822D4B160 /* FIRAuthDefaultUIDelegate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthDefaultUIDelegate.h; path = FirebaseAuth/Sources/Utilities/FIRAuthDefaultUIDelegate.h; sourceTree = ""; }; + 3939D097FA2B064D8642167CB9C80243 /* FIRAuthAPNSTokenManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthAPNSTokenManager.m; path = FirebaseAuth/Sources/SystemService/FIRAuthAPNSTokenManager.m; sourceTree = ""; }; + 39B09EB68575118947CED1CC6D6C471F /* RealmSwift-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "RealmSwift-Info.plist"; sourceTree = ""; }; + 39B4A3F4F9FF7842FA2A7D4F246719A3 /* FIRAuthErrorUtils.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthErrorUtils.h; path = FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h; sourceTree = ""; }; + 39B4FEB4B3B91D6CDE38132BAB3BEE14 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/CFNetwork.framework; sourceTree = DEVELOPER_DIR; }; + 3A18DE4B7A84F362E93E76BCAB3882E7 /* FirebaseAppCheckInterop-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "FirebaseAppCheckInterop-dummy.m"; sourceTree = ""; }; + 3A337A8352740590C160918A1CC6B71B /* FRepo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FRepo.h; path = FirebaseDatabase/Sources/Core/FRepo.h; sourceTree = ""; }; + 3A82FDA5AE234681E92A4CF13D383368 /* ComplexTypes.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ComplexTypes.swift; path = RealmSwift/Impl/ComplexTypes.swift; sourceTree = ""; }; + 3ACA02065590E1AFEA516EA287B96AE9 /* FIRVerifyCustomTokenRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRVerifyCustomTokenRequest.h; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenRequest.h; sourceTree = ""; }; + 3B2DC0C4DFDB5B772B4F9B1EB97645E7 /* RLMUser.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMUser.h; path = include/RLMUser.h; sourceTree = ""; }; + 3B54381D354957163C76271AA6E11ADA /* FIRPhoneMultiFactorGenerator.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRPhoneMultiFactorGenerator.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorGenerator.h; sourceTree = ""; }; + 3B81F7B757D1B962385B509729E603BD /* APLevelDB.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = APLevelDB.mm; path = "FirebaseDatabase/Sources/third_party/Wrap-leveldb/APLevelDB.mm"; sourceTree = ""; }; + 3BA23E086F9B885781704FCA48B4BE17 /* FRangeMerge.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FRangeMerge.h; path = FirebaseDatabase/Sources/Core/FRangeMerge.h; sourceTree = ""; }; + 3BD63FE4290CDD7BAC1946490F265016 /* FIRAuthInterop.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthInterop.h; path = FirebaseAuth/Interop/FIRAuthInterop.h; sourceTree = ""; }; + 3C428F6C9EE7CA9AAF79DA85A514B14A /* pb.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = pb.h; sourceTree = ""; }; + 3C4C5034116D73230351A85353B11BBB /* FRepo.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FRepo.m; path = FirebaseDatabase/Sources/Core/FRepo.m; sourceTree = ""; }; + 3CF270CB5CBFFE011E21EF25448B9646 /* RLMObjectBase_Dynamic.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMObjectBase_Dynamic.h; path = include/RLMObjectBase_Dynamic.h; sourceTree = ""; }; + 3CFE28636C71B865952B8CBA130E29DE /* Persistable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Persistable.swift; path = RealmSwift/Impl/Persistable.swift; sourceTree = ""; }; + 3D1D1CE6B410E1BCE80346A09E546722 /* dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = dummy.m; path = FirebaseAppCheck/Interop/dummy.m; sourceTree = ""; }; + 3D27EA86C69966574F1E107D04DEE758 /* FIRAuthUserDefaults.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthUserDefaults.m; path = FirebaseAuth/Sources/Storage/FIRAuthUserDefaults.m; sourceTree = ""; }; + 3D4E6BB1FEF2DF20718587A7EE8B8918 /* FTupleStringNode.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTupleStringNode.m; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleStringNode.m; sourceTree = ""; }; + 3D63A41B92013D355B257E784C3C5D2E /* FIRInstallationsErrorUtil.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInstallationsErrorUtil.h; path = FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h; sourceTree = ""; }; + 3D6DEDD58747685647800F21525DEFC8 /* RLMRealmConfiguration_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMRealmConfiguration_Private.h; path = include/RLMRealmConfiguration_Private.h; sourceTree = ""; }; + 3DD63AD9A2170EA8DA1F0CED800B448C /* FIRDatabaseReference_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDatabaseReference_Private.h; path = FirebaseDatabase/Sources/Api/Private/FIRDatabaseReference_Private.h; sourceTree = ""; }; + 3DDFE294FE513102A9E25C7407AD8DC4 /* Pods-PRTY-PRTYUITests-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-PRTY-PRTYUITests-acknowledgements.plist"; sourceTree = ""; }; + 3E3B8F36375EA3714EC52956048A32C4 /* histogram.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = histogram.cc; path = util/histogram.cc; sourceTree = ""; }; + 3F2603FE06201768EBAC5948FD708988 /* Pods-PRTYTests-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-PRTYTests-acknowledgements.plist"; sourceTree = ""; }; + 3F37469C8502B8AA3CAD193EF4D56E93 /* FIRAuthProtoMFAEnrollment.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthProtoMFAEnrollment.h; path = FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProtoMFAEnrollment.h; sourceTree = ""; }; + 3F3D7C8AA04555304F587C2EE131762B /* FIRAuthInternalErrors.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthInternalErrors.h; path = FirebaseAuth/Sources/Utilities/FIRAuthInternalErrors.h; sourceTree = ""; }; + 3F4580980FFA6C2CB244BCD3B8BFDE2E /* FIRGitHubAuthProvider.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRGitHubAuthProvider.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRGitHubAuthProvider.h; sourceTree = ""; }; + 3FD194CD3A55CB5AEBE27BCD94D10206 /* FIRGetOOBConfirmationCodeRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRGetOOBConfirmationCodeRequest.m; path = FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeRequest.m; sourceTree = ""; }; + 3FF0C7E3C42C45A71B34F4F0C942A1A7 /* FIRDatabaseConnectionContextProvider.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDatabaseConnectionContextProvider.h; path = FirebaseDatabase/Sources/Login/FIRDatabaseConnectionContextProvider.h; sourceTree = ""; }; + 400F42C6868B6D5EB4B6C01B3A312F5E /* FirebaseCoreInternal.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FirebaseCoreInternal.release.xcconfig; sourceTree = ""; }; + 4017654FAE4B47AA0C9B3F842A344DE0 /* RLMArray.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMArray.mm; path = Realm/RLMArray.mm; sourceTree = ""; }; + 40538536D8C20ED7DA137A5713BB459A /* NSError+RLMSync.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "NSError+RLMSync.h"; path = "include/NSError+RLMSync.h"; sourceTree = ""; }; + 408F5AC132654E114CB2C4642531A12A /* FIRVerifyAssertionRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRVerifyAssertionRequest.m; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.m; sourceTree = ""; }; + 40AA7B7AA35DA6F3567044AE67EC3AE3 /* FIRCurrentDateProvider.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRCurrentDateProvider.m; path = FirebaseInstallations/Source/Library/InstallationsIDController/FIRCurrentDateProvider.m; sourceTree = ""; }; + 4166FCADAD4D4FD1E59EC390EF82F247 /* FIRGameCenterAuthCredential.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRGameCenterAuthCredential.h; path = FirebaseAuth/Sources/AuthProvider/GameCenter/FIRGameCenterAuthCredential.h; sourceTree = ""; }; + 41F5A37DA149DDD896A9588F912417F8 /* RLMSwiftValueStorage.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMSwiftValueStorage.mm; path = Realm/RLMSwiftValueStorage.mm; sourceTree = ""; }; + 4235F9BE23198AFAE32EBEA9B32A5C18 /* ObjectiveCSupport+BSON.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ObjectiveCSupport+BSON.swift"; path = "RealmSwift/ObjectiveCSupport+BSON.swift"; sourceTree = ""; }; + 424182B01E8972FF03D5A9E050282B58 /* FirebaseCoreInternal.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = FirebaseCoreInternal.modulemap; sourceTree = ""; }; + 4299C7EE17ED3C5658CD46D929754564 /* Error.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Error.swift; path = RealmSwift/Error.swift; sourceTree = ""; }; + 42E37BEF1DB058A22126DEAE325C8DB8 /* FIRDatabaseReference.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRDatabaseReference.m; path = FirebaseDatabase/Sources/FIRDatabaseReference.m; sourceTree = ""; }; + 43100CB1F7F8A6943C13D8F0BFD868C0 /* FIRConfiguration.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRConfiguration.m; path = FirebaseCore/Sources/FIRConfiguration.m; sourceTree = ""; }; + 4310F18485AEFC94D8688C3A803C350B /* FCancelEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FCancelEvent.h; path = FirebaseDatabase/Sources/Core/View/FCancelEvent.h; sourceTree = ""; }; + 434FF72C1B06DAFDF7A6F2F790AACEBC /* FIRComponentType.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRComponentType.h; path = FirebaseCore/Extension/FIRComponentType.h; sourceTree = ""; }; + 437919EE08EC6BFCCBAC3BD346309742 /* RealmSwift */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = RealmSwift; path = RealmSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 43B1E4CD7B30B9FD278100133C2AC788 /* FirebaseAuth */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = FirebaseAuth; path = FirebaseAuth.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 43D14090369EEC01BE508BDB88EB84F8 /* RLMSchema.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMSchema.mm; path = Realm/RLMSchema.mm; sourceTree = ""; }; + 44140A47AA4C978E372460E01A273CAE /* Projection.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Projection.swift; path = RealmSwift/Projection.swift; sourceTree = ""; }; + 443669EB0193E1FDA50EE1B7C683DA16 /* write_batch.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = write_batch.cc; path = db/write_batch.cc; sourceTree = ""; }; + 4439B26A132B0978E10DE975AF9F2E70 /* Query.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Query.swift; path = RealmSwift/Query.swift; sourceTree = ""; }; + 447DCBE2B1131BC09AED15BD4E7E6C38 /* GULNetworkMessageCode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULNetworkMessageCode.h; path = GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkMessageCode.h; sourceTree = ""; }; + 447F7001F40D564009C8A48A4B7801EA /* FIRGetAccountInfoRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRGetAccountInfoRequest.m; path = FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoRequest.m; sourceTree = ""; }; + 4480D3ADCD279112EAF94738881E3C65 /* FIRPhoneMultiFactorAssertion+Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FIRPhoneMultiFactorAssertion+Internal.h"; path = "FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorAssertion+Internal.h"; sourceTree = ""; }; + 448F758E8949F357C24A8E3D4F0EE6E2 /* RLMDictionary.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMDictionary.h; path = include/RLMDictionary.h; sourceTree = ""; }; + 44A73C4C6CD01197814C4A8D7D9B1E04 /* Pods-PRTY-PRTYUITests.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-PRTY-PRTYUITests.modulemap"; sourceTree = ""; }; + 44DFA81BB6A42907B0617316BF7476AA /* version_edit.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = version_edit.h; path = db/version_edit.h; sourceTree = ""; }; + 44FFEBF653DCAA7740DA6A359B3DAC77 /* FBLPromises.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBLPromises.h; path = Sources/FBLPromises/include/FBLPromises.h; sourceTree = ""; }; + 454A4F6087FFA109E2BAAD2E3244848F /* RLMSyncSession.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMSyncSession.h; path = include/RLMSyncSession.h; sourceTree = ""; }; + 458BC4E3C00864D5B96FB2C89BE7DED9 /* leveldb-library-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "leveldb-library-dummy.m"; sourceTree = ""; }; + 45DCCB0A7A912B2851D96ECE76C3B6D4 /* FLLRBNode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FLLRBNode.h; path = FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBNode.h; sourceTree = ""; }; + 463CDBD457E0FB4C4ACD2D2BFE1862BE /* RLMMigration.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMMigration.mm; path = Realm/RLMMigration.mm; sourceTree = ""; }; + 4666F2D0D35E201F414EBF12BB1B75AC /* FIRAuthSettings.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthSettings.m; path = FirebaseAuth/Sources/Auth/FIRAuthSettings.m; sourceTree = ""; }; + 46B0CA64A596FDBA487EC8BF5923246E /* FIRInstallationsStatus.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInstallationsStatus.h; path = FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsStatus.h; sourceTree = ""; }; + 46C5E75CF6F0B997F9A910E919A5E1D7 /* FirebaseDatabase.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FirebaseDatabase.debug.xcconfig; sourceTree = ""; }; + 46F03E9D37DE03046046D67857D32E74 /* RLMAPIKeyAuth.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMAPIKeyAuth.mm; path = Realm/RLMAPIKeyAuth.mm; sourceTree = ""; }; + 47384AF77CA4509C7238A8A3B5F9D3C1 /* FIRAuthKeychainServices.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthKeychainServices.m; path = FirebaseAuth/Sources/Storage/FIRAuthKeychainServices.m; sourceTree = ""; }; + 473C88C5429C1D64A09BB61AB8CF96B8 /* FBLPromise+Any.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Any.h"; path = "Sources/FBLPromises/include/FBLPromise+Any.h"; sourceTree = ""; }; + 4785776E6B04F0C704ED408714796CCC /* FIRTwitterAuthCredential.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRTwitterAuthCredential.h; path = FirebaseAuth/Sources/AuthProvider/Twitter/FIRTwitterAuthCredential.h; sourceTree = ""; }; + 4831343EA0DCD89549053AB1F3C335F9 /* RLMFindOneAndModifyOptions.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMFindOneAndModifyOptions.h; path = include/RLMFindOneAndModifyOptions.h; sourceTree = ""; }; + 483DD8D3B583073CED182ABC65E08237 /* FirebaseAnalytics-xcframeworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "FirebaseAnalytics-xcframeworks.sh"; sourceTree = ""; }; + 48D7907809830F1F47820F035D74C78D /* RLMMongoCollection.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMMongoCollection.mm; path = Realm/RLMMongoCollection.mm; sourceTree = ""; }; + 48F42BAA7BEB6F1D7FB7708D9D26470E /* FBLPromise+Delay.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Delay.h"; path = "Sources/FBLPromises/include/FBLPromise+Delay.h"; sourceTree = ""; }; + 4972477850A41A9D9B673C96DEF4168A /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; }; + 49CEB01CF98BF899E526EC7692849F4B /* FTupleTransaction.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTupleTransaction.h; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleTransaction.h; sourceTree = ""; }; + 4A3490944EAFC2F4D1E10697E776D942 /* Property.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Property.swift; path = RealmSwift/Property.swift; sourceTree = ""; }; + 4A65A260D5E743AF8EF26E0EC4DBB9CA /* posix_logger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = posix_logger.h; path = util/posix_logger.h; sourceTree = ""; }; + 4B30B908533087573BAB4A4DBFAB691D /* FIRDataEventType.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDataEventType.h; path = FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDataEventType.h; sourceTree = ""; }; + 4B39E52B0C608DB97C5C4253CF1DF99E /* block.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = block.cc; path = table/block.cc; sourceTree = ""; }; + 4B62A1EFF65D0F7A6EDC00FAB049E14E /* FIRDatabaseConfig.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDatabaseConfig.h; path = FirebaseDatabase/Sources/Api/FIRDatabaseConfig.h; sourceTree = ""; }; + 4BFFCDC8875646C24A0AA7F7C16EAADF /* FIRVerifyCustomTokenRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRVerifyCustomTokenRequest.m; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenRequest.m; sourceTree = ""; }; + 4C38BC7996475558BC1B0527BC88087F /* FIRSendVerificationCodeResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRSendVerificationCodeResponse.h; path = FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeResponse.h; sourceTree = ""; }; + 4C4A0D72C0FDAD19E451C2E21BA93B3A /* RLMRealmConfiguration.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMRealmConfiguration.h; path = include/RLMRealmConfiguration.h; sourceTree = ""; }; + 4C8C68A38AE16BAFA716CDBF9740AAEE /* FIRAuthDefaultUIDelegate.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthDefaultUIDelegate.m; path = FirebaseAuth/Sources/Utilities/FIRAuthDefaultUIDelegate.m; sourceTree = ""; }; + 4CBCF5236A1C6D972EB1E9825C24568D /* RLMSet.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMSet.h; path = include/RLMSet.h; sourceTree = ""; }; + 4DA65E275D60CAA4E6577D4B0C1A9DBE /* FIRComponent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRComponent.h; path = FirebaseCore/Extension/FIRComponent.h; sourceTree = ""; }; + 4DAAF670A3A48BEC4510C5D248BC666C /* FirebaseCoreInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FirebaseCoreInternal.h; path = FirebaseCore/Extension/FirebaseCoreInternal.h; sourceTree = ""; }; + 4DB1A365BD7D10214DD2C7AE73A31366 /* block_builder.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = block_builder.h; path = table/block_builder.h; sourceTree = ""; }; + 4E026AD30098E7501DEFA64FA8A2B8BF /* FIRInstallationsAPIService.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInstallationsAPIService.h; path = FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsAPIService.h; sourceTree = ""; }; + 4E4C5C96B5A1265FA9FC149C8C91EC87 /* FIRVerifyPasswordResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRVerifyPasswordResponse.m; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordResponse.m; sourceTree = ""; }; + 4EA5A35B9693996DBF681BB5E4ED3AB9 /* FIROAuthCredential_Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIROAuthCredential_Internal.h; path = FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthCredential_Internal.h; sourceTree = ""; }; + 4F08C4B9A5E6AFBA8D2DDDA90493AB07 /* HeartbeatStorage.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HeartbeatStorage.swift; path = FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatStorage.swift; sourceTree = ""; }; + 4F4AE0B2518B127D5CFD6A229F918FBE /* FIRInstallationsHTTPError.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRInstallationsHTTPError.m; path = FirebaseInstallations/Source/Library/Errors/FIRInstallationsHTTPError.m; sourceTree = ""; }; + 4F8113D296393D094DD639A535F9873C /* log_writer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = log_writer.h; path = db/log_writer.h; sourceTree = ""; }; + 4FA2B79F663A9D69D6E613EB25A6F2BE /* FirebaseAuth.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FirebaseAuth.release.xcconfig; sourceTree = ""; }; + 4FA3F6838DFFAA39E5B72EDDD953DACE /* GoogleAppMeasurement-xcframeworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "GoogleAppMeasurement-xcframeworks.sh"; sourceTree = ""; }; + 4FF91AFC3D4E8D5DDE6F76B436ADF093 /* FIRSecureTokenResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRSecureTokenResponse.m; path = FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenResponse.m; sourceTree = ""; }; + 501133B694FC9229BA3E4B89DA7124DC /* RLMEvent.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMEvent.mm; path = Realm/RLMEvent.mm; sourceTree = ""; }; + 5026DF9D418AC9740AF4DC88D58E0F34 /* FUtilities.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FUtilities.m; path = FirebaseDatabase/Sources/Utilities/FUtilities.m; sourceTree = ""; }; + 50371EE0D5E9B68064DD3B94892A83DD /* RLMObservation.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMObservation.mm; path = Realm/RLMObservation.mm; sourceTree = ""; }; + 50394C30904748E456D4C35922B549B3 /* cache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = cache.h; path = include/leveldb/cache.h; sourceTree = ""; }; + 5071D4D3329AB8550000CC07BE36AFAB /* CollectionAccess.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CollectionAccess.swift; path = RealmSwift/Impl/CollectionAccess.swift; sourceTree = ""; }; + 507728C48E9B69D1D56C13D2301CDB10 /* FEventRaiser.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FEventRaiser.m; path = FirebaseDatabase/Sources/Core/View/FEventRaiser.m; sourceTree = ""; }; + 51671C73F008B5C0C3751B3855999213 /* FirebaseDatabase */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = FirebaseDatabase; path = FirebaseDatabase.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 5185F33603CDA2B68194411E0A8EE5FC /* FIRMultiFactor.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMultiFactor.m; path = FirebaseAuth/Sources/MultiFactor/FIRMultiFactor.m; sourceTree = ""; }; + 520F17A85613DE207C7D040EBDD6F8BD /* FIRStartMFAEnrollmentRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRStartMFAEnrollmentRequest.m; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentRequest.m; sourceTree = ""; }; + 5218979E6A5F407F3CEDFE2821715668 /* FIRLibrary.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRLibrary.h; path = FirebaseCore/Extension/FIRLibrary.h; sourceTree = ""; }; + 5273EDBC2A77E71FC4220D15FFD2AC31 /* FSRWebSocket.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FSRWebSocket.h; path = FirebaseDatabase/Sources/third_party/SocketRocket/FSRWebSocket.h; sourceTree = ""; }; + 52B4AA8267619A715F34030E9D7C8DAF /* FListenProvider.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FListenProvider.h; path = FirebaseDatabase/Sources/Core/FListenProvider.h; sourceTree = ""; }; + 52E34EC8AAB1C8662FC59D8A62F2E08E /* FirebaseCoreInternal-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "FirebaseCoreInternal-umbrella.h"; sourceTree = ""; }; + 5316165368ABB6512CB6E082B4E2B9C3 /* Pods-PRTYTests-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-PRTYTests-umbrella.h"; sourceTree = ""; }; + 534282AC766172E1738511BDA8F27B1F /* KeyPathStrings.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = KeyPathStrings.swift; path = RealmSwift/Impl/KeyPathStrings.swift; sourceTree = ""; }; + 53F22C31C4648F4E4371ADD62CFCE32C /* FirebaseAnalytics.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FirebaseAnalytics.release.xcconfig; sourceTree = ""; }; + 542B20DEA26B5C074039A87247015DEF /* GULReachabilityChecker.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULReachabilityChecker.m; path = GoogleUtilities/Reachability/GULReachabilityChecker.m; sourceTree = ""; }; + 542FC53B9E7ABA035BA8484DB8D865D7 /* ObjectId.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObjectId.swift; path = RealmSwift/ObjectId.swift; sourceTree = ""; }; + 54DCA8704F0B3CA00373C0DC084CB440 /* GoogleAppMeasurement.xcframework */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = wrapper.xcframework; name = GoogleAppMeasurement.xcframework; path = Frameworks/GoogleAppMeasurement.xcframework; sourceTree = ""; }; + 5506F3E5AA24EDAAE83D9798B944122C /* BasicTypes.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BasicTypes.swift; path = RealmSwift/Impl/BasicTypes.swift; sourceTree = ""; }; + 555B74707E9153148A9CDBFB9095395D /* Realm.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Realm.debug.xcconfig; sourceTree = ""; }; + 55828DC9C361221F1C6E3554B9703949 /* FIRGetAccountInfoResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRGetAccountInfoResponse.m; path = FirebaseAuth/Sources/Backend/RPC/FIRGetAccountInfoResponse.m; sourceTree = ""; }; + 55971155657172B3C8EE36661224A4CF /* RLMObjectSchema.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMObjectSchema.h; path = include/RLMObjectSchema.h; sourceTree = ""; }; + 55FF929E3B066C69F518521636DBA3DA /* FTupleRemovedQueriesEvents.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTupleRemovedQueriesEvents.h; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleRemovedQueriesEvents.h; sourceTree = ""; }; + 56627901A29601B454E5A4D76045BF54 /* FIRComponentContainer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRComponentContainer.h; path = FirebaseCore/Extension/FIRComponentContainer.h; sourceTree = ""; }; + 56824B248662C8E8C141F005C41977B9 /* format.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = format.h; path = table/format.h; sourceTree = ""; }; + 56D7C61A84BD3126201E1B693272E5A8 /* FStringUtilities.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FStringUtilities.m; path = FirebaseDatabase/Sources/Utilities/FStringUtilities.m; sourceTree = ""; }; + 56DA4B923BA10A0AFF4CBCE4257C2480 /* FIRAdditionalUserInfo.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAdditionalUserInfo.m; path = FirebaseAuth/Sources/User/FIRAdditionalUserInfo.m; sourceTree = ""; }; + 5706AC95CB4140FC7CEF869802B2B37A /* FIRAuthGlobalWorkQueue.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthGlobalWorkQueue.m; path = FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.m; sourceTree = ""; }; + 5727B0661FF05A9D9CB986B6E82760FB /* FIRAuthCredential.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthCredential.m; path = FirebaseAuth/Sources/AuthProvider/FIRAuthCredential.m; sourceTree = ""; }; + 578E1B6E76DDE67CFCDF713FC4016967 /* Pods-PRTY */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = "Pods-PRTY"; path = Pods_PRTY.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 57AA2F599A51760A591158FC670C1F2B /* RLMLogger_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMLogger_Private.h; path = include/RLMLogger_Private.h; sourceTree = ""; }; + 57D22D4FC5A856CAA41A5E4B0378EB49 /* histogram.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = histogram.h; path = util/histogram.h; sourceTree = ""; }; + 57E608271810C0DF3502349FA7E1F9AD /* FIRStartMFAEnrollmentResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRStartMFAEnrollmentResponse.m; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentResponse.m; sourceTree = ""; }; + 58050F9C59254E6D397ADB56DFC128C4 /* FIRLogger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRLogger.h; path = FirebaseCore/Extension/FIRLogger.h; sourceTree = ""; }; + 580F4927B5BDF99355238AB3E3B8A646 /* FPathIndex.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FPathIndex.m; path = FirebaseDatabase/Sources/FPathIndex.m; sourceTree = ""; }; + 581EF75B385FA2FCCBB0497AC0AC8A58 /* db.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = db.h; path = include/leveldb/db.h; sourceTree = ""; }; + 5824BEEDD3575E41D0E94856799BCFA8 /* FIRDependency.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDependency.h; path = FirebaseCore/Extension/FIRDependency.h; sourceTree = ""; }; + 5850037D209BF1B3CDAD9335AFDC8EE3 /* Pods-PRTY.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-PRTY.modulemap"; sourceTree = ""; }; + 58E43043367BCAD229609546CB6EF371 /* FBLPromise+Race.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Race.m"; path = "Sources/FBLPromises/FBLPromise+Race.m"; sourceTree = ""; }; + 592D0D7310651F0CA55EFAE60B29BABB /* PromisesObjC-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "PromisesObjC-Info.plist"; sourceTree = ""; }; + 59658C383969DFD4CC50A9FB8FE855AB /* FBLPromise+Validate.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Validate.m"; path = "Sources/FBLPromises/FBLPromise+Validate.m"; sourceTree = ""; }; + 59727615BE1BBAD30154EEDC7630DB67 /* EmbeddedObject.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = EmbeddedObject.swift; path = RealmSwift/EmbeddedObject.swift; sourceTree = ""; }; + 5974F17EA36C2FB1DFB94CB822008CDB /* FIRAppCheckTokenResultInterop.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAppCheckTokenResultInterop.h; path = FirebaseAppCheck/Interop/FIRAppCheckTokenResultInterop.h; sourceTree = ""; }; + 59B1316F443B4F1AC8F4C103BE9970BD /* FBLPromise+Await.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Await.h"; path = "Sources/FBLPromises/include/FBLPromise+Await.h"; sourceTree = ""; }; + 59B92BFC2E5FD6370D6AAD2B96F09C54 /* FIRLogger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRLogger.h; path = FirebaseCore/Extension/FIRLogger.h; sourceTree = ""; }; + 5ABBB25E158253F6289758734B748297 /* FViewProcessor.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FViewProcessor.m; path = FirebaseDatabase/Sources/FViewProcessor.m; sourceTree = ""; }; + 5B8FA1F7710A719A4A55E7366464BC60 /* FIREmailLinkSignInResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIREmailLinkSignInResponse.m; path = FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInResponse.m; sourceTree = ""; }; + 5B906ACE4C08A720ED3DEEE6A58B6D51 /* iterator_wrapper.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = iterator_wrapper.h; path = table/iterator_wrapper.h; sourceTree = ""; }; + 5BC2453F28988CA912B8C605F9E28277 /* FPruneForest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FPruneForest.m; path = FirebaseDatabase/Sources/Persistence/FPruneForest.m; sourceTree = ""; }; + 5BE9A4788D908C70DB01791A60D2E8C8 /* FIRComponentContainer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRComponentContainer.h; path = FirebaseCore/Extension/FIRComponentContainer.h; sourceTree = ""; }; + 5BED05889CD6C4477F7E451D6485915E /* FIRAuthURLPresenter.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthURLPresenter.m; path = FirebaseAuth/Sources/Utilities/FIRAuthURLPresenter.m; sourceTree = ""; }; + 5C04EE56E5B835BB6F333DCBC55AC442 /* FIRDependency.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDependency.h; path = FirebaseCore/Extension/FIRDependency.h; sourceTree = ""; }; + 5C454B144382132DB0C1424B8423538E /* RealmSwift-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RealmSwift-prefix.pch"; sourceTree = ""; }; + 5C604635A949AB81B5D5CAB66362D049 /* RLMUserAPIKey.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMUserAPIKey.mm; path = Realm/RLMUserAPIKey.mm; sourceTree = ""; }; + 5C9BF815DA833EA927104176F6728631 /* FIRFinalizeMFAEnrollmentResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRFinalizeMFAEnrollmentResponse.h; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentResponse.h; sourceTree = ""; }; + 5D2BCDEBF223F71AFF9564E683A322A8 /* FIRMutableData_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMutableData_Private.h; path = FirebaseDatabase/Sources/Api/Private/FIRMutableData_Private.h; sourceTree = ""; }; + 5F207504952B0CD5C9F5FE247A248597 /* FIRInstallations.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRInstallations.m; path = FirebaseInstallations/Source/Library/FIRInstallations.m; sourceTree = ""; }; + 5F3C1CEEBD4F3E655891CC3098279020 /* random.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = random.h; path = util/random.h; sourceTree = ""; }; + 5F42CD147531578D555111E281D9DB32 /* FIRDatabase_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDatabase_Private.h; path = FirebaseDatabase/Sources/Api/Private/FIRDatabase_Private.h; sourceTree = ""; }; + 5F42FD92CC45EDFD0C54EE547EE79090 /* FIRActionCodeSettings.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRActionCodeSettings.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRActionCodeSettings.h; sourceTree = ""; }; + 5F51D8C4AC0945BEB82DE5747E45BC96 /* version_edit.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = version_edit.cc; path = db/version_edit.cc; sourceTree = ""; }; + 5F57F13EBD8F6268EA73B2E4176B7FB5 /* FIRGoogleAuthCredential.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRGoogleAuthCredential.h; path = FirebaseAuth/Sources/AuthProvider/Google/FIRGoogleAuthCredential.h; sourceTree = ""; }; + 5FCFC34AFBC4E5C47B62D36842E9D028 /* FTupleSetIdPath.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTupleSetIdPath.h; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleSetIdPath.h; sourceTree = ""; }; + 600763BBCBED3F50EE109FA6AB08E882 /* block.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = block.h; path = table/block.h; sourceTree = ""; }; + 6046DACC7689D111783C349D3D6D4D73 /* GTMSessionUploadFetcher.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GTMSessionUploadFetcher.m; path = Sources/Core/GTMSessionUploadFetcher.m; sourceTree = ""; }; + 607673A9F4B2F07F2E2EBB8F530B123D /* RLMFindOptions.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMFindOptions.mm; path = Realm/RLMFindOptions.mm; sourceTree = ""; }; + 6081ADA3495E375084C4844160B739B3 /* FIRUserInfoImpl.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRUserInfoImpl.m; path = FirebaseAuth/Sources/User/FIRUserInfoImpl.m; sourceTree = ""; }; + 60E66EB709475B2AE9581154EEAFEF40 /* FOverwrite.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FOverwrite.m; path = FirebaseDatabase/Sources/Core/Operation/FOverwrite.m; sourceTree = ""; }; + 60EE7485A5498FE07A5EBB875A28A6FC /* NSData+FIRBase64.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "NSData+FIRBase64.h"; path = "FirebaseAuth/Sources/Utilities/NSData+FIRBase64.h"; sourceTree = ""; }; + 6109B27325309C7DB2F34C877E65CE8E /* FIRRevokeTokenResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRRevokeTokenResponse.m; path = FirebaseAuth/Sources/Backend/RPC/FIRRevokeTokenResponse.m; sourceTree = ""; }; + 611073B847128EBBC450AA00B49A5852 /* RLMAsyncTask_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMAsyncTask_Private.h; path = include/RLMAsyncTask_Private.h; sourceTree = ""; }; + 6193CC42799E1C407B66E8C95CC11099 /* FPruneForest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FPruneForest.h; path = FirebaseDatabase/Sources/Persistence/FPruneForest.h; sourceTree = ""; }; + 61E8141817AC68D5CC9DCF402DC7F433 /* FIRDependency.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRDependency.m; path = FirebaseCore/Sources/FIRDependency.m; sourceTree = ""; }; + 625421974DC8B2D9D04332AD61B57DA3 /* FirebaseCoreInternal.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FirebaseCoreInternal.debug.xcconfig; sourceTree = ""; }; + 625BF0B0BDAD0167B52F23BE38835B07 /* Pods-PRTY-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-PRTY-Info.plist"; sourceTree = ""; }; + 6287A4A1BAE8862EA2597F0C1383E8FC /* Realm-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Realm-dummy.m"; sourceTree = ""; }; + 6293EEA3422B89FF3E253E3876365114 /* FNamedNode.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FNamedNode.m; path = FirebaseDatabase/Sources/FNamedNode.m; sourceTree = ""; }; + 62DA765EFA6176292C8BB0A39A6430D4 /* RLMSwiftProperty.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMSwiftProperty.h; path = include/RLMSwiftProperty.h; sourceTree = ""; }; + 62DBEBE7FDE694DB7230FEAFD3AC7DD6 /* FPath.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FPath.m; path = FirebaseDatabase/Sources/Core/Utilities/FPath.m; sourceTree = ""; }; + 631552790F8641131F8F403D6D4D68BC /* Pods-PRTY.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-PRTY.release.xcconfig"; sourceTree = ""; }; + 63554B52614D7D8DF01AB2A87A9CC991 /* FTupleCallbackStatus.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTupleCallbackStatus.h; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleCallbackStatus.h; sourceTree = ""; }; + 63618DD550DBA72C753D27AB482CF04E /* FIRFinalizeMFASignInRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRFinalizeMFASignInRequest.h; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInRequest.h; sourceTree = ""; }; + 64108C8865FFF2EE03378892DBAA7633 /* RLMSyncManager.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMSyncManager.mm; path = Realm/RLMSyncManager.mm; sourceTree = ""; }; + 647108F63AEB846763605E0AFE84F78E /* Pods-PRTY-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-PRTY-dummy.m"; sourceTree = ""; }; + 648A0A18D652FE8A5C1DF6848D5864D1 /* FIRInstallationsStoredItem.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInstallationsStoredItem.h; path = FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredItem.h; sourceTree = ""; }; + 64CA733606AC8F6B69927A354B416C4D /* GoogleUtilities.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = GoogleUtilities.debug.xcconfig; sourceTree = ""; }; + 652A3A7D52D06A4AFAE994E85C60432A /* FSyncPoint.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FSyncPoint.h; path = FirebaseDatabase/Sources/Core/FSyncPoint.h; sourceTree = ""; }; + 6547B8C2009B2D61EB11FEC0F64F29F5 /* FSnapshotUtilities.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FSnapshotUtilities.h; path = FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.h; sourceTree = ""; }; + 657050EAF637F805365C58A8E0BC3601 /* FLLRBValueNode.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FLLRBValueNode.m; path = FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBValueNode.m; sourceTree = ""; }; + 6677881A1A790A577070807981ECC661 /* FIRResetPasswordResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRResetPasswordResponse.m; path = FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordResponse.m; sourceTree = ""; }; + 668B626E7E6C85D299AFCEA201C42B08 /* FKeyIndex.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FKeyIndex.h; path = FirebaseDatabase/Sources/FKeyIndex.h; sourceTree = ""; }; + 66CEFE2624DA20593CC818FF907F46F5 /* FIRAuthSerialTaskQueue.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthSerialTaskQueue.m; path = FirebaseAuth/Sources/Auth/FIRAuthSerialTaskQueue.m; sourceTree = ""; }; + 67361D46F9488FA1DC95BE85E46CE3ED /* FIRConfigurationInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRConfigurationInternal.h; path = FirebaseCore/Sources/FIRConfigurationInternal.h; sourceTree = ""; }; + 673C8052EBB7CFC728848688E8635A04 /* LinkingObjects.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LinkingObjects.swift; path = RealmSwift/LinkingObjects.swift; sourceTree = ""; }; + 675C0C404FF5EA964785CFC002A6E20D /* FChildrenNode.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FChildrenNode.m; path = FirebaseDatabase/Sources/Snapshot/FChildrenNode.m; sourceTree = ""; }; + 67DA65C65A6DC928597F98BDE85879D6 /* FIRFinalizeMFASignInResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRFinalizeMFASignInResponse.h; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInResponse.h; sourceTree = ""; }; + 67EA9922C35F5F0019B266058D44FF98 /* FIRWithdrawMFAResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRWithdrawMFAResponse.h; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFAResponse.h; sourceTree = ""; }; + 682683D1FA0D7DFA4BEE25A9AC5C6759 /* Aliases.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Aliases.swift; path = RealmSwift/Aliases.swift; sourceTree = ""; }; + 6829850E183C8570735638BD3F540C47 /* GULLoggerLevel.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULLoggerLevel.h; path = GoogleUtilities/Logger/Public/GoogleUtilities/GULLoggerLevel.h; sourceTree = ""; }; + 684B24EBB223FA5F33D00EACC3360AFB /* RLMMongoCollection.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMMongoCollection.h; path = include/RLMMongoCollection.h; sourceTree = ""; }; + 6892038D8802D6670D85D0F370C2A713 /* FirebaseInstallations.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = FirebaseInstallations.modulemap; sourceTree = ""; }; + 689C26D1B7BCCB029AE9A72765C6468E /* FCompoundHash.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FCompoundHash.h; path = FirebaseDatabase/Sources/Core/FCompoundHash.h; sourceTree = ""; }; + 68AE375B41C0795563080D459FDCC110 /* FIRInstallationsItem+RegisterInstallationAPI.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FIRInstallationsItem+RegisterInstallationAPI.h"; path = "FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsItem+RegisterInstallationAPI.h"; sourceTree = ""; }; + 6904D0037830DB80686AB0A6EDFDD815 /* FTupleFirebase.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTupleFirebase.h; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleFirebase.h; sourceTree = ""; }; + 692CA72025C2AD94D8AD564A919418FB /* FTupleObjects.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTupleObjects.m; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjects.m; sourceTree = ""; }; + 69578BBD7CC915AC07C4B3A36276C339 /* Pods-PRTY-PRTYUITests-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-PRTY-PRTYUITests-dummy.m"; sourceTree = ""; }; + 6A1EB85929DB5ABFC8B1B0F7CA908A93 /* no_destructor.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = no_destructor.h; path = util/no_destructor.h; sourceTree = ""; }; + 6A45F4A50350CD25215F79F11B696584 /* GULSecureCoding.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULSecureCoding.m; path = GoogleUtilities/Environment/GULSecureCoding.m; sourceTree = ""; }; + 6A5B34AC3E337EC7014EA2086077DAB9 /* FIRResetPasswordRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRResetPasswordRequest.m; path = FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordRequest.m; sourceTree = ""; }; + 6A9CA393FA5F4F8BE4BD71ADB0DAE631 /* table.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = table.cc; path = table/table.cc; sourceTree = ""; }; + 6ABE347DB5D72B0A29CB81D058503E94 /* FIRAuthWebViewController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthWebViewController.m; path = FirebaseAuth/Sources/Utilities/FIRAuthWebViewController.m; sourceTree = ""; }; + 6B4C6D7ADDA4ADABDBD392B362DC1F38 /* FIRAuthDataResult.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthDataResult.m; path = FirebaseAuth/Sources/Auth/FIRAuthDataResult.m; sourceTree = ""; }; + 6B613C7C1583C7F1F9A167E85A01750A /* FIRSecureTokenService.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRSecureTokenService.h; path = FirebaseAuth/Sources/SystemService/FIRSecureTokenService.h; sourceTree = ""; }; + 6B63FB84EB4C99C9989AE9702E6B5310 /* FRangeMerge.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FRangeMerge.m; path = FirebaseDatabase/Sources/Core/FRangeMerge.m; sourceTree = ""; }; + 6BA7C44B9E19D70D498CD1406747C619 /* FIRInstallationsSingleOperationPromiseCache.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRInstallationsSingleOperationPromiseCache.m; path = FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsSingleOperationPromiseCache.m; sourceTree = ""; }; + 6BF24E0394DAD3101FF5C00412EB1C4D /* leveldb-library.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "leveldb-library.debug.xcconfig"; sourceTree = ""; }; + 6C12879EEF6A505D3CEE089176D6333E /* RLMDecimal128.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMDecimal128.mm; path = Realm/RLMDecimal128.mm; sourceTree = ""; }; + 6C7E8CA913852DAEA9F764D022D94B48 /* RLMDictionary.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMDictionary.mm; path = Realm/RLMDictionary.mm; sourceTree = ""; }; + 6C892732CFC7F04EDE36414A35202F2F /* RingBuffer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RingBuffer.swift; path = FirebaseCore/Internal/Sources/HeartbeatLogging/RingBuffer.swift; sourceTree = ""; }; + 6C8D0EA446BF7DA682A806ED24FE6AFB /* FBLPromise+Wrap.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Wrap.h"; path = "Sources/FBLPromises/include/FBLPromise+Wrap.h"; sourceTree = ""; }; + 6CE6F0F74A2B43DEE1CA48C3DFBC20DA /* FIRAppCheckInterop.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAppCheckInterop.h; path = FirebaseAppCheck/Interop/FIRAppCheckInterop.h; sourceTree = ""; }; + 6D00B53942427419D9F1A394FBEE64F3 /* RLMEmbeddedObject.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMEmbeddedObject.h; path = include/RLMEmbeddedObject.h; sourceTree = ""; }; + 6D3BA8069DBAAD52F0BBD67EF7D95738 /* FIRPhoneAuthProvider.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRPhoneAuthProvider.m; path = FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthProvider.m; sourceTree = ""; }; + 6DD2A0344579B5A9CAA6BDFFD7B8481F /* RLMUser.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMUser.mm; path = Realm/RLMUser.mm; sourceTree = ""; }; + 6DEADF2D6BCDFA40C7B0F220FE995B41 /* FIRLibrary.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRLibrary.h; path = FirebaseCore/Extension/FIRLibrary.h; sourceTree = ""; }; + 6DFB4AE7F11314CE5775A0522693D21C /* FIRComponent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRComponent.h; path = FirebaseCore/Extension/FIRComponent.h; sourceTree = ""; }; + 6E1AAF86750B38DE664456E8E4A9C10F /* RLMMongoClient.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMMongoClient.mm; path = Realm/RLMMongoClient.mm; sourceTree = ""; }; + 6E654A0432980B1F063FFDBCA71B4084 /* RLMScheduler.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMScheduler.mm; path = Realm/RLMScheduler.mm; sourceTree = ""; }; + 6ECA1090408234F0432AD7A8719CDED2 /* FIRDeleteAccountRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDeleteAccountRequest.h; path = FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountRequest.h; sourceTree = ""; }; + 6EE3C9DA366E6B7ABA2CD3B139B2BFFC /* FIRSignUpNewUserRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRSignUpNewUserRequest.m; path = FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.m; sourceTree = ""; }; + 6F17E4595E3BDA403E8C7DBF3F47B918 /* FIROAuthCredential.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIROAuthCredential.m; path = FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthCredential.m; sourceTree = ""; }; + 6F2297CEDCE776B9F4D682C5BFDFBAF7 /* FQuerySpec.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FQuerySpec.m; path = FirebaseDatabase/Sources/Core/FQuerySpec.m; sourceTree = ""; }; + 6F386A0EAC54042F34AD558B82364330 /* GULAppDelegateSwizzler.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULAppDelegateSwizzler.h; path = GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULAppDelegateSwizzler.h; sourceTree = ""; }; + 6FF141A971FE681D3139DD5BC9039439 /* FIRAuthBackend+MultiFactor.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FIRAuthBackend+MultiFactor.h"; path = "FirebaseAuth/Sources/Backend/FIRAuthBackend+MultiFactor.h"; sourceTree = ""; }; + 701AE09D27677AF927D0756A5C7C40B4 /* RLMPredicateUtil.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMPredicateUtil.mm; path = Realm/RLMPredicateUtil.mm; sourceTree = ""; }; + 703AE36A6535247556EF937C30749277 /* GTMSessionFetcher.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GTMSessionFetcher.h; path = Sources/Core/Public/GTMSessionFetcher/GTMSessionFetcher.h; sourceTree = ""; }; + 70408AF61F223F44EBED723B80F513A4 /* FIRComponentType.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRComponentType.h; path = FirebaseCore/Extension/FIRComponentType.h; sourceTree = ""; }; + 7055A9FCC22D8FE5674415195AAB67AB /* FBLPromiseError.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBLPromiseError.m; path = Sources/FBLPromises/FBLPromiseError.m; sourceTree = ""; }; + 7070066373BC8611A2B554BE77E09B2C /* GULNetworkURLSession.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULNetworkURLSession.m; path = GoogleUtilities/Network/GULNetworkURLSession.m; sourceTree = ""; }; + 707F9FEDC83ABFDAF459079D0BE88C1E /* GULSceneDelegateSwizzler.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULSceneDelegateSwizzler.h; path = GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULSceneDelegateSwizzler.h; sourceTree = ""; }; + 708181884E851CC294593093D3921B23 /* RLMResults_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMResults_Private.h; path = include/RLMResults_Private.h; sourceTree = ""; }; + 70AF99E224EDF12DFD45951388CF82E3 /* AnyRealmValue.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AnyRealmValue.swift; path = RealmSwift/AnyRealmValue.swift; sourceTree = ""; }; + 70F4CDB8C474983A83FFDA390D5A657A /* FSnapshotUtilities.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FSnapshotUtilities.m; path = FirebaseDatabase/Sources/Snapshot/FSnapshotUtilities.m; sourceTree = ""; }; + 718D25283FCCDB355A59F30C238CDC71 /* RealmSwift-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RealmSwift-umbrella.h"; sourceTree = ""; }; + 71EB5FB4222FE68A6E09A16CC088A3EA /* nanopb.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = nanopb.release.xcconfig; sourceTree = ""; }; + 7265EFBF2A684FDD8000FFA1529176CE /* RLMAPIKeyAuth.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMAPIKeyAuth.h; path = include/RLMAPIKeyAuth.h; sourceTree = ""; }; + 726B5EDE338F3B54A4CF771D23EA5618 /* RLMThreadSafeReference.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMThreadSafeReference.h; path = include/RLMThreadSafeReference.h; sourceTree = ""; }; + 72B122535CC236E3BC29334CA1639C6E /* FIRAuth_Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuth_Internal.h; path = FirebaseAuth/Sources/Auth/FIRAuth_Internal.h; sourceTree = ""; }; + 72F431CF7352923F85C4AD27477F4B3E /* FCompoundWrite.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FCompoundWrite.h; path = FirebaseDatabase/Sources/Snapshot/FCompoundWrite.h; sourceTree = ""; }; + 73247FFFFE3299EA4FF88B4C958FCFB2 /* FIRPhoneMultiFactorAssertion.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRPhoneMultiFactorAssertion.m; path = FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorAssertion.m; sourceTree = ""; }; + 7334D38A0B7D794172B7EDC55F342D71 /* FEventRegistration.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FEventRegistration.h; path = FirebaseDatabase/Sources/Core/View/FEventRegistration.h; sourceTree = ""; }; + 733CEDC657436DD895F6CF302461A85D /* FIRAuthStoredUserManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthStoredUserManager.h; path = FirebaseAuth/Sources/SystemService/FIRAuthStoredUserManager.h; sourceTree = ""; }; + 736926EDDD0EACA6E6342ACD806788CB /* GoogleAppMeasurementIdentitySupport.xcframework */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = wrapper.xcframework; name = GoogleAppMeasurementIdentitySupport.xcframework; path = Frameworks/GoogleAppMeasurementIdentitySupport.xcframework; sourceTree = ""; }; + 73874D1391ABB5D9F840E66D19FC0FDF /* FirebaseDatabase-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "FirebaseDatabase-dummy.m"; sourceTree = ""; }; + 73941508AA91B8C0AC7E08B3C43C974A /* FServerValues.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FServerValues.m; path = FirebaseDatabase/Sources/Core/FServerValues.m; sourceTree = ""; }; + 739D1EBC2858FD3E444E93BBB800622E /* RLMSwiftCollectionBase.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMSwiftCollectionBase.mm; path = Realm/RLMSwiftCollectionBase.mm; sourceTree = ""; }; + 73C0174B2AFCC7AE91A522B22727376A /* Map.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Map.swift; path = RealmSwift/Map.swift; sourceTree = ""; }; + 73D394BF34BF20845775F8C96C11C552 /* FIRAuthKeychainServices.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthKeychainServices.h; path = FirebaseAuth/Sources/Storage/FIRAuthKeychainServices.h; sourceTree = ""; }; + 74A5A96FBBF716F052FC7FE7E7799B11 /* PropertyAccessors.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PropertyAccessors.swift; path = RealmSwift/Impl/PropertyAccessors.swift; sourceTree = ""; }; + 74B5118CEAD735734BEAA228AD3D8739 /* FBLPromise+Do.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Do.h"; path = "Sources/FBLPromises/include/FBLPromise+Do.h"; sourceTree = ""; }; + 74F7F76D9723E9827EF3AD57738BD660 /* FIRGitHubAuthProvider.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRGitHubAuthProvider.m; path = FirebaseAuth/Sources/AuthProvider/GitHub/FIRGitHubAuthProvider.m; sourceTree = ""; }; + 753ACF5F1365F9D5FD71BE6F829E2F92 /* Decimal128.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Decimal128.swift; path = RealmSwift/Decimal128.swift; sourceTree = ""; }; + 7547375C6508BD409DCDF96AC19B46BD /* FLLRBEmptyNode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FLLRBEmptyNode.h; path = FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBEmptyNode.h; sourceTree = ""; }; + 75524D426CC700CE7B7C9E5C62779F88 /* GoogleUtilities-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "GoogleUtilities-umbrella.h"; sourceTree = ""; }; + 75552E75CFD01D4BD91E2725CDEF78C1 /* leveldb-library.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "leveldb-library.release.xcconfig"; sourceTree = ""; }; + 75956E3ED82B4C4C3A8BF491AF04E129 /* FCompoundHash.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FCompoundHash.m; path = FirebaseDatabase/Sources/Core/FCompoundHash.m; sourceTree = ""; }; + 75FC8BF03C212294921BDF40A8ACB832 /* RLMObjectSchema.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMObjectSchema.mm; path = Realm/RLMObjectSchema.mm; sourceTree = ""; }; + 7638110F458ECF6341C673A9696D666D /* ObjectSchema.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObjectSchema.swift; path = RealmSwift/ObjectSchema.swift; sourceTree = ""; }; + 7671FC7CD2367A77CBAF94D322CD3EA0 /* windows_logger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = windows_logger.h; path = util/windows_logger.h; sourceTree = ""; }; + 76967898F8101178E562B75A2FE2C7B6 /* FBLPromise+Catch.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Catch.m"; path = "Sources/FBLPromises/FBLPromise+Catch.m"; sourceTree = ""; }; + 76B21F0B55C360125A29B27794C61933 /* GULNetworkInfo.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULNetworkInfo.m; path = GoogleUtilities/Environment/NetworkInfo/GULNetworkInfo.m; sourceTree = ""; }; + 76E8A9B00D0B852C4CBF03F3018E7BA6 /* RealmProperty.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RealmProperty.swift; path = RealmSwift/RealmProperty.swift; sourceTree = ""; }; + 77674F69710E6CF04D1D387F6B6F1F36 /* FIRInstallationsStoredItem.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRInstallationsStoredItem.m; path = FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredItem.m; sourceTree = ""; }; + 77B43A9AB4643A40D2652594DE5E5DFE /* RLMObject.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMObject.mm; path = Realm/RLMObject.mm; sourceTree = ""; }; + 77CF941717A8A5BD89D10005F3094380 /* FRangedFilter.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FRangedFilter.m; path = FirebaseDatabase/Sources/FRangedFilter.m; sourceTree = ""; }; + 77EF00ECB627D79F06240B748B823EED /* RLMRealm+Sync.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = "RLMRealm+Sync.mm"; path = "Realm/RLMRealm+Sync.mm"; sourceTree = ""; }; + 77F0D8AA239C613235E4A219436457D4 /* FBLPromise+Async.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Async.m"; path = "Sources/FBLPromises/FBLPromise+Async.m"; sourceTree = ""; }; + 77FB6AA08E6C71D030AFA0335507B674 /* FStringUtilities.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FStringUtilities.h; path = FirebaseDatabase/Sources/Utilities/FStringUtilities.h; sourceTree = ""; }; + 780F15D6939A98ACA8F237480C9FDF2E /* RLMObject.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMObject.h; path = include/RLMObject.h; sourceTree = ""; }; + 781F45EA0C7D63C20AA65A2ECB8306B9 /* env_windows_test_helper.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = env_windows_test_helper.h; path = util/env_windows_test_helper.h; sourceTree = ""; }; + 782D131BB42C5CBFD43A47DDC8824422 /* FIROptionsInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIROptionsInternal.h; path = FirebaseCore/Extension/FIROptionsInternal.h; sourceTree = ""; }; + 7852B5DBDABD1585A09D661182ED0B4F /* FIRAnalyticsConfiguration.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAnalyticsConfiguration.h; path = FirebaseCore/Sources/FIRAnalyticsConfiguration.h; sourceTree = ""; }; + 786F9BDCFBF6DF893D9F253B20AB4509 /* Storage.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Storage.swift; path = FirebaseCore/Internal/Sources/HeartbeatLogging/Storage.swift; sourceTree = ""; }; + 78A0CF3F16BA622C5E0A626D56DFAE8A /* FIRUserMetadata.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRUserMetadata.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRUserMetadata.h; sourceTree = ""; }; + 78BCFBB3475F1361601C33BBE6B25FFC /* GULReachabilityChecker+Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "GULReachabilityChecker+Internal.h"; path = "GoogleUtilities/Reachability/GULReachabilityChecker+Internal.h"; sourceTree = ""; }; + 78D1E4541AA37C05E37CD3271341EB53 /* FIREmailLinkSignInRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIREmailLinkSignInRequest.h; path = FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInRequest.h; sourceTree = ""; }; + 790371766FE16C535A3A6564C2016038 /* FIRAuthExceptionUtils.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthExceptionUtils.h; path = FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.h; sourceTree = ""; }; + 7908EB620837F7E1D1A620F7A161B653 /* RealmSwift.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = RealmSwift.release.xcconfig; sourceTree = ""; }; + 795AEE8AFDEC780A0E27DFCCEDCBE103 /* table_builder.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = table_builder.h; path = include/leveldb/table_builder.h; sourceTree = ""; }; + 7A268D34F1B85A759DE13BDCDF787C6B /* FirebaseCoreInternal-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "FirebaseCoreInternal-dummy.m"; sourceTree = ""; }; + 7A4A2A3F4FEE1B358A1A649FC0C19EEE /* FIRAuthProtoStartMFAPhoneResponseInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthProtoStartMFAPhoneResponseInfo.h; path = FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneResponseInfo.h; sourceTree = ""; }; + 7AA4F6AE64EE4FC2D1783D3CDE850753 /* pb_decode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = pb_decode.h; sourceTree = ""; }; + 7AAC8D7921DC3CFE9D2E4976DAE3040F /* FIRMultiFactorResolver.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMultiFactorResolver.m; path = FirebaseAuth/Sources/MultiFactor/FIRMultiFactorResolver.m; sourceTree = ""; }; + 7AD60D804ED86004AB6ADDF386296D8C /* FIRGameCenterAuthProvider.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRGameCenterAuthProvider.m; path = FirebaseAuth/Sources/AuthProvider/GameCenter/FIRGameCenterAuthProvider.m; sourceTree = ""; }; + 7AF1FEB5A0A42BDF77BD2CE3A7CDE92E /* FChange.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FChange.m; path = FirebaseDatabase/Sources/Core/View/FChange.m; sourceTree = ""; }; + 7B01D60353BAB7668513EE30428048CA /* FServerValues.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FServerValues.h; path = FirebaseDatabase/Sources/Core/FServerValues.h; sourceTree = ""; }; + 7B05F3BE2B4BA2F8C84E85EC55902EE0 /* RLMRealm_Dynamic.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMRealm_Dynamic.h; path = include/RLMRealm_Dynamic.h; sourceTree = ""; }; + 7B2844F303E92ABE8A160DD9F6582F0C /* FIRInstallationsErrors.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInstallationsErrors.h; path = FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallationsErrors.h; sourceTree = ""; }; + 7BD2BA99023096C1DF3C88F2DE465DD2 /* FBLPromise+Retry.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Retry.h"; path = "Sources/FBLPromises/include/FBLPromise+Retry.h"; sourceTree = ""; }; + 7BE10AFF86267C9FDAC00B2AAB63A15D /* FIRInstallationsStoredAuthToken.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRInstallationsStoredAuthToken.m; path = FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.m; sourceTree = ""; }; + 7C4CCD297749321D38B4D8E1C0E06675 /* FIRAppCheckInterop.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAppCheckInterop.h; path = FirebaseAppCheck/Interop/FIRAppCheckInterop.h; sourceTree = ""; }; + 7CA157D50F38EC9E1EDB65A499D536F7 /* testutil.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = testutil.h; path = util/testutil.h; sourceTree = ""; }; + 7CC89F7D738A2A79CA9191BE2FC708E0 /* FIRServerValue.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRServerValue.m; path = FirebaseDatabase/Sources/Api/FIRServerValue.m; sourceTree = ""; }; + 7D790D2DD3CD5C606CCF3B56048A95D6 /* memtable.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = memtable.h; path = db/memtable.h; sourceTree = ""; }; + 7DA1270DF0D5F31B5860D0879C25BFCF /* FWebSocketConnection.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FWebSocketConnection.m; path = FirebaseDatabase/Sources/Realtime/FWebSocketConnection.m; sourceTree = ""; }; + 7E9095E4AA136950BC9BCC00DC4AF244 /* GULUserDefaults.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULUserDefaults.m; path = GoogleUtilities/UserDefaults/GULUserDefaults.m; sourceTree = ""; }; + 7ECC1E0C372817AC19942A566AB123C1 /* FPriorityIndex.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FPriorityIndex.h; path = FirebaseDatabase/Sources/FPriorityIndex.h; sourceTree = ""; }; + 7F1B362D7A8C6E8B43B41DCA9EC82A5B /* RLMObjectStore.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMObjectStore.mm; path = Realm/RLMObjectStore.mm; sourceTree = ""; }; + 7F2816163119D09FACF48BF06C77144F /* FIRDataSnapshot_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDataSnapshot_Private.h; path = FirebaseDatabase/Sources/Api/Private/FIRDataSnapshot_Private.h; sourceTree = ""; }; + 7F4F042C307A225AAA16C9601FF316FF /* FIRAuthBackend.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthBackend.h; path = FirebaseAuth/Sources/Backend/FIRAuthBackend.h; sourceTree = ""; }; + 7F98669F88B9C95FEB19125B73434800 /* GULAppDelegateSwizzler_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULAppDelegateSwizzler_Private.h; path = GoogleUtilities/AppDelegateSwizzler/Internal/GULAppDelegateSwizzler_Private.h; sourceTree = ""; }; + 7FC074C669327E8C8F84CB1E0EF41773 /* FCompleteChildSource.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FCompleteChildSource.h; path = FirebaseDatabase/Sources/Core/View/Filter/FCompleteChildSource.h; sourceTree = ""; }; + 7FFE5FB751622716C89387E428A18B33 /* FIRPhoneMultiFactorInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRPhoneMultiFactorInfo.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorInfo.h; sourceTree = ""; }; + 80091CE146D230191C846447F22D2BFC /* FIRAuthAppCredential.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthAppCredential.m; path = FirebaseAuth/Sources/SystemService/FIRAuthAppCredential.m; sourceTree = ""; }; + 804256AD4BE732EE9C70262DA3963093 /* nanopb-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "nanopb-prefix.pch"; sourceTree = ""; }; + 81252E5CD0EB33B7028F00FADE62A39B /* FIRSignInWithGameCenterRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRSignInWithGameCenterRequest.m; path = FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterRequest.m; sourceTree = ""; }; + 81418C93A311F0492F62A8F88C3BD66B /* FirebaseAppCheckInterop.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = FirebaseAppCheckInterop.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 81B38C32D7A56C22344E671F7C0B1AF1 /* FIRActionCodeSettings.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRActionCodeSettings.m; path = FirebaseAuth/Sources/Auth/FIRActionCodeSettings.m; sourceTree = ""; }; + 81EF26534B7108DEFF43DFD082550D16 /* two_level_iterator.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = two_level_iterator.h; path = table/two_level_iterator.h; sourceTree = ""; }; + 82144ED3101ECA164213270A3C7A5398 /* NSError+RLMSync.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "NSError+RLMSync.m"; path = "Realm/NSError+RLMSync.m"; sourceTree = ""; }; + 8248C935EA50EC5DC7B87FF59C18BCC0 /* FIRGoogleAuthCredential.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRGoogleAuthCredential.m; path = FirebaseAuth/Sources/AuthProvider/Google/FIRGoogleAuthCredential.m; sourceTree = ""; }; + 8256334A1BB6D43D6A505A6A754FB9AD /* FIRPhoneMultiFactorAssertion.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRPhoneMultiFactorAssertion.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneMultiFactorAssertion.h; sourceTree = ""; }; + 82842089E759BBC3480E5CB007595E93 /* port_stdcxx.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = port_stdcxx.h; path = port/port_stdcxx.h; sourceTree = ""; }; + 82BEA2A9C46781A0D1628AC337433495 /* RealmSwift.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = RealmSwift.modulemap; sourceTree = ""; }; + 82F408B46FDEEDA775BCD20ABA5AEA87 /* RLMObjectSchema_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMObjectSchema_Private.h; path = include/RLMObjectSchema_Private.h; sourceTree = ""; }; + 8353124354524C02C36488028B2F4D02 /* FIRAppInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAppInternal.h; path = FirebaseCore/Extension/FIRAppInternal.h; sourceTree = ""; }; + 836372D75ABF46C08BAD5758AD2B8EBF /* Combine.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Combine.swift; path = RealmSwift/Combine.swift; sourceTree = ""; }; + 83712E3E12FF5DD9E4CC45C82549DD15 /* RLMConstants.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMConstants.h; path = include/RLMConstants.h; sourceTree = ""; }; + 83A7B45E5C8683064DA6B5DAAD5957C0 /* NSURLSession+GULPromises.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "NSURLSession+GULPromises.h"; path = "GoogleUtilities/Environment/Public/GoogleUtilities/NSURLSession+GULPromises.h"; sourceTree = ""; }; + 83B84A215D7F46B8C23EE84B1A5F9CCB /* RLMObject_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMObject_Private.h; path = include/RLMObject_Private.h; sourceTree = ""; }; + 841716D96ED42D3A9096E922F0A3C8E5 /* FTupleTransaction.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTupleTransaction.m; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleTransaction.m; sourceTree = ""; }; + 8466D70DC12DC21169B9A39EB1BBAF8B /* FIRComponentContainer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRComponentContainer.h; path = FirebaseCore/Extension/FIRComponentContainer.h; sourceTree = ""; }; + 851C20472E36ED891170AD12241B66BB /* RLMRealmConfiguration.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMRealmConfiguration.mm; path = Realm/RLMRealmConfiguration.mm; sourceTree = ""; }; + 85221EA6BE483DC672CBF12305306A3E /* GULKeychainUtils.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULKeychainUtils.h; path = GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainUtils.h; sourceTree = ""; }; + 8547F6FA127EF377B812C3DDDB5CC6EA /* RealmSwift.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = RealmSwift.debug.xcconfig; sourceTree = ""; }; + 857C5EEC6F7D3F8980BABFC0863E92C8 /* nanopb-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "nanopb-dummy.m"; sourceTree = ""; }; + 8583BB6D970836E5FDF1168BAB878383 /* RLMFindOneAndModifyOptions.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMFindOneAndModifyOptions.mm; path = Realm/RLMFindOneAndModifyOptions.mm; sourceTree = ""; }; + 85A86307CFF228951C1F53BA876D81A8 /* GTMSessionFetcherService.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GTMSessionFetcherService.h; path = Sources/Core/Public/GTMSessionFetcher/GTMSessionFetcherService.h; sourceTree = ""; }; + 86A9DD91DF789DEE2B780190291B4392 /* FIRVerifyPhoneNumberRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRVerifyPhoneNumberRequest.h; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberRequest.h; sourceTree = ""; }; + 8709E4280FD40FF2D6C51425A4CC4DA8 /* RLMCredentials.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMCredentials.mm; path = Realm/RLMCredentials.mm; sourceTree = ""; }; + 8724DAAB9ED5D56FA204FF734EE4FD86 /* FIRInstallationsSingleOperationPromiseCache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInstallationsSingleOperationPromiseCache.h; path = FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsSingleOperationPromiseCache.h; sourceTree = ""; }; + 87B4B54B444CBCE7121C9CC71213A704 /* RLMSet_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMSet_Private.h; path = include/RLMSet_Private.h; sourceTree = ""; }; + 87F8A8905922D0CF7DAE27789D5EFC50 /* RLMAsymmetricObject.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMAsymmetricObject.mm; path = Realm/RLMAsymmetricObject.mm; sourceTree = ""; }; + 88576C105CD8237BE0FC4B763FDF77AF /* FIRMultiFactorResolver+Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FIRMultiFactorResolver+Internal.h"; path = "FirebaseAuth/Sources/MultiFactor/FIRMultiFactorResolver+Internal.h"; sourceTree = ""; }; + 8863D1E8CCA754A7C72D9B4890E10EDD /* RLMLogger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMLogger.h; path = include/RLMLogger.h; sourceTree = ""; }; + 89442941AAFEBFBD27360DCA80B0C541 /* FLeafNode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FLeafNode.h; path = FirebaseDatabase/Sources/Snapshot/FLeafNode.h; sourceTree = ""; }; + 898ED1F0E51D270602B2D9E712BDFB17 /* FIRAuthAppCredential.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthAppCredential.h; path = FirebaseAuth/Sources/SystemService/FIRAuthAppCredential.h; sourceTree = ""; }; + 89A1FB094E0C49A6D4987A61F9960B34 /* GULReachabilityMessageCode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULReachabilityMessageCode.h; path = GoogleUtilities/Reachability/GULReachabilityMessageCode.h; sourceTree = ""; }; + 89B93A8ED3FC12F718397CD71C98EE02 /* GTMSessionFetcher-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "GTMSessionFetcher-umbrella.h"; sourceTree = ""; }; + 89F626DEF1C52C94294D9723D0C99539 /* FIRInstallationsItem+RegisterInstallationAPI.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FIRInstallationsItem+RegisterInstallationAPI.m"; path = "FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsItem+RegisterInstallationAPI.m"; sourceTree = ""; }; + 8A1CF7A2AB94E939661BF09684D2DF1B /* RLMRealm_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMRealm_Private.h; path = include/RLMRealm_Private.h; sourceTree = ""; }; + 8A5426C951D7F583BE4F54AC6D9FDCBE /* FIRInstallationsAuthTokenResult.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRInstallationsAuthTokenResult.m; path = FirebaseInstallations/Source/Library/FIRInstallationsAuthTokenResult.m; sourceTree = ""; }; + 8A743CE22E7FE0C01E0F378C88109B68 /* leveldb-library.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "leveldb-library.modulemap"; sourceTree = ""; }; + 8AAEDD3920555DD075FFA6D823419E99 /* FIRInstallationsStoredAuthToken.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInstallationsStoredAuthToken.h; path = FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.h; sourceTree = ""; }; + 8ACA29DAD3C62BAB3015BD90E9439CB1 /* FIRInstallationsIIDTokenStore.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRInstallationsIIDTokenStore.m; path = FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDTokenStore.m; sourceTree = ""; }; + 8B828DF519503B35B1B1C7893D5F6C1E /* FIRTwitterAuthProvider.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRTwitterAuthProvider.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRTwitterAuthProvider.h; sourceTree = ""; }; + 8BCC07F63582332DF6501B6233E04AD5 /* FTupleRemovedQueriesEvents.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTupleRemovedQueriesEvents.m; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleRemovedQueriesEvents.m; sourceTree = ""; }; + 8C46AC75A5F40B157446B74CFDEBDCE4 /* FChange.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FChange.h; path = FirebaseDatabase/Sources/Core/View/FChange.h; sourceTree = ""; }; + 8C58E49372EAEEB8B4514B62243B2D8C /* FPendingPut.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FPendingPut.m; path = FirebaseDatabase/Sources/Persistence/FPendingPut.m; sourceTree = ""; }; + 8C87850C03CB12BC395080AD0C60F63C /* RLMEmbeddedObject.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMEmbeddedObject.mm; path = Realm/RLMEmbeddedObject.mm; sourceTree = ""; }; + 8CCBD61D45E1DA5335507549F09ECA06 /* GULNetworkURLSession.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULNetworkURLSession.h; path = GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkURLSession.h; sourceTree = ""; }; + 8CD89FAADE3C7B16A0F34D8014E0ECCE /* FIRAuthAppCredentialManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthAppCredentialManager.m; path = FirebaseAuth/Sources/SystemService/FIRAuthAppCredentialManager.m; sourceTree = ""; }; + 8CEDB3566E20E923946312D7CEF69B71 /* FBLPromise+All.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+All.h"; path = "Sources/FBLPromises/include/FBLPromise+All.h"; sourceTree = ""; }; + 8CF57CF9CBA1F70F48ADF8E3845AD4E5 /* FIRAuthProto.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthProto.h; path = FirebaseAuth/Sources/Backend/RPC/Proto/FIRAuthProto.h; sourceTree = ""; }; + 8D28A3D7BBFED5216A2FCF2D4855B3BE /* FIRVerifyPhoneNumberResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRVerifyPhoneNumberResponse.m; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberResponse.m; sourceTree = ""; }; + 8E042D37247BFBFE5C5FFA198F53B6AA /* GULSecureCoding.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULSecureCoding.h; path = GoogleUtilities/Environment/Public/GoogleUtilities/GULSecureCoding.h; sourceTree = ""; }; + 8E04B2430253816BA0826684401AB443 /* FIRAuthAPNSTokenManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthAPNSTokenManager.h; path = FirebaseAuth/Sources/SystemService/FIRAuthAPNSTokenManager.h; sourceTree = ""; }; + 8E2D8E4D702AA7E3958C44B41A68AEF3 /* FIROptionsInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIROptionsInternal.h; path = FirebaseCore/Extension/FIROptionsInternal.h; sourceTree = ""; }; + 8E47E99A63C56A34F47752275944340C /* FIRHeartbeatLogger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRHeartbeatLogger.h; path = FirebaseCore/Extension/FIRHeartbeatLogger.h; sourceTree = ""; }; + 8E959605E1F403D7C14260C76E2C0B48 /* FIRVerifyClientRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRVerifyClientRequest.m; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientRequest.m; sourceTree = ""; }; + 8F40B3B9417B5D4ED968E1E788B3A38E /* FQuerySpec.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FQuerySpec.h; path = FirebaseDatabase/Sources/Core/FQuerySpec.h; sourceTree = ""; }; + 8FA4AA9362111E7D1B6C89F59C6E425E /* RLMSyncSubscription.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMSyncSubscription.mm; path = Realm/RLMSyncSubscription.mm; sourceTree = ""; }; + 8FD2C61EFB4734EA70647A3B77BF8ACF /* Pods-PRTY-PRTYUITests-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-PRTY-PRTYUITests-umbrella.h"; sourceTree = ""; }; + 9011CDAF888185959FCBA517AA3CCD8D /* RLMSectionedResults.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMSectionedResults.h; path = include/RLMSectionedResults.h; sourceTree = ""; }; + 9020E232EB0972D241D3BF9C28E8BC0B /* FOperationSource.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FOperationSource.h; path = FirebaseDatabase/Sources/Core/Operation/FOperationSource.h; sourceTree = ""; }; + 9035019906CFA898627DB9DD54174418 /* FRangedFilter.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FRangedFilter.h; path = FirebaseDatabase/Sources/FRangedFilter.h; sourceTree = ""; }; + 9081630104DE8D7CFD31DF7D5426FDF3 /* FIRUser.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRUser.m; path = FirebaseAuth/Sources/User/FIRUser.m; sourceTree = ""; }; + 90F49AB280D154511F8828F29429908F /* FIRAuthProtoStartMFAPhoneRequestInfo.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthProtoStartMFAPhoneRequestInfo.m; path = FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneRequestInfo.m; sourceTree = ""; }; + 90F4CCD10E8C11477F4BC57D0F8C8E20 /* FCachePolicy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FCachePolicy.m; path = FirebaseDatabase/Sources/Persistence/FCachePolicy.m; sourceTree = ""; }; + 91067448F334D70084120D1E5EC0040C /* FIRAuthWebViewController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthWebViewController.h; path = FirebaseAuth/Sources/Utilities/FIRAuthWebViewController.h; sourceTree = ""; }; + 919DFEB9C187FA7EEAAFF1CD6E87C64F /* GULHeartbeatDateStorageUserDefaults.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULHeartbeatDateStorageUserDefaults.h; path = GoogleUtilities/Environment/Public/GoogleUtilities/GULHeartbeatDateStorageUserDefaults.h; sourceTree = ""; }; + 91B060AB17825145370421059E87B0CB /* FTupleStringNode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTupleStringNode.h; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleStringNode.h; sourceTree = ""; }; + 921A7FA65DED7374E8FA5FEF975CD444 /* FViewProcessorResult.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FViewProcessorResult.h; path = FirebaseDatabase/Sources/FViewProcessorResult.h; sourceTree = ""; }; + 921BE4A82C4A7A5C72A0C6F8B8FEF200 /* Realm */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Realm; path = Realm.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 92455D44ABE6751BD0F9BD80C8C7B7E7 /* Pods-PRTYTests-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-PRTYTests-Info.plist"; sourceTree = ""; }; + 9254CCCC55DF6E10A7F6C8019FD5F8B8 /* FIRResetPasswordResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRResetPasswordResponse.h; path = FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordResponse.h; sourceTree = ""; }; + 92B72A17E56EBF7CEDC7FBB84BF7A1C7 /* FIRStartMFAEnrollmentRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStartMFAEnrollmentRequest.h; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentRequest.h; sourceTree = ""; }; + 92FA39E85E83F2D45F0EFE7ED6AC3E9D /* fbase64.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = fbase64.h; path = FirebaseDatabase/Sources/third_party/SocketRocket/fbase64.h; sourceTree = ""; }; + 932C2931560E557D677E5D825DF55FF4 /* FIRCreateAuthURIResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRCreateAuthURIResponse.h; path = FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIResponse.h; sourceTree = ""; }; + 9331F4974B99FBE49998E4D3D7182A8C /* FirebaseCoreInternal-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "FirebaseCoreInternal-prefix.pch"; sourceTree = ""; }; + 9392ADE8C2DDE5988894EE97BD57E0D0 /* Pods-PRTY-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-PRTY-acknowledgements.plist"; sourceTree = ""; }; + 93C71DF12581A34115171295278A2235 /* FIRRevokeTokenResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRRevokeTokenResponse.h; path = FirebaseAuth/Sources/Backend/RPC/FIRRevokeTokenResponse.h; sourceTree = ""; }; + 93D1FC7C12423DA20AA334BD7AE69448 /* WeakContainer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = WeakContainer.swift; path = FirebaseCore/Internal/Sources/HeartbeatLogging/WeakContainer.swift; sourceTree = ""; }; + 93E7C59C6BE703966530FFBC723395EF /* FIRAuthAPNSToken.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthAPNSToken.m; path = FirebaseAuth/Sources/SystemService/FIRAuthAPNSToken.m; sourceTree = ""; }; + 9420AAD5DAC96CCA96AB03E31BD57796 /* FIRMutableData.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMutableData.m; path = FirebaseDatabase/Sources/Api/FIRMutableData.m; sourceTree = ""; }; + 944425105FFCFF644DC439575272B712 /* RLMSyncSession.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMSyncSession.mm; path = Realm/RLMSyncSession.mm; sourceTree = ""; }; + 94C405D207D05FB559806347FF4C3110 /* FIRInstallationsHTTPError.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInstallationsHTTPError.h; path = FirebaseInstallations/Source/Library/Errors/FIRInstallationsHTTPError.h; sourceTree = ""; }; + 94CA7DCE38C9B491A31260A067D071EA /* RLMProperty.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMProperty.h; path = include/RLMProperty.h; sourceTree = ""; }; + 94D7FB887A55186658BA2927E263E07E /* FListenComplete.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FListenComplete.m; path = FirebaseDatabase/Sources/FListenComplete.m; sourceTree = ""; }; + 94E05EC88F26D558B547C8E5D72E7792 /* FIROAuthCredential.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIROAuthCredential.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIROAuthCredential.h; sourceTree = ""; }; + 9506BA131E3841461239C5D751AD678A /* FLLRBEmptyNode.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FLLRBEmptyNode.m; path = FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBEmptyNode.m; sourceTree = ""; }; + 9533FA4F9B48BB2174C0ED30C78DFE7E /* FIRPhoneMultiFactorGenerator.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRPhoneMultiFactorGenerator.m; path = FirebaseAuth/Sources/MultiFactor/Phone/FIRPhoneMultiFactorGenerator.m; sourceTree = ""; }; + 955BE9FC76F7CE1DC6CEC4D0204858EB /* RLMEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMEvent.h; path = include/RLMEvent.h; sourceTree = ""; }; + 95EA0878DF345763F81B3830AECFF356 /* FIRInstallationsAuthTokenResultInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInstallationsAuthTokenResultInternal.h; path = FirebaseInstallations/Source/Library/FIRInstallationsAuthTokenResultInternal.h; sourceTree = ""; }; + 9668070A520556E1157179EFD5675DA2 /* iterator.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = iterator.h; path = include/leveldb/iterator.h; sourceTree = ""; }; + 96ED84605B32D89346896DDD098C7B7F /* FIRAuthUserDefaults.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthUserDefaults.h; path = FirebaseAuth/Sources/Storage/FIRAuthUserDefaults.h; sourceTree = ""; }; + 972B364EC6AF475E2DD052A2A60FFC2A /* FImmutableTree.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FImmutableTree.h; path = FirebaseDatabase/Sources/Core/Utilities/FImmutableTree.h; sourceTree = ""; }; + 97376E6BECB554DDCA9DBDA7C7CB9217 /* FIRLibrary.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRLibrary.h; path = FirebaseCore/Extension/FIRLibrary.h; sourceTree = ""; }; + 97392617A9D0A4229CD0CBA298E78B57 /* FSnapshotHolder.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FSnapshotHolder.h; path = FirebaseDatabase/Sources/Core/FSnapshotHolder.h; sourceTree = ""; }; + 975D4CE22FA4C1DA6407E67828831C8E /* FIRAuthTokenResult.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthTokenResult.m; path = FirebaseAuth/Sources/Auth/FIRAuthTokenResult.m; sourceTree = ""; }; + 97C24FBADCCD7036078377512D90D4D7 /* RLMRealmUtil.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMRealmUtil.mm; path = Realm/RLMRealmUtil.mm; sourceTree = ""; }; + 97D9C8B87E834414170ABFDA7040DB3C /* FIRVerifyAssertionRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRVerifyAssertionRequest.h; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h; sourceTree = ""; }; + 97F795562E65992BA4EA307E98284AC4 /* GTMSessionFetcher.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = GTMSessionFetcher.release.xcconfig; sourceTree = ""; }; + 98AA57D4F61DF5CEE54B53D96945100D /* FIRSecureTokenRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRSecureTokenRequest.m; path = FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenRequest.m; sourceTree = ""; }; + 98B7302B3903DB29AD102B2B4A7C077F /* FRepoManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FRepoManager.h; path = FirebaseDatabase/Sources/Core/FRepoManager.h; sourceTree = ""; }; + 99A3796A766AC39C09D1D998A183ED46 /* RLMCredentials.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMCredentials.h; path = include/RLMCredentials.h; sourceTree = ""; }; + 9A30C75392B91F7A665289F629130CC3 /* FIRAuthDataResult.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthDataResult.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthDataResult.h; sourceTree = ""; }; + 9ADF28900A460B3E7E1AF2D6D862756B /* FTupleUserCallback.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTupleUserCallback.h; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleUserCallback.h; sourceTree = ""; }; + 9B7D6683BB4B8820F7AFBD61BFB7F6B3 /* SafariServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SafariServices.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/SafariServices.framework; sourceTree = DEVELOPER_DIR; }; + 9B9A8FE44DFC70CD9D29C885FF6CB87F /* nanopb.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = nanopb.debug.xcconfig; sourceTree = ""; }; + 9C574899E21FF7BC5D52C1B2C2A1FB71 /* HeartbeatsBundle.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HeartbeatsBundle.swift; path = FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatsBundle.swift; sourceTree = ""; }; + 9C65A271995DEF7866A8ACEA5248CC93 /* FCancelEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FCancelEvent.m; path = FirebaseDatabase/Sources/Core/View/FCancelEvent.m; sourceTree = ""; }; + 9C6F5A54008F5FE3B7C04E60A783FF8F /* FPathIndex.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FPathIndex.h; path = FirebaseDatabase/Sources/FPathIndex.h; sourceTree = ""; }; + 9CEC0913FB88FE9BE18552047F830854 /* BSON.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BSON.swift; path = RealmSwift/BSON.swift; sourceTree = ""; }; + 9CF3F69586BC10D21D82153B4BF2A8E2 /* FOperationSource.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FOperationSource.m; path = FirebaseDatabase/Sources/Core/Operation/FOperationSource.m; sourceTree = ""; }; + 9D1A70BBED3AA1D1F9152581BE1E35B7 /* FIRTransactionResult.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRTransactionResult.h; path = FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRTransactionResult.h; sourceTree = ""; }; + 9D857BC602EF666E952EE6B1639A9508 /* FBLPromise+All.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+All.m"; path = "Sources/FBLPromises/FBLPromise+All.m"; sourceTree = ""; }; + 9D885A4F106B62B2C0DB2B5CE2D09E22 /* FTupleNodePath.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTupleNodePath.m; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleNodePath.m; sourceTree = ""; }; + 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; + 9DEFF50571A73345FEF094BB2FEDDBEC /* GULHeartbeatDateStorage.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULHeartbeatDateStorage.m; path = GoogleUtilities/Environment/GULHeartbeatDateStorage.m; sourceTree = ""; }; + 9E3E4E344F68B74F639CDE095DE89DEE /* FValidation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FValidation.m; path = FirebaseDatabase/Sources/Utilities/FValidation.m; sourceTree = ""; }; + 9E7451B12E477E50E5B6D057C62C9818 /* FValueEventRegistration.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FValueEventRegistration.m; path = FirebaseDatabase/Sources/Core/View/FValueEventRegistration.m; sourceTree = ""; }; + 9EC1D2A0AB969A937D8CCD9DA60C7715 /* FIndexedFilter.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIndexedFilter.h; path = FirebaseDatabase/Sources/Core/View/Filter/FIndexedFilter.h; sourceTree = ""; }; + 9ECD48B2C579D35E52365ED54C06D7A4 /* FOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FOperation.h; path = FirebaseDatabase/Sources/Core/Operation/FOperation.h; sourceTree = ""; }; + 9EE5FB69103270807821EFED952A8EA2 /* FTupleCallbackStatus.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTupleCallbackStatus.m; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleCallbackStatus.m; sourceTree = ""; }; + 9EED899C7A00C5E6FBC89D92F112061F /* FIRGoogleAuthProvider.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRGoogleAuthProvider.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRGoogleAuthProvider.h; sourceTree = ""; }; + 9F876082355922D63035B970213AB0CD /* FIRAuthWebView.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthWebView.h; path = FirebaseAuth/Sources/Utilities/FIRAuthWebView.h; sourceTree = ""; }; + 9FAAA110C793DEE87DD244F02733834B /* SectionedResults.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SectionedResults.swift; path = RealmSwift/SectionedResults.swift; sourceTree = ""; }; + 9FE4A6CCA174E0D63A5A98CABD8EC548 /* FIRHeartbeatLogger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRHeartbeatLogger.h; path = FirebaseCore/Extension/FIRHeartbeatLogger.h; sourceTree = ""; }; + 9FEB68EC6BAB21247A9560C3A523173B /* FIRPhoneAuthCredential_Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRPhoneAuthCredential_Internal.h; path = FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthCredential_Internal.h; sourceTree = ""; }; + 9FF9B18D901B58F5B274E797ABF8D03C /* FIRInstallationsIDController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRInstallationsIDController.m; path = FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsIDController.m; sourceTree = ""; }; + A02ACC5171F5816C4717036ECB8B255C /* FIRAppCheckInterop.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAppCheckInterop.h; path = FirebaseAppCheck/Interop/FIRAppCheckInterop.h; sourceTree = ""; }; + A030CC80807AF4C0FDC009471007CC14 /* PromisesObjC.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = PromisesObjC.release.xcconfig; sourceTree = ""; }; + A036C3B6F27E62C0413AA1CB052F1E9C /* FConstants.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FConstants.m; path = FirebaseDatabase/Sources/Constants/FConstants.m; sourceTree = ""; }; + A052E47398426D6826B82AAF3868DAA6 /* FOverwrite.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FOverwrite.h; path = FirebaseDatabase/Sources/Core/Operation/FOverwrite.h; sourceTree = ""; }; + A056A0728CEA9D82899D8B1F03886BDA /* FirebaseCore-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "FirebaseCore-dummy.m"; sourceTree = ""; }; + A1352CAA4472E809464D00B49A3A6BA6 /* FStorageEngine.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FStorageEngine.h; path = FirebaseDatabase/Sources/Persistence/FStorageEngine.h; sourceTree = ""; }; + A16A5315E18D376E152E91F55B367ED7 /* FChildEventRegistration.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FChildEventRegistration.m; path = FirebaseDatabase/Sources/Core/View/FChildEventRegistration.m; sourceTree = ""; }; + A21BE0CCC6934357A32AC861FDF64150 /* FIRSendVerificationCodeRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRSendVerificationCodeRequest.m; path = FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeRequest.m; sourceTree = ""; }; + A2C57AE6DAC312F02E876AD29647C664 /* FIRInstallationsAuthTokenResult.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInstallationsAuthTokenResult.h; path = FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallationsAuthTokenResult.h; sourceTree = ""; }; + A2F7F8DB85024F49526953B427B6486B /* FIRSignUpNewUserRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRSignUpNewUserRequest.h; path = FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.h; sourceTree = ""; }; + A3B0C6C9B2CD46F23B0B57ADFA239899 /* FTree.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTree.h; path = FirebaseDatabase/Sources/Core/Utilities/FTree.h; sourceTree = ""; }; + A3D9BAC3AE5D6F200CE6741CC7D8430A /* FIRAuthRPCRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthRPCRequest.h; path = FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h; sourceTree = ""; }; + A3DBB2AB553DB346C5F9A455867C76A4 /* FIRMultiFactorSession.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMultiFactorSession.m; path = FirebaseAuth/Sources/MultiFactor/FIRMultiFactorSession.m; sourceTree = ""; }; + A3FEEBB89E6BA6F6E8EA89482526C07C /* Pods-PRTY-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-PRTY-acknowledgements.markdown"; sourceTree = ""; }; + A431F7DED716295CBC39AAAC7731B616 /* FIRAuthRPCResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthRPCResponse.h; path = FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h; sourceTree = ""; }; + A43C946F25F4088423BBB29BB0D1E82F /* filter_policy.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = filter_policy.h; path = include/leveldb/filter_policy.h; sourceTree = ""; }; + A44E4167201C1AB4D63CA58B6C88B7D2 /* GULURLSessionDataResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULURLSessionDataResponse.h; path = GoogleUtilities/Environment/Public/GoogleUtilities/GULURLSessionDataResponse.h; sourceTree = ""; }; + A49A8CB71A70BD3B8FB71290DBA32D9F /* FListenProvider.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FListenProvider.m; path = FirebaseDatabase/Sources/Core/FListenProvider.m; sourceTree = ""; }; + A4AE47A83D9419056CA5152B8060EB57 /* FIRMultiFactorAssertion.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMultiFactorAssertion.m; path = FirebaseAuth/Sources/MultiFactor/FIRMultiFactorAssertion.m; sourceTree = ""; }; + A57BCC415D3BC94E35EB525E03037615 /* RLMNetworkTransport.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMNetworkTransport.h; path = include/RLMNetworkTransport.h; sourceTree = ""; }; + A5D259662259C7BE1415453C22210DCA /* FIRAuthProtoStartMFAPhoneRequestInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthProtoStartMFAPhoneRequestInfo.h; path = FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoStartMFAPhoneRequestInfo.h; sourceTree = ""; }; + A5FF33CC502EBCFB234B8B0CAB937207 /* FIRSendVerificationCodeRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRSendVerificationCodeRequest.h; path = FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeRequest.h; sourceTree = ""; }; + A6EE078C25A16F573B5605E4E7F0BC2E /* HeartbeatLoggingTestUtils.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HeartbeatLoggingTestUtils.swift; path = FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatLoggingTestUtils.swift; sourceTree = ""; }; + A7136DC79F7CF21A918462EA6BA72D9F /* FIRInstallationsBackoffController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRInstallationsBackoffController.m; path = FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsBackoffController.m; sourceTree = ""; }; + A74279679B1A5D45438D0DDBFDE0CA14 /* RLMPushClient.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMPushClient.mm; path = Realm/RLMPushClient.mm; sourceTree = ""; }; + A77530BCB920D9861E25B63BE3E4443E /* RLMArray_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMArray_Private.h; path = include/RLMArray_Private.h; sourceTree = ""; }; + A777775526F20173795213860C79ADEE /* FLLRBValueNode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FLLRBValueNode.h; path = FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FLLRBValueNode.h; sourceTree = ""; }; + A7E4C9186535EBC191900B137507E328 /* GULSwizzler.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULSwizzler.m; path = GoogleUtilities/MethodSwizzler/GULSwizzler.m; sourceTree = ""; }; + A800F833AC5404F3FA4FC8CC82716281 /* FIRWithdrawMFARequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRWithdrawMFARequest.h; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFARequest.h; sourceTree = ""; }; + A81FDBBC145D10A1514304C22193715C /* coding.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = coding.h; path = util/coding.h; sourceTree = ""; }; + A8F9DB69F1C068D0A79E78FF631D2D07 /* FirebaseAppCheckInterop-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "FirebaseAppCheckInterop-umbrella.h"; sourceTree = ""; }; + A92EF1CA905127F130D1776E993E98FD /* GULNetworkInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULNetworkInternal.h; path = GoogleUtilities/Network/GULNetworkInternal.h; sourceTree = ""; }; + A98F6CF369D6452E984735A431BE0790 /* FIRLibrary.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRLibrary.h; path = FirebaseCore/Extension/FIRLibrary.h; sourceTree = ""; }; + A99DA8352A55CF898457A0B158BB8961 /* FIRAuthProtoFinalizeMFAPhoneRequestInfo.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthProtoFinalizeMFAPhoneRequestInfo.m; path = FirebaseAuth/Sources/Backend/RPC/Proto/Phone/FIRAuthProtoFinalizeMFAPhoneRequestInfo.m; sourceTree = ""; }; + A9B5783D1DF0F07EC4CC01D3E05F348C /* FTypedefs_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTypedefs_Private.h; path = FirebaseDatabase/Sources/Api/Private/FTypedefs_Private.h; sourceTree = ""; }; + A9C5CAC11B532C8059B2E2040D5A2AE7 /* FIRSetAccountInfoResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRSetAccountInfoResponse.m; path = FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoResponse.m; sourceTree = ""; }; + A9CB8D94CC94FDEDC76F63707334A585 /* FPersistenceManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FPersistenceManager.h; path = FirebaseDatabase/Sources/Persistence/FPersistenceManager.h; sourceTree = ""; }; + A9D715562896C77226A34E182B52AE9E /* RLMProviderClient.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMProviderClient.h; path = include/RLMProviderClient.h; sourceTree = ""; }; + AA83942C00F87EB03B1859665331F578 /* FirebaseDatabase.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FirebaseDatabase.h; path = FirebaseDatabase/Sources/Public/FirebaseDatabase/FirebaseDatabase.h; sourceTree = ""; }; + AAD3672222B78EF845809BCE176BC39C /* FImmutableSortedSet.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FImmutableSortedSet.m; path = FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedSet.m; sourceTree = ""; }; + AAE0B0D562FECE9B4EA7BD57332F263C /* db_impl.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = db_impl.h; path = db/db_impl.h; sourceTree = ""; }; + ABC7F498E2FC7E903D6F8640E17F788A /* Pods-PRTYTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-PRTYTests.debug.xcconfig"; sourceTree = ""; }; + ABCC74735035AF922CF393EA7C93A204 /* FIndexedNode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIndexedNode.h; path = FirebaseDatabase/Sources/Snapshot/FIndexedNode.h; sourceTree = ""; }; + ABE3480E6C4EFBD93505A4B57A945898 /* dumpfile.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = dumpfile.h; path = include/leveldb/dumpfile.h; sourceTree = ""; }; + AC261D7B91CBC6A2616EEE91114F83A5 /* FIRMultiFactorResolver.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMultiFactorResolver.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorResolver.h; sourceTree = ""; }; + AC3496D1774819DE9FF283E783E8FD57 /* FTransformedEnumerator.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTransformedEnumerator.h; path = FirebaseDatabase/Sources/FTransformedEnumerator.h; sourceTree = ""; }; + AC40BB501A5BB0BEBA4E9E370E027119 /* FirebaseAnalytics.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FirebaseAnalytics.debug.xcconfig; sourceTree = ""; }; + AC67D1A683AEF0B1D0C65AE006AFDD82 /* env_posix.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = env_posix.cc; path = util/env_posix.cc; sourceTree = ""; }; + AC8ABFC882AE8D079F88275E0F5AA22D /* FIRAdditionalUserInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAdditionalUserInfo.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRAdditionalUserInfo.h; sourceTree = ""; }; + AD0FDF20ADB9C0908115F409C91E242F /* FBLPromise+Reduce.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Reduce.h"; path = "Sources/FBLPromises/include/FBLPromise+Reduce.h"; sourceTree = ""; }; + AD80C00D5C4B562AD2F08B823827B159 /* env.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = env.h; path = include/leveldb/env.h; sourceTree = ""; }; + ADB9AD101FB170D305160E82F1CC2AA3 /* mutexlock.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = mutexlock.h; path = util/mutexlock.h; sourceTree = ""; }; + ADD8E035121D65CDD6CF8FEC0FE3FBFD /* repair.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = repair.cc; path = db/repair.cc; sourceTree = ""; }; + ADE396F87DDA126FB067A8765E2CCFA7 /* Pods-PRTY.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-PRTY.debug.xcconfig"; sourceTree = ""; }; + AE140AEAF52DA37BEE141D52E151594A /* table.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = table.h; path = include/leveldb/table.h; sourceTree = ""; }; + AE21984D85FCC8A58C4A3DEB607EE9B3 /* arena.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = arena.h; path = util/arena.h; sourceTree = ""; }; + AEB1B3775C7B162C71502AB49434EE36 /* FViewProcessor.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FViewProcessor.h; path = FirebaseDatabase/Sources/FViewProcessor.h; sourceTree = ""; }; + AEB6A7434EF1F3E8455BFE975EDDDC33 /* FIRDatabaseConfig_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDatabaseConfig_Private.h; path = FirebaseDatabase/Sources/FIRDatabaseConfig_Private.h; sourceTree = ""; }; + AEDA4EF090CB0277725FB18D19FD8AC3 /* Pods-PRTY-PRTYUITests-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-PRTY-PRTYUITests-frameworks.sh"; sourceTree = ""; }; + AEF6388410F1929F5AE36C5D9175EBC3 /* FIRDatabaseQuery.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDatabaseQuery.h; path = FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseQuery.h; sourceTree = ""; }; + AF32F1890AC304CEACE3EC8163C6D595 /* builder.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = builder.cc; path = db/builder.cc; sourceTree = ""; }; + AF4C27BB7CD817442F90B3068C676B6B /* RLMArray.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMArray.h; path = include/RLMArray.h; sourceTree = ""; }; + AFB356F5255300E6FB821BAEBE11CEAA /* FQueryParams.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FQueryParams.h; path = FirebaseDatabase/Sources/Core/FQueryParams.h; sourceTree = ""; }; + AFBE43B2C0C2AF9EBCECCCEBBC8D162B /* RLMMigration.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMMigration.h; path = include/RLMMigration.h; sourceTree = ""; }; + AFF21A3F40FF482B7644277954FE53A4 /* FIROAuthProvider.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIROAuthProvider.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIROAuthProvider.h; sourceTree = ""; }; + B0C06E7081B48799232D89E17EB0A49B /* FImmutableSortedSet.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FImmutableSortedSet.h; path = FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedSet.h; sourceTree = ""; }; + B0C804B4546C72B739AD4D126464376F /* hash.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = hash.h; path = util/hash.h; sourceTree = ""; }; + B0CBE3B4CF9091DD07FE7658445755DA /* RLMUtil.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMUtil.mm; path = Realm/RLMUtil.mm; sourceTree = ""; }; + B0F9C1B839FB025457D8E24B0D0E8D9A /* RLMScheduler.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMScheduler.h; path = include/RLMScheduler.h; sourceTree = ""; }; + B11618F2A39522921E515B9556E49021 /* comparator.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = comparator.h; path = include/leveldb/comparator.h; sourceTree = ""; }; + B1383C44D5CC1F593039878620AA112C /* memtable.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = memtable.cc; path = db/memtable.cc; sourceTree = ""; }; + B13B7BABC1263F4E9BC3D14D6AC1096F /* FIRCurrentDateProvider.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRCurrentDateProvider.h; path = FirebaseInstallations/Source/Library/InstallationsIDController/FIRCurrentDateProvider.h; sourceTree = ""; }; + B13E4C7F03E85F82326BD44C4F58BB36 /* FIRMultiFactor.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMultiFactor.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactor.h; sourceTree = ""; }; + B144E5E3A8596BD2FAAEAA56BDD6A884 /* FIRDeleteAccountRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRDeleteAccountRequest.m; path = FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountRequest.m; sourceTree = ""; }; + B16C94E5F3A025995171BD475489E65F /* write_batch.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = write_batch.h; path = include/leveldb/write_batch.h; sourceTree = ""; }; + B16EB04DE78E887824E1C8DBFC66B5F5 /* FIRComponentContainer.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRComponentContainer.m; path = FirebaseCore/Sources/FIRComponentContainer.m; sourceTree = ""; }; + B1DEC2457D87D238E0CD170552886919 /* FIRAuthInterop.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthInterop.h; path = FirebaseAuth/Interop/FIRAuthInterop.h; sourceTree = ""; }; + B1EE524838C98D6E19AF4CF8DB02D099 /* RLMEmailPasswordAuth.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMEmailPasswordAuth.h; path = include/RLMEmailPasswordAuth.h; sourceTree = ""; }; + B2750DC4306D28633B3876C5C545F55F /* GULUserDefaults.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULUserDefaults.h; path = GoogleUtilities/UserDefaults/Public/GoogleUtilities/GULUserDefaults.h; sourceTree = ""; }; + B30E8A2EFD646DD32FBF567E54E8FE3A /* FIRVerifyCustomTokenResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRVerifyCustomTokenResponse.m; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenResponse.m; sourceTree = ""; }; + B328E2210DE31FBAA889235596BD786D /* FIRTransactionResult.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRTransactionResult.m; path = FirebaseDatabase/Sources/Api/FIRTransactionResult.m; sourceTree = ""; }; + B36227C53E719CE8182B4FB7ACEEC2DA /* FirebaseAuth.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FirebaseAuth.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FirebaseAuth.h; sourceTree = ""; }; + B3B9F9E57BAB9DB88B08810413E1BFD7 /* two_level_iterator.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = two_level_iterator.cc; path = table/two_level_iterator.cc; sourceTree = ""; }; + B3FD9E5801F2AD2BD362344F93669102 /* NSData+FIRBase64.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "NSData+FIRBase64.m"; path = "FirebaseAuth/Sources/Utilities/NSData+FIRBase64.m"; sourceTree = ""; }; + B40F9A123AE0840B522636A66050A271 /* FEventGenerator.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FEventGenerator.m; path = FirebaseDatabase/Sources/FEventGenerator.m; sourceTree = ""; }; + B43874C6CBB50E7134FBEC24BABFE14F /* GoogleUtilities */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = GoogleUtilities; path = GoogleUtilities.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + B438E42DDF19AE28B09823D0CCEC5714 /* FIROptionsInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIROptionsInternal.h; path = FirebaseCore/Extension/FIROptionsInternal.h; sourceTree = ""; }; + B508FF5F45501FC204670A03072D40AF /* RLMAccessor.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMAccessor.h; path = include/RLMAccessor.h; sourceTree = ""; }; + B50D0C80ED816334D64C4012ABDB6D91 /* FChildChangeAccumulator.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FChildChangeAccumulator.h; path = FirebaseDatabase/Sources/Core/View/Filter/FChildChangeAccumulator.h; sourceTree = ""; }; + B553FE0894FC0F9CFAA1014CF6D4F9DC /* RLMApp.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMApp.h; path = include/RLMApp.h; sourceTree = ""; }; + B563271FE374CC1858749750DE0541AB /* GTMSessionFetcher.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GTMSessionFetcher.m; path = Sources/Core/GTMSessionFetcher.m; sourceTree = ""; }; + B5779CA3FF1DD9E71297A3043E11DC63 /* FIRUserMetadata.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRUserMetadata.m; path = FirebaseAuth/Sources/User/FIRUserMetadata.m; sourceTree = ""; }; + B58E731F045F472B2AE7CE066F291251 /* GULHeartbeatDateStorable.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULHeartbeatDateStorable.h; path = GoogleUtilities/Environment/Public/GoogleUtilities/GULHeartbeatDateStorable.h; sourceTree = ""; }; + B5D5E48B2A9BCFDED384060054046493 /* hash.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = hash.cc; path = util/hash.cc; sourceTree = ""; }; + B6636FC9D55BA423AE5D31143F16C3C6 /* FIRDatabase.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRDatabase.m; path = FirebaseDatabase/Sources/Api/FIRDatabase.m; sourceTree = ""; }; + B664529372060D95B49A4C4F210AFB3B /* FIROptions.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIROptions.m; path = FirebaseCore/Sources/FIROptions.m; sourceTree = ""; }; + B699CB81D7A551A9BE7FB104B80D114D /* FIRAuthGlobalWorkQueue.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthGlobalWorkQueue.h; path = FirebaseAuth/Sources/Auth/FIRAuthGlobalWorkQueue.h; sourceTree = ""; }; + B6A729DD21BF2EF3E08B418A6DA898B0 /* FBLPromise+Wrap.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Wrap.m"; path = "Sources/FBLPromises/FBLPromise+Wrap.m"; sourceTree = ""; }; + B6AC0D7DAB5655B6C98E8132C5F02847 /* FIRMultiFactorSession.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMultiFactorSession.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorSession.h; sourceTree = ""; }; + B6AF9354970089CC782E648426B0F62D /* env.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = env.cc; path = util/env.cc; sourceTree = ""; }; + B71930D36867FE650530A67FF1AE536D /* PromisesObjC.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = PromisesObjC.modulemap; sourceTree = ""; }; + B7487725A4319C3CAF8225F0C8F99718 /* GULNetwork.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULNetwork.m; path = GoogleUtilities/Network/GULNetwork.m; sourceTree = ""; }; + B759001AEC2B36BC2B380644FBF8AEE3 /* FMaxNode.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FMaxNode.m; path = FirebaseDatabase/Sources/FMaxNode.m; sourceTree = ""; }; + B7596BDDECA588FCF52569F283CD745F /* FTransformedEnumerator.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTransformedEnumerator.m; path = FirebaseDatabase/Sources/FTransformedEnumerator.m; sourceTree = ""; }; + B76E93B48A5797509F56D1C0B9296D4C /* FTupleOnDisconnect.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTupleOnDisconnect.h; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleOnDisconnect.h; sourceTree = ""; }; + B7817A8A19488A6E5E1F62D68DACF069 /* FIRAuthAPNSToken.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthAPNSToken.h; path = FirebaseAuth/Sources/SystemService/FIRAuthAPNSToken.h; sourceTree = ""; }; + B7D00F668FCD769C1AF57B80F9EF273E /* log_format.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = log_format.h; path = db/log_format.h; sourceTree = ""; }; + B843B5687B1E7F297B8EDE84FB98D92D /* RLMCollection.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMCollection.mm; path = Realm/RLMCollection.mm; sourceTree = ""; }; + B860C210552E04D159F16FAC9529BE68 /* options.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = options.cc; path = util/options.cc; sourceTree = ""; }; + B87AF41DF8B5A0C0F400BC9F24C530D1 /* FIRSignUpNewUserResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRSignUpNewUserResponse.m; path = FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserResponse.m; sourceTree = ""; }; + B91A58F056260B927AC64B4781263521 /* FirebaseAppCheckInterop.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = FirebaseAppCheckInterop.modulemap; sourceTree = ""; }; + B947898B4454551FA9410269740D2F69 /* FIRDataSnapshot.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDataSnapshot.h; path = FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDataSnapshot.h; sourceTree = ""; }; + B96EBCC46DCBEDE26365D7AC85351CC5 /* FIRBundleUtil.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRBundleUtil.m; path = FirebaseCore/Sources/FIRBundleUtil.m; sourceTree = ""; }; + B98A05D5A1CDC09C8D241FDD9E8942CA /* FIRDeleteAccountResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDeleteAccountResponse.h; path = FirebaseAuth/Sources/Backend/RPC/FIRDeleteAccountResponse.h; sourceTree = ""; }; + B997ABCC90C9366DF38FDE06D380B2A8 /* FTypedefs.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTypedefs.h; path = FirebaseDatabase/Sources/Utilities/FTypedefs.h; sourceTree = ""; }; + B9DF9F7043C387E6BBD41BFE4E656257 /* RLMEmailPasswordAuth.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMEmailPasswordAuth.mm; path = Realm/RLMEmailPasswordAuth.mm; sourceTree = ""; }; + BA4BB1B3E24F76A1197B5722E1A54B84 /* FIRInstallations.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInstallations.h; path = FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallations.h; sourceTree = ""; }; + BA97061F190CEDC6C816E99501895270 /* FIRHeartbeatLogger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRHeartbeatLogger.h; path = FirebaseCore/Extension/FIRHeartbeatLogger.h; sourceTree = ""; }; + BAA2696F7FBBB1CBD28CC9EE73BA0480 /* FIRSetAccountInfoRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRSetAccountInfoRequest.m; path = FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoRequest.m; sourceTree = ""; }; + BAEF988E635365578AACECB2A52620D3 /* RLMResults.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMResults.mm; path = Realm/RLMResults.mm; sourceTree = ""; }; + BB1C8573631EC09896F9F87AF31645E6 /* ThreadSafeReference.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ThreadSafeReference.swift; path = RealmSwift/ThreadSafeReference.swift; sourceTree = ""; }; + BB43DCDDF68FDAA8606A46164F080265 /* options.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = options.h; path = include/leveldb/options.h; sourceTree = ""; }; + BB799EAE95DCF5C0E5C3CA09470ABA2C /* FBLPromise+Catch.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Catch.h"; path = "Sources/FBLPromises/include/FBLPromise+Catch.h"; sourceTree = ""; }; + BBC0FDBE9BF419C3332954C5D758AE2F /* FMaxNode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FMaxNode.h; path = FirebaseDatabase/Sources/FMaxNode.h; sourceTree = ""; }; + BC987A1227156846E08850D86560BDF5 /* FBLPromise+Then.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Then.h"; path = "Sources/FBLPromises/include/FBLPromise+Then.h"; sourceTree = ""; }; + BCBB934EA3FEB2A60AAE97D3799103B3 /* PromisesObjC.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = PromisesObjC.debug.xcconfig; sourceTree = ""; }; + BCD33795AF033DD0357292495050944A /* merger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = merger.h; path = table/merger.h; sourceTree = ""; }; + BD0338B357A3CDE8F82D07CC33E9666E /* FIRMultiFactorInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMultiFactorInfo.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorInfo.h; sourceTree = ""; }; + BD7537EC51FC4F1A9702E002BC025FDE /* FIRApp.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRApp.h; path = FirebaseCore/Sources/Public/FirebaseCore/FIRApp.h; sourceTree = ""; }; + BD9D20F856B549632C5B821F2B74BCFC /* RLMFindOptions.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMFindOptions.h; path = include/RLMFindOptions.h; sourceTree = ""; }; + BDE9BA49B88ABDE1B7B491F0876E56D6 /* comparator.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = comparator.cc; path = util/comparator.cc; sourceTree = ""; }; + BE470ED8559FFF0453FC817C2D585A1F /* FPersistentConnection.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FPersistentConnection.h; path = FirebaseDatabase/Sources/Core/FPersistentConnection.h; sourceTree = ""; }; + BE522E5C99C9F08611559181764D55B9 /* Realm.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Realm.swift; path = RealmSwift/Realm.swift; sourceTree = ""; }; + BE5EA9BAFBD4C1C39027D404A599B6E0 /* FIRAuthErrorUtils.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthErrorUtils.m; path = FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.m; sourceTree = ""; }; + BE6CCDBE7A5141FB59661292B11561C0 /* FIRInstallationsIIDStore.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRInstallationsIIDStore.m; path = FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDStore.m; sourceTree = ""; }; + BE904D1FED7D94CEE1F8C3A0FCC83148 /* FIRLogger.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRLogger.m; path = FirebaseCore/Sources/FIRLogger.m; sourceTree = ""; }; + BE9749E67C035DA4EB9E5F6AB5530370 /* FTupleFirebase.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTupleFirebase.m; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleFirebase.m; sourceTree = ""; }; + BEA7AE33B74AF59CA502D5FDE7DCD982 /* FIREmailAuthProvider.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIREmailAuthProvider.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIREmailAuthProvider.h; sourceTree = ""; }; + BF274B2900480BCAE368E294B73E5B23 /* FIRAuthUIDelegate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthUIDelegate.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthUIDelegate.h; sourceTree = ""; }; + BF356E62ADDF306CEFC4B8245B5BCE68 /* FIRAuthWebView.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthWebView.m; path = FirebaseAuth/Sources/Utilities/FIRAuthWebView.m; sourceTree = ""; }; + BF5A2E32B76BCCEDB11A4CC15B579BBB /* FBLPromise+Timeout.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Timeout.m"; path = "Sources/FBLPromises/FBLPromise+Timeout.m"; sourceTree = ""; }; + C01A8C68201D99996D349D3CE0CAC1EA /* RLMCollection.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMCollection.h; path = include/RLMCollection.h; sourceTree = ""; }; + C0691B5031307C17D3FEEF999A793420 /* Pods-PRTY-PRTYUITests */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = "Pods-PRTY-PRTYUITests"; path = Pods_PRTY_PRTYUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + C0D3E9D94E45F0CA51973A4FC3F7A77D /* FBLPromise+Always.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Always.m"; path = "Sources/FBLPromises/FBLPromise+Always.m"; sourceTree = ""; }; + C1998E0D8085221AD87F89B614C10E52 /* GTMSessionFetcher */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = GTMSessionFetcher; path = GTMSessionFetcher.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + C20CAC628237BB9D607750E34695E5FC /* GULNetworkLoggerProtocol.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULNetworkLoggerProtocol.h; path = GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkLoggerProtocol.h; sourceTree = ""; }; + C21BB75CDBF87E02D19B34054FA40340 /* FIRAuth.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuth.m; path = FirebaseAuth/Sources/Auth/FIRAuth.m; sourceTree = ""; }; + C221AE887079015A8381423D3733ED04 /* FIRGetOOBConfirmationCodeResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRGetOOBConfirmationCodeResponse.h; path = FirebaseAuth/Sources/Backend/RPC/FIRGetOOBConfirmationCodeResponse.h; sourceTree = ""; }; + C259035AB4864FBC222C048097AEDB6A /* FIRComponentType.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRComponentType.h; path = FirebaseCore/Extension/FIRComponentType.h; sourceTree = ""; }; + C29E8533FF9AF637113A7A692C0FD27D /* ObjectiveCSupport+AnyRealmValue.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ObjectiveCSupport+AnyRealmValue.swift"; path = "RealmSwift/ObjectiveCSupport+AnyRealmValue.swift"; sourceTree = ""; }; + C2CC7D967ED5502EA688B2B429A6B2E0 /* FIRVerifyPasswordResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRVerifyPasswordResponse.h; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordResponse.h; sourceTree = ""; }; + C33F49AFBB23402149BEFBFF42FB5ABE /* Util.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Util.swift; path = RealmSwift/Util.swift; sourceTree = ""; }; + C341B5E37833446B630AF47E00CECF59 /* FIRAuthBackend+MultiFactor.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FIRAuthBackend+MultiFactor.m"; path = "FirebaseAuth/Sources/Backend/FIRAuthBackend+MultiFactor.m"; sourceTree = ""; }; + C36ACCDE3C319DC975D64D8C09A4CB3C /* GULURLSessionDataResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULURLSessionDataResponse.m; path = GoogleUtilities/Environment/URLSessionPromiseWrapper/GULURLSessionDataResponse.m; sourceTree = ""; }; + C375A35EEAB2E08FC388D263A6209408 /* RealmCollection.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RealmCollection.swift; path = RealmSwift/RealmCollection.swift; sourceTree = ""; }; + C37804A80D841783D9BF3A30B9F8016A /* FIRAuthExceptionUtils.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthExceptionUtils.m; path = FirebaseAuth/Sources/Utilities/FIRAuthExceptionUtils.m; sourceTree = ""; }; + C3837D45F314C1B4B6B4AD233C4F06DC /* FIRInstallationsIDController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInstallationsIDController.h; path = FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsIDController.h; sourceTree = ""; }; + C3AB1EF8BE9154067AF395162065B7F7 /* FNamedNode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FNamedNode.h; path = FirebaseDatabase/Sources/FNamedNode.h; sourceTree = ""; }; + C3FBA578EB9F1A354876E51D1ECFC603 /* GULSwizzler.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULSwizzler.h; path = GoogleUtilities/MethodSwizzler/Public/GoogleUtilities/GULSwizzler.h; sourceTree = ""; }; + C4326A02499E82B8CB0C1B52ED00762C /* FIRStartMFASignInRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRStartMFASignInRequest.m; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInRequest.m; sourceTree = ""; }; + C43AF87E49A1E6F9EB9613D7269CD983 /* FPersistentConnection.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FPersistentConnection.m; path = FirebaseDatabase/Sources/Core/FPersistentConnection.m; sourceTree = ""; }; + C443F6191AE6D9CA89D2B2D541E2329E /* FIRBundleUtil.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRBundleUtil.h; path = FirebaseCore/Sources/FIRBundleUtil.h; sourceTree = ""; }; + C4AEE519BA69496F1FD1C1F661D8E156 /* FIRAuthDispatcher.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthDispatcher.m; path = FirebaseAuth/Sources/Auth/FIRAuthDispatcher.m; sourceTree = ""; }; + C4E718B55509A9AA2889EA254EA608CA /* FAckUserWrite.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FAckUserWrite.h; path = FirebaseDatabase/Sources/Core/Operation/FAckUserWrite.h; sourceTree = ""; }; + C586384ED84D2D56FFBE9589841A7C36 /* FIRMultiFactorAssertion.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMultiFactorAssertion.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRMultiFactorAssertion.h; sourceTree = ""; }; + C58E9D971BEAA0B2666855E46772D815 /* GULApplication.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULApplication.h; path = GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULApplication.h; sourceTree = ""; }; + C600859214CB6427CF9C135B659E3AF6 /* GTMSessionFetcherService.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GTMSessionFetcherService.m; path = Sources/Core/GTMSessionFetcherService.m; sourceTree = ""; }; + C6275AF2BB6CE62341D7E3633E717BEE /* logging.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = logging.h; path = util/logging.h; sourceTree = ""; }; + C6545A3F8EC8ED4010C4BE7D98E69E88 /* FIRVerifyClientResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRVerifyClientResponse.m; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientResponse.m; sourceTree = ""; }; + C69F72C06B9F4D036CD7680BFD656FDB /* RLMObjectBase.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMObjectBase.h; path = include/RLMObjectBase.h; sourceTree = ""; }; + C6B2640364AB64A02A4091061D24152C /* RLMError.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMError.h; path = include/RLMError.h; sourceTree = ""; }; + C6C3FF34757A1E2892183B49F5842784 /* FImmutableSortedDictionary.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FImmutableSortedDictionary.m; path = FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedDictionary.m; sourceTree = ""; }; + C6F22D9B59162F598669602515CE72D5 /* FirebaseDatabase-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "FirebaseDatabase-Info.plist"; sourceTree = ""; }; + C71C4ABD7D0982DB872418B5A8E88A5E /* FIROptions.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIROptions.h; path = FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h; sourceTree = ""; }; + C770CCEDA892E21FD63BD717C4A20708 /* db_impl.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = db_impl.cc; path = db/db_impl.cc; sourceTree = ""; }; + C7A2103476D3B0BEBCA3691034634FDD /* FIRRetryHelper.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRRetryHelper.h; path = FirebaseDatabase/Sources/Core/Utilities/FIRRetryHelper.h; sourceTree = ""; }; + C7A7A909033C8FDAD8F306BF09436C37 /* FIRUserInfoImpl.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRUserInfoImpl.h; path = FirebaseAuth/Sources/User/FIRUserInfoImpl.h; sourceTree = ""; }; + C7DC07E2418DC49BC8D66013DDA60E0B /* Pods-PRTYTests-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-PRTYTests-acknowledgements.markdown"; sourceTree = ""; }; + C8357ED2FAC9005A1B855EDE918C7AF5 /* GULKeychainStorage.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULKeychainStorage.h; path = GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainStorage.h; sourceTree = ""; }; + C8756C73EF22A551744BB081DCF4FDEA /* NSData+SRB64Additions.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "NSData+SRB64Additions.h"; path = "FirebaseDatabase/Sources/third_party/SocketRocket/NSData+SRB64Additions.h"; sourceTree = ""; }; + C8B8699512E125DAF372EB2BA3CFB387 /* GULNSData+zlib.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "GULNSData+zlib.h"; path = "GoogleUtilities/NSData+zlib/Public/GoogleUtilities/GULNSData+zlib.h"; sourceTree = ""; }; + C8BDC147022A51D0ED823DC6230006BB /* c.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = c.cc; path = db/c.cc; sourceTree = ""; }; + C8CAF3FC639EB612E0500A5FAA2028C6 /* RLMDecimal128.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMDecimal128.h; path = include/RLMDecimal128.h; sourceTree = ""; }; + C8FAC6B7AC02F097592BE88CD4EABC83 /* GULSceneDelegateSwizzler_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULSceneDelegateSwizzler_Private.h; path = GoogleUtilities/AppDelegateSwizzler/Internal/GULSceneDelegateSwizzler_Private.h; sourceTree = ""; }; + C97005B66F0BCD1C70222679991C6EF8 /* FIRAuthWebUtils.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAuthWebUtils.m; path = FirebaseAuth/Sources/Utilities/FIRAuthWebUtils.m; sourceTree = ""; }; + C9D1BC99201338B767AF74599605CBAB /* RLMSyncConfiguration_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMSyncConfiguration_Private.h; path = include/RLMSyncConfiguration_Private.h; sourceTree = ""; }; + CA22FD4400AA8E8CB40D6E656136F272 /* FIndexedNode.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIndexedNode.m; path = FirebaseDatabase/Sources/Snapshot/FIndexedNode.m; sourceTree = ""; }; + CA25B306FFAA76849CE6925F041F4116 /* FBLPromise+Async.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Async.h"; path = "Sources/FBLPromises/include/FBLPromise+Async.h"; sourceTree = ""; }; + CA25BAC788742E5802F043AFAF3A8086 /* FLimitedFilter.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FLimitedFilter.h; path = FirebaseDatabase/Sources/Core/View/Filter/FLimitedFilter.h; sourceTree = ""; }; + CA3763A5C3BE75A0E0860942F867C9E8 /* FConnection.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FConnection.m; path = FirebaseDatabase/Sources/Realtime/FConnection.m; sourceTree = ""; }; + CA91F1F593BC0E1D3C7684615182D7CF /* FirebaseInstallations.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FirebaseInstallations.debug.xcconfig; sourceTree = ""; }; + CAA738EABBD697265171DE3DAC8E0C17 /* FIRAuthSettings.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthSettings.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthSettings.h; sourceTree = ""; }; + CAACC193A9AD2AE454E57F5C3EF6F1D4 /* FNextPushId.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FNextPushId.m; path = FirebaseDatabase/Sources/Utilities/FNextPushId.m; sourceTree = ""; }; + CAE042BCC7FF44CC71EC43BF6F7B7CBA /* FBLPromise+Then.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Then.m"; path = "Sources/FBLPromises/FBLPromise+Then.m"; sourceTree = ""; }; + CB623088DFC607EEA6CC6E2C99E661BB /* GULReachabilityChecker.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULReachabilityChecker.h; path = GoogleUtilities/Reachability/Public/GoogleUtilities/GULReachabilityChecker.h; sourceTree = ""; }; + CB6CC9C42F657883774DDF1FC12F6B95 /* filter_block.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = filter_block.cc; path = table/filter_block.cc; sourceTree = ""; }; + CB6EC6D167E8A3AB0DFE54EBC765CAA3 /* thread_annotations.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = thread_annotations.h; path = port/thread_annotations.h; sourceTree = ""; }; + CBE5568FBAD64B88E9DEBA7097A70ACB /* GULMutableDictionary.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULMutableDictionary.h; path = GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h; sourceTree = ""; }; + CBF04219BF0CCF068C34ECBB735714FC /* RLMApp.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMApp.mm; path = Realm/RLMApp.mm; sourceTree = ""; }; + CBF3DACAC92F02382C074F36C5FF59C1 /* FIRHeartbeatLogger.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRHeartbeatLogger.m; path = FirebaseCore/Sources/FIRHeartbeatLogger.m; sourceTree = ""; }; + CC35B50226DE5DE0D691E21CE1CAED70 /* RLMPushClient.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMPushClient.h; path = include/RLMPushClient.h; sourceTree = ""; }; + CC576E1F438D451BD01C77F7B27C65A8 /* FIRStartMFAEnrollmentResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStartMFAEnrollmentResponse.h; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRStartMFAEnrollmentResponse.h; sourceTree = ""; }; + CC6D95242984ED92CFCC5367CC6F5AFE /* FIRAuthErrors.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthErrors.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthErrors.h; sourceTree = ""; }; + CD98D5EB6316186187D122179DDBB9DF /* Firebase.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Firebase.release.xcconfig; sourceTree = ""; }; + CDB00D7D033A76284F4C2D94CD218ADA /* FIRInstallationsBackoffController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInstallationsBackoffController.h; path = FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsBackoffController.h; sourceTree = ""; }; + CDCA1EBD36A9944DE635F52ECFC297C6 /* RLMSyncConfiguration.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMSyncConfiguration.mm; path = Realm/RLMSyncConfiguration.mm; sourceTree = ""; }; + CE2E12DEE7E27510B2C96E2C68424DA6 /* RLMUpdateResult.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMUpdateResult.h; path = include/RLMUpdateResult.h; sourceTree = ""; }; + CE3CC14F5AC1D8BCEC33860FC79E5344 /* FValidation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FValidation.h; path = FirebaseDatabase/Sources/Utilities/FValidation.h; sourceTree = ""; }; + CEAE96632CC2337ED6A14302B3022EC8 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/SystemConfiguration.framework; sourceTree = DEVELOPER_DIR; }; + CEBA35B3F0A1172CCFDD4B627C065870 /* Realm.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = Realm.modulemap; sourceTree = ""; }; + CEBEE94472042794604075BCA211146D /* slice.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = slice.h; path = include/leveldb/slice.h; sourceTree = ""; }; + CEC46A5E041A4A0D0E0314CF5F667FFD /* GoogleAppMeasurement.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = GoogleAppMeasurement.debug.xcconfig; sourceTree = ""; }; + CED95F9ADEF91DF005475A84C722E6FA /* FClock.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FClock.h; path = FirebaseDatabase/Sources/FClock.h; sourceTree = ""; }; + CF1CF80E33E84E4C4E5880610EEEB26B /* RLMProperty.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMProperty.mm; path = Realm/RLMProperty.mm; sourceTree = ""; }; + CF1F64FF1371085F3868BD8A29F1725E /* FirebaseDatabase-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "FirebaseDatabase-umbrella.h"; sourceTree = ""; }; + CF81F335A3222C35BAB5B868B46A8AC3 /* FIRTransactionResult_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRTransactionResult_Private.h; path = FirebaseDatabase/Sources/Api/Private/FIRTransactionResult_Private.h; sourceTree = ""; }; + CF8428E4E89357A6FCA2D964BE2D2D03 /* FirebaseInstallations.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FirebaseInstallations.h; path = FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FirebaseInstallations.h; sourceTree = ""; }; + CF93129186968B01B7B193F2016F8569 /* Events.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Events.swift; path = RealmSwift/Events.swift; sourceTree = ""; }; + CF97E0F164DFA9E0C2AA0BA05C846A5A /* RLMMongoDatabase.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMMongoDatabase.h; path = include/RLMMongoDatabase.h; sourceTree = ""; }; + CFB6CCB1B4AF1019876E53953A7D37A8 /* FIRSecureTokenRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRSecureTokenRequest.h; path = FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenRequest.h; sourceTree = ""; }; + CFB945C62972C0C90CE78FE6D174EAD1 /* FTupleTSN.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTupleTSN.m; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleTSN.m; sourceTree = ""; }; + CFDFCB3E3580BB6BEB1A3231B23289DD /* FIRHeartbeatLogger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRHeartbeatLogger.h; path = FirebaseCore/Extension/FIRHeartbeatLogger.h; sourceTree = ""; }; + CFEB25BE4BFD56BF6D6D28C7DBF5F9A2 /* FIRInstallationsStore.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInstallationsStore.h; path = FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStore.h; sourceTree = ""; }; + D00927971D6B3C1621037BDC2C93FB12 /* RLMMongoCollection_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMMongoCollection_Private.h; path = include/RLMMongoCollection_Private.h; sourceTree = ""; }; + D0A9F872C17D0303D7A2EC5BBC973658 /* GULAppEnvironmentUtil.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULAppEnvironmentUtil.h; path = GoogleUtilities/Environment/Public/GoogleUtilities/GULAppEnvironmentUtil.h; sourceTree = ""; }; + D0AA822C47FB8D76517D7B38666F38C1 /* Optional.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Optional.swift; path = RealmSwift/Optional.swift; sourceTree = ""; }; + D0B5650C6E0ADF651F660A4F97DB1A67 /* FIRAuthCredential_Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthCredential_Internal.h; path = FirebaseAuth/Sources/AuthProvider/FIRAuthCredential_Internal.h; sourceTree = ""; }; + D0CCF972A2BCF6A4FA37AA00A90F021D /* FirebaseCore-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "FirebaseCore-Info.plist"; sourceTree = ""; }; + D123FAB0A8C5ECD50735F08853562BC3 /* FTupleTSN.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTupleTSN.h; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleTSN.h; sourceTree = ""; }; + D153033C39ED5D472A14A8B145E0434D /* RLMObjectStore.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMObjectStore.h; path = include/RLMObjectStore.h; sourceTree = ""; }; + D17F4CAEA8B1222B41373E48DDB479F8 /* logging.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = logging.cc; path = util/logging.cc; sourceTree = ""; }; + D1CC4C7FABA96F45EE8B3CD9AAFE20D0 /* SyncSubscription.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SyncSubscription.swift; path = RealmSwift/SyncSubscription.swift; sourceTree = ""; }; + D1FCF70DD745852460CA893C0044F06E /* FRepoManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FRepoManager.m; path = FirebaseDatabase/Sources/Core/FRepoManager.m; sourceTree = ""; }; + D209A08FA1E9922FD310E9BE48FE9AAC /* FIRDependency.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDependency.h; path = FirebaseCore/Extension/FIRDependency.h; sourceTree = ""; }; + D24EAB3656B66CFA3FC4EC757C29A2B0 /* FIRMultiFactorSession+Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FIRMultiFactorSession+Internal.h"; path = "FirebaseAuth/Sources/MultiFactor/FIRMultiFactorSession+Internal.h"; sourceTree = ""; }; + D29E1D68F3B5C6DA0A7A06B72CECF993 /* FirebaseAnalytics.xcframework */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = wrapper.xcframework; name = FirebaseAnalytics.xcframework; path = Frameworks/FirebaseAnalytics.xcframework; sourceTree = ""; }; + D2AEB4E2CAF4CF35E4F45069EB30D0A6 /* RLMSwiftSupport.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RLMSwiftSupport.m; path = Realm/RLMSwiftSupport.m; sourceTree = ""; }; + D3BC4F854711166760C34ADA038051BA /* FTreeSortedDictionary.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTreeSortedDictionary.m; path = FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionary.m; sourceTree = ""; }; + D3C7869F6D75E8CDC540790526E3F955 /* FTree.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTree.m; path = FirebaseDatabase/Sources/Core/Utilities/FTree.m; sourceTree = ""; }; + D3CBF39EB565F7C6E0D1BA08F7C7AC50 /* FIRComponentContainerInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRComponentContainerInternal.h; path = FirebaseCore/Sources/FIRComponentContainerInternal.h; sourceTree = ""; }; + D403AB05C8E5B8D4D7EC9A9E2C7A971E /* MongoClient.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MongoClient.swift; path = RealmSwift/MongoClient.swift; sourceTree = ""; }; + D455DC7451DB6AE120BB8BB269C4F3D9 /* FIRDependency.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDependency.h; path = FirebaseCore/Extension/FIRDependency.h; sourceTree = ""; }; + D499691A37C194CFC8292C3B66E69060 /* RLMResults.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMResults.h; path = include/RLMResults.h; sourceTree = ""; }; + D4B2D1F9402DEE3A5695B326EE5FFD8F /* FIRSendVerificationCodeResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRSendVerificationCodeResponse.m; path = FirebaseAuth/Sources/Backend/RPC/FIRSendVerificationCodeResponse.m; sourceTree = ""; }; + D4C8940B52AD1E94D001B3AC49E7DF7A /* GoogleUtilities-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "GoogleUtilities-Info.plist"; sourceTree = ""; }; + D4CA33A9E671FF56D957091FF43648C9 /* FTreeSortedDictionaryEnumerator.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTreeSortedDictionaryEnumerator.h; path = FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionaryEnumerator.h; sourceTree = ""; }; + D5100D25D948326FCCAF410A4BE86046 /* FIndexedFilter.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIndexedFilter.m; path = FirebaseDatabase/Sources/Core/View/Filter/FIndexedFilter.m; sourceTree = ""; }; + D53299DB70CFB23861357EA947C70688 /* FIRInstallationsIIDStore.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInstallationsIIDStore.h; path = FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDStore.h; sourceTree = ""; }; + D55A3C15FC867492DF0F4DCD8284D6A3 /* FIRFirebaseUserAgent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRFirebaseUserAgent.h; path = FirebaseCore/Sources/FIRFirebaseUserAgent.h; sourceTree = ""; }; + D56EC12CC16DD1D834245EB18033364A /* RLMManagedArray.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMManagedArray.mm; path = Realm/RLMManagedArray.mm; sourceTree = ""; }; + D5890EEE293438821271DA021C01DB15 /* nanopb-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "nanopb-umbrella.h"; sourceTree = ""; }; + D5C8BA1EEC0185497B91CE4F4A3EA391 /* FArraySortedDictionary.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FArraySortedDictionary.m; path = FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FArraySortedDictionary.m; sourceTree = ""; }; + D5DD6C3F39E0FF0D612E4964A5FD8D45 /* SchemaDiscovery.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SchemaDiscovery.swift; path = RealmSwift/Impl/SchemaDiscovery.swift; sourceTree = ""; }; + D6239ED73C89FD84A2B7E3742D7E015E /* status.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = status.h; path = include/leveldb/status.h; sourceTree = ""; }; + D64B72A8936ECC9C34DA6EA69AD8B336 /* FTuplePathValue.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTuplePathValue.h; path = FirebaseDatabase/Sources/Utilities/Tuples/FTuplePathValue.h; sourceTree = ""; }; + D65779CDF02306477DFB2EE59C042724 /* FIRAuthNotificationManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthNotificationManager.h; path = FirebaseAuth/Sources/SystemService/FIRAuthNotificationManager.h; sourceTree = ""; }; + D65CCF92BADFD9664EB7E03196C8195C /* FTupleOnDisconnect.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTupleOnDisconnect.m; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleOnDisconnect.m; sourceTree = ""; }; + D68BEA0EF9DCC01F9EF03619F5C0AE46 /* Pods-PRTYTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-PRTYTests.release.xcconfig"; sourceTree = ""; }; + D69481ED1553EEC1AC684D6C26C0022D /* skiplist.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = skiplist.h; path = db/skiplist.h; sourceTree = ""; }; + D6B797734979214911F26CE6964D223D /* RLMSchema.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMSchema.h; path = include/RLMSchema.h; sourceTree = ""; }; + D71BEF9DD1974C9E1B6490E81C32E5B6 /* PersistedProperty.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PersistedProperty.swift; path = RealmSwift/PersistedProperty.swift; sourceTree = ""; }; + D78A368E37232A2DE537AA23340C97BF /* Realm-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Realm-Info.plist"; sourceTree = ""; }; + D7ADD5B6B5915AEAC85BA95F031C7AAB /* port.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = port.h; path = port/port.h; sourceTree = ""; }; + D7D16DA5AD11F3D6F872D23FA8E6A157 /* FMerge.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FMerge.h; path = FirebaseDatabase/Sources/Core/Operation/FMerge.h; sourceTree = ""; }; + D80EF8C0A8F6337C6FB4F253C9D82B8E /* FIRInstallationsStore.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRInstallationsStore.m; path = FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStore.m; sourceTree = ""; }; + D8780156F717E510F1DB5FA53ECBEEFC /* GULLoggerCodes.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULLoggerCodes.h; path = GoogleUtilities/Common/GULLoggerCodes.h; sourceTree = ""; }; + D881B7E53154441A4B1D49E8DB0FA3F4 /* FIRFacebookAuthCredential.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRFacebookAuthCredential.h; path = FirebaseAuth/Sources/AuthProvider/Facebook/FIRFacebookAuthCredential.h; sourceTree = ""; }; + D887E54D3239CBDA0F3CE1921760C572 /* FEventEmitter.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FEventEmitter.h; path = FirebaseDatabase/Sources/Utilities/FEventEmitter.h; sourceTree = ""; }; + D8A3B55C80E0CC5BC5DAE72FC0F17288 /* GoogleUtilities.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = GoogleUtilities.modulemap; sourceTree = ""; }; + D8D3F8C07FC1809D6A888E03A8585E72 /* FIRDatabaseComponent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRDatabaseComponent.m; path = FirebaseDatabase/Sources/Api/FIRDatabaseComponent.m; sourceTree = ""; }; + D8FF4697BD930A161E25C7F50B4FBC63 /* FChildChangeAccumulator.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FChildChangeAccumulator.m; path = FirebaseDatabase/Sources/Core/View/Filter/FChildChangeAccumulator.m; sourceTree = ""; }; + D93CC25FAAF72AD0E3E8DCA1B38AC5A6 /* FirebaseInstallations-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "FirebaseInstallations-umbrella.h"; sourceTree = ""; }; + D984F82324A6B762CC65B0B8A3D4B26B /* FKeyIndex.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FKeyIndex.m; path = FirebaseDatabase/Sources/FKeyIndex.m; sourceTree = ""; }; + D98C07DBF8AFD2E90F45D95D0BA5E334 /* FTupleObjectNode.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTupleObjectNode.m; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleObjectNode.m; sourceTree = ""; }; + DA158D7DA802B44F18C94FBD0C6A7A7C /* FIRUserMetadata_Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRUserMetadata_Internal.h; path = FirebaseAuth/Sources/User/FIRUserMetadata_Internal.h; sourceTree = ""; }; + DA41FE18FB4EA2B72D7B4F8366676BC1 /* FIRStartMFASignInResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRStartMFASignInResponse.h; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRStartMFASignInResponse.h; sourceTree = ""; }; + DA74B0436802FE2BDE61D436290670BD /* RLMSyncSubscription.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMSyncSubscription.h; path = include/RLMSyncSubscription.h; sourceTree = ""; }; + DAC208FD41CE38A2E2E5ABCDABD3D70E /* RLMSwiftCollectionBase.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMSwiftCollectionBase.h; path = include/RLMSwiftCollectionBase.h; sourceTree = ""; }; + DAC5A28E00D22DC13534FA98A6FF1154 /* FIRIdentityToolkitRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRIdentityToolkitRequest.m; path = FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.m; sourceTree = ""; }; + DB1010F3237A58009791F7F779E11F1D /* FMerge.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FMerge.m; path = FirebaseDatabase/Sources/Core/Operation/FMerge.m; sourceTree = ""; }; + DB96318E2CB72DE3CDFEEF1B9E8644AD /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; + DC183DB0DD726787211F6CDF27F004B0 /* FIROAuthProvider.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIROAuthProvider.m; path = FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthProvider.m; sourceTree = ""; }; + DC3C5F7564BBF625FA085989C71B0540 /* FClock.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FClock.m; path = FirebaseDatabase/Sources/FClock.m; sourceTree = ""; }; + DC9C364C4160499BF30C6614BB9168B2 /* StorageFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = StorageFactory.swift; path = FirebaseCore/Internal/Sources/HeartbeatLogging/StorageFactory.swift; sourceTree = ""; }; + DD1D686105A5C3AABBDDDB266B062F1C /* _ObjC_HeartbeatController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = _ObjC_HeartbeatController.swift; path = FirebaseCore/Internal/Sources/HeartbeatLogging/_ObjC_HeartbeatController.swift; sourceTree = ""; }; + DD6BDED44B8616A9BECF39BB7B8841F2 /* RLMProperty_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMProperty_Private.h; path = include/RLMProperty_Private.h; sourceTree = ""; }; + DDABA880B080FE3D88806F394D8ECB82 /* FIRFinalizeMFASignInResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRFinalizeMFASignInResponse.m; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInResponse.m; sourceTree = ""; }; + DDC9E831C2A72BB2A398571D8AD3C8EA /* testharness.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = testharness.cc; path = util/testharness.cc; sourceTree = ""; }; + DDD2DB49347560B7FD71926843CC00F6 /* FIRTwitterAuthCredential.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRTwitterAuthCredential.m; path = FirebaseAuth/Sources/AuthProvider/Twitter/FIRTwitterAuthCredential.m; sourceTree = ""; }; + DDDD0E5429AF168AA2D3ED8F2AED36D4 /* FLeafNode.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FLeafNode.m; path = FirebaseDatabase/Sources/Snapshot/FLeafNode.m; sourceTree = ""; }; + DDE80AF0D4D25BFCEFB299B8C17CEE4C /* FIRGetProjectConfigResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRGetProjectConfigResponse.m; path = FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigResponse.m; sourceTree = ""; }; + DE35B94C2CED0E8E9CAE38566E26439E /* FDataEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FDataEvent.h; path = FirebaseDatabase/Sources/Core/View/FDataEvent.h; sourceTree = ""; }; + DE6EC9F385F7E055E70A09F1EAFA7E4A /* GULLogger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULLogger.h; path = GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h; sourceTree = ""; }; + DE81F36FF24373414B6EC1A426429DDC /* FBLPromise+Validate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Validate.h"; path = "Sources/FBLPromises/include/FBLPromise+Validate.h"; sourceTree = ""; }; + DF1DFA0E235C7EBFBB0C874CC3FB1BB4 /* FLevelDBStorageEngine.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FLevelDBStorageEngine.h; path = FirebaseDatabase/Sources/Persistence/FLevelDBStorageEngine.h; sourceTree = ""; }; + DF26D9FD9034751F508E469A65F9DE14 /* NSData+SRB64Additions.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "NSData+SRB64Additions.m"; path = "FirebaseDatabase/Sources/third_party/SocketRocket/NSData+SRB64Additions.m"; sourceTree = ""; }; + DF47599DCB441F39488B62462C49AB81 /* FIRLogger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRLogger.h; path = FirebaseCore/Extension/FIRLogger.h; sourceTree = ""; }; + DF49FADD2F521BE21950120B832A1914 /* RLMSwiftValueStorage.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMSwiftValueStorage.h; path = include/RLMSwiftValueStorage.h; sourceTree = ""; }; + DF55A01ECA815A9E60783C3BEAA1609C /* fbase64.c */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.c; name = fbase64.c; path = FirebaseDatabase/Sources/third_party/SocketRocket/fbase64.c; sourceTree = ""; }; + DF68E17A2DB79D8E848E4D63DFB990D9 /* RLMBSON.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMBSON.mm; path = Realm/RLMBSON.mm; sourceTree = ""; }; + DF8D96275E2E2AAC3FD340661C455E7E /* FIRVerifyCustomTokenResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRVerifyCustomTokenResponse.h; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenResponse.h; sourceTree = ""; }; + DFA09D9997A62037EBBA3F916282D412 /* APLevelDB.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = APLevelDB.h; path = "FirebaseDatabase/Sources/third_party/Wrap-leveldb/APLevelDB.h"; sourceTree = ""; }; + DFB42C998CA9D2337B259FCCF7EF8206 /* FIRDatabaseReference.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDatabaseReference.h; path = FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabaseReference.h; sourceTree = ""; }; + DFE8D317CAC32D1548639938EE4E02AB /* RLMManagedSet.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMManagedSet.mm; path = Realm/RLMManagedSet.mm; sourceTree = ""; }; + DFF1E8F69B5E593941C2E469879CCF4A /* FIRAuthWebUtils.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthWebUtils.h; path = FirebaseAuth/Sources/Utilities/FIRAuthWebUtils.h; sourceTree = ""; }; + E00B9C320CCC9F274F7D1867FC7C18E0 /* FBLPromise+Reduce.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Reduce.m"; path = "Sources/FBLPromises/FBLPromise+Reduce.m"; sourceTree = ""; }; + E07ED6727EC0704096E3C366CDD15BF8 /* FIRUserInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRUserInfo.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRUserInfo.h; sourceTree = ""; }; + E0CB4FCA7F89AD1530D8E842C40E2D1D /* RLMClassInfo.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMClassInfo.mm; path = Realm/RLMClassInfo.mm; sourceTree = ""; }; + E0F2C073ECA9F2634031E8A827AEE3AB /* GTMSessionFetcher.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = GTMSessionFetcher.debug.xcconfig; sourceTree = ""; }; + E11FC028A82D1763971334635D2617A3 /* filename.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = filename.cc; path = db/filename.cc; sourceTree = ""; }; + E1349D5F673D710C9751BEF3BD0990CF /* FWriteTree.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FWriteTree.m; path = FirebaseDatabase/Sources/Core/FWriteTree.m; sourceTree = ""; }; + E166A650D7D8C863AB91749CE9A89980 /* c.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = c.h; path = include/leveldb/c.h; sourceTree = ""; }; + E195C7C4C8A627E9BC80CA7047D22DFD /* snapshot.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = snapshot.h; path = db/snapshot.h; sourceTree = ""; }; + E22845731258908F89CCAFAF4476E8E0 /* FIRSecureTokenResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRSecureTokenResponse.h; path = FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenResponse.h; sourceTree = ""; }; + E291F2BE395DCAE350627CC2B42FE6E4 /* FIRFinalizeMFAEnrollmentRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRFinalizeMFAEnrollmentRequest.m; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentRequest.m; sourceTree = ""; }; + E2A825F628843CCD72BD31D2F167A274 /* FIRVersion.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRVersion.h; path = FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h; sourceTree = ""; }; + E2B63D462DB7F827C4B11FD51E4F8E2D /* FirebaseCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = FirebaseCore.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + E2DB273917BC7D135A0439291C9C008C /* FIRFacebookAuthProvider.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRFacebookAuthProvider.m; path = FirebaseAuth/Sources/AuthProvider/Facebook/FIRFacebookAuthProvider.m; sourceTree = ""; }; + E2DDE940DDAC937FC95E2A04A274103D /* FBLPromise+Testing.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Testing.h"; path = "Sources/FBLPromises/include/FBLPromise+Testing.h"; sourceTree = ""; }; + E33AB87C9E1B8F7F515F0C6C418D8B2B /* FIRGoogleAuthProvider.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRGoogleAuthProvider.m; path = FirebaseAuth/Sources/AuthProvider/Google/FIRGoogleAuthProvider.m; sourceTree = ""; }; + E355264F8F23BD69A8E6EC8A430817AD /* ObjectiveCSupport+Sync.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ObjectiveCSupport+Sync.swift"; path = "RealmSwift/ObjectiveCSupport+Sync.swift"; sourceTree = ""; }; + E372170790901E282DA2178AD64F9AF1 /* FBLPromise+Delay.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Delay.m"; path = "Sources/FBLPromises/FBLPromise+Delay.m"; sourceTree = ""; }; + E3B5F7670B5C0CA94B6720CC51510838 /* RLMObjectId.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMObjectId.h; path = include/RLMObjectId.h; sourceTree = ""; }; + E3D7107849E93A425AEA955A36B090EA /* Firebase.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Firebase.debug.xcconfig; sourceTree = ""; }; + E3E1C442BA8DDCEEFA65EE0379DAD33E /* FBLPromise+Always.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Always.h"; path = "Sources/FBLPromises/include/FBLPromise+Always.h"; sourceTree = ""; }; + E4274F4A59E6D6C77EE43A9264D4726C /* FLevelDBStorageEngine.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FLevelDBStorageEngine.m; path = FirebaseDatabase/Sources/Persistence/FLevelDBStorageEngine.m; sourceTree = ""; }; + E466DD483C14B59C82558E3B5D4523E8 /* nanopb-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "nanopb-Info.plist"; sourceTree = ""; }; + E5728A1EC7C20549A71D8E4A6D437EC2 /* FPersistenceManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FPersistenceManager.m; path = FirebaseDatabase/Sources/Persistence/FPersistenceManager.m; sourceTree = ""; }; + E5F8E0CE9018602A1E2F2C90CC6FB33E /* FViewProcessorResult.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FViewProcessorResult.m; path = FirebaseDatabase/Sources/FViewProcessorResult.m; sourceTree = ""; }; + E609518EF2F1803F18D4DF39F3B4FB27 /* FIRAuth.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuth.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuth.h; sourceTree = ""; }; + E6B0319BF99F0E5F8A53C708EE2F0FBE /* FTreeSortedDictionary.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTreeSortedDictionary.h; path = FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionary.h; sourceTree = ""; }; + E75A7FC8166DA36E089D2AD89ACDB3F5 /* RLMQueryUtil.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMQueryUtil.mm; path = Realm/RLMQueryUtil.mm; sourceTree = ""; }; + E7606F26B9DF776AB41E04D3CF6CAE70 /* RLMUpdateResult.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMUpdateResult.mm; path = Realm/RLMUpdateResult.mm; sourceTree = ""; }; + E77B5F799945E2A80CEF1ECB60633E49 /* FBLPromiseError.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBLPromiseError.h; path = Sources/FBLPromises/include/FBLPromiseError.h; sourceTree = ""; }; + E786BAEFF21D797C4F8294C087E59257 /* FIRSignInWithGameCenterResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRSignInWithGameCenterResponse.h; path = FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterResponse.h; sourceTree = ""; }; + E7A629C03445554FC69F62FEB8A6D552 /* FirebaseAppCheckInterop-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "FirebaseAppCheckInterop-prefix.pch"; sourceTree = ""; }; + E823EE8166EE2F183AE2CA0918747CB5 /* FirebaseDatabase.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = FirebaseDatabase.modulemap; sourceTree = ""; }; + E85CC75C83CC5C34C66FEA0792C24588 /* pb_common.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = pb_common.h; sourceTree = ""; }; + E8942392A79DA09DE59AB54A095222B0 /* GULAppEnvironmentUtil.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULAppEnvironmentUtil.m; path = GoogleUtilities/Environment/third_party/GULAppEnvironmentUtil.m; sourceTree = ""; }; + E94ECD3EF54AD47F74DAF000981E3F6D /* FImmutableTree.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FImmutableTree.m; path = FirebaseDatabase/Sources/Core/Utilities/FImmutableTree.m; sourceTree = ""; }; + E979A44E4715ED4F43A9136F01012EA5 /* FIROptionsInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIROptionsInternal.h; path = FirebaseCore/Extension/FIROptionsInternal.h; sourceTree = ""; }; + E9A4687D268F2913AF3361DC3E0DCA57 /* FTreeSortedDictionaryEnumerator.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTreeSortedDictionaryEnumerator.m; path = FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FTreeSortedDictionaryEnumerator.m; sourceTree = ""; }; + E9D20F783BE6512E0DE13B7C0C5670BE /* HeartbeatController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HeartbeatController.swift; path = FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatController.swift; sourceTree = ""; }; + E9E24A592D6788921EFF7CD6B07DA3D0 /* FIRCreateAuthURIResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRCreateAuthURIResponse.m; path = FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIResponse.m; sourceTree = ""; }; + EA00F4F46EC2CD0F233E301B8D7D3F87 /* FTupleBoolBlock.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTupleBoolBlock.m; path = FirebaseDatabase/Sources/Utilities/Tuples/FTupleBoolBlock.m; sourceTree = ""; }; + EA10A779E36C2B20E2D2B85D189969F4 /* pb_common.c */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.c; path = pb_common.c; sourceTree = ""; }; + EA1F9E6CD6CEF164872E5EA441957F62 /* FIRMultiFactorInfo.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMultiFactorInfo.m; path = FirebaseAuth/Sources/MultiFactor/FIRMultiFactorInfo.m; sourceTree = ""; }; + EA3CA50214CA2C30C735EF15DCFDD00C /* RealmKeyedCollection.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RealmKeyedCollection.swift; path = RealmSwift/RealmKeyedCollection.swift; sourceTree = ""; }; + EA57FFE363F883005877B7B2BEB8F282 /* FirebaseAppCheckInterop.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FirebaseAppCheckInterop.debug.xcconfig; sourceTree = ""; }; + EA7D71EB92C35DBEB01DB4C6AFBCC6CD /* RLMProviderClient.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMProviderClient.mm; path = Realm/RLMProviderClient.mm; sourceTree = ""; }; + EA8239410F30B3473F054F4F9AC2D05F /* FWebSocketConnection.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FWebSocketConnection.h; path = FirebaseDatabase/Sources/Realtime/FWebSocketConnection.h; sourceTree = ""; }; + EAB3A0514E6334B17A71E551EFCEB469 /* log_reader.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = log_reader.h; path = db/log_reader.h; sourceTree = ""; }; + EAC3AE1029A198F99DE8B54D835FA231 /* SwiftUI.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SwiftUI.swift; path = RealmSwift/SwiftUI.swift; sourceTree = ""; }; + EADAA6771DED910D18EEE52483AEA223 /* FSyncTree.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FSyncTree.m; path = FirebaseDatabase/Sources/Core/FSyncTree.m; sourceTree = ""; }; + EB340D31B9671B20F48E9C1D40AEB894 /* GULNetworkConstants.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULNetworkConstants.h; path = GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkConstants.h; sourceTree = ""; }; + EB78CE135800E8CDACBD0AE334B55148 /* FIRLoggerLevel.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRLoggerLevel.h; path = FirebaseCore/Sources/Public/FirebaseCore/FIRLoggerLevel.h; sourceTree = ""; }; + EBBB58C277BED60ECBB0936F62871EA6 /* FIRInstallationsErrorUtil.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRInstallationsErrorUtil.m; path = FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.m; sourceTree = ""; }; + EC13AB64AF41FAC54352545976A8CC9A /* NSURLSession+GULPromises.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "NSURLSession+GULPromises.m"; path = "GoogleUtilities/Environment/URLSessionPromiseWrapper/NSURLSession+GULPromises.m"; sourceTree = ""; }; + EC208AAD8607F9C59421288F9B50F57D /* FIRVersion.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRVersion.m; path = FirebaseCore/Sources/FIRVersion.m; sourceTree = ""; }; + EC87252ACE45D15F776E6AB2967A03D1 /* export.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = export.h; path = include/leveldb/export.h; sourceTree = ""; }; + ECF825CA7953BF64C51F8BCB314F7A1C /* dbformat.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = dbformat.cc; path = db/dbformat.cc; sourceTree = ""; }; + ED26D901D7A953FFDFA298223B2EA02C /* FIRWithdrawMFARequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRWithdrawMFARequest.m; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/Unenroll/FIRWithdrawMFARequest.m; sourceTree = ""; }; + EDFEE8706FA0AF292187CAE8E1EF207B /* leveldb-library-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "leveldb-library-umbrella.h"; sourceTree = ""; }; + EE55309BF72F93761475501AEEA09218 /* FParsedUrl.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FParsedUrl.h; path = FirebaseDatabase/Sources/Utilities/FParsedUrl.h; sourceTree = ""; }; + EED7AF0F3BBCD3CF75FB429BB1B43A4A /* RLMObjectBase.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMObjectBase.mm; path = Realm/RLMObjectBase.mm; sourceTree = ""; }; + EEEFE024B53EE0D176146FCC6098D527 /* _ObjC_HeartbeatsPayload.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = _ObjC_HeartbeatsPayload.swift; path = FirebaseCore/Internal/Sources/HeartbeatLogging/_ObjC_HeartbeatsPayload.swift; sourceTree = ""; }; + EF35764F03CD24E9BEFF38AB8C6873BF /* FIRGetProjectConfigRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRGetProjectConfigRequest.m; path = FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigRequest.m; sourceTree = ""; }; + EF4313DE4400552722C93B74B967C814 /* FIRAuthAPNSTokenType.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthAPNSTokenType.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthAPNSTokenType.h; sourceTree = ""; }; + EF82691CD03AEDF56103F9C350618682 /* GoogleUtilities.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = GoogleUtilities.release.xcconfig; sourceTree = ""; }; + EF93B3CD6E2C57E0A8E985819171A8AD /* FIRVerifyAssertionResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRVerifyAssertionResponse.h; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.h; sourceTree = ""; }; + F03959F6EC6AFA8E040BC189C4A27323 /* FIRDataSnapshot.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRDataSnapshot.m; path = FirebaseDatabase/Sources/Api/FIRDataSnapshot.m; sourceTree = ""; }; + F07B9D10EA63EC4EF28E583DF5056E86 /* FirebaseInstallations-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "FirebaseInstallations-Info.plist"; sourceTree = ""; }; + F0B54BCD2027EEA2560F04A5F660DF5F /* FIREmailLinkSignInRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIREmailLinkSignInRequest.m; path = FirebaseAuth/Sources/Backend/RPC/FIREmailLinkSignInRequest.m; sourceTree = ""; }; + F0BFC6AD06F7FAA34D3238F20D1BDDD3 /* RLMRealm.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMRealm.h; path = include/RLMRealm.h; sourceTree = ""; }; + F0C021C6E1701A5C89767E23F96F8FB7 /* pb_encode.c */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.c; path = pb_encode.c; sourceTree = ""; }; + F0C900FADDD4BE441B1FED142B0B0690 /* FIRCreateAuthURIRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRCreateAuthURIRequest.h; path = FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIRequest.h; sourceTree = ""; }; + F0DF6E1A8D6752D88F3DAA4CF23F208A /* FirebaseDatabase.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FirebaseDatabase.release.xcconfig; sourceTree = ""; }; + F0E3797522D2DA92B3D9A8D35FFEDFE2 /* RLMSet.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMSet.mm; path = Realm/RLMSet.mm; sourceTree = ""; }; + F11AA3BD3B6733487D7ED153F816289D /* RealmSwift-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "RealmSwift-dummy.m"; sourceTree = ""; }; + F11CF8FB763A7027E9275814033E4AAA /* RLMUpdateChecker.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMUpdateChecker.mm; path = Realm/RLMUpdateChecker.mm; sourceTree = ""; }; + F1572B79421971BB2F3F25A47639DB2E /* FLimitedFilter.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FLimitedFilter.m; path = FirebaseDatabase/Sources/Core/View/Filter/FLimitedFilter.m; sourceTree = ""; }; + F16A7F5529145AB1A4B7E519508ACF72 /* FIRVerifyPasswordRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRVerifyPasswordRequest.m; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordRequest.m; sourceTree = ""; }; + F18ED32B3B8F221BFA6014B394B24828 /* FNodeFilter.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FNodeFilter.h; path = FirebaseDatabase/Sources/Core/View/Filter/FNodeFilter.h; sourceTree = ""; }; + F1A63F9946D77AA0988F1947BD912CAC /* FirebaseInstallations-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "FirebaseInstallations-dummy.m"; sourceTree = ""; }; + F1CC9D6836BEB84A834ABB338A080E55 /* FIRInstallationsLogger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInstallationsLogger.h; path = FirebaseInstallations/Source/Library/FIRInstallationsLogger.h; sourceTree = ""; }; + F1DC45D9BAAB0EF43B79461F9CE85306 /* FIRGitHubAuthCredential.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRGitHubAuthCredential.m; path = FirebaseAuth/Sources/AuthProvider/GitHub/FIRGitHubAuthCredential.m; sourceTree = ""; }; + F1E367B64874B28C5E8947B105E8CB27 /* FIRDatabaseQuery.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRDatabaseQuery.m; path = FirebaseDatabase/Sources/Api/FIRDatabaseQuery.m; sourceTree = ""; }; + F2348A5807D3DC0C79B38DE2BF5C174B /* FTrackedQueryManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FTrackedQueryManager.h; path = FirebaseDatabase/Sources/Persistence/FTrackedQueryManager.h; sourceTree = ""; }; + F2503973D433D6E9A0D2C052DE9C051C /* FAtomicNumber.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FAtomicNumber.m; path = FirebaseDatabase/Sources/Utilities/FAtomicNumber.m; sourceTree = ""; }; + F26D7F28656F20339771BBA1D7E42D4A /* FIRGameCenterAuthProvider.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRGameCenterAuthProvider.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRGameCenterAuthProvider.h; sourceTree = ""; }; + F2A0CA9C4DCD46B305AFCB09388F8B44 /* FPendingPut.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FPendingPut.h; path = FirebaseDatabase/Sources/Persistence/FPendingPut.h; sourceTree = ""; }; + F2AF3110914F29826DCE78B416523133 /* FImmutableSortedDictionary.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FImmutableSortedDictionary.h; path = FirebaseDatabase/Sources/third_party/FImmutableSortedDictionary/FImmutableSortedDictionary/FImmutableSortedDictionary.h; sourceTree = ""; }; + F2DAEC929043E230DBB3692CFC09A1BA /* FIRInstallationsItem.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRInstallationsItem.m; path = FirebaseInstallations/Source/Library/FIRInstallationsItem.m; sourceTree = ""; }; + F37FE4685A93D38F15751D8281B0E889 /* RLMLogger.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMLogger.mm; path = Realm/RLMLogger.mm; sourceTree = ""; }; + F387E83A61343EB694A8E28807337949 /* log_writer.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = log_writer.cc; path = db/log_writer.cc; sourceTree = ""; }; + F3E5068F34D0E92C3F70A3EEFE682CAB /* RLMNetworkTransport.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMNetworkTransport.mm; path = Realm/RLMNetworkTransport.mm; sourceTree = ""; }; + F40A7949398CF1B354A45647D63F250E /* FIRGetProjectConfigRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRGetProjectConfigRequest.h; path = FirebaseAuth/Sources/Backend/RPC/FIRGetProjectConfigRequest.h; sourceTree = ""; }; + F4212B50C554057BF62AA6A4107D56BC /* Pods-PRTY-PRTYUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-PRTY-PRTYUITests.release.xcconfig"; sourceTree = ""; }; + F4332EC6914A3C94E725975980509BB2 /* PromisesObjC-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "PromisesObjC-umbrella.h"; sourceTree = ""; }; + F433C4D3C5A3828AC08AECBC9337940A /* GULNetworkInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULNetworkInfo.h; path = GoogleUtilities/Environment/Public/GoogleUtilities/GULNetworkInfo.h; sourceTree = ""; }; + F44000EA207E28FDA17F50C681374B50 /* RLMPlatform.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMPlatform.h; path = include/RLMPlatform.h; sourceTree = ""; }; + F46007BED52B57BCF4843B87E9523D49 /* RLMDictionary_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMDictionary_Private.h; path = include/RLMDictionary_Private.h; sourceTree = ""; }; + F4F3CAE474A7B498BF161E01B891F739 /* FSnapshotHolder.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FSnapshotHolder.m; path = FirebaseDatabase/Sources/Core/FSnapshotHolder.m; sourceTree = ""; }; + F50FD872912D12668F5FF512DB8D6FA2 /* FBLPromise+Retry.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Retry.m"; path = "Sources/FBLPromises/FBLPromise+Retry.m"; sourceTree = ""; }; + F545DFF514F5EA358932BB95A431E476 /* FViewCache.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FViewCache.m; path = FirebaseDatabase/Sources/Core/View/FViewCache.m; sourceTree = ""; }; + F5468F77E33BB89CB6344365C97B2821 /* FIRVerifyPasswordRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRVerifyPasswordRequest.h; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyPasswordRequest.h; sourceTree = ""; }; + F557FDA3AF2F031583CCC00944047D8A /* db_iter.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = db_iter.cc; path = db/db_iter.cc; sourceTree = ""; }; + F5AE5CC06827309EE8FD36857AEEAD93 /* FIRComponentType.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRComponentType.h; path = FirebaseCore/Extension/FIRComponentType.h; sourceTree = ""; }; + F5C7322600CB61912E75AD1BB17BDBA9 /* FIRInstallationsAPIService.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRInstallationsAPIService.m; path = FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsAPIService.m; sourceTree = ""; }; + F5D281652BF9F2FE685ADC168FB4217F /* pb_decode.c */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.c; path = pb_decode.c; sourceTree = ""; }; + F5FC60DFF725AF93166D1B0F9E69A00D /* FBLPromise+Any.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Any.m"; path = "Sources/FBLPromises/FBLPromise+Any.m"; sourceTree = ""; }; + F6150C0680A6EE061716FDD32CE733D5 /* RLMSwiftObject.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMSwiftObject.h; path = include/RLMSwiftObject.h; sourceTree = ""; }; + F6204AB7B81D89A39B83FE06046A4725 /* RLMCollection_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMCollection_Private.h; path = include/RLMCollection_Private.h; sourceTree = ""; }; + F62A4B119F14F2DCBA60D4223F2BEDEC /* FPriorityIndex.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FPriorityIndex.m; path = FirebaseDatabase/Sources/FPriorityIndex.m; sourceTree = ""; }; + F6709A26A6D2B2D009B7AD09AB964714 /* FIRPhoneAuthProvider.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRPhoneAuthProvider.h; path = FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthProvider.h; sourceTree = ""; }; + F6D4069FBA41CDF529F7FF7044569873 /* FWriteTreeRef.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FWriteTreeRef.m; path = FirebaseDatabase/Sources/Core/FWriteTreeRef.m; sourceTree = ""; }; + F6EA58853A83F71F9E161BBA885467E3 /* filename.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = filename.h; path = db/filename.h; sourceTree = ""; }; + F7250000B3B67449209507DE01B23064 /* Firebase.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Firebase.h; path = CoreOnly/Sources/Firebase.h; sourceTree = ""; }; + F76CC964DA80E549EEB9C20EB2651EB3 /* FIRRetryHelper.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRRetryHelper.m; path = FirebaseDatabase/Sources/Core/Utilities/FIRRetryHelper.m; sourceTree = ""; }; + F784FF6511E920AAF983C6D82547E28D /* FIRVerifyPhoneNumberRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRVerifyPhoneNumberRequest.m; path = FirebaseAuth/Sources/Backend/RPC/FIRVerifyPhoneNumberRequest.m; sourceTree = ""; }; + F7ADFB69059F59EB2245F0730BC4BC72 /* FirebaseCore.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FirebaseCore.h; path = FirebaseCore/Sources/Public/FirebaseCore/FirebaseCore.h; sourceTree = ""; }; + F81A1054298CE5C004C4FE464C5DCE2C /* FIRSetAccountInfoRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRSetAccountInfoRequest.h; path = FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoRequest.h; sourceTree = ""; }; + F85757FC6D0D70EA704FBC21028EDF46 /* FIRComponent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRComponent.h; path = FirebaseCore/Extension/FIRComponent.h; sourceTree = ""; }; + F8D485A35F3C8EC5C1FB4CF802609E6C /* FIRResetPasswordRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRResetPasswordRequest.h; path = FirebaseAuth/Sources/Backend/RPC/FIRResetPasswordRequest.h; sourceTree = ""; }; + F8E9BD133AFCC06067CDABEEB3220EF1 /* FEventEmitter.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FEventEmitter.m; path = FirebaseDatabase/Sources/Utilities/FEventEmitter.m; sourceTree = ""; }; + F8FAD4104C03D65C5550064D9F044480 /* FTuplePathValue.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FTuplePathValue.m; path = FirebaseDatabase/Sources/Utilities/Tuples/FTuplePathValue.m; sourceTree = ""; }; + F927599937411CFC58D678F8486AB0AC /* RLMSyncUtil.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMSyncUtil.mm; path = Realm/RLMSyncUtil.mm; sourceTree = ""; }; + F9C09D85943C666EFF4A7E7FF556468E /* FIRFinalizeMFAEnrollmentResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRFinalizeMFAEnrollmentResponse.m; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/Enroll/FIRFinalizeMFAEnrollmentResponse.m; sourceTree = ""; }; + F9E888606FE5836F42A73640926AC56C /* FIRAppInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAppInternal.h; path = FirebaseCore/Extension/FIRAppInternal.h; sourceTree = ""; }; + FA03DCA390E3B26A7DCD911883F15289 /* pb_encode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = pb_encode.h; sourceTree = ""; }; + FA41946ADC0A1E4F1F07A106A35D5C1A /* GULNSData+zlib.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "GULNSData+zlib.m"; path = "GoogleUtilities/NSData+zlib/GULNSData+zlib.m"; sourceTree = ""; }; + FA4FC112C43350FA23C041B4F4331E68 /* FIRAnalyticsConfiguration.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAnalyticsConfiguration.m; path = FirebaseCore/Sources/FIRAnalyticsConfiguration.m; sourceTree = ""; }; + FA61EC6075B55FC111B9D7281C25E9CB /* FRepoInfo.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FRepoInfo.m; path = FirebaseDatabase/Sources/Core/FRepoInfo.m; sourceTree = ""; }; + FAB149690E2D664FDECA85D5157CBA67 /* FRepo_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FRepo_Private.h; path = FirebaseDatabase/Sources/Core/FRepo_Private.h; sourceTree = ""; }; + FAEFF93C94DDA61320F23FD69CC400B2 /* RLMSyncConfiguration.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMSyncConfiguration.h; path = include/RLMSyncConfiguration.h; sourceTree = ""; }; + FB1B9D02FB871F65EBDB1D3F578155C0 /* FirebaseInstallations.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FirebaseInstallations.release.xcconfig; sourceTree = ""; }; + FBC36C1DEA1FE665B1571B58B928ED9B /* Sync.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Sync.swift; path = RealmSwift/Sync.swift; sourceTree = ""; }; + FBF69EF961BCBADD5088BF639982EADA /* FIRAppCheckTokenResultInterop.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAppCheckTokenResultInterop.h; path = FirebaseAppCheck/Interop/FIRAppCheckTokenResultInterop.h; sourceTree = ""; }; + FC3CEE71B7D74D3270183AD28E24D9FB /* FirebaseCoreInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FirebaseCoreInternal.h; path = FirebaseCore/Extension/FirebaseCoreInternal.h; sourceTree = ""; }; + FCAD24AC225AC807A081C35F3B371DA4 /* FBLPromise+Recover.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Recover.m"; path = "Sources/FBLPromises/FBLPromise+Recover.m"; sourceTree = ""; }; + FCC47F2FBDB65E9C97CEA7B0375E1E50 /* PromisesObjC-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "PromisesObjC-dummy.m"; sourceTree = ""; }; + FCFFDCA51CE25755A9B7C297EF1226FF /* RLMBSON.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RLMBSON.h; path = include/RLMBSON.h; sourceTree = ""; }; + FD1024348B7D7F91773F548CC6A4A4B5 /* FIRFinalizeMFASignInRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRFinalizeMFASignInRequest.m; path = FirebaseAuth/Sources/Backend/RPC/MultiFactor/SignIn/FIRFinalizeMFASignInRequest.m; sourceTree = ""; }; + FD2C9898C3BAE3BAF41E73B91BB58EDE /* Realm-xcframeworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Realm-xcframeworks.sh"; sourceTree = ""; }; + FD32D97423F1C3AD8AD7075D273598CA /* table_builder.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = table_builder.cc; path = table/table_builder.cc; sourceTree = ""; }; + FD47B704335D3B8A2DAF90093BD29570 /* GULAppDelegateSwizzler.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULAppDelegateSwizzler.m; path = GoogleUtilities/AppDelegateSwizzler/GULAppDelegateSwizzler.m; sourceTree = ""; }; + FD617FE550E98264A4A123767CCCB5C9 /* log_reader.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = log_reader.cc; path = db/log_reader.cc; sourceTree = ""; }; + FDA721544E537F06282FFFFB621FBD30 /* RLMValue.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = RLMValue.mm; path = Realm/RLMValue.mm; sourceTree = ""; }; + FDE9B09BD40DEABB8127F587A4BA535E /* FIRAuthTokenResult_Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAuthTokenResult_Internal.h; path = FirebaseAuth/Sources/Auth/FIRAuthTokenResult_Internal.h; sourceTree = ""; }; + FDF2EFAF7E3BB03DFF3DF33C3AE6D230 /* FIRGitHubAuthCredential.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRGitHubAuthCredential.h; path = FirebaseAuth/Sources/AuthProvider/GitHub/FIRGitHubAuthCredential.h; sourceTree = ""; }; + FDF715A8163A7748E8D70591288E49C2 /* FIREmailPasswordAuthCredential.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIREmailPasswordAuthCredential.h; path = FirebaseAuth/Sources/AuthProvider/Email/FIREmailPasswordAuthCredential.h; sourceTree = ""; }; + FE280A7F867E6C75B2562C0E436F53A3 /* FIRSignInWithGameCenterRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRSignInWithGameCenterRequest.h; path = FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterRequest.h; sourceTree = ""; }; + FE2C17AB2A7CF72D25F49312B857984E /* status.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = status.cc; path = util/status.cc; sourceTree = ""; }; + FE30687F11D90C3A5C7F0BC4A4F7C122 /* builder.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = builder.h; path = db/builder.h; sourceTree = ""; }; + FF4A31EB3E4294B2F18DC6243AD3116D /* FIRSignUpNewUserResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRSignUpNewUserResponse.h; path = FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserResponse.h; sourceTree = ""; }; + FF4E9D78A15423578B14516BCC3D0101 /* FWriteRecord.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FWriteRecord.m; path = FirebaseDatabase/Sources/Core/FWriteRecord.m; sourceTree = ""; }; + FFA993537352A29E3A3014F2098704D6 /* FirebaseAppCheckInterop-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "FirebaseAppCheckInterop-Info.plist"; sourceTree = ""; }; + FFB04E1B4A84C609969A49C26D4AA88F /* FIRDatabase.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRDatabase.h; path = FirebaseDatabase/Sources/Public/FirebaseDatabase/FIRDatabase.h; sourceTree = ""; }; + FFDDE3E628D464C5FAF7C60041209C2C /* env_posix_test_helper.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = env_posix_test_helper.h; path = util/env_posix_test_helper.h; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 071EE1B3E3E99FF4FA7150A43B1FD1BF /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5AE0FC6ECF376011AEBAB1F7C2F04640 /* Foundation.framework in Frameworks */, + 9BE0C432C601BAEF9616CDF193E4D493 /* UIKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 4B55B4F3E8454CE936EFB8DD56D259F3 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 910145FF03824ABFF17CA653C7F0BD5E /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5EFA40AE9BADE8E7281A0412BDA9F7F0 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + F939485D514925747B76EB8FD3A1320A /* Foundation.framework in Frameworks */, + 260FCFDE1EE1A0437CDA85BA253F84C8 /* Security.framework in Frameworks */, + B2EEC59FABCF5E5C59652196C9A16A39 /* SystemConfiguration.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 64DDE5ED426839C4A4CD9BBB3F8667B7 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 164C8171D35E9623BA1D59A6A8BD005D /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 6E361B2041194F74C98AD11E96544DAA /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8BBC41C025C20DD3DF7072540D9ACF8D /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 82879856A592A25C292B176A5AB030D0 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + C820EC6237A1C41121E1F8B8597BBC95 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9E443E8BEE4172A9850FFA0559E7A752 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + A09BE80C5FC981BACED4EA201F7AEACE /* CFNetwork.framework in Frameworks */, + E18454DF2F43C51C823BF865A82A3EC1 /* Foundation.framework in Frameworks */, + C357BF9095103609A41D4DD98905D94A /* Security.framework in Frameworks */, + 033B9A14A4E0FD6594EEBDD1C851F467 /* SystemConfiguration.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + A9C9AA8374FC0D6A8CD0E483218E8362 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 75619E3CA351CC53A27C30DF83812FDA /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + AB17B442E310F969D961119F667BBCDF /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 2B7172EBC25CE6B3C2613DA8DAFE7D19 /* Foundation.framework in Frameworks */, + DEEFD271BF00213BFE8F7D329BD3F5AA /* Security.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B155D1DA6355EBA45AFCDC214898F661 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B8B7329C446F7C0134EAFF904FF52555 /* Foundation.framework in Frameworks */, + 89A78DD0D7EF9512C16FA8A1AD9A9117 /* Security.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C7C79E124E4AD37F94AF8DAC500707A8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + EC992DE9B00DA0F531A2BF0AF67B7D1D /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D000DBC103B489E923B003778C7B14DD /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 97966CCFF45DDA06DCB4F5C9F7C90460 /* Foundation.framework in Frameworks */, + 7914264FBFAC55C55120BA3EA55F62B1 /* SafariServices.framework in Frameworks */, + CEBED60F230DDDC6E9D71CBFE5D4147F /* Security.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + DEE84CA9EAA4386062CD2008F64940DF /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 0511EE38AFFABD31A9AB86C4D34E7244 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + E9DFB23A694E518DE4BE1017CA0DCD4F /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 1C4AD68BD3321CBA37ADFBFBB0EA3A85 /* Foundation.framework in Frameworks */, + 20A59DBE2C17C1DB9D63977A2D093606 /* Security.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F505E157D5DF02FB5B4365D1BA590C5C /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 62A55B1CA17373B9BFBC6BA6887F22A6 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F792F1D276BD794CD5F439902C0136EC /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D7CAC9227069395CEA958D733F6F448D /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 04348C11DD533068D8A531767D3D0A75 /* Environment */ = { + isa = PBXGroup; + children = ( + D0A9F872C17D0303D7A2EC5BBC973658 /* GULAppEnvironmentUtil.h */, + E8942392A79DA09DE59AB54A095222B0 /* GULAppEnvironmentUtil.m */, + B58E731F045F472B2AE7CE066F291251 /* GULHeartbeatDateStorable.h */, + 3287B3FC8DE790FC3DCEC27D6BA1A7BB /* GULHeartbeatDateStorage.h */, + 9DEFF50571A73345FEF094BB2FEDDBEC /* GULHeartbeatDateStorage.m */, + 919DFEB9C187FA7EEAAFF1CD6E87C64F /* GULHeartbeatDateStorageUserDefaults.h */, + 2035F5591F18DB561814028FE3726CF0 /* GULHeartbeatDateStorageUserDefaults.m */, + C8357ED2FAC9005A1B855EDE918C7AF5 /* GULKeychainStorage.h */, + 0AC41380A652260C2B824C6DCD0D123B /* GULKeychainStorage.m */, + 85221EA6BE483DC672CBF12305306A3E /* GULKeychainUtils.h */, + 075A5D7577CF5A3DC2EF3B7C5AB21F9C /* GULKeychainUtils.m */, + F433C4D3C5A3828AC08AECBC9337940A /* GULNetworkInfo.h */, + 76B21F0B55C360125A29B27794C61933 /* GULNetworkInfo.m */, + 8E042D37247BFBFE5C5FFA198F53B6AA /* GULSecureCoding.h */, + 6A45F4A50350CD25215F79F11B696584 /* GULSecureCoding.m */, + A44E4167201C1AB4D63CA58B6C88B7D2 /* GULURLSessionDataResponse.h */, + C36ACCDE3C319DC975D64D8C09A4CB3C /* GULURLSessionDataResponse.m */, + 83A7B45E5C8683064DA6B5DAAD5957C0 /* NSURLSession+GULPromises.h */, + EC13AB64AF41FAC54352545976A8CC9A /* NSURLSession+GULPromises.m */, + ); + name = Environment; + sourceTree = ""; + }; + 04B2401F9AD3DB58FE2072027EE1BCC8 /* CoreOnly */ = { + isa = PBXGroup; + children = ( + F7250000B3B67449209507DE01B23064 /* Firebase.h */, + ); + name = CoreOnly; + sourceTree = ""; + }; + 052EE226D9D27D977634A9435C617BCE /* WithoutAdIdSupport */ = { + isa = PBXGroup; + children = ( + 6D3F418D77B4F1EA304842B28A5E893D /* Frameworks */, + ); + name = WithoutAdIdSupport; + sourceTree = ""; + }; + 066278B9E287AD4787E2B8ED588042FB /* Realm */ = { + isa = PBXGroup; + children = ( + 82144ED3101ECA164213270A3C7A5398 /* NSError+RLMSync.m */, + B508FF5F45501FC204670A03072D40AF /* RLMAccessor.h */, + 277D8E8244D2FA29E1317FCC9FB6C696 /* RLMAccessor.mm */, + 245479B0028A3B41D31BA76DE5EFC18E /* RLMAnalytics.mm */, + 46F03E9D37DE03046046D67857D32E74 /* RLMAPIKeyAuth.mm */, + CBF04219BF0CCF068C34ECBB735714FC /* RLMApp.mm */, + 2290A765CE084379675E2DAE6C691B8F /* RLMApp_Private.h */, + 4017654FAE4B47AA0C9B3F842A344DE0 /* RLMArray.mm */, + A77530BCB920D9861E25B63BE3E4443E /* RLMArray_Private.h */, + 87F8A8905922D0CF7DAE27789D5EFC50 /* RLMAsymmetricObject.mm */, + 02170472A8C1C88AB10DAC7F8DA66B69 /* RLMAsyncTask.mm */, + 611073B847128EBBC450AA00B49A5852 /* RLMAsyncTask_Private.h */, + DF68E17A2DB79D8E848E4D63DFB990D9 /* RLMBSON.mm */, + E0CB4FCA7F89AD1530D8E842C40E2D1D /* RLMClassInfo.mm */, + B843B5687B1E7F297B8EDE84FB98D92D /* RLMCollection.mm */, + F6204AB7B81D89A39B83FE06046A4725 /* RLMCollection_Private.h */, + 0C5F2659D020AEC57B6932441441E7E8 /* RLMConstants.m */, + 8709E4280FD40FF2D6C51425A4CC4DA8 /* RLMCredentials.mm */, + 6C12879EEF6A505D3CEE089176D6333E /* RLMDecimal128.mm */, + 6C7E8CA913852DAEA9F764D022D94B48 /* RLMDictionary.mm */, + F46007BED52B57BCF4843B87E9523D49 /* RLMDictionary_Private.h */, + B9DF9F7043C387E6BBD41BFE4E656257 /* RLMEmailPasswordAuth.mm */, + 8C87850C03CB12BC395080AD0C60F63C /* RLMEmbeddedObject.mm */, + 071248C77545C00DFE9E8A50D439E7AA /* RLMError.mm */, + 955BE9FC76F7CE1DC6CEC4D0204858EB /* RLMEvent.h */, + 501133B694FC9229BA3E4B89DA7124DC /* RLMEvent.mm */, + 8583BB6D970836E5FDF1168BAB878383 /* RLMFindOneAndModifyOptions.mm */, + 607673A9F4B2F07F2E2EBB8F530B123D /* RLMFindOptions.mm */, + F37FE4685A93D38F15751D8281B0E889 /* RLMLogger.mm */, + 57AA2F599A51760A591158FC670C1F2B /* RLMLogger_Private.h */, + D56EC12CC16DD1D834245EB18033364A /* RLMManagedArray.mm */, + 276D23FD6D93BFC03B3E403333FC0C08 /* RLMManagedDictionary.mm */, + DFE8D317CAC32D1548639938EE4E02AB /* RLMManagedSet.mm */, + 463CDBD457E0FB4C4ACD2D2BFE1862BE /* RLMMigration.mm */, + 6E1AAF86750B38DE664456E8E4A9C10F /* RLMMongoClient.mm */, + 48D7907809830F1F47820F035D74C78D /* RLMMongoCollection.mm */, + D00927971D6B3C1621037BDC2C93FB12 /* RLMMongoCollection_Private.h */, + F3E5068F34D0E92C3F70A3EEFE682CAB /* RLMNetworkTransport.mm */, + 77B43A9AB4643A40D2652594DE5E5DFE /* RLMObject.mm */, + 83B84A215D7F46B8C23EE84B1A5F9CCB /* RLMObject_Private.h */, + EED7AF0F3BBCD3CF75FB429BB1B43A4A /* RLMObjectBase.mm */, + 171EC043E8C48B150D6C70B8D3C8551A /* RLMObjectBase_Private.h */, + 061851272BBE3FB093703FA3D36BBF67 /* RLMObjectId.mm */, + 75FC8BF03C212294921BDF40A8ACB832 /* RLMObjectSchema.mm */, + 82F408B46FDEEDA775BCD20ABA5AEA87 /* RLMObjectSchema_Private.h */, + D153033C39ED5D472A14A8B145E0434D /* RLMObjectStore.h */, + 7F1B362D7A8C6E8B43B41DCA9EC82A5B /* RLMObjectStore.mm */, + 50371EE0D5E9B68064DD3B94892A83DD /* RLMObservation.mm */, + 701AE09D27677AF927D0756A5C7C40B4 /* RLMPredicateUtil.mm */, + CF1CF80E33E84E4C4E5880610EEEB26B /* RLMProperty.mm */, + DD6BDED44B8616A9BECF39BB7B8841F2 /* RLMProperty_Private.h */, + EA7D71EB92C35DBEB01DB4C6AFBCC6CD /* RLMProviderClient.mm */, + A74279679B1A5D45438D0DDBFDE0CA14 /* RLMPushClient.mm */, + E75A7FC8166DA36E089D2AD89ACDB3F5 /* RLMQueryUtil.mm */, + 0DD02532F284925CB1FC4D2E2108EEA7 /* RLMRealm.mm */, + 77EF00ECB627D79F06240B748B823EED /* RLMRealm+Sync.mm */, + 8A1CF7A2AB94E939661BF09684D2DF1B /* RLMRealm_Private.h */, + 851C20472E36ED891170AD12241B66BB /* RLMRealmConfiguration.mm */, + 3D6DEDD58747685647800F21525DEFC8 /* RLMRealmConfiguration_Private.h */, + 97C24FBADCCD7036078377512D90D4D7 /* RLMRealmUtil.mm */, + BAEF988E635365578AACECB2A52620D3 /* RLMResults.mm */, + 708181884E851CC294593093D3921B23 /* RLMResults_Private.h */, + B0F9C1B839FB025457D8E24B0D0E8D9A /* RLMScheduler.h */, + 6E654A0432980B1F063FFDBCA71B4084 /* RLMScheduler.mm */, + 43D14090369EEC01BE508BDB88EB84F8 /* RLMSchema.mm */, + 120853B5C287EB6778D0E6F2CAAC678B /* RLMSchema_Private.h */, + 1B6E62F259BD798696AC28CA9B61D063 /* RLMSectionedResults.mm */, + F0E3797522D2DA92B3D9A8D35FFEDFE2 /* RLMSet.mm */, + 87B4B54B444CBCE7121C9CC71213A704 /* RLMSet_Private.h */, + 739D1EBC2858FD3E444E93BBB800622E /* RLMSwiftCollectionBase.mm */, + 62DA765EFA6176292C8BB0A39A6430D4 /* RLMSwiftProperty.h */, + D2AEB4E2CAF4CF35E4F45069EB30D0A6 /* RLMSwiftSupport.m */, + 41F5A37DA149DDD896A9588F912417F8 /* RLMSwiftValueStorage.mm */, + CDCA1EBD36A9944DE635F52ECFC297C6 /* RLMSyncConfiguration.mm */, + C9D1BC99201338B767AF74599605CBAB /* RLMSyncConfiguration_Private.h */, + 64108C8865FFF2EE03378892DBAA7633 /* RLMSyncManager.mm */, + 944425105FFCFF644DC439575272B712 /* RLMSyncSession.mm */, + 8FA4AA9362111E7D1B6C89F59C6E425E /* RLMSyncSubscription.mm */, + 272FB90054BCC4BB95316C5013FC9834 /* RLMSyncSubscription_Private.h */, + F927599937411CFC58D678F8486AB0AC /* RLMSyncUtil.mm */, + 29CBFE174016502905427BA7B5DBE044 /* RLMThreadSafeReference.mm */, + F11CF8FB763A7027E9275814033E4AAA /* RLMUpdateChecker.mm */, + E7606F26B9DF776AB41E04D3CF6CAE70 /* RLMUpdateResult.mm */, + 6DD2A0344579B5A9CAA6BDFFD7B8481F /* RLMUser.mm */, + 0E66C7EAAF91F65896E6CC7C4A7B26F4 /* RLMUser_Private.h */, + 5C604635A949AB81B5D5CAB66362D049 /* RLMUserAPIKey.mm */, + B0CBE3B4CF9091DD07FE7658445755DA /* RLMUtil.mm */, + 3535D8C2C242A80EFE2003ADDADD8EB2 /* RLMUUID.mm */, + FDA721544E537F06282FFFFB621FBD30 /* RLMValue.mm */, + DDFBD7539E664B8B6B16BDB8243C13CC /* Frameworks */, + 7D919CF14BDB8E4172DCEC37AFCFC76F /* Headers */, + 4DEB1A2015448DFA5346A44FB1C580A3 /* Support Files */, + ); + path = Realm; + sourceTree = ""; + }; + 084BA068F69F459D01FDC03CE5102E87 /* Support Files */ = { + isa = PBXGroup; + children = ( + 483DD8D3B583073CED182ABC65E08237 /* FirebaseAnalytics-xcframeworks.sh */, + AC40BB501A5BB0BEBA4E9E370E027119 /* FirebaseAnalytics.debug.xcconfig */, + 53F22C31C4648F4E4371ADD62CFCE32C /* FirebaseAnalytics.release.xcconfig */, + ); + name = "Support Files"; + path = "../Target Support Files/FirebaseAnalytics"; + sourceTree = ""; + }; + 09FC4539103C987BD4A358D70F4300F9 /* Network */ = { + isa = PBXGroup; + children = ( + CBE5568FBAD64B88E9DEBA7097A70ACB /* GULMutableDictionary.h */, + 2ECBE8E8556F51DD2D12C08DE1263BA9 /* GULMutableDictionary.m */, + 06FE9F21A3BCFA3977FAEECD35474C42 /* GULNetwork.h */, + B7487725A4319C3CAF8225F0C8F99718 /* GULNetwork.m */, + EB340D31B9671B20F48E9C1D40AEB894 /* GULNetworkConstants.h */, + 1152AD3AF12FA0DE0A46B04DA8CF3C57 /* GULNetworkConstants.m */, + A92EF1CA905127F130D1776E993E98FD /* GULNetworkInternal.h */, + C20CAC628237BB9D607750E34695E5FC /* GULNetworkLoggerProtocol.h */, + 447DCBE2B1131BC09AED15BD4E7E6C38 /* GULNetworkMessageCode.h */, + 8CCBD61D45E1DA5335507549F09ECA06 /* GULNetworkURLSession.h */, + 7070066373BC8611A2B554BE77E09B2C /* GULNetworkURLSession.m */, + ); + name = Network; + sourceTree = ""; + }; + 0CCAF5CDED2A83DCF55FD076ED546151 /* encode */ = { + isa = PBXGroup; + children = ( + ); + name = encode; + sourceTree = ""; + }; + 12CEE16D507D3813A7564E3C577D51BB /* AdIdSupport */ = { + isa = PBXGroup; + children = ( + 13B305E88DAB57F8C51783ADCEB98B22 /* Frameworks */, + ); + name = AdIdSupport; + sourceTree = ""; + }; + 13B305E88DAB57F8C51783ADCEB98B22 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 736926EDDD0EACA6E6342ACD806788CB /* GoogleAppMeasurementIdentitySupport.xcframework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 29AB22D147708C3ACCB485A392DEED69 /* Support Files */ = { + isa = PBXGroup; + children = ( + 020FDD18BA4ABFA3D61D95E45EFAC4E4 /* FirebaseAuth.modulemap */, + 3365BB0E589B36D213FB9E983F34EF99 /* FirebaseAuth-dummy.m */, + 27D5D30E3C0372FE553B522497F2D079 /* FirebaseAuth-Info.plist */, + 2A0132002DAF9BF16D277AB0D0C07A5C /* FirebaseAuth-umbrella.h */, + 0F8DAE8DAB33858EC467E8C46A252F13 /* FirebaseAuth.debug.xcconfig */, + 4FA2B79F663A9D69D6E613EB25A6F2BE /* FirebaseAuth.release.xcconfig */, + ); + name = "Support Files"; + path = "../Target Support Files/FirebaseAuth"; + sourceTree = ""; + }; + 2D7C8DF6DFFDAE046A414DCDE9EA3554 /* AdIdSupport */ = { + isa = PBXGroup; + children = ( + 843C74ACF66DDA6D7A4F889F091C3944 /* Frameworks */, + ); + name = AdIdSupport; + sourceTree = ""; + }; + 2DE115502795EA5D4E6E0E6F25B76A9B /* Support Files */ = { + isa = PBXGroup; + children = ( + 82BEA2A9C46781A0D1628AC337433495 /* RealmSwift.modulemap */, + F11AA3BD3B6733487D7ED153F816289D /* RealmSwift-dummy.m */, + 39B09EB68575118947CED1CC6D6C471F /* RealmSwift-Info.plist */, + 5C454B144382132DB0C1424B8423538E /* RealmSwift-prefix.pch */, + 718D25283FCCDB355A59F30C238CDC71 /* RealmSwift-umbrella.h */, + 8547F6FA127EF377B812C3DDDB5CC6EA /* RealmSwift.debug.xcconfig */, + 7908EB620837F7E1D1A620F7A161B653 /* RealmSwift.release.xcconfig */, + ); + name = "Support Files"; + path = "../Target Support Files/RealmSwift"; + sourceTree = ""; + }; + 33FCC40DECDFCDC84EF0FE7EA7241AF2 /* AppDelegateSwizzler */ = { + isa = PBXGroup; + children = ( + 6F386A0EAC54042F34AD558B82364330 /* GULAppDelegateSwizzler.h */, + FD47B704335D3B8A2DAF90093BD29570 /* GULAppDelegateSwizzler.m */, + 7F98669F88B9C95FEB19125B73434800 /* GULAppDelegateSwizzler_Private.h */, + C58E9D971BEAA0B2666855E46772D815 /* GULApplication.h */, + D8780156F717E510F1DB5FA53ECBEEFC /* GULLoggerCodes.h */, + 707F9FEDC83ABFDAF459079D0BE88C1E /* GULSceneDelegateSwizzler.h */, + 257F0A0FBD7080CADA3BD0EF0DAA0156 /* GULSceneDelegateSwizzler.m */, + C8FAC6B7AC02F097592BE88CD4EABC83 /* GULSceneDelegateSwizzler_Private.h */, + ); + name = AppDelegateSwizzler; + sourceTree = ""; + }; + 3C58AF22FFF1523566C3A039B0E320D0 /* FirebaseDatabase */ = { + isa = PBXGroup; + children = ( + DFA09D9997A62037EBBA3F916282D412 /* APLevelDB.h */, + 3B81F7B757D1B962385B509729E603BD /* APLevelDB.mm */, + C4E718B55509A9AA2889EA254EA608CA /* FAckUserWrite.h */, + 2AAAEDE8E70C8C7420323BCE56CECD62 /* FAckUserWrite.m */, + 013DBEEBEDDF4A433554616BCBBA997D /* FArraySortedDictionary.h */, + D5C8BA1EEC0185497B91CE4F4A3EA391 /* FArraySortedDictionary.m */, + 2345425439383E6C98582C65C0981322 /* FAtomicNumber.h */, + F2503973D433D6E9A0D2C052DE9C051C /* FAtomicNumber.m */, + DF55A01ECA815A9E60783C3BEAA1609C /* fbase64.c */, + 92FA39E85E83F2D45F0EFE7ED6AC3E9D /* fbase64.h */, + 06304D72C5C2F7A0DB5EC2BD2DBFBB12 /* FCacheNode.h */, + 28F4C70F3E073FC6BA4014DBCBDFC33B /* FCacheNode.m */, + 3463F8E9265223FD78A8E353D9DBC93A /* FCachePolicy.h */, + 90F4CCD10E8C11477F4BC57D0F8C8E20 /* FCachePolicy.m */, + 4310F18485AEFC94D8688C3A803C350B /* FCancelEvent.h */, + 9C65A271995DEF7866A8ACEA5248CC93 /* FCancelEvent.m */, + 8C46AC75A5F40B157446B74CFDEBDCE4 /* FChange.h */, + 7AF1FEB5A0A42BDF77BD2CE3A7CDE92E /* FChange.m */, + B50D0C80ED816334D64C4012ABDB6D91 /* FChildChangeAccumulator.h */, + D8FF4697BD930A161E25C7F50B4FBC63 /* FChildChangeAccumulator.m */, + 16A61136124D22967767C62762E11781 /* FChildEventRegistration.h */, + A16A5315E18D376E152E91F55B367ED7 /* FChildEventRegistration.m */, + 35106334CFDB44A3BF401053F4AB5332 /* FChildrenNode.h */, + 675C0C404FF5EA964785CFC002A6E20D /* FChildrenNode.m */, + CED95F9ADEF91DF005475A84C722E6FA /* FClock.h */, + DC3C5F7564BBF625FA085989C71B0540 /* FClock.m */, + 7FC074C669327E8C8F84CB1E0EF41773 /* FCompleteChildSource.h */, + 689C26D1B7BCCB029AE9A72765C6468E /* FCompoundHash.h */, + 75956E3ED82B4C4C3A8BF491AF04E129 /* FCompoundHash.m */, + 72F431CF7352923F85C4AD27477F4B3E /* FCompoundWrite.h */, + 338AECF668DCCB9C64EBE4A69BB6A954 /* FCompoundWrite.m */, + 0AA78A5FF346BDCCF63A27E56A597B97 /* FConnection.h */, + CA3763A5C3BE75A0E0860942F867C9E8 /* FConnection.m */, + 118893944206EA50EB70686CFE24555F /* FConstants.h */, + A036C3B6F27E62C0413AA1CB052F1E9C /* FConstants.m */, + DE35B94C2CED0E8E9CAE38566E26439E /* FDataEvent.h */, + 2ECCA115AD74D654B14B529508C64F3F /* FDataEvent.m */, + 1B5E77D8721F5D8AC2DD4588444F3EFB /* FEmptyNode.h */, + 2A141BBDF00F68D384672D09E6C8D5CA /* FEmptyNode.m */, + 324CE274DE272729DB6F10A4C8C8401A /* FEvent.h */, + D887E54D3239CBDA0F3CE1921760C572 /* FEventEmitter.h */, + F8E9BD133AFCC06067CDABEEB3220EF1 /* FEventEmitter.m */, + 312A6319AFA1D25F26944EE1A94437CC /* FEventGenerator.h */, + B40F9A123AE0840B522636A66050A271 /* FEventGenerator.m */, + 2D4B3FEF0D03F93C58C129DDF773C0AC /* FEventRaiser.h */, + 507728C48E9B69D1D56C13D2301CDB10 /* FEventRaiser.m */, + 7334D38A0B7D794172B7EDC55F342D71 /* FEventRegistration.h */, + F2AF3110914F29826DCE78B416523133 /* FImmutableSortedDictionary.h */, + C6C3FF34757A1E2892183B49F5842784 /* FImmutableSortedDictionary.m */, + B0C06E7081B48799232D89E17EB0A49B /* FImmutableSortedSet.h */, + AAD3672222B78EF845809BCE176BC39C /* FImmutableSortedSet.m */, + 972B364EC6AF475E2DD052A2A60FFC2A /* FImmutableTree.h */, + E94ECD3EF54AD47F74DAF000981E3F6D /* FImmutableTree.m */, + 1C61B12ACA3E421895B038C2C363D156 /* FIndex.h */, + 2537AFF1FBBC4757A039581EF92AE608 /* FIndex.m */, + 9EC1D2A0AB969A937D8CCD9DA60C7715 /* FIndexedFilter.h */, + D5100D25D948326FCCAF410A4BE86046 /* FIndexedFilter.m */, + ABCC74735035AF922CF393EA7C93A204 /* FIndexedNode.h */, + CA22FD4400AA8E8CB40D6E656136F272 /* FIndexedNode.m */, + 7C4CCD297749321D38B4D8E1C0E06675 /* FIRAppCheckInterop.h */, + FBF69EF961BCBADD5088BF639982EADA /* FIRAppCheckTokenResultInterop.h */, + F9E888606FE5836F42A73640926AC56C /* FIRAppInternal.h */, + B1DEC2457D87D238E0CD170552886919 /* FIRAuthInterop.h */, + 4DA65E275D60CAA4E6577D4B0C1A9DBE /* FIRComponent.h */, + 0D53DBCD1D5DF2809E0E17C553BF1699 /* FIRComponentContainer.h */, + F5AE5CC06827309EE8FD36857AEEAD93 /* FIRComponentType.h */, + FFB04E1B4A84C609969A49C26D4AA88F /* FIRDatabase.h */, + B6636FC9D55BA423AE5D31143F16C3C6 /* FIRDatabase.m */, + 5F42CD147531578D555111E281D9DB32 /* FIRDatabase_Private.h */, + 296BED686200C06B5795701FF3B5C0AB /* FIRDatabaseComponent.h */, + D8D3F8C07FC1809D6A888E03A8585E72 /* FIRDatabaseComponent.m */, + 4B62A1EFF65D0F7A6EDC00FAB049E14E /* FIRDatabaseConfig.h */, + 1A980800E710A010DF494004C96778B7 /* FIRDatabaseConfig.m */, + AEB6A7434EF1F3E8455BFE975EDDDC33 /* FIRDatabaseConfig_Private.h */, + 3FF0C7E3C42C45A71B34F4F0C942A1A7 /* FIRDatabaseConnectionContextProvider.h */, + 2EC642ED48C46A050E79A1F996755054 /* FIRDatabaseConnectionContextProvider.m */, + AEF6388410F1929F5AE36C5D9175EBC3 /* FIRDatabaseQuery.h */, + F1E367B64874B28C5E8947B105E8CB27 /* FIRDatabaseQuery.m */, + 0A03AE62123483BCC06367C075244AD8 /* FIRDatabaseQuery_Private.h */, + DFB42C998CA9D2337B259FCCF7EF8206 /* FIRDatabaseReference.h */, + 42E37BEF1DB058A22126DEAE325C8DB8 /* FIRDatabaseReference.m */, + 3DD63AD9A2170EA8DA1F0CED800B448C /* FIRDatabaseReference_Private.h */, + 4B30B908533087573BAB4A4DBFAB691D /* FIRDataEventType.h */, + B947898B4454551FA9410269740D2F69 /* FIRDataSnapshot.h */, + F03959F6EC6AFA8E040BC189C4A27323 /* FIRDataSnapshot.m */, + 7F2816163119D09FACF48BF06C77144F /* FIRDataSnapshot_Private.h */, + 5824BEEDD3575E41D0E94856799BCFA8 /* FIRDependency.h */, + 16FEB6A940B78555761BBE1CD7FF27F1 /* FirebaseCoreInternal.h */, + AA83942C00F87EB03B1859665331F578 /* FirebaseDatabase.h */, + BA97061F190CEDC6C816E99501895270 /* FIRHeartbeatLogger.h */, + 97376E6BECB554DDCA9DBDA7C7CB9217 /* FIRLibrary.h */, + 1174004659514A219C0CDDF7066B18C2 /* FIRLogger.h */, + 25D51C61BBC33B3A91740F2EBF9B9F9B /* FIRMutableData.h */, + 9420AAD5DAC96CCA96AB03E31BD57796 /* FIRMutableData.m */, + 5D2BCDEBF223F71AFF9564E683A322A8 /* FIRMutableData_Private.h */, + E979A44E4715ED4F43A9136F01012EA5 /* FIROptionsInternal.h */, + C7A2103476D3B0BEBCA3691034634FDD /* FIRRetryHelper.h */, + F76CC964DA80E549EEB9C20EB2651EB3 /* FIRRetryHelper.m */, + 03DCC5D7969A9F8F2B5976EE2BDCF5FD /* FIRServerValue.h */, + 7CC89F7D738A2A79CA9191BE2FC708E0 /* FIRServerValue.m */, + 9D1A70BBED3AA1D1F9152581BE1E35B7 /* FIRTransactionResult.h */, + B328E2210DE31FBAA889235596BD786D /* FIRTransactionResult.m */, + CF81F335A3222C35BAB5B868B46A8AC3 /* FIRTransactionResult_Private.h */, + 35F20F6EE823992F00BCEBD34542EF0A /* FKeepSyncedEventRegistration.h */, + 33F1B68B22D7FE9BC4BA619D1AB5F540 /* FKeepSyncedEventRegistration.m */, + 668B626E7E6C85D299AFCEA201C42B08 /* FKeyIndex.h */, + D984F82324A6B762CC65B0B8A3D4B26B /* FKeyIndex.m */, + 89442941AAFEBFBD27360DCA80B0C541 /* FLeafNode.h */, + DDDD0E5429AF168AA2D3ED8F2AED36D4 /* FLeafNode.m */, + DF1DFA0E235C7EBFBB0C874CC3FB1BB4 /* FLevelDBStorageEngine.h */, + E4274F4A59E6D6C77EE43A9264D4726C /* FLevelDBStorageEngine.m */, + CA25BAC788742E5802F043AFAF3A8086 /* FLimitedFilter.h */, + F1572B79421971BB2F3F25A47639DB2E /* FLimitedFilter.m */, + 1490E33A780917C79C45E316672435C0 /* FListenComplete.h */, + 94D7FB887A55186658BA2927E263E07E /* FListenComplete.m */, + 52B4AA8267619A715F34030E9D7C8DAF /* FListenProvider.h */, + A49A8CB71A70BD3B8FB71290DBA32D9F /* FListenProvider.m */, + 7547375C6508BD409DCDF96AC19B46BD /* FLLRBEmptyNode.h */, + 9506BA131E3841461239C5D751AD678A /* FLLRBEmptyNode.m */, + 45DCCB0A7A912B2851D96ECE76C3B6D4 /* FLLRBNode.h */, + A777775526F20173795213860C79ADEE /* FLLRBValueNode.h */, + 657050EAF637F805365C58A8E0BC3601 /* FLLRBValueNode.m */, + BBC0FDBE9BF419C3332954C5D758AE2F /* FMaxNode.h */, + B759001AEC2B36BC2B380644FBF8AEE3 /* FMaxNode.m */, + D7D16DA5AD11F3D6F872D23FA8E6A157 /* FMerge.h */, + DB1010F3237A58009791F7F779E11F1D /* FMerge.m */, + C3AB1EF8BE9154067AF395162065B7F7 /* FNamedNode.h */, + 6293EEA3422B89FF3E253E3876365114 /* FNamedNode.m */, + 37151480117365DF172C5574B6D0651C /* FNextPushId.h */, + CAACC193A9AD2AE454E57F5C3EF6F1D4 /* FNextPushId.m */, + 1BACF9688C6693A62406F49CBC73F486 /* FNode.h */, + F18ED32B3B8F221BFA6014B394B24828 /* FNodeFilter.h */, + 9ECD48B2C579D35E52365ED54C06D7A4 /* FOperation.h */, + 9020E232EB0972D241D3BF9C28E8BC0B /* FOperationSource.h */, + 9CF3F69586BC10D21D82153B4BF2A8E2 /* FOperationSource.m */, + A052E47398426D6826B82AAF3868DAA6 /* FOverwrite.h */, + 60E66EB709475B2AE9581154EEAFEF40 /* FOverwrite.m */, + EE55309BF72F93761475501AEEA09218 /* FParsedUrl.h */, + 3590D9904E6E3BCACBF1085443FE45FD /* FParsedUrl.m */, + 266C617256AA4E2CB667A0F9044E7108 /* FPath.h */, + 62DBEBE7FDE694DB7230FEAFD3AC7DD6 /* FPath.m */, + 9C6F5A54008F5FE3B7C04E60A783FF8F /* FPathIndex.h */, + 580F4927B5BDF99355238AB3E3B8A646 /* FPathIndex.m */, + F2A0CA9C4DCD46B305AFCB09388F8B44 /* FPendingPut.h */, + 8C58E49372EAEEB8B4514B62243B2D8C /* FPendingPut.m */, + A9CB8D94CC94FDEDC76F63707334A585 /* FPersistenceManager.h */, + E5728A1EC7C20549A71D8E4A6D437EC2 /* FPersistenceManager.m */, + BE470ED8559FFF0453FC817C2D585A1F /* FPersistentConnection.h */, + C43AF87E49A1E6F9EB9613D7269CD983 /* FPersistentConnection.m */, + 7ECC1E0C372817AC19942A566AB123C1 /* FPriorityIndex.h */, + F62A4B119F14F2DCBA60D4223F2BEDEC /* FPriorityIndex.m */, + 6193CC42799E1C407B66E8C95CC11099 /* FPruneForest.h */, + 5BC2453F28988CA912B8C605F9E28277 /* FPruneForest.m */, + AFB356F5255300E6FB821BAEBE11CEAA /* FQueryParams.h */, + 0751FFB6348E774F561AA56090F02B8E /* FQueryParams.m */, + 8F40B3B9417B5D4ED968E1E788B3A38E /* FQuerySpec.h */, + 6F2297CEDCE776B9F4D682C5BFDFBAF7 /* FQuerySpec.m */, + 9035019906CFA898627DB9DD54174418 /* FRangedFilter.h */, + 77CF941717A8A5BD89D10005F3094380 /* FRangedFilter.m */, + 3BA23E086F9B885781704FCA48B4BE17 /* FRangeMerge.h */, + 6B63FB84EB4C99C9989AE9702E6B5310 /* FRangeMerge.m */, + 3A337A8352740590C160918A1CC6B71B /* FRepo.h */, + 3C4C5034116D73230351A85353B11BBB /* FRepo.m */, + FAB149690E2D664FDECA85D5157CBA67 /* FRepo_Private.h */, + 09BC0DF6DDAAB485732A09CE78733647 /* FRepoInfo.h */, + FA61EC6075B55FC111B9D7281C25E9CB /* FRepoInfo.m */, + 98B7302B3903DB29AD102B2B4A7C077F /* FRepoManager.h */, + D1FCF70DD745852460CA893C0044F06E /* FRepoManager.m */, + 7B01D60353BAB7668513EE30428048CA /* FServerValues.h */, + 73941508AA91B8C0AC7E08B3C43C974A /* FServerValues.m */, + 97392617A9D0A4229CD0CBA298E78B57 /* FSnapshotHolder.h */, + F4F3CAE474A7B498BF161E01B891F739 /* FSnapshotHolder.m */, + 6547B8C2009B2D61EB11FEC0F64F29F5 /* FSnapshotUtilities.h */, + 70F4CDB8C474983A83FFDA390D5A657A /* FSnapshotUtilities.m */, + 2A07B044EF3476E89A8934CBC290CDB2 /* FSparseSnapshotTree.h */, + 1D347E1A64C9ADD432B01EE1CD0EF50B /* FSparseSnapshotTree.m */, + 5273EDBC2A77E71FC4220D15FFD2AC31 /* FSRWebSocket.h */, + 09F100EB4B62EBE83645C2D60ED1E078 /* FSRWebSocket.m */, + A1352CAA4472E809464D00B49A3A6BA6 /* FStorageEngine.h */, + 77FB6AA08E6C71D030AFA0335507B674 /* FStringUtilities.h */, + 56D7C61A84BD3126201E1B693272E5A8 /* FStringUtilities.m */, + 652A3A7D52D06A4AFAE994E85C60432A /* FSyncPoint.h */, + 007B099760AAE9DBA8EC8150D40C88BB /* FSyncPoint.m */, + 0C0AF19F9C4062998F561DD8F98DECE3 /* FSyncTree.h */, + EADAA6771DED910D18EEE52483AEA223 /* FSyncTree.m */, + 18B260C2BA6AF298BFDD66833B84A7CB /* FTrackedQuery.h */, + 2DC9D589442044C7CA61657FE041213C /* FTrackedQuery.m */, + F2348A5807D3DC0C79B38DE2BF5C174B /* FTrackedQueryManager.h */, + 102E79069AA2B7FA312F4A307CAB61A3 /* FTrackedQueryManager.m */, + AC3496D1774819DE9FF283E783E8FD57 /* FTransformedEnumerator.h */, + B7596BDDECA588FCF52569F283CD745F /* FTransformedEnumerator.m */, + A3B0C6C9B2CD46F23B0B57ADFA239899 /* FTree.h */, + D3C7869F6D75E8CDC540790526E3F955 /* FTree.m */, + 34182904E0E1E8C02F312847B25E4418 /* FTreeNode.h */, + 039997D3CBE3F7A0E8AF5CAE8CF8AF49 /* FTreeNode.m */, + E6B0319BF99F0E5F8A53C708EE2F0FBE /* FTreeSortedDictionary.h */, + D3BC4F854711166760C34ADA038051BA /* FTreeSortedDictionary.m */, + D4CA33A9E671FF56D957091FF43648C9 /* FTreeSortedDictionaryEnumerator.h */, + E9A4687D268F2913AF3361DC3E0DCA57 /* FTreeSortedDictionaryEnumerator.m */, + 04F3DD0C04BB7E1840D7DD9435C44113 /* FTupleBoolBlock.h */, + EA00F4F46EC2CD0F233E301B8D7D3F87 /* FTupleBoolBlock.m */, + 63554B52614D7D8DF01AB2A87A9CC991 /* FTupleCallbackStatus.h */, + 9EE5FB69103270807821EFED952A8EA2 /* FTupleCallbackStatus.m */, + 6904D0037830DB80686AB0A6EDFDD815 /* FTupleFirebase.h */, + BE9749E67C035DA4EB9E5F6AB5530370 /* FTupleFirebase.m */, + 35E2E52AD208369569D961888AD2CD8E /* FTupleNodePath.h */, + 9D885A4F106B62B2C0DB2B5CE2D09E22 /* FTupleNodePath.m */, + 309FE736880C3235DF3887AA58B3C6CE /* FTupleObjectNode.h */, + D98C07DBF8AFD2E90F45D95D0BA5E334 /* FTupleObjectNode.m */, + 0C8C2F327B6662093A84BFDB0321BAFB /* FTupleObjects.h */, + 692CA72025C2AD94D8AD564A919418FB /* FTupleObjects.m */, + B76E93B48A5797509F56D1C0B9296D4C /* FTupleOnDisconnect.h */, + D65CCF92BADFD9664EB7E03196C8195C /* FTupleOnDisconnect.m */, + D64B72A8936ECC9C34DA6EA69AD8B336 /* FTuplePathValue.h */, + F8FAD4104C03D65C5550064D9F044480 /* FTuplePathValue.m */, + 55FF929E3B066C69F518521636DBA3DA /* FTupleRemovedQueriesEvents.h */, + 8BCC07F63582332DF6501B6233E04AD5 /* FTupleRemovedQueriesEvents.m */, + 5FCFC34AFBC4E5C47B62D36842E9D028 /* FTupleSetIdPath.h */, + 0573A17A7335B226B940471176B068EC /* FTupleSetIdPath.m */, + 91B060AB17825145370421059E87B0CB /* FTupleStringNode.h */, + 3D4E6BB1FEF2DF20718587A7EE8B8918 /* FTupleStringNode.m */, + 49CEB01CF98BF899E526EC7692849F4B /* FTupleTransaction.h */, + 841716D96ED42D3A9096E922F0A3C8E5 /* FTupleTransaction.m */, + D123FAB0A8C5ECD50735F08853562BC3 /* FTupleTSN.h */, + CFB945C62972C0C90CE78FE6D174EAD1 /* FTupleTSN.m */, + 9ADF28900A460B3E7E1AF2D6D862756B /* FTupleUserCallback.h */, + 1EC2C755F7459C7D17578604910BA6C9 /* FTupleUserCallback.m */, + B997ABCC90C9366DF38FDE06D380B2A8 /* FTypedefs.h */, + A9B5783D1DF0F07EC4CC01D3E05F348C /* FTypedefs_Private.h */, + 05842D32365C92508821DBCFF24949FA /* FUtilities.h */, + 5026DF9D418AC9740AF4DC88D58E0F34 /* FUtilities.m */, + CE3CC14F5AC1D8BCEC33860FC79E5344 /* FValidation.h */, + 9E3E4E344F68B74F639CDE095DE89DEE /* FValidation.m */, + 125863111A1DBB3C7CB2752151C25750 /* FValueEventRegistration.h */, + 9E7451B12E477E50E5B6D057C62C9818 /* FValueEventRegistration.m */, + 187AAB69D8B2FC133DAAA952E9154DAB /* FValueIndex.h */, + 004F83479325FA52B3C2EF9F638F5C2C /* FValueIndex.m */, + 2E0B7881254469695A443E9B4ECCF474 /* FView.h */, + 10AC127C6D153D12363D963E92010133 /* FView.m */, + 2873E87EC61B34528E6E869AC2DCD567 /* FViewCache.h */, + F545DFF514F5EA358932BB95A431E476 /* FViewCache.m */, + AEB1B3775C7B162C71502AB49434EE36 /* FViewProcessor.h */, + 5ABBB25E158253F6289758734B748297 /* FViewProcessor.m */, + 921A7FA65DED7374E8FA5FEF975CD444 /* FViewProcessorResult.h */, + E5F8E0CE9018602A1E2F2C90CC6FB33E /* FViewProcessorResult.m */, + EA8239410F30B3473F054F4F9AC2D05F /* FWebSocketConnection.h */, + 7DA1270DF0D5F31B5860D0879C25BFCF /* FWebSocketConnection.m */, + 35220F076E37D3FB4AEFB242DBB9DA87 /* FWriteRecord.h */, + FF4E9D78A15423578B14516BCC3D0101 /* FWriteRecord.m */, + 2B3CB3DFA47B93EEDCE11386C1D23DFF /* FWriteTree.h */, + E1349D5F673D710C9751BEF3BD0990CF /* FWriteTree.m */, + 0E15FA60DA659491727FFBFD46B27EB7 /* FWriteTreeRef.h */, + F6D4069FBA41CDF529F7FF7044569873 /* FWriteTreeRef.m */, + C8756C73EF22A551744BB081DCF4FDEA /* NSData+SRB64Additions.h */, + DF26D9FD9034751F508E469A65F9DE14 /* NSData+SRB64Additions.m */, + FB5DB47764CEA692A58D7FD05D365E5B /* Support Files */, + ); + path = FirebaseDatabase; + sourceTree = ""; + }; + 3D5C9298C50349A99A2F00E8BFF9126B /* Support Files */ = { + isa = PBXGroup; + children = ( + 032A6D00D7568C566A9E84523D7F8ED4 /* FirebaseCore.modulemap */, + A056A0728CEA9D82899D8B1F03886BDA /* FirebaseCore-dummy.m */, + D0CCF972A2BCF6A4FA37AA00A90F021D /* FirebaseCore-Info.plist */, + 254DFE40388CA77868691F69AC5F12D5 /* FirebaseCore-umbrella.h */, + 10D87030427938D0539D5DF4EC4032F1 /* FirebaseCore.debug.xcconfig */, + 0F75325E1AFCBB674768EAEE2D817261 /* FirebaseCore.release.xcconfig */, + ); + name = "Support Files"; + path = "../Target Support Files/FirebaseCore"; + sourceTree = ""; + }; + 40BA3C74D8E4D14ADAC4C541007CE78E /* PromisesObjC */ = { + isa = PBXGroup; + children = ( + 14ED6C038781E8190323E214EB7F8D3E /* FBLPromise.h */, + 1082CC92F4A4AB1688B228846A11F83D /* FBLPromise.m */, + 8CEDB3566E20E923946312D7CEF69B71 /* FBLPromise+All.h */, + 9D857BC602EF666E952EE6B1639A9508 /* FBLPromise+All.m */, + E3E1C442BA8DDCEEFA65EE0379DAD33E /* FBLPromise+Always.h */, + C0D3E9D94E45F0CA51973A4FC3F7A77D /* FBLPromise+Always.m */, + 473C88C5429C1D64A09BB61AB8CF96B8 /* FBLPromise+Any.h */, + F5FC60DFF725AF93166D1B0F9E69A00D /* FBLPromise+Any.m */, + CA25B306FFAA76849CE6925F041F4116 /* FBLPromise+Async.h */, + 77F0D8AA239C613235E4A219436457D4 /* FBLPromise+Async.m */, + 59B1316F443B4F1AC8F4C103BE9970BD /* FBLPromise+Await.h */, + 1173B352316565C062F130D6DF0B2D83 /* FBLPromise+Await.m */, + BB799EAE95DCF5C0E5C3CA09470ABA2C /* FBLPromise+Catch.h */, + 76967898F8101178E562B75A2FE2C7B6 /* FBLPromise+Catch.m */, + 48F42BAA7BEB6F1D7FB7708D9D26470E /* FBLPromise+Delay.h */, + E372170790901E282DA2178AD64F9AF1 /* FBLPromise+Delay.m */, + 74B5118CEAD735734BEAA228AD3D8739 /* FBLPromise+Do.h */, + 30A03FE1790D4156F8F0C48C9824EE5F /* FBLPromise+Do.m */, + 122D962CA59AC2D4A82C5178BE4BE260 /* FBLPromise+Race.h */, + 58E43043367BCAD229609546CB6EF371 /* FBLPromise+Race.m */, + 050B6FE33817741C4489AF2856307BDB /* FBLPromise+Recover.h */, + FCAD24AC225AC807A081C35F3B371DA4 /* FBLPromise+Recover.m */, + AD0FDF20ADB9C0908115F409C91E242F /* FBLPromise+Reduce.h */, + E00B9C320CCC9F274F7D1867FC7C18E0 /* FBLPromise+Reduce.m */, + 7BD2BA99023096C1DF3C88F2DE465DD2 /* FBLPromise+Retry.h */, + F50FD872912D12668F5FF512DB8D6FA2 /* FBLPromise+Retry.m */, + E2DDE940DDAC937FC95E2A04A274103D /* FBLPromise+Testing.h */, + 17586B39950BC2B022A340DD26D64DC0 /* FBLPromise+Testing.m */, + BC987A1227156846E08850D86560BDF5 /* FBLPromise+Then.h */, + CAE042BCC7FF44CC71EC43BF6F7B7CBA /* FBLPromise+Then.m */, + 2710FEC0F62930F9443537F90F05D60F /* FBLPromise+Timeout.h */, + BF5A2E32B76BCCEDB11A4CC15B579BBB /* FBLPromise+Timeout.m */, + DE81F36FF24373414B6EC1A426429DDC /* FBLPromise+Validate.h */, + 59658C383969DFD4CC50A9FB8FE855AB /* FBLPromise+Validate.m */, + 6C8D0EA446BF7DA682A806ED24FE6AFB /* FBLPromise+Wrap.h */, + B6A729DD21BF2EF3E08B418A6DA898B0 /* FBLPromise+Wrap.m */, + E77B5F799945E2A80CEF1ECB60633E49 /* FBLPromiseError.h */, + 7055A9FCC22D8FE5674415195AAB67AB /* FBLPromiseError.m */, + 22876DDCA074830528A1B2A90E9096F6 /* FBLPromisePrivate.h */, + 44FFEBF653DCAA7740DA6A359B3DAC77 /* FBLPromises.h */, + FA21233F2F86D3B6BE73DAA1232FE922 /* Support Files */, + ); + path = PromisesObjC; + sourceTree = ""; + }; + 40ED82A61AF3277F647E69D164E801FE /* Support Files */ = { + isa = PBXGroup; + children = ( + 8A743CE22E7FE0C01E0F378C88109B68 /* leveldb-library.modulemap */, + 458BC4E3C00864D5B96FB2C89BE7DED9 /* leveldb-library-dummy.m */, + 32B097528C97B06073D7C5C2098FC9BE /* leveldb-library-Info.plist */, + 1153AA0F8C924E8939A0BE0804E5FEEA /* leveldb-library-prefix.pch */, + EDFEE8706FA0AF292187CAE8E1EF207B /* leveldb-library-umbrella.h */, + 6BF24E0394DAD3101FF5C00412EB1C4D /* leveldb-library.debug.xcconfig */, + 75552E75CFD01D4BD91E2725CDEF78C1 /* leveldb-library.release.xcconfig */, + ); + name = "Support Files"; + path = "../Target Support Files/leveldb-library"; + sourceTree = ""; + }; + 45ABE944C527C74C9104AEEF22CE729A /* leveldb-library */ = { + isa = PBXGroup; + children = ( + 1ADF76418061CD96E158397CF9BB037B /* arena.cc */, + AE21984D85FCC8A58C4A3DEB607EE9B3 /* arena.h */, + 4B39E52B0C608DB97C5C4253CF1DF99E /* block.cc */, + 600763BBCBED3F50EE109FA6AB08E882 /* block.h */, + 35CB08C83459BF6C53FCF704A67647D6 /* block_builder.cc */, + 4DB1A365BD7D10214DD2C7AE73A31366 /* block_builder.h */, + 0780A95F429DCE64484BDD78CBA3FE12 /* bloom.cc */, + AF32F1890AC304CEACE3EC8163C6D595 /* builder.cc */, + FE30687F11D90C3A5C7F0BC4A4F7C122 /* builder.h */, + C8BDC147022A51D0ED823DC6230006BB /* c.cc */, + E166A650D7D8C863AB91749CE9A89980 /* c.h */, + 110E93ABDED0BDC603500CB52BB1E1E5 /* cache.cc */, + 50394C30904748E456D4C35922B549B3 /* cache.h */, + 18957DF296CAB6C27B5D971F258E0A01 /* coding.cc */, + A81FDBBC145D10A1514304C22193715C /* coding.h */, + BDE9BA49B88ABDE1B7B491F0876E56D6 /* comparator.cc */, + B11618F2A39522921E515B9556E49021 /* comparator.h */, + 17848892389DEF304DC3D3D5F8B965A8 /* crc32c.cc */, + 2B1A9A9086F5222D113BD0D4C6521882 /* crc32c.h */, + 581EF75B385FA2FCCBB0497AC0AC8A58 /* db.h */, + C770CCEDA892E21FD63BD717C4A20708 /* db_impl.cc */, + AAE0B0D562FECE9B4EA7BD57332F263C /* db_impl.h */, + F557FDA3AF2F031583CCC00944047D8A /* db_iter.cc */, + 176C38A32F80DAD2F58BA0865F64426A /* db_iter.h */, + ECF825CA7953BF64C51F8BCB314F7A1C /* dbformat.cc */, + 1051F740E13750B942A9EDA85AA602EE /* dbformat.h */, + 05B386CDC39EA631D1FAAA7D1F0AB45A /* dumpfile.cc */, + ABE3480E6C4EFBD93505A4B57A945898 /* dumpfile.h */, + B6AF9354970089CC782E648426B0F62D /* env.cc */, + AD80C00D5C4B562AD2F08B823827B159 /* env.h */, + AC67D1A683AEF0B1D0C65AE006AFDD82 /* env_posix.cc */, + FFDDE3E628D464C5FAF7C60041209C2C /* env_posix_test_helper.h */, + 781F45EA0C7D63C20AA65A2ECB8306B9 /* env_windows_test_helper.h */, + EC87252ACE45D15F776E6AB2967A03D1 /* export.h */, + E11FC028A82D1763971334635D2617A3 /* filename.cc */, + F6EA58853A83F71F9E161BBA885467E3 /* filename.h */, + CB6CC9C42F657883774DDF1FC12F6B95 /* filter_block.cc */, + 287C36FAAEDA194E995524403501AB31 /* filter_block.h */, + 0BFFC1CBABB5EE6979B7BB6454C1F606 /* filter_policy.cc */, + A43C946F25F4088423BBB29BB0D1E82F /* filter_policy.h */, + 25364FCE8A53D06CD550B641C415881F /* format.cc */, + 56824B248662C8E8C141F005C41977B9 /* format.h */, + B5D5E48B2A9BCFDED384060054046493 /* hash.cc */, + B0C804B4546C72B739AD4D126464376F /* hash.h */, + 3E3B8F36375EA3714EC52956048A32C4 /* histogram.cc */, + 57D22D4FC5A856CAA41A5E4B0378EB49 /* histogram.h */, + 111F794074A676995CDDD8A9D7065800 /* iterator.cc */, + 9668070A520556E1157179EFD5675DA2 /* iterator.h */, + 5B906ACE4C08A720ED3DEEE6A58B6D51 /* iterator_wrapper.h */, + B7D00F668FCD769C1AF57B80F9EF273E /* log_format.h */, + FD617FE550E98264A4A123767CCCB5C9 /* log_reader.cc */, + EAB3A0514E6334B17A71E551EFCEB469 /* log_reader.h */, + F387E83A61343EB694A8E28807337949 /* log_writer.cc */, + 4F8113D296393D094DD639A535F9873C /* log_writer.h */, + D17F4CAEA8B1222B41373E48DDB479F8 /* logging.cc */, + C6275AF2BB6CE62341D7E3633E717BEE /* logging.h */, + B1383C44D5CC1F593039878620AA112C /* memtable.cc */, + 7D790D2DD3CD5C606CCF3B56048A95D6 /* memtable.h */, + 29924CAAFCB95B7922AD14E3631630E1 /* merger.cc */, + BCD33795AF033DD0357292495050944A /* merger.h */, + ADB9AD101FB170D305160E82F1CC2AA3 /* mutexlock.h */, + 6A1EB85929DB5ABFC8B1B0F7CA908A93 /* no_destructor.h */, + B860C210552E04D159F16FAC9529BE68 /* options.cc */, + BB43DCDDF68FDAA8606A46164F080265 /* options.h */, + D7ADD5B6B5915AEAC85BA95F031C7AAB /* port.h */, + 35C5CA813B56606F6856DDAC7EC3B552 /* port_example.h */, + 82842089E759BBC3480E5CB007595E93 /* port_stdcxx.h */, + 4A65A260D5E743AF8EF26E0EC4DBB9CA /* posix_logger.h */, + 5F3C1CEEBD4F3E655891CC3098279020 /* random.h */, + ADD8E035121D65CDD6CF8FEC0FE3FBFD /* repair.cc */, + D69481ED1553EEC1AC684D6C26C0022D /* skiplist.h */, + CEBEE94472042794604075BCA211146D /* slice.h */, + E195C7C4C8A627E9BC80CA7047D22DFD /* snapshot.h */, + FE2C17AB2A7CF72D25F49312B857984E /* status.cc */, + D6239ED73C89FD84A2B7E3742D7E015E /* status.h */, + 6A9CA393FA5F4F8BE4BD71ADB0DAE631 /* table.cc */, + AE140AEAF52DA37BEE141D52E151594A /* table.h */, + FD32D97423F1C3AD8AD7075D273598CA /* table_builder.cc */, + 795AEE8AFDEC780A0E27DFCCEDCBE103 /* table_builder.h */, + 2EB81C3B8587730347BDC959EAAC9FA2 /* table_cache.cc */, + 0C8F9D1F3278289794C00D2F8EC2D354 /* table_cache.h */, + DDC9E831C2A72BB2A398571D8AD3C8EA /* testharness.cc */, + 136D4F7911367790110F5E9240A6FD95 /* testharness.h */, + 7CA157D50F38EC9E1EDB65A499D536F7 /* testutil.h */, + CB6EC6D167E8A3AB0DFE54EBC765CAA3 /* thread_annotations.h */, + B3B9F9E57BAB9DB88B08810413E1BFD7 /* two_level_iterator.cc */, + 81EF26534B7108DEFF43DFD082550D16 /* two_level_iterator.h */, + 5F51D8C4AC0945BEB82DE5747E45BC96 /* version_edit.cc */, + 44DFA81BB6A42907B0617316BF7476AA /* version_edit.h */, + 09B54AFC23373B0CA6F8F53FCAFB8B94 /* version_set.cc */, + 1543F2502D4867CC79A5AFF5A5D871C7 /* version_set.h */, + 7671FC7CD2367A77CBAF94D322CD3EA0 /* windows_logger.h */, + 443669EB0193E1FDA50EE1B7C683DA16 /* write_batch.cc */, + B16C94E5F3A025995171BD475489E65F /* write_batch.h */, + 0F2F425451E6AF67F3E0D5654E90ED43 /* write_batch_internal.h */, + 40ED82A61AF3277F647E69D164E801FE /* Support Files */, + ); + path = "leveldb-library"; + sourceTree = ""; + }; + 45AFDC20EF1F48BAD68B5C6562915F28 /* Support Files */ = { + isa = PBXGroup; + children = ( + 4FA3F6838DFFAA39E5B72EDDD953DACE /* GoogleAppMeasurement-xcframeworks.sh */, + CEC46A5E041A4A0D0E0314CF5F667FFD /* GoogleAppMeasurement.debug.xcconfig */, + 23EAD188D4983631890D4FE0563517B6 /* GoogleAppMeasurement.release.xcconfig */, + ); + name = "Support Files"; + path = "../Target Support Files/GoogleAppMeasurement"; + sourceTree = ""; + }; + 46B2E894C11AE6C8239389477D4C8E26 /* Core */ = { + isa = PBXGroup; + children = ( + 703AE36A6535247556EF937C30749277 /* GTMSessionFetcher.h */, + B563271FE374CC1858749750DE0541AB /* GTMSessionFetcher.m */, + 1ADBEEDE93688F19E571CE7A74DE23AD /* GTMSessionFetcherLogging.h */, + 2FBD192144F1B9FEFEB202A6CA259781 /* GTMSessionFetcherLogging.m */, + 85A86307CFF228951C1F53BA876D81A8 /* GTMSessionFetcherService.h */, + C600859214CB6427CF9C135B659E3AF6 /* GTMSessionFetcherService.m */, + 2E46BC3A6CF1D9F1F138BD437FF6E7AA /* GTMSessionFetcherService+Internal.h */, + 1100DABD72493AA08CE2AC79C1B6E19C /* GTMSessionUploadFetcher.h */, + 6046DACC7689D111783C349D3D6D4D73 /* GTMSessionUploadFetcher.m */, + ); + name = Core; + sourceTree = ""; + }; + 47EF9E00A9BAD2E33DEE38002999E401 /* Firebase */ = { + isa = PBXGroup; + children = ( + 04B2401F9AD3DB58FE2072027EE1BCC8 /* CoreOnly */, + A30CD403F6906B8D861A2CBA7ABBE94B /* Support Files */, + ); + path = Firebase; + sourceTree = ""; + }; + 484FB6A4E4D0DE54B8BF0BC2A89436A2 /* UserDefaults */ = { + isa = PBXGroup; + children = ( + B2750DC4306D28633B3876C5C545F55F /* GULUserDefaults.h */, + 7E9095E4AA136950BC9BCC00DC4AF244 /* GULUserDefaults.m */, + ); + name = UserDefaults; + sourceTree = ""; + }; + 4C31B65B5B5EB3013F88A34E96440B29 /* Support Files */ = { + isa = PBXGroup; + children = ( + 6892038D8802D6670D85D0F370C2A713 /* FirebaseInstallations.modulemap */, + F1A63F9946D77AA0988F1947BD912CAC /* FirebaseInstallations-dummy.m */, + F07B9D10EA63EC4EF28E583DF5056E86 /* FirebaseInstallations-Info.plist */, + D93CC25FAAF72AD0E3E8DCA1B38AC5A6 /* FirebaseInstallations-umbrella.h */, + CA91F1F593BC0E1D3C7684615182D7CF /* FirebaseInstallations.debug.xcconfig */, + FB1B9D02FB871F65EBDB1D3F578155C0 /* FirebaseInstallations.release.xcconfig */, + ); + name = "Support Files"; + path = "../Target Support Files/FirebaseInstallations"; + sourceTree = ""; + }; + 4DEB1A2015448DFA5346A44FB1C580A3 /* Support Files */ = { + isa = PBXGroup; + children = ( + CEBA35B3F0A1172CCFDD4B627C065870 /* Realm.modulemap */, + 6287A4A1BAE8862EA2597F0C1383E8FC /* Realm-dummy.m */, + D78A368E37232A2DE537AA23340C97BF /* Realm-Info.plist */, + 1F6EBB208A039BAD472B7CB6E7FBCFF4 /* Realm-prefix.pch */, + FD2C9898C3BAE3BAF41E73B91BB58EDE /* Realm-xcframeworks.sh */, + 555B74707E9153148A9CDBFB9095395D /* Realm.debug.xcconfig */, + 03E65604EC485B5893B33E6098B32451 /* Realm.release.xcconfig */, + ); + name = "Support Files"; + path = "../Target Support Files/Realm"; + sourceTree = ""; + }; + 56062E9F1708394BD469588869510C52 /* FirebaseInstallations */ = { + isa = PBXGroup; + children = ( + 1F849893A149318894D9DDDDDC9FABE5 /* FIRAppInternal.h */, + 077DD8E014A49337645CEFA1ED433797 /* FIRComponent.h */, + 56627901A29601B454E5A4D76045BF54 /* FIRComponentContainer.h */, + C259035AB4864FBC222C048097AEDB6A /* FIRComponentType.h */, + B13B7BABC1263F4E9BC3D14D6AC1096F /* FIRCurrentDateProvider.h */, + 40AA7B7AA35DA6F3567044AE67EC3AE3 /* FIRCurrentDateProvider.m */, + D209A08FA1E9922FD310E9BE48FE9AAC /* FIRDependency.h */, + FC3CEE71B7D74D3270183AD28E24D9FB /* FirebaseCoreInternal.h */, + CF8428E4E89357A6FCA2D964BE2D2D03 /* FirebaseInstallations.h */, + 27947EE5809D5134A30123C3BAD888C7 /* FirebaseInstallationsInternal.h */, + 9FE4A6CCA174E0D63A5A98CABD8EC548 /* FIRHeartbeatLogger.h */, + BA4BB1B3E24F76A1197B5722E1A54B84 /* FIRInstallations.h */, + 5F207504952B0CD5C9F5FE247A248597 /* FIRInstallations.m */, + 4E026AD30098E7501DEFA64FA8A2B8BF /* FIRInstallationsAPIService.h */, + F5C7322600CB61912E75AD1BB17BDBA9 /* FIRInstallationsAPIService.m */, + A2C57AE6DAC312F02E876AD29647C664 /* FIRInstallationsAuthTokenResult.h */, + 8A5426C951D7F583BE4F54AC6D9FDCBE /* FIRInstallationsAuthTokenResult.m */, + 95EA0878DF345763F81B3830AECFF356 /* FIRInstallationsAuthTokenResultInternal.h */, + CDB00D7D033A76284F4C2D94CD218ADA /* FIRInstallationsBackoffController.h */, + A7136DC79F7CF21A918462EA6BA72D9F /* FIRInstallationsBackoffController.m */, + 7B2844F303E92ABE8A160DD9F6582F0C /* FIRInstallationsErrors.h */, + 3D63A41B92013D355B257E784C3C5D2E /* FIRInstallationsErrorUtil.h */, + EBBB58C277BED60ECBB0936F62871EA6 /* FIRInstallationsErrorUtil.m */, + 94C405D207D05FB559806347FF4C3110 /* FIRInstallationsHTTPError.h */, + 4F4AE0B2518B127D5CFD6A229F918FBE /* FIRInstallationsHTTPError.m */, + C3837D45F314C1B4B6B4AD233C4F06DC /* FIRInstallationsIDController.h */, + 9FF9B18D901B58F5B274E797ABF8D03C /* FIRInstallationsIDController.m */, + D53299DB70CFB23861357EA947C70688 /* FIRInstallationsIIDStore.h */, + BE6CCDBE7A5141FB59661292B11561C0 /* FIRInstallationsIIDStore.m */, + 32CCE9D44B7DBFAB4EC8193C9E7907EF /* FIRInstallationsIIDTokenStore.h */, + 8ACA29DAD3C62BAB3015BD90E9439CB1 /* FIRInstallationsIIDTokenStore.m */, + 24E342468348506C8B682D5206A317CE /* FIRInstallationsItem.h */, + F2DAEC929043E230DBB3692CFC09A1BA /* FIRInstallationsItem.m */, + 68AE375B41C0795563080D459FDCC110 /* FIRInstallationsItem+RegisterInstallationAPI.h */, + 89F626DEF1C52C94294D9723D0C99539 /* FIRInstallationsItem+RegisterInstallationAPI.m */, + F1CC9D6836BEB84A834ABB338A080E55 /* FIRInstallationsLogger.h */, + 0A3C948976000104C7FFE044C96214F8 /* FIRInstallationsLogger.m */, + 8724DAAB9ED5D56FA204FF734EE4FD86 /* FIRInstallationsSingleOperationPromiseCache.h */, + 6BA7C44B9E19D70D498CD1406747C619 /* FIRInstallationsSingleOperationPromiseCache.m */, + 46B0CA64A596FDBA487EC8BF5923246E /* FIRInstallationsStatus.h */, + CFEB25BE4BFD56BF6D6D28C7DBF5F9A2 /* FIRInstallationsStore.h */, + D80EF8C0A8F6337C6FB4F253C9D82B8E /* FIRInstallationsStore.m */, + 8AAEDD3920555DD075FFA6D823419E99 /* FIRInstallationsStoredAuthToken.h */, + 7BE10AFF86267C9FDAC00B2AAB63A15D /* FIRInstallationsStoredAuthToken.m */, + 648A0A18D652FE8A5C1DF6848D5864D1 /* FIRInstallationsStoredItem.h */, + 77674F69710E6CF04D1D387F6B6F1F36 /* FIRInstallationsStoredItem.m */, + 6DEADF2D6BCDFA40C7B0F220FE995B41 /* FIRLibrary.h */, + 58050F9C59254E6D397ADB56DFC128C4 /* FIRLogger.h */, + 8E2D8E4D702AA7E3958C44B41A68AEF3 /* FIROptionsInternal.h */, + 4C31B65B5B5EB3013F88A34E96440B29 /* Support Files */, + ); + path = FirebaseInstallations; + sourceTree = ""; + }; + 6009B320FF4DAC49674C453D5B1CF545 /* Pods-PRTY */ = { + isa = PBXGroup; + children = ( + 5850037D209BF1B3CDAD9335AFDC8EE3 /* Pods-PRTY.modulemap */, + A3FEEBB89E6BA6F6E8EA89482526C07C /* Pods-PRTY-acknowledgements.markdown */, + 9392ADE8C2DDE5988894EE97BD57E0D0 /* Pods-PRTY-acknowledgements.plist */, + 647108F63AEB846763605E0AFE84F78E /* Pods-PRTY-dummy.m */, + 086091EC6366134D5C0A260E2ABF57D5 /* Pods-PRTY-frameworks.sh */, + 625BF0B0BDAD0167B52F23BE38835B07 /* Pods-PRTY-Info.plist */, + 2B738DB0AE5FFD26E7118871882CA3F6 /* Pods-PRTY-umbrella.h */, + ADE396F87DDA126FB067A8765E2CCFA7 /* Pods-PRTY.debug.xcconfig */, + 631552790F8641131F8F403D6D4D68BC /* Pods-PRTY.release.xcconfig */, + ); + name = "Pods-PRTY"; + path = "Target Support Files/Pods-PRTY"; + sourceTree = ""; + }; + 63FF9ADB42142C23E72E13467246EDAC /* Reachability */ = { + isa = PBXGroup; + children = ( + CB623088DFC607EEA6CC6E2C99E661BB /* GULReachabilityChecker.h */, + 542B20DEA26B5C074039A87247015DEF /* GULReachabilityChecker.m */, + 78BCFBB3475F1361601C33BBE6B25FFC /* GULReachabilityChecker+Internal.h */, + 89A1FB094E0C49A6D4987A61F9960B34 /* GULReachabilityMessageCode.h */, + ); + name = Reachability; + sourceTree = ""; + }; + 6D3F418D77B4F1EA304842B28A5E893D /* Frameworks */ = { + isa = PBXGroup; + children = ( + 54DCA8704F0B3CA00373C0DC084CB440 /* GoogleAppMeasurement.xcframework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 714178634F1BAE8778B5800B5A2DC780 /* Targets Support Files */ = { + isa = PBXGroup; + children = ( + 6009B320FF4DAC49674C453D5B1CF545 /* Pods-PRTY */, + EA7F65BAE05ACDC883E3B83E53D5DACB /* Pods-PRTY-PRTYUITests */, + 73F675BA1E52EC7E2B236742C009D491 /* Pods-PRTYTests */, + ); + name = "Targets Support Files"; + sourceTree = ""; + }; + 73C78B7F6E344DBDE0A61BB033C2667C /* FirebaseAuth */ = { + isa = PBXGroup; + children = ( + 5F42FD92CC45EDFD0C54EE547EE79090 /* FIRActionCodeSettings.h */, + 81B38C32D7A56C22344E671F7C0B1AF1 /* FIRActionCodeSettings.m */, + AC8ABFC882AE8D079F88275E0F5AA22D /* FIRAdditionalUserInfo.h */, + 56DA4B923BA10A0AFF4CBCE4257C2480 /* FIRAdditionalUserInfo.m */, + 1A9F68773EE5E52B4D5659917D69DBAF /* FIRAdditionalUserInfo_Internal.h */, + 6CE6F0F74A2B43DEE1CA48C3DFBC20DA /* FIRAppCheckInterop.h */, + 5974F17EA36C2FB1DFB94CB822008CDB /* FIRAppCheckTokenResultInterop.h */, + 301C5C7EB56673BEA7FD351C9E864BD8 /* FIRAppInternal.h */, + E609518EF2F1803F18D4DF39F3B4FB27 /* FIRAuth.h */, + C21BB75CDBF87E02D19B34054FA40340 /* FIRAuth.m */, + 72B122535CC236E3BC29334CA1639C6E /* FIRAuth_Internal.h */, + B7817A8A19488A6E5E1F62D68DACF069 /* FIRAuthAPNSToken.h */, + 93E7C59C6BE703966530FFBC723395EF /* FIRAuthAPNSToken.m */, + 8E04B2430253816BA0826684401AB443 /* FIRAuthAPNSTokenManager.h */, + 3939D097FA2B064D8642167CB9C80243 /* FIRAuthAPNSTokenManager.m */, + EF4313DE4400552722C93B74B967C814 /* FIRAuthAPNSTokenType.h */, + 898ED1F0E51D270602B2D9E712BDFB17 /* FIRAuthAppCredential.h */, + 80091CE146D230191C846447F22D2BFC /* FIRAuthAppCredential.m */, + 2FFCE5665AD9B43DF0409F6A7B9C97B9 /* FIRAuthAppCredentialManager.h */, + 8CD89FAADE3C7B16A0F34D8014E0ECCE /* FIRAuthAppCredentialManager.m */, + 7F4F042C307A225AAA16C9601FF316FF /* FIRAuthBackend.h */, + 1B387526B9BE23AC791723076F4BBF0D /* FIRAuthBackend.m */, + 6FF141A971FE681D3139DD5BC9039439 /* FIRAuthBackend+MultiFactor.h */, + C341B5E37833446B630AF47E00CECF59 /* FIRAuthBackend+MultiFactor.m */, + 2D0A7F15D7C1C5FAB85E7E8AAA2FED49 /* FIRAuthCredential.h */, + 5727B0661FF05A9D9CB986B6E82760FB /* FIRAuthCredential.m */, + D0B5650C6E0ADF651F660A4F97DB1A67 /* FIRAuthCredential_Internal.h */, + 9A30C75392B91F7A665289F629130CC3 /* FIRAuthDataResult.h */, + 6B4C6D7ADDA4ADABDBD392B362DC1F38 /* FIRAuthDataResult.m */, + 00E78D580C86EE50250D99A09C295403 /* FIRAuthDataResult_Internal.h */, + 38C820D1FF6FACD317F69B7822D4B160 /* FIRAuthDefaultUIDelegate.h */, + 4C8C68A38AE16BAFA716CDBF9740AAEE /* FIRAuthDefaultUIDelegate.m */, + 063CA7411C06AB807B4B631C3D730ABC /* FIRAuthDispatcher.h */, + C4AEE519BA69496F1FD1C1F661D8E156 /* FIRAuthDispatcher.m */, + CC6D95242984ED92CFCC5367CC6F5AFE /* FIRAuthErrors.h */, + 39B4A3F4F9FF7842FA2A7D4F246719A3 /* FIRAuthErrorUtils.h */, + BE5EA9BAFBD4C1C39027D404A599B6E0 /* FIRAuthErrorUtils.m */, + 790371766FE16C535A3A6564C2016038 /* FIRAuthExceptionUtils.h */, + C37804A80D841783D9BF3A30B9F8016A /* FIRAuthExceptionUtils.m */, + B699CB81D7A551A9BE7FB104B80D114D /* FIRAuthGlobalWorkQueue.h */, + 5706AC95CB4140FC7CEF869802B2B37A /* FIRAuthGlobalWorkQueue.m */, + 3F3D7C8AA04555304F587C2EE131762B /* FIRAuthInternalErrors.h */, + 3BD63FE4290CDD7BAC1946490F265016 /* FIRAuthInterop.h */, + 73D394BF34BF20845775F8C96C11C552 /* FIRAuthKeychainServices.h */, + 47384AF77CA4509C7238A8A3B5F9D3C1 /* FIRAuthKeychainServices.m */, + D65779CDF02306477DFB2EE59C042724 /* FIRAuthNotificationManager.h */, + 1E85C3D67C66233F215F077D5D4DBAFB /* FIRAuthNotificationManager.m */, + 255C5F38BC053F1E20A8E00981F2D825 /* FIRAuthOperationType.h */, + 8CF57CF9CBA1F70F48ADF8E3845AD4E5 /* FIRAuthProto.h */, + 2102618715F19E54D0AB8FB6593E0326 /* FIRAuthProtoFinalizeMFAPhoneRequestInfo.h */, + A99DA8352A55CF898457A0B158BB8961 /* FIRAuthProtoFinalizeMFAPhoneRequestInfo.m */, + 34BB5F58F426BDBCA59A72E52B095E95 /* FIRAuthProtoFinalizeMFAPhoneResponseInfo.h */, + 20527044548AD5FFF595A5E3278C7287 /* FIRAuthProtoFinalizeMFAPhoneResponseInfo.m */, + 3F37469C8502B8AA3CAD193EF4D56E93 /* FIRAuthProtoMFAEnrollment.h */, + 0E5FD8D39CE43C6B9EF33E3B84B7C417 /* FIRAuthProtoMFAEnrollment.m */, + A5D259662259C7BE1415453C22210DCA /* FIRAuthProtoStartMFAPhoneRequestInfo.h */, + 90F49AB280D154511F8828F29429908F /* FIRAuthProtoStartMFAPhoneRequestInfo.m */, + 7A4A2A3F4FEE1B358A1A649FC0C19EEE /* FIRAuthProtoStartMFAPhoneResponseInfo.h */, + 335DF35A42C03B1C619B15E6AFA1D269 /* FIRAuthProtoStartMFAPhoneResponseInfo.m */, + 32EEA95F0D817AB69D4DD7990267512E /* FIRAuthProvider.m */, + 21F6C74565B78083660C443B41DC95DE /* FIRAuthRequestConfiguration.h */, + 07FFA32CF64DC17468EA57AF8C75CADF /* FIRAuthRequestConfiguration.m */, + A3D9BAC3AE5D6F200CE6741CC7D8430A /* FIRAuthRPCRequest.h */, + A431F7DED716295CBC39AAAC7731B616 /* FIRAuthRPCResponse.h */, + 226C88C2143E230C84E42844AF62C9FC /* FIRAuthSerialTaskQueue.h */, + 66CEFE2624DA20593CC818FF907F46F5 /* FIRAuthSerialTaskQueue.m */, + CAA738EABBD697265171DE3DAC8E0C17 /* FIRAuthSettings.h */, + 4666F2D0D35E201F414EBF12BB1B75AC /* FIRAuthSettings.m */, + 733CEDC657436DD895F6CF302461A85D /* FIRAuthStoredUserManager.h */, + 34D0DBBFFAC44D74581C242E052AFB80 /* FIRAuthStoredUserManager.m */, + 356FA68C30464A29EB11FD7CA7521327 /* FIRAuthTokenResult.h */, + 975D4CE22FA4C1DA6407E67828831C8E /* FIRAuthTokenResult.m */, + FDE9B09BD40DEABB8127F587A4BA535E /* FIRAuthTokenResult_Internal.h */, + BF274B2900480BCAE368E294B73E5B23 /* FIRAuthUIDelegate.h */, + 2919608BB643C33E664256CA53BB95EB /* FIRAuthURLPresenter.h */, + 5BED05889CD6C4477F7E451D6485915E /* FIRAuthURLPresenter.m */, + 96ED84605B32D89346896DDD098C7B7F /* FIRAuthUserDefaults.h */, + 3D27EA86C69966574F1E107D04DEE758 /* FIRAuthUserDefaults.m */, + DFF1E8F69B5E593941C2E469879CCF4A /* FIRAuthWebUtils.h */, + C97005B66F0BCD1C70222679991C6EF8 /* FIRAuthWebUtils.m */, + 9F876082355922D63035B970213AB0CD /* FIRAuthWebView.h */, + BF356E62ADDF306CEFC4B8245B5BCE68 /* FIRAuthWebView.m */, + 91067448F334D70084120D1E5EC0040C /* FIRAuthWebViewController.h */, + 6ABE347DB5D72B0A29CB81D058503E94 /* FIRAuthWebViewController.m */, + F85757FC6D0D70EA704FBC21028EDF46 /* FIRComponent.h */, + 5BE9A4788D908C70DB01791A60D2E8C8 /* FIRComponentContainer.h */, + 70408AF61F223F44EBED723B80F513A4 /* FIRComponentType.h */, + F0C900FADDD4BE441B1FED142B0B0690 /* FIRCreateAuthURIRequest.h */, + 00F472C98AE8DC1A4A60B2718E19B6EE /* FIRCreateAuthURIRequest.m */, + 932C2931560E557D677E5D825DF55FF4 /* FIRCreateAuthURIResponse.h */, + E9E24A592D6788921EFF7CD6B07DA3D0 /* FIRCreateAuthURIResponse.m */, + 6ECA1090408234F0432AD7A8719CDED2 /* FIRDeleteAccountRequest.h */, + B144E5E3A8596BD2FAAEAA56BDD6A884 /* FIRDeleteAccountRequest.m */, + B98A05D5A1CDC09C8D241FDD9E8942CA /* FIRDeleteAccountResponse.h */, + 35D13F140D3BA97AA0F59CD6D0185A2F /* FIRDeleteAccountResponse.m */, + 5C04EE56E5B835BB6F333DCBC55AC442 /* FIRDependency.h */, + B36227C53E719CE8182B4FB7ACEEC2DA /* FirebaseAuth.h */, + 03569094005DFF21986290B7A7CCCD84 /* FirebaseCoreInternal.h */, + BEA7AE33B74AF59CA502D5FDE7DCD982 /* FIREmailAuthProvider.h */, + 300EDAC88419BEDA22431274ECF54354 /* FIREmailAuthProvider.m */, + 78D1E4541AA37C05E37CD3271341EB53 /* FIREmailLinkSignInRequest.h */, + F0B54BCD2027EEA2560F04A5F660DF5F /* FIREmailLinkSignInRequest.m */, + 14313C746BD248B51B801D5D0EAB7816 /* FIREmailLinkSignInResponse.h */, + 5B8FA1F7710A719A4A55E7366464BC60 /* FIREmailLinkSignInResponse.m */, + FDF715A8163A7748E8D70591288E49C2 /* FIREmailPasswordAuthCredential.h */, + 344E6FEA72D17152155F2C9C6C56CA92 /* FIREmailPasswordAuthCredential.m */, + D881B7E53154441A4B1D49E8DB0FA3F4 /* FIRFacebookAuthCredential.h */, + 220EC7D8A2CB38340BCB87DDAF0166CD /* FIRFacebookAuthCredential.m */, + 2BFD21803769DB6C353B3E8AB9C3D04C /* FIRFacebookAuthProvider.h */, + E2DB273917BC7D135A0439291C9C008C /* FIRFacebookAuthProvider.m */, + 06CD6D8F5E3BF730BDA839220939A8AA /* FIRFederatedAuthProvider.h */, + 1BFC4F5515D28AA157359A2FE83628C6 /* FIRFinalizeMFAEnrollmentRequest.h */, + E291F2BE395DCAE350627CC2B42FE6E4 /* FIRFinalizeMFAEnrollmentRequest.m */, + 5C9BF815DA833EA927104176F6728631 /* FIRFinalizeMFAEnrollmentResponse.h */, + F9C09D85943C666EFF4A7E7FF556468E /* FIRFinalizeMFAEnrollmentResponse.m */, + 63618DD550DBA72C753D27AB482CF04E /* FIRFinalizeMFASignInRequest.h */, + FD1024348B7D7F91773F548CC6A4A4B5 /* FIRFinalizeMFASignInRequest.m */, + 67DA65C65A6DC928597F98BDE85879D6 /* FIRFinalizeMFASignInResponse.h */, + DDABA880B080FE3D88806F394D8ECB82 /* FIRFinalizeMFASignInResponse.m */, + 4166FCADAD4D4FD1E59EC390EF82F247 /* FIRGameCenterAuthCredential.h */, + 0F7F3AFAE2A24AD030BDE0A544F117C8 /* FIRGameCenterAuthCredential.m */, + F26D7F28656F20339771BBA1D7E42D4A /* FIRGameCenterAuthProvider.h */, + 7AD60D804ED86004AB6ADDF386296D8C /* FIRGameCenterAuthProvider.m */, + 360D283782E2F70E29346574623B578D /* FIRGetAccountInfoRequest.h */, + 447F7001F40D564009C8A48A4B7801EA /* FIRGetAccountInfoRequest.m */, + 0006371B66B70DA75BA4BAA405CE68B1 /* FIRGetAccountInfoResponse.h */, + 55828DC9C361221F1C6E3554B9703949 /* FIRGetAccountInfoResponse.m */, + 0A6F710CD6390E3FBAEBC393A95FDAE0 /* FIRGetOOBConfirmationCodeRequest.h */, + 3FD194CD3A55CB5AEBE27BCD94D10206 /* FIRGetOOBConfirmationCodeRequest.m */, + C221AE887079015A8381423D3733ED04 /* FIRGetOOBConfirmationCodeResponse.h */, + 186FA2D4398AA444253D80F690200E1D /* FIRGetOOBConfirmationCodeResponse.m */, + F40A7949398CF1B354A45647D63F250E /* FIRGetProjectConfigRequest.h */, + EF35764F03CD24E9BEFF38AB8C6873BF /* FIRGetProjectConfigRequest.m */, + 3023B4F5DDD02CFF5B395E7F490D33CC /* FIRGetProjectConfigResponse.h */, + DDE80AF0D4D25BFCEFB299B8C17CEE4C /* FIRGetProjectConfigResponse.m */, + FDF2EFAF7E3BB03DFF3DF33C3AE6D230 /* FIRGitHubAuthCredential.h */, + F1DC45D9BAAB0EF43B79461F9CE85306 /* FIRGitHubAuthCredential.m */, + 3F4580980FFA6C2CB244BCD3B8BFDE2E /* FIRGitHubAuthProvider.h */, + 74F7F76D9723E9827EF3AD57738BD660 /* FIRGitHubAuthProvider.m */, + 5F57F13EBD8F6268EA73B2E4176B7FB5 /* FIRGoogleAuthCredential.h */, + 8248C935EA50EC5DC7B87FF59C18BCC0 /* FIRGoogleAuthCredential.m */, + 9EED899C7A00C5E6FBC89D92F112061F /* FIRGoogleAuthProvider.h */, + E33AB87C9E1B8F7F515F0C6C418D8B2B /* FIRGoogleAuthProvider.m */, + CFDFCB3E3580BB6BEB1A3231B23289DD /* FIRHeartbeatLogger.h */, + 28BA89D03A923D6F3645E3792D7B6A85 /* FIRIdentityToolkitRequest.h */, + DAC5A28E00D22DC13534FA98A6FF1154 /* FIRIdentityToolkitRequest.m */, + A98F6CF369D6452E984735A431BE0790 /* FIRLibrary.h */, + 59B92BFC2E5FD6370D6AAD2B96F09C54 /* FIRLogger.h */, + B13E4C7F03E85F82326BD44C4F58BB36 /* FIRMultiFactor.h */, + 5185F33603CDA2B68194411E0A8EE5FC /* FIRMultiFactor.m */, + 23DC2294E824B6B4F959947D89FE4AC0 /* FIRMultiFactor+Internal.h */, + C586384ED84D2D56FFBE9589841A7C36 /* FIRMultiFactorAssertion.h */, + A4AE47A83D9419056CA5152B8060EB57 /* FIRMultiFactorAssertion.m */, + 2B33ABC19D62233834F6D06F4927B557 /* FIRMultiFactorAssertion+Internal.h */, + 0FB9ED5CC42FCE28A63013D90A0CE0E3 /* FIRMultiFactorConstants.m */, + BD0338B357A3CDE8F82D07CC33E9666E /* FIRMultiFactorInfo.h */, + EA1F9E6CD6CEF164872E5EA441957F62 /* FIRMultiFactorInfo.m */, + 043C226E59B26E794E9191331A864A5A /* FIRMultiFactorInfo+Internal.h */, + AC261D7B91CBC6A2616EEE91114F83A5 /* FIRMultiFactorResolver.h */, + 7AAC8D7921DC3CFE9D2E4976DAE3040F /* FIRMultiFactorResolver.m */, + 88576C105CD8237BE0FC4B763FDF77AF /* FIRMultiFactorResolver+Internal.h */, + B6AC0D7DAB5655B6C98E8132C5F02847 /* FIRMultiFactorSession.h */, + A3DBB2AB553DB346C5F9A455867C76A4 /* FIRMultiFactorSession.m */, + D24EAB3656B66CFA3FC4EC757C29A2B0 /* FIRMultiFactorSession+Internal.h */, + 94E05EC88F26D558B547C8E5D72E7792 /* FIROAuthCredential.h */, + 6F17E4595E3BDA403E8C7DBF3F47B918 /* FIROAuthCredential.m */, + 4EA5A35B9693996DBF681BB5E4ED3AB9 /* FIROAuthCredential_Internal.h */, + AFF21A3F40FF482B7644277954FE53A4 /* FIROAuthProvider.h */, + DC183DB0DD726787211F6CDF27F004B0 /* FIROAuthProvider.m */, + 782D131BB42C5CBFD43A47DDC8824422 /* FIROptionsInternal.h */, + 12229C986A2EE4B61CDA11875E871A84 /* FIRPhoneAuthCredential.h */, + 2EBF4EF9C2EBB9F4610CF7F1990756D8 /* FIRPhoneAuthCredential.m */, + 9FEB68EC6BAB21247A9560C3A523173B /* FIRPhoneAuthCredential_Internal.h */, + F6709A26A6D2B2D009B7AD09AB964714 /* FIRPhoneAuthProvider.h */, + 6D3BA8069DBAAD52F0BBD67EF7D95738 /* FIRPhoneAuthProvider.m */, + 8256334A1BB6D43D6A505A6A754FB9AD /* FIRPhoneMultiFactorAssertion.h */, + 73247FFFFE3299EA4FF88B4C958FCFB2 /* FIRPhoneMultiFactorAssertion.m */, + 4480D3ADCD279112EAF94738881E3C65 /* FIRPhoneMultiFactorAssertion+Internal.h */, + 3B54381D354957163C76271AA6E11ADA /* FIRPhoneMultiFactorGenerator.h */, + 9533FA4F9B48BB2174C0ED30C78DFE7E /* FIRPhoneMultiFactorGenerator.m */, + 7FFE5FB751622716C89387E428A18B33 /* FIRPhoneMultiFactorInfo.h */, + 0DDE43AA7EDF5492F8787EF6723CE7D5 /* FIRPhoneMultiFactorInfo.m */, + 33996B996CB2DA56D97D8237737419AC /* FIRPhoneMultiFactorInfo+Internal.h */, + F8D485A35F3C8EC5C1FB4CF802609E6C /* FIRResetPasswordRequest.h */, + 6A5B34AC3E337EC7014EA2086077DAB9 /* FIRResetPasswordRequest.m */, + 9254CCCC55DF6E10A7F6C8019FD5F8B8 /* FIRResetPasswordResponse.h */, + 6677881A1A790A577070807981ECC661 /* FIRResetPasswordResponse.m */, + 3244ADC01679A6C46E66783E3006820A /* FIRRevokeTokenRequest.h */, + 360BEAE8353C4A0D3D79A704073FB4D5 /* FIRRevokeTokenRequest.m */, + 93C71DF12581A34115171295278A2235 /* FIRRevokeTokenResponse.h */, + 6109B27325309C7DB2F34C877E65CE8E /* FIRRevokeTokenResponse.m */, + CFB6CCB1B4AF1019876E53953A7D37A8 /* FIRSecureTokenRequest.h */, + 98AA57D4F61DF5CEE54B53D96945100D /* FIRSecureTokenRequest.m */, + E22845731258908F89CCAFAF4476E8E0 /* FIRSecureTokenResponse.h */, + 4FF91AFC3D4E8D5DDE6F76B436ADF093 /* FIRSecureTokenResponse.m */, + 6B613C7C1583C7F1F9A167E85A01750A /* FIRSecureTokenService.h */, + 312C7C07B79F4877B8F6286D00F9C8E8 /* FIRSecureTokenService.m */, + A5FF33CC502EBCFB234B8B0CAB937207 /* FIRSendVerificationCodeRequest.h */, + A21BE0CCC6934357A32AC861FDF64150 /* FIRSendVerificationCodeRequest.m */, + 4C38BC7996475558BC1B0527BC88087F /* FIRSendVerificationCodeResponse.h */, + D4B2D1F9402DEE3A5695B326EE5FFD8F /* FIRSendVerificationCodeResponse.m */, + F81A1054298CE5C004C4FE464C5DCE2C /* FIRSetAccountInfoRequest.h */, + BAA2696F7FBBB1CBD28CC9EE73BA0480 /* FIRSetAccountInfoRequest.m */, + 3239ADF167FDB5AF1EC2F83F1F8DADD3 /* FIRSetAccountInfoResponse.h */, + A9C5CAC11B532C8059B2E2040D5A2AE7 /* FIRSetAccountInfoResponse.m */, + FE280A7F867E6C75B2562C0E436F53A3 /* FIRSignInWithGameCenterRequest.h */, + 81252E5CD0EB33B7028F00FADE62A39B /* FIRSignInWithGameCenterRequest.m */, + E786BAEFF21D797C4F8294C087E59257 /* FIRSignInWithGameCenterResponse.h */, + 35E3F5B427B2657E3077368D97033BB2 /* FIRSignInWithGameCenterResponse.m */, + A2F7F8DB85024F49526953B427B6486B /* FIRSignUpNewUserRequest.h */, + 6EE3C9DA366E6B7ABA2CD3B139B2BFFC /* FIRSignUpNewUserRequest.m */, + FF4A31EB3E4294B2F18DC6243AD3116D /* FIRSignUpNewUserResponse.h */, + B87AF41DF8B5A0C0F400BC9F24C530D1 /* FIRSignUpNewUserResponse.m */, + 92B72A17E56EBF7CEDC7FBB84BF7A1C7 /* FIRStartMFAEnrollmentRequest.h */, + 520F17A85613DE207C7D040EBDD6F8BD /* FIRStartMFAEnrollmentRequest.m */, + CC576E1F438D451BD01C77F7B27C65A8 /* FIRStartMFAEnrollmentResponse.h */, + 57E608271810C0DF3502349FA7E1F9AD /* FIRStartMFAEnrollmentResponse.m */, + 32D3125925FAEC4F82BA1ED3FEDDF2EA /* FIRStartMFASignInRequest.h */, + C4326A02499E82B8CB0C1B52ED00762C /* FIRStartMFASignInRequest.m */, + DA41FE18FB4EA2B72D7B4F8366676BC1 /* FIRStartMFASignInResponse.h */, + 16ADD2871F8ACA2789A95C96B1F4FE19 /* FIRStartMFASignInResponse.m */, + 4785776E6B04F0C704ED408714796CCC /* FIRTwitterAuthCredential.h */, + DDD2DB49347560B7FD71926843CC00F6 /* FIRTwitterAuthCredential.m */, + 8B828DF519503B35B1B1C7893D5F6C1E /* FIRTwitterAuthProvider.h */, + 33057FA5EBAC487EC38B2C709F9F5DA6 /* FIRTwitterAuthProvider.m */, + 0871B1AF60D0FA795C25D0BBC7A6B793 /* FIRUser.h */, + 9081630104DE8D7CFD31DF7D5426FDF3 /* FIRUser.m */, + 251A0FACCAB61BF90F11AAC339D36587 /* FIRUser_Internal.h */, + E07ED6727EC0704096E3C366CDD15BF8 /* FIRUserInfo.h */, + C7A7A909033C8FDAD8F306BF09436C37 /* FIRUserInfoImpl.h */, + 6081ADA3495E375084C4844160B739B3 /* FIRUserInfoImpl.m */, + 78A0CF3F16BA622C5E0A626D56DFAE8A /* FIRUserMetadata.h */, + B5779CA3FF1DD9E71297A3043E11DC63 /* FIRUserMetadata.m */, + DA158D7DA802B44F18C94FBD0C6A7A7C /* FIRUserMetadata_Internal.h */, + 97D9C8B87E834414170ABFDA7040DB3C /* FIRVerifyAssertionRequest.h */, + 408F5AC132654E114CB2C4642531A12A /* FIRVerifyAssertionRequest.m */, + EF93B3CD6E2C57E0A8E985819171A8AD /* FIRVerifyAssertionResponse.h */, + 143EB88CB6BF32B3B92E745AED2B8D1F /* FIRVerifyAssertionResponse.m */, + 1A93BF76000E48D0F95A516E92CF28E8 /* FIRVerifyClientRequest.h */, + 8E959605E1F403D7C14260C76E2C0B48 /* FIRVerifyClientRequest.m */, + 36C43AC2291B2B1D31742EF42B3BFB6D /* FIRVerifyClientResponse.h */, + C6545A3F8EC8ED4010C4BE7D98E69E88 /* FIRVerifyClientResponse.m */, + 3ACA02065590E1AFEA516EA287B96AE9 /* FIRVerifyCustomTokenRequest.h */, + 4BFFCDC8875646C24A0AA7F7C16EAADF /* FIRVerifyCustomTokenRequest.m */, + DF8D96275E2E2AAC3FD340661C455E7E /* FIRVerifyCustomTokenResponse.h */, + B30E8A2EFD646DD32FBF567E54E8FE3A /* FIRVerifyCustomTokenResponse.m */, + F5468F77E33BB89CB6344365C97B2821 /* FIRVerifyPasswordRequest.h */, + F16A7F5529145AB1A4B7E519508ACF72 /* FIRVerifyPasswordRequest.m */, + C2CC7D967ED5502EA688B2B429A6B2E0 /* FIRVerifyPasswordResponse.h */, + 4E4C5C96B5A1265FA9FC149C8C91EC87 /* FIRVerifyPasswordResponse.m */, + 86A9DD91DF789DEE2B780190291B4392 /* FIRVerifyPhoneNumberRequest.h */, + F784FF6511E920AAF983C6D82547E28D /* FIRVerifyPhoneNumberRequest.m */, + 2D47FAEFD73B473DF35243384BFA1770 /* FIRVerifyPhoneNumberResponse.h */, + 8D28A3D7BBFED5216A2FCF2D4855B3BE /* FIRVerifyPhoneNumberResponse.m */, + A800F833AC5404F3FA4FC8CC82716281 /* FIRWithdrawMFARequest.h */, + ED26D901D7A953FFDFA298223B2EA02C /* FIRWithdrawMFARequest.m */, + 67EA9922C35F5F0019B266058D44FF98 /* FIRWithdrawMFAResponse.h */, + 1291C14B3AB631F2898B2F8286A070FE /* FIRWithdrawMFAResponse.m */, + 60EE7485A5498FE07A5EBB875A28A6FC /* NSData+FIRBase64.h */, + B3FD9E5801F2AD2BD362344F93669102 /* NSData+FIRBase64.m */, + 29AB22D147708C3ACCB485A392DEED69 /* Support Files */, + ); + path = FirebaseAuth; + sourceTree = ""; + }; + 73F675BA1E52EC7E2B236742C009D491 /* Pods-PRTYTests */ = { + isa = PBXGroup; + children = ( + 04B8B77B56D977247170C592E6DE11B9 /* Pods-PRTYTests.modulemap */, + C7DC07E2418DC49BC8D66013DDA60E0B /* Pods-PRTYTests-acknowledgements.markdown */, + 3F2603FE06201768EBAC5948FD708988 /* Pods-PRTYTests-acknowledgements.plist */, + 0009925C746201D1B1E5D9602FFC6DCA /* Pods-PRTYTests-dummy.m */, + 92455D44ABE6751BD0F9BD80C8C7B7E7 /* Pods-PRTYTests-Info.plist */, + 5316165368ABB6512CB6E082B4E2B9C3 /* Pods-PRTYTests-umbrella.h */, + ABC7F498E2FC7E903D6F8640E17F788A /* Pods-PRTYTests.debug.xcconfig */, + D68BEA0EF9DCC01F9EF03619F5C0AE46 /* Pods-PRTYTests.release.xcconfig */, + ); + name = "Pods-PRTYTests"; + path = "Target Support Files/Pods-PRTYTests"; + sourceTree = ""; + }; + 7D919CF14BDB8E4172DCEC37AFCFC76F /* Headers */ = { + isa = PBXGroup; + children = ( + 40538536D8C20ED7DA137A5713BB459A /* NSError+RLMSync.h */, + 0306EEC425C1FFBD36CA65D3932A6ADC /* Realm.h */, + 7265EFBF2A684FDD8000FFA1529176CE /* RLMAPIKeyAuth.h */, + B553FE0894FC0F9CFAA1014CF6D4F9DC /* RLMApp.h */, + AF4C27BB7CD817442F90B3068C676B6B /* RLMArray.h */, + 23A3F80698CEECE919C9E022F40AFC28 /* RLMAsymmetricObject.h */, + 260BA989E65D1B70F99F3F9464CD1115 /* RLMAsyncTask.h */, + FCFFDCA51CE25755A9B7C297EF1226FF /* RLMBSON.h */, + C01A8C68201D99996D349D3CE0CAC1EA /* RLMCollection.h */, + 83712E3E12FF5DD9E4CC45C82549DD15 /* RLMConstants.h */, + 99A3796A766AC39C09D1D998A183ED46 /* RLMCredentials.h */, + C8CAF3FC639EB612E0500A5FAA2028C6 /* RLMDecimal128.h */, + 448F758E8949F357C24A8E3D4F0EE6E2 /* RLMDictionary.h */, + B1EE524838C98D6E19AF4CF8DB02D099 /* RLMEmailPasswordAuth.h */, + 6D00B53942427419D9F1A394FBEE64F3 /* RLMEmbeddedObject.h */, + C6B2640364AB64A02A4091061D24152C /* RLMError.h */, + 4831343EA0DCD89549053AB1F3C335F9 /* RLMFindOneAndModifyOptions.h */, + BD9D20F856B549632C5B821F2B74BCFC /* RLMFindOptions.h */, + 8863D1E8CCA754A7C72D9B4890E10EDD /* RLMLogger.h */, + AFBE43B2C0C2AF9EBCECCCEBBC8D162B /* RLMMigration.h */, + 0C642008350A5CF8DEB52E2325A396F1 /* RLMMongoClient.h */, + 684B24EBB223FA5F33D00EACC3360AFB /* RLMMongoCollection.h */, + CF97E0F164DFA9E0C2AA0BA05C846A5A /* RLMMongoDatabase.h */, + A57BCC415D3BC94E35EB525E03037615 /* RLMNetworkTransport.h */, + 780F15D6939A98ACA8F237480C9FDF2E /* RLMObject.h */, + C69F72C06B9F4D036CD7680BFD656FDB /* RLMObjectBase.h */, + 3CF270CB5CBFFE011E21EF25448B9646 /* RLMObjectBase_Dynamic.h */, + E3B5F7670B5C0CA94B6720CC51510838 /* RLMObjectId.h */, + 55971155657172B3C8EE36661224A4CF /* RLMObjectSchema.h */, + F44000EA207E28FDA17F50C681374B50 /* RLMPlatform.h */, + 94CA7DCE38C9B491A31260A067D071EA /* RLMProperty.h */, + A9D715562896C77226A34E182B52AE9E /* RLMProviderClient.h */, + CC35B50226DE5DE0D691E21CE1CAED70 /* RLMPushClient.h */, + F0BFC6AD06F7FAA34D3238F20D1BDDD3 /* RLMRealm.h */, + 0C0CD8603C88F495D0C59CF44AB151EA /* RLMRealm+Sync.h */, + 7B05F3BE2B4BA2F8C84E85EC55902EE0 /* RLMRealm_Dynamic.h */, + 4C4A0D72C0FDAD19E451C2E21BA93B3A /* RLMRealmConfiguration.h */, + D499691A37C194CFC8292C3B66E69060 /* RLMResults.h */, + D6B797734979214911F26CE6964D223D /* RLMSchema.h */, + 9011CDAF888185959FCBA517AA3CCD8D /* RLMSectionedResults.h */, + 4CBCF5236A1C6D972EB1E9825C24568D /* RLMSet.h */, + DAC208FD41CE38A2E2E5ABCDABD3D70E /* RLMSwiftCollectionBase.h */, + F6150C0680A6EE061716FDD32CE733D5 /* RLMSwiftObject.h */, + DF49FADD2F521BE21950120B832A1914 /* RLMSwiftValueStorage.h */, + FAEFF93C94DDA61320F23FD69CC400B2 /* RLMSyncConfiguration.h */, + 2B5BF8D2317897E5636B6D098AAA376C /* RLMSyncManager.h */, + 454A4F6087FFA109E2BAAD2E3244848F /* RLMSyncSession.h */, + DA74B0436802FE2BDE61D436290670BD /* RLMSyncSubscription.h */, + 726B5EDE338F3B54A4CF771D23EA5618 /* RLMThreadSafeReference.h */, + CE2E12DEE7E27510B2C96E2C68424DA6 /* RLMUpdateResult.h */, + 3B2DC0C4DFDB5B772B4F9B1EB97645E7 /* RLMUser.h */, + 34DE85D047CC7AE8971A383A422D922B /* RLMUserAPIKey.h */, + 135176A848ECF939C0716D13BD47BFDB /* RLMValue.h */, + ); + name = Headers; + sourceTree = ""; + }; + 80038AB9E36E52B3BC5184DBE587152F /* Support Files */ = { + isa = PBXGroup; + children = ( + B91A58F056260B927AC64B4781263521 /* FirebaseAppCheckInterop.modulemap */, + 3A18DE4B7A84F362E93E76BCAB3882E7 /* FirebaseAppCheckInterop-dummy.m */, + FFA993537352A29E3A3014F2098704D6 /* FirebaseAppCheckInterop-Info.plist */, + E7A629C03445554FC69F62FEB8A6D552 /* FirebaseAppCheckInterop-prefix.pch */, + A8F9DB69F1C068D0A79E78FF631D2D07 /* FirebaseAppCheckInterop-umbrella.h */, + EA57FFE363F883005877B7B2BEB8F282 /* FirebaseAppCheckInterop.debug.xcconfig */, + 0A0CF7B9BAF15535F28A3BC045F60A22 /* FirebaseAppCheckInterop.release.xcconfig */, + ); + name = "Support Files"; + path = "../Target Support Files/FirebaseAppCheckInterop"; + sourceTree = ""; + }; + 843C74ACF66DDA6D7A4F889F091C3944 /* Frameworks */ = { + isa = PBXGroup; + children = ( + D29E1D68F3B5C6DA0A7A06B72CECF993 /* FirebaseAnalytics.xcframework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 898308531697D66C48B288BE71401EA7 /* GoogleAppMeasurement */ = { + isa = PBXGroup; + children = ( + 12CEE16D507D3813A7564E3C577D51BB /* AdIdSupport */, + 45AFDC20EF1F48BAD68B5C6562915F28 /* Support Files */, + 052EE226D9D27D977634A9435C617BCE /* WithoutAdIdSupport */, + ); + path = GoogleAppMeasurement; + sourceTree = ""; + }; + 8A9C7D1D8625C2A874F22BA6059BAE01 /* Products */ = { + isa = PBXGroup; + children = ( + 81418C93A311F0492F62A8F88C3BD66B /* FirebaseAppCheckInterop.framework */, + 43B1E4CD7B30B9FD278100133C2AC788 /* FirebaseAuth */, + E2B63D462DB7F827C4B11FD51E4F8E2D /* FirebaseCore.framework */, + 148D0F9E8C7373FEAF40D800FC5F1BAA /* FirebaseCoreInternal */, + 51671C73F008B5C0C3751B3855999213 /* FirebaseDatabase */, + 13C8C8B254851998F9289F71229B28A2 /* FirebaseInstallations */, + B43874C6CBB50E7134FBEC24BABFE14F /* GoogleUtilities */, + C1998E0D8085221AD87F89B614C10E52 /* GTMSessionFetcher */, + 0A9F46A999C47653013D3AD854352507 /* leveldb-library */, + 06FC5C9CF96D60C50FCD47D339C91951 /* nanopb */, + 578E1B6E76DDE67CFCDF713FC4016967 /* Pods-PRTY */, + C0691B5031307C17D3FEEF999A793420 /* Pods-PRTY-PRTYUITests */, + 0843F6B3C59457C07E690F4E361631E0 /* Pods-PRTYTests */, + 3347A1AB6546F0A3977529B8F199DC41 /* PromisesObjC */, + 921BE4A82C4A7A5C72A0C6F8B8FEF200 /* Realm */, + 437919EE08EC6BFCCBAC3BD346309742 /* RealmSwift */, + ); + name = Products; + sourceTree = ""; + }; + 8FEE1D22FC6AC8E42721ED12ADD1A20E /* MethodSwizzler */ = { + isa = PBXGroup; + children = ( + 1678ACD8E0AF993C082BA2E26E5C9293 /* GULOriginalIMPConvenienceMacros.h */, + C3FBA578EB9F1A354876E51D1ECFC603 /* GULSwizzler.h */, + A7E4C9186535EBC191900B137507E328 /* GULSwizzler.m */, + ); + name = MethodSwizzler; + sourceTree = ""; + }; + 960C2A914F777684B021D46FDA58960C /* iOS */ = { + isa = PBXGroup; + children = ( + 39B4FEB4B3B91D6CDE38132BAB3BEE14 /* CFNetwork.framework */, + DB96318E2CB72DE3CDFEEF1B9E8644AD /* Foundation.framework */, + 9B7D6683BB4B8820F7AFBD61BFB7F6B3 /* SafariServices.framework */, + 4972477850A41A9D9B673C96DEF4168A /* Security.framework */, + CEAE96632CC2337ED6A14302B3022EC8 /* SystemConfiguration.framework */, + 1799EDD01F3BDE8A78F8501A99E86879 /* UIKit.framework */, + ); + name = iOS; + sourceTree = ""; + }; + 964225B8EC54D9295A2704B30F734CCE /* Logger */ = { + isa = PBXGroup; + children = ( + DE6EC9F385F7E055E70A09F1EAFA7E4A /* GULLogger.h */, + 02D7467DDB121A7DEEE46877041066D7 /* GULLogger.m */, + 6829850E183C8570735638BD3F540C47 /* GULLoggerLevel.h */, + ); + name = Logger; + sourceTree = ""; + }; + 9888D43F7F0FF7C0E4009F2EF36636E1 /* Support Files */ = { + isa = PBXGroup; + children = ( + 424182B01E8972FF03D5A9E050282B58 /* FirebaseCoreInternal.modulemap */, + 7A268D34F1B85A759DE13BDCDF787C6B /* FirebaseCoreInternal-dummy.m */, + 301DBE1318BC044C84AA208FD606A887 /* FirebaseCoreInternal-Info.plist */, + 9331F4974B99FBE49998E4D3D7182A8C /* FirebaseCoreInternal-prefix.pch */, + 52E34EC8AAB1C8662FC59D8A62F2E08E /* FirebaseCoreInternal-umbrella.h */, + 625421974DC8B2D9D04332AD61B57DA3 /* FirebaseCoreInternal.debug.xcconfig */, + 400F42C6868B6D5EB4B6C01B3A312F5E /* FirebaseCoreInternal.release.xcconfig */, + ); + name = "Support Files"; + path = "../Target Support Files/FirebaseCoreInternal"; + sourceTree = ""; + }; + 9A763C0929C561F413AEAAD170F09606 /* FirebaseCoreInternal */ = { + isa = PBXGroup; + children = ( + DD1D686105A5C3AABBDDDB266B062F1C /* _ObjC_HeartbeatController.swift */, + EEEFE024B53EE0D176146FCC6098D527 /* _ObjC_HeartbeatsPayload.swift */, + 2E953C57A2C1A68306C9ADAEC68C1C99 /* Heartbeat.swift */, + E9D20F783BE6512E0DE13B7C0C5670BE /* HeartbeatController.swift */, + A6EE078C25A16F573B5605E4E7F0BC2E /* HeartbeatLoggingTestUtils.swift */, + 9C574899E21FF7BC5D52C1B2C2A1FB71 /* HeartbeatsBundle.swift */, + 1E32862F9DADC43AADD541E3708029A8 /* HeartbeatsPayload.swift */, + 4F08C4B9A5E6AFBA8D2DDDA90493AB07 /* HeartbeatStorage.swift */, + 6C892732CFC7F04EDE36414A35202F2F /* RingBuffer.swift */, + 786F9BDCFBF6DF893D9F253B20AB4509 /* Storage.swift */, + DC9C364C4160499BF30C6614BB9168B2 /* StorageFactory.swift */, + 93D1FC7C12423DA20AA334BD7AE69448 /* WeakContainer.swift */, + 9888D43F7F0FF7C0E4009F2EF36636E1 /* Support Files */, + ); + path = FirebaseCoreInternal; + sourceTree = ""; + }; + 9E7711FC0336CE42638F168302830CDA /* decode */ = { + isa = PBXGroup; + children = ( + ); + name = decode; + sourceTree = ""; + }; + A30CD403F6906B8D861A2CBA7ABBE94B /* Support Files */ = { + isa = PBXGroup; + children = ( + E3D7107849E93A425AEA955A36B090EA /* Firebase.debug.xcconfig */, + CD98D5EB6316186187D122179DDBB9DF /* Firebase.release.xcconfig */, + ); + name = "Support Files"; + path = "../Target Support Files/Firebase"; + sourceTree = ""; + }; + A642180AC9832AE21002859F56594700 /* nanopb */ = { + isa = PBXGroup; + children = ( + 3C428F6C9EE7CA9AAF79DA85A514B14A /* pb.h */, + EA10A779E36C2B20E2D2B85D189969F4 /* pb_common.c */, + E85CC75C83CC5C34C66FEA0792C24588 /* pb_common.h */, + F5D281652BF9F2FE685ADC168FB4217F /* pb_decode.c */, + 7AA4F6AE64EE4FC2D1783D3CDE850753 /* pb_decode.h */, + F0C021C6E1701A5C89767E23F96F8FB7 /* pb_encode.c */, + FA03DCA390E3B26A7DCD911883F15289 /* pb_encode.h */, + 9E7711FC0336CE42638F168302830CDA /* decode */, + 0CCAF5CDED2A83DCF55FD076ED546151 /* encode */, + B699070A9629E5868C65BDF9E80BC08A /* Support Files */, + ); + path = nanopb; + sourceTree = ""; + }; + AA4136EA543A6A861FE56D011DCB4607 /* GTMSessionFetcher */ = { + isa = PBXGroup; + children = ( + 46B2E894C11AE6C8239389477D4C8E26 /* Core */, + CEA85E9DE51C10D5FFE21168BDAE5B2B /* Support Files */, + ); + path = GTMSessionFetcher; + sourceTree = ""; + }; + B699070A9629E5868C65BDF9E80BC08A /* Support Files */ = { + isa = PBXGroup; + children = ( + 2F32604D42064F5693F0C5DD948F6D8D /* nanopb.modulemap */, + 857C5EEC6F7D3F8980BABFC0863E92C8 /* nanopb-dummy.m */, + E466DD483C14B59C82558E3B5D4523E8 /* nanopb-Info.plist */, + 804256AD4BE732EE9C70262DA3963093 /* nanopb-prefix.pch */, + D5890EEE293438821271DA021C01DB15 /* nanopb-umbrella.h */, + 9B9A8FE44DFC70CD9D29C885FF6CB87F /* nanopb.debug.xcconfig */, + 71EB5FB4222FE68A6E09A16CC088A3EA /* nanopb.release.xcconfig */, + ); + name = "Support Files"; + path = "../Target Support Files/nanopb"; + sourceTree = ""; + }; + C03AD6E620BBFB12C88524B3D6588E74 /* FirebaseAppCheckInterop */ = { + isa = PBXGroup; + children = ( + 3D1D1CE6B410E1BCE80346A09E546722 /* dummy.m */, + A02ACC5171F5816C4717036ECB8B255C /* FIRAppCheckInterop.h */, + 303B6E98FABDA657EC15858154A04C4F /* FIRAppCheckTokenResultInterop.h */, + 80038AB9E36E52B3BC5184DBE587152F /* Support Files */, + ); + path = FirebaseAppCheckInterop; + sourceTree = ""; + }; + C5319AE75DA602B72102FD6AA40B2423 /* NSData+zlib */ = { + isa = PBXGroup; + children = ( + C8B8699512E125DAF372EB2BA3CFB387 /* GULNSData+zlib.h */, + FA41946ADC0A1E4F1F07A106A35D5C1A /* GULNSData+zlib.m */, + ); + name = "NSData+zlib"; + sourceTree = ""; + }; + C86379A88CB76835453F6C389B7A46A1 /* FirebaseCore */ = { + isa = PBXGroup; + children = ( + 7852B5DBDABD1585A09D661182ED0B4F /* FIRAnalyticsConfiguration.h */, + FA4FC112C43350FA23C041B4F4331E68 /* FIRAnalyticsConfiguration.m */, + BD7537EC51FC4F1A9702E002BC025FDE /* FIRApp.h */, + 2F92B76E1A6A4787FF52794D225AEB7B /* FIRApp.m */, + 8353124354524C02C36488028B2F4D02 /* FIRAppInternal.h */, + C443F6191AE6D9CA89D2B2D541E2329E /* FIRBundleUtil.h */, + B96EBCC46DCBEDE26365D7AC85351CC5 /* FIRBundleUtil.m */, + 6DFB4AE7F11314CE5775A0522693D21C /* FIRComponent.h */, + 24B4007499458D350361A99EE865BC30 /* FIRComponent.m */, + 8466D70DC12DC21169B9A39EB1BBAF8B /* FIRComponentContainer.h */, + B16EB04DE78E887824E1C8DBFC66B5F5 /* FIRComponentContainer.m */, + D3CBF39EB565F7C6E0D1BA08F7C7AC50 /* FIRComponentContainerInternal.h */, + 434FF72C1B06DAFDF7A6F2F790AACEBC /* FIRComponentType.h */, + 35EBFFB02004349994925EC963A01894 /* FIRComponentType.m */, + 2B05E83977D207F6BE795A000530F88B /* FIRConfiguration.h */, + 43100CB1F7F8A6943C13D8F0BFD868C0 /* FIRConfiguration.m */, + 67361D46F9488FA1DC95BE85E46CE3ED /* FIRConfigurationInternal.h */, + D455DC7451DB6AE120BB8BB269C4F3D9 /* FIRDependency.h */, + 61E8141817AC68D5CC9DCF402DC7F433 /* FIRDependency.m */, + F7ADFB69059F59EB2245F0730BC4BC72 /* FirebaseCore.h */, + 4DAAF670A3A48BEC4510C5D248BC666C /* FirebaseCoreInternal.h */, + D55A3C15FC867492DF0F4DCD8284D6A3 /* FIRFirebaseUserAgent.h */, + 1171CF5F6FD906DFE4F386B29FA61D56 /* FIRFirebaseUserAgent.m */, + 8E47E99A63C56A34F47752275944340C /* FIRHeartbeatLogger.h */, + CBF3DACAC92F02382C074F36C5FF59C1 /* FIRHeartbeatLogger.m */, + 5218979E6A5F407F3CEDFE2821715668 /* FIRLibrary.h */, + DF47599DCB441F39488B62462C49AB81 /* FIRLogger.h */, + BE904D1FED7D94CEE1F8C3A0FCC83148 /* FIRLogger.m */, + EB78CE135800E8CDACBD0AE334B55148 /* FIRLoggerLevel.h */, + C71C4ABD7D0982DB872418B5A8E88A5E /* FIROptions.h */, + B664529372060D95B49A4C4F210AFB3B /* FIROptions.m */, + B438E42DDF19AE28B09823D0CCEC5714 /* FIROptionsInternal.h */, + E2A825F628843CCD72BD31D2F167A274 /* FIRVersion.h */, + EC208AAD8607F9C59421288F9B50F57D /* FIRVersion.m */, + 3D5C9298C50349A99A2F00E8BFF9126B /* Support Files */, + ); + path = FirebaseCore; + sourceTree = ""; + }; + CEA85E9DE51C10D5FFE21168BDAE5B2B /* Support Files */ = { + isa = PBXGroup; + children = ( + 36DA0CC9E409501529A53ABC8F6AA4C9 /* GTMSessionFetcher.modulemap */, + 27A49FDF138880BD7F33CD5008A47C15 /* GTMSessionFetcher-dummy.m */, + 00AF0142CDFB574A26958CAF911B5C05 /* GTMSessionFetcher-Info.plist */, + 89B93A8ED3FC12F718397CD71C98EE02 /* GTMSessionFetcher-umbrella.h */, + E0F2C073ECA9F2634031E8A827AEE3AB /* GTMSessionFetcher.debug.xcconfig */, + 97F795562E65992BA4EA307E98284AC4 /* GTMSessionFetcher.release.xcconfig */, + ); + name = "Support Files"; + path = "../Target Support Files/GTMSessionFetcher"; + sourceTree = ""; + }; + CF1408CF629C7361332E53B88F7BD30C = { + isa = PBXGroup; + children = ( + 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */, + D68CA58901FBF589D75F5E40F1EAF5BA /* Frameworks */, + E6E14D68138F7FBAEC95F07F0F92C3B4 /* Pods */, + 8A9C7D1D8625C2A874F22BA6059BAE01 /* Products */, + 714178634F1BAE8778B5800B5A2DC780 /* Targets Support Files */, + ); + sourceTree = ""; + }; + D351EC19A8D7A59B8055384335EF63C2 /* FirebaseAnalytics */ = { + isa = PBXGroup; + children = ( + 2D7C8DF6DFFDAE046A414DCDE9EA3554 /* AdIdSupport */, + 084BA068F69F459D01FDC03CE5102E87 /* Support Files */, + ); + path = FirebaseAnalytics; + sourceTree = ""; + }; + D537D2CE3F982AD935279D077683BFA9 /* GoogleUtilities */ = { + isa = PBXGroup; + children = ( + 33FCC40DECDFCDC84EF0FE7EA7241AF2 /* AppDelegateSwizzler */, + 04348C11DD533068D8A531767D3D0A75 /* Environment */, + 964225B8EC54D9295A2704B30F734CCE /* Logger */, + 8FEE1D22FC6AC8E42721ED12ADD1A20E /* MethodSwizzler */, + 09FC4539103C987BD4A358D70F4300F9 /* Network */, + C5319AE75DA602B72102FD6AA40B2423 /* NSData+zlib */, + 63FF9ADB42142C23E72E13467246EDAC /* Reachability */, + E33FA0A8FB12C9B9AA491EFA9061A85B /* Support Files */, + 484FB6A4E4D0DE54B8BF0BC2A89436A2 /* UserDefaults */, + ); + path = GoogleUtilities; + sourceTree = ""; + }; + D68CA58901FBF589D75F5E40F1EAF5BA /* Frameworks */ = { + isa = PBXGroup; + children = ( + 960C2A914F777684B021D46FDA58960C /* iOS */, + ); + name = Frameworks; + sourceTree = ""; + }; + DDFBD7539E664B8B6B16BDB8243C13CC /* Frameworks */ = { + isa = PBXGroup; + children = ( + 229308366B6A55E8735EA3EB6903A228 /* realm-monorepo.xcframework */, + ); + name = Frameworks; + sourceTree = ""; + }; + E33FA0A8FB12C9B9AA491EFA9061A85B /* Support Files */ = { + isa = PBXGroup; + children = ( + D8A3B55C80E0CC5BC5DAE72FC0F17288 /* GoogleUtilities.modulemap */, + 1B5CA39A2CE71ED31A7A51A7DEE202E3 /* GoogleUtilities-dummy.m */, + D4C8940B52AD1E94D001B3AC49E7DF7A /* GoogleUtilities-Info.plist */, + 75524D426CC700CE7B7C9E5C62779F88 /* GoogleUtilities-umbrella.h */, + 64CA733606AC8F6B69927A354B416C4D /* GoogleUtilities.debug.xcconfig */, + EF82691CD03AEDF56103F9C350618682 /* GoogleUtilities.release.xcconfig */, + ); + name = "Support Files"; + path = "../Target Support Files/GoogleUtilities"; + sourceTree = ""; + }; + E6E14D68138F7FBAEC95F07F0F92C3B4 /* Pods */ = { + isa = PBXGroup; + children = ( + 47EF9E00A9BAD2E33DEE38002999E401 /* Firebase */, + D351EC19A8D7A59B8055384335EF63C2 /* FirebaseAnalytics */, + C03AD6E620BBFB12C88524B3D6588E74 /* FirebaseAppCheckInterop */, + 73C78B7F6E344DBDE0A61BB033C2667C /* FirebaseAuth */, + C86379A88CB76835453F6C389B7A46A1 /* FirebaseCore */, + 9A763C0929C561F413AEAAD170F09606 /* FirebaseCoreInternal */, + 3C58AF22FFF1523566C3A039B0E320D0 /* FirebaseDatabase */, + 56062E9F1708394BD469588869510C52 /* FirebaseInstallations */, + 898308531697D66C48B288BE71401EA7 /* GoogleAppMeasurement */, + D537D2CE3F982AD935279D077683BFA9 /* GoogleUtilities */, + AA4136EA543A6A861FE56D011DCB4607 /* GTMSessionFetcher */, + 45ABE944C527C74C9104AEEF22CE729A /* leveldb-library */, + A642180AC9832AE21002859F56594700 /* nanopb */, + 40BA3C74D8E4D14ADAC4C541007CE78E /* PromisesObjC */, + 066278B9E287AD4787E2B8ED588042FB /* Realm */, + EF3F56AC7897BEFC15E1086642A81B6E /* RealmSwift */, + ); + name = Pods; + sourceTree = ""; + }; + EA7F65BAE05ACDC883E3B83E53D5DACB /* Pods-PRTY-PRTYUITests */ = { + isa = PBXGroup; + children = ( + 44A73C4C6CD01197814C4A8D7D9B1E04 /* Pods-PRTY-PRTYUITests.modulemap */, + 2BD9A1C4D7C0E01F46C69DCB21ED00B1 /* Pods-PRTY-PRTYUITests-acknowledgements.markdown */, + 3DDFE294FE513102A9E25C7407AD8DC4 /* Pods-PRTY-PRTYUITests-acknowledgements.plist */, + 69578BBD7CC915AC07C4B3A36276C339 /* Pods-PRTY-PRTYUITests-dummy.m */, + AEDA4EF090CB0277725FB18D19FD8AC3 /* Pods-PRTY-PRTYUITests-frameworks.sh */, + 1FAA971A08BB9B6B11705EEE9B77BAD5 /* Pods-PRTY-PRTYUITests-Info.plist */, + 8FD2C61EFB4734EA70647A3B77BF8ACF /* Pods-PRTY-PRTYUITests-umbrella.h */, + 02F08FE90CA068E63145D504F97EA515 /* Pods-PRTY-PRTYUITests.debug.xcconfig */, + F4212B50C554057BF62AA6A4107D56BC /* Pods-PRTY-PRTYUITests.release.xcconfig */, + ); + name = "Pods-PRTY-PRTYUITests"; + path = "Target Support Files/Pods-PRTY-PRTYUITests"; + sourceTree = ""; + }; + EF3F56AC7897BEFC15E1086642A81B6E /* RealmSwift */ = { + isa = PBXGroup; + children = ( + 682683D1FA0D7DFA4BEE25A9AC5C6759 /* Aliases.swift */, + 70AF99E224EDF12DFD45951388CF82E3 /* AnyRealmValue.swift */, + 221A1EC0D7C56B655A04DE2004063628 /* App.swift */, + 161AC9CABA773FA8567619A753121850 /* AsymmetricObject.swift */, + 5506F3E5AA24EDAAE83D9798B944122C /* BasicTypes.swift */, + 9CEC0913FB88FE9BE18552047F830854 /* BSON.swift */, + 5071D4D3329AB8550000CC07BE36AFAB /* CollectionAccess.swift */, + 836372D75ABF46C08BAD5758AD2B8EBF /* Combine.swift */, + 3A82FDA5AE234681E92A4CF13D383368 /* ComplexTypes.swift */, + 24CF3FE9F1F63048BE73769786AA32FA /* CustomPersistable.swift */, + 753ACF5F1365F9D5FD71BE6F829E2F92 /* Decimal128.swift */, + 59727615BE1BBAD30154EEDC7630DB67 /* EmbeddedObject.swift */, + 4299C7EE17ED3C5658CD46D929754564 /* Error.swift */, + CF93129186968B01B7B193F2016F8569 /* Events.swift */, + 534282AC766172E1738511BDA8F27B1F /* KeyPathStrings.swift */, + 673C8052EBB7CFC728848688E8635A04 /* LinkingObjects.swift */, + 31136171FDDC64178366CD0A6B113B84 /* List.swift */, + 73C0174B2AFCC7AE91A522B22727376A /* Map.swift */, + 03AA740D30B94B0A702C0129205701EE /* Migration.swift */, + D403AB05C8E5B8D4D7EC9A9E2C7A971E /* MongoClient.swift */, + 250E7EC04CADDFF718CBE2F2B949220D /* MutableSet.swift */, + 0B9C0BA6C40683E28DD6831B3FC7E7F1 /* ObjcBridgeable.swift */, + 0D5EB8A590366F66FC4D151DF662E315 /* Object.swift */, + 542FC53B9E7ABA035BA8484DB8D865D7 /* ObjectId.swift */, + 2F1F7E6A93AAEE1766B72ADAA3E6F62B /* ObjectiveCSupport.swift */, + C29E8533FF9AF637113A7A692C0FD27D /* ObjectiveCSupport+AnyRealmValue.swift */, + 4235F9BE23198AFAE32EBEA9B32A5C18 /* ObjectiveCSupport+BSON.swift */, + E355264F8F23BD69A8E6EC8A430817AD /* ObjectiveCSupport+Sync.swift */, + 7638110F458ECF6341C673A9696D666D /* ObjectSchema.swift */, + D0AA822C47FB8D76517D7B38666F38C1 /* Optional.swift */, + 3CFE28636C71B865952B8CBA130E29DE /* Persistable.swift */, + D71BEF9DD1974C9E1B6490E81C32E5B6 /* PersistedProperty.swift */, + 44140A47AA4C978E372460E01A273CAE /* Projection.swift */, + 4A3490944EAFC2F4D1E10697E776D942 /* Property.swift */, + 74A5A96FBBF716F052FC7FE7E7799B11 /* PropertyAccessors.swift */, + 4439B26A132B0978E10DE975AF9F2E70 /* Query.swift */, + BE522E5C99C9F08611559181764D55B9 /* Realm.swift */, + C375A35EEAB2E08FC388D263A6209408 /* RealmCollection.swift */, + 32E4A9F082BFCABE2AD6B32D535E37D8 /* RealmCollectionImpl.swift */, + 197274F76C7C01DC8B256E11BA3CA173 /* RealmConfiguration.swift */, + EA3CA50214CA2C30C735EF15DCFDD00C /* RealmKeyedCollection.swift */, + 76E8A9B00D0B852C4CBF03F3018E7BA6 /* RealmProperty.swift */, + 10310C29C4CC4CCC1AC43ECD64772E1C /* Results.swift */, + 2E083BCD2610C9F8CD73B0B83C2A3252 /* RLMSupport.swift */, + 27ECFAE94F84C45208AF513C0E025E9D /* Schema.swift */, + D5DD6C3F39E0FF0D612E4964A5FD8D45 /* SchemaDiscovery.swift */, + 9FAAA110C793DEE87DD244F02733834B /* SectionedResults.swift */, + 046758AD33D0FD687DD1AD08DD311250 /* SortDescriptor.swift */, + EAC3AE1029A198F99DE8B54D835FA231 /* SwiftUI.swift */, + FBC36C1DEA1FE665B1571B58B928ED9B /* Sync.swift */, + D1CC4C7FABA96F45EE8B3CD9AAFE20D0 /* SyncSubscription.swift */, + BB1C8573631EC09896F9F87AF31645E6 /* ThreadSafeReference.swift */, + C33F49AFBB23402149BEFBFF42FB5ABE /* Util.swift */, + 2DE115502795EA5D4E6E0E6F25B76A9B /* Support Files */, + ); + path = RealmSwift; + sourceTree = ""; + }; + FA21233F2F86D3B6BE73DAA1232FE922 /* Support Files */ = { + isa = PBXGroup; + children = ( + B71930D36867FE650530A67FF1AE536D /* PromisesObjC.modulemap */, + FCC47F2FBDB65E9C97CEA7B0375E1E50 /* PromisesObjC-dummy.m */, + 592D0D7310651F0CA55EFAE60B29BABB /* PromisesObjC-Info.plist */, + F4332EC6914A3C94E725975980509BB2 /* PromisesObjC-umbrella.h */, + BCBB934EA3FEB2A60AAE97D3799103B3 /* PromisesObjC.debug.xcconfig */, + A030CC80807AF4C0FDC009471007CC14 /* PromisesObjC.release.xcconfig */, + ); + name = "Support Files"; + path = "../Target Support Files/PromisesObjC"; + sourceTree = ""; + }; + FB5DB47764CEA692A58D7FD05D365E5B /* Support Files */ = { + isa = PBXGroup; + children = ( + E823EE8166EE2F183AE2CA0918747CB5 /* FirebaseDatabase.modulemap */, + 73874D1391ABB5D9F840E66D19FC0FDF /* FirebaseDatabase-dummy.m */, + C6F22D9B59162F598669602515CE72D5 /* FirebaseDatabase-Info.plist */, + CF1F64FF1371085F3868BD8A29F1725E /* FirebaseDatabase-umbrella.h */, + 46C5E75CF6F0B997F9A910E919A5E1D7 /* FirebaseDatabase.debug.xcconfig */, + F0DF6E1A8D6752D88F3DAA4CF23F208A /* FirebaseDatabase.release.xcconfig */, + ); + name = "Support Files"; + path = "../Target Support Files/FirebaseDatabase"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 2656B555E4AD56D6153C7CAA000A9E22 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 38B384070F9EE79308F694D5566C29F8 /* FIRAppInternal.h in Headers */, + 882657E5558E8ACC6634AB9D8FDED37B /* FIRComponent.h in Headers */, + 4171658B89120091D032FE97BA262E6C /* FIRComponentContainer.h in Headers */, + 2E36EC47A992822A4D670D9A237B8894 /* FIRComponentType.h in Headers */, + 9609235EF89429B145D15C35CD97B78B /* FIRCurrentDateProvider.h in Headers */, + D200DDDDED3ADA6C430CC33566EB7E83 /* FIRDependency.h in Headers */, + 4DEDACB8CD42A769352645B89B73201D /* FirebaseCoreInternal.h in Headers */, + 74E46733C9F9E9BEED6F791F1E91CEB0 /* FirebaseInstallations.h in Headers */, + 50CDD7A792E4F8FBC44618421DD8CF9B /* FirebaseInstallations-umbrella.h in Headers */, + 5A0B815B366922A4474119ADF8C6B944 /* FirebaseInstallationsInternal.h in Headers */, + B89733EC7C564F879DA19FFCE4652F67 /* FIRHeartbeatLogger.h in Headers */, + 99720C62F8883DED73FDE4B2E8C8418C /* FIRInstallations.h in Headers */, + D8BBE5D5E027D5EEEA15CBB9DA279FBD /* FIRInstallationsAPIService.h in Headers */, + 7DC2F4C7608BA7017846117B83D6FB2B /* FIRInstallationsAuthTokenResult.h in Headers */, + 9311C57B3CD9E335505406C425678201 /* FIRInstallationsAuthTokenResultInternal.h in Headers */, + CAFBCA09CF5C2F272C040CF7976F4DEC /* FIRInstallationsBackoffController.h in Headers */, + B38189926FD2265A00099C5F5FDC3884 /* FIRInstallationsErrors.h in Headers */, + 5791C5BE858BE11F3C05A9872B4B40E7 /* FIRInstallationsErrorUtil.h in Headers */, + 2B505A23980039E9504F1854F70DEAC1 /* FIRInstallationsHTTPError.h in Headers */, + 1B49710EAEC16C9113A9404A4BDC9E3F /* FIRInstallationsIDController.h in Headers */, + A4595E5A026C972FD6829E2A7D698CFB /* FIRInstallationsIIDStore.h in Headers */, + 30AC90E398AD1879161358AD52E0440D /* FIRInstallationsIIDTokenStore.h in Headers */, + B0F831410CB9D0FA3B471C5100EA35F1 /* FIRInstallationsItem.h in Headers */, + FFFC123D47FB74E967FB4F2401D24BE5 /* FIRInstallationsItem+RegisterInstallationAPI.h in Headers */, + 4D2B7517D0813C662A60572D908D65B1 /* FIRInstallationsLogger.h in Headers */, + C0B022EB886F9DCE13408F6E3041DBAA /* FIRInstallationsSingleOperationPromiseCache.h in Headers */, + 72326CC926D7729374FCF9260D6CACAF /* FIRInstallationsStatus.h in Headers */, + BDCC5C4B4D01C1885658D5CB3A3AC167 /* FIRInstallationsStore.h in Headers */, + DC4D87E65DF1801D3AB23D64E9C7584B /* FIRInstallationsStoredAuthToken.h in Headers */, + 7027C8F66273C15566DC87EA976FBBCA /* FIRInstallationsStoredItem.h in Headers */, + 5FBFE5D037D58A5AFD620C5FDB5E0C7A /* FIRLibrary.h in Headers */, + C479DC41793B5C448FEAE2B131A1AB56 /* FIRLogger.h in Headers */, + 63D74FBA3A84E9500101C5B32FBAF35C /* FIROptionsInternal.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2EDCC5FB1525478D139B5503AEB98F96 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + EF9183138C397191B5FCC5039411001A /* GoogleUtilities-umbrella.h in Headers */, + 6036D8DB4C4B7C592FF94E76A7DF8D98 /* GULAppDelegateSwizzler.h in Headers */, + 1ECDAEF2D8E73A492C15D2FE1ACF3869 /* GULAppDelegateSwizzler_Private.h in Headers */, + 0AFD73DED7EB02CEAAFA2B42AAB79A2B /* GULAppEnvironmentUtil.h in Headers */, + C3DE1ACA5C56880B3AB706DDCF5F15AA /* GULApplication.h in Headers */, + 83FDCCCA6FA59EE3D4C2974A69FB14C8 /* GULHeartbeatDateStorable.h in Headers */, + 6C59DE012FACC419CD2F0259DFEFAF40 /* GULHeartbeatDateStorage.h in Headers */, + 41A3C21316B987FFDBD324926D024C1D /* GULHeartbeatDateStorageUserDefaults.h in Headers */, + 9B921FB7B1E6CE0D70535CD2ADBFC4C4 /* GULKeychainStorage.h in Headers */, + 39A44ED1031AABA976280D99FD4337F0 /* GULKeychainUtils.h in Headers */, + 29F08AF3D1535FD26ABAE795B14EDFA8 /* GULLogger.h in Headers */, + 33108301DF03DB45D48B8F3889DE5906 /* GULLoggerCodes.h in Headers */, + 71B2896D03416092358F5EBCF3E2FC14 /* GULLoggerLevel.h in Headers */, + 442B35CDAB15537B59F5243FD98FFD52 /* GULMutableDictionary.h in Headers */, + 6D2C6F9E260C61A32B0281446400F958 /* GULNetwork.h in Headers */, + F26374CF411669267DB9B0F79015FD8F /* GULNetworkConstants.h in Headers */, + 9D65E3E660A5810772FD494FF83D786B /* GULNetworkInfo.h in Headers */, + 2F6F852A5CF6FF3C8E791FAE3E555A08 /* GULNetworkInternal.h in Headers */, + F1E7D8D5AD985178B7DE1CC0C3905032 /* GULNetworkLoggerProtocol.h in Headers */, + 8A669A05308CB2ACBE76B0F867562EB7 /* GULNetworkMessageCode.h in Headers */, + 705ED32B9CF56B5852CA33C5BCC90233 /* GULNetworkURLSession.h in Headers */, + FF00FEB45507C13D07486E49219A30A1 /* GULNSData+zlib.h in Headers */, + 4C51A5D00224D8834489FEC967ED81CC /* GULOriginalIMPConvenienceMacros.h in Headers */, + EC659275F4A4F5564BD0D55C62FC7CA4 /* GULReachabilityChecker.h in Headers */, + 48A3DD5AB48593E10CC8CC8701045594 /* GULReachabilityChecker+Internal.h in Headers */, + 94AC4F19769153CFA401C98A84B99A8A /* GULReachabilityMessageCode.h in Headers */, + DA099809CF608E0348A0E308A838BA49 /* GULSceneDelegateSwizzler.h in Headers */, + AD82C7808251471F35BA3A73BA03BEDB /* GULSceneDelegateSwizzler_Private.h in Headers */, + 58882B03EECF67F28BEFC616DE13B6EE /* GULSecureCoding.h in Headers */, + 7D8719C93C68BAAD9FB94A7B93982AA8 /* GULSwizzler.h in Headers */, + 5F0E280A37666ADE8D88D12AF7CE94CD /* GULURLSessionDataResponse.h in Headers */, + A47149847911B053BB4CE39AE37276E6 /* GULUserDefaults.h in Headers */, + 331287FF32C8BEDC639F7A8D2ED118CC /* NSURLSession+GULPromises.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 3C24ABE3A93849D4620B2849C03B52D6 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E4803946556D9427C1E7E569B038C1A /* nanopb-umbrella.h in Headers */, + 5BF4201F4F0D3F3912D7CFEC12CB183E /* pb.h in Headers */, + 335FA26ACC34E99D04E31985AA681928 /* pb_common.h in Headers */, + 25BF6CA2126B5CA98749D820B6EE3790 /* pb_decode.h in Headers */, + 992233B1F4B40F8B77EA7CC9D7C8E0F1 /* pb_encode.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 3CB635D5FCA00D7AE71640B07796B6D3 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 38D9942994604B9E407034CDDD612568 /* FBLPromise.h in Headers */, + 4C99278882E436684311D9BFD37937F7 /* FBLPromise+All.h in Headers */, + 496C5E6D646C6F261FB29A676837CA49 /* FBLPromise+Always.h in Headers */, + 9F46CED3C51DA609AE7C985E0017C920 /* FBLPromise+Any.h in Headers */, + 173E484A46C45E4E2EAAEBAEB7D19FBB /* FBLPromise+Async.h in Headers */, + 8507E262AF0B917CD3216BE0E1C0015D /* FBLPromise+Await.h in Headers */, + 924BE5528A081DEF9AE9D2911A7F3A7C /* FBLPromise+Catch.h in Headers */, + 55814156A2B12DE25A5F87842E17DB31 /* FBLPromise+Delay.h in Headers */, + 623172201F28ACB8537E34B99ABB4E75 /* FBLPromise+Do.h in Headers */, + 5445F07D73D86E557BDFD419CD743D6D /* FBLPromise+Race.h in Headers */, + F70F563A55B7BE35625BC0DE69133526 /* FBLPromise+Recover.h in Headers */, + A11B2EE8A74B25AEB3D6A1807235EB50 /* FBLPromise+Reduce.h in Headers */, + DD03813A8D27CBD28F61120EE5540A7F /* FBLPromise+Retry.h in Headers */, + 55D37E587FABDFB9D97DDC35CB8A4A51 /* FBLPromise+Testing.h in Headers */, + BD5ACB67AB00DBBFB9AAB0297FAC4161 /* FBLPromise+Then.h in Headers */, + 7FDB7BFDBE90E751FD01DF78A268D99C /* FBLPromise+Timeout.h in Headers */, + 76952BFE70A646B85266D3EAE1153876 /* FBLPromise+Validate.h in Headers */, + A0C346DD84D892132E629AE4EE267F14 /* FBLPromise+Wrap.h in Headers */, + E728FFC9C06C471B2251C36600FA9637 /* FBLPromiseError.h in Headers */, + AEBCA3B9E36968494D8EF17CBE7A7946 /* FBLPromisePrivate.h in Headers */, + 28128BF32E810A8678D7171A29F0A477 /* FBLPromises.h in Headers */, + 3985FF8BAC3C5B2AE2B6808AA80884B1 /* PromisesObjC-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 4EBE0D77C5B4468AD813EF39DF88DF05 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 4B608FE2ECE665D165D9F46633E74AF9 /* FirebaseCoreInternal-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9DB7BADC3E77EA6ED5B4CD3D33B96C23 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 51D0DF0757943CCB8BB8413E7949854D /* FIRAppCheckInterop.h in Headers */, + D6B2D211BB9CB9A12D9F2F6D9CAA65FB /* FIRAppCheckTokenResultInterop.h in Headers */, + F77E9BFC320A071D1B0F29A909E1D1C4 /* FirebaseAppCheckInterop-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + A581BE0E16E4FCE52E9519A091628842 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 186A9950AD2BC40A5E06896B3F3FFBC4 /* RealmSwift-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + AEB75B39C942BBC857AF16E21F008F81 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 404B52810CF5B35D54D95481794696F8 /* FIRActionCodeSettings.h in Headers */, + 9F4CB6E18F78821866985298E819B20A /* FIRAdditionalUserInfo.h in Headers */, + ADFCE255F5A94F073CA5F5DBF194CB01 /* FIRAdditionalUserInfo_Internal.h in Headers */, + 7F7FFEEF9343C454582B565A2D72178F /* FIRAppCheckInterop.h in Headers */, + 3D1DEC7F7FDA6D8C486B03C1B36475D5 /* FIRAppCheckTokenResultInterop.h in Headers */, + 280B690F41E4F6156DB9194020820A53 /* FIRAppInternal.h in Headers */, + 68005BC2C5F600F7841B5BD2333636EC /* FIRAuth.h in Headers */, + 231B82B559FA16389A48B6C0BCA4BA46 /* FIRAuth_Internal.h in Headers */, + 061AAAC4865C320B832820C7A28132A5 /* FIRAuthAPNSToken.h in Headers */, + 59172902DE2D04BC0A5E95A22D78E6E4 /* FIRAuthAPNSTokenManager.h in Headers */, + FD5127CFB41EA3C43F6BC1448CB31135 /* FIRAuthAPNSTokenType.h in Headers */, + FE2BCCBDF39BF523C12F36BE70307E57 /* FIRAuthAppCredential.h in Headers */, + 486FB1F998459F78D6D2907F7861E8A3 /* FIRAuthAppCredentialManager.h in Headers */, + 49A9A4B4409D9359518456CD7D3156DA /* FIRAuthBackend.h in Headers */, + 0885A108D0AE69C45B5DFF90EF4D5404 /* FIRAuthBackend+MultiFactor.h in Headers */, + 2C9BB565C846B9E82A7B19A6DEDB0D2A /* FIRAuthCredential.h in Headers */, + CC7E403C2DDE4EAA34195F619AB290C7 /* FIRAuthCredential_Internal.h in Headers */, + 7D3E99D0B5F4097DC8CB6992458604CD /* FIRAuthDataResult.h in Headers */, + 582154C6ADD5ABA88AE539266498C60A /* FIRAuthDataResult_Internal.h in Headers */, + 63FFD179F5B7441B72277FBA17CA7E57 /* FIRAuthDefaultUIDelegate.h in Headers */, + E2C0ACDE304C8154F8D114D3849C9206 /* FIRAuthDispatcher.h in Headers */, + B8E868B2092716E5F89E7A04EF1079EA /* FIRAuthErrors.h in Headers */, + 703DE9CF4ECC5464EB8C17404FDC70EF /* FIRAuthErrorUtils.h in Headers */, + D4CB9A2EA3601EA9F9897A74B7ECC895 /* FIRAuthExceptionUtils.h in Headers */, + E2916C9A40D41E306C7B1CCED8AC8D53 /* FIRAuthGlobalWorkQueue.h in Headers */, + 68A1D8991B40FF51D86FCA23FD15A401 /* FIRAuthInternalErrors.h in Headers */, + 2DA2C2154A6BBEE40B136B1C8854FCA0 /* FIRAuthInterop.h in Headers */, + C4DEB058FC4697D7845D56FEA4CC8446 /* FIRAuthKeychainServices.h in Headers */, + E2565A76FD48280A35B688B7DEA233FC /* FIRAuthNotificationManager.h in Headers */, + 2B9D45261AB0F27D7B4FFB0B0B32937F /* FIRAuthOperationType.h in Headers */, + 04C54BD42C853B261EA081931344691B /* FIRAuthProto.h in Headers */, + 54F05B51D5819573F1F0C3EE8AEAF5BF /* FIRAuthProtoFinalizeMFAPhoneRequestInfo.h in Headers */, + 0D57570ED6DA0B24D24B6E96F4F414D4 /* FIRAuthProtoFinalizeMFAPhoneResponseInfo.h in Headers */, + 9D14157D94D8AD8E7E4ED65C882441B6 /* FIRAuthProtoMFAEnrollment.h in Headers */, + 8F6DFFC393590C52DAC213565722C40D /* FIRAuthProtoStartMFAPhoneRequestInfo.h in Headers */, + D0D9A0D6F301A748E7F89A32C6822393 /* FIRAuthProtoStartMFAPhoneResponseInfo.h in Headers */, + 4B78255CFCE26F89B4FB04D56E46577C /* FIRAuthRequestConfiguration.h in Headers */, + F20A0BD5B07FC0792FF857189CE7AFB4 /* FIRAuthRPCRequest.h in Headers */, + 79D0EC285DCC4DD6DC940F2F040086EB /* FIRAuthRPCResponse.h in Headers */, + 2248B7A0012B9511E4F820D7E9701B3F /* FIRAuthSerialTaskQueue.h in Headers */, + 5997E8A72EC4756FD9EA0D217A102E56 /* FIRAuthSettings.h in Headers */, + A27EA8BE9E88868BB6EDC2BAD5E80820 /* FIRAuthStoredUserManager.h in Headers */, + 1F0607B87427A32DE2195E6B3373626A /* FIRAuthTokenResult.h in Headers */, + C8626178E7EE3B1A784C50B1EC4C049B /* FIRAuthTokenResult_Internal.h in Headers */, + 51FBC9718924785B6B4B2827C0569407 /* FIRAuthUIDelegate.h in Headers */, + CC098CA333DF585D4E53DB5E3541CCD8 /* FIRAuthURLPresenter.h in Headers */, + C0DF8DA7126E2280ECC00E581633D9D0 /* FIRAuthUserDefaults.h in Headers */, + 76F0D6FB31C89BA3CE5CFBAC0FF9F71D /* FIRAuthWebUtils.h in Headers */, + 8BA82EA563A0E6460C1C4FFDED4A5CF2 /* FIRAuthWebView.h in Headers */, + D259A175BA77A4853C3834D57A8D988B /* FIRAuthWebViewController.h in Headers */, + 160CB2757087667BBBC83DB6645470A4 /* FIRComponent.h in Headers */, + D10E04ED005166DE728E30E0091434B8 /* FIRComponentContainer.h in Headers */, + 83A89426A1ECA287F8B9E3CF523604DA /* FIRComponentType.h in Headers */, + 96D8CF73824E8DFB9D0738674EBE8885 /* FIRCreateAuthURIRequest.h in Headers */, + 0DA79DE502509F30F6DF82612FF81885 /* FIRCreateAuthURIResponse.h in Headers */, + 5E4B70D26A7E04EF92A34EE613EBFB2A /* FIRDeleteAccountRequest.h in Headers */, + 520DE702E04C513843FE06229BD82259 /* FIRDeleteAccountResponse.h in Headers */, + DDE0BA26BDA6A6C3CE77FFFF9C63C0C4 /* FIRDependency.h in Headers */, + 94BEFCDCEC7A42473FC1D494A29E1CF8 /* FirebaseAuth.h in Headers */, + C8E41AD8618746EC7F633A39328CDAAE /* FirebaseAuth-umbrella.h in Headers */, + 0B2427765D5FE4486052F9AF50E5B0D5 /* FirebaseCoreInternal.h in Headers */, + 03C6606D7430D634EDC9A0A0E7C3C327 /* FIREmailAuthProvider.h in Headers */, + 3310BD9799F4B3C7E08E8692D785EA41 /* FIREmailLinkSignInRequest.h in Headers */, + 3139C4E6340CBE4B22B43096EDB8EB15 /* FIREmailLinkSignInResponse.h in Headers */, + 315DB9E13CC8D07BA11C3A6AE9BAB9CC /* FIREmailPasswordAuthCredential.h in Headers */, + BC5107C6FE41D614D2E229570FB776E7 /* FIRFacebookAuthCredential.h in Headers */, + C46671D11B3BEBA872C9888AF8B2DB16 /* FIRFacebookAuthProvider.h in Headers */, + 1FCDD221A9E732A3CA3D2CDF5BFD85A5 /* FIRFederatedAuthProvider.h in Headers */, + D58019E41FACCB661850911399D9213B /* FIRFinalizeMFAEnrollmentRequest.h in Headers */, + ED84D33835D30E2D1BC665C0048784D5 /* FIRFinalizeMFAEnrollmentResponse.h in Headers */, + 89073846BCA6670F870B7B137814D47B /* FIRFinalizeMFASignInRequest.h in Headers */, + B8316E008B646F18A831E0497A8A534F /* FIRFinalizeMFASignInResponse.h in Headers */, + 069810D5AFB74BAF041B5591C8C284B2 /* FIRGameCenterAuthCredential.h in Headers */, + 8E7060F11BBBEB03E9D34B7858081729 /* FIRGameCenterAuthProvider.h in Headers */, + 565750705CA8C90200D9A1EEF7275FD7 /* FIRGetAccountInfoRequest.h in Headers */, + 0C25A01228C9393D350E75A8B2688EC0 /* FIRGetAccountInfoResponse.h in Headers */, + F33E9CE79C80524B7507FFB796BC089B /* FIRGetOOBConfirmationCodeRequest.h in Headers */, + 2C25D8B69A7076CC958BAB5BD37FCD8D /* FIRGetOOBConfirmationCodeResponse.h in Headers */, + C04C00037217D6B0FA21801099283BB9 /* FIRGetProjectConfigRequest.h in Headers */, + E319346F7B9732FD494ECE12C241911B /* FIRGetProjectConfigResponse.h in Headers */, + 296F785F9BB7CDD1C9718FE9703701E5 /* FIRGitHubAuthCredential.h in Headers */, + A35ECF8CDD51CD1085D528816AB97198 /* FIRGitHubAuthProvider.h in Headers */, + F9269572B7E1F79AD0695542C63253D5 /* FIRGoogleAuthCredential.h in Headers */, + F0ED9B20EED8F5046B60DF1BB893E515 /* FIRGoogleAuthProvider.h in Headers */, + 0C904DAFBAF94A44772444E05843DA9B /* FIRHeartbeatLogger.h in Headers */, + 57A3EF3072CC13E10031822BC6C763E2 /* FIRIdentityToolkitRequest.h in Headers */, + 08BA761685D424F62253220DBB1F4692 /* FIRLibrary.h in Headers */, + D53372B5BBF6015D7925B8BCA6245276 /* FIRLogger.h in Headers */, + FCE1F976A31B6C03B3B71681B632A40C /* FIRMultiFactor.h in Headers */, + 84C158263730504EFA0CBA0928572142 /* FIRMultiFactor+Internal.h in Headers */, + 91161FD58138AB0E2C694035C96B5779 /* FIRMultiFactorAssertion.h in Headers */, + DED0DBA57C460BED50AB906959ECADFE /* FIRMultiFactorAssertion+Internal.h in Headers */, + F9D3ADA4C37A1FC124F9959AA8554670 /* FIRMultiFactorInfo.h in Headers */, + 09EA6EB381880B689D80C64DA13E8B6F /* FIRMultiFactorInfo+Internal.h in Headers */, + 51CB4CF290C18825C5302621D800DEC2 /* FIRMultiFactorResolver.h in Headers */, + D7E0B1ECE4451DA6E3E681AFC9E3CE20 /* FIRMultiFactorResolver+Internal.h in Headers */, + D8F2A6F3893C0186D0B46233B31A1910 /* FIRMultiFactorSession.h in Headers */, + 5F21EF6E74C5254B54F99DF2F37321A1 /* FIRMultiFactorSession+Internal.h in Headers */, + 45DC4DC21EECB903A0AEC26D726A51DF /* FIROAuthCredential.h in Headers */, + 2A47E42F34E410CB363A42BA8358B0F5 /* FIROAuthCredential_Internal.h in Headers */, + AE2819DF95D7AFDAD05C2ABBC3C0BC06 /* FIROAuthProvider.h in Headers */, + 5AC2DDA73F2100F520FFEB5480E511E7 /* FIROptionsInternal.h in Headers */, + 8E043355D82994E1780D651AB0240B45 /* FIRPhoneAuthCredential.h in Headers */, + 2D12A36D05F856956F5CDA84ECFEC8E8 /* FIRPhoneAuthCredential_Internal.h in Headers */, + 53502CA8CADE18039E609C3CD3642AF6 /* FIRPhoneAuthProvider.h in Headers */, + 3C4CB761E2F8364198D4B1309B62510C /* FIRPhoneMultiFactorAssertion.h in Headers */, + 7E797D6BAC015A9DB1DBF2DCB171996A /* FIRPhoneMultiFactorAssertion+Internal.h in Headers */, + 9A67A5511310C707DDD90E5FEB47EA41 /* FIRPhoneMultiFactorGenerator.h in Headers */, + 19344C97DA033C622B62F40E6650E56E /* FIRPhoneMultiFactorInfo.h in Headers */, + 64B9E5FB3BC5313C5CB1C7CF70FCD5BF /* FIRPhoneMultiFactorInfo+Internal.h in Headers */, + 4A48C495B15B169C2B9828A8BEFFB9DD /* FIRResetPasswordRequest.h in Headers */, + 668E0B7C95B37D8DFE134D091A0BFAF5 /* FIRResetPasswordResponse.h in Headers */, + 8DF4C16DBDD29689C7747E810E814836 /* FIRRevokeTokenRequest.h in Headers */, + 72AB8DFD21CA1AE084E1FDB7C204A482 /* FIRRevokeTokenResponse.h in Headers */, + 89B7CABFA86E84E895B197B32BA81FD5 /* FIRSecureTokenRequest.h in Headers */, + 8EB027297697291D2A6CF957EFC4F9F5 /* FIRSecureTokenResponse.h in Headers */, + 7554645B7EE80B5C2D1B06F51A523FE5 /* FIRSecureTokenService.h in Headers */, + E6284E908AF5409603CA525094613726 /* FIRSendVerificationCodeRequest.h in Headers */, + D6C44947FEE40D6011352F10AFF03FC0 /* FIRSendVerificationCodeResponse.h in Headers */, + A3578F1E8CBAD2C225AC7D11C9DDA8D9 /* FIRSetAccountInfoRequest.h in Headers */, + A3F2ACD414E198365E6ED9AD99D097EC /* FIRSetAccountInfoResponse.h in Headers */, + DFE1746A5269BEE6DD306BA59145C307 /* FIRSignInWithGameCenterRequest.h in Headers */, + E22858B989C3D08AC5E7E1ED67468D28 /* FIRSignInWithGameCenterResponse.h in Headers */, + 0D013B8100EB7D31F8C637385C307B38 /* FIRSignUpNewUserRequest.h in Headers */, + C6B76B89A919288D604A47D491FA7EE3 /* FIRSignUpNewUserResponse.h in Headers */, + 075DFF61BE5F0C4C6B1C039BCE9610E2 /* FIRStartMFAEnrollmentRequest.h in Headers */, + F23664D576E15E7398BB588D5B2F132A /* FIRStartMFAEnrollmentResponse.h in Headers */, + 2089B723FD3543B3A649AC26616550CE /* FIRStartMFASignInRequest.h in Headers */, + 082C1131024807CE7E2FBDFF812C3BCB /* FIRStartMFASignInResponse.h in Headers */, + 93605CBB442A1846671A0B857D5C9A81 /* FIRTwitterAuthCredential.h in Headers */, + 98FB19FDCBF27E03A1228A3F51ED84E9 /* FIRTwitterAuthProvider.h in Headers */, + 038242B952D8B42129B77E03E1A519A1 /* FIRUser.h in Headers */, + 2B1964D3F4B7A4E590DA2D60D42C3263 /* FIRUser_Internal.h in Headers */, + 7B4CD08DF8A36987D9561D1599F82BC1 /* FIRUserInfo.h in Headers */, + 572713FA85012B09A410BEEEF0400B23 /* FIRUserInfoImpl.h in Headers */, + E7B389C091FE7D1155C1456195E531F7 /* FIRUserMetadata.h in Headers */, + 745F46C649A9EF4D3EC2810615B87980 /* FIRUserMetadata_Internal.h in Headers */, + 831F97CA0784C52918A070E95B0D3735 /* FIRVerifyAssertionRequest.h in Headers */, + 4AFFADD4B822947985F6930E6557BF87 /* FIRVerifyAssertionResponse.h in Headers */, + 79956513781565B1B06A201C91893DAA /* FIRVerifyClientRequest.h in Headers */, + 6D9CA441C68C8FE9F8B757E9C4C7A34E /* FIRVerifyClientResponse.h in Headers */, + 51126ABE1EBA39EE201F72B0567BD3BA /* FIRVerifyCustomTokenRequest.h in Headers */, + D82684D89B5905862B5A06E431E4A6F6 /* FIRVerifyCustomTokenResponse.h in Headers */, + 6B93BE98BFB7A771824B968D139D4451 /* FIRVerifyPasswordRequest.h in Headers */, + BA8344D3B25EBACBE20F5A12CEA3DDD9 /* FIRVerifyPasswordResponse.h in Headers */, + 00FEC32E8F0A1C904919B1F4F522A0D7 /* FIRVerifyPhoneNumberRequest.h in Headers */, + BFA7A13A2995D892BC108E0B0D53191D /* FIRVerifyPhoneNumberResponse.h in Headers */, + 1955ED863CC66C0EAAE4E38C196A9EBC /* FIRWithdrawMFARequest.h in Headers */, + 0CC18E591907BF6B77BC02E7302E0CEE /* FIRWithdrawMFAResponse.h in Headers */, + E8EBA782F6C257A93E8D3A95D9F5C266 /* NSData+FIRBase64.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BC1CA4BE9E11C654BC2BD71A39EA1E3C /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 3EC845F88149384EC83CD47A57F9D374 /* GTMSessionFetcher.h in Headers */, + 3626BEFF142ABEFB340C17ED85052C4D /* GTMSessionFetcher-umbrella.h in Headers */, + 00CC58E0E5D67FF05E13D15377F3AB80 /* GTMSessionFetcherLogging.h in Headers */, + F67FE7C9AFC88C161332DCD647A9799F /* GTMSessionFetcherService.h in Headers */, + 6F41546A492D5F6448970F4278FF2A07 /* GTMSessionFetcherService+Internal.h in Headers */, + 44291122DBE8E9AD92E8CC7F49F17A03 /* GTMSessionUploadFetcher.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BD7485A9A3C8A3584D1A4143701351D2 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + F5A9905AFF28A99966232E7EB9274196 /* Pods-PRTY-PRTYUITests-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + CBA49643794F86DECF4DC16E0322BCC9 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 517660A661274C4A72A3E7FAE2B9883A /* Pods-PRTY-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + CCA73A9FF8AE128D14D92AA9ACEE5DB0 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 1F7125A2397241BCD087960ACFA0C8F2 /* APLevelDB.h in Headers */, + ABAC3114CDDD664D12B2B33A93063D5C /* FAckUserWrite.h in Headers */, + F3320DB40CFC2F70058E85A452DD3359 /* FArraySortedDictionary.h in Headers */, + D260ECDDE28A0556DB93E754D43C25F8 /* FAtomicNumber.h in Headers */, + 55284658D32D0CDD85FA37EF35A79238 /* fbase64.h in Headers */, + 35C92F88D02F66D3CD811EE747A0D2D1 /* FCacheNode.h in Headers */, + 99BB16964483ACCEFFE2E25131479EAD /* FCachePolicy.h in Headers */, + C2B5190B51BE0FAE537831925FF254D3 /* FCancelEvent.h in Headers */, + 8A59933B92420A17E5E4CAD5C66E7DBB /* FChange.h in Headers */, + 23C461911D9808F97D596DDDDD453436 /* FChildChangeAccumulator.h in Headers */, + D048FAB5314A168A7C43CCBC16780B5C /* FChildEventRegistration.h in Headers */, + 481B69706CC4E586BD0C1BF080020D26 /* FChildrenNode.h in Headers */, + D12BC2FB1D3DC4592128F923781BE852 /* FClock.h in Headers */, + A0BA99A9C218794AE29315E27D045246 /* FCompleteChildSource.h in Headers */, + F43E7403F18847664D85B40C4B548801 /* FCompoundHash.h in Headers */, + 30A465DB1D908AF3A1D79C4FCB0BC837 /* FCompoundWrite.h in Headers */, + 8B60F24BB5A70BB9917F6CFE09910EE8 /* FConnection.h in Headers */, + 284B6D6F6370F71E42AEEAB66779B572 /* FConstants.h in Headers */, + BA7F42CD95B27BD397FF9D3C5E2DB084 /* FDataEvent.h in Headers */, + C61143E52DEA5930248C02F7D44FDBCE /* FEmptyNode.h in Headers */, + 1442DE70EF3D59599F5A0C08837389B5 /* FEvent.h in Headers */, + 7836A9112F980071C3771D7D999DE7C4 /* FEventEmitter.h in Headers */, + 61C65BF648375A8DF65199887BA1CC36 /* FEventGenerator.h in Headers */, + EA79854AD3918CA21E7420761A594DBC /* FEventRaiser.h in Headers */, + 6534652571843696A0F64F405498D430 /* FEventRegistration.h in Headers */, + D2578A9339552C39A0F02C5270FB1CFF /* FImmutableSortedDictionary.h in Headers */, + D534E5D3B33F23C23AC12827BB2E15D7 /* FImmutableSortedSet.h in Headers */, + 02DA238295776C954EDDF831D7027D24 /* FImmutableTree.h in Headers */, + 9E79B559377D95495396E828598C66AB /* FIndex.h in Headers */, + C046821A21D98EABE254E3F597C87976 /* FIndexedFilter.h in Headers */, + 6F93BBD384F487594C48556579A2E8ED /* FIndexedNode.h in Headers */, + 0C14DFEB59A69A6264B9F5AFB91565DF /* FIRAppCheckInterop.h in Headers */, + E60EA635FFB19BB7C38CA8D88E0CCFB2 /* FIRAppCheckTokenResultInterop.h in Headers */, + 3D57F293DE68AED8D0A21AC6D76A05EE /* FIRAppInternal.h in Headers */, + 5BECFA895A8912A75721584A238F04F7 /* FIRAuthInterop.h in Headers */, + C5D49AFCFB7FAFFDE26F4D088E92FB33 /* FIRComponent.h in Headers */, + 83128FD5CDA88B84C9E7C5F0CA0C68F4 /* FIRComponentContainer.h in Headers */, + 0F38CB49C51C49A6AFF68848C37B24DE /* FIRComponentType.h in Headers */, + FFA8772FA4A072B867456081598B8E9D /* FIRDatabase.h in Headers */, + 8487D1FF04DE63D5B5FBA89D3D5C6CD7 /* FIRDatabase_Private.h in Headers */, + D4D154F12A9508D4453FC2E0B1B2A3C1 /* FIRDatabaseComponent.h in Headers */, + EA03FC54A195BCAD5218701A5B904734 /* FIRDatabaseConfig.h in Headers */, + CBDB9BD5C1AD3C89C7FC98CE3E976CAF /* FIRDatabaseConfig_Private.h in Headers */, + CC404F5613533237A8782BCE33094619 /* FIRDatabaseConnectionContextProvider.h in Headers */, + 2F578C1D7FD3AEF6A55B5625D3502A61 /* FIRDatabaseQuery.h in Headers */, + EB586BD5D0A80F02EB2CE9F00D11E5C0 /* FIRDatabaseQuery_Private.h in Headers */, + F982C8D70D706DD41B1C47052126723E /* FIRDatabaseReference.h in Headers */, + D4C0E07416FD5F73DD67CB509AD491D1 /* FIRDatabaseReference_Private.h in Headers */, + 32F5FDC13D8F0F7B9D01D264D7D09D32 /* FIRDataEventType.h in Headers */, + BFECD5D79B67FEA725A2A2160D0D372A /* FIRDataSnapshot.h in Headers */, + 5700CD33EC84CEA20B9E8D458063882A /* FIRDataSnapshot_Private.h in Headers */, + 9AC52B23473AE7928D42958AA1841110 /* FIRDependency.h in Headers */, + C0A2D94BE8E64BD7092E214A3C6DC8F7 /* FirebaseCoreInternal.h in Headers */, + 780E30F358C54CC11BC53DEDA85BCDCE /* FirebaseDatabase.h in Headers */, + 352A47A6F158DBB01933867841790478 /* FirebaseDatabase-umbrella.h in Headers */, + 7A46E80C28977AA1EAC551BCEACBC631 /* FIRHeartbeatLogger.h in Headers */, + 18C6F896810D32D01B3208154D689CEF /* FIRLibrary.h in Headers */, + BF8A055237F1D258F87166BDF415E667 /* FIRLogger.h in Headers */, + 838BCB7118626D6D427E87BC53CDDD26 /* FIRMutableData.h in Headers */, + A3F8479F3A970E032D0A3E07C81EF3A7 /* FIRMutableData_Private.h in Headers */, + 6EE7668A320D637AD0788EFFFC8E1F67 /* FIROptionsInternal.h in Headers */, + C68AA3E3D27F09F3C65E95FE0FA9A773 /* FIRRetryHelper.h in Headers */, + E5C0EB38B4AB858401C362D87E78DB59 /* FIRServerValue.h in Headers */, + E00D22D438AA185BF358A07FF0E0BE19 /* FIRTransactionResult.h in Headers */, + D49F99D6E4662F4EE1194AF5CD9FDE5C /* FIRTransactionResult_Private.h in Headers */, + A6F389E893B67866C913A7CC967BE7EA /* FKeepSyncedEventRegistration.h in Headers */, + BE21697F0A9CCBFFD083CAB673468FFE /* FKeyIndex.h in Headers */, + 2E8BEF00344577175E9103DBF07FD880 /* FLeafNode.h in Headers */, + 2091B27B45767BE89BD047867367DF30 /* FLevelDBStorageEngine.h in Headers */, + E66B26493E5450BF72C07766E4B210D4 /* FLimitedFilter.h in Headers */, + 3CFB18B0527BA0AEE99AEF919724A524 /* FListenComplete.h in Headers */, + 540B40700F4D887009995777BE969707 /* FListenProvider.h in Headers */, + 01FCD91768C7B43218C3250882812F23 /* FLLRBEmptyNode.h in Headers */, + 6F4303D28697F0CD7593FD437D4AEED5 /* FLLRBNode.h in Headers */, + 55D159558CD752F60B91D48FD16B5B14 /* FLLRBValueNode.h in Headers */, + CA8BB025FB57BCC168A9AC80794CFA1D /* FMaxNode.h in Headers */, + 180BF9A8B4FB2EE3D1F2CB2F024F5F85 /* FMerge.h in Headers */, + 4DCA1C2000C8709D077527E34A1ACF55 /* FNamedNode.h in Headers */, + 266B77BE7D14531F8F80B830618A2322 /* FNextPushId.h in Headers */, + BE41A7861D927FA0B900D659EF81BDC9 /* FNode.h in Headers */, + B399D68CDF262A8E78D6F4085C479B9A /* FNodeFilter.h in Headers */, + BB4B91C245873ED03D924E22707518F0 /* FOperation.h in Headers */, + EBD66CD12254355FB20A1BA8DEABF253 /* FOperationSource.h in Headers */, + 2327507B9D5595050D98860F7CC24F63 /* FOverwrite.h in Headers */, + BB64E140F2511E1A201B5035D0D94FDA /* FParsedUrl.h in Headers */, + 0D79E35CEA44F0952C080D02E834339E /* FPath.h in Headers */, + DED8B9BA2D7639B05CA4AF45A83B4A3A /* FPathIndex.h in Headers */, + 869EF688D8253A7B5CE1B53198AED047 /* FPendingPut.h in Headers */, + A10C98239F7AF3C8A45A1F2A33B6038E /* FPersistenceManager.h in Headers */, + E96C247FA47305CECFF921819D6B1B32 /* FPersistentConnection.h in Headers */, + B2B29029DD1D746CE09B3E27066129F9 /* FPriorityIndex.h in Headers */, + 811E4C0162D96D681C927C81A56E8617 /* FPruneForest.h in Headers */, + 1A340BB5ECA742DF70E865839937A42A /* FQueryParams.h in Headers */, + 878F4B6FDC69E25ACF2DB1E1524B86D3 /* FQuerySpec.h in Headers */, + 2F4BC38B89616077E07A1672A9E23BEC /* FRangedFilter.h in Headers */, + E1592F441247C0469A674A0E0F738AF2 /* FRangeMerge.h in Headers */, + F7056900C929A66DE9C7C3709D538CF5 /* FRepo.h in Headers */, + 54D1FFB96451C7B3EB31FDAA8D1A93E3 /* FRepo_Private.h in Headers */, + CDB19F68F28169453D4C9D9161031D69 /* FRepoInfo.h in Headers */, + 2B11BFEC836C5038F4C1E58BD1A35FCE /* FRepoManager.h in Headers */, + 4A96408EC60E5F1D98C83BB0237A612F /* FServerValues.h in Headers */, + 5245FD7B67D000DD606C54FF58571B23 /* FSnapshotHolder.h in Headers */, + 1F2FE99E303BEDEE81468398721C5697 /* FSnapshotUtilities.h in Headers */, + 15998BE1E8E0F093D62A96474AA11256 /* FSparseSnapshotTree.h in Headers */, + 3DE45AD6C793FC5662B38765F089A571 /* FSRWebSocket.h in Headers */, + F7C7EB039AE633F1B5C99360FDEC4685 /* FStorageEngine.h in Headers */, + 7A19FB567C9E37705D6FED5A68EEA1F0 /* FStringUtilities.h in Headers */, + 13533801B7E1A587D45E709EB8BD6159 /* FSyncPoint.h in Headers */, + 9D86DDE6D19CD5509A5ECCF254ED3336 /* FSyncTree.h in Headers */, + E6B66B5094D16D6C2F439158E68F8453 /* FTrackedQuery.h in Headers */, + 3606144765DE64C83E8ABCF7769E9589 /* FTrackedQueryManager.h in Headers */, + A7D53C0DD6A4F8238BD524B8BD1D7A13 /* FTransformedEnumerator.h in Headers */, + 187595E76222B7A73977531CCC6E728E /* FTree.h in Headers */, + E5DC059D5B0285E2244EC66BC86D982D /* FTreeNode.h in Headers */, + E79D6DB4E78C4F31D33B529C12E3509E /* FTreeSortedDictionary.h in Headers */, + 3D16DDB8C9EBAD7CF2BEB2BF60F08ACC /* FTreeSortedDictionaryEnumerator.h in Headers */, + ECCD62448DCA613BA7D1125EF24669F2 /* FTupleBoolBlock.h in Headers */, + 59DBE5D4B7A5CE7E86AAE82D7B242964 /* FTupleCallbackStatus.h in Headers */, + 73494A7AA13DE730145715BB6C5026AC /* FTupleFirebase.h in Headers */, + EA43386142F3A4FA976A68C2D8F9AAEB /* FTupleNodePath.h in Headers */, + 1583014E980020AFC5FCFFA20E7E1589 /* FTupleObjectNode.h in Headers */, + 5FB06882FB3FFC654DCC1AE26110B315 /* FTupleObjects.h in Headers */, + 8B24E60ABEC3AB8D09B4524EECAA378E /* FTupleOnDisconnect.h in Headers */, + 4A509D1DADB51A3417913A34B8352F8C /* FTuplePathValue.h in Headers */, + 8ED70935C31DEC00D90FDA2DFFAE5A1B /* FTupleRemovedQueriesEvents.h in Headers */, + AD8FA6C3AF584A8AE1983BA729DF3A07 /* FTupleSetIdPath.h in Headers */, + C47C17432E9D7E48AA716B7B672DE9EC /* FTupleStringNode.h in Headers */, + 84DF7A56FB06C5B144AA1A22C2F6AD36 /* FTupleTransaction.h in Headers */, + 67937E2E8F7F37C6511383F05A56B941 /* FTupleTSN.h in Headers */, + 2BDA434ED438CA7501C58441AA8E58B3 /* FTupleUserCallback.h in Headers */, + 44C56B638B17F5B6DCB5FCD503D0174F /* FTypedefs.h in Headers */, + 0B9DC3C5A979E7BDF04CBCA3461FCFB9 /* FTypedefs_Private.h in Headers */, + C1CA135946CA13DF232F8101E13E7B9C /* FUtilities.h in Headers */, + B82F8A63C5DC9E69986D4EBA7E7F3876 /* FValidation.h in Headers */, + 9DA9A1427D2FBE2618C79F8F8ADEC9D9 /* FValueEventRegistration.h in Headers */, + 5609685AD9628CB2C95E0110E743CF9D /* FValueIndex.h in Headers */, + AE88A770938D3331DA56158D4149E829 /* FView.h in Headers */, + 16255205935C0EDAD6061E7DC422D451 /* FViewCache.h in Headers */, + 07DFFFA39382BF47F87F85F4060411C6 /* FViewProcessor.h in Headers */, + 38F29F91F5CDD2A7690A581BFB0567EE /* FViewProcessorResult.h in Headers */, + 7B10CA8D611210BC9AEEA70EE4059A35 /* FWebSocketConnection.h in Headers */, + EBD27DA186C47F37477C4D2FD98AB122 /* FWriteRecord.h in Headers */, + FC91692EEA460F6AB5A7258EE960ED7D /* FWriteTree.h in Headers */, + 7C0DC16B7C992AF9C7B3B9221CF12113 /* FWriteTreeRef.h in Headers */, + 875F9A299293C79C833F6A1968117299 /* NSData+SRB64Additions.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + CF0EA83F894208CF9D1B0228145A1659 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 3C7D6E44E8B2D1CAD761AE1E52A96E38 /* NSError+RLMSync.h in Headers */, + 928622B3D584F08FB48CCA5357562D6C /* Realm.h in Headers */, + E23E882A1005A1B0C8395A1AADE4A815 /* RLMAccessor.h in Headers */, + 802198BC371E8E13B62E61235B8BD084 /* RLMAPIKeyAuth.h in Headers */, + 8B88E5A9D0C57CCE176581D749719D1B /* RLMApp.h in Headers */, + 2AFC8AD2E5BE28E28D99F3377D847D05 /* RLMApp_Private.h in Headers */, + 67D409B2F1E6AAA495FBBD92F5C45E3F /* RLMArray.h in Headers */, + 21C58D39D595DB6E2522245782514F73 /* RLMArray_Private.h in Headers */, + 29B1483F501DE1434F01C5798A66B54F /* RLMAsymmetricObject.h in Headers */, + 7CEAC0F052AAFD79BEC81BF85E40C111 /* RLMAsyncTask.h in Headers */, + 0DE810456153ACAC87B26F587B903E75 /* RLMAsyncTask_Private.h in Headers */, + A75CCB280339D151D59272139672AEB3 /* RLMBSON.h in Headers */, + 9CAA1F8F766383E30D4E2EE96E394A9C /* RLMCollection.h in Headers */, + 72BF69AEEB29A843EC0088DFA55979C5 /* RLMCollection_Private.h in Headers */, + 5FAD38ED361CFAFC0E4AF120C95BA013 /* RLMConstants.h in Headers */, + C049DE1B6175B99E372E70DF1F9241AB /* RLMCredentials.h in Headers */, + EFDA49F8F77C6CA54BA1C56F73B76BF6 /* RLMDecimal128.h in Headers */, + 2B4F071A28E58BF95E34258DE39AD449 /* RLMDictionary.h in Headers */, + C3BAEF874A581AE9B3E5BF66D5E431E5 /* RLMDictionary_Private.h in Headers */, + 86CAE83EE76AFAD891FF538BF7E3F060 /* RLMEmailPasswordAuth.h in Headers */, + B5115253D4214741AB8DDBC2BF58E222 /* RLMEmbeddedObject.h in Headers */, + 5BDE98E505CAFDBCEED5C84E82F9958B /* RLMError.h in Headers */, + DC365FBBDC86092EDCF4B284E44FAB47 /* RLMEvent.h in Headers */, + B3D14EE8BE8A3F664067BCCEC7E5C843 /* RLMFindOneAndModifyOptions.h in Headers */, + 8577E7D27B4FAA529100D60E8FE6FCC9 /* RLMFindOptions.h in Headers */, + 812DE624EF12F8735C6AA3F521034C72 /* RLMLogger.h in Headers */, + 3E1BCE16271BB78E389F562A312BD2C5 /* RLMLogger_Private.h in Headers */, + D3AB2D43660D45764524F9D018835C2E /* RLMMigration.h in Headers */, + E74C6FF02E4A9B3DB2C9BFF991C7BBA6 /* RLMMongoClient.h in Headers */, + 3A05E4136818D9A738393A7C46D4EAFA /* RLMMongoCollection.h in Headers */, + 4DA78481AA044CB40BDB1AD282BA35B8 /* RLMMongoCollection_Private.h in Headers */, + 15EAD31ACB9B27C3A1193121331E7579 /* RLMMongoDatabase.h in Headers */, + 0632B4C782BDE709D2E6D3F430584653 /* RLMNetworkTransport.h in Headers */, + 5CC62BA3C946FBC25A11AB5778675995 /* RLMObject.h in Headers */, + D81B797CD2571F21D720DC21E87360F6 /* RLMObject_Private.h in Headers */, + 60C0157E685DD1F2BAF7D7E47E5FC8F4 /* RLMObjectBase.h in Headers */, + 97BE95E381B9FDACEE58261D36045A21 /* RLMObjectBase_Dynamic.h in Headers */, + 6B78FBCD579F9C61B65E8B50D8EDD439 /* RLMObjectBase_Private.h in Headers */, + FB82B31BA1AFC627C65F9764A7094C8B /* RLMObjectId.h in Headers */, + 37CDF5442F766E20BD807E2265C6EF55 /* RLMObjectSchema.h in Headers */, + BA057835099158FDFDA0C1F7A35C289F /* RLMObjectSchema_Private.h in Headers */, + 605323DEC358BEE719E4D52B3627DACA /* RLMObjectStore.h in Headers */, + F4610C06DBF2174D4B20830E6F9E7618 /* RLMPlatform.h in Headers */, + EADF5AC8B74DD5106820523572EE7506 /* RLMProperty.h in Headers */, + 84C69069142A72AF88B4BB8994E7679B /* RLMProperty_Private.h in Headers */, + 940B828B191381F6A1A9D40902364630 /* RLMProviderClient.h in Headers */, + 643A7722C9C5049ED385CD61C0D2C74C /* RLMPushClient.h in Headers */, + 23E3887CC08BDC547463047B858849BE /* RLMRealm.h in Headers */, + 947AE0004C53D32999ECEC79204D2FE1 /* RLMRealm+Sync.h in Headers */, + 5145A069D3AD0759F1133EFCB5313C00 /* RLMRealm_Dynamic.h in Headers */, + D2BA7AE944BA6CFCFC0A39048D9BB707 /* RLMRealm_Private.h in Headers */, + BB0E71EF9840588153CB86879EAAAEE3 /* RLMRealmConfiguration.h in Headers */, + 355D95383A9CE3130A45726FC2EEF811 /* RLMRealmConfiguration_Private.h in Headers */, + 270305E8D407E8059D9FFD2D9565DAF6 /* RLMResults.h in Headers */, + 43DEA604571EA56BDD9171DE48C65DB3 /* RLMResults_Private.h in Headers */, + 521B7AF46A4DA8F73C0FCE98A8652410 /* RLMScheduler.h in Headers */, + C46AC4E9C3E597F9900ED4D12F934F3B /* RLMSchema.h in Headers */, + 4E3873B890396CA5576DEADB4D8DA616 /* RLMSchema_Private.h in Headers */, + 2B66A4B70C36AA4D0DBED20183E3EB4F /* RLMSectionedResults.h in Headers */, + CCF6E8E0CC2205BF731C033CF4AA6810 /* RLMSet.h in Headers */, + 6937D13B8FF8AB3A213A5DF4E9219D47 /* RLMSet_Private.h in Headers */, + 200F9D45C92F76E4D7BCDD330FF456D5 /* RLMSwiftCollectionBase.h in Headers */, + 6AE773CDC43873AD079E95360A32A284 /* RLMSwiftObject.h in Headers */, + A664E8B743AE58614C1043A9D353359E /* RLMSwiftProperty.h in Headers */, + 3D730C9DC0E969B8CB05CD83179E0E24 /* RLMSwiftValueStorage.h in Headers */, + 7B3830BF34B0CD961AFEABBA5A353A30 /* RLMSyncConfiguration.h in Headers */, + 75A82B4A272F013FEF4657F458C9C529 /* RLMSyncConfiguration_Private.h in Headers */, + 4C3A971EFC4B51F07BF7A2C487073D4D /* RLMSyncManager.h in Headers */, + 876BA4C97CB5877A759607A404CCDCE3 /* RLMSyncSession.h in Headers */, + D48DBD7232BDC3A01578CD4E7D5C95BC /* RLMSyncSubscription.h in Headers */, + 27D9F773AB09ACEA1463B46594D36905 /* RLMSyncSubscription_Private.h in Headers */, + DDC1FB1EB139826C6FF10FCB2E91947A /* RLMThreadSafeReference.h in Headers */, + A6A5E3C4226D1666D8D40D598EBCFA47 /* RLMUpdateResult.h in Headers */, + 0D980C39895D93AE95B64B87D9D05FA7 /* RLMUser.h in Headers */, + 6F37A41886CA7FFFBA8576AEF58E2D6F /* RLMUser_Private.h in Headers */, + 1A41A84E600185E54A9D4A3FFD5177BC /* RLMUserAPIKey.h in Headers */, + 7ABA215D32B0D02167C6FB4BDBDE3398 /* RLMValue.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D486FF348850A9BC90B4B01A5AB90CD3 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + D2D06F2A49CC6BA3F7425EE460E0EE87 /* FIRAnalyticsConfiguration.h in Headers */, + 90AF3C42D8F7E3B51C7CE7A5DC2C3407 /* FIRApp.h in Headers */, + C5ED69C4AA8BF6199DAF2C2BCABBA12F /* FIRAppInternal.h in Headers */, + D42931C1B9778BAE429EB1D3BA1325BF /* FIRBundleUtil.h in Headers */, + A2235A3B04B2347E27E03A400BDA8F67 /* FIRComponent.h in Headers */, + B94C1066CCFE8D7C8B902DED4BE9FCE1 /* FIRComponentContainer.h in Headers */, + 21A191B2DC557588618AF79120F64B45 /* FIRComponentContainerInternal.h in Headers */, + 1E43DE43BBB68B7F97D958FFE0D6361C /* FIRComponentType.h in Headers */, + 7213E5E3F75461A35E62B98665FED91D /* FIRConfiguration.h in Headers */, + 1E5410EFB9924CC9454BDA535D3F4DEA /* FIRConfigurationInternal.h in Headers */, + 0C9C133167200A1AC793C5B4F01B2ED8 /* FIRDependency.h in Headers */, + DFB24E24E3F25F5D5F990BF040C8D4DC /* FirebaseCore.h in Headers */, + 5DECDE1DDD458F2D47F8C641C638E348 /* FirebaseCore-umbrella.h in Headers */, + F4E7ECDDA22430555FED5B6B5A48CBE6 /* FirebaseCoreInternal.h in Headers */, + 4368C42C4F53C03122E577AC4A39A34C /* FIRFirebaseUserAgent.h in Headers */, + A9805E610FDB0C5C030851F00172CE23 /* FIRHeartbeatLogger.h in Headers */, + 8563FB6F9023EA1647E0D89264455498 /* FIRLibrary.h in Headers */, + 1DAF869CDE6189F9FA50BC1288038DB4 /* FIRLogger.h in Headers */, + 90F5214A87703025030C79659166F248 /* FIRLoggerLevel.h in Headers */, + E5B93B9B88365818621927C4E207BBCE /* FIROptions.h in Headers */, + 02328FAFA4CAC5A88D871C0D4281062A /* FIROptionsInternal.h in Headers */, + 1F8482568311E5D193A3655C8C67F53D /* FIRVersion.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + DC71FE0FDB969777B51B0289B766D675 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 58DE67C18F2A1D9FE9418218F72B7757 /* Pods-PRTYTests-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EFC77448D212B12D96230FF242364CF3 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 10382ACB48A8FA82118A649D3A8979DC /* arena.h in Headers */, + AD7BCAB6BE202FF2D009E7E088E3DEC0 /* block.h in Headers */, + A921770EBECAFB9A3BF11619955F6491 /* block_builder.h in Headers */, + 32D55723E434E34412EE79D3ED27F36C /* builder.h in Headers */, + 0FDAF73F04F6DBF0ABD393BDE2CC4651 /* c.h in Headers */, + 5B0D2E37D013049C4FDCDF690DA1AEA9 /* cache.h in Headers */, + 89B7946331B18912484080D3D5650838 /* coding.h in Headers */, + E7B3B7A549F8566E5D2F59B0FE2020C0 /* comparator.h in Headers */, + 04A77BA00EE781F8B02B69EDBB61E959 /* crc32c.h in Headers */, + 9F4D180B838B06FAB57B4062BDACAC16 /* db.h in Headers */, + F2012DF27E5CCA5800F11829AC6C06D1 /* db_impl.h in Headers */, + 13E9FAFB711C21EDFDE915E77BC98076 /* db_iter.h in Headers */, + 64487BBCCACB841B1DAF3A8FD45CE1C7 /* dbformat.h in Headers */, + 753A9063781468314E5535FA51D18770 /* dumpfile.h in Headers */, + 66E2AA64199527717DA5CA9F0703ABF4 /* env.h in Headers */, + 4E6803BAEBD925222351FE9B6885F3DC /* env_posix_test_helper.h in Headers */, + 8944B8D4A577AF297043ABF9977D7F7B /* env_windows_test_helper.h in Headers */, + 839E07D95440A3F636BE770B0DAB0338 /* export.h in Headers */, + BD2957E94F11BC2656255B32ED9A4937 /* filename.h in Headers */, + B0BD0D34D2B49C6F6AF6709C5CD3D2A4 /* filter_block.h in Headers */, + 108EDC903235587BF65B92ECC17761BA /* filter_policy.h in Headers */, + C8E2336FEDA5BACB621022D61C185B66 /* format.h in Headers */, + 945A33542D7BDB6356AA2442B6601CA6 /* hash.h in Headers */, + E6F7A6A7B2EFBD2AD51F53960EB8E530 /* histogram.h in Headers */, + 01C75D80D822B72FE13911FF8BBBA934 /* iterator.h in Headers */, + 82336698B7047F4B03FD0A754CE1F0CF /* iterator_wrapper.h in Headers */, + 2726B73C90D07E3FC35D1EABAF7B68D1 /* leveldb-library-umbrella.h in Headers */, + 56D6E3DB181AF1B10B1893736E4DE442 /* log_format.h in Headers */, + 4BC450BD29DA1B1F0A6393E89BCAEF67 /* log_reader.h in Headers */, + 57F7C783C5CC5A1BEFFF5ECC67792080 /* log_writer.h in Headers */, + 4826009A120992E817EFAE9BD91E5E8C /* logging.h in Headers */, + 589E4C484F651A492FBB935FBF740DEB /* memtable.h in Headers */, + 4E05FA1B2E051ADC104673E3740280D6 /* merger.h in Headers */, + B625F27E68B1BC1194572B6E3FD04F8B /* mutexlock.h in Headers */, + 93BCB3BA76BFD984CA350338DDD1B5AD /* no_destructor.h in Headers */, + 0C912F4D2C555B0D7F78D176F4595827 /* options.h in Headers */, + C070A4BC082AEC327BDB69A965E55AF8 /* port.h in Headers */, + 2F3EDA73AAD29A88A95922DCC6404CF1 /* port_example.h in Headers */, + EC81C960F707C65ACA0D26A4658C15CB /* port_stdcxx.h in Headers */, + 0EBA9EA5EDC9B05CAC03D6A3C8340BA7 /* posix_logger.h in Headers */, + 41E257B3BE577D173F85A8527E26BDB2 /* random.h in Headers */, + AABB04026DDE6C037FF7496D6B47EBFB /* skiplist.h in Headers */, + B0DB6A1D468D898FFF34AB95A7323CC1 /* slice.h in Headers */, + C7E0AE69B6132CFC359AC4CA35CAC927 /* snapshot.h in Headers */, + 7E869C45F0B7BBA5DC477008646C53E8 /* status.h in Headers */, + 657FA1B537040FA0900273E09DACF02A /* table.h in Headers */, + F81B60944AA404D3DC3B198B886EC053 /* table_builder.h in Headers */, + 1C0679E65CDB66E90C07A50D045635FC /* table_cache.h in Headers */, + F4E23CC44884A30B093B217992E074CD /* testharness.h in Headers */, + 8F7E464A2CB88BF555C24CEA466463E1 /* testutil.h in Headers */, + 6554025CC0DAA62DA09B3C2E06896D90 /* thread_annotations.h in Headers */, + 86B8E81017D9B71A3C2D750A26EE3943 /* two_level_iterator.h in Headers */, + 01E38B9CF9813D66B186AAEED4868E4D /* version_edit.h in Headers */, + BF6874BB68C6E5D4386E78B11A4E45DA /* version_set.h in Headers */, + 04CD6531A0F2CD57CD074175471F18B7 /* windows_logger.h in Headers */, + F0B910E4767D4E42AB5BD44A08FCDB6E /* write_batch.h in Headers */, + B1FF1AF7078C2A4114FAD6976C4B1E57 /* write_batch_internal.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 25E9E9A17BC3F670357D7385C521E48E /* FirebaseCoreInternal */ = { + isa = PBXNativeTarget; + buildConfigurationList = AC64B97F43C4BCE84E89B8268FE95E5B /* Build configuration list for PBXNativeTarget "FirebaseCoreInternal" */; + buildPhases = ( + 4EBE0D77C5B4468AD813EF39DF88DF05 /* Headers */, + 5247680F11155F1D19CE08DFF2E5F5E1 /* Sources */, + 6E361B2041194F74C98AD11E96544DAA /* Frameworks */, + 8F743370BB354EED4CBFA3EA278F8983 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 7781D1A853CFF5B95ECEF15333106B3B /* PBXTargetDependency */, + ); + name = FirebaseCoreInternal; + productName = FirebaseCoreInternal; + productReference = 148D0F9E8C7373FEAF40D800FC5F1BAA /* FirebaseCoreInternal */; + productType = "com.apple.product-type.framework"; + }; + 2BBF7206D7FAC92C82A042A99C4A98F8 /* PromisesObjC */ = { + isa = PBXNativeTarget; + buildConfigurationList = 2E73F4C2B5A4B9C40BAE58F7EEDC3DCB /* Build configuration list for PBXNativeTarget "PromisesObjC" */; + buildPhases = ( + 3CB635D5FCA00D7AE71640B07796B6D3 /* Headers */, + DA858220231C82A6847539E26E824855 /* Sources */, + F792F1D276BD794CD5F439902C0136EC /* Frameworks */, + 338BCA529BA415086531B514BE9F8A3A /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = PromisesObjC; + productName = FBLPromises; + productReference = 3347A1AB6546F0A3977529B8F199DC41 /* PromisesObjC */; + productType = "com.apple.product-type.framework"; + }; + 4402AFF83DBDC4DD07E198685FDC2DF2 /* FirebaseCore */ = { + isa = PBXNativeTarget; + buildConfigurationList = 2855B05178AD62797D0BF666C343D36F /* Build configuration list for PBXNativeTarget "FirebaseCore" */; + buildPhases = ( + D486FF348850A9BC90B4B01A5AB90CD3 /* Headers */, + D765C8B133300FCAA82F70EF2ECAB17E /* Sources */, + 071EE1B3E3E99FF4FA7150A43B1FD1BF /* Frameworks */, + 5E8722C64275812C68FE7AFCF7BCA2BE /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 68CC63C8AE203A24235298262F25EB10 /* PBXTargetDependency */, + 7CA54BB6A25BCEAEA46B61CAE5587B05 /* PBXTargetDependency */, + ); + name = FirebaseCore; + productName = FirebaseCore; + productReference = E2B63D462DB7F827C4B11FD51E4F8E2D /* FirebaseCore.framework */; + productType = "com.apple.product-type.framework"; + }; + 529E88BEF546B07BF299A1A026C8E512 /* Pods-PRTY-PRTYUITests */ = { + isa = PBXNativeTarget; + buildConfigurationList = DC8173BDD7FF6F3046B2E35AEE71BA95 /* Build configuration list for PBXNativeTarget "Pods-PRTY-PRTYUITests" */; + buildPhases = ( + BD7485A9A3C8A3584D1A4143701351D2 /* Headers */, + 30BC68F352378C1FF538B3E8007FD521 /* Sources */, + 64DDE5ED426839C4A4CD9BBB3F8667B7 /* Frameworks */, + FC4B199657FDE81B92D39111779BCB37 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + D421120D8554F8E12EBB40B20881A853 /* PBXTargetDependency */, + D30677DEBACD4A079A03CAAF5A39ABA6 /* PBXTargetDependency */, + 50C022351001704DBD141972C64C0B3B /* PBXTargetDependency */, + 0F4757955A504ECAE388CC5BE81056AE /* PBXTargetDependency */, + F1A9A9C4F8CA487C39BA2B767D511D1E /* PBXTargetDependency */, + 6C2008F54C753B8AEC9A08F9921CF356 /* PBXTargetDependency */, + 1757F2FA1AAEF6A9C441BC669EFBDF6B /* PBXTargetDependency */, + A37CC460FA4A05863FE7CEFD2CA5D5D7 /* PBXTargetDependency */, + B4EB3D3BEA15B52C67D5D4094E386A77 /* PBXTargetDependency */, + DFC7E744966BEF08AF267D354C09B45B /* PBXTargetDependency */, + FDC1FF1FA32C278B2CC15847FF80833A /* PBXTargetDependency */, + 818C3FA3CBC90DD1217FB6C02B0560A9 /* PBXTargetDependency */, + 3C75B2CC8950641BCADC7487D21B9A16 /* PBXTargetDependency */, + 93E004BDD77E2CD8D4D958CEDBEAAD40 /* PBXTargetDependency */, + 96B0396DD423ED13C7FB4FFF8DDAFE6F /* PBXTargetDependency */, + 299F18F46115C72594F32E746E9260EA /* PBXTargetDependency */, + ); + name = "Pods-PRTY-PRTYUITests"; + productName = Pods_PRTY_PRTYUITests; + productReference = C0691B5031307C17D3FEEF999A793420 /* Pods-PRTY-PRTYUITests */; + productType = "com.apple.product-type.framework"; + }; + 68494F30B4A13F8E5E88BCCAEC25B0A4 /* Realm */ = { + isa = PBXNativeTarget; + buildConfigurationList = A13B4C93C7094E3C86F1FDE75AB90123 /* Build configuration list for PBXNativeTarget "Realm" */; + buildPhases = ( + CF0EA83F894208CF9D1B0228145A1659 /* Headers */, + A7251DEEB84017C53E839EE10B835C9C /* Copy . Private Headers */, + C285DFF620C646030E5EBD6B526878CD /* Copy . Public Headers */, + FA354BE48FD7369D54CB7B3158C363DE /* [CP] Copy XCFrameworks */, + D323A3910196AA573884E8DC3B9FB113 /* Sources */, + AB17B442E310F969D961119F667BBCDF /* Frameworks */, + 2CFFC25BEBFE4B6448D588D6FAAB9DF8 /* Resources */, + 9F85DAA4D8E084370376F52F354B2BA8 /* Create Symlinks to Header Folders */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Realm; + productName = Realm; + productReference = 921BE4A82C4A7A5C72A0C6F8B8FEF200 /* Realm */; + productType = "com.apple.product-type.framework"; + }; + 6AE4A3D573DED275B034E20506596C62 /* FirebaseAuth */ = { + isa = PBXNativeTarget; + buildConfigurationList = E5F7DF13DDEFD7ACEEE70AB494CD3E05 /* Build configuration list for PBXNativeTarget "FirebaseAuth" */; + buildPhases = ( + AEB75B39C942BBC857AF16E21F008F81 /* Headers */, + D5A620A5F495FC64A17F189D2516D358 /* Sources */, + D000DBC103B489E923B003778C7B14DD /* Frameworks */, + 5D7D0001A7BAA52B64CD4FCD68504CCA /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 8B5C692A01CB61AB3EF650B1581F8BC5 /* PBXTargetDependency */, + 132B0D4551FC783FFD3097D68DF4D8E3 /* PBXTargetDependency */, + 417FACEC67AA54B817EA5A446C6ACB84 /* PBXTargetDependency */, + 2F8A9E9BE393C38D6BFA3AB6D119FF50 /* PBXTargetDependency */, + ); + name = FirebaseAuth; + productName = FirebaseAuth; + productReference = 43B1E4CD7B30B9FD278100133C2AC788 /* FirebaseAuth */; + productType = "com.apple.product-type.framework"; + }; + 6EB67D63E9CBABC9495A7C2F928737F2 /* Pods-PRTY */ = { + isa = PBXNativeTarget; + buildConfigurationList = 2E588B50D62583B18B24E582537EBB3B /* Build configuration list for PBXNativeTarget "Pods-PRTY" */; + buildPhases = ( + CBA49643794F86DECF4DC16E0322BCC9 /* Headers */, + 5749B727B15BE526D5DFC1737D71DC3A /* Sources */, + DEE84CA9EAA4386062CD2008F64940DF /* Frameworks */, + D30AD35E1032616180146C5176BA8E13 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 692C74FE9B172EF43008D8ED4DFC8652 /* PBXTargetDependency */, + B469E89D00D7BE78CA71249120F70241 /* PBXTargetDependency */, + B65705DCE9634C91886C9F80D9E9854C /* PBXTargetDependency */, + 4DF413C704E60FEFBA90A369758F1887 /* PBXTargetDependency */, + 155B559C9378F5E0535C8CEAAD0FB999 /* PBXTargetDependency */, + 55ECF6B64FA55364FD2FF47FA4725459 /* PBXTargetDependency */, + 7BBC1F663124F70FBDBA94CCA30E6069 /* PBXTargetDependency */, + 7D5BD7A59B4C1592668B39269A6D3599 /* PBXTargetDependency */, + 4E0DA9400274EC15070258528BABC95A /* PBXTargetDependency */, + BAB1B8936EE33F3B3881CB3D669D5137 /* PBXTargetDependency */, + 7A137EA28E4BB4A749ADBC90F4B620A5 /* PBXTargetDependency */, + 49E9B79D46C6BF9329EEDE0EC4840589 /* PBXTargetDependency */, + 158099800731E6A2843DE293A6DF05E2 /* PBXTargetDependency */, + 5F295AE2ECA94FC42D49CE9382B5016B /* PBXTargetDependency */, + 30FDD3B599E5911258641BF8E872EE1A /* PBXTargetDependency */, + 5B3F4AC1DB067B920B86D301F8586D97 /* PBXTargetDependency */, + ); + name = "Pods-PRTY"; + productName = Pods_PRTY; + productReference = 578E1B6E76DDE67CFCDF713FC4016967 /* Pods-PRTY */; + productType = "com.apple.product-type.framework"; + }; + 736AF68F6527ACF6B4A4C54728824A1C /* FirebaseDatabase */ = { + isa = PBXNativeTarget; + buildConfigurationList = 55DB65357524849130CCE7F4329350CA /* Build configuration list for PBXNativeTarget "FirebaseDatabase" */; + buildPhases = ( + CCA73A9FF8AE128D14D92AA9ACEE5DB0 /* Headers */, + 89EB07CB900B66C02E3225906EF3DF18 /* Sources */, + 9E443E8BEE4172A9850FFA0559E7A752 /* Frameworks */, + 525C1E1C5ABC4E70C7BEF6CF248C0214 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 6DDD5FE0D9098A9F8F5AA20684E020B7 /* PBXTargetDependency */, + 4468DA3D7E6E8FC052A2F65CAF2727C7 /* PBXTargetDependency */, + ); + name = FirebaseDatabase; + productName = FirebaseDatabase; + productReference = 51671C73F008B5C0C3751B3855999213 /* FirebaseDatabase */; + productType = "com.apple.product-type.framework"; + }; + 782725687624F8665247B84AB581BEB1 /* RealmSwift */ = { + isa = PBXNativeTarget; + buildConfigurationList = 47354ADB1930A2E9F4E3E91AAD1FE58A /* Build configuration list for PBXNativeTarget "RealmSwift" */; + buildPhases = ( + A581BE0E16E4FCE52E9519A091628842 /* Headers */, + 7E19C03913F3D1CB2F7603740B976F22 /* Sources */, + 4B55B4F3E8454CE936EFB8DD56D259F3 /* Frameworks */, + BC161F0D64F6CD4690D014D8E20E3BDD /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 281F7A03D7628007DF7F542A79C0DAC0 /* PBXTargetDependency */, + ); + name = RealmSwift; + productName = RealmSwift; + productReference = 437919EE08EC6BFCCBAC3BD346309742 /* RealmSwift */; + productType = "com.apple.product-type.framework"; + }; + 87803597EB3F20FC46472B85392EC4FD /* FirebaseInstallations */ = { + isa = PBXNativeTarget; + buildConfigurationList = EC3EBC32F26CF0150F071F37032496AE /* Build configuration list for PBXNativeTarget "FirebaseInstallations" */; + buildPhases = ( + 2656B555E4AD56D6153C7CAA000A9E22 /* Headers */, + A92DD21F0E5CF4BC77F40FAADF0A5F9A /* Sources */, + E9DFB23A694E518DE4BE1017CA0DCD4F /* Frameworks */, + DCD47CE1726FE68C385F01BC57FD2854 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 9D8FDBCDA70255AC2F71E45491AE2973 /* PBXTargetDependency */, + E5DB5B4BCB3F94126F6BE409F2216CE1 /* PBXTargetDependency */, + 4C5DD9E123B972A158AF253768B93583 /* PBXTargetDependency */, + ); + name = FirebaseInstallations; + productName = FirebaseInstallations; + productReference = 13C8C8B254851998F9289F71229B28A2 /* FirebaseInstallations */; + productType = "com.apple.product-type.framework"; + }; + 8D7F5D5DD528D21A72DC87ADA5B12E2D /* GoogleUtilities */ = { + isa = PBXNativeTarget; + buildConfigurationList = C62BEA7CAAEC1D2DABBE4A1FC9F75FB6 /* Build configuration list for PBXNativeTarget "GoogleUtilities" */; + buildPhases = ( + 2EDCC5FB1525478D139B5503AEB98F96 /* Headers */, + 0D3FCCE646B28E244D72A1A3698695C3 /* Sources */, + 5EFA40AE9BADE8E7281A0412BDA9F7F0 /* Frameworks */, + 7974A7FCC9E21265EB020985EA8332B0 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 5FF71D0AF92B42C7AFA1BBED9382F714 /* PBXTargetDependency */, + ); + name = GoogleUtilities; + productName = GoogleUtilities; + productReference = B43874C6CBB50E7134FBEC24BABFE14F /* GoogleUtilities */; + productType = "com.apple.product-type.framework"; + }; + 9307B7A119490930CF70393AB529AAC1 /* leveldb-library */ = { + isa = PBXNativeTarget; + buildConfigurationList = D40D167B127A50CE651D70AF63382772 /* Build configuration list for PBXNativeTarget "leveldb-library" */; + buildPhases = ( + EFC77448D212B12D96230FF242364CF3 /* Headers */, + 3715CA3B6B9EE99D064B2C36184C82D9 /* Sources */, + 82879856A592A25C292B176A5AB030D0 /* Frameworks */, + 678E6BA5562C5CAB8DD4F156F0BF8D0F /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "leveldb-library"; + productName = leveldb; + productReference = 0A9F46A999C47653013D3AD854352507 /* leveldb-library */; + productType = "com.apple.product-type.framework"; + }; + A3BF0BB6444EC30779EBCC2951266E58 /* Pods-PRTYTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 3B337C9C6CA2E899D2250ACACB574378 /* Build configuration list for PBXNativeTarget "Pods-PRTYTests" */; + buildPhases = ( + DC71FE0FDB969777B51B0289B766D675 /* Headers */, + BBB4075EF780F447FD07401829CDCDAE /* Sources */, + C7C79E124E4AD37F94AF8DAC500707A8 /* Frameworks */, + B0B315E13892C4D2C4339F62C918E612 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 4C294EC2211BC25057989F9AA2F72608 /* PBXTargetDependency */, + ); + name = "Pods-PRTYTests"; + productName = Pods_PRTYTests; + productReference = 0843F6B3C59457C07E690F4E361631E0 /* Pods-PRTYTests */; + productType = "com.apple.product-type.framework"; + }; + D2B5E7DCCBBFB32341D857D01211A1A3 /* nanopb */ = { + isa = PBXNativeTarget; + buildConfigurationList = E81670CAD096B4447BC3A704B9D0CCEE /* Build configuration list for PBXNativeTarget "nanopb" */; + buildPhases = ( + 3C24ABE3A93849D4620B2849C03B52D6 /* Headers */, + 65097535AFBD36CE07E08721EDB1A964 /* Sources */, + F505E157D5DF02FB5B4365D1BA590C5C /* Frameworks */, + 88721B61631FB1E00D85FAF9ED4E7CA0 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = nanopb; + productName = nanopb; + productReference = 06FC5C9CF96D60C50FCD47D339C91951 /* nanopb */; + productType = "com.apple.product-type.framework"; + }; + D676E21115185671D7258A56944ABE98 /* GTMSessionFetcher */ = { + isa = PBXNativeTarget; + buildConfigurationList = 15AA93CF5F4D00C188CA7354B47DB2A8 /* Build configuration list for PBXNativeTarget "GTMSessionFetcher" */; + buildPhases = ( + BC1CA4BE9E11C654BC2BD71A39EA1E3C /* Headers */, + F88E3A34DA55EDCAF90F98F31891F840 /* Sources */, + B155D1DA6355EBA45AFCDC214898F661 /* Frameworks */, + 5AC7A1A9A1DFBF7F8E3BC89757D45E78 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = GTMSessionFetcher; + productName = GTMSessionFetcher; + productReference = C1998E0D8085221AD87F89B614C10E52 /* GTMSessionFetcher */; + productType = "com.apple.product-type.framework"; + }; + DD28B439BE8B17D9339D9B526F144347 /* FirebaseAppCheckInterop */ = { + isa = PBXNativeTarget; + buildConfigurationList = E1BA027A65D078933D0CEA8ACE53EE28 /* Build configuration list for PBXNativeTarget "FirebaseAppCheckInterop" */; + buildPhases = ( + 9DB7BADC3E77EA6ED5B4CD3D33B96C23 /* Headers */, + B080529307DA28876436C8EB76D2E251 /* Sources */, + A9C9AA8374FC0D6A8CD0E483218E8362 /* Frameworks */, + ECB05F69414972185C8AC88C4939C9A7 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = FirebaseAppCheckInterop; + productName = FirebaseAppCheckInterop; + productReference = 81418C93A311F0492F62A8F88C3BD66B /* FirebaseAppCheckInterop.framework */; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + BFDFE7DC352907FC980B868725387E98 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1300; + LastUpgradeCheck = 1430; + }; + buildConfigurationList = 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */; + compatibilityVersion = "Xcode 14.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + Base, + en, + ); + mainGroup = CF1408CF629C7361332E53B88F7BD30C; + productRefGroup = 8A9C7D1D8625C2A874F22BA6059BAE01 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 072CEA044D2EF26F03496D5996BBF59F /* Firebase */, + C49E7A4D59E5C8BE8DE9FB1EFB150185 /* FirebaseAnalytics */, + DD28B439BE8B17D9339D9B526F144347 /* FirebaseAppCheckInterop */, + 6AE4A3D573DED275B034E20506596C62 /* FirebaseAuth */, + 4402AFF83DBDC4DD07E198685FDC2DF2 /* FirebaseCore */, + 25E9E9A17BC3F670357D7385C521E48E /* FirebaseCoreInternal */, + 736AF68F6527ACF6B4A4C54728824A1C /* FirebaseDatabase */, + 87803597EB3F20FC46472B85392EC4FD /* FirebaseInstallations */, + B53D977A951AFC38B21751B706C1DF83 /* GoogleAppMeasurement */, + 8D7F5D5DD528D21A72DC87ADA5B12E2D /* GoogleUtilities */, + D676E21115185671D7258A56944ABE98 /* GTMSessionFetcher */, + 9307B7A119490930CF70393AB529AAC1 /* leveldb-library */, + D2B5E7DCCBBFB32341D857D01211A1A3 /* nanopb */, + 6EB67D63E9CBABC9495A7C2F928737F2 /* Pods-PRTY */, + 529E88BEF546B07BF299A1A026C8E512 /* Pods-PRTY-PRTYUITests */, + A3BF0BB6444EC30779EBCC2951266E58 /* Pods-PRTYTests */, + 2BBF7206D7FAC92C82A042A99C4A98F8 /* PromisesObjC */, + 68494F30B4A13F8E5E88BCCAEC25B0A4 /* Realm */, + 782725687624F8665247B84AB581BEB1 /* RealmSwift */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 2CFFC25BEBFE4B6448D588D6FAAB9DF8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 338BCA529BA415086531B514BE9F8A3A /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 525C1E1C5ABC4E70C7BEF6CF248C0214 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5AC7A1A9A1DFBF7F8E3BC89757D45E78 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5D7D0001A7BAA52B64CD4FCD68504CCA /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5E8722C64275812C68FE7AFCF7BCA2BE /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 678E6BA5562C5CAB8DD4F156F0BF8D0F /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 7974A7FCC9E21265EB020985EA8332B0 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 88721B61631FB1E00D85FAF9ED4E7CA0 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8F743370BB354EED4CBFA3EA278F8983 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B0B315E13892C4D2C4339F62C918E612 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BC161F0D64F6CD4690D014D8E20E3BDD /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D30AD35E1032616180146C5176BA8E13 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + DCD47CE1726FE68C385F01BC57FD2854 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + ECB05F69414972185C8AC88C4939C9A7 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FC4B199657FDE81B92D39111779BCB37 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 83B95425D2BD5BA4375FA7E7ABB6BD93 /* [CP] Copy XCFrameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/GoogleAppMeasurement/GoogleAppMeasurement-xcframeworks-input-files.xcfilelist", + ); + name = "[CP] Copy XCFrameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/GoogleAppMeasurement/GoogleAppMeasurement-xcframeworks-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/GoogleAppMeasurement/GoogleAppMeasurement-xcframeworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 9F85DAA4D8E084370376F52F354B2BA8 /* Create Symlinks to Header Folders */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Create Symlinks to Header Folders"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "cd \"$CONFIGURATION_BUILD_DIR/$WRAPPER_NAME\" || exit 1\nif [ ! -d Versions ]; then\n # Not a versioned framework, so no need to do anything\n exit 0\nfi\n\npublic_path=\"${PUBLIC_HEADERS_FOLDER_PATH#$CONTENTS_FOLDER_PATH/}\"\nif [ ! -f \"$public_path\" ]; then\n ln -fs \"${PUBLIC_HEADERS_FOLDER_PATH#$WRAPPER_NAME/}\" \"$public_path\"\nfi\n\nprivate_path=\"${PRIVATE_HEADERS_FOLDER_PATH#$CONTENTS_FOLDER_PATH/}\"\nif [ ! -f \"$private_path\" ]; then\n ln -fs \"${PRIVATE_HEADERS_FOLDER_PATH#$WRAPPER_NAME/}\" \"$private_path\"\nfi\n"; + }; + F1FD9E30F1BAAA93D028A88FBEB9E90F /* [CP] Copy XCFrameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/FirebaseAnalytics/FirebaseAnalytics-xcframeworks-input-files.xcfilelist", + ); + name = "[CP] Copy XCFrameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/FirebaseAnalytics/FirebaseAnalytics-xcframeworks-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/FirebaseAnalytics/FirebaseAnalytics-xcframeworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + FA354BE48FD7369D54CB7B3158C363DE /* [CP] Copy XCFrameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Realm/Realm-xcframeworks-input-files.xcfilelist", + ); + name = "[CP] Copy XCFrameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Realm/Realm-xcframeworks-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Realm/Realm-xcframeworks.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 0D3FCCE646B28E244D72A1A3698695C3 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 6C8114A52703DCCBD717A2C65AD5E69C /* GoogleUtilities-dummy.m in Sources */, + C07A83B6F8272719F207BAE2E077D573 /* GULAppDelegateSwizzler.m in Sources */, + 1A5DBDF8EC79DB739D6F6333801E6E7D /* GULAppEnvironmentUtil.m in Sources */, + 80A205DB9FAF20A0C8A635E28A6D167B /* GULHeartbeatDateStorage.m in Sources */, + C5344851C80D3EB6EC78C422351D1862 /* GULHeartbeatDateStorageUserDefaults.m in Sources */, + 36EAF66821BFB428D34426904FA4CED6 /* GULKeychainStorage.m in Sources */, + DDCC2DC2EEC342615590DEBF5899BCEC /* GULKeychainUtils.m in Sources */, + 5D8F3549757CF9CC44FB0D55347EC1E0 /* GULLogger.m in Sources */, + CB72164F55028933140BF6E03EC064D1 /* GULMutableDictionary.m in Sources */, + 3E501C4D318CD0E51008FFEBB5786936 /* GULNetwork.m in Sources */, + 15A2E78F986153130CC782DE70297984 /* GULNetworkConstants.m in Sources */, + 6F2488447014917CC4AAF15465543EA3 /* GULNetworkInfo.m in Sources */, + 063AEAC2993E1F7E50141FF96012FCBC /* GULNetworkURLSession.m in Sources */, + 1D959CCB6684555C4421436045A397B8 /* GULNSData+zlib.m in Sources */, + F1D9094B4F5304543CCF8B7134C4CDD9 /* GULReachabilityChecker.m in Sources */, + 3B728B444B95692D159372CD8462A19A /* GULSceneDelegateSwizzler.m in Sources */, + 9EB707DA936F64F9FE7139226B5EA01A /* GULSecureCoding.m in Sources */, + B8B47B601574BA7BBFD029157CA4E628 /* GULSwizzler.m in Sources */, + 04255801699620ACD92B0118549C4F6B /* GULURLSessionDataResponse.m in Sources */, + 5FCCD637451B4362B20EF5C1DF4FE27D /* GULUserDefaults.m in Sources */, + F9D55B925CB1E274C7E86DADED3C9006 /* NSURLSession+GULPromises.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 30BC68F352378C1FF538B3E8007FD521 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5F8A63633E05A9E7B34F5D31A8989574 /* Pods-PRTY-PRTYUITests-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 3715CA3B6B9EE99D064B2C36184C82D9 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 813F3F1E791272CFF8A1F4A11E041408 /* arena.cc in Sources */, + 50D4D65EE4C1B4EDB3D8B2AA68B1A01D /* block.cc in Sources */, + 4832A53F299328B249B42F6C13641B38 /* block_builder.cc in Sources */, + A4BB95BC9251977B0A08075C77AA9DC3 /* bloom.cc in Sources */, + 7636F152E8794F10E4A36E2753703115 /* builder.cc in Sources */, + DB7950971D2B42CFF36F27EECF3821A7 /* c.cc in Sources */, + F94984129D6304129EE220C872F865B4 /* cache.cc in Sources */, + 30370665ED1ABB8568DDEC0A31B1D441 /* coding.cc in Sources */, + 35CE3B95660A62605924372F4F2161FC /* comparator.cc in Sources */, + 8EFC7D5B421515836B695F56A2729CFF /* crc32c.cc in Sources */, + C5322C26D74065EC41562C9EEBF78150 /* db_impl.cc in Sources */, + 905BFD0510C4C0ED5C97B3864A25E5B4 /* db_iter.cc in Sources */, + 201D4EB6D2A2AE8B478AAF3D905349FF /* dbformat.cc in Sources */, + 52BB88609ECD059EBB11D6B25FD1E313 /* dumpfile.cc in Sources */, + 90DF05CC96171E8108A83697467E39C4 /* env.cc in Sources */, + 6A3CF6C2BF8B0291E6EDE3A1DD05B00A /* env_posix.cc in Sources */, + F75854BE6F0E74A60701E844DFFBC597 /* filename.cc in Sources */, + 437CCE734A37C465BF1C06785DA8AB4B /* filter_block.cc in Sources */, + 6E09FC0722B6BBC771CD1C26DD93B664 /* filter_policy.cc in Sources */, + F5C2EF7AC1CA47FE84C3356B7467849E /* format.cc in Sources */, + 846A31A1003204664D2D37D032DF4D79 /* hash.cc in Sources */, + BBE799CAF8880799CDEEDBA765FFC7CA /* histogram.cc in Sources */, + F03F8775698CB7D3BE31C481977C771B /* iterator.cc in Sources */, + 42166693E19EE0C7271C40B2D97DC71A /* leveldb-library-dummy.m in Sources */, + E8CDC21A1379922EFEA8922958C76451 /* log_reader.cc in Sources */, + 8DF9BFFC1C27B66DF18D7A1A77B20A66 /* log_writer.cc in Sources */, + 312CA68E22F5BAF8D5BB7F0538FED1CB /* logging.cc in Sources */, + 34A7A9C91800828112A8B3AF6B36D8CE /* memtable.cc in Sources */, + C2BDB75DB8DF24B7F2A588E64FBCC466 /* merger.cc in Sources */, + D2173B9C59F3ED7A67431C3AC53CBDBC /* options.cc in Sources */, + 978D74F5AFBE1950843BE1748E2E6BF6 /* repair.cc in Sources */, + 9774D25AD742E9273057E0F008F3830C /* status.cc in Sources */, + 07C276C1C2CA802328111B82EC042276 /* table.cc in Sources */, + C6C6AA35F49FCFA34BEF41CFFDD7ACFB /* table_builder.cc in Sources */, + 176C194122DABDA7F7F2F4F3767E9808 /* table_cache.cc in Sources */, + 18774A6239D9CE2E626517CA92D04E8F /* testharness.cc in Sources */, + 3B74BA9E808626DD2C5906054F55A87C /* two_level_iterator.cc in Sources */, + B30F3599D78D2A3A0344C528972F6A5B /* version_edit.cc in Sources */, + 85660B253CFD7166CDEDE73C9CB1E992 /* version_set.cc in Sources */, + A25122EB1C1C87A2AE4F62F9ECE66DCB /* write_batch.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5247680F11155F1D19CE08DFF2E5F5E1 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8634EB48AFD69C6F560107A205C95B48 /* _ObjC_HeartbeatController.swift in Sources */, + B8751E3FB95E013FB515F455EB018E83 /* _ObjC_HeartbeatsPayload.swift in Sources */, + 00617798FE5A15909C04A310A21147FF /* FirebaseCoreInternal-dummy.m in Sources */, + CFAF28FE3DFEB84A1862B6CCEAE64B88 /* Heartbeat.swift in Sources */, + 8FA126ECD66FB79D079893AA823C9575 /* HeartbeatController.swift in Sources */, + 486464C1D84C601D5ABFC53920E4B959 /* HeartbeatLoggingTestUtils.swift in Sources */, + 2AB3F88542B7A1594C161DF518EA7A09 /* HeartbeatsBundle.swift in Sources */, + 7346BD05A5E330BD6C4B7DEAB82A087E /* HeartbeatsPayload.swift in Sources */, + 6B28A1F6364323D6F1EE3B59DB3A2B3E /* HeartbeatStorage.swift in Sources */, + B26EE4F4E233857BC1A9B1CDFE66657D /* RingBuffer.swift in Sources */, + CB44D8EE576BFF2CCC5176F139A86EE2 /* Storage.swift in Sources */, + 4E09CC3E7BFB08BF1D4E9C22246B5114 /* StorageFactory.swift in Sources */, + 108C00BBD7DB265FE04674D64F825F96 /* WeakContainer.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5749B727B15BE526D5DFC1737D71DC3A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + DD2B25557D1C5C7198184E033C9F5E78 /* Pods-PRTY-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 65097535AFBD36CE07E08721EDB1A964 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 70EA9C51B91189AC304E612F4998C52D /* nanopb-dummy.m in Sources */, + 4FB8F7A00DAC6A8C59492FAA33A6F33A /* pb_common.c in Sources */, + D9DFEE8BBB15E18235DBA274639050DF /* pb_decode.c in Sources */, + 57FA026564E61B5A7C007FE2B748A227 /* pb_encode.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 7E19C03913F3D1CB2F7603740B976F22 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 39EA99A31B37C65E005202F18FBB2782 /* Aliases.swift in Sources */, + 2E9DCF5DE252DD97076AFC91842225CF /* AnyRealmValue.swift in Sources */, + 682649CEC1CA3CFF6F01C692754E53D5 /* App.swift in Sources */, + B785E35AE212C2CB4C4CD0D84C49B90D /* AsymmetricObject.swift in Sources */, + BF5352E6A21E27DB879C2189155F17EA /* BasicTypes.swift in Sources */, + 3F5DC8E1E4127053A92C72E08D27F5D8 /* BSON.swift in Sources */, + DE9AC4D1B35C9E07B979930D5C0B38DF /* CollectionAccess.swift in Sources */, + B59E22971F8D4CE5681BF67535A363F7 /* Combine.swift in Sources */, + 8A9025AE4A9232EF04AAFFA2EEA1416F /* ComplexTypes.swift in Sources */, + 3E036CAA97F279B0C6ABD859726A047A /* CustomPersistable.swift in Sources */, + 5B8A458DC7C87F427A5C463F3CAC517B /* Decimal128.swift in Sources */, + 7AA5D2ED28C6B278DB39BC615D38ED5B /* EmbeddedObject.swift in Sources */, + FE7FC652161CB9CBDDBA9E5BE3397011 /* Error.swift in Sources */, + 8BD86B5E5C4D9040FF6F940A7DDE5B5E /* Events.swift in Sources */, + 0442CEDEA4243DD8629F664272A285DE /* KeyPathStrings.swift in Sources */, + 1CA0567A035870C832DE6060E1C348A1 /* LinkingObjects.swift in Sources */, + DC1CC94EA95338783CD4596CF2882942 /* List.swift in Sources */, + 781671C9525101E2C5AC80A6C3DF54C6 /* Map.swift in Sources */, + 752C7184ED4531729174293BFC7AF6E7 /* Migration.swift in Sources */, + ABD61BF538B0440B014502E121AD906D /* MongoClient.swift in Sources */, + B837F9BAA1E321E18780F3B8903BC004 /* MutableSet.swift in Sources */, + D9D8EA266CD7C5885464952BC9B2678D /* ObjcBridgeable.swift in Sources */, + F3117B7CBCA74424D090B0911C96DC89 /* Object.swift in Sources */, + C11339074CE5C4A8DF75384CCC987B77 /* ObjectId.swift in Sources */, + 2C7492344C6598F8514582D5B34F6956 /* ObjectiveCSupport.swift in Sources */, + BBCE391F1AC55EFC2A589E550ACCC1B6 /* ObjectiveCSupport+AnyRealmValue.swift in Sources */, + 868EC2D6F5E462D6EC55BCAA99DA1848 /* ObjectiveCSupport+BSON.swift in Sources */, + 5F0A29426B5289CE22EE51AFE0A28775 /* ObjectiveCSupport+Sync.swift in Sources */, + F80CCCEBF9794DC3E8B4EEB8FAAA2D0B /* ObjectSchema.swift in Sources */, + AAD9FDCF7389C0EFE67CCD5B9BAF3115 /* Optional.swift in Sources */, + 13B5FCEFE1051075D694B06BD6345BB2 /* Persistable.swift in Sources */, + AFFEB160C9DAC32478B61FCCED14535B /* PersistedProperty.swift in Sources */, + 5A112F8271072DE73024CBA8078043AA /* Projection.swift in Sources */, + 609EB115EBE2C1BB25EE2FF2EE67A4BD /* Property.swift in Sources */, + 6FC16F5639926D99A63C51C6AB855C2D /* PropertyAccessors.swift in Sources */, + 07F261922769AA1165299B51787D22D6 /* Query.swift in Sources */, + A2D241953E4F2DA88EEC3CED7DEDF8B1 /* Realm.swift in Sources */, + B4EE276AF7CB12ED9DB48318D8914C2B /* RealmCollection.swift in Sources */, + 1E563604E3C43CD98D2CFC150359E536 /* RealmCollectionImpl.swift in Sources */, + 1059F6E4C81D4442F9A0443E56682D22 /* RealmConfiguration.swift in Sources */, + FE2F13D80F1F4B8A605390C3399EF3AD /* RealmKeyedCollection.swift in Sources */, + B46E52EDBD14DEA140A5EE7F128F7D70 /* RealmProperty.swift in Sources */, + 56040CFFA72105E3B95C1D44A8AAD299 /* RealmSwift-dummy.m in Sources */, + 06304E80795DA749417F68A31C6A4D74 /* Results.swift in Sources */, + 58C96277ECC03358ED0A472DA23F3F53 /* RLMSupport.swift in Sources */, + 8C42A7A9022BBAFCF982F250E3A7500D /* Schema.swift in Sources */, + 71ED8B725658B0D3E35D4B72106BC615 /* SchemaDiscovery.swift in Sources */, + 79DF5164542097A87970D857C22688FD /* SectionedResults.swift in Sources */, + 1AE31850261F971BBAE81FA9859C5DBE /* SortDescriptor.swift in Sources */, + 876EE37947934409808939990FBC28D7 /* SwiftUI.swift in Sources */, + 3E1B5386B32268FA87A5B13C81242612 /* Sync.swift in Sources */, + 3EEB5CD0432AE4C966A336FE407F4564 /* SyncSubscription.swift in Sources */, + CCD1C585CE4E9DBE15769F38E06842C2 /* ThreadSafeReference.swift in Sources */, + E34B80A9A8B49857FCD043CAE44D1EC0 /* Util.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 89EB07CB900B66C02E3225906EF3DF18 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 49EB428C817FA945F9BB6A3995F73FFF /* APLevelDB.mm in Sources */, + D30A9B44711199CA00581A2201414536 /* FAckUserWrite.m in Sources */, + 4C9439E7A3507B105C4BB4707F0E7334 /* FArraySortedDictionary.m in Sources */, + 1044D7EB9FFD66F58378B57517E41EFE /* FAtomicNumber.m in Sources */, + FF13FD276737DDB7385A0E9C635991F7 /* fbase64.c in Sources */, + 585DFEF219F029D15010CD641EF535F8 /* FCacheNode.m in Sources */, + 4A449CBD996AF1DD78CA968B1EA4898B /* FCachePolicy.m in Sources */, + 37938C045A4BF24A92E0C73970A55CCC /* FCancelEvent.m in Sources */, + 7CC2243707E36C7D6999E039DFB5B218 /* FChange.m in Sources */, + C2ADDCDFD0B92BEEC6D449000FB4882E /* FChildChangeAccumulator.m in Sources */, + A8B023366D664D7D355BF2F5B7970DEF /* FChildEventRegistration.m in Sources */, + A6AC4CEAEC8C92DC44FD5692E5CFF9F0 /* FChildrenNode.m in Sources */, + A811DDDB0D93AEFA12BAF266B214D115 /* FClock.m in Sources */, + E3B3840EAB0F5AAE1FFCEB635A2B5121 /* FCompoundHash.m in Sources */, + C67E939C044C8C6A96A7F913403D7D12 /* FCompoundWrite.m in Sources */, + 7032415E7E58896C284DAE637501C451 /* FConnection.m in Sources */, + B51D7F506DFEA060C1CB741903F75CF8 /* FConstants.m in Sources */, + BED9922AAC7CEE176632814E91E88EE3 /* FDataEvent.m in Sources */, + FA0D3093DDC70715973905B191D740CA /* FEmptyNode.m in Sources */, + FD69336AE1B542C200DA412FF326EC11 /* FEventEmitter.m in Sources */, + 263E861581658DF48841CD38DE090E27 /* FEventGenerator.m in Sources */, + 992B6529BBC99C3FDFA09AEEA0621D39 /* FEventRaiser.m in Sources */, + 8EAB6FC18913E8F2528C2B1A94A2678B /* FImmutableSortedDictionary.m in Sources */, + 966C504495609E40E3EAF21EE23244FB /* FImmutableSortedSet.m in Sources */, + FC74AFA3716766723E2B0239EAD3E274 /* FImmutableTree.m in Sources */, + 1020D1695BBA61AE0FCA0561BA37C4F5 /* FIndex.m in Sources */, + 9E55EC0DF4903FAF9A23AFFB105AAE54 /* FIndexedFilter.m in Sources */, + AF4E7917DEE0C2E522FF4A32FFB50CB7 /* FIndexedNode.m in Sources */, + 96BC606C6F0FE863C7994163F10D96EB /* FIRDatabase.m in Sources */, + 9B012A8F604FAA865C6F47354D4E8577 /* FIRDatabaseComponent.m in Sources */, + 04E85FDCD1BF5720CAE73C11B9DECA10 /* FIRDatabaseConfig.m in Sources */, + 2C476F4F273960B86AC4FB592BC004D6 /* FIRDatabaseConnectionContextProvider.m in Sources */, + 05D13830C0296C1BC8EED51A2C8AC790 /* FIRDatabaseQuery.m in Sources */, + 8BF7C00E7B596F069966DB2F0DA0B308 /* FIRDatabaseReference.m in Sources */, + 99B62D32054FE258375BCDD48305CF93 /* FIRDataSnapshot.m in Sources */, + B284929F06F08C99A8A41B3C444E005F /* FirebaseDatabase-dummy.m in Sources */, + 2389325BD1515692FCF0905C00D4D8A0 /* FIRMutableData.m in Sources */, + 633CB270D7455590E3E9E7C0BB61BA0E /* FIRRetryHelper.m in Sources */, + 1B3BCA0AEE5AC15E825670A550338EEF /* FIRServerValue.m in Sources */, + FB2A314ECB8499A987353600D006BDF2 /* FIRTransactionResult.m in Sources */, + 7212BE09C35F4BD336F79AFBC24874A4 /* FKeepSyncedEventRegistration.m in Sources */, + A717A83405C484FDE5A4D037892343FC /* FKeyIndex.m in Sources */, + F8E864A9944D645898FEDF5C14BBA609 /* FLeafNode.m in Sources */, + 609DC9E302A653DA56687D5C92A1CF52 /* FLevelDBStorageEngine.m in Sources */, + 8C5D76997AA50A03C0507ABE81B8EA90 /* FLimitedFilter.m in Sources */, + D646F95EC5C99A8C2FB7BB15F8EC6557 /* FListenComplete.m in Sources */, + 3D3A8614FAF4D83BF0F47714E011D9EE /* FListenProvider.m in Sources */, + C31C9FA5FD979162E48E1D3972872173 /* FLLRBEmptyNode.m in Sources */, + F2BD51600D0A5C24260E09ADDF39BF65 /* FLLRBValueNode.m in Sources */, + 0DA668730ACF231E73644A814D74A957 /* FMaxNode.m in Sources */, + 2838AAEA623CEB269148E955BDD4CE93 /* FMerge.m in Sources */, + 269D36571B40B60D117D163D7B87597B /* FNamedNode.m in Sources */, + 5A1109D02A51716B3DC2E37A3FC5632E /* FNextPushId.m in Sources */, + 6D3B7C2BF20A55C9D460151D79439BEE /* FOperationSource.m in Sources */, + 7158EE753AFBCD149B1110FAEF2E6DCF /* FOverwrite.m in Sources */, + 5C7234476A52BF7C290A0A4395E1CE65 /* FParsedUrl.m in Sources */, + BD13356B7C0CAB0D612190773C0480A4 /* FPath.m in Sources */, + F776D3E140166311A001DB9FC98853A1 /* FPathIndex.m in Sources */, + 5E1FC2F73D8BCC5F49BA87CD68F27737 /* FPendingPut.m in Sources */, + 009D232C1C36C96BAAD1C29F8D70776D /* FPersistenceManager.m in Sources */, + 6FB22426B2EB8D375C6730C6742B1133 /* FPersistentConnection.m in Sources */, + 5B5A896DEF606171FF5CD8478E3129F2 /* FPriorityIndex.m in Sources */, + 6B1F6C00D9884BD500BD80BA0A8B562A /* FPruneForest.m in Sources */, + 15C622DC1904FBD6FB918B7832172CEF /* FQueryParams.m in Sources */, + 2F0B5B4DE3359F3E1EFCBA5955134B94 /* FQuerySpec.m in Sources */, + D82059120A48162DA564D2E2D50DBDEB /* FRangedFilter.m in Sources */, + D8455788A35E4CF431E52B2F7EB76AC0 /* FRangeMerge.m in Sources */, + 7FF8B428E990D7D592F65F6EFBE7D222 /* FRepo.m in Sources */, + 6167C40443525D692BA386E55620DD14 /* FRepoInfo.m in Sources */, + EF029687EE62CFF7A201138A9A961A2E /* FRepoManager.m in Sources */, + 7C41C73363E436830C727DE77EAAE9E4 /* FServerValues.m in Sources */, + B784F4B4A2325A1F719961C174067AE6 /* FSnapshotHolder.m in Sources */, + B3769095DE70D4998B1F2E1A54B058E7 /* FSnapshotUtilities.m in Sources */, + 229802FCEB7A418CD2C5103658823BAA /* FSparseSnapshotTree.m in Sources */, + 94CA0E83F2B89D06241D54A94058B6D5 /* FSRWebSocket.m in Sources */, + 0A538E60675F1A4A8520BBB3F6A9308C /* FStringUtilities.m in Sources */, + 9B91307547BEDA714941231459B7A8C0 /* FSyncPoint.m in Sources */, + 9D52E14C4FE9CA72CC28383D5BD51546 /* FSyncTree.m in Sources */, + EFE5E6AC5BB761FB55261A9D992293D8 /* FTrackedQuery.m in Sources */, + 865ABE450423382E3C18852BA9B78BD8 /* FTrackedQueryManager.m in Sources */, + FFACC2D38CD2693E59AA2CE0C74B2B33 /* FTransformedEnumerator.m in Sources */, + 186B723BA9635B8C2A44DA292E12B770 /* FTree.m in Sources */, + 2DE2E901B48A92BBEEC0DA9F0AC58643 /* FTreeNode.m in Sources */, + 9D927CE9C76B13599666AE9A345525F3 /* FTreeSortedDictionary.m in Sources */, + 4F51C722E3194985A2C961E89366F2F2 /* FTreeSortedDictionaryEnumerator.m in Sources */, + DD6533A9C97BB1393002A7590E2B70F2 /* FTupleBoolBlock.m in Sources */, + D5530F56A633ED858516420DDC785BA5 /* FTupleCallbackStatus.m in Sources */, + 70665A637908A34422AEA93EED2F7BDF /* FTupleFirebase.m in Sources */, + 174FB4CA96ABA27CC7B3F3D233C7458E /* FTupleNodePath.m in Sources */, + 0E9AF13F9D3A60B0D9CEECBFE24B4F16 /* FTupleObjectNode.m in Sources */, + ABDBC17D9DAC3AB0815997E4EBF8DF34 /* FTupleObjects.m in Sources */, + 9AD0B4DB3C43A0B34DED85DED855CE09 /* FTupleOnDisconnect.m in Sources */, + 6C584A75762A7121616EEAEEABA54280 /* FTuplePathValue.m in Sources */, + CC0A2E0CC16606F7F9FED89017360DF6 /* FTupleRemovedQueriesEvents.m in Sources */, + 603AB74B5E67811B4D03346CA6FBCADD /* FTupleSetIdPath.m in Sources */, + 39BC691EE1B9EC37E1F6E5FAD28EDD4B /* FTupleStringNode.m in Sources */, + BE0802B7354FC89221F4366ECDD35398 /* FTupleTransaction.m in Sources */, + A3337A425F2D7098E8E0FF8C7D54A556 /* FTupleTSN.m in Sources */, + 1C292460A5B87AD8C4248AF11B9BADD5 /* FTupleUserCallback.m in Sources */, + 555CCCBC50108665AC9117CDB6F576E2 /* FUtilities.m in Sources */, + 8328BB1B08B1B7D0DCC2C75EE9F36EAB /* FValidation.m in Sources */, + 0FEC32864EB9E4825B82766A0968B455 /* FValueEventRegistration.m in Sources */, + 38A7CFB28A653498AC76B3DBD8E872C3 /* FValueIndex.m in Sources */, + 9680102310967F59CA76AF4B0301A138 /* FView.m in Sources */, + B9420B1AEF7A229BE322D42494F6A4AD /* FViewCache.m in Sources */, + 917BC551095B7D467693400C1981BC58 /* FViewProcessor.m in Sources */, + DB9C97512B77301DAB4399FFC26933CC /* FViewProcessorResult.m in Sources */, + 949E867236FB69DBCA105E66DFD437A1 /* FWebSocketConnection.m in Sources */, + 0F624737C8B25492C886BFC1CC5115E5 /* FWriteRecord.m in Sources */, + DFEC3309D6492AD8DDE0516E83A3F5D5 /* FWriteTree.m in Sources */, + 3532C2D4D8F7DE7C4B6028B2533DE424 /* FWriteTreeRef.m in Sources */, + EBD59139C3F995AC17309B4FF3F32751 /* NSData+SRB64Additions.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + A92DD21F0E5CF4BC77F40FAADF0A5F9A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5CA3A6BE0C3058AFF6CB3EA559809BAF /* FIRCurrentDateProvider.m in Sources */, + D0E5286861360BCB4F7DEB39F5FB9D19 /* FirebaseInstallations-dummy.m in Sources */, + 6A7947EDEF0FD4A230501DEEBA20B426 /* FIRInstallations.m in Sources */, + 479B60053A3DD2352139C5F4438BA674 /* FIRInstallationsAPIService.m in Sources */, + F10EE87B15A28BECC7142627D6CA4BA1 /* FIRInstallationsAuthTokenResult.m in Sources */, + 5337561978B91F1E3E2D06222FD818CA /* FIRInstallationsBackoffController.m in Sources */, + B4D51CF0EB25677858925A7E23D6344E /* FIRInstallationsErrorUtil.m in Sources */, + ECF384925EB148C037CD4A9EF2366163 /* FIRInstallationsHTTPError.m in Sources */, + 267D4C41BB1B461358E2BB57169328F9 /* FIRInstallationsIDController.m in Sources */, + 27110206EA54BA318491514F1E5AC600 /* FIRInstallationsIIDStore.m in Sources */, + E8F1FDCEE4DAC3658676B3BD4CCA4DF7 /* FIRInstallationsIIDTokenStore.m in Sources */, + FAA41046BC0FD7DA7F16B3C094B7C7A4 /* FIRInstallationsItem.m in Sources */, + A1D05B2080062B9F5FE73C57D34B1BF1 /* FIRInstallationsItem+RegisterInstallationAPI.m in Sources */, + 848F464B8D76264AAB71B6E9809DD130 /* FIRInstallationsLogger.m in Sources */, + 03CDC8C7A3DD78EB4A71480159F2EDD2 /* FIRInstallationsSingleOperationPromiseCache.m in Sources */, + 4658CF4DF9D5266AFD60AD5B08CDD9FD /* FIRInstallationsStore.m in Sources */, + 74BB146F22D7FF85888EF332589FC2E1 /* FIRInstallationsStoredAuthToken.m in Sources */, + FE81A9DEF16D478E586D05E003497B10 /* FIRInstallationsStoredItem.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B080529307DA28876436C8EB76D2E251 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 9671A6738BEE91011FDC3399A96B431A /* dummy.m in Sources */, + 39ED90D10209900AD8F48B6673062030 /* FirebaseAppCheckInterop-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BBB4075EF780F447FD07401829CDCDAE /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 21CFD2B6DC3E36215D9BCC8158B2CAEE /* Pods-PRTYTests-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D323A3910196AA573884E8DC3B9FB113 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 30AE109E466587FB7257790E9FB5E4EB /* NSError+RLMSync.m in Sources */, + EC4C9EB9A74BB5447000582F572A5356 /* Realm-dummy.m in Sources */, + 54F62BCFBC519F4FD6C42F437664AC6E /* RLMAccessor.mm in Sources */, + 73FE3010502203A12B08BBE54C8E2055 /* RLMAnalytics.mm in Sources */, + F646D4658110406F996A48C0B448FAB7 /* RLMAPIKeyAuth.mm in Sources */, + B787C57C3EF4635A72E630ACD6F40BA3 /* RLMApp.mm in Sources */, + 17ACA929F7991E272C9A70302E8F470D /* RLMArray.mm in Sources */, + 14730F31F1DC012AF4075208DE6B99C3 /* RLMAsymmetricObject.mm in Sources */, + 5CD7BEA809F7A6459BE94B7FB8E4E220 /* RLMAsyncTask.mm in Sources */, + 122FB696FFF548CC3C300271E3C85852 /* RLMBSON.mm in Sources */, + DD8584CBD50A0A5628C32118683454B3 /* RLMClassInfo.mm in Sources */, + FA8FA0E3B86B3F7A1E20213EF3344C0E /* RLMCollection.mm in Sources */, + 59A212C68AC67FFFE1BBFFA322B06CEB /* RLMConstants.m in Sources */, + E11EC38CFBC70683F81F2858E8F10439 /* RLMCredentials.mm in Sources */, + 21133EAD7666F99E72CB375C737B5F84 /* RLMDecimal128.mm in Sources */, + DA143FCE1DF739C0493449CE4BA33D7E /* RLMDictionary.mm in Sources */, + 328F275F96233AC46D18AE4FC60269F2 /* RLMEmailPasswordAuth.mm in Sources */, + 7441914D0D9C68B7F20C77230326D22B /* RLMEmbeddedObject.mm in Sources */, + BEDF46F72C441F3549090A88F01DD917 /* RLMError.mm in Sources */, + 1EDCB680A779A00F4F6662BE40051FFD /* RLMEvent.mm in Sources */, + D9EDB119313CA2168485F0024FD98B6C /* RLMFindOneAndModifyOptions.mm in Sources */, + 0F4B1CDC7A0FBF93D3CF6DE9E5120356 /* RLMFindOptions.mm in Sources */, + 29F00DB50FF8AA7AD4FCD36D00B6AF5A /* RLMLogger.mm in Sources */, + 2E6AA9AEB8C9A11A88CCC93D3678124D /* RLMManagedArray.mm in Sources */, + F74EB5E9CFAC4748D7780350953B940C /* RLMManagedDictionary.mm in Sources */, + CB735F99DCB6A60A24E6B7C4F3BFD674 /* RLMManagedSet.mm in Sources */, + 4866194CFA963278423EAB19CF0919EB /* RLMMigration.mm in Sources */, + 482EAA47E185193C33011CB530672D66 /* RLMMongoClient.mm in Sources */, + 81172B43F338ED500082F2E012C1CE3B /* RLMMongoCollection.mm in Sources */, + 47E84DE98A0BCA4869BB30F4E00A4213 /* RLMNetworkTransport.mm in Sources */, + 1C94C778746A9747B0C9300710ABFF00 /* RLMObject.mm in Sources */, + 3FBC587410256792D44C22FE350580B7 /* RLMObjectBase.mm in Sources */, + CF1CA992D8E849D8E071EC1134DB762E /* RLMObjectId.mm in Sources */, + 848BB8E075B1AE26528D06BBDB2BB918 /* RLMObjectSchema.mm in Sources */, + A1BC422359DF11ED2C7B3FE4C5214942 /* RLMObjectStore.mm in Sources */, + 5964B58BB046CB6CCD8E511CBCAEA80E /* RLMObservation.mm in Sources */, + 69DFDFF0AF88E04E100B31F3B8232C0D /* RLMPredicateUtil.mm in Sources */, + C2BE5C95EDF2CE6BC335C709D6E44067 /* RLMProperty.mm in Sources */, + BD58FB4CADE9D1D06BAA8E61127892D1 /* RLMProviderClient.mm in Sources */, + 282B9343DCF3A93E1B5FB83297B1B56F /* RLMPushClient.mm in Sources */, + 9EE4B196ADC91A640E2948C889DE2C2D /* RLMQueryUtil.mm in Sources */, + AF19A4C6CAE1776A211A41FA60B74540 /* RLMRealm.mm in Sources */, + BB4561A2ED45CC603872EDC873FEA6C1 /* RLMRealm+Sync.mm in Sources */, + 790A45A6460CBFA52D094D0D5656D86D /* RLMRealmConfiguration.mm in Sources */, + 5805F658F32743DE99FEAB6A6F4A21D9 /* RLMRealmUtil.mm in Sources */, + 94019D9BAB6F218A17B853C14ABFA29C /* RLMResults.mm in Sources */, + 0CD9B5FD1CDE92219291ED4E89CC768F /* RLMScheduler.mm in Sources */, + AA5F2686F0E973FBAC628822736DCF5A /* RLMSchema.mm in Sources */, + C88EEA9C29E546AD0D04EE06B3113BDF /* RLMSectionedResults.mm in Sources */, + 1E75EC8BC9F736D1C338F9D1F9EAFC7A /* RLMSet.mm in Sources */, + C49F41A0E496C24E4146A289BC043389 /* RLMSwiftCollectionBase.mm in Sources */, + 1B758413CB8C82D2C26A49A1DF222B4B /* RLMSwiftSupport.m in Sources */, + C277A58F5843B31AB8F166E7E342194C /* RLMSwiftValueStorage.mm in Sources */, + E51FC18B468CA4DB966243C9DB3A6B91 /* RLMSyncConfiguration.mm in Sources */, + CFDA1E348801BB27D286CF747AAF3187 /* RLMSyncManager.mm in Sources */, + D7F425B8A1234098B7CAB015B96896FD /* RLMSyncSession.mm in Sources */, + 313FC85C8B36FDF89836E2BF03CFF5C0 /* RLMSyncSubscription.mm in Sources */, + D42E8EF287DF8D1299662DCD8D2592ED /* RLMSyncUtil.mm in Sources */, + 6DC739B4759D5679D631B2297D2618B6 /* RLMThreadSafeReference.mm in Sources */, + 3652FD94A1EDA7EC5CE3D584EDEEEB53 /* RLMUpdateChecker.mm in Sources */, + DC70FCD19F37D5A2AF1C1FAD1771F031 /* RLMUpdateResult.mm in Sources */, + 2A31970FF0E9775502FDAD1367C9A8C3 /* RLMUser.mm in Sources */, + 76826B9B18013A5F61252F19CF86402D /* RLMUserAPIKey.mm in Sources */, + A2510B92AFE46DCBC196E0E40550856B /* RLMUtil.mm in Sources */, + 1C7518A96589FAC93583DA08463ACD30 /* RLMUUID.mm in Sources */, + 8D204A8354310BC2EC1FEAB676241A2D /* RLMValue.mm in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D5A620A5F495FC64A17F189D2516D358 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 9881252194046087CFD77E71E63721A1 /* FIRActionCodeSettings.m in Sources */, + A173A3BC99B9C858CECE483B60C57951 /* FIRAdditionalUserInfo.m in Sources */, + 864E5DB771C48AA0E2B10853506C779F /* FIRAuth.m in Sources */, + A17CA87BA5842902B638DEE5BFEB2EE2 /* FIRAuthAPNSToken.m in Sources */, + 25A2FDE3446D76FAC5F9DA3D4E0A1F08 /* FIRAuthAPNSTokenManager.m in Sources */, + AB4928353201F4B67A73A0880CA939BC /* FIRAuthAppCredential.m in Sources */, + 30BC5B49C4B53971EA7F8689DDF5C8D7 /* FIRAuthAppCredentialManager.m in Sources */, + F025CF81C5FDDDAC6BD6D31CD9458D18 /* FIRAuthBackend.m in Sources */, + AC5C0A72839F72F5CBB97472EF544076 /* FIRAuthBackend+MultiFactor.m in Sources */, + 06D0DEC16407DB4731F5EECFD70BB596 /* FIRAuthCredential.m in Sources */, + 8F5C1D74BE2842634974271AE9FC7945 /* FIRAuthDataResult.m in Sources */, + 61836E97EC307FE78A3188DC59E80766 /* FIRAuthDefaultUIDelegate.m in Sources */, + 3EF90985FBC0EFC597433890E552681B /* FIRAuthDispatcher.m in Sources */, + 56DD497298CFD6B9BE25A7DB188F137A /* FIRAuthErrorUtils.m in Sources */, + 90B1D14277BAD1823703CF9E200B39A2 /* FIRAuthExceptionUtils.m in Sources */, + 1272C08EDBFCEEAB914C7169E258237E /* FIRAuthGlobalWorkQueue.m in Sources */, + FFA2DAEB0C26A15082FF1CF616F37743 /* FIRAuthKeychainServices.m in Sources */, + 4722136B0312A5C842F3A30A08A703D8 /* FIRAuthNotificationManager.m in Sources */, + 07BE846F330C6E3CC21666B1689703E3 /* FIRAuthProtoFinalizeMFAPhoneRequestInfo.m in Sources */, + 962C5416547AB875A95DC457450E16C4 /* FIRAuthProtoFinalizeMFAPhoneResponseInfo.m in Sources */, + DD7C92CFAEA3DF3952EF609A42353BB8 /* FIRAuthProtoMFAEnrollment.m in Sources */, + 1A8D3239CD91ED4D979E2061BAE3E994 /* FIRAuthProtoStartMFAPhoneRequestInfo.m in Sources */, + FE5621DEC98FB31AA72B2E7EFCF47E5E /* FIRAuthProtoStartMFAPhoneResponseInfo.m in Sources */, + 0F670C7670C381D6919E9E6EDC010C2A /* FIRAuthProvider.m in Sources */, + A527417E86B49E6FE60D3EC555DEE9F2 /* FIRAuthRequestConfiguration.m in Sources */, + 29432E2D848A8D5FDC653A470795980F /* FIRAuthSerialTaskQueue.m in Sources */, + 9CB06FE748D924EE8F8216D24A4DC2E5 /* FIRAuthSettings.m in Sources */, + BE6E9AAE134ED6EB4353EAFA3D61DCD1 /* FIRAuthStoredUserManager.m in Sources */, + 43DA1A03E3CA90322A1E2D113F2CEF8D /* FIRAuthTokenResult.m in Sources */, + B2A567972E2A3A00493F89D63B361337 /* FIRAuthURLPresenter.m in Sources */, + E3C9567E3F690C2202CB3C1CAA301921 /* FIRAuthUserDefaults.m in Sources */, + 0ECF3C22EF17A827CBB6633E059D3F5F /* FIRAuthWebUtils.m in Sources */, + F1B335949B234A973FC70F5D9545BBC0 /* FIRAuthWebView.m in Sources */, + B4A11489809A67AB70513E3C6064FD0F /* FIRAuthWebViewController.m in Sources */, + FC59AB27D5307BDF740094CC16954F56 /* FIRCreateAuthURIRequest.m in Sources */, + 379E03816B0498680EEA825E07B75BAB /* FIRCreateAuthURIResponse.m in Sources */, + B6554DE2E058C862C452D40EC7C7D270 /* FIRDeleteAccountRequest.m in Sources */, + 94E96158433F7455C36D5D1ED2CDE61A /* FIRDeleteAccountResponse.m in Sources */, + 3CE18A1F048FB0FCAEB327D11D9F7812 /* FirebaseAuth-dummy.m in Sources */, + 03FD460B72E20F8CEB4BAA02B6AB20EE /* FIREmailAuthProvider.m in Sources */, + 5031EDD6D39ABE328F106298097D68CF /* FIREmailLinkSignInRequest.m in Sources */, + ED2B4154C90873BF34D9F53C5E66C2D5 /* FIREmailLinkSignInResponse.m in Sources */, + 48188B5EFF05E24BCBD3BF8A74F5835C /* FIREmailPasswordAuthCredential.m in Sources */, + F1719DA02D57E086A37F581EB6DE31A0 /* FIRFacebookAuthCredential.m in Sources */, + 3F3A0AE5CD76C9173676C44A0EB816F9 /* FIRFacebookAuthProvider.m in Sources */, + EA2D0A5C868A11E3A21F053F33E61C73 /* FIRFinalizeMFAEnrollmentRequest.m in Sources */, + 2AA16A5788CFD8693903222735840723 /* FIRFinalizeMFAEnrollmentResponse.m in Sources */, + 2FB72ED3C83C69112786822E6A109B1D /* FIRFinalizeMFASignInRequest.m in Sources */, + 209C8610E46A99257A7EA9E79D4CE3A7 /* FIRFinalizeMFASignInResponse.m in Sources */, + 4C1DE7029ADD87FB8DCFB376283C5898 /* FIRGameCenterAuthCredential.m in Sources */, + 949AB19E291233083C42BE9ADBFC20D5 /* FIRGameCenterAuthProvider.m in Sources */, + D4F202A907C8D419AB82200B814F0953 /* FIRGetAccountInfoRequest.m in Sources */, + 458C1FF89558037425722E55EB0B3DBA /* FIRGetAccountInfoResponse.m in Sources */, + 7C4D567C727D32276A67A4634F5F1F1A /* FIRGetOOBConfirmationCodeRequest.m in Sources */, + 5F0035F3A7972050FF180F1353B39463 /* FIRGetOOBConfirmationCodeResponse.m in Sources */, + 25D1EE805A5E8D9B263A2D8B335F6124 /* FIRGetProjectConfigRequest.m in Sources */, + 75A9EC193CE5BFDD61D3D32361BC45E3 /* FIRGetProjectConfigResponse.m in Sources */, + 854AC47AA62CDBAE18A357DFFB84D80A /* FIRGitHubAuthCredential.m in Sources */, + 10C49AD71798CA4BDBB9F953BAED0CF6 /* FIRGitHubAuthProvider.m in Sources */, + 9A032416A3664E846492883825B07F3E /* FIRGoogleAuthCredential.m in Sources */, + EE7AF6437947FDF718E2A9CFAEBC3737 /* FIRGoogleAuthProvider.m in Sources */, + 43E6D5C2FC9D50383B2C39CDA9929534 /* FIRIdentityToolkitRequest.m in Sources */, + 672CFE0E53EE27776F329249118ACE25 /* FIRMultiFactor.m in Sources */, + 1CA90EEE7B12A5FF6A8BB43FEBB1AB47 /* FIRMultiFactorAssertion.m in Sources */, + E2A421C6B07D202EC46EBF8FBE4A6C2A /* FIRMultiFactorConstants.m in Sources */, + DB58CCADAD27983D22346E4ED8FDEED7 /* FIRMultiFactorInfo.m in Sources */, + 6D980042B490765086010F317F4006E5 /* FIRMultiFactorResolver.m in Sources */, + 02153F7E42E3C9AE4AE7C4DBC80F19A9 /* FIRMultiFactorSession.m in Sources */, + 04D7C641B10FBB28AC75BF6A12614002 /* FIROAuthCredential.m in Sources */, + E5549CBA417D626744A8617A1735FE49 /* FIROAuthProvider.m in Sources */, + 4F06F225D9F08ABDBD0F08524EB8D580 /* FIRPhoneAuthCredential.m in Sources */, + 4DF7C4E7DE1A2616D895833DA75A1259 /* FIRPhoneAuthProvider.m in Sources */, + C35D99F8D318ED34EA275C7266752AA9 /* FIRPhoneMultiFactorAssertion.m in Sources */, + 1D8397CFAB68F89506B82B8E5DE0E332 /* FIRPhoneMultiFactorGenerator.m in Sources */, + EF7D157C0B2D4029FBFBC6E072954952 /* FIRPhoneMultiFactorInfo.m in Sources */, + 932580A3057AD248F08F7B62D7F85D47 /* FIRResetPasswordRequest.m in Sources */, + 70244986A48B56752A1F63833EFB408C /* FIRResetPasswordResponse.m in Sources */, + C78BF0F094DD0D20A1603776BA2888D1 /* FIRRevokeTokenRequest.m in Sources */, + 86F76D1A633F29F914531D3E5BEC31A7 /* FIRRevokeTokenResponse.m in Sources */, + DA288525260D987D8F913FF83AF10B2B /* FIRSecureTokenRequest.m in Sources */, + 1E7BA32AA3F6BE570C598689E2BAC9DF /* FIRSecureTokenResponse.m in Sources */, + 71FEA929BEAAE87FEECC90064CAD12E1 /* FIRSecureTokenService.m in Sources */, + 5D312581A8E49DA56F5A578C9716869C /* FIRSendVerificationCodeRequest.m in Sources */, + A20BA28DEF36B1CB3E6E8F9205BD1678 /* FIRSendVerificationCodeResponse.m in Sources */, + 27946A092ED65B47834CB76DB96A76D9 /* FIRSetAccountInfoRequest.m in Sources */, + 01B167FB9B5EE4202F1D7019DFBF1206 /* FIRSetAccountInfoResponse.m in Sources */, + 21751DBB5EAA38F1C2BC416F1F0477B4 /* FIRSignInWithGameCenterRequest.m in Sources */, + 6D5601D8011B68E29F793C2F38E7E339 /* FIRSignInWithGameCenterResponse.m in Sources */, + 314291CBDDA8230AE9D787E30CD4087C /* FIRSignUpNewUserRequest.m in Sources */, + EE2B13BBE97EB26F8D122A01EC320175 /* FIRSignUpNewUserResponse.m in Sources */, + 04E0867585C77CDB92E740D5ED5E9DC0 /* FIRStartMFAEnrollmentRequest.m in Sources */, + 7B4466D42A8889C378D2DAA303B2481E /* FIRStartMFAEnrollmentResponse.m in Sources */, + D03A42EF380D585E615FC9FAF77BA4A9 /* FIRStartMFASignInRequest.m in Sources */, + 0C56480A60541302683296892E8E22F3 /* FIRStartMFASignInResponse.m in Sources */, + C9927E5817F375F4470F9EB4DE12DD83 /* FIRTwitterAuthCredential.m in Sources */, + 0CE8EEEBA36B0D52833A0245A57D9EBE /* FIRTwitterAuthProvider.m in Sources */, + 7A53C4BAC24FFF020B3D1C730A195B27 /* FIRUser.m in Sources */, + DBBDEC5D335671836A90EE8DF97EF8A3 /* FIRUserInfoImpl.m in Sources */, + BD69E327C8A2D5C6F4BA40913755AAD0 /* FIRUserMetadata.m in Sources */, + B8B5CAECF1D4440DA7E242D4D0B09BDA /* FIRVerifyAssertionRequest.m in Sources */, + 51F3891D59A4214B173A1EAEBE5F327A /* FIRVerifyAssertionResponse.m in Sources */, + 3CC55DD6A04CCCD387282A9F4477E0C9 /* FIRVerifyClientRequest.m in Sources */, + CBD2AD02B6042702A5AC2833AFC1829F /* FIRVerifyClientResponse.m in Sources */, + 867C59EC12A60569E2AB24E1B53247B4 /* FIRVerifyCustomTokenRequest.m in Sources */, + 665E44FD4B1FD5EB5403D5169D7E56CA /* FIRVerifyCustomTokenResponse.m in Sources */, + 580DC037A2A349DE3A5BAF94A36211C5 /* FIRVerifyPasswordRequest.m in Sources */, + 8305B8FF0E42EC1E6CC732785D3DF4E3 /* FIRVerifyPasswordResponse.m in Sources */, + C41D7F7A4FA6DA2FFC5DD86778C06DE1 /* FIRVerifyPhoneNumberRequest.m in Sources */, + 2AC9B914114C83566F0335E463C35CBF /* FIRVerifyPhoneNumberResponse.m in Sources */, + 9CAE0CEC8F47B76BE29471EDED2DDC89 /* FIRWithdrawMFARequest.m in Sources */, + 969E8E99A97BF0FCEFF6BC5BAED14B58 /* FIRWithdrawMFAResponse.m in Sources */, + 90B308AD77D91B69ADDB109CB0D75829 /* NSData+FIRBase64.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D765C8B133300FCAA82F70EF2ECAB17E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + A5EEE1954FBC0A5798C8992A05C4F717 /* FIRAnalyticsConfiguration.m in Sources */, + FB665E38D5A479AEEDCFFD011F149A13 /* FIRApp.m in Sources */, + 30C0073032317A76CDBA70B681414B9D /* FIRBundleUtil.m in Sources */, + 17B25894B99C479DE96C344CFBBEFD7F /* FIRComponent.m in Sources */, + 2D73F53F12D6DB49131B7A5898BA3651 /* FIRComponentContainer.m in Sources */, + 8B57B7A29A06D531CB4988E8F2492796 /* FIRComponentType.m in Sources */, + BB3AC17CF1CBD8C6675F7AB2565239EB /* FIRConfiguration.m in Sources */, + C92E5DE5B2BC5978D5A60D208FB9A050 /* FIRDependency.m in Sources */, + D0ACD95FD5301C5C9E40E3C5DFEB289D /* FirebaseCore-dummy.m in Sources */, + F3A800D4B3012F97A4482F04FB2F0D26 /* FIRFirebaseUserAgent.m in Sources */, + 501CCFC0727924636987808BF71FDA97 /* FIRHeartbeatLogger.m in Sources */, + 568B5B5D2DF06DCD731EDAAA735AFCD0 /* FIRLogger.m in Sources */, + 992270036034484690C0D43686A3352F /* FIROptions.m in Sources */, + 2848C9835FB27AFFE43D089CCD1C9EE7 /* FIRVersion.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + DA858220231C82A6847539E26E824855 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C2BD266797A754A6FCAB38E867F6F4B4 /* FBLPromise.m in Sources */, + 84DF36844DF0F23CD6AE44EB60A4E70F /* FBLPromise+All.m in Sources */, + B499873D96BE7E087783337479CECA89 /* FBLPromise+Always.m in Sources */, + 2B0FDB6E145DC289E4826D8FF4CC7F06 /* FBLPromise+Any.m in Sources */, + E52A2C906C5E2437C3089E99C8BEB9B0 /* FBLPromise+Async.m in Sources */, + 52CCA2C0E0519F7E94D786041FE01870 /* FBLPromise+Await.m in Sources */, + 491FCEDE5FCD1E4853BC3EC46EB3FB24 /* FBLPromise+Catch.m in Sources */, + E05FA77305030016A6C83C4B315FCB15 /* FBLPromise+Delay.m in Sources */, + 3CEF90A4BF4D698D3C0E6E28F79F8D90 /* FBLPromise+Do.m in Sources */, + C93BB8422D8332A3F5684DDC390B946B /* FBLPromise+Race.m in Sources */, + 918653E16077446E3228300361F811C7 /* FBLPromise+Recover.m in Sources */, + F31CC2BA137A263D576A36AB0AA40E8A /* FBLPromise+Reduce.m in Sources */, + 3A973A8CB0DEE9F13BCA66F95AB34C1C /* FBLPromise+Retry.m in Sources */, + 2D7E51E790AFE79B85372E8B7030C235 /* FBLPromise+Testing.m in Sources */, + AAC54DF236959D637BAAC9D487AB53EB /* FBLPromise+Then.m in Sources */, + F24A2722E2CC4700F04B1087504EAF7D /* FBLPromise+Timeout.m in Sources */, + 2E536C9ED61E08A9DFC5E8F32A33B60A /* FBLPromise+Validate.m in Sources */, + 89F5F005CF42FB4F0313CEEF776AD3A5 /* FBLPromise+Wrap.m in Sources */, + AB90B36902E786169B8AEF90BABDBB7A /* FBLPromiseError.m in Sources */, + 46DDFA750D4F8FC1AD257891B13954F7 /* PromisesObjC-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F88E3A34DA55EDCAF90F98F31891F840 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + AEA62B264E04B2E2B4C3B279D838CD7D /* GTMSessionFetcher.m in Sources */, + 4DCEFFB1FBD0DD6F77A3D6CAB6FF6BE5 /* GTMSessionFetcher-dummy.m in Sources */, + B1D5C5A53BE576222D41A8601FD6333B /* GTMSessionFetcherLogging.m in Sources */, + 3804F8E81CAFD3284E1516A54D6F04B7 /* GTMSessionFetcherService.m in Sources */, + B1F7ECE15B477A3F7F9B6417469B5FF9 /* GTMSessionUploadFetcher.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 013E8573996C58ACAAC5E290C08CF0FA /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = GoogleAppMeasurement; + target = B53D977A951AFC38B21751B706C1DF83 /* GoogleAppMeasurement */; + targetProxy = B02D047C18BA97E1CCED89BDA620C907 /* PBXContainerItemProxy */; + }; + 0F4757955A504ECAE388CC5BE81056AE /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseAuth; + target = 6AE4A3D573DED275B034E20506596C62 /* FirebaseAuth */; + targetProxy = AC814FA86648A9EA9FC2438DCDF553A0 /* PBXContainerItemProxy */; + }; + 132B0D4551FC783FFD3097D68DF4D8E3 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseCore; + target = 4402AFF83DBDC4DD07E198685FDC2DF2 /* FirebaseCore */; + targetProxy = 93D09E74D894F9DA140CDFD4CC314A49 /* PBXContainerItemProxy */; + }; + 155B559C9378F5E0535C8CEAAD0FB999 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseCore; + target = 4402AFF83DBDC4DD07E198685FDC2DF2 /* FirebaseCore */; + targetProxy = FAE09F295913CE5870F2600E737BD884 /* PBXContainerItemProxy */; + }; + 158099800731E6A2843DE293A6DF05E2 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Realm; + target = 68494F30B4A13F8E5E88BCCAEC25B0A4 /* Realm */; + targetProxy = 7A83C545054283193154F50A0D70E089 /* PBXContainerItemProxy */; + }; + 1757F2FA1AAEF6A9C441BC669EFBDF6B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseDatabase; + target = 736AF68F6527ACF6B4A4C54728824A1C /* FirebaseDatabase */; + targetProxy = F15B1E28F8F656804698054C67A9968D /* PBXContainerItemProxy */; + }; + 281F7A03D7628007DF7F542A79C0DAC0 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Realm; + target = 68494F30B4A13F8E5E88BCCAEC25B0A4 /* Realm */; + targetProxy = 4F6978D24DDD2B673979E92879905610 /* PBXContainerItemProxy */; + }; + 299F18F46115C72594F32E746E9260EA /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = nanopb; + target = D2B5E7DCCBBFB32341D857D01211A1A3 /* nanopb */; + targetProxy = 825E5630272C9862D73FDCB626215B14 /* PBXContainerItemProxy */; + }; + 2F8A9E9BE393C38D6BFA3AB6D119FF50 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = GoogleUtilities; + target = 8D7F5D5DD528D21A72DC87ADA5B12E2D /* GoogleUtilities */; + targetProxy = 0516152CFD505C7F0B0F8A16FCA90AD9 /* PBXContainerItemProxy */; + }; + 30FDD3B599E5911258641BF8E872EE1A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "leveldb-library"; + target = 9307B7A119490930CF70393AB529AAC1 /* leveldb-library */; + targetProxy = D3B2A91186893F85EC9A0D5E8AE3F180 /* PBXContainerItemProxy */; + }; + 3C75B2CC8950641BCADC7487D21B9A16 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Realm; + target = 68494F30B4A13F8E5E88BCCAEC25B0A4 /* Realm */; + targetProxy = 4C6C3C078CB5C9B18F5BA52C4AF6929C /* PBXContainerItemProxy */; + }; + 417FACEC67AA54B817EA5A446C6ACB84 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = GTMSessionFetcher; + target = D676E21115185671D7258A56944ABE98 /* GTMSessionFetcher */; + targetProxy = 9DB6502B940BC7A4311340732F4A82FC /* PBXContainerItemProxy */; + }; + 4468DA3D7E6E8FC052A2F65CAF2727C7 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "leveldb-library"; + target = 9307B7A119490930CF70393AB529AAC1 /* leveldb-library */; + targetProxy = E44ACD1C4BCA32274285B332CAEFFC7C /* PBXContainerItemProxy */; + }; + 49E9B79D46C6BF9329EEDE0EC4840589 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = PromisesObjC; + target = 2BBF7206D7FAC92C82A042A99C4A98F8 /* PromisesObjC */; + targetProxy = D2EC79994CB78BF25744580D912EA76B /* PBXContainerItemProxy */; + }; + 4C294EC2211BC25057989F9AA2F72608 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "Pods-PRTY"; + target = 6EB67D63E9CBABC9495A7C2F928737F2 /* Pods-PRTY */; + targetProxy = 5BD9ADE5AAA4535686FAAA1C3CC0357D /* PBXContainerItemProxy */; + }; + 4C5DD9E123B972A158AF253768B93583 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = PromisesObjC; + target = 2BBF7206D7FAC92C82A042A99C4A98F8 /* PromisesObjC */; + targetProxy = 31E77B69BA9B2AA4BE68E9BFA19F85CC /* PBXContainerItemProxy */; + }; + 4DF413C704E60FEFBA90A369758F1887 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseAuth; + target = 6AE4A3D573DED275B034E20506596C62 /* FirebaseAuth */; + targetProxy = 3108DDC56CCB0CDC4E6BDFE021997DDE /* PBXContainerItemProxy */; + }; + 4E0DA9400274EC15070258528BABC95A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = GTMSessionFetcher; + target = D676E21115185671D7258A56944ABE98 /* GTMSessionFetcher */; + targetProxy = 443F5DC9F3D1DE495A2D326006F980FB /* PBXContainerItemProxy */; + }; + 50C022351001704DBD141972C64C0B3B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseAppCheckInterop; + target = DD28B439BE8B17D9339D9B526F144347 /* FirebaseAppCheckInterop */; + targetProxy = B1EC55D5BFD3FC0E774363F72E4494A6 /* PBXContainerItemProxy */; + }; + 55ECF6B64FA55364FD2FF47FA4725459 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseCoreInternal; + target = 25E9E9A17BC3F670357D7385C521E48E /* FirebaseCoreInternal */; + targetProxy = D9DDD885C5F83A9E84C453FF34838738 /* PBXContainerItemProxy */; + }; + 5B3F4AC1DB067B920B86D301F8586D97 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = nanopb; + target = D2B5E7DCCBBFB32341D857D01211A1A3 /* nanopb */; + targetProxy = 2D147F859DDB7890AB63757B2B48D558 /* PBXContainerItemProxy */; + }; + 5BDE0A3955F4B848ADBF521062D8852D /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = GoogleUtilities; + target = 8D7F5D5DD528D21A72DC87ADA5B12E2D /* GoogleUtilities */; + targetProxy = 8CB010577E0BE59D2312C3B77669CC8B /* PBXContainerItemProxy */; + }; + 5F295AE2ECA94FC42D49CE9382B5016B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = RealmSwift; + target = 782725687624F8665247B84AB581BEB1 /* RealmSwift */; + targetProxy = 308ABA41B2D29D0D1B37A17A4B12F138 /* PBXContainerItemProxy */; + }; + 5FF71D0AF92B42C7AFA1BBED9382F714 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = PromisesObjC; + target = 2BBF7206D7FAC92C82A042A99C4A98F8 /* PromisesObjC */; + targetProxy = 14A322A1AC500E74EDF645DC892EA44D /* PBXContainerItemProxy */; + }; + 68CC63C8AE203A24235298262F25EB10 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseCoreInternal; + target = 25E9E9A17BC3F670357D7385C521E48E /* FirebaseCoreInternal */; + targetProxy = 6F43C42E7927FD30D223C4082AD1E611 /* PBXContainerItemProxy */; + }; + 692C74FE9B172EF43008D8ED4DFC8652 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Firebase; + target = 072CEA044D2EF26F03496D5996BBF59F /* Firebase */; + targetProxy = 7E879050E608976F80175EA65F8BC320 /* PBXContainerItemProxy */; + }; + 6C2008F54C753B8AEC9A08F9921CF356 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseCoreInternal; + target = 25E9E9A17BC3F670357D7385C521E48E /* FirebaseCoreInternal */; + targetProxy = 61E1F30BB49E1CFA5E47E05FB2CC4945 /* PBXContainerItemProxy */; + }; + 6DDD5FE0D9098A9F8F5AA20684E020B7 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseCore; + target = 4402AFF83DBDC4DD07E198685FDC2DF2 /* FirebaseCore */; + targetProxy = FA117A33ECCCB87CC55E174C24B02719 /* PBXContainerItemProxy */; + }; + 774B463620166FF8826D78B6C95772B6 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseDatabase; + target = 736AF68F6527ACF6B4A4C54728824A1C /* FirebaseDatabase */; + targetProxy = A27C3F3F02080EF60222D292BFCA0415 /* PBXContainerItemProxy */; + }; + 7781D1A853CFF5B95ECEF15333106B3B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = GoogleUtilities; + target = 8D7F5D5DD528D21A72DC87ADA5B12E2D /* GoogleUtilities */; + targetProxy = 098C48605ADC39486758E23BA26539F7 /* PBXContainerItemProxy */; + }; + 7A137EA28E4BB4A749ADBC90F4B620A5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = GoogleUtilities; + target = 8D7F5D5DD528D21A72DC87ADA5B12E2D /* GoogleUtilities */; + targetProxy = 6D40EDCF4FADF10C87091425A26E2172 /* PBXContainerItemProxy */; + }; + 7BBC1F663124F70FBDBA94CCA30E6069 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseDatabase; + target = 736AF68F6527ACF6B4A4C54728824A1C /* FirebaseDatabase */; + targetProxy = 33D8BFB977D35D03620D1DFF284C88D9 /* PBXContainerItemProxy */; + }; + 7CA54BB6A25BCEAEA46B61CAE5587B05 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = GoogleUtilities; + target = 8D7F5D5DD528D21A72DC87ADA5B12E2D /* GoogleUtilities */; + targetProxy = 74142478B4FC8B27E39C042BD1E36403 /* PBXContainerItemProxy */; + }; + 7D5BD7A59B4C1592668B39269A6D3599 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseInstallations; + target = 87803597EB3F20FC46472B85392EC4FD /* FirebaseInstallations */; + targetProxy = 9AD642D3BE68B4B2A425E8B6FE438C4C /* PBXContainerItemProxy */; + }; + 818C3FA3CBC90DD1217FB6C02B0560A9 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = PromisesObjC; + target = 2BBF7206D7FAC92C82A042A99C4A98F8 /* PromisesObjC */; + targetProxy = 2DDAB5BB6DECA834588DCE67F913C08F /* PBXContainerItemProxy */; + }; + 8B5C692A01CB61AB3EF650B1581F8BC5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseAppCheckInterop; + target = DD28B439BE8B17D9339D9B526F144347 /* FirebaseAppCheckInterop */; + targetProxy = D6DFDCFFAD1A3D0821E7CBFDBE773355 /* PBXContainerItemProxy */; + }; + 93E004BDD77E2CD8D4D958CEDBEAAD40 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = RealmSwift; + target = 782725687624F8665247B84AB581BEB1 /* RealmSwift */; + targetProxy = 7C2DD98B54749B01C52F6F805BCCF988 /* PBXContainerItemProxy */; + }; + 96B0396DD423ED13C7FB4FFF8DDAFE6F /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "leveldb-library"; + target = 9307B7A119490930CF70393AB529AAC1 /* leveldb-library */; + targetProxy = D5DC6F9AB94C697099D58DBD7EA567F7 /* PBXContainerItemProxy */; + }; + 9D8FDBCDA70255AC2F71E45491AE2973 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseCore; + target = 4402AFF83DBDC4DD07E198685FDC2DF2 /* FirebaseCore */; + targetProxy = 8FED94D31CE78026A377FC87CF489CD5 /* PBXContainerItemProxy */; + }; + A37CC460FA4A05863FE7CEFD2CA5D5D7 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseInstallations; + target = 87803597EB3F20FC46472B85392EC4FD /* FirebaseInstallations */; + targetProxy = D835DB6B3AE8421567C44B91F7E5975E /* PBXContainerItemProxy */; + }; + A9B4A1AD9D39009794B539EBDE6DD5A1 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = nanopb; + target = D2B5E7DCCBBFB32341D857D01211A1A3 /* nanopb */; + targetProxy = C944FF5406DC8599A20BCFFC8BAA2221 /* PBXContainerItemProxy */; + }; + AB813BADA5C8B5B5E1AC06E26A0E4072 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseCore; + target = 4402AFF83DBDC4DD07E198685FDC2DF2 /* FirebaseCore */; + targetProxy = 819C09EAE7F010DD612DFBCD69E40FCC /* PBXContainerItemProxy */; + }; + B469E89D00D7BE78CA71249120F70241 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseAnalytics; + target = C49E7A4D59E5C8BE8DE9FB1EFB150185 /* FirebaseAnalytics */; + targetProxy = 78BCAB41F407804D6FC2BD1E2911218D /* PBXContainerItemProxy */; + }; + B4EB3D3BEA15B52C67D5D4094E386A77 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = GTMSessionFetcher; + target = D676E21115185671D7258A56944ABE98 /* GTMSessionFetcher */; + targetProxy = 6FCBD942CDF63E61FE2190400F6CD3FA /* PBXContainerItemProxy */; + }; + B65705DCE9634C91886C9F80D9E9854C /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseAppCheckInterop; + target = DD28B439BE8B17D9339D9B526F144347 /* FirebaseAppCheckInterop */; + targetProxy = A7FCDBA4F6755115DC3CDBE58DCED780 /* PBXContainerItemProxy */; + }; + BAB1B8936EE33F3B3881CB3D669D5137 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = GoogleAppMeasurement; + target = B53D977A951AFC38B21751B706C1DF83 /* GoogleAppMeasurement */; + targetProxy = 1673B004612F96977DBC24524410576C /* PBXContainerItemProxy */; + }; + D11B3AC94525F901567ED83ABDA99EB1 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = nanopb; + target = D2B5E7DCCBBFB32341D857D01211A1A3 /* nanopb */; + targetProxy = E0EC0F3F3F512E174FCB13C02032280E /* PBXContainerItemProxy */; + }; + D30677DEBACD4A079A03CAAF5A39ABA6 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseAnalytics; + target = C49E7A4D59E5C8BE8DE9FB1EFB150185 /* FirebaseAnalytics */; + targetProxy = B78518C0F06A7F78C8BA8C29F750E165 /* PBXContainerItemProxy */; + }; + D322FD0C2A19F7C28987A7EECEDD22ED /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = GoogleUtilities; + target = 8D7F5D5DD528D21A72DC87ADA5B12E2D /* GoogleUtilities */; + targetProxy = D6286A89240200BBCDEAA1BDFEFABC96 /* PBXContainerItemProxy */; + }; + D421120D8554F8E12EBB40B20881A853 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Firebase; + target = 072CEA044D2EF26F03496D5996BBF59F /* Firebase */; + targetProxy = 39A18CEC6FA11024467A2918EC7D6BC6 /* PBXContainerItemProxy */; + }; + D58FFA70B17AA29C1EBBF258007459DE /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseInstallations; + target = 87803597EB3F20FC46472B85392EC4FD /* FirebaseInstallations */; + targetProxy = 3492D860BE14792B6CCAA6C9F8E4E505 /* PBXContainerItemProxy */; + }; + DFC7E744966BEF08AF267D354C09B45B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = GoogleAppMeasurement; + target = B53D977A951AFC38B21751B706C1DF83 /* GoogleAppMeasurement */; + targetProxy = D5B50C51D354989FF8B1A057EBC1AE3A /* PBXContainerItemProxy */; + }; + E5CCB3D080BE105847132F88805A855A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseCore; + target = 4402AFF83DBDC4DD07E198685FDC2DF2 /* FirebaseCore */; + targetProxy = B55E86A2610B1EF5E73A5410E17D0D95 /* PBXContainerItemProxy */; + }; + E5DB5B4BCB3F94126F6BE409F2216CE1 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = GoogleUtilities; + target = 8D7F5D5DD528D21A72DC87ADA5B12E2D /* GoogleUtilities */; + targetProxy = DFB4583EE4CA5B4263ECD1F9C5633838 /* PBXContainerItemProxy */; + }; + E6E557B60C168CACEE6735A71890345A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseAuth; + target = 6AE4A3D573DED275B034E20506596C62 /* FirebaseAuth */; + targetProxy = 318C1A405308D930D20AE22EB1FD4150 /* PBXContainerItemProxy */; + }; + EE5FAD0A2825DCEFCA8DE9122EF93B48 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseAnalytics; + target = C49E7A4D59E5C8BE8DE9FB1EFB150185 /* FirebaseAnalytics */; + targetProxy = EB91152D34D1393B9475FE1D58A2F496 /* PBXContainerItemProxy */; + }; + F1A9A9C4F8CA487C39BA2B767D511D1E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseCore; + target = 4402AFF83DBDC4DD07E198685FDC2DF2 /* FirebaseCore */; + targetProxy = 1BA286B69860AA1E04F78ABEDF3294A7 /* PBXContainerItemProxy */; + }; + FDC1FF1FA32C278B2CC15847FF80833A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = GoogleUtilities; + target = 8D7F5D5DD528D21A72DC87ADA5B12E2D /* GoogleUtilities */; + targetProxy = 04F2B059621A8F52AF612957704DB52F /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 13EBB127A540535132FDFB4C04DBF21E /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 0F75325E1AFCBB674768EAEE2D817261 /* FirebaseCore.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/FirebaseCore/FirebaseCore-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.1; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/FirebaseCore/FirebaseCore.modulemap"; + PRODUCT_MODULE_NAME = FirebaseCore; + PRODUCT_NAME = FirebaseCore; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.3; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 1CC7D80F6048BDC9D0C722D9A6CCF243 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 03E65604EC485B5893B33E6098B32451 /* Realm.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/Realm/Realm-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/Realm/Realm-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/Realm/Realm.modulemap"; + PRODUCT_MODULE_NAME = Realm; + PRODUCT_NAME = Realm; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 27771C3B8645B75300ED4AF5B64B9E7F /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 6BF24E0394DAD3101FF5C00412EB1C4D /* leveldb-library.debug.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/leveldb-library/leveldb-library-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/leveldb-library/leveldb-library-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/leveldb-library/leveldb-library.modulemap"; + PRODUCT_MODULE_NAME = leveldb; + PRODUCT_NAME = leveldb; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 27FE92F02FCFC95FE5DBA394A5A8AD9B /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = F0DF6E1A8D6752D88F3DAA4CF23F208A /* FirebaseDatabase.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/FirebaseDatabase/FirebaseDatabase-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/FirebaseDatabase/FirebaseDatabase.modulemap"; + PRODUCT_MODULE_NAME = FirebaseDatabase; + PRODUCT_NAME = FirebaseDatabase; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.3; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 2E71D3D7C49F59AB6409767D2846F05E /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = F4212B50C554057BF62AA6A4107D56BC /* Pods-PRTY-PRTYUITests.release.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/Pods-PRTY-PRTYUITests/Pods-PRTY-PRTYUITests-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.1; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-PRTY-PRTYUITests/Pods-PRTY-PRTYUITests.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 2F2052BEA5F71E8D84297A959DA4C1A9 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D68BEA0EF9DCC01F9EF03619F5C0AE46 /* Pods-PRTYTests.release.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/Pods-PRTYTests/Pods-PRTYTests-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.1; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-PRTYTests/Pods-PRTYTests.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 30305253AFB828F175D53C952E946928 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 64CA733606AC8F6B69927A354B416C4D /* GoogleUtilities.debug.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/GoogleUtilities/GoogleUtilities-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/GoogleUtilities/GoogleUtilities.modulemap"; + PRODUCT_MODULE_NAME = GoogleUtilities; + PRODUCT_NAME = GoogleUtilities; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 3AFCBF6761C664BEBCD02942CD57AF53 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 0A0CF7B9BAF15535F28A3BC045F60A22 /* FirebaseAppCheckInterop.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/FirebaseAppCheckInterop/FirebaseAppCheckInterop-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/FirebaseAppCheckInterop/FirebaseAppCheckInterop-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.1; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/FirebaseAppCheckInterop/FirebaseAppCheckInterop.modulemap"; + PRODUCT_MODULE_NAME = FirebaseAppCheckInterop; + PRODUCT_NAME = FirebaseAppCheckInterop; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 3E7096E689683CDD176083E1F233CD41 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = FB1B9D02FB871F65EBDB1D3F578155C0 /* FirebaseInstallations.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/FirebaseInstallations/FirebaseInstallations-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/FirebaseInstallations/FirebaseInstallations.modulemap"; + PRODUCT_MODULE_NAME = FirebaseInstallations; + PRODUCT_NAME = FirebaseInstallations; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.3; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 41FDA83C48F3EFE6E7011CCA4E0BF90E /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 631552790F8641131F8F403D6D4D68BC /* Pods-PRTY.release.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/Pods-PRTY/Pods-PRTY-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.1; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-PRTY/Pods-PRTY.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 45285987FDC204B9DB7C0228892D4B3E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "POD_CONFIGURATION_DEBUG=1", + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.1; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + STRIP_INSTALLED_PRODUCT = NO; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + SYMROOT = "${SRCROOT}/../build"; + }; + name = Debug; + }; + 4BC16B6DA2DBD2FCB85D2B2E1668876D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = E3D7107849E93A425AEA955A36B090EA /* Firebase.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ENABLE_OBJC_WEAK = NO; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 4EE58C404C20A39E8E53AC6B8C3EBC08 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 23EAD188D4983631890D4FE0563517B6 /* GoogleAppMeasurement.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ENABLE_OBJC_WEAK = NO; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 539E84DD5A1268807B25E52D82197D75 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 400F42C6868B6D5EB4B6C01B3A312F5E /* FirebaseCoreInternal.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal.modulemap"; + PRODUCT_MODULE_NAME = FirebaseCoreInternal; + PRODUCT_NAME = FirebaseCoreInternal; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.3; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 6AF9D8D0B4F4FA4695A8EEF773CD3FBC /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "POD_CONFIGURATION_RELEASE=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.1; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + STRIP_INSTALLED_PRODUCT = NO; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_VERSION = 5.0; + SYMROOT = "${SRCROOT}/../build"; + }; + name = Release; + }; + 78D464E448C01A9B7152B867387689DF /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 0F8DAE8DAB33858EC467E8C46A252F13 /* FirebaseAuth.debug.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/FirebaseAuth/FirebaseAuth-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/FirebaseAuth/FirebaseAuth.modulemap"; + PRODUCT_MODULE_NAME = FirebaseAuth; + PRODUCT_NAME = FirebaseAuth; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.3; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 7961BF0B89F74314288ACFF93A803292 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = ADE396F87DDA126FB067A8765E2CCFA7 /* Pods-PRTY.debug.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/Pods-PRTY/Pods-PRTY-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.1; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-PRTY/Pods-PRTY.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 7BED1A91DDE7553B1AC160C230D61A91 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = CA91F1F593BC0E1D3C7684615182D7CF /* FirebaseInstallations.debug.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/FirebaseInstallations/FirebaseInstallations-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/FirebaseInstallations/FirebaseInstallations.modulemap"; + PRODUCT_MODULE_NAME = FirebaseInstallations; + PRODUCT_NAME = FirebaseInstallations; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.3; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 84971A590416E7195FA3E895F88755D0 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7908EB620837F7E1D1A620F7A161B653 /* RealmSwift.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/RealmSwift/RealmSwift-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/RealmSwift/RealmSwift-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/RealmSwift/RealmSwift.modulemap"; + PRODUCT_MODULE_NAME = RealmSwift; + PRODUCT_NAME = RealmSwift; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 88D77340EC0C562CBBAFAEDFF1E36EFF /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = AC40BB501A5BB0BEBA4E9E370E027119 /* FirebaseAnalytics.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ENABLE_OBJC_WEAK = NO; + IPHONEOS_DEPLOYMENT_TARGET = 16.1; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 8981C809098CE2CAB6B2BB2C411BB8B4 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 75552E75CFD01D4BD91E2725CDEF78C1 /* leveldb-library.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/leveldb-library/leveldb-library-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/leveldb-library/leveldb-library-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/leveldb-library/leveldb-library.modulemap"; + PRODUCT_MODULE_NAME = leveldb; + PRODUCT_NAME = leveldb; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 8C6D27ACDCB12B50E70407A8C75DE546 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = A030CC80807AF4C0FDC009471007CC14 /* PromisesObjC.release.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/PromisesObjC/PromisesObjC-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/PromisesObjC/PromisesObjC.modulemap"; + PRODUCT_MODULE_NAME = FBLPromises; + PRODUCT_NAME = FBLPromises; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 8DC5D995DAFD09875086CEF883FC1154 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 02F08FE90CA068E63145D504F97EA515 /* Pods-PRTY-PRTYUITests.debug.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/Pods-PRTY-PRTYUITests/Pods-PRTY-PRTYUITests-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.1; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-PRTY-PRTYUITests/Pods-PRTY-PRTYUITests.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 912125D476135C6CEA2051E0DA3BA063 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = CD98D5EB6316186187D122179DDBB9DF /* Firebase.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ENABLE_OBJC_WEAK = NO; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 9BBDFCB5595D0D6E4158510FD63B1008 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 71EB5FB4222FE68A6E09A16CC088A3EA /* nanopb.release.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/nanopb/nanopb-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/nanopb/nanopb-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/nanopb/nanopb.modulemap"; + PRODUCT_MODULE_NAME = nanopb; + PRODUCT_NAME = nanopb; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + A2C0DCDF023E92F3EFB936842EAC1B16 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = ABC7F498E2FC7E903D6F8640E17F788A /* Pods-PRTYTests.debug.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/Pods-PRTYTests/Pods-PRTYTests-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.1; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-PRTYTests/Pods-PRTYTests.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + ACF5D7A80DB305349170C6C107A24B77 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 46C5E75CF6F0B997F9A910E919A5E1D7 /* FirebaseDatabase.debug.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/FirebaseDatabase/FirebaseDatabase-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/FirebaseDatabase/FirebaseDatabase.modulemap"; + PRODUCT_MODULE_NAME = FirebaseDatabase; + PRODUCT_NAME = FirebaseDatabase; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.3; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + AD67ACEC5E0CB491BF2C49D02AC8064D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 8547F6FA127EF377B812C3DDDB5CC6EA /* RealmSwift.debug.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/RealmSwift/RealmSwift-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/RealmSwift/RealmSwift-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/RealmSwift/RealmSwift.modulemap"; + PRODUCT_MODULE_NAME = RealmSwift; + PRODUCT_NAME = RealmSwift; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + AF59895517B2C547506A7148DEF5B144 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 4FA2B79F663A9D69D6E613EB25A6F2BE /* FirebaseAuth.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/FirebaseAuth/FirebaseAuth-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/FirebaseAuth/FirebaseAuth.modulemap"; + PRODUCT_MODULE_NAME = FirebaseAuth; + PRODUCT_NAME = FirebaseAuth; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.3; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + B1F292BB0109C165EF2EA3E4C590D30E /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = EF82691CD03AEDF56103F9C350618682 /* GoogleUtilities.release.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/GoogleUtilities/GoogleUtilities-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/GoogleUtilities/GoogleUtilities.modulemap"; + PRODUCT_MODULE_NAME = GoogleUtilities; + PRODUCT_NAME = GoogleUtilities; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + B27A555B7D37ADDC4FC843D44AFE7DFA /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = CEC46A5E041A4A0D0E0314CF5F667FFD /* GoogleAppMeasurement.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ENABLE_OBJC_WEAK = NO; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + C0822C9B97C8A4B017B0E075AFFBFB80 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9B9A8FE44DFC70CD9D29C885FF6CB87F /* nanopb.debug.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/nanopb/nanopb-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/nanopb/nanopb-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/nanopb/nanopb.modulemap"; + PRODUCT_MODULE_NAME = nanopb; + PRODUCT_NAME = nanopb; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + C10AED32F6EE162B1900B1CCE9BA9884 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = E0F2C073ECA9F2634031E8A827AEE3AB /* GTMSessionFetcher.debug.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/GTMSessionFetcher/GTMSessionFetcher-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/GTMSessionFetcher/GTMSessionFetcher.modulemap"; + PRODUCT_MODULE_NAME = GTMSessionFetcher; + PRODUCT_NAME = GTMSessionFetcher; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + C56989B8CA3659EC43AB61372388A90D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 53F22C31C4648F4E4371ADD62CFCE32C /* FirebaseAnalytics.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ENABLE_OBJC_WEAK = NO; + IPHONEOS_DEPLOYMENT_TARGET = 16.1; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + CBC2E66943DAC5CB5FEAF78BC4F58DF5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 555B74707E9153148A9CDBFB9095395D /* Realm.debug.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/Realm/Realm-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/Realm/Realm-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/Realm/Realm.modulemap"; + PRODUCT_MODULE_NAME = Realm; + PRODUCT_NAME = Realm; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + CF6DAB5681E4DD5679AC46B508FC2E47 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = EA57FFE363F883005877B7B2BEB8F282 /* FirebaseAppCheckInterop.debug.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/FirebaseAppCheckInterop/FirebaseAppCheckInterop-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/FirebaseAppCheckInterop/FirebaseAppCheckInterop-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.1; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/FirebaseAppCheckInterop/FirebaseAppCheckInterop.modulemap"; + PRODUCT_MODULE_NAME = FirebaseAppCheckInterop; + PRODUCT_NAME = FirebaseAppCheckInterop; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + DAE3AF50F7BA12A486A3B8080A3A720A /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 97F795562E65992BA4EA307E98284AC4 /* GTMSessionFetcher.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/GTMSessionFetcher/GTMSessionFetcher-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/GTMSessionFetcher/GTMSessionFetcher.modulemap"; + PRODUCT_MODULE_NAME = GTMSessionFetcher; + PRODUCT_NAME = GTMSessionFetcher; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + E95C9155360502CBF5A983AF228F9320 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 10D87030427938D0539D5DF4EC4032F1 /* FirebaseCore.debug.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/FirebaseCore/FirebaseCore-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.1; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/FirebaseCore/FirebaseCore.modulemap"; + PRODUCT_MODULE_NAME = FirebaseCore; + PRODUCT_NAME = FirebaseCore; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.3; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + F1A6066674BD0A94337DC9359754C953 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 625421974DC8B2D9D04332AD61B57DA3 /* FirebaseCoreInternal.debug.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal.modulemap"; + PRODUCT_MODULE_NAME = FirebaseCoreInternal; + PRODUCT_NAME = FirebaseCoreInternal; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.3; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + FFF81CC3C6C196F56925F56D516052D9 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = BCBB934EA3FEB2A60AAE97D3799103B3 /* PromisesObjC.debug.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/PromisesObjC/PromisesObjC-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/PromisesObjC/PromisesObjC.modulemap"; + PRODUCT_MODULE_NAME = FBLPromises; + PRODUCT_NAME = FBLPromises; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 15AA93CF5F4D00C188CA7354B47DB2A8 /* Build configuration list for PBXNativeTarget "GTMSessionFetcher" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C10AED32F6EE162B1900B1CCE9BA9884 /* Debug */, + DAE3AF50F7BA12A486A3B8080A3A720A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 2855B05178AD62797D0BF666C343D36F /* Build configuration list for PBXNativeTarget "FirebaseCore" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + E95C9155360502CBF5A983AF228F9320 /* Debug */, + 13EBB127A540535132FDFB4C04DBF21E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 2E588B50D62583B18B24E582537EBB3B /* Build configuration list for PBXNativeTarget "Pods-PRTY" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 7961BF0B89F74314288ACFF93A803292 /* Debug */, + 41FDA83C48F3EFE6E7011CCA4E0BF90E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 2E73F4C2B5A4B9C40BAE58F7EEDC3DCB /* Build configuration list for PBXNativeTarget "PromisesObjC" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FFF81CC3C6C196F56925F56D516052D9 /* Debug */, + 8C6D27ACDCB12B50E70407A8C75DE546 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 3B337C9C6CA2E899D2250ACACB574378 /* Build configuration list for PBXNativeTarget "Pods-PRTYTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + A2C0DCDF023E92F3EFB936842EAC1B16 /* Debug */, + 2F2052BEA5F71E8D84297A959DA4C1A9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 47354ADB1930A2E9F4E3E91AAD1FE58A /* Build configuration list for PBXNativeTarget "RealmSwift" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + AD67ACEC5E0CB491BF2C49D02AC8064D /* Debug */, + 84971A590416E7195FA3E895F88755D0 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 45285987FDC204B9DB7C0228892D4B3E /* Debug */, + 6AF9D8D0B4F4FA4695A8EEF773CD3FBC /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 55DB65357524849130CCE7F4329350CA /* Build configuration list for PBXNativeTarget "FirebaseDatabase" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + ACF5D7A80DB305349170C6C107A24B77 /* Debug */, + 27FE92F02FCFC95FE5DBA394A5A8AD9B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5823FAB140D66B9C27BAAB580E779242 /* Build configuration list for PBXAggregateTarget "FirebaseAnalytics" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 88D77340EC0C562CBBAFAEDFF1E36EFF /* Debug */, + C56989B8CA3659EC43AB61372388A90D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 77A2A922B1E9CABA47FABBE48E70F593 /* Build configuration list for PBXAggregateTarget "GoogleAppMeasurement" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B27A555B7D37ADDC4FC843D44AFE7DFA /* Debug */, + 4EE58C404C20A39E8E53AC6B8C3EBC08 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 8EB88B4FC0FC9B16DC04AEB4E446B11D /* Build configuration list for PBXAggregateTarget "Firebase" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4BC16B6DA2DBD2FCB85D2B2E1668876D /* Debug */, + 912125D476135C6CEA2051E0DA3BA063 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + A13B4C93C7094E3C86F1FDE75AB90123 /* Build configuration list for PBXNativeTarget "Realm" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + CBC2E66943DAC5CB5FEAF78BC4F58DF5 /* Debug */, + 1CC7D80F6048BDC9D0C722D9A6CCF243 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + AC64B97F43C4BCE84E89B8268FE95E5B /* Build configuration list for PBXNativeTarget "FirebaseCoreInternal" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F1A6066674BD0A94337DC9359754C953 /* Debug */, + 539E84DD5A1268807B25E52D82197D75 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C62BEA7CAAEC1D2DABBE4A1FC9F75FB6 /* Build configuration list for PBXNativeTarget "GoogleUtilities" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 30305253AFB828F175D53C952E946928 /* Debug */, + B1F292BB0109C165EF2EA3E4C590D30E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + D40D167B127A50CE651D70AF63382772 /* Build configuration list for PBXNativeTarget "leveldb-library" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 27771C3B8645B75300ED4AF5B64B9E7F /* Debug */, + 8981C809098CE2CAB6B2BB2C411BB8B4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + DC8173BDD7FF6F3046B2E35AEE71BA95 /* Build configuration list for PBXNativeTarget "Pods-PRTY-PRTYUITests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8DC5D995DAFD09875086CEF883FC1154 /* Debug */, + 2E71D3D7C49F59AB6409767D2846F05E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + E1BA027A65D078933D0CEA8ACE53EE28 /* Build configuration list for PBXNativeTarget "FirebaseAppCheckInterop" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + CF6DAB5681E4DD5679AC46B508FC2E47 /* Debug */, + 3AFCBF6761C664BEBCD02942CD57AF53 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + E5F7DF13DDEFD7ACEEE70AB494CD3E05 /* Build configuration list for PBXNativeTarget "FirebaseAuth" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 78D464E448C01A9B7152B867387689DF /* Debug */, + AF59895517B2C547506A7148DEF5B144 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + E81670CAD096B4447BC3A704B9D0CCEE /* Build configuration list for PBXNativeTarget "nanopb" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C0822C9B97C8A4B017B0E075AFFBFB80 /* Debug */, + 9BBDFCB5595D0D6E4158510FD63B1008 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + EC3EBC32F26CF0150F071F37032496AE /* Build configuration list for PBXNativeTarget "FirebaseInstallations" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 7BED1A91DDE7553B1AC160C230D61A91 /* Debug */, + 3E7096E689683CDD176083E1F233CD41 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = BFDFE7DC352907FC980B868725387E98 /* Project object */; +} diff --git a/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/Firebase.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/Firebase.xcscheme new file mode 100644 index 0000000..0c9c164 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/Firebase.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/FirebaseAnalytics.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/FirebaseAnalytics.xcscheme new file mode 100644 index 0000000..a2b2407 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/FirebaseAnalytics.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/FirebaseAppCheckInterop.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/FirebaseAppCheckInterop.xcscheme new file mode 100644 index 0000000..93408bf --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/FirebaseAppCheckInterop.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/FirebaseAuth.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/FirebaseAuth.xcscheme new file mode 100644 index 0000000..8c2ac83 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/FirebaseAuth.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/FirebaseCore.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/FirebaseCore.xcscheme new file mode 100644 index 0000000..21dbada --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/FirebaseCore.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/FirebaseCoreInternal.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/FirebaseCoreInternal.xcscheme new file mode 100644 index 0000000..0d4e045 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/FirebaseCoreInternal.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/FirebaseDatabase.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/FirebaseDatabase.xcscheme new file mode 100644 index 0000000..87ed26b --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/FirebaseDatabase.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/FirebaseInstallations.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/FirebaseInstallations.xcscheme new file mode 100644 index 0000000..0489893 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/FirebaseInstallations.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/GTMSessionFetcher.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/GTMSessionFetcher.xcscheme new file mode 100644 index 0000000..17837bc --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/GTMSessionFetcher.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/GoogleAppMeasurement.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/GoogleAppMeasurement.xcscheme new file mode 100644 index 0000000..349ce48 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/GoogleAppMeasurement.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/GoogleUtilities.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/GoogleUtilities.xcscheme new file mode 100644 index 0000000..2f3c9e5 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/GoogleUtilities.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/Pods-PRTY-PRTYUITests.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/Pods-PRTY-PRTYUITests.xcscheme new file mode 100644 index 0000000..6251e09 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/Pods-PRTY-PRTYUITests.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/Pods-PRTY.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/Pods-PRTY.xcscheme new file mode 100644 index 0000000..64775da --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/Pods-PRTY.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/Pods-PRTYTests.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/Pods-PRTYTests.xcscheme new file mode 100644 index 0000000..4cfaa42 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/Pods-PRTYTests.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/PromisesObjC.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/PromisesObjC.xcscheme new file mode 100644 index 0000000..a86e542 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/PromisesObjC.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/Realm.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/Realm.xcscheme new file mode 100644 index 0000000..7f62861 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/Realm.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/RealmSwift.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/RealmSwift.xcscheme new file mode 100644 index 0000000..d27b65a --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/RealmSwift.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/leveldb-library.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/leveldb-library.xcscheme new file mode 100644 index 0000000..f2e442e --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/leveldb-library.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/nanopb.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/nanopb.xcscheme new file mode 100644 index 0000000..42eb6f5 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/nanopb.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/xcschememanagement.plist b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..016f4da --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/quinnbutcher.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,106 @@ + + + + + SchemeUserState + + Firebase.xcscheme + + isShown + + + FirebaseAnalytics.xcscheme + + isShown + + + FirebaseAppCheckInterop.xcscheme + + isShown + + + FirebaseAuth.xcscheme + + isShown + + + FirebaseCore.xcscheme + + isShown + + + FirebaseCoreInternal.xcscheme + + isShown + + + FirebaseDatabase.xcscheme + + isShown + + + FirebaseInstallations.xcscheme + + isShown + + + GTMSessionFetcher.xcscheme + + isShown + + + GoogleAppMeasurement.xcscheme + + isShown + + + GoogleUtilities.xcscheme + + isShown + + + Pods-PRTY-PRTYUITests.xcscheme + + isShown + + + Pods-PRTY.xcscheme + + isShown + + + Pods-PRTYTests.xcscheme + + isShown + + + PromisesObjC.xcscheme + + isShown + + + Realm.xcscheme + + isShown + + + RealmSwift.xcscheme + + isShown + + + leveldb-library.xcscheme + + isShown + + + nanopb.xcscheme + + isShown + + + + SuppressBuildableAutocreation + + + diff --git a/Pods/PromisesObjC/LICENSE b/Pods/PromisesObjC/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/Pods/PromisesObjC/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/Pods/PromisesObjC/README.md b/Pods/PromisesObjC/README.md new file mode 100644 index 0000000..e0e65b7 --- /dev/null +++ b/Pods/PromisesObjC/README.md @@ -0,0 +1,60 @@ +[![Apache +License](https://img.shields.io/github/license/google/promises.svg)](LICENSE) +[![Travis](https://api.travis-ci.org/google/promises.svg?branch=master)](https://travis-ci.org/google/promises) +[![Gitter Chat](https://badges.gitter.im/google/promises.svg)](https://gitter.im/google/promises) + +![Platforms](https://img.shields.io/badge/platforms-macOS%20%7C%20iOS%20%7C%20tvOS%20%7C%20watchOS-blue.svg?longCache=true&style=flat) +![Languages](https://img.shields.io/badge/languages-Swift%20%7C%20ObjC-orange.svg?longCache=true&style=flat) +![Package Managers](https://img.shields.io/badge/supports-Bazel%20%7C%20SwiftPM%20%7C%20CocoaPods%20%7C%20Carthage-yellow.svg?longCache=true&style=flat) + +# Promises + +Promises is a modern framework that provides a synchronization construct for +Objective-C and Swift to facilitate writing asynchronous code. + +* [Introduction](g3doc/index.md) + * [The problem with async + code](g3doc/index.md#the-problem-with-async-code) + * [Promises to the rescue](g3doc/index.md#promises-to-the-rescue) + * [What is a promise?](g3doc/index.md#what-is-a-promise) +* [Framework](g3doc/index.md#framework) + * [Features](g3doc/index.md#features) + * [Benchmark](g3doc/index.md#benchmark) +* [Getting started](g3doc/index.md#getting-started) + * [Add dependency](g3doc/index.md#add-dependency) + * [Import](g3doc/index.md#import) + * [Adopt](g3doc/index.md#adopt) +* [Basics](g3doc/index.md#basics) + * [Creating promises](g3doc/index.md#creating-promises) + * [Async](g3doc/index.md#async) + * [Do](g3doc/index.md#do) + * [Pending](g3doc/index.md#pending) + * [Resolved](g3doc/index.md#create-a-resolved-promise) + * [Observing fulfillment](g3doc/index.md#observing-fulfillment) + * [Then](g3doc/index.md#then) + * [Observing rejection](g3doc/index.md#observing-rejection) + * [Catch](g3doc/index.md#catch) +* [Extensions](g3doc/index.md#extensions) + * [All](g3doc/index.md#all) + * [Always](g3doc/index.md#always) + * [Any](g3doc/index.md#any) + * [AwaitPromise](g3doc/index.md#awaitpromise) + * [Delay](g3doc/index.md#delay) + * [Race](g3doc/index.md#race) + * [Recover](g3doc/index.md#recover) + * [Reduce](g3doc/index.md#reduce) + * [Retry](g3doc/index.md#retry) + * [Timeout](g3doc/index.md#timeout) + * [Validate](g3doc/index.md#validate) + * [Wrap](g3doc/index.md#wrap) +* [Advanced topics](g3doc/index.md#advanced-topics) + * [Default dispatch queue](g3doc/index.md#default-dispatch-queue) + * [Ownership and retain + cycles](g3doc/index.md#ownership-and-retain-cycles) + * [Testing](g3doc/index.md#testing) + * [Objective-C <-> Swift + interoperability](g3doc/index.md#objective-c---swift-interoperability) + * [Dot-syntax in Objective-C](g3doc/index.md#dot-syntax-in-objective-c) +* [Anti-patterns](g3doc/index.md#anti-patterns) + * [Broken chain](g3doc/index.md#broken-chain) + * [Nested promises](g3doc/index.md#nested-promises) diff --git a/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+All.m b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+All.m new file mode 100644 index 0000000..bb3582a --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+All.m @@ -0,0 +1,86 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromise+All.h" + +#import "FBLPromise+Async.h" +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (AllAdditions) + ++ (FBLPromise *)all:(NSArray *)promises { + return [self onQueue:self.defaultDispatchQueue all:promises]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue all:(NSArray *)allPromises { + NSParameterAssert(queue); + NSParameterAssert(allPromises); + + if (allPromises.count == 0) { + return [[self alloc] initWithResolution:@[]]; + } + NSMutableArray *promises = [allPromises mutableCopy]; + return [self + onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + for (NSUInteger i = 0; i < promises.count; ++i) { + id promise = promises[i]; + if ([promise isKindOfClass:self]) { + continue; + } else if ([promise isKindOfClass:[NSError class]]) { + reject(promise); + return; + } else { + [promises replaceObjectAtIndex:i + withObject:[[self alloc] initWithResolution:promise]]; + } + } + for (FBLPromise *promise in promises) { + [promise observeOnQueue:queue + fulfill:^(id __unused _) { + // Wait until all are fulfilled. + for (FBLPromise *promise in promises) { + if (!promise.isFulfilled) { + return; + } + } + // If called multiple times, only the first one affects the result. + fulfill([promises valueForKey:NSStringFromSelector(@selector(value))]); + } + reject:^(NSError *error) { + reject(error); + }]; + } + }]; +} + +@end + +@implementation FBLPromise (DotSyntax_AllAdditions) + ++ (FBLPromise * (^)(NSArray *))all { + return ^(NSArray *promises) { + return [self all:promises]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, NSArray *))allOn { + return ^(dispatch_queue_t queue, NSArray *promises) { + return [self onQueue:queue all:promises]; + }; +} + +@end diff --git a/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Always.m b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Always.m new file mode 100644 index 0000000..6927442 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Always.m @@ -0,0 +1,58 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromise+Always.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (AlwaysAdditions) + +- (FBLPromise *)always:(FBLPromiseAlwaysWorkBlock)work { + return [self onQueue:FBLPromise.defaultDispatchQueue always:work]; +} + +- (FBLPromise *)onQueue:(dispatch_queue_t)queue always:(FBLPromiseAlwaysWorkBlock)work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self chainOnQueue:queue + chainedFulfill:^id(id value) { + work(); + return value; + } + chainedReject:^id(NSError *error) { + work(); + return error; + }]; +} + +@end + +@implementation FBLPromise (DotSyntax_AlwaysAdditions) + +- (FBLPromise * (^)(FBLPromiseAlwaysWorkBlock))always { + return ^(FBLPromiseAlwaysWorkBlock work) { + return [self always:work]; + }; +} + +- (FBLPromise * (^)(dispatch_queue_t, FBLPromiseAlwaysWorkBlock))alwaysOn { + return ^(dispatch_queue_t queue, FBLPromiseAlwaysWorkBlock work) { + return [self onQueue:queue always:work]; + }; +} + +@end diff --git a/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Any.m b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Any.m new file mode 100644 index 0000000..6500134 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Any.m @@ -0,0 +1,112 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromise+Any.h" + +#import "FBLPromise+Async.h" +#import "FBLPromisePrivate.h" + +static NSArray *FBLPromiseCombineValuesAndErrors(NSArray *promises) { + NSMutableArray *combinedValuesAndErrors = [[NSMutableArray alloc] init]; + for (FBLPromise *promise in promises) { + if (promise.isFulfilled) { + [combinedValuesAndErrors addObject:promise.value ?: [NSNull null]]; + continue; + } + if (promise.isRejected) { + [combinedValuesAndErrors addObject:promise.error]; + continue; + } + assert(!promise.isPending); + }; + return combinedValuesAndErrors; +} + +@implementation FBLPromise (AnyAdditions) + ++ (FBLPromise *)any:(NSArray *)promises { + return [self onQueue:FBLPromise.defaultDispatchQueue any:promises]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue any:(NSArray *)anyPromises { + NSParameterAssert(queue); + NSParameterAssert(anyPromises); + + if (anyPromises.count == 0) { + return [[self alloc] initWithResolution:@[]]; + } + NSMutableArray *promises = [anyPromises mutableCopy]; + return [self + onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + for (NSUInteger i = 0; i < promises.count; ++i) { + id promise = promises[i]; + if ([promise isKindOfClass:self]) { + continue; + } else { + [promises replaceObjectAtIndex:i + withObject:[[self alloc] initWithResolution:promise]]; + } + } + for (FBLPromise *promise in promises) { + [promise observeOnQueue:queue + fulfill:^(id __unused _) { + // Wait until all are resolved. + for (FBLPromise *promise in promises) { + if (promise.isPending) { + return; + } + } + // If called multiple times, only the first one affects the result. + fulfill(FBLPromiseCombineValuesAndErrors(promises)); + } + reject:^(NSError *error) { + BOOL atLeastOneIsFulfilled = NO; + for (FBLPromise *promise in promises) { + if (promise.isPending) { + return; + } + if (promise.isFulfilled) { + atLeastOneIsFulfilled = YES; + } + } + if (atLeastOneIsFulfilled) { + fulfill(FBLPromiseCombineValuesAndErrors(promises)); + } else { + reject(error); + } + }]; + } + }]; +} + +@end + +@implementation FBLPromise (DotSyntax_AnyAdditions) + ++ (FBLPromise * (^)(NSArray *))any { + return ^(NSArray *promises) { + return [self any:promises]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, NSArray *))anyOn { + return ^(dispatch_queue_t queue, NSArray *promises) { + return [self onQueue:queue any:promises]; + }; +} + +@end diff --git a/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Async.m b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Async.m new file mode 100644 index 0000000..bc338e9 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Async.m @@ -0,0 +1,70 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromise+Async.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (AsyncAdditions) + ++ (instancetype)async:(FBLPromiseAsyncWorkBlock)work { + return [self onQueue:self.defaultDispatchQueue async:work]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue async:(FBLPromiseAsyncWorkBlock)work { + NSParameterAssert(queue); + NSParameterAssert(work); + + FBLPromise *promise = [[self alloc] initPending]; + dispatch_group_async(FBLPromise.dispatchGroup, queue, ^{ + work( + ^(id __nullable value) { + if ([value isKindOfClass:[FBLPromise class]]) { + [(FBLPromise *)value observeOnQueue:queue + fulfill:^(id __nullable value) { + [promise fulfill:value]; + } + reject:^(NSError *error) { + [promise reject:error]; + }]; + } else { + [promise fulfill:value]; + } + }, + ^(NSError *error) { + [promise reject:error]; + }); + }); + return promise; +} + +@end + +@implementation FBLPromise (DotSyntax_AsyncAdditions) + ++ (FBLPromise* (^)(FBLPromiseAsyncWorkBlock))async { + return ^(FBLPromiseAsyncWorkBlock work) { + return [self async:work]; + }; +} + ++ (FBLPromise* (^)(dispatch_queue_t, FBLPromiseAsyncWorkBlock))asyncOn { + return ^(dispatch_queue_t queue, FBLPromiseAsyncWorkBlock work) { + return [self onQueue:queue async:work]; + }; +} + +@end diff --git a/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Await.m b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Await.m new file mode 100644 index 0000000..ea3b87a --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Await.m @@ -0,0 +1,48 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromise+Await.h" + +#import "FBLPromisePrivate.h" + +id __nullable FBLPromiseAwait(FBLPromise *promise, NSError **outError) { + assert(promise); + + static dispatch_once_t onceToken; + static dispatch_queue_t queue; + dispatch_once(&onceToken, ^{ + queue = dispatch_queue_create("com.google.FBLPromises.Await", DISPATCH_QUEUE_CONCURRENT); + }); + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + id __block resolution; + NSError __block *blockError; + [promise chainOnQueue:queue + chainedFulfill:^id(id value) { + resolution = value; + dispatch_semaphore_signal(semaphore); + return value; + } + chainedReject:^id(NSError *error) { + blockError = error; + dispatch_semaphore_signal(semaphore); + return error; + }]; + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + if (outError) { + *outError = blockError; + } + return resolution; +} diff --git a/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Catch.m b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Catch.m new file mode 100644 index 0000000..25e8ce6 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Catch.m @@ -0,0 +1,55 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromise+Catch.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (CatchAdditions) + +- (FBLPromise *)catch:(FBLPromiseCatchWorkBlock)reject { + return [self onQueue:FBLPromise.defaultDispatchQueue catch:reject]; +} + +- (FBLPromise *)onQueue:(dispatch_queue_t)queue catch:(FBLPromiseCatchWorkBlock)reject { + NSParameterAssert(queue); + NSParameterAssert(reject); + + return [self chainOnQueue:queue + chainedFulfill:nil + chainedReject:^id(NSError *error) { + reject(error); + return error; + }]; +} + +@end + +@implementation FBLPromise (DotSyntax_CatchAdditions) + +- (FBLPromise* (^)(FBLPromiseCatchWorkBlock))catch { + return ^(FBLPromiseCatchWorkBlock catch) { + return [self catch:catch]; + }; +} + +- (FBLPromise* (^)(dispatch_queue_t, FBLPromiseCatchWorkBlock))catchOn { + return ^(dispatch_queue_t queue, FBLPromiseCatchWorkBlock catch) { + return [self onQueue:queue catch:catch]; + }; +} + +@end diff --git a/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Delay.m b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Delay.m new file mode 100644 index 0000000..34626ef --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Delay.m @@ -0,0 +1,59 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromise+Delay.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (DelayAdditions) + +- (FBLPromise *)delay:(NSTimeInterval)interval { + return [self onQueue:FBLPromise.defaultDispatchQueue delay:interval]; +} + +- (FBLPromise *)onQueue:(dispatch_queue_t)queue delay:(NSTimeInterval)interval { + NSParameterAssert(queue); + + FBLPromise *promise = [[[self class] alloc] initPending]; + [self observeOnQueue:queue + fulfill:^(id __nullable value) { + dispatch_after(dispatch_time(0, (int64_t)(interval * NSEC_PER_SEC)), queue, ^{ + [promise fulfill:value]; + }); + } + reject:^(NSError *error) { + [promise reject:error]; + }]; + return promise; +} + +@end + +@implementation FBLPromise (DotSyntax_DelayAdditions) + +- (FBLPromise * (^)(NSTimeInterval))delay { + return ^(NSTimeInterval interval) { + return [self delay:interval]; + }; +} + +- (FBLPromise * (^)(dispatch_queue_t, NSTimeInterval))delayOn { + return ^(dispatch_queue_t queue, NSTimeInterval interval) { + return [self onQueue:queue delay:interval]; + }; +} + +@end diff --git a/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Do.m b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Do.m new file mode 100644 index 0000000..3839a64 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Do.m @@ -0,0 +1,59 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromise+Do.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (DoAdditions) + ++ (instancetype)do:(FBLPromiseDoWorkBlock)work { + return [self onQueue:self.defaultDispatchQueue do:work]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue do:(FBLPromiseDoWorkBlock)work { + NSParameterAssert(queue); + NSParameterAssert(work); + + FBLPromise *promise = [[self alloc] initPending]; + dispatch_group_async(FBLPromise.dispatchGroup, queue, ^{ + id value = work(); + if ([value isKindOfClass:[FBLPromise class]]) { + [(FBLPromise *)value observeOnQueue:queue + fulfill:^(id __nullable value) { + [promise fulfill:value]; + } + reject:^(NSError *error) { + [promise reject:error]; + }]; + } else { + [promise fulfill:value]; + } + }); + return promise; +} + +@end + +@implementation FBLPromise (DotSyntax_DoAdditions) + ++ (FBLPromise* (^)(dispatch_queue_t, FBLPromiseDoWorkBlock))doOn { + return ^(dispatch_queue_t queue, FBLPromiseDoWorkBlock work) { + return [self onQueue:queue do:work]; + }; +} + +@end diff --git a/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Race.m b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Race.m new file mode 100644 index 0000000..bdbc88e --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Race.m @@ -0,0 +1,65 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromise+Race.h" + +#import "FBLPromise+Async.h" +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (RaceAdditions) + ++ (instancetype)race:(NSArray *)promises { + return [self onQueue:self.defaultDispatchQueue race:promises]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue race:(NSArray *)racePromises { + NSParameterAssert(queue); + NSAssert(racePromises.count > 0, @"No promises to observe"); + + NSArray *promises = [racePromises copy]; + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + for (id promise in promises) { + if (![promise isKindOfClass:self]) { + fulfill(promise); + return; + } + } + // Subscribe all, but only the first one to resolve will change + // the resulting promise's state. + for (FBLPromise *promise in promises) { + [promise observeOnQueue:queue fulfill:fulfill reject:reject]; + } + }]; +} + +@end + +@implementation FBLPromise (DotSyntax_RaceAdditions) + ++ (FBLPromise * (^)(NSArray *))race { + return ^(NSArray *promises) { + return [self race:promises]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, NSArray *))raceOn { + return ^(dispatch_queue_t queue, NSArray *promises) { + return [self onQueue:queue race:promises]; + }; +} + +@end diff --git a/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Recover.m b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Recover.m new file mode 100644 index 0000000..0c9326a --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Recover.m @@ -0,0 +1,54 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromise+Recover.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (RecoverAdditions) + +- (FBLPromise *)recover:(FBLPromiseRecoverWorkBlock)recovery { + return [self onQueue:FBLPromise.defaultDispatchQueue recover:recovery]; +} + +- (FBLPromise *)onQueue:(dispatch_queue_t)queue recover:(FBLPromiseRecoverWorkBlock)recovery { + NSParameterAssert(queue); + NSParameterAssert(recovery); + + return [self chainOnQueue:queue + chainedFulfill:nil + chainedReject:^id(NSError *error) { + return recovery(error); + }]; +} + +@end + +@implementation FBLPromise (DotSyntax_RecoverAdditions) + +- (FBLPromise * (^)(FBLPromiseRecoverWorkBlock))recover { + return ^(FBLPromiseRecoverWorkBlock recovery) { + return [self recover:recovery]; + }; +} + +- (FBLPromise * (^)(dispatch_queue_t, FBLPromiseRecoverWorkBlock))recoverOn { + return ^(dispatch_queue_t queue, FBLPromiseRecoverWorkBlock recovery) { + return [self onQueue:queue recover:recovery]; + }; +} + +@end diff --git a/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Reduce.m b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Reduce.m new file mode 100644 index 0000000..1f3fc50 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Reduce.m @@ -0,0 +1,61 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromise+Reduce.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (ReduceAdditions) + +- (FBLPromise *)reduce:(NSArray *)items combine:(FBLPromiseReducerBlock)reducer { + return [self onQueue:FBLPromise.defaultDispatchQueue reduce:items combine:reducer]; +} + +- (FBLPromise *)onQueue:(dispatch_queue_t)queue + reduce:(NSArray *)items + combine:(FBLPromiseReducerBlock)reducer { + NSParameterAssert(queue); + NSParameterAssert(items); + NSParameterAssert(reducer); + + FBLPromise *promise = self; + for (id item in items) { + promise = [promise chainOnQueue:queue + chainedFulfill:^id(id value) { + return reducer(value, item); + } + chainedReject:nil]; + } + return promise; +} + +@end + +@implementation FBLPromise (DotSyntax_ReduceAdditions) + +- (FBLPromise * (^)(NSArray *, FBLPromiseReducerBlock))reduce { + return ^(NSArray *items, FBLPromiseReducerBlock reducer) { + return [self reduce:items combine:reducer]; + }; +} + +- (FBLPromise * (^)(dispatch_queue_t, NSArray *, FBLPromiseReducerBlock))reduceOn { + return ^(dispatch_queue_t queue, NSArray *items, FBLPromiseReducerBlock reducer) { + return [self onQueue:queue reduce:items combine:reducer]; + }; +} + +@end diff --git a/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Retry.m b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Retry.m new file mode 100644 index 0000000..01a87db --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Retry.m @@ -0,0 +1,128 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromise+Retry.h" + +#import "FBLPromisePrivate.h" + +NSInteger const FBLPromiseRetryDefaultAttemptsCount = 1; +NSTimeInterval const FBLPromiseRetryDefaultDelayInterval = 1.0; + +static void FBLPromiseRetryAttempt(FBLPromise *promise, dispatch_queue_t queue, NSInteger count, + NSTimeInterval interval, FBLPromiseRetryPredicateBlock predicate, + FBLPromiseRetryWorkBlock work) { + __auto_type retrier = ^(id __nullable value) { + if ([value isKindOfClass:[NSError class]]) { + if (count <= 0 || (predicate && !predicate(count, value))) { + [promise reject:value]; + } else { + dispatch_after(dispatch_time(0, (int64_t)(interval * NSEC_PER_SEC)), queue, ^{ + FBLPromiseRetryAttempt(promise, queue, count - 1, interval, predicate, work); + }); + } + } else { + [promise fulfill:value]; + } + }; + id value = work(); + if ([value isKindOfClass:[FBLPromise class]]) { + [(FBLPromise *)value observeOnQueue:queue fulfill:retrier reject:retrier]; + } else { + retrier(value); + } +} + +@implementation FBLPromise (RetryAdditions) + ++ (instancetype)retry:(FBLPromiseRetryWorkBlock)work { + return [self onQueue:FBLPromise.defaultDispatchQueue retry:work]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue retry:(FBLPromiseRetryWorkBlock)work { + return [self onQueue:queue attempts:FBLPromiseRetryDefaultAttemptsCount retry:work]; +} + ++ (instancetype)attempts:(NSInteger)count retry:(FBLPromiseRetryWorkBlock)work { + return [self onQueue:FBLPromise.defaultDispatchQueue attempts:count retry:work]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue + attempts:(NSInteger)count + retry:(FBLPromiseRetryWorkBlock)work { + return [self onQueue:queue + attempts:count + delay:FBLPromiseRetryDefaultDelayInterval + condition:nil + retry:work]; +} + ++ (instancetype)attempts:(NSInteger)count + delay:(NSTimeInterval)interval + condition:(nullable FBLPromiseRetryPredicateBlock)predicate + retry:(FBLPromiseRetryWorkBlock)work { + return [self onQueue:FBLPromise.defaultDispatchQueue + attempts:count + delay:interval + condition:predicate + retry:work]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue + attempts:(NSInteger)count + delay:(NSTimeInterval)interval + condition:(nullable FBLPromiseRetryPredicateBlock)predicate + retry:(FBLPromiseRetryWorkBlock)work { + NSParameterAssert(queue); + NSParameterAssert(work); + + FBLPromise *promise = [[self alloc] initPending]; + FBLPromiseRetryAttempt(promise, queue, count, interval, predicate, work); + return promise; +} + +@end + +@implementation FBLPromise (DotSyntax_RetryAdditions) + ++ (FBLPromise * (^)(FBLPromiseRetryWorkBlock))retry { + return ^id(FBLPromiseRetryWorkBlock work) { + return [self retry:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, FBLPromiseRetryWorkBlock))retryOn { + return ^id(dispatch_queue_t queue, FBLPromiseRetryWorkBlock work) { + return [self onQueue:queue retry:work]; + }; +} + ++ (FBLPromise * (^)(NSInteger, NSTimeInterval, FBLPromiseRetryPredicateBlock, + FBLPromiseRetryWorkBlock))retryAgain { + return ^id(NSInteger count, NSTimeInterval interval, FBLPromiseRetryPredicateBlock predicate, + FBLPromiseRetryWorkBlock work) { + return [self attempts:count delay:interval condition:predicate retry:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, NSInteger, NSTimeInterval, FBLPromiseRetryPredicateBlock, + FBLPromiseRetryWorkBlock))retryAgainOn { + return ^id(dispatch_queue_t queue, NSInteger count, NSTimeInterval interval, + FBLPromiseRetryPredicateBlock predicate, FBLPromiseRetryWorkBlock work) { + return [self onQueue:queue attempts:count delay:interval condition:predicate retry:work]; + }; +} + +@end diff --git a/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Testing.m b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Testing.m new file mode 100644 index 0000000..33d3536 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Testing.m @@ -0,0 +1,55 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromise+Testing.h" + +BOOL FBLWaitForPromisesWithTimeout(NSTimeInterval timeout) { + BOOL isTimedOut = NO; + NSDate *timeoutDate = [NSDate dateWithTimeIntervalSinceNow:timeout]; + static NSTimeInterval const minimalTimeout = 0.01; + static int64_t const minimalTimeToWait = (int64_t)(minimalTimeout * NSEC_PER_SEC); + dispatch_time_t waitTime = dispatch_time(DISPATCH_TIME_NOW, minimalTimeToWait); + dispatch_group_t dispatchGroup = FBLPromise.dispatchGroup; + NSRunLoop *runLoop = NSRunLoop.currentRunLoop; + while (dispatch_group_wait(dispatchGroup, waitTime)) { + isTimedOut = timeoutDate.timeIntervalSinceNow < 0.0; + if (isTimedOut) { + break; + } + [runLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:minimalTimeout]]; + } + return !isTimedOut; +} + +@implementation FBLPromise (TestingAdditions) + +// These properties are implemented in the FBLPromise class itself. +@dynamic isPending; +@dynamic isFulfilled; +@dynamic isRejected; +@dynamic value; +@dynamic error; + ++ (dispatch_group_t)dispatchGroup { + static dispatch_group_t gDispatchGroup; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + gDispatchGroup = dispatch_group_create(); + }); + return gDispatchGroup; +} + +@end diff --git a/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Then.m b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Then.m new file mode 100644 index 0000000..ab03bd1 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Then.m @@ -0,0 +1,50 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromise+Then.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (ThenAdditions) + +- (FBLPromise *)then:(FBLPromiseThenWorkBlock)work { + return [self onQueue:FBLPromise.defaultDispatchQueue then:work]; +} + +- (FBLPromise *)onQueue:(dispatch_queue_t)queue then:(FBLPromiseThenWorkBlock)work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self chainOnQueue:queue chainedFulfill:work chainedReject:nil]; +} + +@end + +@implementation FBLPromise (DotSyntax_ThenAdditions) + +- (FBLPromise* (^)(FBLPromiseThenWorkBlock))then { + return ^(FBLPromiseThenWorkBlock work) { + return [self then:work]; + }; +} + +- (FBLPromise* (^)(dispatch_queue_t, FBLPromiseThenWorkBlock))thenOn { + return ^(dispatch_queue_t queue, FBLPromiseThenWorkBlock work) { + return [self onQueue:queue then:work]; + }; +} + +@end diff --git a/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Timeout.m b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Timeout.m new file mode 100644 index 0000000..0eb3744 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Timeout.m @@ -0,0 +1,64 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromise+Timeout.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (TimeoutAdditions) + +- (FBLPromise *)timeout:(NSTimeInterval)interval { + return [self onQueue:FBLPromise.defaultDispatchQueue timeout:interval]; +} + +- (FBLPromise *)onQueue:(dispatch_queue_t)queue timeout:(NSTimeInterval)interval { + NSParameterAssert(queue); + + FBLPromise *promise = [[[self class] alloc] initPending]; + [self observeOnQueue:queue + fulfill:^(id __nullable value) { + [promise fulfill:value]; + } + reject:^(NSError *error) { + [promise reject:error]; + }]; + FBLPromise* __weak weakPromise = promise; + dispatch_after(dispatch_time(0, (int64_t)(interval * NSEC_PER_SEC)), queue, ^{ + NSError *timedOutError = [[NSError alloc] initWithDomain:FBLPromiseErrorDomain + code:FBLPromiseErrorCodeTimedOut + userInfo:nil]; + [weakPromise reject:timedOutError]; + }); + return promise; +} + +@end + +@implementation FBLPromise (DotSyntax_TimeoutAdditions) + +- (FBLPromise* (^)(NSTimeInterval))timeout { + return ^(NSTimeInterval interval) { + return [self timeout:interval]; + }; +} + +- (FBLPromise* (^)(dispatch_queue_t, NSTimeInterval))timeoutOn { + return ^(dispatch_queue_t queue, NSTimeInterval interval) { + return [self onQueue:queue timeout:interval]; + }; +} + +@end diff --git a/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Validate.m b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Validate.m new file mode 100644 index 0000000..1e21e81 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Validate.m @@ -0,0 +1,56 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromise+Validate.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (ValidateAdditions) + +- (FBLPromise*)validate:(FBLPromiseValidateWorkBlock)predicate { + return [self onQueue:FBLPromise.defaultDispatchQueue validate:predicate]; +} + +- (FBLPromise*)onQueue:(dispatch_queue_t)queue validate:(FBLPromiseValidateWorkBlock)predicate { + NSParameterAssert(queue); + NSParameterAssert(predicate); + + FBLPromiseChainedFulfillBlock chainedFulfill = ^id(id value) { + return predicate(value) ? value : + [[NSError alloc] initWithDomain:FBLPromiseErrorDomain + code:FBLPromiseErrorCodeValidationFailure + userInfo:nil]; + }; + return [self chainOnQueue:queue chainedFulfill:chainedFulfill chainedReject:nil]; +} + +@end + +@implementation FBLPromise (DotSyntax_ValidateAdditions) + +- (FBLPromise* (^)(FBLPromiseValidateWorkBlock))validate { + return ^(FBLPromiseValidateWorkBlock predicate) { + return [self validate:predicate]; + }; +} + +- (FBLPromise* (^)(dispatch_queue_t, FBLPromiseValidateWorkBlock))validateOn { + return ^(dispatch_queue_t queue, FBLPromiseValidateWorkBlock predicate) { + return [self onQueue:queue validate:predicate]; + }; +} + +@end diff --git a/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Wrap.m b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Wrap.m new file mode 100644 index 0000000..ee10951 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Wrap.m @@ -0,0 +1,420 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromise+Wrap.h" + +#import "FBLPromise+Async.h" + +@implementation FBLPromise (WrapAdditions) + ++ (instancetype)wrapCompletion:(void (^)(FBLPromiseCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapCompletion:work]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapCompletion:(void (^)(FBLPromiseCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) { + work(^{ + fulfill(nil); + }); + }]; +} + ++ (instancetype)wrapObjectCompletion:(void (^)(FBLPromiseObjectCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapObjectCompletion:work]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapObjectCompletion:(void (^)(FBLPromiseObjectCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) { + work(^(id __nullable value) { + fulfill(value); + }); + }]; +} + ++ (instancetype)wrapErrorCompletion:(void (^)(FBLPromiseErrorCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapErrorCompletion:work]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapErrorCompletion:(void (^)(FBLPromiseErrorCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + work(^(NSError *__nullable error) { + if (error) { + reject(error); + } else { + fulfill(nil); + } + }); + }]; +} + ++ (instancetype)wrapObjectOrErrorCompletion:(void (^)(FBLPromiseObjectOrErrorCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapObjectOrErrorCompletion:work]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapObjectOrErrorCompletion:(void (^)(FBLPromiseObjectOrErrorCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + work(^(id __nullable value, NSError *__nullable error) { + if (error) { + reject(error); + } else { + fulfill(value); + } + }); + }]; +} + ++ (instancetype)wrapErrorOrObjectCompletion:(void (^)(FBLPromiseErrorOrObjectCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapErrorOrObjectCompletion:work]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapErrorOrObjectCompletion:(void (^)(FBLPromiseErrorOrObjectCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + work(^(NSError *__nullable error, id __nullable value) { + if (error) { + reject(error); + } else { + fulfill(value); + } + }); + }]; +} + ++ (FBLPromise *)wrap2ObjectsOrErrorCompletion: + (void (^)(FBLPromise2ObjectsOrErrorCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrap2ObjectsOrErrorCompletion:work]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + wrap2ObjectsOrErrorCompletion:(void (^)(FBLPromise2ObjectsOrErrorCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + work(^(id __nullable value1, id __nullable value2, NSError *__nullable error) { + if (error) { + reject(error); + } else { + fulfill(@[ value1 ?: [NSNull null], value2 ?: [NSNull null] ]); + } + }); + }]; +} + ++ (FBLPromise *)wrapBoolCompletion:(void (^)(FBLPromiseBoolCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapBoolCompletion:work]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + wrapBoolCompletion:(void (^)(FBLPromiseBoolCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) { + work(^(BOOL value) { + fulfill(@(value)); + }); + }]; +} + ++ (FBLPromise *)wrapBoolOrErrorCompletion: + (void (^)(FBLPromiseBoolOrErrorCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapBoolOrErrorCompletion:work]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + wrapBoolOrErrorCompletion:(void (^)(FBLPromiseBoolOrErrorCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + work(^(BOOL value, NSError *__nullable error) { + if (error) { + reject(error); + } else { + fulfill(@(value)); + } + }); + }]; +} + ++ (FBLPromise *)wrapIntegerCompletion:(void (^)(FBLPromiseIntegerCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapIntegerCompletion:work]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + wrapIntegerCompletion:(void (^)(FBLPromiseIntegerCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) { + work(^(NSInteger value) { + fulfill(@(value)); + }); + }]; +} + ++ (FBLPromise *)wrapIntegerOrErrorCompletion: + (void (^)(FBLPromiseIntegerOrErrorCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapIntegerOrErrorCompletion:work]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + wrapIntegerOrErrorCompletion:(void (^)(FBLPromiseIntegerOrErrorCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + work(^(NSInteger value, NSError *__nullable error) { + if (error) { + reject(error); + } else { + fulfill(@(value)); + } + }); + }]; +} + ++ (FBLPromise *)wrapDoubleCompletion:(void (^)(FBLPromiseDoubleCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapDoubleCompletion:work]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + wrapDoubleCompletion:(void (^)(FBLPromiseDoubleCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:(dispatch_queue_t)queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) { + work(^(double value) { + fulfill(@(value)); + }); + }]; +} + ++ (FBLPromise *)wrapDoubleOrErrorCompletion: + (void (^)(FBLPromiseDoubleOrErrorCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapDoubleOrErrorCompletion:work]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + wrapDoubleOrErrorCompletion:(void (^)(FBLPromiseDoubleOrErrorCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + work(^(double value, NSError *__nullable error) { + if (error) { + reject(error); + } else { + fulfill(@(value)); + } + }); + }]; +} + +@end + +@implementation FBLPromise (DotSyntax_WrapAdditions) + ++ (FBLPromise * (^)(void (^)(FBLPromiseCompletion)))wrapCompletion { + return ^(void (^work)(FBLPromiseCompletion)) { + return [self wrapCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, void (^)(FBLPromiseCompletion)))wrapCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseCompletion)) { + return [self onQueue:queue wrapCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseObjectCompletion)))wrapObjectCompletion { + return ^(void (^work)(FBLPromiseObjectCompletion)) { + return [self wrapObjectCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, void (^)(FBLPromiseObjectCompletion)))wrapObjectCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseObjectCompletion)) { + return [self onQueue:queue wrapObjectCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseErrorCompletion)))wrapErrorCompletion { + return ^(void (^work)(FBLPromiseErrorCompletion)) { + return [self wrapErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, void (^)(FBLPromiseErrorCompletion)))wrapErrorCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseErrorCompletion)) { + return [self onQueue:queue wrapErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseObjectOrErrorCompletion)))wrapObjectOrErrorCompletion { + return ^(void (^work)(FBLPromiseObjectOrErrorCompletion)) { + return [self wrapObjectOrErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, + void (^)(FBLPromiseObjectOrErrorCompletion)))wrapObjectOrErrorCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseObjectOrErrorCompletion)) { + return [self onQueue:queue wrapObjectOrErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseErrorOrObjectCompletion)))wrapErrorOrObjectCompletion { + return ^(void (^work)(FBLPromiseErrorOrObjectCompletion)) { + return [self wrapErrorOrObjectCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, + void (^)(FBLPromiseErrorOrObjectCompletion)))wrapErrorOrObjectCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseErrorOrObjectCompletion)) { + return [self onQueue:queue wrapErrorOrObjectCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromise2ObjectsOrErrorCompletion))) + wrap2ObjectsOrErrorCompletion { + return ^(void (^work)(FBLPromise2ObjectsOrErrorCompletion)) { + return [self wrap2ObjectsOrErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, void (^)(FBLPromise2ObjectsOrErrorCompletion))) + wrap2ObjectsOrErrorCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromise2ObjectsOrErrorCompletion)) { + return [self onQueue:queue wrap2ObjectsOrErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseBoolCompletion)))wrapBoolCompletion { + return ^(void (^work)(FBLPromiseBoolCompletion)) { + return [self wrapBoolCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, + void (^)(FBLPromiseBoolCompletion)))wrapBoolCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseBoolCompletion)) { + return [self onQueue:queue wrapBoolCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseBoolOrErrorCompletion))) + wrapBoolOrErrorCompletion { + return ^(void (^work)(FBLPromiseBoolOrErrorCompletion)) { + return [self wrapBoolOrErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, void (^)(FBLPromiseBoolOrErrorCompletion))) + wrapBoolOrErrorCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseBoolOrErrorCompletion)) { + return [self onQueue:queue wrapBoolOrErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseIntegerCompletion)))wrapIntegerCompletion { + return ^(void (^work)(FBLPromiseIntegerCompletion)) { + return [self wrapIntegerCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, + void (^)(FBLPromiseIntegerCompletion)))wrapIntegerCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseIntegerCompletion)) { + return [self onQueue:queue wrapIntegerCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseIntegerOrErrorCompletion))) + wrapIntegerOrErrorCompletion { + return ^(void (^work)(FBLPromiseIntegerOrErrorCompletion)) { + return [self wrapIntegerOrErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, void (^)(FBLPromiseIntegerOrErrorCompletion))) + wrapIntegerOrErrorCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseIntegerOrErrorCompletion)) { + return [self onQueue:queue wrapIntegerOrErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseDoubleCompletion)))wrapDoubleCompletion { + return ^(void (^work)(FBLPromiseDoubleCompletion)) { + return [self wrapDoubleCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, + void (^)(FBLPromiseDoubleCompletion)))wrapDoubleCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseDoubleCompletion)) { + return [self onQueue:queue wrapDoubleCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseDoubleOrErrorCompletion))) + wrapDoubleOrErrorCompletion { + return ^(void (^work)(FBLPromiseDoubleOrErrorCompletion)) { + return [self wrapDoubleOrErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, void (^)(FBLPromiseDoubleOrErrorCompletion))) + wrapDoubleOrErrorCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseDoubleOrErrorCompletion)) { + return [self onQueue:queue wrapDoubleOrErrorCompletion:work]; + }; +} + +@end diff --git a/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise.m b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise.m new file mode 100644 index 0000000..666db79 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise.m @@ -0,0 +1,299 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromisePrivate.h" + +/** All states a promise can be in. */ +typedef NS_ENUM(NSInteger, FBLPromiseState) { + FBLPromiseStatePending = 0, + FBLPromiseStateFulfilled, + FBLPromiseStateRejected, +}; + +typedef void (^FBLPromiseObserver)(FBLPromiseState state, id __nullable resolution); + +static dispatch_queue_t gFBLPromiseDefaultDispatchQueue; + +@implementation FBLPromise { + /** Current state of the promise. */ + FBLPromiseState _state; + /** + Set of arbitrary objects to keep strongly while the promise is pending. + Becomes nil after the promise has been resolved. + */ + NSMutableSet *__nullable _pendingObjects; + /** + Value to fulfill the promise with. + Can be nil if the promise is still pending, was resolved with nil or after it has been rejected. + */ + id __nullable _value; + /** + Error to reject the promise with. + Can be nil if the promise is still pending or after it has been fulfilled. + */ + NSError *__nullable _error; + /** List of observers to notify when the promise gets resolved. */ + NSMutableArray *_observers; +} + ++ (void)initialize { + if (self == [FBLPromise class]) { + gFBLPromiseDefaultDispatchQueue = dispatch_get_main_queue(); + } +} + ++ (dispatch_queue_t)defaultDispatchQueue { + @synchronized(self) { + return gFBLPromiseDefaultDispatchQueue; + } +} + ++ (void)setDefaultDispatchQueue:(dispatch_queue_t)queue { + NSParameterAssert(queue); + + @synchronized(self) { + gFBLPromiseDefaultDispatchQueue = queue; + } +} + ++ (instancetype)pendingPromise { + return [[self alloc] initPending]; +} + ++ (instancetype)resolvedWith:(nullable id)resolution { + return [[self alloc] initWithResolution:resolution]; +} + +- (void)fulfill:(nullable id)value { + if ([value isKindOfClass:[NSError class]]) { + [self reject:(NSError *)value]; + } else { + @synchronized(self) { + if (_state == FBLPromiseStatePending) { + _state = FBLPromiseStateFulfilled; + _value = value; + _pendingObjects = nil; + for (FBLPromiseObserver observer in _observers) { + observer(_state, _value); + } + _observers = nil; + dispatch_group_leave(FBLPromise.dispatchGroup); + } + } + } +} + +- (void)reject:(NSError *)error { + NSAssert([error isKindOfClass:[NSError class]], @"Invalid error type."); + + if (![error isKindOfClass:[NSError class]]) { + // Give up on invalid error type in Release mode. + @throw error; // NOLINT + } + @synchronized(self) { + if (_state == FBLPromiseStatePending) { + _state = FBLPromiseStateRejected; + _error = error; + _pendingObjects = nil; + for (FBLPromiseObserver observer in _observers) { + observer(_state, _error); + } + _observers = nil; + dispatch_group_leave(FBLPromise.dispatchGroup); + } + } +} + +#pragma mark - NSObject + +- (NSString *)description { + if (self.isFulfilled) { + return [NSString stringWithFormat:@"<%@ %p> Fulfilled: %@", NSStringFromClass([self class]), + self, self.value]; + } + if (self.isRejected) { + return [NSString stringWithFormat:@"<%@ %p> Rejected: %@", NSStringFromClass([self class]), + self, self.error]; + } + return [NSString stringWithFormat:@"<%@ %p> Pending", NSStringFromClass([self class]), self]; +} + +#pragma mark - Private + +- (instancetype)initPending { + self = [super init]; + if (self) { + dispatch_group_enter(FBLPromise.dispatchGroup); + } + return self; +} + +- (instancetype)initWithResolution:(nullable id)resolution { + self = [super init]; + if (self) { + if ([resolution isKindOfClass:[NSError class]]) { + _state = FBLPromiseStateRejected; + _error = (NSError *)resolution; + } else { + _state = FBLPromiseStateFulfilled; + _value = resolution; + } + } + return self; +} + +- (void)dealloc { + if (_state == FBLPromiseStatePending) { + dispatch_group_leave(FBLPromise.dispatchGroup); + } +} + +- (BOOL)isPending { + @synchronized(self) { + return _state == FBLPromiseStatePending; + } +} + +- (BOOL)isFulfilled { + @synchronized(self) { + return _state == FBLPromiseStateFulfilled; + } +} + +- (BOOL)isRejected { + @synchronized(self) { + return _state == FBLPromiseStateRejected; + } +} + +- (nullable id)value { + @synchronized(self) { + return _value; + } +} + +- (NSError *__nullable)error { + @synchronized(self) { + return _error; + } +} + +- (void)addPendingObject:(id)object { + NSParameterAssert(object); + + @synchronized(self) { + if (_state == FBLPromiseStatePending) { + if (!_pendingObjects) { + _pendingObjects = [[NSMutableSet alloc] init]; + } + [_pendingObjects addObject:object]; + } + } +} + +- (void)observeOnQueue:(dispatch_queue_t)queue + fulfill:(FBLPromiseOnFulfillBlock)onFulfill + reject:(FBLPromiseOnRejectBlock)onReject { + NSParameterAssert(queue); + NSParameterAssert(onFulfill); + NSParameterAssert(onReject); + + @synchronized(self) { + switch (_state) { + case FBLPromiseStatePending: { + if (!_observers) { + _observers = [[NSMutableArray alloc] init]; + } + [_observers addObject:^(FBLPromiseState state, id __nullable resolution) { + dispatch_group_async(FBLPromise.dispatchGroup, queue, ^{ + switch (state) { + case FBLPromiseStatePending: + break; + case FBLPromiseStateFulfilled: + onFulfill(resolution); + break; + case FBLPromiseStateRejected: + onReject(resolution); + break; + } + }); + }]; + break; + } + case FBLPromiseStateFulfilled: { + dispatch_group_async(FBLPromise.dispatchGroup, queue, ^{ + onFulfill(self->_value); + }); + break; + } + case FBLPromiseStateRejected: { + dispatch_group_async(FBLPromise.dispatchGroup, queue, ^{ + onReject(self->_error); + }); + break; + } + } + } +} + +- (FBLPromise *)chainOnQueue:(dispatch_queue_t)queue + chainedFulfill:(FBLPromiseChainedFulfillBlock)chainedFulfill + chainedReject:(FBLPromiseChainedRejectBlock)chainedReject { + NSParameterAssert(queue); + + FBLPromise *promise = [[[self class] alloc] initPending]; + __auto_type resolver = ^(id __nullable value) { + if ([value isKindOfClass:[FBLPromise class]]) { + [(FBLPromise *)value observeOnQueue:queue + fulfill:^(id __nullable value) { + [promise fulfill:value]; + } + reject:^(NSError *error) { + [promise reject:error]; + }]; + } else { + [promise fulfill:value]; + } + }; + [self observeOnQueue:queue + fulfill:^(id __nullable value) { + value = chainedFulfill ? chainedFulfill(value) : value; + resolver(value); + } + reject:^(NSError *error) { + id value = chainedReject ? chainedReject(error) : error; + resolver(value); + }]; + return promise; +} + +@end + +@implementation FBLPromise (DotSyntaxAdditions) + ++ (instancetype (^)(void))pending { + return ^(void) { + return [self pendingPromise]; + }; +} + ++ (instancetype (^)(id __nullable))resolved { + return ^(id resolution) { + return [self resolvedWith:resolution]; + }; +} + +@end diff --git a/Pods/PromisesObjC/Sources/FBLPromises/FBLPromiseError.m b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromiseError.m new file mode 100644 index 0000000..1cc181a --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromiseError.m @@ -0,0 +1,19 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromiseError.h" + +NSErrorDomain const FBLPromiseErrorDomain = @"com.google.FBLPromises.Error"; diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+All.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+All.h new file mode 100644 index 0000000..9c0090e --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+All.h @@ -0,0 +1,63 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(AllAdditions) + +/** + Wait until all of the given promises are fulfilled. + If one of the given promises is rejected, then the returned promise is rejected with same error. + If any other arbitrary value or `NSError` appears in the array instead of `FBLPromise`, + it's implicitly considered a pre-fulfilled or pre-rejected `FBLPromise` correspondingly. + Promises resolved with `nil` become `NSNull` instances in the resulting array. + + @param promises Promises to wait for. + @return Promise of an array containing the values of input promises in the same order. + */ ++ (FBLPromise *)all:(NSArray *)promises NS_SWIFT_UNAVAILABLE(""); + +/** + Wait until all of the given promises are fulfilled. + If one of the given promises is rejected, then the returned promise is rejected with same error. + If any other arbitrary value or `NSError` appears in the array instead of `FBLPromise`, + it's implicitly considered a pre-fulfilled or pre-rejected FBLPromise correspondingly. + Promises resolved with `nil` become `NSNull` instances in the resulting array. + + @param queue A queue to dispatch on. + @param promises Promises to wait for. + @return Promise of an array containing the values of input promises in the same order. + */ ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + all:(NSArray *)promises NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `all` operators. + Usage: FBLPromise.all(@[ ... ]) + */ +@interface FBLPromise(DotSyntax_AllAdditions) + ++ (FBLPromise * (^)(NSArray *))all FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise * (^)(dispatch_queue_t, NSArray *))allOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Always.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Always.h new file mode 100644 index 0000000..13000f5 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Always.h @@ -0,0 +1,54 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(AlwaysAdditions) + +typedef void (^FBLPromiseAlwaysWorkBlock)(void) NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block that always executes, no matter if the receiver is rejected or fulfilled. + @return A new pending promise to be resolved with same resolution as the receiver. + */ +- (FBLPromise *)always:(FBLPromiseAlwaysWorkBlock)work NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to dispatch on. + @param work A block that always executes, no matter if the receiver is rejected or fulfilled. + @return A new pending promise to be resolved with same resolution as the receiver. + */ +- (FBLPromise *)onQueue:(dispatch_queue_t)queue + always:(FBLPromiseAlwaysWorkBlock)work NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `always` operators. + Usage: promise.always(^{...}) + */ +@interface FBLPromise(DotSyntax_AlwaysAdditions) + +- (FBLPromise* (^)(FBLPromiseAlwaysWorkBlock))always FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); +- (FBLPromise* (^)(dispatch_queue_t, FBLPromiseAlwaysWorkBlock))alwaysOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Any.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Any.h new file mode 100644 index 0000000..82875bf --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Any.h @@ -0,0 +1,69 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(AnyAdditions) + +/** + Waits until all of the given promises are either fulfilled or rejected. + If all promises are rejected, then the returned promise is rejected with same error + as the last one rejected. + If at least one of the promises is fulfilled, the resulting promise is fulfilled with an array of + values or `NSErrors`, matching the original order of fulfilled or rejected promises respectively. + If any other arbitrary value or `NSError` appears in the array instead of `FBLPromise`, + it's implicitly considered a pre-fulfilled or pre-rejected `FBLPromise` correspondingly. + Promises resolved with `nil` become `NSNull` instances in the resulting array. + + @param promises Promises to wait for. + @return Promise of array containing the values or `NSError`s of input promises in the same order. + */ ++ (FBLPromise *)any:(NSArray *)promises NS_SWIFT_UNAVAILABLE(""); + +/** + Waits until all of the given promises are either fulfilled or rejected. + If all promises are rejected, then the returned promise is rejected with same error + as the last one rejected. + If at least one of the promises is fulfilled, the resulting promise is fulfilled with an array of + values or `NSError`s, matching the original order of fulfilled or rejected promises respectively. + If any other arbitrary value or `NSError` appears in the array instead of `FBLPromise`, + it's implicitly considered a pre-fulfilled or pre-rejected `FBLPromise` correspondingly. + Promises resolved with `nil` become `NSNull` instances in the resulting array. + + @param queue A queue to dispatch on. + @param promises Promises to wait for. + @return Promise of array containing the values or `NSError`s of input promises in the same order. + */ ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + any:(NSArray *)promises NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `any` operators. + Usage: FBLPromise.any(@[ ... ]) + */ +@interface FBLPromise(DotSyntax_AnyAdditions) + ++ (FBLPromise * (^)(NSArray *))any FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise * (^)(dispatch_queue_t, NSArray *))anyOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Async.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Async.h new file mode 100644 index 0000000..0588a9e --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Async.h @@ -0,0 +1,60 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(AsyncAdditions) + +typedef void (^FBLPromiseFulfillBlock)(Value __nullable value) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseRejectBlock)(NSError *error) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseAsyncWorkBlock)(FBLPromiseFulfillBlock fulfill, + FBLPromiseRejectBlock reject) NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise and executes `work` block asynchronously. + + @param work A block to perform any operations needed to resolve the promise. + @return A new pending promise. + */ ++ (instancetype)async:(FBLPromiseAsyncWorkBlock)work NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise and executes `work` block asynchronously on the given queue. + + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @return A new pending promise. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue + async:(FBLPromiseAsyncWorkBlock)work NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `async` operators. + Usage: FBLPromise.async(^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { ... }) + */ +@interface FBLPromise(DotSyntax_AsyncAdditions) + ++ (FBLPromise* (^)(FBLPromiseAsyncWorkBlock))async FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, FBLPromiseAsyncWorkBlock))asyncOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Await.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Await.h new file mode 100644 index 0000000..c97a1ba --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Await.h @@ -0,0 +1,32 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + Waits for promise resolution. The current thread blocks until the promise is resolved. + + @param promise Promise to wait for. + @param error Error the promise was rejected with, or `nil` if the promise was fulfilled. + @return Value the promise was fulfilled with. If the promise was rejected, the return value + is always `nil`, but the error out arg is not. + */ +FOUNDATION_EXTERN id __nullable FBLPromiseAwait(FBLPromise *promise, + NSError **error) NS_REFINED_FOR_SWIFT; + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Catch.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Catch.h new file mode 100644 index 0000000..a9ff170 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Catch.h @@ -0,0 +1,59 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(CatchAdditions) + +typedef void (^FBLPromiseCatchWorkBlock)(NSError *error) NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise which eventually gets resolved with same resolution as the receiver. + If receiver is rejected, then `reject` block is executed asynchronously. + + @param reject A block to handle the error that receiver was rejected with. + @return A new pending promise. + */ +- (FBLPromise *)catch:(FBLPromiseCatchWorkBlock)reject NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise which eventually gets resolved with same resolution as the receiver. + If receiver is rejected, then `reject` block is executed asynchronously on the given queue. + + @param queue A queue to invoke the `reject` block on. + @param reject A block to handle the error that receiver was rejected with. + @return A new pending promise. + */ +- (FBLPromise *)onQueue:(dispatch_queue_t)queue + catch:(FBLPromiseCatchWorkBlock)reject NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `catch` operators. + Usage: promise.catch(^(NSError *error) { ... }) + */ +@interface FBLPromise(DotSyntax_CatchAdditions) + +- (FBLPromise* (^)(FBLPromiseCatchWorkBlock))catch FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); +- (FBLPromise* (^)(dispatch_queue_t, FBLPromiseCatchWorkBlock))catchOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Delay.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Delay.h new file mode 100644 index 0000000..557df48 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Delay.h @@ -0,0 +1,59 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(DelayAdditions) + +/** + Creates a new pending promise that fulfills with the same value as `self` after the `delay`, or + rejects with the same error immediately. + + @param interval Time to wait in seconds. + @return A new pending promise that fulfills at least `delay` seconds later than `self`, or rejects + with the same error immediately. + */ +- (FBLPromise *)delay:(NSTimeInterval)interval NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a new pending promise that fulfills with the same value as `self` after the `delay`, or + rejects with the same error immediately. + + @param queue A queue to dispatch on. + @param interval Time to wait in seconds. + @return A new pending promise that fulfills at least `delay` seconds later than `self`, or rejects + with the same error immediately. + */ +- (FBLPromise *)onQueue:(dispatch_queue_t)queue + delay:(NSTimeInterval)interval NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `delay` operators. + Usage: promise.delay(...) + */ +@interface FBLPromise(DotSyntax_DelayAdditions) + +- (FBLPromise * (^)(NSTimeInterval))delay FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); +- (FBLPromise * (^)(dispatch_queue_t, NSTimeInterval))delayOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Do.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Do.h new file mode 100644 index 0000000..6838e0a --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Do.h @@ -0,0 +1,55 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(DoAdditions) + +typedef id __nullable (^FBLPromiseDoWorkBlock)(void) NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise and executes `work` block asynchronously. + + @param work A block that returns a value or an error used to resolve the promise. + @return A new pending promise. + */ ++ (instancetype)do:(FBLPromiseDoWorkBlock)work NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise and executes `work` block asynchronously on the given queue. + + @param queue A queue to invoke the `work` block on. + @param work A block that returns a value or an error used to resolve the promise. + @return A new pending promise. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue do:(FBLPromiseDoWorkBlock)work NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `do` operators. + Usage: FBLPromise.doOn(queue, ^(NSError *error) { ... }) + */ +@interface FBLPromise(DotSyntax_DoAdditions) + ++ (FBLPromise * (^)(dispatch_queue_t, FBLPromiseDoWorkBlock))doOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Race.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Race.h new file mode 100644 index 0000000..2f67258 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Race.h @@ -0,0 +1,62 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(RaceAdditions) + +/** + Wait until any of the given promises are fulfilled. + If one of the promises is rejected, then the returned promise is rejected with same error. + If any other arbitrary value or `NSError` appears in the array instead of `FBLPromise`, + it's implicitly considered a pre-fulfilled or pre-rejected `FBLPromise` correspondingly. + + @param promises Promises to wait for. + @return A new pending promise to be resolved with the same resolution as the first promise, among + the given ones, which was resolved. + */ ++ (instancetype)race:(NSArray *)promises NS_SWIFT_UNAVAILABLE(""); + +/** + Wait until any of the given promises are fulfilled. + If one of the promises is rejected, then the returned promise is rejected with same error. + If any other arbitrary value or `NSError` appears in the array instead of `FBLPromise`, + it's implicitly considered a pre-fulfilled or pre-rejected `FBLPromise` correspondingly. + + @param queue A queue to dispatch on. + @param promises Promises to wait for. + @return A new pending promise to be resolved with the same resolution as the first promise, among + the given ones, which was resolved. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue race:(NSArray *)promises NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `race` operators. + Usage: FBLPromise.race(@[ ... ]) + */ +@interface FBLPromise(DotSyntax_RaceAdditions) + ++ (FBLPromise * (^)(NSArray *))race FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise * (^)(dispatch_queue_t, NSArray *))raceOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Recover.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Recover.h new file mode 100644 index 0000000..bb7df7e --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Recover.h @@ -0,0 +1,60 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(RecoverAdditions) + +typedef id __nullable (^FBLPromiseRecoverWorkBlock)(NSError *error) NS_SWIFT_UNAVAILABLE(""); + +/** + Provides a new promise to recover in case the receiver gets rejected. + + @param recovery A block to handle the error that the receiver was rejected with. + @return A new pending promise to use instead of the rejected one that gets resolved with resolution + returned from `recovery` block. + */ +- (FBLPromise *)recover:(FBLPromiseRecoverWorkBlock)recovery NS_SWIFT_UNAVAILABLE(""); + +/** + Provides a new promise to recover in case the receiver gets rejected. + + @param queue A queue to dispatch on. + @param recovery A block to handle the error that the receiver was rejected with. + @return A new pending promise to use instead of the rejected one that gets resolved with resolution + returned from `recovery` block. + */ +- (FBLPromise *)onQueue:(dispatch_queue_t)queue + recover:(FBLPromiseRecoverWorkBlock)recovery NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `recover` operators. + Usage: promise.recover(^id(NSError *error) {...}) + */ +@interface FBLPromise(DotSyntax_RecoverAdditions) + +- (FBLPromise * (^)(FBLPromiseRecoverWorkBlock))recover FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); +- (FBLPromise * (^)(dispatch_queue_t, FBLPromiseRecoverWorkBlock))recoverOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Reduce.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Reduce.h new file mode 100644 index 0000000..5bb1eee --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Reduce.h @@ -0,0 +1,71 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(ReduceAdditions) + +typedef id __nullable (^FBLPromiseReducerBlock)(Value __nullable partial, id next) + NS_SWIFT_UNAVAILABLE(""); + +/** + Sequentially reduces a collection of values to a single promise using a given combining block + and the value `self` resolves with as initial value. + + @param items An array of values to process in order. + @param reducer A block to combine an accumulating value and an element of the sequence into + the new accumulating value or a promise resolved with it, to be used in the next + call of the `reducer` or returned to the caller. + @return A new pending promise returned from the last `reducer` invocation. + Or `self` if `items` is empty. + */ +- (FBLPromise *)reduce:(NSArray *)items + combine:(FBLPromiseReducerBlock)reducer NS_SWIFT_UNAVAILABLE(""); + +/** + Sequentially reduces a collection of values to a single promise using a given combining block + and the value `self` resolves with as initial value. + + @param queue A queue to dispatch on. + @param items An array of values to process in order. + @param reducer A block to combine an accumulating value and an element of the sequence into + the new accumulating value or a promise resolved with it, to be used in the next + call of the `reducer` or returned to the caller. + @return A new pending promise returned from the last `reducer` invocation. + Or `self` if `items` is empty. + */ +- (FBLPromise *)onQueue:(dispatch_queue_t)queue + reduce:(NSArray *)items + combine:(FBLPromiseReducerBlock)reducer NS_SWIFT_UNAVAILABLE(""); + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `reduce` operators. + Usage: promise.reduce(values, ^id(id partial, id next) { ... }) + */ +@interface FBLPromise(DotSyntax_ReduceAdditions) + +- (FBLPromise * (^)(NSArray *, FBLPromiseReducerBlock))reduce FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); +- (FBLPromise * (^)(dispatch_queue_t, NSArray *, FBLPromiseReducerBlock))reduceOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Retry.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Retry.h new file mode 100644 index 0000000..414a17a --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Retry.h @@ -0,0 +1,165 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +/** The default number of retry attempts is 1. */ +FOUNDATION_EXTERN NSInteger const FBLPromiseRetryDefaultAttemptsCount NS_REFINED_FOR_SWIFT; + +/** The default delay interval before making a retry attempt is 1.0 second. */ +FOUNDATION_EXTERN NSTimeInterval const FBLPromiseRetryDefaultDelayInterval NS_REFINED_FOR_SWIFT; + +@interface FBLPromise(RetryAdditions) + +typedef id __nullable (^FBLPromiseRetryWorkBlock)(void) NS_SWIFT_UNAVAILABLE(""); +typedef BOOL (^FBLPromiseRetryPredicateBlock)(NSInteger, NSError *) NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise that fulfills with the same value as the promise returned from `work` + block, which executes asynchronously, or rejects with the same error after all retry attempts have + been exhausted. Defaults to `FBLPromiseRetryDefaultAttemptsCount` attempt(s) on rejection where the + `work` block is retried after a delay of `FBLPromiseRetryDefaultDelayInterval` second(s). + + @param work A block that executes asynchronously on the default queue and returns a value or an + error used to resolve the promise. + @return A new pending promise that fulfills with the same value as the promise returned from `work` + block, or rejects with the same error after all retry attempts have been exhausted. + */ ++ (instancetype)retry:(FBLPromiseRetryWorkBlock)work NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise that fulfills with the same value as the promise returned from `work` + block, which executes asynchronously on the given `queue`, or rejects with the same error after all + retry attempts have been exhausted. Defaults to `FBLPromiseRetryDefaultAttemptsCount` attempt(s) on + rejection where the `work` block is retried on the given `queue` after a delay of + `FBLPromiseRetryDefaultDelayInterval` second(s). + + @param queue A queue to invoke the `work` block on. + @param work A block that executes asynchronously on the given `queue` and returns a value or an + error used to resolve the promise. + @return A new pending promise that fulfills with the same value as the promise returned from `work` + block, or rejects with the same error after all retry attempts have been exhausted. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue + retry:(FBLPromiseRetryWorkBlock)work NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise that fulfills with the same value as the promise returned from `work` + block, which executes asynchronously, or rejects with the same error after all retry attempts have + been exhausted. + + @param count Max number of retry attempts. The `work` block will be executed once if the specified + count is less than or equal to zero. + @param work A block that executes asynchronously on the default queue and returns a value or an + error used to resolve the promise. + @return A new pending promise that fulfills with the same value as the promise returned from `work` + block, or rejects with the same error after all retry attempts have been exhausted. + */ ++ (instancetype)attempts:(NSInteger)count + retry:(FBLPromiseRetryWorkBlock)work NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise that fulfills with the same value as the promise returned from `work` + block, which executes asynchronously on the given `queue`, or rejects with the same error after all + retry attempts have been exhausted. + + @param queue A queue to invoke the `work` block on. + @param count Max number of retry attempts. The `work` block will be executed once if the specified + count is less than or equal to zero. + @param work A block that executes asynchronously on the given `queue` and returns a value or an + error used to resolve the promise. + @return A new pending promise that fulfills with the same value as the promise returned from `work` + block, or rejects with the same error after all retry attempts have been exhausted. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue + attempts:(NSInteger)count + retry:(FBLPromiseRetryWorkBlock)work NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise that fulfills with the same value as the promise returned from `work` + block, which executes asynchronously, or rejects with the same error after all retry attempts have + been exhausted. On rejection, the `work` block is retried after the given delay `interval` and will + continue to retry until the number of specified attempts have been exhausted or will bail early if + the given condition is not met. + + @param count Max number of retry attempts. The `work` block will be executed once if the specified + count is less than or equal to zero. + @param interval Time to wait before the next retry attempt. + @param predicate Condition to check before the next retry attempt. The predicate block provides the + the number of remaining retry attempts and the error that the promise was rejected + with. + @param work A block that executes asynchronously on the default queue and returns a value or an + error used to resolve the promise. + @return A new pending promise that fulfills with the same value as the promise returned from `work` + block, or rejects with the same error after all retry attempts have been exhausted or if + the given condition is not met. + */ ++ (instancetype)attempts:(NSInteger)count + delay:(NSTimeInterval)interval + condition:(nullable FBLPromiseRetryPredicateBlock)predicate + retry:(FBLPromiseRetryWorkBlock)work NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise that fulfills with the same value as the promise returned from `work` + block, which executes asynchronously on the given `queue`, or rejects with the same error after all + retry attempts have been exhausted. On rejection, the `work` block is retried after the given + delay `interval` and will continue to retry until the number of specified attempts have been + exhausted or will bail early if the given condition is not met. + + @param queue A queue to invoke the `work` block on. + @param count Max number of retry attempts. The `work` block will be executed once if the specified + count is less than or equal to zero. + @param interval Time to wait before the next retry attempt. + @param predicate Condition to check before the next retry attempt. The predicate block provides the + the number of remaining retry attempts and the error that the promise was rejected + with. + @param work A block that executes asynchronously on the given `queue` and returns a value or an + error used to resolve the promise. + @return A new pending promise that fulfills with the same value as the promise returned from `work` + block, or rejects with the same error after all retry attempts have been exhausted or if + the given condition is not met. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue + attempts:(NSInteger)count + delay:(NSTimeInterval)interval + condition:(nullable FBLPromiseRetryPredicateBlock)predicate + retry:(FBLPromiseRetryWorkBlock)work NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise+Retry` operators. + Usage: FBLPromise.retry(^id { ... }) + */ +@interface FBLPromise(DotSyntax_RetryAdditions) + ++ (FBLPromise * (^)(FBLPromiseRetryWorkBlock))retry FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise * (^)(dispatch_queue_t, FBLPromiseRetryWorkBlock))retryOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise * (^)(NSInteger, NSTimeInterval, FBLPromiseRetryPredicateBlock __nullable, + FBLPromiseRetryWorkBlock))retryAgain FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise * (^)(dispatch_queue_t, NSInteger, NSTimeInterval, + FBLPromiseRetryPredicateBlock __nullable, + FBLPromiseRetryWorkBlock))retryAgainOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Testing.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Testing.h new file mode 100644 index 0000000..8478ae2 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Testing.h @@ -0,0 +1,57 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + Waits for all scheduled promises blocks. + + @param timeout Maximum time to wait. + @return YES if all promises blocks have completed before the timeout and NO otherwise. + */ +FOUNDATION_EXTERN BOOL FBLWaitForPromisesWithTimeout(NSTimeInterval timeout) NS_REFINED_FOR_SWIFT; + +@interface FBLPromise(TestingAdditions) + +/** + Dispatch group for promises that is typically used to wait for all scheduled blocks. + */ +@property(class, nonatomic, readonly) dispatch_group_t dispatchGroup NS_REFINED_FOR_SWIFT; + +/** + Properties to get the current state of the promise. + */ +@property(nonatomic, readonly) BOOL isPending NS_REFINED_FOR_SWIFT; +@property(nonatomic, readonly) BOOL isFulfilled NS_REFINED_FOR_SWIFT; +@property(nonatomic, readonly) BOOL isRejected NS_REFINED_FOR_SWIFT; + +/** + Value the promise was fulfilled with. + Can be nil if the promise is still pending, was resolved with nil or after it has been rejected. + */ +@property(nonatomic, readonly, nullable) Value value NS_REFINED_FOR_SWIFT; + +/** + Error the promise was rejected with. + Can be nil if the promise is still pending or after it has been fulfilled. + */ +@property(nonatomic, readonly, nullable) NSError *error NS_REFINED_FOR_SWIFT; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Then.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Then.h new file mode 100644 index 0000000..32027e6 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Then.h @@ -0,0 +1,63 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(ThenAdditions) + +typedef id __nullable (^FBLPromiseThenWorkBlock)(Value __nullable value) NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise which eventually gets resolved with resolution returned from `work` + block: either value, error or another promise. The `work` block is executed asynchronously only + when the receiver is fulfilled. If receiver is rejected, the returned promise is also rejected with + the same error. + + @param work A block to handle the value that receiver was fulfilled with. + @return A new pending promise to be resolved with resolution returned from the `work` block. + */ +- (FBLPromise *)then:(FBLPromiseThenWorkBlock)work NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise which eventually gets resolved with resolution returned from `work` + block: either value, error or another promise. The `work` block is executed asynchronously when the + receiver is fulfilled. If receiver is rejected, the returned promise is also rejected with the same + error. + + @param queue A queue to invoke the `work` block on. + @param work A block to handle the value that receiver was fulfilled with. + @return A new pending promise to be resolved with resolution returned from the `work` block. + */ +- (FBLPromise *)onQueue:(dispatch_queue_t)queue + then:(FBLPromiseThenWorkBlock)work NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `then` operators. + Usage: promise.then(^id(id value) { ... }) + */ +@interface FBLPromise(DotSyntax_ThenAdditions) + +- (FBLPromise* (^)(FBLPromiseThenWorkBlock))then FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); +- (FBLPromise* (^)(dispatch_queue_t, FBLPromiseThenWorkBlock))thenOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Timeout.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Timeout.h new file mode 100644 index 0000000..184ba16 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Timeout.h @@ -0,0 +1,57 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(TimeoutAdditions) + +/** + Waits for a promise with the specified `timeout`. + + @param interval Time to wait in seconds. + @return A new pending promise that gets either resolved with same resolution as the receiver or + rejected with `FBLPromiseErrorCodeTimedOut` error code in `FBLPromiseErrorDomain`. + */ +- (FBLPromise *)timeout:(NSTimeInterval)interval NS_SWIFT_UNAVAILABLE(""); + +/** + Waits for a promise with the specified `timeout`. + + @param queue A queue to dispatch on. + @param interval Time to wait in seconds. + @return A new pending promise that gets either resolved with same resolution as the receiver or + rejected with `FBLPromiseErrorCodeTimedOut` error code in `FBLPromiseErrorDomain`. + */ +- (FBLPromise *)onQueue:(dispatch_queue_t)queue + timeout:(NSTimeInterval)interval NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `timeout` operators. + Usage: promise.timeout(...) + */ +@interface FBLPromise(DotSyntax_TimeoutAdditions) + +- (FBLPromise* (^)(NSTimeInterval))timeout FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); +- (FBLPromise* (^)(dispatch_queue_t, NSTimeInterval))timeoutOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Validate.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Validate.h new file mode 100644 index 0000000..9dfa2f1 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Validate.h @@ -0,0 +1,60 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(ValidateAdditions) + +typedef BOOL (^FBLPromiseValidateWorkBlock)(Value __nullable value) NS_SWIFT_UNAVAILABLE(""); + +/** + Validates a fulfilled value or rejects the value if it can not be validated. + + @param predicate An expression to validate. + @return A new pending promise that gets either resolved with same resolution as the receiver or + rejected with `FBLPromiseErrorCodeValidationFailure` error code in `FBLPromiseErrorDomain`. + */ +- (FBLPromise *)validate:(FBLPromiseValidateWorkBlock)predicate NS_SWIFT_UNAVAILABLE(""); + +/** + Validates a fulfilled value or rejects the value if it can not be validated. + + @param queue A queue to dispatch on. + @param predicate An expression to validate. + @return A new pending promise that gets either resolved with same resolution as the receiver or + rejected with `FBLPromiseErrorCodeValidationFailure` error code in `FBLPromiseErrorDomain`. + */ +- (FBLPromise *)onQueue:(dispatch_queue_t)queue + validate:(FBLPromiseValidateWorkBlock)predicate NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `validate` operators. + Usage: promise.validate(^BOOL(id value) { ... }) + */ +@interface FBLPromise(DotSyntax_ValidateAdditions) + +- (FBLPromise * (^)(FBLPromiseValidateWorkBlock))validate FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); +- (FBLPromise * (^)(dispatch_queue_t, FBLPromiseValidateWorkBlock))validateOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Wrap.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Wrap.h new file mode 100644 index 0000000..664e1bb --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Wrap.h @@ -0,0 +1,316 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + Different types of completion handlers available to be wrapped with promise. + */ +typedef void (^FBLPromiseCompletion)(void) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseObjectCompletion)(id __nullable) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseErrorCompletion)(NSError* __nullable) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseObjectOrErrorCompletion)(id __nullable, NSError* __nullable) + NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseErrorOrObjectCompletion)(NSError* __nullable, id __nullable) + NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromise2ObjectsOrErrorCompletion)(id __nullable, id __nullable, + NSError* __nullable) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseBoolCompletion)(BOOL) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseBoolOrErrorCompletion)(BOOL, NSError* __nullable) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseIntegerCompletion)(NSInteger) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseIntegerOrErrorCompletion)(NSInteger, NSError* __nullable) + NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseDoubleCompletion)(double) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseDoubleOrErrorCompletion)(double, NSError* __nullable) + NS_SWIFT_UNAVAILABLE(""); + +/** + Provides an easy way to convert methods that use common callback patterns into promises. + */ +@interface FBLPromise(WrapAdditions) + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with `nil` when completion handler is invoked. + */ ++ (instancetype)wrapCompletion:(void (^)(FBLPromiseCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with `nil` when completion handler is invoked. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapCompletion:(void (^)(FBLPromiseCompletion handler))work NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an object provided by completion handler. + */ ++ (instancetype)wrapObjectCompletion:(void (^)(FBLPromiseObjectCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an object provided by completion handler. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapObjectCompletion:(void (^)(FBLPromiseObjectCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an error provided by completion handler. + If error is `nil`, fulfills with `nil`, otherwise rejects with the error. + */ ++ (instancetype)wrapErrorCompletion:(void (^)(FBLPromiseErrorCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an error provided by completion handler. + If error is `nil`, fulfills with `nil`, otherwise rejects with the error. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapErrorCompletion:(void (^)(FBLPromiseErrorCompletion handler))work NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an object provided by completion handler if error is `nil`. + Otherwise, rejects with the error. + */ ++ (instancetype)wrapObjectOrErrorCompletion: + (void (^)(FBLPromiseObjectOrErrorCompletion handler))work NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an object provided by completion handler if error is `nil`. + Otherwise, rejects with the error. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapObjectOrErrorCompletion:(void (^)(FBLPromiseObjectOrErrorCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an error or object provided by completion handler. If error + is not `nil`, rejects with the error. + */ ++ (instancetype)wrapErrorOrObjectCompletion: + (void (^)(FBLPromiseErrorOrObjectCompletion handler))work NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an error or object provided by completion handler. If error + is not `nil`, rejects with the error. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapErrorOrObjectCompletion:(void (^)(FBLPromiseErrorOrObjectCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an array of objects provided by completion handler in order + if error is `nil`. Otherwise, rejects with the error. + */ ++ (FBLPromise*)wrap2ObjectsOrErrorCompletion: + (void (^)(FBLPromise2ObjectsOrErrorCompletion handler))work NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an array of objects provided by completion handler in order + if error is `nil`. Otherwise, rejects with the error. + */ ++ (FBLPromise*)onQueue:(dispatch_queue_t)queue + wrap2ObjectsOrErrorCompletion:(void (^)(FBLPromise2ObjectsOrErrorCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping YES/NO. + */ ++ (FBLPromise*)wrapBoolCompletion:(void (^)(FBLPromiseBoolCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping YES/NO. + */ ++ (FBLPromise*)onQueue:(dispatch_queue_t)queue + wrapBoolCompletion:(void (^)(FBLPromiseBoolCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping YES/NO when error is `nil`. + Otherwise rejects with the error. + */ ++ (FBLPromise*)wrapBoolOrErrorCompletion: + (void (^)(FBLPromiseBoolOrErrorCompletion handler))work NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping YES/NO when error is `nil`. + Otherwise rejects with the error. + */ ++ (FBLPromise*)onQueue:(dispatch_queue_t)queue + wrapBoolOrErrorCompletion:(void (^)(FBLPromiseBoolOrErrorCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping an integer. + */ ++ (FBLPromise*)wrapIntegerCompletion:(void (^)(FBLPromiseIntegerCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping an integer. + */ ++ (FBLPromise*)onQueue:(dispatch_queue_t)queue + wrapIntegerCompletion:(void (^)(FBLPromiseIntegerCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping an integer when error is `nil`. + Otherwise rejects with the error. + */ ++ (FBLPromise*)wrapIntegerOrErrorCompletion: + (void (^)(FBLPromiseIntegerOrErrorCompletion handler))work NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping an integer when error is `nil`. + Otherwise rejects with the error. + */ ++ (FBLPromise*)onQueue:(dispatch_queue_t)queue + wrapIntegerOrErrorCompletion:(void (^)(FBLPromiseIntegerOrErrorCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping a double. + */ ++ (FBLPromise*)wrapDoubleCompletion:(void (^)(FBLPromiseDoubleCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping a double. + */ ++ (FBLPromise*)onQueue:(dispatch_queue_t)queue + wrapDoubleCompletion:(void (^)(FBLPromiseDoubleCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping a double when error is `nil`. + Otherwise rejects with the error. + */ ++ (FBLPromise*)wrapDoubleOrErrorCompletion: + (void (^)(FBLPromiseDoubleOrErrorCompletion handler))work NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping a double when error is `nil`. + Otherwise rejects with the error. + */ ++ (FBLPromise*)onQueue:(dispatch_queue_t)queue + wrapDoubleOrErrorCompletion:(void (^)(FBLPromiseDoubleOrErrorCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `wrap` operators. + Usage: FBLPromise.wrapCompletion(^(FBLPromiseCompletion handler) {...}) + */ +@interface FBLPromise(DotSyntax_WrapAdditions) + ++ (FBLPromise* (^)(void (^)(FBLPromiseCompletion)))wrapCompletion FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, void (^)(FBLPromiseCompletion)))wrapCompletionOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseObjectCompletion)))wrapObjectCompletion + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, void (^)(FBLPromiseObjectCompletion)))wrapObjectCompletionOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseErrorCompletion)))wrapErrorCompletion FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, void (^)(FBLPromiseErrorCompletion)))wrapErrorCompletionOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseObjectOrErrorCompletion)))wrapObjectOrErrorCompletion + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, + void (^)(FBLPromiseObjectOrErrorCompletion)))wrapObjectOrErrorCompletionOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseErrorOrObjectCompletion)))wrapErrorOrObjectCompletion + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, + void (^)(FBLPromiseErrorOrObjectCompletion)))wrapErrorOrObjectCompletionOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromise2ObjectsOrErrorCompletion))) + wrap2ObjectsOrErrorCompletion FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, void (^)(FBLPromise2ObjectsOrErrorCompletion))) + wrap2ObjectsOrErrorCompletionOn FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseBoolCompletion)))wrapBoolCompletion + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, + void (^)(FBLPromiseBoolCompletion)))wrapBoolCompletionOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseBoolOrErrorCompletion)))wrapBoolOrErrorCompletion + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, + void (^)(FBLPromiseBoolOrErrorCompletion)))wrapBoolOrErrorCompletionOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseIntegerCompletion)))wrapIntegerCompletion + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, + void (^)(FBLPromiseIntegerCompletion)))wrapIntegerCompletionOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseIntegerOrErrorCompletion))) + wrapIntegerOrErrorCompletion FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, void (^)(FBLPromiseIntegerOrErrorCompletion))) + wrapIntegerOrErrorCompletionOn FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseDoubleCompletion)))wrapDoubleCompletion + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, + void (^)(FBLPromiseDoubleCompletion)))wrapDoubleCompletionOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseDoubleOrErrorCompletion))) + wrapDoubleOrErrorCompletion FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, void (^)(FBLPromiseDoubleOrErrorCompletion))) + wrapDoubleOrErrorCompletionOn FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise.h new file mode 100644 index 0000000..b1380dc --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise.h @@ -0,0 +1,93 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromiseError.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + Promises synchronization construct in Objective-C. + */ +@interface FBLPromise<__covariant Value> : NSObject + +/** + Default dispatch queue used for `FBLPromise`, which is `main` if a queue is not specified. + */ +@property(class) dispatch_queue_t defaultDispatchQueue NS_REFINED_FOR_SWIFT; + +/** + Creates a pending promise. + */ ++ (instancetype)pendingPromise NS_REFINED_FOR_SWIFT; + +/** + Creates a resolved promise. + + @param resolution An object to resolve the promise with: either a value or an error. + @return A new resolved promise. + */ ++ (instancetype)resolvedWith:(nullable id)resolution NS_REFINED_FOR_SWIFT; + +/** + Synchronously fulfills the promise with a value. + + @param value An arbitrary value to fulfill the promise with, including `nil`. + */ +- (void)fulfill:(nullable Value)value NS_REFINED_FOR_SWIFT; + +/** + Synchronously rejects the promise with an error. + + @param error An error to reject the promise with. + */ +- (void)reject:(NSError *)error NS_REFINED_FOR_SWIFT; + ++ (instancetype)new NS_UNAVAILABLE; +- (instancetype)init NS_UNAVAILABLE; +@end + +@interface FBLPromise() + +/** + Adds an object to the set of pending objects to keep strongly while the promise is pending. + Used by the Swift wrappers to keep them alive until the underlying ObjC promise is resolved. + + @param object An object to add. + */ +- (void)addPendingObject:(id)object NS_REFINED_FOR_SWIFT; + +@end + +#ifdef FBL_PROMISES_DOT_SYNTAX_IS_DEPRECATED +#define FBL_PROMISES_DOT_SYNTAX __attribute__((deprecated)) +#else +#define FBL_PROMISES_DOT_SYNTAX +#endif + +@interface FBLPromise(DotSyntaxAdditions) + +/** + Convenience dot-syntax wrappers for FBLPromise. + Usage: FBLPromise.pending() + FBLPromise.resolved(value) + + */ ++ (instancetype (^)(void))pending FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (instancetype (^)(id __nullable))resolved FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromiseError.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromiseError.h new file mode 100644 index 0000000..d37af53 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromiseError.h @@ -0,0 +1,43 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 + +NS_ASSUME_NONNULL_BEGIN + +FOUNDATION_EXTERN NSErrorDomain const FBLPromiseErrorDomain NS_REFINED_FOR_SWIFT; + +/** + Possible error codes in `FBLPromiseErrorDomain`. + */ +typedef NS_ENUM(NSInteger, FBLPromiseErrorCode) { + /** Promise failed to resolve in time. */ + FBLPromiseErrorCodeTimedOut = 1, + /** Validation predicate returned false. */ + FBLPromiseErrorCodeValidationFailure = 2, +} NS_REFINED_FOR_SWIFT; + +NS_INLINE BOOL FBLPromiseErrorIsTimedOut(NSError *error) NS_SWIFT_UNAVAILABLE("") { + return error.domain == FBLPromiseErrorDomain && + error.code == FBLPromiseErrorCodeTimedOut; +} + +NS_INLINE BOOL FBLPromiseErrorIsValidationFailure(NSError *error) NS_SWIFT_UNAVAILABLE("") { + return error.domain == FBLPromiseErrorDomain && + error.code == FBLPromiseErrorCodeValidationFailure; +} + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromisePrivate.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromisePrivate.h new file mode 100644 index 0000000..7a132f2 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromisePrivate.h @@ -0,0 +1,66 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromise+Testing.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + Miscellaneous low-level private interfaces available to extend standard FBLPromise functionality. + */ +@interface FBLPromise() + +typedef void (^FBLPromiseOnFulfillBlock)(Value __nullable value) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseOnRejectBlock)(NSError *error) NS_SWIFT_UNAVAILABLE(""); +typedef id __nullable (^__nullable FBLPromiseChainedFulfillBlock)(Value __nullable value) + NS_SWIFT_UNAVAILABLE(""); +typedef id __nullable (^__nullable FBLPromiseChainedRejectBlock)(NSError *error) + NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise. + */ +- (instancetype)initPending NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a resolved promise. + + @param resolution An object to resolve the promise with: either a value or an error. + @return A new resolved promise. + */ +- (instancetype)initWithResolution:(nullable id)resolution NS_SWIFT_UNAVAILABLE(""); + +/** + Invokes `fulfill` and `reject` blocks on `queue` when the receiver gets either fulfilled or + rejected respectively. + */ +- (void)observeOnQueue:(dispatch_queue_t)queue + fulfill:(FBLPromiseOnFulfillBlock)onFulfill + reject:(FBLPromiseOnRejectBlock)onReject NS_SWIFT_UNAVAILABLE(""); + +/** + Returns a new promise which gets resolved with the return value of `chainedFulfill` or + `chainedReject` blocks respectively. The blocks are invoked when the receiver gets either + fulfilled or rejected. If `nil` is passed to either block arg, the returned promise is resolved + with the same resolution as the receiver. + */ +- (FBLPromise *)chainOnQueue:(dispatch_queue_t)queue + chainedFulfill:(FBLPromiseChainedFulfillBlock)chainedFulfill + chainedReject:(FBLPromiseChainedRejectBlock)chainedReject NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromises.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromises.h new file mode 100644 index 0000000..2d90bad --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromises.h @@ -0,0 +1,32 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + 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 "FBLPromise+All.h" +#import "FBLPromise+Always.h" +#import "FBLPromise+Any.h" +#import "FBLPromise+Async.h" +#import "FBLPromise+Await.h" +#import "FBLPromise+Catch.h" +#import "FBLPromise+Delay.h" +#import "FBLPromise+Do.h" +#import "FBLPromise+Race.h" +#import "FBLPromise+Recover.h" +#import "FBLPromise+Reduce.h" +#import "FBLPromise+Retry.h" +#import "FBLPromise+Then.h" +#import "FBLPromise+Timeout.h" +#import "FBLPromise+Validate.h" +#import "FBLPromise+Wrap.h" diff --git a/Pods/Realm/LICENSE b/Pods/Realm/LICENSE new file mode 100644 index 0000000..66a27ec --- /dev/null +++ b/Pods/Realm/LICENSE @@ -0,0 +1,177 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/Pods/Realm/README.md b/Pods/Realm/README.md new file mode 100644 index 0000000..99909f7 --- /dev/null +++ b/Pods/Realm/README.md @@ -0,0 +1,171 @@ +![Realm](https://github.com/realm/realm-swift/raw/master/logo.png) + +Realm is a mobile database that runs directly inside phones, tablets or wearables. +This repository holds the source code for the iOS, macOS, tvOS & watchOS versions of Realm Swift & Realm Objective-C. + +## Why Use Realm + +* **Intuitive to Developers:** Realm’s object-oriented data model is simple to learn, doesn’t need an ORM, and lets you write less code. +* **Built for Mobile:** Realm is fully-featured, lightweight, and efficiently uses memory, disk space, and battery life. +* **Designed for Offline Use:** Realm’s local database persists data on-disk, so apps work as well offline as they do online. +* **[Device Sync](https://www.mongodb.com/atlas/app-services/device-sync)**: Makes it simple to keep data in sync across users, devices, and your backend in real-time. Get started for free with [a template application](https://github.com/mongodb/template-app-swiftui-todo) and [create the cloud backend](http://mongodb.com/realm/register?utm_medium=github_atlas_CTA&utm_source=realm_swift_github). + +## Object-Oriented: Streamline Your Code + +Realm was built for mobile developers, with simplicity in mind. The idiomatic, object-oriented data model can save you thousands of lines of code. + +```swift +// Define your models like regular Swift classes +class Dog: Object { + @Persisted var name: String + @Persisted var age: Int +} +class Person: Object { + @Persisted(primaryKey: true) var _id: String + @Persisted var name: String + @Persisted var age: Int + // Create relationships by pointing an Object field to another Class + @Persisted var dogs: List +} +// Use them like regular Swift objects +let dog = Dog() +dog.name = "Rex" +dog.age = 1 +print("name of dog: \(dog.name)") + +// Get the default Realm +let realm = try! Realm() +// Persist your data easily with a write transaction +try! realm.write { + realm.add(dog) +} +``` +## Live Objects: Build Reactive Apps +Realm’s live objects mean data updated anywhere is automatically updated everywhere. +```swift +// Open the default realm. +let realm = try! Realm() + +var token: NotificationToken? + +let dog = Dog() +dog.name = "Max" + +// Create a dog in the realm. +try! realm.write { + realm.add(dog) +} + +// Set up the listener & observe object notifications. +token = dog.observe { change in + switch change { + case .change(let properties): + for property in properties { + print("Property '\(property.name)' changed to '\(property.newValue!)'"); + } + case .error(let error): + print("An error occurred: (error)") + case .deleted: + print("The object was deleted.") + } +} + +// Update the dog's name to see the effect. +try! realm.write { + dog.name = "Wolfie" +} +``` +### SwiftUI +Realm integrates directly with SwiftUI, updating your views so you don't have to. +```swift +struct ContactsView: View { + @ObservedResults(Person.self) var persons + + var body: some View { + List { + ForEach(persons) { person in + Text(person.name) + } + .onMove(perform: $persons.move) + .onDelete(perform: $persons.remove) + }.navigationBarItems(trailing: + Button("Add") { + $persons.append(Person()) + } + ) + } +} +``` + +## Fully Encrypted +Data can be encrypted in-flight and at-rest, keeping even the most sensitive data secure. +```swift +// Generate a random encryption key +var key = Data(count: 64) +_ = key.withUnsafeMutableBytes { bytes in + SecRandomCopyBytes(kSecRandomDefault, 64, bytes) +} + +// Add the encryption key to the config and open the realm +let config = Realm.Configuration(encryptionKey: key) +let realm = try Realm(configuration: config) + +// Use the Realm as normal +let dogs = realm.objects(Dog.self).filter("name contains 'Fido'") +``` + +## Getting Started + +We support installing Realm via Swift Package Manager, CocoaPods, Carthage, or by importing a dynamic XCFramework. + +For more information, see the detailed instructions in our [docs](https://docs.mongodb.com/realm/sdk/ios/install/). + +Interested in getting started for free with [a template application](https://github.com/mongodb/template-app-swiftui-todo) that includes a cloud backend and Sync? [Create a MongoDB Atlas Account](http://mongodb.com/realm/register?utm_medium=github_atlas_CTA&utm_source=realm_swift_github). + +## Documentation + +The documentation can be found at [docs.mongodb.com/realm/sdk/ios/](https://docs.mongodb.com/realm/sdk/ios/). +The API reference is located at [docs.mongodb.com/realm-sdks/swift/latest/](https://docs.mongodb.com/realm-sdks/swift/latest/) + +## Getting Help + +- **Need help with your code?**: Look for previous questions with the[`realm` tag](https://stackoverflow.com/questions/tagged/realm?sort=newest) on Stack Overflow or [ask a new question](https://stackoverflow.com/questions/ask?tags=realm). For general discussion that might be considered too broad for Stack Overflow, use the [Community Forum](https://developer.mongodb.com/community/forums/tags/c/realm-sdks/58/swift/). +- **Have a bug to report?** [Open a GitHub issue](https://github.com/realm/realm-swift/issues/new). If possible, include the version of Realm, a full log, the Realm file, and a project that shows the issue. +- **Have a feature request?** [Open a GitHub issue](https://github.com/realm/realm-swift/issues/new). Tell us what the feature should do and why you want the feature. + +## Building Realm + +In case you don't want to use the precompiled version, you can build Realm yourself from source. + +Prerequisites: + +* Building Realm requires Xcode 11.x or newer. +* Building Realm documentation requires [jazzy](https://github.com/realm/jazzy) + +Once you have all the necessary prerequisites, building Realm.framework just takes a single command: `sh build.sh build`. You'll need an internet connection the first time you build Realm to download the core binary. + +Run `sh build.sh help` to see all the actions you can perform (build ios/osx, generate docs, test, etc.). + +## Contributing + +See [CONTRIBUTING.md](CONTRIBUTING.md) for more details! + +## Code of Conduct + +This project adheres to the [MongoDB Code of Conduct](https://www.mongodb.com/community-code-of-conduct). +By participating, you are expected to uphold this code. Please report +unacceptable behavior to [community-conduct@mongodb.com](mailto:community-conduct@mongodb.com). + +## License + +Realm Objective-C & Realm Swift are published under the Apache 2.0 license. +Realm Core is also published under the Apache 2.0 license and is available +[here](https://github.com/realm/realm-core). + +## Feedback + +**_If you use Realm and are happy with it, please consider sending out a tweet mentioning [@realm](https://twitter.com/realm) to share your thoughts!_** + +**_And if you don't like it, please let us know what you would like improved, so we can fix it!_** + + diff --git a/Pods/Realm/Realm/NSError+RLMSync.m b/Pods/Realm/Realm/NSError+RLMSync.m new file mode 100644 index 0000000..4825c01 --- /dev/null +++ b/Pods/Realm/Realm/NSError+RLMSync.m @@ -0,0 +1,43 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2017 Realm Inc. +// +// 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 "NSError+RLMSync.h" + +#import "RLMError.h" + +@implementation NSError (RLMSync) + +- (RLMSyncErrorActionToken *)rlmSync_errorActionToken { + if (self.domain != RLMSyncErrorDomain) { + return nil; + } + if (self.code == RLMSyncErrorClientResetError + || self.code == RLMSyncErrorPermissionDeniedError) { + return (RLMSyncErrorActionToken *)self.userInfo[kRLMSyncErrorActionTokenKey]; + } + return nil; +} + +- (NSString *)rlmSync_clientResetBackedUpRealmPath { + if (self.domain == RLMSyncErrorDomain && self.code == RLMSyncErrorClientResetError) { + return self.userInfo[kRLMSyncPathOfRealmBackupCopyKey]; + } + return nil; +} + +@end diff --git a/Pods/Realm/Realm/RLMAPIKeyAuth.mm b/Pods/Realm/Realm/RLMAPIKeyAuth.mm new file mode 100644 index 0000000..ded32cc --- /dev/null +++ b/Pods/Realm/Realm/RLMAPIKeyAuth.mm @@ -0,0 +1,90 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 "RLMAPIKeyAuth.h" +#import "RLMProviderClient_Private.hpp" + +#import "RLMApp_Private.hpp" +#import "RLMUserAPIKey_Private.hpp" +#import "RLMObjectId_Private.hpp" + +using namespace realm::app; + +@implementation RLMAPIKeyAuth + +- (App::UserAPIKeyProviderClient)client { + return self.app._realmApp->provider_client(); +} + +- (std::shared_ptr)currentUser { + return self.app._realmApp->current_user(); +} + +static realm::util::UniqueFunction)> +wrapCompletion(RLMOptionalUserAPIKeyBlock completion) { + return [completion](App::UserAPIKey userAPIKey, std::optional error) { + if (error) { + return completion(nil, makeError(*error)); + } + return completion([[RLMUserAPIKey alloc] initWithUserAPIKey:userAPIKey], nil); + }; +} + +- (void)createAPIKeyWithName:(NSString *)name + completion:(RLMOptionalUserAPIKeyBlock)completion { + self.client.create_api_key(name.UTF8String, self.currentUser, wrapCompletion(completion)); +} + +- (void)fetchAPIKey:(RLMObjectId *)objectId + completion:(RLMOptionalUserAPIKeyBlock)completion { + self.client.fetch_api_key(objectId.value, self.currentUser, wrapCompletion(completion)); +} + +- (void)fetchAPIKeysWithCompletion:(RLMUserAPIKeysBlock)completion { + self.client.fetch_api_keys(self.currentUser, + ^(const std::vector& userAPIKeys, + std::optional error) { + if (error) { + return completion(nil, makeError(*error)); + } + + NSMutableArray *apiKeys = [[NSMutableArray alloc] init]; + for (auto &userAPIKey : userAPIKeys) { + [apiKeys addObject:[[RLMUserAPIKey alloc] initWithUserAPIKey:userAPIKey]]; + } + + return completion(apiKeys, nil); + }); +} + +- (void)deleteAPIKey:(RLMObjectId *)objectId + completion:(RLMAPIKeyAuthOptionalErrorBlock)completion { + self.client.delete_api_key(objectId.value, self.currentUser, RLMWrapCompletion(completion)); +} + +- (void)enableAPIKey:(RLMObjectId *)objectId + completion:(RLMAPIKeyAuthOptionalErrorBlock)completion { + self.client.enable_api_key(objectId.value, self.currentUser, RLMWrapCompletion(completion)); +} + +- (void)disableAPIKey:(RLMObjectId *)objectId + completion:(RLMAPIKeyAuthOptionalErrorBlock)completion { + self.client.disable_api_key(objectId.value, self.currentUser, RLMWrapCompletion(completion)); +} + +@end diff --git a/Pods/Realm/Realm/RLMAccessor.mm b/Pods/Realm/Realm/RLMAccessor.mm new file mode 100644 index 0000000..2b98bbd --- /dev/null +++ b/Pods/Realm/Realm/RLMAccessor.mm @@ -0,0 +1,1197 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// 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 "RLMAccessor.hpp" + +#import "RLMArray_Private.hpp" +#import "RLMDictionary_Private.hpp" +#import "RLMObjectId_Private.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObjectStore.h" +#import "RLMObject_Private.hpp" +#import "RLMObservation.hpp" +#import "RLMProperty_Private.h" +#import "RLMRealm_Private.hpp" +#import "RLMResults_Private.hpp" +#import "RLMSchema_Private.h" +#import "RLMSet_Private.hpp" +#import "RLMSwiftProperty.h" +#import "RLMUUID_Private.hpp" +#import "RLMUtil.hpp" + +#import +#import + +#import +#import + +#pragma mark Helper functions + +using realm::ColKey; + +namespace realm { +template<> +Obj Obj::get(ColKey col) const { + ObjKey key = get(col); + return key ? get_target_table(col)->get_object(key) : Obj(); +} + +} // namespace realm + +namespace { +realm::Property const& getProperty(__unsafe_unretained RLMObjectBase *const obj, NSUInteger index) { + return obj->_info->objectSchema->persisted_properties[index]; +} + +realm::Property const& getProperty(__unsafe_unretained RLMObjectBase *const obj, + __unsafe_unretained RLMProperty *const prop) { + if (prop.linkOriginPropertyName) { + return obj->_info->objectSchema->computed_properties[prop.index]; + } + return obj->_info->objectSchema->persisted_properties[prop.index]; +} + +template +bool isNull(T const& v) { + return !v; +} +template<> +bool isNull(realm::Timestamp const& v) { + return v.is_null(); +} +template<> +bool isNull(realm::ObjectId const&) { + return false; +} +template<> +bool isNull(realm::Decimal128 const& v) { + return v.is_null(); +} +template<> +bool isNull(realm::Mixed const& v) { + return v.is_null(); +} +template<> +bool isNull(realm::UUID const&) { + return false; +} + +template +T get(__unsafe_unretained RLMObjectBase *const obj, NSUInteger index) { + RLMVerifyAttached(obj); + return obj->_row.get(getProperty(obj, index).column_key); +} + +template +id getBoxed(__unsafe_unretained RLMObjectBase *const obj, NSUInteger index) { + RLMVerifyAttached(obj); + auto& prop = getProperty(obj, index); + RLMAccessorContext ctx(obj, &prop); + auto value = obj->_row.get(prop.column_key); + return isNull(value) ? nil : ctx.box(std::move(value)); +} + +template +T getOptional(__unsafe_unretained RLMObjectBase *const obj, uint16_t key, bool *gotValue) { + auto ret = get>(obj, key); + if (ret) { + *gotValue = true; + } + return ret.value_or(T{}); +} + +template +void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key, T val) { + obj->_row.set(key, val); +} + +template +void setValueOrNull(__unsafe_unretained RLMObjectBase *const obj, ColKey col, + __unsafe_unretained id const value) { + RLMVerifyInWriteTransaction(obj); + + RLMTranslateError([&] { + if (value) { + if constexpr (std::is_same_v) { + obj->_row.set(col, RLMObjcToMixed(value, obj->_realm, realm::CreatePolicy::SetLink)); + } + else { + RLMStatelessAccessorContext ctx; + obj->_row.set(col, ctx.unbox(value)); + } + } + else { + obj->_row.set_null(col); + } + }); +} + +void setValue(__unsafe_unretained RLMObjectBase *const obj, + ColKey key, __unsafe_unretained NSDate *const date) { + setValueOrNull(obj, key, date); +} + +void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key, + __unsafe_unretained NSData *const value) { + setValueOrNull(obj, key, value); +} + +void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key, + __unsafe_unretained NSString *const value) { + setValueOrNull(obj, key, value); +} + +void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key, + __unsafe_unretained RLMObjectBase *const val) { + if (!val) { + obj->_row.set(key, realm::null()); + return; + } + + if (!val->_row) { + RLMAccessorContext{obj, key}.createObject(val, {.create = true}, false, {}); + } + + // make sure it is the correct type + auto table = val->_row.get_table(); + if (table != obj->_row.get_table()->get_link_target(key)) { + @throw RLMException(@"Can't set object of type '%@' to property of type '%@'", + val->_objectSchema.className, + obj->_info->propertyForTableColumn(key).objectClassName); + } + if (!table->is_embedded()) { + obj->_row.set(key, val->_row.get_key()); + } + else if (obj->_row.get_linked_object(key).get_key() != val->_row.get_key()) { + @throw RLMException(@"Can't set link to existing managed embedded object"); + } +} + +id RLMCollectionClassForProperty(RLMProperty *prop, bool isManaged) { + Class cls = nil; + if (prop.array) { + cls = isManaged ? [RLMManagedArray class] : [RLMArray class]; + } else if (prop.set) { + cls = isManaged ? [RLMManagedSet class] : [RLMSet class]; + } else if (prop.dictionary) { + cls = isManaged ? [RLMManagedDictionary class] : [RLMDictionary class]; + } else { + @throw RLMException(@"Invalid collection '%@' for class '%@'.", + prop.name, prop.objectClassName); + } + return cls; +} + +// collection getter/setter +id getCollection(__unsafe_unretained RLMObjectBase *const obj, NSUInteger propIndex) { + RLMVerifyAttached(obj); + auto prop = obj->_info->rlmObjectSchema.properties[propIndex]; + Class cls = RLMCollectionClassForProperty(prop, true); + return [[cls alloc] initWithParent:obj property:prop]; +} + +template +void assignValue(__unsafe_unretained RLMObjectBase *const obj, + __unsafe_unretained RLMProperty *const prop, + ColKey key, + __unsafe_unretained id const value) { + auto info = obj->_info; + Collection collection(obj->_realm->_realm, obj->_row, key); + if (collection.get_type() == realm::PropertyType::Object) { + info = &obj->_info->linkTargetType(prop.index); + } + RLMAccessorContext ctx(*info); + RLMTranslateError([&] { + collection.assign(ctx, value, realm::CreatePolicy::ForceCreate); + }); +} + +void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key, + __unsafe_unretained id const value) { + auto prop = obj->_info->propertyForTableColumn(key); + RLMValidateValueForProperty(value, obj->_info->rlmObjectSchema, prop, true); + + if (prop.array) { + assignValue(obj, prop, key, value); + } + else if (prop.set) { + assignValue(obj, prop, key, value); + } + else if (prop.dictionary) { + assignValue(obj, prop, key, value); + } +} + +void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key, + __unsafe_unretained NSNumber *const intObject) { + setValueOrNull(obj, key, intObject); +} + +void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key, + __unsafe_unretained NSNumber *const floatObject) { + setValueOrNull(obj, key, floatObject); +} + +void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key, + __unsafe_unretained NSNumber *const doubleObject) { + setValueOrNull(obj, key, doubleObject); +} + +void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key, + __unsafe_unretained NSNumber *const boolObject) { + setValueOrNull(obj, key, boolObject); +} + +void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key, + __unsafe_unretained RLMDecimal128 *const value) { + setValueOrNull(obj, key, value); +} + +void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key, + __unsafe_unretained RLMObjectId *const value) { + setValueOrNull(obj, key, value); +} + +void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key, + __unsafe_unretained NSUUID *const value) { + setValueOrNull(obj, key, value); +} + +void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key, + __unsafe_unretained id const value) { + setValueOrNull(obj, key, value); +} + +RLMLinkingObjects *getLinkingObjects(__unsafe_unretained RLMObjectBase *const obj, + __unsafe_unretained RLMProperty *const property) { + RLMVerifyAttached(obj); + auto& objectInfo = obj->_realm->_info[property.objectClassName]; + auto& linkOrigin = obj->_info->objectSchema->computed_properties[property.index].link_origin_property_name; + auto linkingProperty = objectInfo.objectSchema->property_for_name(linkOrigin); + auto backlinkView = obj->_row.get_backlink_view(objectInfo.table(), linkingProperty->column_key); + realm::Results results(obj->_realm->_realm, std::move(backlinkView)); + return [RLMLinkingObjects resultsWithObjectInfo:objectInfo results:std::move(results)]; +} + +// any getter/setter +template +id makeGetter(NSUInteger index) { + return ^(__unsafe_unretained RLMObjectBase *const obj) { + return static_cast(get(obj, index)); + }; +} + +template +id makeBoxedGetter(NSUInteger index) { + return ^(__unsafe_unretained RLMObjectBase *const obj) { + return getBoxed(obj, index); + }; +} +template +id makeOptionalGetter(NSUInteger index) { + return ^(__unsafe_unretained RLMObjectBase *const obj) { + return getBoxed>(obj, index); + }; +} +template +id makeNumberGetter(NSUInteger index, bool boxed, bool optional) { + if (optional) { + return makeOptionalGetter(index); + } + if (boxed) { + return makeBoxedGetter(index); + } + return makeGetter(index); +} +template +id makeWrapperGetter(NSUInteger index, bool optional) { + if (optional) { + return makeOptionalGetter(index); + } + return makeBoxedGetter(index); +} + +// dynamic getter with column closure +id managedGetter(RLMProperty *prop, const char *type) { + NSUInteger index = prop.index; + if (prop.collection && prop.type != RLMPropertyTypeLinkingObjects) { + return ^id(__unsafe_unretained RLMObjectBase *const obj) { + return getCollection(obj, index); + }; + } + + bool boxed = *type == '@'; + switch (prop.type) { + case RLMPropertyTypeInt: + if (prop.optional || boxed) { + return makeNumberGetter(index, boxed, prop.optional); + } + switch (*type) { + case 'c': return makeGetter(index); + case 's': return makeGetter(index); + case 'i': return makeGetter(index); + case 'l': return makeGetter(index); + case 'q': return makeGetter(index); + default: + @throw RLMException(@"Unexpected property type for Objective-C type code"); + } + case RLMPropertyTypeFloat: + return makeNumberGetter(index, boxed, prop.optional); + case RLMPropertyTypeDouble: + return makeNumberGetter(index, boxed, prop.optional); + case RLMPropertyTypeBool: + return makeNumberGetter(index, boxed, prop.optional); + case RLMPropertyTypeString: + return makeBoxedGetter(index); + case RLMPropertyTypeDate: + return makeBoxedGetter(index); + case RLMPropertyTypeData: + return makeBoxedGetter(index); + case RLMPropertyTypeObject: + return makeBoxedGetter(index); + case RLMPropertyTypeDecimal128: + return makeBoxedGetter(index); + case RLMPropertyTypeObjectId: + return makeWrapperGetter(index, prop.optional); + case RLMPropertyTypeAny: + // Mixed is represented as optional in Core, + // but not in Cocoa. We use `makeBoxedGetter` over + // `makeWrapperGetter` becuase Mixed can box a `null` representation. + return makeBoxedGetter(index); + case RLMPropertyTypeLinkingObjects: + return ^(__unsafe_unretained RLMObjectBase *const obj) { + return getLinkingObjects(obj, prop); + }; + case RLMPropertyTypeUUID: + return makeWrapperGetter(index, prop.optional); + } +} + +static realm::ColKey willChange(RLMObservationTracker& tracker, + __unsafe_unretained RLMObjectBase *const obj, NSUInteger index) { + auto& prop = getProperty(obj, index); + if (prop.is_primary) { + @throw RLMException(@"Primary key can't be changed after an object is inserted."); + } + tracker.willChange(RLMGetObservationInfo(obj->_observationInfo, obj->_row.get_key(), *obj->_info), + obj->_objectSchema.properties[index].name); + return prop.column_key; +} + +template +void kvoSetValue(__unsafe_unretained RLMObjectBase *const obj, NSUInteger index, ArgType value) { + RLMVerifyInWriteTransaction(obj); + RLMObservationTracker tracker(obj->_realm); + auto key = willChange(tracker, obj, index); + if constexpr (std::is_same_v) { + tracker.trackDeletions(); + } + setValue(obj, key, static_cast(value)); +} + +template +id makeSetter(__unsafe_unretained RLMProperty *const prop) { + if (prop.isPrimary) { + return ^(__unused RLMObjectBase *obj, __unused ArgType val) { + @throw RLMException(@"Primary key can't be changed after an object is inserted."); + }; + } + + NSUInteger index = prop.index; + return ^(__unsafe_unretained RLMObjectBase *const obj, ArgType val) { + kvoSetValue(obj, index, val); + }; +} + +// dynamic setter with column closure +id managedSetter(RLMProperty *prop, const char *type) { + if (prop.collection && prop.type != RLMPropertyTypeLinkingObjects) { + return makeSetter>(prop); + } + + bool boxed = prop.optional || *type == '@'; + switch (prop.type) { + case RLMPropertyTypeInt: + if (boxed) { + return makeSetter *>(prop); + } + switch (*type) { + case 'c': return makeSetter(prop); + case 's': return makeSetter(prop); + case 'i': return makeSetter(prop); + case 'l': return makeSetter(prop); + case 'q': return makeSetter(prop); + default: + @throw RLMException(@"Unexpected property type for Objective-C type code"); + } + case RLMPropertyTypeFloat: + return boxed ? makeSetter *>(prop) : makeSetter(prop); + case RLMPropertyTypeDouble: + return boxed ? makeSetter *>(prop) : makeSetter(prop); + case RLMPropertyTypeBool: + return boxed ? makeSetter *>(prop) : makeSetter(prop); + case RLMPropertyTypeString: return makeSetter(prop); + case RLMPropertyTypeDate: return makeSetter(prop); + case RLMPropertyTypeData: return makeSetter(prop); + case RLMPropertyTypeAny: return makeSetter>(prop); + case RLMPropertyTypeLinkingObjects: return nil; + case RLMPropertyTypeObject: return makeSetter(prop); + case RLMPropertyTypeObjectId: return makeSetter(prop); + case RLMPropertyTypeDecimal128: return makeSetter(prop); + case RLMPropertyTypeUUID: return makeSetter(prop); + } +} + +// call getter for superclass for property at key +id superGet(RLMObjectBase *obj, NSString *propName) { + typedef id (*getter_type)(RLMObjectBase *, SEL); + RLMProperty *prop = obj->_objectSchema[propName]; + Class superClass = class_getSuperclass(obj.class); + getter_type superGetter = (getter_type)[superClass instanceMethodForSelector:prop.getterSel]; + return superGetter(obj, prop.getterSel); +} + +// call setter for superclass for property at key +void superSet(RLMObjectBase *obj, NSString *propName, id val) { + typedef void (*setter_type)(RLMObjectBase *, SEL, id collection); + RLMProperty *prop = obj->_objectSchema[propName]; + Class superClass = class_getSuperclass(obj.class); + setter_type superSetter = (setter_type)[superClass instanceMethodForSelector:prop.setterSel]; + superSetter(obj, prop.setterSel, val); +} + +// getter/setter for unmanaged object +id unmanagedGetter(RLMProperty *prop, const char *) { + // only override getters for RLMCollection and linking objects properties + if (prop.type == RLMPropertyTypeLinkingObjects) { + return ^(RLMObjectBase *) { return [RLMResults emptyDetachedResults]; }; + } + if (prop.collection) { + NSString *propName = prop.name; + Class cls = RLMCollectionClassForProperty(prop, false); + if (prop.type == RLMPropertyTypeObject) { + NSString *objectClassName = prop.objectClassName; + RLMPropertyType keyType = prop.dictionaryKeyType; + return ^(RLMObjectBase *obj) { + id val = superGet(obj, propName); + if (!val) { + val = [[cls alloc] initWithObjectClassName:objectClassName keyType:keyType]; + superSet(obj, propName, val); + } + return val; + }; + } + auto type = prop.type; + auto optional = prop.optional; + auto dictionaryKeyType = prop.dictionaryKeyType; + return ^(RLMObjectBase *obj) { + id val = superGet(obj, propName); + if (!val) { + val = [[cls alloc] initWithObjectType:type optional:optional keyType:dictionaryKeyType]; + superSet(obj, propName, val); + } + return val; + }; + } + return nil; +} + +id unmanagedSetter(RLMProperty *prop, const char *) { + // Only RLMCollection types need special handling for the unmanaged setter + if (!prop.collection) { + return nil; + } + + NSString *propName = prop.name; + return ^(RLMObjectBase *obj, id values) { + auto prop = obj->_objectSchema[propName]; + RLMValidateValueForProperty(values, obj->_objectSchema, prop, true); + + Class cls = RLMCollectionClassForProperty(prop, false); + id collection; + // make copy when setting (as is the case for all other variants) + if (prop.type == RLMPropertyTypeObject) { + collection = [[cls alloc] initWithObjectClassName:prop.objectClassName keyType:prop.dictionaryKeyType]; + } + else { + collection = [[cls alloc] initWithObjectType:prop.type optional:prop.optional keyType:prop.dictionaryKeyType]; + } + + if (prop.dictionary) + [collection addEntriesFromDictionary:(id)values]; + else + [collection addObjects:values]; + superSet(obj, propName, collection); + }; +} + +void addMethod(Class cls, __unsafe_unretained RLMProperty *const prop, + id (*getter)(RLMProperty *, const char *), + id (*setter)(RLMProperty *, const char *)) { + SEL sel = prop.getterSel; + if (!sel) { + return; + } + auto getterMethod = class_getInstanceMethod(cls, sel); + if (!getterMethod) { + return; + } + + const char *getterType = method_getTypeEncoding(getterMethod); + if (id block = getter(prop, getterType)) { + class_addMethod(cls, sel, imp_implementationWithBlock(block), getterType); + } + + if (!(sel = prop.setterSel)) { + return; + } + auto setterMethod = class_getInstanceMethod(cls, sel); + if (!setterMethod) { + return; + } + if (id block = setter(prop, getterType)) { // note: deliberately getterType as it's easier to grab the relevant type from + class_addMethod(cls, sel, imp_implementationWithBlock(block), method_getTypeEncoding(setterMethod)); + } +} + +Class createAccessorClass(Class objectClass, + RLMObjectSchema *schema, + const char *accessorClassName, + id (*getterGetter)(RLMProperty *, const char *), + id (*setterGetter)(RLMProperty *, const char *)) { + REALM_ASSERT_DEBUG(RLMIsObjectOrSubclass(objectClass)); + + // create and register proxy class which derives from object class + Class accClass = objc_allocateClassPair(objectClass, accessorClassName, 0); + if (!accClass) { + // Class with that name already exists, so just return the pre-existing one + // This should only happen for our standalone "accessors" + return objc_lookUpClass(accessorClassName); + } + + // override getters/setters for each propery + for (RLMProperty *prop in schema.properties) { + addMethod(accClass, prop, getterGetter, setterGetter); + } + for (RLMProperty *prop in schema.computedProperties) { + addMethod(accClass, prop, getterGetter, setterGetter); + } + + objc_registerClassPair(accClass); + + return accClass; +} + +bool requiresUnmanagedAccessor(RLMObjectSchema *schema) { + for (RLMProperty *prop in schema.properties) { + if (prop.collection && !prop.swiftIvar) { + return true; + } + } + for (RLMProperty *prop in schema.computedProperties) { + if (prop.collection && !prop.swiftIvar) { + return true; + } + } + return false; +} +} // anonymous namespace + +#pragma mark - Public Interface + +Class RLMManagedAccessorClassForObjectClass(Class objectClass, RLMObjectSchema *schema, const char *name) { + return createAccessorClass(objectClass, schema, name, managedGetter, managedSetter); +} + +Class RLMUnmanagedAccessorClassForObjectClass(Class objectClass, RLMObjectSchema *schema) { + if (!requiresUnmanagedAccessor(schema)) { + return objectClass; + } + return createAccessorClass(objectClass, schema, + [@"RLM:Unmanaged " stringByAppendingString:schema.className].UTF8String, + unmanagedGetter, unmanagedSetter); +} + +// implement the class method className on accessors to return the className of the +// base object +void RLMReplaceClassNameMethod(Class accessorClass, NSString *className) { + Class metaClass = object_getClass(accessorClass); + IMP imp = imp_implementationWithBlock(^(Class) { return className; }); + class_addMethod(metaClass, @selector(className), imp, "@@:"); +} + +// implement the shared schema method +void RLMReplaceSharedSchemaMethod(Class accessorClass, RLMObjectSchema *schema) { + REALM_ASSERT(accessorClass != [RealmSwiftObject class]); + Class metaClass = object_getClass(accessorClass); + IMP imp = imp_implementationWithBlock(^(Class cls) { + if (cls == accessorClass) { + return schema; + } + + // If we aren't being called directly on the class this was overridden + // for, the class is either a subclass which we haven't initialized yet, + // or it's a runtime-generated class which should use the parent's + // schema. We check for the latter by checking if the immediate + // descendent of the desired class is a class generated by us (there + // may be further subclasses not generated by us for things like KVO). + Class parent = class_getSuperclass(cls); + while (parent != accessorClass) { + cls = parent; + parent = class_getSuperclass(cls); + } + + static const char accessorClassPrefix[] = "RLM:"; + if (!strncmp(class_getName(cls), accessorClassPrefix, sizeof(accessorClassPrefix) - 1)) { + return schema; + } + + return [RLMSchema sharedSchemaForClass:cls]; + }); + class_addMethod(metaClass, @selector(sharedSchema), imp, "@@:"); +} + +void RLMDynamicValidatedSet(RLMObjectBase *obj, NSString *propName, id val) { + RLMVerifyAttached(obj); + RLMObjectSchema *schema = obj->_objectSchema; + RLMProperty *prop = schema[propName]; + if (!prop) { + @throw RLMException(@"Invalid property name '%@' for class '%@'.", + propName, obj->_objectSchema.className); + } + if (prop.isPrimary) { + @throw RLMException(@"Primary key can't be changed to '%@' after an object is inserted.", val); + } + + // Because embedded objects cannot be created directly, we accept anything + // that can be converted to an embedded object for dynamic link set operations. + bool is_embedded = prop.type == RLMPropertyTypeObject && obj->_info->linkTargetType(prop.index).rlmObjectSchema.isEmbedded; + RLMValidateValueForProperty(val, schema, prop, !is_embedded); + RLMDynamicSet(obj, prop, RLMCoerceToNil(val)); +} + +// Precondition: the property is not a primary key +void RLMDynamicSet(__unsafe_unretained RLMObjectBase *const obj, + __unsafe_unretained RLMProperty *const prop, + __unsafe_unretained id const val) { + REALM_ASSERT_DEBUG(!prop.isPrimary); + realm::Object o(obj->_info->realm->_realm, *obj->_info->objectSchema, obj->_row); + RLMAccessorContext c(obj); + RLMTranslateError([&] { + o.set_property_value(c, getProperty(obj, prop).name, val ?: NSNull.null); + }); +} + +id RLMDynamicGet(__unsafe_unretained RLMObjectBase *const obj, __unsafe_unretained RLMProperty *const prop) { + if (auto accessor = prop.swiftAccessor; accessor && [obj isKindOfClass:obj->_objectSchema.objectClass]) { + return RLMCoerceToNil([accessor get:prop on:obj]); + } + if (!obj->_realm) { + return [obj valueForKey:prop.name]; + } + + realm::Object o(obj->_realm->_realm, *obj->_info->objectSchema, obj->_row); + RLMAccessorContext c(obj); + c.currentProperty = prop; + return RLMTranslateError([&] { + return RLMCoerceToNil(o.get_property_value(c, getProperty(obj, prop))); + }); +} + +id RLMDynamicGetByName(__unsafe_unretained RLMObjectBase *const obj, + __unsafe_unretained NSString *const propName) { + RLMProperty *prop = obj->_objectSchema[propName]; + if (!prop) { + @throw RLMException(@"Invalid property name '%@' for class '%@'.", + propName, obj->_objectSchema.className); + } + return RLMDynamicGet(obj, prop); +} + +#pragma mark - Swift property getters and setter + +#define REALM_SWIFT_PROPERTY_ACCESSOR(objc, swift, rlmtype) \ + objc RLMGetSwiftProperty##swift(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) { \ + return get(obj, key); \ + } \ + objc RLMGetSwiftProperty##swift##Optional(__unsafe_unretained RLMObjectBase *const obj, uint16_t key, bool *gotValue) { \ + return getOptional(obj, key, gotValue); \ + } \ + void RLMSetSwiftProperty##swift(__unsafe_unretained RLMObjectBase *const obj, uint16_t key, objc value) { \ + RLMVerifyAttached(obj); \ + kvoSetValue(obj, key, value); \ + } +REALM_FOR_EACH_SWIFT_PRIMITIVE_TYPE(REALM_SWIFT_PROPERTY_ACCESSOR) +#undef REALM_SWIFT_PROPERTY_ACCESSOR + +#define REALM_SWIFT_PROPERTY_ACCESSOR(objc, swift, rlmtype) \ + void RLMSetSwiftProperty##swift(__unsafe_unretained RLMObjectBase *const obj, uint16_t key, objc *value) { \ + RLMVerifyAttached(obj); \ + kvoSetValue(obj, key, value); \ + } +REALM_FOR_EACH_SWIFT_OBJECT_TYPE(REALM_SWIFT_PROPERTY_ACCESSOR) +#undef REALM_SWIFT_PROPERTY_ACCESSOR + +NSString *RLMGetSwiftPropertyString(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) { + return getBoxed(obj, key); +} + +NSData *RLMGetSwiftPropertyData(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) { + return getBoxed(obj, key); +} + +NSDate *RLMGetSwiftPropertyDate(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) { + return getBoxed(obj, key); +} + +NSUUID *RLMGetSwiftPropertyUUID(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) { + return getBoxed>(obj, key); +} + +RLMObjectId *RLMGetSwiftPropertyObjectId(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) { + return getBoxed>(obj, key); +} + +RLMDecimal128 *RLMGetSwiftPropertyDecimal128(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) { + return getBoxed(obj, key); +} + +RLMArray *RLMGetSwiftPropertyArray(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) { + return getCollection(obj, key); +} +RLMSet *RLMGetSwiftPropertySet(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) { + return getCollection(obj, key); +} +RLMDictionary *RLMGetSwiftPropertyMap(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) { + return getCollection(obj, key); +} + +void RLMSetSwiftPropertyNil(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) { + RLMVerifyInWriteTransaction(obj); + if (getProperty(obj, key).type == realm::PropertyType::Object) { + kvoSetValue(obj, key, (RLMObjectBase *)nil); + } + else { + // The type used here is arbitrary; it simply needs to be any non-object type + kvoSetValue(obj, key, (NSNumber *)nil); + } +} + +void RLMSetSwiftPropertyObject(__unsafe_unretained RLMObjectBase *const obj, uint16_t key, + __unsafe_unretained RLMObjectBase *const target) { + kvoSetValue(obj, key, target); +} + +RLMObjectBase *RLMGetSwiftPropertyObject(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) { + return getBoxed(obj, key); +} + +void RLMSetSwiftPropertyAny(__unsafe_unretained RLMObjectBase *const obj, uint16_t key, + __unsafe_unretained id const value) { + kvoSetValue(obj, key, value); +} + +id RLMGetSwiftPropertyAny(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) { + return getBoxed(obj, key); +} + +#pragma mark - RLMAccessorContext + +RLMAccessorContext::~RLMAccessorContext() = default; + +RLMAccessorContext::RLMAccessorContext(RLMAccessorContext& parent, realm::Obj const& obj, + realm::Property const& property) +: _realm(parent._realm) +, _info(property.type == realm::PropertyType::Object ? parent._info.linkTargetType(property) : parent._info) +, _parentObject(obj) +, _parentObjectInfo(&parent._info) +, _colKey(property.column_key) +{ +} + +RLMAccessorContext::RLMAccessorContext(RLMClassInfo& info) +: _realm(info.realm), _info(info) +{ +} + +RLMAccessorContext::RLMAccessorContext(__unsafe_unretained RLMObjectBase *const parent, + const realm::Property *prop) +: _realm(parent->_realm) +, _info(prop && prop->type == realm::PropertyType::Object ? parent->_info->linkTargetType(*prop) + : *parent->_info) +, _parentObject(parent->_row) +, _parentObjectInfo(parent->_info) +, _colKey(prop ? prop->column_key : ColKey{}) +{ +} + +RLMAccessorContext::RLMAccessorContext(__unsafe_unretained RLMObjectBase *const parent, + realm::ColKey col) +: _realm(parent->_realm) +, _info(_realm->_info[parent->_info->propertyForTableColumn(col).objectClassName]) +, _parentObject(parent->_row) +, _parentObjectInfo(parent->_info) +, _colKey(col) +{ +} + +id RLMAccessorContext::defaultValue(__unsafe_unretained NSString *const key) { + if (!_defaultValues) { + _defaultValues = RLMDefaultValuesForObjectSchema(_info.rlmObjectSchema); + } + return _defaultValues[key]; +} + +id RLMAccessorContext::propertyValue(id obj, size_t propIndex, + __unsafe_unretained RLMProperty *const prop) { + obj = RLMBridgeSwiftValue(obj) ?: obj; + + // Property value from an NSArray + if ([obj respondsToSelector:@selector(objectAtIndex:)]) { + return propIndex < [obj count] ? [obj objectAtIndex:propIndex] : nil; + } + + // Property value from an NSDictionary + if ([obj respondsToSelector:@selector(objectForKey:)]) { + return [obj objectForKey:prop.name]; + } + + // Property value from an instance of this object type + if ([obj isKindOfClass:_info.rlmObjectSchema.objectClass] && prop.swiftAccessor) { + return [prop.swiftAccessor get:prop on:obj]; + } + + // Property value from some object that's KVC-compatible + id value = RLMValidatedValueForProperty(obj, [obj respondsToSelector:prop.getterSel] ? prop.getterName : prop.name, + _info.rlmObjectSchema.className); + return value ?: NSNull.null; +} + +realm::Obj RLMAccessorContext::create_embedded_object() { + if (!_parentObject) { + @throw RLMException(@"Embedded objects cannot be created directly"); + } + return _parentObject.create_and_set_linked_object(_colKey); +} + +id RLMAccessorContext::box(realm::Mixed v) { + return RLMMixedToObjc(v, _realm, &_info); +} + +id RLMAccessorContext::box(realm::List&& l) { + REALM_ASSERT(_parentObjectInfo); + REALM_ASSERT(currentProperty); + return [[RLMManagedArray alloc] initWithBackingCollection:std::move(l) + parentInfo:_parentObjectInfo + property:currentProperty]; +} + +id RLMAccessorContext::box(realm::object_store::Set&& s) { + REALM_ASSERT(_parentObjectInfo); + REALM_ASSERT(currentProperty); + return [[RLMManagedSet alloc] initWithBackingCollection:std::move(s) + parentInfo:_parentObjectInfo + property:currentProperty]; +} + +id RLMAccessorContext::box(realm::object_store::Dictionary&& d) { + REALM_ASSERT(_parentObjectInfo); + REALM_ASSERT(currentProperty); + return [[RLMManagedDictionary alloc] initWithBackingCollection:std::move(d) + parentInfo:_parentObjectInfo + property:currentProperty]; +} + +id RLMAccessorContext::box(realm::Object&& o) { + REALM_ASSERT(currentProperty); + return RLMCreateObjectAccessor(_info.linkTargetType(currentProperty.index), o.obj()); +} + +id RLMAccessorContext::box(realm::Obj&& r) { + if (!currentProperty) { + // If currentProperty is set, then we're reading from a Collection and + // that reported an audit read for us. If not, we need to report the + // audit read. This happens automatically when creating a + // `realm::Object`, but our object accessors don't wrap that type. + realm::Object(_realm->_realm, *_info.objectSchema, r, _parentObject, _colKey); + } + return RLMCreateObjectAccessor(_info, std::move(r)); +} + +id RLMAccessorContext::box(realm::Results&& r) { + REALM_ASSERT(currentProperty); + return [RLMResults resultsWithObjectInfo:_realm->_info[currentProperty.objectClassName] + results:std::move(r)]; +} + +using realm::ObjKey; +using realm::CreatePolicy; + +template +static T *bridged(__unsafe_unretained id const value) { + return [value isKindOfClass:[T class]] ? value : RLMBridgeSwiftValue(value); +} + +template<> +realm::Timestamp RLMStatelessAccessorContext::unbox(__unsafe_unretained id const value) { + id v = RLMCoerceToNil(value); + return RLMTimestampForNSDate(bridged(v)); +} + +template<> +bool RLMStatelessAccessorContext::unbox(__unsafe_unretained id const v) { + return [bridged(v) boolValue]; +} +template<> +double RLMStatelessAccessorContext::unbox(__unsafe_unretained id const v) { + return [bridged(v) doubleValue]; +} +template<> +float RLMStatelessAccessorContext::unbox(__unsafe_unretained id const v) { + return [bridged(v) floatValue]; +} +template<> +long long RLMStatelessAccessorContext::unbox(__unsafe_unretained id const v) { + return [bridged(v) longLongValue]; +} +template<> +realm::BinaryData RLMStatelessAccessorContext::unbox(id v) { + v = RLMCoerceToNil(v); + return RLMBinaryDataForNSData(bridged(v)); +} +template<> +realm::StringData RLMStatelessAccessorContext::unbox(id v) { + v = RLMCoerceToNil(v); + return RLMStringDataWithNSString(bridged(v)); +} +template<> +realm::Decimal128 RLMStatelessAccessorContext::unbox(id v) { + return RLMObjcToDecimal128(v); +} +template<> +realm::ObjectId RLMStatelessAccessorContext::unbox(id v) { + return bridged(v).value; +} +template<> +realm::UUID RLMStatelessAccessorContext::unbox(id v) { + return RLMObjcToUUID(bridged(v)); +} +template<> +realm::Mixed RLMAccessorContext::unbox(__unsafe_unretained id v, CreatePolicy p, ObjKey) { + return RLMObjcToMixed(v, _realm, p); +} + +template +static auto toOptional(__unsafe_unretained id const value) { + id v = RLMCoerceToNil(value); + return v ? realm::util::make_optional(RLMStatelessAccessorContext::unbox(v)) + : realm::util::none; +} + +template<> +std::optional RLMStatelessAccessorContext::unbox(__unsafe_unretained id const v) { + return toOptional(v); +} +template<> +std::optional RLMStatelessAccessorContext::unbox(__unsafe_unretained id const v) { + return toOptional(v); +} +template<> +std::optional RLMStatelessAccessorContext::unbox(__unsafe_unretained id const v) { + return toOptional(v); +} +template<> +std::optional RLMStatelessAccessorContext::unbox(__unsafe_unretained id const v) { + return toOptional(v); +} +template<> +std::optional RLMStatelessAccessorContext::unbox(__unsafe_unretained id const v) { + return toOptional(v); +} +template<> +std::optional RLMStatelessAccessorContext::unbox(__unsafe_unretained id const v) { + return toOptional(v); +} + +std::pair +RLMAccessorContext::createObject(id value, realm::CreatePolicy policy, + bool forceCreate, ObjKey existingKey) { + if (!value || value == NSNull.null) { + @throw RLMException(@"Must provide a non-nil value."); + } + + if ([value isKindOfClass:[NSArray class]] && [value count] > _info.objectSchema->persisted_properties.size()) { + @throw RLMException(@"Invalid array input: more values (%llu) than properties (%llu).", + (unsigned long long)[value count], + (unsigned long long)_info.objectSchema->persisted_properties.size()); + } + + RLMObjectBase *objBase = RLMDynamicCast(value); + realm::Obj obj, *outObj = nullptr; + bool requiresSwiftUIObservers = false; + if (objBase) { + if (objBase.isInvalidated) { + if (policy.create && !policy.copy) { + @throw RLMException(@"Adding a deleted or invalidated object to a Realm is not permitted"); + } + else { + @throw RLMException(@"Object has been deleted or invalidated."); + } + } + if (policy.copy) { + if (policy.update || !forceCreate) { + // create(update: true) is a no-op when given an object already in + // the Realm which is of the correct type + if (objBase->_realm == _realm && objBase->_row.get_table() == _info.table() && !_info.table()->is_embedded()) { + return {objBase->_row, true}; + } + } + // Otherwise we copy the object + objBase = nil; + } + else { + outObj = &objBase->_row; + // add() on an object already managed by this Realm is a no-op + if (objBase->_realm == _realm) { + return {objBase->_row, true}; + } + if (!policy.create) { + return {realm::Obj(), false}; + } + if (objBase->_realm) { + @throw RLMException(@"Object is already managed by another Realm. Use create instead to copy it into this Realm."); + } + if (objBase->_observationInfo && objBase->_observationInfo->hasObservers()) { + requiresSwiftUIObservers = [RLMSwiftUIKVO removeObserversFromObject:objBase]; + if (!requiresSwiftUIObservers) { + @throw RLMException(@"Cannot add an object with observers to a Realm"); + } + } + + REALM_ASSERT([objBase->_objectSchema.className isEqualToString:_info.rlmObjectSchema.className]); + REALM_ASSERT([objBase isKindOfClass:_info.rlmObjectSchema.unmanagedClass]); + + objBase->_info = &_info; + objBase->_realm = _realm; + objBase->_objectSchema = _info.rlmObjectSchema; + } + } + if (!policy.create) { + return {realm::Obj(), false}; + } + if (!outObj) { + outObj = &obj; + } + + try { + realm::Object::create(*this, _realm->_realm, *_info.objectSchema, + (id)value, policy, existingKey, outObj).obj(); + } + catch (std::exception const& e) { + @throw RLMException(e); + } + + if (objBase) { + for (RLMProperty *prop in _info.rlmObjectSchema.properties) { + // set the ivars for object and array properties to nil as otherwise the + // accessors retain objects that are no longer accessible via the properties + // this is mainly an issue when the object graph being added has cycles, + // as it's not obvious that the user has to set the *ivars* to nil to + // avoid leaking memory + if (prop.type == RLMPropertyTypeObject && !prop.swiftIvar) { + ((void(*)(id, SEL, id))objc_msgSend)(objBase, prop.setterSel, nil); + } + } + + object_setClass(objBase, _info.rlmObjectSchema.accessorClass); + RLMInitializeSwiftAccessor(objBase, true); + } + + if (requiresSwiftUIObservers) { + [RLMSwiftUIKVO addObserversToObject:objBase]; + } + + return {*outObj, false}; +} + +template<> +realm::Obj RLMAccessorContext::unbox(__unsafe_unretained id const v, CreatePolicy policy, ObjKey key) { + return createObject(v, policy, false, key).first; +} + +void RLMAccessorContext::will_change(realm::Obj const& row, realm::Property const& prop) { + auto obsInfo = RLMGetObservationInfo(nullptr, row.get_key(), _info); + if (!_observationHelper) { + if (obsInfo || prop.type == realm::PropertyType::Object) { + _observationHelper = std::make_unique(_info.realm); + } + } + if (_observationHelper) { + _observationHelper->willChange(obsInfo, _info.propertyForTableColumn(prop.column_key).name); + if (prop.type == realm::PropertyType::Object) { + _observationHelper->trackDeletions(); + } + } +} + +void RLMAccessorContext::did_change() { + if (_observationHelper) { + _observationHelper->didChange(); + } +} + +RLMOptionalId RLMAccessorContext::value_for_property(__unsafe_unretained id const obj, + realm::Property const&, size_t propIndex) { + auto prop = _info.rlmObjectSchema.properties[propIndex]; + id value = propertyValue(obj, propIndex, prop); + if (value) { + RLMValidateValueForProperty(value, _info.rlmObjectSchema, prop); + } + return RLMOptionalId{value}; +} + +RLMOptionalId RLMAccessorContext::default_value_for_property(realm::ObjectSchema const&, + realm::Property const& prop) +{ + return RLMOptionalId{defaultValue(@(prop.name.c_str()))}; +} + +bool RLMStatelessAccessorContext::is_same_list(realm::List const& list, + __unsafe_unretained id const v) noexcept { + return [v respondsToSelector:@selector(isBackedByList:)] && [v isBackedByList:list]; +} + +bool RLMStatelessAccessorContext::is_same_set(realm::object_store::Set const& set, + __unsafe_unretained id const v) noexcept { + return [v respondsToSelector:@selector(isBackedBySet:)] && [v isBackedBySet:set]; +} + +bool RLMStatelessAccessorContext::is_same_dictionary(realm::object_store::Dictionary const& dict, + __unsafe_unretained id const v) noexcept { + return [v respondsToSelector:@selector(isBackedByDictionary:)] && [v isBackedByDictionary:dict]; +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wincomplete-implementation" +@implementation RLMManagedPropertyAccessor +// Most types don't need to distinguish between promote and init so provide a default ++ (void)promote:(RLMProperty *)property on:(RLMObjectBase *)parent { + [self initialize:property on:parent]; +} +@end +#pragma clang diagnostic pop diff --git a/Pods/Realm/Realm/RLMAnalytics.mm b/Pods/Realm/Realm/RLMAnalytics.mm new file mode 100644 index 0000000..ed9c968 --- /dev/null +++ b/Pods/Realm/Realm/RLMAnalytics.mm @@ -0,0 +1,430 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// 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. +// +//////////////////////////////////////////////////////////////////////////// + +// Asynchronously submits build information to Realm if running in an iOS +// simulator or on OS X if a debugger is attached. Does nothing if running on an +// iOS / watchOS device or if a debugger is *not* attached. +// +// To be clear: this does *not* run when your app is in production or on +// your end-user’s devices; it will only run in the simulator or when a debugger +// is attached. +// +// Why are we doing this? In short, because it helps us build a better product +// for you. None of the data personally identifies you, your employer or your +// app, but it *will* help us understand what language you use, what iOS +// versions you target, etc. Having this info will help prioritizing our time, +// adding new features and deprecating old features. Collecting an anonymized +// bundle & anonymized MAC is the only way for us to count actual usage of the +// other metrics accurately. If we don’t have a way to deduplicate the info +// reported, it will be useless, as a single developer building their Swift app +// 10 times would report 10 times more than a single Objective-C developer that +// only builds once, making the data all but useless. +// No one likes sharing data unless it’s necessary, we get it, and we’ve +// debated adding this for a long long time. Since Realm is a free product +// without an email signup, we feel this is a necessary step so we can collect +// relevant data to build a better product for you. If you truly, absolutely +// feel compelled to not send this data back to Realm, then you can set an env +// variable named REALM_DISABLE_ANALYTICS. Since Realm is free we believe +// letting these analytics run is a small price to pay for the product & support +// we give you. +// +// Currently the following information is reported: +// - What version of Realm and core is being used, and from which language (obj-c or Swift). +// - Which platform and version of OS X it's running on (in case Xcode aggressively drops +// support for older versions again, we need to know what we need to support). +// - The minimum iOS/OS X version that the application is targeting (again, to +// help us decide what versions we need to support). +// - An anonymous MAC address and bundle ID to aggregate the other information on. +// - The host platform OSX and version. +// - The XCode version. +// - Some info about the features been used when opening the realm for the first time. + +#import "RLMAnalytics.hpp" + +#import + +#if TARGET_IPHONE_SIMULATOR || TARGET_OS_MAC || (TARGET_OS_WATCH && TARGET_OS_SIMULATOR) || (TARGET_OS_TV && TARGET_OS_SIMULATOR) +#import "RLMObjectSchema_Private.h" +#import "RLMRealmConfiguration_Private.h" +#import "RLMSchema_Private.h" +#import "RLMSyncConfiguration.h" +#import "RLMUtil.hpp" + +#import +#import +#import +#import +#import + +#import + +#ifndef REALM_COCOA_VERSION +#import "RLMVersion.h" +#endif + +#ifndef REALM_IOPLATFORMUUID +#import +#endif + +// Wrapper for sysctl() that handles the memory management stuff +static auto RLMSysCtl(int *mib, u_int mibSize, size_t *bufferSize) { + std::unique_ptr buffer(nullptr, &free); + + int ret = sysctl(mib, mibSize, nullptr, bufferSize, nullptr, 0); + if (ret != 0) { + return buffer; + } + + buffer.reset(malloc(*bufferSize)); + if (!buffer) { + return buffer; + } + + ret = sysctl(mib, mibSize, buffer.get(), bufferSize, nullptr, 0); + if (ret != 0) { + buffer.reset(); + } + + return buffer; +} + +// Get the version of OS X we're running on (even in the simulator this gives +// the OS X version and not the simulated iOS version) +static NSString *RLMHostOSVersion() { + size_t size; + sysctlbyname("kern.osproductversion", NULL, &size, NULL, 0); + char *model = (char*)malloc(size); + sysctlbyname("kern.osproductversion", model, &size, NULL, 0); + NSString *deviceModel = [NSString stringWithCString:model encoding:NSUTF8StringEncoding]; + free(model); + return deviceModel; +} + +static NSString *RLMTargetArch() { + NSString *targetArchitecture; +#if TARGET_CPU_X86_64 + targetArchitecture = @"x86_64"; +#elif TARGET_CPU_ARM64 + targetArchitecture = @"arm64"; +#endif + return targetArchitecture; +} + +// Hash the data in the given buffer and convert it to a hex-format string +NSString *RLMHashBase16Data(const void *bytes, size_t length) { + unsigned char buffer[CC_SHA256_DIGEST_LENGTH]; + CC_SHA256(bytes, static_cast(length), buffer); + + char formatted[CC_SHA256_DIGEST_LENGTH * 2 + 1]; + for (int i = 0; i < CC_SHA256_DIGEST_LENGTH; ++i) { + snprintf(formatted + i * 2, sizeof(formatted) - i * 2, "%02x", buffer[i]); + } + + return [[NSString alloc] initWithBytes:formatted + length:CC_SHA256_DIGEST_LENGTH * 2 + encoding:NSUTF8StringEncoding]; +} + +static std::optional> getMacAddress(int id) { + char buff[] = "en0"; + snprintf(buff + 2, 2, "%d", id); + int index = static_cast(if_nametoindex(buff)); + if (!index) { + return std::nullopt; + } + + std::array mib = {{CTL_NET, PF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, index}}; + size_t bufferSize; + auto buffer = RLMSysCtl(&mib[0], mib.size(), &bufferSize); + if (!buffer) { + return std::nullopt; + } + + // sockaddr_dl struct is immediately after the if_msghdr struct in the buffer + auto sockaddr = reinterpret_cast(static_cast(buffer.get()) + 1); + std::array mac; + std::memcpy(&mac[0], sockaddr->sdl_data + sockaddr->sdl_nlen, 6); + + // Touch bar internal network interface, which is identical on all touch bar macs + if (mac == std::array{0xAC, 0xDE, 0x48, 0x00, 0x11, 0x22}) { + return std::nullopt; + } + + // The mac address reported on iOS. It's unclear how we're seeing this as + // this code doesn't run on iOS, but it somehow sometimes happens. + if (mac == std::array{2, 0, 0, 0, 0, 0}) { + return std::nullopt; + } + + return mac; +} + +// Returns the hash of the MAC address of the first network adaptor since the +// vendorIdentifier isn't constant between iOS simulators. +static NSString *RLMMACAddress() { + for (int i = 0; i < 9; ++i) { + if (auto mac = getMacAddress(i)) { + return RLMHashBase16Data(&(*mac)[0], 6); + } + } + return @"unknown"; + } + +static NSString *RLMBuilderId() { + NSString *ioPlatformUuid = REALM_IOPLATFORMUUID; + if ([ioPlatformUuid length] == 0) { + return nil; + } + NSString *salt = @"Realm is great"; + NSString *saltedId = [ioPlatformUuid stringByAppendingString:salt]; + NSData *data = [saltedId dataUsingEncoding:NSUTF8StringEncoding]; + + unsigned char buffer[CC_SHA256_DIGEST_LENGTH]; + CC_SHA256(data.bytes, static_cast(data.length), buffer); + NSData* hashedData = [NSData dataWithBytes:buffer length:CC_SHA256_DIGEST_LENGTH]; + + // Base64 Encoding + return [hashedData base64EncodedStringWithOptions:kNilOptions]; +} + +static NSDictionary *RLMBaseMetrics() { + static NSString *kUnknownString = @"unknown"; + NSBundle *appBundle = NSBundle.mainBundle; + NSString *hashedBundleID = appBundle.bundleIdentifier; + + // Main bundle isn't always the one of interest (e.g. when running tests + // it's xctest rather than the app's bundle), so look for one with a bundle ID + if (!hashedBundleID) { + for (NSBundle *bundle in NSBundle.allBundles) { + if ((hashedBundleID = bundle.bundleIdentifier)) { + appBundle = bundle; + break; + } + } + } + + // If we found a bundle ID anywhere, hash it as it could contain sensitive + // information (e.g. the name of an unannounced product) + if (hashedBundleID) { + NSData *data = [hashedBundleID dataUsingEncoding:NSUTF8StringEncoding]; + hashedBundleID = RLMHashBase16Data(data.bytes, data.length); + } + + Class swiftDecimal128 = NSClassFromString(@"RealmSwiftDecimal128"); + BOOL isSwift = swiftDecimal128 != nil; + + NSString *hashedDistinctId = RLMMACAddress(); + // We use the IOPlatformUUID if is available (Cocoapods, SPM), + // in case we cannot obtain it (Pre-built binaries) we use the hashed mac address. + NSString *hashedBuilderId = RLMBuilderId() ?: hashedDistinctId; + + NSDictionary *info = appBundle.infoDictionary; + + return @{ + // MixPanel properties + @"token": @"ce0fac19508f6c8f20066d345d360fd0", + + // Anonymous identifiers to deduplicate events + @"distinct_id": hashedDistinctId, + @"builder_id": hashedBuilderId, + + @"Anonymized MAC Address": hashedDistinctId, + @"Anonymized Bundle ID": hashedBundleID ?: kUnknownString, + + // SDK Info + @"Binding": @"cocoa", + // Which version of Realm is being used + @"Realm Version": REALM_COCOA_VERSION, + @"Core Version": @REALM_VERSION, + + // Language Info + @"Language": isSwift ? @"swift" : @"objc", + + // Target Info + // Current OS version the app is targeting + @"Target OS Version": [[NSProcessInfo processInfo] operatingSystemVersionString], + // Minimum OS version the app is targeting + @"Target OS Minimum Version": info[@"MinimumOSVersion"] ?: info[@"LSMinimumSystemVersion"] ?: kUnknownString, +#if TARGET_OS_WATCH + @"Target OS Type": @"watchos", +#elif TARGET_OS_TV + @"Target OS Type": @"tvos", +#elif TARGET_OS_IPHONE + @"Target OS Type": @"ios", +#else + @"Target OS Type": @"macos", +#endif + @"Target CPU Arch": RLMTargetArch() ?: kUnknownString, + + // Framework +#if TARGET_OS_MACCATALYST + @"Framework": @"maccatalyst", +#endif + + // Host Info + // Host OS version being built on + @"Host OS Type": @"macos", + @"Host OS Version": RLMHostOSVersion() ?: kUnknownString, + + // Installation method +#ifdef SWIFT_PACKAGE + @"Installation Method": @"spm", +#elif defined(COCOAPODS) + @"Installation Method": @"cocoapods", +#elif defined(CARTHAGE) + @"Installation Method": @"carthage", +#elif defined(REALM_IOS_STATIC) + @"Installation Method": @"static framework", +#else + @"Installation Method": @"other", +#endif + + // Compiler Info + @"Compiler": @"clang", + @"Clang Version": @__clang_version__, + @"Clang Major Version": @__clang_major__, + }; +} + +// This will only be executed once but depending on the number of objects, could take sometime +static NSDictionary *RLMSchemaMetrics(RLMSchema *schema) { + NSMutableDictionary *featuresDictionary = [@{@"Embedded_Object": @0, + @"Asymmetric_Object": @0, + @"Object_Link": @0, + @"Mixed": @0, + @"Primitive_List": @0, + @"Primitive_Set": @0, + @"Primitive_Dictionary": @0, + @"Object_List": @0, + @"Object_Set": @0, + @"Object_Dictionary": @0, + @"Backlink": @0, + } mutableCopy]; + + for (RLMObjectSchema *objectSchema in schema.objectSchema) { + if (objectSchema.isEmbedded) { + featuresDictionary[@"Embedded_Object"] = @1; + } + if (objectSchema.isAsymmetric) { + featuresDictionary[@"Asymmetric_Object"] = @1; + } + + for (RLMProperty *property in objectSchema.properties) { + if (property.array) { + if (property.type == RLMPropertyTypeObject) { + featuresDictionary[@"Object_List"] = @1; + } else { + featuresDictionary[@"Primitive_List"] = @1; + } + continue; + } + if (property.set) { + if (property.type == RLMPropertyTypeObject) { + featuresDictionary[@"Object_Set"] = @1; + } else { + featuresDictionary[@"Primitive_Set"] = @1; + } + continue; + } + if (property.dictionary) { + if (property.type == RLMPropertyTypeObject) { + featuresDictionary[@"Object_Dictionary"] = @1; + } else { + featuresDictionary[@"Primitive_Dictionary"] = @1; + } + continue; + } + + switch (property.type) { + case RLMPropertyTypeAny: + featuresDictionary[@"Mixed"] = @1; + break; + case RLMPropertyTypeObject: + featuresDictionary[@"Object_Link"] = @1; + break; + case RLMPropertyTypeLinkingObjects: + featuresDictionary[@"Backlink"] = @1; + break; + default: + break; + } + } + } + return featuresDictionary; +} + +static NSDictionary *RLMConfigurationMetrics(RLMRealmConfiguration *configuration) { + RLMSyncConfiguration *syncConfiguration = configuration.syncConfiguration; + bool isSync = syncConfiguration != nil; + bool isPBSSync = syncConfiguration.partitionValue != nil; + bool isFlexibleSync = (isSync && !isPBSSync); + auto resetMode = syncConfiguration.clientResetMode; + + bool isCompactOnLaunch = configuration.shouldCompactOnLaunch != nil; + bool migrationBlock = configuration.migrationBlock != nil; + + return @{ + // Sync + @"Sync Enabled": isSync ? @"true" : @"false", + @"Flx_Sync": isFlexibleSync ? @1 : @0, + @"Pbs_Sync": isPBSSync ? @1 : @0, + + // Client Reset + @"CR_Recover_Discard": (isSync && resetMode == RLMClientResetModeRecoverOrDiscardUnsyncedChanges) ? @1 : @0, + @"CR_Recover": (isSync && resetMode == RLMClientResetModeRecoverUnsyncedChanges) ? @1 : @0, + @"CR_Discard": (isSync && resetMode == RLMClientResetModeDiscardUnsyncedChanges) ? @1 : @0, + @"CR_Manual": (isSync && resetMode == RLMClientResetModeManual) ? @1 : @0, + + // Configuration + @"Compact_On_Launch": isCompactOnLaunch ? @1 : @0, + @"Schema_Migration_Block": migrationBlock ? @1 : @0, + }; +} + +void RLMSendAnalytics(RLMRealmConfiguration *configuration, RLMSchema *schema) { + if (getenv("REALM_DISABLE_ANALYTICS") || !RLMIsDebuggerAttached() || RLMIsRunningInPlayground()) { + return; + } + + id config = [configuration copy]; + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + NSDictionary *baseMetrics = RLMBaseMetrics(); + NSDictionary *schemaMetrics = RLMSchemaMetrics(schema); + NSDictionary *configurationMetrics = RLMConfigurationMetrics(config); + + NSMutableDictionary *metrics = [[NSMutableDictionary alloc] init]; + [metrics addEntriesFromDictionary:baseMetrics]; + [metrics addEntriesFromDictionary:schemaMetrics]; + [metrics addEntriesFromDictionary:configurationMetrics]; + + NSDictionary *payloadN = @{@"event": @"Run", @"properties": metrics}; + NSData *payload = [NSJSONSerialization dataWithJSONObject:payloadN options:0 error:nil]; + + NSString *url = @"https://data.mongodb-api.com/app/realmsdkmetrics-zmhtm/endpoint/metric_webhook/metric?data=%@"; + NSString *formatted = [NSString stringWithFormat:url, [payload base64EncodedStringWithOptions:0]]; + // No error handling or anything because logging errors annoyed people for no + // real benefit, and it's not clear what else we could do + [[NSURLSession.sharedSession dataTaskWithURL:[NSURL URLWithString:formatted]] resume]; + }); +} + +#else + +void RLMSendAnalytics() {} + +#endif diff --git a/Pods/Realm/Realm/RLMApp.mm b/Pods/Realm/Realm/RLMApp.mm new file mode 100644 index 0000000..f9d31be --- /dev/null +++ b/Pods/Realm/Realm/RLMApp.mm @@ -0,0 +1,486 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 "RLMApp_Private.hpp" + +#import +#if __has_include() +#import +#define REALM_UIDEVICE_AVAILABLE +#endif + +#import "RLMAnalytics.hpp" +#import "RLMBSON_Private.hpp" +#import "RLMCredentials_Private.hpp" +#import "RLMEmailPasswordAuth.h" +#import "RLMLogger.h" +#import "RLMPushClient_Private.hpp" +#import "RLMSyncManager_Private.hpp" +#import "RLMUser_Private.hpp" +#import "RLMUtil.hpp" + +#import +#import + +#if !defined(REALM_COCOA_VERSION) +#import "RLMVersion.h" +#endif + +using namespace realm; + +#pragma mark CocoaNetworkTransport +namespace { + /// Internal transport struct to bridge RLMNetworkingTransporting to the GenericNetworkTransport. + class CocoaNetworkTransport : public realm::app::GenericNetworkTransport { + public: + CocoaNetworkTransport(id transport) : m_transport(transport) {} + + void send_request_to_server(const app::Request& request, + util::UniqueFunction&& completion) override { + // Convert the app::Request to an RLMRequest + auto rlmRequest = [RLMRequest new]; + rlmRequest.url = @(request.url.data()); + rlmRequest.body = @(request.body.data()); + NSMutableDictionary *headers = [NSMutableDictionary new]; + for (auto&& header : request.headers) { + headers[@(header.first.data())] = @(header.second.data()); + } + rlmRequest.headers = headers; + rlmRequest.method = static_cast(request.method); + rlmRequest.timeout = request.timeout_ms / 1000.0; + + // Send the request through to the Cocoa level transport + auto completion_ptr = completion.release(); + [m_transport sendRequestToServer:rlmRequest completion:^(RLMResponse *response) { + util::UniqueFunction completion(completion_ptr); + std::map bridgingHeaders; + [response.headers enumerateKeysAndObjectsUsingBlock:[&](NSString *key, NSString *value, BOOL *) { + bridgingHeaders[key.UTF8String] = value.UTF8String; + }]; + + // Convert the RLMResponse to an app:Response and pass downstream to + // the object store + completion(app::Response{ + .http_status_code = static_cast(response.httpStatusCode), + .custom_status_code = static_cast(response.customStatusCode), + .headers = bridgingHeaders, + .body = response.body ? response.body.UTF8String : "" + }); + }]; + } + + id transport() const { + return m_transport; + } + private: + id m_transport; + }; +} + +#pragma mark RLMAppConfiguration +@implementation RLMAppConfiguration { + realm::app::App::Config _config; + SyncClientConfig _clientConfig; +} + +- (instancetype)init { + if (self = [super init]) { + self.enableSessionMultiplexing = true; + self.encryptMetadata = !getenv("REALM_DISABLE_METADATA_ENCRYPTION") && !RLMIsRunningInPlayground(); + RLMNSStringToStdString(_clientConfig.base_file_path, RLMDefaultDirectoryForBundleIdentifier(nil)); + + _config.device_info.sdk = "Realm Swift"; + + // Platform info isn't available when running via `swift test`. + // Non-Xcode SPM builds can't build for anything but macOS, so this is + // probably unimportant for now and we can just report "unknown" + auto processInfo = [NSProcessInfo processInfo]; + RLMNSStringToStdString(_config.device_info.platform_version, + [processInfo operatingSystemVersionString] ?: @"unknown"); + RLMNSStringToStdString(_config.device_info.sdk_version, REALM_COCOA_VERSION); + } + return self; +} + +- (instancetype)initWithBaseURL:(nullable NSString *)baseURL + transport:(nullable id)transport + localAppName:(nullable NSString *)localAppName + localAppVersion:(nullable NSString *)localAppVersion { + return [self initWithBaseURL:baseURL + transport:transport + localAppName:localAppName + localAppVersion:localAppVersion + defaultRequestTimeoutMS:60000]; +} + +- (instancetype)initWithBaseURL:(nullable NSString *)baseURL + transport:(nullable id)transport + localAppName:(nullable NSString *)localAppName + localAppVersion:(nullable NSString *)localAppVersion + defaultRequestTimeoutMS:(NSUInteger)defaultRequestTimeoutMS { + if (self = [self init]) { + self.baseURL = baseURL; + self.transport = transport; + self.localAppName = localAppName; + self.localAppVersion = localAppVersion; + self.defaultRequestTimeoutMS = defaultRequestTimeoutMS; + configureSyncConnectionParameters(_config); + } + return self; +} + +static void configureSyncConnectionParameters(realm::app::App::Config& config) { + // Anonymized BundleId + NSString *bundleId = [[NSBundle mainBundle] bundleIdentifier]; + NSData *bundleIdData = [bundleId dataUsingEncoding:NSUTF8StringEncoding]; + RLMNSStringToStdString(config.device_info.bundle_id, RLMHashBase16Data(bundleIdData.bytes, bundleIdData.length)); + + config.device_info.sdk = "Realm Swift"; + RLMNSStringToStdString(config.device_info.sdk_version, REALM_COCOA_VERSION); + + auto processInfo = [NSProcessInfo processInfo]; + RLMNSStringToStdString(config.device_info.platform_version, + [processInfo operatingSystemVersionString] ?: @"unknown"); + + RLMNSStringToStdString(config.device_info.framework_version, @__clang_version__); + +#ifdef REALM_UIDEVICE_AVAILABLE + RLMNSStringToStdString(config.device_info.device_name, [UIDevice currentDevice].model); +#endif + struct utsname systemInfo; + uname(&systemInfo); + config.device_info.device_version = systemInfo.machine; +} + +- (const realm::app::App::Config&)config { + if (!_config.transport) { + self.transport = nil; + } + return _config; +} + +- (const realm::SyncClientConfig&)clientConfig { + return _clientConfig; +} + +- (id)copyWithZone:(NSZone *)zone { + RLMAppConfiguration *copy = [[RLMAppConfiguration alloc] init]; + copy->_config = _config; + copy->_clientConfig = _clientConfig; + return copy; +} + +- (NSString *)appId { + return RLMStringViewToNSString(_config.app_id); +} + +- (void)setAppId:(NSString *)appId { + if ([appId length] == 0) { + @throw RLMException(@"AppId cannot be an empty string"); + } + + RLMNSStringToStdString(_config.app_id, appId); +} + +static NSString *getOptionalString(const std::optional& str) { + return str ? RLMStringViewToNSString(*str) : nil; +} + +static void setOptionalString(std::optional& dst, NSString *src) { + if (src.length == 0) { + dst.reset(); + } + else { + dst.emplace(); + RLMNSStringToStdString(*dst, src); + } +} + +- (NSString *)baseURL { + return getOptionalString(_config.base_url); +} + +- (void)setBaseURL:(nullable NSString *)baseURL { + setOptionalString(_config.base_url, baseURL); +} + +- (id)transport { + return static_cast(*_config.transport).transport(); +} + +- (void)setTransport:(id)transport { + if (!transport) { + transport = [RLMNetworkTransport new]; + } + _config.transport = std::make_shared(transport); +} + +- (NSString *)localAppName { + return getOptionalString(_config.local_app_name); +} + +- (void)setLocalAppName:(nullable NSString *)localAppName { + setOptionalString(_config.local_app_name, localAppName); +} + +- (NSString *)localAppVersion { + return getOptionalString(_config.local_app_version); +} + +- (void)setLocalAppVersion:(nullable NSString *)localAppVersion { + setOptionalString(_config.local_app_version, localAppVersion); +} + +- (NSUInteger)defaultRequestTimeoutMS { + return _config.default_request_timeout_ms.value_or(60000U); +} + +- (void)setDefaultRequestTimeoutMS:(NSUInteger)defaultRequestTimeoutMS { + _config.default_request_timeout_ms = (uint64_t)defaultRequestTimeoutMS; +} + +- (BOOL)enableSessionMultiplexing { + return _clientConfig.multiplex_sessions; +} + +- (void)setEnableSessionMultiplexing:(BOOL)enableSessionMultiplexing { + _clientConfig.multiplex_sessions = enableSessionMultiplexing; +} + +- (BOOL)encryptMetadata { + return _clientConfig.metadata_mode == SyncManager::MetadataMode::Encryption; +} + +- (void)setEncryptMetadata:(BOOL)encryptMetadata { + _clientConfig.metadata_mode = encryptMetadata ? SyncManager::MetadataMode::Encryption + : SyncManager::MetadataMode::NoEncryption; +} + +- (NSURL *)rootDirectory { + return [NSURL fileURLWithPath:RLMStringViewToNSString(_clientConfig.base_file_path)]; +} + +- (void)setRootDirectory:(NSURL *)rootDirectory { + RLMNSStringToStdString(_clientConfig.base_file_path, rootDirectory.path); +} + +- (RLMSyncTimeoutOptions *)syncTimeouts { + return [[RLMSyncTimeoutOptions alloc] initWithOptions:_clientConfig.timeouts]; +} + +- (void)setSyncTimeouts:(RLMSyncTimeoutOptions *)syncTimeouts { + _clientConfig.timeouts = syncTimeouts->_options; +} + +@end + +#pragma mark RLMAppSubscriptionToken + +@implementation RLMAppSubscriptionToken { + std::shared_ptr _app; + std::optional _token; +} + +- (instancetype)initWithApp:(std::shared_ptr)app token:(app::App::Token&&)token { + if (self = [super init]) { + _app = std::move(app); + _token = std::move(token); + } + return self; +} + +- (void)unsubscribe { + _token.reset(); + _app.reset(); +} +@end + +#pragma mark RLMApp +@interface RLMApp() { + std::shared_ptr _app; + __weak id _authorizationDelegate API_AVAILABLE(ios(13.0), macos(10.15), tvos(13.0), watchos(6.0)); +} + +@end + +@implementation RLMApp : NSObject + ++ (void)initialize { + [RLMRealm class]; + // Even though there is nothing to log when the App initialises, we want to + // be able to log anything happening after this e.g. login/register. + [RLMLogger class]; +} + +- (instancetype)initWithApp:(std::shared_ptr&&)app config:(RLMAppConfiguration *)config { + if (self = [super init]) { + _app = std::move(app); + _configuration = config; + _syncManager = [[RLMSyncManager alloc] initWithSyncManager:_app->sync_manager()]; + } + return self; +} + +- (instancetype)initWithConfiguration:(RLMAppConfiguration *)configuration { + if (self = [super init]) { + _app = RLMTranslateError([&] { + return app::App::get_shared_app(configuration.config, configuration.clientConfig); + }); + _configuration = configuration; + _syncManager = [[RLMSyncManager alloc] initWithSyncManager:_app->sync_manager()]; + } + return self; +} + +static NSMutableDictionary *s_apps = [NSMutableDictionary new]; +static std::mutex& s_appMutex = *new std::mutex(); + ++ (NSArray *)allApps { + std::lock_guard lock(s_appMutex); + return s_apps.allValues; +} + ++ (void)resetAppCache { + std::lock_guard lock(s_appMutex); + [s_apps removeAllObjects]; + app::App::clear_cached_apps(); +} + ++ (instancetype)appWithConfiguration:(RLMAppConfiguration *)configuration { + std::lock_guard lock(s_appMutex); + NSString *appId = configuration.appId; + if (RLMApp *app = s_apps[appId]) { + return app; + } + return s_apps[appId] = [[RLMApp alloc] initWithConfiguration:configuration.copy]; +} + ++ (instancetype)appWithId:(NSString *)appId configuration:(RLMAppConfiguration *)configuration { + std::lock_guard lock(s_appMutex); + if (RLMApp *app = s_apps[appId]) { + return app; + } + configuration = configuration.copy; + configuration.appId = appId; + return s_apps[appId] = [[RLMApp alloc] initWithConfiguration:configuration]; +} + ++ (instancetype)appWithId:(NSString *)appId { + std::lock_guard lock(s_appMutex); + if (RLMApp *app = s_apps[appId]) { + return app; + } + auto config = [[RLMAppConfiguration alloc] init]; + config.appId = appId; + return s_apps[appId] = [[RLMApp alloc] initWithConfiguration:config]; +} + +- (NSString *)appId { + return @(_app->config().app_id.c_str()); +} + +- (std::shared_ptr)_realmApp { + return _app; +} + +- (NSDictionary *)allUsers { + NSMutableDictionary *buffer = [NSMutableDictionary new]; + for (auto&& user : _app->sync_manager()->all_users()) { + NSString *identity = @(user->identity().c_str()); + buffer[identity] = [[RLMUser alloc] initWithUser:std::move(user) app:self]; + } + return buffer; +} + +- (RLMUser *)currentUser { + if (auto user = _app->sync_manager()->get_current_user()) { + return [[RLMUser alloc] initWithUser:user app:self]; + } + return nil; +} + +- (RLMEmailPasswordAuth *)emailPasswordAuth { + return [[RLMEmailPasswordAuth alloc] initWithApp: self]; +} + +- (void)loginWithCredential:(RLMCredentials *)credentials + completion:(RLMUserCompletionBlock)completionHandler { + auto completion = ^(std::shared_ptr user, std::optional error) { + if (error) { + return completionHandler(nil, makeError(*error)); + } + + completionHandler([[RLMUser alloc] initWithUser:user app:self], nil); + }; + return RLMTranslateError([&] { + return _app->log_in_with_credentials(credentials.appCredentials, completion); + }); +} + +- (RLMUser *)switchToUser:(RLMUser *)syncUser { + return RLMTranslateError([&] { + return [[RLMUser alloc] initWithUser:_app->switch_user(syncUser._syncUser) app:self]; + }); +} + +- (RLMPushClient *)pushClientWithServiceName:(NSString *)serviceName { + return RLMTranslateError([&] { + return [[RLMPushClient alloc] initWithPushClient:_app->push_notification_client(serviceName.UTF8String)]; + }); +} + +#pragma mark - Sign In With Apple Extension + +- (void)setAuthorizationDelegate:(id)authorizationDelegate API_AVAILABLE(ios(13.0), macos(10.15), tvos(13.0), watchos(6.0)) { + _authorizationDelegate = authorizationDelegate; +} + +- (id)authorizationDelegate API_AVAILABLE(ios(13.0), macos(10.15), tvos(13.0), watchos(6.0)) { + return _authorizationDelegate; +} + +- (void)setASAuthorizationControllerDelegateForController:(ASAuthorizationController *)controller API_AVAILABLE(ios(13.0), macos(10.15), tvos(13.0), watchos(6.0)) { + controller.delegate = self; +} + +- (void)authorizationController:(__unused ASAuthorizationController *)controller + didCompleteWithAuthorization:(ASAuthorization *)authorization API_AVAILABLE(ios(13.0), macos(10.15), tvos(13.0), watchos(6.0)) { + NSString *jwt = [[NSString alloc] initWithData:((ASAuthorizationAppleIDCredential *)authorization.credential).identityToken + encoding:NSUTF8StringEncoding]; + [self loginWithCredential:[RLMCredentials credentialsWithAppleToken:jwt] + completion:^(RLMUser *user, NSError *error) { + if (user) { + [self.authorizationDelegate authenticationDidCompleteWithUser:user]; + } else { + [self.authorizationDelegate authenticationDidFailWithError:error]; + } + }]; +} + +- (void)authorizationController:(__unused ASAuthorizationController *)controller + didCompleteWithError:(NSError *)error API_AVAILABLE(ios(13.0), macos(10.15), tvos(13.0), watchos(6.0)) { + [self.authorizationDelegate authenticationDidFailWithError:error]; +} + +- (RLMAppSubscriptionToken *)subscribe:(RLMAppNotificationBlock)block { + return [[RLMAppSubscriptionToken alloc] initWithApp:_app token:_app->subscribe([block, self] (auto&) { + block(self); + })]; +} + +@end diff --git a/Pods/Realm/Realm/RLMArray.mm b/Pods/Realm/Realm/RLMArray.mm new file mode 100644 index 0000000..ae34c64 --- /dev/null +++ b/Pods/Realm/Realm/RLMArray.mm @@ -0,0 +1,629 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// 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 "RLMArray_Private.hpp" + +#import "RLMObjectSchema.h" +#import "RLMObjectStore.h" +#import "RLMObject_Private.h" +#import "RLMProperty_Private.h" +#import "RLMQueryUtil.hpp" +#import "RLMSchema_Private.h" +#import "RLMSwiftSupport.h" +#import "RLMThreadSafeReference_Private.hpp" +#import "RLMUtil.hpp" + +@interface RLMArray () +@end + +@implementation RLMArray { + // Backing array when this instance is unmanaged + @public + NSMutableArray *_backingCollection; +} +#pragma mark - Initializers + +- (instancetype)initWithObjectClassName:(__unsafe_unretained NSString *const)objectClassName + keyType:(__unused RLMPropertyType)keyType { + return [self initWithObjectClassName:objectClassName]; +} +- (instancetype)initWithObjectType:(RLMPropertyType)type optional:(BOOL)optional + keyType:(__unused RLMPropertyType)keyType { + return [self initWithObjectType:type optional:optional]; +} + +- (instancetype)initWithObjectClassName:(__unsafe_unretained NSString *const)objectClassName { + REALM_ASSERT([objectClassName length] > 0); + self = [super init]; + if (self) { + _objectClassName = objectClassName; + _type = RLMPropertyTypeObject; + } + return self; +} + +- (instancetype)initWithObjectType:(RLMPropertyType)type optional:(BOOL)optional { + REALM_ASSERT(type != RLMPropertyTypeObject); + self = [super init]; + if (self) { + _type = type; + _optional = optional; + } + return self; +} + +- (void)setParent:(RLMObjectBase *)parentObject property:(RLMProperty *)property { + _parentObject = parentObject; + _key = property.name; + _isLegacyProperty = property.isLegacy; +} + +#pragma mark - Convenience wrappers used for all RLMArray types + +- (void)addObjects:(id)objects { + for (id obj in objects) { + [self addObject:obj]; + } +} + +- (void)addObject:(id)object { + [self insertObject:object atIndex:self.count]; +} + +- (void)removeLastObject { + NSUInteger count = self.count; + if (count) { + [self removeObjectAtIndex:count-1]; + } +} + +- (id)objectAtIndexedSubscript:(NSUInteger)index { + return [self objectAtIndex:index]; +} + +- (void)setObject:(id)newValue atIndexedSubscript:(NSUInteger)index { + [self replaceObjectAtIndex:index withObject:newValue]; +} + +- (RLMResults *)sortedResultsUsingKeyPath:(NSString *)keyPath ascending:(BOOL)ascending { + return [self sortedResultsUsingDescriptors:@[[RLMSortDescriptor sortDescriptorWithKeyPath:keyPath ascending:ascending]]]; +} + +- (NSUInteger)indexOfObjectWhere:(NSString *)predicateFormat, ... { + va_list args; + va_start(args, predicateFormat); + NSUInteger index = [self indexOfObjectWhere:predicateFormat args:args]; + va_end(args); + return index; +} + +- (NSUInteger)indexOfObjectWhere:(NSString *)predicateFormat args:(va_list)args { + return [self indexOfObjectWithPredicate:[NSPredicate predicateWithFormat:predicateFormat + arguments:args]]; +} + +// The compiler complains about the method's argument type not matching due to +// it not having the generic type attached, but it doesn't seem to be possible +// to actually include the generic type +// http://www.openradar.me/radar?id=6135653276319744 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wmismatched-parameter-types" +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMArray *, RLMCollectionChange *, NSError *))block { + return RLMAddNotificationBlock(self, block, nil, nil); +} +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMArray *, RLMCollectionChange *, NSError *))block + queue:(dispatch_queue_t)queue { + return RLMAddNotificationBlock(self, block, nil, queue); +} + +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMArray *, RLMCollectionChange *, NSError *))block + keyPaths:(NSArray *)keyPaths { + return RLMAddNotificationBlock(self, block, keyPaths, nil); +} + +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMArray *, RLMCollectionChange *, NSError *))block + keyPaths:(NSArray *)keyPaths + queue:(dispatch_queue_t)queue { + return RLMAddNotificationBlock(self, block, keyPaths, queue); +} +#pragma clang diagnostic pop + +#pragma mark - Unmanaged RLMArray implementation + +- (RLMRealm *)realm { + return nil; +} + +- (id)firstObject { + if (self.count) { + return [self objectAtIndex:0]; + } + return nil; +} + +- (id)lastObject { + NSUInteger count = self.count; + if (count) { + return [self objectAtIndex:count-1]; + } + return nil; +} + +- (id)objectAtIndex:(NSUInteger)index { + validateArrayBounds(self, index); + return [_backingCollection objectAtIndex:index]; +} + +- (NSUInteger)count { + return _backingCollection.count; +} + +- (BOOL)isInvalidated { + return NO; +} + +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state + objects:(__unused __unsafe_unretained id [])buffer + count:(__unused NSUInteger)len { + return RLMUnmanagedFastEnumerate(_backingCollection, state); +} + +template +static void changeArray(__unsafe_unretained RLMArray *const ar, + NSKeyValueChange kind, dispatch_block_t f, IndexSetFactory&& is) { + if (!ar->_backingCollection) { + ar->_backingCollection = [NSMutableArray new]; + } + + if (RLMObjectBase *parent = ar->_parentObject) { + NSIndexSet *indexes = is(); + [parent willChange:kind valuesAtIndexes:indexes forKey:ar->_key]; + f(); + [parent didChange:kind valuesAtIndexes:indexes forKey:ar->_key]; + } + else { + f(); + } +} + +static void changeArray(__unsafe_unretained RLMArray *const ar, NSKeyValueChange kind, + NSUInteger index, dispatch_block_t f) { + changeArray(ar, kind, f, [=] { return [NSIndexSet indexSetWithIndex:index]; }); +} + +static void changeArray(__unsafe_unretained RLMArray *const ar, NSKeyValueChange kind, + NSRange range, dispatch_block_t f) { + changeArray(ar, kind, f, [=] { return [NSIndexSet indexSetWithIndexesInRange:range]; }); +} + +static void changeArray(__unsafe_unretained RLMArray *const ar, NSKeyValueChange kind, + NSIndexSet *is, dispatch_block_t f) { + changeArray(ar, kind, f, [=] { return is; }); +} + +void RLMArrayValidateMatchingObjectType(__unsafe_unretained RLMArray *const array, + __unsafe_unretained id const value) { + if (!value && !array->_optional) { + @throw RLMException(@"Invalid nil value for array of '%@'.", + array->_objectClassName ?: RLMTypeToString(array->_type)); + } + if (array->_type != RLMPropertyTypeObject) { + if (!RLMValidateValue(value, array->_type, array->_optional, false, nil)) { + @throw RLMException(@"Invalid value '%@' of type '%@' for expected type '%@%s'.", + value, [value class], RLMTypeToString(array->_type), + array->_optional ? "?" : ""); + } + return; + } + + auto object = RLMDynamicCast(value); + if (!object) { + return; + } + if (!object->_objectSchema) { + @throw RLMException(@"Object cannot be inserted unless the schema is initialized. " + "This can happen if you try to insert objects into a RLMArray / List from a default value or from an overriden unmanaged initializer (`init()`)."); + } + if (![array->_objectClassName isEqualToString:object->_objectSchema.className]) { + @throw RLMException(@"Object of type '%@' does not match RLMArray type '%@'.", + object->_objectSchema.className, array->_objectClassName); + } +} + +static void validateArrayBounds(__unsafe_unretained RLMArray *const ar, + NSUInteger index, bool allowOnePastEnd=false) { + NSUInteger max = ar->_backingCollection.count + allowOnePastEnd; + if (index >= max) { + @throw RLMException(@"Index %llu is out of bounds (must be less than %llu).", + (unsigned long long)index, (unsigned long long)max); + } +} + +- (void)addObjectsFromArray:(NSArray *)array { + for (id obj in array) { + RLMArrayValidateMatchingObjectType(self, obj); + } + changeArray(self, NSKeyValueChangeInsertion, NSMakeRange(_backingCollection.count, array.count), ^{ + [_backingCollection addObjectsFromArray:array]; + }); +} + +- (void)insertObject:(id)anObject atIndex:(NSUInteger)index { + RLMArrayValidateMatchingObjectType(self, anObject); + validateArrayBounds(self, index, true); + changeArray(self, NSKeyValueChangeInsertion, index, ^{ + [_backingCollection insertObject:anObject atIndex:index]; + }); +} + +- (void)insertObjects:(id)objects atIndexes:(NSIndexSet *)indexes { + changeArray(self, NSKeyValueChangeInsertion, indexes, ^{ + NSUInteger currentIndex = [indexes firstIndex]; + for (RLMObject *obj in objects) { + RLMArrayValidateMatchingObjectType(self, obj); + [_backingCollection insertObject:obj atIndex:currentIndex]; + currentIndex = [indexes indexGreaterThanIndex:currentIndex]; + } + }); +} + +- (void)removeObjectAtIndex:(NSUInteger)index { + validateArrayBounds(self, index); + changeArray(self, NSKeyValueChangeRemoval, index, ^{ + [_backingCollection removeObjectAtIndex:index]; + }); +} + +- (void)removeObjectsAtIndexes:(NSIndexSet *)indexes { + changeArray(self, NSKeyValueChangeRemoval, indexes, ^{ + [_backingCollection removeObjectsAtIndexes:indexes]; + }); +} + +- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject { + RLMArrayValidateMatchingObjectType(self, anObject); + validateArrayBounds(self, index); + changeArray(self, NSKeyValueChangeReplacement, index, ^{ + [_backingCollection replaceObjectAtIndex:index withObject:anObject]; + }); +} + +- (void)moveObjectAtIndex:(NSUInteger)sourceIndex toIndex:(NSUInteger)destinationIndex { + validateArrayBounds(self, sourceIndex); + validateArrayBounds(self, destinationIndex); + id original = _backingCollection[sourceIndex]; + + auto start = std::min(sourceIndex, destinationIndex); + auto len = std::max(sourceIndex, destinationIndex) - start + 1; + changeArray(self, NSKeyValueChangeReplacement, {start, len}, ^{ + [_backingCollection removeObjectAtIndex:sourceIndex]; + [_backingCollection insertObject:original atIndex:destinationIndex]; + }); +} + +- (void)exchangeObjectAtIndex:(NSUInteger)index1 withObjectAtIndex:(NSUInteger)index2 { + validateArrayBounds(self, index1); + validateArrayBounds(self, index2); + + changeArray(self, NSKeyValueChangeReplacement, ^{ + [_backingCollection exchangeObjectAtIndex:index1 withObjectAtIndex:index2]; + }, [=] { + NSMutableIndexSet *set = [[NSMutableIndexSet alloc] initWithIndex:index1]; + [set addIndex:index2]; + return set; + }); +} + +- (NSUInteger)indexOfObject:(id)object { + RLMArrayValidateMatchingObjectType(self, object); + if (!_backingCollection) { + return NSNotFound; + } + if (_type != RLMPropertyTypeObject) { + return [_backingCollection indexOfObject:object]; + } + + NSUInteger index = 0; + for (RLMObjectBase *cmp in _backingCollection) { + if (RLMObjectBaseAreEqual(object, cmp)) { + return index; + } + index++; + } + return NSNotFound; +} + +- (void)removeAllObjects { + changeArray(self, NSKeyValueChangeRemoval, NSMakeRange(0, _backingCollection.count), ^{ + [_backingCollection removeAllObjects]; + }); +} + +- (void)replaceAllObjectsWithObjects:(NSArray *)objects { + if (_backingCollection.count) { + changeArray(self, NSKeyValueChangeRemoval, NSMakeRange(0, _backingCollection.count), ^{ + [_backingCollection removeAllObjects]; + }); + } + if (![objects respondsToSelector:@selector(count)] || !objects.count) { + return; + } + changeArray(self, NSKeyValueChangeInsertion, NSMakeRange(0, objects.count), ^{ + for (id object in objects) { + [_backingCollection addObject:object]; + } + }); +} + +- (RLMResults *)objectsWhere:(NSString *)predicateFormat, ... { + va_list args; + va_start(args, predicateFormat); + RLMResults *results = [self objectsWhere:predicateFormat args:args]; + va_end(args); + return results; +} + +- (RLMResults *)objectsWhere:(NSString *)predicateFormat args:(va_list)args { + return [self objectsWithPredicate:[NSPredicate predicateWithFormat:predicateFormat arguments:args]]; +} + +- (RLMPropertyType)typeForProperty:(NSString *)propertyName { + if ([propertyName isEqualToString:@"self"]) { + return _type; + } + + RLMObjectSchema *objectSchema; + if (_backingCollection.count) { + objectSchema = [_backingCollection[0] objectSchema]; + } + else { + objectSchema = [RLMSchema.partialPrivateSharedSchema schemaForClassName:_objectClassName]; + } + + return RLMValidatedProperty(objectSchema, propertyName).type; +} + +- (id)aggregateProperty:(NSString *)key operation:(NSString *)op method:(SEL)sel { + // Although delegating to valueForKeyPath: here would allow to support + // nested key paths as well, limiting functionality gives consistency + // between unmanaged and managed arrays. + if ([key rangeOfString:@"."].location != NSNotFound) { + @throw RLMException(@"Nested key paths are not supported yet for KVC collection operators."); + } + + bool allowDate = false; + bool sum = false; + if ([op isEqualToString:@"@min"] || [op isEqualToString:@"@max"]) { + allowDate = true; + } + else if ([op isEqualToString:@"@sum"]) { + sum = true; + } + else if (![op isEqualToString:@"@avg"]) { + // Just delegate to NSArray for all other operators + return [_backingCollection valueForKeyPath:[op stringByAppendingPathExtension:key]]; + } + + RLMPropertyType type = [self typeForProperty:key]; + if (!canAggregate(type, allowDate)) { + NSString *method = sel ? NSStringFromSelector(sel) : op; + if (_type == RLMPropertyTypeObject) { + @throw RLMException(@"%@: is not supported for %@ property '%@.%@'", + method, RLMTypeToString(type), _objectClassName, key); + } + else { + @throw RLMException(@"%@ is not supported for %@%s array", + method, RLMTypeToString(_type), _optional ? "?" : ""); + } + } + + NSArray *values = [key isEqualToString:@"self"] ? _backingCollection : [_backingCollection valueForKey:key]; + if (_optional) { + // Filter out NSNull values to match our behavior on managed arrays + NSIndexSet *nonnull = [values indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger, BOOL *) { + return obj != NSNull.null; + }]; + if (nonnull.count < values.count) { + values = [values objectsAtIndexes:nonnull]; + } + } + id result = [values valueForKeyPath:[op stringByAppendingString:@".self"]]; + return sum && !result ? @0 : result; +} + +- (id)valueForKeyPath:(NSString *)keyPath { + if ([keyPath characterAtIndex:0] != '@') { + return _backingCollection ? [_backingCollection valueForKeyPath:keyPath] : [super valueForKeyPath:keyPath]; + } + + if (!_backingCollection) { + _backingCollection = [NSMutableArray new]; + } + + NSUInteger dot = [keyPath rangeOfString:@"."].location; + if (dot == NSNotFound) { + return [_backingCollection valueForKeyPath:keyPath]; + } + + NSString *op = [keyPath substringToIndex:dot]; + NSString *key = [keyPath substringFromIndex:dot + 1]; + return [self aggregateProperty:key operation:op method:nil]; +} + +- (id)valueForKey:(NSString *)key { + if ([key isEqualToString:RLMInvalidatedKey]) { + return @NO; // Unmanaged arrays are never invalidated + } + if (!_backingCollection) { + _backingCollection = [NSMutableArray new]; + } + return [_backingCollection valueForKey:key]; +} + +- (void)setValue:(id)value forKey:(NSString *)key { + if ([key isEqualToString:@"self"]) { + RLMArrayValidateMatchingObjectType(self, value); + for (NSUInteger i = 0, count = _backingCollection.count; i < count; ++i) { + _backingCollection[i] = value; + } + return; + } + else if (_type == RLMPropertyTypeObject) { + [_backingCollection setValue:value forKey:key]; + } + else { + [self setValue:value forUndefinedKey:key]; + } +} + +- (id)minOfProperty:(NSString *)property { + return [self aggregateProperty:property operation:@"@min" method:_cmd]; +} + +- (id)maxOfProperty:(NSString *)property { + return [self aggregateProperty:property operation:@"@max" method:_cmd]; +} + +- (id)sumOfProperty:(NSString *)property { + return [self aggregateProperty:property operation:@"@sum" method:_cmd]; +} + +- (id)averageOfProperty:(NSString *)property { + return [self aggregateProperty:property operation:@"@avg" method:_cmd]; +} + +- (NSUInteger)indexOfObjectWithPredicate:(NSPredicate *)predicate { + if (!_backingCollection) { + return NSNotFound; + } + return [_backingCollection indexOfObjectPassingTest:^BOOL(id obj, NSUInteger, BOOL *) { + return [predicate evaluateWithObject:obj]; + }]; +} + +- (NSArray *)objectsAtIndexes:(NSIndexSet *)indexes { + if ([indexes indexGreaterThanOrEqualToIndex:self.count] != NSNotFound) { + return nil; + } + return [_backingCollection objectsAtIndexes:indexes] ?: @[]; +} + +- (BOOL)isEqual:(id)object { + if (auto array = RLMDynamicCast(object)) { + if (array.realm) { + return NO; + } + NSArray *otherCollection = array->_backingCollection; + return (_backingCollection.count == 0 && otherCollection.count == 0) + || [_backingCollection isEqual:otherCollection]; + } + return NO; +} + +- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath + options:(NSKeyValueObservingOptions)options context:(void *)context { + RLMValidateArrayObservationKey(keyPath, self); + [super addObserver:observer forKeyPath:keyPath options:options context:context]; +} + +#pragma mark - Methods unsupported on unmanaged RLMArray instances + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-parameter" + +- (RLMResults *)objectsWithPredicate:(NSPredicate *)predicate { + @throw RLMException(@"This method may only be called on RLMArray instances retrieved from an RLMRealm"); +} + +- (RLMResults *)sortedResultsUsingDescriptors:(NSArray *)properties { + @throw RLMException(@"This method may only be called on RLMArray instances retrieved from an RLMRealm"); +} + +- (RLMResults *)distinctResultsUsingKeyPaths:(NSArray *)keyPaths { + @throw RLMException(@"This method may only be called on RLMArray instances retrieved from an RLMRealm"); +} + +- (RLMSectionedResults *)sectionedResultsSortedUsingKeyPath:(NSString *)keyPath + ascending:(BOOL)ascending + keyBlock:(RLMSectionedResultsKeyBlock)keyBlock { + @throw RLMException(@"This method may only be called on RLMArray instances retrieved from an RLMRealm"); +} + +- (RLMSectionedResults *)sectionedResultsUsingSortDescriptors:(NSArray *)sortDescriptors + keyBlock:(RLMSectionedResultsKeyBlock)keyBlock { + @throw RLMException(@"This method may only be called on RLMArray instances retrieved from an RLMRealm"); +} + +- (instancetype)freeze { + @throw RLMException(@"This method may only be called on RLMArray instances retrieved from an RLMRealm"); +} + +- (instancetype)thaw { + @throw RLMException(@"This method may only be called on RLMArray instances retrieved from an RLMRealm"); +} + +#pragma mark - Thread Confined Protocol Conformance + +- (realm::ThreadSafeReference)makeThreadSafeReference { + REALM_TERMINATE("Unexpected handover of unmanaged `RLMArray`"); +} + +- (id)objectiveCMetadata { + REALM_TERMINATE("Unexpected handover of unmanaged `RLMArray`"); +} + ++ (instancetype)objectWithThreadSafeReference:(realm::ThreadSafeReference)reference + metadata:(id)metadata + realm:(RLMRealm *)realm { + REALM_TERMINATE("Unexpected handover of unmanaged `RLMArray`"); +} + +#pragma clang diagnostic pop // unused parameter warning + +#pragma mark - Superclass Overrides + +- (NSString *)description { + return [self descriptionWithMaxDepth:RLMDescriptionMaxDepth]; +} + +- (NSString *)descriptionWithMaxDepth:(NSUInteger)depth { + return RLMDescriptionWithMaxDepth(@"RLMArray", self, depth); +} + +#pragma mark - Key Path Strings + +- (NSString *)propertyKey { + return _key; +} + +@end + +@implementation RLMSortDescriptor + ++ (instancetype)sortDescriptorWithKeyPath:(NSString *)keyPath ascending:(BOOL)ascending { + RLMSortDescriptor *desc = [[RLMSortDescriptor alloc] init]; + desc->_keyPath = keyPath; + desc->_ascending = ascending; + return desc; +} + +- (instancetype)reversedSortDescriptor { + return [self.class sortDescriptorWithKeyPath:_keyPath ascending:!_ascending]; +} + +@end diff --git a/Pods/Realm/Realm/RLMAsymmetricObject.mm b/Pods/Realm/Realm/RLMAsymmetricObject.mm new file mode 100644 index 0000000..d6634a4 --- /dev/null +++ b/Pods/Realm/Realm/RLMAsymmetricObject.mm @@ -0,0 +1,101 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2022 Realm Inc. +// +// 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 "RLMAsymmetricObject.h" + +#import "RLMObject_Private.hpp" +#import "RLMObjectStore.h" +#import "RLMSchema_Private.h" + +@implementation RLMAsymmetricObject +// synthesized in RLMObjectBase but redeclared here for documentation purposes +@dynamic objectSchema; + +#pragma mark - Designated Initializers + +- (instancetype)init { + return [super init]; +} + +#pragma mark - Convenience Initializers + +- (instancetype)initWithValue:(id)value { + if (!(self = [self init])) { + return nil; + } + RLMInitializeWithValue(self, value, RLMSchema.partialPrivateSharedSchema); + return self; +} + +#pragma mark - Class-based Object Creation + ++ (instancetype)createInRealm:(RLMRealm *)realm withValue:(id)value { + RLMCreateAsymmetricObjectInRealm(realm, [self className], value); + return nil; +} + +#pragma mark - Subscripting + +- (id)objectForKeyedSubscript:(NSString *)key { + return RLMObjectBaseObjectForKeyedSubscript(self, key); +} + +- (void)setObject:(id)obj forKeyedSubscript:(NSString *)key { + RLMObjectBaseSetObjectForKeyedSubscript(self, key, obj); +} + +#pragma mark - Other Instance Methods + ++ (NSString *)className { + return [super className]; +} + +#pragma mark - Default values for schema definition + ++ (NSString *)primaryKey { + return nil; +} + ++ (NSArray *)indexedProperties { + return @[]; +} + ++ (NSDictionary *)linkingObjectsProperties { + return @{}; +} + ++ (NSDictionary *)defaultPropertyValues { + return nil; +} + ++ (NSArray *)ignoredProperties { + return nil; +} + ++ (NSArray *)requiredProperties { + return @[]; +} + ++ (bool)_realmIgnoreClass { + return false; +} + ++ (bool)isAsymmetric { + return true; +} +@end diff --git a/Pods/Realm/Realm/RLMAsyncTask.mm b/Pods/Realm/Realm/RLMAsyncTask.mm new file mode 100644 index 0000000..6c7d0f8 --- /dev/null +++ b/Pods/Realm/Realm/RLMAsyncTask.mm @@ -0,0 +1,476 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2023 Realm Inc. +// +// 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 "RLMAsyncTask_Private.h" + +#import "RLMError_Private.hpp" +#import "RLMRealm_Private.hpp" +#import "RLMRealmConfiguration_Private.hpp" +#import "RLMScheduler.h" +#import "RLMSyncSubscription_Private.h" +#import "RLMUtil.hpp" + +#import +#import +#import +#import + +static dispatch_queue_t s_async_open_queue = dispatch_queue_create("io.realm.asyncOpenDispatchQueue", + DISPATCH_QUEUE_CONCURRENT); +void RLMSetAsyncOpenQueue(dispatch_queue_t queue) { + s_async_open_queue = queue; +} + +static NSError *s_canceledError = [NSError errorWithDomain:NSPOSIXErrorDomain + code:ECANCELED userInfo:@{ + NSLocalizedDescriptionKey: @"Operation canceled" +}]; + +__attribute__((objc_direct_members)) +@implementation RLMAsyncOpenTask { + RLMUnfairMutex _mutex; + std::shared_ptr _task; + std::vector _progressBlocks; + bool _cancel; + + RLMRealmConfiguration *_configuration; + RLMScheduler *_scheduler; + bool _waitForDownloadCompletion; + void (^_completion)(NSError *); + + RLMRealm *_backgroundRealm; +} + +- (void)addProgressNotificationOnQueue:(dispatch_queue_t)queue block:(RLMProgressNotificationBlock)block { + auto wrappedBlock = ^(NSUInteger transferred_bytes, NSUInteger transferrable_bytes) { + dispatch_async(queue, ^{ + @autoreleasepool { + block(transferred_bytes, transferrable_bytes); + } + }); + }; + + std::lock_guard lock(_mutex); + if (_task) { + _task->register_download_progress_notifier(wrappedBlock); + } + else if (!_cancel) { + _progressBlocks.push_back(wrappedBlock); + } +} + +- (void)addProgressNotificationBlock:(RLMProgressNotificationBlock)block { + [self addProgressNotificationOnQueue:dispatch_get_main_queue() block:block]; +} + +- (void)cancel { + std::lock_guard lock(_mutex); + _cancel = true; + _progressBlocks.clear(); + if (_task) { + _task->cancel(); + // Cancelling realm::AsyncOpenTask results in it never calling our callback, + // so if we're currently in that we have to just send the cancellation + // error immediately. In all other cases, though, we want to wait until + // we've actually cancelled and will send the error the next time we + // check for cancellation + [self reportError:s_canceledError]; + } +} + +- (instancetype)initWithConfiguration:(RLMRealmConfiguration *)configuration + confinedTo:(RLMScheduler *)scheduler + download:(bool)waitForDownloadCompletion { + if (!(self = [super init])) { + return self; + } + + // Copying the configuration here as the user could potentially modify + // the config after calling async open + _configuration = configuration.copy; + _scheduler = scheduler; + _waitForDownloadCompletion = waitForDownloadCompletion; + + return self; +} + +- (instancetype)initWithConfiguration:(RLMRealmConfiguration *)configuration + confinedTo:(RLMScheduler *)confinement + download:(bool)waitForDownloadCompletion + completion:(RLMAsyncOpenRealmCallback)completion { + self = [self initWithConfiguration:configuration confinedTo:confinement + download:waitForDownloadCompletion]; + [self waitForOpen:completion]; + return self; +} + +- (void)waitForOpen:(RLMAsyncOpenRealmCallback)completion { + __weak auto weakSelf = self; + [self waitWithCompletion:^(NSError *error) { + RLMRealm *realm; + if (auto self = weakSelf) { + realm = self->_localRealm; + self->_localRealm = nil; + } + completion(realm, error); + }]; +} + +- (void)waitWithCompletion:(void (^)(NSError *))completion { + std::lock_guard lock(_mutex); + _completion = completion; + if (_cancel) { + return [self reportError:s_canceledError]; + } + + // get_synchronized_realm() synchronously opens the DB and performs file-format + // upgrades, so we want to dispatch to the background before invoking it. + dispatch_async(s_async_open_queue, ^{ + @autoreleasepool { + [self startAsyncOpen]; + } + }); +} + +// The full async open flow is: +// 1. Dispatch to a background queue +// 2. Use Realm::get_synchronized_realm() to create the Realm file, run +// migrations and compactions, and download the latest data from the server. +// 3. Dispatch back to queue +// 4. Initialize a RLMRealm in the background queue to perform the SDK +// initialization (e.g. creating managed accessor classes). +// 5. Wait for initial flexible sync subscriptions to complete +// 6. Dispatch to the final scheduler +// 7. Open the final RLMRealm, release the previously opened background one, +// and then invoke the completion callback. +// +// Steps 2 and 5 are skipped for non-sync or non-flexible sync Realms, in which +// case step 4 will handle doing migrations and compactions etc. in the background. +// +// At any point `cancel` can be called from another thread. Cancellation is mostly +// cooperative rather than preemptive: we check at each step if we've been cancelled, +// and if so call the completion with the cancellation error rather than +// proceeding. Downloading the data from the server is the one exception to this. +// Ideally waiting for flexible sync subscriptions would also be preempted. +- (void)startAsyncOpen { + std::unique_lock lock(_mutex); + if ([self checkCancellation]) { + return; + } + + if (_waitForDownloadCompletion && _configuration.configRef.sync_config) { +#if REALM_ENABLE_SYNC + _task = realm::Realm::get_synchronized_realm(_configuration.config); + for (auto& block : _progressBlocks) { + _task->register_download_progress_notifier(block); + } + _progressBlocks.clear(); + _task->start([=](realm::ThreadSafeReference ref, std::exception_ptr err) { + std::lock_guard lock(_mutex); + if ([self checkCancellation]) { + return; + } + // Note that cancellation intentionally trumps reporting other kinds + // of errors + if (err) { + return [self reportException:err]; + } + + // Dispatch blocks can only capture copyable types, so we need to + // resolve the TSR to a shared_ptr + auto realm = ref.resolve>(nullptr); + // We're now running on the sync worker thread, so hop back + // to a more appropriate queue for the next stage of init. + dispatch_async(s_async_open_queue, ^{ + @autoreleasepool { + [self downloadCompleted]; + // Capture the Realm to keep the RealmCoordinator alive + // so that we don't have to reopen it. + static_cast(realm); + } + }); + }); +#else + @throw RLMException(@"Realm was not built with sync enabled"); +#endif + } + else { + // We're not downloading first, so just proceed directly to the next step. + lock.unlock(); + [self downloadCompleted]; + } +} + +- (void)downloadCompleted { + std::unique_lock lock(_mutex); + _task.reset(); + if ([self checkCancellation]) { + return; + } + + NSError *error; + // We've now downloaded all data (if applicable) and done the object + // store initialization, and are back on our background queue. Next we + // want to do our own initialization while still in the background + @autoreleasepool { + // Holding onto the Realm so that opening the final Realm on the target + // scheduler can hit the fast path + _backgroundRealm = [RLMRealm realmWithConfiguration:_configuration + confinedTo:RLMScheduler.currentRunLoop error:&error]; + if (error) { + return [self reportError:error]; + } + } + +#if REALM_ENABLE_SYNC + // If we're opening a flexible sync Realm, we now want to wait for the + // initial subscriptions to be ready + if (_waitForDownloadCompletion && _backgroundRealm.isFlexibleSync) { + auto subscriptions = _backgroundRealm.subscriptions; + if (subscriptions.state == RLMSyncSubscriptionStatePending) { + // FIXME: need cancellation for waiting for the subscription + return [subscriptions waitForSynchronizationOnQueue:nil + completionBlock:^(NSError *error) { + if (error) { + std::lock_guard lock(_mutex); + return [self reportError:error]; + } + [self asyncOpenCompleted]; + }]; + } + } +#endif + lock.unlock(); + [self asyncOpenCompleted]; +} + +- (void)asyncOpenCompleted { + std::lock_guard lock(_mutex); + if (![self checkCancellation]) { + [_scheduler invoke:^{ + [self openFinalRealmAndCallCompletion]; + }]; + } +} + +- (void)openFinalRealmAndCallCompletion { + std::unique_lock lock(_mutex); + @autoreleasepool { + if ([self checkCancellation]) { + return; + } + if (!_completion) { + return; + } + NSError *error; + auto completion = _completion; + // It should not actually be possible for this to fail + _localRealm = [RLMRealm realmWithConfiguration:_configuration + confinedTo:_scheduler + error:&error]; + [self releaseResources]; + + lock.unlock(); + completion(error); + } +} + +- (bool)checkCancellation { + if (_cancel && _completion) { + [self reportError:s_canceledError]; + } + return _cancel; +} + +- (void)reportException:(std::exception_ptr const&)err { + try { + std::rethrow_exception(err); + } + catch (realm::Exception const& e) { + if (e.code() == realm::ErrorCodes::OperationAborted) { + return [self reportError:s_canceledError]; + } + [self reportError:makeError(e)]; + } + catch (...) { + NSError *error; + RLMRealmTranslateException(&error); + [self reportError:error]; + } +} + +- (void)reportError:(NSError *)error { + if (!_completion || !_scheduler) { + return; + } + + auto completion = _completion; + auto scheduler = _scheduler; + [self releaseResources]; + [scheduler invoke:^{ + completion(error); + }]; +} + +- (void)releaseResources { + _backgroundRealm = nil; + _configuration = nil; + _scheduler = nil; + _completion = nil; +} +@end + +@implementation RLMAsyncDownloadTask { + RLMUnfairMutex _mutex; + std::shared_ptr _session; + bool _started; +} + +- (instancetype)initWithRealm:(RLMRealm *)realm { + if (self = [super init]) { + _session = realm->_realm->sync_session(); + } + return self; +} + +- (void)waitWithCompletion:(void (^)(NSError *_Nullable))completion { + std::unique_lock lock(_mutex); + if (!_session) { + lock.unlock(); + return completion(nil); + } + + _started = true; + _session->revive_if_needed(); + _session->wait_for_download_completion([=](realm::Status status) { + completion(makeError(status)); + }); +} + +- (void)cancel { + std::unique_lock lock(_mutex); + if (_started) { + _session->force_close(); + } + _session = nullptr; +} +@end + +__attribute__((objc_direct_members)) +@implementation RLMAsyncRefreshTask { + RLMUnfairMutex _mutex; + void (^_completion)(bool); + bool _complete; + bool _didRefresh; +} + +- (void)complete:(bool)didRefresh { + void (^completion)(bool); + { + std::lock_guard lock(_mutex); + std::swap(completion, _completion); + _complete = true; + // If we're both cancelled and did complete a refresh then continue + // to report true + _didRefresh = _didRefresh || didRefresh; + } + if (completion) { + completion(didRefresh); + } +} + +- (void)wait:(void (^)(bool))completion { + bool didRefresh; + { + std::lock_guard lock(_mutex); + if (!_complete) { + _completion = completion; + return; + } + didRefresh = _didRefresh; + } + completion(didRefresh); +} + ++ (RLMAsyncRefreshTask *)completedRefresh { + static RLMAsyncRefreshTask *shared = [] { + auto refresh = [[RLMAsyncRefreshTask alloc] init]; + refresh->_complete = true; + refresh->_didRefresh = true; + return refresh; + }(); + return shared; +} +@end + +@implementation RLMAsyncWriteTask { + // Mutex guards _realm and _completion + RLMUnfairMutex _mutex; + + // _realm is non-nil only while waiting for an async write to begin. It is + // set to `nil` when it either completes or is cancelled. + RLMRealm *_realm; + dispatch_block_t _completion; + + RLMAsyncTransactionId _id; +} + +// No locking needed for these two as they have to be called before the +// cancellation handler is set up +- (instancetype)initWithRealm:(RLMRealm *)realm { + if (self = [super init]) { + _realm = realm; + } + return self; +} +- (void)setTransactionId:(RLMAsyncTransactionId)transactionID { + _id = transactionID; +} + +- (void)complete:(bool)cancel { + // The swap-under-lock pattern is used to avoid invoking the callback with + // a lock held + dispatch_block_t completion; + { + std::lock_guard lock(_mutex); + std::swap(completion, _completion); + if (cancel) { + // This is a no-op if cancellation is coming after the wait completed + [_realm cancelAsyncTransaction:_id]; + } + _realm = nil; + } + if (completion) { + completion(); + } +} + +- (void)wait:(void (^)())completion { + { + std::lock_guard lock(_mutex); + // `_realm` being non-nil means it's neither completed nor been cancelled + if (_realm) { + _completion = completion; + return; + } + } + + // It has either been completed or cancelled, so call the callback immediately + completion(); +} +@end diff --git a/Pods/Realm/Realm/RLMBSON.mm b/Pods/Realm/Realm/RLMBSON.mm new file mode 100644 index 0000000..c6c49a6 --- /dev/null +++ b/Pods/Realm/Realm/RLMBSON.mm @@ -0,0 +1,423 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 "RLMBSON_Private.hpp" + +#import "RLMDecimal128_Private.hpp" +#import "RLMObjectId_Private.hpp" +#import "RLMUUID_Private.hpp" +#import "RLMUtil.hpp" + +#import + +using namespace realm; +using namespace bson; + +#pragma mark NSNull + +@implementation NSNull (RLMBSON) + +- (RLMBSONType)bsonType { + return RLMBSONTypeNull; +} + +@end + +#pragma mark RLMObjectId + +@implementation RLMObjectId (RLMBSON) + +- (RLMBSONType)bsonType { + return RLMBSONTypeObjectId; +} + +@end + +#pragma mark RLMDecimal128 + +@implementation RLMDecimal128 (RLMBSON) + +- (RLMBSONType)bsonType { + return RLMBSONTypeDecimal128; +} + +@end + +#pragma mark NSString + +@implementation NSString (RLMBSON) + +- (RLMBSONType)bsonType { + return RLMBSONTypeString; +} + +@end + +#pragma mark NSNumber + +@implementation NSNumber (RLMBSON) + +- (RLMBSONType)bsonType { + char numberType = [self objCType][0]; + + if (numberType == *@encode(bool) || + numberType == *@encode(char)) { + return RLMBSONTypeBool; + } else if (numberType == *@encode(int) || + numberType == *@encode(short) || + numberType == *@encode(unsigned short) || + numberType == *@encode(unsigned int)) { + return RLMBSONTypeInt32; + } else if (numberType == *@encode(long) || + numberType == *@encode(long long) || + numberType == *@encode(unsigned long) || + numberType == *@encode(unsigned long long)) { + return RLMBSONTypeInt64; + } else { + return RLMBSONTypeDouble; + } +} + +@end + +#pragma mark NSMutableArray + +@implementation NSMutableArray (RLMBSON) + +- (RLMBSONType)bsonType { + return RLMBSONTypeArray; +} + +- (instancetype)initWithBsonArray:(BsonArray)bsonArray { + + if ((self = [self init])) { + for (auto& entry : bsonArray) { + [self addObject:RLMConvertBsonToRLMBSON(entry)]; + } + + return self; + } + + return nil; +} + +@end + +@implementation NSArray (RLMBSON) + +- (BsonArray)bsonArrayValue { + BsonArray bsonArray; + for (id value in self) { + bsonArray.push_back(RLMConvertRLMBSONToBson(value)); + } + return bsonArray; +} + +- (RLMBSONType)bsonType { + return RLMBSONTypeArray; +} + +@end + +#pragma mark NSDictionary + +@implementation NSMutableDictionary (RLMBSON) + +- (RLMBSONType)bsonType { + return RLMBSONTypeDocument; +} + +- (BsonDocument)bsonDocumentValue { + BsonDocument bsonDocument; + for (NSString *value in self) { + bsonDocument[value.UTF8String] = RLMConvertRLMBSONToBson(self[value]); + } + return bsonDocument; +} + +- (instancetype)initWithBsonDocument:(BsonDocument)bsonDocument { + if ((self = [self init])) { + for (auto it = bsonDocument.begin(); it != bsonDocument.end(); ++it) { + const auto& entry = (*it); + [self setObject:RLMConvertBsonToRLMBSON(entry.second) forKey:@(entry.first.data())]; + } + + return self; + } + + return nil; +} + +@end + +@implementation NSDictionary (RLMBSON) + +- (RLMBSONType)bsonType { + return RLMBSONTypeDocument; +} + +- (BsonDocument)bsonDocumentValue { + BsonDocument bsonDocument; + for (NSString *value in self) { + bsonDocument[value.UTF8String] = RLMConvertRLMBSONToBson(self[value]); + } + return bsonDocument; +} + +@end + +#pragma mark NSData + +@implementation NSData (RLMBSON) + +- (RLMBSONType)bsonType { + return RLMBSONTypeBinary; +} + +- (instancetype)initWithBsonBinary:(std::vector)bsonBinary { + if ((self = [NSData dataWithBytes:bsonBinary.data() length:bsonBinary.size()])) { + return self; + } + + return nil; +} + +@end + +#pragma mark NSDate + +@implementation NSDate (RLMBSON) + +- (RLMBSONType)bsonType { + return RLMBSONTypeDatetime; +} + +@end + +#pragma mark NSUUID + +@implementation NSUUID (RLMBSON) + +- (RLMBSONType)bsonType { + return RLMBSONTypeUUID; +} + +@end + +#pragma mark NSRegularExpression + +@implementation NSRegularExpression (RLMBSON) + +- (RLMBSONType)bsonType { + return RLMBSONTypeRegularExpression; +} + +- (RegularExpression)regularExpressionValue { + using Option = RegularExpression::Option; + std::string s; + + if ((_options & NSRegularExpressionCaseInsensitive) != 0) s += 'i'; + if ((_options & NSRegularExpressionUseUnixLineSeparators) != 0) s += 'm'; + if ((_options & NSRegularExpressionDotMatchesLineSeparators) != 0) s += 's'; + if ((_options & NSRegularExpressionUseUnicodeWordBoundaries) != 0) s += 'x'; + + return RegularExpression(_pattern.UTF8String, s); +} + +- (instancetype)initWithRegularExpression:(RegularExpression)regularExpression { + if ((self = [self init])) { + _pattern = @(regularExpression.pattern().data()); + switch (regularExpression.options()) { + case realm::bson::RegularExpression::Option::None: + _options = 0; + break; + case realm::bson::RegularExpression::Option::IgnoreCase: + _options = NSRegularExpressionCaseInsensitive; + break; + case realm::bson::RegularExpression::Option::Multiline: + _options = NSRegularExpressionUseUnixLineSeparators; + break; + case realm::bson::RegularExpression::Option::Dotall: + _options = NSRegularExpressionDotMatchesLineSeparators; + break; + case realm::bson::RegularExpression::Option::Extended: + _options = NSRegularExpressionUseUnicodeWordBoundaries; + break; + } + return self; + } + + return nil; +} + +@end + +#pragma mark RLMMaxKey + +@implementation RLMMaxKey + +- (BOOL)isEqual:(id)other { + return other == self || ([other class] == [self class]); +} + +- (NSUInteger)hash { + return 0; +} + +@end + +#pragma mark RLMMaxKey + +@implementation RLMMinKey + +- (BOOL)isEqual:(id)other { + return other == self || ([other class] == [self class]); +} + +- (NSUInteger)hash { + return 0; +} + +@end + +@implementation RLMMaxKey (RLMBSON) + +- (RLMBSONType)bsonType { + return RLMBSONTypeMaxKey; +} + +@end + +@implementation RLMMinKey (RLMBSON) + +- (RLMBSONType)bsonType { + return RLMBSONTypeMinKey; +} + +@end + +#pragma mark RLMBSONToBson + +Bson RLMConvertRLMBSONToBson(id b) { + switch ([b bsonType]) { + case RLMBSONTypeString: + return ((NSString *)b).UTF8String; + case RLMBSONTypeInt32: + return ((NSNumber *)b).intValue; + case RLMBSONTypeInt64: + return ((NSNumber *)b).longLongValue; + case RLMBSONTypeObjectId: + return [((RLMObjectId *)b) value]; + case RLMBSONTypeNull: + return util::none; + case RLMBSONTypeBool: + return (bool)((NSNumber *)b).boolValue; + case RLMBSONTypeDouble: + return ((NSNumber *)b).doubleValue; + case RLMBSONTypeBinary: + return std::vector((char*)((NSData *)b).bytes, + ((char*)((NSData *)b).bytes) + (int)((NSData *)b).length); + case RLMBSONTypeTimestamp: + // This represents a value of `Timestamp` in a MongoDB Collection. + return MongoTimestamp(((NSDate *)b).timeIntervalSince1970, 0); + case RLMBSONTypeDatetime: + // This represents a value of `Date` in a MongoDB Collection. + return RLMTimestampForNSDate((NSDate *)b); + case RLMBSONTypeDecimal128: + return [((RLMDecimal128 *)b) decimal128Value]; + case RLMBSONTypeRegularExpression: + return [((NSRegularExpression *)b) regularExpressionValue]; + case RLMBSONTypeMaxKey: + return max_key; + case RLMBSONTypeMinKey: + return min_key; + case RLMBSONTypeDocument: + return [((NSDictionary *)b) bsonDocumentValue]; + case RLMBSONTypeArray: + return [((NSArray *)b) bsonArrayValue]; + case RLMBSONTypeUUID: + return [((NSUUID *)b) rlm_uuidValue]; + } +} + +BsonDocument RLMConvertRLMBSONArrayToBsonDocument(NSArray> *array) { + BsonDocument bsonDocument = BsonDocument{}; + for (NSDictionary> *item in array) { + [item enumerateKeysAndObjectsUsingBlock:[&](NSString *key, id bson, BOOL *) { + bsonDocument[key.UTF8String] = RLMConvertRLMBSONToBson(bson); + }]; + } + return bsonDocument; +} + +#pragma mark BsonToRLMBSON + +id RLMConvertBsonToRLMBSON(const Bson& b) { + switch (b.type()) { + case realm::bson::Bson::Type::Null: + return [NSNull null]; + case realm::bson::Bson::Type::Int32: + return @(static_cast(b)); + case realm::bson::Bson::Type::Int64: + return @(static_cast(b)); + case realm::bson::Bson::Type::Bool: + return @(static_cast(b)); + case realm::bson::Bson::Type::Double: + return @(static_cast(b)); + case realm::bson::Bson::Type::String: + return @(static_cast(b).c_str()); + case realm::bson::Bson::Type::Binary: + return [[NSData alloc] initWithBsonBinary:static_cast>(b)]; + case realm::bson::Bson::Type::Timestamp: + return [[NSDate alloc] initWithTimeIntervalSince1970:static_cast(b).seconds]; + case realm::bson::Bson::Type::Datetime: + return [[NSDate alloc] initWithTimeIntervalSince1970:static_cast(b).get_seconds()]; + case realm::bson::Bson::Type::ObjectId: + return [[RLMObjectId alloc] initWithValue:static_cast(b)]; + case realm::bson::Bson::Type::Decimal128: + return [[RLMDecimal128 alloc] initWithDecimal128:static_cast(b)]; + case realm::bson::Bson::Type::RegularExpression: + return [[NSRegularExpression alloc] initWithRegularExpression:static_cast(b)]; + case realm::bson::Bson::Type::MaxKey: + return [RLMMaxKey new]; + case realm::bson::Bson::Type::MinKey: + return [RLMMinKey new]; + case realm::bson::Bson::Type::Document: + return [[NSMutableDictionary alloc] initWithBsonDocument:static_cast(b)]; + case realm::bson::Bson::Type::Array: + return [[NSMutableArray alloc] initWithBsonArray:static_cast(b)]; + case realm::bson::Bson::Type::Uuid: + return [[NSUUID alloc] initWithRealmUUID:static_cast(b)]; + } + return nil; +} + +id RLMConvertBsonDocumentToRLMBSON(std::optional b) { + return b ? RLMConvertBsonToRLMBSON(*b) : nil; +} + +NSArray> *RLMConvertBsonDocumentToRLMBSONArray(std::optional b) { + if (!b) { + return @[]; + } + NSMutableArray> *array = [[NSMutableArray alloc] init]; + for (const auto& [key, value] : *b) { + [array addObject:@{@(key.c_str()): RLMConvertBsonToRLMBSON(value)}]; + } + return array; +} diff --git a/Pods/Realm/Realm/RLMClassInfo.mm b/Pods/Realm/Realm/RLMClassInfo.mm new file mode 100644 index 0000000..a9dff94 --- /dev/null +++ b/Pods/Realm/Realm/RLMClassInfo.mm @@ -0,0 +1,229 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// 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 "RLMClassInfo.hpp" + +#import "RLMRealm_Private.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMSchema.h" +#import "RLMProperty_Private.h" +#import "RLMQueryUtil.hpp" +#import "RLMUtil.hpp" + +#import +#import +#import +#import +#import + +using namespace realm; + +RLMClassInfo::RLMClassInfo(__unsafe_unretained RLMRealm *const realm, + __unsafe_unretained RLMObjectSchema *const rlmObjectSchema, + const realm::ObjectSchema *objectSchema) +: realm(realm), rlmObjectSchema(rlmObjectSchema), objectSchema(objectSchema) { } + +RLMClassInfo::RLMClassInfo(RLMRealm *realm, RLMObjectSchema *rlmObjectSchema, + std::unique_ptr schema) +: realm(realm) +, rlmObjectSchema(rlmObjectSchema) +, objectSchema(&*schema) +, dynamicObjectSchema(std::move(schema)) +, dynamicRLMObjectSchema(rlmObjectSchema) +{ } + +realm::TableRef RLMClassInfo::table() const { + if (auto key = objectSchema->table_key) { + return realm.group.get_table(objectSchema->table_key); + } + return nullptr; +} + +RLMProperty *RLMClassInfo::propertyForTableColumn(ColKey col) const noexcept { + auto const& props = objectSchema->persisted_properties; + for (size_t i = 0; i < props.size(); ++i) { + if (props[i].column_key == col) { + return rlmObjectSchema.properties[i]; + } + } + return nil; +} + +RLMProperty *RLMClassInfo::propertyForPrimaryKey() const noexcept { + return rlmObjectSchema.primaryKeyProperty; +} + +realm::ColKey RLMClassInfo::tableColumn(NSString *propertyName) const { + return tableColumn(RLMValidatedProperty(rlmObjectSchema, propertyName)); +} + +realm::ColKey RLMClassInfo::tableColumn(RLMProperty *property) const { + return objectSchema->persisted_properties[property.index].column_key; +} + +realm::ColKey RLMClassInfo::computedTableColumn(RLMProperty *property) const { + // Retrieve the table key and class info for the origin property + // that corresponds to the target property. + RLMClassInfo& originInfo = realm->_info[property.objectClassName]; + TableKey originTableKey = originInfo.objectSchema->table_key; + + TableRef originTable = realm.group.get_table(originTableKey); + // Get the column key for origin's forward link that links to the property on the target. + ColKey forwardLinkKey = originInfo.tableColumn(property.linkOriginPropertyName); + + // The column key opposite of the origin's forward link is the target's backlink property. + return originTable->get_opposite_column(forwardLinkKey); +} + +RLMClassInfo &RLMClassInfo::linkTargetType(size_t propertyIndex) { + return realm->_info[rlmObjectSchema.properties[propertyIndex].objectClassName]; +} + +RLMClassInfo &RLMClassInfo::linkTargetType(realm::Property const& property) { + REALM_ASSERT(property.type == PropertyType::Object); + return linkTargetType(&property - &objectSchema->persisted_properties[0]); +} + +RLMClassInfo &RLMClassInfo::resolve(__unsafe_unretained RLMRealm *const realm) { + return realm->_info[rlmObjectSchema.className]; +} + +bool RLMClassInfo::isSwiftClass() const noexcept { + return rlmObjectSchema.isSwiftClass; +} + +bool RLMClassInfo::isDynamic() const noexcept { + return !!dynamicObjectSchema; +} + +static KeyPath keyPathFromString(RLMRealm *realm, + RLMSchema *schema, + const RLMClassInfo *info, + RLMObjectSchema *rlmObjectSchema, + NSString *keyPath) { + KeyPath keyPairs; + + for (NSString *component in [keyPath componentsSeparatedByString:@"."]) { + RLMProperty *property = rlmObjectSchema[component]; + if (!property) { + throw RLMException(@"Invalid property name: property '%@' not found in object of type '%@'", + component, rlmObjectSchema.className); + } + + TableKey tk = info->objectSchema->table_key; + ColKey ck; + if (property.type == RLMPropertyTypeObject) { + ck = info->tableColumn(property.name); + info = &realm->_info[property.objectClassName]; + rlmObjectSchema = schema[property.objectClassName]; + } else if (property.type == RLMPropertyTypeLinkingObjects) { + ck = info->computedTableColumn(property); + info = &realm->_info[property.objectClassName]; + rlmObjectSchema = schema[property.objectClassName]; + } else { + ck = info->tableColumn(property.name); + } + + keyPairs.emplace_back(tk, ck); + } + return keyPairs; +} + +std::optional RLMClassInfo::keyPathArrayFromStringArray(NSArray *keyPaths) const { + std::optional keyPathArray; + if (keyPaths.count) { + keyPathArray.emplace(); + for (NSString *keyPath in keyPaths) { + keyPathArray->push_back(keyPathFromString(realm, realm.schema, this, + rlmObjectSchema, keyPath)); + } + } + return keyPathArray; +} + +RLMSchemaInfo::impl::iterator RLMSchemaInfo::begin() noexcept { return m_objects.begin(); } +RLMSchemaInfo::impl::iterator RLMSchemaInfo::end() noexcept { return m_objects.end(); } +RLMSchemaInfo::impl::const_iterator RLMSchemaInfo::begin() const noexcept { return m_objects.begin(); } +RLMSchemaInfo::impl::const_iterator RLMSchemaInfo::end() const noexcept { return m_objects.end(); } + +RLMClassInfo& RLMSchemaInfo::operator[](NSString *name) { + auto it = m_objects.find(name); + if (it == m_objects.end()) { + @throw RLMException(@"Object type '%@' is not managed by the Realm. " + @"If using a custom `objectClasses` / `objectTypes` array in your configuration, " + @"add `%@` to the list of `objectClasses` / `objectTypes`.", + name, name); + } + return *&it->second; +} + +RLMClassInfo* RLMSchemaInfo::operator[](realm::TableKey key) { + for (auto& [name, info] : m_objects) { + if (info.objectSchema->table_key == key) + return &info; + } + return nullptr; +} + +RLMSchemaInfo::RLMSchemaInfo(RLMRealm *realm) { + RLMSchema *rlmSchema = realm.schema; + realm::Schema const& schema = realm->_realm->schema(); + // rlmSchema can be larger due to multiple classes backed by one table + REALM_ASSERT(rlmSchema.objectSchema.count >= schema.size()); + + m_objects.reserve(schema.size()); + for (RLMObjectSchema *rlmObjectSchema in rlmSchema.objectSchema) { + auto it = schema.find(rlmObjectSchema.objectStoreName); + if (it == schema.end()) { + continue; + } + m_objects.emplace(std::piecewise_construct, + std::forward_as_tuple(rlmObjectSchema.className), + std::forward_as_tuple(realm, rlmObjectSchema, + &*it)); + } +} + +RLMSchemaInfo RLMSchemaInfo::clone(realm::Schema const& source_schema, + __unsafe_unretained RLMRealm *const target_realm) { + RLMSchemaInfo info; + info.m_objects.reserve(m_objects.size()); + + auto& schema = target_realm->_realm->schema(); + REALM_ASSERT_DEBUG(schema == source_schema); + for (auto& [name, class_info] : m_objects) { + if (class_info.isDynamic()) { + continue; + } + size_t idx = class_info.objectSchema - &*source_schema.begin(); + info.m_objects.emplace(std::piecewise_construct, + std::forward_as_tuple(name), + std::forward_as_tuple(target_realm, class_info.rlmObjectSchema, + &*schema.begin() + idx)); + } + return info; +} + +void RLMSchemaInfo::appendDynamicObjectSchema(std::unique_ptr schema, + RLMObjectSchema *objectSchema, + __unsafe_unretained RLMRealm *const target_realm) { + m_objects.emplace(std::piecewise_construct, + std::forward_as_tuple(objectSchema.className), + std::forward_as_tuple(target_realm, objectSchema, + std::move(schema))); +} diff --git a/Pods/Realm/Realm/RLMCollection.mm b/Pods/Realm/Realm/RLMCollection.mm new file mode 100644 index 0000000..aebaf1e --- /dev/null +++ b/Pods/Realm/Realm/RLMCollection.mm @@ -0,0 +1,541 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// 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 "RLMCollection_Private.hpp" + +#import "RLMAccessor.hpp" +#import "RLMArray_Private.hpp" +#import "RLMDictionary_Private.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObjectStore.h" +#import "RLMObject_Private.hpp" +#import "RLMObservation.hpp" +#import "RLMProperty_Private.h" +#import "RLMSet_Private.hpp" +#import "RLMSwiftCollectionBase.h" + +#import +#import +#import +#import + +static const int RLMEnumerationBufferSize = 16; + +@implementation RLMFastEnumerator { + // The buffer supplied by fast enumeration does not retain the objects given + // to it, but because we create objects on-demand and don't want them + // autoreleased (a table can have more rows than the device has memory for + // accessor objects) we need a thing to retain them. + id _strongBuffer[RLMEnumerationBufferSize]; + + RLMRealm *_realm; + RLMClassInfo *_info; + + // A pointer to either _snapshot or a Results from the source collection, + // to avoid having to copy the Results when not in a write transaction + realm::Results *_results; + realm::Results _snapshot; + + // A strong reference to the collection being enumerated to ensure it stays + // alive when we're holding a pointer to a member in it + id _collection; +} + +- (instancetype)initWithBackingCollection:(realm::object_store::Collection const&)backingCollection + collection:(id)collection + classInfo:(RLMClassInfo&)info { + self = [super init]; + if (self) { + _info = &info; + _realm = _info->realm; + + if (_realm.inWriteTransaction) { + _snapshot = backingCollection.as_results().snapshot(); + } + else { + _snapshot = backingCollection.as_results(); + _collection = collection; + [_realm registerEnumerator:self]; + } + _results = &_snapshot; + } + return self; +} + +- (instancetype)initWithBackingDictionary:(realm::object_store::Dictionary const&)backingDictionary + dictionary:(RLMManagedDictionary *)dictionary + classInfo:(RLMClassInfo&)info { + self = [super init]; + if (self) { + _info = &info; + _realm = _info->realm; + + if (_realm.inWriteTransaction) { + _snapshot = backingDictionary.get_keys().snapshot(); + } + else { + _snapshot = backingDictionary.get_keys(); + _collection = dictionary; + [_realm registerEnumerator:self]; + } + _results = &_snapshot; + } + return self; +} + +- (instancetype)initWithResults:(realm::Results&)results + collection:(id)collection + classInfo:(RLMClassInfo&)info { + self = [super init]; + if (self) { + _info = &info; + _realm = _info->realm; + if (_realm.inWriteTransaction) { + _snapshot = results.snapshot(); + _results = &_snapshot; + } + else { + _results = &results; + _collection = collection; + [_realm registerEnumerator:self]; + } + } + return self; +} + +- (void)dealloc { + if (_collection) { + [_realm unregisterEnumerator:self]; + } +} + +- (void)detach { + _snapshot = _results->snapshot(); + _results = &_snapshot; + _collection = nil; +} + +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state + count:(NSUInteger)len { + [_realm verifyThread]; + if (!_results->is_valid()) { + @throw RLMException(@"Collection is no longer valid"); + } + // The fast enumeration buffer size is currently a hardcoded number in the + // compiler so this can't actually happen, but just in case it changes in + // the future... + if (len > RLMEnumerationBufferSize) { + len = RLMEnumerationBufferSize; + } + + NSUInteger batchCount = 0, count = state->extra[1]; + + @autoreleasepool { + RLMAccessorContext ctx(*_info); + for (NSUInteger index = state->state; index < count && batchCount < len; ++index) { + _strongBuffer[batchCount] = _results->get(ctx, index); + batchCount++; + } + } + + for (NSUInteger i = batchCount; i < len; ++i) { + _strongBuffer[i] = nil; + } + + if (batchCount == 0) { + // Release our data if we're done, as we're autoreleased and so may + // stick around for a while + if (_collection) { + _collection = nil; + [_realm unregisterEnumerator:self]; + } + + _snapshot = {}; + } + + state->itemsPtr = (__unsafe_unretained id *)(void *)_strongBuffer; + state->state += batchCount; + state->mutationsPtr = state->extra+1; + + return batchCount; +} +@end + +NSUInteger RLMFastEnumerate(NSFastEnumerationState *state, + NSUInteger len, + id collection) { + __autoreleasing RLMFastEnumerator *enumerator; + if (state->state == 0) { + enumerator = collection.fastEnumerator; + state->extra[0] = (long)enumerator; + state->extra[1] = collection.count; + } + else { + enumerator = (__bridge id)(void *)state->extra[0]; + } + + return [enumerator countByEnumeratingWithState:state count:len]; +} + +@interface RLMArrayHolder : NSObject +@end +@implementation RLMArrayHolder { + std::unique_ptr items; +} + +NSUInteger RLMUnmanagedFastEnumerate(id collection, NSFastEnumerationState *state) { + if (state->state != 0) { + return 0; + } + + // We need to enumerate a copy of the backing array so that it doesn't + // reflect changes made during enumeration. This copy has to be autoreleased + // (since there's nowhere for us to store a strong reference), and uses + // RLMArrayHolder rather than an NSArray because NSArray doesn't guarantee + // that it'll use a single contiguous block of memory, and if it doesn't + // we'd need to forward multiple calls to this method to the same NSArray, + // which would require holding a reference to it somewhere. + __autoreleasing RLMArrayHolder *copy = [[RLMArrayHolder alloc] init]; + copy->items = std::make_unique([collection count]); + + NSUInteger i = 0; + for (id object in collection) { + copy->items[i++] = object; + } + + state->itemsPtr = (__unsafe_unretained id *)(void *)copy->items.get(); + // needs to point to something valid, but the whole point of this is so + // that it can't be changed + state->mutationsPtr = state->extra; + state->state = i; + + return i; +} +@end + +template +NSArray *RLMCollectionValueForKey(Collection& collection, NSString *key, RLMClassInfo& info) { + size_t count = collection.size(); + if (count == 0) { + return @[]; + } + + NSMutableArray *array = [NSMutableArray arrayWithCapacity:count]; + if ([key isEqualToString:@"self"]) { + RLMAccessorContext context(info); + for (size_t i = 0; i < count; ++i) { + [array addObject:collection.get(context, i) ?: NSNull.null]; + } + return array; + } + + if (collection.get_type() != realm::PropertyType::Object) { + RLMAccessorContext context(info); + for (size_t i = 0; i < count; ++i) { + [array addObject:[collection.get(context, i) valueForKey:key] ?: NSNull.null]; + } + return array; + } + + RLMObject *accessor = RLMCreateManagedAccessor(info.rlmObjectSchema.accessorClass, &info); + auto prop = info.rlmObjectSchema[key]; + + // Collection properties need to be handled specially since we need to create + // a new collection each time + if (info.rlmObjectSchema.isSwiftClass) { + if (prop.collection && prop.swiftAccessor) { + // Grab the actual class for the generic collection from an instance of it + // so that we can make instances of the collection without creating a new + // object accessor each time + Class cls = [[prop.swiftAccessor get:prop on:accessor] class]; + for (size_t i = 0; i < count; ++i) { + RLMSwiftCollectionBase *base = [[cls alloc] init]; + base._rlmCollection = [[[cls _backingCollectionType] alloc] + initWithParent:collection.get(i) property:prop parentInfo:info]; + [array addObject:base]; + } + return array; + } + } + + auto swiftAccessor = prop.swiftAccessor; + for (size_t i = 0; i < count; i++) { + accessor->_row = collection.get(i); + if (swiftAccessor) { + [swiftAccessor initialize:prop on:accessor]; + } + [array addObject:[accessor valueForKey:key] ?: NSNull.null]; + } + return array; +} + +realm::ColKey columnForProperty(NSString *propertyName, + realm::object_store::Collection const& backingCollection, + RLMClassInfo *objectInfo, + RLMPropertyType propertyType, + RLMCollectionType collectionType) { + if (backingCollection.get_type() == realm::PropertyType::Object) { + return objectInfo->tableColumn(propertyName); + } + if (![propertyName isEqualToString:@"self"]) { + NSString *collectionTypeName; + switch (collectionType) { + case RLMCollectionTypeArray: + collectionTypeName = @"Arrays"; + break; + case RLMCollectionTypeSet: + collectionTypeName = @"Sets"; + break; + case RLMCollectionTypeDictionary: + collectionTypeName = @"Dictionaries"; + break; + } + @throw RLMException(@"%@ of '%@' can only be aggregated on \"self\"", + collectionTypeName, RLMTypeToString(propertyType)); + } + return {}; +} + +template NSArray *RLMCollectionValueForKey(realm::Results&, NSString *, RLMClassInfo&); +template NSArray *RLMCollectionValueForKey(realm::List&, NSString *, RLMClassInfo&); +template NSArray *RLMCollectionValueForKey(realm::object_store::Set&, NSString *, RLMClassInfo&); + +void RLMCollectionSetValueForKey(id collection, NSString *key, id value) { + realm::TableView tv = [collection tableView]; + if (tv.size() == 0) { + return; + } + + RLMClassInfo *info = collection.objectInfo; + RLMObject *accessor = RLMCreateManagedAccessor(info->rlmObjectSchema.accessorClass, info); + for (size_t i = 0; i < tv.size(); i++) { + accessor->_row = tv[i]; + RLMInitializeSwiftAccessor(accessor, false); + [accessor setValue:value forKey:key]; + } +} + +void RLMAssignToCollection(id collection, id value) { + [(id)collection replaceAllObjectsWithObjects:value]; +} + +NSString *RLMDescriptionWithMaxDepth(NSString *name, + id collection, + NSUInteger depth) { + if (depth == 0) { + return @""; + } + + const NSUInteger maxObjects = 100; + auto str = [NSMutableString stringWithFormat:@"%@<%@> <%p> (\n", name, + [collection objectClassName] ?: RLMTypeToString([collection type]), + (void *)collection]; + size_t index = 0, skipped = 0; + for (id obj in collection) { + NSString *sub; + if ([obj respondsToSelector:@selector(descriptionWithMaxDepth:)]) { + sub = [obj descriptionWithMaxDepth:depth - 1]; + } + else { + sub = [obj description]; + } + + // Indent child objects + NSString *objDescription = [sub stringByReplacingOccurrencesOfString:@"\n" + withString:@"\n\t"]; + [str appendFormat:@"\t[%zu] %@,\n", index++, objDescription]; + if (index >= maxObjects) { + skipped = collection.count - maxObjects; + break; + } + } + + // Remove last comma and newline characters + if (collection.count > 0) { + [str deleteCharactersInRange:NSMakeRange(str.length-2, 2)]; + } + if (skipped) { + [str appendFormat:@"\n\t... %zu objects skipped.", skipped]; + } + [str appendFormat:@"\n)"]; + return str; +} + +std::vector> RLMSortDescriptorsToKeypathArray(NSArray *properties) { + std::vector> keypaths; + keypaths.reserve(properties.count); + for (RLMSortDescriptor *desc in properties) { + if ([desc.keyPath rangeOfString:@"@"].location != NSNotFound) { + @throw RLMException(@"Cannot sort on key path '%@': KVC collection operators are not supported.", desc.keyPath); + } + keypaths.push_back({desc.keyPath.UTF8String, desc.ascending}); + } + return keypaths; +} + +@implementation RLMCollectionChange { + realm::CollectionChangeSet _indices; +} + +- (instancetype)initWithChanges:(realm::CollectionChangeSet)indices { + self = [super init]; + if (self) { + _indices = std::move(indices); + } + return self; +} + +static NSArray *toArray(realm::IndexSet const& set) { + NSMutableArray *ret = [NSMutableArray new]; + for (auto index : set.as_indexes()) { + [ret addObject:@(index)]; + } + return ret; +} + +- (NSArray *)insertions { + return toArray(_indices.insertions); +} + +- (NSArray *)deletions { + return toArray(_indices.deletions); +} + +- (NSArray *)modifications { + return toArray(_indices.modifications); +} + +- (NSArray *)deletionsInSection:(NSUInteger)section { + return RLMToIndexPathArray(_indices.deletions, section); +} + +- (NSArray *)insertionsInSection:(NSUInteger)section { + return RLMToIndexPathArray(_indices.insertions, section); +} + +- (NSArray *)modificationsInSection:(NSUInteger)section { + return RLMToIndexPathArray(_indices.modifications, section); +} + +- (NSString *)description { + return [NSString stringWithFormat:@" insertions: %@, deletions: %@, modifications: %@", + (__bridge void *)self, self.insertions, self.deletions, self.modifications]; +} + +@end + +namespace { +struct CollectionCallbackWrapper { + void (^block)(id, id, NSError *); + id collection; + bool ignoreChangesInInitialNotification; + + void operator()(realm::CollectionChangeSet const& changes) { + if (ignoreChangesInInitialNotification) { + ignoreChangesInInitialNotification = false; + block(collection, nil, nil); + } + else if (changes.empty()) { + block(collection, nil, nil); + } + else if (!changes.collection_root_was_deleted || !changes.deletions.empty()) { + block(collection, [[RLMCollectionChange alloc] initWithChanges:changes], nil); + } + } +}; +} // anonymous namespace + +@interface RLMCancellationToken : RLMNotificationToken +@end + +RLM_HIDDEN +@implementation RLMCancellationToken { + __unsafe_unretained RLMRealm *_realm; + realm::NotificationToken _token; + RLMUnfairMutex _mutex; +} + +- (RLMRealm *)realm { + std::lock_guard lock(_mutex); + return _realm; +} + +- (void)suppressNextNotification { + std::lock_guard lock(_mutex); + if (_realm) { + _token.suppress_next(); + } +} + +- (bool)invalidate { + std::lock_guard lock(_mutex); + if (_realm) { + _token = {}; + _realm = nil; + return true; + } + return false; +} + +RLMNotificationToken *RLMAddNotificationBlock(id c, id block, + NSArray *keyPaths, + dispatch_queue_t queue) { + id collection = c; + RLMRealm *realm = collection.realm; + if (!realm) { + @throw RLMException(@"Change notifications are only supported on managed collections."); + } + auto token = [[RLMCancellationToken alloc] init]; + token->_realm = realm; + + RLMClassInfo *info = collection.objectInfo; + if (!queue) { + [realm verifyNotificationsAreSupported:true]; + token->_token = [collection addNotificationCallback:block keyPaths:info->keyPathArrayFromStringArray(keyPaths)]; + return token; + } + + RLMThreadSafeReference *tsr = [RLMThreadSafeReference referenceWithThreadConfined:collection]; + RLMRealmConfiguration *config = realm.configuration; + dispatch_async(queue, ^{ + std::lock_guard lock(token->_mutex); + if (!token->_realm) { + return; + } + RLMRealm *realm = token->_realm = [RLMRealm realmWithConfiguration:config queue:queue error:nil]; + id collection = [realm resolveThreadSafeReference:tsr]; + token->_token = [collection addNotificationCallback:block keyPaths:info->keyPathArrayFromStringArray(keyPaths)]; + }); + return token; +} + +realm::CollectionChangeCallback RLMWrapCollectionChangeCallback(void (^block)(id, id, NSError *), + id collection, bool skipFirst) { + return CollectionCallbackWrapper{block, collection, skipFirst}; +} +@end + +NSArray *RLMToIndexPathArray(realm::IndexSet const& set, NSUInteger section) { + NSMutableArray *ret = [NSMutableArray new]; + NSUInteger path[2] = {section, 0}; + for (auto index : set.as_indexes()) { + path[1] = index; + [ret addObject:[NSIndexPath indexPathWithIndexes:path length:2]]; + } + return ret; +} diff --git a/Pods/Realm/Realm/RLMConstants.m b/Pods/Realm/Realm/RLMConstants.m new file mode 100644 index 0000000..f7d2433 --- /dev/null +++ b/Pods/Realm/Realm/RLMConstants.m @@ -0,0 +1,32 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// 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 + +RLMNotification const RLMRealmRefreshRequiredNotification = @"RLMRealmRefreshRequiredNotification"; +RLMNotification const RLMRealmDidChangeNotification = @"RLMRealmDidChangeNotification"; + +NSString * const RLMExceptionName = @"RLMException"; + +NSString * const RLMRealmVersionKey = @"RLMRealmVersion"; + +NSString * const RLMRealmCoreVersionKey = @"RLMRealmCoreVersion"; + +NSString * const RLMInvalidatedKey = @"invalidated"; + +NSString * const RLMBackupRealmConfigurationErrorKey = @"RLMBackupRealmConfiguration"; diff --git a/Pods/Realm/Realm/RLMCredentials.mm b/Pods/Realm/Realm/RLMCredentials.mm new file mode 100644 index 0000000..ac6d2eb --- /dev/null +++ b/Pods/Realm/Realm/RLMCredentials.mm @@ -0,0 +1,87 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// 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 "RLMCredentials_Private.hpp" + +#import "RLMBSON_Private.hpp" +#import "RLMUtil.hpp" + +#import + +using namespace realm::app; + +@implementation RLMCredentials +- (instancetype)initWithAppCredentials:(AppCredentials&&)credentials { + if (self = [super init]) { + _appCredentials = std::move(credentials); + _provider = @(_appCredentials.provider_as_string().data()); + return self; + } + return nil; +} + ++ (instancetype)credentialsWithFacebookToken:(RLMCredentialsToken)token { + return [[self alloc] initWithAppCredentials:AppCredentials::facebook(token.UTF8String)]; +} + ++ (instancetype)credentialsWithGoogleAuthCode:(RLMCredentialsToken)token { + return [[self alloc] initWithAppCredentials:AppCredentials::google(AuthCode(token.UTF8String))]; +} + ++ (instancetype)credentialsWithGoogleIdToken:(RLMCredentialsToken)token { + return [[self alloc] initWithAppCredentials:AppCredentials::google(IdToken(token.UTF8String))]; +} + ++ (instancetype)credentialsWithAppleToken:(RLMCredentialsToken)token { + return [[self alloc] initWithAppCredentials:AppCredentials::apple(token.UTF8String)]; +} + ++ (instancetype)credentialsWithEmail:(NSString *)username + password:(NSString *)password { + return [[self alloc] initWithAppCredentials:AppCredentials::username_password(username.UTF8String, + password.UTF8String)]; +} + ++ (instancetype)credentialsWithJWT:(NSString *)token { + return [[self alloc] initWithAppCredentials:AppCredentials::custom(token.UTF8String)]; +} + ++ (instancetype)credentialsWithFunctionPayload:(NSDictionary> *)payload { + return [[self alloc] initWithAppCredentials:AppCredentials::function(static_cast(RLMConvertRLMBSONToBson(payload)))]; +} + ++ (instancetype)credentialsWithUserAPIKey:(NSString *)apiKey { + return [[self alloc] initWithAppCredentials:AppCredentials::api_key(apiKey.UTF8String)]; +} + ++ (instancetype)credentialsWithServerAPIKey:(NSString *)apiKey { + return [[self alloc] initWithAppCredentials:AppCredentials::api_key(apiKey.UTF8String)]; +} + ++ (instancetype)anonymousCredentials { + return [[self alloc] initWithAppCredentials:AppCredentials::anonymous()]; +} + +- (BOOL)isEqual:(id)object { + if (auto that = RLMDynamicCast(object)) { + return [self.provider isEqualToString:that.provider] + && self.appCredentials.serialize_as_json() == that.appCredentials.serialize_as_json(); + } + return NO; +} +@end diff --git a/Pods/Realm/Realm/RLMDecimal128.mm b/Pods/Realm/Realm/RLMDecimal128.mm new file mode 100644 index 0000000..3a70174 --- /dev/null +++ b/Pods/Realm/Realm/RLMDecimal128.mm @@ -0,0 +1,220 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 "RLMDecimal128_Private.hpp" + +#import "RLMUtil.hpp" + +#import + +// Swift's obj-c bridging does not support making an obj-c defined class conform +// to Decodable, so we need a Swift-defined subclass for that. This means that +// when Realm Swift is being used, we need to produce objects of that type rather +// than our obj-c defined type. objc_runtime_visible marks the type as being +// visible only to the obj-c runtime and not the linker, which means that it'll +// be `nil` at runtime rather than being a linker error if it's not defined, and +// valid if it happens to be defined by some other library (i.e. Realm Swift). +// +// At the point where the objects are being allocated we generally don't have +// any good way of knowing whether or not it's going to end up being used by +// Swift, so we just switch to the subclass unconditionally if the subclass +// exists. This shouldn't have any impact on obj-c code other than a small +// performance hit. +[[clang::objc_runtime_visible]] +@interface RealmSwiftDecimal128 : RLMDecimal128 +@end + +@implementation RLMDecimal128 { + realm::Decimal128 _value; +} + +- (instancetype)init { + if (self = [super init]) { + if (auto cls = [RealmSwiftDecimal128 class]; cls && cls != self.class) { + object_setClass(self, cls); + } + } + return self; +} + +- (instancetype)initWithDecimal128:(realm::Decimal128)value { + if ((self = [self init])) { + _value = value; + } + return self; +} + +- (instancetype)initWithValue:(id)value { + if ((self = [self init])) { + _value = RLMObjcToDecimal128(value); + } + return self; +} + +- (instancetype)initWithNumber:(NSNumber *)number { + if ((self = [self init])) { + _value = RLMObjcToDecimal128(number); + } + return self; +} + +- (instancetype)initWithString:(NSString *)string error:(__unused NSError **)error { + if ((self = [self init])) { + _value = realm::Decimal128(string.UTF8String); + } + return self; +} + ++ (instancetype)decimalWithNumber:(NSNumber *)number { + return [[self alloc] initWithNumber:number]; +} + ++ (instancetype)decimalWithNSDecimal:(NSDecimalNumber *)number { + return [[self alloc] initWithString:number.stringValue error:nil]; +} + +- (id)copyWithZone:(NSZone *)zone { + RLMDecimal128 *copy = [[self.class allocWithZone:zone] init]; + copy->_value = _value; + return copy; +} + +- (realm::Decimal128)decimal128Value { + return _value; +} + +- (BOOL)isEqual:(id)object { + if (auto decimal128 = RLMDynamicCast(object)) { + return _value == decimal128->_value; + } + if (auto number = RLMDynamicCast(object)) { + return _value == RLMObjcToDecimal128(number); + } + return NO; +} + +- (NSUInteger)hash { + return @(self.doubleValue).hash; +} + +- (NSString *)description { + return self.stringValue; +} + +- (NSComparisonResult)compare:(RLMDecimal128 *)other { + return static_cast(_value.compare(other->_value)); +} + +- (double)doubleValue { + return [NSDecimalNumber decimalNumberWithDecimal:self.decimalValue].doubleValue; +} + +- (NSDecimal)decimalValue { + NSDecimal ret; + [[[NSScanner alloc] initWithString:@(_value.to_string().c_str())] scanDecimal:&ret]; + return ret; +} + +- (NSString *)stringValue { + auto str = _value.to_string(); + // If there's a decimal point, trim trailing zeroes + auto decimal_pos = str.find('.'); + if (decimal_pos != std::string::npos) { + // Look specifically at the range between the decimal point and the E + // if it's present, and the rest of the string if not + std::string_view sv = str; + auto e_pos = str.find('E', decimal_pos); + if (e_pos != std::string::npos) { + sv = sv.substr(0, e_pos); + } + + // Remove everything between the character after the final non-zero + // and the end of the string (or the E) + auto final_non_zero = sv.find_last_not_of('0'); + REALM_ASSERT(final_non_zero != std::string::npos); + if (final_non_zero == decimal_pos) { + // Also drop the decimal if there's no non-zero digits after it + --final_non_zero; + } + str.erase(final_non_zero + 1, sv.size() - final_non_zero - 1); + } + return @(str.c_str()); +} + +- (BOOL)isNaN { + return _value.is_nan(); +} + +- (RLMDecimal128 *)magnitude { + auto result = realm::Decimal128(abs(self.doubleValue)); + return [[RLMDecimal128 alloc] initWithDecimal128:result]; +} + +- (void)negate { + _value = realm::Decimal128(-self.doubleValue); +} + ++ (RLMDecimal128 *)minimumDecimalNumber { + return [[RLMDecimal128 alloc] initWithDecimal128:std::numeric_limits::lowest()]; +} + ++ (RLMDecimal128 *)maximumDecimalNumber { + return [[RLMDecimal128 alloc] initWithDecimal128:std::numeric_limits::max()]; +} + +- (RLMDecimal128 *)decimalNumberByAdding:(RLMDecimal128 *)decimalNumber { + auto rhs = RLMObjcToDecimal128(decimalNumber); + return [[RLMDecimal128 alloc] initWithDecimal128:_value+rhs]; +} + +- (RLMDecimal128 *)decimalNumberByDividingBy:(RLMDecimal128 *)decimalNumber { + auto rhs = RLMObjcToDecimal128(decimalNumber); + return [[RLMDecimal128 alloc] initWithDecimal128:_value/rhs]; +} + +- (RLMDecimal128 *)decimalNumberBySubtracting:(RLMDecimal128 *)decimalNumber { + auto rhs = RLMObjcToDecimal128(decimalNumber); + return [[RLMDecimal128 alloc] initWithDecimal128:_value-rhs]; +} + +- (RLMDecimal128 *)decimalNumberByMultiplyingBy:(RLMDecimal128 *)decimalNumber { + auto rhs = RLMObjcToDecimal128(decimalNumber); + return [[RLMDecimal128 alloc] initWithDecimal128:_value*rhs]; +} + +- (BOOL)isGreaterThan:(RLMDecimal128 *)decimalNumber { + auto rhs = RLMObjcToDecimal128(decimalNumber); + return _value > rhs; +} + +- (BOOL)isGreaterThanOrEqualTo:(RLMDecimal128 *)decimalNumber { + auto rhs = RLMObjcToDecimal128(decimalNumber); + return _value >= rhs; +} + +- (BOOL)isLessThan:(RLMDecimal128 *)decimalNumber { + auto rhs = RLMObjcToDecimal128(decimalNumber); + return _value < rhs; +} + +- (BOOL)isLessThanOrEqualTo:(RLMDecimal128 *)decimalNumber { + auto rhs = RLMObjcToDecimal128(decimalNumber); + return _value <= rhs; +} + +@end diff --git a/Pods/Realm/Realm/RLMDictionary.mm b/Pods/Realm/Realm/RLMDictionary.mm new file mode 100644 index 0000000..650a011 --- /dev/null +++ b/Pods/Realm/Realm/RLMDictionary.mm @@ -0,0 +1,563 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2021 Realm Inc. +// +// 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 "RLMDictionary_Private.hpp" +#import "RLMObject_Private.h" +#import "RLMObjectSchema.h" +#import "RLMProperty_Private.h" +#import "RLMQueryUtil.hpp" +#import "RLMSchema_Private.h" +#import "RLMThreadSafeReference_Private.hpp" +#import "RLMUtil.hpp" + +@interface RLMDictionary () +@end + +@implementation NSString (RLMDictionaryKey) +@end + +@implementation RLMDictionary { +@public + // Backing dictionary when this instance is unmanaged + NSMutableDictionary *_backingCollection; +} + +#pragma mark Initializers + +- (instancetype)initWithObjectClassName:(__unsafe_unretained NSString *const)objectClassName + keyType:(RLMPropertyType)keyType { + REALM_ASSERT([objectClassName length] > 0); + REALM_ASSERT(RLMValidateKeyType(keyType)); + self = [super init]; + if (self) { + _objectClassName = objectClassName; + _type = RLMPropertyTypeObject; + _keyType = keyType; + _optional = YES; + } + return self; +} + +- (instancetype)initWithObjectType:(RLMPropertyType)type optional:(BOOL)optional keyType:(RLMPropertyType)keyType { + REALM_ASSERT(RLMValidateKeyType(keyType)); + REALM_ASSERT(type != RLMPropertyTypeObject); + self = [super init]; + if (self) { + _type = type; + _keyType = keyType; + _optional = optional; + } + return self; +} + +- (void)setParent:(RLMObjectBase *)parentObject property:(RLMProperty *)property { + _parentObject = parentObject; + _key = property.name; + _isLegacyProperty = property.isLegacy; +} + +static bool RLMValidateKeyType(RLMPropertyType keyType) { + switch (keyType) { + case RLMPropertyTypeString: + return true; + default: + return false; + } +} + +id RLMDictionaryKey(__unsafe_unretained RLMDictionary *const dictionary, + __unsafe_unretained id const key) { + if (!key) { + @throw RLMException(@"Invalid nil key for dictionary expecting key of type '%@'.", + dictionary->_objectClassName ?: RLMTypeToString(dictionary.keyType)); + } + id validated = RLMValidateValue(key, dictionary.keyType, false, false, nil); + if (!validated) { + @throw RLMException(@"Invalid key '%@' of type '%@' for expected type '%@'.", + key, [key class], RLMTypeToString(dictionary.keyType)); + } + return validated; +} + +id RLMDictionaryValue(__unsafe_unretained RLMDictionary *const dictionary, + __unsafe_unretained id const value) { + if (!value) { + return value; + } + if (dictionary->_type != RLMPropertyTypeObject) { + id validated = RLMValidateValue(value, dictionary->_type, dictionary->_optional, false, nil); + if (!validated) { + @throw RLMException(@"Invalid value '%@' of type '%@' for expected type '%@%s'.", + value, [value class], RLMTypeToString(dictionary->_type), + dictionary->_optional ? "?" : ""); + } + return validated; + } + + if (auto valueObject = RLMDynamicCast(value)) { + if (!valueObject->_objectSchema) { + @throw RLMException(@"Object cannot be inserted unless the schema is initialized. " + "This can happen if you try to insert objects into a RLMDictionary / Map from a default value or from an overridden unmanaged initializer (`init()`) or if the key is uninitialized."); + } + if (![dictionary->_objectClassName isEqualToString:valueObject->_objectSchema.className]) { + @throw RLMException(@"Value of type '%@' does not match RLMDictionary value type '%@'.", + valueObject->_objectSchema.className, dictionary->_objectClassName); + } + } + else if (![value isKindOfClass:NSNull.class]) { + @throw RLMException(@"Value of type '%@' does not match RLMDictionary value type '%@'.", + [value className], dictionary->_objectClassName); + } + + return value; +} + +static void changeDictionary(__unsafe_unretained RLMDictionary *const dictionary, + dispatch_block_t f) { + if (!dictionary->_backingCollection) { + dictionary->_backingCollection = [NSMutableDictionary new]; + } + if (RLMObjectBase *parent = dictionary->_parentObject) { + [parent willChangeValueForKey:dictionary->_key]; + f(); + [parent didChangeValueForKey:dictionary->_key]; + } + else { + f(); + } +} + +// The compiler complains about the method's argument type not matching due to +// it not having the generic type attached, but it doesn't seem to be possible +// to actually include the generic type +// http://www.openradar.me/radar?id=6135653276319744 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wmismatched-parameter-types" +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMDictionary *, RLMDictionaryChange *, NSError *))block { + return RLMAddNotificationBlock(self, block, nil, nil); +} +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMDictionary *, RLMDictionaryChange *, NSError *))block + queue:(dispatch_queue_t)queue { + return RLMAddNotificationBlock(self, block, nil, queue); +} + +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMDictionary *, RLMDictionaryChange *, NSError *))block + keyPaths:(nullable NSArray *)keyPaths + queue:(dispatch_queue_t)queue { + return RLMAddNotificationBlock(self, block, keyPaths, queue); +} + +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMDictionary *, RLMDictionaryChange *, NSError *))block + keyPaths:(nullable NSArray *)keyPaths { + return RLMAddNotificationBlock(self, block, keyPaths, nil); +} +#pragma clang diagnostic pop + +#pragma mark - Unmanaged RLMDictionary implementation + +- (RLMRealm *)realm { + return nil; +} + +- (NSUInteger)count { + return _backingCollection.count; +} + +- (NSArray *)allKeys { + return _backingCollection.allKeys ?: @[]; +} + +- (NSArray *)allValues { + return _backingCollection.allValues ?: @[]; +} + +- (nullable id)objectForKey:(id)key { + if (!_backingCollection) { + _backingCollection = [NSMutableDictionary new]; + } + return [_backingCollection objectForKey:key]; +} + +- (nullable id)objectForKeyedSubscript:(id)key { + return [self objectForKey:key]; +} + +- (BOOL)isInvalidated { + return NO; +} + +- (void)setValue:(nullable id)value forKey:(nonnull NSString *)key { + [self setObject:value forKeyedSubscript:key]; +} + +- (void)setDictionary:(id)dictionary { + if (!dictionary || dictionary == NSNull.null) { + return [self removeAllObjects]; + } + if (![dictionary respondsToSelector:@selector(enumerateKeysAndObjectsUsingBlock:)]) { + @throw RLMException(@"Cannot set dictionary to object of class '%@'", [dictionary className]); + } + + changeDictionary(self, ^{ + [_backingCollection removeAllObjects]; + [dictionary enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *) { + [_backingCollection setObject:RLMDictionaryValue(self, value) + forKey:RLMDictionaryKey(self, key)]; + }]; + }); +} + +- (void)setObject:(id)obj forKeyedSubscript:(id)key { + if (obj) { + [self setObject:obj forKey:key]; + } + else { + [self removeObjectForKey:key]; + } +} + +- (void)setObject:(id)obj forKey:(id)key { + changeDictionary(self, ^{ + [_backingCollection setObject:RLMDictionaryValue(self, obj) + forKey:RLMDictionaryKey(self, key)]; + }); +} + +- (void)removeAllObjects { + changeDictionary(self, ^{ + [_backingCollection removeAllObjects]; + }); +} + +- (void)removeObjectsForKeys:(NSArray *)keyArray { + changeDictionary(self, ^{ + [_backingCollection removeObjectsForKeys:keyArray]; + }); +} + +- (void)removeObjectForKey:(id)key { + changeDictionary(self, ^{ + [_backingCollection removeObjectForKey:key]; + }); +} + +- (void)enumerateKeysAndObjectsUsingBlock:(void (^)(id key, id obj, BOOL *stop))block { + [_backingCollection enumerateKeysAndObjectsUsingBlock:block]; +} + +- (nullable id)valueForKey:(nonnull NSString *)key { + if ([key isEqualToString:RLMInvalidatedKey]) { + return @NO; // Unmanaged dictionaries are never invalidated + } + if (!_backingCollection) { + _backingCollection = [NSMutableDictionary new]; + } + return [_backingCollection valueForKey:key]; +} + +- (id)valueForKeyPath:(NSString *)keyPath { + if ([keyPath characterAtIndex:0] != '@') { + return _backingCollection ? [_backingCollection valueForKeyPath:keyPath] : [super valueForKeyPath:keyPath]; + } + if (!_backingCollection) { + _backingCollection = [NSMutableDictionary new]; + } + NSUInteger dot = [keyPath rangeOfString:@"."].location; + if (dot == NSNotFound) { + return [_backingCollection valueForKeyPath:keyPath]; + } + + NSString *op = [keyPath substringToIndex:dot]; + NSString *key = [keyPath substringFromIndex:dot + 1]; + return [self aggregateProperty:key operation:op method:nil]; +} + +- (void)addEntriesFromDictionary:(id)otherDictionary { + if (!otherDictionary) { + return; + } + if (![otherDictionary respondsToSelector:@selector(enumerateKeysAndObjectsUsingBlock:)]) { + @throw RLMException(@"Cannot add entries from object of class '%@'", [otherDictionary className]); + } + + changeDictionary(self, ^{ + [otherDictionary enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *) { + _backingCollection[RLMDictionaryKey(self, key)] = RLMDictionaryValue(self, value); + }]; + }); +} + +- (NSUInteger)countByEnumeratingWithState:(nonnull NSFastEnumerationState *)state + objects:(__unsafe_unretained id _Nullable * _Nonnull)buffer + count:(NSUInteger)len { + return RLMUnmanagedFastEnumerate(_backingCollection.allKeys, state); +} + +#pragma mark - Aggregate operations + +- (RLMPropertyType)typeForProperty:(NSString *)propertyName { + if ([propertyName isEqualToString:@"self"]) { + return _type; + } + + RLMObjectSchema *objectSchema; + if (_backingCollection.count) { + objectSchema = [_backingCollection.allValues[0] objectSchema]; + } + else { + objectSchema = [RLMSchema.partialPrivateSharedSchema schemaForClassName:_objectClassName]; + } + + return RLMValidatedProperty(objectSchema, propertyName).type; +} + +- (id)aggregateProperty:(NSString *)key operation:(NSString *)op method:(SEL)sel { + // Although delegating to valueForKeyPath: here would allow to support + // nested key paths as well, limiting functionality gives consistency + // between unmanaged and managed arrays. + if ([key rangeOfString:@"."].location != NSNotFound) { + @throw RLMException(@"Nested key paths are not supported yet for KVC collection operators."); + } + + if ([op isEqualToString:@"@distinctUnionOfObjects"]) { + @throw RLMException(@"this class does not implement the distinctUnionOfObjects"); + } + + bool allowDate = false; + bool sum = false; + if ([op isEqualToString:@"@min"] || [op isEqualToString:@"@max"]) { + allowDate = true; + } + else if ([op isEqualToString:@"@sum"]) { + sum = true; + } + else if (![op isEqualToString:@"@avg"]) { + // Just delegate to NSDictionary for all other operators + return [_backingCollection valueForKeyPath:[op stringByAppendingPathExtension:key]]; + } + + RLMPropertyType type = [self typeForProperty:key]; + if (!canAggregate(type, allowDate)) { + NSString *method = sel ? NSStringFromSelector(sel) : op; + if (_type == RLMPropertyTypeObject) { + @throw RLMException(@"%@: is not supported for %@ property '%@.%@'", + method, RLMTypeToString(type), _objectClassName, key); + } + else { + @throw RLMException(@"%@ is not supported for %@%s dictionary", + method, RLMTypeToString(_type), _optional ? "?" : ""); + } + } + + NSArray *values = [key isEqualToString:@"self"] ? _backingCollection.allValues : [_backingCollection.allValues valueForKey:key]; + + if (_optional) { + // Filter out NSNull values to match our behavior on managed arrays + NSIndexSet *nonnull = [values indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger, BOOL *) { + return obj != NSNull.null; + }]; + if (nonnull.count < values.count) { + values = [values objectsAtIndexes:nonnull]; + } + } + id result = [values valueForKeyPath:[op stringByAppendingString:@".self"]]; + return sum && !result ? @0 : result; +} + +- (id)minOfProperty:(NSString *)property { + return [self aggregateProperty:property operation:@"@min" method:_cmd]; +} + +- (id)maxOfProperty:(NSString *)property { + return [self aggregateProperty:property operation:@"@max" method:_cmd]; +} + +- (id)sumOfProperty:(NSString *)property { + return [self aggregateProperty:property operation:@"@sum" method:_cmd]; +} + +- (id)averageOfProperty:(NSString *)property { + return [self aggregateProperty:property operation:@"@avg" method:_cmd]; +} + +- (nonnull RLMResults *)objectsWhere:(nonnull NSString *)predicateFormat, ... { + va_list args; + va_start(args, predicateFormat); + RLMResults *results = [self objectsWhere:predicateFormat args:args]; + va_end(args); + return results; +} + +- (nonnull RLMResults *)objectsWhere:(nonnull NSString *)predicateFormat args:(va_list)args { + return [self objectsWithPredicate:[NSPredicate predicateWithFormat:predicateFormat arguments:args]]; +} + +- (BOOL)isEqual:(id)object { + if (auto dictionary = RLMDynamicCast(object)) { + return !dictionary.realm + && ((_backingCollection.count == 0 && dictionary->_backingCollection.count == 0) + || [_backingCollection isEqual:dictionary->_backingCollection]); + } + return NO; +} + +- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath + options:(NSKeyValueObservingOptions)options context:(void *)context { + RLMDictionaryValidateObservationKey(keyPath, self); + [super addObserver:observer forKeyPath:keyPath options:options context:context]; +} + +#pragma mark - Key Path Strings + +- (NSString *)propertyKey { + return _key; +} + +#pragma mark - Methods unsupported on unmanaged RLMDictionary instances + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-parameter" + +- (nonnull RLMResults *)objectsWithPredicate:(nonnull NSPredicate *)predicate { + @throw RLMException(@"This method may only be called on RLMDictionary instances retrieved from an RLMRealm"); +} + +- (RLMResults *)sortedResultsUsingDescriptors:(nonnull NSArray *)properties { + @throw RLMException(@"This method may only be called on RLMDictionary instances retrieved from an RLMRealm"); +} + +- (RLMResults *)sortedResultsUsingKeyPath:(nonnull NSString *)keyPath ascending:(BOOL)ascending { + @throw RLMException(@"This method may only be called on RLMDictionary instances retrieved from an RLMRealm"); +} + +- (RLMResults *)distinctResultsUsingKeyPaths:(NSArray *)keyPaths { + @throw RLMException(@"This method may only be called on RLMDictionary instances retrieved from an RLMRealm"); +} + +- (instancetype)freeze { + @throw RLMException(@"This method may only be called on RLMDictionary instances retrieved from an RLMRealm"); +} + +- (instancetype)thaw { + @throw RLMException(@"This method may only be called on RLMDictionary instances retrieved from an RLMRealm"); +} + +- (NSUInteger)indexOfObject:(id)value { + @throw RLMException(@"This method is not available on RLMDictionary."); +} + +- (id)objectAtIndex:(NSUInteger)index { + @throw RLMException(@"This method is not available on RLMDictionary."); +} + +- (nullable NSArray *)objectsAtIndexes:(nonnull NSIndexSet *)indexes { + @throw RLMException(@"This method is not available on RLMDictionary."); +} + +- (RLMSectionedResults *)sectionedResultsSortedUsingKeyPath:(NSString *)keyPath + ascending:(BOOL)ascending + keyBlock:(RLMSectionedResultsKeyBlock)keyBlock { + @throw RLMException(@"This method is not available on RLMDictionary."); +} + +- (RLMSectionedResults *)sectionedResultsUsingSortDescriptors:(NSArray *)sortDescriptors + keyBlock:(RLMSectionedResultsKeyBlock)keyBlock { + @throw RLMException(@"This method is not available on RLMDictionary."); +} + +#pragma clang diagnostic pop // unused parameter warning + +#pragma mark - Thread Confined Protocol Conformance + +- (realm::ThreadSafeReference)makeThreadSafeReference { + REALM_TERMINATE("Unexpected handover of unmanaged `RLMDictionary`"); +} + +- (id)objectiveCMetadata { + REALM_TERMINATE("Unexpected handover of unmanaged `RLMDictionary`"); +} + ++ (instancetype)objectWithThreadSafeReference:(realm::ThreadSafeReference)reference + metadata:(id)metadata + realm:(RLMRealm *)realm { + REALM_TERMINATE("Unexpected handover of unmanaged `RLMDictionary`"); +} + +#pragma mark - Superclass Overrides + +- (NSString *)description { + return [self descriptionWithMaxDepth:RLMDescriptionMaxDepth]; +} + +- (NSString *)descriptionWithMaxDepth:(NSUInteger)depth { + return RLMDictionaryDescriptionWithMaxDepth(@"RLMDictionary", self, depth); +} + +NSString *RLMDictionaryDescriptionWithMaxDepth(NSString *name, + RLMDictionary *dictionary, + NSUInteger depth) { + if (depth == 0) { + return @""; + } + + const NSUInteger maxObjects = 100; + auto str = [NSMutableString stringWithFormat:@"%@<%@, %@> <%p> (\n", name, + RLMTypeToString([dictionary keyType]), + [dictionary objectClassName] ?: RLMTypeToString([dictionary type]), + (void *)dictionary]; + size_t index = 0, skipped = 0; + for (id key in dictionary) { + id value = dictionary[key]; + NSString *keyDesc; + if ([key respondsToSelector:@selector(descriptionWithMaxDepth:)]) { + keyDesc = [key descriptionWithMaxDepth:depth - 1]; + } + else { + keyDesc = [key description]; + } + NSString *valDesc; + if ([value respondsToSelector:@selector(descriptionWithMaxDepth:)]) { + valDesc = [value descriptionWithMaxDepth:depth - 1]; + } + else { + valDesc = [value description]; + } + + // Indent child objects + NSString *sub = [NSString stringWithFormat:@"[%@]: %@", keyDesc, valDesc]; + NSString *objDescription = [sub stringByReplacingOccurrencesOfString:@"\n" + withString:@"\n\t"]; + [str appendFormat:@"%@,\n", objDescription]; + if (index >= maxObjects) { + skipped = dictionary.count - maxObjects; + break; + } + } + + // Remove last comma and newline characters + if (dictionary.count > 0) { + [str deleteCharactersInRange:NSMakeRange(str.length-2, 2)]; + } + if (skipped) { + [str appendFormat:@"\n\t... %zu objects skipped.", skipped]; + } + [str appendFormat:@"\n)"]; + return str; +} + +@end diff --git a/Pods/Realm/Realm/RLMEmailPasswordAuth.mm b/Pods/Realm/Realm/RLMEmailPasswordAuth.mm new file mode 100644 index 0000000..890fb20 --- /dev/null +++ b/Pods/Realm/Realm/RLMEmailPasswordAuth.mm @@ -0,0 +1,78 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 "RLMEmailPasswordAuth.h" + +#import "RLMApp_Private.hpp" +#import "RLMBSON_Private.hpp" +#import "RLMProviderClient_Private.hpp" + +#import + +@implementation RLMEmailPasswordAuth + +- (realm::app::App::UsernamePasswordProviderClient)client { + return self.app._realmApp->provider_client(); +} + +- (void)registerUserWithEmail:(NSString *)email + password:(NSString *)password + completion:(RLMEmailPasswordAuthOptionalErrorBlock)completion { + self.client.register_email(email.UTF8String, password.UTF8String, RLMWrapCompletion(completion)); +} + +- (void)confirmUser:(NSString *)token + tokenId:(NSString *)tokenId + completion:(RLMEmailPasswordAuthOptionalErrorBlock)completion { + self.client.confirm_user(token.UTF8String, tokenId.UTF8String, RLMWrapCompletion(completion)); +} + +- (void)retryCustomConfirmation:(NSString *)email + completion:(RLMEmailPasswordAuthOptionalErrorBlock)completion { + self.client.retry_custom_confirmation(email.UTF8String, RLMWrapCompletion(completion)); +} + +- (void)resendConfirmationEmail:(NSString *)email + completion:(RLMEmailPasswordAuthOptionalErrorBlock)completion { + self.client.resend_confirmation_email(email.UTF8String, RLMWrapCompletion(completion)); +} + +- (void)sendResetPasswordEmail:(NSString *)email + completion:(RLMEmailPasswordAuthOptionalErrorBlock)completion { + self.client.send_reset_password_email(email.UTF8String, RLMWrapCompletion(completion)); +} + +- (void)resetPasswordTo:(NSString *)password + token:(NSString *)token + tokenId:(NSString *)tokenId + completion:(RLMEmailPasswordAuthOptionalErrorBlock)completion { + self.client.reset_password(password.UTF8String, token.UTF8String, tokenId.UTF8String, + RLMWrapCompletion(completion)); +} + +- (void)callResetPasswordFunction:(NSString *)email + password:(NSString *)password + args:(NSArray> *)args + completion:(RLMEmailPasswordAuthOptionalErrorBlock)completion { + self.client.call_reset_password_function(email.UTF8String, + password.UTF8String, + static_cast(RLMConvertRLMBSONToBson(args)), + RLMWrapCompletion(completion)); +} + +@end diff --git a/Pods/Realm/Realm/RLMEmbeddedObject.mm b/Pods/Realm/Realm/RLMEmbeddedObject.mm new file mode 100644 index 0000000..fb216e5 --- /dev/null +++ b/Pods/Realm/Realm/RLMEmbeddedObject.mm @@ -0,0 +1,123 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 "RLMEmbeddedObject.h" + +#import "RLMObject_Private.hpp" +#import "RLMSchema_Private.h" + +@implementation RLMEmbeddedObject +// synthesized in RLMObjectBase but redeclared here for documentation purposes +@dynamic invalidated, realm, objectSchema; + +#pragma mark - Designated Initializers + +- (instancetype)init { + return [super init]; +} + +#pragma mark - Convenience Initializers + +- (instancetype)initWithValue:(id)value { + if (!(self = [self init])) { + return nil; + } + RLMInitializeWithValue(self, value, RLMSchema.partialPrivateSharedSchema); + return self; +} + +#pragma mark - Subscripting + +- (id)objectForKeyedSubscript:(NSString *)key { + return RLMObjectBaseObjectForKeyedSubscript(self, key); +} + +- (void)setObject:(id)obj forKeyedSubscript:(NSString *)key { + RLMObjectBaseSetObjectForKeyedSubscript(self, key, obj); +} + +#pragma mark - Other Instance Methods + +- (BOOL)isEqualToObject:(RLMObjectBase *)object { + return [object isKindOfClass:RLMObjectBase.class] && RLMObjectBaseAreEqual(self, object); +} + +- (instancetype)freeze { + return RLMObjectFreeze(self); +} + +- (instancetype)thaw { + return RLMObjectThaw(self); +} + +- (RLMNotificationToken *)addNotificationBlock:(RLMObjectChangeBlock)block { + return RLMObjectAddNotificationBlock(self, block, nil, nil); +} + +- (RLMNotificationToken *)addNotificationBlock:(RLMObjectChangeBlock)block queue:(dispatch_queue_t)queue { + return RLMObjectAddNotificationBlock(self, block, nil, queue); +} + +- (RLMNotificationToken *)addNotificationBlock:(RLMObjectChangeBlock)block keyPaths:(NSArray *)keyPaths { + return RLMObjectAddNotificationBlock(self, block, keyPaths, nil); +} + +- (RLMNotificationToken *)addNotificationBlock:(RLMObjectChangeBlock)block + keyPaths:(NSArray *)keyPaths + queue:(dispatch_queue_t)queue { + return RLMObjectAddNotificationBlock(self, block, keyPaths, queue); +} + ++ (NSString *)className { + return [super className]; +} + +#pragma mark - Default values for schema definition + ++ (NSString *)primaryKey { + return nil; +} + ++ (NSArray *)indexedProperties { + return @[]; +} + ++ (NSDictionary *)linkingObjectsProperties { + return @{}; +} + ++ (NSDictionary *)defaultPropertyValues { + return nil; +} + ++ (NSArray *)ignoredProperties { + return nil; +} + ++ (NSArray *)requiredProperties { + return @[]; +} + ++ (bool)_realmIgnoreClass { + return false; +} + ++ (bool)isEmbedded { + return true; +} +@end diff --git a/Pods/Realm/Realm/RLMError.mm b/Pods/Realm/Realm/RLMError.mm new file mode 100644 index 0000000..652129f --- /dev/null +++ b/Pods/Realm/Realm/RLMError.mm @@ -0,0 +1,288 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2022 Realm Inc. +// +// 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 "RLMError_Private.hpp" + +#import "RLMUtil.hpp" +#import "RLMSyncSession_Private.hpp" + +#import +#import +#import + +NSString *const RLMErrorDomain = @"io.realm"; +NSString *const RLMUnknownSystemErrorDomain = @"io.realm.unknown"; +NSString *const RLMSyncErrorDomain = @"io.realm.sync"; +NSString *const RLMSyncAuthErrorDomain = @"io.realm.sync.auth"; +NSString *const RLMAppErrorDomain = @"io.realm.app"; + +NSString *const kRLMSyncPathOfRealmBackupCopyKey = @"recovered_realm_location_path"; +NSString *const kRLMSyncErrorActionTokenKey = @"error_action_token"; +NSString *const RLMErrorCodeKey = @"Error Code"; +NSString *const RLMErrorCodeNameKey = @"Error Name"; +NSString *const RLMServerLogURLKey = @"Server Log URL"; +NSString *const RLMCompensatingWriteInfoKey = @"Compensating Write Info"; +NSString *const RLMHTTPStatusCodeKey = @"HTTP Status Code"; +static NSString *const RLMDeprecatedErrorCodeKey = @"Error Code"; + +namespace { +NSInteger translateFileError(realm::ErrorCodes::Error code) { + using ec = realm::ErrorCodes::Error; + switch (code) { + case ec::AddressSpaceExhausted: return RLMErrorAddressSpaceExhausted; + case ec::DeleteOnOpenRealm: return RLMErrorAlreadyOpen; + case ec::FileAlreadyExists: return RLMErrorFileExists; + case ec::FileFormatUpgradeRequired: return RLMErrorFileFormatUpgradeRequired; + case ec::FileNotFound: return RLMErrorFileNotFound; + case ec::FileOperationFailed: return RLMErrorFileOperationFailed; + case ec::IncompatibleHistories: return RLMErrorIncompatibleHistories; + case ec::IncompatibleLockFile: return RLMErrorIncompatibleLockFile; + case ec::IncompatibleSession: return RLMErrorIncompatibleSession; + case ec::InvalidDatabase: return RLMErrorInvalidDatabase; + case ec::MultipleSyncAgents: return RLMErrorMultipleSyncAgents; + case ec::NoSubscriptionForWrite: return RLMErrorNoSubscriptionForWrite; + case ec::OutOfDiskSpace: return RLMErrorOutOfDiskSpace; + case ec::PermissionDenied: return RLMErrorFilePermissionDenied; + case ec::SchemaMismatch: return RLMErrorSchemaMismatch; + case ec::SubscriptionFailed: return RLMErrorSubscriptionFailed; + case ec::UnsupportedFileFormatVersion: return RLMErrorUnsupportedFileFormatVersion; + + case ec::APIKeyAlreadyExists: return RLMAppErrorAPIKeyAlreadyExists; + case ec::AccountNameInUse: return RLMAppErrorAccountNameInUse; + case ec::AppUnknownError: return RLMAppErrorUnknown; + case ec::AuthError: return RLMAppErrorAuthError; + case ec::AuthProviderNotFound: return RLMAppErrorAuthProviderNotFound; + case ec::DomainNotAllowed: return RLMAppErrorDomainNotAllowed; + case ec::ExecutionTimeLimitExceeded: return RLMAppErrorExecutionTimeLimitExceeded; + case ec::FunctionExecutionError: return RLMAppErrorFunctionExecutionError; + case ec::FunctionInvalid: return RLMAppErrorFunctionInvalid; + case ec::FunctionNotFound: return RLMAppErrorFunctionNotFound; + case ec::FunctionSyntaxError: return RLMAppErrorFunctionSyntaxError; + case ec::InvalidPassword: return RLMAppErrorInvalidPassword; + case ec::InvalidSession: return RLMAppErrorInvalidSession; + case ec::MaintenanceInProgress: return RLMAppErrorMaintenanceInProgress; + case ec::MissingParameter: return RLMAppErrorMissingParameter; + case ec::MongoDBError: return RLMAppErrorMongoDBError; + case ec::NotCallable: return RLMAppErrorNotCallable; + case ec::ReadSizeLimitExceeded: return RLMAppErrorReadSizeLimitExceeded; + case ec::UserAlreadyConfirmed: return RLMAppErrorUserAlreadyConfirmed; + case ec::UserAppDomainMismatch: return RLMAppErrorUserAppDomainMismatch; + case ec::UserDisabled: return RLMAppErrorUserDisabled; + case ec::UserNotFound: return RLMAppErrorUserNotFound; + case ec::ValueAlreadyExists: return RLMAppErrorValueAlreadyExists; + case ec::ValueDuplicateName: return RLMAppErrorValueDuplicateName; + case ec::ValueNotFound: return RLMAppErrorValueNotFound; + + case ec::AWSError: + case ec::GCMError: + case ec::HTTPError: + case ec::InternalServerError: + case ec::TwilioError: + return RLMAppErrorInternalServerError; + + case ec::ArgumentsNotAllowed: + case ec::BadRequest: + case ec::InvalidParameter: + return RLMAppErrorBadRequest; + + default: { + auto category = realm::ErrorCodes::error_categories(code); + if (category.test(realm::ErrorCategory::file_access)) { + return RLMErrorFileAccess; + } + if (category.test(realm::ErrorCategory::app_error)) { + return RLMAppErrorUnknown; + } + return RLMErrorFail; + } + } +} + +NSString *errorDomain(realm::ErrorCodes::Error error) { + auto category = realm::ErrorCodes::error_categories(error); + if (category.test(realm::ErrorCategory::app_error)) { + return RLMAppErrorDomain; + } + return RLMErrorDomain; +} + +NSString *errorString(realm::ErrorCodes::Error error) { + return RLMStringViewToNSString(realm::ErrorCodes::error_string(error)); +} + +NSError *translateSystemError(std::error_code ec, const char *msg) { + int code = ec.value(); + BOOL isGenericCategoryError = ec.category() == std::generic_category() + || ec.category() == realm::util::error::basic_system_error_category(); + NSString *errorDomain = isGenericCategoryError ? NSPOSIXErrorDomain : RLMUnknownSystemErrorDomain; + + NSMutableDictionary *userInfo = [NSMutableDictionary new]; + userInfo[NSLocalizedDescriptionKey] = @(msg); + // FIXME: remove these in v11 + userInfo[@"Error Code"] = @(code); + userInfo[@"Category"] = @(ec.category().name()); + +#if REALM_ENABLE_SYNC + if (ec.category() == realm::sync::client_error_category()) { + if (code == static_cast(realm::sync::Client::Error::connect_timeout)) { + errorDomain = NSPOSIXErrorDomain; + code = ETIMEDOUT; + } + else { + errorDomain = RLMSyncErrorDomain; + } + } +#endif + + return [NSError errorWithDomain:errorDomain code:code userInfo:userInfo.copy]; +} +} // anonymous namespace + +NSError *makeError(realm::Status const& status) { + if (status.is_ok()) { + return nil; + } + auto code = translateFileError(status.code()); + return [NSError errorWithDomain:errorDomain(status.code()) + code:code + userInfo:@{NSLocalizedDescriptionKey: @(status.reason().c_str()), + RLMDeprecatedErrorCodeKey: @(code), + RLMErrorCodeNameKey: errorString(status.code())}]; +} + +NSError *makeError(realm::Exception const& exception) { + auto status = exception.to_status(); + if (status.code() == realm::ErrorCodes::SystemError && status.get_std_error_code() != std::error_code{}) { + return translateSystemError(status.get_std_error_code(), exception.what()); + } + + NSInteger code = translateFileError(exception.code()); + return [NSError errorWithDomain:errorDomain(status.code()) + code:code + userInfo:@{NSLocalizedDescriptionKey: @(exception.what()), + RLMDeprecatedErrorCodeKey: @(code), + RLMErrorCodeNameKey: errorString(exception.code())}]; + +} + +NSError *makeError(realm::FileAccessError const& exception) { + NSInteger code = translateFileError(exception.code()); + return [NSError errorWithDomain:errorDomain(exception.code()) + code:code + userInfo:@{NSLocalizedDescriptionKey: @(exception.what()), + NSFilePathErrorKey: @(exception.get_path().data()), + RLMDeprecatedErrorCodeKey: @(code), + RLMErrorCodeNameKey: errorString(exception.code())}]; +} + +NSError *makeError(std::exception const& exception) { + return [NSError errorWithDomain:RLMErrorDomain + code:RLMErrorFail + userInfo:@{NSLocalizedDescriptionKey: @(exception.what())}]; +} + +NSError *makeError(std::system_error const& exception) { + return translateSystemError(exception.code(), exception.what()); +} + +__attribute__((objc_direct_members)) +@implementation RLMCompensatingWriteInfo { + realm::sync::CompensatingWriteErrorInfo _info; +} + +- (instancetype)initWithInfo:(realm::sync::CompensatingWriteErrorInfo&&)info { + if ((self = [super init])) { + _info = std::move(info); + } + return self; +} + +- (NSString *)objectType { + return @(_info.object_name.c_str()); +} + +- (NSString *)reason { + return @(_info.reason.c_str()); +} + +- (id)primaryKey { + return RLMMixedToObjc(_info.primary_key); +} +@end + +NSError *makeError(realm::SyncError&& error) { + auto& status = error.to_status(); + if (status.is_ok()) { + return nil; + } + + NSMutableDictionary *userInfo = [NSMutableDictionary new]; + userInfo[NSLocalizedDescriptionKey] = RLMStringViewToNSString(error.simple_message); + if (!error.logURL.empty()) { + userInfo[RLMServerLogURLKey] = RLMStringViewToNSString(error.logURL); + } + if (!error.compensating_writes_info.empty()) { + NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:error.compensating_writes_info.size()]; + for (auto& info : error.compensating_writes_info) { + [array addObject:[[RLMCompensatingWriteInfo alloc] initWithInfo:std::move(info)]]; + } + userInfo[RLMCompensatingWriteInfoKey] = [array copy]; + } + for (auto& pair : error.user_info) { + if (pair.first == realm::SyncError::c_original_file_path_key) { + userInfo[kRLMSyncErrorActionTokenKey] = + [[RLMSyncErrorActionToken alloc] initWithOriginalPath:pair.second]; + } + else if (pair.first == realm::SyncError::c_recovery_file_path_key) { + userInfo[kRLMSyncPathOfRealmBackupCopyKey] = @(pair.second.c_str()); + } + } + + RLMSyncError errorCode = RLMSyncErrorClientInternalError; + if (error.is_client_reset_requested()) + errorCode = RLMSyncErrorClientResetError; + else if (error.is_session_level_protocol_error()) { + using enum realm::sync::ProtocolError; + switch (static_cast(error.to_status().get_std_error_code().value())) { + case permission_denied: errorCode = RLMSyncErrorPermissionDeniedError; break; + case bad_authentication: errorCode = RLMSyncErrorClientUserError; break; + case compensating_write: errorCode = RLMSyncErrorWriteRejected; break; + default: errorCode = RLMSyncErrorClientSessionError; + } + } + else if (!error.is_fatal) { + return nil; + } + + return [NSError errorWithDomain:RLMSyncErrorDomain code:errorCode userInfo:userInfo.copy]; +} + +NSError *makeError(realm::app::AppError const& appError) { + auto& status = appError.to_status(); + if (status.is_ok()) { + return nil; + } + + auto code = translateFileError(status.code()); + return [NSError errorWithDomain:errorDomain(status.code()) + code:code + userInfo:@{NSLocalizedDescriptionKey: @(status.reason().c_str()), + RLMDeprecatedErrorCodeKey: @(code), + RLMErrorCodeNameKey: errorString(status.code()), + RLMServerLogURLKey: @(appError.link_to_server_logs.c_str())}]; +} diff --git a/Pods/Realm/Realm/RLMEvent.mm b/Pods/Realm/Realm/RLMEvent.mm new file mode 100644 index 0000000..33da3f1 --- /dev/null +++ b/Pods/Realm/Realm/RLMEvent.mm @@ -0,0 +1,226 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2022 Realm Inc. +// +// 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 + +#import "RLMError_Private.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObjectStore.h" +#import "RLMObject_Private.hpp" +#import "RLMRealmConfiguration_Private.hpp" +#import "RLMRealmUtil.hpp" +#import "RLMRealm_Private.hpp" +#import "RLMSyncConfiguration_Private.hpp" +#import "RLMSyncManager_Private.hpp" +#import "RLMUser_Private.hpp" +#import "RLMUtil.hpp" + +#import +#import +#import + +using namespace realm; + +@interface RLMObjectBase () +- (NSString *)customEventRepresentation; +@end + +namespace { +util::UniqueFunction wrapCompletion(void (^completion)(NSError *)) { + if (!completion) { + return nullptr; + } + return [=](std::exception_ptr err) { + @autoreleasepool { + if (!err) { + return completion(nil); + } + try { + std::rethrow_exception(err); + } + catch (NSException *e) { + auto info = @{@"ExceptionName": e.name ?: NSNull.null, + @"ExceptionReason": e.reason ?: NSNull.null, + @"ExceptionCallStackReturnAddresses": e.callStackReturnAddresses, + @"ExceptionCallStackSymbols": e.callStackSymbols, + @"ExceptionUserInfo": e.userInfo ?: NSNull.null}; + completion([NSError errorWithDomain:RLMErrorDomain code:RLMErrorFail userInfo:info]); + } + catch (...) { + NSError *error; + RLMRealmTranslateException(&error); + completion(error); + } + } + }; +} + +realm::AuditInterface *auditContext(RLMEventContext *context) { + return reinterpret_cast(context); +} + +std::vector> convertMetadata(NSDictionary *metadata) { + std::vector> ret; + ret.reserve(metadata.count); + [metadata enumerateKeysAndObjectsUsingBlock:[&](NSString *key, NSString *value, BOOL *) { + ret.emplace_back(key.UTF8String, value.UTF8String); + }]; + return ret; +} + +std::optional nsStringToOptionalString(NSString *str) { + if (!str) { + return util::none; + } + + std::string ret; + RLMNSStringToStdString(ret, str); + return ret; +} +} // anonymous namespace + +uint64_t RLMEventBeginScope(RLMEventContext *context, NSString *activity) { + return auditContext(context)->begin_scope(activity.UTF8String); +} + +void RLMEventCommitScope(RLMEventContext *context, uint64_t scope_id, RLMEventCompletion completion) { + auditContext(context)->end_scope(scope_id, wrapCompletion(completion)); +} + +void RLMEventCancelScope(RLMEventContext *context, uint64_t scope_id) { + auditContext(context)->cancel_scope(scope_id); +} + +bool RLMEventIsActive(RLMEventContext *context, uint64_t scope_id) { + return auditContext(context)->is_scope_valid(scope_id); +} + +void RLMEventRecordEvent(RLMEventContext *context, NSString *activity, NSString *event, + NSString *data, RLMEventCompletion completion) { + auditContext(context)->record_event(activity.UTF8String, nsStringToOptionalString(event), + nsStringToOptionalString(data), wrapCompletion(completion)); +} + +void RLMEventUpdateMetadata(RLMEventContext *context, NSDictionary *newMetadata) { + auditContext(context)->update_metadata(convertMetadata(newMetadata)); +} + +RLMEventContext *RLMEventGetContext(RLMRealm *realm) { + return reinterpret_cast(realm->_realm->audit_context()); +} + +class RLMEventSerializer : public realm::AuditObjectSerializer { +public: + RLMEventSerializer(RLMRealmConfiguration *c) : _config(c.copy) { + auto& config = _config.configRef; + config.cache = false; + config.audit_config = nullptr; + config.automatic_change_notifications = false; + } + + ~RLMEventSerializer() { + scope_complete(); + } + + void scope_complete() final { + for (auto& [_, acc] : _accessorMap) { + if (acc) { + acc->_realm = nil; + acc->_objectSchema = nil; + } + } + if (_realm) { + _realm->_realm->close(); + _realm = nil; + } + } + + void to_json(nlohmann::json& out, const Obj& obj) final { + @autoreleasepool { + auto tableKey = obj.get_table()->get_key(); + RLMObjectBase *acc = getAccessor(tableKey); + if (!acc) { + return AuditObjectSerializer::to_json(out, obj); + } + + if (!acc->_realm) { + acc->_realm = realm(); + acc->_info = acc->_realm->_info[tableKey]; + acc->_objectSchema = acc->_info->rlmObjectSchema; + } + + acc->_row = obj; + RLMInitializeSwiftAccessor(acc, false); + NSString *customRepresentation = [acc customEventRepresentation]; + out = nlohmann::json::parse(customRepresentation.UTF8String); + } + } + +private: + RLMRealmConfiguration *_config; + RLMRealm *_realm; + std::unordered_map _accessorMap; + + RLMRealm *realm() { + if (!_realm) { + _realm = [RLMRealm realmWithConfiguration:_config error:nil]; + } + return _realm; + } + + RLMObjectBase *getAccessor(TableKey tableKey) { + auto it = _accessorMap.find(tableKey.value); + if (it != _accessorMap.end()) { + return it->second; + } + + RLMClassInfo *info = realm()->_info[tableKey]; + if (!info || !info->rlmObjectSchema.hasCustomEventSerialization) { + _accessorMap.insert({tableKey.value, nil}); + return nil; + } + + RLMObjectBase *acc = [[info->rlmObjectSchema.accessorClass alloc] init]; + acc->_realm = realm(); + acc->_objectSchema = info->rlmObjectSchema; + acc->_info = info; + _accessorMap.insert({tableKey.value, acc}); + return acc; + } +}; + +@implementation RLMEventConfiguration +- (std::shared_ptr)auditConfigWithRealmConfiguration:(RLMRealmConfiguration *)realmConfig { + auto config = std::make_shared(); + config->audit_user = self.syncUser._syncUser; + config->partition_value_prefix = self.partitionPrefix.UTF8String; + config->metadata = convertMetadata(self.metadata); + config->serializer = std::make_shared(realmConfig); + if (_logger) { + config->logger = RLMWrapLogFunction(_logger); + } + if (_errorHandler) { + config->sync_error_handler = [eh = _errorHandler](realm::SyncError e) { + if (auto error = makeError(std::move(e))) { + eh(error); + } + }; + } + return config; +} +@end diff --git a/Pods/Realm/Realm/RLMFindOneAndModifyOptions.mm b/Pods/Realm/Realm/RLMFindOneAndModifyOptions.mm new file mode 100644 index 0000000..d21ba10 --- /dev/null +++ b/Pods/Realm/Realm/RLMFindOneAndModifyOptions.mm @@ -0,0 +1,110 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 "RLMFindOneAndModifyOptions_Private.hpp" +#import "RLMBSON_Private.hpp" +#import "RLMCollection.h" + +@interface RLMFindOneAndModifyOptions() { + realm::app::MongoCollection::FindOneAndModifyOptions _options; +}; +@end + +@implementation RLMFindOneAndModifyOptions + +- (instancetype)initWithProjection:(id _Nullable)projection + sort:(id _Nullable)sort + upsert:(BOOL)upsert + shouldReturnNewDocument:(BOOL)shouldReturnNewDocument { + if (self = [super init]) { + self.upsert = upsert; + self.shouldReturnNewDocument = shouldReturnNewDocument; + self.projection = projection; + self.sort = sort; + } + return self; +} + +- (instancetype)initWithProjection:(id _Nullable)projection + sorting:(NSArray> *)sorting + upsert:(BOOL)upsert + shouldReturnNewDocument:(BOOL)shouldReturnNewDocument { + if (self = [super init]) { + self.upsert = upsert; + self.shouldReturnNewDocument = shouldReturnNewDocument; + self.projection = projection; + self.sorting = sorting; + } + return self; +} + +- (realm::app::MongoCollection::FindOneAndModifyOptions)_findOneAndModifyOptions { + return _options; +} + +- (id)projection { + return RLMConvertBsonDocumentToRLMBSON(_options.projection_bson); +} + +- (id)sort { + return RLMConvertBsonDocumentToRLMBSON(_options.sort_bson); +} + +- (NSArray> *)sorting { + return RLMConvertBsonDocumentToRLMBSONArray(_options.sort_bson); +} + +- (BOOL)upsert { + return _options.upsert; +} + +- (BOOL)shouldReturnNewDocument { + return _options.return_new_document; +} + +- (void)setProjection:(id)projection { + if (projection) { + auto bson = realm::bson::BsonDocument(RLMConvertRLMBSONToBson(projection)); + _options.projection_bson = std::optional(bson); + } else { + _options.projection_bson = realm::util::none; + } +} + +- (void)setSort:(id)sort { + if (sort) { + auto bson = realm::bson::BsonDocument(RLMConvertRLMBSONToBson(sort)); + _options.sort_bson = std::optional(bson); + } else { + _options.sort_bson = realm::util::none; + } +} + +- (void)setSorting:(NSArray> *)sorting { + _options.sort_bson = RLMConvertRLMBSONArrayToBsonDocument(sorting); +} + +- (void)setUpsert:(BOOL)upsert { + _options.upsert = upsert; +} + +- (void)setShouldReturnNewDocument:(BOOL)returnNewDocument { + _options.return_new_document = returnNewDocument; +} + +@end diff --git a/Pods/Realm/Realm/RLMFindOptions.mm b/Pods/Realm/Realm/RLMFindOptions.mm new file mode 100644 index 0000000..37a2bc4 --- /dev/null +++ b/Pods/Realm/Realm/RLMFindOptions.mm @@ -0,0 +1,116 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 "RLMFindOptions_Private.hpp" +#import "RLMBSON_Private.hpp" +#import "RLMCollection.h" + +@interface RLMFindOptions() { + realm::app::MongoCollection::FindOptions _options; +}; +@end + +@implementation RLMFindOptions + +- (instancetype)initWithLimit:(NSInteger)limit + projection:(id _Nullable)projection + sort:(id _Nullable)sort { + if (self = [super init]) { + self.projection = projection; + self.sort = sort; + self.limit = limit; + } + return self; +} + +- (instancetype)initWithProjection:(id _Nullable)projection + sort:(id _Nullable)sort { + if (self = [super init]) { + self.projection = projection; + self.sort = sort; + } + return self; +} + +- (instancetype)initWithLimit:(NSInteger)limit + projection:(id _Nullable)projection + sorting:(NSArray> *)sorting { + if (self = [super init]) { + self.projection = projection; + self.sorting = sorting; + self.limit = limit; + } + return self; +} + +- (instancetype)initWithProjection:(id _Nullable)projection + sorting:(NSArray> *)sorting { + if (self = [super init]) { + self.projection = projection; + self.sorting = sorting; + } + return self; +} + +- (realm::app::MongoCollection::FindOptions)_findOptions { + return _options; +} + +- (id)projection { + return RLMConvertBsonDocumentToRLMBSON(_options.projection_bson); +} + +- (id)sort { + return RLMConvertBsonDocumentToRLMBSON(_options.sort_bson); +} + +- (NSArray> *)sorting { + return RLMConvertBsonDocumentToRLMBSONArray(_options.sort_bson); +} + +- (void)setProjection:(id)projection { + if (projection) { + auto bson = realm::bson::BsonDocument(RLMConvertRLMBSONToBson(projection)); + _options.projection_bson = std::optional(bson); + } else { + _options.projection_bson = realm::util::none; + } +} + +- (void)setSort:(id)sort { + if (sort) { + auto bson = realm::bson::BsonDocument(RLMConvertRLMBSONToBson(sort)); + _options.sort_bson = std::optional(bson); + } else { + _options.sort_bson = realm::util::none; + } +} + +- (void)setSorting:(NSArray> *)sorting { + _options.sort_bson = RLMConvertRLMBSONArrayToBsonDocument(sorting); +} + +- (NSInteger)limit { + return static_cast(_options.limit.value_or(0)); +} + +- (void)setLimit:(NSInteger)limit { + _options.limit = std::optional(limit); +} + +@end diff --git a/Pods/Realm/Realm/RLMLogger.mm b/Pods/Realm/Realm/RLMLogger.mm new file mode 100644 index 0000000..caa7988 --- /dev/null +++ b/Pods/Realm/Realm/RLMLogger.mm @@ -0,0 +1,159 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2023 Realm Inc. +// +// 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 "RLMLogger_Private.h" + +#import "RLMUtil.hpp" + +#import + +typedef void (^RLMLoggerFunction)(RLMLogLevel level, NSString *message); + +using namespace realm; +using Logger = realm::util::Logger; +using Level = Logger::Level; + +namespace { +static Level levelForLogLevel(RLMLogLevel logLevel) { + switch (logLevel) { + case RLMLogLevelOff: return Level::off; + case RLMLogLevelFatal: return Level::fatal; + case RLMLogLevelError: return Level::error; + case RLMLogLevelWarn: return Level::warn; + case RLMLogLevelInfo: return Level::info; + case RLMLogLevelDetail: return Level::detail; + case RLMLogLevelDebug: return Level::debug; + case RLMLogLevelTrace: return Level::trace; + case RLMLogLevelAll: return Level::all; + } + REALM_UNREACHABLE(); // Unrecognized log level. +} + +static RLMLogLevel logLevelForLevel(Level logLevel) { + switch (logLevel) { + case Level::off: return RLMLogLevelOff; + case Level::fatal: return RLMLogLevelFatal; + case Level::error: return RLMLogLevelError; + case Level::warn: return RLMLogLevelWarn; + case Level::info: return RLMLogLevelInfo; + case Level::detail: return RLMLogLevelDetail; + case Level::debug: return RLMLogLevelDebug; + case Level::trace: return RLMLogLevelTrace; + case Level::all: return RLMLogLevelAll; + } + REALM_UNREACHABLE(); // Unrecognized log level. +} + +static NSString* levelPrefix(Level logLevel) { + switch (logLevel) { + case Level::off: + case Level::all: return @""; + case Level::trace: return @"Trace"; + case Level::debug: return @"Debug"; + case Level::detail: return @"Detail"; + case Level::info: return @"Info"; + case Level::error: return @"Error"; + case Level::warn: return @"Warning"; + case Level::fatal: return @"Fatal"; + } + REALM_UNREACHABLE(); // Unrecognized log level. +} + +struct CocoaLogger : public Logger { + void do_log(Level level, const std::string& message) override { + NSLog(@"%@: %@", levelPrefix(level), RLMStringDataToNSString(message)); + } +}; + +class CustomLogger : public Logger { +public: + RLMLoggerFunction function; + void do_log(Level level, const std::string& message) override { + @autoreleasepool { + if (function) { + function(logLevelForLevel(level), RLMStringDataToNSString(message)); + } + } + } +}; +} // anonymous namespace + +@implementation RLMLogger { + std::shared_ptr _logger; +} + +typedef void(^LoggerBlock)(RLMLogLevel level, NSString *message); + +- (RLMLogLevel)level { + return logLevelForLevel(_logger->get_level_threshold()); +} + +- (void)setLevel:(RLMLogLevel)level { + _logger->set_level_threshold(levelForLogLevel(level)); +} + ++ (void)initialize { + auto defaultLogger = std::make_shared(); + defaultLogger->set_level_threshold(Level::info); + Logger::set_default_logger(defaultLogger); +} + +- (instancetype)initWithLogger:(std::shared_ptr)logger { + if (self = [self init]) { + self->_logger = logger; + } + return self; +} + +- (instancetype)initWithLevel:(RLMLogLevel)level logFunction:(RLMLogFunction)logFunction { + if (self = [super init]) { + auto logger = std::make_shared(); + logger->set_level_threshold(levelForLogLevel(level)); + logger->function = logFunction; + self->_logger = logger; + } + return self; +} + +- (void)logWithLevel:(RLMLogLevel)logLevel message:(NSString *)message, ... { + auto level = levelForLogLevel(logLevel); + if (_logger->would_log(level)) { + va_list args; + va_start(args, message); + _logger->log(level, "%1", [[NSString alloc] initWithFormat:message arguments:args].UTF8String); + va_end(args); + } +} + +- (void)logLevel:(RLMLogLevel)logLevel message:(NSString *)message { + auto level = levelForLogLevel(logLevel); + if (_logger->would_log(level)) { + _logger->log(level, "%1", message.UTF8String); + } +} + +#pragma mark Global Logger Setter + ++ (instancetype)defaultLogger { + return [[RLMLogger alloc] initWithLogger:Logger::get_default_logger()]; +} + ++ (void)setDefaultLogger:(RLMLogger *)logger { + Logger::set_default_logger(logger->_logger); +} +@end diff --git a/Pods/Realm/Realm/RLMManagedArray.mm b/Pods/Realm/Realm/RLMManagedArray.mm new file mode 100644 index 0000000..44aee52 --- /dev/null +++ b/Pods/Realm/Realm/RLMManagedArray.mm @@ -0,0 +1,549 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// 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 "RLMArray_Private.hpp" + +#import "RLMAccessor.hpp" +#import "RLMCollection_Private.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObjectStore.h" +#import "RLMObject_Private.hpp" +#import "RLMObservation.hpp" +#import "RLMProperty_Private.hpp" +#import "RLMQueryUtil.hpp" +#import "RLMRealm_Private.hpp" +#import "RLMRealmConfiguration_Private.hpp" +#import "RLMSchema.h" +#import "RLMSectionedResults_Private.hpp" +#import "RLMThreadSafeReference_Private.hpp" +#import "RLMUtil.hpp" + +#import +#import +#import +#import + +#import + +@interface RLMManagedArrayHandoverMetadata : NSObject +@property (nonatomic) NSString *parentClassName; +@property (nonatomic) NSString *key; +@end + +@implementation RLMManagedArrayHandoverMetadata +@end + +@interface RLMManagedArray () +@end + +// +// RLMArray implementation +// +@implementation RLMManagedArray { +@public + realm::List _backingList; + RLMRealm *_realm; + RLMClassInfo *_objectInfo; + RLMClassInfo *_ownerInfo; + std::unique_ptr _observationInfo; +} + +- (RLMManagedArray *)initWithBackingCollection:(realm::List)list + parentInfo:(RLMClassInfo *)parentInfo + property:(__unsafe_unretained RLMProperty *const)property { + if (property.type == RLMPropertyTypeObject) + self = [self initWithObjectClassName:property.objectClassName]; + else + self = [self initWithObjectType:property.type + optional:property.optional]; + if (self) { + _realm = parentInfo->realm; + REALM_ASSERT(list.get_realm() == _realm->_realm); + _backingList = std::move(list); + _ownerInfo = parentInfo; + if (property.type == RLMPropertyTypeObject) + _objectInfo = &parentInfo->linkTargetType(property.index); + else + _objectInfo = _ownerInfo; + _key = property.name; + } + return self; +} + +- (RLMManagedArray *)initWithParent:(__unsafe_unretained RLMObjectBase *const)parentObject + property:(__unsafe_unretained RLMProperty *const)property { + __unsafe_unretained RLMRealm *const realm = parentObject->_realm; + auto col = parentObject->_info->tableColumn(property); + return [self initWithBackingCollection:realm::List(realm->_realm, parentObject->_row, col) + parentInfo:parentObject->_info + property:property]; +} + +- (RLMManagedArray *)initWithParent:(realm::Obj)parent + property:(__unsafe_unretained RLMProperty *const)property + parentInfo:(RLMClassInfo&)info { + auto col = info.tableColumn(property); + return [self initWithBackingCollection:realm::List(info.realm->_realm, parent, col) + parentInfo:&info + property:property]; +} + +void RLMValidateArrayObservationKey(__unsafe_unretained NSString *const keyPath, + __unsafe_unretained RLMArray *const array) { + if (![keyPath isEqualToString:RLMInvalidatedKey]) { + @throw RLMException(@"[<%@ %p> addObserver:forKeyPath:options:context:] is not supported. Key path: %@", + [array class], array, keyPath); + } +} + +void RLMEnsureArrayObservationInfo(std::unique_ptr& info, + __unsafe_unretained NSString *const keyPath, + __unsafe_unretained RLMArray *const array, + __unsafe_unretained id const observed) { + RLMValidateArrayObservationKey(keyPath, array); + if (!info && array.class == [RLMManagedArray class]) { + auto lv = static_cast(array); + info = std::make_unique(*lv->_ownerInfo, + lv->_backingList.get_parent_object_key(), + observed); + } +} + +template +__attribute__((always_inline)) +static auto translateErrors(Function&& f) { + return translateCollectionError(static_cast(f), @"List"); +} + +template +static void changeArray(__unsafe_unretained RLMManagedArray *const ar, + NSKeyValueChange kind, dispatch_block_t f, IndexSetFactory&& is) { + translateErrors([&] { ar->_backingList.verify_in_transaction(); }); + + RLMObservationTracker tracker(ar->_realm); + tracker.trackDeletions(); + auto obsInfo = RLMGetObservationInfo(ar->_observationInfo.get(), + ar->_backingList.get_parent_object_key(), + *ar->_ownerInfo); + if (obsInfo) { + tracker.willChange(obsInfo, ar->_key, kind, is()); + } + + translateErrors(f); +} + +static void changeArray(__unsafe_unretained RLMManagedArray *const ar, NSKeyValueChange kind, NSUInteger index, dispatch_block_t f) { + changeArray(ar, kind, f, [=] { return [NSIndexSet indexSetWithIndex:index]; }); +} + +static void changeArray(__unsafe_unretained RLMManagedArray *const ar, NSKeyValueChange kind, NSRange range, dispatch_block_t f) { + changeArray(ar, kind, f, [=] { return [NSIndexSet indexSetWithIndexesInRange:range]; }); +} + +static void changeArray(__unsafe_unretained RLMManagedArray *const ar, NSKeyValueChange kind, NSIndexSet *is, dispatch_block_t f) { + changeArray(ar, kind, f, [=] { return is; }); +} + +// +// public method implementations +// +- (RLMRealm *)realm { + return _realm; +} + +- (NSUInteger)count { + return translateErrors([&] { return _backingList.size(); }); +} + +- (BOOL)isInvalidated { + return translateErrors([&] { return !_backingList.is_valid(); }); +} + +- (RLMClassInfo *)objectInfo { + return _objectInfo; +} + + +- (bool)isBackedByList:(realm::List const&)list { + return _backingList == list; +} + +- (BOOL)isEqual:(id)object { + return [object respondsToSelector:@selector(isBackedByList:)] && [object isBackedByList:_backingList]; +} + +- (NSUInteger)hash { + return std::hash()(_backingList); +} + +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state + objects:(__unused __unsafe_unretained id [])buffer + count:(NSUInteger)len { + return RLMFastEnumerate(state, len, self); +} + +- (id)objectAtIndex:(NSUInteger)index { + return translateErrors([&] { + RLMAccessorContext context(*_objectInfo); + return _backingList.get(context, index); + }); +} + +static void RLMInsertObject(RLMManagedArray *ar, id object, NSUInteger index) { + RLMArrayValidateMatchingObjectType(ar, object); + if (index == NSUIntegerMax) { + index = translateErrors([&] { return ar->_backingList.size(); }); + } + + changeArray(ar, NSKeyValueChangeInsertion, index, ^{ + RLMAccessorContext context(*ar->_objectInfo); + ar->_backingList.insert(context, index, object); + }); +} + +- (void)addObject:(id)object { + RLMInsertObject(self, object, NSUIntegerMax); +} + +- (void)insertObject:(id)object atIndex:(NSUInteger)index { + RLMInsertObject(self, object, index); +} + +- (void)insertObjects:(id)objects atIndexes:(NSIndexSet *)indexes { + changeArray(self, NSKeyValueChangeInsertion, indexes, ^{ + NSUInteger index = [indexes firstIndex]; + RLMAccessorContext context(*_objectInfo); + for (id obj in objects) { + RLMArrayValidateMatchingObjectType(self, obj); + _backingList.insert(context, index, obj); + index = [indexes indexGreaterThanIndex:index]; + } + }); +} + +- (void)removeObjectAtIndex:(NSUInteger)index { + changeArray(self, NSKeyValueChangeRemoval, index, ^{ + _backingList.remove(index); + }); +} + +- (void)removeObjectsAtIndexes:(NSIndexSet *)indexes { + changeArray(self, NSKeyValueChangeRemoval, indexes, ^{ + [indexes enumerateIndexesWithOptions:NSEnumerationReverse usingBlock:^(NSUInteger idx, BOOL *) { + _backingList.remove(idx); + }]; + }); +} + +- (void)addObjectsFromArray:(NSArray *)array { + changeArray(self, NSKeyValueChangeInsertion, NSMakeRange(self.count, array.count), ^{ + RLMAccessorContext context(*_objectInfo); + for (id obj in array) { + RLMArrayValidateMatchingObjectType(self, obj); + _backingList.add(context, obj); + } + }); +} + +- (void)removeAllObjects { + changeArray(self, NSKeyValueChangeRemoval, NSMakeRange(0, self.count), ^{ + _backingList.remove_all(); + }); +} + +- (void)replaceAllObjectsWithObjects:(NSArray *)objects { + if (auto count = self.count) { + changeArray(self, NSKeyValueChangeRemoval, NSMakeRange(0, count), ^{ + _backingList.remove_all(); + }); + } + if (![objects respondsToSelector:@selector(count)] || !objects.count) { + return; + } + changeArray(self, NSKeyValueChangeInsertion, NSMakeRange(0, objects.count), ^{ + RLMAccessorContext context(*_objectInfo); + _backingList.assign(context, objects); + }); +} + +- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)object { + RLMArrayValidateMatchingObjectType(self, object); + changeArray(self, NSKeyValueChangeReplacement, index, ^{ + RLMAccessorContext context(*_objectInfo); + if (index >= _backingList.size()) { + @throw RLMException(@"Index %llu is out of bounds (must be less than %llu).", + (unsigned long long)index, (unsigned long long)_backingList.size()); + } + _backingList.set(context, index, object); + }); +} + +- (void)moveObjectAtIndex:(NSUInteger)sourceIndex toIndex:(NSUInteger)destinationIndex { + auto start = std::min(sourceIndex, destinationIndex); + auto len = std::max(sourceIndex, destinationIndex) - start + 1; + changeArray(self, NSKeyValueChangeReplacement, {start, len}, ^{ + _backingList.move(sourceIndex, destinationIndex); + }); +} + +- (void)exchangeObjectAtIndex:(NSUInteger)index1 withObjectAtIndex:(NSUInteger)index2 { + changeArray(self, NSKeyValueChangeReplacement, ^{ + _backingList.swap(index1, index2); + }, [=] { + NSMutableIndexSet *set = [[NSMutableIndexSet alloc] initWithIndex:index1]; + [set addIndex:index2]; + return set; + }); +} + +- (NSUInteger)indexOfObject:(id)object { + RLMArrayValidateMatchingObjectType(self, object); + return translateErrors([&] { + RLMAccessorContext context(*_objectInfo); + return RLMConvertNotFound(_backingList.find(context, object)); + }); +} + +- (id)valueForKeyPath:(NSString *)keyPath { + if ([keyPath hasPrefix:@"@"]) { + // Delegate KVC collection operators to RLMResults + return translateErrors([&] { + auto results = [RLMResults resultsWithObjectInfo:*_objectInfo results:_backingList.as_results()]; + return [results valueForKeyPath:keyPath]; + }); + } + return [super valueForKeyPath:keyPath]; +} + +- (id)valueForKey:(NSString *)key { + // Ideally we'd use "@invalidated" for this so that "invalidated" would use + // normal array KVC semantics, but observing @things works very oddly (when + // it's part of a key path, it's triggered automatically when array index + // changes occur, and can't be sent explicitly, but works normally when it's + // the entire key path), and an RLMManagedArray *can't* have objects where + // invalidated is true, so we're not losing much. + return translateErrors([&]() -> id { + if ([key isEqualToString:RLMInvalidatedKey]) { + return @(!_backingList.is_valid()); + } + + _backingList.verify_attached(); + return RLMCollectionValueForKey(_backingList, key, *_objectInfo); + }); +} + +- (void)setValue:(id)value forKey:(NSString *)key { + if ([key isEqualToString:@"self"]) { + RLMArrayValidateMatchingObjectType(self, value); + RLMAccessorContext context(*_objectInfo); + translateErrors([&] { + for (size_t i = 0, count = _backingList.size(); i < count; ++i) { + _backingList.set(context, i, value); + } + }); + return; + } + else if (_type == RLMPropertyTypeObject) { + RLMArrayValidateMatchingObjectType(self, value); + translateErrors([&] { _backingList.verify_in_transaction(); }); + RLMCollectionSetValueForKey(self, key, value); + } + else { + [self setValue:value forUndefinedKey:key]; + } +} + +- (id)minOfProperty:(NSString *)property { + auto column = columnForProperty(property, _backingList, _objectInfo, _type, RLMCollectionTypeArray); + auto value = translateErrors([&] { return _backingList.min(column); }); + return value ? RLMMixedToObjc(*value) : nil; +} + +- (id)maxOfProperty:(NSString *)property { + auto column = columnForProperty(property, _backingList, _objectInfo, _type, RLMCollectionTypeArray); + auto value = translateErrors([&] { return _backingList.max(column); }); + return value ? RLMMixedToObjc(*value) : nil; +} + +- (id)sumOfProperty:(NSString *)property { + auto column = columnForProperty(property, _backingList, _objectInfo, _type, RLMCollectionTypeArray); + return RLMMixedToObjc(translateErrors([&] { return _backingList.sum(column); })); +} + +- (id)averageOfProperty:(NSString *)property { + auto column = columnForProperty(property, _backingList, _objectInfo, _type, RLMCollectionTypeArray); + auto value = translateErrors([&] { return _backingList.average(column); }); + return value ? RLMMixedToObjc(*value) : nil; +} + +- (void)deleteObjectsFromRealm { + if (_type != RLMPropertyTypeObject) { + @throw RLMException(@"Cannot delete objects from RLMArray<%@>: only RLMObjects can be deleted.", RLMTypeToString(_type)); + } + // delete all target rows from the realm + RLMObservationTracker tracker(_realm, true); + translateErrors([&] { _backingList.delete_all(); }); +} + +- (RLMResults *)sortedResultsUsingDescriptors:(NSArray *)properties { + return translateErrors([&] { + return [RLMResults resultsWithObjectInfo:*_objectInfo + results:_backingList.sort(RLMSortDescriptorsToKeypathArray(properties))]; + }); +} + +- (RLMResults *)distinctResultsUsingKeyPaths:(NSArray *)keyPaths { + return translateErrors([&] { + auto results = [RLMResults resultsWithObjectInfo:*_objectInfo results:_backingList.as_results()]; + return [results distinctResultsUsingKeyPaths:keyPaths]; + }); +} + +- (RLMResults *)objectsWithPredicate:(NSPredicate *)predicate { + if (_type != RLMPropertyTypeObject) { + @throw RLMException(@"Querying is currently only implemented for arrays of Realm Objects"); + } + auto query = RLMPredicateToQuery(predicate, _objectInfo->rlmObjectSchema, _realm.schema, _realm.group); + auto results = translateErrors([&] { return _backingList.filter(std::move(query)); }); + return [RLMResults resultsWithObjectInfo:*_objectInfo results:std::move(results)]; +} + +- (NSUInteger)indexOfObjectWithPredicate:(NSPredicate *)predicate { + if (_type != RLMPropertyTypeObject) { + @throw RLMException(@"Querying is currently only implemented for arrays of Realm Objects"); + } + realm::Query query = RLMPredicateToQuery(predicate, _objectInfo->rlmObjectSchema, + _realm.schema, _realm.group); + + return translateErrors([&] { + return RLMConvertNotFound(_backingList.find(std::move(query))); + }); +} + +- (NSArray *)objectsAtIndexes:(NSIndexSet *)indexes { + size_t c = self.count; + NSMutableArray *result = [[NSMutableArray alloc] initWithCapacity:indexes.count]; + NSUInteger i = [indexes firstIndex]; + RLMAccessorContext context(*_objectInfo); + while (i != NSNotFound) { + // Given KVO relies on `objectsAtIndexes` we need to make sure + // that no out of bounds exceptions are generated. This disallows us to mirror + // the exception logic in Foundation, but it is better than nothing. + if (i >= 0 && i < c) { + [result addObject:_backingList.get(context, i)]; + } else { + // silently abort. + return nil; + } + i = [indexes indexGreaterThanIndex:i]; + } + return result; +} + +- (RLMSectionedResults *)sectionedResultsSortedUsingKeyPath:(NSString *)keyPath + ascending:(BOOL)ascending + keyBlock:(RLMSectionedResultsKeyBlock)keyBlock { + return [[RLMSectionedResults alloc] initWithResults:[self sortedResultsUsingKeyPath:keyPath ascending:ascending] + keyBlock:keyBlock]; +} + +- (RLMSectionedResults *)sectionedResultsUsingSortDescriptors:(NSArray *)sortDescriptors + keyBlock:(RLMSectionedResultsKeyBlock)keyBlock { + return [[RLMSectionedResults alloc] initWithResults:[self sortedResultsUsingDescriptors:sortDescriptors] + keyBlock:keyBlock]; +} + +- (void)addObserver:(id)observer + forKeyPath:(NSString *)keyPath + options:(NSKeyValueObservingOptions)options + context:(void *)context { + RLMEnsureArrayObservationInfo(_observationInfo, keyPath, self, self); + [super addObserver:observer forKeyPath:keyPath options:options context:context]; +} + +- (realm::TableView)tableView { + return translateErrors([&] { return _backingList.get_query(); }).find_all(); +} + +- (RLMFastEnumerator *)fastEnumerator { + return translateErrors([&] { + return [[RLMFastEnumerator alloc] initWithBackingCollection:_backingList + collection:self + classInfo:*_objectInfo]; + }); +} + +- (BOOL)isFrozen { + return _realm.isFrozen; +} + +- (instancetype)resolveInRealm:(RLMRealm *)realm { + auto& parentInfo = _ownerInfo->resolve(realm); + return translateErrors([&] { + return [[self.class alloc] initWithBackingCollection:_backingList.freeze(realm->_realm) + parentInfo:&parentInfo + property:parentInfo.rlmObjectSchema[_key]]; + }); +} + +- (instancetype)freeze { + if (self.frozen) { + return self; + } + return [self resolveInRealm:_realm.freeze]; +} + +- (instancetype)thaw { + if (!self.frozen) { + return self; + } + return [self resolveInRealm:_realm.thaw]; +} + +- (realm::NotificationToken)addNotificationCallback:(id)block +keyPaths:(std::optional>>>&&)keyPaths { + return _backingList.add_notification_callback(RLMWrapCollectionChangeCallback(block, self, false), std::move(keyPaths)); +} + +#pragma mark - Thread Confined Protocol Conformance + +- (realm::ThreadSafeReference)makeThreadSafeReference { + return _backingList; +} + +- (RLMManagedArrayHandoverMetadata *)objectiveCMetadata { + RLMManagedArrayHandoverMetadata *metadata = [[RLMManagedArrayHandoverMetadata alloc] init]; + metadata.parentClassName = _ownerInfo->rlmObjectSchema.className; + metadata.key = _key; + return metadata; +} + ++ (instancetype)objectWithThreadSafeReference:(realm::ThreadSafeReference)reference + metadata:(RLMManagedArrayHandoverMetadata *)metadata + realm:(RLMRealm *)realm { + auto list = reference.resolve(realm->_realm); + if (!list.is_valid()) { + return nil; + } + RLMClassInfo *parentInfo = &realm->_info[metadata.parentClassName]; + return [[RLMManagedArray alloc] initWithBackingCollection:std::move(list) + parentInfo:parentInfo + property:parentInfo->rlmObjectSchema[metadata.key]]; +} + +@end diff --git a/Pods/Realm/Realm/RLMManagedDictionary.mm b/Pods/Realm/Realm/RLMManagedDictionary.mm new file mode 100644 index 0000000..fa3c1ec --- /dev/null +++ b/Pods/Realm/Realm/RLMManagedDictionary.mm @@ -0,0 +1,539 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2021 Realm Inc. +// +// 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 "RLMDictionary_Private.hpp" + +#import "RLMAccessor.hpp" +#import "RLMCollection_Private.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObjectStore.h" +#import "RLMObject_Private.hpp" +#import "RLMObservation.hpp" +#import "RLMProperty_Private.h" +#import "RLMQueryUtil.hpp" +#import "RLMRealm_Private.hpp" +#import "RLMRealmConfiguration_Private.hpp" +#import "RLMSchema.h" +#import "RLMThreadSafeReference_Private.hpp" +#import "RLMUtil.hpp" + +#import +#import +#import + +@interface RLMManagedDictionary () { + @public + realm::object_store::Dictionary _backingCollection; +} +@end + +@implementation RLMDictionaryChange { + realm::DictionaryChangeSet _changes; +} + +- (instancetype)initWithChanges:(realm::DictionaryChangeSet const&)changes { + self = [super init]; + if (self) { + _changes = changes; + } + return self; +} + +static NSArray *toArray(std::vector const& v) { + NSMutableArray *ret = [[NSMutableArray alloc] initWithCapacity:v.size()]; + for (auto& mixed : v) { + [ret addObject:RLMMixedToObjc(mixed)]; + } + return ret; +} + +- (NSArray *)insertions { + return toArray(_changes.insertions); +} + +- (NSArray *)deletions { + return toArray(_changes.deletions); +} + +- (NSArray *)modifications { + return toArray(_changes.modifications); +} + +- (NSString *)description { + return [NSString stringWithFormat:@" insertions: %@, deletions: %@, modifications: %@", + (__bridge void *)self, self.insertions, self.deletions, self.modifications]; +} + +@end + +@interface RLMManagedCollectionHandoverMetadata : NSObject +@property (nonatomic) NSString *parentClassName; +@property (nonatomic) NSString *key; +@end + +@implementation RLMManagedCollectionHandoverMetadata +@end + +@implementation RLMManagedDictionary { +@public + RLMRealm *_realm; + RLMClassInfo *_objectInfo; + RLMClassInfo *_ownerInfo; + std::unique_ptr _observationInfo; +} + +- (RLMManagedDictionary *)initWithBackingCollection:(realm::object_store::Dictionary)dictionary + parentInfo:(RLMClassInfo *)parentInfo + property:(__unsafe_unretained RLMProperty *const)property { + if (property.type == RLMPropertyTypeObject) + self = [self initWithObjectClassName:property.objectClassName keyType:property.dictionaryKeyType]; + else + self = [self initWithObjectType:property.type optional:property.optional keyType:property.dictionaryKeyType]; + if (self) { + _realm = parentInfo->realm; + REALM_ASSERT(dictionary.get_realm() == _realm->_realm); + _backingCollection = std::move(dictionary); + _ownerInfo = parentInfo; + if (property.type == RLMPropertyTypeObject) + _objectInfo = &parentInfo->linkTargetType(property.index); + else + _objectInfo = _ownerInfo; + _key = property.name; + } + return self; +} + +- (RLMManagedDictionary *)initWithParent:(__unsafe_unretained RLMObjectBase *const)parentObject + property:(__unsafe_unretained RLMProperty *const)property { + __unsafe_unretained RLMRealm *const realm = parentObject->_realm; + auto col = parentObject->_info->tableColumn(property); + return [self initWithBackingCollection:realm::object_store::Dictionary(realm->_realm, parentObject->_row, col) + parentInfo:parentObject->_info + property:property]; +} + +- (RLMManagedDictionary *)initWithParent:(realm::Obj)parent + property:(__unsafe_unretained RLMProperty *const)property + parentInfo:(RLMClassInfo&)info { + auto col = info.tableColumn(property); + return [self initWithBackingCollection:realm::object_store::Dictionary(info.realm->_realm, parent, col) + parentInfo:&info + property:property]; +} + +void RLMDictionaryValidateObservationKey(__unsafe_unretained NSString *const keyPath, + __unsafe_unretained RLMDictionary *const dictionary) { + if (![keyPath isEqualToString:RLMInvalidatedKey]) { + @throw RLMException(@"[<%@ %p> addObserver:forKeyPath:options:context:] is not supported. Key path: %@", + [dictionary class], dictionary, keyPath); + } +} + +void RLMEnsureDictionaryObservationInfo(std::unique_ptr& info, + __unsafe_unretained NSString *const keyPath, + __unsafe_unretained RLMDictionary *const dictionary, + __unsafe_unretained id const observed) { + RLMDictionaryValidateObservationKey(keyPath, dictionary); + if (!info && dictionary.class == [RLMManagedDictionary class]) { + auto lv = static_cast(dictionary); + info = std::make_unique(*lv->_ownerInfo, + lv->_backingCollection.get_parent_object_key(), + observed); + } +} + +// +// validation helpers +// +template +__attribute__((always_inline)) +static auto translateErrors(Function&& f) { + return translateCollectionError(static_cast(f), @"Dictionary"); +} + +static void changeDictionary(__unsafe_unretained RLMManagedDictionary *const dict, + dispatch_block_t f) { + translateErrors([&] { dict->_backingCollection.verify_in_transaction(); }); + + RLMObservationTracker tracker(dict->_realm); + tracker.trackDeletions(); + auto obsInfo = RLMGetObservationInfo(dict->_observationInfo.get(), + dict->_backingCollection.get_parent_object_key(), + *dict->_ownerInfo); + if (obsInfo) { + tracker.willChange(obsInfo, dict->_key); + } + + translateErrors(f); +} + +// +// public method implementations +// +- (RLMRealm *)realm { + return _realm; +} + +- (NSUInteger)count { + return translateErrors([&] { + return _backingCollection.size(); + }); +} + +static NSMutableArray *resultsToArray(RLMClassInfo& info, realm::Results r) { + RLMAccessorContext c(info); + NSMutableArray *array = [NSMutableArray arrayWithCapacity:r.size()]; + for (size_t i = 0, size = r.size(); i < size; ++i) { + [array addObject:r.get(c, i)]; + } + return array; +} + +- (NSArray *)allKeys { + return translateErrors([&] { + return resultsToArray(*_objectInfo, _backingCollection.get_keys()); + }); +} + +- (NSArray *)allValues { + return translateErrors([&] { + return resultsToArray(*_objectInfo, _backingCollection.get_values()); + }); +} + +- (BOOL)isInvalidated { + return translateErrors([&] { return !_backingCollection.is_valid(); }); +} + +- (RLMClassInfo *)objectInfo { + return _objectInfo; +} + +- (bool)isBackedByDictionary:(realm::object_store::Dictionary const&)dictionary { + return _backingCollection == dictionary; +} + +- (BOOL)isEqual:(id)object { + return [object respondsToSelector:@selector(isBackedByDictionary:)] && + [object isBackedByDictionary:_backingCollection]; +} + +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state + objects:(__unused __unsafe_unretained id [])buffer + count:(NSUInteger)len { + return RLMFastEnumerate(state, len, self); +} + +#pragma mark - Object Retrieval + +- (nullable id)objectForKey:(id)key { + return translateErrors([&]() -> id { + [self.realm verifyThread]; + RLMAccessorContext context(*_objectInfo); + if (auto value = _backingCollection.try_get_any(context.unbox(key))) { + return context.box(*value); + } + return nil; + }); +} + +- (void)setObject:(id)obj forKey:(id)key { + changeDictionary(self, ^{ + RLMAccessorContext c(*_objectInfo); + _backingCollection.insert(c, c.unbox(RLMDictionaryKey(self, key)), + RLMDictionaryValue(self, obj)); + }); +} + +- (void)removeAllObjects { + changeDictionary(self, ^{ + _backingCollection.remove_all(); + }); +} + +- (void)removeObjectsForKeys:(NSArray *)keyArray { + RLMAccessorContext context(*_objectInfo); + changeDictionary(self, [&] { + for (id key in keyArray) { + _backingCollection.try_erase(context.unbox(key)); + } + }); +} + +- (void)removeObjectForKey:(id)key { + changeDictionary(self, ^{ + RLMAccessorContext context(*_objectInfo); + _backingCollection.try_erase(context.unbox(key)); + }); +} + +- (void)enumerateKeysAndObjectsUsingBlock:(void (^)(id key, id obj, BOOL *stop))block { + RLMAccessorContext c(*_objectInfo); + BOOL stop = false; + @autoreleasepool { + for (auto&& [key, value] : _backingCollection) { + block(c.box(key), c.box(value), &stop); + if (stop) { + break; + } + } + } +} + +- (void)mergeDictionary:(id)dictionary clear:(bool)clear { + if (!clear && !dictionary) { + return; + } + if (dictionary && ![dictionary respondsToSelector:@selector(enumerateKeysAndObjectsUsingBlock:)]) { + @throw RLMException(@"Cannot %@ object of class '%@'", + clear ? @"set dictionary to" : @"add entries from", + [dictionary className]); + } + + changeDictionary(self, ^{ + RLMAccessorContext c(*_objectInfo); + if (clear) { + _backingCollection.remove_all(); + } + [dictionary enumerateKeysAndObjectsUsingBlock:[&](id key, id value, BOOL *) { + _backingCollection.insert(c, c.unbox(RLMDictionaryKey(self, key)), + RLMDictionaryValue(self, value)); + }]; + }); +} + +- (void)setDictionary:(id)dictionary { + [self mergeDictionary:RLMCoerceToNil(dictionary) clear:true]; +} + +- (void)addEntriesFromDictionary:(id)otherDictionary { + [self mergeDictionary:otherDictionary clear:false]; +} + +#pragma mark - KVC + +- (id)valueForKeyPath:(NSString *)keyPath { + if ([keyPath hasPrefix:@"@"]) { + // Delegate KVC collection operators to RLMResults + return translateErrors([&] { + auto results = [RLMResults resultsWithObjectInfo:*_objectInfo + results:_backingCollection.as_results()]; + return [results valueForKeyPath:keyPath]; + }); + } + return [super valueForKeyPath:keyPath]; +} + +- (id)valueForKey:(NSString *)key { + if ([key isEqualToString:RLMInvalidatedKey]) { + return @(!_backingCollection.is_valid()); + } + return [self objectForKey:key]; +} + +- (void)setValue:(id)value forKey:(nonnull NSString *)key { + [self setObject:value forKeyedSubscript:key]; +} + +- (id)minOfProperty:(NSString *)property { + auto column = columnForProperty(property, _backingCollection, _objectInfo, _type, RLMCollectionTypeDictionary); + auto value = translateErrors([&] { + return _backingCollection.as_results().min(column); + }); + return value ? RLMMixedToObjc(*value) : nil; +} + +- (id)maxOfProperty:(NSString *)property { + auto column = columnForProperty(property, _backingCollection, _objectInfo, _type, RLMCollectionTypeDictionary); + auto value = translateErrors([&] { + return _backingCollection.as_results().max(column); + }); + return value ? RLMMixedToObjc(*value) : nil; +} + +- (id)sumOfProperty:(NSString *)property { + auto column = columnForProperty(property, _backingCollection, _objectInfo, _type, RLMCollectionTypeDictionary); + auto value = translateErrors([&] { + return _backingCollection.as_results().sum(column); + }); + return value ? RLMMixedToObjc(*value) : @0; +} + +- (id)averageOfProperty:(NSString *)property { + auto column = columnForProperty(property, _backingCollection, _objectInfo, _type, RLMCollectionTypeDictionary); + auto value = translateErrors([&] { + return _backingCollection.as_results().average(column); + }); + return value ? RLMMixedToObjc(*value) : nil; +} + +- (void)deleteObjectsFromRealm { + if (_type != RLMPropertyTypeObject) { + @throw RLMException(@"Cannot delete objects from RLMManagedDictionary: only RLMObjects can be deleted.", RLMTypeToString(_type), _optional? @"?": @""); + } + // delete all target rows from the realm + RLMObservationTracker tracker(_realm, true); + translateErrors([&] { + for (auto&& [key, value] : _backingCollection) { + _realm.group.get_object(value.get_link()).remove(); + } + _backingCollection.remove_all(); + }); +} + +- (RLMResults *)sortedResultsUsingDescriptors:(NSArray *)properties { + return translateErrors([&] { + return [RLMResults resultsWithObjectInfo:*_objectInfo + results:_backingCollection.as_results().sort(RLMSortDescriptorsToKeypathArray(properties))]; + }); +} + +- (RLMResults *)sortedResultsUsingKeyPath:(nonnull NSString *)keyPath ascending:(BOOL)ascending { + return [self sortedResultsUsingDescriptors:@[[RLMSortDescriptor sortDescriptorWithKeyPath:keyPath ascending:ascending]]]; +} + +- (RLMResults *)distinctResultsUsingKeyPaths:(NSArray *)keyPaths { + return translateErrors([&] { + auto results = [RLMResults resultsWithObjectInfo:*_objectInfo results:_backingCollection.as_results()]; + return [results distinctResultsUsingKeyPaths:keyPaths]; + }); +} + +- (RLMResults *)objectsWithPredicate:(NSPredicate *)predicate { + if (_type != RLMPropertyTypeObject) { + @throw RLMException(@"Querying is currently only implemented for dictionaries of Realm Objects"); + } + auto query = RLMPredicateToQuery(predicate, _objectInfo->rlmObjectSchema, _realm.schema, _realm.group); + auto results = translateErrors([&] { + return _backingCollection.as_results().filter(std::move(query)); + }); + return [RLMResults resultsWithObjectInfo:*_objectInfo results:std::move(results)]; +} + +- (void)addObserver:(id)observer + forKeyPath:(NSString *)keyPath + options:(NSKeyValueObservingOptions)options + context:(void *)context { + RLMEnsureDictionaryObservationInfo(_observationInfo, keyPath, self, self); + [super addObserver:observer forKeyPath:keyPath options:options context:context]; +} + +- (realm::TableView)tableView { + return translateErrors([&] { + return _backingCollection.as_results().get_query(); + }).find_all(); +} + +- (RLMFastEnumerator *)fastEnumerator { + return translateErrors([&] { + return [[RLMFastEnumerator alloc] initWithBackingDictionary:_backingCollection + dictionary:self + classInfo:*_objectInfo]; + }); +} + +- (BOOL)isFrozen { + return _realm.isFrozen; +} + +- (instancetype)resolveInRealm:(RLMRealm *)realm { + auto& parentInfo = _ownerInfo->resolve(realm); + return translateErrors([&] { + return [[self.class alloc] initWithBackingCollection:_backingCollection.freeze(realm->_realm) + parentInfo:&parentInfo + property:parentInfo.rlmObjectSchema[_key]]; + }); +} + +- (instancetype)freeze { + if (self.frozen) { + return self; + } + return [self resolveInRealm:_realm.freeze]; +} + +- (instancetype)thaw { + if (!self.frozen) { + return self; + } + return [self resolveInRealm:_realm.thaw]; +} + +namespace { +struct DictionaryCallbackWrapper { + void (^block)(id, RLMDictionaryChange *, NSError *); + RLMManagedDictionary *collection; + realm::TransactionRef previousTransaction; + + DictionaryCallbackWrapper(void (^block)(id, RLMDictionaryChange *, NSError *), RLMManagedDictionary *dictionary) + : block(block) + , collection(dictionary) + , previousTransaction(static_cast(collection.realm.group).duplicate()) + { + } + + void operator()(realm::DictionaryChangeSet const& changes) { + if (changes.deletions.empty() && changes.insertions.empty() && changes.modifications.empty()) { + block(collection, nil, nil); + } + else { + block(collection, [[RLMDictionaryChange alloc] initWithChanges:changes], nil); + } + if (collection.isInvalidated) { + previousTransaction->end_read(); + } + else { + previousTransaction->advance_read(static_cast(collection.realm.group).get_version_of_current_transaction()); + } + } +}; +} // anonymous namespace + +- (realm::NotificationToken)addNotificationCallback:(id)block +keyPaths:(std::optional>>>&&)keyPaths { + return _backingCollection.add_key_based_notification_callback(DictionaryCallbackWrapper{block, self}, + std::move(keyPaths)); +} + +#pragma mark - Thread Confined Protocol Conformance + +- (realm::ThreadSafeReference)makeThreadSafeReference { + return _backingCollection; +} + +- (RLMManagedCollectionHandoverMetadata *)objectiveCMetadata { + RLMManagedCollectionHandoverMetadata *metadata = [[RLMManagedCollectionHandoverMetadata alloc] init]; + metadata.parentClassName = _ownerInfo->rlmObjectSchema.className; + metadata.key = _key; + return metadata; +} + ++ (instancetype)objectWithThreadSafeReference:(realm::ThreadSafeReference)reference + metadata:(RLMManagedCollectionHandoverMetadata *)metadata + realm:(RLMRealm *)realm { + auto dictionary = reference.resolve(realm->_realm); + if (!dictionary.is_valid()) { + return nil; + } + RLMClassInfo *parentInfo = &realm->_info[metadata.parentClassName]; + return [[RLMManagedDictionary alloc] initWithBackingCollection:std::move(dictionary) + parentInfo:parentInfo + property:parentInfo->rlmObjectSchema[metadata.key]]; +} + +@end diff --git a/Pods/Realm/Realm/RLMManagedSet.mm b/Pods/Realm/Realm/RLMManagedSet.mm new file mode 100644 index 0000000..bc03584 --- /dev/null +++ b/Pods/Realm/Realm/RLMManagedSet.mm @@ -0,0 +1,552 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 "RLMSet_Private.hpp" + +#import "RLMAccessor.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObjectStore.h" +#import "RLMObject_Private.hpp" +#import "RLMObservation.hpp" +#import "RLMProperty_Private.h" +#import "RLMQueryUtil.hpp" +#import "RLMRealm_Private.hpp" +#import "RLMSchema.h" +#import "RLMSectionedResults_Private.hpp" +#import "RLMThreadSafeReference_Private.hpp" +#import "RLMUtil.hpp" + +#import +#import +#import + +#import +#import + +@interface RLMManagedSetHandoverMetadata : NSObject +@property (nonatomic) NSString *parentClassName; +@property (nonatomic) NSString *key; +@end + +@implementation RLMManagedSetHandoverMetadata +@end + +@interface RLMManagedSet () +@end + +// +// RLMSet implementation +// +@implementation RLMManagedSet { +@public + realm::object_store::Set _backingSet; + RLMRealm *_realm; + RLMClassInfo *_objectInfo; + RLMClassInfo *_ownerInfo; + std::unique_ptr _observationInfo; +} + +- (RLMManagedSet *)initWithBackingCollection:(realm::object_store::Set)set + parentInfo:(RLMClassInfo *)parentInfo + property:(__unsafe_unretained RLMProperty *const)property { + if (property.type == RLMPropertyTypeObject) + self = [self initWithObjectClassName:property.objectClassName]; + else + self = [self initWithObjectType:property.type + optional:property.optional]; + if (self) { + _realm = parentInfo->realm; + REALM_ASSERT(set.get_realm() == _realm->_realm); + _backingSet = std::move(set); + _ownerInfo = parentInfo; + if (property.type == RLMPropertyTypeObject) + _objectInfo = &parentInfo->linkTargetType(property.index); + else + _objectInfo = _ownerInfo; + _key = property.name; + } + return self; +} + +- (RLMManagedSet *)initWithParent:(__unsafe_unretained RLMObjectBase *const)parentObject + property:(__unsafe_unretained RLMProperty *const)property { + __unsafe_unretained RLMRealm *const realm = parentObject->_realm; + auto col = parentObject->_info->tableColumn(property); + return [self initWithBackingCollection:realm::object_store::Set(realm->_realm, parentObject->_row, col) + parentInfo:parentObject->_info + property:property]; +} + +- (RLMManagedSet *)initWithParent:(realm::Obj)parent + property:(__unsafe_unretained RLMProperty *const)property + parentInfo:(RLMClassInfo&)info { + auto col = info.tableColumn(property); + return [self initWithBackingCollection:realm::object_store::Set(info.realm->_realm, parent, col) + parentInfo:&info + property:property]; +} + +void RLMValidateSetObservationKey(__unsafe_unretained NSString *const keyPath, + __unsafe_unretained RLMSet *const set) { + if (![keyPath isEqualToString:RLMInvalidatedKey]) { + @throw RLMException(@"[<%@ %p> addObserver:forKeyPath:options:context:] is not supported. Key path: %@", + [set class], set, keyPath); + } +} + +void RLMEnsureSetObservationInfo(std::unique_ptr& info, + __unsafe_unretained NSString *const keyPath, + __unsafe_unretained RLMSet *const set, + __unsafe_unretained id const observed) { + RLMValidateSetObservationKey(keyPath, set); + if (!info && set.class == [RLMManagedSet class]) { + auto lv = static_cast(set); + info = std::make_unique(*lv->_ownerInfo, + lv->_backingSet.get_parent_object_key(), + observed); + } +} + +template +__attribute__((always_inline)) +static auto translateErrors(Function&& f) { + return translateCollectionError(static_cast(f), @"Set"); +} + +static void changeSet(__unsafe_unretained RLMManagedSet *const set, + dispatch_block_t f) { + translateErrors([&] { set->_backingSet.verify_in_transaction(); }); + + RLMObservationTracker tracker(set->_realm, false); + tracker.trackDeletions(); + auto obsInfo = RLMGetObservationInfo(set->_observationInfo.get(), + set->_backingSet.get_parent_object_key(), + *set->_ownerInfo); + if (obsInfo) { + tracker.willChange(obsInfo, set->_key); + } + + translateErrors(f); +} + +// +// public method implementations +// +- (RLMRealm *)realm { + return _realm; +} + +- (NSUInteger)count { + return translateErrors([&] { return _backingSet.size(); }); +} + +- (NSArray *)allObjects { + NSMutableArray *arr = [NSMutableArray new]; + for (id prop : self) { + [arr addObject:prop]; + } + return arr; +} + +- (BOOL)isInvalidated { + return translateErrors([&] { return !_backingSet.is_valid(); }); +} + +- (RLMClassInfo *)objectInfo { + return _objectInfo; +} + + +- (bool)isBackedBySet:(realm::object_store::Set const&)set { + return _backingSet == set; +} + +- (BOOL)isEqual:(id)object { + return [object respondsToSelector:@selector(isBackedBySet:)] && [object isBackedBySet:_backingSet]; +} + +- (NSUInteger)hash { + return std::hash()(_backingSet); +} + +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state + objects:(__unused __unsafe_unretained id [])buffer + count:(NSUInteger)len { + return RLMFastEnumerate(state, len, self); +} + +static void RLMInsertObject(RLMManagedSet *set, id object) { + RLMSetValidateMatchingObjectType(set, object); + changeSet(set, ^{ + RLMAccessorContext context(*set->_objectInfo); + set->_backingSet.insert(context, object); + }); +} + +static void RLMRemoveObject(RLMManagedSet *set, id object) { + RLMSetValidateMatchingObjectType(set, object); + changeSet(set, ^{ + RLMAccessorContext context(*set->_objectInfo); + set->_backingSet.remove(context, object); + }); +} + +static void ensureInWriteTransaction(NSString *message, RLMManagedSet *set, RLMManagedSet *otherSet) { + if (!set.realm.inWriteTransaction && !otherSet.realm.inWriteTransaction) { + @throw RLMException(@"Can only perform %@ in a Realm in a write transaction - call beginWriteTransaction on an RLMRealm instance first.", message); + } +} + +- (void)addObject:(id)object { + RLMInsertObject(self, object); +} + +- (void)addObjects:(id)objects { + changeSet(self, ^{ + RLMAccessorContext context(*_objectInfo); + for (id obj in objects) { + RLMSetValidateMatchingObjectType(self, obj); + _backingSet.insert(context, obj); + } + }); +} + +- (void)removeObject:(id)object { + RLMRemoveObject(self, object); +} + +- (void)removeAllObjects { + changeSet(self, ^{ + _backingSet.remove_all(); + }); +} + +- (void)replaceAllObjectsWithObjects:(NSArray *)objects { + changeSet(self, ^{ + RLMAccessorContext context(*_objectInfo); + _backingSet.assign(context, objects); + }); +} + +- (RLMManagedSet *)managedObjectFrom:(RLMSet *)set { + auto managedSet = RLMDynamicCast(set); + if (!managedSet) { + @throw RLMException(@"Right hand side value must be a managed Set."); + } + if (_type != managedSet->_type) { + @throw RLMException(@"Cannot intersect sets of type '%@' and '%@'.", + RLMTypeToString(_type), RLMTypeToString(managedSet->_type)); + } + if (_realm != managedSet->_realm) { + @throw RLMException(@"Cannot insersect sets managed by different Realms."); + } + if (_objectInfo != managedSet->_objectInfo) { + @throw RLMException(@"Cannot intersect sets of type '%@' and '%@'.", + _objectInfo->rlmObjectSchema.className, + managedSet->_objectInfo->rlmObjectSchema.className); + + } + return managedSet; +} + +- (BOOL)isSubsetOfSet:(RLMSet *)set { + RLMManagedSet *rhs = [self managedObjectFrom:set]; + return _backingSet.is_subset_of(rhs->_backingSet); +} + +- (BOOL)intersectsSet:(RLMSet *)set { + RLMManagedSet *rhs = [self managedObjectFrom:set]; + return _backingSet.intersects(rhs->_backingSet); +} + +- (BOOL)containsObject:(id)obj { + RLMSetValidateMatchingObjectType(self, obj); + RLMAccessorContext context(*_objectInfo); + auto r = _backingSet.find(context, obj); + return r != realm::npos; +} + +- (BOOL)isEqualToSet:(RLMSet *)set { + RLMManagedSet *rhs = [self managedObjectFrom:set]; + return [self isEqual:rhs]; +} + +- (void)setSet:(RLMSet *)set { + RLMManagedSet *rhs = [self managedObjectFrom:set]; + ensureInWriteTransaction(@"[RLMSet setSet:]", self, rhs); + changeSet(self, ^{ + RLMAccessorContext context(*_objectInfo); + _backingSet.assign(context, rhs); + }); +} + +- (void)intersectSet:(RLMSet *)set { + RLMManagedSet *rhs = [self managedObjectFrom:set]; + ensureInWriteTransaction(@"[RLMSet intersectSet:]", self, rhs); + changeSet(self, ^{ + _backingSet.assign_intersection(rhs->_backingSet); + }); +} + +- (void)unionSet:(RLMSet *)set { + RLMManagedSet *rhs = [self managedObjectFrom:set]; + ensureInWriteTransaction(@"[RLMSet unionSet:]", self, rhs); + changeSet(self, ^{ + _backingSet.assign_union(rhs->_backingSet); + }); +} + +- (void)minusSet:(RLMSet *)set { + RLMManagedSet *rhs = [self managedObjectFrom:set]; + ensureInWriteTransaction(@"[RLMSet minusSet:]", self, rhs); + changeSet(self, ^{ + _backingSet.assign_difference(rhs->_backingSet); + }); +} + +- (id)objectAtIndex:(NSUInteger)index { + return translateErrors([&] { + RLMAccessorContext context(*_objectInfo); + return _backingSet.get(context, index); + }); +} + +- (NSArray *)objectsAtIndexes:(NSIndexSet *)indexes { + size_t count = self.count; + NSMutableArray *result = [[NSMutableArray alloc] initWithCapacity:indexes.count]; + RLMAccessorContext context(*_objectInfo); + for (NSUInteger i = indexes.firstIndex; i != NSNotFound; i = [indexes indexGreaterThanIndex:i]) { + if (i >= count) { + return nil; + } + [result addObject:_backingSet.get(context, i)]; + } + return result; +} + +- (id)firstObject { + return translateErrors([&] { + RLMAccessorContext context(*_objectInfo); + return _backingSet.size() ? _backingSet.get(context, 0) : nil; + }); +} + +- (id)lastObject { + return translateErrors([&] { + RLMAccessorContext context(*_objectInfo); + size_t size = _backingSet.size(); + return size ? _backingSet.get(context, size - 1) : nil; + }); +} + +- (id)valueForKeyPath:(NSString *)keyPath { + if ([keyPath hasPrefix:@"@"]) { + // Delegate KVC collection operators to RLMResults + return translateErrors([&] { + auto results = [RLMResults resultsWithObjectInfo:*_objectInfo results:_backingSet.as_results()]; + return [results valueForKeyPath:keyPath]; + }); + } + return [super valueForKeyPath:keyPath]; +} + +- (id)valueForKey:(NSString *)key { + // Ideally we'd use "@invalidated" for this so that "invalidated" would use + // normal array KVC semantics, but observing @things works very oddly (when + // it's part of a key path, it's triggered automatically when array index + // changes occur, and can't be sent explicitly, but works normally when it's + // the entire key path), and an RLMManagedSet *can't* have objects where + // invalidated is true, so we're not losing much. + return translateErrors([&]() -> id { + if ([key isEqualToString:RLMInvalidatedKey]) { + return @(!_backingSet.is_valid()); + } + + _backingSet.verify_attached(); + return [NSSet setWithArray:RLMCollectionValueForKey(_backingSet, key, *_objectInfo)]; + }); + return nil; +} + +- (void)setValue:(id)value forKey:(NSString *)key { + if ([key isEqualToString:@"self"]) { + RLMSetValidateMatchingObjectType(self, value); + RLMAccessorContext context(*_objectInfo); + translateErrors([&] { + _backingSet.remove_all(); + _backingSet.insert(context, value); + return; + }); + } else if (_type == RLMPropertyTypeObject) { + RLMSetValidateMatchingObjectType(self, value); + translateErrors([&] { _backingSet.verify_in_transaction(); }); + RLMCollectionSetValueForKey(self, key, value); + } + else { + [self setValue:value forUndefinedKey:key]; + } +} + +- (id)minOfProperty:(NSString *)property { + auto column = columnForProperty(property, _backingSet, _objectInfo, _type, RLMCollectionTypeSet); + auto value = translateErrors([&] { return _backingSet.min(column); }); + return value ? RLMMixedToObjc(*value) : nil; +} + +- (id)maxOfProperty:(NSString *)property { + auto column = columnForProperty(property, _backingSet, _objectInfo, _type, RLMCollectionTypeSet); + auto value = translateErrors([&] { return _backingSet.max(column); }); + return value ? RLMMixedToObjc(*value) : nil; +} + +- (id)sumOfProperty:(NSString *)property { + auto column = columnForProperty(property, _backingSet, _objectInfo, _type, RLMCollectionTypeSet); + return RLMMixedToObjc(translateErrors([&] { return _backingSet.sum(column); })); +} + +- (id)averageOfProperty:(NSString *)property { + auto column = columnForProperty(property, _backingSet, _objectInfo, _type, RLMCollectionTypeSet); + auto value = translateErrors([&] { return _backingSet.average(column); }); + return value ? RLMMixedToObjc(*value) : nil; +} + +- (void)deleteObjectsFromRealm { + if (_type != RLMPropertyTypeObject) { + @throw RLMException(@"Cannot delete objects from RLMSet<%@>: only RLMObjects can be deleted.", RLMTypeToString(_type)); + } + // delete all target rows from the realm + RLMObservationTracker tracker(_realm, true); + translateErrors([&] { _backingSet.delete_all(); }); +} + +- (RLMResults *)sortedResultsUsingDescriptors:(NSArray *)properties { + return translateErrors([&] { + return [RLMResults resultsWithObjectInfo:*_objectInfo + results:_backingSet.sort(RLMSortDescriptorsToKeypathArray(properties))]; + }); +} + +- (RLMResults *)distinctResultsUsingKeyPaths:(NSArray *)keyPaths { + return translateErrors([&] { + auto results = [RLMResults resultsWithObjectInfo:*_objectInfo results:_backingSet.as_results()]; + return [results distinctResultsUsingKeyPaths:keyPaths]; + }); +} + +- (RLMResults *)objectsWithPredicate:(NSPredicate *)predicate { + if (_type != RLMPropertyTypeObject) { + @throw RLMException(@"Querying is currently only implemented for sets of Realm Objects"); + } + auto query = RLMPredicateToQuery(predicate, _objectInfo->rlmObjectSchema, _realm.schema, _realm.group); + auto results = translateErrors([&] { return _backingSet.filter(std::move(query)); }); + return [RLMResults resultsWithObjectInfo:*_objectInfo results:std::move(results)]; +} + +- (RLMSectionedResults *)sectionedResultsSortedUsingKeyPath:(NSString *)keyPath + ascending:(BOOL)ascending + keyBlock:(RLMSectionedResultsKeyBlock)keyBlock { + return [[RLMSectionedResults alloc] initWithResults:[self sortedResultsUsingKeyPath:keyPath ascending:ascending] + keyBlock:keyBlock]; +} + +- (RLMSectionedResults *)sectionedResultsUsingSortDescriptors:(NSArray *)sortDescriptors + keyBlock:(RLMSectionedResultsKeyBlock)keyBlock { + return [[RLMSectionedResults alloc] initWithResults:[self sortedResultsUsingDescriptors:sortDescriptors] + keyBlock:keyBlock]; +} + +- (void)addObserver:(id)observer + forKeyPath:(NSString *)keyPath + options:(NSKeyValueObservingOptions)options + context:(void *)context { + RLMEnsureSetObservationInfo(_observationInfo, keyPath, self, self); + [super addObserver:observer forKeyPath:keyPath options:options context:context]; +} + +- (RLMFastEnumerator *)fastEnumerator { + return translateErrors([&] { + return [[RLMFastEnumerator alloc] initWithBackingCollection:_backingSet + collection:self + classInfo:*_objectInfo]; + }); +} + +- (realm::TableView)tableView { + return translateErrors([&] { return _backingSet.get_query(); }).find_all(); +} + +- (BOOL)isFrozen { + return _realm.isFrozen; +} + +- (instancetype)resolveInRealm:(RLMRealm *)realm { + auto& parentInfo = _ownerInfo->resolve(realm); + return translateErrors([&] { + return [[self.class alloc] initWithBackingCollection:_backingSet.freeze(realm->_realm) + parentInfo:&parentInfo + property:parentInfo.rlmObjectSchema[_key]]; + }); +} + +- (instancetype)freeze { + if (self.frozen) { + return self; + } + return [self resolveInRealm:_realm.freeze]; +} + +- (instancetype)thaw { + if (!self.frozen) { + return self; + } + return [self resolveInRealm:_realm.thaw]; +} + +- (realm::NotificationToken)addNotificationCallback:(id)block +keyPaths:(std::optional>>>&&)keyPaths { + return _backingSet.add_notification_callback(RLMWrapCollectionChangeCallback(block, self, false), std::move(keyPaths)); +} + +#pragma mark - Thread Confined Protocol Conformance + +- (realm::ThreadSafeReference)makeThreadSafeReference { + return _backingSet; +} + +- (RLMManagedSetHandoverMetadata *)objectiveCMetadata { + RLMManagedSetHandoverMetadata *metadata = [[RLMManagedSetHandoverMetadata alloc] init]; + metadata.parentClassName = _ownerInfo->rlmObjectSchema.className; + metadata.key = _key; + return metadata; +} + ++ (instancetype)objectWithThreadSafeReference:(realm::ThreadSafeReference)reference + metadata:(RLMManagedSetHandoverMetadata *)metadata + realm:(RLMRealm *)realm { + auto set = reference.resolve(realm->_realm); + if (!set.is_valid()) { + return nil; + } + RLMClassInfo *parentInfo = &realm->_info[metadata.parentClassName]; + return [[RLMManagedSet alloc] initWithBackingCollection:std::move(set) + parentInfo:parentInfo + property:parentInfo->rlmObjectSchema[metadata.key]]; +} + +@end + diff --git a/Pods/Realm/Realm/RLMMigration.mm b/Pods/Realm/Realm/RLMMigration.mm new file mode 100644 index 0000000..bddf6d8 --- /dev/null +++ b/Pods/Realm/Realm/RLMMigration.mm @@ -0,0 +1,166 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// 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 "RLMMigration_Private.h" + +#import "RLMAccessor.h" +#import "RLMObject_Private.h" +#import "RLMObject_Private.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObjectStore.h" +#import "RLMProperty_Private.h" +#import "RLMRealm_Dynamic.h" +#import "RLMRealm_Private.hpp" +#import "RLMResults_Private.hpp" +#import "RLMSchema_Private.hpp" +#import "RLMUtil.hpp" + +#import +#import +#import +#import + +using namespace realm; + +@implementation RLMMigration { + realm::Schema *_schema; +} + +- (instancetype)initWithRealm:(RLMRealm *)realm oldRealm:(RLMRealm *)oldRealm schema:(realm::Schema &)schema { + self = [super init]; + if (self) { + _realm = realm; + _oldRealm = oldRealm; + _schema = &schema; + } + return self; +} + +- (RLMSchema *)oldSchema { + return self.oldRealm.schema; +} + +- (RLMSchema *)newSchema { + return self.realm.schema; +} + +- (void)enumerateObjects:(NSString *)className block:(__attribute__((noescape)) RLMObjectMigrationBlock)block { + RLMResults *objects = [_realm.schema schemaForClassName:className] ? [_realm allObjects:className] : nil; + RLMResults *oldObjects = [_oldRealm.schema schemaForClassName:className] ? [_oldRealm allObjects:className] : nil; + + // For whatever reason if this is a newly added table we enumerate the + // objects in it, while in all other cases we enumerate only the existing + // objects. It's unclear how this could be useful, but changing it would + // also be a pointless breaking change and it's unlikely to be hurting anyone. + if (objects && !oldObjects) { + for (RLMObject *object in objects) { + @autoreleasepool { + block(nil, object); + } + } + return; + } + + // If a table will be deleted it can still be enumerated during the migration + // so that data can be saved or transfered to other tables if necessary. + if (!objects && oldObjects) { + for (RLMObject *oldObject in oldObjects) { + @autoreleasepool { + block(oldObject, nil); + } + } + return; + } + + if (oldObjects.count == 0 || objects.count == 0) { + return; + } + + auto& info = _realm->_info[className]; + for (RLMObject *oldObject in oldObjects) { + @autoreleasepool { + Obj newObj; + try { + newObj = info.table()->get_object(oldObject->_row.get_key()); + } + catch (KeyNotFound const&) { + continue; + } + block(oldObject, (id)RLMCreateObjectAccessor(info, std::move(newObj))); + } + } +} + +- (void)execute:(RLMMigrationBlock)block objectClass:(Class)dynamicObjectClass { + if (!dynamicObjectClass) { + dynamicObjectClass = RLMDynamicObject.class; + } + @autoreleasepool { + // disable all primary keys for migration and use DynamicObject for all types + for (RLMObjectSchema *objectSchema in _realm.schema.objectSchema) { + objectSchema.accessorClass = dynamicObjectClass; + objectSchema.primaryKeyProperty.isPrimary = NO; + } + for (RLMObjectSchema *objectSchema in _oldRealm.schema.objectSchema) { + objectSchema.accessorClass = dynamicObjectClass; + } + + block(self, _oldRealm->_realm->schema_version()); + + _oldRealm = nil; + _realm = nil; + } +} + +- (RLMObject *)createObject:(NSString *)className withValue:(id)value { + return [_realm createObject:className withValue:value]; +} + +- (RLMObject *)createObject:(NSString *)className withObject:(id)object { + return [self createObject:className withValue:object]; +} + +- (void)deleteObject:(RLMObject *)object { + [_realm deleteObject:object]; +} + +- (BOOL)deleteDataForClassName:(NSString *)name { + if (!name) { + return false; + } + + TableRef table = ObjectStore::table_for_object_type(_realm.group, name.UTF8String); + if (!table) { + return false; + } + if ([_realm.schema schemaForClassName:name]) { + table->clear(); + } + else { + _realm.group.remove_table(table->get_key()); + } + + return true; +} + +- (void)renamePropertyForClass:(NSString *)className oldName:(NSString *)oldName newName:(NSString *)newName { + realm::ObjectStore::rename_property(_realm.group, *_schema, className.UTF8String, + oldName.UTF8String, newName.UTF8String); +} + +@end diff --git a/Pods/Realm/Realm/RLMMongoClient.mm b/Pods/Realm/Realm/RLMMongoClient.mm new file mode 100644 index 0000000..1867a54 --- /dev/null +++ b/Pods/Realm/Realm/RLMMongoClient.mm @@ -0,0 +1,67 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 "RLMMongoClient_Private.hpp" + +#import "RLMMongoDatabase_Private.hpp" +#import "RLMMongoCollection_Private.h" +#import "RLMApp_Private.hpp" + +#import +#import +#import + +@implementation RLMMongoClient + +- (instancetype)initWithUser:(RLMUser *)user serviceName:(NSString *)serviceName { + if (self = [super init]) { + _user = user; + _name = serviceName; + } + return self; +} + +- (RLMMongoDatabase *)databaseWithName:(NSString *)name { + return [[RLMMongoDatabase alloc] initWithUser:self.user + serviceName:self.name + databaseName:name]; +} + +@end + +@implementation RLMMongoDatabase + +- (instancetype)initWithUser:(RLMUser *)user + serviceName:(NSString *)serviceName + databaseName:(NSString *)databaseName { + if (self = [super init]) { + _user = user; + _serviceName = serviceName; + _name = databaseName; + } + return self; +} + +- (RLMMongoCollection *)collectionWithName:(NSString *)name { + return [[RLMMongoCollection alloc] initWithUser:self.user + serviceName:self.serviceName + databaseName:self.name + collectionName:name]; +} + +@end diff --git a/Pods/Realm/Realm/RLMMongoCollection.mm b/Pods/Realm/Realm/RLMMongoCollection.mm new file mode 100644 index 0000000..ee3bfa4 --- /dev/null +++ b/Pods/Realm/Realm/RLMMongoCollection.mm @@ -0,0 +1,440 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 "RLMMongoCollection_Private.h" + +#import "RLMApp_Private.hpp" +#import "RLMBSON_Private.hpp" +#import "RLMError_Private.hpp" +#import "RLMFindOneAndModifyOptions_Private.hpp" +#import "RLMFindOptions_Private.hpp" +#import "RLMNetworkTransport_Private.hpp" +#import "RLMUpdateResult_Private.hpp" +#import "RLMUser_Private.hpp" + +#import +#import +#import + +__attribute__((objc_direct_members)) +@implementation RLMChangeStream { +@public + realm::app::WatchStream _watchStream; + id _subscriber; + __weak NSURLSession *_session; + void (^_schedule)(dispatch_block_t); +} + +- (instancetype)initWithChangeEventSubscriber:(id)subscriber + scheduler:(void (^)(dispatch_block_t))scheduler { + if (self = [super init]) { + _subscriber = subscriber; + _schedule = scheduler; + } + return self; +} + +- (void)didCloseWithError:(NSError *)error { + _schedule(^{ + [_subscriber changeStreamDidCloseWithError:error]; + }); +} + +- (void)didOpen { + _schedule(^{ + [_subscriber changeStreamDidOpen:self]; + }); +} + +- (void)didReceiveError:(nonnull NSError *)error { + _schedule(^{ + [_subscriber changeStreamDidReceiveError:error]; + }); +} + +- (void)didReceiveEvent:(nonnull NSData *)event { + if (_watchStream.state() == realm::app::WatchStream::State::NEED_DATA) { + [event enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *) { + _watchStream.feed_buffer(std::string_view(static_cast(bytes), byteRange.length)); + }]; + } + + while (_watchStream.state() == realm::app::WatchStream::State::HAVE_EVENT) { + id event = RLMConvertBsonToRLMBSON(_watchStream.next_event()); + _schedule(^{ + [_subscriber changeStreamDidReceiveChangeEvent:event]; + }); + } + + if (_watchStream.state() == realm::app::WatchStream::State::HAVE_ERROR) { + [self didReceiveError:makeError(_watchStream.error())]; + } +} + +- (void)attachURLSession:(NSURLSession *)urlSession { + _session = urlSession; +} + +- (void)close { + [_session invalidateAndCancel]; +} +@end + +static realm::bson::BsonDocument toBsonDocument(id bson) { + return realm::bson::BsonDocument(RLMConvertRLMBSONToBson(bson)); +} +static realm::bson::BsonArray toBsonArray(id bson) { + return realm::bson::BsonArray(RLMConvertRLMBSONToBson(bson)); +} + +__attribute__((objc_direct_members)) +@interface RLMMongoCollection () +@property (nonatomic, strong) RLMUser *user; +@property (nonatomic, strong) NSString *serviceName; +@property (nonatomic, strong) NSString *databaseName; +@end + +__attribute__((objc_direct_members)) +@implementation RLMMongoCollection +- (instancetype)initWithUser:(RLMUser *)user + serviceName:(NSString *)serviceName + databaseName:(NSString *)databaseName + collectionName:(NSString *)collectionName { + if (self = [super init]) { + _user = user; + _serviceName = serviceName; + _databaseName = databaseName; + _name = collectionName; + } + return self; +} + +- (realm::app::MongoCollection)collection:(NSString *)name { + return _user._syncUser->mongo_client(self.serviceName.UTF8String) + .db(self.databaseName.UTF8String).collection(name.UTF8String); +} + +- (realm::app::MongoCollection)collection { + return [self collection:self.name]; +} + +- (void)findWhere:(NSDictionary> *)document + options:(RLMFindOptions *)options + completion:(RLMMongoFindBlock)completion { + self.collection.find(toBsonDocument(document), [options _findOptions], + [completion](std::optional documents, + std::optional error) { + if (error) { + return completion(nil, makeError(*error)); + } + completion((NSArray> *> *)RLMConvertBsonToRLMBSON(*documents), nil); + }); +} + +- (void)findWhere:(NSDictionary> *)document + completion:(RLMMongoFindBlock)completion { + [self findWhere:document options:[[RLMFindOptions alloc] init] completion:completion]; +} + +- (void)findOneDocumentWhere:(NSDictionary> *)document + options:(RLMFindOptions *)options + completion:(RLMMongoFindOneBlock)completion { + self.collection.find_one(toBsonDocument(document), [options _findOptions], + [completion](std::optional document, + std::optional error) { + if (error) { + return completion(nil, makeError(*error)); + } + if (document) { + completion((NSDictionary> *)RLMConvertBsonToRLMBSON(*document), nil); + } else { + completion(nil, nil); + } + }); +} + +- (void)findOneDocumentWhere:(NSDictionary> *)document + completion:(RLMMongoFindOneBlock)completion { + [self findOneDocumentWhere:document options:[[RLMFindOptions alloc] init] completion:completion]; +} + +- (void)insertOneDocument:(NSDictionary> *)document + completion:(RLMMongoInsertBlock)completion { + self.collection.insert_one(toBsonDocument(document), + [completion](std::optional objectId, + std::optional error) { + if (error) { + return completion(nil, makeError(*error)); + } + completion(RLMConvertBsonToRLMBSON(*objectId), nil); + }); +} + +- (void)insertManyDocuments:(NSArray> *> *)documents + completion:(RLMMongoInsertManyBlock)completion { + self.collection.insert_many(toBsonArray(documents), + [completion](std::vector insertedIds, + std::optional error) { + if (error) { + return completion(nil, makeError(*error)); + } + NSMutableArray *insertedArr = [[NSMutableArray alloc] initWithCapacity:insertedIds.size()]; + for (auto& objectId : insertedIds) { + [insertedArr addObject:RLMConvertBsonToRLMBSON(objectId)]; + } + completion(insertedArr, nil); + }); +} + +- (void)aggregateWithPipeline:(NSArray> *> *)pipeline + completion:(RLMMongoFindBlock)completion { + self.collection.aggregate(toBsonArray(pipeline), + [completion](std::optional documents, + std::optional error) { + if (error) { + return completion(nil, makeError(*error)); + } + completion((NSArray *)RLMConvertBsonToRLMBSON(*documents), nil); + }); +} + +- (void)countWhere:(NSDictionary> *)document + limit:(NSInteger)limit + completion:(RLMMongoCountBlock)completion { + self.collection.count(toBsonDocument(document), limit, + [completion](uint64_t count, + std::optional error) { + if (error) { + return completion(0, makeError(*error)); + } + completion(static_cast(count), nil); + }); +} + +- (void)countWhere:(NSDictionary> *)document + completion:(RLMMongoCountBlock)completion { + [self countWhere:document limit:0 completion:completion]; +} + +- (void)deleteOneDocumentWhere:(NSDictionary> *)document + completion:(RLMMongoCountBlock)completion { + self.collection.delete_one(toBsonDocument(document), + [completion](uint64_t count, + std::optional error) { + if (error) { + return completion(0, makeError(*error)); + } + completion(static_cast(count), nil); + }); +} + +- (void)deleteManyDocumentsWhere:(NSDictionary> *)document + completion:(RLMMongoCountBlock)completion { + self.collection.delete_many(toBsonDocument(document), + [completion](uint64_t count, + std::optional error) { + if (error) { + return completion(0, makeError(*error)); + } + completion(static_cast(count), nil); + }); +} + +- (void)updateOneDocumentWhere:(NSDictionary> *)filterDocument + updateDocument:(NSDictionary> *)updateDocument + upsert:(BOOL)upsert + completion:(RLMMongoUpdateBlock)completion { + self.collection.update_one(toBsonDocument(filterDocument), toBsonDocument(updateDocument), + upsert, + [completion](realm::app::MongoCollection::UpdateResult result, + std::optional error) { + if (error) { + return completion(nil, makeError(*error)); + } + completion([[RLMUpdateResult alloc] initWithUpdateResult:result], nil); + }); +} + +- (void)updateOneDocumentWhere:(NSDictionary> *)filterDocument + updateDocument:(NSDictionary> *)updateDocument + completion:(RLMMongoUpdateBlock)completion { + [self updateOneDocumentWhere:filterDocument + updateDocument:updateDocument + upsert:NO + completion:completion]; +} + +- (void)updateManyDocumentsWhere:(NSDictionary> *)filterDocument + updateDocument:(NSDictionary> *)updateDocument + upsert:(BOOL)upsert + completion:(RLMMongoUpdateBlock)completion { + self.collection.update_many(toBsonDocument(filterDocument), toBsonDocument(updateDocument), + upsert, + [completion](realm::app::MongoCollection::UpdateResult result, + std::optional error) { + if (error) { + return completion(nil, makeError(*error)); + } + completion([[RLMUpdateResult alloc] initWithUpdateResult:result], nil); + }); +} + +- (void)updateManyDocumentsWhere:(NSDictionary> *)filterDocument + updateDocument:(NSDictionary> *)updateDocument + completion:(RLMMongoUpdateBlock)completion { + [self updateManyDocumentsWhere:filterDocument + updateDocument:updateDocument + upsert:NO + completion:completion]; +} + +- (void)findOneAndUpdateWhere:(NSDictionary> *)filterDocument + updateDocument:(NSDictionary> *)updateDocument + options:(RLMFindOneAndModifyOptions *)options + completion:(RLMMongoFindOneBlock)completion { + self.collection.find_one_and_update(toBsonDocument(filterDocument), toBsonDocument(updateDocument), + [options _findOneAndModifyOptions], + [completion](std::optional document, + std::optional error) { + if (error) { + return completion(nil, makeError(*error)); + } + + return completion((NSDictionary *)RLMConvertBsonDocumentToRLMBSON(document), nil); + }); +} + +- (void)findOneAndUpdateWhere:(NSDictionary> *)filterDocument + updateDocument:(NSDictionary> *)updateDocument + completion:(RLMMongoFindOneBlock)completion { + [self findOneAndUpdateWhere:filterDocument + updateDocument:updateDocument + options:[[RLMFindOneAndModifyOptions alloc] init] + completion:completion]; +} + +- (void)findOneAndReplaceWhere:(NSDictionary> *)filterDocument + replacementDocument:(NSDictionary> *)replacementDocument + options:(RLMFindOneAndModifyOptions *)options + completion:(RLMMongoFindOneBlock)completion { + self.collection.find_one_and_replace(toBsonDocument(filterDocument), toBsonDocument(replacementDocument), + [options _findOneAndModifyOptions], + [completion](std::optional document, + std::optional error) { + if (error) { + return completion(nil, makeError(*error)); + } + + return completion((NSDictionary *)RLMConvertBsonDocumentToRLMBSON(document), nil); + }); +} + +- (void)findOneAndReplaceWhere:(NSDictionary> *)filterDocument + replacementDocument:(NSDictionary> *)replacementDocument + completion:(RLMMongoFindOneBlock)completion { + [self findOneAndReplaceWhere:filterDocument + replacementDocument:replacementDocument + options:[[RLMFindOneAndModifyOptions alloc] init] + completion:completion]; +} + +- (void)findOneAndDeleteWhere:(NSDictionary> *)filterDocument + options:(RLMFindOneAndModifyOptions *)options + completion:(RLMMongoDeleteBlock)completion { + self.collection.find_one_and_delete(toBsonDocument(filterDocument), + [options _findOneAndModifyOptions], + [completion](std::optional document, + std::optional error) { + if (error) { + return completion(nil, makeError(*error)); + } + + return completion((NSDictionary *)RLMConvertBsonDocumentToRLMBSON(document), nil); + }); +} + +- (void)findOneAndDeleteWhere:(NSDictionary> *)filterDocument + completion:(RLMMongoDeleteBlock)completion { + [self findOneAndDeleteWhere:filterDocument + options:[[RLMFindOneAndModifyOptions alloc] init] + completion:completion]; +} + +- (RLMChangeStream *)watchWithDelegate:(id)delegate + delegateQueue:(nullable dispatch_queue_t)delegateQueue { + return [self watchWithMatchFilter:nil + idFilter:nil + delegate:delegate + delegateQueue:delegateQueue]; +} + +- (RLMChangeStream *)watchWithFilterIds:(NSArray *)filterIds + delegate:(id)delegate + delegateQueue:(nullable dispatch_queue_t)delegateQueue { + return [self watchWithMatchFilter:nil + idFilter:filterIds + delegate:delegate + delegateQueue:delegateQueue]; +} + +- (RLMChangeStream *)watchWithMatchFilter:(NSDictionary> *)matchFilter + delegate:(id)delegate + delegateQueue:(nullable dispatch_queue_t)delegateQueue { + return [self watchWithMatchFilter:matchFilter + idFilter:nil + delegate:delegate + delegateQueue:delegateQueue]; +} + +- (RLMChangeStream *)watchWithMatchFilter:(nullable id)matchFilter + idFilter:(nullable id)idFilter + delegate:(id)delegate + delegateQueue:(nullable dispatch_queue_t)queue { + queue = queue ?: dispatch_get_main_queue(); + return [self watchWithMatchFilter:matchFilter + idFilter:idFilter + delegate:delegate + scheduler:^(dispatch_block_t block) { dispatch_async(queue, block); }]; +} + +- (RLMChangeStream *)watchWithMatchFilter:(nullable id)matchFilter + idFilter:(nullable id)idFilter + delegate:(id)delegate + scheduler:(void (^)(dispatch_block_t))scheduler { + realm::bson::BsonDocument baseArgs = { + {"database", self.databaseName.UTF8String}, + {"collection", self.name.UTF8String} + }; + + if (matchFilter) { + baseArgs["filter"] = RLMConvertRLMBSONToBson(matchFilter); + } + if (idFilter) { + baseArgs["ids"] = RLMConvertRLMBSONToBson(idFilter); + } + auto args = realm::bson::BsonArray{baseArgs}; + auto app = self.user.app._realmApp; + auto request = app->make_streaming_request(app->current_user(), "watch", args, + std::optional(self.serviceName.UTF8String)); + auto changeStream = [[RLMChangeStream alloc] initWithChangeEventSubscriber:delegate scheduler:scheduler]; + RLMNetworkTransport *transport = self.user.app.configuration.transport; + RLMRequest *rlmRequest = RLMRequestFromRequest(request); + changeStream->_session = [transport doStreamRequest:rlmRequest eventSubscriber:changeStream]; + return changeStream; +} +@end diff --git a/Pods/Realm/Realm/RLMNetworkTransport.mm b/Pods/Realm/Realm/RLMNetworkTransport.mm new file mode 100644 index 0000000..edd12cf --- /dev/null +++ b/Pods/Realm/Realm/RLMNetworkTransport.mm @@ -0,0 +1,238 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 "RLMNetworkTransport_Private.hpp" + +#import "RLMApp.h" +#import "RLMError.h" +#import "RLMRealmConfiguration.h" +#import "RLMSyncUtil_Private.hpp" +#import "RLMSyncManager_Private.hpp" +#import "RLMUtil.hpp" + +#import +#import + +using namespace realm; + +static_assert((int)RLMHTTPMethodGET == (int)app::HttpMethod::get); +static_assert((int)RLMHTTPMethodPOST == (int)app::HttpMethod::post); +static_assert((int)RLMHTTPMethodPUT == (int)app::HttpMethod::put); +static_assert((int)RLMHTTPMethodPATCH == (int)app::HttpMethod::patch); +static_assert((int)RLMHTTPMethodDELETE == (int)app::HttpMethod::del); + +#pragma mark RLMSessionDelegate + +@interface RLMSessionDelegate : NSObject ++ (instancetype)delegateWithCompletion:(RLMNetworkTransportCompletionBlock)completion; +@end + +NSString * const RLMHTTPMethodToNSString[] = { + [RLMHTTPMethodGET] = @"GET", + [RLMHTTPMethodPOST] = @"POST", + [RLMHTTPMethodPUT] = @"PUT", + [RLMHTTPMethodPATCH] = @"PATCH", + [RLMHTTPMethodDELETE] = @"DELETE" +}; + +@implementation RLMRequest +@end + +@implementation RLMResponse +@end + +@interface RLMEventSessionDelegate : NSObject ++ (instancetype)delegateWithEventSubscriber:(id)subscriber; +@end; + +@implementation RLMNetworkTransport + +- (void)sendRequestToServer:(RLMRequest *)request + completion:(RLMNetworkTransportCompletionBlock)completionBlock { + // Create the request + NSURL *requestURL = [[NSURL alloc] initWithString: request.url]; + NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:requestURL]; + urlRequest.HTTPMethod = RLMHTTPMethodToNSString[request.method]; + if (![urlRequest.HTTPMethod isEqualToString:@"GET"]) { + urlRequest.HTTPBody = [request.body dataUsingEncoding:NSUTF8StringEncoding]; + } + urlRequest.timeoutInterval = request.timeout; + + for (NSString *key in request.headers) { + [urlRequest addValue:request.headers[key] forHTTPHeaderField:key]; + } + id delegate = [RLMSessionDelegate delegateWithCompletion:completionBlock]; + auto session = [NSURLSession sessionWithConfiguration:NSURLSessionConfiguration.defaultSessionConfiguration + delegate:delegate delegateQueue:nil]; + + // Add the request to a task and start it + [[session dataTaskWithRequest:urlRequest] resume]; + // Tell the session to destroy itself once it's done with the request + [session finishTasksAndInvalidate]; +} + +- (NSURLSession *)doStreamRequest:(nonnull RLMRequest *)request + eventSubscriber:(nonnull id)subscriber { + NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration]; + sessionConfig.timeoutIntervalForRequest = 30; + sessionConfig.timeoutIntervalForResource = INT_MAX; + sessionConfig.HTTPAdditionalHeaders = @{ + @"Content-Type": @"text/event-stream", + @"Cache": @"no-cache", + @"Accept": @"text/event-stream" + }; + id delegate = [RLMEventSessionDelegate delegateWithEventSubscriber:subscriber]; + auto session = [NSURLSession sessionWithConfiguration:sessionConfig + delegate:delegate + delegateQueue:nil]; + NSURL *url = [[NSURL alloc] initWithString:request.url]; + [[session dataTaskWithURL:url] resume]; + return session; +} + +RLMRequest *RLMRequestFromRequest(realm::app::Request const& request) { + RLMRequest *rlmRequest = [RLMRequest new]; + NSMutableDictionary *headersDict = [NSMutableDictionary new]; + for (auto &[key, value] : request.headers) { + headersDict[@(key.c_str())] = @(value.c_str()); + } + rlmRequest.headers = headersDict; + rlmRequest.method = static_cast(request.method); + rlmRequest.timeout = request.timeout_ms; + rlmRequest.url = @(request.url.c_str()); + rlmRequest.body = @(request.body.c_str()); + return rlmRequest; +} + +@end + +#pragma mark RLMSessionDelegate + +@implementation RLMSessionDelegate { + NSData *_data; + RLMNetworkTransportCompletionBlock _completionBlock; +} + ++ (instancetype)delegateWithCompletion:(RLMNetworkTransportCompletionBlock)completion { + RLMSessionDelegate *delegate = [RLMSessionDelegate new]; + delegate->_completionBlock = completion; + return delegate; +} + +- (void)URLSession:(__unused NSURLSession *)session + dataTask:(__unused NSURLSessionDataTask *)dataTask + didReceiveData:(NSData *)data { + if (!_data) { + _data = data; + return; + } + if (![_data respondsToSelector:@selector(appendData:)]) { + _data = [_data mutableCopy]; + } + [(id)_data appendData:data]; +} + +- (void)URLSession:(__unused NSURLSession *)session + task:(NSURLSessionTask *)task +didCompleteWithError:(NSError *)error +{ + RLMResponse *response = [RLMResponse new]; + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) task.response; + response.headers = httpResponse.allHeaderFields; + response.httpStatusCode = httpResponse.statusCode; + + if (error) { + response.body = error.localizedDescription; + response.customStatusCode = error.code; + return _completionBlock(response); + } + + response.body = [[NSString alloc] initWithData:_data encoding:NSUTF8StringEncoding]; + + _completionBlock(response); +} + +@end + +@implementation RLMEventSessionDelegate { + id _subscriber; + bool _hasOpened; +} + ++ (instancetype)delegateWithEventSubscriber:(id)subscriber { + RLMEventSessionDelegate *delegate = [RLMEventSessionDelegate new]; + delegate->_subscriber = subscriber; + return delegate; +} + +- (void)URLSession:(__unused NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + didReceiveData:(NSData *)data { + if (!_hasOpened) { + _hasOpened = true; + [_subscriber didOpen]; + } + + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)dataTask.response; + if (httpResponse.statusCode == 200) { + return [_subscriber didReceiveEvent:data]; + } + + NSString *errorStatus = [NSString stringWithFormat:@"URLSession HTTP error code: %ld", + (long)httpResponse.statusCode]; + NSError *error = [NSError errorWithDomain:RLMAppErrorDomain + code:RLMAppErrorHttpRequestFailed + userInfo:@{NSLocalizedDescriptionKey: errorStatus, + RLMHTTPStatusCodeKey: @(httpResponse.statusCode), + NSURLErrorFailingURLErrorKey: dataTask.currentRequest.URL}]; + return [_subscriber didCloseWithError:error]; +} + +- (void)URLSession:(__unused NSURLSession *)session + task:(NSURLSessionTask *)task +didCompleteWithError:(NSError *)error +{ + RLMResponse *response = [RLMResponse new]; + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)task.response; + response.headers = httpResponse.allHeaderFields; + response.httpStatusCode = httpResponse.statusCode; + + // -999 indicates that the session was cancelled. + if (error && (error.code != -999)) { + response.body = [error localizedDescription]; + return [_subscriber didCloseWithError:error]; + } + if (error && (error.code == -999)) { + return [_subscriber didCloseWithError:nil]; + } + if (response.httpStatusCode == 200) { + return; + } + + NSString *errorStatus = [NSString stringWithFormat:@"URLSession HTTP error code: %ld", + (long)httpResponse.statusCode]; + NSError *wrappedError = [NSError errorWithDomain:RLMAppErrorDomain + code:RLMAppErrorHttpRequestFailed + userInfo:@{NSLocalizedDescriptionKey: errorStatus, + RLMHTTPStatusCodeKey: @(httpResponse.statusCode), + NSURLErrorFailingURLErrorKey: task.currentRequest.URL, + NSUnderlyingErrorKey: error}]; + return [_subscriber didCloseWithError:wrappedError]; +} + +@end diff --git a/Pods/Realm/Realm/RLMObject.mm b/Pods/Realm/Realm/RLMObject.mm new file mode 100644 index 0000000..aedbaab --- /dev/null +++ b/Pods/Realm/Realm/RLMObject.mm @@ -0,0 +1,254 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// 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 "RLMObject_Private.hpp" + +#import "RLMAccessor.h" +#import "RLMArray.h" +#import "RLMCollection_Private.hpp" +#import "RLMObjectBase_Private.h" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObjectStore.h" +#import "RLMProperty_Private.h" +#import "RLMQueryUtil.hpp" +#import "RLMRealm_Private.hpp" +#import "RLMSchema_Private.h" + +#import + +// We declare things in RLMObject which are actually implemented in RLMObjectBase +// for documentation's sake, which leads to -Wunimplemented-method warnings. +// Other alternatives to this would be to disable -Wunimplemented-method for this +// file (but then we could miss legitimately missing things), or declaring the +// inherited things in a category (but they currently aren't nicely grouped for +// that). +@implementation RLMObject + +// synthesized in RLMObjectBase +@dynamic invalidated, realm, objectSchema; + +#pragma mark - Designated Initializers + +- (instancetype)init { + return [super init]; +} + +#pragma mark - Convenience Initializers + +- (instancetype)initWithValue:(id)value { + if (!(self = [self init])) { + return nil; + } + RLMInitializeWithValue(self, value, RLMSchema.partialPrivateSharedSchema); + return self; +} + +#pragma mark - Class-based Object Creation + ++ (instancetype)createInDefaultRealmWithValue:(id)value { + return (RLMObject *)RLMCreateObjectInRealmWithValue([RLMRealm defaultRealm], [self className], value, RLMUpdatePolicyError); +} + ++ (instancetype)createInRealm:(RLMRealm *)realm withValue:(id)value { + return (RLMObject *)RLMCreateObjectInRealmWithValue(realm, [self className], value, RLMUpdatePolicyError); +} + ++ (instancetype)createOrUpdateInDefaultRealmWithValue:(id)value { + return [self createOrUpdateInRealm:[RLMRealm defaultRealm] withValue:value]; +} + ++ (instancetype)createOrUpdateModifiedInDefaultRealmWithValue:(id)value { + return [self createOrUpdateModifiedInRealm:[RLMRealm defaultRealm] withValue:value]; +} + ++ (instancetype)createOrUpdateInRealm:(RLMRealm *)realm withValue:(id)value { + RLMVerifyHasPrimaryKey(self); + return (RLMObject *)RLMCreateObjectInRealmWithValue(realm, [self className], value, RLMUpdatePolicyUpdateAll); +} + ++ (instancetype)createOrUpdateModifiedInRealm:(RLMRealm *)realm withValue:(id)value { + RLMVerifyHasPrimaryKey(self); + return (RLMObject *)RLMCreateObjectInRealmWithValue(realm, [self className], value, RLMUpdatePolicyUpdateChanged); +} + +#pragma mark - Subscripting + +- (id)objectForKeyedSubscript:(NSString *)key { + return RLMObjectBaseObjectForKeyedSubscript(self, key); +} + +- (void)setObject:(id)obj forKeyedSubscript:(NSString *)key { + RLMObjectBaseSetObjectForKeyedSubscript(self, key, obj); +} + +#pragma mark - Getting & Querying + ++ (RLMResults *)allObjects { + return RLMGetObjects(RLMRealm.defaultRealm, self.className, nil); +} + ++ (RLMResults *)allObjectsInRealm:(__unsafe_unretained RLMRealm *const)realm { + return RLMGetObjects(realm, self.className, nil); +} + ++ (RLMResults *)objectsWhere:(NSString *)predicateFormat, ... { + va_list args; + va_start(args, predicateFormat); + RLMResults *results = [self objectsWhere:predicateFormat args:args]; + va_end(args); + return results; +} + ++ (RLMResults *)objectsWhere:(NSString *)predicateFormat args:(va_list)args { + return [self objectsWithPredicate:[NSPredicate predicateWithFormat:predicateFormat arguments:args]]; +} + ++ (RLMResults *)objectsInRealm:(RLMRealm *)realm where:(NSString *)predicateFormat, ... { + va_list args; + va_start(args, predicateFormat); + RLMResults *results = [self objectsInRealm:realm where:predicateFormat args:args]; + va_end(args); + return results; +} + ++ (RLMResults *)objectsInRealm:(RLMRealm *)realm where:(NSString *)predicateFormat args:(va_list)args { + return [self objectsInRealm:realm withPredicate:[NSPredicate predicateWithFormat:predicateFormat arguments:args]]; +} + ++ (RLMResults *)objectsWithPredicate:(NSPredicate *)predicate { + return RLMGetObjects(RLMRealm.defaultRealm, self.className, predicate); +} + ++ (RLMResults *)objectsInRealm:(RLMRealm *)realm withPredicate:(NSPredicate *)predicate { + return RLMGetObjects(realm, self.className, predicate); +} + ++ (instancetype)objectForPrimaryKey:(id)primaryKey { + return RLMGetObject(RLMRealm.defaultRealm, self.className, primaryKey); +} + ++ (instancetype)objectInRealm:(RLMRealm *)realm forPrimaryKey:(id)primaryKey { + return RLMGetObject(realm, self.className, primaryKey); +} + +#pragma mark - Other Instance Methods + +- (BOOL)isEqualToObject:(RLMObject *)object { + return [object isKindOfClass:RLMObject.class] && RLMObjectBaseAreEqual(self, object); +} + +- (instancetype)freeze { + return RLMObjectFreeze(self); +} + +- (instancetype)thaw { + return RLMObjectThaw(self); +} + +- (BOOL)isFrozen { + return _realm.isFrozen; +} + +- (RLMNotificationToken *)addNotificationBlock:(RLMObjectChangeBlock)block { + return RLMObjectAddNotificationBlock(self, block, nil, nil); +} + +- (RLMNotificationToken *)addNotificationBlock:(RLMObjectChangeBlock)block + queue:(nonnull dispatch_queue_t)queue { + return RLMObjectAddNotificationBlock(self, block, nil, queue); +} + +- (RLMNotificationToken *)addNotificationBlock:(RLMObjectChangeBlock)block + keyPaths:(NSArray *)keyPaths { + return RLMObjectAddNotificationBlock(self, block, keyPaths, nil); +} + +- (RLMNotificationToken *)addNotificationBlock:(RLMObjectChangeBlock)block + keyPaths:(NSArray *)keyPaths + queue:(dispatch_queue_t)queue { + return RLMObjectAddNotificationBlock(self, block, keyPaths, queue); + +} + ++ (NSString *)className { + return [super className]; +} + +#pragma mark - Default values for schema definition + ++ (NSArray *)indexedProperties { + return @[]; +} + ++ (NSDictionary *)linkingObjectsProperties { + return @{}; +} + ++ (NSDictionary *)defaultPropertyValues { + return nil; +} + ++ (NSString *)primaryKey { + return nil; +} + ++ (NSArray *)ignoredProperties { + return nil; +} + ++ (NSArray *)requiredProperties { + return @[]; +} + ++ (bool)_realmIgnoreClass { + return false; +} + +@end + +@implementation RLMDynamicObject + ++ (bool)_realmIgnoreClass { + return true; +} + ++ (BOOL)shouldIncludeInDefaultSchema { + return NO; +} + +- (id)valueForUndefinedKey:(NSString *)key { + return RLMDynamicGetByName(self, key); +} + +- (void)setValue:(id)value forUndefinedKey:(NSString *)key { + RLMDynamicValidatedSet(self, key, value); +} + ++ (RLMObjectSchema *)sharedSchema { + return nil; +} + +@end + +BOOL RLMIsObjectOrSubclass(Class klass) { + return RLMIsKindOfClass(klass, RLMObjectBase.class); +} + +BOOL RLMIsObjectSubclass(Class klass) { + return RLMIsKindOfClass(class_getSuperclass(class_getSuperclass(klass)), RLMObjectBase.class); +} diff --git a/Pods/Realm/Realm/RLMObjectBase.mm b/Pods/Realm/Realm/RLMObjectBase.mm new file mode 100644 index 0000000..02b2154 --- /dev/null +++ b/Pods/Realm/Realm/RLMObjectBase.mm @@ -0,0 +1,858 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// 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 "RLMObject_Private.hpp" +#import "RLMObjectBase_Private.h" + +#import "RLMAccessor.h" +#import "RLMArray_Private.hpp" +#import "RLMDecimal128.h" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObjectStore.h" +#import "RLMObservation.hpp" +#import "RLMProperty_Private.h" +#import "RLMRealm_Private.hpp" +#import "RLMSchema_Private.h" +#import "RLMSet_Private.hpp" +#import "RLMSwiftCollectionBase.h" +#import "RLMSwiftSupport.h" +#import "RLMThreadSafeReference_Private.hpp" +#import "RLMUtil.hpp" + +#import +#import +#import + +using namespace realm; + +const NSUInteger RLMDescriptionMaxDepth = 5; + + +static bool isManagedAccessorClass(Class cls) { + const char *className = class_getName(cls); + const char accessorClassPrefix[] = "RLM:Managed"; + return strncmp(className, accessorClassPrefix, sizeof(accessorClassPrefix) - 1) == 0; +} + +static void maybeInitObjectSchemaForUnmanaged(RLMObjectBase *obj) { + Class cls = obj.class; + if (isManagedAccessorClass(cls)) { + return; + } + + obj->_objectSchema = [cls sharedSchema]; + if (!obj->_objectSchema) { + return; + } + + // set default values + if (!obj->_objectSchema.isSwiftClass) { + NSDictionary *dict = RLMDefaultValuesForObjectSchema(obj->_objectSchema); + for (NSString *key in dict) { + [obj setValue:dict[key] forKey:key]; + } + } + + // set unmanaged accessor class + object_setClass(obj, obj->_objectSchema.unmanagedClass); +} + +@interface RLMObjectBase () +@end + +@implementation RLMObjectBase + +- (instancetype)init { + if ((self = [super init])) { + maybeInitObjectSchemaForUnmanaged(self); + } + return self; +} + +- (void)dealloc { + // This can't be a unique_ptr because associated objects are removed + // *after* c++ members are destroyed and dealloc is called, and we need it + // to be in a validish state when that happens + delete _observationInfo; + _observationInfo = nullptr; +} + +static id coerceToObjectType(id obj, Class cls, RLMSchema *schema) { + if ([obj isKindOfClass:cls]) { + return obj; + } + obj = RLMBridgeSwiftValue(obj) ?: obj; + id value = [[cls alloc] init]; + RLMInitializeWithValue(value, obj, schema); + return value; +} + +static id validatedObjectForProperty(__unsafe_unretained id const obj, + __unsafe_unretained RLMObjectSchema *const objectSchema, + __unsafe_unretained RLMProperty *const prop, + __unsafe_unretained RLMSchema *const schema) { + RLMValidateValueForProperty(obj, objectSchema, prop); + if (!obj || obj == NSNull.null) { + return nil; + } + if (prop.type == RLMPropertyTypeObject) { + Class objectClass = schema[prop.objectClassName].objectClass; + id enumerable = RLMAsFastEnumeration(obj); + if (prop.dictionary) { + NSMutableDictionary *ret = [[NSMutableDictionary alloc] init]; + for (id key in enumerable) { + id val = RLMCoerceToNil(obj[key]); + if (val) { + val = coerceToObjectType(obj[key], objectClass, schema); + } + [ret setObject:val ?: NSNull.null forKey:key]; + } + return ret; + } + else if (prop.collection) { + NSMutableArray *ret = [[NSMutableArray alloc] init]; + for (id el in enumerable) { + [ret addObject:coerceToObjectType(el, objectClass, schema)]; + } + return ret; + } + return coerceToObjectType(obj, objectClass, schema); + } + else if (prop.type == RLMPropertyTypeDecimal128 && !prop.collection) { + return [[RLMDecimal128 alloc] initWithValue:obj]; + } + return obj; +} + +void RLMInitializeWithValue(RLMObjectBase *self, id value, RLMSchema *schema) { + if (!value || value == NSNull.null) { + @throw RLMException(@"Must provide a non-nil value."); + } + + RLMObjectSchema *objectSchema = self->_objectSchema; + if (!objectSchema) { + // Will be nil if we're called during schema init, when we don't want + // to actually populate the object anyway + return; + } + + NSArray *properties = objectSchema.properties; + if (NSArray *array = RLMDynamicCast(value)) { + if (array.count > properties.count) { + @throw RLMException(@"Invalid array input: more values (%llu) than properties (%llu).", + (unsigned long long)array.count, (unsigned long long)properties.count); + } + NSUInteger i = 0; + for (id val in array) { + RLMProperty *prop = properties[i++]; + [self setValue:validatedObjectForProperty(RLMCoerceToNil(val), objectSchema, prop, schema) + forKey:prop.name]; + } + } + else { + // assume our object is an NSDictionary or an object with kvc properties + for (RLMProperty *prop in properties) { + id obj = RLMValidatedValueForProperty(value, prop.name, objectSchema.className); + + // don't set unspecified properties + if (!obj) { + continue; + } + + [self setValue:validatedObjectForProperty(RLMCoerceToNil(obj), objectSchema, prop, schema) + forKey:prop.name]; + } + } +} + +id RLMCreateManagedAccessor(Class cls, RLMClassInfo *info) { + RLMObjectBase *obj = [[cls alloc] init]; + obj->_info = info; + obj->_realm = info->realm; + obj->_objectSchema = info->rlmObjectSchema; + return obj; +} + +- (id)valueForKey:(NSString *)key { + if (_observationInfo) { + return _observationInfo->valueForKey(key); + } + return [super valueForKey:key]; +} + +// Generic Swift properties can't be dynamic, so KVO doesn't work for them by default +- (id)valueForUndefinedKey:(NSString *)key { + RLMProperty *prop = _objectSchema[key]; + if (Class swiftAccessor = prop.swiftAccessor) { + return RLMCoerceToNil([swiftAccessor get:prop on:self]); + } + return [super valueForUndefinedKey:key]; +} + +- (void)setValue:(id)value forUndefinedKey:(NSString *)key { + value = RLMCoerceToNil(value); + RLMProperty *property = _objectSchema[key]; + if (property.collection) { + if (id enumerable = RLMAsFastEnumeration(value)) { + value = validatedObjectForProperty(value, _objectSchema, property, + RLMSchema.partialPrivateSharedSchema); + } + } + if (auto swiftAccessor = property.swiftAccessor) { + [swiftAccessor set:property on:self to:value]; + } + else { + [super setValue:value forUndefinedKey:key]; + } +} + +// overridden at runtime per-class for performance ++ (NSString *)className { + NSString *className = NSStringFromClass(self); + if ([RLMSwiftSupport isSwiftClassName:className]) { + className = [RLMSwiftSupport demangleClassName:className]; + } + return className; +} + +// overridden at runtime per-class for performance ++ (RLMObjectSchema *)sharedSchema { + return [RLMSchema sharedSchemaForClass:self.class]; +} + ++ (void)initializeLinkedObjectSchemas { + for (RLMProperty *prop in self.sharedSchema.properties) { + if (prop.type == RLMPropertyTypeObject && !RLMSchema.partialPrivateSharedSchema[prop.objectClassName]) { + [[RLMSchema classForString:prop.objectClassName] initializeLinkedObjectSchemas]; + } + } +} + ++ (nullable NSArray *)_getProperties { + return nil; +} + +- (NSString *)description { + if (self.isInvalidated) { + return @"[invalid object]"; + } + + return [self descriptionWithMaxDepth:RLMDescriptionMaxDepth]; +} + +- (NSString *)descriptionWithMaxDepth:(NSUInteger)depth { + if (depth == 0) { + return @""; + } + + NSString *baseClassName = _objectSchema.className; + NSMutableString *mString = [NSMutableString stringWithFormat:@"%@ {\n", baseClassName]; + + for (RLMProperty *property in _objectSchema.properties) { + id object = [(id)self objectForKeyedSubscript:property.name]; + NSString *sub; + if ([object respondsToSelector:@selector(descriptionWithMaxDepth:)]) { + sub = [object descriptionWithMaxDepth:depth - 1]; + } + else if (property.type == RLMPropertyTypeData) { + static NSUInteger maxPrintedDataLength = 24; + NSData *data = object; + NSUInteger length = data.length; + if (length > maxPrintedDataLength) { + data = [NSData dataWithBytes:data.bytes length:maxPrintedDataLength]; + } + NSString *dataDescription = [data description]; + sub = [NSString stringWithFormat:@"<%@ — %lu total bytes>", [dataDescription substringWithRange:NSMakeRange(1, dataDescription.length - 2)], (unsigned long)length]; + } + else { + sub = [object description]; + } + [mString appendFormat:@"\t%@ = %@;\n", property.name, [sub stringByReplacingOccurrencesOfString:@"\n" withString:@"\n\t"]]; + } + [mString appendString:@"}"]; + + return [NSString stringWithString:mString]; +} + +- (RLMRealm *)realm { + return _realm; +} + +- (RLMObjectSchema *)objectSchema { + return _objectSchema; +} + +- (BOOL)isInvalidated { + // if not unmanaged and our accessor has been detached, we have been deleted + return _info && !_row.is_valid(); +} + +- (BOOL)isEqual:(id)object { + if (RLMObjectBase *other = RLMDynamicCast(object)) { + if (_objectSchema.primaryKeyProperty || _realm.isFrozen) { + return RLMObjectBaseAreEqual(self, other); + } + } + return [super isEqual:object]; +} + +- (NSUInteger)hash { + if (_objectSchema.primaryKeyProperty) { + // If we have a primary key property, that's an immutable value which we + // can use as the identity of the object. + id primaryProperty = [self valueForKey:_objectSchema.primaryKeyProperty.name]; + + // modify the hash of our primary key value to avoid potential (although unlikely) collisions + return [primaryProperty hash] ^ 1; + } + else if (_realm.isFrozen) { + // The object key can never change for frozen objects, so that's usable + // for objects without primary keys + return static_cast(_row.get_key().value); + } + else { + // Non-frozen objects without primary keys don't have any immutable + // concept of identity that we can hash so we have to fall back to + // pointer equality + return [super hash]; + } +} + ++ (BOOL)shouldIncludeInDefaultSchema { + return RLMIsObjectSubclass(self); +} + ++ (NSString *)primaryKey { + return nil; +} + ++ (NSString *)_realmObjectName { + return nil; +} + ++ (NSDictionary *)_realmColumnNames { + return nil; +} + ++ (bool)_realmIgnoreClass { + return false; +} + ++ (bool)isEmbedded { + return false; +} + ++ (bool)isAsymmetric { + return false; +} + +// This enables to override the propertiesMapping in Swift, it is not to be used in Objective-C API. ++ (NSDictionary *)propertiesMapping { + return @{}; +} + +- (id)mutableArrayValueForKey:(NSString *)key { + id obj = [self valueForKey:key]; + if ([obj isKindOfClass:[RLMArray class]]) { + return obj; + } + return [super mutableArrayValueForKey:key]; +} + +- (id)mutableSetValueForKey:(NSString *)key { + id obj = [self valueForKey:key]; + if ([obj isKindOfClass:[RLMSet class]]) { + return obj; + } + return [super mutableSetValueForKey:key]; +} + +- (void)addObserver:(id)observer + forKeyPath:(NSString *)keyPath + options:(NSKeyValueObservingOptions)options + context:(void *)context { + if (!_observationInfo) { + _observationInfo = new RLMObservationInfo(self); + } + _observationInfo->recordObserver(_row, _info, _objectSchema, keyPath); + + [super addObserver:observer forKeyPath:keyPath options:options context:context]; +} + +- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath { + [super removeObserver:observer forKeyPath:keyPath]; + if (_observationInfo) + _observationInfo->removeObserver(); +} + ++ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key { + RLMProperty *prop = [self.class sharedSchema][key]; + if (isManagedAccessorClass(self)) { + // Managed accessors explicitly call willChange/didChange for managed + // properties, so we don't want KVO to override the setters to do that + return !prop; + } + if (prop.swiftAccessor) { + // Properties with swift accessors don't have obj-c getters/setters and + // will explode if KVO tries to override them + return NO; + } + + return [super automaticallyNotifiesObserversForKey:key]; +} + ++ (void)observe:(RLMObjectBase *)object + keyPaths:(nullable NSArray *)keyPaths + block:(RLMObjectNotificationCallback)block + completion:(void (^)(RLMNotificationToken *))completion { +} + +#pragma mark - Thread Confined Protocol Conformance + +- (realm::ThreadSafeReference)makeThreadSafeReference { + return Object(_realm->_realm, *_info->objectSchema, _row); +} + +- (id)objectiveCMetadata { + return nil; +} + ++ (instancetype)objectWithThreadSafeReference:(realm::ThreadSafeReference)reference + metadata:(__unused id)metadata + realm:(RLMRealm *)realm { + Object object = reference.resolve(realm->_realm); + if (!object.is_valid()) { + return nil; + } + NSString *objectClassName = @(object.get_object_schema().name.c_str()); + return RLMCreateObjectAccessor(realm->_info[objectClassName], object.obj()); +} + +@end + +RLMRealm *RLMObjectBaseRealm(__unsafe_unretained RLMObjectBase *object) { + return object ? object->_realm : nil; +} + +RLMObjectSchema *RLMObjectBaseObjectSchema(__unsafe_unretained RLMObjectBase *object) { + return object ? object->_objectSchema : nil; +} + +id RLMObjectBaseObjectForKeyedSubscript(RLMObjectBase *object, NSString *key) { + if (!object) { + return nil; + } + + if (object->_realm) { + return RLMDynamicGetByName(object, key); + } + else { + return [object valueForKey:key]; + } +} + +void RLMObjectBaseSetObjectForKeyedSubscript(RLMObjectBase *object, NSString *key, id obj) { + if (!object) { + return; + } + + if (object->_realm || object.class == object->_objectSchema.accessorClass) { + RLMDynamicValidatedSet(object, key, obj); + } + else { + [object setValue:obj forKey:key]; + } +} + + +BOOL RLMObjectBaseAreEqual(RLMObjectBase *o1, RLMObjectBase *o2) { + // if not the correct types throw + if ((o1 && ![o1 isKindOfClass:RLMObjectBase.class]) || (o2 && ![o2 isKindOfClass:RLMObjectBase.class])) { + @throw RLMException(@"Can only compare objects of class RLMObjectBase"); + } + // if identical object (or both are nil) + if (o1 == o2) { + return YES; + } + // if one is nil + if (o1 == nil || o2 == nil) { + return NO; + } + // if not in realm or differing realms + if (o1->_realm == nil || o1->_realm != o2->_realm) { + return NO; + } + // if either are detached + if (!o1->_row.is_valid() || !o2->_row.is_valid()) { + return NO; + } + // if table and index are the same + return o1->_row.get_table() == o2->_row.get_table() + && o1->_row.get_key() == o2->_row.get_key(); +} + +static id resolveObject(RLMObjectBase *obj, RLMRealm *realm) { + RLMObjectBase *resolved = RLMCreateManagedAccessor(obj.class, &realm->_info[obj->_info->rlmObjectSchema.className]); + resolved->_row = realm->_realm->import_copy_of(obj->_row); + if (!resolved->_row.is_valid()) { + return nil; + } + RLMInitializeSwiftAccessor(resolved, false); + return resolved; +} + +id RLMObjectFreeze(RLMObjectBase *obj) { + if (!obj->_realm && !obj.isInvalidated) { + @throw RLMException(@"Unmanaged objects cannot be frozen."); + } + RLMVerifyAttached(obj); + if (obj->_realm.frozen) { + return obj; + } + obj = resolveObject(obj, obj->_realm.freeze); + if (!obj) { + @throw RLMException(@"Cannot freeze an object in the same write transaction as it was created in."); + } + return obj; +} + +id RLMObjectThaw(RLMObjectBase *obj) { + if (!obj->_realm && !obj.isInvalidated) { + @throw RLMException(@"Unmanaged objects cannot be frozen."); + } + RLMVerifyAttached(obj); + if (!obj->_realm.frozen) { + return obj; + } + return resolveObject(obj, obj->_realm.thaw); +} + +id RLMValidatedValueForProperty(id object, NSString *key, NSString *className) { + @try { + return [object valueForKey:key]; + } + @catch (NSException *e) { + if ([e.name isEqualToString:NSUndefinedKeyException]) { + @throw RLMException(@"Invalid value '%@' to initialize object of type '%@': missing key '%@'", + object, className, key); + } + @throw; + } +} + +#pragma mark - Notifications + +namespace { +struct ObjectChangeCallbackWrapper { + RLMObjectNotificationCallback block; + RLMObjectBase *object; + void (^registrationCompletion)(); + + NSArray *propertyNames = nil; + NSArray *oldValues = nil; + bool deleted = false; + + void populateProperties(realm::CollectionChangeSet const& c) { + if (propertyNames) { + return; + } + if (!c.deletions.empty()) { + deleted = true; + return; + } + if (c.columns.empty()) { + return; + } + + // FIXME: It's possible for the column key of a persisted property + // to equal the column key of a computed property. + auto properties = [NSMutableArray new]; + for (RLMProperty *property in object->_info->rlmObjectSchema.properties) { + auto columnKey = object->_info->tableColumn(property).value; + if (c.columns.count(columnKey)) { + [properties addObject:property.name]; + } + } + for (RLMProperty *property in object->_info->rlmObjectSchema.computedProperties) { + auto columnKey = object->_info->computedTableColumn(property).value; + if (c.columns.count(columnKey)) { + [properties addObject:property.name]; + } + } + if (properties.count) { + propertyNames = properties; + } + } + + NSArray *readValues(realm::CollectionChangeSet const& c) { + if (c.empty()) { + return nil; + } + populateProperties(c); + if (!propertyNames) { + return nil; + } + + auto values = [NSMutableArray arrayWithCapacity:propertyNames.count]; + for (NSString *name in propertyNames) { + id value = [object valueForKey:name]; + if (!value || [value isKindOfClass:[RLMArray class]]) { + [values addObject:NSNull.null]; + } + else { + [values addObject:value]; + } + } + return values; + } + + void before(realm::CollectionChangeSet const& c) { + @autoreleasepool { + oldValues = readValues(c); + } + } + + void after(realm::CollectionChangeSet const& c) { + @autoreleasepool { + if (registrationCompletion) { + registrationCompletion(); + registrationCompletion = nil; + } + auto newValues = readValues(c); + if (deleted) { + block(nil, nil, nil, nil, nil); + } + else if (newValues) { + block(object, propertyNames, oldValues, newValues, nil); + } + propertyNames = nil; + oldValues = nil; + } + } +}; +} // anonymous namespace + +@interface RLMPropertyChange () +@property (nonatomic, readwrite, strong) NSString *name; +@property (nonatomic, readwrite, strong, nullable) id previousValue; +@property (nonatomic, readwrite, strong, nullable) id value; +@end + +@implementation RLMPropertyChange +- (NSString *)description { + return [NSString stringWithFormat:@" %@ %@ -> %@", + (__bridge void *)self, _name, _previousValue, _value]; +} +@end + +enum class TokenState { + Initializing, + Cancelled, + Ready +}; + +RLM_DIRECT_MEMBERS +@implementation RLMObjectNotificationToken { + RLMUnfairMutex _mutex; + __unsafe_unretained RLMRealm *_realm; + realm::Object _object; + realm::NotificationToken _token; + void (^_completion)(void); + TokenState _state; +} + +- (RLMRealm *)realm { + std::lock_guard lock(_mutex); + return _realm; +} + +- (void)suppressNextNotification { + std::lock_guard lock(_mutex); + if (_object.is_valid()) { + _token.suppress_next(); + } +} + +- (bool)invalidate { + dispatch_block_t completion; + { + std::lock_guard lock(_mutex); + if (_state == TokenState::Cancelled) { + REALM_ASSERT(!_completion); + return false; + } + _realm = nil; + _token = {}; + _object = {}; + _state = TokenState::Cancelled; + std::swap(completion, _completion); + } + if (completion) { + completion(); + } + return true; +} + +- (void)addNotificationBlock:(RLMObjectNotificationCallback)block + threadSafeReference:(RLMThreadSafeReference *)tsr + config:(RLMRealmConfiguration *)config + keyPaths:(NSArray *)keyPaths + queue:(dispatch_queue_t)queue { + std::lock_guard lock(_mutex); + if (_state != TokenState::Initializing) { + // Token was invalidated before we got this far + return; + } + + NSError *error; + _realm = [RLMRealm realmWithConfiguration:config queue:queue error:&error]; + if (!_realm) { + block(nil, nil, nil, nil, error); + return; + } + RLMObjectBase *obj = [_realm resolveThreadSafeReference:tsr]; + + _object = realm::Object(_realm->_realm, *obj->_info->objectSchema, obj->_row); + _token = _object.add_notification_callback(ObjectChangeCallbackWrapper{block, obj}, + obj->_info->keyPathArrayFromStringArray(keyPaths)); +} + +- (void)observe:(RLMObjectBase *)obj + keyPaths:(NSArray *)keyPaths + block:(RLMObjectNotificationCallback)block { + std::lock_guard lock(_mutex); + if (_state != TokenState::Initializing) { + return; + } + _object = realm::Object(obj->_realm->_realm, *obj->_info->objectSchema, obj->_row); + _realm = obj->_realm; + + auto completion = [self] { + dispatch_block_t completion; + { + std::lock_guard lock(_mutex); + if (_state == TokenState::Initializing) { + _state = TokenState::Ready; + } + std::swap(completion, _completion); + } + if (completion) { + completion(); + } + }; + _token = _object.add_notification_callback(ObjectChangeCallbackWrapper{block, obj, completion}, + obj->_info->keyPathArrayFromStringArray(keyPaths)); +} + +- (void)registrationComplete:(void (^)())completion { + { + std::lock_guard lock(_mutex); + if (_state == TokenState::Initializing) { + _completion = completion; + return; + } + } + completion(); +} + +RLMNotificationToken *RLMObjectBaseAddNotificationBlock(RLMObjectBase *obj, + NSArray *keyPaths, + dispatch_queue_t queue, + RLMObjectNotificationCallback block) { + if (!obj->_realm) { + @throw RLMException(@"Only objects which are managed by a Realm support change notifications"); + } + + if (!queue) { + [obj->_realm verifyNotificationsAreSupported:true]; + auto token = [[RLMObjectNotificationToken alloc] init]; + [token observe:obj keyPaths:keyPaths block:block]; + return token; + } + + RLMThreadSafeReference *tsr = [RLMThreadSafeReference referenceWithThreadConfined:(id)obj]; + auto token = [[RLMObjectNotificationToken alloc] init]; + token->_realm = obj->_realm; + RLMRealmConfiguration *config = obj->_realm.configuration; + dispatch_async(queue, ^{ + @autoreleasepool { + [token addNotificationBlock:block threadSafeReference:tsr config:config keyPaths:keyPaths queue:queue]; + } + }); + return token; +} +@end + +RLMNotificationToken *RLMObjectAddNotificationBlock(RLMObjectBase *obj, RLMObjectChangeBlock block, NSArray *keyPaths, dispatch_queue_t queue) { + return RLMObjectBaseAddNotificationBlock(obj, keyPaths, queue, ^(RLMObjectBase *, NSArray *propertyNames, + NSArray *oldValues, NSArray *newValues, NSError *error) { + if (error) { + block(false, nil, error); + } + else if (!propertyNames) { + block(true, nil, nil); + } + else { + auto properties = [NSMutableArray arrayWithCapacity:propertyNames.count]; + for (NSUInteger i = 0, count = propertyNames.count; i < count; ++i) { + auto prop = [RLMPropertyChange new]; + prop.name = propertyNames[i]; + prop.previousValue = RLMCoerceToNil(oldValues[i]); + prop.value = RLMCoerceToNil(newValues[i]); + [properties addObject:prop]; + } + block(false, properties, nil); + } + }); +} + +uint64_t RLMObjectBaseGetCombineId(__unsafe_unretained RLMObjectBase *const obj) { + if (obj.invalidated) { + RLMVerifyAttached(obj); + } + if (obj->_realm) { + return obj->_row.get_key().value; + } + return reinterpret_cast((__bridge void *)obj); +} + +@implementation RealmSwiftObject ++ (BOOL)accessInstanceVariablesDirectly { + // By default KVO will try to directly read ivars if a thing with a matching + // name is observed and there's no objc property with that name. This + // crashes when it tries to read a property wrapper ivar, and is never + // useful for Swift classes. + return NO; +} +@end + +@implementation RealmSwiftEmbeddedObject ++ (BOOL)accessInstanceVariablesDirectly { + return NO; +} +@end + +@implementation RealmSwiftAsymmetricObject ++ (BOOL)accessInstanceVariablesDirectly { + return NO; +} + ++ (bool)isAsymmetric { + return YES; +} +@end diff --git a/Pods/Realm/Realm/RLMObjectId.mm b/Pods/Realm/Realm/RLMObjectId.mm new file mode 100644 index 0000000..f156b3a --- /dev/null +++ b/Pods/Realm/Realm/RLMObjectId.mm @@ -0,0 +1,134 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 "RLMObjectId_Private.hpp" + +#import "RLMError_Private.hpp" +#import "RLMUtil.hpp" + +#import + +// Swift's obj-c bridging does not support making an obj-c defined class conform +// to Decodable, so we need a Swift-defined subclass for that. This means that +// when Realm Swift is being used, we need to produce objects of that type rather +// than our obj-c defined type. objc_runtime_visible marks the type as being +// visbile only to the obj-c runtime and not the linker, which means that it'll +// be `nil` at runtime rather than being a linker error if it's not defined, and +// valid if it happens to be defined by some other library (i.e. Realm Swift). +// +// At the point where the objects are being allocated we generally don't have +// any good way of knowing whether or not it's going to end up being used by +// Swift, so we just switch to the subclass unconditionally if the subclass +// exists. This shouldn't have any impact on obj-c code other than a small +// performance hit. +[[clang::objc_runtime_visible]] +@interface RealmSwiftObjectId : RLMObjectId +@end + +@implementation RLMObjectId +- (instancetype)init { + if ((self = [super init])) { + if (auto cls = [RealmSwiftObjectId class]; cls && cls != self.class) { + object_setClass(self, cls); + } + } + return self; +} + +- (instancetype)initWithString:(NSString *)string error:(NSError **)error { + if ((self = [self init])) { + const char *str = string.UTF8String; + if (!realm::ObjectId::is_valid_str(str)) { + if (error) { + NSString *msg = [NSString stringWithFormat:@"Invalid Object ID string '%@': must be 24 hex digits", string]; + *error = [NSError errorWithDomain:RLMErrorDomain + code:RLMErrorInvalidInput + userInfo:@{NSLocalizedDescriptionKey: msg}]; + } + return nil; + } + _value = realm::ObjectId(str); + } + return self; +} + +- (instancetype)initWithTimestamp:(NSDate *)timestamp + machineIdentifier:(int)machineIdentifier + processIdentifier:(int)processIdentifier { + if ((self = [self init])) { + _value = realm::ObjectId(RLMTimestampForNSDate(timestamp), machineIdentifier, processIdentifier); + } + return self; +} + +- (instancetype)initWithValue:(realm::ObjectId)value { + if ((self = [self init])) { + _value = value; + } + return self; +} + +- (id)copyWithZone:(NSZone *)zone { + // RLMObjectID is immutable so we don't have to actually copy + return self; +} + ++ (instancetype)objectId { + return [[RLMObjectId alloc] initWithValue:realm::ObjectId::gen()]; +} + +- (BOOL)isEqual:(id)object { + if (RLMObjectId *objectId = RLMDynamicCast(object)) { + return objectId->_value == _value; + } + return NO; +} + +- (BOOL)isGreaterThan:(nullable RLMObjectId *)objectId { + return _value > objectId.value; +} + +- (BOOL)isGreaterThanOrEqualTo:(nullable RLMObjectId *)objectId { + return _value >= objectId.value; +} + +- (BOOL)isLessThan:(nullable RLMObjectId *)objectId { + return _value < objectId.value; +} + +- (BOOL)isLessThanOrEqualTo:(nullable RLMObjectId *)objectId { + return _value <= objectId.value; +} + +- (NSUInteger)hash { + return _value.hash(); +} + +- (NSString *)description { + return self.stringValue; +} + +- (NSString *)stringValue { + return @(_value.to_string().c_str()); +} + +- (NSDate *)timestamp { + return RLMTimestampToNSDate(_value.get_timestamp()); +} + +@end diff --git a/Pods/Realm/Realm/RLMObjectSchema.mm b/Pods/Realm/Realm/RLMObjectSchema.mm new file mode 100644 index 0000000..774d9c2 --- /dev/null +++ b/Pods/Realm/Realm/RLMObjectSchema.mm @@ -0,0 +1,398 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// 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 "RLMObjectSchema_Private.hpp" + +#import "RLMEmbeddedObject.h" +#import "RLMObject_Private.h" +#import "RLMProperty_Private.hpp" +#import "RLMRealm_Dynamic.h" +#import "RLMRealm_Private.hpp" +#import "RLMSchema_Private.h" +#import "RLMSwiftCollectionBase.h" +#import "RLMSwiftSupport.h" +#import "RLMUtil.hpp" + +#import +#import + +using namespace realm; + +@protocol RLMCustomEventRepresentable +@end + +// private properties +@interface RLMObjectSchema () +@property (nonatomic, readwrite) NSDictionary *allPropertiesByName; +@property (nonatomic, readwrite) NSString *className; +@end + +@implementation RLMObjectSchema { + std::string _objectStoreName; +} + +- (instancetype)initWithClassName:(NSString *)objectClassName objectClass:(Class)objectClass properties:(NSArray *)properties { + self = [super init]; + self.className = objectClassName; + self.properties = properties; + self.objectClass = objectClass; + self.accessorClass = objectClass; + self.unmanagedClass = objectClass; + return self; +} + +// return properties by name +- (RLMProperty *)objectForKeyedSubscript:(__unsafe_unretained NSString *const)key { + return _allPropertiesByName[key]; +} + +// create property map when setting property array +- (void)setProperties:(NSArray *)properties { + _properties = properties; + [self _propertiesDidChange]; +} + +- (void)setComputedProperties:(NSArray *)computedProperties { + _computedProperties = computedProperties; + [self _propertiesDidChange]; +} + +- (void)_propertiesDidChange { + _primaryKeyProperty = nil; + NSMutableDictionary *map = [NSMutableDictionary dictionaryWithCapacity:_properties.count + _computedProperties.count]; + NSUInteger index = 0; + for (RLMProperty *prop in _properties) { + prop.index = index++; + map[prop.name] = prop; + if (prop.isPrimary) { + if (_primaryKeyProperty) { + @throw RLMException(@"Properties '%@' and '%@' are both marked as the primary key of '%@'", + prop.name, _primaryKeyProperty.name, _className); + } + _primaryKeyProperty = prop; + } + } + index = 0; + for (RLMProperty *prop in _computedProperties) { + prop.index = index++; + map[prop.name] = prop; + } + _allPropertiesByName = map; + + if (RLMIsSwiftObjectClass(_accessorClass)) { + NSMutableArray *genericProperties = [NSMutableArray new]; + for (RLMProperty *prop in _properties) { + if (prop.swiftAccessor) { + [genericProperties addObject:prop]; + } + } + // Currently all computed properties are Swift generics + [genericProperties addObjectsFromArray:_computedProperties]; + + if (genericProperties.count) { + _swiftGenericProperties = genericProperties; + } + else { + _swiftGenericProperties = nil; + } + } +} + + +- (void)setPrimaryKeyProperty:(RLMProperty *)primaryKeyProperty { + _primaryKeyProperty.isPrimary = NO; + primaryKeyProperty.isPrimary = YES; + _primaryKeyProperty = primaryKeyProperty; + _primaryKeyProperty.indexed = YES; +} + ++ (instancetype)schemaForObjectClass:(Class)objectClass { + RLMObjectSchema *schema = [RLMObjectSchema new]; + + // determine classname from objectclass as className method has not yet been updated + NSString *className = NSStringFromClass(objectClass); + bool hasSwiftName = [RLMSwiftSupport isSwiftClassName:className]; + if (hasSwiftName) { + className = [RLMSwiftSupport demangleClassName:className]; + } + + bool isSwift = hasSwiftName || RLMIsSwiftObjectClass(objectClass); + + schema.className = className; + schema.objectClass = objectClass; + schema.accessorClass = objectClass; + schema.unmanagedClass = objectClass; + schema.isSwiftClass = isSwift; + schema.hasCustomEventSerialization = [objectClass conformsToProtocol:@protocol(RLMCustomEventRepresentable)]; + + bool isEmbedded = [(id)objectClass isEmbedded]; + bool isAsymmetric = [(id)objectClass isAsymmetric]; + REALM_ASSERT(!(isEmbedded && isAsymmetric)); + schema.isEmbedded = isEmbedded; + schema.isAsymmetric = isAsymmetric; + + // create array of RLMProperties, inserting properties of superclasses first + Class cls = objectClass; + Class superClass = class_getSuperclass(cls); + NSArray *allProperties = @[]; + while (superClass && superClass != RLMObjectBase.class) { + allProperties = [[RLMObjectSchema propertiesForClass:cls isSwift:isSwift] + arrayByAddingObjectsFromArray:allProperties]; + cls = superClass; + superClass = class_getSuperclass(superClass); + } + NSArray *persistedProperties = [allProperties filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(RLMProperty *property, NSDictionary *) { + return !RLMPropertyTypeIsComputed(property.type); + }]]; + schema.properties = persistedProperties; + + NSArray *computedProperties = [allProperties filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(RLMProperty *property, NSDictionary *) { + return RLMPropertyTypeIsComputed(property.type); + }]]; + schema.computedProperties = computedProperties; + + // verify that we didn't add any properties twice due to inheritance + if (allProperties.count != [NSSet setWithArray:[allProperties valueForKey:@"name"]].count) { + NSCountedSet *countedPropertyNames = [NSCountedSet setWithArray:[allProperties valueForKey:@"name"]]; + NSArray *duplicatePropertyNames = [countedPropertyNames filteredSetUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id object, NSDictionary *) { + return [countedPropertyNames countForObject:object] > 1; + }]].allObjects; + + if (duplicatePropertyNames.count == 1) { + @throw RLMException(@"Property '%@' is declared multiple times in the class hierarchy of '%@'", duplicatePropertyNames.firstObject, className); + } else { + @throw RLMException(@"Object '%@' has properties that are declared multiple times in its class hierarchy: '%@'", className, [duplicatePropertyNames componentsJoinedByString:@"', '"]); + } + } + + if (NSString *primaryKey = [objectClass primaryKey]) { + for (RLMProperty *prop in schema.properties) { + if ([primaryKey isEqualToString:prop.name]) { + prop.indexed = YES; + schema.primaryKeyProperty = prop; + break; + } + } + + if (!schema.primaryKeyProperty) { + @throw RLMException(@"Primary key property '%@' does not exist on object '%@'", primaryKey, className); + } + if (schema.primaryKeyProperty.type != RLMPropertyTypeInt && + schema.primaryKeyProperty.type != RLMPropertyTypeString && + schema.primaryKeyProperty.type != RLMPropertyTypeObjectId && + schema.primaryKeyProperty.type != RLMPropertyTypeUUID) { + @throw RLMException(@"Property '%@' cannot be made the primary key of '%@' because it is not a 'string', 'int', 'objectId', or 'uuid' property.", + primaryKey, className); + } + } + + for (RLMProperty *prop in schema.properties) { + if (prop.optional && prop.collection && !prop.dictionary && (prop.type == RLMPropertyTypeObject || prop.type == RLMPropertyTypeLinkingObjects)) { + // FIXME: message is awkward + @throw RLMException(@"Property '%@.%@' cannot be made optional because optional '%@' properties are not supported.", + className, prop.name, RLMTypeToString(prop.type)); + } + } + + if ([objectClass shouldIncludeInDefaultSchema] + && schema.isSwiftClass + && schema.properties.count == 0) { + @throw RLMException(@"No properties are defined for '%@'. Did you remember to mark them with '@objc' in your model?", schema.className); + } + return schema; +} + ++ (NSArray *)propertiesForClass:(Class)objectClass isSwift:(bool)isSwiftClass { + if (NSArray *props = [objectClass _getProperties]) { + return props; + } + + // For Swift subclasses of RLMObject we need an instance of the object when parsing properties + id swiftObjectInstance = isSwiftClass ? [[objectClass alloc] init] : nil; + + NSArray *ignoredProperties = [objectClass ignoredProperties]; + NSDictionary *linkingObjectsProperties = [objectClass linkingObjectsProperties]; + NSDictionary *columnNameMap = [objectClass _realmColumnNames]; + + unsigned int count; + std::unique_ptr props(class_copyPropertyList(objectClass, &count), &free); + NSMutableArray *propArray = [NSMutableArray arrayWithCapacity:count]; + NSSet *indexed = [[NSSet alloc] initWithArray:[objectClass indexedProperties]]; + for (unsigned int i = 0; i < count; i++) { + NSString *propertyName = @(property_getName(props[i])); + if ([ignoredProperties containsObject:propertyName]) { + continue; + } + + RLMProperty *prop = nil; + if (isSwiftClass) { + prop = [[RLMProperty alloc] initSwiftPropertyWithName:propertyName + indexed:[indexed containsObject:propertyName] + linkPropertyDescriptor:linkingObjectsProperties[propertyName] + property:props[i] + instance:swiftObjectInstance]; + } + else { + prop = [[RLMProperty alloc] initWithName:propertyName + indexed:[indexed containsObject:propertyName] + linkPropertyDescriptor:linkingObjectsProperties[propertyName] + property:props[i]]; + } + + if (prop) { + if (columnNameMap) { + prop.columnName = columnNameMap[prop.name]; + } + [propArray addObject:prop]; + } + } + + if (auto requiredProperties = [objectClass requiredProperties]) { + for (RLMProperty *property in propArray) { + bool required = [requiredProperties containsObject:property.name]; + if (required && property.type == RLMPropertyTypeObject && (!property.collection || property.dictionary)) { + @throw RLMException(@"Object properties cannot be made required, " + "but '+[%@ requiredProperties]' included '%@'", objectClass, property.name); + } + property.optional &= !required; + } + } + + for (RLMProperty *property in propArray) { + if (!property.optional && property.type == RLMPropertyTypeObject && !property.collection) { + @throw RLMException(@"The `%@.%@` property must be marked as being optional.", + [objectClass className], property.name); + } + if (property.type == RLMPropertyTypeAny) { + property.optional = NO; + } + } + + return propArray; +} + +- (id)copyWithZone:(NSZone *)zone { + RLMObjectSchema *schema = [[RLMObjectSchema allocWithZone:zone] init]; + schema->_objectClass = _objectClass; + schema->_className = _className; + schema->_objectClass = _objectClass; + schema->_accessorClass = _objectClass; + schema->_unmanagedClass = _unmanagedClass; + schema->_isSwiftClass = _isSwiftClass; + schema->_isEmbedded = _isEmbedded; + schema->_isAsymmetric = _isAsymmetric; + schema->_properties = [[NSArray allocWithZone:zone] initWithArray:_properties copyItems:YES]; + schema->_computedProperties = [[NSArray allocWithZone:zone] initWithArray:_computedProperties copyItems:YES]; + [schema _propertiesDidChange]; + return schema; +} + +- (BOOL)isEqualToObjectSchema:(RLMObjectSchema *)objectSchema { + if (objectSchema.properties.count != _properties.count) { + return NO; + } + + if (![_properties isEqualToArray:objectSchema.properties]) { + return NO; + } + if (![_computedProperties isEqualToArray:objectSchema.computedProperties]) { + return NO; + } + + return YES; +} + +- (NSString *)description { + NSMutableString *propertiesString = [NSMutableString string]; + for (RLMProperty *property in self.properties) { + [propertiesString appendFormat:@"\t%@\n", [property.description stringByReplacingOccurrencesOfString:@"\n" withString:@"\n\t"]]; + } + for (RLMProperty *property in self.computedProperties) { + [propertiesString appendFormat:@"\t%@\n", [property.description stringByReplacingOccurrencesOfString:@"\n" withString:@"\n\t"]]; + } + return [NSString stringWithFormat:@"%@ %@{\n%@}", + self.className, _isEmbedded ? @"(embedded) " : @"", propertiesString]; +} + +- (NSString *)objectName { + return [self.objectClass _realmObjectName] ?: _className; +} + +- (std::string const&)objectStoreName { + if (_objectStoreName.empty()) { + _objectStoreName = self.objectName.UTF8String; + } + return _objectStoreName; +} + +- (realm::ObjectSchema)objectStoreCopy:(RLMSchema *)schema { + using Type = ObjectSchema::ObjectType; + ObjectSchema objectSchema; + objectSchema.name = self.objectStoreName; + objectSchema.primary_key = _primaryKeyProperty ? _primaryKeyProperty.columnName.UTF8String : ""; + objectSchema.table_type = _isAsymmetric ? Type::TopLevelAsymmetric : _isEmbedded ? Type::Embedded : Type::TopLevel; + for (RLMProperty *prop in _properties) { + Property p = [prop objectStoreCopy:schema]; + p.is_primary = (prop == _primaryKeyProperty); + objectSchema.persisted_properties.push_back(std::move(p)); + } + for (RLMProperty *prop in _computedProperties) { + objectSchema.computed_properties.push_back([prop objectStoreCopy:schema]); + } + return objectSchema; +} + ++ (instancetype)objectSchemaForObjectStoreSchema:(realm::ObjectSchema const&)objectSchema { + RLMObjectSchema *schema = [RLMObjectSchema new]; + schema.className = @(objectSchema.name.c_str()); + schema.isEmbedded = objectSchema.table_type == ObjectSchema::ObjectType::Embedded; + schema.isAsymmetric = objectSchema.table_type == ObjectSchema::ObjectType::TopLevelAsymmetric; + + // create array of RLMProperties + NSMutableArray *properties = [NSMutableArray arrayWithCapacity:objectSchema.persisted_properties.size()]; + for (const Property &prop : objectSchema.persisted_properties) { + RLMProperty *property = [RLMProperty propertyForObjectStoreProperty:prop]; + property.isPrimary = (prop.name == objectSchema.primary_key); + [properties addObject:property]; + } + schema.properties = properties; + + NSMutableArray *computedProperties = [NSMutableArray arrayWithCapacity:objectSchema.computed_properties.size()]; + for (const Property &prop : objectSchema.computed_properties) { + [computedProperties addObject:[RLMProperty propertyForObjectStoreProperty:prop]]; + } + schema.computedProperties = computedProperties; + + // get primary key from realm metadata + if (objectSchema.primary_key.length()) { + NSString *primaryKeyString = [NSString stringWithUTF8String:objectSchema.primary_key.c_str()]; + schema.primaryKeyProperty = schema[primaryKeyString]; + if (!schema.primaryKeyProperty) { + @throw RLMException(@"No property matching primary key '%@'", primaryKeyString); + } + } + + // for dynamic schema use vanilla RLMDynamicObject accessor classes + schema.objectClass = RLMObject.class; + schema.accessorClass = RLMDynamicObject.class; + schema.unmanagedClass = RLMObject.class; + + return schema; +} + +@end diff --git a/Pods/Realm/Realm/RLMObjectStore.mm b/Pods/Realm/Realm/RLMObjectStore.mm new file mode 100644 index 0000000..ff87f45 --- /dev/null +++ b/Pods/Realm/Realm/RLMObjectStore.mm @@ -0,0 +1,247 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// 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 "RLMObjectStore.h" + +#import "RLMAccessor.hpp" +#import "RLMArray_Private.hpp" +#import "RLMObservation.hpp" +#import "RLMObject_Private.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMProperty_Private.h" +#import "RLMQueryUtil.hpp" +#import "RLMRealm_Private.hpp" +#import "RLMSchema_Private.h" +#import "RLMSet_Private.hpp" +#import "RLMSwiftCollectionBase.h" +#import "RLMSwiftSupport.h" +#import "RLMUtil.hpp" +#import "RLMSwiftValueStorage.h" + +#import +#import +#import +#import + +#import + +using namespace realm; + +static inline void RLMVerifyRealmRead(__unsafe_unretained RLMRealm *const realm) { + if (!realm) { + @throw RLMException(@"Realm must not be nil"); + } + [realm verifyThread]; + if (realm->_realm->is_closed()) { + // This message may seem overly specific, but frozen Realms are currently + // the only ones which we outright close. + @throw RLMException(@"Cannot read from a frozen Realm which has been invalidated."); + } +} + +void RLMVerifyInWriteTransaction(__unsafe_unretained RLMRealm *const realm) { + RLMVerifyRealmRead(realm); + // if realm is not writable throw + if (!realm.inWriteTransaction) { + @throw RLMException(@"Can only add, remove, or create objects in a Realm in a write transaction - call beginWriteTransaction on an RLMRealm instance first."); + } +} + +void RLMInitializeSwiftAccessor(__unsafe_unretained RLMObjectBase *const object, bool promoteExisting) { + if (!object || !object->_row || !object->_objectSchema->_isSwiftClass) { + return; + } + if (![object isKindOfClass:object->_objectSchema.objectClass]) { + // It can be a different class if it's a dynamic object, and those don't + // require any init here (and would crash since they don't have the ivars) + return; + } + + if (promoteExisting) { + for (RLMProperty *prop in object->_objectSchema.swiftGenericProperties) { + [prop.swiftAccessor promote:prop on:object]; + } + } + else { + for (RLMProperty *prop in object->_objectSchema.swiftGenericProperties) { + [prop.swiftAccessor initialize:prop on:object]; + } + } +} + +void RLMVerifyHasPrimaryKey(Class cls) { + RLMObjectSchema *schema = [cls sharedSchema]; + if (!schema.primaryKeyProperty) { + NSString *reason = [NSString stringWithFormat:@"'%@' does not have a primary key and can not be updated", schema.className]; + @throw [NSException exceptionWithName:@"RLMException" reason:reason userInfo:nil]; + } +} + +static CreatePolicy updatePolicyToCreatePolicy(RLMUpdatePolicy policy) { + CreatePolicy createPolicy = {.create = true, .copy = false, .diff = false, .update = false}; + switch (policy) { + case RLMUpdatePolicyError: + break; + case RLMUpdatePolicyUpdateChanged: + createPolicy.diff = true; + [[clang::fallthrough]]; + case RLMUpdatePolicyUpdateAll: + createPolicy.update = true; + break; + } + return createPolicy; +} + +void RLMAddObjectToRealm(__unsafe_unretained RLMObjectBase *const object, + __unsafe_unretained RLMRealm *const realm, + RLMUpdatePolicy updatePolicy) { + RLMVerifyInWriteTransaction(realm); + + CreatePolicy createPolicy = updatePolicyToCreatePolicy(updatePolicy); + createPolicy.copy = false; + auto& info = realm->_info[object->_objectSchema.className]; + RLMAccessorContext c{info}; + c.createObject(object, createPolicy); +} + +RLMObjectBase *RLMCreateObjectInRealmWithValue(RLMRealm *realm, NSString *className, + id value, RLMUpdatePolicy updatePolicy) { + RLMVerifyInWriteTransaction(realm); + + CreatePolicy createPolicy = updatePolicyToCreatePolicy(updatePolicy); + createPolicy.copy = true; + + auto& info = realm->_info[className]; + RLMAccessorContext c{info}; + RLMObjectBase *object = RLMCreateManagedAccessor(info.rlmObjectSchema.accessorClass, &info); + auto [obj, reuseExisting] = c.createObject(value, createPolicy, true); + if (reuseExisting) { + return value; + } + object->_row = std::move(obj); + RLMInitializeSwiftAccessor(object, false); + return object; +} + +void RLMCreateAsymmetricObjectInRealm(RLMRealm *realm, NSString *className, id value) { + RLMVerifyInWriteTransaction(realm); + + CreatePolicy createPolicy = {.create = true, .copy = true, .diff = false, .update = false}; + + auto& info = realm->_info[className]; + RLMAccessorContext c{info}; + c.createObject(value, createPolicy); +} + +RLMObjectBase *RLMObjectFromObjLink(RLMRealm *realm, realm::ObjLink&& objLink, bool parentIsSwiftObject) { + if (auto* tableInfo = realm->_info[objLink.get_table_key()]) { + return RLMCreateObjectAccessor(*tableInfo, objLink.get_obj_key().value); + } else { + // Construct the object dynamically. + // This code path should only be hit on first access of the object. + Class cls = parentIsSwiftObject ? [RealmSwiftDynamicObject class] : [RLMDynamicObject class]; + auto& group = realm->_realm->read_group(); + auto schema = std::make_unique(group, + group.get_table_name(objLink.get_table_key()), + objLink.get_table_key()); + RLMObjectSchema *rlmObjectSchema = [RLMObjectSchema objectSchemaForObjectStoreSchema:*schema]; + rlmObjectSchema.accessorClass = cls; + rlmObjectSchema.isSwiftClass = parentIsSwiftObject; + realm->_info.appendDynamicObjectSchema(std::move(schema), rlmObjectSchema, realm); + return RLMCreateObjectAccessor(realm->_info[rlmObjectSchema.className], objLink.get_obj_key().value); + } +} + +void RLMDeleteObjectFromRealm(__unsafe_unretained RLMObjectBase *const object, + __unsafe_unretained RLMRealm *const realm) { + if (realm != object->_realm) { + @throw RLMException(@"Can only delete an object from the Realm it belongs to."); + } + + RLMVerifyInWriteTransaction(object->_realm); + + if (object->_row.is_valid()) { + RLMObservationTracker tracker(realm, true); + object->_row.remove(); + } + object->_realm = nil; +} + +void RLMDeleteAllObjectsFromRealm(RLMRealm *realm) { + RLMVerifyInWriteTransaction(realm); + + // clear table for each object schema + for (auto& info : realm->_info) { + RLMClearTable(info.second); + } +} + +RLMResults *RLMGetObjects(__unsafe_unretained RLMRealm *const realm, + NSString *objectClassName, + NSPredicate *predicate) { + RLMVerifyRealmRead(realm); + + // create view from table and predicate + RLMClassInfo& info = realm->_info[objectClassName]; + if (!info.table()) { + // read-only realms may be missing tables since we can't add any + // missing ones on init + return [RLMResults resultsWithObjectInfo:info results:{}]; + } + + if (predicate) { + realm::Query query = RLMPredicateToQuery(predicate, info.rlmObjectSchema, realm.schema, realm.group); + return [RLMResults resultsWithObjectInfo:info + results:realm::Results(realm->_realm, std::move(query))]; + } + + return [RLMResults resultsWithObjectInfo:info + results:realm::Results(realm->_realm, info.table())]; +} + +id RLMGetObject(RLMRealm *realm, NSString *objectClassName, id key) { + RLMVerifyRealmRead(realm); + + auto& info = realm->_info[objectClassName]; + if (RLMProperty *prop = info.propertyForPrimaryKey()) { + RLMValidateValueForProperty(key, info.rlmObjectSchema, prop); + } + try { + RLMAccessorContext c{info}; + auto obj = realm::Object::get_for_primary_key(c, realm->_realm, *info.objectSchema, + key ?: NSNull.null); + if (!obj.is_valid()) + return nil; + return RLMCreateObjectAccessor(info, obj.obj()); + } + catch (std::exception const& e) { + @throw RLMException(e); + } +} + +RLMObjectBase *RLMCreateObjectAccessor(RLMClassInfo& info, int64_t key) { + return RLMCreateObjectAccessor(info, info.table()->get_object(realm::ObjKey(key))); +} + +// Create accessor and register with realm +RLMObjectBase *RLMCreateObjectAccessor(RLMClassInfo& info, realm::Obj&& obj) { + RLMObjectBase *accessor = RLMCreateManagedAccessor(info.rlmObjectSchema.accessorClass, &info); + accessor->_row = std::move(obj); + RLMInitializeSwiftAccessor(accessor, false); + return accessor; +} diff --git a/Pods/Realm/Realm/RLMObservation.mm b/Pods/Realm/Realm/RLMObservation.mm new file mode 100644 index 0000000..579f2b3 --- /dev/null +++ b/Pods/Realm/Realm/RLMObservation.mm @@ -0,0 +1,554 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// 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 "RLMObservation.hpp" + +#import "RLMAccessor.h" +#import "RLMArray_Private.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObject_Private.hpp" +#import "RLMProperty_Private.h" +#import "RLMQueryUtil.hpp" +#import "RLMRealm_Private.hpp" +#import "RLMSchema_Private.h" +#import "RLMSet_Private.hpp" +#import "RLMSwiftCollectionBase.h" +#import "RLMSwiftValueStorage.h" + +#import + +using namespace realm; + +namespace { + template + struct IteratorPair { + Iterator first; + Iterator second; + }; + template + Iterator begin(IteratorPair const& p) { + return p.first; + } + template + Iterator end(IteratorPair const& p) { + return p.second; + } + + template + auto reverse(Container const& c) { + return IteratorPair{c.rbegin(), c.rend()}; + } +} + +RLMObservationInfo::RLMObservationInfo(RLMClassInfo &objectSchema, realm::ObjKey row, id object) +: object(object) +, objectSchema(&objectSchema) +{ + setRow(*objectSchema.table(), row); +} + +RLMObservationInfo::RLMObservationInfo(id object) +: object(object) +{ +} + +RLMObservationInfo::~RLMObservationInfo() { + if (prev) { + // Not the head of the linked list, so just detach from the list + REALM_ASSERT_DEBUG(prev->next == this); + prev->next = next; + if (next) { + REALM_ASSERT_DEBUG(next->prev == this); + next->prev = prev; + } + } + else if (objectSchema) { + // The head of the list, so remove self from the object schema's array + // of observation info, either replacing self with the next info or + // removing entirely if there is no next + auto end = objectSchema->observedObjects.end(); + auto it = find(objectSchema->observedObjects.begin(), end, this); + if (it != end) { + if (next) { + *it = next; + next->prev = nullptr; + } + else { + iter_swap(it, std::prev(end)); + objectSchema->observedObjects.pop_back(); + } + } + } + // Otherwise the observed object was unmanaged, so nothing to do + +#ifdef DEBUG + // ensure that incorrect cleanup fails noisily + object = (__bridge id)(void *)-1; + prev = (RLMObservationInfo *)-1; + next = (RLMObservationInfo *)-1; +#endif +} + +NSString *RLMObservationInfo::columnName(realm::ColKey col) const noexcept { + return objectSchema->propertyForTableColumn(col).name; +} + +void RLMObservationInfo::willChange(NSString *key, NSKeyValueChange kind, NSIndexSet *indexes) const { + if (indexes) { + forEach([=](__unsafe_unretained auto o) { + [o willChange:kind valuesAtIndexes:indexes forKey:key]; + }); + } + else { + forEach([=](__unsafe_unretained auto o) { + [o willChangeValueForKey:key]; + }); + } +} + +void RLMObservationInfo::didChange(NSString *key, NSKeyValueChange kind, NSIndexSet *indexes) const { + if (indexes) { + forEach([=](__unsafe_unretained auto o) { + [o didChange:kind valuesAtIndexes:indexes forKey:key]; + }); + } + else { + forEach([=](__unsafe_unretained auto o) { + [o didChangeValueForKey:key]; + }); + } +} + +void RLMObservationInfo::prepareForInvalidation() { + REALM_ASSERT_DEBUG(objectSchema); + REALM_ASSERT_DEBUG(!prev); + for (auto info = this; info; info = info->next) + info->invalidated = true; +} + +void RLMObservationInfo::setRow(realm::Table const& table, realm::ObjKey key) { + REALM_ASSERT_DEBUG(!row); + REALM_ASSERT_DEBUG(objectSchema); + row = table.get_object(key); + for (auto info : objectSchema->observedObjects) { + if (info->row && info->row.get_key() == key) { + prev = info; + next = info->next; + if (next) + next->prev = this; + info->next = this; + return; + } + } + objectSchema->observedObjects.push_back(this); +} + +void RLMObservationInfo::recordObserver(realm::Obj& objectRow, RLMClassInfo *objectInfo, + __unsafe_unretained RLMObjectSchema *const objectSchema, + __unsafe_unretained NSString *const keyPath) { + ++observerCount; + if (row) { + return; + } + + // add ourselves to the list of observed objects if this is the first time + // an observer is being added to a managed object + if (objectRow) { + this->objectSchema = objectInfo; + setRow(*objectRow.get_table(), objectRow.get_key()); + return; + } + + // Arrays need a reference to their containing object to avoid having to + // go through the awful proxy object from mutableArrayValueForKey. + // For managed objects we do this when the object is added or created + // (and have to to support notifications from modifying an object which + // was never observed), but for Swift classes (both RealmSwift and + // RLMObject) we can't do it then because we don't know what the parent + // object is. + + NSUInteger sep = [keyPath rangeOfString:@"."].location; + NSString *key = sep == NSNotFound ? keyPath : [keyPath substringToIndex:sep]; + RLMProperty *prop = objectSchema[key]; + if (auto swiftAccessor = prop.swiftAccessor) { + [swiftAccessor observe:prop on:object]; + } + else if (prop.collection) { + [valueForKey(key) setParent:object property:prop]; + } +} + +void RLMObservationInfo::removeObserver() { + --observerCount; +} + +id RLMObservationInfo::valueForKey(NSString *key) { + if (invalidated) { + if ([key isEqualToString:RLMInvalidatedKey]) { + return @YES; + } + return cachedObjects[key]; + } + + if (key != lastKey) { + lastKey = key; + lastProp = objectSchema ? objectSchema->rlmObjectSchema[key] : nil; + } + + static auto superValueForKey = reinterpret_cast([NSObject methodForSelector:@selector(valueForKey:)]); + if (!lastProp) { + // Not a managed property, so use NSObject's implementation of valueForKey: + return RLMCoerceToNil(superValueForKey(object, @selector(valueForKey:), key)); + } + + auto getSuper = [&] { + return row ? RLMDynamicGet(object, lastProp) : RLMCoerceToNil(superValueForKey(object, @selector(valueForKey:), key)); + }; + + // We need to return the same object each time for observing over keypaths + // to work, so we store a cache of them here. We can't just cache them on + // the object as that leads to retain cycles. + if (lastProp.collection) { + id value = cachedObjects[key]; + if (!value) { + value = getSuper(); + if (!cachedObjects) { + cachedObjects = [NSMutableDictionary new]; + } + cachedObjects[key] = value; + } + return value; + } + + if (lastProp.type == RLMPropertyTypeObject) { + auto col = row.get_table()->get_column_key(lastProp.name.UTF8String); + if (row.is_null(col)) { + [cachedObjects removeObjectForKey:key]; + return nil; + } + + RLMObjectBase *value = cachedObjects[key]; + if (value && value->_row.get_key() == row.get(col)) { + return value; + } + value = getSuper(); + if (!cachedObjects) { + cachedObjects = [NSMutableDictionary new]; + } + cachedObjects[key] = value; + return value; + } + + return getSuper(); +} + +RLMObservationInfo *RLMGetObservationInfo(RLMObservationInfo *info, realm::ObjKey row, + RLMClassInfo& objectSchema) { + if (info) { + return info; + } + + for (RLMObservationInfo *info : objectSchema.observedObjects) { + if (info->isForRow(row)) { + return info; + } + } + + return nullptr; +} + +void RLMClearTable(RLMClassInfo &objectSchema) { + if (!objectSchema.table()) { + // Orphaned embedded object types are included in the schema but do not + // create a table at all, so we may not have a table here and just + // don't need to do anything + return; + } + + for (auto info : objectSchema.observedObjects) { + info->willChange(RLMInvalidatedKey); + } + + { + RLMObservationTracker tracker(objectSchema.realm, true); + Results(objectSchema.realm->_realm, objectSchema.table()).clear(); + + for (auto info : objectSchema.observedObjects) { + info->prepareForInvalidation(); + } + } + + for (auto info : reverse(objectSchema.observedObjects)) { + info->didChange(RLMInvalidatedKey); + } + + objectSchema.observedObjects.clear(); +} + +RLMObservationTracker::RLMObservationTracker(__unsafe_unretained RLMRealm *const realm, bool trackDeletions) +: _realm(realm) +, _group(realm.group) +{ + if (trackDeletions) { + this->trackDeletions(); + } +} + +RLMObservationTracker::~RLMObservationTracker() { + didChange(); +} + +void RLMObservationTracker::willChange(RLMObservationInfo *info, NSString *key, + NSKeyValueChange kind, NSIndexSet *indexes) { + _key = key; + _kind = kind; + _indexes = indexes; + _info = info; + if (_info) { + _info->willChange(key, kind, indexes); + } +} + +void RLMObservationTracker::trackDeletions() { + if (_group.has_cascade_notification_handler()) { + // We're nested inside another call which will handle any cascaded changes for us + return; + } + + for (auto& info : _realm->_info) { + if (!info.second.observedObjects.empty()) { + _observedTables.push_back(&info.second.observedObjects); + } + } + + // No need for change tracking if no objects are observed + if (_observedTables.empty()) { + return; + } + + _group.set_cascade_notification_handler([=](realm::Group::CascadeNotification const& cs) { + cascadeNotification(cs); + }); +} + +template +void RLMObservationTracker::cascadeNotification(CascadeNotification const& cs) { + if (cs.rows.empty() && cs.links.empty()) { + return; + } + + size_t invalidatedCount = _invalidated.size(); + size_t changeCount = _changes.size(); + + auto tableKey = [](RLMObservationInfo *info) { + return info->getRow().get_table()->get_key(); + }; + std::sort(begin(_observedTables), end(_observedTables), + [=](auto a, auto b) { return tableKey(a->front()) < tableKey(b->front()); }); + for (auto const& link : cs.links) { + auto table = std::find_if(_observedTables.begin(), _observedTables.end(), [&](auto table) { + return tableKey(table->front()) == link.origin_table; + }); + if (table == _observedTables.end()) { + continue; + } + + for (auto observer : **table) { + if (!observer->isForRow(link.origin_key)) { + continue; + } + + NSString *name = observer->columnName(link.origin_col_key); + if (observer->getRow().get_table()->get_column_type(link.origin_col_key) != type_LinkList) { + _changes.push_back({observer, name}); + continue; + } + + auto c = find_if(begin(_changes), end(_changes), [&](auto const& c) { + return c.info == observer && c.property == name; + }); + if (c == end(_changes)) { + _changes.push_back({observer, name, [NSMutableIndexSet new]}); + c = prev(end(_changes)); + } + + // We know what row index is being removed from the LinkView, + // but what we actually want is the indexes in the LinkView that + // are going away + auto linkview = observer->getRow().get_linklist(link.origin_col_key); + linkview.find_all(link.old_target_key, [&](size_t index) { + [c->indexes addIndex:index]; + }); + } + } + if (!cs.rows.empty()) { + using Row = realm::Group::CascadeNotification::row; + auto begin = cs.rows.begin(); + for (auto table : _observedTables) { + auto currentTableKey = tableKey(table->front()); + if (begin->table_key < currentTableKey) { + // Find the first deleted object in or after this table + begin = std::lower_bound(begin, cs.rows.end(), Row{currentTableKey, realm::ObjKey(0)}); + } + if (begin == cs.rows.end()) { + // No more deleted objects + break; + } + if (currentTableKey < begin->table_key) { + // Next deleted object is in a table after this one + continue; + } + + // Find the end of the deletions in this table + auto end = std::lower_bound(begin, cs.rows.end(), Row{realm::TableKey(currentTableKey.value + 1), realm::ObjKey(0)}); + + // Check each observed object to see if it's in the deleted rows + for (auto info : *table) { + if (std::binary_search(begin, end, Row{currentTableKey, info->getRow().get_key()})) { + _invalidated.push_back(info); + } + } + + // Advance the begin iterator to the start of the next table + begin = end; + if (begin == cs.rows.end()) { + break; + } + } + } + + // The relative order of these loops is very important + for (size_t i = invalidatedCount; i < _invalidated.size(); ++i) { + _invalidated[i]->willChange(RLMInvalidatedKey); + } + for (size_t i = changeCount; i < _changes.size(); ++i) { + auto const& change = _changes[i]; + change.info->willChange(change.property, NSKeyValueChangeRemoval, change.indexes); + } + for (size_t i = invalidatedCount; i < _invalidated.size(); ++i) { + _invalidated[i]->prepareForInvalidation(); + } +} + +void RLMObservationTracker::didChange() { + if (_info) { + _info->didChange(_key, _kind, _indexes); + _info = nullptr; + } + if (_observedTables.empty()) { + return; + } + _group.set_cascade_notification_handler(nullptr); + + for (auto const& change : reverse(_changes)) { + change.info->didChange(change.property, NSKeyValueChangeRemoval, change.indexes); + } + for (auto info : reverse(_invalidated)) { + info->didChange(RLMInvalidatedKey); + } + _observedTables.clear(); + _changes.clear(); + _invalidated.clear(); +} + +namespace { +template +void forEach(realm::BindingContext::ObserverState const& state, Func&& func) { + for (auto& change : state.changes) { + func(realm::ColKey(change.first), change.second, static_cast(state.info)); + } +} +} + +std::vector RLMGetObservedRows(RLMSchemaInfo const& schema) { + std::vector observers; + for (auto& table : schema) { + for (auto info : table.second.observedObjects) { + auto const& row = info->getRow(); + if (!row.is_valid()) + continue; + observers.push_back({ + row.get_table()->get_key(), + row.get_key(), + info}); + } + } + sort(begin(observers), end(observers)); + return observers; +} + +static NSKeyValueChange convert(realm::BindingContext::ColumnInfo::Kind kind) { + switch (kind) { + case realm::BindingContext::ColumnInfo::Kind::None: + case realm::BindingContext::ColumnInfo::Kind::SetAll: + return NSKeyValueChangeSetting; + case realm::BindingContext::ColumnInfo::Kind::Set: + return NSKeyValueChangeReplacement; + case realm::BindingContext::ColumnInfo::Kind::Insert: + return NSKeyValueChangeInsertion; + case realm::BindingContext::ColumnInfo::Kind::Remove: + return NSKeyValueChangeRemoval; + } +} + +static NSIndexSet *convert(realm::IndexSet const& in, NSMutableIndexSet *out) { + if (in.empty()) { + return nil; + } + + [out removeAllIndexes]; + for (auto range : in) { + [out addIndexesInRange:{range.first, range.second - range.first}]; + } + return out; +} + +void RLMWillChange(std::vector const& observed, + std::vector const& invalidated) { + for (auto info : invalidated) { + static_cast(info)->willChange(RLMInvalidatedKey); + } + if (!observed.empty()) { + NSMutableIndexSet *indexes = [NSMutableIndexSet new]; + for (auto const& o : observed) { + forEach(o, [&](realm::ColKey colKey, auto const& change, RLMObservationInfo *info) { + info->willChange(info->columnName(colKey), + convert(change.kind), convert(change.indices, indexes)); + }); + } + } + for (auto info : invalidated) { + static_cast(info)->prepareForInvalidation(); + } +} + +void RLMDidChange(std::vector const& observed, + std::vector const& invalidated) { + if (!observed.empty()) { + // Loop in reverse order to avoid O(N^2) behavior in Foundation + NSMutableIndexSet *indexes = [NSMutableIndexSet new]; + for (auto const& o : reverse(observed)) { + forEach(o, [&](realm::ColKey col, auto const& change, RLMObservationInfo *info) { + info->didChange(info->columnName(col), convert(change.kind), convert(change.indices, indexes)); + }); + } + } + for (auto const& info : reverse(invalidated)) { + static_cast(info)->didChange(RLMInvalidatedKey); + } +} diff --git a/Pods/Realm/Realm/RLMPredicateUtil.mm b/Pods/Realm/Realm/RLMPredicateUtil.mm new file mode 100644 index 0000000..05dcf46 --- /dev/null +++ b/Pods/Realm/Realm/RLMPredicateUtil.mm @@ -0,0 +1,106 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// 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 "RLMPredicateUtil.hpp" + +#include + +namespace { + +struct PredicateExpressionTransformer { + PredicateExpressionTransformer(ExpressionVisitor visitor) : m_visitor(visitor) { } + + NSExpression *visit(NSExpression *expression) const; + NSPredicate *visit(NSPredicate *predicate) const; + + ExpressionVisitor m_visitor; +}; + +NSExpression *PredicateExpressionTransformer::visit(NSExpression *expression) const { + expression = m_visitor(expression); + + switch (expression.expressionType) { + case NSFunctionExpressionType: { + NSMutableArray *arguments = [NSMutableArray array]; + for (NSExpression *argument in expression.arguments) { + [arguments addObject:visit(argument)]; + } + if (expression.operand) { + return [NSExpression expressionForFunction:visit(expression.operand) selectorName:expression.function arguments:arguments]; + } else { + return [NSExpression expressionForFunction:expression.function arguments:arguments]; + } + } + + case NSUnionSetExpressionType: + return [NSExpression expressionForUnionSet:visit(expression.leftExpression) with:visit(expression.rightExpression)]; + case NSIntersectSetExpressionType: + return [NSExpression expressionForIntersectSet:visit(expression.leftExpression) with:visit(expression.rightExpression)]; + case NSMinusSetExpressionType: + return [NSExpression expressionForMinusSet:visit(expression.leftExpression) with:visit(expression.rightExpression)]; + + case NSSubqueryExpressionType: { + NSExpression *collection = expression.collection; + // NSExpression.collection is declared as id, but appears to always hold an NSExpression for subqueries. + REALM_ASSERT([collection isKindOfClass:[NSExpression class]]); + return [NSExpression expressionForSubquery:visit(collection) usingIteratorVariable:expression.variable predicate:visit(expression.predicate)]; + } + + case NSAggregateExpressionType: { + NSMutableArray *subexpressions = [NSMutableArray array]; + for (NSExpression *subexpression in expression.collection) { + [subexpressions addObject:visit(subexpression)]; + } + return [NSExpression expressionForAggregate:subexpressions]; + } + + case NSConditionalExpressionType: +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpartial-availability" + return [NSExpression expressionForConditional:visit(expression.predicate) trueExpression:visit(expression.trueExpression) falseExpression:visit(expression.falseExpression)]; +#pragma clang diagnostic pop + + default: + // The remaining expression types do not contain nested expressions or predicates. + return expression; + } +} + +NSPredicate *PredicateExpressionTransformer::visit(NSPredicate *predicate) const { + if ([predicate isKindOfClass:[NSCompoundPredicate class]]) { + NSCompoundPredicate *compoundPredicate = (NSCompoundPredicate *)predicate; + NSMutableArray *subpredicates = [NSMutableArray array]; + for (NSPredicate *subpredicate in compoundPredicate.subpredicates) { + [subpredicates addObject:visit(subpredicate)]; + } + return [[NSCompoundPredicate alloc] initWithType:compoundPredicate.compoundPredicateType subpredicates:subpredicates]; + } + if ([predicate isKindOfClass:[NSComparisonPredicate class]]) { + NSComparisonPredicate *comparisonPredicate = (NSComparisonPredicate *)predicate; + NSExpression *leftExpression = visit(comparisonPredicate.leftExpression); + NSExpression *rightExpression = visit(comparisonPredicate.rightExpression); + return [NSComparisonPredicate predicateWithLeftExpression:leftExpression rightExpression:rightExpression modifier:comparisonPredicate.comparisonPredicateModifier type:comparisonPredicate.predicateOperatorType options:comparisonPredicate.options]; + } + return predicate; +} + +} // anonymous namespace + +NSPredicate *transformPredicate(NSPredicate *predicate, ExpressionVisitor visitor) { + PredicateExpressionTransformer transformer(visitor); + return transformer.visit(predicate); +} diff --git a/Pods/Realm/Realm/RLMProperty.mm b/Pods/Realm/Realm/RLMProperty.mm new file mode 100644 index 0000000..9f45801 --- /dev/null +++ b/Pods/Realm/Realm/RLMProperty.mm @@ -0,0 +1,784 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// 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 "RLMProperty_Private.hpp" + +#import "RLMArray_Private.hpp" +#import "RLMDictionary_Private.hpp" +#import "RLMObject.h" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObject_Private.h" +#import "RLMSchema_Private.h" +#import "RLMSet_Private.hpp" +#import "RLMSwiftSupport.h" +#import "RLMUtil.hpp" + +#import + +static_assert((int)RLMPropertyTypeInt == (int)realm::PropertyType::Int); +static_assert((int)RLMPropertyTypeBool == (int)realm::PropertyType::Bool); +static_assert((int)RLMPropertyTypeFloat == (int)realm::PropertyType::Float); +static_assert((int)RLMPropertyTypeDouble == (int)realm::PropertyType::Double); +static_assert((int)RLMPropertyTypeString == (int)realm::PropertyType::String); +static_assert((int)RLMPropertyTypeData == (int)realm::PropertyType::Data); +static_assert((int)RLMPropertyTypeDate == (int)realm::PropertyType::Date); +static_assert((int)RLMPropertyTypeObject == (int)realm::PropertyType::Object); +static_assert((int)RLMPropertyTypeObjectId == (int)realm::PropertyType::ObjectId); +static_assert((int)RLMPropertyTypeDecimal128 == (int)realm::PropertyType::Decimal); +static_assert((int)RLMPropertyTypeUUID == (int)realm::PropertyType::UUID); +static_assert((int)RLMPropertyTypeAny == (int)realm::PropertyType::Mixed); + +BOOL RLMPropertyTypeIsComputed(RLMPropertyType propertyType) { + return propertyType == RLMPropertyTypeLinkingObjects; +} + +// Swift obeys the ARC naming conventions for method families (except for init) +// but the end result doesn't really work (using KVC on a method returning a +// retained value results in a leak, but not returning a retained value results +// in crashes). Objective-C makes properties with naming fitting the method +// families a compile error, so we just disallow them in Swift as well. +// http://clang.llvm.org/docs/AutomaticReferenceCounting.html#arc-method-families +void RLMValidateSwiftPropertyName(NSString *name) { + // To belong to a method family, the property name must begin with the family + // name followed by a non-lowercase letter (or nothing), with an optional + // leading underscore + const char *str = name.UTF8String; + if (str[0] == '_') + ++str; + auto nameSize = strlen(str); + + // Note that "init" is deliberately not in this list because Swift does not + // infer family membership for it. + for (auto family : {"alloc", "new", "copy", "mutableCopy"}) { + auto familySize = strlen(family); + if (nameSize < familySize || !std::equal(str, str + familySize, family)) { + continue; + } + if (familySize == nameSize || !islower(str[familySize])) { + @throw RLMException(@"Property names beginning with '%s' are not " + "supported. Swift follows ARC's ownership " + "rules for methods based on their name, which " + "results in memory leaks when accessing " + "properties which return retained values via KVC.", + family); + } + return; + } +} + +static bool rawTypeShouldBeTreatedAsComputedProperty(NSString *rawType) { + return [rawType isEqualToString:@"@\"RLMLinkingObjects\""] || [rawType hasPrefix:@"@\"RLMLinkingObjects<"]; +} + +@implementation RLMProperty + ++ (instancetype)propertyForObjectStoreProperty:(const realm::Property &)prop { + auto ret = [[RLMProperty alloc] initWithName:@(prop.name.c_str()) + type:static_cast(prop.type & ~realm::PropertyType::Flags) + objectClassName:prop.object_type.length() ? @(prop.object_type.c_str()) : nil + linkOriginPropertyName:prop.link_origin_property_name.length() ? @(prop.link_origin_property_name.c_str()) : nil + indexed:prop.is_indexed + optional:isNullable(prop.type)]; + if (is_array(prop.type)) { + ret->_array = true; + } + if (is_set(prop.type)) { + ret->_set = true; + } + if (is_dictionary(prop.type)) { + // TODO: We need a way to store the dictionary + // key type in realm::Property once we support more + // key types. + ret->_dictionaryKeyType = RLMPropertyTypeString; + ret->_dictionary = true; + } + if (!prop.public_name.empty()) { + ret->_columnName = ret->_name; + ret->_name = @(prop.public_name.c_str()); + } + return ret; +} + +- (instancetype)initWithName:(NSString *)name + type:(RLMPropertyType)type + objectClassName:(NSString *)objectClassName + linkOriginPropertyName:(NSString *)linkOriginPropertyName + indexed:(BOOL)indexed + optional:(BOOL)optional { + self = [super init]; + if (self) { + _name = name; + _type = type; + _objectClassName = objectClassName; + _linkOriginPropertyName = linkOriginPropertyName; + _indexed = indexed; + _optional = optional; + [self updateAccessors]; + } + + return self; +} + +- (void)updateAccessors { + // populate getter/setter names if generic + if (!_getterName) { + _getterName = _name; + } + if (!_setterName) { + // Objective-C setters only capitalize the first letter of the property name if it falls between 'a' and 'z' + int asciiCode = [_name characterAtIndex:0]; + BOOL shouldUppercase = asciiCode >= 'a' && asciiCode <= 'z'; + NSString *firstChar = [_name substringToIndex:1]; + firstChar = shouldUppercase ? firstChar.uppercaseString : firstChar; + _setterName = [NSString stringWithFormat:@"set%@%@:", firstChar, [_name substringFromIndex:1]]; + } + + _getterSel = NSSelectorFromString(_getterName); + _setterSel = NSSelectorFromString(_setterName); +} + +static std::optional typeFromProtocolString(const char *type) { + if (strcmp(type, "RLMValue>\"") == 0) { + return RLMPropertyTypeAny; + } + if (strncmp(type, "RLM", 3)) { + return realm::none; + } + type += 3; + if (strcmp(type, "Int>\"") == 0) { + return RLMPropertyTypeInt; + } + if (strcmp(type, "Float>\"") == 0) { + return RLMPropertyTypeFloat; + } + if (strcmp(type, "Double>\"") == 0) { + return RLMPropertyTypeDouble; + } + if (strcmp(type, "Bool>\"") == 0) { + return RLMPropertyTypeBool; + } + if (strcmp(type, "String>\"") == 0) { + return RLMPropertyTypeString; + } + if (strcmp(type, "Data>\"") == 0) { + return RLMPropertyTypeData; + } + if (strcmp(type, "Date>\"") == 0) { + return RLMPropertyTypeDate; + } + if (strcmp(type, "Decimal128>\"") == 0) { + return RLMPropertyTypeDecimal128; + } + if (strcmp(type, "ObjectId>\"") == 0) { + return RLMPropertyTypeObjectId; + } + if (strcmp(type, "UUID>\"") == 0) { + return RLMPropertyTypeUUID; + } + return realm::none; +} + +// determine RLMPropertyType from objc code - returns true if valid type was found/set +- (BOOL)setTypeFromRawType:(NSString *)rawType { + const char *code = rawType.UTF8String; + switch (*code) { + case 's': // short + case 'i': // int + case 'l': // long + case 'q': // long long + _type = RLMPropertyTypeInt; + return YES; + case 'f': + _type = RLMPropertyTypeFloat; + return YES; + case 'd': + _type = RLMPropertyTypeDouble; + return YES; + case 'c': // BOOL is stored as char - since rlm has no char type this is ok + case 'B': + _type = RLMPropertyTypeBool; + return YES; + case '@': + break; + default: + return NO; + } + + _optional = true; + static const char arrayPrefix[] = "@\"RLMArray<"; + static const int arrayPrefixLen = sizeof(arrayPrefix) - 1; + + static const char setPrefix[] = "@\"RLMSet<"; + static const int setPrefixLen = sizeof(setPrefix) - 1; + + static const char dictionaryPrefix[] = "@\"RLMDictionary<"; + static const int dictionaryPrefixLen = sizeof(dictionaryPrefix) - 1; + + static const char numberPrefix[] = "@\"NSNumber<"; + static const int numberPrefixLen = sizeof(numberPrefix) - 1; + + static const char linkingObjectsPrefix[] = "@\"RLMLinkingObjects"; + static const int linkingObjectsPrefixLen = sizeof(linkingObjectsPrefix) - 1; + + _array = strncmp(code, arrayPrefix, arrayPrefixLen) == 0; + _set = strncmp(code, setPrefix, setPrefixLen) == 0; + _dictionary = strncmp(code, dictionaryPrefix, dictionaryPrefixLen) == 0; + + if (strcmp(code, "@\"NSString\"") == 0) { + _type = RLMPropertyTypeString; + } + else if (strcmp(code, "@\"NSDate\"") == 0) { + _type = RLMPropertyTypeDate; + } + else if (strcmp(code, "@\"NSData\"") == 0) { + _type = RLMPropertyTypeData; + } + else if (strcmp(code, "@\"RLMDecimal128\"") == 0) { + _type = RLMPropertyTypeDecimal128; + } + else if (strcmp(code, "@\"RLMObjectId\"") == 0) { + _type = RLMPropertyTypeObjectId; + } + else if (strcmp(code, "@\"NSUUID\"") == 0) { + _type = RLMPropertyTypeUUID; + } + else if (strcmp(code, "@\"\"") == 0) { + _type = RLMPropertyTypeAny; + // Mixed can represent a null type but can't explicitly be an optional type. + _optional = false; + } + else if (_array || _set || _dictionary) { + size_t prefixLen = 0; + NSString *collectionName; + if (_array) { + prefixLen = arrayPrefixLen; + collectionName = @"RLMArray"; + } + else if (_set) { + prefixLen = setPrefixLen; + collectionName = @"RLMSet"; + } + else if (_dictionary) { + // get the type, by working backward from RLMDictionary + size_t typeLen = 0; + size_t codeSize = strlen(code); + for (size_t i = codeSize; i > 0; i--) { + if (code[i] == '>' && i != (codeSize-2)) { // -2 means we skip the first time we see '>' + typeLen = i; + break; + } + } + prefixLen = typeLen+size_t(2); // +2 start at the type name + collectionName = @"RLMDictionary"; + + // Get the key type + if (strstr(code + dictionaryPrefixLen, "RLMString><") != NULL) { + _dictionaryKeyType = RLMPropertyTypeString; + } + } + + if (auto type = typeFromProtocolString(code + prefixLen)) { + _type = *type; + return YES; + } + + // get object class from type string - @"RLMSomeCollection" + _objectClassName = [[NSString alloc] initWithBytes:code + prefixLen + length:strlen(code + prefixLen) - 2 // drop trailing >" + encoding:NSUTF8StringEncoding]; + + if ([RLMSchema classForString:_objectClassName]) { + // Dictionaries require object types to be nullable. This is due to + // the fact that if you delete a realm object that exists in a dictionary + // the key should stay present but the value should be null. + _optional = _dictionary; + _type = RLMPropertyTypeObject; + return YES; + } + @throw RLMException(@"Property '%@' is of type '%@<%@>' which is not a supported %@ object type. " + @"%@ can only contain instances of RLMObject subclasses. " + @"See https://www.mongodb.com/docs/realm/sdk/swift/fundamentals/relationships/#to-many-relationship " + @"for more information.", _name, collectionName, _objectClassName, collectionName, collectionName); + } + else if (strncmp(code, numberPrefix, numberPrefixLen) == 0) { + auto type = typeFromProtocolString(code + numberPrefixLen); + if (type && (*type == RLMPropertyTypeInt || *type == RLMPropertyTypeFloat || *type == RLMPropertyTypeDouble || *type == RLMPropertyTypeBool)) { + _type = *type; + return YES; + } + @throw RLMException(@"Property '%@' is of type %s which is not a supported NSNumber object type. " + @"NSNumbers can only be RLMInt, RLMFloat, RLMDouble, and RLMBool at the moment. " + @"See https://www.mongodb.com/docs/realm/sdk/swift/data-types/supported-property-types/ " + @"for more information.", _name, code + 1); + } + else if (strncmp(code, linkingObjectsPrefix, linkingObjectsPrefixLen) == 0 && + (code[linkingObjectsPrefixLen] == '"' || code[linkingObjectsPrefixLen] == '<')) { + _type = RLMPropertyTypeLinkingObjects; + _optional = false; + _array = true; + + if (!_objectClassName || !_linkOriginPropertyName) { + @throw RLMException(@"Property '%@' is of type RLMLinkingObjects but +linkingObjectsProperties did not specify the class " + "or property that is the origin of the link.", _name); + } + + // If the property was declared with a protocol indicating the contained type, validate that it matches + // the class from the dictionary returned by +linkingObjectsProperties. + if (code[linkingObjectsPrefixLen] == '<') { + NSString *classNameFromProtocol = [[NSString alloc] initWithBytes:code + linkingObjectsPrefixLen + 1 + length:strlen(code + linkingObjectsPrefixLen) - 3 // drop trailing >" + encoding:NSUTF8StringEncoding]; + if (![_objectClassName isEqualToString:classNameFromProtocol]) { + @throw RLMException(@"Property '%@' was declared with type RLMLinkingObjects<%@>, but a conflicting " + "class name of '%@' was returned by +linkingObjectsProperties.", _name, + classNameFromProtocol, _objectClassName); + } + } + } + else if (strcmp(code, "@\"NSNumber\"") == 0) { + @throw RLMException(@"Property '%@' requires a protocol defining the contained type - example: NSNumber.", _name); + } + else if (strcmp(code, "@\"RLMArray\"") == 0) { + @throw RLMException(@"Property '%@' requires a protocol defining the contained type - example: RLMArray.", _name); + } + else if (strcmp(code, "@\"RLMSet\"") == 0) { + @throw RLMException(@"Property '%@' requires a protocol defining the contained type - example: RLMSet.", _name); + } + else if (strcmp(code, "@\"RLMDictionary\"") == 0) { + @throw RLMException(@"Property '%@' requires a protocol defining the contained type - example: RLMDictionary.", _name); + } + else { + NSString *className; + Class cls = nil; + if (code[1] == '\0') { + className = @"id"; + } + else { + // for objects strip the quotes and @ + className = [rawType substringWithRange:NSMakeRange(2, rawType.length-3)]; + cls = [RLMSchema classForString:className]; + } + + if (!cls) { + @throw RLMException(@"Property '%@' is declared as '%@', which is not a supported RLMObject property type. " + @"All properties must be primitives, NSString, NSDate, NSData, NSNumber, RLMArray, RLMSet, " + @"RLMDictionary, RLMLinkingObjects, RLMDecimal128, RLMObjectId, or subclasses of RLMObject. " + @"See https://www.mongodb.com/docs/realm-legacy/docs/objc/latest/api/Classes/RLMObject.html " + @"for more information.", _name, className); + } + + _type = RLMPropertyTypeObject; + _optional = true; + _objectClassName = [cls className] ?: className; + } + return YES; +} + +- (void)parseObjcProperty:(objc_property_t)property + readOnly:(bool *)readOnly + computed:(bool *)computed + rawType:(NSString **)rawType { + unsigned int count; + objc_property_attribute_t *attrs = property_copyAttributeList(property, &count); + + *computed = true; + for (size_t i = 0; i < count; ++i) { + switch (*attrs[i].name) { + case 'T': + *rawType = @(attrs[i].value); + break; + case 'R': + *readOnly = true; + break; + case 'G': + _getterName = @(attrs[i].value); + break; + case 'S': + _setterName = @(attrs[i].value); + break; + case 'V': // backing ivar name + *computed = false; + break; + + case '&': + // retain/assign + break; + case 'C': + // copy + break; + case 'D': + // dynamic + break; + case 'N': + // nonatomic + break; + case 'P': + // GC'able + break; + case 'W': + // weak + break; + default: + break; + } + } + free(attrs); +} + +- (instancetype)initSwiftPropertyWithName:(NSString *)name + indexed:(BOOL)indexed + linkPropertyDescriptor:(RLMPropertyDescriptor *)linkPropertyDescriptor + property:(objc_property_t)property + instance:(RLMObject *)obj { + self = [super init]; + if (!self) { + return nil; + } + + RLMValidateSwiftPropertyName(name); + + _name = name; + _indexed = indexed; + + if (linkPropertyDescriptor) { + _objectClassName = [linkPropertyDescriptor.objectClass className]; + _linkOriginPropertyName = linkPropertyDescriptor.propertyName; + } + + NSString *rawType; + bool readOnly = false; + bool isComputed = false; + [self parseObjcProperty:property readOnly:&readOnly computed:&isComputed rawType:&rawType]; + + // Swift sometimes doesn't explicitly set the ivar name in the metadata, so check if + // there's an ivar with the same name as the property. + if (!readOnly && isComputed && class_getInstanceVariable([obj class], name.UTF8String)) { + isComputed = false; + } + + // Check if there's a storage ivar for a lazy property in this name. We don't honor + // @lazy in managed objects, but allow it for unmanaged objects which are + // subclasses of RLMObject (but not RealmSwift.Object). It's unclear if there's a + // good reason for this difference. + if (!readOnly && isComputed) { + // Xcode 10 and earlier + NSString *backingPropertyName = [NSString stringWithFormat:@"%@.storage", name]; + isComputed = !class_getInstanceVariable([obj class], backingPropertyName.UTF8String); + } + if (!readOnly && isComputed) { + // Xcode 11 + NSString *backingPropertyName = [NSString stringWithFormat:@"$__lazy_storage_$_%@", name]; + isComputed = !class_getInstanceVariable([obj class], backingPropertyName.UTF8String); + } + + if (readOnly || isComputed) { + return nil; + } + + id propertyValue = [obj valueForKey:_name]; + + // FIXME: temporarily workaround added since Objective-C generics used in Swift show up as `@` + // * broken starting in Swift 3.0 Xcode 8 b1 + // * tested to still be broken in Swift 3.0 Xcode 8 b6 + // * if the Realm Objective-C Swift tests pass with this removed, it's been fixed + // * once it has been fixed, remove this entire conditional block (contents included) entirely + // * Bug Report: SR-2031 https://bugs.swift.org/browse/SR-2031 + if ([rawType isEqualToString:@"@"]) { + if (propertyValue) { + rawType = [NSString stringWithFormat:@"@\"%@\"", [propertyValue class]]; + } else if (linkPropertyDescriptor) { + // we're going to naively assume that the user used the correct type since we can't check it + rawType = @"@\"RLMLinkingObjects\""; + } + } + + // convert array / set / dictionary types to objc variant + if ([rawType isEqualToString:@"@\"RLMArray\""]) { + RLMArray *value = propertyValue; + _type = value.type; + _optional = value.optional; + _array = true; + _objectClassName = value.objectClassName; + if (_type == RLMPropertyTypeObject && ![RLMSchema classForString:_objectClassName]) { + @throw RLMException(@"Property '%@' is of type 'RLMArray<%@>' which is not a supported RLMArray object type. " + @"RLMArrays can only contain instances of RLMObject subclasses. " + @"See https://www.mongodb.com/docs/realm/sdk/swift/fundamentals/relationships/#to-many-relationship " + @"for more information.", _name, _objectClassName); + } + } + else if ([rawType isEqualToString:@"@\"RLMSet\""]) { + RLMSet *value = propertyValue; + _type = value.type; + _optional = value.optional; + _set = true; + _objectClassName = value.objectClassName; + if (_type == RLMPropertyTypeObject && ![RLMSchema classForString:_objectClassName]) { + @throw RLMException(@"Property '%@' is of type 'RLMSet<%@>' which is not a supported RLMSet object type. " + @"RLMSets can only contain instances of RLMObject subclasses. " + @"See https://www.mongodb.com/docs/realm/sdk/swift/fundamentals/relationships/#to-many-relationship " + @"for more information.", _name, _objectClassName); + } + } + else if ([rawType isEqualToString:@"@\"RLMDictionary\""]) { + RLMDictionary *value = propertyValue; + _type = value.type; + _dictionaryKeyType = value.keyType; + _optional = value.optional; + _dictionary = true; + _objectClassName = value.objectClassName; + if (_type == RLMPropertyTypeObject && ![RLMSchema classForString:_objectClassName]) { + @throw RLMException(@"Property '%@' is of type 'RLMDictionary' which is not a supported RLMDictionary object type. " + @"RLMDictionarys can only contain instances of RLMObject subclasses. " + @"See https://www.mongodb.com/docs/realm/sdk/swift/fundamentals/relationships/#to-many-relationship " + @"for more information.", _name, _objectClassName); + } + } + else if ([rawType isEqualToString:@"@\"NSNumber\""]) { + const char *numberType = [propertyValue objCType]; + if (!numberType) { + @throw RLMException(@"Can't persist NSNumber without default value: use a Swift-native number type or provide a default value."); + } + _optional = true; + switch (*numberType) { + case 'i': case 'l': case 'q': + _type = RLMPropertyTypeInt; + break; + case 'f': + _type = RLMPropertyTypeFloat; + break; + case 'd': + _type = RLMPropertyTypeDouble; + break; + case 'B': case 'c': + _type = RLMPropertyTypeBool; + break; + default: + @throw RLMException(@"Can't persist NSNumber of type '%s': only integers, floats, doubles, and bools are currently supported.", numberType); + } + } + else if (![self setTypeFromRawType:rawType]) { + @throw RLMException(@"Can't persist property '%@' with incompatible type. " + "Add to Object.ignoredProperties() class method to ignore.", + self.name); + } + + if ([rawType isEqualToString:@"c"]) { + // Check if it's a BOOL or Int8 by trying to set it to 2 and seeing if + // it actually sets it to 1. + [obj setValue:@2 forKey:name]; + NSNumber *value = [obj valueForKey:name]; + _type = value.intValue == 2 ? RLMPropertyTypeInt : RLMPropertyTypeBool; + } + + // update getter/setter names + [self updateAccessors]; + + return self; +} + +- (instancetype)initWithName:(NSString *)name + indexed:(BOOL)indexed + linkPropertyDescriptor:(RLMPropertyDescriptor *)linkPropertyDescriptor + property:(objc_property_t)property +{ + self = [super init]; + if (!self) { + return nil; + } + + _name = name; + _indexed = indexed; + + if (linkPropertyDescriptor) { + _objectClassName = [linkPropertyDescriptor.objectClass className]; + _linkOriginPropertyName = linkPropertyDescriptor.propertyName; + } + + NSString *rawType; + bool isReadOnly = false; + bool isComputed = false; + [self parseObjcProperty:property readOnly:&isReadOnly computed:&isComputed rawType:&rawType]; + bool shouldBeTreatedAsComputedProperty = rawTypeShouldBeTreatedAsComputedProperty(rawType); + if ((isReadOnly || isComputed) && !shouldBeTreatedAsComputedProperty) { + return nil; + } + + if (![self setTypeFromRawType:rawType]) { + @throw RLMException(@"Can't persist property '%@' with incompatible type. " + "Add to ignoredPropertyNames: method to ignore.", self.name); + } + + if (!isReadOnly && shouldBeTreatedAsComputedProperty) { + @throw RLMException(@"Property '%@' must be declared as readonly as %@ properties cannot be written to.", + self.name, RLMTypeToString(_type)); + } + + // update getter/setter names + [self updateAccessors]; + + return self; +} + +- (id)copyWithZone:(NSZone *)zone { + RLMProperty *prop = [[RLMProperty allocWithZone:zone] init]; + prop->_name = _name; + prop->_columnName = _columnName; + prop->_type = _type; + prop->_objectClassName = _objectClassName; + prop->_array = _array; + prop->_set = _set; + prop->_dictionary = _dictionary; + prop->_dictionaryKeyType = _dictionaryKeyType; + prop->_indexed = _indexed; + prop->_getterName = _getterName; + prop->_setterName = _setterName; + prop->_getterSel = _getterSel; + prop->_setterSel = _setterSel; + prop->_isPrimary = _isPrimary; + prop->_swiftAccessor = _swiftAccessor; + prop->_swiftIvar = _swiftIvar; + prop->_optional = _optional; + prop->_linkOriginPropertyName = _linkOriginPropertyName; + return prop; +} + +- (RLMProperty *)copyWithNewName:(NSString *)name { + RLMProperty *prop = [self copy]; + prop.name = name; + return prop; +} + +- (BOOL)isEqual:(id)object { + if (![object isKindOfClass:[RLMProperty class]]) { + return NO; + } + + return [self isEqualToProperty:object]; +} + +- (BOOL)isEqualToProperty:(RLMProperty *)property { + return _type == property->_type + && _indexed == property->_indexed + && _isPrimary == property->_isPrimary + && _optional == property->_optional + && [_name isEqualToString:property->_name] + && (_objectClassName == property->_objectClassName || [_objectClassName isEqualToString:property->_objectClassName]) + && (_linkOriginPropertyName == property->_linkOriginPropertyName || + [_linkOriginPropertyName isEqualToString:property->_linkOriginPropertyName]); +} + +- (BOOL)collection { + return self.set || self.array || self.dictionary; +} + +- (NSString *)description { + NSString *objectClassName = @""; + if (self.type == RLMPropertyTypeObject || self.type == RLMPropertyTypeLinkingObjects) { + objectClassName = [NSString stringWithFormat: + @"\tobjectClassName = %@;\n" + @"\tlinkOriginPropertyName = %@;\n", + self.objectClassName, self.linkOriginPropertyName]; + } + return [NSString stringWithFormat: + @"%@ {\n" + "\ttype = %@;\n" + "%@" + "\tcolumnName = %@;\n" + "\tindexed = %@;\n" + "\tisPrimary = %@;\n" + "\tarray = %@;\n" + "\tset = %@;\n" + "\tdictionary = %@;\n" + "\toptional = %@;\n" + "}", + self.name, RLMTypeToString(self.type), + objectClassName, + self.columnName, + self.indexed ? @"YES" : @"NO", + self.isPrimary ? @"YES" : @"NO", + self.array ? @"YES" : @"NO", + self.set ? @"YES" : @"NO", + self.dictionary ? @"YES" : @"NO", + self.optional ? @"YES" : @"NO"]; +} + +- (NSString *)columnName { + return _columnName ?: _name; +} + +- (realm::Property)objectStoreCopy:(RLMSchema *)schema { + realm::Property p; + p.name = self.columnName.UTF8String; + if (_columnName) { + p.public_name = _name.UTF8String; + } + if (_objectClassName) { + RLMObjectSchema *targetSchema = schema[_objectClassName]; + p.object_type = (targetSchema.objectName ?: _objectClassName).UTF8String; + if (_linkOriginPropertyName) { + p.link_origin_property_name = (targetSchema[_linkOriginPropertyName].columnName ?: _linkOriginPropertyName).UTF8String; + } + } + p.is_indexed = static_cast(_indexed); + p.type = static_cast(_type); + if (_array) { + p.type |= realm::PropertyType::Array; + } + if (_set) { + p.type |= realm::PropertyType::Set; + } + if (_dictionary) { + p.type |= realm::PropertyType::Dictionary; + } + if (_optional || p.type == realm::PropertyType::Mixed) { + p.type |= realm::PropertyType::Nullable; + } + return p; +} + +- (NSString *)typeName { + if (!self.collection) { + return RLMTypeToString(_type); + } + NSString *collectionName; + if (_swiftAccessor) { + collectionName = _array ? @"List" : + _set ? @"MutableSet" : + @"Map"; + } + else { + collectionName = _array ? @"RLMArray" : + _set ? @"RLMSet" : + @"RLMDictionary"; + } + return [NSString stringWithFormat:@"%@<%@>", collectionName, RLMTypeToString(_type)]; +} + +@end + +@implementation RLMPropertyDescriptor + ++ (instancetype)descriptorWithClass:(Class)objectClass propertyName:(NSString *)propertyName +{ + RLMPropertyDescriptor *descriptor = [[RLMPropertyDescriptor alloc] init]; + descriptor->_objectClass = objectClass; + descriptor->_propertyName = propertyName; + return descriptor; +} + +@end diff --git a/Pods/Realm/Realm/RLMProviderClient.mm b/Pods/Realm/Realm/RLMProviderClient.mm new file mode 100644 index 0000000..48417c4 --- /dev/null +++ b/Pods/Realm/Realm/RLMProviderClient.mm @@ -0,0 +1,44 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 "RLMProviderClient_Private.hpp" + +#import "RLMApp_Private.hpp" + +#import +#import + +@implementation RLMProviderClient +- (instancetype)initWithApp:(RLMApp *)app { + self = [super init]; + if (self) { + _app = app; + } + return self; +} + +realm::util::UniqueFunction)> +RLMWrapCompletion(RLMProviderClientOptionalErrorBlock completion) { + return [completion](std::optional error) { + if (error) { + return completion(makeError(*error)); + } + completion(nil); + }; +} +@end diff --git a/Pods/Realm/Realm/RLMPushClient.mm b/Pods/Realm/Realm/RLMPushClient.mm new file mode 100644 index 0000000..61061d4 --- /dev/null +++ b/Pods/Realm/Realm/RLMPushClient.mm @@ -0,0 +1,57 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 "RLMPushClient_Private.hpp" + +#import "RLMApp_Private.hpp" +#import "RLMUser_Private.hpp" + +#import + +@implementation RLMPushClient { + std::optional _pushClient; +} + +- (instancetype)initWithPushClient:(realm::app::PushClient&&)pushClient { + if (self = [super init]) { + _pushClient = std::move(pushClient); + return self; + } + return nil; +} + +- (void)registerDeviceWithToken:(NSString *)token user:(RLMUser *)user completion:(RLMOptionalErrorBlock)completion { + _pushClient->register_device(token.UTF8String, user._syncUser, ^(std::optional error) { + if (error) { + return completion(makeError(*error)); + } + completion(nil); + }); +} + + +- (void)deregisterDeviceForUser:(RLMUser *)user completion:(RLMOptionalErrorBlock)completion { + _pushClient->deregister_device(user._syncUser, ^(std::optional error) { + if (error) { + return completion(makeError(*error)); + } + completion(nil); + }); +} + +@end diff --git a/Pods/Realm/Realm/RLMQueryUtil.mm b/Pods/Realm/Realm/RLMQueryUtil.mm new file mode 100644 index 0000000..45f343c --- /dev/null +++ b/Pods/Realm/Realm/RLMQueryUtil.mm @@ -0,0 +1,1828 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// 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 "RLMQueryUtil.hpp" + +#import "RLMAccessor.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObject_Private.hpp" +#import "RLMPredicateUtil.hpp" +#import "RLMProperty_Private.h" +#import "RLMSchema.h" +#import "RLMUtil.hpp" + +#import +#import +#import +#import +#import +#import + +using namespace realm; + +NSString * const RLMPropertiesComparisonTypeMismatchException = @"RLMPropertiesComparisonTypeMismatchException"; +NSString * const RLMUnsupportedTypesFoundInPropertyComparisonException = @"RLMUnsupportedTypesFoundInPropertyComparisonException"; + +NSString * const RLMPropertiesComparisonTypeMismatchReason = @"Property type mismatch between %@ and %@"; +NSString * const RLMUnsupportedTypesFoundInPropertyComparisonReason = @"Comparison between %@ and %@"; + +namespace { + +// small helper to create the many exceptions thrown when parsing predicates +[[gnu::cold]] [[noreturn]] +void throwException(NSString *name, NSString *format, ...) { + va_list args; + va_start(args, format); + NSString *reason = [[NSString alloc] initWithFormat:format arguments:args]; + va_end(args); + + @throw [NSException exceptionWithName:name reason:reason userInfo:nil]; +} + +// check a precondition and throw an exception if it is not met +// this should be used iff the condition being false indicates a bug in the caller +// of the function checking its preconditions +void RLMPrecondition(bool condition, NSString *name, NSString *format, ...) { + if (__builtin_expect(condition, 1)) { + return; + } + + va_list args; + va_start(args, format); + NSString *reason = [[NSString alloc] initWithFormat:format arguments:args]; + va_end(args); + + @throw [NSException exceptionWithName:name reason:reason userInfo:nil]; +} + +BOOL propertyTypeIsNumeric(RLMPropertyType propertyType) { + switch (propertyType) { + case RLMPropertyTypeInt: + case RLMPropertyTypeFloat: + case RLMPropertyTypeDouble: + case RLMPropertyTypeDecimal128: + case RLMPropertyTypeDate: + case RLMPropertyTypeAny: + return YES; + default: + return NO; + } +} + +bool propertyTypeIsLink(RLMPropertyType type) { + return type == RLMPropertyTypeObject || type == RLMPropertyTypeLinkingObjects; +} + +bool isObjectValidForProperty(id value, RLMProperty *prop) { + if (prop.collection) { + if (propertyTypeIsLink(prop.type)) { + RLMObjectBase *obj = RLMDynamicCast(value); + if (!obj) { + obj = RLMDynamicCast(RLMBridgeSwiftValue(value)); + } + if (!obj) { + return false; + } + return [RLMObjectBaseObjectSchema(obj).className isEqualToString:prop.objectClassName]; + } + return RLMValidateValue(value, prop.type, prop.optional, false, nil); + } + return RLMIsObjectValidForProperty(value, prop); +} + + +// Equal and ContainsSubstring are used by QueryBuilder::add_string_constraint as the comparator +// for performing diacritic-insensitive comparisons. + +StringData get_string(Mixed const& m) { + if (m.is_null()) + return StringData(); + if (m.get_type() == type_String) + return m.get_string(); + auto b = m.get_binary(); + return StringData(b.data(), b.size()); +} + +bool equal(CFStringCompareFlags options, StringData v1, StringData v2) +{ + if (v1.is_null() || v2.is_null()) { + return v1.is_null() == v2.is_null(); + } + + auto s1 = util::adoptCF(CFStringCreateWithBytesNoCopy(kCFAllocatorSystemDefault, (const UInt8*)v1.data(), v1.size(), + kCFStringEncodingUTF8, false, kCFAllocatorNull)); + auto s2 = util::adoptCF(CFStringCreateWithBytesNoCopy(kCFAllocatorSystemDefault, (const UInt8*)v2.data(), v2.size(), + kCFStringEncodingUTF8, false, kCFAllocatorNull)); + + return CFStringCompare(s1.get(), s2.get(), options) == kCFCompareEqualTo; +} + +template +struct Equal { + using CaseSensitive = Equal; + using CaseInsensitive = Equal; + + bool operator()(Mixed v1, Mixed v2) const + { + return equal(options, get_string(v1), get_string(v2)); + } + + static const char* description() { return options & kCFCompareCaseInsensitive ? "==[cd]" : "==[d]"; } +}; + +template +struct NotEqual { + using CaseSensitive = NotEqual; + using CaseInsensitive = NotEqual; + + bool operator()(Mixed v1, Mixed v2) const + { + return !equal(options, get_string(v1), get_string(v2)); + } + + static const char* description() { return options & kCFCompareCaseInsensitive ? "!=[cd]" : "!=[d]"; } +}; + +bool contains_substring(CFStringCompareFlags options, StringData v1, StringData v2) +{ + if (v2.is_null()) { + // Everything contains NULL + return true; + } + + if (v1.is_null()) { + // NULL contains nothing (except NULL, handled above) + return false; + } + + if (v2.size() == 0) { + // Everything (except NULL, handled above) contains the empty string + return true; + } + + auto s1 = util::adoptCF(CFStringCreateWithBytesNoCopy(kCFAllocatorSystemDefault, (const UInt8*)v1.data(), v1.size(), + kCFStringEncodingUTF8, false, kCFAllocatorNull)); + auto s2 = util::adoptCF(CFStringCreateWithBytesNoCopy(kCFAllocatorSystemDefault, (const UInt8*)v2.data(), v2.size(), + kCFStringEncodingUTF8, false, kCFAllocatorNull)); + + return CFStringFind(s1.get(), s2.get(), options).location != kCFNotFound; +} + +template +struct ContainsSubstring { + using CaseSensitive = ContainsSubstring; + using CaseInsensitive = ContainsSubstring; + + bool operator()(Mixed v1, Mixed v2) const + { + return contains_substring(options, get_string(v1), get_string(v2)); + } + + static const char* description() { return options & kCFCompareCaseInsensitive ? "CONTAINS[cd]" : "CONTAINS[d]"; } +}; + + +NSString *operatorName(NSPredicateOperatorType operatorType) +{ + switch (operatorType) { + case NSLessThanPredicateOperatorType: + return @"<"; + case NSLessThanOrEqualToPredicateOperatorType: + return @"<="; + case NSGreaterThanPredicateOperatorType: + return @">"; + case NSGreaterThanOrEqualToPredicateOperatorType: + return @">="; + case NSEqualToPredicateOperatorType: + return @"=="; + case NSNotEqualToPredicateOperatorType: + return @"!="; + case NSMatchesPredicateOperatorType: + return @"MATCHES"; + case NSLikePredicateOperatorType: + return @"LIKE"; + case NSBeginsWithPredicateOperatorType: + return @"BEGINSWITH"; + case NSEndsWithPredicateOperatorType: + return @"ENDSWITH"; + case NSInPredicateOperatorType: + return @"IN"; + case NSContainsPredicateOperatorType: + return @"CONTAINS"; + case NSBetweenPredicateOperatorType: + return @"BETWEEN"; + case NSCustomSelectorPredicateOperatorType: + return @"custom selector"; + } + + return [NSString stringWithFormat:@"unknown operator %lu", (unsigned long)operatorType]; +} + +[[gnu::cold]] [[noreturn]] +void unsupportedOperator(RLMPropertyType datatype, NSPredicateOperatorType operatorType) { + throwException(@"Invalid operator type", + @"Operator '%@' not supported for type '%@'", + operatorName(operatorType), RLMTypeToString(datatype)); +} + +bool isNSNull(id value) { + return !value || value == NSNull.null; +} + +template +bool isNSNull(T) { + return false; +} + +Table& get_table(Group& group, RLMObjectSchema *objectSchema) +{ + return *ObjectStore::table_for_object_type(group, objectSchema.objectStoreName); +} + +// A reference to a column within a query. Can be resolved to a Columns for use in query expressions. +class ColumnReference { +public: + ColumnReference(Query& query, Group& group, RLMSchema *schema, RLMProperty* property, std::vector&& links = {}) + : m_links(std::move(links)), m_property(property), m_schema(schema), m_group(&group), m_query(&query), m_link_chain(query.get_table()) + { + for (const auto& link : m_links) { + if (link.type != RLMPropertyTypeLinkingObjects) { + m_link_chain.link(link.columnName.UTF8String); + } + else { + auto [link_origin_table, link_origin_column] = link_origin(link); + m_link_chain.backlink(link_origin_table, link_origin_column); + } + } + m_col = m_link_chain.get_current_table()->get_column_key(m_property.columnName.UTF8String); + } + + ColumnReference(Query& query, Group& group, RLMSchema *schema) + : m_schema(schema), m_group(&group), m_query(&query) + { + } + + template + auto resolve(SubQuery&&... subquery) const + { + static_assert(sizeof...(SubQuery) < 2, "resolve() takes at most one subquery"); + + // LinkChain::column() mutates it, so we need to make a copy + auto lc = m_link_chain; + if (type() != RLMPropertyTypeLinkingObjects) { + return lc.column(column(), std::forward(subquery)...); + } + + if constexpr (std::is_same_v) { + auto [table, col] = link_origin(m_property); + return lc.column(table, col, std::forward(subquery)...); + } + + REALM_TERMINATE("LinkingObjects property did not have column type Link"); + } + + RLMProperty *property() const { return m_property; } + ColKey column() const { return m_col; } + RLMPropertyType type() const { return property().type; } + + RLMObjectSchema *link_target_object_schema() const + { + REALM_ASSERT(is_link()); + return m_schema[property().objectClassName]; + } + + bool is_link() const noexcept { + return propertyTypeIsLink(type()); + } + + bool has_any_to_many_links() const { + return std::any_of(begin(m_links), end(m_links), + [](RLMProperty *property) { return property.collection; }); + } + + ColumnReference last_link_column() const { + REALM_ASSERT(!m_links.empty()); + return {*m_query, *m_group, m_schema, m_links.back(), {m_links.begin(), m_links.end() - 1}}; + } + + ColumnReference column_ignoring_links(Query& query) const { + return {query, *m_group, m_schema, m_property}; + } + + ColumnReference append(RLMProperty *prop) const { + auto links = m_links; + if (m_property) { + links.push_back(m_property); + } + return ColumnReference(*m_query, *m_group, m_schema, prop, std::move(links)); + } + + void validate_comparison(id value) const { + RLMPrecondition(isObjectValidForProperty(value, m_property), + @"Invalid value", @"Cannot compare value '%@' of type '%@' to property '%@' of type '%@'", + value, [value class], m_property.name, m_property.objectClassName ?: RLMTypeToString(m_property.type)); + if (RLMObjectBase *obj = RLMDynamicCast(value)) { + RLMPrecondition(!obj->_row.is_valid() || m_group == &obj->_realm.group, + @"Invalid value origin", @"Object must be from the Realm being queried"); + } + } + +private: + std::pair link_origin(RLMProperty *prop) const + { + RLMObjectSchema *link_origin_schema = m_schema[prop.objectClassName]; + Table& link_origin_table = get_table(*m_group, link_origin_schema); + NSString *column_name = link_origin_schema[prop.linkOriginPropertyName].columnName; + auto link_origin_column = link_origin_table.get_column_key(column_name.UTF8String); + return {link_origin_table, link_origin_column}; + } + + std::vector m_links; + RLMProperty *m_property; + RLMSchema *m_schema; + Group *m_group; + Query *m_query; + LinkChain m_link_chain; + ColKey m_col; +}; + +class CollectionOperation { +public: + enum Type { + None, + Count, + Minimum, + Maximum, + Sum, + Average, + // Dictionary specific. + AllKeys + }; + + CollectionOperation(Type type, ColumnReference&& link_column, ColumnReference&& column) + : m_type(type) + , m_link_column(std::move(link_column)) + , m_column(std::move(column)) + { + REALM_ASSERT(m_type != None); + } + + Type type() const { return m_type; } + const ColumnReference& link_column() const { return m_link_column; } + const ColumnReference& column() const { return m_column; } + + void validate_comparison(id value) const { + bool valid = true; + switch (m_type) { + case Count: + RLMPrecondition([value isKindOfClass:[NSNumber class]], @"Invalid operand", + @"%@ can only be compared with a numeric value.", name_for_type(m_type)); + return; + case Average: + case Minimum: + case Maximum: + // Null on min/max/average matches arrays with no non-null values, including on non-nullable types + valid = isNSNull(value) || isObjectValidForProperty(value, m_column.property()); + break; + case Sum: + // Sums are never null + valid = !isNSNull(value) && isObjectValidForProperty(value, m_column.property()); + break; + case AllKeys: + RLMPrecondition(isNSNull(value) || [value isKindOfClass:[NSString class]], @"Invalid operand", + @"@allKeys can only be compared with a string value."); + return; + case None: break; + } + RLMPrecondition(valid, @"Invalid operand", + @"%@ on a property of type %@ cannot be compared with '%@'", + name_for_type(m_type), RLMTypeToString(m_column.type()), value); + } + + void validate_comparison(const ColumnReference& column) const { + switch (m_type) { + case Count: + RLMPrecondition(propertyTypeIsNumeric(column.type()), @"Invalid operand", + @"%@ can only be compared with a numeric value.", name_for_type(m_type)); + break; + case Average: case Minimum: case Maximum: case Sum: + RLMPrecondition(propertyTypeIsNumeric(column.type()), @"Invalid operand", + @"%@ on a property of type %@ cannot be compared with property of type '%@'", + name_for_type(m_type), RLMTypeToString(m_column.type()), RLMTypeToString(column.type())); + break; + case AllKeys: + RLMPrecondition(column.type() == RLMPropertyTypeString, @"Invalid operand", + @"@allKeys can only be compared with a string value."); + break; + case None: break; + } + } + + static Type type_for_name(NSString *name) { + if ([name isEqualToString:@"@count"]) { + return Count; + } + if ([name isEqualToString:@"@min"]) { + return Minimum; + } + if ([name isEqualToString:@"@max"]) { + return Maximum; + } + if ([name isEqualToString:@"@sum"]) { + return Sum; + } + if ([name isEqualToString:@"@avg"]) { + return Average; + } + if ([name isEqualToString:@"@allKeys"]) { + return AllKeys; + } + return None; + } + +private: + static NSString *name_for_type(Type type) { + switch (type) { + case Count: return @"@count"; + case Minimum: return @"@min"; + case Maximum: return @"@max"; + case Sum: return @"@sum"; + case Average: return @"@avg"; + case AllKeys: return @"@allKeys"; + case None: REALM_UNREACHABLE(); + } + } + + Type m_type; + ColumnReference m_link_column; + ColumnReference m_column; +}; + +struct KeyPath; + +class QueryBuilder { +public: + QueryBuilder(Query& query, Group& group, RLMSchema *schema) + : m_query(query), m_group(group), m_schema(schema) { } + + void apply_predicate(NSPredicate *predicate, RLMObjectSchema *objectSchema); + + + void apply_collection_operator_expression(KeyPath&& kp, id value, NSComparisonPredicate *pred); + void apply_value_expression(KeyPath&& kp, id value, NSComparisonPredicate *pred); + void apply_column_expression(KeyPath&& left, KeyPath&& right, NSComparisonPredicate *predicate); + void apply_function_expression(RLMObjectSchema *objectSchema, NSExpression *functionExpression, + NSPredicateOperatorType operatorType, NSExpression *right); + void apply_map_expression(RLMObjectSchema *objectSchema, NSExpression *functionExpression, + NSComparisonPredicateOptions options, NSPredicateOperatorType operatorType, + NSExpression *right); + + template + void add_numeric_constraint(RLMPropertyType datatype, + NSPredicateOperatorType operatorType, + A&& lhs, B&& rhs); + + template + void add_bool_constraint(RLMPropertyType, NSPredicateOperatorType operatorType, A&& lhs, B&& rhs); + + template + void add_mixed_constraint(NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions predicateOptions, + Columns&& column, T value); + + template + void add_mixed_constraint(NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions predicateOptions, + Columns&& column, const ColumnReference& c); + + template + void do_add_mixed_constraint(NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions predicateOptions, + Columns&& column, Mixed&& value); + + template + void add_substring_constraint(const T& value, Query condition); + template + void add_substring_constraint(const Columns& value, Query condition); + + template + void add_string_constraint(NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions predicateOptions, + C&& column, T&& value); + + template + void add_diacritic_sensitive_string_constraint(NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions predicateOptions, + C&& column, T&& value); + template + void do_add_diacritic_sensitive_string_constraint(NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions predicateOptions, + C&& column, T&& value); + + template + void add_constraint(NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions predicateOptions, + ColumnReference const& column, R const& rhs); + template typename W, typename T> + void do_add_constraint(RLMPropertyType type, NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions predicateOptions, ColumnReference const& column, T&& value); + + void add_between_constraint(const ColumnReference& column, id value); + + void add_memberwise_equality_constraint(const ColumnReference& column, RLMObjectBase *obj); + + void add_link_constraint(NSPredicateOperatorType operatorType, const ColumnReference& column, RLMObjectBase *obj); + void add_link_constraint(NSPredicateOperatorType operatorType, const ColumnReference& column, realm::null); + void add_link_constraint(NSPredicateOperatorType, const ColumnReference&, const ColumnReference&); + + template + void add_collection_operation_constraint(NSPredicateOperatorType operatorType, + const CollectionOperation& collectionOperation, R&& rhs, + NSComparisonPredicateOptions comparisionOptions); + template + void add_collection_operation_constraint(NSPredicateOperatorType operatorType, + const CollectionOperation& collectionOperation, R&& rhs, + NSComparisonPredicateOptions comparisionOptions); + template + void add_collection_operation_constraint(NSPredicateOperatorType operatorType, + const CollectionOperation& collectionOperation, R&& rhs, + NSComparisonPredicateOptions comparisionOptions); + + + CollectionOperation collection_operation_from_key_path(KeyPath&& kp); + ColumnReference column_reference_from_key_path(KeyPath&& kp, bool isAggregate); + + +private: + Query& m_query; + Group& m_group; + RLMSchema *m_schema; +}; + +#pragma mark Numeric Constraints + +// add a clause for numeric constraints based on operator type +template +void QueryBuilder::add_numeric_constraint(RLMPropertyType datatype, + NSPredicateOperatorType operatorType, + A&& lhs, B&& rhs) +{ + switch (operatorType) { + case NSLessThanPredicateOperatorType: + m_query.and_query(lhs < rhs); + break; + case NSLessThanOrEqualToPredicateOperatorType: + m_query.and_query(lhs <= rhs); + break; + case NSGreaterThanPredicateOperatorType: + m_query.and_query(lhs > rhs); + break; + case NSGreaterThanOrEqualToPredicateOperatorType: + m_query.and_query(lhs >= rhs); + break; + case NSEqualToPredicateOperatorType: + m_query.and_query(lhs == rhs); + break; + case NSNotEqualToPredicateOperatorType: + m_query.and_query(lhs != rhs); + break; + default: + unsupportedOperator(datatype, operatorType); + } +} + +template +void QueryBuilder::add_bool_constraint(RLMPropertyType datatype, + NSPredicateOperatorType operatorType, + A&& lhs, B&& rhs) { + switch (operatorType) { + case NSEqualToPredicateOperatorType: + m_query.and_query(lhs == rhs); + break; + case NSNotEqualToPredicateOperatorType: + m_query.and_query(lhs != rhs); + break; + default: + unsupportedOperator(datatype, operatorType); + } +} + +#pragma mark String Constraints + +template +void QueryBuilder::add_substring_constraint(const T& value, Query condition) { + // Foundation always returns false for substring operations with a RHS of null or "". + m_query.and_query(value.size() + ? std::move(condition) + : std::unique_ptr(new FalseExpression)); +} + +template<> +void QueryBuilder::add_substring_constraint(const Mixed& value, Query condition) { + // Foundation always returns false for substring operations with a RHS of null or "". + m_query.and_query(value.get_string().size() + ? std::move(condition) + : std::unique_ptr(new FalseExpression)); +} + + +template +void QueryBuilder::add_substring_constraint(const Columns& value, Query condition) { + // Foundation always returns false for substring operations with a RHS of null or "". + // We don't need to concern ourselves with the possibility of value traversing a link list + // and producing multiple values per row as such expressions will have been rejected. + m_query.and_query(const_cast&>(value).size() != 0 && std::move(condition)); +} + +template +Query make_diacritic_insensitive_constraint(bool caseSensitive, std::unique_ptr left, std::unique_ptr right) { + using CompareCS = Compare; + using CompareCI = Compare; + if (caseSensitive) { + return make_expression(std::move(left), std::move(right)); + } + else { + return make_expression(std::move(left), std::move(right)); + } +}; + +Query make_diacritic_insensitive_constraint(NSPredicateOperatorType operatorType, bool caseSensitive, + std::unique_ptr left, std::unique_ptr right) { + switch (operatorType) { + case NSBeginsWithPredicateOperatorType: { + constexpr auto flags = kCFCompareDiacriticInsensitive | kCFCompareAnchored; + return make_diacritic_insensitive_constraint>(caseSensitive, std::move(left), std::move(right)); + } + case NSEndsWithPredicateOperatorType: { + constexpr auto flags = kCFCompareDiacriticInsensitive | kCFCompareAnchored | kCFCompareBackwards; + return make_diacritic_insensitive_constraint>(caseSensitive, std::move(left), std::move(right)); + } + case NSContainsPredicateOperatorType: { + constexpr auto flags = kCFCompareDiacriticInsensitive; + return make_diacritic_insensitive_constraint>(caseSensitive, std::move(left), std::move(right)); + } + default: + REALM_COMPILER_HINT_UNREACHABLE(); + } +} + +template +void QueryBuilder::do_add_diacritic_sensitive_string_constraint(NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions predicateOptions, + C&& column, T&& value) { + bool caseSensitive = !(predicateOptions & NSCaseInsensitivePredicateOption); + switch (operatorType) { + case NSBeginsWithPredicateOperatorType: + add_substring_constraint(value, column.begins_with(value, caseSensitive)); + break; + case NSEndsWithPredicateOperatorType: + add_substring_constraint(value, column.ends_with(value, caseSensitive)); + break; + case NSContainsPredicateOperatorType: + add_substring_constraint(value, column.contains(value, caseSensitive)); + break; + case NSEqualToPredicateOperatorType: + m_query.and_query(column.equal(value, caseSensitive)); + break; + case NSNotEqualToPredicateOperatorType: + m_query.and_query(column.not_equal(value, caseSensitive)); + break; + case NSLikePredicateOperatorType: + m_query.and_query(column.like(value, caseSensitive)); + break; + default: { + if constexpr (is_any_v, Columns>, Columns>>) { + unsupportedOperator(RLMPropertyTypeString, operatorType); + } + else if constexpr (is_any_v, Columns>, Columns>>) { + unsupportedOperator(RLMPropertyTypeData, operatorType); + } + else if constexpr (is_any_v, Columns>, Columns>>) { + unsupportedOperator(RLMPropertyTypeAny, operatorType); + } + else if constexpr (is_any_v>) { + // The underlying storage type Dictionary is always Mixed. This creates an issue + // where we cannot be descriptive about the exception as we do not know + // the actual value type. + throwException(@"Invalid operand type", + @"Operator '%@' not supported for string queries on Dictionary.", + operatorName(operatorType)); + } + } + } +} + +template +void QueryBuilder::add_diacritic_sensitive_string_constraint(NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions predicateOptions, + C&& column, T&& value) { + if constexpr (is_any_v>) { + // This nesting isnt pretty but without it the compiler will complain about `T` having no known + // conversion from Columns to Mixed. This is due to the fact that all values on a + // dictionary column are boxed in Mixed. + if constexpr (is_any_v) { + do_add_diacritic_sensitive_string_constraint(operatorType, predicateOptions, std::forward(column), value); + } + } + else { + do_add_diacritic_sensitive_string_constraint(operatorType, predicateOptions, std::forward(column), value); + } +} + +template +void QueryBuilder::add_string_constraint(NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions predicateOptions, + C&& column, T&& value) { + if (!(predicateOptions & NSDiacriticInsensitivePredicateOption)) { + add_diacritic_sensitive_string_constraint(operatorType, predicateOptions, std::forward(column), std::move(value)); + return; + } + + auto as_subexpr = util::overload{ + [](StringData value) { return make_subexpr(value); }, + [](BinaryData value) { return make_subexpr(StringData(value.data(), value.size())); }, + [](Mixed value) { + // When Mixed is null calling `get_type` will throw an exception. + if (value.is_null()) + return make_subexpr(value.get_string()); + switch (value.get_type()) { + case DataType::Type::String: + return make_subexpr(value.get_string()); + case DataType::Type::Binary: + return make_subexpr(StringData(value.get_binary().data(), value.get_binary().size())); + default: + REALM_UNREACHABLE(); + } + }, + [](auto& c) { return c.clone(); } + }; + auto left = as_subexpr(column); + auto right = as_subexpr(value); + + bool caseSensitive = !(predicateOptions & NSCaseInsensitivePredicateOption); + constexpr auto flags = kCFCompareDiacriticInsensitive | kCFCompareAnchored; + switch (operatorType) { + case NSBeginsWithPredicateOperatorType: + case NSEndsWithPredicateOperatorType: + case NSContainsPredicateOperatorType: + add_substring_constraint(value, make_diacritic_insensitive_constraint(operatorType, caseSensitive, std::move(left), std::move(right))); + break; + case NSNotEqualToPredicateOperatorType: + m_query.and_query(make_diacritic_insensitive_constraint>(caseSensitive, std::move(left), std::move(right))); + break; + case NSEqualToPredicateOperatorType: + m_query.and_query(make_diacritic_insensitive_constraint>(caseSensitive, std::move(left), std::move(right))); + break; + case NSLikePredicateOperatorType: + throwException(@"Invalid operator type", + @"Operator 'LIKE' not supported with diacritic-insensitive modifier."); + default: + unsupportedOperator(RLMPropertyTypeString, operatorType); + } +} + +id value_from_constant_expression_or_value(id value) { + if (NSExpression *exp = RLMDynamicCast(value)) { + RLMPrecondition(exp.expressionType == NSConstantValueExpressionType, + @"Invalid value", + @"Expressions within predicate aggregates must be constant values"); + return exp.constantValue; + } + return value; +} + +void validate_and_extract_between_range(id value, RLMProperty *prop, id *from, id *to) { + NSArray *array = RLMDynamicCast(value); + RLMPrecondition(array, @"Invalid value", @"object must be of type NSArray for BETWEEN operations"); + RLMPrecondition(array.count == 2, @"Invalid value", @"NSArray object must contain exactly two objects for BETWEEN operations"); + + *from = value_from_constant_expression_or_value(array.firstObject); + *to = value_from_constant_expression_or_value(array.lastObject); + RLMPrecondition(isObjectValidForProperty(*from, prop) && isObjectValidForProperty(*to, prop), + @"Invalid value", + @"NSArray objects must be of type %@ for BETWEEN operations", RLMTypeToString(prop.type)); +} + +#pragma mark Between Constraint + +void QueryBuilder::add_between_constraint(const ColumnReference& column, id value) { + if (column.has_any_to_many_links()) { + auto link_column = column.last_link_column(); + Query subquery = get_table(m_group, link_column.link_target_object_schema()).where(); + QueryBuilder(subquery, m_group, m_schema).add_between_constraint(column.column_ignoring_links(subquery), value); + + m_query.and_query(link_column.resolve(std::move(subquery)).count() > 0); + return; + } + + id from, to; + validate_and_extract_between_range(value, column.property(), &from, &to); + + if (!propertyTypeIsNumeric(column.type())) { + return unsupportedOperator(column.type(), NSBetweenPredicateOperatorType); + } + + m_query.group(); + add_constraint(NSGreaterThanOrEqualToPredicateOperatorType, 0, column, from); + add_constraint(NSLessThanOrEqualToPredicateOperatorType, 0, column, to); + m_query.end_group(); +} + +#pragma mark Link Constraints + +void QueryBuilder::add_memberwise_equality_constraint(const ColumnReference& column, RLMObjectBase *obj) { + for (RLMProperty *property in obj->_objectSchema.properties) { + // Both of these probably are implementable, but are significantly more complicated. + RLMPrecondition(!property.collection, @"Invalid predicate", + @"Unsupported property '%@.%@' for memberwise equality query: equality on collections is not implemented.", + obj->_objectSchema.className, property.name); + RLMPrecondition(!propertyTypeIsLink(property.type), @"Invalid predicate", + @"Unsupported property '%@.%@' for memberwise equality query: object links are not implemented.", + obj->_objectSchema.className, property.name); + add_constraint(NSEqualToPredicateOperatorType, 0, column.append(property), RLMDynamicGet(obj, property)); + } +} + +void QueryBuilder::add_link_constraint(NSPredicateOperatorType operatorType, + const ColumnReference& column, RLMObjectBase *obj) { + // If the value isn't actually a RLMObject then it's something which bridges + // to RLMObject, i.e. a custom type mapping to an embedded object. For those + // we want to perform memberwise equality rather than equality on the link itself. + if (![obj isKindOfClass:[RLMObjectBase class]]) { + obj = RLMBridgeSwiftValue(obj); + REALM_ASSERT([obj isKindOfClass:[RLMObjectBase class]]); + + // Collections need to use subqueries, but unary links can just use a + // group. Unary links could also use a subquery but that has worse performance. + if (column.property().collection) { + Query subquery = get_table(m_group, column.link_target_object_schema()).where(); + QueryBuilder(subquery, m_group, m_schema) + .add_memberwise_equality_constraint(ColumnReference(subquery, m_group, m_schema), obj); + if (operatorType == NSEqualToPredicateOperatorType) { + m_query.and_query(column.resolve(std::move(subquery)).count() > 0); + } + else { + // This strange condition is because "ANY list != x" isn't + // "NONE list == x"; there must be an object in the list for + // this to match + m_query.and_query(column.resolve().count() > 0 && + column.resolve(std::move(subquery)).count() == 0); + } + } + else { + if (operatorType == NSNotEqualToPredicateOperatorType) { + m_query.Not(); + } + + m_query.group(); + add_memberwise_equality_constraint(column, obj); + m_query.end_group(); + } + return; + } + + if (!obj->_row.is_valid()) { + // Unmanaged or deleted objects are not equal to any managed objects. + // For arrays this effectively checks if there are any objects in the + // array, while for links it's just always constant true or false + // (for != and = respectively). + if (column.has_any_to_many_links() || column.property().collection) { + add_link_constraint(operatorType, column, null()); + } + else if (operatorType == NSEqualToPredicateOperatorType) { + m_query.and_query(std::unique_ptr(new FalseExpression)); + } + else { + m_query.and_query(std::unique_ptr(new TrueExpression)); + } + } + else { + if (column.property().dictionary) { + add_bool_constraint(RLMPropertyTypeObject, operatorType, column.resolve(), obj->_row); + } + else { + add_bool_constraint(RLMPropertyTypeObject, operatorType, column.resolve(), obj->_row); + } + } +} + +void QueryBuilder::add_link_constraint(NSPredicateOperatorType operatorType, + const ColumnReference& column, realm::null) { + if (column.property().dictionary) { + add_bool_constraint(RLMPropertyTypeObject, operatorType, column.resolve(), null()); + } + else { + add_bool_constraint(RLMPropertyTypeObject, operatorType, column.resolve(), null()); + } +} + +void QueryBuilder::add_link_constraint(NSPredicateOperatorType operatorType, + const ColumnReference& a, const ColumnReference& b) { + if (a.property().dictionary) { + add_bool_constraint(RLMPropertyTypeObject, operatorType, a.resolve(), b.resolve()); + } + else { + add_bool_constraint(RLMPropertyTypeObject, operatorType, a.resolve(), b.resolve()); + } +} + +// iterate over an array of subpredicates, using @func to build a query from each +// one and ORing them together +template +void process_or_group(Query &query, id array, Func&& func) { + array = RLMAsFastEnumeration(array); + RLMPrecondition(array, @"Invalid value", @"IN clause requires an array of items"); + + query.group(); + + bool first = true; + for (id item in array) { + if (!first) { + query.Or(); + } + first = false; + + func(item); + } + + if (first) { + // Queries can't be empty, so if there's zero things in the OR group + // validation will fail. Work around this by adding an expression which + // will never find any rows in a table. + query.and_query(std::unique_ptr(new FalseExpression)); + } + + query.end_group(); +} + +#pragma mark Conversion Helpers + +template +realm::null value_of_type(realm::null) { + return realm::null(); +} + +template +auto value_of_type(__unsafe_unretained const id value) { + return RLMStatelessAccessorContext::unbox(value); +} + +template <> +auto value_of_type(id value) { + return RLMObjcToMixed(value, nil, CreatePolicy::Skip); +} + +template +auto value_of_type(const ColumnReference& column) { + return column.resolve(); +} + +template +void convert_null(T&& value, Fn&& fn) { + if (isNSNull(value)) { + fn(null()); + } + else { + fn(value); + } +} + +template typename W, typename T> +void QueryBuilder::do_add_constraint(RLMPropertyType type, NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions predicateOptions, ColumnReference const& column, T&& value) +{ + switch (type) { + case RLMPropertyTypeBool: + convert_null(value, [&](auto&& value) { + add_bool_constraint(type, operatorType, column.resolve>(), + value_of_type(value)); + }); + break; + case RLMPropertyTypeObjectId: + convert_null(value, [&](auto&& value) { + add_bool_constraint(type, operatorType, column.resolve>(), + value_of_type(value)); + }); + break; + case RLMPropertyTypeDate: + convert_null(value, [&](auto&& value) { + add_numeric_constraint(type, operatorType, column.resolve>(), + value_of_type(value)); + }); + break; + case RLMPropertyTypeDouble: + convert_null(value, [&](auto&& value) { + add_numeric_constraint(type, operatorType, column.resolve>(), + value_of_type(value)); + }); + break; + case RLMPropertyTypeFloat: + convert_null(value, [&](auto&& value) { + add_numeric_constraint(type, operatorType, column.resolve>(), + value_of_type(value)); + }); + break; + case RLMPropertyTypeInt: + convert_null(value, [&](auto&& value) { + add_numeric_constraint(type, operatorType, column.resolve>(), + value_of_type(value)); + }); + break; + case RLMPropertyTypeDecimal128: + convert_null(value, [&](auto&& value) { + add_numeric_constraint(type, operatorType, column.resolve>(), + value_of_type(value)); + }); + break; + case RLMPropertyTypeString: + add_string_constraint(operatorType, predicateOptions, column.resolve>(), + value_of_type(value)); + break; + case RLMPropertyTypeData: + add_string_constraint(operatorType, predicateOptions, + column.resolve>(), + value_of_type(value)); + break; + case RLMPropertyTypeObject: + case RLMPropertyTypeLinkingObjects: + convert_null(value, [&](auto&& value) { + add_link_constraint(operatorType, column, value); + }); + break; + case RLMPropertyTypeUUID: + convert_null(value, [&](auto&& value) { + add_bool_constraint(type, operatorType, column.resolve>(), + value_of_type(value)); + }); + break; + case RLMPropertyTypeAny: + convert_null(value, [&](auto&& value) { + add_mixed_constraint(operatorType, + predicateOptions, + column.resolve>(), + value); + }); + } +} + +#pragma mark Mixed Constraints + +template +void QueryBuilder::add_mixed_constraint(NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions predicateOptions, + Columns&& column, + T value) +{ + // Handle cases where a string might be '1' or '0'. Without this the string + // will be boxed as a bool and thus string query operations will crash in core. + if constexpr(std::is_same_v) { + if (auto str = RLMDynamicCast(value)) { + add_string_constraint(operatorType, predicateOptions, + std::move(column), realm::Mixed([str UTF8String])); + return; + } + } + do_add_mixed_constraint(operatorType, predicateOptions, + std::move(column), value_of_type(value)); +} + +template +void QueryBuilder::do_add_mixed_constraint(NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions predicateOptions, + Columns&& column, + Mixed&& value) +{ + switch (operatorType) { + case NSLessThanPredicateOperatorType: + m_query.and_query(column < value); + break; + case NSLessThanOrEqualToPredicateOperatorType: + m_query.and_query(column <= value); + break; + case NSGreaterThanPredicateOperatorType: + m_query.and_query(column > value); + break; + case NSGreaterThanOrEqualToPredicateOperatorType: + m_query.and_query(column >= value); + break; + case NSEqualToPredicateOperatorType: + m_query.and_query(column == value); + break; + case NSNotEqualToPredicateOperatorType: + m_query.and_query(column != value); + break; + // String comparison operators: There isn't a way for a string value + // to get down here, but a rhs of NULL can + case NSLikePredicateOperatorType: + case NSMatchesPredicateOperatorType: + case NSBeginsWithPredicateOperatorType: + case NSEndsWithPredicateOperatorType: + case NSContainsPredicateOperatorType: + add_string_constraint(operatorType, predicateOptions, + std::move(column), value); + break; + default: + break; + } +} + +template +void QueryBuilder::add_mixed_constraint(NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions, + Columns&& column, + const ColumnReference& value) +{ + add_bool_constraint(RLMPropertyTypeObject, operatorType, column, value.resolve()); +} + +template +using Identity = T; +template +using AlwaysDictionary = Dictionary; + +template +void QueryBuilder::add_constraint(NSPredicateOperatorType operatorType, + NSComparisonPredicateOptions predicateOptions, ColumnReference const& column, R const& rhs) +{ + auto type = column.type(); + if (column.property().array) { + do_add_constraint(type, operatorType, predicateOptions, column, rhs); + } + else if (column.property().set) { + do_add_constraint(type, operatorType, predicateOptions, column, rhs); + } + else if (column.property().dictionary) { + do_add_constraint(type, operatorType, predicateOptions, column, rhs); + } + else { + do_add_constraint(type, operatorType, predicateOptions, column, rhs); + } +} + +struct KeyPath { + std::vector links; + RLMProperty *property; + CollectionOperation::Type collectionOperation; + bool containsToManyRelationship; +}; + +KeyPath key_path_from_string(RLMSchema *schema, RLMObjectSchema *objectSchema, NSString *keyPath) +{ + RLMProperty *property; + std::vector links; + + CollectionOperation::Type collectionOperation = CollectionOperation::None; + NSString *collectionOperationName; + bool keyPathContainsToManyRelationship = false; + + NSUInteger start = 0, length = keyPath.length, end = length; + for (; end != NSNotFound; start = end + 1) { + end = [keyPath rangeOfString:@"." options:0 range:{start, length - start}].location; + RLMPrecondition(end == NSNotFound || end + 1 < length, @"Invalid predicate", + @"Invalid keypath '%@': no key name after last '.'", keyPath); + RLMPrecondition(end > start, @"Invalid predicate", + @"Invalid keypath '%@': no key name before '.'", keyPath); + + NSString *propertyName = [keyPath substringWithRange:{start, end == NSNotFound ? length - start : end - start}]; + + if ([propertyName characterAtIndex:0] == '@') { + if ([propertyName isEqualToString:@"@allValues"]) { + RLMPrecondition(property.dictionary, @"Invalid predicate", + @"Invalid keypath '%@': @allValues must follow a dictionary property.", keyPath); + continue; + } + RLMPrecondition(collectionOperation == CollectionOperation::None, @"Invalid predicate", + @"Invalid keypath '%@': at most one collection operation per keypath is supported.", keyPath); + collectionOperation = CollectionOperation::type_for_name(propertyName); + RLMPrecondition(collectionOperation != CollectionOperation::None, @"Invalid predicate", + @"Invalid keypath '%@': Unsupported collection operation '%@'", keyPath, propertyName); + + RLMPrecondition(property.collection, @"Invalid predicate", + @"Invalid keypath '%@': collection operation '%@' must be applied to a collection", keyPath, propertyName); + switch (collectionOperation) { + case CollectionOperation::None: + REALM_UNREACHABLE(); + case CollectionOperation::Count: + RLMPrecondition(end == NSNotFound, @"Invalid predicate", + @"Invalid keypath '%@': @count must appear at the end of a keypath.", keyPath); + break; + case CollectionOperation::AllKeys: + RLMPrecondition(end == NSNotFound, @"Invalid predicate", + @"Invalid keypath '%@': @allKeys must appear at the end of a keypath.", keyPath); + RLMPrecondition(property.dictionary, @"Invalid predicate", + @"Invalid keypath '%@': @allKeys must follow a dictionary property.", keyPath); + break; + default: + if (propertyTypeIsLink(property.type)) { + RLMPrecondition(end != NSNotFound, @"Invalid predicate", + @"Invalid keypath '%@': %@ on a collection of objects cannot appear at the end of a keypath.", keyPath, propertyName); + } + else { + RLMPrecondition(end == NSNotFound, @"Invalid predicate", + @"Invalid keypath '%@': %@ on a collection of values must appear at the end of a keypath.", keyPath, propertyName); + RLMPrecondition(propertyTypeIsNumeric(property.type), @"Invalid predicate", + @"Invalid keypath '%@': %@ can only be applied to a collection of numeric values.", keyPath, propertyName); + } + } + collectionOperationName = propertyName; + continue; + } + + RLMPrecondition(objectSchema, @"Invalid predicate", + @"Invalid keypath '%@': %@ property %@ can only be followed by a collection operation.", + keyPath, property.typeName, property.name); + + property = objectSchema[propertyName]; + RLMPrecondition(property, @"Invalid predicate", + @"Invalid keypath '%@': Property '%@' not found in object of type '%@'", + keyPath, propertyName, objectSchema.className); + RLMPrecondition(collectionOperation == CollectionOperation::None || (propertyTypeIsNumeric(property.type) && !property.collection), + @"Invalid predicate", + @"Invalid keypath '%@': %@ must be followed by a numeric property.", keyPath, collectionOperationName); + + if (property.collection) + keyPathContainsToManyRelationship = true; + + links.push_back(property); + + if (end != NSNotFound) { + RLMPrecondition(property.type == RLMPropertyTypeObject || property.type == RLMPropertyTypeLinkingObjects || property.collection, + @"Invalid predicate", @"Invalid keypath '%@': Property '%@.%@' is not a link or collection and can only appear at the end of a keypath.", + keyPath, objectSchema.className, propertyName); + objectSchema = property.objectClassName ? schema[property.objectClassName] : nil; + } + }; + + links.pop_back(); + return {std::move(links), property, collectionOperation, keyPathContainsToManyRelationship}; +} + +ColumnReference QueryBuilder::column_reference_from_key_path(KeyPath&& kp, bool isAggregate) +{ + if (isAggregate && !kp.containsToManyRelationship) { + throwException(@"Invalid predicate", + @"Aggregate operations can only be used on key paths that include an collection property"); + } else if (!isAggregate && kp.containsToManyRelationship) { + throwException(@"Invalid predicate", + @"Key paths that include a collection property must use aggregate operations"); + } + + return ColumnReference(m_query, m_group, m_schema, kp.property, std::move(kp.links)); +} + +#pragma mark Collection Operations + +// static_assert is always evaluated even if it's inside a if constexpr +// unless the value is derived from the template argument, in which case it's +// only evaluated if that branch is active +template struct AlwaysFalse : std::false_type {}; + +template +auto collection_operation_expr_2(Column&& column) { + if constexpr (OperationType == CollectionOperation::Minimum) { + return column.min(); + } + else if constexpr (OperationType == CollectionOperation::Maximum) { + return column.max(); + } + else if constexpr (OperationType == CollectionOperation::Sum) { + return column.sum(); + } + else if constexpr (OperationType == CollectionOperation::Average) { + return column.average(); + } + else { + static_assert(AlwaysFalse::value, "invalid operation type"); + } +} + +template +auto collection_operation_expr(CollectionOperation operation) { + REALM_ASSERT(operation.type() == OperationType); + + if constexpr (IsLinkCollection) { + auto&& resolved = operation.link_column().resolve(); + auto col = operation.column().column(); + return collection_operation_expr_2(resolved.template column(col)); + } + else if constexpr (IsDictionary) { + return collection_operation_expr_2(operation.link_column().resolve()); + } + else { + return collection_operation_expr_2(operation.link_column().resolve>()); + } +} + +template +void QueryBuilder::add_collection_operation_constraint(NSPredicateOperatorType operatorType, + CollectionOperation const& collectionOperation, R&& rhs, + NSComparisonPredicateOptions) +{ + auto type = IsLinkCollection ? collectionOperation.column().type() : collectionOperation.link_column().type(); + + switch (type) { + case RLMPropertyTypeInt: + add_numeric_constraint(type, operatorType, + collection_operation_expr(collectionOperation), + value_of_type(rhs)); + break; + case RLMPropertyTypeFloat: + add_numeric_constraint(type, operatorType, + collection_operation_expr(collectionOperation), + value_of_type(rhs)); + break; + case RLMPropertyTypeDouble: + add_numeric_constraint(type, operatorType, + collection_operation_expr(collectionOperation), + value_of_type(rhs)); + break; + case RLMPropertyTypeDecimal128: + add_numeric_constraint(type, operatorType, + collection_operation_expr(collectionOperation), + value_of_type(rhs)); + break; + case RLMPropertyTypeDate: + if constexpr (Operation == CollectionOperation::Sum || Operation == CollectionOperation::Average) { + throwException(@"Unsupported predicate value type", + @"Cannot sum or average date properties"); + } + else { + add_numeric_constraint(type, operatorType, + collection_operation_expr(collectionOperation), + value_of_type(rhs)); + } + break; + case RLMPropertyTypeAny: + add_numeric_constraint(type, operatorType, + collection_operation_expr(collectionOperation), + value_of_type(rhs)); + break; + default: + REALM_ASSERT(false && "Only numeric property types should hit this path."); + } +} + +template +void QueryBuilder::add_collection_operation_constraint(NSPredicateOperatorType operatorType, + CollectionOperation const& collectionOperation, R&& rhs, + NSComparisonPredicateOptions options) +{ + convert_null(rhs, [&](auto&& rhs) { + if (collectionOperation.link_column().is_link()) { + add_collection_operation_constraint(operatorType, collectionOperation, std::move(rhs), options); + } + else if (collectionOperation.column().property().dictionary) { + add_collection_operation_constraint(operatorType, collectionOperation, std::move(rhs), options); + } + else { + add_collection_operation_constraint(operatorType, collectionOperation, std::move(rhs), options); + } + }); +} + +template +void get_collection_type(__unsafe_unretained RLMProperty *prop, Fn&& fn) { + if (prop.array) { + fn((Lst*)0); + } + else if (prop.set) { + fn((Set*)0); + } + else { + fn((Dictionary*)0); + } +} + +template +void QueryBuilder::add_collection_operation_constraint(NSPredicateOperatorType operatorType, + CollectionOperation const& collectionOperation, R&& rhs, + NSComparisonPredicateOptions comparisonOptions) +{ + switch (collectionOperation.type()) { + case CollectionOperation::None: + break; + case CollectionOperation::Count: { + auto& column = collectionOperation.link_column(); + RLMPropertyType type = column.type(); + auto rhsValue = value_of_type(rhs); + auto continuation = [&](auto t) { + add_numeric_constraint(type, operatorType, column.resolve>().size(), rhsValue); + }; + + switch (type) { + case RLMPropertyTypeBool: + return get_collection_type(column.property(), std::move(continuation)); + case RLMPropertyTypeObjectId: + return get_collection_type(column.property(), std::move(continuation)); + case RLMPropertyTypeDate: + return get_collection_type(column.property(), std::move(continuation)); + case RLMPropertyTypeDouble: + return get_collection_type(column.property(), std::move(continuation)); + case RLMPropertyTypeFloat: + return get_collection_type(column.property(), std::move(continuation)); + case RLMPropertyTypeInt: + return get_collection_type(column.property(), std::move(continuation)); + case RLMPropertyTypeDecimal128: + return get_collection_type(column.property(), std::move(continuation)); + case RLMPropertyTypeString: + return get_collection_type(column.property(), std::move(continuation)); + case RLMPropertyTypeData: + return get_collection_type(column.property(), std::move(continuation)); + case RLMPropertyTypeUUID: + return get_collection_type(column.property(), std::move(continuation)); + case RLMPropertyTypeAny: + return get_collection_type(column.property(), std::move(continuation)); + case RLMPropertyTypeObject: + case RLMPropertyTypeLinkingObjects: + return add_numeric_constraint(type, operatorType, column.resolve().count(), rhsValue); + } + } + case CollectionOperation::Minimum: + add_collection_operation_constraint(operatorType, collectionOperation, std::move(rhs), comparisonOptions); + break; + case CollectionOperation::Maximum: + add_collection_operation_constraint(operatorType, collectionOperation, std::move(rhs), comparisonOptions); + break; + case CollectionOperation::Sum: + add_collection_operation_constraint(operatorType, collectionOperation, std::move(rhs), comparisonOptions); + break; + case CollectionOperation::Average: + add_collection_operation_constraint(operatorType, collectionOperation, std::move(rhs), comparisonOptions); + break; + case CollectionOperation::AllKeys: { + // BETWEEN and IN are not supported by @allKeys as the parsing for collection + // operators happens before and disection of a rhs array of values. + add_string_constraint(operatorType, comparisonOptions, + Columns(collectionOperation.link_column().column(), m_query.get_table()).keys(), + value_of_type(rhs)); + break; + } + } +} + +bool key_path_contains_collection_operator(const KeyPath& kp) { + return kp.collectionOperation != CollectionOperation::None; +} + +CollectionOperation QueryBuilder::collection_operation_from_key_path(KeyPath&& kp) { + // Collection operations can either come at the end, or immediately before + // the last property. Count and AllKeys are always the end, while + // min/max/sum/avg are at the end for collections of primitives and one + // before the end for collections of objects (with the aggregate done on a + // property of those objects). For one-before-the-end we need to construct + // a KeyPath to both the final link and the final property. + KeyPath linkPrefix = kp; + if (kp.collectionOperation != CollectionOperation::Count && kp.collectionOperation != CollectionOperation::AllKeys && !kp.property.collection) { + REALM_ASSERT(!kp.links.empty()); + linkPrefix.property = linkPrefix.links.back(); + linkPrefix.links.pop_back(); + } + return CollectionOperation(kp.collectionOperation, column_reference_from_key_path(std::move(linkPrefix), true), + column_reference_from_key_path(std::move(kp), true)); +} + +NSPredicateOperatorType invert_comparison_operator(NSPredicateOperatorType type) { + switch (type) { + case NSLessThanPredicateOperatorType: + return NSGreaterThanPredicateOperatorType; + case NSLessThanOrEqualToPredicateOperatorType: + return NSGreaterThanOrEqualToPredicateOperatorType; + case NSGreaterThanPredicateOperatorType: + return NSLessThanPredicateOperatorType; + case NSGreaterThanOrEqualToPredicateOperatorType: + return NSLessThanOrEqualToPredicateOperatorType; + case NSBeginsWithPredicateOperatorType: + case NSEndsWithPredicateOperatorType: + case NSContainsPredicateOperatorType: + case NSLikePredicateOperatorType: + throwException(@"Unsupported predicate", @"Operator '%@' requires a keypath on the left side.", operatorName(type)); + default: + return type; + } +} + +void QueryBuilder::apply_collection_operator_expression(KeyPath&& kp, id value, + NSComparisonPredicate *pred) { + CollectionOperation operation = collection_operation_from_key_path(std::move(kp)); + operation.validate_comparison(value); + + auto type = pred.predicateOperatorType; + if (pred.leftExpression.expressionType != NSKeyPathExpressionType) { + // Turn "a > b" into "b < a" so that we can always put the column on the lhs + type = invert_comparison_operator(type); + } + add_collection_operation_constraint(type, operation, value, pred.options); +} + +void QueryBuilder::apply_value_expression(KeyPath&& kp, id value, NSComparisonPredicate *pred) +{ + if (key_path_contains_collection_operator(kp)) { + apply_collection_operator_expression(std::move(kp), value, pred); + return; + } + + bool isAny = pred.comparisonPredicateModifier == NSAnyPredicateModifier; + ColumnReference column = column_reference_from_key_path(std::move(kp), isAny); + + // check to see if this is a between query + if (pred.predicateOperatorType == NSBetweenPredicateOperatorType) { + add_between_constraint(std::move(column), value); + return; + } + + // turn "key.path IN collection" into ored together ==. "collection IN key.path" is handled elsewhere. + if (pred.predicateOperatorType == NSInPredicateOperatorType) { + process_or_group(m_query, value, [&](id item) { + id normalized = value_from_constant_expression_or_value(item); + column.validate_comparison(normalized); + add_constraint(NSEqualToPredicateOperatorType, pred.options, column, normalized); + }); + return; + } + + column.validate_comparison(value); + if (pred.leftExpression.expressionType == NSKeyPathExpressionType) { + add_constraint(pred.predicateOperatorType, pred.options, std::move(column), value); + } else { + add_constraint(invert_comparison_operator(pred.predicateOperatorType), pred.options, std::move(column), value); + } +} + +void QueryBuilder::apply_column_expression(KeyPath&& leftKeyPath, KeyPath&& rightKeyPath, NSComparisonPredicate *predicate) +{ + bool left_key_path_contains_collection_operator = key_path_contains_collection_operator(leftKeyPath); + bool right_key_path_contains_collection_operator = key_path_contains_collection_operator(rightKeyPath); + if (left_key_path_contains_collection_operator && right_key_path_contains_collection_operator) { + throwException(@"Unsupported predicate", @"Key paths including aggregate operations cannot be compared with other aggregate operations."); + } + + if (left_key_path_contains_collection_operator) { + CollectionOperation left = collection_operation_from_key_path(std::move(leftKeyPath)); + ColumnReference right = column_reference_from_key_path(std::move(rightKeyPath), false); + left.validate_comparison(right); + add_collection_operation_constraint(predicate.predicateOperatorType, std::move(left), std::move(right), predicate.options); + return; + } + if (right_key_path_contains_collection_operator) { + ColumnReference left = column_reference_from_key_path(std::move(leftKeyPath), false); + CollectionOperation right = collection_operation_from_key_path(std::move(rightKeyPath)); + right.validate_comparison(left); + add_collection_operation_constraint(invert_comparison_operator(predicate.predicateOperatorType), + std::move(right), std::move(left), predicate.options); + return; + } + + bool isAny = false; + ColumnReference left = column_reference_from_key_path(std::move(leftKeyPath), isAny); + ColumnReference right = column_reference_from_key_path(std::move(rightKeyPath), isAny); + + // NOTE: It's assumed that column type must match and no automatic type conversion is supported. + RLMPrecondition(left.type() == right.type(), + RLMPropertiesComparisonTypeMismatchException, + RLMPropertiesComparisonTypeMismatchReason, + RLMTypeToString(left.type()), + RLMTypeToString(right.type())); + + // TODO: Should we handle special case where left row is the same as right row (tautology) + add_constraint(predicate.predicateOperatorType, predicate.options, + std::move(left), std::move(right)); +} + +// Identify expressions of the form [SELF valueForKeyPath:] +bool is_self_value_for_key_path_function_expression(NSExpression *expression) +{ + if (expression.expressionType != NSFunctionExpressionType) + return false; + + if (expression.operand.expressionType != NSEvaluatedObjectExpressionType) + return false; + + return [expression.function isEqualToString:@"valueForKeyPath:"]; +} + +// -[NSPredicate predicateWithSubtitutionVariables:] results in function expressions of the form [SELF valueForKeyPath:] +// that apply_predicate cannot handle. Replace such expressions with equivalent NSKeyPathExpressionType expressions. +NSExpression *simplify_self_value_for_key_path_function_expression(NSExpression *expression) { + if (is_self_value_for_key_path_function_expression(expression)) { + if (NSString *keyPath = [expression.arguments.firstObject keyPath]) { + return [NSExpression expressionForKeyPath:keyPath]; + } + } + return expression; +} + +void QueryBuilder::apply_map_expression(RLMObjectSchema *objectSchema, NSExpression *functionExpression, + NSComparisonPredicateOptions options, NSPredicateOperatorType operatorType, + NSExpression *right) { + NSString *keyPath; + NSString *mapKey; + if (functionExpression.operand.expressionType == NSKeyPathExpressionType) { + NSExpression *mapItems = [functionExpression.arguments firstObject]; + NSExpression *linkCol = [[functionExpression.operand arguments] firstObject]; + NSExpression *mapCol = [mapItems.arguments firstObject]; + mapKey = [mapItems.arguments[1] constantValue]; + keyPath = [NSString stringWithFormat:@"%@.%@", linkCol.keyPath, mapCol.keyPath]; + } else { + keyPath = [functionExpression.arguments.firstObject keyPath]; + mapKey = [functionExpression.arguments[1] constantValue]; + } + + ColumnReference collectionColumn = column_reference_from_key_path(key_path_from_string(m_schema, objectSchema, keyPath), true); + RLMPrecondition(collectionColumn.property().dictionary, @"Invalid predicate", + @"Invalid keypath '%@': only dictionaries support subscript predicates.", functionExpression); + add_mixed_constraint(operatorType, options, collectionColumn.resolve().key(mapKey.UTF8String), right.constantValue); +} + +void QueryBuilder::apply_function_expression(RLMObjectSchema *objectSchema, NSExpression *functionExpression, + NSPredicateOperatorType operatorType, NSExpression *right) { + RLMPrecondition(functionExpression.operand.expressionType == NSSubqueryExpressionType, + @"Invalid predicate", @"The '%@' function is not supported.", functionExpression.function); + RLMPrecondition([functionExpression.function isEqualToString:@"valueForKeyPath:"] && functionExpression.arguments.count == 1, + @"Invalid predicate", @"The '%@' function is not supported on the result of a SUBQUERY.", functionExpression.function); + + NSExpression *keyPathExpression = functionExpression.arguments.firstObject; + RLMPrecondition([keyPathExpression.keyPath isEqualToString:@"@count"], + @"Invalid predicate", @"SUBQUERY is only supported when immediately followed by .@count that is compared with a constant number."); + RLMPrecondition(right.expressionType == NSConstantValueExpressionType && [right.constantValue isKindOfClass:[NSNumber class]], + @"Invalid predicate expression", @"SUBQUERY(…).@count is only supported when compared with a constant number."); + + NSExpression *subqueryExpression = functionExpression.operand; + int64_t value = [right.constantValue integerValue]; + + ColumnReference collectionColumn = column_reference_from_key_path(key_path_from_string(m_schema, objectSchema, [subqueryExpression.collection keyPath]), true); + RLMObjectSchema *collectionMemberObjectSchema = m_schema[collectionColumn.property().objectClassName]; + + // Eliminate references to the iteration variable in the subquery. + NSPredicate *subqueryPredicate = [subqueryExpression.predicate predicateWithSubstitutionVariables:@{subqueryExpression.variable: [NSExpression expressionForEvaluatedObject]}]; + subqueryPredicate = transformPredicate(subqueryPredicate, simplify_self_value_for_key_path_function_expression); + + Query subquery = RLMPredicateToQuery(subqueryPredicate, collectionMemberObjectSchema, m_schema, m_group); + add_numeric_constraint(RLMPropertyTypeInt, operatorType, + collectionColumn.resolve(std::move(subquery)).count(), value); +} + +void QueryBuilder::apply_predicate(NSPredicate *predicate, RLMObjectSchema *objectSchema) +{ + // Compound predicates. + if ([predicate isMemberOfClass:[NSCompoundPredicate class]]) { + NSCompoundPredicate *comp = (NSCompoundPredicate *)predicate; + + switch ([comp compoundPredicateType]) { + case NSAndPredicateType: + if (comp.subpredicates.count) { + // Add all of the subpredicates. + m_query.group(); + for (NSPredicate *subp in comp.subpredicates) { + apply_predicate(subp, objectSchema); + } + m_query.end_group(); + } else { + // NSCompoundPredicate's documentation states that an AND predicate with no subpredicates evaluates to TRUE. + m_query.and_query(std::unique_ptr(new TrueExpression)); + } + break; + + case NSOrPredicateType: { + // Add all of the subpredicates with ors inbetween. + process_or_group(m_query, comp.subpredicates, [&](__unsafe_unretained NSPredicate *const subp) { + apply_predicate(subp, objectSchema); + }); + break; + } + + case NSNotPredicateType: + // Add the negated subpredicate + m_query.Not(); + apply_predicate(comp.subpredicates.firstObject, objectSchema); + break; + + default: + // Not actually possible short of users making their own weird + // broken subclass of NSPredicate + throwException(@"Invalid compound predicate type", + @"Only AND, OR, and NOT compound predicates are supported"); + } + } + else if ([predicate isMemberOfClass:[NSComparisonPredicate class]]) { + NSComparisonPredicate *compp = (NSComparisonPredicate *)predicate; + + RLMPrecondition(compp.comparisonPredicateModifier != NSAllPredicateModifier, + @"Invalid predicate", @"ALL modifier not supported"); + + NSExpressionType exp1Type = compp.leftExpression.expressionType; + NSExpressionType exp2Type = compp.rightExpression.expressionType; + + if (compp.predicateOperatorType == NSBetweenPredicateOperatorType || compp.predicateOperatorType == NSInPredicateOperatorType) { + // Inserting an array via %@ gives NSConstantValueExpressionType, but including it directly gives NSAggregateExpressionType + if (exp1Type == NSKeyPathExpressionType && (exp2Type == NSAggregateExpressionType || exp2Type == NSConstantValueExpressionType)) { + // "key.path IN %@", "key.path IN {…}", "key.path BETWEEN %@", or "key.path BETWEEN {…}". + exp2Type = NSConstantValueExpressionType; + } + else if (compp.predicateOperatorType == NSInPredicateOperatorType && exp1Type == NSConstantValueExpressionType && exp2Type == NSKeyPathExpressionType) { + // "%@ IN key.path" is equivalent to "ANY key.path IN %@". Rewrite the former into the latter. + compp = [NSComparisonPredicate predicateWithLeftExpression:compp.rightExpression rightExpression:compp.leftExpression + modifier:NSAnyPredicateModifier type:NSEqualToPredicateOperatorType options:0]; + exp1Type = NSKeyPathExpressionType; + exp2Type = NSConstantValueExpressionType; + } + else { + if (compp.predicateOperatorType == NSBetweenPredicateOperatorType) { + throwException(@"Invalid predicate", + @"Predicate with BETWEEN operator must compare a KeyPath with an aggregate with two values"); + } + else if (compp.predicateOperatorType == NSInPredicateOperatorType) { + throwException(@"Invalid predicate", + @"Predicate with IN operator must compare a KeyPath with an aggregate"); + } + } + } + + if (exp1Type == NSKeyPathExpressionType && exp2Type == NSKeyPathExpressionType) { + // both expression are KeyPaths + apply_column_expression(key_path_from_string(m_schema, objectSchema, compp.leftExpression.keyPath), + key_path_from_string(m_schema, objectSchema, compp.rightExpression.keyPath), + compp); + } + else if (exp1Type == NSKeyPathExpressionType && exp2Type == NSConstantValueExpressionType) { + // comparing keypath to value + apply_value_expression(key_path_from_string(m_schema, objectSchema, compp.leftExpression.keyPath), + compp.rightExpression.constantValue, compp); + } + else if (exp1Type == NSConstantValueExpressionType && exp2Type == NSKeyPathExpressionType) { + // comparing value to keypath + apply_value_expression(key_path_from_string(m_schema, objectSchema, compp.rightExpression.keyPath), + compp.leftExpression.constantValue, compp); + } + else if (exp1Type == NSFunctionExpressionType) { + if (compp.leftExpression.operand.expressionType == NSSubqueryExpressionType) { + apply_function_expression(objectSchema, compp.leftExpression, compp.predicateOperatorType, compp.rightExpression); + } else { + apply_map_expression(objectSchema, compp.leftExpression, compp.options, compp.predicateOperatorType, compp.rightExpression); + } + } + else if (exp1Type == NSSubqueryExpressionType) { + // The subquery expressions that we support are handled by the NSFunctionExpressionType case above. + throwException(@"Invalid predicate expression", @"SUBQUERY is only supported when immediately followed by .@count."); + } + else { + throwException(@"Invalid predicate expressions", + @"Predicate expressions must compare a keypath and another keypath or a constant value"); + } + } + else if ([predicate isEqual:[NSPredicate predicateWithValue:YES]]) { + m_query.and_query(std::unique_ptr(new TrueExpression)); + } else if ([predicate isEqual:[NSPredicate predicateWithValue:NO]]) { + m_query.and_query(std::unique_ptr(new FalseExpression)); + } + else { + // invalid predicate type + throwException(@"Invalid predicate", + @"Only support compound, comparison, and constant predicates"); + } +} +} // namespace + +realm::Query RLMPredicateToQuery(NSPredicate *predicate, RLMObjectSchema *objectSchema, + RLMSchema *schema, Group &group) +{ + auto query = get_table(group, objectSchema).where(); + + // passing a nil predicate is a no-op + if (!predicate) { + return query; + } + + try { + @autoreleasepool { + QueryBuilder(query, group, schema).apply_predicate(predicate, objectSchema); + } + } + catch (std::exception const& e) { + @throw RLMException(e); + } + + return query; +} + +// return the property for a validated column name +RLMProperty *RLMValidatedProperty(RLMObjectSchema *desc, NSString *columnName) { + RLMProperty *prop = desc[columnName]; + RLMPrecondition(prop, @"Invalid property name", + @"Property '%@' not found in object of type '%@'", columnName, desc.className); + return prop; +} diff --git a/Pods/Realm/Realm/RLMRealm+Sync.mm b/Pods/Realm/Realm/RLMRealm+Sync.mm new file mode 100644 index 0000000..9ee8b0a --- /dev/null +++ b/Pods/Realm/Realm/RLMRealm+Sync.mm @@ -0,0 +1,40 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2017 Realm Inc. +// +// 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 "RLMRealm+Sync.h" + +#import "RLMObjectBase.h" +#import "RLMQueryUtil.hpp" +#import "RLMObjectSchema.h" +#import "RLMRealm_Private.hpp" +#import "RLMResults_Private.hpp" +#import "RLMSchema.h" +#import "RLMSyncSession.h" + +#import +#import + +using namespace realm; + +@implementation RLMRealm (Sync) + +- (RLMSyncSession *)syncSession { + return [RLMSyncSession sessionForRealm:self]; +} + +@end diff --git a/Pods/Realm/Realm/RLMRealm.mm b/Pods/Realm/Realm/RLMRealm.mm new file mode 100644 index 0000000..059fa60 --- /dev/null +++ b/Pods/Realm/Realm/RLMRealm.mm @@ -0,0 +1,1105 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// 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 "RLMRealm_Private.hpp" + +#import "RLMAnalytics.hpp" +#import "RLMAsyncTask_Private.h" +#import "RLMArray_Private.hpp" +#import "RLMDictionary_Private.hpp" +#import "RLMError_Private.hpp" +#import "RLMLogger.h" +#import "RLMMigration_Private.h" +#import "RLMObject_Private.h" +#import "RLMObject_Private.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObjectStore.h" +#import "RLMObservation.hpp" +#import "RLMProperty.h" +#import "RLMProperty_Private.h" +#import "RLMQueryUtil.hpp" +#import "RLMRealmConfiguration_Private.hpp" +#import "RLMRealmUtil.hpp" +#import "RLMScheduler.h" +#import "RLMSchema_Private.hpp" +#import "RLMSyncConfiguration.h" +#import "RLMSyncConfiguration_Private.hpp" +#import "RLMSet_Private.hpp" +#import "RLMThreadSafeReference_Private.hpp" +#import "RLMUpdateChecker.hpp" +#import "RLMUtil.hpp" + +#import +#import +#import +#import +#import +#import +#import +#import + +#if REALM_ENABLE_SYNC +#import "RLMSyncManager_Private.hpp" +#import "RLMSyncSession_Private.hpp" +#import "RLMSyncUtil_Private.hpp" +#import "RLMSyncSubscription_Private.hpp" + +#import +#endif + +using namespace realm; +using util::File; + +@interface RLMRealmNotificationToken : RLMNotificationToken +@property (nonatomic, strong) RLMRealm *realm; +@property (nonatomic, copy) RLMNotificationBlock block; +@end + +@interface RLMRealm () +@property (nonatomic, strong) NSHashTable *notificationHandlers; +- (void)sendNotifications:(RLMNotification)notification; +@end + +void RLMDisableSyncToDisk() { + realm::disable_sync_to_disk(); +} + +static std::atomic s_set_skip_backup_attribute{true}; +void RLMSetSkipBackupAttribute(bool value) { + s_set_skip_backup_attribute = value; +} + +static void RLMAddSkipBackupAttributeToItemAtPath(std::string_view path) { + [[NSURL fileURLWithPath:@(path.data())] setResourceValue:@YES forKey:NSURLIsExcludedFromBackupKey error:nil]; +} + +void RLMWaitForRealmToClose(NSString *path) { + NSString *lockfilePath = [path stringByAppendingString:@".lock"]; + File lockfile(lockfilePath.UTF8String, File::mode_Update); + lockfile.set_fifo_path([path stringByAppendingString:@".management"].UTF8String, "lock.fifo"); + while (!lockfile.try_rw_lock_exclusive()) { + sched_yield(); + } +} + +BOOL RLMIsRealmCachedAtPath(NSString *path) { + return RLMGetAnyCachedRealmForPath([path cStringUsingEncoding:NSUTF8StringEncoding]) != nil; +} + +RLM_HIDDEN +@implementation RLMRealmNotificationToken +- (bool)invalidate { + if (_realm) { + [_realm verifyThread]; + [_realm.notificationHandlers removeObject:self]; + _realm = nil; + _block = nil; + return true; + } + return false; +} + +- (void)suppressNextNotification { + // Temporarily replace the block with one which restores the old block + // rather than producing a notification. + + // This briefly creates a retain cycle but it's fine because the block will + // be synchronously called shortly after this method is called. Unlike with + // collection notifications, this does not have to go through the object + // store or do fancy things to handle transaction coalescing because it's + // called synchronously by the obj-c code and not by the object store. + auto notificationBlock = _block; + _block = ^(RLMNotification, RLMRealm *) { + _block = notificationBlock; + }; +} + +- (void)dealloc { + if (_realm || _block) { + NSLog(@"RLMNotificationToken released without unregistering a notification. You must hold " + @"on to the RLMNotificationToken returned from addNotificationBlock and call " + @"-[RLMNotificationToken invalidate] when you no longer wish to receive RLMRealm notifications."); + } +} +@end + +static bool shouldForciblyDisableEncryption() { + static bool disableEncryption = getenv("REALM_DISABLE_ENCRYPTION"); + return disableEncryption; +} + +NSData *RLMRealmValidatedEncryptionKey(NSData *key) { + if (shouldForciblyDisableEncryption()) { + return nil; + } + + if (key && key.length != 64) { + @throw RLMException(@"Encryption key must be exactly 64 bytes long"); + } + + return key; +} + +REALM_NOINLINE void RLMRealmTranslateException(NSError **error) { + try { + throw; + } + catch (FileAccessError const& ex) { + RLMSetErrorOrThrow(makeError(ex), error); + } + catch (Exception const& ex) { + RLMSetErrorOrThrow(makeError(ex), error); + } + catch (std::system_error const& ex) { + RLMSetErrorOrThrow(makeError(ex), error); + } + catch (std::exception const& ex) { + RLMSetErrorOrThrow(makeError(ex), error); + } +} + +namespace { +// ARC tries to eliminate calls to autorelease when the value is then immediately +// returned, but this results in significantly different semantics between debug +// and release builds for RLMRealm, so force it to always autorelease. +// NEXT-MAJOR: we should switch to NS_RETURNS_RETAINED, which did not exist yet +// when we wrote this but is the correct thing. +id autorelease(__unsafe_unretained id value) { + // +1 __bridge_retained, -1 CFAutorelease + return value ? (__bridge id)CFAutorelease((__bridge_retained CFTypeRef)value) : nil; +} + +RLMRealm *getCachedRealm(RLMRealmConfiguration *configuration, RLMScheduler *options) NS_RETURNS_RETAINED { + auto& config = configuration.configRef; + if (!configuration.cache && !configuration.dynamic) { + return nil; + } + + RLMRealm *realm = RLMGetCachedRealm(configuration, options); + if (!realm) { + return nil; + } + + auto const& oldConfig = realm->_realm->config(); + if ((oldConfig.read_only() || oldConfig.immutable()) != configuration.readOnly) { + @throw RLMException(@"Realm at path '%@' already opened with different read permissions", configuration.fileURL.path); + } + if (oldConfig.in_memory != config.in_memory) { + @throw RLMException(@"Realm at path '%@' already opened with different inMemory settings", configuration.fileURL.path); + } + if (realm.dynamic != configuration.dynamic) { + @throw RLMException(@"Realm at path '%@' already opened with different dynamic settings", configuration.fileURL.path); + } + if (oldConfig.encryption_key != config.encryption_key) { + @throw RLMException(@"Realm at path '%@' already opened with different encryption key", configuration.fileURL.path); + } + return autorelease(realm); +} + +bool copySeedFile(RLMRealmConfiguration *configuration, NSError **error) { + if (!configuration.seedFilePath) { + return false; + } + @autoreleasepool { + bool didCopySeed = false; + NSError *copyError; + DB::call_with_lock(configuration.path, [&](auto const&) { + didCopySeed = [[NSFileManager defaultManager] copyItemAtURL:configuration.seedFilePath + toURL:configuration.fileURL + error:©Error]; + }); + if (!didCopySeed && copyError != nil && copyError.code != NSFileWriteFileExistsError) { + RLMSetErrorOrThrow(copyError, error); + return true; + } + } + return false; +} +} // anonymous namespace + +@implementation RLMRealm { + std::mutex _collectionEnumeratorMutex; + NSHashTable *_collectionEnumerators; + bool _sendingNotifications; +} + ++ (void)initialize { + // In cases where we are not using a synced Realm, we initialise the default logger + // before opening any realm. + [RLMLogger class]; +} + ++ (void)runFirstCheckForConfiguration:(RLMRealmConfiguration *)configuration schema:(RLMSchema *)schema { + static bool initialized; + if (initialized) { + return; + } + initialized = true; + + // Run Analytics on the very first any Realm open. + RLMSendAnalytics(configuration, schema); + RLMCheckForUpdates(); +} + +- (instancetype)initPrivate { + self = [super init]; + return self; +} + +- (BOOL)isEmpty { + return realm::ObjectStore::is_empty(self.group); +} + +- (void)verifyThread { + try { + _realm->verify_thread(); + } + catch (std::exception const& e) { + @throw RLMException(e); + } +} + +- (BOOL)inWriteTransaction { + return _realm->is_in_transaction(); +} + +- (realm::Group &)group { + return _realm->read_group(); +} + +- (BOOL)autorefresh { + return _realm->auto_refresh(); +} + +- (void)setAutorefresh:(BOOL)autorefresh { + try { + _realm->set_auto_refresh(autorefresh); + } + catch (std::exception const& e) { + @throw RLMException(e); + } +} + ++ (instancetype)defaultRealm { + return [RLMRealm realmWithConfiguration:[RLMRealmConfiguration rawDefaultConfiguration] error:nil]; +} + ++ (instancetype)defaultRealmForQueue:(dispatch_queue_t)queue { + return [RLMRealm realmWithConfiguration:[RLMRealmConfiguration rawDefaultConfiguration] + queue:queue error:nil]; +} + ++ (instancetype)realmWithURL:(NSURL *)fileURL { + RLMRealmConfiguration *configuration = [RLMRealmConfiguration defaultConfiguration]; + configuration.fileURL = fileURL; + return [RLMRealm realmWithConfiguration:configuration error:nil]; +} + ++ (RLMAsyncOpenTask *)asyncOpenWithConfiguration:(RLMRealmConfiguration *)configuration + callbackQueue:(dispatch_queue_t)callbackQueue + callback:(RLMAsyncOpenRealmCallback)callback { + return [[RLMAsyncOpenTask alloc] initWithConfiguration:configuration + confinedTo:[RLMScheduler dispatchQueue:callbackQueue] + download:true completion:callback]; +} + ++ (instancetype)realmWithSharedRealm:(SharedRealm)sharedRealm + schema:(RLMSchema *)schema + dynamic:(bool)dynamic { + RLMRealm *realm = [[RLMRealm alloc] initPrivate]; + realm->_realm = sharedRealm; + realm->_dynamic = dynamic; + realm->_schema = schema; + if (!dynamic) { + realm->_realm->set_schema_subset(schema.objectStoreCopy); + } + realm->_info = RLMSchemaInfo(realm); + return autorelease(realm); +} + ++ (instancetype)realmWithConfiguration:(RLMRealmConfiguration *)configuration error:(NSError **)error { + return autorelease([self realmWithConfiguration:configuration + confinedTo:RLMScheduler.currentRunLoop + error:error]); +} + ++ (instancetype)realmWithConfiguration:(RLMRealmConfiguration *)configuration + queue:(dispatch_queue_t)queue + error:(NSError **)error { + return autorelease([self realmWithConfiguration:configuration + confinedTo:[RLMScheduler dispatchQueue:queue] + error:error]); +} + ++ (instancetype)realmWithConfiguration:(RLMRealmConfiguration *)configuration + confinedTo:(RLMScheduler *)scheduler + error:(NSError **)error { + // First check if we already have a cached Realm for this config + if (auto realm = getCachedRealm(configuration, scheduler)) { + return realm; + } + + if (copySeedFile(configuration, error)) { + return nil; + } + + bool dynamic = configuration.dynamic; + bool cache = configuration.cache; + + Realm::Config config = configuration.config; + + RLMRealm *realm = [[self alloc] initPrivate]; + realm->_dynamic = dynamic; + realm->_actor = scheduler.actor; + + // protects the realm cache and accessors cache + static auto& initLock = *new RLMUnfairMutex; + std::lock_guard lock(initLock); + + try { + config.scheduler = scheduler.osScheduler; + if (config.scheduler && !config.scheduler->is_on_thread()) { + throw RLMException(@"Realm opened from incorrect dispatch queue."); + } + realm->_realm = Realm::get_shared_realm(config); + } + catch (...) { + RLMRealmTranslateException(error); + return nil; + } + + bool realmIsCached = false; + // if we have a cached realm on another thread we can skip a few steps and + // just grab its schema + @autoreleasepool { + // ensure that cachedRealm doesn't end up in this thread's autorelease pool + if (auto cachedRealm = RLMGetAnyCachedRealmForPath(config.path)) { + realm->_realm->set_schema_subset(cachedRealm->_realm->schema()); + realm->_schema = cachedRealm.schema; + realm->_info = cachedRealm->_info.clone(cachedRealm->_realm->schema(), realm); + realmIsCached = true; + } + } + + bool isFirstOpen = false; + if (realm->_schema) { } + else if (dynamic) { + realm->_schema = [RLMSchema dynamicSchemaFromObjectStoreSchema:realm->_realm->schema()]; + realm->_info = RLMSchemaInfo(realm); + } + else { + // set/align schema or perform migration if needed + RLMSchema *schema = configuration.customSchema ?: RLMSchema.sharedSchema; + + MigrationFunction migrationFunction; + auto migrationBlock = configuration.migrationBlock; + if (migrationBlock && configuration.schemaVersion > 0) { + migrationFunction = [=](SharedRealm old_realm, SharedRealm realm, Schema& mutableSchema) { + RLMSchema *oldSchema = [RLMSchema dynamicSchemaFromObjectStoreSchema:old_realm->schema()]; + RLMRealm *oldRealm = [RLMRealm realmWithSharedRealm:old_realm + schema:oldSchema + dynamic:true]; + + // The destination RLMRealm can't just use the schema from the + // SharedRealm because it doesn't have information about whether or + // not a class was defined in Swift, which effects how new objects + // are created + RLMRealm *newRealm = [RLMRealm realmWithSharedRealm:realm + schema:schema.copy + dynamic:true]; + + [[[RLMMigration alloc] initWithRealm:newRealm oldRealm:oldRealm schema:mutableSchema] + execute:migrationBlock objectClass:configuration.migrationObjectClass]; + + oldRealm->_realm = nullptr; + newRealm->_realm = nullptr; + }; + } + + DataInitializationFunction initializationFunction; + if (!configuration.rerunOnOpen && configuration.initialSubscriptions) { + initializationFunction = [&isFirstOpen](SharedRealm) { + isFirstOpen = true; + }; + } + + try { + realm->_realm->update_schema(schema.objectStoreCopy, config.schema_version, + std::move(migrationFunction), std::move(initializationFunction)); + } + catch (...) { + RLMRealmTranslateException(error); + return nil; + } + + realm->_schema = schema; + realm->_info = RLMSchemaInfo(realm); + RLMSchemaEnsureAccessorsCreated(realm.schema); + + if (!configuration.readOnly) { + REALM_ASSERT(!realm->_realm->is_in_read_transaction()); + + if (s_set_skip_backup_attribute) { + RLMAddSkipBackupAttributeToItemAtPath(config.path + ".management"); + RLMAddSkipBackupAttributeToItemAtPath(config.path + ".lock"); + RLMAddSkipBackupAttributeToItemAtPath(config.path + ".note"); + } + } + } + + if (cache) { + RLMCacheRealm(configuration, scheduler, realm); + } + + if (!configuration.readOnly) { + realm->_realm->m_binding_context = RLMCreateBindingContext(realm); + realm->_realm->m_binding_context->realm = realm->_realm; + } + +#if REALM_ENABLE_SYNC + if (isFirstOpen || (configuration.rerunOnOpen && !realmIsCached)) { + RLMSyncSubscriptionSet *subscriptions = realm.subscriptions; + [subscriptions update:^{ + configuration.initialSubscriptions(subscriptions); + }]; + } +#endif + + // Run Analytics and Update checker, this will be run only the first any realm open + [self runFirstCheckForConfiguration:configuration schema:realm.schema]; + + return realm; +} + ++ (void)resetRealmState { + RLMClearRealmCache(); + realm::_impl::RealmCoordinator::clear_cache(); + [RLMRealmConfiguration resetRealmConfigurationState]; +} + +- (void)verifyNotificationsAreSupported:(bool)isCollection { + [self verifyThread]; + if (_realm->config().immutable()) { + @throw RLMException(@"Read-only Realms do not change and do not have change notifications."); + } + if (_realm->is_frozen()) { + @throw RLMException(@"Frozen Realms do not change and do not have change notifications."); + } + if (_realm->config().automatic_change_notifications && !_realm->can_deliver_notifications()) { + @throw RLMException(@"Can only add notification blocks from within runloops."); + } + if (isCollection && _realm->is_in_transaction()) { + @throw RLMException(@"Cannot register notification blocks from within write transactions."); + } +} + +- (RLMNotificationToken *)addNotificationBlock:(RLMNotificationBlock)block { + if (!block) { + @throw RLMException(@"The notification block should not be nil"); + } + [self verifyNotificationsAreSupported:false]; + + _realm->read_group(); + + if (!_notificationHandlers) { + _notificationHandlers = [NSHashTable hashTableWithOptions:NSPointerFunctionsWeakMemory]; + } + + RLMRealmNotificationToken *token = [[RLMRealmNotificationToken alloc] init]; + token.realm = self; + token.block = block; + [_notificationHandlers addObject:token]; + return token; +} + +- (void)sendNotifications:(RLMNotification)notification { + NSAssert(!_realm->config().immutable(), @"Read-only realms do not have notifications"); + if (_sendingNotifications) { + return; + } + NSUInteger count = _notificationHandlers.count; + if (count == 0) { + return; + } + + _sendingNotifications = true; + auto cleanup = realm::util::make_scope_exit([&]() noexcept { + _sendingNotifications = false; + }); + + // call this realm's notification blocks + if (count == 1) { + if (auto block = [_notificationHandlers.anyObject block]) { + block(notification, self); + } + } + else { + for (RLMRealmNotificationToken *token in _notificationHandlers.allObjects) { + if (auto block = token.block) { + block(notification, self); + } + } + } +} + +- (RLMRealmConfiguration *)configuration { + RLMRealmConfiguration *configuration = [[RLMRealmConfiguration alloc] init]; + configuration.configRef = _realm->config(); + configuration.dynamic = _dynamic; + configuration.customSchema = _schema; + return configuration; +} + +- (void)beginWriteTransaction { + [self beginWriteTransactionWithError:nil]; +} + +- (BOOL)beginWriteTransactionWithError:(NSError **)error { + try { + _realm->begin_transaction(); + return YES; + } + catch (...) { + RLMRealmTranslateException(error); + return NO; + } +} + +- (void)commitWriteTransaction { + [self commitWriteTransaction:nil]; +} + +- (BOOL)commitWriteTransaction:(NSError **)error { + return [self commitWriteTransactionWithoutNotifying:@[] error:error]; +} + +- (BOOL)commitWriteTransactionWithoutNotifying:(NSArray *)tokens error:(NSError **)error { + for (RLMNotificationToken *token in tokens) { + if (token.realm != self) { + @throw RLMException(@"Incorrect Realm: only notifications for the Realm being modified can be skipped."); + } + [token suppressNextNotification]; + } + + try { + _realm->commit_transaction(); + return YES; + } + catch (...) { + RLMRealmTranslateException(error); + return NO; + } +} + +- (void)transactionWithBlock:(__attribute__((noescape)) void(^)(void))block { + [self transactionWithBlock:block error:nil]; +} + +- (BOOL)transactionWithBlock:(__attribute__((noescape)) void(^)(void))block error:(NSError **)outError { + return [self transactionWithoutNotifying:@[] block:block error:outError]; +} + +- (void)transactionWithoutNotifying:(NSArray *)tokens block:(__attribute__((noescape)) void(^)(void))block { + [self transactionWithoutNotifying:tokens block:block error:nil]; +} + +- (BOOL)transactionWithoutNotifying:(NSArray *)tokens block:(__attribute__((noescape)) void(^)(void))block error:(NSError **)error { + [self beginWriteTransactionWithError:error]; + block(); + if (_realm->is_in_transaction()) { + return [self commitWriteTransactionWithoutNotifying:tokens error:error]; + } + return YES; +} + +- (void)cancelWriteTransaction { + try { + _realm->cancel_transaction(); + } + catch (std::exception &ex) { + @throw RLMException(ex); + } +} + +- (BOOL)isPerformingAsynchronousWriteOperations { + return _realm->is_in_async_transaction(); +} + +- (RLMAsyncTransactionId)beginAsyncWriteTransaction:(void(^)())block { + try { + return _realm->async_begin_transaction(block); + } + catch (std::exception &ex) { + @throw RLMException(ex); + } +} + +- (RLMAsyncTransactionId)commitAsyncWriteTransaction { + try { + return _realm->async_commit_transaction(); + } + catch (...) { + RLMRealmTranslateException(nil); + return 0; + } +} + +- (RLMAsyncWriteTask *)beginAsyncWrite { + try { + auto write = [[RLMAsyncWriteTask alloc] initWithRealm:self]; + write.transactionId = _realm->async_begin_transaction(^{ [write complete:false]; }, true); + return write; + } + catch (std::exception &ex) { + @throw RLMException(ex); + } +} + +- (void)commitAsyncWriteWithGrouping:(bool)allowGrouping + completion:(void(^)(NSError *_Nullable))completion { + [self commitAsyncWriteTransaction:completion allowGrouping:allowGrouping]; +} + +- (RLMAsyncTransactionId)commitAsyncWriteTransaction:(void(^)(NSError *))completionBlock { + return [self commitAsyncWriteTransaction:completionBlock allowGrouping:false]; +} + +- (RLMAsyncTransactionId)commitAsyncWriteTransaction:(nullable void(^)(NSError *))completionBlock + allowGrouping:(BOOL)allowGrouping { + try { + auto completion = [=](std::exception_ptr err) { + @autoreleasepool { + if (!completionBlock) { + std::rethrow_exception(err); + return; + } + if (err) { + try { + std::rethrow_exception(err); + } + catch (...) { + NSError *error; + RLMRealmTranslateException(&error); + completionBlock(error); + } + } else { + completionBlock(nil); + } + } + }; + + if (completionBlock) { + return _realm->async_commit_transaction(completion, allowGrouping); + } + return _realm->async_commit_transaction(nullptr, allowGrouping); + } + catch (...) { + RLMRealmTranslateException(nil); + return 0; + } +} + +- (void)cancelAsyncTransaction:(RLMAsyncTransactionId)asyncTransactionId { + try { + _realm->async_cancel_transaction(asyncTransactionId); + } + catch (std::exception &ex) { + @throw RLMException(ex); + } +} + +- (RLMAsyncTransactionId)asyncTransactionWithBlock:(void(^)())block onComplete:(nullable void(^)(NSError *))completionBlock { + return [self beginAsyncWriteTransaction:^{ + block(); + if (_realm->is_in_transaction()) { + [self commitAsyncWriteTransaction:completionBlock]; + } + }]; +} + +- (RLMAsyncTransactionId)asyncTransactionWithBlock:(void(^)())block { + return [self beginAsyncWriteTransaction:^{ + block(); + if (_realm->is_in_transaction()) { + [self commitAsyncWriteTransaction]; + } + }]; +} + +- (void)invalidate { + if (_realm->is_in_transaction()) { + NSLog(@"WARNING: An RLMRealm instance was invalidated during a write " + "transaction and all pending changes have been rolled back."); + } + + [self detachAllEnumerators]; + + for (auto& objectInfo : _info) { + for (RLMObservationInfo *info : objectInfo.second.observedObjects) { + info->willChange(RLMInvalidatedKey); + } + } + + _realm->invalidate(); + + for (auto& objectInfo : _info) { + for (RLMObservationInfo *info : objectInfo.second.observedObjects) { + info->didChange(RLMInvalidatedKey); + } + } + + if (_realm->is_frozen()) { + _realm->close(); + } +} + +- (nullable id)resolveThreadSafeReference:(RLMThreadSafeReference *)reference { + return [reference resolveReferenceInRealm:self]; +} + +/** + Replaces all string columns in this Realm with a string enumeration column and compacts the + database file. + + Cannot be called from a write transaction. + + Compaction will not occur if other `RLMRealm` instances exist. + + While compaction is in progress, attempts by other threads or processes to open the database will + wait. + + Be warned that resource requirements for compaction is proportional to the amount of live data in + the database. + + Compaction works by writing the database contents to a temporary database file and then replacing + the database with the temporary one. The name of the temporary file is formed by appending + `.tmp_compaction_space` to the name of the database. + + @return YES if the compaction succeeded. + */ +- (BOOL)compact { + // compact() automatically ends the read transaction, but we need to clean + // up cached state and send invalidated notifications when that happens, so + // explicitly end it first unless we're in a write transaction (in which + // case compact() will throw an exception) + if (!_realm->is_in_transaction()) { + [self invalidate]; + } + + try { + return _realm->compact(); + } + catch (std::exception const& ex) { + @throw RLMException(ex); + } +} + +- (void)dealloc { + if (_realm) { + if (_realm->is_in_transaction()) { + [self cancelWriteTransaction]; + NSLog(@"WARNING: An RLMRealm instance was deallocated during a write transaction and all " + "pending changes have been rolled back. Make sure to retain a reference to the " + "RLMRealm for the duration of the write transaction."); + } + } +} + +- (BOOL)refresh { + if (_realm->config().immutable()) { + @throw RLMException(@"Read-only Realms do not change and cannot be refreshed."); + } + try { + return _realm->refresh(); + } + catch (std::exception const& e) { + @throw RLMException(e); + } +} + +- (void)addObject:(__unsafe_unretained RLMObject *const)object { + RLMAddObjectToRealm(object, self, RLMUpdatePolicyError); +} + +- (void)addObjects:(id)objects { + for (RLMObject *obj in objects) { + if (![obj isKindOfClass:RLMObjectBase.class]) { + @throw RLMException(@"Cannot insert objects of type %@ with addObjects:. Only RLMObjects are supported.", + NSStringFromClass(obj.class)); + } + [self addObject:obj]; + } +} + +- (void)addOrUpdateObject:(RLMObject *)object { + // verify primary key + if (!object.objectSchema.primaryKeyProperty) { + @throw RLMException(@"'%@' does not have a primary key and can not be updated", object.objectSchema.className); + } + + RLMAddObjectToRealm(object, self, RLMUpdatePolicyUpdateAll); +} + +- (void)addOrUpdateObjects:(id)objects { + for (RLMObject *obj in objects) { + if (![obj isKindOfClass:RLMObjectBase.class]) { + @throw RLMException(@"Cannot add or update objects of type %@ with addOrUpdateObjects:. Only RLMObjects are" + " supported.", + NSStringFromClass(obj.class)); + } + [self addOrUpdateObject:obj]; + } +} + +- (void)deleteObject:(RLMObject *)object { + RLMDeleteObjectFromRealm(object, self); +} + +- (void)deleteObjects:(id)objects { + id idObjects = objects; + if ([idObjects respondsToSelector:@selector(realm)] + && [idObjects respondsToSelector:@selector(deleteObjectsFromRealm)]) { + if (self != (RLMRealm *)[idObjects realm]) { + @throw RLMException(@"Can only delete objects from the Realm they belong to."); + } + [idObjects deleteObjectsFromRealm]; + return; + } + + if (auto array = RLMDynamicCast(objects)) { + if (array.type != RLMPropertyTypeObject) { + @throw RLMException(@"Cannot delete objects from RLMArray<%@>: only RLMObjects can be deleted.", + RLMTypeToString(array.type)); + } + } + else if (auto set = RLMDynamicCast(objects)) { + if (set.type != RLMPropertyTypeObject) { + @throw RLMException(@"Cannot delete objects from RLMSet<%@>: only RLMObjects can be deleted.", + RLMTypeToString(set.type)); + } + } + else if (auto dictionary = RLMDynamicCast(objects)) { + if (dictionary.type != RLMPropertyTypeObject) { + @throw RLMException(@"Cannot delete objects from RLMDictionary of type %@: only RLMObjects can be deleted.", + RLMTypeToString(dictionary.type)); + } + for (RLMObject *obj in dictionary.allValues) { + RLMDeleteObjectFromRealm(obj, self); + } + return; + } + for (RLMObject *obj in objects) { + if (![obj isKindOfClass:RLMObjectBase.class]) { + @throw RLMException(@"Cannot delete objects of type %@ with deleteObjects:. Only RLMObjects can be deleted.", + NSStringFromClass(obj.class)); + } + RLMDeleteObjectFromRealm(obj, self); + } +} + +- (void)deleteAllObjects { + RLMDeleteAllObjectsFromRealm(self); +} + +- (RLMResults *)allObjects:(NSString *)objectClassName { + return RLMGetObjects(self, objectClassName, nil); +} + +- (RLMResults *)objects:(NSString *)objectClassName where:(NSString *)predicateFormat, ... { + va_list args; + va_start(args, predicateFormat); + RLMResults *results = [self objects:objectClassName where:predicateFormat args:args]; + va_end(args); + return results; +} + +- (RLMResults *)objects:(NSString *)objectClassName where:(NSString *)predicateFormat args:(va_list)args { + return [self objects:objectClassName withPredicate:[NSPredicate predicateWithFormat:predicateFormat arguments:args]]; +} + +- (RLMResults *)objects:(NSString *)objectClassName withPredicate:(NSPredicate *)predicate { + return RLMGetObjects(self, objectClassName, predicate); +} + +- (RLMObject *)objectWithClassName:(NSString *)className forPrimaryKey:(id)primaryKey { + return RLMGetObject(self, className, primaryKey); +} + ++ (uint64_t)schemaVersionAtURL:(NSURL *)fileURL encryptionKey:(NSData *)key error:(NSError **)error { + RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init]; + config.fileURL = fileURL; + config.encryptionKey = RLMRealmValidatedEncryptionKey(key); + + uint64_t version = RLMNotVersioned; + try { + version = Realm::get_schema_version(config.configRef); + } + catch (...) { + RLMRealmTranslateException(error); + return version; + } + + if (error && version == realm::ObjectStore::NotVersioned) { + auto msg = [NSString stringWithFormat:@"Realm at path '%@' has not been initialized.", fileURL.path]; + *error = [NSError errorWithDomain:RLMErrorDomain + code:RLMErrorInvalidDatabase + userInfo:@{NSLocalizedDescriptionKey: msg, + NSFilePathErrorKey: fileURL.path}]; + } + return version; +} + ++ (BOOL)performMigrationForConfiguration:(RLMRealmConfiguration *)configuration error:(NSError **)error { + if (RLMGetAnyCachedRealmForPath(configuration.path)) { + @throw RLMException(@"Cannot migrate Realms that are already open."); + } + + NSError *localError; // Prevents autorelease + BOOL success; + @autoreleasepool { + success = [RLMRealm realmWithConfiguration:configuration error:&localError] != nil; + } + if (!success && error) { + *error = localError; // Must set outside pool otherwise will free anyway + } + return success; +} + +- (RLMObject *)createObject:(NSString *)className withValue:(id)value { + return (RLMObject *)RLMCreateObjectInRealmWithValue(self, className, value, RLMUpdatePolicyError); +} + +- (BOOL)writeCopyToURL:(NSURL *)fileURL encryptionKey:(NSData *)key error:(NSError **)error { + RLMRealmConfiguration *configuration = [RLMRealmConfiguration new]; + configuration.fileURL = fileURL; + configuration.encryptionKey = key; + return [self writeCopyForConfiguration:configuration error:error]; +} + +- (BOOL)writeCopyForConfiguration:(RLMRealmConfiguration *)configuration error:(NSError **)error { + try { + _realm->convert(configuration.configRef, false); + return YES; + } + catch (...) { + if (error) { + RLMRealmTranslateException(error); + } + } + return NO; +} + ++ (BOOL)fileExistsForConfiguration:(RLMRealmConfiguration *)config { + return [NSFileManager.defaultManager fileExistsAtPath:config.pathOnDisk]; +} + ++ (BOOL)deleteFilesForConfiguration:(RLMRealmConfiguration *)config error:(NSError **)error { + bool didDeleteAny = false; + try { + realm::Realm::delete_files(config.path, &didDeleteAny); + } + catch (realm::FileAccessError const& e) { + if (error) { + // For backwards compatibility, but this should go away in 11.0 + if (e.code() == realm::ErrorCodes::PermissionDenied) { + *error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSFileWriteNoPermissionError + userInfo:@{NSLocalizedDescriptionKey: @(e.what()), + NSFilePathErrorKey: @(e.get_path().data())}]; + } + else { + RLMRealmTranslateException(error); + } + } + } + catch (...) { + if (error) { + RLMRealmTranslateException(error); + } + } + return didDeleteAny; +} + +- (BOOL)isFrozen { + return _realm->is_frozen(); +} + +- (RLMRealm *)freeze { + [self verifyThread]; + return self.isFrozen ? self : RLMGetFrozenRealmForSourceRealm(self); +} + +- (RLMRealm *)thaw { + [self verifyThread]; + return self.isFrozen ? [RLMRealm realmWithConfiguration:self.configuration error:nil] : self; +} + +- (RLMRealm *)frozenCopy { + try { + RLMRealm *realm = [[RLMRealm alloc] initPrivate]; + realm->_realm = _realm->freeze(); + realm->_realm->read_group(); + realm->_dynamic = _dynamic; + realm->_schema = _schema; + realm->_info = RLMSchemaInfo(realm); + return realm; + } + catch (std::exception const& e) { + @throw RLMException(e); + } +} + +- (void)registerEnumerator:(RLMFastEnumerator *)enumerator { + std::lock_guard lock(_collectionEnumeratorMutex); + if (!_collectionEnumerators) { + _collectionEnumerators = [NSHashTable hashTableWithOptions:NSPointerFunctionsWeakMemory]; + } + [_collectionEnumerators addObject:enumerator]; +} + +- (void)unregisterEnumerator:(RLMFastEnumerator *)enumerator { + std::lock_guard lock(_collectionEnumeratorMutex); + [_collectionEnumerators removeObject:enumerator]; +} + +- (void)detachAllEnumerators { + std::lock_guard lock(_collectionEnumeratorMutex); + for (RLMFastEnumerator *enumerator in _collectionEnumerators) { + [enumerator detach]; + } + _collectionEnumerators = nil; +} + +- (bool)isFlexibleSync { +#if REALM_ENABLE_SYNC + return _realm->config().sync_config && _realm->config().sync_config->flx_sync_requested; +#else + return false; +#endif +} + +- (RLMSyncSubscriptionSet *)subscriptions { +#if REALM_ENABLE_SYNC + if (!self.isFlexibleSync) { + @throw RLMException(@"This Realm was not configured with flexible sync"); + } + return [[RLMSyncSubscriptionSet alloc] initWithSubscriptionSet:_realm->get_latest_subscription_set() realm:self]; +#else + @throw RLMException(@"Realm was not compiled with sync enabled"); +#endif +} +@end diff --git a/Pods/Realm/Realm/RLMRealmConfiguration.mm b/Pods/Realm/Realm/RLMRealmConfiguration.mm new file mode 100644 index 0000000..55d4707 --- /dev/null +++ b/Pods/Realm/Realm/RLMRealmConfiguration.mm @@ -0,0 +1,412 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// 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 "RLMRealmConfiguration_Private.h" + +#import "RLMEvent.h" +#import "RLMObjectSchema_Private.hpp" +#import "RLMRealm_Private.h" +#import "RLMSchema_Private.hpp" +#import "RLMUtil.hpp" + +#import +#import + +#if REALM_ENABLE_SYNC +#import "RLMSyncConfiguration_Private.hpp" +#import "RLMUser_Private.hpp" + +#import +#import +#import +#else +@class RLMSyncConfiguration; +#endif + +static NSString *const c_RLMRealmConfigurationProperties[] = { + @"fileURL", + @"inMemoryIdentifier", + @"encryptionKey", + @"readOnly", + @"schemaVersion", + @"migrationBlock", + @"deleteRealmIfMigrationNeeded", + @"shouldCompactOnLaunch", + @"dynamic", + @"customSchema", +}; + +static NSString *const c_defaultRealmFileName = @"default.realm"; +RLMRealmConfiguration *s_defaultConfiguration; + +NSString *RLMRealmPathForFileAndBundleIdentifier(NSString *fileName, NSString *bundleIdentifier) { + return [RLMDefaultDirectoryForBundleIdentifier(bundleIdentifier) + stringByAppendingPathComponent:fileName]; +} + +NSString *RLMRealmPathForFile(NSString *fileName) { + static NSString *directory = RLMDefaultDirectoryForBundleIdentifier(nil); + return [directory stringByAppendingPathComponent:fileName]; +} + +@implementation RLMRealmConfiguration { + realm::Realm::Config _config; + RLMSyncErrorReportingBlock _manualClientResetHandler; +} + +- (realm::Realm::Config&)configRef { + return _config; +} + +- (std::string const&)path { + return _config.path; +} + ++ (instancetype)defaultConfiguration { + return [[self rawDefaultConfiguration] copy]; +} + ++ (void)setDefaultConfiguration:(RLMRealmConfiguration *)configuration { + if (!configuration) { + @throw RLMException(@"Cannot set the default configuration to nil."); + } + @synchronized(c_defaultRealmFileName) { + s_defaultConfiguration = [configuration copy]; + } +} + ++ (RLMRealmConfiguration *)rawDefaultConfiguration { + RLMRealmConfiguration *configuration; + @synchronized(c_defaultRealmFileName) { + if (!s_defaultConfiguration) { + s_defaultConfiguration = [[RLMRealmConfiguration alloc] init]; + } + configuration = s_defaultConfiguration; + } + return configuration; +} + ++ (void)resetRealmConfigurationState { + @synchronized(c_defaultRealmFileName) { + s_defaultConfiguration = nil; + } +} + +- (instancetype)init { + self = [super init]; + if (self) { + static NSURL *defaultRealmURL = [NSURL fileURLWithPath:RLMRealmPathForFile(c_defaultRealmFileName)]; + self.fileURL = defaultRealmURL; + self.schemaVersion = 0; + self.cache = YES; + _config.automatically_handle_backlinks_in_migrations = true; + } + + return self; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + RLMRealmConfiguration *configuration = [[[self class] allocWithZone:zone] init]; + configuration->_config = _config; + configuration->_cache = _cache; + configuration->_dynamic = _dynamic; + configuration->_migrationBlock = _migrationBlock; + configuration->_shouldCompactOnLaunch = _shouldCompactOnLaunch; + configuration->_customSchema = _customSchema; + configuration->_eventConfiguration = _eventConfiguration; + configuration->_migrationObjectClass = _migrationObjectClass; + configuration->_initialSubscriptions = _initialSubscriptions; + configuration->_rerunOnOpen = _rerunOnOpen; + return configuration; +} + +- (NSString *)description { + NSMutableString *string = [NSMutableString stringWithFormat:@"%@ {\n", self.class]; + for (NSString *key : c_RLMRealmConfigurationProperties) { + NSString *description = [[self valueForKey:key] description]; + description = [description stringByReplacingOccurrencesOfString:@"\n" withString:@"\n\t"]; + + [string appendFormat:@"\t%@ = %@;\n", key, description]; + } + return [string stringByAppendingString:@"}"]; +} + +- (NSURL *)fileURL { + if (_config.in_memory) { + return nil; + } + return [NSURL fileURLWithPath:@(_config.path.c_str())]; +} + +- (void)setFileURL:(NSURL *)fileURL { + NSString *path = fileURL.path; + if (path.length == 0) { + @throw RLMException(@"Realm path must not be empty"); + } + + RLMNSStringToStdString(_config.path, path); + _config.in_memory = false; +} + +- (NSString *)inMemoryIdentifier { + if (!_config.in_memory) { + return nil; + } + return [@(_config.path.c_str()) lastPathComponent]; +} + +- (void)setInMemoryIdentifier:(NSString *)inMemoryIdentifier { + if (inMemoryIdentifier.length == 0) { + @throw RLMException(@"In-memory identifier must not be empty"); + } + _config.sync_config = nullptr; + _seedFilePath = nil; + + RLMNSStringToStdString(_config.path, [NSTemporaryDirectory() stringByAppendingPathComponent:inMemoryIdentifier]); + _config.in_memory = true; +} + +- (void)setSeedFilePath:(NSURL *)seedFilePath { + _seedFilePath = seedFilePath; + if (_seedFilePath) { + _config.in_memory = false; + } +} + +- (NSData *)encryptionKey { + return _config.encryption_key.empty() ? nil : [NSData dataWithBytes:_config.encryption_key.data() length:_config.encryption_key.size()]; +} + +- (void)setEncryptionKey:(NSData * __nullable)encryptionKey { + if (NSData *key = RLMRealmValidatedEncryptionKey(encryptionKey)) { + auto bytes = static_cast(key.bytes); + _config.encryption_key.assign(bytes, bytes + key.length); + } + else { + _config.encryption_key.clear(); + } +} + +- (BOOL)readOnly { + return _config.immutable() || _config.read_only(); +} + +static bool isSync(realm::Realm::Config const& config) { +#if REALM_ENABLE_SYNC + return !!config.sync_config; +#endif + return false; +} + +- (void)updateSchemaMode { + if (self.deleteRealmIfMigrationNeeded) { + if (isSync(_config)) { + @throw RLMException(@"Cannot set 'deleteRealmIfMigrationNeeded' when sync is enabled ('syncConfig' is set)."); + } + } + else if (self.readOnly) { + _config.schema_mode = isSync(_config) ? realm::SchemaMode::ReadOnly : realm::SchemaMode::Immutable; + } + else if (isSync(_config)) { + if (_customSchema) { + _config.schema_mode = realm::SchemaMode::AdditiveExplicit; + } + else { + _config.schema_mode = realm::SchemaMode::AdditiveDiscovered; + } + } + else { + _config.schema_mode = realm::SchemaMode::Automatic; + } +} + +- (void)setReadOnly:(BOOL)readOnly { + if (readOnly) { + if (self.deleteRealmIfMigrationNeeded) { + @throw RLMException(@"Cannot set `readOnly` when `deleteRealmIfMigrationNeeded` is set."); + } else if (self.shouldCompactOnLaunch) { + @throw RLMException(@"Cannot set `readOnly` when `shouldCompactOnLaunch` is set."); + } + _config.schema_mode = isSync(_config) ? realm::SchemaMode::ReadOnly : realm::SchemaMode::Immutable; + } + else if (self.readOnly) { + _config.schema_mode = realm::SchemaMode::Automatic; + [self updateSchemaMode]; + } +} + +- (uint64_t)schemaVersion { + return _config.schema_version; +} + +- (void)setSchemaVersion:(uint64_t)schemaVersion { + if (schemaVersion == RLMNotVersioned) { + @throw RLMException(@"Cannot set schema version to %llu (RLMNotVersioned)", RLMNotVersioned); + } + _config.schema_version = schemaVersion; +} + +- (BOOL)deleteRealmIfMigrationNeeded { + return _config.schema_mode == realm::SchemaMode::SoftResetFile; +} + +- (void)setDeleteRealmIfMigrationNeeded:(BOOL)deleteRealmIfMigrationNeeded { + if (deleteRealmIfMigrationNeeded) { + if (self.readOnly) { + @throw RLMException(@"Cannot set `deleteRealmIfMigrationNeeded` when `readOnly` is set."); + } + if (isSync(_config)) { + @throw RLMException(@"Cannot set 'deleteRealmIfMigrationNeeded' when sync is enabled ('syncConfig' is set)."); + } + _config.schema_mode = realm::SchemaMode::SoftResetFile; + } + else if (self.deleteRealmIfMigrationNeeded) { + _config.schema_mode = realm::SchemaMode::Automatic; + } +} + +- (NSArray *)objectClasses { + return [_customSchema.objectSchema valueForKeyPath:@"objectClass"]; +} + +- (void)setObjectClasses:(NSArray *)objectClasses { + _customSchema = objectClasses ? [RLMSchema schemaWithObjectClasses:objectClasses] : nil; + [self updateSchemaMode]; +} + +- (NSUInteger)maximumNumberOfActiveVersions { + if (_config.max_number_of_active_versions > std::numeric_limits::max()) { + return std::numeric_limits::max(); + } + return static_cast(_config.max_number_of_active_versions); +} + +- (void)setMaximumNumberOfActiveVersions:(NSUInteger)maximumNumberOfActiveVersions { + if (maximumNumberOfActiveVersions == 0) { + _config.max_number_of_active_versions = std::numeric_limits::max(); + } + else { + _config.max_number_of_active_versions = maximumNumberOfActiveVersions; + } +} + +- (void)setDynamic:(bool)dynamic { + _dynamic = dynamic; + self.cache = !dynamic; +} + +- (bool)disableFormatUpgrade { + return _config.disable_format_upgrade; +} + +- (void)setDisableFormatUpgrade:(bool)disableFormatUpgrade { + _config.disable_format_upgrade = disableFormatUpgrade; +} + +- (realm::SchemaMode)schemaMode { + return _config.schema_mode; +} + +- (void)setSchemaMode:(realm::SchemaMode)mode { + _config.schema_mode = mode; +} + +- (NSString *)pathOnDisk { + return @(_config.path.c_str()); +} + +- (void)setShouldCompactOnLaunch:(RLMShouldCompactOnLaunchBlock)shouldCompactOnLaunch { + if (shouldCompactOnLaunch) { + if (_config.immutable()) { + @throw RLMException(@"Cannot set `shouldCompactOnLaunch` when `readOnly` is set."); + } + _config.should_compact_on_launch_function = shouldCompactOnLaunch; + } + else { + _config.should_compact_on_launch_function = nullptr; + } + _shouldCompactOnLaunch = shouldCompactOnLaunch; +} + +- (void)setCustomSchemaWithoutCopying:(RLMSchema *)schema { + _customSchema = schema; +} + +- (bool)disableAutomaticChangeNotifications { + return !_config.automatic_change_notifications; +} + +- (void)setDisableAutomaticChangeNotifications:(bool)disableAutomaticChangeNotifications { + _config.automatic_change_notifications = !disableAutomaticChangeNotifications; +} + +#if REALM_ENABLE_SYNC +- (void)setSyncConfiguration:(RLMSyncConfiguration *)syncConfiguration { + if (syncConfiguration == nil) { + _config.sync_config = nullptr; + return; + } + RLMUser *user = syncConfiguration.user; + if (user.state == RLMUserStateRemoved) { + @throw RLMException(@"Cannot set a sync configuration which has an errored-out user."); + } + + NSAssert(user.identifier, @"Cannot call this method on a user that doesn't have an identifier."); + _config.in_memory = false; + _config.sync_config = std::make_shared(syncConfiguration.rawConfiguration); + _config.path = syncConfiguration.path; + + // The manual client reset handler doesn't exist on the raw config, + // so assign it here. + _manualClientResetHandler = syncConfiguration.manualClientResetHandler; + + [self updateSchemaMode]; +} + +- (RLMSyncConfiguration *)syncConfiguration { + if (!_config.sync_config) { + return nil; + } + RLMSyncConfiguration* syncConfig = [[RLMSyncConfiguration alloc] initWithRawConfig:*_config.sync_config path:_config.path]; + syncConfig.manualClientResetHandler = _manualClientResetHandler; + return syncConfig; +} + +#else // REALM_ENABLE_SYNC +- (RLMSyncConfiguration *)syncConfiguration { + return nil; +} +#endif // REALM_ENABLE_SYNC + +- (realm::Realm::Config)config { + auto config = _config; + if (config.sync_config) { + config.sync_config = std::make_shared(*config.sync_config); + } +#if REALM_ENABLE_SYNC + if (config.sync_config) { + RLMSetConfigInfoForClientResetCallbacks(*config.sync_config, self); + } + if (_eventConfiguration) { + config.audit_config = [_eventConfiguration auditConfigWithRealmConfiguration:self]; + } +#endif + return config; +} + +@end diff --git a/Pods/Realm/Realm/RLMRealmUtil.mm b/Pods/Realm/Realm/RLMRealmUtil.mm new file mode 100644 index 0000000..2fad212 --- /dev/null +++ b/Pods/Realm/Realm/RLMRealmUtil.mm @@ -0,0 +1,279 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// 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 "RLMRealmUtil.hpp" + +#import "RLMAsyncTask_Private.h" +#import "RLMObservation.hpp" +#import "RLMRealmConfiguration_Private.hpp" +#import "RLMRealm_Private.hpp" +#import "RLMScheduler.h" +#import "RLMUtil.hpp" + +#import +#import +#import +#import + +#import + +// Global realm state +static auto& s_realmCacheMutex = *new RLMUnfairMutex; +static auto& s_realmsPerPath = *new std::map(); +static auto& s_frozenRealms = *new std::map(); + +void RLMCacheRealm(__unsafe_unretained RLMRealmConfiguration *const configuration, + RLMScheduler *scheduler, + __unsafe_unretained RLMRealm *const realm) { + auto& path = configuration.path; + auto key = scheduler.cacheKey; + std::lock_guard lock(s_realmCacheMutex); + NSMapTable *realms = s_realmsPerPath[path]; + if (!realms) { + s_realmsPerPath[path] = realms = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsOpaquePersonality|NSPointerFunctionsOpaqueMemory + valueOptions:NSPointerFunctionsWeakMemory]; + } + [realms setObject:realm forKey:(__bridge id)key]; +} + +RLMRealm *RLMGetCachedRealm(__unsafe_unretained RLMRealmConfiguration *const configuration, + RLMScheduler *scheduler) { + auto key = scheduler.cacheKey; + auto& path = configuration.path; + std::lock_guard lock(s_realmCacheMutex); + RLMRealm *realm = [s_realmsPerPath[path] objectForKey:(__bridge id)key]; + if (realm && !realm->_realm->scheduler()->is_on_thread()) { + // We can get here in two cases: if the user is trying to open a + // queue-bound Realm from the wrong queue, or if we have a stale cached + // Realm which is bound to a thread that no longer exists. In the first + // case we'll throw an error later on; in the second we'll just create + // a new RLMRealm and replace the cache entry with one bound to the + // thread that now exists. + realm = nil; + } + return realm; +} + +RLMRealm *RLMGetAnyCachedRealm(__unsafe_unretained RLMRealmConfiguration *const configuration) { + return RLMGetAnyCachedRealmForPath(configuration.path); +} + +RLMRealm *RLMGetAnyCachedRealmForPath(std::string const& path) { + std::lock_guard lock(s_realmCacheMutex); + return [s_realmsPerPath[path] objectEnumerator].nextObject; +} + +void RLMClearRealmCache() { + std::lock_guard lock(s_realmCacheMutex); + s_realmsPerPath.clear(); + s_frozenRealms.clear(); +} + +RLMRealm *RLMGetFrozenRealmForSourceRealm(__unsafe_unretained RLMRealm *const sourceRealm) { + std::lock_guard lock(s_realmCacheMutex); + auto& r = *sourceRealm->_realm; + auto& path = r.config().path; + NSMapTable *realms = s_realmsPerPath[path]; + if (!realms) { + s_realmsPerPath[path] = realms = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsIntegerPersonality|NSPointerFunctionsOpaqueMemory + valueOptions:NSPointerFunctionsWeakMemory]; + } + r.read_group(); + auto version = reinterpret_cast(r.read_transaction_version().version); + RLMRealm *realm = [realms objectForKey:(__bridge id)version]; + if (!realm) { + realm = [sourceRealm frozenCopy]; + [realms setObject:realm forKey:(__bridge id)version]; + } + return realm; +} + +namespace { +void advance_to_ready(realm::Realm& realm) { + if (!realm.auto_refresh()) { + realm.set_auto_refresh(true); + realm.notify(); + realm.set_auto_refresh(false); + } +} + +class RLMNotificationHelper : public realm::BindingContext { +public: + RLMNotificationHelper(RLMRealm *realm) : _realm(realm) { } + + void before_notify() override { + @autoreleasepool { + auto blocks = std::move(_beforeNotify); + _beforeNotify.clear(); + for (auto block : blocks) { + block(); + } + } + } + + void changes_available() override { + @autoreleasepool { + auto realm = _realm; + if (!realm || realm.autorefresh) { + return; + } + + // If an async refresh has been requested, then do that now instead + // of notifying of a pending version available. Note that this will + // recursively call this function and then exit above due to + // autorefresh being true. + if (_refreshHandlers.empty()) { + [realm sendNotifications:RLMRealmRefreshRequiredNotification]; + } + else { + advance_to_ready(*realm->_realm); + } + } + } + + std::vector get_observed_rows() override { + @autoreleasepool { + if (auto realm = _realm) { + [realm detachAllEnumerators]; + return RLMGetObservedRows(realm->_info); + } + return {}; + } + } + + void will_change(std::vector const& observed, + std::vector const& invalidated) override { + @autoreleasepool { + RLMWillChange(observed, invalidated); + } + } + + void did_change(std::vector const& observed, + std::vector const& invalidated, bool version_changed) override { + @autoreleasepool { + __strong auto realm = _realm; + try { + RLMDidChange(observed, invalidated); + if (version_changed) { + [realm sendNotifications:RLMRealmDidChangeNotification]; + } + } + catch (...) { + // This can only be called during a write transaction if it was + // called due to the transaction beginning, so cancel it to ensure + // exceptions thrown here behave the same as exceptions thrown when + // actually beginning the write + if (realm.inWriteTransaction) { + [realm cancelWriteTransaction]; + } + throw; + } + + if (!realm || !version_changed) { + return; + } + auto new_version = realm->_realm->current_transaction_version(); + if (!new_version) { + return; + } + + std::erase_if(_refreshHandlers, [&](auto& handler) { + auto& [target_version, completion] = handler; + if (new_version->version >= target_version) { + completion(true); + return true; + } + return false; + }); + } + } + + void add_before_notify_block(dispatch_block_t block) { + _beforeNotify.push_back(block); + } + + void wait_for_refresh(realm::DB::version_type version, RLMAsyncRefreshCompletion completion) { + _refreshHandlers.emplace_back(version, completion); + } + +private: + // This is owned by the realm, so it needs to not retain the realm + __weak RLMRealm *const _realm; + std::vector _beforeNotify; + std::vector> _refreshHandlers; +}; +} // anonymous namespace + +std::unique_ptr RLMCreateBindingContext(__unsafe_unretained RLMRealm *const realm) { + return std::unique_ptr(new RLMNotificationHelper(realm)); +} + +void RLMAddBeforeNotifyBlock(RLMRealm *realm, dispatch_block_t block) { + static_cast(realm->_realm->m_binding_context.get())->add_before_notify_block(block); +} + +@implementation RLMPinnedRealm { + realm::TransactionRef _pin; +} + +- (instancetype)initWithRealm:(RLMRealm *)realm { + if (self = [super init]) { + _pin = realm->_realm->duplicate(); + _configuration = realm.configuration; + } + return self; +} + +- (void)unpin { + _pin.reset(); +} +@end + +RLMAsyncRefreshTask *RLMRealmRefreshAsync(RLMRealm *rlmRealm) { + auto& realm = *rlmRealm->_realm; + if (realm.is_frozen() || realm.config().immutable()) { + return nil; + } + + // Refresh is a no-op if the Realm isn't currently in a read transaction + // or is up-to-date + auto latest = realm.latest_snapshot_version(); + auto current = realm.current_transaction_version(); + if (!latest || !current || current->version == *latest) + return nil; + + // If autorefresh is disabled, we may have already been notified of a new + // version and simply not advanced to it. + advance_to_ready(realm); + + // This may have advanced to the latest version in which case there's + // nothing left to do + current = realm.current_transaction_version(); + if (current && current->version >= *latest) + return [RLMAsyncRefreshTask completedRefresh]; + auto refresh = [[RLMAsyncRefreshTask alloc] init]; + + // Register the continuation to be called once the new version is ready + auto& context = static_cast(*realm.m_binding_context); + context.wait_for_refresh(*latest, ^(bool didRefresh) { [refresh complete:didRefresh]; }); + return refresh; +} + +void RLMRunAsyncNotifiers(NSString *path) { + realm::_impl::RealmCoordinator::get_existing_coordinator(path.UTF8String)->on_change(); +} diff --git a/Pods/Realm/Realm/RLMResults.mm b/Pods/Realm/Realm/RLMResults.mm new file mode 100644 index 0000000..7df0958 --- /dev/null +++ b/Pods/Realm/Realm/RLMResults.mm @@ -0,0 +1,594 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// 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 "RLMResults_Private.hpp" + +#import "RLMAccessor.hpp" +#import "RLMArray_Private.hpp" +#import "RLMCollection_Private.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObjectStore.h" +#import "RLMObject_Private.hpp" +#import "RLMObservation.hpp" +#import "RLMProperty_Private.h" +#import "RLMQueryUtil.hpp" +#import "RLMRealmConfiguration_Private.hpp" +#import "RLMSchema_Private.h" +#import "RLMSectionedResults_Private.hpp" +#import "RLMThreadSafeReference_Private.hpp" +#import "RLMUtil.hpp" + +#import +#import +#import + +#import + +using namespace realm; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wincomplete-implementation" +@implementation RLMNotificationToken +- (bool)invalidate { + return false; +} +@end +#pragma clang diagnostic pop + +@interface RLMResults () +@end + +// +// RLMResults implementation +// +@implementation RLMResults { + RLMRealm *_realm; + RLMClassInfo *_info; +} + +- (instancetype)initPrivate { + self = [super init]; + return self; +} + +- (instancetype)initWithResults:(Results)results { + if (self = [super init]) { + _results = std::move(results); + } + return self; +} + +static void assertKeyPathIsNotNested(NSString *keyPath) { + if ([keyPath rangeOfString:@"."].location != NSNotFound) { + @throw RLMException(@"Nested key paths are not supported yet for KVC collection operators."); + } +} + +void RLMThrowCollectionException(NSString *collectionName) { + try { + throw; + } + catch (realm::WrongTransactionState const&) { + @throw RLMException(@"Cannot modify %@ outside of a write transaction.", collectionName); + } + catch (realm::OutOfBounds const& e) { + @throw RLMException(@"Index %zu is out of bounds (must be less than %zu).", + e.index, e.size); + } + catch (realm::Exception const& e) { + @throw RLMException(e); + } + catch (std::exception const& e) { + @throw RLMException(e); + } +} + +template +__attribute__((always_inline)) +static auto translateErrors(Function&& f) { + return translateCollectionError(static_cast(f), @"Results"); +} + +- (instancetype)initWithObjectInfo:(RLMClassInfo&)info + results:(realm::Results&&)results { + if (self = [super init]) { + _results = std::move(results); + _realm = info.realm; + _info = &info; + } + return self; +} + ++ (instancetype)resultsWithObjectInfo:(RLMClassInfo&)info + results:(realm::Results&&)results { + return [[self alloc] initWithObjectInfo:info results:std::move(results)]; +} + ++ (instancetype)emptyDetachedResults { + return [[self alloc] initPrivate]; +} + +- (instancetype)subresultsWithResults:(realm::Results)results { + return [self.class resultsWithObjectInfo:*_info results:std::move(results)]; +} + +static inline void RLMResultsValidateInWriteTransaction(__unsafe_unretained RLMResults *const ar) { + ar->_realm->_realm->verify_thread(); + ar->_realm->_realm->verify_in_write(); +} + +- (BOOL)isInvalidated { + return translateErrors([&] { return !_results.is_valid(); }); +} + +- (NSUInteger)count { + return translateErrors([&] { return _results.size(); }); +} + +- (RLMPropertyType)type { + return translateErrors([&] { + return static_cast(_results.get_type() & ~realm::PropertyType::Nullable); + }); +} + +- (BOOL)isOptional { + return translateErrors([&] { + return is_nullable(_results.get_type()); + }); +} + +- (NSString *)objectClassName { + return translateErrors([&] { + if (_info && _results.get_type() == realm::PropertyType::Object) { + return _info->rlmObjectSchema.className; + } + return (NSString *)nil; + }); +} + +- (RLMClassInfo *)objectInfo { + return _info; +} + +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state + objects:(__unused __unsafe_unretained id [])buffer + count:(NSUInteger)len { + if (!_info) { + return 0; + } + if (state->state == 0) { + translateErrors([&] { + _results.evaluate_query_if_needed(); + }); + } + return RLMFastEnumerate(state, len, self); +} + +- (NSUInteger)indexOfObjectWhere:(NSString *)predicateFormat, ... { + va_list args; + va_start(args, predicateFormat); + NSUInteger index = [self indexOfObjectWhere:predicateFormat args:args]; + va_end(args); + return index; +} + +- (NSUInteger)indexOfObjectWhere:(NSString *)predicateFormat args:(va_list)args { + return [self indexOfObjectWithPredicate:[NSPredicate predicateWithFormat:predicateFormat + arguments:args]]; +} + +- (NSUInteger)indexOfObjectWithPredicate:(NSPredicate *)predicate { + if (_results.get_mode() == Results::Mode::Empty) { + return NSNotFound; + } + + return translateErrors([&] { + if (_results.get_type() != realm::PropertyType::Object) { + @throw RLMException(@"Querying is currently only implemented for arrays of Realm Objects"); + } + return RLMConvertNotFound(_results.index_of(RLMPredicateToQuery(predicate, _info->rlmObjectSchema, _realm.schema, _realm.group))); + }); +} + +- (id)objectAtIndex:(NSUInteger)index { + RLMAccessorContext ctx(*_info); + return translateErrors([&] { + return _results.get(ctx, index); + }); +} + +- (NSArray *)objectsAtIndexes:(NSIndexSet *)indexes { + if (!_info) { + return nil; + } + size_t c = self.count; + NSMutableArray *result = [[NSMutableArray alloc] initWithCapacity:indexes.count]; + NSUInteger i = [indexes firstIndex]; + RLMAccessorContext context(*_info); + while (i != NSNotFound) { + if (i >= 0 && i < c) { + [result addObject:_results.get(context, i)]; + } else { + return nil; + } + i = [indexes indexGreaterThanIndex:i]; + } + return result; +} + +- (id)firstObject { + if (!_info) { + return nil; + } + RLMAccessorContext ctx(*_info); + return translateErrors([&] { + return _results.first(ctx); + }); +} + +- (id)lastObject { + if (!_info) { + return nil; + } + RLMAccessorContext ctx(*_info); + return translateErrors([&] { + return _results.last(ctx); + }); +} + +- (NSUInteger)indexOfObject:(id)object { + if (!_info || !object) { + return NSNotFound; + } + if (RLMObjectBase *obj = RLMDynamicCast(object)) { + // Unmanaged objects are considered not equal to all managed objects + if (!obj->_realm && !obj.invalidated) { + return NSNotFound; + } + } + RLMAccessorContext ctx(*_info); + return translateErrors([&] { + return RLMConvertNotFound(_results.index_of(ctx, object)); + }); +} + +- (id)valueForKeyPath:(NSString *)keyPath { + if ([keyPath characterAtIndex:0] != '@') { + return [super valueForKeyPath:keyPath]; + } + if ([keyPath isEqualToString:@"@count"]) { + return @(self.count); + } + + NSRange operatorRange = [keyPath rangeOfString:@"." options:NSLiteralSearch]; + NSUInteger keyPathLength = keyPath.length; + NSUInteger separatorIndex = operatorRange.location != NSNotFound ? operatorRange.location : keyPathLength; + NSString *operatorName = [keyPath substringWithRange:NSMakeRange(1, separatorIndex - 1)]; + SEL opSelector = NSSelectorFromString([NSString stringWithFormat:@"_%@ForKeyPath:", operatorName]); + if (![self respondsToSelector:opSelector]) { + @throw RLMException(@"Unsupported KVC collection operator found in key path '%@'", keyPath); + } + if (separatorIndex >= keyPathLength - 1) { + @throw RLMException(@"Missing key path for KVC collection operator %@ in key path '%@'", + operatorName, keyPath); + } + NSString *operatorKeyPath = [keyPath substringFromIndex:separatorIndex + 1]; + return ((id(*)(id, SEL, id))objc_msgSend)(self, opSelector, operatorKeyPath); +} + +- (id)valueForKey:(NSString *)key { + if (!_info) { + return @[]; + } + return translateErrors([&] { + return RLMCollectionValueForKey(_results, key, *_info); + }); +} + +- (void)setValue:(id)value forKey:(NSString *)key { + translateErrors([&] { RLMResultsValidateInWriteTransaction(self); }); + RLMCollectionSetValueForKey(self, key, value); +} + +- (NSNumber *)_aggregateForKeyPath:(NSString *)keyPath + method:(std::optional (Results::*)(ColKey))method + methodName:(NSString *)methodName returnNilForEmpty:(BOOL)returnNilForEmpty { + assertKeyPathIsNotNested(keyPath); + return [self aggregate:keyPath method:method returnNilForEmpty:returnNilForEmpty]; +} + +- (NSNumber *)_minForKeyPath:(NSString *)keyPath { + return [self _aggregateForKeyPath:keyPath method:&Results::min methodName:@"@min" returnNilForEmpty:YES]; +} + +- (NSNumber *)_maxForKeyPath:(NSString *)keyPath { + return [self _aggregateForKeyPath:keyPath method:&Results::max methodName:@"@max" returnNilForEmpty:YES]; +} + +- (NSNumber *)_sumForKeyPath:(NSString *)keyPath { + return [self _aggregateForKeyPath:keyPath method:&Results::sum methodName:@"@sum" returnNilForEmpty:NO]; +} + +- (NSNumber *)_avgForKeyPath:(NSString *)keyPath { + assertKeyPathIsNotNested(keyPath); + return [self averageOfProperty:keyPath]; +} + +- (NSArray *)_unionOfObjectsForKeyPath:(NSString *)keyPath { + assertKeyPathIsNotNested(keyPath); + return translateErrors([&] { + return RLMCollectionValueForKey(_results, keyPath, *_info); + }); +} + +- (NSArray *)_distinctUnionOfObjectsForKeyPath:(NSString *)keyPath { + return [NSSet setWithArray:[self _unionOfObjectsForKeyPath:keyPath]].allObjects; +} + +- (NSArray *)_unionOfArraysForKeyPath:(NSString *)keyPath { + assertKeyPathIsNotNested(keyPath); + if ([keyPath isEqualToString:@"self"]) { + @throw RLMException(@"self is not a valid key-path for a KVC array collection operator as 'unionOfArrays'."); + } + + return translateErrors([&] { + NSMutableArray *flatArray = [NSMutableArray new]; + for (id array in RLMCollectionValueForKey(_results, keyPath, *_info)) { + for (id value in array) { + [flatArray addObject:value]; + } + } + return flatArray; + }); +} + +- (NSArray *)_distinctUnionOfArraysForKeyPath:(__unused NSString *)keyPath { + return [NSSet setWithArray:[self _unionOfArraysForKeyPath:keyPath]].allObjects; +} + +- (RLMResults *)objectsWhere:(NSString *)predicateFormat, ... { + va_list args; + va_start(args, predicateFormat); + RLMResults *results = [self objectsWhere:predicateFormat args:args]; + va_end(args); + return results; +} + +- (RLMResults *)objectsWhere:(NSString *)predicateFormat args:(va_list)args { + return [self objectsWithPredicate:[NSPredicate predicateWithFormat:predicateFormat arguments:args]]; +} + +- (RLMResults *)objectsWithPredicate:(NSPredicate *)predicate { + return translateErrors([&] { + if (_results.get_mode() == Results::Mode::Empty) { + return self; + } + if (_results.get_type() != realm::PropertyType::Object) { + @throw RLMException(@"Querying is currently only implemented for arrays of Realm Objects"); + } + auto query = RLMPredicateToQuery(predicate, _info->rlmObjectSchema, _realm.schema, _realm.group); + return [self subresultsWithResults:_results.filter(std::move(query))]; + }); +} + +- (RLMResults *)sortedResultsUsingKeyPath:(NSString *)keyPath ascending:(BOOL)ascending { + return [self sortedResultsUsingDescriptors:@[[RLMSortDescriptor sortDescriptorWithKeyPath:keyPath ascending:ascending]]]; +} + +- (RLMResults *)sortedResultsUsingDescriptors:(NSArray *)properties { + if (properties.count == 0) { + return self; + } + return translateErrors([&] { + if (_results.get_mode() == Results::Mode::Empty) { + return self; + } + return [self subresultsWithResults:_results.sort(RLMSortDescriptorsToKeypathArray(properties))]; + }); +} + +- (RLMResults *)distinctResultsUsingKeyPaths:(NSArray *)keyPaths { + for (NSString *keyPath in keyPaths) { + if ([keyPath rangeOfString:@"@"].location != NSNotFound) { + @throw RLMException(@"Cannot distinct on keypath '%@': KVC collection operators are not supported.", keyPath); + } + } + return translateErrors([&] { + if (_results.get_mode() == Results::Mode::Empty) { + return self; + } + + std::vector keyPathsVector; + for (NSString *keyPath in keyPaths) { + keyPathsVector.push_back(keyPath.UTF8String); + } + + return [self subresultsWithResults:_results.distinct(keyPathsVector)]; + }); +} + +- (id)objectAtIndexedSubscript:(NSUInteger)index { + return [self objectAtIndex:index]; +} + +- (id)aggregate:(NSString *)property + method:(std::optional (Results::*)(ColKey))method +returnNilForEmpty:(BOOL)returnNilForEmpty { + if (_results.get_mode() == Results::Mode::Empty) { + return returnNilForEmpty ? nil : @0; + } + ColKey column; + if (self.type == RLMPropertyTypeObject || ![property isEqualToString:@"self"]) { + column = _info->tableColumn(property); + } + + auto value = translateErrors([&] { return (_results.*method)(column); }); + return value ? RLMMixedToObjc(*value) : nil; +} + +- (id)minOfProperty:(NSString *)property { + return [self aggregate:property method:&Results::min returnNilForEmpty:YES]; +} + +- (id)maxOfProperty:(NSString *)property { + return [self aggregate:property method:&Results::max returnNilForEmpty:YES]; +} + +- (id)sumOfProperty:(NSString *)property { + return [self aggregate:property method:&Results::sum returnNilForEmpty:NO]; +} + +- (id)averageOfProperty:(NSString *)property { + return [self aggregate:property method:&Results::average returnNilForEmpty:YES]; +} + +- (RLMSectionedResults *)sectionedResultsSortedUsingKeyPath:(NSString *)keyPath + ascending:(BOOL)ascending + keyBlock:(RLMSectionedResultsKeyBlock)keyBlock { + return [[RLMSectionedResults alloc] initWithResults:[self sortedResultsUsingKeyPath:keyPath ascending:ascending] + keyBlock:keyBlock]; +} + +- (RLMSectionedResults *)sectionedResultsUsingSortDescriptors:(NSArray *)sortDescriptors + keyBlock:(RLMSectionedResultsKeyBlock)keyBlock { + return [[RLMSectionedResults alloc] initWithResults:[self sortedResultsUsingDescriptors:sortDescriptors] + keyBlock:keyBlock]; +} + +- (void)deleteObjectsFromRealm { + if (self.type != RLMPropertyTypeObject) { + @throw RLMException(@"Cannot delete objects from RLMResults<%@>: only RLMObjects can be deleted.", + RLMTypeToString(self.type)); + } + return translateErrors([&] { + if (_results.get_mode() == Results::Mode::Table) { + RLMResultsValidateInWriteTransaction(self); + RLMClearTable(*_info); + } + else { + RLMObservationTracker tracker(_realm, true); + _results.clear(); + } + }); +} + +- (NSString *)description { + return RLMDescriptionWithMaxDepth(@"RLMResults", self, RLMDescriptionMaxDepth); +} + +- (realm::TableView)tableView { + return translateErrors([&] { return _results.get_tableview(); }); +} + +- (RLMFastEnumerator *)fastEnumerator { + return translateErrors([&] { + return [[RLMFastEnumerator alloc] initWithResults:_results + collection:self + classInfo:*_info]; + }); +} + +- (RLMResults *)snapshot { + return translateErrors([&] { + return [self subresultsWithResults:_results.snapshot()]; + }); +} + +- (BOOL)isFrozen { + return _realm.frozen; +} + +- (instancetype)resolveInRealm:(RLMRealm *)realm { + return translateErrors([&] { + return [self.class resultsWithObjectInfo:_info->resolve(realm) + results:_results.freeze(realm->_realm)]; + }); +} + +- (instancetype)freeze { + if (self.frozen) { + return self; + } + return [self resolveInRealm:_realm.freeze]; +} + +- (instancetype)thaw { + if (!self.frozen) { + return self; + } + return [self resolveInRealm:_realm.thaw]; +} + +// The compiler complains about the method's argument type not matching due to +// it not having the generic type attached, but it doesn't seem to be possible +// to actually include the generic type +// http://www.openradar.me/radar?id=6135653276319744 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wmismatched-parameter-types" +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMResults *, RLMCollectionChange *, NSError *))block { + return RLMAddNotificationBlock(self, block, nil, nil); +} +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMResults *, RLMCollectionChange *, NSError *))block queue:(dispatch_queue_t)queue { + return RLMAddNotificationBlock(self, block, nil, queue); +} + +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMResults *, RLMCollectionChange *, NSError *))block keyPaths:(NSArray *)keyPaths { + return RLMAddNotificationBlock(self, block, keyPaths, nil); +} + +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMResults *, RLMCollectionChange *, NSError *))block + keyPaths:(NSArray *)keyPaths + queue:(dispatch_queue_t)queue { + return RLMAddNotificationBlock(self, block, keyPaths, queue); +} +#pragma clang diagnostic pop + +- (realm::NotificationToken)addNotificationCallback:(id)block +keyPaths:(std::optional>>>&&)keyPaths { + return _results.add_notification_callback(RLMWrapCollectionChangeCallback(block, self, true), std::move(keyPaths)); +} + +- (BOOL)isAttached { + return !!_realm; +} + +#pragma mark - Thread Confined Protocol Conformance + +- (realm::ThreadSafeReference)makeThreadSafeReference { + return _results; +} + +- (id)objectiveCMetadata { + return nil; +} + ++ (instancetype)objectWithThreadSafeReference:(realm::ThreadSafeReference)reference + metadata:(__unused id)metadata + realm:(RLMRealm *)realm { + auto results = reference.resolve(realm->_realm); + return [RLMResults resultsWithObjectInfo:realm->_info[RLMStringDataToNSString(results.get_object_type())] + results:std::move(results)]; +} + +@end + +@implementation RLMLinkingObjects +- (NSString *)description { + return RLMDescriptionWithMaxDepth(@"RLMLinkingObjects", self, RLMDescriptionMaxDepth); +} +@end diff --git a/Pods/Realm/Realm/RLMScheduler.mm b/Pods/Realm/Realm/RLMScheduler.mm new file mode 100644 index 0000000..75fd556 --- /dev/null +++ b/Pods/Realm/Realm/RLMScheduler.mm @@ -0,0 +1,217 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2023 Realm Inc. +// +// 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 "RLMScheduler.h" + +#import "RLMUtil.hpp" + +#include + +@interface RLMMainRunLoopScheduler : RLMScheduler +@end + +RLM_HIDDEN +@implementation RLMMainRunLoopScheduler +- (std::shared_ptr)osScheduler { + return realm::util::Scheduler::make_runloop(CFRunLoopGetMain()); +} + +- (void *)cacheKey { + // The main thread and main queue share a cache key of `std::numeric_limits::max()` + // so that they give the same instance. Other Realms are keyed on either the thread or the queue. + // Note that despite being a void* the cache key is not actually a pointer; + // this is just an artifact of NSMapTable's strange API. + return reinterpret_cast(std::numeric_limits::max()); +} + +// We can't access MainActor.shared directly from obj-c and need to set it from +// Swift. The locking here is _almost_ unnecessary as this is set from a static +// initializer before the value can ever be read, but mixed use of the obj-c and +// Swift APIs could potentially race on the read. +static auto& g_mainActorLock = *new RLMUnfairMutex; +static id g_mainActor; +void RLMSetMainActor(id actor) { + std::lock_guard lock(g_mainActorLock); + g_mainActor = actor; +} +- (id)actor { + std::lock_guard lock(g_mainActorLock); + return g_mainActor; +} + +- (void)invoke:(dispatch_block_t)block { + dispatch_async(dispatch_get_main_queue(), block); +} +@end + +@interface RLMDispatchQueueScheduler : RLMScheduler +@end + +RLM_HIDDEN +@implementation RLMDispatchQueueScheduler { + dispatch_queue_t _queue; +} + +- (instancetype)initWithQueue:(dispatch_queue_t)queue { + if (self = [super init]) { + _queue = queue; + } + return self; +} + +- (void)invoke:(dispatch_block_t)block { + dispatch_async(_queue, block); +} + +- (std::shared_ptr)osScheduler { + if (_queue == dispatch_get_main_queue()) { + return RLMScheduler.mainRunLoop.osScheduler; + } + return realm::util::Scheduler::make_dispatch((__bridge void *)_queue); +} + +- (void *)cacheKey { + if (_queue == dispatch_get_main_queue()) { + return RLMScheduler.mainRunLoop.cacheKey; + } + return (__bridge void *)_queue; +} +@end + +namespace { +class ActorScheduler final : public realm::util::Scheduler { +public: + ActorScheduler(void (^invoke)(dispatch_block_t), dispatch_block_t verify) + : _invoke(invoke) , _verify(verify) {} + + void invoke(realm::util::UniqueFunction&& fn) override { + auto ptr = fn.release(); + _invoke(^{ + realm::util::UniqueFunction fn(ptr); + fn(); + }); + } + + // This currently isn't actually implementable, but fortunately is only used + // to report errors when we aren't on the thread, so triggering the actor + // data race detection is good enough. + bool is_on_thread() const noexcept override { + _verify(); + return true; + } + + // This is used for OS Realm caching, which we don't use (as we have our own cache) + bool is_same_as(const Scheduler *) const noexcept override { + REALM_UNREACHABLE(); + } + + // Actor isolated Realms can always invoke blocks + bool can_invoke() const noexcept override { + return true; + } + +private: + void (^_invoke)(dispatch_block_t); + dispatch_block_t _verify; +}; +} + +@interface RLMActorScheduler : RLMScheduler +@end + +RLM_HIDDEN +@implementation RLMActorScheduler { + id _actor; + void (^_invoke)(dispatch_block_t); + void (^_verify)(); +} + +- (instancetype)initWithActor:(id)actor invoke:(void (^)(dispatch_block_t))invoke verify:(void (^)())verify { + if (self = [super init]) { + _actor = actor; + _invoke = invoke; + _verify = verify; + } + return self; +} + +- (void)invoke:(dispatch_block_t)block { + _invoke(block); +} + +- (std::shared_ptr)osScheduler { + return std::make_shared(_invoke, _verify); +} + +- (void *)cacheKey { + return (__bridge void *)_actor; +} + +- (id)actor { + return _actor; +} +@end + +@implementation RLMScheduler ++ (RLMScheduler *)currentRunLoop { + if (pthread_main_np()) { + return RLMScheduler.mainRunLoop; + } + + static RLMScheduler *currentRunLoopScheduler = [[RLMScheduler alloc] init]; + return currentRunLoopScheduler; +} + ++ (RLMScheduler *)mainRunLoop { + static RLMScheduler *mainRunLoopScheduler = [[RLMMainRunLoopScheduler alloc] init]; + return mainRunLoopScheduler; +} + ++ (RLMScheduler *)dispatchQueue:(dispatch_queue_t)queue { + if (queue) { + return [[RLMDispatchQueueScheduler alloc] initWithQueue:queue]; + } + return RLMScheduler.currentRunLoop; +} + ++ (RLMScheduler *)actor:(id)actor invoke:(void (^)(dispatch_block_t))invoke verify:(void (^)())verify { + auto mainRunLoopScheduler = RLMScheduler.mainRunLoop; + if (actor == mainRunLoopScheduler.actor) { + return mainRunLoopScheduler; + } + return [[RLMActorScheduler alloc] initWithActor:actor invoke:invoke verify:verify]; +} + +- (void)invoke:(dispatch_block_t)block { + // Currently not used or needed for run loops + REALM_UNREACHABLE(); +} + +- (std::shared_ptr)osScheduler { + // For normal thread-confined Realms we let object store create the scheduler + return nullptr; +} + +- (void *)cacheKey { + return pthread_self(); +} + +- (id)actor { + return nil; +} +@end diff --git a/Pods/Realm/Realm/RLMSchema.mm b/Pods/Realm/Realm/RLMSchema.mm new file mode 100644 index 0000000..aeb72f9 --- /dev/null +++ b/Pods/Realm/Realm/RLMSchema.mm @@ -0,0 +1,415 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// 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 "RLMSchema_Private.hpp" + +#import "RLMAccessor.h" +#import "RLMObjectBase_Private.h" +#import "RLMObject_Private.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMProperty_Private.h" +#import "RLMRealm_Private.hpp" +#import "RLMSwiftSupport.h" +#import "RLMUtil.hpp" + +#import +#import +#import +#import +#import + +#import +#import + +using namespace realm; + +const uint64_t RLMNotVersioned = realm::ObjectStore::NotVersioned; + +// RLMSchema private properties +@interface RLMSchema () +@property (nonatomic, readwrite) NSMutableDictionary *objectSchemaByName; +@end + +// Private RLMSchema subclass that skips class registration on lookup +@interface RLMPrivateSchema : RLMSchema +@end +@implementation RLMPrivateSchema +- (RLMObjectSchema *)schemaForClassName:(NSString *)className { + return self.objectSchemaByName[className]; +} + +- (RLMObjectSchema *)objectForKeyedSubscript:(__unsafe_unretained NSString *const)className { + return [self schemaForClassName:className]; +} +@end + +static RLMSchema *s_sharedSchema = [[RLMSchema alloc] init]; +static NSMutableDictionary *s_localNameToClass = [[NSMutableDictionary alloc] init]; +static RLMSchema *s_privateSharedSchema = [[RLMPrivateSchema alloc] init]; + +static enum class SharedSchemaState { + Uninitialized, + Initializing, + Initialized +} s_sharedSchemaState = SharedSchemaState::Uninitialized; + +@implementation RLMSchema { + NSArray *_objectSchema; + realm::Schema _objectStoreSchema; +} + +static void createAccessors(RLMObjectSchema *objectSchema) { + constexpr const size_t bufferSize + = sizeof("RLM:Managed ") // includes spot for null terminator + + std::numeric_limits::digits10 + + realm::Group::max_table_name_length; + + char className[bufferSize] = "RLM:Managed "; + char *const start = className + strlen(className); + + static unsigned long long count = 0; + snprintf(start, bufferSize - strlen(className), + "%llu %s", count++, objectSchema.className.UTF8String); + objectSchema.accessorClass = RLMManagedAccessorClassForObjectClass(objectSchema.objectClass, objectSchema, className); + objectSchema.unmanagedClass = RLMUnmanagedAccessorClassForObjectClass(objectSchema.objectClass, objectSchema); +} + +void RLMSchemaEnsureAccessorsCreated(RLMSchema *schema) { + for (RLMObjectSchema *objectSchema in schema.objectSchema) { + if (objectSchema.accessorClass == objectSchema.objectClass) { + // Locking inside the loop to optimize for the common case at + // the expense of worse perf in the rare scenario where this is + // actually needed. + @synchronized(s_localNameToClass) { + createAccessors(objectSchema); + } + } + } +} + +// Caller must @synchronize on s_localNameToClass +static RLMObjectSchema *registerClass(Class cls) { + if (RLMObjectSchema *schema = s_privateSharedSchema[[cls className]]) { + return schema; + } + + auto prevState = s_sharedSchemaState; + s_sharedSchemaState = SharedSchemaState::Initializing; + RLMObjectSchema *schema; + { + util::ScopeExit cleanup([&]() noexcept { + s_sharedSchemaState = prevState; + }); + schema = [RLMObjectSchema schemaForObjectClass:cls]; + } + + createAccessors(schema); + // override sharedSchema class methods for performance + RLMReplaceSharedSchemaMethod(cls, schema); + + s_privateSharedSchema.objectSchemaByName[schema.className] = schema; + if ([cls shouldIncludeInDefaultSchema] && prevState != SharedSchemaState::Initialized) { + s_sharedSchema.objectSchemaByName[schema.className] = schema; + } + + return schema; +} + +// Caller must @synchronize on s_localNameToClass +static void RLMRegisterClassLocalNames(Class *classes, NSUInteger count) { + for (NSUInteger i = 0; i < count; i++) { + Class cls = classes[i]; + if (!RLMIsObjectSubclass(cls)) { + continue; + } + if ([cls _realmIgnoreClass]) { + continue; + } + + NSString *className = NSStringFromClass(cls); + if ([className hasPrefix:@"RLM:"] || [className hasPrefix:@"NSKVONotifying"]) { + continue; + } + + if ([RLMSwiftSupport isSwiftClassName:className]) { + className = [RLMSwiftSupport demangleClassName:className]; + } + // NSStringFromClass demangles the names for top-level Swift classes + // but not for nested classes. _T indicates it's a Swift symbol, t + // indicates it's a type, and C indicates it's a class. + else if ([className hasPrefix:@"_TtC"]) { + @throw RLMException(@"Object subclass '%@' must explicitly set the class's objective-c name with @objc(ClassName) because it is not a top-level public class.", className); + } + + if (Class existingClass = s_localNameToClass[className]) { + if (existingClass != cls) { + @throw RLMException(@"RLMObject subclasses with the same name cannot be included twice in the same target. " + @"Please make sure '%@' is only linked once to your current target.", className); + } + continue; + } + + s_localNameToClass[className] = cls; + RLMReplaceClassNameMethod(cls, className); + } +} + +- (instancetype)init { + self = [super init]; + if (self) { + _objectSchemaByName = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (NSArray *)objectSchema { + if (!_objectSchema) { + _objectSchema = [_objectSchemaByName allValues]; + } + return _objectSchema; +} + +- (void)setObjectSchema:(NSArray *)objectSchema { + _objectSchema = objectSchema; + _objectSchemaByName = [NSMutableDictionary dictionaryWithCapacity:objectSchema.count]; + for (RLMObjectSchema *object in objectSchema) { + [_objectSchemaByName setObject:object forKey:object.className]; + } +} + +- (RLMObjectSchema *)schemaForClassName:(NSString *)className { + if (RLMObjectSchema *schema = _objectSchemaByName[className]) { + return schema; // fast path for already-initialized schemas + } else if (Class cls = [RLMSchema classForString:className]) { + [cls sharedSchema]; // initialize the schema + return _objectSchemaByName[className]; // try again + } else { + return nil; + } +} + +- (RLMObjectSchema *)objectForKeyedSubscript:(__unsafe_unretained NSString *const)className { + RLMObjectSchema *schema = [self schemaForClassName:className]; + if (!schema) { + @throw RLMException(@"Object type '%@' not managed by the Realm", className); + } + return schema; +} + ++ (instancetype)schemaWithObjectClasses:(NSArray *)classes { + NSUInteger count = classes.count; + auto classArray = std::make_unique<__unsafe_unretained Class[]>(count); + [classes getObjects:classArray.get() range:NSMakeRange(0, count)]; + + RLMSchema *schema = [[self alloc] init]; + @synchronized(s_localNameToClass) { + RLMRegisterClassLocalNames(classArray.get(), count); + + schema->_objectSchemaByName = [NSMutableDictionary dictionaryWithCapacity:count]; + for (Class cls in classes) { + if (!RLMIsObjectSubclass(cls)) { + @throw RLMException(@"Can't add non-Object type '%@' to a schema.", cls); + } + schema->_objectSchemaByName[[cls className]] = registerClass(cls); + } + } + + NSMutableArray *errors = [NSMutableArray new]; + // Verify that all of the targets of links are included in the class list + [schema->_objectSchemaByName enumerateKeysAndObjectsUsingBlock:^(id, RLMObjectSchema *objectSchema, BOOL *) { + for (RLMProperty *prop in objectSchema.properties) { + if (prop.type != RLMPropertyTypeObject) { + continue; + } + if (!schema->_objectSchemaByName[prop.objectClassName]) { + [errors addObject:[NSString stringWithFormat:@"- '%@.%@' links to class '%@', which is missing from the list of classes managed by the Realm", objectSchema.className, prop.name, prop.objectClassName]]; + } + } + }]; + if (errors.count) { + @throw RLMException(@"Invalid class subset list:\n%@", [errors componentsJoinedByString:@"\n"]); + } + + return schema; +} + ++ (RLMObjectSchema *)sharedSchemaForClass:(Class)cls { + @synchronized(s_localNameToClass) { + // We create instances of Swift objects during schema init, and they + // obviously need to not also try to initialize the schema + if (s_sharedSchemaState == SharedSchemaState::Initializing) { + return nil; + } + // Don't register the base classes in the schema even if someone calls + // sharedSchema on them directly + if (cls == [RLMObjectBase class] || class_getSuperclass(cls) == [RLMObjectBase class]) { + return nil; + } + + RLMRegisterClassLocalNames(&cls, 1); + RLMObjectSchema *objectSchema = registerClass(cls); + [cls initializeLinkedObjectSchemas]; + return objectSchema; + } +} + ++ (instancetype)partialSharedSchema { + return s_sharedSchema; +} + ++ (instancetype)partialPrivateSharedSchema { + return s_privateSharedSchema; +} + +// schema based on runtime objects ++ (instancetype)sharedSchema { + @synchronized(s_localNameToClass) { + // We replace this method with one which just returns s_sharedSchema + // once initialization is complete, but we still need to check if it's + // already complete because it may have been done by another thread + // while we were waiting for the lock + if (s_sharedSchemaState == SharedSchemaState::Initialized) { + return s_sharedSchema; + } + + if (s_sharedSchemaState == SharedSchemaState::Initializing) { + @throw RLMException(@"Illegal recursive call of +[%@ %@]. Note: Properties of Swift `Object` classes must not be prepopulated with queried results from a Realm.", self, NSStringFromSelector(_cmd)); + } + + s_sharedSchemaState = SharedSchemaState::Initializing; + try { + // Make sure we've discovered all classes + { + unsigned int numClasses; + using malloc_ptr = std::unique_ptr<__unsafe_unretained Class[], decltype(&free)>; + malloc_ptr classes(objc_copyClassList(&numClasses), &free); + RLMRegisterClassLocalNames(classes.get(), numClasses); + } + + [s_localNameToClass enumerateKeysAndObjectsUsingBlock:^(NSString *, Class cls, BOOL *) { + registerClass(cls); + }]; + } + catch (...) { + s_sharedSchemaState = SharedSchemaState::Uninitialized; + throw; + } + + // Replace this method with one that doesn't need to acquire a lock + Class metaClass = objc_getMetaClass(class_getName(self)); + IMP imp = imp_implementationWithBlock(^{ return s_sharedSchema; }); + class_replaceMethod(metaClass, @selector(sharedSchema), imp, "@@:"); + + s_sharedSchemaState = SharedSchemaState::Initialized; + } + + return s_sharedSchema; +} + +// schema based on tables in a realm ++ (instancetype)dynamicSchemaFromObjectStoreSchema:(Schema const&)objectStoreSchema { + // cache descriptors for all subclasses of RLMObject + NSMutableArray *schemaArray = [NSMutableArray arrayWithCapacity:objectStoreSchema.size()]; + for (auto &objectSchema : objectStoreSchema) { + RLMObjectSchema *schema = [RLMObjectSchema objectSchemaForObjectStoreSchema:objectSchema]; + [schemaArray addObject:schema]; + } + + // set class array and mapping + RLMSchema *schema = [RLMSchema new]; + schema.objectSchema = schemaArray; + return schema; +} + ++ (Class)classForString:(NSString *)className { + if (Class cls = s_localNameToClass[className]) { + return cls; + } + + if (Class cls = NSClassFromString(className)) { + return RLMIsObjectSubclass(cls) ? cls : nil; + } + + // className might be the local name of a Swift class we haven't registered + // yet, so scan them all then recheck + { + unsigned int numClasses; + std::unique_ptr<__unsafe_unretained Class[], decltype(&free)> classes(objc_copyClassList(&numClasses), &free); + RLMRegisterClassLocalNames(classes.get(), numClasses); + } + + return s_localNameToClass[className]; +} + +- (id)copyWithZone:(NSZone *)zone { + RLMSchema *schema = [[RLMSchema allocWithZone:zone] init]; + schema->_objectSchemaByName = [[NSMutableDictionary allocWithZone:zone] + initWithDictionary:_objectSchemaByName copyItems:YES]; + return schema; +} + +- (BOOL)isEqualToSchema:(RLMSchema *)schema { + if (_objectSchemaByName.count != schema->_objectSchemaByName.count) { + return NO; + } + __block BOOL matches = YES; + [_objectSchemaByName enumerateKeysAndObjectsUsingBlock:^(NSString *name, RLMObjectSchema *objectSchema, BOOL *stop) { + if (![schema->_objectSchemaByName[name] isEqualToObjectSchema:objectSchema]) { + *stop = YES; + matches = NO; + } + }]; + return matches; +} + +- (NSString *)description { + NSMutableString *objectSchemaString = [NSMutableString string]; + NSArray *sort = @[[NSSortDescriptor sortDescriptorWithKey:@"className" ascending:YES]]; + for (RLMObjectSchema *objectSchema in [self.objectSchema sortedArrayUsingDescriptors:sort]) { + [objectSchemaString appendFormat:@"\t%@\n", + [objectSchema.description stringByReplacingOccurrencesOfString:@"\n" withString:@"\n\t"]]; + } + return [NSString stringWithFormat:@"Schema {\n%@}", objectSchemaString]; +} + +- (Schema)objectStoreCopy { + if (_objectStoreSchema.size() == 0) { + std::vector schema; + schema.reserve(_objectSchemaByName.count); + [_objectSchemaByName enumerateKeysAndObjectsUsingBlock:[&](NSString *, RLMObjectSchema *objectSchema, BOOL *) { + schema.push_back([objectSchema objectStoreCopy:self]); + }]; + + // Having both obj-c and Swift classes for the same tables results in + // duplicate ObjectSchemas that we need to filter out + std::sort(begin(schema), end(schema), [](auto&& a, auto&& b) { return a.name < b.name; }); + schema.erase(std::unique(begin(schema), end(schema), [](auto&& a, auto&& b) { + if (a.name == b.name) { + // If we make _realmObjectName public this needs to be turned into an exception + REALM_ASSERT_DEBUG(a.persisted_properties == b.persisted_properties); + return true; + } + return false; + }), end(schema)); + + _objectStoreSchema = std::move(schema); + } + return _objectStoreSchema; +} + +@end diff --git a/Pods/Realm/Realm/RLMSectionedResults.mm b/Pods/Realm/Realm/RLMSectionedResults.mm new file mode 100644 index 0000000..df78ce8 --- /dev/null +++ b/Pods/Realm/Realm/RLMSectionedResults.mm @@ -0,0 +1,669 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2022 Realm Inc. +// +// 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 "RLMSectionedResults_Private.hpp" +#import "RLMAccessor.hpp" +#import "RLMCollection_Private.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObservation.hpp" +#import "RLMRealm_Private.hpp" +#import "RLMResults.h" +#import "RLMResults_Private.hpp" +#import "RLMThreadSafeReference_Private.hpp" + +namespace { +struct CollectionCallbackWrapper { + void (^block)(id, RLMSectionedResultsChange *); + id collection; + bool ignoreChangesInInitialNotification = true; + + void operator()(realm::SectionedResultsChangeSet const& changes) { + if (ignoreChangesInInitialNotification) { + ignoreChangesInInitialNotification = false; + return block(collection, nil); + } + + block(collection, [[RLMSectionedResultsChange alloc] initWithChanges:changes]); + } +}; + +template +__attribute__((always_inline)) +auto translateErrors(Function&& f) { + return translateCollectionError(static_cast(f), @"SectionedResults"); +} +} // anonymous namespace + +@implementation RLMSectionedResultsChange { + realm::SectionedResultsChangeSet _indices; +} + +- (instancetype)initWithChanges:(realm::SectionedResultsChangeSet)indices { + self = [super init]; + if (self) { + _indices = std::move(indices); + } + return self; +} + +- (NSArray *)indexesFromVector:(std::vector const&)indexMap { + NSMutableArray *a = [NSMutableArray new]; + for (size_t i = 0; i < indexMap.size(); ++i) { + NSUInteger path[2] = {i, 0}; + for (auto index : indexMap[i].as_indexes()) { + path[1] = index; + [a addObject:[NSIndexPath indexPathWithIndexes:path length:2]]; + } + } + return a; +} + +- (NSArray *)insertions { + return [self indexesFromVector:_indices.insertions]; +} + +- (NSArray *)deletions { + return [self indexesFromVector:_indices.deletions]; +} + +- (NSArray *)modifications { + return [self indexesFromVector:_indices.modifications]; +} + +- (NSIndexSet *)sectionsToInsert { + NSMutableIndexSet *indices = [NSMutableIndexSet new]; + for (auto i : _indices.sections_to_insert.as_indexes()) { + [indices addIndex:i]; + } + return indices; +} + +- (NSIndexSet *)sectionsToRemove { + NSMutableIndexSet *indices = [NSMutableIndexSet new]; + for (auto i : _indices.sections_to_delete.as_indexes()) { + [indices addIndex:i]; + } + return indices; +} + +/// Returns the index paths of the deletion indices in the given section. +- (NSArray *)deletionsInSection:(NSUInteger)section { + return RLMToIndexPathArray(_indices.deletions[section], section); +} + +/// Returns the index paths of the insertion indices in the given section. +- (NSArray *)insertionsInSection:(NSUInteger)section { + return RLMToIndexPathArray(_indices.insertions[section], section); +} + +/// Returns the index paths of the modification indices in the given section. +- (NSArray *)modificationsInSection:(NSUInteger)section { + return RLMToIndexPathArray(_indices.modifications[section], section); +} + +static NSString *indexPathToString(NSArray *indexes) { + if (indexes.count == 0) { + return @"[]"; + } + return [NSString stringWithFormat:@"[\n\t%@\n\t]", [indexes componentsJoinedByString:@"\n\t\t"]]; +}; + +static NSString *indexSetToString(NSIndexSet *sections) { + if (sections.count == 0) { + return @"[]"; + } + return [NSString stringWithFormat:@"[\n\t%@\n\t]", sections]; +} + +- (NSString *)description { + return [NSString stringWithFormat:@" {\n\tinsertions: %@,\n\tdeletions: %@,\n\tmodifications: %@,\n\tsectionsToInsert: %@,\n\tsectionsToRemove: %@\n}", + (__bridge void *)self, + indexPathToString(self.insertions), + indexPathToString(self.deletions), + indexPathToString(self.modifications), + indexSetToString(self.sectionsToInsert), indexSetToString(self.sectionsToRemove)]; +} + +@end + +struct SectionedResultsKeyProjection { + RLMClassInfo *_info; + RLMSectionedResultsKeyBlock _block; + + realm::Mixed operator()(realm::Mixed obj, realm::SharedRealm) { + RLMAccessorContext context(*_info); + id value = _block(context.box(obj)); + return context.unbox(value); + } +}; + +@interface RLMSectionedResultsEnumerator() { + // The buffer supplied by fast enumeration does not retain the objects given + // to it, but because we create objects on-demand and don't want them + // autoreleased (a table can have more rows than the device has memory for + // accessor objects) we need a thing to retain them. + id _strongBuffer[16]; + id _sectionedResult; +} +@end + +@implementation RLMSectionedResultsEnumerator + +- (instancetype)initWithSectionedResults:(RLMSectionedResults *)sectionedResults { + if (self = [super init]) { + _sectionedResult = [sectionedResults snapshot]; + return self; + } + return nil; +} + +- (instancetype)initWithResultsSection:(RLMSection *)resultsSection { + if (self = [super init]) { + _sectionedResult = resultsSection; + return self; + } + return nil; +} + +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state + count:(NSUInteger)len { + NSUInteger batchCount = 0, count = [_sectionedResult count]; + for (NSUInteger index = state->state; index < count && batchCount < len; ++index) { + id sectionedResults = [_sectionedResult objectAtIndex:index]; + _strongBuffer[batchCount] = sectionedResults; + batchCount++; + } + + for (NSUInteger i = batchCount; i < len; ++i) { + _strongBuffer[i] = nil; + } + + if (batchCount == 0) { + // Release our data if we're done, as we're autoreleased and so may + // stick around for a while + if (_sectionedResult) { + _sectionedResult = nil; + } + } + + state->itemsPtr = (__unsafe_unretained id *)(void *)_strongBuffer; + state->state += batchCount; + state->mutationsPtr = state->extra+1; + + return batchCount; +} + +@end + +NSUInteger RLMFastEnumerate(NSFastEnumerationState *state, + NSUInteger len, + RLMSectionedResults *collection) { + __autoreleasing RLMSectionedResultsEnumerator *enumerator; + if (state->state == 0) { + enumerator = collection.fastEnumerator; + state->extra[0] = (long)enumerator; + state->extra[1] = collection.count; + } + else { + enumerator = (__bridge id)(void *)state->extra[0]; + } + + return [enumerator countByEnumeratingWithState:state count:len]; +} + +NSUInteger RLMFastEnumerate(NSFastEnumerationState *state, + NSUInteger len, + RLMSection *collection) { + __autoreleasing RLMSectionedResultsEnumerator *enumerator; + if (state->state == 0) { + enumerator = collection.fastEnumerator; + state->extra[0] = (long)enumerator; + state->extra[1] = collection.count; + } + else { + enumerator = (__bridge id)(void *)state->extra[0]; + } + + return [enumerator countByEnumeratingWithState:state count:len]; +} + +@interface RLMSectionedResults () +@end + +@implementation RLMSectionedResults { + @public + realm::SectionedResults _sectionedResults; + RLMSectionedResultsKeyBlock _keyBlock; + // We need to hold an instance to the parent + // `Results` so we can obtain a ThreadSafeReference + // for notifications. + realm::Results _results; + @private + RLMRealm *_realm; + RLMClassInfo *_info; +} + +- (instancetype)initWithResults:(realm::Results&&)results + realm:(RLMRealm *)realm + objectInfo:(RLMClassInfo&)objectInfo + keyBlock:(RLMSectionedResultsKeyBlock)keyBlock { + if (self = [super init]) { + _info = &objectInfo; + _realm = realm; + _keyBlock = keyBlock; + _results = std::move(results); + _sectionedResults = _results.sectioned_results(SectionedResultsKeyProjection{_info, _keyBlock}); + } + return self; +} + +- (instancetype)initWithSectionedResults:(realm::SectionedResults&&)sectionedResults + objectInfo:(RLMClassInfo&)objectInfo + keyBlock:(RLMSectionedResultsKeyBlock)keyBlock{ + if (self = [super init]) { + _info = &objectInfo; + _realm = _info->realm; + _sectionedResults = std::move(sectionedResults); + _keyBlock = keyBlock; + } + return self; +} + +- (instancetype)initWithResults:(RLMResults *)results + keyBlock:(RLMSectionedResultsKeyBlock)keyBlock { + if (self = [super init]) { + _info = results.objectInfo; + _realm = results.realm; + _keyBlock = keyBlock; + _results = results->_results; + _sectionedResults = results->_results.sectioned_results(SectionedResultsKeyProjection{_info, _keyBlock}); + } + return self; +} + +- (NSArray *)allKeys { + return translateErrors([&] { + NSUInteger count = [self count]; + NSMutableArray *arr = [NSMutableArray arrayWithCapacity:count]; + for (NSUInteger i = 0; i < count; i++) { + [arr addObject:RLMMixedToObjc(_sectionedResults[i].key())]; + } + return arr; + }); +} + +- (RLMSectionedResultsEnumerator *)fastEnumerator { + return [[RLMSectionedResultsEnumerator alloc] initWithSectionedResults:self]; +} + +- (RLMRealm *)realm { + return _realm; +} + +- (NSUInteger)count { + return translateErrors([&] { + return _sectionedResults.size(); + }); +} + +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state + objects:(__unused __unsafe_unretained id [])buffer + count:(NSUInteger)len { + return RLMFastEnumerate(state, len, self); +} + +- (id)objectAtIndexedSubscript:(NSUInteger)index { + return [self objectAtIndex:index]; +} + +- (id)objectAtIndex:(NSUInteger)index { + return [[RLMSection alloc] initWithResultsSection:_sectionedResults[index] + parent:self]; +} + +// The compiler complains about the method's argument type not matching due to +// it not having the generic type attached, but it doesn't seem to be possible +// to actually include the generic type +// http://www.openradar.me/radar?id=6135653276319744 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wmismatched-parameter-types" +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMResults *, RLMSectionedResultsChange *))block { + return RLMAddNotificationBlock(self, block, nil, nil); +} +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMResults *, RLMSectionedResultsChange *))block queue:(dispatch_queue_t)queue { + return RLMAddNotificationBlock(self, block, nil, queue); +} + +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMResults *, RLMSectionedResultsChange *))block + keyPaths:(NSArray *)keyPaths { + return RLMAddNotificationBlock(self, block, keyPaths, nil); +} + +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMResults *, RLMSectionedResultsChange *))block + keyPaths:(NSArray *)keyPaths + queue:(dispatch_queue_t)queue { + return RLMAddNotificationBlock(self, block, keyPaths, queue); +} +#pragma clang diagnostic pop + +- (realm::NotificationToken)addNotificationCallback:(id)block +keyPaths:(std::optional>>>&&)keyPaths { + return _sectionedResults.add_notification_callback(CollectionCallbackWrapper{block, self}, std::move(keyPaths)); +} + +- (RLMClassInfo *)objectInfo { + return _info; +} + +- (instancetype)resolveInRealm:(RLMRealm *)realm { + return translateErrors([&] { + if (realm.isFrozen) { + return [[RLMSectionedResults alloc] initWithSectionedResults:_sectionedResults.freeze(realm->_realm) + objectInfo:_info->resolve(realm) + keyBlock:_keyBlock]; + } + else { + auto sr = _sectionedResults.freeze(realm->_realm); + sr.reset_section_callback(SectionedResultsKeyProjection {&_info->resolve(realm), _keyBlock}); + return [[RLMSectionedResults alloc] initWithSectionedResults:std::move(sr) + objectInfo:_info->resolve(realm) + keyBlock:_keyBlock]; + } + }); +} + +- (instancetype)freeze { + if (self.frozen) { + return self; + } + return [self resolveInRealm:_realm.freeze]; +} + +- (instancetype)thaw { + if (!self.frozen) { + return self; + } + return [self resolveInRealm:_realm.thaw]; +} + + +#pragma mark - Thread Confined Protocol Conformance + +- (realm::ThreadSafeReference)makeThreadSafeReference { + return _results; +} + +- (id)objectiveCMetadata { + return _keyBlock; +} + ++ (instancetype)objectWithThreadSafeReference:(realm::ThreadSafeReference)reference + metadata:(id)metadata + realm:(RLMRealm *)realm { + auto results = reference.resolve(realm->_realm); + auto objType = RLMStringDataToNSString(results.get_object_type()); + return [[RLMSectionedResults alloc] initWithResults:std::move(results) + realm:realm + objectInfo:realm->_info[objType] + keyBlock:(RLMSectionedResultsKeyBlock)metadata]; +} + +- (BOOL)isInvalidated { + return translateErrors([&] { return !_sectionedResults.is_valid(); }); +} + +- (NSString *)description { + NSString *objType = @""; + if (_info) { + objType = [NSString stringWithFormat:@"<%@>", _info->rlmObjectSchema.className]; + } + const NSUInteger maxObjects = 100; + auto str = [NSMutableString stringWithFormat:@"RLMSectionedResults%@ <%p> (\n", objType, (void *)self]; + size_t index = 0, skipped = 0; + for (RLMSection *section in self) { + NSString *sub = [section description]; + // Indent child objects + NSString *objDescription = [sub stringByReplacingOccurrencesOfString:@"\n" + withString:@"\n\t"]; + [str appendFormat:@"\t[%@] %@,\n", section.key, objDescription]; + index++; + if (index >= maxObjects) { + skipped = self.count - maxObjects; + break; + } + } + + // Remove last comma and newline characters + if (self.count > 0) { + [str deleteCharactersInRange:NSMakeRange(str.length-2, 2)]; + } + if (skipped) { + [str appendFormat:@"\n\t... %zu objects skipped.", skipped]; + } + [str appendFormat:@"\n)"]; + return str; +} + +- (RLMSectionedResults *)snapshot { + RLMSectionedResults *sr = [RLMSectionedResults new]; + sr->_sectionedResults = _sectionedResults.snapshot(); + sr->_info = _info; + sr->_realm = _realm; + return sr; +} + +- (BOOL)isFrozen { + return translateErrors([&] { return _sectionedResults.is_frozen(); }); +} + +@end + +/// Stores information about a given section during thread handover. +@interface RLMSectionMetadata : NSObject + +@property (nonatomic, strong) RLMSectionedResultsKeyBlock keyBlock; +@property (nonatomic, copy) id sectionKey; + +- (instancetype)initWithKeyBlock:(RLMSectionedResultsKeyBlock)keyBlock + sectionKey:(id)sectionKey; +@end + +@implementation RLMSectionMetadata +- (instancetype)initWithKeyBlock:(RLMSectionedResultsKeyBlock)keyBlock + sectionKey:(id)sectionKey { + if (self = [super init]) { + _keyBlock = keyBlock; + _sectionKey = sectionKey; + } + return self; +} +@end + +@interface RLMSection () +@end + +@implementation RLMSection { + RLMSectionedResults *_parent; + realm::ResultsSection _resultsSection; +} + +- (NSString *)description { + const NSUInteger maxObjects = 100; + auto str = [NSMutableString stringWithFormat:@"RLMSection <%p> (\n", (void *)self]; + size_t index = 0, skipped = 0; + for (id obj in self) { + NSString *sub = [obj description]; + // Indent child objects + NSString *objDescription = [sub stringByReplacingOccurrencesOfString:@"\n" + withString:@"\n\t"]; + [str appendFormat:@"\t[%zu] %@,\n", index++, objDescription]; + if (index >= maxObjects) { + skipped = self.count - maxObjects; + break; + } + } + + // Remove last comma and newline characters + if (self.count > 0) { + [str deleteCharactersInRange:NSMakeRange(str.length-2, 2)]; + } + if (skipped) { + [str appendFormat:@"\n\t... %zu objects skipped.", skipped]; + } + [str appendFormat:@"\n)"]; + return str; +} + +- (instancetype)initWithResultsSection:(realm::ResultsSection&&)resultsSection + parent:(RLMSectionedResults *)parent +{ + if (self = [super init]) { + _resultsSection = std::move(resultsSection); + _parent = parent; + } + return self; +} + +- (id)objectAtIndexedSubscript:(NSUInteger)index { + return [self objectAtIndex:index]; +} + +- (id)objectAtIndex:(NSUInteger)index { + RLMAccessorContext ctx(*_parent.objectInfo); + return translateErrors([&] { + return ctx.box(_resultsSection[index]); + }); +} + +- (NSUInteger)count { + return translateErrors([&] { + return _resultsSection.size(); + }); +} + +- (id)key { + return translateErrors([&] { + return RLMMixedToObjc(_resultsSection.key()); + }); +} + +- (RLMSectionedResultsEnumerator *)fastEnumerator { + return [[RLMSectionedResultsEnumerator alloc] initWithResultsSection:self]; +} + +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state + objects:(__unused __unsafe_unretained id [])buffer + count:(NSUInteger)len { + return RLMFastEnumerate(state, len, self); +} + +- (RLMRealm *)realm { + return _parent.realm; +} + +- (RLMClassInfo *)objectInfo { + return _parent.objectInfo; +} + +- (BOOL)isInvalidated { + return translateErrors([&] { return !_resultsSection.is_valid(); }); +} + +- (BOOL)isFrozen { + return translateErrors([&] { return _parent.frozen; }); +} + +// The compiler complains about the method's argument type not matching due to +// it not having the generic type attached, but it doesn't seem to be possible +// to actually include the generic type +// http://www.openradar.me/radar?id=6135653276319744 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wmismatched-parameter-types" +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMResults *, RLMSectionedResultsChange *))block { + return RLMAddNotificationBlock(self, block, nil, nil); +} +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMResults *, RLMSectionedResultsChange *))block queue:(dispatch_queue_t)queue { + return RLMAddNotificationBlock(self, block, nil, queue); +} + +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMResults *, RLMSectionedResultsChange *))block keyPaths:(NSArray *)keyPaths { + return RLMAddNotificationBlock(self, block, keyPaths, nil); +} + +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMResults *, RLMSectionedResultsChange *))block + keyPaths:(NSArray *)keyPaths + queue:(dispatch_queue_t)queue { + return RLMAddNotificationBlock(self, block, keyPaths, queue); +} +#pragma clang diagnostic pop + +- (realm::NotificationToken)addNotificationCallback:(id)block +keyPaths:(std::optional>>>&&)keyPaths { + return _resultsSection.add_notification_callback(CollectionCallbackWrapper{block, self}, std::move(keyPaths)); +} + +#pragma mark - Thread Confined Protocol Conformance + +- (realm::ThreadSafeReference)makeThreadSafeReference { + return _parent->_results; +} + +- (RLMSectionMetadata *)objectiveCMetadata { + return [[RLMSectionMetadata alloc] initWithKeyBlock:_parent->_keyBlock + sectionKey:self.key]; +} + ++ (instancetype)objectWithThreadSafeReference:(realm::ThreadSafeReference)reference + metadata:(RLMSectionMetadata *)metadata + realm:(RLMRealm *)realm { + auto results = reference.resolve(realm->_realm); + auto objType = RLMStringDataToNSString(results.get_object_type()); + + RLMSectionedResults *sr = [[RLMSectionedResults alloc] initWithResults:std::move(results) + realm:realm + objectInfo:realm->_info[objType] + keyBlock:metadata.keyBlock]; + return translateErrors([&] { + return [[RLMSection alloc] initWithResultsSection:sr->_sectionedResults[RLMObjcToMixed(metadata.sectionKey)] + parent:sr]; + }); +} + +- (instancetype)resolveInRealm:(RLMRealm *)realm { + return translateErrors([&] { + RLMSectionedResults *sr = realm.isFrozen ? [_parent freeze] : [_parent thaw]; + return [[RLMSection alloc] initWithResultsSection:sr->_sectionedResults[RLMObjcToMixed(self.key)] + parent:sr]; + }); +} + +- (instancetype)freeze { + if (self.frozen) { + return self; + } + return [self resolveInRealm:_parent.realm.freeze]; +} + +- (instancetype)thaw { + if (!self.frozen) { + return self; + } + return [self resolveInRealm:_parent.realm.thaw]; +} + +@end diff --git a/Pods/Realm/Realm/RLMSet.mm b/Pods/Realm/Realm/RLMSet.mm new file mode 100644 index 0000000..bfe44df --- /dev/null +++ b/Pods/Realm/Realm/RLMSet.mm @@ -0,0 +1,553 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 "RLMSet_Private.hpp" + +#import "RLMObjectSchema.h" +#import "RLMObjectStore.h" +#import "RLMObject_Private.h" +#import "RLMProperty_Private.h" +#import "RLMQueryUtil.hpp" +#import "RLMSchema_Private.h" +#import "RLMSwiftSupport.h" +#import "RLMThreadSafeReference_Private.hpp" +#import "RLMUtil.hpp" + +@interface RLMSet () +@end + +@implementation RLMSet { +@public + // Backing set when this instance is unmanaged + NSMutableOrderedSet *_backingCollection; +} + +#pragma mark - Initializers + +- (instancetype)initWithObjectClassName:(__unsafe_unretained NSString *const)objectClassName + keyType:(__unused RLMPropertyType)keyType { + return [self initWithObjectClassName:objectClassName]; +} +- (instancetype)initWithObjectType:(RLMPropertyType)type + optional:(BOOL)optional + keyType:(__unused RLMPropertyType)keyType { + return [self initWithObjectType:type optional:optional]; +} + +- (instancetype)initWithObjectClassName:(__unsafe_unretained NSString *const)objectClassName { + REALM_ASSERT([objectClassName length] > 0); + self = [super init]; + if (self) { + _objectClassName = objectClassName; + _type = RLMPropertyTypeObject; + } + return self; +} + +- (instancetype)initWithObjectType:(RLMPropertyType)type optional:(BOOL)optional { + self = [super init]; + if (self) { + _type = type; + _optional = optional; + } + return self; +} + +- (void)setParent:(RLMObjectBase *)parentObject property:(RLMProperty *)property { + _parentObject = parentObject; + _key = property.name; + _isLegacyProperty = property.isLegacy; +} + +#pragma mark - Convenience wrappers used for all RLMSet types + +- (void)addObjects:(id)objects { + for (id obj in objects) { + [self addObject:obj]; + } +} + +- (void)addObject:(id)object { + RLMSetValidateMatchingObjectType(self, object); + changeSet(self, ^{ + [_backingCollection addObject:object]; + }); +} + +- (void)setObject:(id)newValue atIndexedSubscript:(NSUInteger)index { + REALM_TERMINATE("Replacing objects at an indexed subscript is not supported on RLMSet"); +} + +- (void)setSet:(RLMSet *)set { + for (id obj in set) { + RLMSetValidateMatchingObjectType(self, obj); + } + changeSet(self, ^{ + [_backingCollection removeAllObjects]; + [_backingCollection unionOrderedSet:set->_backingCollection]; + }); +} + +- (void)intersectSet:(RLMSet *)set { + for (id obj in set) { + RLMSetValidateMatchingObjectType(self, obj); + } + changeSet(self, ^{ + [_backingCollection intersectOrderedSet:set->_backingCollection]; + }); +} + +- (void)minusSet:(RLMSet *)set { + for (id obj in set) { + RLMSetValidateMatchingObjectType(self, obj); + } + changeSet(self, ^{ + [_backingCollection minusOrderedSet:set->_backingCollection]; + }); +} + +- (void)unionSet:(RLMSet *)set { + for (id obj in set) { + RLMSetValidateMatchingObjectType(self, obj); + } + changeSet(self, ^{ + [_backingCollection unionOrderedSet:set->_backingCollection]; + }); +} + +- (BOOL)isSubsetOfSet:(RLMSet *)set { + for (id obj in set) { + RLMSetValidateMatchingObjectType(self, obj); + } + return [_backingCollection isSubsetOfOrderedSet:set->_backingCollection]; +} + +- (BOOL)intersectsSet:(RLMSet *)set { + for (id obj in set) { + RLMSetValidateMatchingObjectType(self, obj); + } + return [_backingCollection intersectsOrderedSet:set->_backingCollection]; +} + +- (BOOL)containsObject:(id)obj { + RLMSetValidateMatchingObjectType(self, obj); + return [_backingCollection containsObject:obj]; +} + +- (BOOL)isEqualToSet:(RLMSet *)set { + return [self isEqual:set]; +} + +- (RLMResults *)sortedResultsUsingKeyPath:(NSString *)keyPath ascending:(BOOL)ascending { + return [self sortedResultsUsingDescriptors:@[[RLMSortDescriptor sortDescriptorWithKeyPath:keyPath ascending:ascending]]]; +} + +- (nonnull id)objectAtIndexedSubscript:(NSUInteger)index { + return [self objectAtIndex:index]; +} + +// The compiler complains about the method's argument type not matching due to +// it not having the generic type attached, but it doesn't seem to be possible +// to actually include the generic type +// http://www.openradar.me/radar?id=6135653276319744 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wmismatched-parameter-types" +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMArray *, RLMCollectionChange *, NSError *))block { + return RLMAddNotificationBlock(self, block, nil, nil); +} +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMArray *, RLMCollectionChange *, NSError *))block + queue:(dispatch_queue_t)queue { + return RLMAddNotificationBlock(self, block, nil, queue); +} + +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMArray *, RLMCollectionChange *, NSError *))block + keyPaths:(NSArray *)keyPaths { + return RLMAddNotificationBlock(self, block, keyPaths,nil); +} + +- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMArray *, RLMCollectionChange *, NSError *))block + keyPaths:(NSArray *)keyPaths + queue:(dispatch_queue_t)queue { + return RLMAddNotificationBlock(self, block, keyPaths, queue); +} +#pragma clang diagnostic pop + +#pragma mark - Unmanaged RLMSet implementation + +- (RLMRealm *)realm { + return nil; +} + +- (NSUInteger)count { + return _backingCollection.count; +} + +- (NSArray *)allObjects { + return _backingCollection.array; +} + +// For use with MutableSet subscripting, NSSet does not support +// subscripting while its Swift counterpart `Set` does. +- (id)objectAtIndex:(NSUInteger)index { + validateSetBounds(self, index); + return _backingCollection[index]; +} + +- (NSArray *)objectsAtIndexes:(NSIndexSet *)indexes { + if ([indexes indexGreaterThanOrEqualToIndex:self.count] != NSNotFound) { + return nil; + } + return [_backingCollection objectsAtIndexes:indexes] ?: @[]; +} + +- (id)firstObject { + return _backingCollection.firstObject; +} + +- (id)lastObject { + return _backingCollection.lastObject; +} + +- (BOOL)isInvalidated { + return NO; +} + +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state + objects:(__unused __unsafe_unretained id [])buffer + count:(__unused NSUInteger)len { + return RLMUnmanagedFastEnumerate(_backingCollection, state); +} + +static void changeSet(__unsafe_unretained RLMSet *const set, + dispatch_block_t f) { + if (!set->_backingCollection) { + set->_backingCollection = [NSMutableOrderedSet new]; + } + + if (RLMObjectBase *parent = set->_parentObject) { + [parent willChangeValueForKey:set->_key]; + f(); + [parent didChangeValueForKey:set->_key]; + } + else { + f(); + } +} + +static void validateSetBounds(__unsafe_unretained RLMSet *const set, + NSUInteger index, + bool allowOnePastEnd=false) { + NSUInteger max = set->_backingCollection.count + allowOnePastEnd; + if (index >= max) { + @throw RLMException(@"Index %llu is out of bounds (must be less than %llu).", + (unsigned long long)index, (unsigned long long)max); + } +} + +- (void)removeAllObjects { + changeSet(self, ^{ + [_backingCollection removeAllObjects]; + }); +} + +- (void)removeObject:(id)object { + RLMSetValidateMatchingObjectType(self, object); + changeSet(self, ^{ + [_backingCollection removeObject:object]; + }); +} + +- (void)replaceAllObjectsWithObjects:(NSArray *)objects { + changeSet(self, ^{ + [_backingCollection removeAllObjects]; + if (!objects || (id)objects == NSNull.null) { + return; + } + for (id object in objects) { + [_backingCollection addObject:object]; + } + }); +} + +- (RLMResults *)objectsWhere:(NSString *)predicateFormat, ... { + va_list args; + va_start(args, predicateFormat); + RLMResults *results = [self objectsWhere:predicateFormat args:args]; + va_end(args); + return results; +} + +- (RLMResults *)objectsWhere:(NSString *)predicateFormat args:(va_list)args { + return [self objectsWithPredicate:[NSPredicate predicateWithFormat:predicateFormat arguments:args]]; +} + +- (RLMPropertyType)typeForProperty:(NSString *)propertyName { + if ([propertyName isEqualToString:@"self"]) { + return _type; + } + + RLMObjectSchema *objectSchema; + if (_backingCollection.count) { + objectSchema = [_backingCollection[0] objectSchema]; + } + else { + objectSchema = [RLMSchema.partialPrivateSharedSchema schemaForClassName:_objectClassName]; + } + + return RLMValidatedProperty(objectSchema, propertyName).type; +} + +- (id)aggregateProperty:(NSString *)key operation:(NSString *)op method:(SEL)sel { + // Although delegating to valueForKeyPath: here would allow to support + // nested key paths as well, limiting functionality gives consistency + // between unmanaged and managed arrays. + if ([key rangeOfString:@"."].location != NSNotFound) { + @throw RLMException(@"Nested key paths are not supported yet for KVC collection operators."); + } + + if ([op isEqualToString:@"@distinctUnionOfObjects"]) { + @throw RLMException(@"this class does not implement the distinctUnionOfObjects"); + } + + bool allowDate = false; + bool sum = false; + if ([op isEqualToString:@"@min"] || [op isEqualToString:@"@max"]) { + allowDate = true; + } + else if ([op isEqualToString:@"@sum"]) { + sum = true; + } + else if (![op isEqualToString:@"@avg"]) { + // Just delegate to NSSet for all other operators + return [_backingCollection valueForKeyPath:[op stringByAppendingPathExtension:key]]; + } + + RLMPropertyType type = [self typeForProperty:key]; + if (!canAggregate(type, allowDate)) { + NSString *method = sel ? NSStringFromSelector(sel) : op; + if (_type == RLMPropertyTypeObject) { + @throw RLMException(@"%@: is not supported for %@ property '%@.%@'", + method, RLMTypeToString(type), _objectClassName, key); + } + else { + @throw RLMException(@"%@ is not supported for %@%s set", + method, RLMTypeToString(_type), _optional ? "?" : ""); + } + } + + // `valueForKeyPath` on NSSet will only return distinct values, which is an + // issue as the realm::object_store::Set aggregate methods will calculate + // the result based on each element of a property regardless of uniqueness. + // To get around this we will need to use the `array` property of the NSMutableOrderedSet + NSArray *values = [key isEqualToString:@"self"] ? _backingCollection.array : [_backingCollection.array valueForKey:key]; + if (_optional) { + // Filter out NSNull values to match our behavior on managed arrays + NSIndexSet *nonnull = [values indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger, BOOL *) { + return obj != NSNull.null; + }]; + if (nonnull.count < values.count) { + values = [values objectsAtIndexes:nonnull]; + } + } + + id result = [values valueForKeyPath:[op stringByAppendingString:@".self"]]; + return sum && !result ? @0 : result; +} + +static NSSet *toUnorderedSet(id value) { + if (auto orderedSet = RLMDynamicCast(value)) { + return orderedSet.set; + } + return value; +} + +- (id)valueForKeyPath:(NSString *)keyPath { + if ([keyPath characterAtIndex:0] != '@') { + return toUnorderedSet(_backingCollection ? [_backingCollection valueForKeyPath:keyPath] : [super valueForKeyPath:keyPath]); + } + + if (!_backingCollection) { + _backingCollection = [NSMutableOrderedSet new]; + } + + NSUInteger dot = [keyPath rangeOfString:@"."].location; + if (dot == NSNotFound) { + return [_backingCollection valueForKeyPath:keyPath]; + } + + NSString *op = [keyPath substringToIndex:dot]; + NSString *key = [keyPath substringFromIndex:dot + 1]; + return [self aggregateProperty:key operation:op method:nil]; +} + +- (id)valueForKey:(NSString *)key { + if ([key isEqualToString:RLMInvalidatedKey]) { + return @NO; // Unmanaged sets are never invalidated + } + if (!_backingCollection) { + _backingCollection = [NSMutableOrderedSet new]; + } + return toUnorderedSet([_backingCollection valueForKey:key]); +} + +- (void)setValue:(id)value forKey:(NSString *)key { + if ([key isEqualToString:@"self"]) { + RLMSetValidateMatchingObjectType(self, value); + [_backingCollection removeAllObjects]; + [_backingCollection addObject:value]; + return; + } + else if (_type == RLMPropertyTypeObject) { + [_backingCollection setValue:value forKey:key]; + } + else { + [self setValue:value forUndefinedKey:key]; + } +} + +- (id)minOfProperty:(NSString *)property { + return [self aggregateProperty:property operation:@"@min" method:_cmd]; +} + +- (id)maxOfProperty:(NSString *)property { + return [self aggregateProperty:property operation:@"@max" method:_cmd]; +} + +- (id)sumOfProperty:(NSString *)property { + return [self aggregateProperty:property operation:@"@sum" method:_cmd]; +} + +- (id)averageOfProperty:(NSString *)property { + return [self aggregateProperty:property operation:@"@avg" method:_cmd]; +} + +- (BOOL)isEqual:(id)object { + if (auto set = RLMDynamicCast(object)) { + return !set.realm + && ((_backingCollection.count == 0 && set->_backingCollection.count == 0) + || [_backingCollection isEqual:set->_backingCollection]); + } + return NO; +} + +- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath + options:(NSKeyValueObservingOptions)options context:(void *)context { + RLMValidateSetObservationKey(keyPath, self); + [super addObserver:observer forKeyPath:keyPath options:options context:context]; +} + +void RLMSetValidateMatchingObjectType(__unsafe_unretained RLMSet *const set, + __unsafe_unretained id const value) { + if (!value && !set->_optional) { + @throw RLMException(@"Invalid nil value for set of '%@'.", + set->_objectClassName ?: RLMTypeToString(set->_type)); + } + if (set->_type != RLMPropertyTypeObject) { + if (!RLMValidateValue(value, set->_type, set->_optional, false, nil)) { + @throw RLMException(@"Invalid value '%@' of type '%@' for expected type '%@%s'.", + value, [value class], RLMTypeToString(set->_type), + set->_optional ? "?" : ""); + } + return; + } + + auto object = RLMDynamicCast(value); + if (!object) { + return; + } + if (!object->_objectSchema) { + @throw RLMException(@"Object cannot be inserted unless the schema is initialized. " + "This can happen if you try to insert objects into a RLMSet / Set from a default value or from an overriden unmanaged initializer (`init()`)."); + } + if (![set->_objectClassName isEqualToString:object->_objectSchema.className] + && (set->_type != RLMPropertyTypeAny)) { + @throw RLMException(@"Object of type '%@' does not match RLMSet type '%@'.", + object->_objectSchema.className, set->_objectClassName); + } +} + +#pragma mark - Key Path Strings + +- (NSString *)propertyKey { + return _key; +} + +#pragma mark - Methods unsupported on unmanaged RLMSet instances + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-parameter" + +- (RLMResults *)objectsWithPredicate:(NSPredicate *)predicate { + @throw RLMException(@"This method may only be called on RLMSet instances retrieved from an RLMRealm"); +} + +- (RLMResults *)sortedResultsUsingDescriptors:(NSArray *)properties { + @throw RLMException(@"This method may only be called on RLMSet instances retrieved from an RLMRealm"); +} + +- (RLMResults *)distinctResultsUsingKeyPaths:(NSArray *)keyPaths { + @throw RLMException(@"This method may only be called on RLMSet instances retrieved from an RLMRealm"); +} + +- (RLMSectionedResults *)sectionedResultsSortedUsingKeyPath:(NSString *)keyPath + ascending:(BOOL)ascending + keyBlock:(RLMSectionedResultsKeyBlock)keyBlock { + @throw RLMException(@"This method may only be called on RLMSet instances retrieved from an RLMRealm"); +} + +- (RLMSectionedResults *)sectionedResultsUsingSortDescriptors:(NSArray *)sortDescriptors + keyBlock:(RLMSectionedResultsKeyBlock)keyBlock { + @throw RLMException(@"This method may only be called on RLMSet instances retrieved from an RLMRealm"); +} + +- (instancetype)freeze { + @throw RLMException(@"This method may only be called on RLMSet instances retrieved from an RLMRealm"); +} + +- (instancetype)thaw { + @throw RLMException(@"This method may only be called on RLMSet instances retrieved from an RLMRealm"); +} + +#pragma mark - Thread Confined Protocol Conformance + +- (realm::ThreadSafeReference)makeThreadSafeReference { + REALM_TERMINATE("Unexpected handover of unmanaged `RLMSet`"); +} + +- (id)objectiveCMetadata { + REALM_TERMINATE("Unexpected handover of unmanaged `RLMSet`"); +} + ++ (instancetype)objectWithThreadSafeReference:(realm::ThreadSafeReference)reference + metadata:(id)metadata + realm:(RLMRealm *)realm { + REALM_TERMINATE("Unexpected handover of unmanaged `RLMSet`"); +} + +#pragma clang diagnostic pop // unused parameter warning + +#pragma mark - Superclass Overrides + +- (NSString *)description { + return [self descriptionWithMaxDepth:RLMDescriptionMaxDepth]; +} + +- (NSString *)descriptionWithMaxDepth:(NSUInteger)depth { + return RLMDescriptionWithMaxDepth(@"RLMSet", self, depth); +} +@end diff --git a/Pods/Realm/Realm/RLMSwiftCollectionBase.mm b/Pods/Realm/Realm/RLMSwiftCollectionBase.mm new file mode 100644 index 0000000..d635c91 --- /dev/null +++ b/Pods/Realm/Realm/RLMSwiftCollectionBase.mm @@ -0,0 +1,172 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2021 Realm Inc. +// +// 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 "RLMSwiftCollectionBase.h" + +#import "RLMArray_Private.hpp" +#import "RLMObjectSchema_Private.h" +#import "RLMObject_Private.hpp" +#import "RLMObservation.hpp" +#import "RLMProperty_Private.h" +#import "RLMSet_Private.hpp" +#import "RLMDictionary_Private.hpp" + +@interface RLMArray (KVO) +- (NSArray *)objectsAtIndexes:(__unused NSIndexSet *)indexes; +@end + +// Some of the things declared in the interface are handled by the proxy forwarding +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wincomplete-implementation" + +@implementation RLMSwiftCollectionBase + ++ (id)_unmanagedCollection { + return nil; +} + ++ (Class)_backingCollectionType { + REALM_UNREACHABLE(); +} + +- (instancetype)init { + return self; +} + +- (instancetype)initWithCollection:(id)collection { + __rlmCollection = collection; + return self; +} + +- (id)_rlmCollection { + if (!__rlmCollection) { + __rlmCollection = self.class._unmanagedCollection; + } + return __rlmCollection; +} + +- (BOOL)isKindOfClass:(Class)aClass { + return [self._rlmCollection isKindOfClass:aClass] || RLMIsKindOfClass(object_getClass(self), aClass); +} + +- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel { + return [(id)self._rlmCollection methodSignatureForSelector:sel]; +} + +- (void)forwardInvocation:(NSInvocation *)invocation { + [invocation invokeWithTarget:self._rlmCollection]; +} + +- (id)forwardingTargetForSelector:(__unused SEL)sel { + return self._rlmCollection; +} + +- (BOOL)respondsToSelector:(SEL)aSelector { + return [self._rlmCollection respondsToSelector:aSelector]; +} + +- (void)doesNotRecognizeSelector:(SEL)aSelector { + [(id)self._rlmCollection doesNotRecognizeSelector:aSelector]; +} + +- (BOOL)isEqual:(id)object { + if (auto collection = RLMDynamicCast(object)) { + if (!__rlmCollection) { + return !collection->__rlmCollection.realm && collection->__rlmCollection.count == 0; + } + return [__rlmCollection isEqual:collection->__rlmCollection]; + } + return NO; +} + +- (BOOL)conformsToProtocol:(Protocol *)aProtocol { + return aProtocol == @protocol(NSFastEnumeration) || [self._rlmCollection conformsToProtocol:aProtocol]; +} + +@end + +#pragma clang diagnostic pop + +@implementation RLMLinkingObjectsHandle { + realm::TableKey _tableKey; + realm::ObjKey _objKey; + RLMClassInfo *_info; + RLMRealm *_realm; + RLMProperty *_property; + + RLMResults *_results; +} + +- (instancetype)initWithObject:(RLMObjectBase *)object property:(RLMProperty *)prop { + if (!(self = [super init])) { + return nil; + } + // KeyPath strings will invoke this initializer with an unmanaged object + // so guard against that. + if (object->_realm) { + auto& obj = object->_row; + _tableKey = obj.get_table()->get_key(); + _objKey = obj.get_key(); + _info = object->_info; + _realm = object->_realm; + } + _property = prop; + + return self; +} + +- (instancetype)initWithLinkingObjects:(RLMResults *)linkingObjects { + if (!(self = [super init])) { + return nil; + } + _realm = linkingObjects.realm; + _results = linkingObjects; + + return self; +} + +- (RLMResults *)results { + if (_results) { + return _results; + } + [_realm verifyThread]; + + auto table = _realm.group.get_table(_tableKey); + if (!table->is_valid(_objKey)) { + @throw RLMException(@"Object has been deleted or invalidated."); + } + + auto obj = _realm.group.get_table(_tableKey)->get_object(_objKey); + auto& objectInfo = _realm->_info[_property.objectClassName]; + auto& linkOrigin = _info->objectSchema->computed_properties[_property.index].link_origin_property_name; + auto linkingProperty = objectInfo.objectSchema->property_for_name(linkOrigin); + realm::Results results(_realm->_realm, obj.get_backlink_view(objectInfo.table(), linkingProperty->column_key)); + _results = [RLMLinkingObjects resultsWithObjectInfo:objectInfo results:std::move(results)]; + _realm = nil; + return _results; +} + +- (NSString *)_propertyKey { + return _property.name; +} + +- (BOOL)_isLegacyProperty { + return _property.isLegacy; +} + +@end diff --git a/Pods/Realm/Realm/RLMSwiftSupport.m b/Pods/Realm/Realm/RLMSwiftSupport.m new file mode 100644 index 0000000..e16c79e --- /dev/null +++ b/Pods/Realm/Realm/RLMSwiftSupport.m @@ -0,0 +1,31 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// 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 "RLMSwiftSupport.h" + +@implementation RLMSwiftSupport + ++ (BOOL)isSwiftClassName:(NSString *)className { + return [className rangeOfString:@"."].location != NSNotFound; +} + ++ (NSString *)demangleClassName:(NSString *)className { + return [className substringFromIndex:[className rangeOfString:@"."].location + 1]; +} + +@end diff --git a/Pods/Realm/Realm/RLMSwiftValueStorage.mm b/Pods/Realm/Realm/RLMSwiftValueStorage.mm new file mode 100644 index 0000000..80cfc33 --- /dev/null +++ b/Pods/Realm/Realm/RLMSwiftValueStorage.mm @@ -0,0 +1,182 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// 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 "RLMSwiftValueStorage.h" + +#import "RLMAccessor.hpp" +#import "RLMObject_Private.hpp" +#import "RLMProperty_Private.h" +#import "RLMUtil.hpp" + +#import + +namespace { +struct SwiftValueStorageBase { + virtual id get() = 0; + virtual void set(id) = 0; + virtual NSString *propertyName() = 0; + virtual ~SwiftValueStorageBase() = default; +}; + +class UnmanagedSwiftValueStorage : public SwiftValueStorageBase { +public: + id get() override { + return _value; + } + + void set(__unsafe_unretained const id newValue) override { + @autoreleasepool { + RLMObjectBase *object = _parent; + [object willChangeValueForKey:_property]; + _value = newValue; + [object didChangeValueForKey:_property]; + } + } + + void attach(__unsafe_unretained RLMObjectBase *const obj, NSString *property) { + if (!_property) { + _property = property; + _parent = obj; + } + } + + NSString *propertyName() override { + return _property; + } + +private: + id _value; + NSString *_property; + __weak RLMObjectBase *_parent; + +}; + +class ManagedSwiftValueStorage : public SwiftValueStorageBase { +public: + ManagedSwiftValueStorage(RLMObjectBase *obj, RLMProperty *prop) + : _realm(obj->_realm) + , _object(obj->_realm->_realm, *obj->_info->objectSchema, obj->_row) + , _columnName(prop.columnName.UTF8String) + , _ctx(*obj->_info) + { + } + + id get() override { + return _object.get_property_value(_ctx, _columnName); + } + + void set(__unsafe_unretained id const value) override { + _object.set_property_value(_ctx, _columnName, value ?: NSNull.null); + } + + NSString *propertyName() override { + // Should never be called on a managed object. + REALM_UNREACHABLE(); + } + +private: + // We have to hold onto a strong reference to the Realm as + // RLMAccessorContext holds a non-retaining one. + __unused RLMRealm *_realm; + realm::Object _object; + std::string _columnName; + RLMAccessorContext _ctx; +}; +} // anonymous namespace + +@interface RLMSwiftValueStorage () { + std::unique_ptr _impl; +} +@end + +@implementation RLMSwiftValueStorage +- (instancetype)init { + return self; +} + +- (BOOL)isKindOfClass:(Class)aClass { + return [RLMGetSwiftValueStorage(self) isKindOfClass:aClass] || RLMIsKindOfClass(object_getClass(self), aClass); +} + +- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel { + return [RLMGetSwiftValueStorage(self) methodSignatureForSelector:sel]; +} + +- (void)forwardInvocation:(NSInvocation *)invocation { + [invocation invokeWithTarget:RLMGetSwiftValueStorage(self)]; +} + +- (id)forwardingTargetForSelector:(__unused SEL)sel { + return RLMGetSwiftValueStorage(self); +} + +- (BOOL)respondsToSelector:(SEL)aSelector { + return [RLMGetSwiftValueStorage(self) respondsToSelector:aSelector]; +} + +- (void)doesNotRecognizeSelector:(SEL)aSelector { + [RLMGetSwiftValueStorage(self) doesNotRecognizeSelector:aSelector]; +} + +id RLMGetSwiftValueStorage(__unsafe_unretained RLMSwiftValueStorage *const self) { + try { + return self->_impl ? RLMCoerceToNil(self->_impl->get()) : nil; + } + catch (std::exception const& err) { + @throw RLMException(err); + } +} + +void RLMSetSwiftValueStorage(__unsafe_unretained RLMSwiftValueStorage *const self, __unsafe_unretained const id value) { + try { + if (!self->_impl && value) { + self->_impl.reset(new UnmanagedSwiftValueStorage); + } + if (self->_impl) { + self->_impl->set(value); + } + } + catch (std::exception const& err) { + @throw RLMException(err); + } +} + +void RLMInitializeManagedSwiftValueStorage(__unsafe_unretained RLMSwiftValueStorage *const self, + __unsafe_unretained RLMObjectBase *const parent, + __unsafe_unretained RLMProperty *const prop) { + REALM_ASSERT(parent->_realm); + self->_impl.reset(new ManagedSwiftValueStorage(parent, prop)); +} + +void RLMInitializeUnmanagedSwiftValueStorage(__unsafe_unretained RLMSwiftValueStorage *const self, + __unsafe_unretained RLMObjectBase *const parent, + __unsafe_unretained RLMProperty *const prop) { + if (parent->_realm) { + return; + } + if (!self->_impl) { + self->_impl.reset(new UnmanagedSwiftValueStorage); + } + static_cast(*self->_impl).attach(parent, prop.name); +} + +NSString *RLMSwiftValueStorageGetPropertyName(RLMSwiftValueStorage *const self) { + return self->_impl->propertyName(); +} + +@end diff --git a/Pods/Realm/Realm/RLMSyncConfiguration.mm b/Pods/Realm/Realm/RLMSyncConfiguration.mm new file mode 100644 index 0000000..cb63e5f --- /dev/null +++ b/Pods/Realm/Realm/RLMSyncConfiguration.mm @@ -0,0 +1,290 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// 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 "RLMSyncConfiguration_Private.hpp" + +#import "RLMApp_Private.hpp" +#import "RLMBSON_Private.hpp" +#import "RLMError_Private.hpp" +#import "RLMRealm_Private.hpp" +#import "RLMRealmConfiguration_Private.h" +#import "RLMRealmConfiguration_Private.hpp" +#import "RLMRealmUtil.hpp" +#import "RLMSchema_Private.hpp" +#import "RLMSyncManager_Private.hpp" +#import "RLMSyncSession_Private.hpp" +#import "RLMSyncUtil_Private.hpp" +#import "RLMUser_Private.hpp" +#import "RLMUtil.hpp" + +#import +#import +#import +#import +#import + +using namespace realm; + +namespace { +using ProtocolError = realm::sync::ProtocolError; + +struct CallbackSchema { + bool dynamic; + std::string path; + RLMSchema *customSchema; + + RLMSchema *getSchema(Realm& realm) { + if (dynamic) { + return [RLMSchema dynamicSchemaFromObjectStoreSchema:realm.schema()]; + } + if (auto cached = RLMGetAnyCachedRealmForPath(path)) { + return cached.schema; + } + return customSchema ?: RLMSchema.sharedSchema; + } +}; + +struct BeforeClientResetWrapper : CallbackSchema { + RLMClientResetBeforeBlock block; + void operator()(std::shared_ptr local) { + @autoreleasepool { + if (local->schema_version() != RLMNotVersioned) { + block([RLMRealm realmWithSharedRealm:local schema:getSchema(*local) dynamic:false]); + } + } + } +}; + +struct AfterClientResetWrapper : CallbackSchema { + RLMClientResetAfterBlock block; + void operator()(std::shared_ptr local, ThreadSafeReference remote, bool) { + @autoreleasepool { + if (local->schema_version() != RLMNotVersioned) { + RLMSchema *schema = getSchema(*local); + RLMRealm *localRealm = [RLMRealm realmWithSharedRealm:local + schema:schema + dynamic:false]; + + RLMRealm *remoteRealm = [RLMRealm realmWithSharedRealm:Realm::get_shared_realm(std::move(remote)) + schema:schema + dynamic:false]; + block(localRealm, remoteRealm); + } + } + } +}; +} // anonymous namespace + +@interface RLMSyncConfiguration () { + std::unique_ptr _config; + RLMSyncErrorReportingBlock _manualClientResetHandler; +} + +@end + +@implementation RLMSyncConfiguration + +@dynamic stopPolicy; + +- (instancetype)initWithRawConfig:(realm::SyncConfig)config path:(std::string const&)path { + if (self = [super init]) { + _config = std::make_unique(std::move(config)); + _path = path; + } + return self; +} + +- (BOOL)isEqual:(id)object { + if (![object isKindOfClass:[RLMSyncConfiguration class]]) { + return NO; + } + RLMSyncConfiguration *that = (RLMSyncConfiguration *)object; + return [self.partitionValue isEqual:that.partitionValue] + && [self.user isEqual:that.user] + && self.stopPolicy == that.stopPolicy; +} + +- (realm::SyncConfig&)rawConfiguration { + return *_config; +} + +- (RLMUser *)user { + RLMApp *app = [RLMApp appWithId:@(_config->user->sync_manager()->app().lock()->config().app_id.data())]; + return [[RLMUser alloc] initWithUser:_config->user app:app]; +} + +- (RLMSyncStopPolicy)stopPolicy { + return translateStopPolicy(_config->stop_policy); +} + +- (void)setStopPolicy:(RLMSyncStopPolicy)stopPolicy { + _config->stop_policy = translateStopPolicy(stopPolicy); +} + +- (RLMClientResetMode)clientResetMode { + return RLMClientResetMode(_config->client_resync_mode); +} + +- (void)setClientResetMode:(RLMClientResetMode)clientResetMode { + _config->client_resync_mode = realm::ClientResyncMode(clientResetMode); +} + +- (RLMClientResetBeforeBlock)beforeClientReset { + if (_config->notify_before_client_reset) { + auto wrapper = _config->notify_before_client_reset.target(); + return wrapper->block; + } else { + return nil; + } +} + +- (void)setBeforeClientReset:(RLMClientResetBeforeBlock)beforeClientReset { + if (!beforeClientReset) { + _config->notify_before_client_reset = nullptr; + } else if (self.clientResetMode == RLMClientResetModeManual) { + @throw RLMException(@"RLMClientResetBeforeBlock reset notifications are not supported in Manual mode. Use RLMSyncConfiguration.manualClientResetHandler or RLMSyncManager.ErrorHandler"); + } else { + _config->notify_before_client_reset = BeforeClientResetWrapper{.block = beforeClientReset}; + } +} + +- (RLMClientResetAfterBlock)afterClientReset { + if (_config->notify_after_client_reset) { + auto wrapper = _config->notify_after_client_reset.target(); + return wrapper->block; + } else { + return nil; + } +} + +- (void)setAfterClientReset:(RLMClientResetAfterBlock)afterClientReset { + if (!afterClientReset) { + _config->notify_after_client_reset = nullptr; + } else if (self.clientResetMode == RLMClientResetModeManual) { + @throw RLMException(@"RLMClientResetAfterBlock reset notifications are not supported in Manual mode. Use RLMSyncConfiguration.manualClientResetHandler or RLMSyncManager.ErrorHandler"); + } else { + _config->notify_after_client_reset = AfterClientResetWrapper{.block = afterClientReset}; + } +} + +- (RLMSyncErrorReportingBlock)manualClientResetHandler { + return _manualClientResetHandler; +} + +- (void)setManualClientResetHandler:(RLMSyncErrorReportingBlock)manualClientReset { + if (!manualClientReset) { + _manualClientResetHandler = nil; + } else if (self.clientResetMode != RLMClientResetModeManual) { + @throw RLMException(@"A manual client reset handler can only be set with RLMClientResetModeManual"); + } else { + _manualClientResetHandler = manualClientReset; + } + [self assignConfigErrorHandler:self.user]; +} + +void RLMSetConfigInfoForClientResetCallbacks(realm::SyncConfig& syncConfig, RLMRealmConfiguration *config) { + if (syncConfig.notify_before_client_reset) { + auto before = syncConfig.notify_before_client_reset.target(); + before->dynamic = config.dynamic; + before->path = config.path; + before->customSchema = config.customSchema; + } + if (syncConfig.notify_after_client_reset) { + auto after = syncConfig.notify_after_client_reset.target(); + after->dynamic = config.dynamic; + after->path = config.path; + after->customSchema = config.customSchema; + } +} + +- (id)partitionValue { + if (!_config->partition_value.empty()) { + return RLMConvertBsonToRLMBSON(realm::bson::parse(_config->partition_value.c_str())); + } + return nil; +} + +- (bool)cancelAsyncOpenOnNonFatalErrors { + return _config->cancel_waits_on_nonfatal_error; +} + +- (void)setCancelAsyncOpenOnNonFatalErrors:(bool)cancelAsyncOpenOnNonFatalErrors { + _config->cancel_waits_on_nonfatal_error = cancelAsyncOpenOnNonFatalErrors; +} + +- (void)assignConfigErrorHandler:(RLMUser *)user { + RLMSyncManager *manager = [user.app syncManager]; + __weak RLMSyncManager *weakManager = manager; + RLMSyncErrorReportingBlock resetHandler = self.manualClientResetHandler; + _config->error_handler = [weakManager, resetHandler](std::shared_ptr errored_session, SyncError error) { + RLMSyncErrorReportingBlock errorHandler; + if (error.is_client_reset_requested()) { + errorHandler = resetHandler; + } + if (!errorHandler) { + @autoreleasepool { + errorHandler = weakManager.errorHandler; + } + } + if (!errorHandler) { + return; + } + NSError *nsError = makeError(std::move(error)); + if (!nsError) { + return; + } + RLMSyncSession *session = [[RLMSyncSession alloc] initWithSyncSession:errored_session]; + dispatch_async(dispatch_get_main_queue(), ^{ + // Keep the SyncSession alive until the callback completes as + // RLMSyncSession only holds a weak reference + static_cast(errored_session); + errorHandler(nsError, session); + }); + }; +}; + +static void setDefaults(SyncConfig& config, RLMUser *user) { + config.client_resync_mode = ClientResyncMode::Recover; + config.stop_policy = SyncSessionStopPolicy::AfterChangesUploaded; + [user.app.syncManager populateConfig:config]; +} + +- (instancetype)initWithUser:(RLMUser *)user + partitionValue:(nullable id)partitionValue { + if (self = [super init]) { + std::stringstream s; + s << RLMConvertRLMBSONToBson(partitionValue); + _config = std::make_unique([user _syncUser], s.str()); + _path = [user pathForPartitionValue:_config->partition_value]; + setDefaults(*_config, user); + [self assignConfigErrorHandler:user]; + } + return self; +} + +- (instancetype)initWithUser:(RLMUser *)user { + if (self = [super init]) { + _config = std::make_unique([user _syncUser], SyncConfig::FLXSyncEnabled{}); + _path = [user pathForFlexibleSync]; + setDefaults(*_config, user); + [self assignConfigErrorHandler:user]; + } + return self; +} + +@end diff --git a/Pods/Realm/Realm/RLMSyncManager.mm b/Pods/Realm/Realm/RLMSyncManager.mm new file mode 100644 index 0000000..a0c3d41 --- /dev/null +++ b/Pods/Realm/Realm/RLMSyncManager.mm @@ -0,0 +1,277 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// 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 "RLMSyncManager_Private.hpp" + +#import "RLMApp_Private.hpp" +#import "RLMSyncSession_Private.hpp" +#import "RLMUser_Private.hpp" +#import "RLMSyncUtil_Private.hpp" +#import "RLMUtil.hpp" + +#import +#import +#import + +#if !defined(REALM_COCOA_VERSION) +#import "RLMVersion.h" +#endif + +#include + +using namespace realm; + +// NEXT-MAJOR: All the code associated to the logger from sync manager should be removed. +using Level = realm::util::Logger::Level; + +namespace { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +Level levelForSyncLogLevel(RLMSyncLogLevel logLevel) { + switch (logLevel) { + case RLMSyncLogLevelOff: return Level::off; + case RLMSyncLogLevelFatal: return Level::fatal; + case RLMSyncLogLevelError: return Level::error; + case RLMSyncLogLevelWarn: return Level::warn; + case RLMSyncLogLevelInfo: return Level::info; + case RLMSyncLogLevelDetail: return Level::detail; + case RLMSyncLogLevelDebug: return Level::debug; + case RLMSyncLogLevelTrace: return Level::trace; + case RLMSyncLogLevelAll: return Level::all; + } + REALM_UNREACHABLE(); // Unrecognized log level. +} + +RLMSyncLogLevel logLevelForLevel(Level logLevel) { + switch (logLevel) { + case Level::off: return RLMSyncLogLevelOff; + case Level::fatal: return RLMSyncLogLevelFatal; + case Level::error: return RLMSyncLogLevelError; + case Level::warn: return RLMSyncLogLevelWarn; + case Level::info: return RLMSyncLogLevelInfo; + case Level::detail: return RLMSyncLogLevelDetail; + case Level::debug: return RLMSyncLogLevelDebug; + case Level::trace: return RLMSyncLogLevelTrace; + case Level::all: return RLMSyncLogLevelAll; + } + REALM_UNREACHABLE(); // Unrecognized log level. +} +#pragma clang diagnostic pop + +#pragma mark - Loggers + +struct CocoaSyncLogger : public realm::util::Logger { + void do_log(Level, const std::string& message) override { + NSLog(@"Sync: %@", RLMStringDataToNSString(message)); + } +}; + +static std::unique_ptr defaultSyncLogger(realm::util::Logger::Level level) { + auto logger = std::make_unique(); + logger->set_level_threshold(level); + return std::move(logger); +} + +struct CallbackLogger : public realm::util::Logger { + RLMSyncLogFunction logFn; + void do_log(Level level, const std::string& message) override { + @autoreleasepool { + logFn(logLevelForLevel(level), RLMStringDataToNSString(message)); + } + } +}; + +} // anonymous namespace + +std::shared_ptr RLMWrapLogFunction(RLMSyncLogFunction fn) { + auto logger = std::make_shared(); + logger->logFn = fn; + logger->set_level_threshold(Level::all); + return logger; +} + +#pragma mark - RLMSyncManager + +@implementation RLMSyncManager { + RLMUnfairMutex _mutex; + std::shared_ptr _syncManager; + NSDictionary *_customRequestHeaders; + RLMSyncLogFunction _logger; +} + +- (instancetype)initWithSyncManager:(std::shared_ptr)syncManager { + if (self = [super init]) { + [RLMUser _setUpBindingContextFactory]; + _syncManager = syncManager; + return self; + } + return nil; +} + +- (std::weak_ptr)app { + return _syncManager->app(); +} + +- (NSDictionary *)customRequestHeaders { + std::lock_guard lock(_mutex); + return _customRequestHeaders; +} + +- (void)setCustomRequestHeaders:(NSDictionary *)customRequestHeaders { + { + std::lock_guard lock(_mutex); + _customRequestHeaders = customRequestHeaders.copy; + } + + for (auto&& user : _syncManager->all_users()) { + for (auto&& session : user->all_sessions()) { + auto config = session->config(); + config.custom_http_headers.clear(); + for (NSString *key in customRequestHeaders) { + config.custom_http_headers.emplace(key.UTF8String, customRequestHeaders[key].UTF8String); + } + session->update_configuration(std::move(config)); + } + } +} + +- (RLMSyncLogFunction)logger { + std::lock_guard lock(_mutex); + return _logger; +} + +- (void)setLogger:(RLMSyncLogFunction)logFn { + { + std::lock_guard lock(_mutex); + _logger = logFn; + } + if (logFn) { + _syncManager->set_logger_factory([logFn](realm::util::Logger::Level level) { + auto logger = std::make_unique(); + logger->logFn = logFn; + logger->set_level_threshold(level); + return logger; + }); + } + else { + _syncManager->set_logger_factory(defaultSyncLogger); + } +} + +#pragma mark - Passthrough properties + +- (NSString *)userAgent { + return @(_syncManager->config().user_agent_application_info.c_str()); +} + +- (void)setUserAgent:(NSString *)userAgent { + _syncManager->set_user_agent(RLMStringDataWithNSString(userAgent)); +} + +- (RLMSyncTimeoutOptions *)timeoutOptions { + return [[RLMSyncTimeoutOptions alloc] initWithOptions:_syncManager->config().timeouts]; +} + +- (void)setTimeoutOptions:(RLMSyncTimeoutOptions *)timeoutOptions { + _syncManager->set_timeouts(timeoutOptions->_options); +} + +- (RLMSyncLogLevel)logLevel { + return logLevelForLevel(_syncManager->log_level()); +} + +- (void)setLogLevel:(RLMSyncLogLevel)logLevel { + _syncManager->set_log_level(levelForSyncLogLevel(logLevel)); +} + +#pragma mark - Private API + +- (void)resetForTesting { + _errorHandler = nil; + _logger = nil; + _authorizationHeaderName = nil; + _customRequestHeaders = nil; + _syncManager->reset_for_testing(); +} + +- (std::shared_ptr)syncManager { + return _syncManager; +} + +- (void)waitForSessionTermination { + _syncManager->wait_for_sessions_to_terminate(); +} + +- (void)populateConfig:(realm::SyncConfig&)config { + @synchronized (self) { + if (_authorizationHeaderName) { + config.authorization_header_name.emplace(_authorizationHeaderName.UTF8String); + } + [_customRequestHeaders enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *header, BOOL *) { + config.custom_http_headers.emplace(key.UTF8String, header.UTF8String); + }]; + } +} +@end + +#pragma mark - RLMSyncTimeoutOptions + +@implementation RLMSyncTimeoutOptions +- (instancetype)initWithOptions:(realm::SyncClientTimeouts)options { + if (self = [super init]) { + _options = options; + } + return self; +} + +- (NSUInteger)connectTimeout { + return static_cast(_options.connect_timeout); +} +- (void)setConnectTimeout:(NSUInteger)connectTimeout { + _options.connect_timeout = connectTimeout; +} + +- (NSUInteger)connectLingerTime { + return static_cast(_options.connection_linger_time); +} +- (void)setConnectionLingerTime:(NSUInteger)connectionLingerTime { + _options.connection_linger_time = connectionLingerTime; +} + +- (NSUInteger)pingKeepalivePeriod { + return static_cast(_options.ping_keepalive_period); +} +- (void)setPingKeepalivePeriod:(NSUInteger)pingKeepalivePeriod { + _options.ping_keepalive_period = pingKeepalivePeriod; +} + +- (NSUInteger)pongKeepaliveTimeout { + return static_cast(_options.pong_keepalive_timeout); +} +- (void)setPongKeepaliveTimeout:(NSUInteger)pongKeepaliveTimeout { + _options.pong_keepalive_timeout = pongKeepaliveTimeout; +} + +- (NSUInteger)fastReconnectLimit { + return static_cast(_options.fast_reconnect_limit); +} +- (void)setFastReconnectLimit:(NSUInteger)fastReconnectLimit { + _options.fast_reconnect_limit = fastReconnectLimit; +} + +@end diff --git a/Pods/Realm/Realm/RLMSyncSession.mm b/Pods/Realm/Realm/RLMSyncSession.mm new file mode 100644 index 0000000..f181db3 --- /dev/null +++ b/Pods/Realm/Realm/RLMSyncSession.mm @@ -0,0 +1,273 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// 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 "RLMSyncSession_Private.hpp" + +#import "RLMApp.h" +#import "RLMRealm_Private.hpp" +#import "RLMError_Private.hpp" +#import "RLMSyncConfiguration_Private.hpp" +#import "RLMUser_Private.hpp" +#import "RLMSyncManager_Private.hpp" +#import "RLMSyncUtil_Private.hpp" + +#import +#import + +using namespace realm; + +@interface RLMSyncErrorActionToken () { +@public + std::string _originalPath; + BOOL _isValid; +} +@end + +@interface RLMProgressNotificationToken() { + uint64_t _token; + std::shared_ptr _session; +} +@end + +@implementation RLMProgressNotificationToken + +- (void)suppressNextNotification { + // No-op, but implemented in case this token is passed to + // `-[RLMRealm commitWriteTransactionWithoutNotifying:]`. +} + +- (bool)invalidate { + if (_session) { + _session->unregister_progress_notifier(_token); + _session.reset(); + _token = 0; + return true; + } + return false; +} + +- (nullable instancetype)initWithTokenValue:(uint64_t)token + session:(std::shared_ptr)session { + if (token == 0) { + return nil; + } + if (self = [super init]) { + _token = token; + _session = session; + return self; + } + return nil; +} + +@end + +@interface RLMSyncSession () +@property (class, nonatomic, readonly) dispatch_queue_t notificationsQueue; +@property (atomic, readwrite) RLMSyncConnectionState connectionState; +@end + +@implementation RLMSyncSession + ++ (dispatch_queue_t)notificationsQueue { + static auto queue = dispatch_queue_create("io.realm.sync.sessionsNotificationQueue", DISPATCH_QUEUE_SERIAL); + return queue; +} + +static RLMSyncConnectionState convertConnectionState(SyncSession::ConnectionState state) { + switch (state) { + case SyncSession::ConnectionState::Disconnected: return RLMSyncConnectionStateDisconnected; + case SyncSession::ConnectionState::Connecting: return RLMSyncConnectionStateConnecting; + case SyncSession::ConnectionState::Connected: return RLMSyncConnectionStateConnected; + } +} + +- (instancetype)initWithSyncSession:(std::shared_ptr const&)session { + if (self = [super init]) { + _session = session; + _connectionState = convertConnectionState(session->connection_state()); + // No need to save the token as RLMSyncSession always outlives the + // underlying SyncSession + session->register_connection_change_callback([=](auto, auto newState) { + dispatch_async(dispatch_get_main_queue(), ^{ + self.connectionState = convertConnectionState(newState); + }); + }); + return self; + } + return nil; +} + +- (RLMSyncConfiguration *)configuration { + if (auto session = _session.lock()) { + return [[RLMSyncConfiguration alloc] initWithRawConfig:session->config() path:session->path()]; + } + return nil; +} + +- (NSURL *)realmURL { + if (auto session = _session.lock()) { + if (auto url = session->full_realm_url()) { + return [NSURL URLWithString:@(url->c_str())]; + } + } + return nil; +} + +- (RLMUser *)parentUser { + if (auto session = _session.lock()) { + if (auto app = session->user()->sync_manager()->app().lock()) { + auto rlmApp = [RLMApp appWithId:@(app->config().app_id.data())]; + return [[RLMUser alloc] initWithUser:session->user() app:rlmApp]; + } + } + return nil; +} + +- (RLMSyncSessionState)state { + if (auto session = _session.lock()) { + if (session->state() == SyncSession::State::Inactive) { + return RLMSyncSessionStateInactive; + } + return RLMSyncSessionStateActive; + } + return RLMSyncSessionStateInvalid; +} + +- (void)suspend { + if (auto session = _session.lock()) { + session->force_close(); + } +} + +- (void)resume { + if (auto session = _session.lock()) { + session->revive_if_needed(); + } +} + +- (void)pause { + // NEXT-MAJOR: this is what suspend should be + if (auto session = _session.lock()) { + session->pause(); + } +} + +- (void)unpause { + // NEXT-MAJOR: this is what resume should be + if (auto session = _session.lock()) { + session->resume(); + } +} + +static util::UniqueFunction wrapCompletion(dispatch_queue_t queue, + void (^callback)(NSError *)) { + queue = queue ?: dispatch_get_main_queue(); + return [=](Status status) { + NSError *error = makeError(status); + dispatch_async(queue, ^{ + callback(error); + }); + }; +} + +- (BOOL)waitForUploadCompletionOnQueue:(dispatch_queue_t)queue callback:(void(^)(NSError *))callback { + if (auto session = _session.lock()) { + session->wait_for_upload_completion(wrapCompletion(queue, callback)); + return YES; + } + return NO; +} + +- (BOOL)waitForDownloadCompletionOnQueue:(dispatch_queue_t)queue callback:(void(^)(NSError *))callback { + if (auto session = _session.lock()) { + session->wait_for_download_completion(wrapCompletion(queue, callback)); + return YES; + } + return NO; +} + +- (RLMProgressNotificationToken *)addProgressNotificationForDirection:(RLMSyncProgressDirection)direction + mode:(RLMSyncProgressMode)mode + block:(RLMProgressNotificationBlock)block { + if (auto session = _session.lock()) { + dispatch_queue_t queue = RLMSyncSession.notificationsQueue; + auto notifier_direction = (direction == RLMSyncProgressDirectionUpload + ? SyncSession::ProgressDirection::upload + : SyncSession::ProgressDirection::download); + bool is_streaming = (mode == RLMSyncProgressModeReportIndefinitely); + uint64_t token = session->register_progress_notifier([=](uint64_t transferred, uint64_t transferrable) { + dispatch_async(queue, ^{ + block((NSUInteger)transferred, (NSUInteger)transferrable); + }); + }, notifier_direction, is_streaming); + return [[RLMProgressNotificationToken alloc] initWithTokenValue:token session:session]; + } + return nil; +} + ++ (void)immediatelyHandleError:(RLMSyncErrorActionToken *)token syncManager:(RLMSyncManager *)syncManager { + if (!token->_isValid) { + return; + } + token->_isValid = NO; + + [syncManager syncManager]->immediately_run_file_actions(std::move(token->_originalPath)); +} + ++ (nullable RLMSyncSession *)sessionForRealm:(RLMRealm *)realm { + auto& config = realm->_realm->config().sync_config; + if (!config) { + return nil; + } + if (auto session = config->user->session_for_on_disk_path(realm->_realm->config().path)) { + return [[RLMSyncSession alloc] initWithSyncSession:session]; + } + return nil; +} + +- (NSString *)description { + return [NSString stringWithFormat: + @" {\n" + "\tstate = %d;\n" + "\tconnectionState = %d;\n" + "\trealmURL = %@;\n" + "\tuser = %@;\n" + "}", + (__bridge void *)self, + static_cast(self.state), + static_cast(self.connectionState), + self.realmURL, + self.parentUser.identifier]; +} + +@end + +// MARK: - Error action token + +@implementation RLMSyncErrorActionToken + +- (instancetype)initWithOriginalPath:(std::string)originalPath { + if (self = [super init]) { + _isValid = YES; + _originalPath = std::move(originalPath); + return self; + } + return nil; +} + +@end diff --git a/Pods/Realm/Realm/RLMSyncSubscription.mm b/Pods/Realm/Realm/RLMSyncSubscription.mm new file mode 100644 index 0000000..a31c26b --- /dev/null +++ b/Pods/Realm/Realm/RLMSyncSubscription.mm @@ -0,0 +1,535 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2021 Realm Inc. +// +// 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 "RLMSyncSubscription_Private.hpp" + +#import "RLMError_Private.hpp" +#import "RLMObjectId_Private.hpp" +#import "RLMQueryUtil.hpp" +#import "RLMRealm_Private.hpp" +#import "RLMUtil.hpp" + +#import +#import +#import + +#pragma mark - Subscription + +@interface RLMSyncSubscription () { + std::unique_ptr _subscription; + RLMSyncSubscriptionSet *_subscriptionSet; +} +@end + +@implementation RLMSyncSubscription + +- (instancetype)initWithSubscription:(realm::sync::Subscription)subscription subscriptionSet:(RLMSyncSubscriptionSet *)subscriptionSet { + if (self = [super init]) { + _subscription = std::make_unique(subscription); + _subscriptionSet = subscriptionSet; + return self; + } + return nil; +} + +- (RLMObjectId *)identifier { + return [[RLMObjectId alloc] initWithValue:_subscription->id]; +} + +- (nullable NSString *)name { + auto name = _subscription->name; + if (name) { + return @(name->c_str()); + } + return nil; +} + +- (NSDate *)createdAt { + return RLMTimestampToNSDate(_subscription->created_at); +} + +- (NSDate *)updatedAt { + return RLMTimestampToNSDate(_subscription->updated_at); +} + +- (NSString *)queryString { + return @(_subscription->query_string.c_str()); +} + +- (NSString *)objectClassName { + return @(_subscription->object_class_name.c_str()); +} + +- (void)updateSubscriptionWhere:(NSString *)predicateFormat, ... { + va_list args; + va_start(args, predicateFormat); + [self updateSubscriptionWhere:predicateFormat + args:args]; + va_end(args); +} + +- (void)updateSubscriptionWhere:(NSString *)predicateFormat + args:(va_list)args { + [self updateSubscriptionWithPredicate:[NSPredicate predicateWithFormat:predicateFormat arguments:args]]; +} + +- (void)updateSubscriptionWithPredicate:(NSPredicate *)predicate { + if (self.name != nil) { + [_subscriptionSet addSubscriptionWithClassName:self.objectClassName + subscriptionName:self.name + predicate:predicate + updateExisting:true]; + } + else { + RLMSyncSubscription *foundSubscription = [_subscriptionSet subscriptionWithClassName:self.objectClassName where:self.queryString]; + if (foundSubscription) { + [_subscriptionSet removeSubscription:foundSubscription]; + [_subscriptionSet addSubscriptionWithClassName:self.objectClassName + predicate:predicate]; + } else { + @throw RLMException(@"Cannot update a non-existent subscription."); + } + } +} + +@end + +#pragma mark - SubscriptionSet + +@interface RLMSyncSubscriptionSet () { + std::unique_ptr _subscriptionSet; + std::unique_ptr _mutableSubscriptionSet; + NSHashTable *_enumerators; +} +@end + +@interface RLMSyncSubscriptionEnumerator() { + // The buffer supplied by fast enumeration does not retain the objects given + // to it, but because we create objects on-demand and don't want them + // autoreleased (a table can have more rows than the device has memory for + // accessor objects) we need a thing to retain them. + id _strongBuffer[16]; +} +@end + +@implementation RLMSyncSubscriptionEnumerator + +- (instancetype)initWithSubscriptionSet:(RLMSyncSubscriptionSet *)subscriptionSet { + if (self = [super init]) { + _subscriptionSet = subscriptionSet; + return self; + } + return nil; +} +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state + count:(NSUInteger)len { + NSUInteger batchCount = 0, count = [_subscriptionSet count]; + for (NSUInteger index = state->state; index < count && batchCount < len; ++index) { + auto subscription = [_subscriptionSet objectAtIndex:index]; + _strongBuffer[batchCount] = subscription; + batchCount++; + } + + for (NSUInteger i = batchCount; i < len; ++i) { + _strongBuffer[i] = nil; + } + + if (batchCount == 0) { + // Release our data if we're done, as we're autoreleased and so may + // stick around for a while + if (_subscriptionSet) { + _subscriptionSet = nil; + } + } + + + state->itemsPtr = (__unsafe_unretained id *)(void *)_strongBuffer; + state->state += batchCount; + state->mutationsPtr = state->extra+1; + + return batchCount; +} + +@end + +NSUInteger RLMFastEnumerate(NSFastEnumerationState *state, + NSUInteger len, + RLMSyncSubscriptionSet *collection) { + __autoreleasing RLMSyncSubscriptionEnumerator *enumerator; + if (state->state == 0) { + enumerator = collection.fastEnumerator; + state->extra[0] = (long)enumerator; + state->extra[1] = collection.count; + } + else { + enumerator = (__bridge id)(void *)state->extra[0]; + } + + return [enumerator countByEnumeratingWithState:state count:len]; +} + +@implementation RLMSyncSubscriptionSet { + std::mutex _collectionEnumeratorMutex; + RLMRealm *_realm; +} + +- (instancetype)initWithSubscriptionSet:(realm::sync::SubscriptionSet)subscriptionSet + realm:(RLMRealm *)realm { + if (self = [super init]) { + _subscriptionSet = std::make_unique(subscriptionSet); + _realm = realm; + return self; + } + return nil; +} + +- (RLMSyncSubscriptionEnumerator *)fastEnumerator { + return [[RLMSyncSubscriptionEnumerator alloc] initWithSubscriptionSet:self]; +} + +- (NSUInteger)count { + return _subscriptionSet->size(); +} + +- (nullable NSError *)error { + _subscriptionSet->refresh(); + NSString *errorMessage = RLMStringDataToNSString(_subscriptionSet->error_str()); + if (errorMessage.length == 0) { + return nil; + } + return [[NSError alloc] initWithDomain:RLMSyncErrorDomain + code:RLMSyncErrorInvalidFlexibleSyncSubscriptions + userInfo:@{NSLocalizedDescriptionKey: errorMessage}]; +} + +- (RLMSyncSubscriptionState)state { + _subscriptionSet->refresh(); + switch (_subscriptionSet->state()) { + case realm::sync::SubscriptionSet::State::Uncommitted: + case realm::sync::SubscriptionSet::State::Pending: + case realm::sync::SubscriptionSet::State::Bootstrapping: + case realm::sync::SubscriptionSet::State::AwaitingMark: + return RLMSyncSubscriptionStatePending; + case realm::sync::SubscriptionSet::State::Complete: + return RLMSyncSubscriptionStateComplete; + case realm::sync::SubscriptionSet::State::Error: + return RLMSyncSubscriptionStateError; + case realm::sync::SubscriptionSet::State::Superseded: + return RLMSyncSubscriptionStateSuperseded; + } +} + +#pragma mark - Batch Update subscriptions + +- (void)update:(__attribute__((noescape)) void(^)(void))block { + return [self update:block onComplete:nil]; +} + +- (void)update:(__attribute__((noescape)) void(^)(void))block onComplete:(void(^)(NSError *))completionBlock { + if (_mutableSubscriptionSet) { + @throw RLMException(@"Cannot initiate a write transaction on subscription set that is already being updated."); + } + _mutableSubscriptionSet = std::make_unique(_subscriptionSet->make_mutable_copy()); + realm::util::ScopeExit cleanup([&]() noexcept { + if (_mutableSubscriptionSet) { + _mutableSubscriptionSet = nullptr; + _subscriptionSet->refresh(); + } + }); + + block(); + + try { + _subscriptionSet = std::make_unique(std::move(*_mutableSubscriptionSet).commit()); + _mutableSubscriptionSet = nullptr; + } + catch (realm::Exception const& ex) { + @throw RLMException(ex); + } + catch (std::exception const& ex) { + @throw RLMException(ex); + } + + if (completionBlock) { + [self waitForSynchronizationOnQueue:nil completionBlock:completionBlock]; + } +} + +- (void)waitForSynchronizationOnQueue:(nullable dispatch_queue_t)queue + completionBlock:(void(^)(NSError *))completionBlock { + _subscriptionSet->get_state_change_notification(realm::sync::SubscriptionSet::State::Complete) + .get_async([completionBlock, queue](realm::StatusWith state) noexcept { + if (queue) { + return dispatch_async(queue, ^{ + completionBlock(makeError(state)); + }); + } + return completionBlock(makeError(state)); + }); +} + +#pragma mark - Find subscription + +- (nullable RLMSyncSubscription *)subscriptionWithName:(NSString *)name { + auto subscription = _subscriptionSet->find([name UTF8String]); + if (subscription) { + return [[RLMSyncSubscription alloc] initWithSubscription:*subscription + subscriptionSet:self]; + } + return nil; +} + +- (nullable RLMSyncSubscription *)subscriptionWithClassName:(NSString *)objectClassName + where:(NSString *)predicateFormat, ... { + va_list args; + va_start(args, predicateFormat); + return [self subscriptionWithClassName:objectClassName + where:predicateFormat + args:args]; + va_end(args); +} + +- (nullable RLMSyncSubscription *)subscriptionWithClassName:(NSString *)objectClassName + where:(NSString *)predicateFormat + args:(va_list)args { + return [self subscriptionWithClassName:objectClassName + predicate:[NSPredicate predicateWithFormat:predicateFormat arguments:args]]; +} + +- (nullable RLMSyncSubscription *)subscriptionWithClassName:(NSString *)objectClassName + predicate:(NSPredicate *)predicate { + RLMClassInfo& info = _realm->_info[objectClassName]; + auto query = RLMPredicateToQuery(predicate, info.rlmObjectSchema, _realm.schema, _realm.group); + auto subscription = _subscriptionSet->find(query); + if (subscription) { + return [[RLMSyncSubscription alloc] initWithSubscription:*subscription + subscriptionSet:self]; + } + return nil; +} + + +#pragma mark - Add a Subscription + +- (void)addSubscriptionWithClassName:(NSString *)objectClassName + where:(NSString *)predicateFormat, ... { + va_list args; + va_start(args, predicateFormat); + return [self addSubscriptionWithClassName:objectClassName + where:predicateFormat + args:args]; + va_end(args); +} + +- (void)addSubscriptionWithClassName:(NSString *)objectClassName + where:(NSString *)predicateFormat + args:(va_list)args { + [self addSubscriptionWithClassName:objectClassName + subscriptionName:nil + predicate:[NSPredicate predicateWithFormat:predicateFormat arguments:args]]; +} + +- (void)addSubscriptionWithClassName:(NSString *)objectClassName + subscriptionName:(NSString *)name + where:(NSString *)predicateFormat, ... { + va_list args; + va_start(args, predicateFormat); + return [self addSubscriptionWithClassName:objectClassName + subscriptionName:name + where:predicateFormat + args:args]; + va_end(args); +} + +- (void)addSubscriptionWithClassName:(NSString *)objectClassName + subscriptionName:(NSString *)name + where:(NSString *)predicateFormat + args:(va_list)args { + [self addSubscriptionWithClassName:objectClassName + subscriptionName:name + predicate:[NSPredicate predicateWithFormat:predicateFormat arguments:args]]; + +} + +- (void)addSubscriptionWithClassName:(NSString *)objectClassName + predicate:(NSPredicate *)predicate { + return [self addSubscriptionWithClassName:objectClassName + subscriptionName:nil + predicate:predicate]; +} + +- (void)addSubscriptionWithClassName:(NSString *)objectClassName + subscriptionName:(nullable NSString *)name + predicate:(NSPredicate *)predicate { + return [self addSubscriptionWithClassName:objectClassName + subscriptionName:name + predicate:predicate + updateExisting:false]; +} + +- (void)addSubscriptionWithClassName:(NSString *)objectClassName + subscriptionName:(nullable NSString *)name + predicate:(NSPredicate *)predicate + updateExisting:(BOOL)updateExisting { + [self verifyInWriteTransaction]; + + RLMClassInfo& info = _realm->_info[objectClassName]; + auto query = RLMPredicateToQuery(predicate, info.rlmObjectSchema, _realm.schema, _realm.group); + + if (name) { + if (updateExisting || !_mutableSubscriptionSet->find(name.UTF8String)) { + _mutableSubscriptionSet->insert_or_assign(name.UTF8String, query); + } + else { + @throw RLMException(@"A subscription named '%@' already exists. If you meant to update the existing subscription please use the `update` method.", name); + } + } + else { + _mutableSubscriptionSet->insert_or_assign(query); + } +} + +#pragma mark - Remove Subscription + +- (void)removeSubscriptionWithName:(NSString *)name { + [self verifyInWriteTransaction]; + + auto subscription = _subscriptionSet->find([name UTF8String]); + if (subscription) { + _mutableSubscriptionSet->erase(subscription->name); + } +} + +- (void)removeSubscriptionWithClassName:(NSString *)objectClassName + where:(NSString *)predicateFormat, ... { + va_list args; + va_start(args, predicateFormat); + [self removeSubscriptionWithClassName:objectClassName + where:predicateFormat + args:args]; + va_end(args); +} + +- (void)removeSubscriptionWithClassName:(NSString *)objectClassName + where:(NSString *)predicateFormat + args:(va_list)args { + [self removeSubscriptionWithClassName:objectClassName + predicate:[NSPredicate predicateWithFormat:predicateFormat arguments:args]]; +} + +- (void)removeSubscriptionWithClassName:(NSString *)objectClassName + predicate:(NSPredicate *)predicate { + [self verifyInWriteTransaction]; + + RLMClassInfo& info = _realm->_info[objectClassName]; + auto query = RLMPredicateToQuery(predicate, info.rlmObjectSchema, _realm.schema, _realm.group); + auto subscription = _subscriptionSet->find(query); + if (subscription) { + _mutableSubscriptionSet->erase(query); + } +} + +- (void)removeSubscription:(RLMSyncSubscription *)subscription { + [self verifyInWriteTransaction]; + + for (auto it = _mutableSubscriptionSet->begin(); it != _mutableSubscriptionSet->end();) { + if (it->id == subscription.identifier.value) { + it = _mutableSubscriptionSet->erase(it); + return; + } + it++; + } +} + +#pragma mark - Remove Subscriptions + +- (void)removeAllSubscriptions { + [self verifyInWriteTransaction]; + _mutableSubscriptionSet->clear(); +} + +- (void)removeAllSubscriptionsWithClassName:(NSString *)className { + [self verifyInWriteTransaction]; + + for (auto it = _mutableSubscriptionSet->begin(); it != _mutableSubscriptionSet->end();) { + if (it->object_class_name == [className UTF8String]) { + it = _mutableSubscriptionSet->erase(it); + } + else { + it++; + } + } +} + +#pragma mark - NSFastEnumerator + +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state + objects:(__unused __unsafe_unretained id [])buffer + count:(NSUInteger)len { + return RLMFastEnumerate(state, len, self); +} + +#pragma mark - SubscriptionSet Collection + +- (RLMSyncSubscription *)objectAtIndex:(NSUInteger)index { + auto size = _subscriptionSet->size(); + if (index >= size) { + @throw RLMException(@"Index %llu is out of bounds (must be less than %llu).", + (unsigned long long)index, (unsigned long long)size); + } + + return [[RLMSyncSubscription alloc]initWithSubscription:_subscriptionSet->at(size_t(index)) + subscriptionSet:self]; +} + +- (RLMSyncSubscription *)firstObject { + if (_subscriptionSet->size() < 1) { + return nil; + } + return [[RLMSyncSubscription alloc]initWithSubscription:_subscriptionSet->at(size_t(0)) + subscriptionSet:self]; +} + +- (RLMSyncSubscription *)lastObject { + if (_subscriptionSet->size() < 1) { + return nil; + } + + return [[RLMSyncSubscription alloc]initWithSubscription:_subscriptionSet->at(_subscriptionSet->size()-1) + subscriptionSet:self]; +} + +#pragma mark - Subscript + +- (id)objectAtIndexedSubscript:(NSUInteger)index { + return [self objectAtIndex:index]; +} + +#pragma mark - Private API + +- (uint64_t)version { + return _subscriptionSet->version(); +} + +- (void)verifyInWriteTransaction { + if (_mutableSubscriptionSet == nil) { + @throw RLMException(@"Can only add, remove, or update subscriptions within a write subscription block."); + } +} + +@end diff --git a/Pods/Realm/Realm/RLMSyncUtil.mm b/Pods/Realm/Realm/RLMSyncUtil.mm new file mode 100644 index 0000000..8246f8d --- /dev/null +++ b/Pods/Realm/Realm/RLMSyncUtil.mm @@ -0,0 +1,54 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// 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 "RLMSyncUtil_Private.hpp" + +#import "RLMUser_Private.hpp" + +NSString *const kRLMSyncPathOfRealmBackupCopyKey = @"recovered_realm_location_path"; +NSString *const kRLMSyncErrorActionTokenKey = @"error_action_token"; + +#pragma mark - C++ APIs + +using namespace realm; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +static_assert((int)RLMClientResetModeDiscardLocal == (int)realm::ClientResyncMode::DiscardLocal); +#pragma clang diagnostic pop +static_assert((int)RLMClientResetModeDiscardUnsyncedChanges == (int)realm::ClientResyncMode::DiscardLocal); +static_assert((int)RLMClientResetModeRecoverUnsyncedChanges == (int)realm::ClientResyncMode::Recover); +static_assert((int)RLMClientResetModeRecoverOrDiscardUnsyncedChanges == (int)realm::ClientResyncMode::RecoverOrDiscard); +static_assert((int)RLMClientResetModeManual == (int)realm::ClientResyncMode::Manual); + +static_assert(int(RLMSyncStopPolicyImmediately) == int(SyncSessionStopPolicy::Immediately)); +static_assert(int(RLMSyncStopPolicyLiveIndefinitely) == int(SyncSessionStopPolicy::LiveIndefinitely)); +static_assert(int(RLMSyncStopPolicyAfterChangesUploaded) == int(SyncSessionStopPolicy::AfterChangesUploaded)); + +SyncSessionStopPolicy translateStopPolicy(RLMSyncStopPolicy stopPolicy) { + return static_cast(stopPolicy); +} + +RLMSyncStopPolicy translateStopPolicy(SyncSessionStopPolicy stopPolicy) { + return static_cast(stopPolicy); +} + +CocoaSyncUserContext& context_for(const std::shared_ptr& user) +{ + return *std::static_pointer_cast(user->binding_context()); +} diff --git a/Pods/Realm/Realm/RLMThreadSafeReference.mm b/Pods/Realm/Realm/RLMThreadSafeReference.mm new file mode 100644 index 0000000..d582332 --- /dev/null +++ b/Pods/Realm/Realm/RLMThreadSafeReference.mm @@ -0,0 +1,69 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// 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 "RLMThreadSafeReference_Private.hpp" +#import "RLMUtil.hpp" + +@implementation RLMThreadSafeReference { + realm::ThreadSafeReference _reference; + id _metadata; + Class _type; +} + +- (instancetype)initWithThreadConfined:(id)threadConfined { + if (!(self = [super init])) { + return nil; + } + + REALM_ASSERT_DEBUG([threadConfined conformsToProtocol:@protocol(RLMThreadConfined)]); + if (![threadConfined conformsToProtocol:@protocol(RLMThreadConfined_Private)]) { + @throw RLMException(@"Illegal custom conformance to `RLMThreadConfined` by `%@`", threadConfined.class); + } else if (threadConfined.invalidated) { + @throw RLMException(@"Cannot construct reference to invalidated object"); + } else if (!threadConfined.realm) { + @throw RLMException(@"Cannot construct reference to unmanaged object, " + "which can be passed across threads directly"); + } + + RLMTranslateError([&] { + _reference = [(id)threadConfined makeThreadSafeReference]; + _metadata = ((id)threadConfined).objectiveCMetadata; + }); + _type = threadConfined.class; + + return self; +} + ++ (instancetype)referenceWithThreadConfined:(id)threadConfined { + return [[self alloc] initWithThreadConfined:threadConfined]; +} + +- (id)resolveReferenceInRealm:(RLMRealm *)realm { + if (!_reference) { + @throw RLMException(@"Can only resolve a thread safe reference once."); + } + return RLMTranslateError([&] { + return [_type objectWithThreadSafeReference:std::move(_reference) metadata:_metadata realm:realm]; + }); +} + +- (BOOL)isInvalidated { + return !_reference; +} + +@end diff --git a/Pods/Realm/Realm/RLMUUID.mm b/Pods/Realm/Realm/RLMUUID.mm new file mode 100644 index 0000000..2a2f2d6 --- /dev/null +++ b/Pods/Realm/Realm/RLMUUID.mm @@ -0,0 +1,34 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 "RLMUUID_Private.hpp" + +#import + +@implementation NSUUID (RLMUUIDSupport) + +- (instancetype)initWithRealmUUID:(realm::UUID)rUuid { + self = [self initWithUUIDBytes:rUuid.to_bytes().data()]; + return self; +} + +- (realm::UUID)rlm_uuidValue { + return realm::UUID(self.UUIDString.UTF8String); +} + +@end diff --git a/Pods/Realm/Realm/RLMUpdateChecker.mm b/Pods/Realm/Realm/RLMUpdateChecker.mm new file mode 100644 index 0000000..6e54746 --- /dev/null +++ b/Pods/Realm/Realm/RLMUpdateChecker.mm @@ -0,0 +1,60 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// 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 "RLMUpdateChecker.hpp" + +#import "RLMRealm.h" +#import "RLMUtil.hpp" + +#if TARGET_IPHONE_SIMULATOR && !defined(REALM_COCOA_VERSION) +#import "RLMVersion.h" +#endif + +void RLMCheckForUpdates() { +#if TARGET_IPHONE_SIMULATOR + if (getenv("REALM_DISABLE_UPDATE_CHECKER") || RLMIsRunningInPlayground()) { + return; + } + + NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"alpha|beta|rc" + options:(NSRegularExpressionOptions)0 + error:nil]; + NSUInteger numberOfMatches = [regex numberOfMatchesInString:REALM_COCOA_VERSION + options:(NSMatchingOptions)0 + range:NSMakeRange(0, REALM_COCOA_VERSION.length)]; + + if (numberOfMatches > 0) { + // pre-release version, skip update checking + return; + } + + auto handler = ^(NSData *data, NSURLResponse *response, NSError *error) { + if (error || ((NSHTTPURLResponse *)response).statusCode != 200) { + return; + } + + NSString *latestVersion = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + if (![REALM_COCOA_VERSION isEqualToString:latestVersion]) { + NSLog(@"Version %@ of Realm is now available: https://github.com/realm/realm-swift/blob/v%@/CHANGELOG.md", latestVersion, latestVersion); + } + }; + + NSString *url = [NSString stringWithFormat:@"https://static.realm.io/update/cocoa?%@", REALM_COCOA_VERSION]; + [[NSURLSession.sharedSession dataTaskWithURL:[NSURL URLWithString:url] completionHandler:handler] resume]; +#endif +} diff --git a/Pods/Realm/Realm/RLMUpdateResult.mm b/Pods/Realm/Realm/RLMUpdateResult.mm new file mode 100644 index 0000000..cd73ec4 --- /dev/null +++ b/Pods/Realm/Realm/RLMUpdateResult.mm @@ -0,0 +1,38 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 "RLMUpdateResult_Private.hpp" + +#import "RLMBSON_Private.hpp" +#import "RLMUtil.hpp" + +@implementation RLMUpdateResult + +- (instancetype)initWithUpdateResult:(realm::app::MongoCollection::UpdateResult)updateResult { + if (self = [super init]) { + _matchedCount = updateResult.matched_count; + _modifiedCount = updateResult.modified_count; + if (updateResult.upserted_id) { + _documentId = RLMConvertBsonToRLMBSON(*updateResult.upserted_id); + _objectId = RLMDynamicCast(_documentId); + } + } + return self; +} + +@end diff --git a/Pods/Realm/Realm/RLMUser.mm b/Pods/Realm/Realm/RLMUser.mm new file mode 100644 index 0000000..5e17359 --- /dev/null +++ b/Pods/Realm/Realm/RLMUser.mm @@ -0,0 +1,498 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// 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 "RLMUser_Private.hpp" + +#import "RLMAPIKeyAuth.h" +#import "RLMApp_Private.hpp" +#import "RLMBSON_Private.hpp" +#import "RLMCredentials_Private.hpp" +#import "RLMMongoClient_Private.hpp" +#import "RLMRealmConfiguration_Private.h" +#import "RLMSyncConfiguration_Private.hpp" +#import "RLMSyncSession_Private.hpp" +#import "RLMUtil.hpp" + +#import +#import +#import +#import + +using namespace realm; + +@interface RLMUser () { + std::shared_ptr _user; +} +@end + +@implementation RLMUserSubscriptionToken { + std::shared_ptr _user; + std::optional::Token> _token; +} + +- (instancetype)initWithUser:(std::shared_ptr)user token:(realm::Subscribable::Token&&)token { + if (self = [super init]) { + _user = std::move(user); + _token = std::move(token); + } + return self; +} + +- (void)unsubscribe { + _token.reset(); + _user.reset(); +} +@end + +@implementation RLMUser + +#pragma mark - API + +- (instancetype)initWithUser:(std::shared_ptr)user + app:(RLMApp *)app { + if (self = [super init]) { + _user = user; + _app = app; + return self; + } + return nil; +} + +- (BOOL)isEqual:(id)object { + if (![object isKindOfClass:[RLMUser class]]) { + return NO; + } + return _user == ((RLMUser *)object)->_user; +} + +- (RLMRealmConfiguration *)configurationWithPartitionValue:(nullable id)partitionValue { + return [self configurationWithPartitionValue:partitionValue clientResetMode:RLMClientResetModeRecoverUnsyncedChanges]; +} + +- (RLMRealmConfiguration *)configurationWithPartitionValue:(nullable id)partitionValue + clientResetMode:(RLMClientResetMode)clientResetMode { + auto syncConfig = [[RLMSyncConfiguration alloc] initWithUser:self + partitionValue:partitionValue]; + syncConfig.clientResetMode = clientResetMode; + RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init]; + config.syncConfiguration = syncConfig; + return config; +} + +- (RLMRealmConfiguration *)configurationWithPartitionValue:(nullable id)partitionValue + clientResetMode:(RLMClientResetMode)clientResetMode + notifyBeforeReset:(nullable RLMClientResetBeforeBlock)beforeResetBlock + notifyAfterReset:(nullable RLMClientResetAfterBlock)afterResetBlock { + auto syncConfig = [[RLMSyncConfiguration alloc] initWithUser:self + partitionValue:partitionValue]; + syncConfig.clientResetMode = clientResetMode; + syncConfig.beforeClientReset = beforeResetBlock; + syncConfig.afterClientReset = afterResetBlock; + RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init]; + config.syncConfiguration = syncConfig; + return config; +} + +- (RLMRealmConfiguration *)configurationWithPartitionValue:(nullable id)partitionValue + clientResetMode:(RLMClientResetMode)clientResetMode + manualClientResetHandler:(nullable RLMSyncErrorReportingBlock)manualClientResetHandler { + auto syncConfig = [[RLMSyncConfiguration alloc] initWithUser:self + partitionValue:partitionValue]; + syncConfig.clientResetMode = clientResetMode; + syncConfig.manualClientResetHandler = manualClientResetHandler; + RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init]; + config.syncConfiguration = syncConfig; + return config; +} + +- (RLMRealmConfiguration *)flexibleSyncConfiguration { + RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init]; + config.syncConfiguration = [[RLMSyncConfiguration alloc] initWithUser:self]; + return config; +} + +- (RLMRealmConfiguration *)flexibleSyncConfigurationWithClientResetMode:(RLMClientResetMode)clientResetMode + notifyBeforeReset:(nullable RLMClientResetBeforeBlock)beforeResetBlock + notifyAfterReset:(nullable RLMClientResetAfterBlock)afterResetBlock { + auto syncConfig = [[RLMSyncConfiguration alloc] initWithUser:self]; + RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init]; + syncConfig.clientResetMode = clientResetMode; + syncConfig.beforeClientReset = beforeResetBlock; + syncConfig.afterClientReset = afterResetBlock; + config.syncConfiguration = syncConfig; + return config; +} + +- (RLMRealmConfiguration *)flexibleSyncConfigurationWithClientResetMode:(RLMClientResetMode)clientResetMode + manualClientResetHandler:(nullable RLMSyncErrorReportingBlock)manualClientResetHandler { + auto syncConfig = [[RLMSyncConfiguration alloc] initWithUser:self]; + RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init]; + syncConfig.clientResetMode = clientResetMode; + syncConfig.manualClientResetHandler = manualClientResetHandler; + config.syncConfiguration = syncConfig; + return config; +} + +- (RLMRealmConfiguration *)flexibleSyncConfigurationWithInitialSubscriptions:(RLMFlexibleSyncInitialSubscriptionsBlock)initialSubscriptions + rerunOnOpen:(BOOL)rerunOnOpen { + auto syncConfig = [[RLMSyncConfiguration alloc] initWithUser:self]; + RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init]; + config.initialSubscriptions = initialSubscriptions; + config.rerunOnOpen = rerunOnOpen; + config.syncConfiguration = syncConfig; + return config; +} + +- (RLMRealmConfiguration *)flexibleSyncConfigurationWithInitialSubscriptions:(RLMFlexibleSyncInitialSubscriptionsBlock)initialSubscriptions + rerunOnOpen:(BOOL)rerunOnOpen + clientResetMode:(RLMClientResetMode)clientResetMode + notifyBeforeReset:(nullable RLMClientResetBeforeBlock)beforeResetBlock + notifyAfterReset:(nullable RLMClientResetAfterBlock)afterResetBlock { + auto syncConfig = [[RLMSyncConfiguration alloc] initWithUser:self]; + RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init]; + syncConfig.clientResetMode = clientResetMode; + syncConfig.beforeClientReset = beforeResetBlock; + syncConfig.afterClientReset = afterResetBlock; + config.initialSubscriptions = initialSubscriptions; + config.rerunOnOpen = rerunOnOpen; + config.syncConfiguration = syncConfig; + return config; +} + +- (RLMRealmConfiguration *)flexibleSyncConfigurationWithInitialSubscriptions:(RLMFlexibleSyncInitialSubscriptionsBlock)initialSubscriptions + rerunOnOpen:(BOOL)rerunOnOpen + clientResetMode:(RLMClientResetMode)clientResetMode + manualClientResetHandler:(nullable RLMSyncErrorReportingBlock)manualClientResetHandler { + auto syncConfig = [[RLMSyncConfiguration alloc] initWithUser:self]; + RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init]; + syncConfig.clientResetMode = clientResetMode; + syncConfig.manualClientResetHandler = manualClientResetHandler; + config.initialSubscriptions = initialSubscriptions; + config.rerunOnOpen = rerunOnOpen; + config.syncConfiguration = syncConfig; + return config; +} + +- (void)logOut { + if (!_user) { + return; + } + _user->log_out(); +} + +- (BOOL)isLoggedIn { + return _user->is_logged_in(); +} + +- (void)invalidate { + if (!_user) { + return; + } + _user = nullptr; +} + +- (std::string)pathForPartitionValue:(std::string const&)value { + if (!_user) { + return ""; + } + + SyncConfig config(_user, value); + auto path = _user->sync_manager()->path_for_realm(config, value); + if ([NSFileManager.defaultManager fileExistsAtPath:@(path.c_str())]) { + return path; + } + + // Previous versions converted the partition value to a path *twice*, + // so if the file resulting from that exists open it instead + NSString *encodedPartitionValue = [@(value.data()) + stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLPathAllowedCharacterSet]]; + NSString *overEncodedRealmName = [[NSString alloc] initWithFormat:@"%@/%@", self.identifier, encodedPartitionValue]; + auto legacyPath = _user->sync_manager()->path_for_realm(config, std::string(overEncodedRealmName.UTF8String)); + if ([NSFileManager.defaultManager fileExistsAtPath:@(legacyPath.c_str())]) { + return legacyPath; + } + + return path; +} + +- (std::string)pathForFlexibleSync { + if (!_user) { + @throw RLMException(@"This is an exceptional state, `RLMUser` cannot be initialised without a reference to `SyncUser`"); + } + + SyncConfig config(_user, SyncConfig::FLXSyncEnabled{}); + return _user->sync_manager()->path_for_realm(config, realm::none); +} + +- (nullable RLMSyncSession *)sessionForPartitionValue:(id)partitionValue { + if (!_user) { + return nil; + } + + std::stringstream s; + s << RLMConvertRLMBSONToBson(partitionValue); + auto path = [self pathForPartitionValue:s.str()]; + if (auto session = _user->session_for_on_disk_path(path)) { + return [[RLMSyncSession alloc] initWithSyncSession:session]; + } + return nil; +} + +- (NSArray *)allSessions { + if (!_user) { + return @[]; + } + NSMutableArray *buffer = [NSMutableArray array]; + auto sessions = _user->all_sessions(); + for (auto session : sessions) { + [buffer addObject:[[RLMSyncSession alloc] initWithSyncSession:std::move(session)]]; + } + return [buffer copy]; +} + +- (NSString *)identifier { + if (!_user) { + return @""; + } + return @(_user->identity().c_str()); +} + +- (NSArray *)identities { + if (!_user) { + return @[]; + } + NSMutableArray *buffer = [NSMutableArray array]; + auto identities = _user->identities(); + for (auto& identity : identities) { + [buffer addObject: [[RLMUserIdentity alloc] initUserIdentityWithProviderType:@(identity.provider_type.c_str()) + identifier:@(identity.id.c_str())]]; + } + + return [buffer copy]; +} + +- (RLMUserState)state { + if (!_user) { + return RLMUserStateRemoved; + } + switch (_user->state()) { + case SyncUser::State::LoggedIn: + return RLMUserStateLoggedIn; + case SyncUser::State::LoggedOut: + return RLMUserStateLoggedOut; + case SyncUser::State::Removed: + return RLMUserStateRemoved; + } +} + +- (void)refreshCustomDataWithCompletion:(RLMUserCustomDataBlock)completion { + _user->refresh_custom_data([completion, self](std::optional error) { + if (!error) { + return completion([self customData], nil); + } + + completion(nil, makeError(*error)); + }); +} + +- (void)linkUserWithCredentials:(RLMCredentials *)credentials + completion:(RLMOptionalUserBlock)completion { + _app._realmApp->link_user(_user, credentials.appCredentials, + ^(std::shared_ptr user, std::optional error) { + if (error) { + return completion(nil, makeError(*error)); + } + + completion([[RLMUser alloc] initWithUser:user app:_app], nil); + }); +} + +- (void)removeWithCompletion:(RLMOptionalErrorBlock)completion { + _app._realmApp->remove_user(_user, ^(std::optional error) { + [self handleResponse:error completion:completion]; + }); +} + +- (void)deleteWithCompletion:(RLMUserOptionalErrorBlock)completion { + _app._realmApp->delete_user(_user, ^(std::optional error) { + [self handleResponse:error completion:completion]; + }); +} + +- (void)logOutWithCompletion:(RLMOptionalErrorBlock)completion { + _app._realmApp->log_out(_user, ^(std::optional error) { + [self handleResponse:error completion:completion]; + }); +} + +- (RLMAPIKeyAuth *)apiKeysAuth { + return [[RLMAPIKeyAuth alloc] initWithApp:_app]; +} + +- (RLMMongoClient *)mongoClientWithServiceName:(NSString *)serviceName { + return [[RLMMongoClient alloc] initWithUser:self serviceName:serviceName]; +} + +- (void)callFunctionNamed:(NSString *)name + arguments:(NSArray> *)arguments + completionBlock:(RLMCallFunctionCompletionBlock)completionBlock { + bson::BsonArray args; + + for (id argument in arguments) { + args.push_back(RLMConvertRLMBSONToBson(argument)); + } + + _app._realmApp->call_function(_user, name.UTF8String, args, + [completionBlock](std::optional&& response, + std::optional error) { + if (error) { + return completionBlock(nil, makeError(*error)); + } + + completionBlock(RLMConvertBsonToRLMBSON(*response), nil); + }); +} + +- (void)handleResponse:(std::optional)error + completion:(RLMOptionalErrorBlock)completion { + if (error) { + return completion(makeError(*error)); + } + completion(nil); +} + +#pragma mark - Private API + ++ (void)_setUpBindingContextFactory { + SyncUser::set_binding_context_factory([] { + return std::make_shared(); + }); +} + +- (NSString *)refreshToken { + if (!_user || _user->refresh_token().empty()) { + return nil; + } + return @(_user->refresh_token().c_str()); +} + +- (NSString *)accessToken { + if (!_user || _user->access_token().empty()) { + return nil; + } + return @(_user->access_token().c_str()); +} + +- (NSDictionary *)customData { + if (!_user || !_user->custom_data()) { + return @{}; + } + + return (NSDictionary *)RLMConvertBsonToRLMBSON(*_user->custom_data()); +} + +- (RLMUserProfile *)profile { + if (!_user) { + return [RLMUserProfile new]; + } + + return [[RLMUserProfile alloc] initWithUserProfile:_user->user_profile()]; +} +- (std::shared_ptr)_syncUser { + return _user; +} + +- (RLMUserSubscriptionToken *)subscribe:(RLMUserNotificationBlock)block { + return [[RLMUserSubscriptionToken alloc] initWithUser:_user token:_user->subscribe([block, self] (auto&) { + block(self); + })]; +} +@end + +#pragma mark - RLMUserIdentity + +@implementation RLMUserIdentity + +- (instancetype)initUserIdentityWithProviderType:(NSString *)providerType + identifier:(NSString *)identifier { + if (self = [super init]) { + _providerType = providerType; + _identifier = identifier; + } + return self; +} + +@end + +#pragma mark - RLMUserProfile + +@interface RLMUserProfile () { + SyncUserProfile _userProfile; +} +@end + +static NSString* userProfileMemberToNSString(const std::optional& member) { + if (member == util::none) { + return nil; + } + return @(member->c_str()); +} + +@implementation RLMUserProfile + +using UserProfileMember = std::optional (SyncUserProfile::*)() const; + +- (instancetype)initWithUserProfile:(SyncUserProfile)userProfile { + if (self = [super init]) { + _userProfile = std::move(userProfile); + } + return self; +} + +- (NSString *)name { + return userProfileMemberToNSString(_userProfile.name()); +} +- (NSString *)email { + return userProfileMemberToNSString(_userProfile.email()); +} +- (NSString *)pictureURL { + return userProfileMemberToNSString(_userProfile.picture_url()); +} +- (NSString *)firstName { + return userProfileMemberToNSString(_userProfile.first_name()); +} +- (NSString *)lastName { + return userProfileMemberToNSString(_userProfile.last_name());; +} +- (NSString *)gender { + return userProfileMemberToNSString(_userProfile.gender()); +} +- (NSString *)birthday { + return userProfileMemberToNSString(_userProfile.birthday()); +} +- (NSString *)minAge { + return userProfileMemberToNSString(_userProfile.min_age()); +} +- (NSString *)maxAge { + return userProfileMemberToNSString(_userProfile.max_age()); +} +- (NSDictionary *)metadata { + return (NSDictionary *)RLMConvertBsonToRLMBSON(_userProfile.data()); +} + +@end diff --git a/Pods/Realm/Realm/RLMUserAPIKey.mm b/Pods/Realm/Realm/RLMUserAPIKey.mm new file mode 100644 index 0000000..cce6e29 --- /dev/null +++ b/Pods/Realm/Realm/RLMUserAPIKey.mm @@ -0,0 +1,68 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 "RLMUserAPIKey.h" +#import "RLMUserAPIKey_Private.hpp" +#import "RLMUtil.hpp" +#import "RLMObjectId_Private.hpp" + +@interface RLMUserAPIKey() { + realm::app::App::UserAPIKey _userAPIKey; +} +@end + +@implementation RLMUserAPIKey + +- (instancetype)initWithUserAPIKey:(realm::app::App::UserAPIKey)userAPIKey { + if (self = [super init]) { + _userAPIKey = userAPIKey; + return self; + } + + return nil; +} + +// Indicates if the API key is disabled or not +- (BOOL)disabled { + return _userAPIKey.disabled; +} + +// The name of the key. +- (NSString *)name { + return @(_userAPIKey.name.c_str()); +} + +// The actual key. Will only be included in +// the response when an API key is first created. +- (NSString *)key { + if (_userAPIKey.key) { + return @(_userAPIKey.key->c_str()); + } + + return nil; +} + +- (RLMObjectId *)objectId { + return [[RLMObjectId alloc] initWithValue:_userAPIKey.id]; +} + +- (realm::app::App::UserAPIKey)_apiKey { + return _userAPIKey; +} + +@end diff --git a/Pods/Realm/Realm/RLMUtil.mm b/Pods/Realm/Realm/RLMUtil.mm new file mode 100644 index 0000000..d99e402 --- /dev/null +++ b/Pods/Realm/Realm/RLMUtil.mm @@ -0,0 +1,557 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// 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 "RLMUtil.hpp" + +#import "RLMArray_Private.hpp" +#import "RLMAccessor.hpp" +#import "RLMDecimal128_Private.hpp" +#import "RLMDictionary_Private.h" +#import "RLMError_Private.hpp" +#import "RLMObjectId_Private.hpp" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObjectStore.h" +#import "RLMObject_Private.hpp" +#import "RLMProperty_Private.h" +#import "RLMSwiftValueStorage.h" +#import "RLMSchema_Private.h" +#import "RLMSet_Private.hpp" +#import "RLMSwiftCollectionBase.h" +#import "RLMSwiftSupport.h" +#import "RLMUUID_Private.hpp" +#import "RLMValue.h" + +#import +#import + +#include +#include + +#if !defined(REALM_COCOA_VERSION) +#import "RLMVersion.h" +#endif + +static inline RLMArray *asRLMArray(__unsafe_unretained id const value) { + return RLMDynamicCast(value) ?: RLMDynamicCast(value)._rlmCollection; +} + +static inline RLMSet *asRLMSet(__unsafe_unretained id const value) { + return RLMDynamicCast(value) ?: RLMDynamicCast(value)._rlmCollection; +} + +static inline RLMDictionary *asRLMDictionary(__unsafe_unretained id const value) { + return RLMDynamicCast(value) ?: RLMDynamicCast(value)._rlmCollection; +} + +static inline bool checkCollectionType(__unsafe_unretained id const collection, + RLMPropertyType type, + bool optional, + __unsafe_unretained NSString *const objectClassName) { + return collection.type == type && collection.optional == optional + && (type != RLMPropertyTypeObject || [collection.objectClassName isEqualToString:objectClassName]); +} + +static id (*s_bridgeValue)(id); +id RLMAsFastEnumeration(__unsafe_unretained id obj) { + if (!obj) { + return nil; + } + if ([obj conformsToProtocol:@protocol(NSFastEnumeration)]) { + return obj; + } + if (s_bridgeValue) { + id bridged = s_bridgeValue(obj); + if ([bridged conformsToProtocol:@protocol(NSFastEnumeration)]) { + return bridged; + } + } + return nil; +} + +void RLMSetSwiftBridgeCallback(id (*callback)(id)) { + s_bridgeValue = callback; +} + +id RLMBridgeSwiftValue(__unsafe_unretained id value) { + if (!value || !s_bridgeValue) { + return nil; + } + return s_bridgeValue(value); +} + +bool RLMIsSwiftObjectClass(Class cls) { + return [cls isSubclassOfClass:RealmSwiftObject.class] + || [cls isSubclassOfClass:RealmSwiftEmbeddedObject.class]; +} + +static BOOL validateValue(__unsafe_unretained id const value, + RLMPropertyType type, + bool optional, + bool collection, + __unsafe_unretained NSString *const objectClassName) { + if (optional && !RLMCoerceToNil(value)) { + return YES; + } + + if (collection) { + if (auto rlmArray = asRLMArray(value)) { + return checkCollectionType(rlmArray, type, optional, objectClassName); + } + else if (auto rlmSet = asRLMSet(value)) { + return checkCollectionType(rlmSet, type, optional, objectClassName); + } + else if (auto rlmDictionary = asRLMDictionary(value)) { + return checkCollectionType(rlmDictionary, type, optional, objectClassName); + } + if (id enumeration = RLMAsFastEnumeration(value)) { + // check each element for compliance + for (id el in enumeration) { + if (!RLMValidateValue(el, type, optional, false, objectClassName)) { + return NO; + } + } + return YES; + } + if (!value || value == NSNull.null) { + return YES; + } + return NO; + } + + switch (type) { + case RLMPropertyTypeString: + return [value isKindOfClass:[NSString class]]; + case RLMPropertyTypeBool: + if ([value isKindOfClass:[NSNumber class]]) { + return numberIsBool(value); + } + return NO; + case RLMPropertyTypeDate: + return [value isKindOfClass:[NSDate class]]; + case RLMPropertyTypeInt: + if (NSNumber *number = RLMDynamicCast(value)) { + return numberIsInteger(number); + } + return NO; + case RLMPropertyTypeFloat: + if (NSNumber *number = RLMDynamicCast(value)) { + return numberIsFloat(number); + } + return NO; + case RLMPropertyTypeDouble: + if (NSNumber *number = RLMDynamicCast(value)) { + return numberIsDouble(number); + } + return NO; + case RLMPropertyTypeData: + return [value isKindOfClass:[NSData class]]; + case RLMPropertyTypeAny: { + return !value + || [value conformsToProtocol:@protocol(RLMValue)]; + } + case RLMPropertyTypeLinkingObjects: + return YES; + case RLMPropertyTypeObject: { + // only NSNull, nil, or objects which derive from RLMObject and match the given + // object class are valid + RLMObjectBase *objBase = RLMDynamicCast(value); + return objBase && [objBase->_objectSchema.className isEqualToString:objectClassName]; + } + case RLMPropertyTypeObjectId: + return [value isKindOfClass:[RLMObjectId class]]; + case RLMPropertyTypeDecimal128: + return [value isKindOfClass:[NSNumber class]] + || [value isKindOfClass:[RLMDecimal128 class]] + || ([value isKindOfClass:[NSString class]] && realm::Decimal128::is_valid_str([value UTF8String])); + case RLMPropertyTypeUUID: + return [value isKindOfClass:[NSUUID class]] + || ([value isKindOfClass:[NSString class]] && realm::UUID::is_valid_string([value UTF8String])); + } + @throw RLMException(@"Invalid RLMPropertyType specified"); +} + +id RLMValidateValue(__unsafe_unretained id const value, + RLMPropertyType type, bool optional, bool collection, + __unsafe_unretained NSString *const objectClassName) { + if (validateValue(value, type, optional, collection, objectClassName)) { + return value ?: NSNull.null; + } + if (id bridged = RLMBridgeSwiftValue(value)) { + if (validateValue(bridged, type, optional, collection, objectClassName)) { + return bridged ?: NSNull.null; + } + } + return nil; + } + + +void RLMThrowTypeError(__unsafe_unretained id const obj, + __unsafe_unretained RLMObjectSchema *const objectSchema, + __unsafe_unretained RLMProperty *const prop) { + @throw RLMException(@"Invalid value '%@' of type '%@' for '%@%s'%s property '%@.%@'.", + obj, [obj class], + prop.objectClassName ?: RLMTypeToString(prop.type), prop.optional ? "?" : "", + prop.array ? " array" : prop.set ? " set" : prop.dictionary ? " dictionary" : "", objectSchema.className, prop.name); +} + +void RLMValidateValueForProperty(__unsafe_unretained id const obj, + __unsafe_unretained RLMObjectSchema *const objectSchema, + __unsafe_unretained RLMProperty *const prop, + bool validateObjects) { + // This duplicates a lot of the checks in RLMIsObjectValidForProperty() + // for the sake of more specific error messages + if (prop.collection) { + // nil is considered equivalent to an empty array for historical reasons + // since we don't support null arrays (only arrays containing null), + // it's not worth the BC break to change this + if (!obj || obj == NSNull.null) { + return; + } + id enumeration = RLMAsFastEnumeration(obj); + if (!enumeration) { + @throw RLMException(@"Invalid value (%@) for '%@%s' %@ property '%@.%@': value is not enumerable.", + obj, + prop.objectClassName ?: RLMTypeToString(prop.type), + prop.optional ? "?" : "", + prop.array ? @"array" : @"set", + objectSchema.className, prop.name); + } + if (!validateObjects && prop.type == RLMPropertyTypeObject) { + return; + } + + if (RLMArray *array = asRLMArray(obj)) { + if (!checkCollectionType(array, prop.type, prop.optional, prop.objectClassName)) { + @throw RLMException(@"RLMArray<%@%s> does not match expected type '%@%s' for property '%@.%@'.", + array.objectClassName ?: RLMTypeToString(array.type), array.optional ? "?" : "", + prop.objectClassName ?: RLMTypeToString(prop.type), prop.optional ? "?" : "", + objectSchema.className, prop.name); + } + return; + } + else if (RLMSet *set = asRLMSet(obj)) { + if (!checkCollectionType(set, prop.type, prop.optional, prop.objectClassName)) { + @throw RLMException(@"RLMSet<%@%s> does not match expected type '%@%s' for property '%@.%@'.", + set.objectClassName ?: RLMTypeToString(set.type), set.optional ? "?" : "", + prop.objectClassName ?: RLMTypeToString(prop.type), prop.optional ? "?" : "", + objectSchema.className, prop.name); + } + return; + } + else if (RLMDictionary *dictionary = asRLMDictionary(obj)) { + if (!checkCollectionType(dictionary, prop.type, prop.optional, prop.objectClassName)) { + @throw RLMException(@"RLMDictionary<%@, %@%s> does not match expected type '%@%s' for property '%@.%@'.", + RLMTypeToString(dictionary.keyType), + dictionary.objectClassName ?: RLMTypeToString(dictionary.type), dictionary.optional ? "?" : "", + prop.objectClassName ?: RLMTypeToString(prop.type), prop.optional ? "?" : "", + objectSchema.className, prop.name); + } + return; + } + + if (prop.dictionary) { + for (id key in enumeration) { + id value = enumeration[key]; + if (!RLMValidateValue(value, prop.type, prop.optional, false, prop.objectClassName)) { + RLMThrowTypeError(value, objectSchema, prop); + } + } + } + else { + for (id value in enumeration) { + if (!RLMValidateValue(value, prop.type, prop.optional, false, prop.objectClassName)) { + RLMThrowTypeError(value, objectSchema, prop); + } + } + } + return; + } + + // For create() we want to skip the validation logic for objects because + // we allow much fuzzier matching (any KVC-compatible object with at least + // all the non-defaulted fields), and all the logic for that lives in the + // object store rather than here + if (prop.type == RLMPropertyTypeObject && !validateObjects) { + return; + } + if (RLMIsObjectValidForProperty(obj, prop)) { + return; + } + + RLMThrowTypeError(obj, objectSchema, prop); +} + +BOOL RLMIsObjectValidForProperty(__unsafe_unretained id const obj, + __unsafe_unretained RLMProperty *const property) { + return RLMValidateValue(obj, property.type, property.optional, property.collection, property.objectClassName) != nil; +} + +NSDictionary *RLMDefaultValuesForObjectSchema(__unsafe_unretained RLMObjectSchema *const objectSchema) { + if (!objectSchema.isSwiftClass) { + return [objectSchema.objectClass defaultPropertyValues]; + } + + NSMutableDictionary *defaults = nil; + if ([objectSchema.objectClass isSubclassOfClass:RLMObject.class]) { + defaults = [NSMutableDictionary dictionaryWithDictionary:[objectSchema.objectClass defaultPropertyValues]]; + } + else { + defaults = [NSMutableDictionary dictionary]; + } + RLMObject *defaultObject = [[objectSchema.objectClass alloc] init]; + for (RLMProperty *prop in objectSchema.properties) { + if (!defaults[prop.name] && defaultObject[prop.name]) { + defaults[prop.name] = defaultObject[prop.name]; + } + } + return defaults; +} + +static NSException *RLMException(NSString *reason, NSDictionary *additionalUserInfo) { + NSMutableDictionary *userInfo = @{RLMRealmVersionKey: REALM_COCOA_VERSION, + RLMRealmCoreVersionKey: @REALM_VERSION}.mutableCopy; + if (additionalUserInfo != nil) { + [userInfo addEntriesFromDictionary:additionalUserInfo]; + } + NSException *e = [NSException exceptionWithName:RLMExceptionName + reason:reason + userInfo:userInfo]; + return e; +} + +NSException *RLMException(NSString *fmt, ...) { + va_list args; + va_start(args, fmt); + NSException *e = RLMException([[NSString alloc] initWithFormat:fmt arguments:args], @{}); + va_end(args); + return e; +} + +NSException *RLMException(std::exception const& exception) { + return RLMException(@"%s", exception.what()); +} + +NSException *RLMException(realm::Exception const& exception) { + return RLMException(@(exception.what()), + @{@"Error Code": @(exception.code()), + @"Underlying": makeError(exception.to_status())}); +} + +void RLMSetErrorOrThrow(NSError *error, NSError **outError) { + if (outError) { + *outError = error; + } + else { + @throw RLMException(error.localizedDescription, @{NSUnderlyingErrorKey: error}); + } +} + +BOOL RLMIsDebuggerAttached() +{ + int name[] = { + CTL_KERN, + KERN_PROC, + KERN_PROC_PID, + getpid() + }; + + struct kinfo_proc info; + size_t info_size = sizeof(info); + if (sysctl(name, sizeof(name)/sizeof(name[0]), &info, &info_size, NULL, 0) == -1) { + NSLog(@"sysctl() failed: %s", strerror(errno)); + return false; + } + + return (info.kp_proc.p_flag & P_TRACED) != 0; +} + +BOOL RLMIsRunningInPlayground() { + return [[NSBundle mainBundle].bundleIdentifier hasPrefix:@"com.apple.dt.playground."]; +} + +realm::Mixed RLMObjcToMixed(__unsafe_unretained id const value, + __unsafe_unretained RLMRealm *const realm, + realm::CreatePolicy createPolicy) { + if (!value || value == NSNull.null) { + return realm::Mixed(); + } + id v; + if ([value conformsToProtocol:@protocol(RLMValue)]) { + v = value; + } + else { + v = RLMBridgeSwiftValue(value); + if (v == NSNull.null) { + return realm::Mixed(); + } + REALM_ASSERT([v conformsToProtocol:@protocol(RLMValue)]); + } + + RLMPropertyType type = [v rlm_valueType]; + return switch_on_type(static_cast(type), realm::util::overload{[&](realm::Obj*) { + // The RLMObjectBase may be unmanaged and therefor has no RLMClassInfo attached. + // So we fetch from the Realm instead. + // If the Object is managed use it's RLMClassInfo instead so we do not have to do a + // lookup in the table of schemas. + RLMObjectBase *objBase = v; + RLMAccessorContext c{objBase->_info ? *objBase->_info : realm->_info[objBase->_objectSchema.className]}; + auto obj = c.unbox(v, createPolicy); + return obj.is_valid() ? realm::Mixed(obj) : realm::Mixed(); + }, [&](auto t) { + RLMStatelessAccessorContext c; + return realm::Mixed(c.unbox>(v)); + }, [&](realm::Mixed*) -> realm::Mixed { + REALM_UNREACHABLE(); + }}); +} + +id RLMMixedToObjc(realm::Mixed const& mixed, + __unsafe_unretained RLMRealm *realm, + RLMClassInfo *classInfo) { + if (mixed.is_null()) { + return NSNull.null; + } + switch (mixed.get_type()) { + case realm::type_String: + return RLMStringDataToNSString(mixed.get_string()); + case realm::type_Int: + return @(mixed.get_int()); + case realm::type_Float: + return @(mixed.get_float()); + case realm::type_Double: + return @(mixed.get_double()); + case realm::type_Bool: + return @(mixed.get_bool()); + case realm::type_Timestamp: + return RLMTimestampToNSDate(mixed.get_timestamp()); + case realm::type_Binary: + return RLMBinaryDataToNSData(mixed.get()); + case realm::type_Decimal: + return [[RLMDecimal128 alloc] initWithDecimal128:mixed.get()]; + case realm::type_ObjectId: + return [[RLMObjectId alloc] initWithValue:mixed.get()]; + case realm::type_TypedLink: + return RLMObjectFromObjLink(realm, mixed.get(), classInfo->isSwiftClass()); + case realm::type_Link: { + auto obj = classInfo->table()->get_object((mixed).get()); + return RLMCreateObjectAccessor(*classInfo, std::move(obj)); + } + case realm::type_UUID: + return [[NSUUID alloc] initWithRealmUUID:mixed.get()]; + case realm::type_LinkList: + REALM_UNREACHABLE(); + default: + @throw RLMException(@"Invalid data type for RLMPropertyTypeAny property."); + } +} + +realm::UUID RLMObjcToUUID(__unsafe_unretained id const value) { + try { + if (auto uuid = RLMDynamicCast(value)) { + return uuid.rlm_uuidValue; + } + if (auto string = RLMDynamicCast(value)) { + return realm::UUID(string.UTF8String); + } + } + catch (std::exception const& e) { + @throw RLMException(@"Cannot convert value '%@' of type '%@' to uuid: %s", + value, [value class], e.what()); + } + @throw RLMException(@"Cannot convert value '%@' of type '%@' to uuid", value, [value class]); +} + +realm::Decimal128 RLMObjcToDecimal128(__unsafe_unretained id const value) { + try { + if (!value || value == NSNull.null) { + return realm::Decimal128(realm::null()); + } + if (auto decimal = RLMDynamicCast(value)) { + return decimal.decimal128Value; + } + if (auto string = RLMDynamicCast(value)) { + return realm::Decimal128(string.UTF8String); + } + if (auto decimal = RLMDynamicCast(value)) { + return realm::Decimal128(decimal.stringValue.UTF8String); + } + if (auto number = RLMDynamicCast(value)) { + auto type = number.objCType[0]; + if (type == *@encode(double) || type == *@encode(float)) { + return realm::Decimal128(number.doubleValue); + } + else if (std::isupper(type)) { + return realm::Decimal128(number.unsignedLongLongValue); + } + else { + return realm::Decimal128(number.longLongValue); + } + } + if (id bridged = RLMBridgeSwiftValue(value); bridged != value) { + return RLMObjcToDecimal128(bridged); + } + } + catch (std::exception const& e) { + @throw RLMException(@"Cannot convert value '%@' of type '%@' to decimal128: %s", + value, [value class], e.what()); + } + @throw RLMException(@"Cannot convert value '%@' of type '%@' to decimal128", value, [value class]); +} + +NSString *RLMDefaultDirectoryForBundleIdentifier(NSString *bundleIdentifier) { +#if TARGET_OS_TV + (void)bundleIdentifier; + // tvOS prohibits writing to the Documents directory, so we use the Library/Caches directory instead. + return NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0]; +#elif TARGET_OS_IPHONE && !TARGET_OS_MACCATALYST + (void)bundleIdentifier; + // On iOS the Documents directory isn't user-visible, so put files there + return NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; +#else + // On OS X it is, so put files in Application Support. If we aren't running + // in a sandbox, put it in a subdirectory based on the bundle identifier + // to avoid accidentally sharing files between applications + NSString *path = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES)[0]; + if (![[NSProcessInfo processInfo] environment][@"APP_SANDBOX_CONTAINER_ID"]) { + if (!bundleIdentifier) { + bundleIdentifier = [NSBundle mainBundle].bundleIdentifier; + } + if (!bundleIdentifier) { + bundleIdentifier = [NSBundle mainBundle].executablePath.lastPathComponent; + } + + path = [path stringByAppendingPathComponent:bundleIdentifier]; + + // create directory + [[NSFileManager defaultManager] createDirectoryAtPath:path + withIntermediateDirectories:YES + attributes:nil + error:nil]; + } + return path; +#endif +} + +NSDateFormatter *RLMISO8601Formatter() { + // note: NSISO8601DateFormatter can't be used as it doesn't support milliseconds + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; + dateFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]; + dateFormatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss.SSSZ"; + dateFormatter.calendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian]; + return dateFormatter; +} diff --git a/Pods/Realm/Realm/RLMValue.mm b/Pods/Realm/Realm/RLMValue.mm new file mode 100644 index 0000000..ec36455 --- /dev/null +++ b/Pods/Realm/Realm/RLMValue.mm @@ -0,0 +1,124 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// 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 "RLMValue.h" +#import "RLMUtil.hpp" + +#pragma mark NSData + +@implementation NSData (RLMValue) + +- (RLMPropertyType)rlm_valueType { + return RLMPropertyTypeData; +} + +@end + +#pragma mark NSDate + +@implementation NSDate (RLMValue) + +- (RLMPropertyType)rlm_valueType { + return RLMPropertyTypeDate; +} + +@end + +#pragma mark NSNumber + +@implementation NSNumber (RLMValue) + +- (RLMPropertyType)rlm_valueType { + if ([self objCType][0] == 'c' && (self.intValue == 0 || self.intValue == 1)) { + return RLMPropertyTypeBool; + } + else if (numberIsInteger(self)) { + return RLMPropertyTypeInt; + } + else if (*@encode(float) == [self objCType][0]) { + return RLMPropertyTypeFloat; + } + else if (*@encode(double) == [self objCType][0]) { + return RLMPropertyTypeDouble; + } + else { + @throw RLMException(@"Unknown numeric type on type RLMValue."); + } +} + +@end + +#pragma mark NSNull + +@implementation NSNull (RLMValue) + +- (RLMPropertyType)rlm_valueType { + return RLMPropertyTypeAny; +} + +@end + +#pragma mark NSString + +@implementation NSString (RLMValue) + +- (RLMPropertyType)rlm_valueType { + return RLMPropertyTypeString; +} + +@end + +#pragma mark NSUUID + +@implementation NSUUID (RLMValue) + +- (RLMPropertyType)rlm_valueType { + return RLMPropertyTypeUUID; +} + +@end + +#pragma mark RLMDecimal128 + +@implementation RLMDecimal128 (RLMValue) + +- (RLMPropertyType)rlm_valueType { + return RLMPropertyTypeDecimal128; +} + +@end + +#pragma mark RLMObjectBase + +@implementation RLMObjectBase (RLMValue) + +- (RLMPropertyType)rlm_valueType { + return RLMPropertyTypeObject; +} + +@end + +#pragma mark RLMObjectId + +@implementation RLMObjectId (RLMValue) + +- (RLMPropertyType)rlm_valueType { + return RLMPropertyTypeObjectId; +} + +@end diff --git a/Pods/Realm/Realm/Realm.modulemap b/Pods/Realm/Realm/Realm.modulemap new file mode 100644 index 0000000..ed5e7fe --- /dev/null +++ b/Pods/Realm/Realm/Realm.modulemap @@ -0,0 +1,89 @@ +framework module Realm { + export Foundation + + umbrella header "Realm.h" + + header "RLMArray.h" + header "RLMAsymmetricObject.h" + header "RLMDecimal128.h" + header "RLMDictionary.h" + header "RLMEmbeddedObject.h" + header "RLMLogger.h" + header "RLMMigration.h" + header "RLMObject.h" + header "RLMObjectId.h" + header "RLMObjectSchema.h" + header "RLMPlatform.h" + header "RLMProperty.h" + header "RLMProviderClient.h" + header "RLMRealm+Sync.h" + header "RLMRealm.h" + header "RLMRealmConfiguration.h" + header "RLMResults.h" + header "RLMSchema.h" + header "RLMSectionedResults.h" + header "RLMSet.h" + header "RLMValue.h" + + header "RLMApp.h" + header "RLMCredentials.h" + header "RLMNetworkTransport.h" + header "RLMPushClient.h" + header "RLMRealm+Sync.h" + header "RLMSyncConfiguration.h" + header "RLMSyncManager.h" + header "RLMSyncSession.h" + header "RLMUser.h" + header "RLMUserAPIKey.h" + header "RLMAPIKeyAuth.h" + header "RLMEmailPasswordAuth.h" + header "NSError+RLMSync.h" + header "RLMBSON.h" + header "RLMMongoClient.h" + header "RLMMongoDatabase.h" + header "RLMMongoCollection.h" + header "RLMUpdateResult.h" + header "RLMFindOptions.h" + header "RLMFindOneAndModifyOptions.h" + header "RLMSyncSubscription.h" + + explicit module Private { + header "RLMAccessor.h" + header "RLMApp_Private.h" + header "RLMArray_Private.h" + header "RLMAsyncTask_Private.h" + header "RLMCollection_Private.h" + header "RLMDictionary_Private.h" + header "RLMLogger_Private.h" + header "RLMEvent.h" + header "RLMMongoCollection_Private.h" + header "RLMObjectBase_Dynamic.h" + header "RLMObjectBase_Private.h" + header "RLMObjectSchema_Private.h" + header "RLMObjectStore.h" + header "RLMObject_Private.h" + header "RLMProperty_Private.h" + header "RLMRealmConfiguration_Private.h" + header "RLMRealm_Private.h" + header "RLMResults_Private.h" + header "RLMScheduler.h" + header "RLMSchema_Private.h" + header "RLMSectionedResults.h" + header "RLMSet_Private.h" + header "RLMSwiftCollectionBase.h" + header "RLMSwiftProperty.h" + header "RLMSwiftValueStorage.h" + header "RLMSyncConfiguration_Private.h" + header "RLMSyncSubscription_Private.h" + header "RLMUser_Private.h" + } + + explicit module Dynamic { + header "RLMRealm_Dynamic.h" + header "RLMObjectBase_Dynamic.h" + } + + explicit module Swift { + header "RLMSwiftObject.h" + } +} diff --git a/Pods/Realm/core/realm-monorepo.xcframework/Info.plist b/Pods/Realm/core/realm-monorepo.xcframework/Info.plist new file mode 100644 index 0000000..be7aa1b --- /dev/null +++ b/Pods/Realm/core/realm-monorepo.xcframework/Info.plist @@ -0,0 +1,125 @@ + + + + + AvailableLibraries + + + HeadersPath + Headers + LibraryIdentifier + macos-x86_64_arm64 + LibraryPath + librealm-monorepo.a + SupportedArchitectures + x86_64 +arm64 + SupportedPlatform + macos + + + HeadersPath + Headers + LibraryIdentifier + ios-arm64 + LibraryPath + librealm-monorepo.a + SupportedArchitectures + arm64 + SupportedPlatform + ios + + + HeadersPath + Headers + LibraryIdentifier + ios-arm64_x86_64-simulator + LibraryPath + librealm-monorepo.a + SupportedArchitectures + arm64 +x86_64 + SupportedPlatform + ios + SupportedPlatformVariant + simulator + + + HeadersPath + Headers + LibraryIdentifier + ios-arm64_x86_64-maccatalyst + LibraryPath + librealm-monorepo.a + SupportedArchitectures + arm64 +x86_64 + SupportedPlatform + ios + SupportedPlatformVariant + maccatalyst + + + HeadersPath + Headers + LibraryIdentifier + watchos-arm64_armv7k_arm64_32 + LibraryPath + librealm-monorepo.a + SupportedArchitectures + arm64 +armv7k +arm64_32 + SupportedPlatform + watchos + + + HeadersPath + Headers + LibraryIdentifier + watchos-arm64_i386_x86_64-simulator + LibraryPath + librealm-monorepo.a + SupportedArchitectures + arm64 +i386 +x86_64 + SupportedPlatform + watchos + SupportedPlatformVariant + simulator + + + HeadersPath + Headers + LibraryIdentifier + tvos-arm64 + LibraryPath + librealm-monorepo.a + SupportedArchitectures + arm64 + SupportedPlatform + tvos + + + HeadersPath + Headers + LibraryIdentifier + tvos-arm64_x86_64-simulator + LibraryPath + librealm-monorepo.a + SupportedArchitectures + arm64 +x86_64 + SupportedPlatform + tvos + SupportedPlatformVariant + simulator + + + CFBundlePackageType + XFWK + XCFrameworkFormatVersion + 1.0 + + diff --git a/Pods/Realm/core/realm-monorepo.xcframework/ios-arm64/Headers/external/json/json.hpp b/Pods/Realm/core/realm-monorepo.xcframework/ios-arm64/Headers/external/json/json.hpp new file mode 100644 index 0000000..77bd173 --- /dev/null +++ b/Pods/Realm/core/realm-monorepo.xcframework/ios-arm64/Headers/external/json/json.hpp @@ -0,0 +1,22875 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ +| | |__ | | | | | | version 3.7.3 +|_____|_____|_____|_|___| https://github.com/nlohmann/json + +Licensed under the MIT License . +SPDX-License-Identifier: MIT +Copyright (c) 2013-2019 Niels Lohmann . + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef INCLUDE_NLOHMANN_JSON_HPP_ +#define INCLUDE_NLOHMANN_JSON_HPP_ + +#define NLOHMANN_JSON_VERSION_MAJOR 3 +#define NLOHMANN_JSON_VERSION_MINOR 7 +#define NLOHMANN_JSON_VERSION_PATCH 3 + +#include // all_of, find, for_each +#include // assert +#include // and, not, or +#include // nullptr_t, ptrdiff_t, size_t +#include // hash, less +#include // initializer_list +#include // istream, ostream +#include // random_access_iterator_tag +#include // unique_ptr +#include // accumulate +#include // string, stoi, to_string +#include // declval, forward, move, pair, swap +#include // vector + +// #include + + +#include + +// #include + + +#include // transform +#include // array +#include // and, not +#include // forward_list +#include // inserter, front_inserter, end +#include // map +#include // string +#include // tuple, make_tuple +#include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible +#include // unordered_map +#include // pair, declval +#include // valarray + +// #include + + +#include // exception +#include // runtime_error +#include // to_string + +// #include + + +#include // size_t + +namespace nlohmann +{ +namespace detail +{ +/// struct to capture the start position of the current token +struct position_t +{ + /// the total number of characters read + std::size_t chars_read_total = 0; + /// the number of characters read in the current line + std::size_t chars_read_current_line = 0; + /// the number of lines read + std::size_t lines_read = 0; + + /// conversion to size_t to preserve SAX interface + constexpr operator size_t() const + { + return chars_read_total; + } +}; + +} // namespace detail +} // namespace nlohmann + +// #include + + +#include // pair +// #include +/* Hedley - https://nemequ.github.io/hedley + * Created by Evan Nemerson + * + * To the extent possible under law, the author(s) have dedicated all + * copyright and related and neighboring rights to this software to + * the public domain worldwide. This software is distributed without + * any warranty. + * + * For details, see . + * SPDX-License-Identifier: CC0-1.0 + */ + +#if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 11) +#if defined(JSON_HEDLEY_VERSION) + #undef JSON_HEDLEY_VERSION +#endif +#define JSON_HEDLEY_VERSION 11 + +#if defined(JSON_HEDLEY_STRINGIFY_EX) + #undef JSON_HEDLEY_STRINGIFY_EX +#endif +#define JSON_HEDLEY_STRINGIFY_EX(x) #x + +#if defined(JSON_HEDLEY_STRINGIFY) + #undef JSON_HEDLEY_STRINGIFY +#endif +#define JSON_HEDLEY_STRINGIFY(x) JSON_HEDLEY_STRINGIFY_EX(x) + +#if defined(JSON_HEDLEY_CONCAT_EX) + #undef JSON_HEDLEY_CONCAT_EX +#endif +#define JSON_HEDLEY_CONCAT_EX(a,b) a##b + +#if defined(JSON_HEDLEY_CONCAT) + #undef JSON_HEDLEY_CONCAT +#endif +#define JSON_HEDLEY_CONCAT(a,b) JSON_HEDLEY_CONCAT_EX(a,b) + +#if defined(JSON_HEDLEY_VERSION_ENCODE) + #undef JSON_HEDLEY_VERSION_ENCODE +#endif +#define JSON_HEDLEY_VERSION_ENCODE(major,minor,revision) (((major) * 1000000) + ((minor) * 1000) + (revision)) + +#if defined(JSON_HEDLEY_VERSION_DECODE_MAJOR) + #undef JSON_HEDLEY_VERSION_DECODE_MAJOR +#endif +#define JSON_HEDLEY_VERSION_DECODE_MAJOR(version) ((version) / 1000000) + +#if defined(JSON_HEDLEY_VERSION_DECODE_MINOR) + #undef JSON_HEDLEY_VERSION_DECODE_MINOR +#endif +#define JSON_HEDLEY_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000) + +#if defined(JSON_HEDLEY_VERSION_DECODE_REVISION) + #undef JSON_HEDLEY_VERSION_DECODE_REVISION +#endif +#define JSON_HEDLEY_VERSION_DECODE_REVISION(version) ((version) % 1000) + +#if defined(JSON_HEDLEY_GNUC_VERSION) + #undef JSON_HEDLEY_GNUC_VERSION +#endif +#if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__) + #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +#elif defined(__GNUC__) + #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0) +#endif + +#if defined(JSON_HEDLEY_GNUC_VERSION_CHECK) + #undef JSON_HEDLEY_GNUC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_GNUC_VERSION) + #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GNUC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_MSVC_VERSION) + #undef JSON_HEDLEY_MSVC_VERSION +#endif +#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100) +#elif defined(_MSC_FULL_VER) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10) +#elif defined(_MSC_VER) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0) +#endif + +#if defined(JSON_HEDLEY_MSVC_VERSION_CHECK) + #undef JSON_HEDLEY_MSVC_VERSION_CHECK +#endif +#if !defined(_MSC_VER) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (0) +#elif defined(_MSC_VER) && (_MSC_VER >= 1400) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch))) +#elif defined(_MSC_VER) && (_MSC_VER >= 1200) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch))) +#else + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor))) +#endif + +#if defined(JSON_HEDLEY_INTEL_VERSION) + #undef JSON_HEDLEY_INTEL_VERSION +#endif +#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) + #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE) +#elif defined(__INTEL_COMPILER) + #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) +#endif + +#if defined(JSON_HEDLEY_INTEL_VERSION_CHECK) + #undef JSON_HEDLEY_INTEL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_INTEL_VERSION) + #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_PGI_VERSION) + #undef JSON_HEDLEY_PGI_VERSION +#endif +#if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__) + #define JSON_HEDLEY_PGI_VERSION JSON_HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__) +#endif + +#if defined(JSON_HEDLEY_PGI_VERSION_CHECK) + #undef JSON_HEDLEY_PGI_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_PGI_VERSION) + #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PGI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_SUNPRO_VERSION) + #undef JSON_HEDLEY_SUNPRO_VERSION +#endif +#if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10) +#elif defined(__SUNPRO_C) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf) +#elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10) +#elif defined(__SUNPRO_CC) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf) +#endif + +#if defined(JSON_HEDLEY_SUNPRO_VERSION_CHECK) + #undef JSON_HEDLEY_SUNPRO_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_SUNPRO_VERSION) + #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_SUNPRO_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) + #undef JSON_HEDLEY_EMSCRIPTEN_VERSION +#endif +#if defined(__EMSCRIPTEN__) + #define JSON_HEDLEY_EMSCRIPTEN_VERSION JSON_HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__) +#endif + +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK) + #undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) + #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_EMSCRIPTEN_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_ARM_VERSION) + #undef JSON_HEDLEY_ARM_VERSION +#endif +#if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION) + #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100) +#elif defined(__CC_ARM) && defined(__ARMCC_VERSION) + #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100) +#endif + +#if defined(JSON_HEDLEY_ARM_VERSION_CHECK) + #undef JSON_HEDLEY_ARM_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_ARM_VERSION) + #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_ARM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_IBM_VERSION) + #undef JSON_HEDLEY_IBM_VERSION +#endif +#if defined(__ibmxl__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__) +#elif defined(__xlC__) && defined(__xlC_ver__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff) +#elif defined(__xlC__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0) +#endif + +#if defined(JSON_HEDLEY_IBM_VERSION_CHECK) + #undef JSON_HEDLEY_IBM_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_IBM_VERSION) + #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IBM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_VERSION) + #undef JSON_HEDLEY_TI_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) + #define JSON_HEDLEY_TI_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_VERSION_CHECK) + #undef JSON_HEDLEY_TI_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_VERSION) + #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_CRAY_VERSION) + #undef JSON_HEDLEY_CRAY_VERSION +#endif +#if defined(_CRAYC) + #if defined(_RELEASE_PATCHLEVEL) + #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL) + #else + #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0) + #endif +#endif + +#if defined(JSON_HEDLEY_CRAY_VERSION_CHECK) + #undef JSON_HEDLEY_CRAY_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_CRAY_VERSION) + #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_CRAY_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_IAR_VERSION) + #undef JSON_HEDLEY_IAR_VERSION +#endif +#if defined(__IAR_SYSTEMS_ICC__) + #if __VER__ > 1000 + #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000)) + #else + #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE(VER / 100, __VER__ % 100, 0) + #endif +#endif + +#if defined(JSON_HEDLEY_IAR_VERSION_CHECK) + #undef JSON_HEDLEY_IAR_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_IAR_VERSION) + #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IAR_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TINYC_VERSION) + #undef JSON_HEDLEY_TINYC_VERSION +#endif +#if defined(__TINYC__) + #define JSON_HEDLEY_TINYC_VERSION JSON_HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100) +#endif + +#if defined(JSON_HEDLEY_TINYC_VERSION_CHECK) + #undef JSON_HEDLEY_TINYC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TINYC_VERSION) + #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TINYC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_DMC_VERSION) + #undef JSON_HEDLEY_DMC_VERSION +#endif +#if defined(__DMC__) + #define JSON_HEDLEY_DMC_VERSION JSON_HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf) +#endif + +#if defined(JSON_HEDLEY_DMC_VERSION_CHECK) + #undef JSON_HEDLEY_DMC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_DMC_VERSION) + #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_DMC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_COMPCERT_VERSION) + #undef JSON_HEDLEY_COMPCERT_VERSION +#endif +#if defined(__COMPCERT_VERSION__) + #define JSON_HEDLEY_COMPCERT_VERSION JSON_HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100) +#endif + +#if defined(JSON_HEDLEY_COMPCERT_VERSION_CHECK) + #undef JSON_HEDLEY_COMPCERT_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_COMPCERT_VERSION) + #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_COMPCERT_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_PELLES_VERSION) + #undef JSON_HEDLEY_PELLES_VERSION +#endif +#if defined(__POCC__) + #define JSON_HEDLEY_PELLES_VERSION JSON_HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0) +#endif + +#if defined(JSON_HEDLEY_PELLES_VERSION_CHECK) + #undef JSON_HEDLEY_PELLES_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_PELLES_VERSION) + #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PELLES_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_GCC_VERSION) + #undef JSON_HEDLEY_GCC_VERSION +#endif +#if \ + defined(JSON_HEDLEY_GNUC_VERSION) && \ + !defined(__clang__) && \ + !defined(JSON_HEDLEY_INTEL_VERSION) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_ARM_VERSION) && \ + !defined(JSON_HEDLEY_TI_VERSION) && \ + !defined(__COMPCERT__) + #define JSON_HEDLEY_GCC_VERSION JSON_HEDLEY_GNUC_VERSION +#endif + +#if defined(JSON_HEDLEY_GCC_VERSION_CHECK) + #undef JSON_HEDLEY_GCC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_GCC_VERSION) + #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) + #define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute) +#else + #define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) + #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) __has_attribute(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) + #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) __has_attribute(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE +#endif +#if \ + defined(__has_cpp_attribute) && \ + defined(__cplusplus) && \ + (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS) + #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS +#endif +#if !defined(__cplusplus) || !defined(__has_cpp_attribute) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) +#elif \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \ + (!defined(JSON_HEDLEY_MSVC_VERSION) || JSON_HEDLEY_MSVC_VERSION_CHECK(19,20,0)) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(ns::attribute) +#else + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE +#endif +#if defined(__has_cpp_attribute) && defined(__cplusplus) + #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE +#endif +#if defined(__has_cpp_attribute) && defined(__cplusplus) + #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_BUILTIN) + #undef JSON_HEDLEY_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin) +#else + #define JSON_HEDLEY_HAS_BUILTIN(builtin) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_BUILTIN) + #undef JSON_HEDLEY_GNUC_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#else + #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_BUILTIN) + #undef JSON_HEDLEY_GCC_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#else + #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_FEATURE) + #undef JSON_HEDLEY_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_HAS_FEATURE(feature) __has_feature(feature) +#else + #define JSON_HEDLEY_HAS_FEATURE(feature) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_FEATURE) + #undef JSON_HEDLEY_GNUC_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#else + #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_FEATURE) + #undef JSON_HEDLEY_GCC_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#else + #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_EXTENSION) + #undef JSON_HEDLEY_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_HAS_EXTENSION(extension) __has_extension(extension) +#else + #define JSON_HEDLEY_HAS_EXTENSION(extension) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_EXTENSION) + #undef JSON_HEDLEY_GNUC_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#else + #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_EXTENSION) + #undef JSON_HEDLEY_GCC_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#else + #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_WARNING) + #undef JSON_HEDLEY_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_HAS_WARNING(warning) __has_warning(warning) +#else + #define JSON_HEDLEY_HAS_WARNING(warning) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_WARNING) + #undef JSON_HEDLEY_GNUC_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#else + #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_WARNING) + #undef JSON_HEDLEY_GCC_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#else + #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +/* JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for + HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ +#endif +#if defined(__cplusplus) && JSON_HEDLEY_HAS_WARNING("-Wc++98-compat") +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + xpr \ + JSON_HEDLEY_DIAGNOSTIC_POP +#else +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x +#endif + +#if \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + defined(__clang__) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR)) + #define JSON_HEDLEY_PRAGMA(value) _Pragma(#value) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_PRAGMA(value) __pragma(value) +#else + #define JSON_HEDLEY_PRAGMA(value) +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_PUSH) + #undef JSON_HEDLEY_DIAGNOSTIC_PUSH +#endif +#if defined(JSON_HEDLEY_DIAGNOSTIC_POP) + #undef JSON_HEDLEY_DIAGNOSTIC_POP +#endif +#if defined(__clang__) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("clang diagnostic pop") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push)) + #define JSON_HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop)) +#elif JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("pop") +#elif JSON_HEDLEY_TI_VERSION_CHECK(8,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop") +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") +#else + #define JSON_HEDLEY_DIAGNOSTIC_PUSH + #define JSON_HEDLEY_DIAGNOSTIC_POP +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wdeprecated-declarations") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)") +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996)) +#elif JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215") +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)") +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068)) +#elif JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-attributes") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("warning(disable:1292)") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030)) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)") +#elif JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wcast-qual") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#endif + +#if defined(JSON_HEDLEY_DEPRECATED) + #undef JSON_HEDLEY_DEPRECATED +#endif +#if defined(JSON_HEDLEY_DEPRECATED_FOR) + #undef JSON_HEDLEY_DEPRECATED_FOR +#endif +#if defined(__cplusplus) && (__cplusplus >= 201402L) + #define JSON_HEDLEY_DEPRECATED(since) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]]) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]]) +#elif \ + JSON_HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8,3,0) + #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since))) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement))) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(deprecated) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) + #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__)) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__)) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) + #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since)) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement)) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,0) + #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated) +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DEPRECATED(since) _Pragma("deprecated") + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma("deprecated") +#else + #define JSON_HEDLEY_DEPRECATED(since) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) +#endif + +#if defined(JSON_HEDLEY_UNAVAILABLE) + #undef JSON_HEDLEY_UNAVAILABLE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(warning) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since))) +#else + #define JSON_HEDLEY_UNAVAILABLE(available_since) +#endif + +#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT) + #undef JSON_HEDLEY_WARN_UNUSED_RESULT +#endif +#if defined(__cplusplus) && (__cplusplus >= 201703L) + #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) +#elif defined(_Check_return_) /* SAL */ + #define JSON_HEDLEY_WARN_UNUSED_RESULT _Check_return_ +#else + #define JSON_HEDLEY_WARN_UNUSED_RESULT +#endif + +#if defined(JSON_HEDLEY_SENTINEL) + #undef JSON_HEDLEY_SENTINEL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(sentinel) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) + #define JSON_HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position))) +#else + #define JSON_HEDLEY_SENTINEL(position) +#endif + +#if defined(JSON_HEDLEY_NO_RETURN) + #undef JSON_HEDLEY_NO_RETURN +#endif +#if JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_NO_RETURN __noreturn +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L + #define JSON_HEDLEY_NO_RETURN _Noreturn +#elif defined(__cplusplus) && (__cplusplus >= 201103L) + #define JSON_HEDLEY_NO_RETURN JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]]) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(noreturn) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,2,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(18,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(17,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) + #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_NO_RETURN _Pragma("does_not_return") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) + #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) +#elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus) + #define JSON_HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;") +#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) + #define JSON_HEDLEY_NO_RETURN __attribute((noreturn)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) + #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) +#else + #define JSON_HEDLEY_NO_RETURN +#endif + +#if defined(JSON_HEDLEY_NO_ESCAPE) + #undef JSON_HEDLEY_NO_ESCAPE +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(noescape) + #define JSON_HEDLEY_NO_ESCAPE __attribute__((__noescape__)) +#else + #define JSON_HEDLEY_NO_ESCAPE +#endif + +#if defined(JSON_HEDLEY_UNREACHABLE) + #undef JSON_HEDLEY_UNREACHABLE +#endif +#if defined(JSON_HEDLEY_UNREACHABLE_RETURN) + #undef JSON_HEDLEY_UNREACHABLE_RETURN +#endif +#if \ + (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(JSON_HEDLEY_ARM_VERSION))) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) + #define JSON_HEDLEY_UNREACHABLE() __builtin_unreachable() +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) + #define JSON_HEDLEY_UNREACHABLE() __assume(0) +#elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) + #if defined(__cplusplus) + #define JSON_HEDLEY_UNREACHABLE() std::_nassert(0) + #else + #define JSON_HEDLEY_UNREACHABLE() _nassert(0) + #endif + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return value +#elif defined(EXIT_FAILURE) + #define JSON_HEDLEY_UNREACHABLE() abort() +#else + #define JSON_HEDLEY_UNREACHABLE() + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return value +#endif +#if !defined(JSON_HEDLEY_UNREACHABLE_RETURN) + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) JSON_HEDLEY_UNREACHABLE() +#endif + +#if defined(JSON_HEDLEY_ASSUME) + #undef JSON_HEDLEY_ASSUME +#endif +#if \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_ASSUME(expr) __assume(expr) +#elif JSON_HEDLEY_HAS_BUILTIN(__builtin_assume) + #define JSON_HEDLEY_ASSUME(expr) __builtin_assume(expr) +#elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) + #if defined(__cplusplus) + #define JSON_HEDLEY_ASSUME(expr) std::_nassert(expr) + #else + #define JSON_HEDLEY_ASSUME(expr) _nassert(expr) + #endif +#elif \ + (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && !defined(JSON_HEDLEY_ARM_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) + #define JSON_HEDLEY_ASSUME(expr) ((void) ((expr) ? 1 : (__builtin_unreachable(), 1))) +#else + #define JSON_HEDLEY_ASSUME(expr) ((void) (expr)) +#endif + +JSON_HEDLEY_DIAGNOSTIC_PUSH +#if JSON_HEDLEY_HAS_WARNING("-Wpedantic") + #pragma clang diagnostic ignored "-Wpedantic" +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat-pedantic") && defined(__cplusplus) + #pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#endif +#if JSON_HEDLEY_GCC_HAS_WARNING("-Wvariadic-macros",4,0,0) + #if defined(__clang__) + #pragma clang diagnostic ignored "-Wvariadic-macros" + #elif defined(JSON_HEDLEY_GCC_VERSION) + #pragma GCC diagnostic ignored "-Wvariadic-macros" + #endif +#endif +#if defined(JSON_HEDLEY_NON_NULL) + #undef JSON_HEDLEY_NON_NULL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(nonnull) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) + #define JSON_HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__))) +#else + #define JSON_HEDLEY_NON_NULL(...) +#endif +JSON_HEDLEY_DIAGNOSTIC_POP + +#if defined(JSON_HEDLEY_PRINTF_FORMAT) + #undef JSON_HEDLEY_PRINTF_FORMAT +#endif +#if defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check))) +#elif defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check))) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(format) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check))) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(6,0,0) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check)) +#else + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) +#endif + +#if defined(JSON_HEDLEY_CONSTEXPR) + #undef JSON_HEDLEY_CONSTEXPR +#endif +#if defined(__cplusplus) + #if __cplusplus >= 201103L + #define JSON_HEDLEY_CONSTEXPR JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr) + #endif +#endif +#if !defined(JSON_HEDLEY_CONSTEXPR) + #define JSON_HEDLEY_CONSTEXPR +#endif + +#if defined(JSON_HEDLEY_PREDICT) + #undef JSON_HEDLEY_PREDICT +#endif +#if defined(JSON_HEDLEY_LIKELY) + #undef JSON_HEDLEY_LIKELY +#endif +#if defined(JSON_HEDLEY_UNLIKELY) + #undef JSON_HEDLEY_UNLIKELY +#endif +#if defined(JSON_HEDLEY_UNPREDICTABLE) + #undef JSON_HEDLEY_UNPREDICTABLE +#endif +#if JSON_HEDLEY_HAS_BUILTIN(__builtin_unpredictable) + #define JSON_HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable(!!(expr)) +#endif +#if \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(9,0,0) +# define JSON_HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability(expr, value, probability) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1, probability) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0, probability) +# define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) +# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) +#if !defined(JSON_HEDLEY_BUILTIN_UNPREDICTABLE) + #define JSON_HEDLEY_BUILTIN_UNPREDICTABLE(expr) __builtin_expect_with_probability(!!(expr), 1, 0.5) +#endif +#elif \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,27) +# define JSON_HEDLEY_PREDICT(expr, expected, probability) \ + (((probability) >= 0.9) ? __builtin_expect(!!(expr), (expected)) : (((void) (expected)), !!(expr))) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \ + (__extension__ ({ \ + JSON_HEDLEY_CONSTEXPR double hedley_probability_ = (probability); \ + ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \ + })) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) \ + (__extension__ ({ \ + JSON_HEDLEY_CONSTEXPR double hedley_probability_ = (probability); \ + ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \ + })) +# define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) +# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) +#else +# define JSON_HEDLEY_PREDICT(expr, expected, probability) (((void) (expected)), !!(expr)) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr)) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr)) +# define JSON_HEDLEY_LIKELY(expr) (!!(expr)) +# define JSON_HEDLEY_UNLIKELY(expr) (!!(expr)) +#endif +#if !defined(JSON_HEDLEY_UNPREDICTABLE) + #define JSON_HEDLEY_UNPREDICTABLE(expr) JSON_HEDLEY_PREDICT(expr, 1, 0.5) +#endif + +#if defined(JSON_HEDLEY_MALLOC) + #undef JSON_HEDLEY_MALLOC +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(malloc) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) + #define JSON_HEDLEY_MALLOC __attribute__((__malloc__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_MALLOC _Pragma("returns_new_memory") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(14, 0, 0) + #define JSON_HEDLEY_MALLOC __declspec(restrict) +#else + #define JSON_HEDLEY_MALLOC +#endif + +#if defined(JSON_HEDLEY_PURE) + #undef JSON_HEDLEY_PURE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(pure) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(2,96,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_PURE __attribute__((__pure__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_PURE _Pragma("does_not_write_global_data") +#elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus) + #define JSON_HEDLEY_PURE _Pragma("FUNC_IS_PURE;") +#else + #define JSON_HEDLEY_PURE +#endif + +#if defined(JSON_HEDLEY_CONST) + #undef JSON_HEDLEY_CONST +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(const) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(2,5,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_CONST __attribute__((__const__)) +#elif \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_CONST _Pragma("no_side_effect") +#else + #define JSON_HEDLEY_CONST JSON_HEDLEY_PURE +#endif + +#if defined(JSON_HEDLEY_RESTRICT) + #undef JSON_HEDLEY_RESTRICT +#endif +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus) + #define JSON_HEDLEY_RESTRICT restrict +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ + defined(__clang__) + #define JSON_HEDLEY_RESTRICT __restrict +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus) + #define JSON_HEDLEY_RESTRICT _Restrict +#else + #define JSON_HEDLEY_RESTRICT +#endif + +#if defined(JSON_HEDLEY_INLINE) + #undef JSON_HEDLEY_INLINE +#endif +#if \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + (defined(__cplusplus) && (__cplusplus >= 199711L)) + #define JSON_HEDLEY_INLINE inline +#elif \ + defined(JSON_HEDLEY_GCC_VERSION) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(6,2,0) + #define JSON_HEDLEY_INLINE __inline__ +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_INLINE __inline +#else + #define JSON_HEDLEY_INLINE +#endif + +#if defined(JSON_HEDLEY_ALWAYS_INLINE) + #undef JSON_HEDLEY_ALWAYS_INLINE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(always_inline) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) + #define JSON_HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) JSON_HEDLEY_INLINE +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) + #define JSON_HEDLEY_ALWAYS_INLINE __forceinline +#elif JSON_HEDLEY_TI_VERSION_CHECK(7,0,0) && defined(__cplusplus) + #define JSON_HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_ALWAYS_INLINE _Pragma("inline=forced") +#else + #define JSON_HEDLEY_ALWAYS_INLINE JSON_HEDLEY_INLINE +#endif + +#if defined(JSON_HEDLEY_NEVER_INLINE) + #undef JSON_HEDLEY_NEVER_INLINE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(noinline) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) + #define JSON_HEDLEY_NEVER_INLINE __attribute__((__noinline__)) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) + #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(10,2,0) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("noinline") +#elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("inline=never") +#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) + #define JSON_HEDLEY_NEVER_INLINE __attribute((noinline)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) + #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) +#else + #define JSON_HEDLEY_NEVER_INLINE +#endif + +#if defined(JSON_HEDLEY_PRIVATE) + #undef JSON_HEDLEY_PRIVATE +#endif +#if defined(JSON_HEDLEY_PUBLIC) + #undef JSON_HEDLEY_PUBLIC +#endif +#if defined(JSON_HEDLEY_IMPORT) + #undef JSON_HEDLEY_IMPORT +#endif +#if defined(_WIN32) || defined(__CYGWIN__) + #define JSON_HEDLEY_PRIVATE + #define JSON_HEDLEY_PUBLIC __declspec(dllexport) + #define JSON_HEDLEY_IMPORT __declspec(dllimport) +#else + #if \ + JSON_HEDLEY_HAS_ATTRIBUTE(visibility) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_EABI__) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) + #define JSON_HEDLEY_PRIVATE __attribute__((__visibility__("hidden"))) + #define JSON_HEDLEY_PUBLIC __attribute__((__visibility__("default"))) + #else + #define JSON_HEDLEY_PRIVATE + #define JSON_HEDLEY_PUBLIC + #endif + #define JSON_HEDLEY_IMPORT extern +#endif + +#if defined(JSON_HEDLEY_NO_THROW) + #undef JSON_HEDLEY_NO_THROW +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(nothrow) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_NO_THROW __attribute__((__nothrow__)) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) + #define JSON_HEDLEY_NO_THROW __declspec(nothrow) +#else + #define JSON_HEDLEY_NO_THROW +#endif + +#if defined(JSON_HEDLEY_FALL_THROUGH) + #undef JSON_HEDLEY_FALL_THROUGH +#endif +#if JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(fallthrough,7,0,0) && !defined(JSON_HEDLEY_PGI_VERSION) + #define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__)) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough) + #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]]) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough) + #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]]) +#elif defined(__fallthrough) /* SAL */ + #define JSON_HEDLEY_FALL_THROUGH __fallthrough +#else + #define JSON_HEDLEY_FALL_THROUGH +#endif + +#if defined(JSON_HEDLEY_RETURNS_NON_NULL) + #undef JSON_HEDLEY_RETURNS_NON_NULL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) + #define JSON_HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__)) +#elif defined(_Ret_notnull_) /* SAL */ + #define JSON_HEDLEY_RETURNS_NON_NULL _Ret_notnull_ +#else + #define JSON_HEDLEY_RETURNS_NON_NULL +#endif + +#if defined(JSON_HEDLEY_ARRAY_PARAM) + #undef JSON_HEDLEY_ARRAY_PARAM +#endif +#if \ + defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ + !defined(__STDC_NO_VLA__) && \ + !defined(__cplusplus) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_TINYC_VERSION) + #define JSON_HEDLEY_ARRAY_PARAM(name) (name) +#else + #define JSON_HEDLEY_ARRAY_PARAM(name) +#endif + +#if defined(JSON_HEDLEY_IS_CONSTANT) + #undef JSON_HEDLEY_IS_CONSTANT +#endif +#if defined(JSON_HEDLEY_REQUIRE_CONSTEXPR) + #undef JSON_HEDLEY_REQUIRE_CONSTEXPR +#endif +/* JSON_HEDLEY_IS_CONSTEXPR_ is for + HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ +#if defined(JSON_HEDLEY_IS_CONSTEXPR_) + #undef JSON_HEDLEY_IS_CONSTEXPR_ +#endif +#if \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,19) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(6,1,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) + #define JSON_HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr) +#endif +#if !defined(__cplusplus) +# if \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,24) +#if defined(__INTPTR_TYPE__) + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*) +#else + #include + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*) +#endif +# elif \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && !defined(JSON_HEDLEY_SUNPRO_VERSION) && !defined(JSON_HEDLEY_PGI_VERSION)) || \ + JSON_HEDLEY_HAS_EXTENSION(c_generic_selections) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,3,0) +#if defined(__INTPTR_TYPE__) + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0) +#else + #include + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0) +#endif +# elif \ + defined(JSON_HEDLEY_GCC_VERSION) || \ + defined(JSON_HEDLEY_INTEL_VERSION) || \ + defined(JSON_HEDLEY_TINYC_VERSION) || \ + defined(JSON_HEDLEY_TI_VERSION) || \ + defined(__clang__) +# define JSON_HEDLEY_IS_CONSTEXPR_(expr) ( \ + sizeof(void) != \ + sizeof(*( \ + 1 ? \ + ((void*) ((expr) * 0L) ) : \ +((struct { char v[sizeof(void) * 2]; } *) 1) \ + ) \ + ) \ + ) +# endif +#endif +#if defined(JSON_HEDLEY_IS_CONSTEXPR_) + #if !defined(JSON_HEDLEY_IS_CONSTANT) + #define JSON_HEDLEY_IS_CONSTANT(expr) JSON_HEDLEY_IS_CONSTEXPR_(expr) + #endif + #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (JSON_HEDLEY_IS_CONSTEXPR_(expr) ? (expr) : (-1)) +#else + #if !defined(JSON_HEDLEY_IS_CONSTANT) + #define JSON_HEDLEY_IS_CONSTANT(expr) (0) + #endif + #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (expr) +#endif + +#if defined(JSON_HEDLEY_BEGIN_C_DECLS) + #undef JSON_HEDLEY_BEGIN_C_DECLS +#endif +#if defined(JSON_HEDLEY_END_C_DECLS) + #undef JSON_HEDLEY_END_C_DECLS +#endif +#if defined(JSON_HEDLEY_C_DECL) + #undef JSON_HEDLEY_C_DECL +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_BEGIN_C_DECLS extern "C" { + #define JSON_HEDLEY_END_C_DECLS } + #define JSON_HEDLEY_C_DECL extern "C" +#else + #define JSON_HEDLEY_BEGIN_C_DECLS + #define JSON_HEDLEY_END_C_DECLS + #define JSON_HEDLEY_C_DECL +#endif + +#if defined(JSON_HEDLEY_STATIC_ASSERT) + #undef JSON_HEDLEY_STATIC_ASSERT +#endif +#if \ + !defined(__cplusplus) && ( \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \ + JSON_HEDLEY_HAS_FEATURE(c_static_assert) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(6,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + defined(_Static_assert) \ + ) +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message) +#elif \ + (defined(__cplusplus) && (__cplusplus >= 201103L)) || \ + JSON_HEDLEY_MSVC_VERSION_CHECK(16,0,0) || \ + (defined(__cplusplus) && JSON_HEDLEY_TI_VERSION_CHECK(8,3,0)) +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message)) +#else +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) +#endif + +#if defined(JSON_HEDLEY_CONST_CAST) + #undef JSON_HEDLEY_CONST_CAST +#endif +#if defined(__cplusplus) +# define JSON_HEDLEY_CONST_CAST(T, expr) (const_cast(expr)) +#elif \ + JSON_HEDLEY_HAS_WARNING("-Wcast-qual") || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \ + ((T) (expr)); \ + JSON_HEDLEY_DIAGNOSTIC_POP \ + })) +#else +# define JSON_HEDLEY_CONST_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_REINTERPRET_CAST) + #undef JSON_HEDLEY_REINTERPRET_CAST +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast(expr)) +#else + #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (*((T*) &(expr))) +#endif + +#if defined(JSON_HEDLEY_STATIC_CAST) + #undef JSON_HEDLEY_STATIC_CAST +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_STATIC_CAST(T, expr) (static_cast(expr)) +#else + #define JSON_HEDLEY_STATIC_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_CPP_CAST) + #undef JSON_HEDLEY_CPP_CAST +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_CPP_CAST(T, expr) static_cast(expr) +#else + #define JSON_HEDLEY_CPP_CAST(T, expr) (expr) +#endif + +#if defined(JSON_HEDLEY_NULL) + #undef JSON_HEDLEY_NULL +#endif +#if defined(__cplusplus) + #if __cplusplus >= 201103L + #define JSON_HEDLEY_NULL JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr) + #elif defined(NULL) + #define JSON_HEDLEY_NULL NULL + #else + #define JSON_HEDLEY_NULL JSON_HEDLEY_STATIC_CAST(void*, 0) + #endif +#elif defined(NULL) + #define JSON_HEDLEY_NULL NULL +#else + #define JSON_HEDLEY_NULL ((void*) 0) +#endif + +#if defined(JSON_HEDLEY_MESSAGE) + #undef JSON_HEDLEY_MESSAGE +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") +# define JSON_HEDLEY_MESSAGE(msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + JSON_HEDLEY_PRAGMA(message msg) \ + JSON_HEDLEY_DIAGNOSTIC_POP +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message msg) +#elif JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(_CRI message msg) +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#else +# define JSON_HEDLEY_MESSAGE(msg) +#endif + +#if defined(JSON_HEDLEY_WARNING) + #undef JSON_HEDLEY_WARNING +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") +# define JSON_HEDLEY_WARNING(msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + JSON_HEDLEY_PRAGMA(clang warning msg) \ + JSON_HEDLEY_DIAGNOSTIC_POP +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,8,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(GCC warning msg) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#else +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_MESSAGE(msg) +#endif + +#if defined(JSON_HEDLEY_REQUIRE) + #undef JSON_HEDLEY_REQUIRE +#endif +#if defined(JSON_HEDLEY_REQUIRE_MSG) + #undef JSON_HEDLEY_REQUIRE_MSG +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(diagnose_if) +# if JSON_HEDLEY_HAS_WARNING("-Wgcc-compat") +# define JSON_HEDLEY_REQUIRE(expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((diagnose_if(!(expr), #expr, "error"))) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((diagnose_if(!(expr), msg, "error"))) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# else +# define JSON_HEDLEY_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, "error"))) +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, "error"))) +# endif +#else +# define JSON_HEDLEY_REQUIRE(expr) +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) +#endif + +#if defined(JSON_HEDLEY_FLAGS) + #undef JSON_HEDLEY_FLAGS +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(flag_enum) + #define JSON_HEDLEY_FLAGS __attribute__((__flag_enum__)) +#endif + +#if defined(JSON_HEDLEY_FLAGS_CAST) + #undef JSON_HEDLEY_FLAGS_CAST +#endif +#if JSON_HEDLEY_INTEL_VERSION_CHECK(19,0,0) +# define JSON_HEDLEY_FLAGS_CAST(T, expr) (__extension__ ({ \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("warning(disable:188)") \ + ((T) (expr)); \ + JSON_HEDLEY_DIAGNOSTIC_POP \ + })) +#else +# define JSON_HEDLEY_FLAGS_CAST(T, expr) JSON_HEDLEY_STATIC_CAST(T, expr) +#endif + +#if defined(JSON_HEDLEY_EMPTY_BASES) + #undef JSON_HEDLEY_EMPTY_BASES +#endif +#if JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,23918) && !JSON_HEDLEY_MSVC_VERSION_CHECK(20,0,0) + #define JSON_HEDLEY_EMPTY_BASES __declspec(empty_bases) +#else + #define JSON_HEDLEY_EMPTY_BASES +#endif + +/* Remaining macros are deprecated. */ + +#if defined(JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK) + #undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK +#endif +#if defined(__clang__) + #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0) +#else + #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_CLANG_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_BUILTIN) + #undef JSON_HEDLEY_CLANG_HAS_BUILTIN +#endif +#define JSON_HEDLEY_CLANG_HAS_BUILTIN(builtin) JSON_HEDLEY_HAS_BUILTIN(builtin) + +#if defined(JSON_HEDLEY_CLANG_HAS_FEATURE) + #undef JSON_HEDLEY_CLANG_HAS_FEATURE +#endif +#define JSON_HEDLEY_CLANG_HAS_FEATURE(feature) JSON_HEDLEY_HAS_FEATURE(feature) + +#if defined(JSON_HEDLEY_CLANG_HAS_EXTENSION) + #undef JSON_HEDLEY_CLANG_HAS_EXTENSION +#endif +#define JSON_HEDLEY_CLANG_HAS_EXTENSION(extension) JSON_HEDLEY_HAS_EXTENSION(extension) + +#if defined(JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_WARNING) + #undef JSON_HEDLEY_CLANG_HAS_WARNING +#endif +#define JSON_HEDLEY_CLANG_HAS_WARNING(warning) JSON_HEDLEY_HAS_WARNING(warning) + +#endif /* !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < X) */ + + +// This file contains all internal macro definitions +// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them + +// exclude unsupported compilers +#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK) + #if defined(__clang__) + #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 + #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 + #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #endif +#endif + +// C++ language standard detection +#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 +#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #define JSON_HAS_CPP_14 +#endif + +// disable float-equal warnings on GCC/clang +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + +// disable documentation warnings on clang +#if defined(__clang__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdocumentation" +#endif + +// allow to disable exceptions +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) + #define JSON_THROW(exception) throw exception + #define JSON_TRY try + #define JSON_CATCH(exception) catch(exception) + #define JSON_INTERNAL_CATCH(exception) catch(exception) +#else + #include + #define JSON_THROW(exception) std::abort() + #define JSON_TRY if(true) + #define JSON_CATCH(exception) if(false) + #define JSON_INTERNAL_CATCH(exception) if(false) +#endif + +// override exception macros +#if defined(JSON_THROW_USER) + #undef JSON_THROW + #define JSON_THROW JSON_THROW_USER +#endif +#if defined(JSON_TRY_USER) + #undef JSON_TRY + #define JSON_TRY JSON_TRY_USER +#endif +#if defined(JSON_CATCH_USER) + #undef JSON_CATCH + #define JSON_CATCH JSON_CATCH_USER + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_CATCH_USER +#endif +#if defined(JSON_INTERNAL_CATCH_USER) + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER +#endif + +/*! +@brief macro to briefly define a mapping between an enum and JSON +@def NLOHMANN_JSON_SERIALIZE_ENUM +@since version 3.4.0 +*/ +#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ + template \ + inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [e](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.first == e; \ + }); \ + j = ((it != std::end(m)) ? it : std::begin(m))->second; \ + } \ + template \ + inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [&j](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.second == j; \ + }); \ + e = ((it != std::end(m)) ? it : std::begin(m))->first; \ + } + +// Ugly macros to avoid uglier copy-paste when specializing basic_json. They +// may be removed in the future once the class is split. + +#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ + template class ObjectType, \ + template class ArrayType, \ + class StringType, class BooleanType, class NumberIntegerType, \ + class NumberUnsignedType, class NumberFloatType, \ + template class AllocatorType, \ + template class JSONSerializer> + +#define NLOHMANN_BASIC_JSON_TPL \ + basic_json + + +namespace nlohmann +{ +namespace detail +{ +//////////////// +// exceptions // +//////////////// + +/*! +@brief general exception of the @ref basic_json class + +This class is an extension of `std::exception` objects with a member @a id for +exception ids. It is used as the base class for all exceptions thrown by the +@ref basic_json class. This class can hence be used as "wildcard" to catch +exceptions. + +Subclasses: +- @ref parse_error for exceptions indicating a parse error +- @ref invalid_iterator for exceptions indicating errors with iterators +- @ref type_error for exceptions indicating executing a member function with + a wrong type +- @ref out_of_range for exceptions indicating access out of the defined range +- @ref other_error for exceptions indicating other library errors + +@internal +@note To have nothrow-copy-constructible exceptions, we internally use + `std::runtime_error` which can cope with arbitrary-length error messages. + Intermediate strings are built with static functions and then passed to + the actual constructor. +@endinternal + +@liveexample{The following code shows how arbitrary library exceptions can be +caught.,exception} + +@since version 3.0.0 +*/ +class exception : public std::exception +{ + public: + /// returns the explanatory string + JSON_HEDLEY_RETURNS_NON_NULL + const char* what() const noexcept override + { + return m.what(); + } + + /// the id of the exception + const int id; + + protected: + JSON_HEDLEY_NON_NULL(3) + exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} + + static std::string name(const std::string& ename, int id_) + { + return "[json.exception." + ename + "." + std::to_string(id_) + "] "; + } + + private: + /// an exception object as storage for error messages + std::runtime_error m; +}; + +/*! +@brief exception indicating a parse error + +This exception is thrown by the library when a parse error occurs. Parse errors +can occur during the deserialization of JSON text, CBOR, MessagePack, as well +as when using JSON Patch. + +Member @a byte holds the byte index of the last read character in the input +file. + +Exceptions have ids 1xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position. +json.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. +json.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. +json.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. +json.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. +json.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`. +json.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. +json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. +json.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number. +json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. +json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. +json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read. +json.exception.parse_error.114 | parse error: Unsupported BSON record type 0x0F | The parsing of the corresponding BSON record type is not implemented (yet). + +@note For an input with n bytes, 1 is the index of the first character and n+1 + is the index of the terminating null byte or the end of file. This also + holds true when reading a byte vector (CBOR or MessagePack). + +@liveexample{The following code shows how a `parse_error` exception can be +caught.,parse_error} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref out_of_range for exceptions indicating access out of the defined range +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class parse_error : public exception +{ + public: + /*! + @brief create a parse error exception + @param[in] id_ the id of the exception + @param[in] pos the position where the error occurred (or with + chars_read_total=0 if the position cannot be + determined) + @param[in] what_arg the explanatory string + @return parse_error object + */ + static parse_error create(int id_, const position_t& pos, const std::string& what_arg) + { + std::string w = exception::name("parse_error", id_) + "parse error" + + position_string(pos) + ": " + what_arg; + return parse_error(id_, pos.chars_read_total, w.c_str()); + } + + static parse_error create(int id_, std::size_t byte_, const std::string& what_arg) + { + std::string w = exception::name("parse_error", id_) + "parse error" + + (byte_ != 0 ? (" at byte " + std::to_string(byte_)) : "") + + ": " + what_arg; + return parse_error(id_, byte_, w.c_str()); + } + + /*! + @brief byte index of the parse error + + The byte index of the last read character in the input file. + + @note For an input with n bytes, 1 is the index of the first character and + n+1 is the index of the terminating null byte or the end of file. + This also holds true when reading a byte vector (CBOR or MessagePack). + */ + const std::size_t byte; + + private: + parse_error(int id_, std::size_t byte_, const char* what_arg) + : exception(id_, what_arg), byte(byte_) {} + + static std::string position_string(const position_t& pos) + { + return " at line " + std::to_string(pos.lines_read + 1) + + ", column " + std::to_string(pos.chars_read_current_line); + } +}; + +/*! +@brief exception indicating errors with iterators + +This exception is thrown if iterators passed to a library function do not match +the expected semantics. + +Exceptions have ids 2xx. + +name / id | example message | description +----------------------------------- | --------------- | ------------------------- +json.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. +json.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. +json.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. +json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. +json.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. +json.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. +json.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to. +json.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container. +json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered. +json.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). + +@liveexample{The following code shows how an `invalid_iterator` exception can be +caught.,invalid_iterator} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref out_of_range for exceptions indicating access out of the defined range +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class invalid_iterator : public exception +{ + public: + static invalid_iterator create(int id_, const std::string& what_arg) + { + std::string w = exception::name("invalid_iterator", id_) + what_arg; + return invalid_iterator(id_, w.c_str()); + } + + private: + JSON_HEDLEY_NON_NULL(3) + invalid_iterator(int id_, const char* what_arg) + : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating executing a member function with a wrong type + +This exception is thrown in case of a type error; that is, a library function is +executed on a JSON value whose type does not match the expected semantics. + +Exceptions have ids 3xx. + +name / id | example message | description +----------------------------- | --------------- | ------------------------- +json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. +json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. +json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t &. +json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types. +json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types. +json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types. +json.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types. +json.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. +json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types. +json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types. +json.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types. +json.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types. +json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. +json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers. +json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. +json.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. | +json.exception.type_error.317 | JSON value cannot be serialized to requested format | The dynamic type of the object cannot be represented in the requested serialization format (e.g. a raw `true` or `null` JSON object cannot be serialized to BSON) | + +@liveexample{The following code shows how a `type_error` exception can be +caught.,type_error} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref out_of_range for exceptions indicating access out of the defined range +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class type_error : public exception +{ + public: + static type_error create(int id_, const std::string& what_arg) + { + std::string w = exception::name("type_error", id_) + what_arg; + return type_error(id_, w.c_str()); + } + + private: + JSON_HEDLEY_NON_NULL(3) + type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating access out of the defined range + +This exception is thrown in case a library function is called on an input +parameter that exceeds the expected range, for instance in case of array +indices or nonexisting object keys. + +Exceptions have ids 4xx. + +name / id | example message | description +------------------------------- | --------------- | ------------------------- +json.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1. +json.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it. +json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object. +json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved. +json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. +json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF. +json.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON and BSON only support integer numbers up to 9223372036854775807. | +json.exception.out_of_range.408 | excessive array size: 8658170730974374167 | The size (following `#`) of an UBJSON array or object exceeds the maximal capacity. | +json.exception.out_of_range.409 | BSON key cannot contain code point U+0000 (at byte 2) | Key identifiers to be serialized to BSON cannot contain code point U+0000, since the key is stored as zero-terminated c-string | + +@liveexample{The following code shows how an `out_of_range` exception can be +caught.,out_of_range} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class out_of_range : public exception +{ + public: + static out_of_range create(int id_, const std::string& what_arg) + { + std::string w = exception::name("out_of_range", id_) + what_arg; + return out_of_range(id_, w.c_str()); + } + + private: + JSON_HEDLEY_NON_NULL(3) + out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating other library errors + +This exception is thrown in case of errors that cannot be classified with the +other exception types. + +Exceptions have ids 5xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed. + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref out_of_range for exceptions indicating access out of the defined range + +@liveexample{The following code shows how an `other_error` exception can be +caught.,other_error} + +@since version 3.0.0 +*/ +class other_error : public exception +{ + public: + static other_error create(int id_, const std::string& what_arg) + { + std::string w = exception::name("other_error", id_) + what_arg; + return other_error(id_, w.c_str()); + } + + private: + JSON_HEDLEY_NON_NULL(3) + other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + + +#include // not +#include // size_t +#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type + +namespace nlohmann +{ +namespace detail +{ +// alias templates to reduce boilerplate +template +using enable_if_t = typename std::enable_if::type; + +template +using uncvref_t = typename std::remove_cv::type>::type; + +// implementation of C++14 index_sequence and affiliates +// source: https://stackoverflow.com/a/32223343 +template +struct index_sequence +{ + using type = index_sequence; + using value_type = std::size_t; + static constexpr std::size_t size() noexcept + { + return sizeof...(Ints); + } +}; + +template +struct merge_and_renumber; + +template +struct merge_and_renumber, index_sequence> + : index_sequence < I1..., (sizeof...(I1) + I2)... > {}; + +template +struct make_index_sequence + : merge_and_renumber < typename make_index_sequence < N / 2 >::type, + typename make_index_sequence < N - N / 2 >::type > {}; + +template<> struct make_index_sequence<0> : index_sequence<> {}; +template<> struct make_index_sequence<1> : index_sequence<0> {}; + +template +using index_sequence_for = make_index_sequence; + +// dispatch utility (taken from ranges-v3) +template struct priority_tag : priority_tag < N - 1 > {}; +template<> struct priority_tag<0> {}; + +// taken from ranges-v3 +template +struct static_const +{ + static constexpr T value{}; +}; + +template +constexpr T static_const::value; +} // namespace detail +} // namespace nlohmann + +// #include + + +#include // not +#include // numeric_limits +#include // false_type, is_constructible, is_integral, is_same, true_type +#include // declval + +// #include + + +#include // random_access_iterator_tag + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template struct make_void +{ + using type = void; +}; +template using void_t = typename make_void::type; +} // namespace detail +} // namespace nlohmann + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template +struct iterator_types {}; + +template +struct iterator_types < + It, + void_t> +{ + using difference_type = typename It::difference_type; + using value_type = typename It::value_type; + using pointer = typename It::pointer; + using reference = typename It::reference; + using iterator_category = typename It::iterator_category; +}; + +// This is required as some compilers implement std::iterator_traits in a way that +// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341. +template +struct iterator_traits +{ +}; + +template +struct iterator_traits < T, enable_if_t < !std::is_pointer::value >> + : iterator_types +{ +}; + +template +struct iterator_traits::value>> +{ + using iterator_category = std::random_access_iterator_tag; + using value_type = T; + using difference_type = ptrdiff_t; + using pointer = T*; + using reference = T&; +}; +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + +// #include + + +#include + +// #include + + +// https://en.cppreference.com/w/cpp/experimental/is_detected +namespace nlohmann +{ +namespace detail +{ +struct nonesuch +{ + nonesuch() = delete; + ~nonesuch() = delete; + nonesuch(nonesuch const&) = delete; + nonesuch(nonesuch const&&) = delete; + void operator=(nonesuch const&) = delete; + void operator=(nonesuch&&) = delete; +}; + +template class Op, + class... Args> +struct detector +{ + using value_t = std::false_type; + using type = Default; +}; + +template class Op, class... Args> +struct detector>, Op, Args...> +{ + using value_t = std::true_type; + using type = Op; +}; + +template