From 059ddc41a08d1651c76f23f822aa0213d160725f Mon Sep 17 00:00:00 2001 From: bruvzg <7645683+bruvzg@users.noreply.github.com> Date: Tue, 30 Apr 2024 16:22:57 +0300 Subject: [PATCH] [macOS export] Add support for privacy manifest configuration. --- .../Contents/Resources/PrivacyInfo.xcprivacy | 8 + .../doc_classes/EditorExportPlatformMacOS.xml | 426 ++++++++++++++++++ platform/macos/export/export_plugin.cpp | 159 +++++++ platform/macos/export/export_plugin.h | 1 + 4 files changed, 594 insertions(+) create mode 100644 misc/dist/macos_template.app/Contents/Resources/PrivacyInfo.xcprivacy diff --git a/misc/dist/macos_template.app/Contents/Resources/PrivacyInfo.xcprivacy b/misc/dist/macos_template.app/Contents/Resources/PrivacyInfo.xcprivacy new file mode 100644 index 00000000000..a5257b74a4a --- /dev/null +++ b/misc/dist/macos_template.app/Contents/Resources/PrivacyInfo.xcprivacy @@ -0,0 +1,8 @@ + + + + + $priv_tracking + $priv_collection + + diff --git a/platform/macos/doc_classes/EditorExportPlatformMacOS.xml b/platform/macos/doc_classes/EditorExportPlatformMacOS.xml index 7355042a48c..92ade4b77a2 100644 --- a/platform/macos/doc_classes/EditorExportPlatformMacOS.xml +++ b/platform/macos/doc_classes/EditorExportPlatformMacOS.xml @@ -211,6 +211,426 @@ A message displayed when requesting access to the device's camera (localized). + + Indicates whether your app collects advertising data. + + + The reasons your app collects advertising data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links advertising data to the user's identity. + + + Indicates whether your app uses advertising data for tracking. + + + Indicates whether your app collects audio data data. + + + The reasons your app collects audio data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links audio data data to the user's identity. + + + Indicates whether your app uses audio data data for tracking. + + + Indicates whether your app collects browsing history. + + + The reasons your app collects browsing history. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links browsing history to the user's identity. + + + Indicates whether your app uses browsing history for tracking. + + + Indicates whether your app collects coarse location data. + + + The reasons your app collects coarse location data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links coarse location data to the user's identity. + + + Indicates whether your app uses coarse location data for tracking. + + + Indicates whether your app collects contacts. + + + The reasons your app collects contacts. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links contacts to the user's identity. + + + Indicates whether your app uses contacts for tracking. + + + Indicates whether your app collects crash data. + + + The reasons your app collects crash data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links crash data to the user's identity. + + + Indicates whether your app uses crash data for tracking. + + + Indicates whether your app collects credit information. + + + The reasons your app collects credit information. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links credit information to the user's identity. + + + Indicates whether your app uses credit information for tracking. + + + Indicates whether your app collects customer support data. + + + The reasons your app collects customer support data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links customer support data to the user's identity. + + + Indicates whether your app uses customer support data for tracking. + + + Indicates whether your app collects device IDs. + + + The reasons your app collects device IDs. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links device IDs to the user's identity. + + + Indicates whether your app uses device IDs for tracking. + + + Indicates whether your app collects email address. + + + The reasons your app collects email address. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links email address to the user's identity. + + + Indicates whether your app uses email address for tracking. + + + Indicates whether your app collects emails or text messages. + + + The reasons your app collects emails or text messages. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links emails or text messages to the user's identity. + + + Indicates whether your app uses emails or text messages for tracking. + + + Indicates whether your app collects environment scanning data. + + + The reasons your app collects environment scanning data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links environment scanning data to the user's identity. + + + Indicates whether your app uses environment scanning data for tracking. + + + Indicates whether your app collects fitness and exercise data. + + + The reasons your app collects fitness and exercise data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links fitness and exercise data to the user's identity. + + + Indicates whether your app uses fitness and exercise data for tracking. + + + Indicates whether your app collects gameplay content. + + + The reasons your app collects gameplay content. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links gameplay content to the user's identity. + + + Indicates whether your app uses gameplay content for tracking. + + + Indicates whether your app collects user's hand structure and hand movements. + + + The reasons your app collects user's hand structure and hand movements. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links user's hand structure and hand movements to the user's identity. + + + Indicates whether your app uses user's hand structure and hand movements for tracking. + + + Indicates whether your app collects user's head movement. + + + The reasons your app collects user's head movement. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links user's head movement to the user's identity. + + + Indicates whether your app uses user's head movement for tracking. + + + Indicates whether your app collects health and medical data. + + + The reasons your app collects health and medical data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links health and medical data to the user's identity. + + + Indicates whether your app uses health and medical data for tracking. + + + Indicates whether your app collects user's name. + + + The reasons your app collects user's name. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links user's name to the user's identity. + + + Indicates whether your app uses user's name for tracking. + + + Indicates whether your app collects any other contact information. + + + The reasons your app collects any other contact information. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links any other contact information to the user's identity. + + + Indicates whether your app uses any other contact information for tracking. + + + Indicates whether your app collects any other data. + + + The reasons your app collects any other data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links any other data to the user's identity. + + + Indicates whether your app uses any other data for tracking. + + + Indicates whether your app collects any other diagnostic data. + + + The reasons your app collects any other diagnostic data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links any other diagnostic data to the user's identity. + + + Indicates whether your app uses any other diagnostic data for tracking. + + + Indicates whether your app collects any other financial information. + + + The reasons your app collects any other financial information. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links any other financial information to the user's identity. + + + Indicates whether your app uses any other financial information for tracking. + + + Indicates whether your app collects any other usage data. + + + The reasons your app collects any other usage data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links any other usage data to the user's identity. + + + Indicates whether your app uses any other usage data for tracking. + + + Indicates whether your app collects any other user generated content. + + + The reasons your app collects any other user generated content. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links any other user generated content to the user's identity. + + + Indicates whether your app uses any other user generated content for tracking. + + + Indicates whether your app collects payment information. + + + The reasons your app collects payment information. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links payment information to the user's identity. + + + Indicates whether your app uses payment information for tracking. + + + Indicates whether your app collects performance data. + + + The reasons your app collects performance data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links performance data to the user's identity. + + + Indicates whether your app uses performance data for tracking. + + + Indicates whether your app collects phone number. + + + The reasons your app collects phone number. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links phone number to the user's identity. + + + Indicates whether your app uses phone number for tracking. + + + Indicates whether your app collects photos or videos. + + + The reasons your app collects photos or videos. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links photos or videos to the user's identity. + + + Indicates whether your app uses photos or videos for tracking. + + + Indicates whether your app collects physical address. + + + The reasons your app collects physical address. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links physical address to the user's identity. + + + Indicates whether your app uses physical address for tracking. + + + Indicates whether your app collects precise location data. + + + The reasons your app collects precise location data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links precise location data to the user's identity. + + + Indicates whether your app uses precise location data for tracking. + + + Indicates whether your app collects product interaction data. + + + The reasons your app collects product interaction data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links product interaction data to the user's identity. + + + Indicates whether your app uses product interaction data for tracking. + + + Indicates whether your app collects purchase history. + + + The reasons your app collects purchase history. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links purchase history to the user's identity. + + + Indicates whether your app uses purchase history for tracking. + + + Indicates whether your app collects search history. + + + The reasons your app collects search history. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links search history to the user's identity. + + + Indicates whether your app uses search history for tracking. + + + Indicates whether your app collects sensitive user information. + + + The reasons your app collects sensitive user information. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links sensitive user information to the user's identity. + + + Indicates whether your app uses sensitive user information for tracking. + + + Indicates whether your app collects user IDs. + + + The reasons your app collects user IDs. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links user IDs to the user's identity. + + + Indicates whether your app uses user IDs for tracking. + A message displayed when requesting access to the user's "Desktop" folder (in English). @@ -259,6 +679,12 @@ A message displayed when requesting access to the user's removable drives (localized). + + The list of internet domains your app connects to that engage in tracking. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files]Privacy manifest files[/url]. + + + Indicates whether your app uses data for tracking. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files]Privacy manifest files[/url]. + Script code to execute on the remote host when app is finished. The following variables can be used in the script: diff --git a/platform/macos/export/export_plugin.cpp b/platform/macos/export/export_plugin.cpp index 5f52d33318f..73e96f2874f 100644 --- a/platform/macos/export/export_plugin.cpp +++ b/platform/macos/export/export_plugin.cpp @@ -325,6 +325,11 @@ bool EditorExportPlatformMacOS::get_export_option_visibility(const EditorExportP } } break; } + + bool advanced_options_enabled = p_preset->are_advanced_options_enabled(); + if (p_option.begins_with("privacy")) { + return advanced_options_enabled; + } } // These entitlements are required to run managed code, and are always enabled in Mono builds. @@ -373,6 +378,58 @@ List EditorExportPlatformMacOS::get_binary_extensions(const Ref *r_options) const { #ifdef MACOS_ENABLED r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "export/distribution_type", PROPERTY_HINT_ENUM, "Testing,Distribution,App Store"), 1, true)); @@ -484,6 +541,25 @@ void EditorExportPlatformMacOS::get_export_options(List *r_options r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/removable_volumes_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use removable volumes"), "", false, true)); r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/removable_volumes_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "privacy/tracking_enabled"), false)); + r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "privacy/tracking_domains"), Vector())); + + { + String hint; + for (uint64_t i = 0; i < sizeof(data_collect_purpose_info) / sizeof(data_collect_purpose_info[0]); ++i) { + if (i != 0) { + hint += ","; + } + hint += vformat("%s:%d", data_collect_purpose_info[i].prop_name, (1 << i)); + } + for (uint64_t i = 0; i < sizeof(data_collect_type_info) / sizeof(data_collect_type_info[0]); ++i) { + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, vformat("privacy/collected_data/%s/collected", data_collect_type_info[i].prop_name)), false)); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, vformat("privacy/collected_data/%s/linked_to_user", data_collect_type_info[i].prop_name)), false)); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, vformat("privacy/collected_data/%s/used_for_tracking", data_collect_type_info[i].prop_name)), false)); + r_options->push_back(ExportOption(PropertyInfo(Variant::INT, vformat("privacy/collected_data/%s/collection_purposes", data_collect_type_info[i].prop_name), PROPERTY_HINT_FLAGS, hint), 0)); + } + } + String run_script = "#!/usr/bin/env bash\n" "unzip -o -q \"{temp_dir}/{archive_name}\" -d \"{temp_dir}\"\n" "open \"{temp_dir}/{exe_name}.app\" --args {cmd_args}"; @@ -644,6 +720,85 @@ void EditorExportPlatformMacOS::_make_icon(const Ref &p_pres p_data = data; } +void EditorExportPlatformMacOS::_fix_privacy_manifest(const Ref &p_preset, Vector &plist) { + String str; + String strnew; + str.parse_utf8((const char *)plist.ptr(), plist.size()); + Vector lines = str.split("\n"); + for (int i = 0; i < lines.size(); i++) { + if (lines[i].find("$priv_collection") != -1) { + bool section_opened = false; + for (uint64_t j = 0; j < sizeof(data_collect_type_info) / sizeof(data_collect_type_info[0]); ++j) { + bool data_collected = p_preset->get(vformat("privacy/collected_data/%s/collected", data_collect_type_info[j].prop_name)); + bool linked = p_preset->get(vformat("privacy/collected_data/%s/linked_to_user", data_collect_type_info[j].prop_name)); + bool tracking = p_preset->get(vformat("privacy/collected_data/%s/used_for_tracking", data_collect_type_info[j].prop_name)); + int purposes = p_preset->get(vformat("privacy/collected_data/%s/collection_purposes", data_collect_type_info[j].prop_name)); + if (data_collected) { + if (!section_opened) { + section_opened = true; + strnew += "\tNSPrivacyCollectedDataTypes\n"; + strnew += "\t\n"; + } + strnew += "\t\t\n"; + strnew += "\t\t\tNSPrivacyCollectedDataType\n"; + strnew += vformat("\t\t\t%s\n", data_collect_type_info[j].type_name); + strnew += "\t\t\t\tNSPrivacyCollectedDataTypeLinked\n"; + if (linked) { + strnew += "\t\t\t\t\n"; + } else { + strnew += "\t\t\t\t\n"; + } + strnew += "\t\t\t\tNSPrivacyCollectedDataTypeTracking\n"; + if (tracking) { + strnew += "\t\t\t\t\n"; + } else { + strnew += "\t\t\t\t\n"; + } + if (purposes != 0) { + strnew += "\t\t\t\tNSPrivacyCollectedDataTypePurposes\n"; + strnew += "\t\t\t\t\n"; + for (uint64_t k = 0; k < sizeof(data_collect_purpose_info) / sizeof(data_collect_purpose_info[0]); ++k) { + if (purposes & (1 << k)) { + strnew += vformat("\t\t\t\t\t%s\n", data_collect_purpose_info[k].type_name); + } + } + strnew += "\t\t\t\t\n"; + } + strnew += "\t\t\t\n"; + } + } + if (section_opened) { + strnew += "\t\n"; + } + } else if (lines[i].find("$priv_tracking") != -1) { + bool tracking = p_preset->get("privacy/tracking_enabled"); + strnew += "\tNSPrivacyTracking\n"; + if (tracking) { + strnew += "\t\n"; + } else { + strnew += "\t\n"; + } + Vector tracking_domains = p_preset->get("privacy/tracking_domains"); + if (!tracking_domains.is_empty()) { + strnew += "\tNSPrivacyTrackingDomains\n"; + strnew += "\t\n"; + for (const String &E : tracking_domains) { + strnew += "\t\t" + E + "\n"; + } + strnew += "\t\n"; + } + } else { + strnew += lines[i] + "\n"; + } + } + + CharString cs = strnew.utf8(); + plist.resize(cs.size() - 1); + for (int i = 0; i < cs.size() - 1; i++) { + plist.write[i] = cs[i]; + } +} + void EditorExportPlatformMacOS::_fix_plist(const Ref &p_preset, Vector &plist, const String &p_binary) { String str; String strnew; @@ -1674,6 +1829,10 @@ Error EditorExportPlatformMacOS::export_project(const Ref &p _fix_plist(p_preset, data, pkg_name); } + if (file == "Contents/Resources/PrivacyInfo.xcprivacy") { + _fix_privacy_manifest(p_preset, data); + } + if (file.begins_with("Contents/MacOS/godot_")) { if (file != "Contents/MacOS/" + binary_to_use) { ret = unzGoToNextFile(src_pkg_zip); diff --git a/platform/macos/export/export_plugin.h b/platform/macos/export/export_plugin.h index 2d615abedee..6134d756b91 100644 --- a/platform/macos/export/export_plugin.h +++ b/platform/macos/export/export_plugin.h @@ -85,6 +85,7 @@ class EditorExportPlatformMacOS : public EditorExportPlatform { OS::ProcessID ssh_pid = 0; int menu_options = 0; + void _fix_privacy_manifest(const Ref &p_preset, Vector &plist); void _fix_plist(const Ref &p_preset, Vector &plist, const String &p_binary); void _make_icon(const Ref &p_preset, const Ref &p_icon, Vector &p_data);