From d88acdee70daa690374f2359fbc3efed7e46744d Mon Sep 17 00:00:00 2001 From: Brandon Stalnaker <33703490+BrandonStalnaker@users.noreply.github.com> Date: Wed, 21 Feb 2024 10:29:06 -0500 Subject: [PATCH] feat: Add Privacy Manifest and Tracking Domain Logic (#249) * feat: Add Privacy Manifes * feat: Setup Logic for Tracking URL (#248) --- PrivacyInfo.xcprivacy | 84 +++++++++++++++++++ UnitTests/MPNetworkCommunicationTests.m | 60 ++++++++++--- mParticle-Apple-SDK.xcodeproj/project.pbxproj | 2 + .../Network/MPNetworkCommunication.m | 14 +++- 4 files changed, 145 insertions(+), 15 deletions(-) create mode 100644 PrivacyInfo.xcprivacy diff --git a/PrivacyInfo.xcprivacy b/PrivacyInfo.xcprivacy new file mode 100644 index 00000000..0cf4c588 --- /dev/null +++ b/PrivacyInfo.xcprivacy @@ -0,0 +1,84 @@ + + + + + NSPrivacyTracking + + NSPrivacyTrackingDomains + + NSPrivacyCollectedDataTypes + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeCrashData + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAnalytics + + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeAdvertisingData + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAnalytics + + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeProductInteraction + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAnalytics + + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeDeviceID + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAnalytics + + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeUserID + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAnalytics + + + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPITypeReasons + + CA92.1 + + + + + diff --git a/UnitTests/MPNetworkCommunicationTests.m b/UnitTests/MPNetworkCommunicationTests.m index f19dca81..40f582e0 100644 --- a/UnitTests/MPNetworkCommunicationTests.m +++ b/UnitTests/MPNetworkCommunicationTests.m @@ -838,30 +838,64 @@ - (void)testMaxAgeForCacheCapitalization { XCTAssertEqualObjects([networkCommunication maxAgeForCache:test5], @16); } -- (void)testPodURLRouting { +- (void)testPodURLRoutingAndTrackingURL { // NOTE: All keys are fake and randomly generated just for this test NSArray *testKeys = @[ - @[@"4u8wmsug0pf5tbf58lgjiouma3qukrgbu", @"nativesdks.us1.mparticle.com", @"identity.us1.mparticle.com"], - @[@"us1-1vc4gbp24cdtx6e31s58icnymzy83f1uf", @"nativesdks.us1.mparticle.com", @"identity.us1.mparticle.com"], - @[@"us2-v2p8lr3w2g90vtpaumbq21zy05cl50qm3", @"nativesdks.us2.mparticle.com", @"identity.us2.mparticle.com"], - @[@"eu1-bkabfno0b8zpv5bwi2zm2mfa1kfml19al", @"nativesdks.eu1.mparticle.com", @"identity.eu1.mparticle.com"], - @[@"au1-iermuj83dbeoshm0n32f10feotclq6i4a", @"nativesdks.au1.mparticle.com", @"identity.au1.mparticle.com"], - @[@"st1-k77ivhkbbqf4ce0s3y12zpcthyn1ixfyu", @"nativesdks.st1.mparticle.com", @"identity.st1.mparticle.com"], - @[@"us3-w1y2y8yj8q58d5bx9u2dvtxzl4cpa7cuf", @"nativesdks.us3.mparticle.com", @"identity.us3.mparticle.com"] + @[@"4u8wmsug0pf5tbf58lgjiouma3qukrgbu", @"nativesdks.us1.mparticle.com", @"identity.us1.mparticle.com", @"tracking-nativesdks.us1.mparticle.com", @"tracking-identity.us1.mparticle.com"], + @[@"us1-1vc4gbp24cdtx6e31s58icnymzy83f1uf", @"nativesdks.us1.mparticle.com", @"identity.us1.mparticle.com", @"tracking-nativesdks.us1.mparticle.com", @"tracking-identity.us1.mparticle.com"], + @[@"us2-v2p8lr3w2g90vtpaumbq21zy05cl50qm3", @"nativesdks.us2.mparticle.com", @"identity.us2.mparticle.com", @"tracking-nativesdks.us2.mparticle.com", @"tracking-identity.us2.mparticle.com"], + @[@"eu1-bkabfno0b8zpv5bwi2zm2mfa1kfml19al", @"nativesdks.eu1.mparticle.com", @"identity.eu1.mparticle.com", @"tracking-nativesdks.eu1.mparticle.com", @"tracking-identity.eu1.mparticle.com"], + @[@"au1-iermuj83dbeoshm0n32f10feotclq6i4a", @"nativesdks.au1.mparticle.com", @"identity.au1.mparticle.com", @"tracking-nativesdks.au1.mparticle.com", @"tracking-identity.au1.mparticle.com"], + @[@"st1-k77ivhkbbqf4ce0s3y12zpcthyn1ixfyu", @"nativesdks.st1.mparticle.com", @"identity.st1.mparticle.com", @"tracking-nativesdks.st1.mparticle.com", @"tracking-identity.st1.mparticle.com"], + @[@"us3-w1y2y8yj8q58d5bx9u2dvtxzl4cpa7cuf", @"nativesdks.us3.mparticle.com", @"identity.us3.mparticle.com", @"tracking-nativesdks.us3.mparticle.com", @"tracking-identity.us3.mparticle.com"] ]; + MPNetworkCommunication *networkCommunication = [[MPNetworkCommunication alloc] init]; + MPStateMachine *stateMachine = [MParticle sharedInstance].stateMachine; NSString *oldEventHost = @"nativesdks.mparticle.com"; NSString *oldIdentityHost = @"identity.mparticle.com"; - MPNetworkCommunication *networkCommunication = [[MPNetworkCommunication alloc] init]; + stateMachine.enableDirectRouting = NO; + stateMachine.attAuthorizationStatus = @(MPATTAuthorizationStatusNotDetermined); for (NSArray *test in testKeys) { NSString *key = test[0]; + stateMachine.apiKey = key; + + XCTAssertEqualObjects(oldEventHost, [networkCommunication defaultEventHost]); + XCTAssertEqualObjects(oldIdentityHost, [networkCommunication defaultIdentityHost]); + } + + NSString *newEventHost = @"tracking-nativesdks.mparticle.com"; + NSString *newIdentityHost = @"tracking-identity.mparticle.com"; + stateMachine.attAuthorizationStatus = @(MPATTAuthorizationStatusAuthorized); + for (NSArray *test in testKeys) { + NSString *key = test[0]; + stateMachine.apiKey = key; + + XCTAssertEqualObjects(newEventHost, [networkCommunication defaultEventHost]); + XCTAssertEqualObjects(newIdentityHost, [networkCommunication defaultIdentityHost]); + } + + stateMachine.enableDirectRouting = YES; + stateMachine.attAuthorizationStatus = @(MPATTAuthorizationStatusNotDetermined); + for (NSArray *test in testKeys) { + NSString *key = test[0]; + stateMachine.apiKey = key; NSString *eventHost = test[1]; NSString *identityHost = test[2]; - XCTAssertEqualObjects(eventHost, [networkCommunication defaultHostWithSubdomain:kMPURLHostEventSubdomain apiKey:key enableDirectRouting:YES]); - XCTAssertEqualObjects(identityHost, [networkCommunication defaultHostWithSubdomain:kMPURLHostIdentitySubdomain apiKey:key enableDirectRouting:YES]); - XCTAssertEqualObjects(oldEventHost, [networkCommunication defaultHostWithSubdomain:kMPURLHostEventSubdomain apiKey:key enableDirectRouting:NO]); - XCTAssertEqualObjects(oldIdentityHost, [networkCommunication defaultHostWithSubdomain:kMPURLHostIdentitySubdomain apiKey:key enableDirectRouting:NO]); + XCTAssertEqualObjects(eventHost, [networkCommunication defaultEventHost]); + XCTAssertEqualObjects(identityHost, [networkCommunication defaultIdentityHost]); + } + + stateMachine.attAuthorizationStatus = @(MPATTAuthorizationStatusAuthorized); + for (NSArray *test in testKeys) { + NSString *key = test[0]; + stateMachine.apiKey = key; + NSString *eventHost = test[3]; + NSString *identityHost = test[4]; + + XCTAssertEqualObjects(eventHost, [networkCommunication defaultEventHost]); + XCTAssertEqualObjects(identityHost, [networkCommunication defaultIdentityHost]); } } diff --git a/mParticle-Apple-SDK.xcodeproj/project.pbxproj b/mParticle-Apple-SDK.xcodeproj/project.pbxproj index 5f92a6fd..b88ced01 100644 --- a/mParticle-Apple-SDK.xcodeproj/project.pbxproj +++ b/mParticle-Apple-SDK.xcodeproj/project.pbxproj @@ -809,6 +809,7 @@ 53FDD1BC2AE871AF003D5FA1 /* MPIHasher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPIHasher.swift; sourceTree = ""; }; D3724C182AE02AF60074CD67 /* mParticle_Apple_SDK_NoLocation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mParticle_Apple_SDK_NoLocation.h; sourceTree = ""; }; D3B3E2062AE028EC001AB58C /* mParticle_Apple_SDK.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mParticle_Apple_SDK.h; sourceTree = ""; }; + D3BA75152B614E3D008C3C65 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -852,6 +853,7 @@ 53A79A6F29CCCD6400E7489F = { isa = PBXGroup; children = ( + D3BA75152B614E3D008C3C65 /* PrivacyInfo.xcprivacy */, 53A79CFE29CE12AB00E7489F /* mParticle-Apple-SDK.modulemap */, 53A79CFF29CE23D600E7489F /* mParticle-Apple-SDK-NoLocation.modulemap */, 53A79A7B29CCCD6400E7489F /* mParticle-Apple-SDK */, diff --git a/mParticle-Apple-SDK/Network/MPNetworkCommunication.m b/mParticle-Apple-SDK/Network/MPNetworkCommunication.m index e004fbbc..7267adb8 100644 --- a/mParticle-Apple-SDK/Network/MPNetworkCommunication.m +++ b/mParticle-Apple-SDK/Network/MPNetworkCommunication.m @@ -53,6 +53,8 @@ NSString *const kMPURLHostConfig = @"config2.mparticle.com"; NSString *const kMPURLHostEventSubdomain = @"nativesdks"; NSString *const kMPURLHostIdentitySubdomain = @"identity"; +NSString *const kMPURLHostEventTrackingSubdomain = @"tracking-nativesdks"; +NSString *const kMPURLHostIdentityTrackingSubdomain = @"tracking-identity"; NSString *const kMPIdentityCachingMaxAgeHeader = @"X-MP-Max-Age"; @@ -134,12 +136,20 @@ - (NSString *)defaultHostWithSubdomain:(NSString *)subdomain apiKey:(NSString *) - (NSString *)defaultEventHost { MPStateMachine *stateMachine = [MParticle sharedInstance].stateMachine; - return [self defaultHostWithSubdomain:kMPURLHostEventSubdomain apiKey:stateMachine.apiKey enableDirectRouting:stateMachine.enableDirectRouting]; + if (stateMachine.attAuthorizationStatus.integerValue == MPATTAuthorizationStatusAuthorized) { + return [self defaultHostWithSubdomain:kMPURLHostEventTrackingSubdomain apiKey:stateMachine.apiKey enableDirectRouting:stateMachine.enableDirectRouting]; + } else { + return [self defaultHostWithSubdomain:kMPURLHostEventSubdomain apiKey:stateMachine.apiKey enableDirectRouting:stateMachine.enableDirectRouting]; + } } - (NSString *)defaultIdentityHost { MPStateMachine *stateMachine = [MParticle sharedInstance].stateMachine; - return [self defaultHostWithSubdomain:kMPURLHostIdentitySubdomain apiKey:stateMachine.apiKey enableDirectRouting:stateMachine.enableDirectRouting]; + if (stateMachine.attAuthorizationStatus.integerValue == MPATTAuthorizationStatusAuthorized) { + return [self defaultHostWithSubdomain:kMPURLHostIdentityTrackingSubdomain apiKey:stateMachine.apiKey enableDirectRouting:stateMachine.enableDirectRouting]; + } else { + return [self defaultHostWithSubdomain:kMPURLHostIdentitySubdomain apiKey:stateMachine.apiKey enableDirectRouting:stateMachine.enableDirectRouting]; + } } - (MPURL *)configURL {