Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: privacy manifest files #677

Merged
merged 4 commits into from
Apr 10, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 5 additions & 2 deletions CustomerIODataPipelines.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@ Pod::Spec.new do |spec|
# spec.osx.deployment_target = "10.15"
# spec.tvos.deployment_target = '13.0'

spec.source_files = "Sources/DataPipeline/**/*"
spec.exclude_files = "Sources/**/*{.md}"
path_to_source_for_module = "Sources/DataPipeline"
spec.source_files = "#{path_to_source_for_module}/**/*{.swift}"
spec.resource_bundle = {
"#{spec.module_name}_Privacy" => "#{path_to_source_for_module}/Resources/PrivacyInfo.xcprivacy"
}
spec.module_name = "CioDataPipelines" # the `import X` name when using SDK in Swift files

spec.dependency "CustomerIOCommon", "= #{spec.version.to_s}"
Expand Down
8 changes: 6 additions & 2 deletions CustomerIOMessagingInApp.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,12 @@ Pod::Spec.new do |spec|
# spec.osx.deployment_target = "10.15"
# spec.tvos.deployment_target = '13.0'

spec.source_files = "Sources/MessagingInApp/**/*"
spec.exclude_files = "Sources/**/*{.md}"
path_to_source_for_module = "Sources/MessagingInApp"
spec.source_files = "#{path_to_source_for_module}/**/*{.swift}"
spec.resource_bundle = {
"#{spec.module_name}_Privacy" => "#{path_to_source_for_module}/Resources/PrivacyInfo.xcprivacy"
}

spec.module_name = "CioMessagingInApp" # the `import X` name when using SDK in Swift files

spec.dependency "CustomerIOCommon", "= #{spec.version.to_s}"
Expand Down
8 changes: 6 additions & 2 deletions CustomerIOMessagingPushAPN.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,12 @@ Pod::Spec.new do |spec|
# spec.osx.deployment_target = "10.15"
# spec.tvos.deployment_target = '13.0'

spec.source_files = "Sources/MessagingPushAPN/**/*"
spec.exclude_files = "Sources/**/*{.md}"
path_to_source_for_module = "Sources/MessagingPushAPN"
spec.source_files = "#{path_to_source_for_module}/**/*{.swift}"
spec.resource_bundle = {
"#{spec.module_name}_Privacy" => "#{path_to_source_for_module}/Resources/PrivacyInfo.xcprivacy"
}

spec.module_name = "CioMessagingPushAPN" # the `import X` name when using SDK in Swift files

spec.dependency "CustomerIOMessagingPush", "= #{spec.version.to_s}"
Expand Down
8 changes: 6 additions & 2 deletions CustomerIOMessagingPushFCM.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,12 @@ Pod::Spec.new do |spec|
# spec.osx.deployment_target = "10.15"
# spec.tvos.deployment_target = '13.0'

spec.source_files = "Sources/MessagingPushFCM/**/*"
spec.exclude_files = "Sources/**/*{.md}"
path_to_source_for_module = "Sources/MessagingPushFCM"
spec.source_files = "#{path_to_source_for_module}/**/*{.swift}"
spec.resource_bundle = {
"#{spec.module_name}_Privacy" => "#{path_to_source_for_module}/Resources/PrivacyInfo.xcprivacy"
}

spec.module_name = "CioMessagingPushFCM" # the `import X` name when using SDK in Swift files

spec.dependency "CustomerIOMessagingPush", "= #{spec.version.to_s}"
Expand Down
20 changes: 16 additions & 4 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,30 +82,42 @@ let package = Package(
// Data Pipeline
.target(name: "CioDataPipelines",
dependencies: ["CioInternalCommon", "CioTrackingMigration", .product(name: "Segment", package: "Segment")],
path: "Sources/DataPipeline"),
path: "Sources/DataPipeline",
resources: [
.process("Resources/PrivacyInfo.xcprivacy"),
]),
.testTarget(name: "DataPipelineTests",
dependencies: ["CioDataPipelines", "SharedTests"],
path: "Tests/DataPipeline"),

