diff --git a/database/DatabaseExampleSwiftUI/DatabaseExample/DatabaseExample.entitlements b/database/DatabaseExampleSwiftUI/DatabaseExample/DatabaseExample.entitlements new file mode 100644 index 000000000..eccdd1d2b --- /dev/null +++ b/database/DatabaseExampleSwiftUI/DatabaseExample/DatabaseExample.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.developer.devicecheck.appattest-environment + production + + diff --git a/database/DatabaseExampleSwiftUI/DatabaseExample/DatabaseExample.xcodeproj/project.pbxproj b/database/DatabaseExampleSwiftUI/DatabaseExample/DatabaseExample.xcodeproj/project.pbxproj index 4a3f4ad9d..14bbfcf13 100644 --- a/database/DatabaseExampleSwiftUI/DatabaseExample/DatabaseExample.xcodeproj/project.pbxproj +++ b/database/DatabaseExampleSwiftUI/DatabaseExample/DatabaseExample.xcodeproj/project.pbxproj @@ -7,7 +7,20 @@ objects = { /* Begin PBXBuildFile section */ - B9029EF126A10B1500C92F12 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = B9029EF026A10B1500C92F12 /* GoogleService-Info.plist */; }; + 9A0FAF2F26E7CFD10092BADD /* FirebaseAppCheck in Frameworks */ = {isa = PBXBuildFile; productRef = 9A0FAF2E26E7CFD10092BADD /* FirebaseAppCheck */; }; + 9A0FAF3126E7D1310092BADD /* FirebaseAppCheck in Frameworks */ = {isa = PBXBuildFile; productRef = 9A0FAF3026E7D1310092BADD /* FirebaseAppCheck */; }; + 9A0FAF3326E7D1380092BADD /* FirebaseAppCheck in Frameworks */ = {isa = PBXBuildFile; productRef = 9A0FAF3226E7D1380092BADD /* FirebaseAppCheck */; }; + 9A0FAF3626E7E3A00092BADD /* SimpleAppCheckProviderFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A0FAF3526E7E3A00092BADD /* SimpleAppCheckProviderFactory.swift */; }; + 9A0FAF3726E7E3A00092BADD /* SimpleAppCheckProviderFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A0FAF3526E7E3A00092BADD /* SimpleAppCheckProviderFactory.swift */; }; + 9A0FAF3826E7E3A00092BADD /* SimpleAppCheckProviderFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A0FAF3526E7E3A00092BADD /* SimpleAppCheckProviderFactory.swift */; }; + 9A0FAF3E26EA90340092BADD /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 9A0FAF3D26EA90340092BADD /* GoogleService-Info.plist */; }; + 9A0FAF3F26EA90340092BADD /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 9A0FAF3D26EA90340092BADD /* GoogleService-Info.plist */; }; + 9A0FAF4026EA90340092BADD /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 9A0FAF3D26EA90340092BADD /* GoogleService-Info.plist */; }; + 9A0FAF4426EAB3AB0092BADD /* MyCustomAppCheckProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A0FAF4326EAB3AB0092BADD /* MyCustomAppCheckProvider.swift */; }; + 9A0FAF4526EAB3AB0092BADD /* MyCustomAppCheckProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A0FAF4326EAB3AB0092BADD /* MyCustomAppCheckProvider.swift */; }; + 9A0FAF4626EAB3AB0092BADD /* MyCustomAppCheckProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A0FAF4326EAB3AB0092BADD /* MyCustomAppCheckProvider.swift */; }; + 9A0FAF4A26EAB5E40092BADD /* FirebaseRemoteConfig in Frameworks */ = {isa = PBXBuildFile; productRef = 9A0FAF4926EAB5E40092BADD /* FirebaseRemoteConfig */; }; + 9A0FAF4C26EB95E20092BADD /* FirebaseAnalytics in Frameworks */ = {isa = PBXBuildFile; productRef = 9A0FAF4B26EB95E20092BADD /* FirebaseAnalytics */; }; C70B63FF2696B29400851A91 /* NewPostsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C70B63FE2696B29400851A91 /* NewPostsView.swift */; }; C70B64002696B29400851A91 /* NewPostsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C70B63FE2696B29400851A91 /* NewPostsView.swift */; }; C730A31F26B0998A00A29E81 /* PostsType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C730A31E26B0998A00A29E81 /* PostsType.swift */; }; @@ -23,9 +36,7 @@ C796F29A26CCDCF50076C5F5 /* FirebaseDatabase in Frameworks */ = {isa = PBXBuildFile; productRef = C796F29926CCDCF50076C5F5 /* FirebaseDatabase */; }; C796F29C26CCE3DA0076C5F5 /* ScreenDimensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C796F29B26CCE3DA0076C5F5 /* ScreenDimensions.swift */; }; C796F29D26CCE3DA0076C5F5 /* ScreenDimensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C796F29B26CCE3DA0076C5F5 /* ScreenDimensions.swift */; }; - C796F29E26CCE9DE0076C5F5 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = B9029EF026A10B1500C92F12 /* GoogleService-Info.plist */; }; C796F2AD26D2281A0076C5F5 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C796F2AC26D2281A0076C5F5 /* Preview Assets.xcassets */; }; - C796F2B226D228380076C5F5 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = B9029EF026A10B1500C92F12 /* GoogleService-Info.plist */; }; C796F2B326D2283B0076C5F5 /* Comment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7C6B5B2268DAC1800546A57 /* Comment.swift */; }; C796F2B426D2283E0076C5F5 /* UserViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7F60CF5268EBEDE002F68AB /* UserViewModel.swift */; }; C796F2B526D228410076C5F5 /* PostViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C79D1AC226A4114600B6A169 /* PostViewModel.swift */; }; @@ -96,7 +107,10 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - B9029EF026A10B1500C92F12 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; + 9A0FAF3526E7E3A00092BADD /* SimpleAppCheckProviderFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleAppCheckProviderFactory.swift; sourceTree = ""; }; + 9A0FAF3D26EA90340092BADD /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; + 9A0FAF4126EA914D0092BADD /* DatabaseExample.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DatabaseExample.entitlements; sourceTree = ""; }; + 9A0FAF4326EAB3AB0092BADD /* MyCustomAppCheckProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyCustomAppCheckProvider.swift; sourceTree = ""; }; C70B63FE2696B29400851A91 /* NewPostsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewPostsView.swift; sourceTree = ""; }; C730A31E26B0998A00A29E81 /* PostsType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostsType.swift; sourceTree = ""; }; C7690D8826DE0BD900F30AA6 /* UITests_iOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UITests_iOS.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -154,6 +168,7 @@ buildActionMask = 2147483647; files = ( C796F2C526D228F30076C5F5 /* FirebaseDatabase in Frameworks */, + 9A0FAF3326E7D1380092BADD /* FirebaseAppCheck in Frameworks */, C796F2C326D228F30076C5F5 /* FirebaseAuth in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -162,9 +177,12 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 9A0FAF2F26E7CFD10092BADD /* FirebaseAppCheck in Frameworks */, C7C6B59B268C8D7800546A57 /* FirebaseDatabase in Frameworks */, + 9A0FAF4C26EB95E20092BADD /* FirebaseAnalytics in Frameworks */, C7C6B597268C8D7800546A57 /* FirebaseDatabaseSwift-Beta in Frameworks */, C7C6B599268C8D7800546A57 /* FirebaseAuth in Frameworks */, + 9A0FAF4A26EAB5E40092BADD /* FirebaseRemoteConfig in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -173,6 +191,7 @@ buildActionMask = 2147483647; files = ( C796F29A26CCDCF50076C5F5 /* FirebaseDatabase in Frameworks */, + 9A0FAF3126E7D1310092BADD /* FirebaseAppCheck in Frameworks */, C796F29826CCDCEF0076C5F5 /* FirebaseAuth in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -180,6 +199,15 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 9A0FAF3426E7E37E0092BADD /* AppCheck */ = { + isa = PBXGroup; + children = ( + 9A0FAF3526E7E3A00092BADD /* SimpleAppCheckProviderFactory.swift */, + 9A0FAF4326EAB3AB0092BADD /* MyCustomAppCheckProvider.swift */, + ); + path = AppCheck; + sourceTree = ""; + }; C796F29626CCDCEF0076C5F5 /* Frameworks */ = { isa = PBXGroup; children = ( @@ -207,7 +235,8 @@ C7C6B56E268C8C9A00546A57 = { isa = PBXGroup; children = ( - B9029EF026A10B1500C92F12 /* GoogleService-Info.plist */, + 9A0FAF4126EA914D0092BADD /* DatabaseExample.entitlements */, + 9A0FAF3D26EA90340092BADD /* GoogleService-Info.plist */, C7C6B573268C8C9A00546A57 /* Shared */, C7C6B57D268C8C9C00546A57 /* iOS */, C7C6B584268C8C9C00546A57 /* macOS */, @@ -220,6 +249,7 @@ C7C6B573268C8C9A00546A57 /* Shared */ = { isa = PBXGroup; children = ( + 9A0FAF3426E7E37E0092BADD /* AppCheck */, C7C6B5A5268CED2600546A57 /* Models */, C7C6B5A4268CED2000546A57 /* Views */, C7C6B574268C8C9A00546A57 /* DatabaseExampleApp.swift */, @@ -360,6 +390,7 @@ packageProductDependencies = ( C796F2C226D228F30076C5F5 /* FirebaseAuth */, C796F2C426D228F30076C5F5 /* FirebaseDatabase */, + 9A0FAF3226E7D1380092BADD /* FirebaseAppCheck */, ); productName = tvOSDatabaseExample; productReference = C796F2A326D228180076C5F5 /* DatabaseExample (tvOS).app */; @@ -382,6 +413,9 @@ C7C6B596268C8D7800546A57 /* FirebaseDatabaseSwift-Beta */, C7C6B598268C8D7800546A57 /* FirebaseAuth */, C7C6B59A268C8D7800546A57 /* FirebaseDatabase */, + 9A0FAF2E26E7CFD10092BADD /* FirebaseAppCheck */, + 9A0FAF4926EAB5E40092BADD /* FirebaseRemoteConfig */, + 9A0FAF4B26EB95E20092BADD /* FirebaseAnalytics */, ); productName = "DatabaseExample (iOS)"; productReference = C7C6B57B268C8C9C00546A57 /* DatabaseExample.app */; @@ -403,6 +437,7 @@ packageProductDependencies = ( C796F29726CCDCEF0076C5F5 /* FirebaseAuth */, C796F29926CCDCF50076C5F5 /* FirebaseDatabase */, + 9A0FAF3026E7D1310092BADD /* FirebaseAppCheck */, ); productName = "DatabaseExample (macOS)"; productReference = C7C6B583268C8C9C00546A57 /* DatabaseExample.app */; @@ -497,7 +532,7 @@ files = ( C796F2AD26D2281A0076C5F5 /* Preview Assets.xcassets in Resources */, C796F2C626D390010076C5F5 /* Assets.xcassets in Resources */, - C796F2B226D228380076C5F5 /* GoogleService-Info.plist in Resources */, + 9A0FAF4026EA90340092BADD /* GoogleService-Info.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -505,8 +540,8 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 9A0FAF3E26EA90340092BADD /* GoogleService-Info.plist in Resources */, C7C6B58B268C8C9C00546A57 /* Assets.xcassets in Resources */, - B9029EF126A10B1500C92F12 /* GoogleService-Info.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -514,8 +549,8 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 9A0FAF3F26EA90340092BADD /* GoogleService-Info.plist in Resources */, C7C6B58C268C8C9C00546A57 /* Assets.xcassets in Resources */, - C796F29E26CCE9DE0076C5F5 /* GoogleService-Info.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -560,8 +595,10 @@ C796F2B926D228490076C5F5 /* NewPostsView.swift in Sources */, C796F2BF26D228490076C5F5 /* Database+Extensions.swift in Sources */, C796F2B326D2283B0076C5F5 /* Comment.swift in Sources */, + 9A0FAF3826E7E3A00092BADD /* SimpleAppCheckProviderFactory.swift in Sources */, C796F2C026D228490076C5F5 /* DatabaseExampleApp.swift in Sources */, C796F2B426D2283E0076C5F5 /* UserViewModel.swift in Sources */, + 9A0FAF4626EAB3AB0092BADD /* MyCustomAppCheckProvider.swift in Sources */, C796F2BD26D228490076C5F5 /* LoginView.swift in Sources */, C796F2BB26D228490076C5F5 /* SignUpView.swift in Sources */, C796F2BA26D228490076C5F5 /* PostCell.swift in Sources */, @@ -582,8 +619,10 @@ C79D1AED26A8D9A300B6A169 /* PostsView.swift in Sources */, C77ABFAE26B8A7FF00BDE919 /* Database+Extensions.swift in Sources */, C7F60CFC268EE316002F68AB /* ContentView.swift in Sources */, + 9A0FAF3626E7E3A00092BADD /* SimpleAppCheckProviderFactory.swift in Sources */, C799B60E269E1CEF00A43C40 /* PostDetailView.swift in Sources */, C70B63FF2696B29400851A91 /* NewPostsView.swift in Sources */, + 9A0FAF4426EAB3AB0092BADD /* MyCustomAppCheckProvider.swift in Sources */, C7F60CF2268E352F002F68AB /* SignUpView.swift in Sources */, C7C6B587268C8C9C00546A57 /* DatabaseExampleApp.swift in Sources */, C730A31F26B0998A00A29E81 /* PostsType.swift in Sources */, @@ -604,8 +643,10 @@ C79D1AEE26A8D9A300B6A169 /* PostsView.swift in Sources */, C77ABFAF26B8A7FF00BDE919 /* Database+Extensions.swift in Sources */, C7F60CFD268EE316002F68AB /* ContentView.swift in Sources */, + 9A0FAF3726E7E3A00092BADD /* SimpleAppCheckProviderFactory.swift in Sources */, C799B60F269E1CEF00A43C40 /* PostDetailView.swift in Sources */, C70B64002696B29400851A91 /* NewPostsView.swift in Sources */, + 9A0FAF4526EAB3AB0092BADD /* MyCustomAppCheckProvider.swift in Sources */, C7F60CF3268E352F002F68AB /* SignUpView.swift in Sources */, C7C6B588268C8C9C00546A57 /* DatabaseExampleApp.swift in Sources */, C730A32026B0998A00A29E81 /* PostsType.swift in Sources */, @@ -955,7 +996,10 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = DatabaseExample.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 374XEWX2QT; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = iOS/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.0; @@ -963,8 +1007,9 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.google.firebase.quickstart.DatabaseExample; + PRODUCT_BUNDLE_IDENTIFIER = com.google.mmaksym.DeviceTokenGenerator; PRODUCT_NAME = DatabaseExample; + PROVISIONING_PROFILE_SPECIFIER = ""; SDKROOT = iphoneos; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -976,7 +1021,10 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = DatabaseExample.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 374XEWX2QT; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = iOS/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.0; @@ -984,8 +1032,9 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.google.firebase.quickstart.DatabaseExample; + PRODUCT_BUNDLE_IDENTIFIER = com.google.mmaksym.DeviceTokenGenerator; PRODUCT_NAME = DatabaseExample; + PROVISIONING_PROFILE_SPECIFIER = ""; SDKROOT = iphoneos; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -999,8 +1048,10 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = macOS/macOS.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = 374XEWX2QT; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = macOS/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -1008,7 +1059,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 11.0; - PRODUCT_BUNDLE_IDENTIFIER = com.google.firebase.quickstart.DatabaseExample; + PRODUCT_BUNDLE_IDENTIFIER = com.google.mmaksym.DeviceTokenGenerator; PRODUCT_NAME = DatabaseExample; SDKROOT = macosx; SWIFT_VERSION = 5.0; @@ -1021,8 +1072,10 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = macOS/macOS.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = 374XEWX2QT; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = macOS/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -1030,7 +1083,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 11.0; - PRODUCT_BUNDLE_IDENTIFIER = com.google.firebase.quickstart.DatabaseExample; + PRODUCT_BUNDLE_IDENTIFIER = com.google.mmaksym.DeviceTokenGenerator; PRODUCT_NAME = DatabaseExample; SDKROOT = macosx; SWIFT_VERSION = 5.0; @@ -1117,6 +1170,31 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ + 9A0FAF2E26E7CFD10092BADD /* FirebaseAppCheck */ = { + isa = XCSwiftPackageProductDependency; + package = C7C6B595268C8D7800546A57 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseAppCheck; + }; + 9A0FAF3026E7D1310092BADD /* FirebaseAppCheck */ = { + isa = XCSwiftPackageProductDependency; + package = C7C6B595268C8D7800546A57 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseAppCheck; + }; + 9A0FAF3226E7D1380092BADD /* FirebaseAppCheck */ = { + isa = XCSwiftPackageProductDependency; + package = C7C6B595268C8D7800546A57 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseAppCheck; + }; + 9A0FAF4926EAB5E40092BADD /* FirebaseRemoteConfig */ = { + isa = XCSwiftPackageProductDependency; + package = C7C6B595268C8D7800546A57 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseRemoteConfig; + }; + 9A0FAF4B26EB95E20092BADD /* FirebaseAnalytics */ = { + isa = XCSwiftPackageProductDependency; + package = C7C6B595268C8D7800546A57 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseAnalytics; + }; C796F29726CCDCEF0076C5F5 /* FirebaseAuth */ = { isa = XCSwiftPackageProductDependency; package = C7C6B595268C8D7800546A57 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; diff --git a/database/DatabaseExampleSwiftUI/DatabaseExample/GoogleService-Info.plist b/database/DatabaseExampleSwiftUI/DatabaseExample/GoogleService-Info.plist deleted file mode 100644 index 9fe4b489f..000000000 --- a/database/DatabaseExampleSwiftUI/DatabaseExample/GoogleService-Info.plist +++ /dev/null @@ -1,40 +0,0 @@ - - - - - AD_UNIT_ID_FOR_BANNER_TEST - ca-app-pub-3940256099942544/2934735716 - AD_UNIT_ID_FOR_INTERSTITIAL_TEST - ca-app-pub-3940256099942544/4411468910 - API_KEY - AIzaSyAzlj4APqi5S58nFtE52Da0fYBOHA2MhaY - BUNDLE_ID - com.google.firebase.quickstart.DatabaseExample - CLIENT_ID - 123456789000-hjugbg6ud799v4c49dim8ce2usclthar.apps.googleusercontent.com - DATABASE_URL - https://mockproject-1234.firebaseio.com - GCM_SENDER_ID - 123456789000 - GOOGLE_APP_ID - 1:123456789000:ios:f1bf012572b04063 - IS_ADS_ENABLED - - IS_ANALYTICS_ENABLED - - IS_APPINVITE_ENABLED - - IS_GCM_ENABLED - - IS_SIGNIN_ENABLED - - PLIST_VERSION - 1 - PROJECT_ID - mockproject-1234 - REVERSED_CLIENT_ID - com.googleusercontent.apps.123456789000-hjugbg6ud799v4c49dim8ce2usclthar - STORAGE_BUCKET - mockproject-1234.appspot.com - - diff --git a/database/DatabaseExampleSwiftUI/DatabaseExample/Shared/AppCheck/MyCustomAppCheckProvider.swift b/database/DatabaseExampleSwiftUI/DatabaseExample/Shared/AppCheck/MyCustomAppCheckProvider.swift new file mode 100644 index 000000000..9810d82ed --- /dev/null +++ b/database/DatabaseExampleSwiftUI/DatabaseExample/Shared/AppCheck/MyCustomAppCheckProvider.swift @@ -0,0 +1,128 @@ +// +// Copyright (c) 2021 Google 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 Foundation +import DeviceCheck + +import Firebase + +/// The App Check provider that uses Firebase Remote Config to either forward +/// Firebase App Check token request to the standard AppAttestProvider fail +/// to skip attestation. The attestation provider also logs Analytics events to +/// track if App Attest API is available on a device and if attestation +/// succeeded or failed. The main motivation to use the custom App Check +/// provider is to gradually enable App Attest attestation to avoid throttling +/// form Apple backend. Another reason is tracking additional metrics with +/// Firebase Analytics. +/// NOTE: This is an example and may require additional optimizations to ensure the best performance in a production app, e.g. you may want to avoid fetching and activating Remote Config as a part of attestation and prefer to do it separately to avoid additional latency of the attestation process. +class MyCustomAppCheckProvider: NSObject, AppCheckProvider { + let firebaseApp: FirebaseApp + + init(firebaseApp: FirebaseApp) { + self.firebaseApp = firebaseApp + + super.init() + + // Log Analytics event if App Attest is available. + logAppAttestAvailability() + + #if DEBUG + // Print FIS Auth token for + printFISToken() + #endif + } + + private lazy var appAttestProvider: AppAttestProvider? = { + AppAttestProvider(app: self.firebaseApp) + }() + + func getToken(completion handler: @escaping (AppCheckToken?, Error?) -> Void) { + // Fetch App Attest flag from remote config. + let remoteConfig = RemoteConfig.remoteConfig(app: firebaseApp) + remoteConfig.fetchAndActivate { remoteConfigStatus, error in + // Get App Attest flag value. + let appAttestEnabled = remoteConfig[Constants.appAttestRemoteConfigFlagName].boolValue + + guard appAttestEnabled else { + // Skip attestation if App Attest is disabled. Another attestation method like DeviceCheck may be used instead of just skipping. + handler(nil, ProviderError.appAttestIsDisabled) + return + } + + // Try to obtain App Attest provider instance and fail if cannot. + guard let appAttestProvider = self.appAttestProvider else { + handler(nil, ProviderError.appAttestIsUnavailable) + return + } + + appAttestProvider.getToken(completion: handler) + + // If App Attest is enabled for the app instance then forward the Firebase App Check token request to App Attest provider. + appAttestProvider.getToken { token, error in + // Log an analytics event to track attestation success rate and make a decision if App Attest rollout should proceed. + let appAttestEvent = (token != nil && error == nil) ? Constants + .appAttestAvailableSuccessEventName : Constants.appAttestAvailableFailureEventName + Analytics.logEvent(appAttestEvent, parameters: nil) + + // Pass the result to the handler. + handler(token, error) + } + } + } + + /// Logs an Analytics event if App Attest is available. It will be used as a trigger for the App Attest rollout A/B testing experiment. + private func logAppAttestAvailability() { + if DCAppAttestService.shared.isSupported { + Analytics.logEvent(Constants.appAttestAvailableEventName, parameters: nil) + } + } + + /// Retrieves and prints a Firebase Installations Service (FIS) auth token. + /// The token can be used to assign a particular A/B testing experiment variant to a test device. + private func printFISToken() { + Installations.installations(app: firebaseApp).authToken { tokenResult, error in + print("FIS auth token: \(String(describing: tokenResult?.authToken))") + } + } + + // A factory class to connect the custom provider to Firebase App Check. + class Factory: NSObject, AppCheckProviderFactory { + func createProvider(with app: FirebaseApp) -> AppCheckProvider? { + return MyCustomAppCheckProvider(firebaseApp: app) + } + } +} + +extension MyCustomAppCheckProvider { + /// The provider errors enum. + enum ProviderError: Error { + case appAttestIsDisabled + case appAttestIsUnavailable + } + + /// Constants. + enum Constants { + /// Remote Config flag name for enabling/disabling App Attest. + static let appAttestRemoteConfigFlagName = "AppAttestEnabled" + + /// Analytics event name to log if App Attest is available on the device. + static let appAttestAvailableEventName = "AppAttestAvailable" + /// Analytics event name to log when App Attest attestation succeeds. + static let appAttestAvailableSuccessEventName = "AppAttestSuccess" + /// Analytics event name to log when App Attest attestation fails. + static let appAttestAvailableFailureEventName = "AppAttestFailure" + } +} diff --git a/database/DatabaseExampleSwiftUI/DatabaseExample/Shared/AppCheck/SimpleAppCheckProviderFactory.swift b/database/DatabaseExampleSwiftUI/DatabaseExample/Shared/AppCheck/SimpleAppCheckProviderFactory.swift new file mode 100644 index 000000000..4bf35e7a0 --- /dev/null +++ b/database/DatabaseExampleSwiftUI/DatabaseExample/Shared/AppCheck/SimpleAppCheckProviderFactory.swift @@ -0,0 +1,40 @@ +// +// Copyright (c) 2021 Google 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 Foundation +import Firebase + +class SimpleAppCheckProviderFactory: NSObject, AppCheckProviderFactory { + func createProvider(with app: FirebaseApp) -> AppCheckProvider? { + #if targetEnvironment(simulator) + // App Attest is not available on simulators. + // Use a debug provider. + let provider = AppCheckDebugProvider(app: app) + + // Print only locally generated token to avoid a valid token leak on CI. + print("Firebase App Check debug token: \(provider?.localDebugToken() ?? "")") + + return provider + #else + if #available(iOS 14.0, *) { + // Use App Attest provider on real devices. + return MyCustomAppCheckProvider(app: app) + } else { + return DeviceCheckProvider(app: app) + } + #endif + } +} diff --git a/database/DatabaseExampleSwiftUI/DatabaseExample/Shared/DatabaseExampleApp.swift b/database/DatabaseExampleSwiftUI/DatabaseExample/Shared/DatabaseExampleApp.swift index f40e832e7..fe1bd7ffb 100644 --- a/database/DatabaseExampleSwiftUI/DatabaseExample/Shared/DatabaseExampleApp.swift +++ b/database/DatabaseExampleSwiftUI/DatabaseExample/Shared/DatabaseExampleApp.swift @@ -20,6 +20,9 @@ import Firebase @main struct DatabaseExampleApp: App { init() { + // Set an instance of `MyAppCheckProviderFactory` as an App Check provider factory before + // configuring Firebase. + AppCheck.setAppCheckProviderFactory(MyCustomAppCheckProvider.Factory()) FirebaseApp.configure() }