summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
authorbruvzg <7645683+bruvzg@users.noreply.github.com>2022-08-09 18:51:43 +0300
committerbruvzg <7645683+bruvzg@users.noreply.github.com>2022-08-26 14:23:31 +0300
commitd91cb1d5d57de970d027ffbd46b41cfd847c10dc (patch)
tree582168305780bc4a7631bb83eecc0f308a34a68c /platform
parentdc4193b478dec409132bf50d90fdb4c6760a109a (diff)
[macOS export] Simplify code signing options, add support for rcodesign tool for signing and notarization.
Diffstat (limited to 'platform')
-rw-r--r--platform/macos/export/export.cpp8
-rw-r--r--platform/macos/export/export_plugin.cpp639
-rw-r--r--platform/macos/export/export_plugin.h2
-rw-r--r--platform/windows/export/export_plugin.cpp14
-rw-r--r--platform/windows/export/export_plugin.h2
5 files changed, 449 insertions, 216 deletions
diff --git a/platform/macos/export/export.cpp b/platform/macos/export/export.cpp
index ff7457081f..f219616df4 100644
--- a/platform/macos/export/export.cpp
+++ b/platform/macos/export/export.cpp
@@ -33,8 +33,12 @@
#include "export_plugin.h"
void register_macos_exporter() {
- EDITOR_DEF("export/macos/force_builtin_codesign", false);
- EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::BOOL, "export/macos/force_builtin_codesign", PROPERTY_HINT_NONE));
+ EDITOR_DEF("export/macos/rcodesign", "");
+#ifdef WINDOWS_ENABLED
+ EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/macos/rcodesign", PROPERTY_HINT_GLOBAL_FILE, "*.exe"));
+#else
+ EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/macos/rcodesign", PROPERTY_HINT_GLOBAL_FILE));
+#endif
Ref<EditorExportPlatformMacOS> platform;
platform.instantiate();
diff --git a/platform/macos/export/export_plugin.cpp b/platform/macos/export/export_plugin.cpp
index 76052f7938..4b453add5a 100644
--- a/platform/macos/export/export_plugin.cpp
+++ b/platform/macos/export/export_plugin.cpp
@@ -51,11 +51,51 @@ void EditorExportPlatformMacOS::get_preset_features(const Ref<EditorExportPreset
r_features->push_back(p_preset->get("binary_format/architecture"));
}
-bool EditorExportPlatformMacOS::get_export_option_visibility(const String &p_option, const HashMap<StringName, Variant> &p_options) const {
- // These options are not supported by built-in codesign, used on non macOS host.
- if (!OS::get_singleton()->has_feature("macos")) {
- if (p_option == "codesign/identity" || p_option == "codesign/timestamp" || p_option == "codesign/hardened_runtime" || p_option == "codesign/custom_options" || p_option.begins_with("notarization/")) {
- return false;
+bool EditorExportPlatformMacOS::get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option, const HashMap<StringName, Variant> &p_options) const {
+ // Hide irrelevant code signing options.
+ if (p_preset) {
+ int codesign_tool = p_preset->get("codesign/codesign");
+ switch (codesign_tool) {
+ case 1: { // built-in ad-hoc
+ if (p_option == "codesign/identity" || p_option == "codesign/certificate_file" || p_option == "codesign/certificate_password" || p_option == "codesign/custom_options") {
+ return false;
+ }
+ } break;
+ case 2: { // "rcodesign"
+ if (p_option == "codesign/identity") {
+ return false;
+ }
+ } break;
+#ifdef MACOS_ENABLED
+ case 3: { // "codesign"
+ if (p_option == "codesign/certificate_file" || p_option == "codesign/certificate_password") {
+ return false;
+ }
+ } break;
+#endif
+ default: { // disabled
+ if (p_option == "codesign/identity" || p_option == "codesign/certificate_file" || p_option == "codesign/certificate_password" || p_option == "codesign/custom_options" || p_option.begins_with("codesign/entitlements")) {
+ return false;
+ }
+ } break;
+ }
+
+ // Hide irrelevant notarization options.
+ int notary_tool = p_preset->get("notarization/notarization");
+ switch (notary_tool) {
+ case 1: { // "rcodesign"
+ if (p_option == "notarization/apple_id_name" || p_option == "notarization/apple_id_password" || p_option == "notarization/apple_team_id") {
+ return false;
+ }
+ } break;
+ case 2: { // "altool"
+ // All options are visible.
+ } break;
+ default: { // disabled
+ if (p_option == "notarization/apple_id_name" || p_option == "notarization/apple_id_password" || p_option == "notarization/apple_team_id" || p_option == "notarization/api_uuid" || p_option == "notarization/api_key") {
+ return false;
+ }
+ } break;
}
}
@@ -83,40 +123,22 @@ void EditorExportPlatformMacOS::get_export_options(List<ExportOption> *r_options
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/copyright"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "application/copyright_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "display/high_res"), false));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/microphone_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the microphone"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/microphone_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/camera_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the camera"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/camera_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/location_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the location information"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/location_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/address_book_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the address book"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/address_book_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/calendar_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the calendar"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/calendar_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/photos_library_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the photo library"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/photos_library_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/desktop_folder_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use Desktop folder"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/desktop_folder_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/documents_folder_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use Documents folder"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/documents_folder_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/downloads_folder_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use Downloads folder"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/downloads_folder_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/network_volumes_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use network volumes"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/network_volumes_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
- 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"), ""));
- 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, "codesign/enable"), true));
+#ifdef MACOS_ENABLED
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/codesign", PROPERTY_HINT_ENUM, "Disabled,Built-in (ad-hoc only),PyOxidizer rcodesign,Xcode codesign"), 3, true));
+#else
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/codesign", PROPERTY_HINT_ENUM, "Disabled,Built-in (ad-hoc only),PyOxidizer rcodesign"), 1, true));
+#endif
+ // "codesign" only options:
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/identity", PROPERTY_HINT_PLACEHOLDER_TEXT, "Type: Name (ID)"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/timestamp"), true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/replace_existing_signature"), true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/hardened_runtime"), true));
+ // "rcodesign" only options:
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/certificate_file", PROPERTY_HINT_GLOBAL_FILE, "*.pfx,*.p12"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/certificate_password", PROPERTY_HINT_PASSWORD), ""));
+ // "codesign" and "rcodesign" only options:
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/entitlements/custom_file", PROPERTY_HINT_GLOBAL_FILE, "*.plist"), ""));
-
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/allow_jit_code_execution"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/allow_unsigned_executable_memory"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/allow_dyld_environment_variables"), false));
-
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/disable_library_validation"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/audio_input"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/camera"), false));
@@ -126,7 +148,6 @@ void EditorExportPlatformMacOS::get_export_options(List<ExportOption> *r_options
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/photos_library"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/apple_events"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/debugging"), false));
-
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/app_sandbox/enabled"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/app_sandbox/network_server"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/app_sandbox/network_client"), false));
@@ -137,13 +158,43 @@ void EditorExportPlatformMacOS::get_export_options(List<ExportOption> *r_options
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_music", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_movies", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0));
r_options->push_back(ExportOption(PropertyInfo(Variant::ARRAY, "codesign/entitlements/app_sandbox/helper_executables", PROPERTY_HINT_ARRAY_TYPE, itos(Variant::STRING) + "/" + itos(PROPERTY_HINT_GLOBAL_FILE) + ":"), Array()));
-
r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "codesign/custom_options"), PackedStringArray()));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "notarization/enable"), false));
+#ifdef MACOS_ENABLED
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "notarization/notarization", PROPERTY_HINT_ENUM, "Disabled,PyOxidizer rcodesign,Xcode altool"), 0, true));
+#else
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "notarization/notarization", PROPERTY_HINT_ENUM, "Disabled,PyOxidizer rcodesign"), 0, true));
+#endif
+ // "altool" only options:
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_id_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Apple ID email"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_id_password", PROPERTY_HINT_PLACEHOLDER_TEXT, "Enable two-factor authentication and provide app-specific password"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_id_password", PROPERTY_HINT_PASSWORD, "Enable two-factor authentication and provide app-specific password"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_team_id", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide team ID if your Apple ID belongs to multiple teams"), ""));
+ // "altool" and "rcodesign" only options:
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/api_uuid", PROPERTY_HINT_PLACEHOLDER_TEXT, "App Store Connect issuer ID"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/api_key", PROPERTY_HINT_PLACEHOLDER_TEXT, "App Store Connect API key ID"), ""));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/microphone_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the microphone"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/microphone_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/camera_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the camera"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/camera_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/location_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the location information"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/location_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/address_book_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the address book"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/address_book_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/calendar_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the calendar"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/calendar_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/photos_library_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the photo library"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/photos_library_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/desktop_folder_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use Desktop folder"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/desktop_folder_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/documents_folder_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use Documents folder"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/documents_folder_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/downloads_folder_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use Downloads folder"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/downloads_folder_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/network_volumes_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use network volumes"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/network_volumes_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
+ 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"), ""));
+ 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, "texture_format/s3tc"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc"), false));
@@ -415,156 +466,284 @@ void EditorExportPlatformMacOS::_fix_plist(const Ref<EditorExportPreset> &p_pres
*/
Error EditorExportPlatformMacOS::_notarize(const Ref<EditorExportPreset> &p_preset, const String &p_path) {
+ int notary_tool = p_preset->get("notarization/notarization");
+ switch (notary_tool) {
+ case 1: { // "rcodesign"
+ print_verbose("using rcodesign notarization...");
+
+ String rcodesign = EditorSettings::get_singleton()->get("export/macos/rcodesign").operator String();
+ if (rcodesign.is_empty()) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("rcodesign path is not set. Configure rcodesign path in the Editor Settings (Export > macOS > rcodesign)."));
+ return Error::FAILED;
+ }
+
+ List<String> args;
+
+ args.push_back("notary-submit");
+
+ if (p_preset->get("notarization/api_uuid") == "") {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("App Store Connect issuer ID name not specified."));
+ return Error::FAILED;
+ }
+ if (p_preset->get("notarization/api_key") == "") {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("App Store Connect API key ID not specified."));
+ return Error::FAILED;
+ }
+
+ args.push_back("--api-issuer");
+ args.push_back(p_preset->get("notarization/api_uuid"));
+
+ args.push_back("--api-key");
+ args.push_back(p_preset->get("notarization/api_key"));
+
+ args.push_back(p_path);
+
+ String str;
+ int exitcode = 0;
+
+ Error err = OS::get_singleton()->execute(rcodesign, args, &str, &exitcode, true);
+ if (err != OK) {
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Notarization"), TTR("Could not start rcodesign executable."));
+ return err;
+ }
+
+ int rq_offset = str.find("created submission ID:");
+ if (exitcode != 0 || rq_offset == -1) {
+ print_line("rcodesign (" + p_path + "):\n" + str);
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Notarization"), TTR("Notarization failed, see editor log for details."));
+ return Error::FAILED;
+ } else {
+ print_verbose("rcodesign (" + p_path + "):\n" + str);
+ int next_nl = str.find("\n", rq_offset);
+ String request_uuid = (next_nl == -1) ? str.substr(rq_offset + 14, -1) : str.substr(rq_offset + 14, next_nl - rq_offset - 14);
+ add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), vformat(TTR("Notarization request UUID: \"%s\""), request_uuid));
+ add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), TTR("The notarization process generally takes less than an hour."));
+ add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t" + TTR("You can check progress manually by opening a Terminal and running the following command:"));
+ add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t\t\"rcodesign notary-log --api-issuer <api uuid> --api-key <api key> <request uuid>\"");
+ add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t" + TTR("Run the following command to staple the notarization ticket to the exported application (optional):"));
+ add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t\t\"rcodesign staple <app path>\"");
+ }
+ } break;
#ifdef MACOS_ENABLED
- List<String> args;
+ case 2: { // "altool"
+ print_verbose("using altool notarization...");
- args.push_back("altool");
- args.push_back("--notarize-app");
+ if (!FileAccess::exists("/usr/bin/xcrun") && !FileAccess::exists("/bin/xcrun")) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("Xcode command line tools are not installed."));
+ return Error::FAILED;
+ }
- args.push_back("--primary-bundle-id");
- args.push_back(p_preset->get("application/bundle_identifier"));
+ List<String> args;
- args.push_back("--username");
- args.push_back(p_preset->get("notarization/apple_id_name"));
+ args.push_back("altool");
+ args.push_back("--notarize-app");
- args.push_back("--password");
- args.push_back(p_preset->get("notarization/apple_id_password"));
+ args.push_back("--primary-bundle-id");
+ args.push_back(p_preset->get("application/bundle_identifier"));
- args.push_back("--type");
- args.push_back("osx");
+ if (p_preset->get("notarization/apple_id_name") == "" && p_preset->get("notarization/api_uuid") == "") {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("Neither Apple ID name nor App Store Connect issuer ID name not specified."));
+ return Error::FAILED;
+ }
+ if (p_preset->get("notarization/apple_id_name") != "" && p_preset->get("notarization/api_uuid") != "") {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("Both Apple ID name and App Store Connect issuer ID name are specified, only one should be set at the same time."));
+ return Error::FAILED;
+ }
- if (p_preset->get("notarization/apple_team_id")) {
- args.push_back("--asc-provider");
- args.push_back(p_preset->get("notarization/apple_team_id"));
- }
+ if (p_preset->get("notarization/apple_id_name") != "") {
+ if (p_preset->get("notarization/apple_id_password") == "") {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("Apple ID password not specified."));
+ return Error::FAILED;
+ }
+ args.push_back("--username");
+ args.push_back(p_preset->get("notarization/apple_id_name"));
- args.push_back("--file");
- args.push_back(p_path);
+ args.push_back("--password");
+ args.push_back(p_preset->get("notarization/apple_id_password"));
+ } else {
+ if (p_preset->get("notarization/api_key") == "") {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("App Store Connect API key ID not specified."));
+ return Error::FAILED;
+ }
+ args.push_back("--apiIssuer");
+ args.push_back(p_preset->get("notarization/api_uuid"));
- String str;
- Error err = OS::get_singleton()->execute("xcrun", args, &str, nullptr, true);
- if (err != OK || (str.find("not found") != -1) || (str.find("not recognized") != -1)) {
- add_message(EXPORT_MESSAGE_WARNING, TTR("Notarization"), TTR("Could not start xcrun executable."));
- return err;
- }
+ args.push_back("--apiKey");
+ args.push_back(p_preset->get("notarization/api_key"));
+ }
- print_verbose("altool (" + p_path + "):\n" + str);
- int rq_offset = str.find("RequestUUID");
- if (rq_offset == -1) {
- add_message(EXPORT_MESSAGE_WARNING, TTR("Notarization"), TTR("Notarization failed."));
- return FAILED;
- } else {
- int next_nl = str.find("\n", rq_offset);
- String request_uuid = (next_nl == -1) ? str.substr(rq_offset + 14, -1) : str.substr(rq_offset + 14, next_nl - rq_offset - 14);
- add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), vformat(TTR("Notarization request UUID: \"%s\""), request_uuid));
- add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), TTR("The notarization process generally takes less than an hour. When the process is completed, you'll receive an email."));
- add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t" + TTR("You can check progress manually by opening a Terminal and running the following command:"));
- add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t\t\"xcrun altool --notarization-history 0 -u <your email> -p <app-specific pwd>\"");
- add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t" + TTR("Run the following command to staple the notarization ticket to the exported application (optional):"));
- add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t\t\"xcrun stapler staple <app path>\"");
- }
+ args.push_back("--type");
+ args.push_back("osx");
-#endif
+ if (p_preset->get("notarization/apple_team_id")) {
+ args.push_back("--asc-provider");
+ args.push_back(p_preset->get("notarization/apple_team_id"));
+ }
+ args.push_back("--file");
+ args.push_back(p_path);
+
+ String str;
+ int exitcode = 0;
+ Error err = OS::get_singleton()->execute("xcrun", args, &str, &exitcode, true);
+ if (err != OK) {
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Notarization"), TTR("Could not start xcrun executable."));
+ return err;
+ }
+
+ int rq_offset = str.find("RequestUUID");
+ if (exitcode != 0 || rq_offset == -1) {
+ print_line("xcrun altool (" + p_path + "):\n" + str);
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Notarization"), TTR("Notarization failed, see editor log for details."));
+ return Error::FAILED;
+ } else {
+ print_verbose("xcrun altool (" + p_path + "):\n" + str);
+ int next_nl = str.find("\n", rq_offset);
+ String request_uuid = (next_nl == -1) ? str.substr(rq_offset + 14, -1) : str.substr(rq_offset + 14, next_nl - rq_offset - 14);
+ add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), vformat(TTR("Notarization request UUID: \"%s\""), request_uuid));
+ add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), TTR("The notarization process generally takes less than an hour. When the process is completed, you'll receive an email."));
+ add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t" + TTR("You can check progress manually by opening a Terminal and running the following command:"));
+ add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t\t\"xcrun altool --notarization-history 0 -u <your email> -p <app-specific pwd>\"");
+ add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t" + TTR("Run the following command to staple the notarization ticket to the exported application (optional):"));
+ add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t\t\"xcrun stapler staple <app path>\"");
+ }
+ } break;
+#endif
+ default: {
+ };
+ }
return OK;
}
Error EditorExportPlatformMacOS::_code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path, bool p_warn) {
- bool force_builtin_codesign = EditorSettings::get_singleton()->get("export/macos/force_builtin_codesign");
- bool ad_hoc = (p_preset->get("codesign/identity") == "" || p_preset->get("codesign/identity") == "-");
-
- if ((!FileAccess::exists("/usr/bin/codesign") && !FileAccess::exists("/bin/codesign")) || force_builtin_codesign) {
- print_verbose("using built-in codesign...");
+ int codesign_tool = p_preset->get("codesign/codesign");
+ switch (codesign_tool) {
+ case 1: { // built-in ad-hoc
+ print_verbose("using built-in codesign...");
#ifdef MODULE_REGEX_ENABLED
-
-#ifdef MACOS_ENABLED
- if (p_preset->get("codesign/timestamp") && p_warn) {
- add_message(EXPORT_MESSAGE_INFO, TTR("Code Signing"), TTR("Timestamping is not compatible with ad-hoc signature, and was disabled!"));
- }
- if (p_preset->get("codesign/hardened_runtime") && p_warn) {
- add_message(EXPORT_MESSAGE_INFO, TTR("Code Signing"), TTR("Hardened Runtime is not compatible with ad-hoc signature, and was disabled!"));
- }
-#endif
-
- String error_msg;
- Error err = CodeSign::codesign(false, p_preset->get("codesign/replace_existing_signature"), p_path, p_ent_path, error_msg);
- if (err != OK) {
- add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("Built-in CodeSign failed with error \"%s\"."), error_msg));
- return FAILED;
- }
+ String error_msg;
+ Error err = CodeSign::codesign(false, true, p_path, p_ent_path, error_msg);
+ if (err != OK) {
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("Built-in CodeSign failed with error \"%s\"."), error_msg));
+ return Error::FAILED;
+ }
#else
- add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Built-in CodeSign require regex module."));
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Built-in CodeSign require regex module."));
#endif
- return OK;
- } else {
- print_verbose("using external codesign...");
- List<String> args;
- if (p_preset->get("codesign/timestamp")) {
- if (ad_hoc) {
- if (p_warn) {
- add_message(EXPORT_MESSAGE_INFO, TTR("Code Signing"), TTR("Timestamping is not compatible with ad-hoc signature, and was disabled!"));
- }
- } else {
- args.push_back("--timestamp");
+ } break;
+ case 2: { // "rcodesign"
+ print_verbose("using rcodesign codesign...");
+
+ String rcodesign = EditorSettings::get_singleton()->get("export/macos/rcodesign").operator String();
+ if (rcodesign.is_empty()) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Code Signing"), TTR("Xrcodesign path is not set. Configure rcodesign path in the Editor Settings (Export > macOS > rcodesign)."));
+ return Error::FAILED;
}
- }
- if (p_preset->get("codesign/hardened_runtime")) {
- if (ad_hoc) {
- if (p_warn) {
- add_message(EXPORT_MESSAGE_INFO, TTR("Code Signing"), TTR("Hardened Runtime is not compatible with ad-hoc signature, and was disabled!"));
- }
+
+ List<String> args;
+ args.push_back("sign");
+
+ if (p_path.get_extension() != "dmg") {
+ args.push_back("--entitlements-xml-path");
+ args.push_back(p_ent_path);
+ }
+
+ String certificate_file = p_preset->get("codesign/certificate_file");
+ String certificate_pass = p_preset->get("codesign/certificate_password");
+ if (!certificate_file.is_empty() && !certificate_file.is_empty()) {
+ args.push_back("--p12-file");
+ args.push_back(certificate_file);
+ args.push_back("--p12-password");
+ args.push_back(certificate_pass);
+ }
+
+ args.push_back("-v"); /* provide some more feedback */
+
+ args.push_back(p_path);
+
+ String str;
+ int exitcode = 0;
+
+ Error err = OS::get_singleton()->execute(rcodesign, args, &str, &exitcode, true);
+ if (err != OK) {
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start rcodesign executable."));
+ return err;
+ }
+
+ if (exitcode != 0) {
+ print_line("rcodesign (" + p_path + "):\n" + str);
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Code signing failed, see editor log for details."));
+ return Error::FAILED;
} else {
+ print_verbose("rcodesign (" + p_path + "):\n" + str);
+ }
+ } break;
+#ifdef MACOS_ENABLED
+ case 3: { // "codesign"
+ print_verbose("using xcode codesign...");
+
+ if (!FileAccess::exists("/usr/bin/codesign") && !FileAccess::exists("/bin/codesign")) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Code Signing"), TTR("Xcode command line tools are not installed."));
+ return Error::FAILED;
+ }
+
+ bool ad_hoc = (p_preset->get("codesign/identity") == "" || p_preset->get("codesign/identity") == "-");
+
+ List<String> args;
+ if (!ad_hoc) {
+ args.push_back("--timestamp");
args.push_back("--options");
args.push_back("runtime");
}
- }
-
- if (p_path.get_extension() != "dmg") {
- args.push_back("--entitlements");
- args.push_back(p_ent_path);
- }
- PackedStringArray user_args = p_preset->get("codesign/custom_options");
- for (int i = 0; i < user_args.size(); i++) {
- String user_arg = user_args[i].strip_edges();
- if (!user_arg.is_empty()) {
- args.push_back(user_arg);
+ if (p_path.get_extension() != "dmg") {
+ args.push_back("--entitlements");
+ args.push_back(p_ent_path);
}
- }
- args.push_back("-s");
- if (ad_hoc) {
- args.push_back("-");
- } else {
- args.push_back(p_preset->get("codesign/identity"));
- }
+ PackedStringArray user_args = p_preset->get("codesign/custom_options");
+ for (int i = 0; i < user_args.size(); i++) {
+ String user_arg = user_args[i].strip_edges();
+ if (!user_arg.is_empty()) {
+ args.push_back(user_arg);
+ }
+ }
- args.push_back("-v"); /* provide some more feedback */
+ args.push_back("-s");
+ if (ad_hoc) {
+ args.push_back("-");
+ } else {
+ args.push_back(p_preset->get("codesign/identity"));
+ }
- if (p_preset->get("codesign/replace_existing_signature")) {
+ args.push_back("-v"); /* provide some more feedback */
args.push_back("-f");
- }
- args.push_back(p_path);
+ args.push_back(p_path);
- String str;
- Error err = OS::get_singleton()->execute("codesign", args, &str, nullptr, true);
- if (err != OK || (str.find("not found") != -1) || (str.find("not recognized") != -1)) {
- add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start codesign executable, make sure Xcode command line tools are installed."));
- return err;
- }
+ String str;
+ int exitcode = 0;
- print_verbose("codesign (" + p_path + "):\n" + str);
- if (str.find("no identity found") != -1) {
- add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("No identity found."));
- return FAILED;
- }
- if ((str.find("unrecognized blob type") != -1) || (str.find("cannot read entitlement data") != -1)) {
- add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Invalid entitlements file."));
- return FAILED;
- }
- return OK;
+ Error err = OS::get_singleton()->execute("codesign", args, &str, nullptr, true);
+ if (err != OK) {
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start codesign executable, make sure Xcode command line tools are installed."));
+ return err;
+ }
+
+ if (exitcode != 0) {
+ print_line("codesign (" + p_path + "):\n" + str);
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Code signing failed, see editor log for details."));
+ return Error::FAILED;
+ } else {
+ print_verbose("codesign (" + p_path + "):\n" + str);
+ }
+ } break;
+#endif
+ default: {
+ };
}
+
+ return OK;
}
Error EditorExportPlatformMacOS::_code_sign_directory(const Ref<EditorExportPreset> &p_preset, const String &p_path,
@@ -816,7 +995,9 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
err = ERR_CANT_CREATE;
}
- DirAccess::remove_file_or_error(scr_path);
+ if (FileAccess::exists(scr_path)) {
+ DirAccess::remove_file_or_error(scr_path);
+ }
if (DirAccess::exists(tmp_app_path_name)) {
String old_dir = tmp_app_dir->get_current_dir();
if (tmp_app_dir->change_dir(tmp_app_path_name) == OK) {
@@ -1148,7 +1329,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
err = save_pack(p_preset, p_debug, pack_path, &shared_objects);
// See if we can code sign our new package.
- bool sign_enabled = p_preset->get("codesign/enable");
+ bool sign_enabled = (p_preset->get("codesign/codesign").operator int() > 0);
String ent_path = p_preset->get("codesign/entitlements/custom_file");
String hlp_ent_path = EditorPaths::get_singleton()->get_cache_dir().plus_file(pkg_name + "_helper.entitlements");
@@ -1314,14 +1495,25 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
}
}
- bool ad_hoc = true;
- if (err == OK) {
+ bool ad_hoc = false;
+ int codesign_tool = p_preset->get("codesign/codesign");
+ switch (codesign_tool) {
+ case 1: { // built-in ad-hoc
+ ad_hoc = true;
+ } break;
+ case 2: { // "rcodesign"
+ ad_hoc = p_preset->get("codesign/certificate_file").operator String().is_empty() || p_preset->get("codesign/certificate_password").operator String().is_empty();
+ } break;
#ifdef MACOS_ENABLED
- String sign_identity = p_preset->get("codesign/identity");
-#else
- String sign_identity = "-";
+ case 3: { // "codesign"
+ ad_hoc = (p_preset->get("codesign/identity") == "" || p_preset->get("codesign/identity") == "-");
+ } break;
#endif
- ad_hoc = (sign_identity == "" || sign_identity == "-");
+ default: {
+ };
+ }
+
+ if (err == OK) {
bool lib_validation = p_preset->get("codesign/entitlements/disable_library_validation");
if ((!dylibs_found.is_empty() || !shared_objects.is_empty()) && sign_enabled && ad_hoc && !lib_validation) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Code Signing"), TTR("Ad-hoc signed applications require the 'Disable Library Validation' entitlement to load dynamic libraries."));
@@ -1404,8 +1596,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
}
}
-#ifdef MACOS_ENABLED
- bool noto_enabled = p_preset->get("notarization/enable");
+ bool noto_enabled = (p_preset->get("notarization/notarization").operator int() > 0);
if (err == OK && noto_enabled) {
if (export_format == "app") {
add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), TTR("Notarization requires the app to be archived first, select the DMG or ZIP export format instead."));
@@ -1416,10 +1607,11 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
err = _notarize(p_preset, p_path);
}
}
-#endif
// Clean up temporary entitlements files.
- DirAccess::remove_file_or_error(hlp_ent_path);
+ if (FileAccess::exists(hlp_ent_path)) {
+ DirAccess::remove_file_or_error(hlp_ent_path);
+ }
// Clean up temporary .app dir and generated entitlements.
if ((String)(p_preset->get("codesign/entitlements/custom_file")) == "") {
@@ -1602,65 +1794,98 @@ bool EditorExportPlatformMacOS::has_valid_project_configuration(const Ref<Editor
valid = false;
}
- bool sign_enabled = p_preset->get("codesign/enable");
-
+ bool ad_hoc = false;
+ int codesign_tool = p_preset->get("codesign/codesign");
+ switch (codesign_tool) {
+ case 1: { // built-in ad-hoc
+ ad_hoc = true;
+ } break;
+ case 2: { // "rcodesign"
+ ad_hoc = p_preset->get("codesign/certificate_file").operator String().is_empty() || p_preset->get("codesign/certificate_password").operator String().is_empty();
+ } break;
#ifdef MACOS_ENABLED
- bool noto_enabled = p_preset->get("notarization/enable");
- bool ad_hoc = ((p_preset->get("codesign/identity") == "") || (p_preset->get("codesign/identity") == "-"));
-
- if (!ad_hoc && (bool)EditorSettings::get_singleton()->get("export/macos/force_builtin_codesign")) {
- err += TTR("Warning: Built-in \"codesign\" is selected in the Editor Settings. Code signing is limited to ad-hoc signature only.") + "\n";
- }
- if (!ad_hoc && !FileAccess::exists("/usr/bin/codesign") && !FileAccess::exists("/bin/codesign")) {
- err += TTR("Warning: Xcode command line tools are not installed, using built-in \"codesign\". Code signing is limited to ad-hoc signature only.") + "\n";
+ case 3: { // "codesign"
+ ad_hoc = (p_preset->get("codesign/identity") == "" || p_preset->get("codesign/identity") == "-");
+ } break;
+#endif
+ default: {
+ };
}
+ int notary_tool = p_preset->get("notarization/notarization");
- if (noto_enabled) {
+ if (notary_tool > 0) {
if (ad_hoc) {
err += TTR("Notarization: Notarization with an ad-hoc signature is not supported.") + "\n";
valid = false;
}
- if (!sign_enabled) {
+ if (codesign_tool == 0) {
err += TTR("Notarization: Code signing is required for notarization.") + "\n";
valid = false;
}
- if (!(bool)p_preset->get("codesign/hardened_runtime")) {
- err += TTR("Notarization: Hardened runtime is required for notarization.") + "\n";
- valid = false;
- }
- if (!(bool)p_preset->get("codesign/timestamp")) {
- err += TTR("Notarization: Timestamping is required for notarization.") + "\n";
- valid = false;
- }
- if (p_preset->get("notarization/apple_id_name") == "") {
- err += TTR("Notarization: Apple ID name not specified.") + "\n";
- valid = false;
- }
- if (p_preset->get("notarization/apple_id_password") == "") {
- err += TTR("Notarization: Apple ID password not specified.") + "\n";
- valid = false;
+ if (notary_tool == 2) {
+ if (!FileAccess::exists("/usr/bin/xcrun") && !FileAccess::exists("/bin/xcrun")) {
+ err += TTR("Notarization: Xcode command line tools are not installed.") + "\n";
+ valid = false;
+ }
+ if (p_preset->get("notarization/apple_id_name") == "" && p_preset->get("notarization/api_uuid") == "") {
+ err += TTR("Notarization: Neither Apple ID name nor App Store Connect issuer ID name not specified.") + "\n";
+ valid = false;
+ } else if (p_preset->get("notarization/apple_id_name") != "" && p_preset->get("notarization/api_uuid") != "") {
+ err += TTR("Notarization: Both Apple ID name and App Store Connect issuer ID name are specified, only one should be set at the same time.") + "\n";
+ valid = false;
+ } else {
+ if (p_preset->get("notarization/apple_id_name") != "") {
+ if (p_preset->get("notarization/apple_id_password") == "") {
+ err += TTR("Notarization: Apple ID password not specified.") + "\n";
+ }
+ valid = false;
+ }
+ if (p_preset->get("notarization/api_uuid") != "") {
+ if (p_preset->get("notarization/api_key") == "") {
+ err += TTR("Notarization: App Store Connect API key ID not specified.") + "\n";
+ valid = false;
+ }
+ }
+ }
+ } else if (notary_tool == 1) {
+ if (p_preset->get("notarization/api_uuid") == "") {
+ err += TTR("Notarization: App Store Connect issuer ID name not specified.") + "\n";
+ valid = false;
+ }
+ if (p_preset->get("notarization/api_key") == "") {
+ err += TTR("Notarization: App Store Connect API key ID not specified.") + "\n";
+ valid = false;
+ }
+
+ String rcodesign = EditorSettings::get_singleton()->get("export/macos/rcodesign").operator String();
+ if (rcodesign.is_empty()) {
+ err += TTR("Notarization: rcodesign path is not set. Configure rcodesign path in the Editor Settings (Export > macOS > rcodesign).") + "\n";
+ valid = false;
+ }
}
} else {
err += TTR("Warning: Notarization is disabled. The exported project will be blocked by Gatekeeper if it's downloaded from an unknown source.") + "\n";
- if (!sign_enabled) {
+ if (codesign_tool == 0) {
err += TTR("Code signing is disabled. The exported project will not run on Macs with enabled Gatekeeper and Apple Silicon powered Macs.") + "\n";
- } else {
- if ((bool)p_preset->get("codesign/hardened_runtime") && ad_hoc) {
- err += TTR("Hardened Runtime is not compatible with ad-hoc signature, and will be disabled!") + "\n";
- }
- if ((bool)p_preset->get("codesign/timestamp") && ad_hoc) {
- err += TTR("Timestamping is not compatible with ad-hoc signature, and will be disabled!") + "\n";
- }
}
}
-#else
- err += TTR("Warning: Notarization is not supported from this OS. The exported project will be blocked by Gatekeeper if it's downloaded from an unknown source.") + "\n";
- if (!sign_enabled) {
- err += TTR("Code signing is disabled. The exported project will not run on Macs with enabled Gatekeeper and Apple Silicon powered Macs.") + "\n";
- }
-#endif
- if (sign_enabled) {
+ if (codesign_tool > 0) {
+ if (ad_hoc) {
+ err += TTR("Code signing: Using ad-hoc signature. The exported project will be blocked by Gatekeeper") + "\n";
+ }
+ if (codesign_tool == 3) {
+ if (!FileAccess::exists("/usr/bin/codesign") && !FileAccess::exists("/bin/codesign")) {
+ err += TTR("Code signing: Xcode command line tools are not installed.") + "\n";
+ valid = false;
+ }
+ } else if (codesign_tool == 2) {
+ String rcodesign = EditorSettings::get_singleton()->get("export/macos/rcodesign").operator String();
+ if (rcodesign.is_empty()) {
+ err += TTR("Code signing: rcodesign path is not set. Configure rcodesign path in the Editor Settings (Export > macOS > rcodesign).") + "\n";
+ valid = false;
+ }
+ }
if ((bool)p_preset->get("codesign/entitlements/audio_input") && ((String)p_preset->get("privacy/microphone_usage_description")).is_empty()) {
err += TTR("Privacy: Microphone access is enabled, but usage description is not specified.") + "\n";
valid = false;
diff --git a/platform/macos/export/export_plugin.h b/platform/macos/export/export_plugin.h
index 4603c61a28..87790129d3 100644
--- a/platform/macos/export/export_plugin.h
+++ b/platform/macos/export/export_plugin.h
@@ -101,7 +101,7 @@ class EditorExportPlatformMacOS : public EditorExportPlatform {
protected:
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const override;
virtual void get_export_options(List<ExportOption> *r_options) override;
- virtual bool get_export_option_visibility(const String &p_option, const HashMap<StringName, Variant> &p_options) const override;
+ virtual bool get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option, const HashMap<StringName, Variant> &p_options) const override;
public:
virtual String get_name() const override { return "macOS"; }
diff --git a/platform/windows/export/export_plugin.cpp b/platform/windows/export/export_plugin.cpp
index 9d3ec31f73..cb0bd44cfb 100644
--- a/platform/windows/export/export_plugin.cpp
+++ b/platform/windows/export/export_plugin.cpp
@@ -113,7 +113,7 @@ List<String> EditorExportPlatformWindows::get_binary_extensions(const Ref<Editor
return list;
}
-bool EditorExportPlatformWindows::get_export_option_visibility(const String &p_option, const HashMap<StringName, Variant> &p_options) const {
+bool EditorExportPlatformWindows::get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option, const HashMap<StringName, Variant> &p_options) const {
// This option is not supported by "osslsigncode", used on non-Windows host.
if (!OS::get_singleton()->has_feature("windows") && p_option == "codesign/identity_type") {
return false;
@@ -128,7 +128,7 @@ void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_optio
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/enable"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/identity_type", PROPERTY_HINT_ENUM, "Select automatically,Use PKCS12 file (specify *.PFX/*.P12 file),Use certificate store (specify SHA1 hash)"), 0));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/identity", PROPERTY_HINT_GLOBAL_FILE, "*.pfx,*.p12"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/password"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/password", PROPERTY_HINT_PASSWORD), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/timestamp"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/timestamp_server_url"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/digest_algorithm", PROPERTY_HINT_ENUM, "SHA1,SHA256"), 1));
@@ -231,7 +231,7 @@ Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset
String str;
Error err = OS::get_singleton()->execute(rcedit_path, args, &str, nullptr, true);
if (err != OK || (str.find("not found") != -1) || (str.find("not recognized") != -1)) {
- add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), TTR("Could not start rcedit executable. Configure rcedit path in the Editor Settings (Export > Windows > Rcedit), or disable \"Application > Modify Resources\" in the export preset."));
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), TTR("Could not start rcedit executable. Configure rcedit path in the Editor Settings (Export > Windows > rcedit), or disable \"Application > Modify Resources\" in the export preset."));
return err;
}
print_line("rcedit (" + p_path + "): " + str);
@@ -379,7 +379,11 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
String str;
Error err = OS::get_singleton()->execute(signtool_path, args, &str, nullptr, true);
if (err != OK || (str.find("not found") != -1) || (str.find("not recognized") != -1)) {
- add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start signtool executable. Configure signtool path in the Editor Settings (Export > Windows > Signtool), or disable \"Codesign\" in the export preset."));
+#ifndef WINDOWS_ENABLED
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start signtool executable. Configure signtool path in the Editor Settings (Export > Windows > signtool), or disable \"Codesign\" in the export preset."));
+#else
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start osslsigncode executable. Configure signtool path in the Editor Settings (Export > Windows > osslsigncode), or disable \"Codesign\" in the export preset."));
+#endif
return err;
}
@@ -418,7 +422,7 @@ bool EditorExportPlatformWindows::has_valid_export_configuration(const Ref<Edito
String rcedit_path = EditorSettings::get_singleton()->get("export/windows/rcedit");
if (p_preset->get("application/modify_resources") && rcedit_path.is_empty()) {
- err += TTR("The rcedit tool must be configured in the Editor Settings (Export > Windows > Rcedit) to change the icon or app information data.") + "\n";
+ err += TTR("The rcedit tool must be configured in the Editor Settings (Export > Windows > rcedit) to change the icon or app information data.") + "\n";
}
if (!err.is_empty()) {
diff --git a/platform/windows/export/export_plugin.h b/platform/windows/export/export_plugin.h
index 3ea8ff3dc9..f85331c898 100644
--- a/platform/windows/export/export_plugin.h
+++ b/platform/windows/export/export_plugin.h
@@ -48,9 +48,9 @@ public:
virtual Error sign_shared_object(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path) override;
virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override;
virtual void get_export_options(List<ExportOption> *r_options) override;
- virtual bool get_export_option_visibility(const String &p_option, const HashMap<StringName, Variant> &p_options) const override;
virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const override;
+ virtual bool get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option, const HashMap<StringName, Variant> &p_options) const override;
virtual String get_template_file_name(const String &p_target, const String &p_arch) const override;
virtual Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) override;
};