// APN
.target(name: "CioMessagingPushAPN",
dependencies: ["CioMessagingPush"],
path: "Sources/MessagingPushAPN"),
path: "Sources/MessagingPushAPN",
resources: [
.process("Resources/PrivacyInfo.xcprivacy"),
]),
.testTarget(name: "MessagingPushAPNTests",
dependencies: ["CioMessagingPushAPN", "SharedTests"],
path: "Tests/MessagingPushAPN"),
// FCM
.target(name: "CioMessagingPushFCM",
dependencies: ["CioMessagingPush", .product(name: "FirebaseMessaging", package: "Firebase")],
path: "Sources/MessagingPushFCM"),
path: "Sources/MessagingPushFCM",
resources: [
.process("Resources/PrivacyInfo.xcprivacy"),
]),
.testTarget(name: "MessagingPushFCMTests",
dependencies: ["CioMessagingPushFCM", "SharedTests"],
path: "Tests/MessagingPushFCM"),

// Messaging in-app
.target(name: "CioMessagingInApp",
dependencies: ["CioInternalCommon"],
path: "Sources/MessagingInApp"),
path: "Sources/MessagingInApp",
resources: [
.process("Resources/PrivacyInfo.xcprivacy"),
]),
.testTarget(name: "MessagingInAppTests",
dependencies: ["CioMessagingInApp", "SharedTests"],
path: "Tests/MessagingInApp"),
Expand Down
79 changes: 79 additions & 0 deletions Sources/DataPipeline/Resources/PrivacyInfo.xcprivacy
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!--
Docs for this section: https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests
This section is describing what information our SDK collects about the app user.

It's my understanding that this section is for what our SDK requires, not what a customer can do with our SDK. Therefore, if something is optional, use `false`.
levibostian marked this conversation as resolved.
Show resolved Hide resolved
Customers must create their own privacy file for what their app does and provide that to Apple. That's where customers report what they might be using our SDK for.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Customers do not need to declare their dependancies privacy requirements based on the second line in this call out at the top of this page.
image

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewing the comments in this file and the documentation you linked to, I think the comments in this file are up-to-date and accurate.

Do you have a suggestion of a change to make to these comments?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the issue is around the interpretation of "required". Since their app is collecting an email address and passing it to us, they would have to declare that. If we ever created a UI to collect the email and link to a user then we'd have to declare the email address. Therefore in the first case email isn't a "required" part of our SDK.

So this does work, but the wording made that tough to interpret. I provided a suggestion to the line that might make that more clear.

levibostian marked this conversation as resolved.
Show resolved Hide resolved
-->
<key>NSPrivacyCollectedDataTypes</key>
<array>

<!--
Section for SDKs that capture "Such as screen name, handle, account ID, assigned user ID, customer number, or other user- or account-level ID that can be used to identify a particular user or account."
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we have to specify the things we capture, like app name etc?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, you do not need to specify what you capture. Instead specify what categories that you capture.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I may have misunderstood your question.

Looking at the docs for NSPrivacyCollectedDataTypes, I do not see anything in there regarding app name, app version.

If you see a category in this apple doc that is missing in this file, please mention the missing category in our notion doc.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was based on this where it mentions adding custom data types but maybe we can skip these as I am unsure.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm open to skipping adding any custom data types for now. Apples documents aren't always the most clear, so it will be tough to determine what qualifies as a custom data type that we might need to declare.

-->
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypeUserID</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<false/> <!-- because of anonymous profiles, linking to a person is optional -->
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added a comment in notion about it

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am keeping this value as-is until we give others on team time to read documentation and give suggestions for this value.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since to utilize basically any functionality of Customer.io, we need to link usage data to a user typically email or a device. This is the rational for marking this as true. If we mark this as false, it means that Customer.io does not have any data linked to a user anywhere in our systems.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added comment on notion too. We only need a profile to function, so even if they use aliases to create profiles, sending push notifications and in-app messages should still be possible based on the data linked to the user, which I believe aligns with Apple's privacy details. For sending email, it's true that linking an actual email is necessary, but we don’t force it and it likely falls under the customer app's privacy? 🤔

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From https://developer.apple.com/app-store/app-privacy-details/#linked-data

