From 8400d96c13f7ba481a00e521bff8135dcfa0df03 Mon Sep 17 00:00:00 2001 From: Nathan Schott Date: Thu, 18 Apr 2024 09:32:29 -0400 Subject: [PATCH] refactor: add privacy manifest file and remove tracking IDs (#30) --- PayPalMessages.podspec | 2 +- PayPalMessages.xcodeproj/project.pbxproj | 4 ++ .../Analytics/AnalyticsLogger.swift | 2 - .../PayPalMessages/Analytics/CloudEvent.swift | 4 -- .../Config/PayPalMessageConfig.swift | 12 +---- .../Config/PayPalMessageModalConfig.swift | 8 +--- .../PayPalMessages/IO/MessageRequest.swift | 4 +- .../PayPalMessageModalViewModel.swift | 2 - Sources/PayPalMessages/PrivacyInfo.xcprivacy | 36 +++++++++++++++ .../Mocks/PayPalMessageRequestMock.swift | 2 +- .../PayPalMessageConfigTests.swift | 21 --------- .../PayPalMessageLoggerTests.swift | 44 +------------------ 12 files changed, 47 insertions(+), 94 deletions(-) create mode 100644 Sources/PayPalMessages/PrivacyInfo.xcprivacy diff --git a/PayPalMessages.podspec b/PayPalMessages.podspec index 95d71fa..eb5df82 100644 --- a/PayPalMessages.podspec +++ b/PayPalMessages.podspec @@ -13,6 +13,6 @@ Pod::Spec.new do |s| s.source_files = "Sources/PayPalMessages/**/*.swift" s.resource_bundle = { - "PayPalMessages" => ['Sources/PayPalMessages/*.xcassets'] + "PayPalMessages" => ['Sources/PayPalMessages/*.xcassets', 'Sources/PayPalMessages/PrivacyInfo.xcprivacy'] } end diff --git a/PayPalMessages.xcodeproj/project.pbxproj b/PayPalMessages.xcodeproj/project.pbxproj index a0e04a0..36d2b70 100644 --- a/PayPalMessages.xcodeproj/project.pbxproj +++ b/PayPalMessages.xcodeproj/project.pbxproj @@ -11,6 +11,7 @@ C61D84472B33348C00F372EF /* CloudEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C61D84462B33348C00F372EF /* CloudEvent.swift */; }; C62FF8232B742C9400890823 /* ResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = C62FF8222B742C9400890823 /* ResponseError.swift */; }; C62FF8252B74315B00890823 /* ResponseErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C62FF8242B74315B00890823 /* ResponseErrorTests.swift */; }; + C62FF8272B852E4000890823 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = C62FF8262B852E4000890823 /* PrivacyInfo.xcprivacy */; }; C635F4362A9645B10096F9FF /* PayPalMessages.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C635F42E2A9645B10096F9FF /* PayPalMessages.framework */; }; C635F4C12A964A020096F9FF /* PayPalMessageModalViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C635F48E2A964A020096F9FF /* PayPalMessageModalViewModel.swift */; }; C635F4C32A964A020096F9FF /* AnalyticsEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C635F4912A964A020096F9FF /* AnalyticsEvent.swift */; }; @@ -91,6 +92,7 @@ C61D84462B33348C00F372EF /* CloudEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudEvent.swift; sourceTree = ""; }; C62FF8222B742C9400890823 /* ResponseError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResponseError.swift; sourceTree = ""; }; C62FF8242B74315B00890823 /* ResponseErrorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResponseErrorTests.swift; sourceTree = ""; }; + C62FF8262B852E4000890823 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; C635F42E2A9645B10096F9FF /* PayPalMessages.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = PayPalMessages.framework; sourceTree = BUILT_PRODUCTS_DIR; }; C635F4352A9645B10096F9FF /* PayPalMessagesTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PayPalMessagesTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; C635F48E2A964A020096F9FF /* PayPalMessageModalViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PayPalMessageModalViewModel.swift; sourceTree = ""; }; @@ -220,6 +222,7 @@ C635F4AC2A964A020096F9FF /* Utils */, C635F4BE2A964A020096F9FF /* Views */, C635F4AB2A964A020096F9FF /* Assets.xcassets */, + C62FF8262B852E4000890823 /* PrivacyInfo.xcprivacy */, C635F4C02A964A020096F9FF /* PayPalMessageModal.swift */, C635F48E2A964A020096F9FF /* PayPalMessageModalViewModel.swift */, C635F4982A964A020096F9FF /* PayPalMessageView.swift */, @@ -460,6 +463,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + C62FF8272B852E4000890823 /* PrivacyInfo.xcprivacy in Resources */, C635F4DA2A964A020096F9FF /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Sources/PayPalMessages/Analytics/AnalyticsLogger.swift b/Sources/PayPalMessages/Analytics/AnalyticsLogger.swift index 816624a..a3e7728 100644 --- a/Sources/PayPalMessages/Analytics/AnalyticsLogger.swift +++ b/Sources/PayPalMessages/Analytics/AnalyticsLogger.swift @@ -13,8 +13,6 @@ class Weak { class AnalyticsLogger: Encodable { // Global Details - static var deviceID: String? = UIDevice.current.identifierForVendor?.uuidString - static var sessionID: String = UUID().uuidString static var integrationVersion: String? static var integrationName: String? diff --git a/Sources/PayPalMessages/Analytics/CloudEvent.swift b/Sources/PayPalMessages/Analytics/CloudEvent.swift index 8769026..80d32d6 100644 --- a/Sources/PayPalMessages/Analytics/CloudEvent.swift +++ b/Sources/PayPalMessages/Analytics/CloudEvent.swift @@ -108,8 +108,6 @@ class CloudEvent: Encodable { var dataContainer = container.nestedContainer(keyedBy: IntegrationKey.self, forKey: .data) - try dataContainer.encodeIfPresent(AnalyticsLogger.deviceID, forKey: .deviceID) - try dataContainer.encodeIfPresent(AnalyticsLogger.sessionID, forKey: .sessionID) try dataContainer.encodeIfPresent(AnalyticsLogger.integrationVersion, forKey: .integrationVersion) try dataContainer.encodeIfPresent(AnalyticsLogger.integrationName, forKey: .integrationName) @@ -142,8 +140,6 @@ class CloudEvent: Encodable { case partnerAttributionID = "partner_attribution_id" case merchantProfileHash = "merchant_profile_hash" // Global Details - case deviceID = "device_id" - case sessionID = "session_id" case integrationVersion = "integration_version" case integrationName = "integration_name" // Build Details diff --git a/Sources/PayPalMessages/Config/PayPalMessageConfig.swift b/Sources/PayPalMessages/Config/PayPalMessageConfig.swift index 892611d..5ef6a0a 100644 --- a/Sources/PayPalMessages/Config/PayPalMessageConfig.swift +++ b/Sources/PayPalMessages/Config/PayPalMessageConfig.swift @@ -99,19 +99,9 @@ public class PayPalMessageConfig: NSObject { public static func setGlobalAnalytics( integrationName: String, - integrationVersion: String, - deviceID: String? = nil, - sessionID: String? = nil + integrationVersion: String ) { AnalyticsLogger.integrationName = integrationName AnalyticsLogger.integrationVersion = integrationVersion - - if let deviceID { - AnalyticsLogger.deviceID = deviceID - } - - if let sessionID { - AnalyticsLogger.sessionID = sessionID - } } } diff --git a/Sources/PayPalMessages/Config/PayPalMessageModalConfig.swift b/Sources/PayPalMessages/Config/PayPalMessageModalConfig.swift index 3412342..d1a5d1d 100644 --- a/Sources/PayPalMessages/Config/PayPalMessageModalConfig.swift +++ b/Sources/PayPalMessages/Config/PayPalMessageModalConfig.swift @@ -101,15 +101,11 @@ class PayPalMessageModalConfig: NSObject, Encodable { public static func setGlobalAnalytics( integrationName: String, - integrationVersion: String, - deviceID: String? = nil, - sessionID: String? = nil + integrationVersion: String ) { PayPalMessageConfig.setGlobalAnalytics( integrationName: integrationName, - integrationVersion: integrationVersion, - deviceID: deviceID, - sessionID: sessionID + integrationVersion: integrationVersion ) } diff --git a/Sources/PayPalMessages/IO/MessageRequest.swift b/Sources/PayPalMessages/IO/MessageRequest.swift index cee3c51..7dc96b9 100644 --- a/Sources/PayPalMessages/IO/MessageRequest.swift +++ b/Sources/PayPalMessages/IO/MessageRequest.swift @@ -51,9 +51,7 @@ class MessageRequest: MessageRequestable { "instance_id": parameters.instanceID, "version": BuildInfo.version, "integration_type": BuildInfo.integrationType, - "integration_version": AnalyticsLogger.integrationVersion, - "device_id": AnalyticsLogger.deviceID, - "session_id": AnalyticsLogger.sessionID + "integration_version": AnalyticsLogger.integrationVersion ].filter { guard let value = $0.value else { return false } diff --git a/Sources/PayPalMessages/PayPalMessageModalViewModel.swift b/Sources/PayPalMessages/PayPalMessageModalViewModel.swift index 420a89c..cc752ad 100644 --- a/Sources/PayPalMessages/PayPalMessageModalViewModel.swift +++ b/Sources/PayPalMessages/PayPalMessageModalViewModel.swift @@ -74,8 +74,6 @@ class PayPalMessageModalViewModel: NSObject, WKNavigationDelegate, WKScriptMessa "integration_identifier": integrationIdentifier, "ignore_cache": ignoreCache?.description, "integration_version": AnalyticsLogger.integrationVersion, - "device_id": AnalyticsLogger.deviceID, - "session_id": AnalyticsLogger.sessionID, "features": "native-modal" ].filter { guard let value = $0.value else { return false } diff --git a/Sources/PayPalMessages/PrivacyInfo.xcprivacy b/Sources/PayPalMessages/PrivacyInfo.xcprivacy new file mode 100644 index 0000000..c43df25 --- /dev/null +++ b/Sources/PayPalMessages/PrivacyInfo.xcprivacy @@ -0,0 +1,36 @@ + + + + + NSPrivacyCollectedDataTypes + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeProductInteraction + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAnalytics + + + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPITypeReasons + + CA92.1 + + + + NSPrivacyTrackingDomains + + NSPrivacyTracking + + + diff --git a/Tests/PayPalMessagesTests/Mocks/PayPalMessageRequestMock.swift b/Tests/PayPalMessagesTests/Mocks/PayPalMessageRequestMock.swift index 96e6824..51de7a8 100644 --- a/Tests/PayPalMessagesTests/Mocks/PayPalMessageRequestMock.swift +++ b/Tests/PayPalMessagesTests/Mocks/PayPalMessageRequestMock.swift @@ -48,7 +48,7 @@ class PayPalMessageRequestMock: MessageRequestable { } if case .success(messageResponse: let messageResponse) = scenario, let messageResponse { - return messageResponse + return messageResponse } return MessageResponse( diff --git a/Tests/PayPalMessagesTests/PayPalMessageConfigTests.swift b/Tests/PayPalMessagesTests/PayPalMessageConfigTests.swift index bc36ba1..c1a7f03 100644 --- a/Tests/PayPalMessagesTests/PayPalMessageConfigTests.swift +++ b/Tests/PayPalMessagesTests/PayPalMessageConfigTests.swift @@ -5,35 +5,14 @@ import XCTest func testSetGlobalAnalytics() { let integrationName = "MyIntegration" let integrationVersion = "1.0" - let deviceID = "Device123" - let sessionID = "Session456" PayPalMessageModalConfig.setGlobalAnalytics( - integrationName: integrationName, - integrationVersion: integrationVersion, - deviceID: deviceID, - sessionID: sessionID - ) - - XCTAssertEqual(AnalyticsLogger.integrationName, integrationName) - XCTAssertEqual(AnalyticsLogger.integrationVersion, integrationVersion) - XCTAssertEqual(AnalyticsLogger.deviceID, deviceID) - XCTAssertEqual(AnalyticsLogger.sessionID, sessionID) -} - -func testSetGlobalAnalyticsWithDefaults() { - let integrationName = "MyIntegration" - let integrationVersion = "1.0" - - PayPalMessageConfig.setGlobalAnalytics( integrationName: integrationName, integrationVersion: integrationVersion ) XCTAssertEqual(AnalyticsLogger.integrationName, integrationName) XCTAssertEqual(AnalyticsLogger.integrationVersion, integrationVersion) - XCTAssertNil(AnalyticsLogger.deviceID) - XCTAssertNil(AnalyticsLogger.sessionID) } func testStandardIntegrationInitialization() { diff --git a/Tests/PayPalMessagesTests/PayPalMessageLoggerTests.swift b/Tests/PayPalMessagesTests/PayPalMessageLoggerTests.swift index 9c2ec65..53a67e6 100644 --- a/Tests/PayPalMessagesTests/PayPalMessageLoggerTests.swift +++ b/Tests/PayPalMessagesTests/PayPalMessageLoggerTests.swift @@ -43,9 +43,7 @@ final class PayPalMessageLoggerTests: XCTestCase { PayPalMessageConfig.setGlobalAnalytics( integrationName: "Test_SDK", - integrationVersion: "0.1.0", - deviceID: "987654321", - sessionID: "123456789" + integrationVersion: "0.1.0" ) // Inject mock sender to intercept log requests @@ -88,8 +86,6 @@ final class PayPalMessageLoggerTests: XCTestCase { "client_id": "testloggerclientid", "merchant_profile_hash": "TEST_HASH", "integration_version": "0.1.0", - "device_id": "987654321", - "session_id": "123456789", "components": [ [ "amount": 50, @@ -162,8 +158,6 @@ final class PayPalMessageLoggerTests: XCTestCase { "integration_type": "NATIVE_IOS", "client_id": "testloggerclientid", "integration_version": "0.1.0", - "device_id": "987654321", - "session_id": "123456789", "components": [ [ "amount": 50, @@ -232,8 +226,6 @@ final class PayPalMessageLoggerTests: XCTestCase { "client_id": "testloggerclientid", "merchant_profile_hash": "TEST_HASH", "integration_version": "0.1.0", - "device_id": "987654321", - "session_id": "123456789", "components": [ [ "amount": 50, @@ -301,8 +293,6 @@ final class PayPalMessageLoggerTests: XCTestCase { "client_id": "testloggerclientid", "merchant_profile_hash": "TEST_HASH", "integration_version": "0.1.0", - "device_id": "987654321", - "session_id": "123456789", "components": [ [ "amount": 50, @@ -359,8 +349,6 @@ final class PayPalMessageLoggerTests: XCTestCase { "client_id": "testloggerclientid", "merchant_profile_hash": "TEST_HASH", "integration_version": "0.1.0", - "device_id": "987654321", - "session_id": "123456789", "components": [ [ "amount": 50, @@ -426,8 +414,6 @@ final class PayPalMessageLoggerTests: XCTestCase { "client_id": "testloggerclientid2", "merchant_profile_hash": "TEST_HASH", "integration_version": "0.1.0", - "device_id": "987654321", - "session_id": "123456789", "components": [ [ "amount": 100, @@ -485,34 +471,6 @@ final class PayPalMessageLoggerTests: XCTestCase { XCTAssert(clientID1 == "testloggerclientid3" || clientID2 == "testloggerclientid3") } - func testNilDeviceIDDoesNotOverwrite() { - PayPalMessageConfig.setGlobalAnalytics( - integrationName: "Test_SDK", - integrationVersion: "0.1.0" - ) - - let messageLogger = AnalyticsLogger(.message(Weak(message))) - - messageLogger.addEvent(.messageRender(renderDuration: 10, requestDuration: 15)) - - AnalyticsService.shared.flushEvents() - - guard let data = mockSender.calls.last, - let data = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { - return XCTFail("invalid JSON data") - } - - guard let deviceID = (data["data"] as? [String: Any])?["device_id"] as? String else { - return XCTFail("missing device_id") - } - guard let sessionID = (data["data"] as? [String: Any])?["session_id"] as? String else { - return XCTFail("missing session_id") - } - - XCTAssert(deviceID == "987654321") - XCTAssert(sessionID == "123456789") - } - // MARK: - Helper assert functions private func assert(payload: [String: Any], equals expectedPayload: [String: Any]) {