diff --git a/Firestore/CHANGELOG.md b/Firestore/CHANGELOG.md index e92b663da5b..1ff2bf5c443 100644 --- a/Firestore/CHANGELOG.md +++ b/Firestore/CHANGELOG.md @@ -1,4 +1,5 @@ # Unreleased +- [fixed] Fixed the way gRPC certificates are loaded on macOS (#2604). # 1.1.0 - [feature] Added `FieldValue.increment()`, which can be used in diff --git a/Firestore/Example/App/iOS/Images.xcassets/AppIcon.appiconset/Contents.json b/Firestore/Example/App/iOS/Images.xcassets/AppIcon.appiconset/Contents.json index d7070bc5c02..d8db8d65fd7 100644 --- a/Firestore/Example/App/iOS/Images.xcassets/AppIcon.appiconset/Contents.json +++ b/Firestore/Example/App/iOS/Images.xcassets/AppIcon.appiconset/Contents.json @@ -84,10 +84,15 @@ "idiom" : "ipad", "size" : "83.5x83.5", "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" } ], "info" : { "version" : 1, "author" : "xcode" } -} +} \ No newline at end of file diff --git a/Firestore/Example/App/macOS_example/AppDelegate.m b/Firestore/Example/App/macOS_example/AppDelegate.m index 5a852fd41cc..0c753a7eed7 100644 --- a/Firestore/Example/App/macOS_example/AppDelegate.m +++ b/Firestore/Example/App/macOS_example/AppDelegate.m @@ -35,7 +35,6 @@ - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { // do the timestamp fix FIRFirestoreSettings *settings = db.settings; - settings.timestampsInSnapshotsEnabled = true; db.settings = settings; // create a doc diff --git a/Firestore/Example/Firestore.xcodeproj/project.pbxproj b/Firestore/Example/Firestore.xcodeproj/project.pbxproj index 0f3be773fd4..978f3f465fb 100644 --- a/Firestore/Example/Firestore.xcodeproj/project.pbxproj +++ b/Firestore/Example/Firestore.xcodeproj/project.pbxproj @@ -561,7 +561,7 @@ B9C261C26C5D311E1E3C0CB9 /* query_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = query_test.cc; sourceTree = ""; }; BB92EB03E3F92485023F64ED /* Pods_Firestore_Example_iOS_Firestore_SwiftTests_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Firestore_Example_iOS_Firestore_SwiftTests_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; C8522DE226C467C54E6788D8 /* mutation_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = mutation_test.cc; sourceTree = ""; }; - D0A6E9136804A41CEC9D55D4 /* delayed_constructor_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; path = delayed_constructor_test.cc; sourceTree = ""; }; + D0A6E9136804A41CEC9D55D4 /* delayed_constructor_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = delayed_constructor_test.cc; sourceTree = ""; }; D3CC3DC5338DCAF43A211155 /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; }; D5B2593BCB52957D62F1C9D3 /* perf_spec_test.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = perf_spec_test.json; sourceTree = ""; }; D5B25E7E7D6873CBA4571841 /* FIRNumericTransformTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FIRNumericTransformTests.mm; sourceTree = ""; }; @@ -2936,8 +2936,6 @@ "\"leveldb\"", "-framework", "\"nanopb\"", - "-framework", - "\"openssl\"", "-ObjC", ); PRODUCT_BUNDLE_IDENTIFIER = "com.google.Firestore-macOS"; @@ -3012,8 +3010,6 @@ "\"leveldb\"", "-framework", "\"nanopb\"", - "-framework", - "\"openssl\"", "-ObjC", ); PRODUCT_BUNDLE_IDENTIFIER = "com.google.Firestore-macOS"; diff --git a/Firestore/core/src/firebase/firestore/remote/grpc_root_certificate_finder_apple.mm b/Firestore/core/src/firebase/firestore/remote/grpc_root_certificate_finder_apple.mm index 4cde6ea75dd..b7e0db4b0f5 100644 --- a/Firestore/core/src/firebase/firestore/remote/grpc_root_certificate_finder_apple.mm +++ b/Firestore/core/src/firebase/firestore/remote/grpc_root_certificate_finder_apple.mm @@ -16,14 +16,15 @@ #include "Firestore/core/src/firebase/firestore/remote/grpc_root_certificate_finder.h" +#import + #include #include "Firestore/core/src/firebase/firestore/util/filesystem.h" #include "Firestore/core/src/firebase/firestore/util/hard_assert.h" #include "Firestore/core/src/firebase/firestore/util/log.h" #include "Firestore/core/src/firebase/firestore/util/statusor.h" - -#import "Firestore/Source/Core/FSTFirestoreClient.h" +#include "absl/strings/str_cat.h" namespace firebase { namespace firestore { @@ -34,45 +35,106 @@ using util::StatusOr; using util::StringFormat; +namespace { + +/** + * Finds the roots.pem certificate file in the given resource bundle and logs + * the outcome. + * + * @param bundle The bundle to check. Can be a nested bundle in Resources or + * an app or framework bundle to look in directly. + * @param parent The parent bundle of the bundle to search. Used for logging. + */ +NSString* _Nullable FindCertFileInResourceBundle(NSBundle* _Nullable bundle, + NSBundle* _Nullable parent) { + if (!bundle) return nil; + + NSString* path = [bundle pathForResource:@"roots" ofType:@"pem"]; + if (util::LogIsDebugEnabled()) { + std::string message = + absl::StrCat("roots.pem ", path ? "found " : "not found ", "in bundle ", + util::MakeString([bundle bundleIdentifier])); + if (parent) { + absl::StrAppend(&message, " (in parent ", + util::MakeString([parent bundleIdentifier]), ")"); + } + LOG_DEBUG("%s", message); + } + + return path; +} + +/** + * Finds gRPCCertificates.bundle inside the given parent, if it exists. + * + * This function exists mostly to handle differences in platforms. + * On iOS, resources are nested directly within the top-level of the parent + * bundle, but on macOS this will actually be in Contents/Resources. + * + * @param parent A framework or app bundle to check. + * @return The nested gRPCCertificates.bundle if found, otherwise nil. + */ +NSBundle* _Nullable FindCertBundleInParent(NSBundle* _Nullable parent) { + if (!parent) return nil; + + NSString* path = [parent pathForResource:@"gRPCCertificates" + ofType:@"bundle"]; + if (!path) return nil; + + return [[NSBundle alloc] initWithPath:path]; +} + +NSBundle* _Nullable FindFirestoreFrameworkBundle() { + // Load FIRFirestore reflectively to avoid a circular reference at build time. + Class firestore_class = objc_getClass("FIRFirestore"); + if (!firestore_class) return nil; + + return [NSBundle bundleForClass:firestore_class]; +} + +/** + * Finds the path to the roots.pem certificates file, wherever it may be. + * + * Carthage users will find roots.pem inside gRPCCertificates.bundle in + * the main bundle. + * + * There have been enough variations and workarounds posted on this that + * this also accepts the roots.pem file outside gRPCCertificates.bundle. + */ NSString* FindPathToCertificatesFile() { - // Certificates file might be present in either the gRPC-C++ bundle or (for + // Certificates file might be present in either the gRPC-C++ framework or (for // some projects) in the main bundle. NSBundle* bundles[] = { - // Try to load certificates bundled by gRPC-C++. + // CocoaPods: try to load from the gRPC-C++ Framework. [NSBundle bundleWithIdentifier:@"org.cocoapods.grpcpp"], - // Users manually adding resources to the project may add the - // certificate to the main application bundle. Note that `mainBundle` is - // nil for unit tests of library projects, so it cannot fully substitute - // for checking the framework bundle. + + // Carthage: try to load from the FirebaseFirestore.framework + FindFirestoreFrameworkBundle(), + + // Carthage and manual projects: users manually adding resources to the + // project may add the certificate to the main application bundle. Note + // that `mainBundle` is nil for unit tests of library projects. [NSBundle mainBundle], }; - // search for the roots.pem file in each of these resource locations - NSString* possibleResources[] = { - @"gRPCCertificates.bundle/roots", - @"roots", - }; + NSString* path = nil; - for (NSBundle* bundle : bundles) { - if (!bundle) { - continue; - } + for (NSBundle* parent : bundles) { + if (!parent) continue; - for (NSString* resource : possibleResources) { - NSString* path = [bundle pathForResource:resource ofType:@"pem"]; - if (path) { - LOG_DEBUG("%s.pem found in bundle %s", resource, - [bundle bundleIdentifier]); - return path; - } else { - LOG_DEBUG("%s.pem not found in bundle %s", resource, - [bundle bundleIdentifier]); - } - } + NSBundle* certs_bundle = FindCertBundleInParent(parent); + path = FindCertFileInResourceBundle(certs_bundle, parent); + if (path) break; + + path = FindCertFileInResourceBundle(parent, nil); + if (path) break; } - return nil; + + return path; } +} // namespace + std::string LoadGrpcRootCertificate() { NSString* path = FindPathToCertificatesFile(); HARD_ASSERT(