Additionally, in order for data not to be linked to a particular user’s identity, you must avoid certain activities after collection:
You must not attempt to link the data back to the user’s identity.
You must not tie the data to other datasets that enable it to be linked to a particular user’s identity.

I believe we do both of these activities, which I why I tend to go for true

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR thread has been discussed in a Notion comment.
I suggest reviewing this updated section in Notion and comment there if you have more feedback.

<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAppFunctionality</string>
<string>NSPrivacyCollectedDataTypePurposeAnalytics</string>
<string>NSPrivacyCollectedDataTypePurposeProductPersonalization</string>
</array>
</dict>

<!--
Section for SDKs that capture "Such as app launches, taps, clicks, scrolling information, music listening data, video views, saved place in a game, video, or song, or other information about how the user interacts with the app."
-->
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypeProductInteraction</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<false/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAppFunctionality</string>
<string>NSPrivacyCollectedDataTypePurposeAnalytics</string>
<string>NSPrivacyCollectedDataTypePurposeProductPersonalization</string>
</array>
</dict>
</array>

<!--
Document on this section: https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api
Documents if our SDK uses certain system calls and why. Prevents SDK using fingerprinting.
-->
<key>NSPrivacyAccessedAPITypes</key>
<array>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>CA92.1</string>
</array>
</dict>
</array>

<!-- "third-party SDK uses data for tracking as defined under the App Tracking Transparency framework."
See section "Asking permission to track" in this webpage:
https://developer.apple.com/app-store/user-privacy-and-data-use/
-->
<key>NSPrivacyTracking</key>
<false/>

<!-- Because we use NSPrivacyTracking=false, this section is not required.
<key>NSPrivacyTrackingDomains</key>
-->
</dict>
</plist>
41 changes: 41 additions & 0 deletions Sources/MessagingInApp/Resources/PrivacyInfo.xcprivacy
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!--
See DataPipelines module for documentation of this file. Including resources for each section to learn more.
-->
<key>NSPrivacyCollectedDataTypes</key>
<array>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypeProductInteraction</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<false/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAppFunctionality</string>
<string>NSPrivacyCollectedDataTypePurposeAnalytics</string>
<string>NSPrivacyCollectedDataTypePurposeProductPersonalization</string>
</array>
</dict>
</array>

<key>NSPrivacyAccessedAPITypes</key>
<array>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>CA92.1</string>
</array>
</dict>
</array>

<key>NSPrivacyTracking</key>
<false/>
</dict>
</plist>
43 changes: 43 additions & 0 deletions Sources/MessagingPushAPN/Resources/PrivacyInfo.xcprivacy
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!--
See DataPipelines module for documentation of this file. Including resources for each section to learn more.

**Important** - Keep this file in sync with other push modules in SDK.
-->
<key>NSPrivacyCollectedDataTypes</key>
<array>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypeProductInteraction</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<false/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAppFunctionality</string>
<string>NSPrivacyCollectedDataTypePurposeAnalytics</string>
<string>NSPrivacyCollectedDataTypePurposeProductPersonalization</string>
</array>
</dict>
</array>

<key>NSPrivacyAccessedAPITypes</key>
<array>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>CA92.1</string>
</array>
</dict>
</array>

<key>NSPrivacyTracking</key>
<false/>
</dict>
</plist>
43 changes: 43 additions & 0 deletions Sources/MessagingPushFCM/Resources/PrivacyInfo.xcprivacy
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!--
See DataPipelines module for documentation of this file. Including resources for each section to learn more.

**Important** - Keep this file in sync with other push modules in SDK.
-->
<key>NSPrivacyCollectedDataTypes</key>
<array>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypeProductInteraction</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<false/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAppFunctionality</string>
<string>NSPrivacyCollectedDataTypePurposeAnalytics</string>
<string>NSPrivacyCollectedDataTypePurposeProductPersonalization</string>
</array>
</dict>
</array>

<key>NSPrivacyAccessedAPITypes</key>
<array>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>CA92.1</string>
</array>
</dict>
</array>

<key>NSPrivacyTracking</key>
<false/>
</dict>
</plist>