diff --git a/core/core_constants.cpp b/core/core_constants.cpp index d88dda66090f..ceab71ff2e6d 100644 --- a/core/core_constants.cpp +++ b/core/core_constants.cpp @@ -704,6 +704,7 @@ void register_global_constants() { BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT); BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_EDITOR_BASIC_SETTING); BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_READ_ONLY); + BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_SECRET); BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_DEFAULT); BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_NO_EDITOR); diff --git a/core/object/object.h b/core/object/object.h index ed2c6254174c..2e709d6ffe50 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -118,6 +118,7 @@ enum PropertyUsageFlags { PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT = 1 << 26, // For Object properties, instantiate them when creating in editor. PROPERTY_USAGE_EDITOR_BASIC_SETTING = 1 << 27, //for project or editor settings, show when basic settings are selected. PROPERTY_USAGE_READ_ONLY = 1 << 28, // Mark a property as read-only in the inspector. + PROPERTY_USAGE_SECRET = 1 << 29, // Export preset credentials that should be stored separately from the rest of the export config. PROPERTY_USAGE_DEFAULT = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR, PROPERTY_USAGE_NO_EDITOR = PROPERTY_USAGE_STORAGE, diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index a0b623936a6b..b98d9adcecc5 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -2842,6 +2842,9 @@ The property is read-only in the [EditorInspector]. + + An export preset property with this flag contains confidential information and is stored separately from the rest of the export preset configuration. + Default usage (storage, editor and network). diff --git a/editor/export/editor_export.cpp b/editor/export/editor_export.cpp index 3f192342a184..c6faefc45feb 100644 --- a/editor/export/editor_export.cpp +++ b/editor/export/editor_export.cpp @@ -37,7 +37,9 @@ EditorExport *EditorExport::singleton = nullptr; void EditorExport::_save() { Ref config; + Ref credentials; config.instantiate(); + credentials.instantiate(); for (int i = 0; i < export_presets.size(); i++) { Ref preset = export_presets[i]; String section = "preset." + itos(i); @@ -83,16 +85,21 @@ void EditorExport::_save() { config->set_value(section, "encryption_exclude_filters", preset->get_enc_ex_filter()); config->set_value(section, "encrypt_pck", preset->get_enc_pck()); config->set_value(section, "encrypt_directory", preset->get_enc_directory()); - config->set_value(section, "script_encryption_key", preset->get_script_encryption_key()); + credentials->set_value(section, "script_encryption_key", preset->get_script_encryption_key()); String option_section = "preset." + itos(i) + ".options"; for (const PropertyInfo &E : preset->get_properties()) { - config->set_value(option_section, E.name, preset->get(E.name)); + if (E.usage & PROPERTY_USAGE_SECRET) { + credentials->set_value(option_section, E.name, preset->get(E.name)); + } else { + config->set_value(option_section, E.name, preset->get(E.name)); + } } } config->save("res://export_presets.cfg"); + credentials->save("res://.godot/export_credentials.cfg"); } void EditorExport::save_presets() { @@ -202,6 +209,13 @@ void EditorExport::load_config() { return; } + Ref credentials; + credentials.instantiate(); + err = credentials->load("res://.godot/export_credentials.cfg"); + if (!(err == OK || err == ERR_FILE_NOT_FOUND)) { + return; + } + block_save = true; int index = 0; @@ -284,22 +298,30 @@ void EditorExport::load_config() { if (config->has_section_key(section, "encryption_exclude_filters")) { preset->set_enc_ex_filter(config->get_value(section, "encryption_exclude_filters")); } - if (config->has_section_key(section, "script_encryption_key")) { - preset->set_script_encryption_key(config->get_value(section, "script_encryption_key")); + if (credentials->has_section_key(section, "script_encryption_key")) { + preset->set_script_encryption_key(credentials->get_value(section, "script_encryption_key")); } String option_section = "preset." + itos(index) + ".options"; List options; - config->get_section_keys(option_section, &options); for (const String &E : options) { Variant value = config->get_value(option_section, E); - preset->set(E, value); } + if (credentials->has_section(option_section)) { + options.clear(); + credentials->get_section_keys(option_section, &options); + + for (const String &E : options) { + Variant value = credentials->get_value(option_section, E); + preset->set(E, value); + } + } + add_export_preset(preset); index++; } diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp index 670f5af713b0..65ffa45b383c 100644 --- a/editor/export/editor_export_platform.cpp +++ b/editor/export/editor_export_platform.cpp @@ -818,6 +818,14 @@ String EditorExportPlatform::_export_customize(const String &p_path, LocalVector return save_path.is_empty() ? p_path : save_path; } +String EditorExportPlatform::_get_script_encryption_key(const Ref &p_preset) const { + const String from_env = OS::get_singleton()->get_environment(ENV_SCRIPT_ENCRYPTION_KEY); + if (!from_env.is_empty()) { + return from_env.to_lower(); + } + return p_preset->get_script_encryption_key().to_lower(); +} + Vector EditorExportPlatform::get_forced_export_files() { Vector files; @@ -946,7 +954,7 @@ Error EditorExportPlatform::export_project_files(const Ref & } // Get encryption key. - String script_key = p_preset->get_script_encryption_key().to_lower(); + String script_key = _get_script_encryption_key(p_preset); key.resize(32); if (script_key.length() == 64) { for (int i = 0; i < 32; i++) { @@ -1577,7 +1585,7 @@ Error EditorExportPlatform::save_pack(const Ref &p_preset, b Ref fhead = f; if (enc_pck && enc_directory) { - String script_key = p_preset->get_script_encryption_key().to_lower(); + String script_key = _get_script_encryption_key(p_preset); Vector key; key.resize(32); if (script_key.length() == 64) { diff --git a/editor/export/editor_export_platform.h b/editor/export/editor_export_platform.h index df5a66f099a7..3b9663ebdf38 100644 --- a/editor/export/editor_export_platform.h +++ b/editor/export/editor_export_platform.h @@ -43,6 +43,8 @@ struct EditorProgress; class EditorExportPlugin; +const String ENV_SCRIPT_ENCRYPTION_KEY = "GODOT_SCRIPT_ENCRYPTION_KEY"; + class EditorExportPlatform : public RefCounted { GDCLASS(EditorExportPlatform, RefCounted); @@ -116,6 +118,7 @@ private: bool _is_editable_ancestor(Node *p_root, Node *p_node); String _export_customize(const String &p_path, LocalVector> &customize_resources_plugins, LocalVector> &customize_scenes_plugins, HashMap &export_cache, const String &export_base_path, bool p_force_save); + String _get_script_encryption_key(const Ref &p_preset) const; protected: struct ExportNotifier { diff --git a/editor/export/editor_export_preset.cpp b/editor/export/editor_export_preset.cpp index ac9347960525..2aca19a2ad57 100644 --- a/editor/export/editor_export_preset.cpp +++ b/editor/export/editor_export_preset.cpp @@ -302,4 +302,15 @@ String EditorExportPreset::get_script_encryption_key() const { return script_key; } +Variant EditorExportPreset::get_or_env(const StringName &p_name, const String &p_env_var, bool *r_valid) const { + const String from_env = OS::get_singleton()->get_environment(p_env_var); + if (!from_env.is_empty()) { + if (r_valid) { + *r_valid = true; + } + return from_env; + } + return get(p_name, r_valid); +} + EditorExportPreset::EditorExportPreset() {} diff --git a/editor/export/editor_export_preset.h b/editor/export/editor_export_preset.h index 003e3c05a352..194858b4e879 100644 --- a/editor/export/editor_export_preset.h +++ b/editor/export/editor_export_preset.h @@ -152,6 +152,8 @@ public: void set_script_encryption_key(const String &p_key); String get_script_encryption_key() const; + Variant get_or_env(const StringName &p_name, const String &p_env_var, bool *r_valid = nullptr) const; + const List &get_properties() const { return properties; } EditorExportPreset(); diff --git a/platform/android/doc_classes/EditorExportPlatformAndroid.xml b/platform/android/doc_classes/EditorExportPlatformAndroid.xml index 1a0777428790..11129ca1496c 100644 --- a/platform/android/doc_classes/EditorExportPlatformAndroid.xml +++ b/platform/android/doc_classes/EditorExportPlatformAndroid.xml @@ -58,21 +58,27 @@ Path of the debug keystore file. + Can be overridden with the environment variable [code]GODOT_ANDROID_KEYSTORE_DEBUG_PATH[/code]. Password for the debug keystore file. + Can be overridden with the environment variable [code]GODOT_ANDROID_KEYSTORE_DEBUG_PASSWORD[/code]. User name for the debug keystore file. + Can be overridden with the environment variable [code]GODOT_ANDROID_KEYSTORE_DEBUG_USER[/code]. Path of the release keystore file. + Can be overridden with the environment variable [code]GODOT_ANDROID_KEYSTORE_RELEASE_PATH[/code]. Password for the release keystore file. + Can be overridden with the environment variable [code]GODOT_ANDROID_KEYSTORE_RELEASE_PASSWORD[/code]. User name for the release keystore file. + Can be overridden with the environment variable [code]GODOT_ANDROID_KEYSTORE_RELEASE_USER[/code]. Background layer of the application adaptive icon file. diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp index 87f4cf2de2d7..d8dd453faff3 100644 --- a/platform/android/export/export_plugin.cpp +++ b/platform/android/export/export_plugin.cpp @@ -1825,12 +1825,12 @@ void EditorExportPlatformAndroid::get_export_options(List *r_optio r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, vformat("%s/%s", PNAME("architectures"), abi)), is_default)); } - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/debug", PROPERTY_HINT_GLOBAL_FILE, "*.keystore,*.jks"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/debug_user"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/debug_password"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release", PROPERTY_HINT_GLOBAL_FILE, "*.keystore,*.jks"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release_user"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release_password"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/debug", PROPERTY_HINT_GLOBAL_FILE, "*.keystore,*.jks", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/debug_user", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/debug_password", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release", PROPERTY_HINT_GLOBAL_FILE, "*.keystore,*.jks", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release_user", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release_password", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/code", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 1)); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "version/name"), "1.0")); @@ -2277,9 +2277,9 @@ bool EditorExportPlatformAndroid::has_valid_export_configuration(const Refget("keystore/debug"); - String dk_user = p_preset->get("keystore/debug_user"); - String dk_password = p_preset->get("keystore/debug_password"); + String dk = p_preset->get_or_env("keystore/debug", ENV_ANDROID_KEYSTORE_DEBUG_PATH); + String dk_user = p_preset->get_or_env("keystore/debug_user", ENV_ANDROID_KEYSTORE_DEBUG_USER); + String dk_password = p_preset->get_or_env("keystore/debug_password", ENV_ANDROID_KEYSTORE_DEBUG_PASS); if ((dk.is_empty() || dk_user.is_empty() || dk_password.is_empty()) && (!dk.is_empty() || !dk_user.is_empty() || !dk_password.is_empty())) { valid = false; @@ -2294,9 +2294,9 @@ bool EditorExportPlatformAndroid::has_valid_export_configuration(const Refget("keystore/release"); - String rk_user = p_preset->get("keystore/release_user"); - String rk_password = p_preset->get("keystore/release_password"); + String rk = p_preset->get_or_env("keystore/release", ENV_ANDROID_KEYSTORE_RELEASE_PATH); + String rk_user = p_preset->get_or_env("keystore/release_user", ENV_ANDROID_KEYSTORE_RELEASE_USER); + String rk_password = p_preset->get_or_env("keystore/release_password", ENV_ANDROID_KEYSTORE_RELEASE_PASS); if ((rk.is_empty() || rk_user.is_empty() || rk_password.is_empty()) && (!rk.is_empty() || !rk_user.is_empty() || !rk_password.is_empty())) { valid = false; @@ -2507,9 +2507,9 @@ void EditorExportPlatformAndroid::get_command_line_flags(const Ref &p_preset, bool p_debug, const String &export_path, EditorProgress &ep) { int export_format = int(p_preset->get("gradle_build/export_format")); String export_label = export_format == EXPORT_FORMAT_AAB ? "AAB" : "APK"; - String release_keystore = p_preset->get("keystore/release"); - String release_username = p_preset->get("keystore/release_user"); - String release_password = p_preset->get("keystore/release_password"); + String release_keystore = p_preset->get_or_env("keystore/release", ENV_ANDROID_KEYSTORE_RELEASE_PATH); + String release_username = p_preset->get_or_env("keystore/release_user", ENV_ANDROID_KEYSTORE_RELEASE_USER); + String release_password = p_preset->get_or_env("keystore/release_password", ENV_ANDROID_KEYSTORE_RELEASE_PASS); String target_sdk_version = p_preset->get("gradle_build/target_sdk"); if (!target_sdk_version.is_valid_int()) { target_sdk_version = itos(DEFAULT_TARGET_SDK_VERSION); @@ -2529,9 +2529,9 @@ Error EditorExportPlatformAndroid::sign_apk(const Ref &p_pre String password; String user; if (p_debug) { - keystore = p_preset->get("keystore/debug"); - password = p_preset->get("keystore/debug_password"); - user = p_preset->get("keystore/debug_user"); + keystore = p_preset->get_or_env("keystore/debug", ENV_ANDROID_KEYSTORE_DEBUG_PATH); + password = p_preset->get_or_env("keystore/debug_password", ENV_ANDROID_KEYSTORE_DEBUG_PASS); + user = p_preset->get_or_env("keystore/debug_user", ENV_ANDROID_KEYSTORE_DEBUG_USER); if (keystore.is_empty()) { keystore = EDITOR_GET("export/android/debug_keystore"); @@ -2886,9 +2886,9 @@ Error EditorExportPlatformAndroid::export_project_helper(const Refget("keystore/debug"); - String debug_password = p_preset->get("keystore/debug_password"); - String debug_user = p_preset->get("keystore/debug_user"); + String debug_keystore = p_preset->get_or_env("keystore/debug", ENV_ANDROID_KEYSTORE_DEBUG_PATH); + String debug_password = p_preset->get_or_env("keystore/debug_password", ENV_ANDROID_KEYSTORE_DEBUG_PASS); + String debug_user = p_preset->get_or_env("keystore/debug_user", ENV_ANDROID_KEYSTORE_DEBUG_USER); if (debug_keystore.is_empty()) { debug_keystore = EDITOR_GET("export/android/debug_keystore"); @@ -2908,9 +2908,9 @@ Error EditorExportPlatformAndroid::export_project_helper(const Refget("keystore/release_user"); - String release_password = p_preset->get("keystore/release_password"); + String release_keystore = p_preset->get_or_env("keystore/release", ENV_ANDROID_KEYSTORE_RELEASE_PATH); + String release_username = p_preset->get_or_env("keystore/release_user", ENV_ANDROID_KEYSTORE_RELEASE_USER); + String release_password = p_preset->get_or_env("keystore/release_password", ENV_ANDROID_KEYSTORE_RELEASE_PASS); if (release_keystore.is_relative_path()) { release_keystore = OS::get_singleton()->get_resource_dir().path_join(release_keystore).simplify_path(); } diff --git a/platform/android/export/export_plugin.h b/platform/android/export/export_plugin.h index f9dad5ce5e0a..390b8c6465c8 100644 --- a/platform/android/export/export_plugin.h +++ b/platform/android/export/export_plugin.h @@ -49,6 +49,15 @@ const String SPLASH_CONFIG_XML_CONTENT = R"SPLASH( )SPLASH"; +// Optional environment variables for defining confidential information. If any +// of these is set, they will override the values set in the credentials file. +const String ENV_ANDROID_KEYSTORE_DEBUG_PATH = "GODOT_ANDROID_KEYSTORE_DEBUG_PATH"; +const String ENV_ANDROID_KEYSTORE_DEBUG_USER = "GODOT_ANDROID_KEYSTORE_DEBUG_USER"; +const String ENV_ANDROID_KEYSTORE_DEBUG_PASS = "GODOT_ANDROID_KEYSTORE_DEBUG_PASSWORD"; +const String ENV_ANDROID_KEYSTORE_RELEASE_PATH = "GODOT_ANDROID_KEYSTORE_RELEASE_PATH"; +const String ENV_ANDROID_KEYSTORE_RELEASE_USER = "GODOT_ANDROID_KEYSTORE_RELEASE_USER"; +const String ENV_ANDROID_KEYSTORE_RELEASE_PASS = "GODOT_ANDROID_KEYSTORE_RELEASE_PASSWORD"; + struct LauncherIcon { const char *export_path; int dimensions = 0; diff --git a/platform/ios/doc_classes/EditorExportPlatformIOS.xml b/platform/ios/doc_classes/EditorExportPlatformIOS.xml index ef2b0a256de0..70b999eb0f6c 100644 --- a/platform/ios/doc_classes/EditorExportPlatformIOS.xml +++ b/platform/ios/doc_classes/EditorExportPlatformIOS.xml @@ -35,9 +35,11 @@ UUID of the provisioning profile. If left empty, Xcode will download or create a provisioning profile automatically. See [url=https://developer.apple.com/help/account/manage-profiles/edit-download-or-delete-profiles]Edit, download, or delete provisioning profiles[/url]. + Can be overridden with the environment variable [code]GODOT_IOS_PROVISIONING_PROFILE_UUID_DEBUG[/code]. UUID of the provisioning profile. If left empty, Xcode will download or create a provisioning profile automatically. See [url=https://developer.apple.com/help/account/manage-profiles/edit-download-or-delete-profiles]Edit, download, or delete provisioning profiles[/url]. + Can be overridden with the environment variable [code]GODOT_IOS_PROVISIONING_PROFILE_UUID_RELEASE[/code]. Application version visible to the user, can only contain numeric characters ([code]0-9[/code]) and periods ([code].[/code]). diff --git a/platform/ios/export/export_plugin.cpp b/platform/ios/export/export_plugin.cpp index 9c0e4e39e8e8..06741a12e4d6 100644 --- a/platform/ios/export/export_plugin.cpp +++ b/platform/ios/export/export_plugin.cpp @@ -160,10 +160,10 @@ void EditorExportPlatformIOS::get_export_options(List *r_options) r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/app_store_team_id"), "", false, true)); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/provisioning_profile_uuid_debug"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/provisioning_profile_uuid_debug", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/code_sign_identity_debug", PROPERTY_HINT_PLACEHOLDER_TEXT, "iPhone Developer"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/export_method_debug", PROPERTY_HINT_ENUM, "App Store,Development,Ad-Hoc,Enterprise"), 1)); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/provisioning_profile_uuid_release"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/provisioning_profile_uuid_release", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/code_sign_identity_release", PROPERTY_HINT_PLACEHOLDER_TEXT, "iPhone Distribution"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/export_method_release", PROPERTY_HINT_ENUM, "App Store,Development,Ad-Hoc,Enterprise"), 0)); @@ -253,8 +253,8 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref &p_ }; String dbg_sign_id = p_preset->get("application/code_sign_identity_debug").operator String().is_empty() ? "iPhone Developer" : p_preset->get("application/code_sign_identity_debug"); String rel_sign_id = p_preset->get("application/code_sign_identity_release").operator String().is_empty() ? "iPhone Distribution" : p_preset->get("application/code_sign_identity_release"); - bool dbg_manual = !p_preset->get("application/provisioning_profile_uuid_debug").operator String().is_empty() || (dbg_sign_id != "iPhone Developer"); - bool rel_manual = !p_preset->get("application/provisioning_profile_uuid_release").operator String().is_empty() || (rel_sign_id != "iPhone Distribution"); + bool dbg_manual = !p_preset->get_or_env("application/provisioning_profile_uuid_debug", ENV_IOS_PROFILE_UUID_DEBUG).operator String().is_empty() || (dbg_sign_id != "iPhone Developer"); + bool rel_manual = !p_preset->get_or_env("application/provisioning_profile_uuid_release", ENV_IOS_PROFILE_UUID_RELEASE).operator String().is_empty() || (rel_sign_id != "iPhone Distribution"); String str; String strnew; str.parse_utf8((const char *)pfile.ptr(), pfile.size()); @@ -288,9 +288,9 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref &p_ int export_method = p_preset->get(p_debug ? "application/export_method_debug" : "application/export_method_release"); strnew += lines[i].replace("$export_method", export_method_string[export_method]) + "\n"; } else if (lines[i].find("$provisioning_profile_uuid_release") != -1) { - strnew += lines[i].replace("$provisioning_profile_uuid_release", p_preset->get("application/provisioning_profile_uuid_release")) + "\n"; + strnew += lines[i].replace("$provisioning_profile_uuid_release", p_preset->get_or_env("application/provisioning_profile_uuid_release", ENV_IOS_PROFILE_UUID_RELEASE)) + "\n"; } else if (lines[i].find("$provisioning_profile_uuid_debug") != -1) { - strnew += lines[i].replace("$provisioning_profile_uuid_debug", p_preset->get("application/provisioning_profile_uuid_debug")) + "\n"; + strnew += lines[i].replace("$provisioning_profile_uuid_debug", p_preset->get_or_env("application/provisioning_profile_uuid_debug", ENV_IOS_PROFILE_UUID_DEBUG)) + "\n"; } else if (lines[i].find("$code_sign_style_debug") != -1) { if (dbg_manual) { strnew += lines[i].replace("$code_sign_style_debug", "Manual") + "\n"; @@ -304,7 +304,7 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref &p_ strnew += lines[i].replace("$code_sign_style_release", "Automatic") + "\n"; } } else if (lines[i].find("$provisioning_profile_uuid") != -1) { - String uuid = p_debug ? p_preset->get("application/provisioning_profile_uuid_debug") : p_preset->get("application/provisioning_profile_uuid_release"); + String uuid = p_debug ? p_preset->get_or_env("application/provisioning_profile_uuid_debug", ENV_IOS_PROFILE_UUID_DEBUG) : p_preset->get_or_env("application/provisioning_profile_uuid_release", ENV_IOS_PROFILE_UUID_RELEASE); strnew += lines[i].replace("$provisioning_profile_uuid", uuid) + "\n"; } else if (lines[i].find("$code_sign_identity_debug") != -1) { strnew += lines[i].replace("$code_sign_identity_debug", dbg_sign_id) + "\n"; diff --git a/platform/ios/export/export_plugin.h b/platform/ios/export/export_plugin.h index 0fde3b7c0b72..9afefef121b0 100644 --- a/platform/ios/export/export_plugin.h +++ b/platform/ios/export/export_plugin.h @@ -49,6 +49,11 @@ #include +// Optional environment variables for defining confidential information. If any +// of these is set, they will override the values set in the credentials file. +const String ENV_IOS_PROFILE_UUID_DEBUG = "GODOT_IOS_PROVISIONING_PROFILE_UUID_DEBUG"; +const String ENV_IOS_PROFILE_UUID_RELEASE = "GODOT_IOS_PROVISIONING_PROFILE_UUID_RELEASE"; + class EditorExportPlatformIOS : public EditorExportPlatform { GDCLASS(EditorExportPlatformIOS, EditorExportPlatform); diff --git a/platform/macos/doc_classes/EditorExportPlatformMacOS.xml b/platform/macos/doc_classes/EditorExportPlatformMacOS.xml index f57af3bbd745..64e1efde2699 100644 --- a/platform/macos/doc_classes/EditorExportPlatformMacOS.xml +++ b/platform/macos/doc_classes/EditorExportPlatformMacOS.xml @@ -50,9 +50,11 @@ PKCS #12 certificate file used to sign [code].app[/code] bundle. + Can be overridden with the environment variable [code]GODOT_MACOS_CODESIGN_CERTIFICATE_FILE[/code]. Password for the certificate file used to sign [code].app[/code] bundle. + Can be overridden with the environment variable [code]GODOT_MACOS_CODESIGN_CERTIFICATE_PASSWORD[/code]. Tool to use for code signing. @@ -138,6 +140,7 @@ Provisioning profile file downloaded from Apple developer account dashboard. See [url=https://developer.apple.com/help/account/manage-profiles/edit-download-or-delete-profiles]Edit, download, or delete provisioning profiles[/url]. + Can be overridden with the environment variable [code]GODOT_MACOS_CODESIGN_PROVISIONING_PROFILE[/code]. Path to the custom export template. If left empty, default template is used. @@ -156,18 +159,23 @@ Apple App Store Connect API issuer key file. + Can be overridden with the environment variable [code]GODOT_MACOS_NOTARIZATION_API_KEY[/code]. Apple App Store Connect API issuer key ID. + Can be overridden with the environment variable [code]GODOT_MACOS_NOTARIZATION_API_KEY_ID[/code]. Apple App Store Connect API issuer UUID. + Can be overridden with the environment variable [code]GODOT_MACOS_NOTARIZATION_API_UUID[/code]. Apple ID account name (email address). + Can be overridden with the environment variable [code]GODOT_MACOS_NOTARIZATION_APPLE_ID_NAME[/code]. Apple ID app-specific password. + Can be overridden with the environment variable [code]GODOT_MACOS_NOTARIZATION_APPLE_ID_PASSWORD[/code]. Tool to use for notarization. diff --git a/platform/macos/export/export_plugin.cpp b/platform/macos/export/export_plugin.cpp index cd9d17dd4fc2..be677f4da2ae 100644 --- a/platform/macos/export/export_plugin.cpp +++ b/platform/macos/export/export_plugin.cpp @@ -73,7 +73,7 @@ String EditorExportPlatformMacOS::get_export_option_warning(const EditorExportPr 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(); + ad_hoc = p_preset->get_or_env("codesign/certificate_file", ENV_MAC_CODESIGN_CERT_FILE).operator String().is_empty() || p_preset->get_or_env("codesign/certificate_password", ENV_MAC_CODESIGN_CERT_FILE).operator String().is_empty(); } break; #ifdef MACOS_ENABLED case 3: { // "codesign" @@ -114,7 +114,7 @@ String EditorExportPlatformMacOS::get_export_option_warning(const EditorExportPr } if (p_name == "codesign/provisioning_profile" && dist_type == 2) { - String pprof = p_preset->get("codesign/provisioning_profile"); + String pprof = p_preset->get_or_env("codesign/provisioning_profile", ENV_MAC_CODESIGN_PROFILE); if (pprof.is_empty()) { return TTR("Provisioning profile is required for App Store distribution."); } @@ -154,8 +154,8 @@ String EditorExportPlatformMacOS::get_export_option_warning(const EditorExportPr if (notary_tool == 2 || notary_tool == 3) { if (p_name == "notarization/apple_id_name" || p_name == "notarization/api_uuid") { - String apple_id = p_preset->get("notarization/apple_id_name"); - String api_uuid = p_preset->get("notarization/api_uuid"); + String apple_id = p_preset->get_or_env("notarization/apple_id_name", ENV_MAC_NOTARIZATION_APPLE_ID); + String api_uuid = p_preset->get_or_env("notarization/api_uuid", ENV_MAC_NOTARIZATION_UUID); if (apple_id.is_empty() && api_uuid.is_empty()) { return TTR("Neither Apple ID name nor App Store Connect issuer ID name not specified."); } @@ -164,28 +164,28 @@ String EditorExportPlatformMacOS::get_export_option_warning(const EditorExportPr } } if (p_name == "notarization/apple_id_password") { - String apple_id = p_preset->get("notarization/apple_id_name"); - String apple_pass = p_preset->get("notarization/apple_id_password"); + String apple_id = p_preset->get_or_env("notarization/apple_id_name", ENV_MAC_NOTARIZATION_APPLE_ID); + String apple_pass = p_preset->get_or_env("notarization/apple_id_password", ENV_MAC_NOTARIZATION_APPLE_PASS); if (!apple_id.is_empty() && apple_pass.is_empty()) { return TTR("Apple ID password not specified."); } } if (p_name == "notarization/api_key_id") { - String api_uuid = p_preset->get("notarization/api_uuid"); - String api_key = p_preset->get("notarization/api_key_id"); + String api_uuid = p_preset->get_or_env("notarization/api_uuid", ENV_MAC_NOTARIZATION_UUID); + String api_key = p_preset->get_or_env("notarization/api_key_id", ENV_MAC_NOTARIZATION_KEY_ID); if (!api_uuid.is_empty() && api_key.is_empty()) { return TTR("App Store Connect API key ID not specified."); } } } else if (notary_tool == 1) { if (p_name == "notarization/api_uuid") { - String api_uuid = p_preset->get("notarization/api_uuid"); + String api_uuid = p_preset->get_or_env("notarization/api_uuid", ENV_MAC_NOTARIZATION_UUID); if (api_uuid.is_empty()) { return TTR("App Store Connect issuer ID name not specified."); } } if (p_name == "notarization/api_key_id") { - String api_key = p_preset->get("notarization/api_key_id"); + String api_key = p_preset->get_or_env("notarization/api_key_id", ENV_MAC_NOTARIZATION_KEY_ID); if (api_key.is_empty()) { return TTR("App Store Connect API key ID not specified."); } @@ -398,10 +398,10 @@ void EditorExportPlatformMacOS::get_export_options(List *r_options // "codesign" only options: r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/identity", PROPERTY_HINT_PLACEHOLDER_TEXT, "Type: Name (ID)"), "")); // "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), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/certificate_file", PROPERTY_HINT_GLOBAL_FILE, "*.pfx,*.p12", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/certificate_password", PROPERTY_HINT_PASSWORD, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "")); // "codesign" and "rcodesign" only options: - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/provisioning_profile", PROPERTY_HINT_GLOBAL_FILE, "*.provisionprofile"), "", false, true)); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/provisioning_profile", PROPERTY_HINT_GLOBAL_FILE, "*.provisionprofile", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "", false, true)); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/entitlements/custom_file", PROPERTY_HINT_GLOBAL_FILE, "*.plist"), "", true)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/allow_jit_code_execution"), false)); @@ -434,12 +434,12 @@ void EditorExportPlatformMacOS::get_export_options(List *r_options r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "notarization/notarization", PROPERTY_HINT_ENUM, "Disabled,rcodesign"), 0, true)); #endif // "altool" and "notarytool" only options: - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_id_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Apple ID email"), "", false, true)); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_id_password", PROPERTY_HINT_PASSWORD, "Enable two-factor authentication and provide app-specific password"), "", false, true)); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_id_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Apple ID email", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "", false, true)); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_id_password", PROPERTY_HINT_PASSWORD, "Enable two-factor authentication and provide app-specific password", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "", false, true)); // "altool", "notarytool" and "rcodesign" only options: - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/api_uuid", PROPERTY_HINT_PLACEHOLDER_TEXT, "App Store Connect issuer ID UUID"), "", false, true)); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/api_key", PROPERTY_HINT_GLOBAL_FILE, "*.p8"), "", false, true)); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/api_key_id", PROPERTY_HINT_PLACEHOLDER_TEXT, "App Store Connect API key ID"), "", false, true)); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/api_uuid", PROPERTY_HINT_PLACEHOLDER_TEXT, "App Store Connect issuer ID UUID", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "", false, true)); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/api_key", PROPERTY_HINT_GLOBAL_FILE, "*.p8", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "", false, true)); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/api_key_id", PROPERTY_HINT_PLACEHOLDER_TEXT, "App Store Connect API key ID", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "", false, true)); 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"), "", false, true)); r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/microphone_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); @@ -776,24 +776,24 @@ Error EditorExportPlatformMacOS::_notarize(const Ref &p_pres args.push_back("notary-submit"); - if (p_preset->get("notarization/api_uuid") == "") { + if (p_preset->get_or_env("notarization/api_uuid", ENV_MAC_NOTARIZATION_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") == "") { + if (p_preset->get_or_env("notarization/api_key", ENV_MAC_NOTARIZATION_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(p_preset->get_or_env("notarization/api_uuid", ENV_MAC_NOTARIZATION_UUID)); args.push_back("--api-key"); - args.push_back(p_preset->get("notarization/api_key_id")); + args.push_back(p_preset->get_or_env("notarization/api_key_id", ENV_MAC_NOTARIZATION_KEY_ID)); - if (!p_preset->get("notarization/api_key").operator String().is_empty()) { + if (!p_preset->get_or_env("notarization/api_key", ENV_MAC_NOTARIZATION_KEY).operator String().is_empty()) { args.push_back("--api-key-path"); - args.push_back(p_preset->get("notarization/api_key")); + args.push_back(p_preset->get_or_env("notarization/api_key", ENV_MAC_NOTARIZATION_KEY)); } args.push_back(p_path); @@ -840,40 +840,40 @@ Error EditorExportPlatformMacOS::_notarize(const Ref &p_pres args.push_back(p_path); - if (p_preset->get("notarization/apple_id_name") == "" && p_preset->get("notarization/api_uuid") == "") { + if (p_preset->get_or_env("notarization/apple_id_name", ENV_MAC_NOTARIZATION_APPLE_ID) == "" && p_preset->get_or_env("notarization/api_uuid", ENV_MAC_NOTARIZATION_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") != "") { + if (p_preset->get_or_env("notarization/apple_id_name", ENV_MAC_NOTARIZATION_APPLE_ID) != "" && p_preset->get_or_env("notarization/api_uuid", ENV_MAC_NOTARIZATION_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_id_name") != "") { - if (p_preset->get("notarization/apple_id_password") == "") { + if (p_preset->get_or_env("notarization/apple_id_name", ENV_MAC_NOTARIZATION_APPLE_ID) != "") { + if (p_preset->get_or_env("notarization/apple_id_password", ENV_MAC_NOTARIZATION_APPLE_PASS) == "") { add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("Apple ID password not specified.")); return Error::FAILED; } args.push_back("--apple-id"); - args.push_back(p_preset->get("notarization/apple_id_name")); + args.push_back(p_preset->get_or_env("notarization/apple_id_name", ENV_MAC_NOTARIZATION_APPLE_ID)); args.push_back("--password"); - args.push_back(p_preset->get("notarization/apple_id_password")); + args.push_back(p_preset->get_or_env("notarization/apple_id_password", ENV_MAC_NOTARIZATION_APPLE_PASS)); } else { - if (p_preset->get("notarization/api_key_id") == "") { + if (p_preset->get_or_env("notarization/api_key_id", ENV_MAC_NOTARIZATION_KEY_ID) == "") { add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("App Store Connect API key ID not specified.")); return Error::FAILED; } args.push_back("--issuer"); - args.push_back(p_preset->get("notarization/api_uuid")); + args.push_back(p_preset->get_or_env("notarization/api_uuid", ENV_MAC_NOTARIZATION_UUID)); - if (!p_preset->get("notarization/api_key").operator String().is_empty()) { + if (!p_preset->get_or_env("notarization/api_key", ENV_MAC_NOTARIZATION_KEY).operator String().is_empty()) { args.push_back("--key"); - args.push_back(p_preset->get("notarization/api_key")); + args.push_back(p_preset->get_or_env("notarization/api_key", ENV_MAC_NOTARIZATION_KEY)); } args.push_back("--key-id"); - args.push_back(p_preset->get("notarization/api_key_id")); + args.push_back(p_preset->get_or_env("notarization/api_key_id", ENV_MAC_NOTARIZATION_KEY_ID)); } args.push_back("--no-progress"); @@ -925,35 +925,35 @@ Error EditorExportPlatformMacOS::_notarize(const Ref &p_pres args.push_back("--primary-bundle-id"); args.push_back(p_preset->get("application/bundle_identifier")); - if (p_preset->get("notarization/apple_id_name") == "" && p_preset->get("notarization/api_uuid") == "") { + if (p_preset->get_or_env("notarization/apple_id_name", ENV_MAC_NOTARIZATION_APPLE_ID) == "" && p_preset->get_or_env("notarization/api_uuid", ENV_MAC_NOTARIZATION_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") != "") { + if (p_preset->get_or_env("notarization/apple_id_name", ENV_MAC_NOTARIZATION_APPLE_ID) != "" && p_preset->get_or_env("notarization/api_uuid", ENV_MAC_NOTARIZATION_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_id_name") != "") { - if (p_preset->get("notarization/apple_id_password") == "") { + if (p_preset->get_or_env("notarization/apple_id_name", ENV_MAC_NOTARIZATION_APPLE_ID) != "") { + if (p_preset->get_or_env("notarization/apple_id_password", ENV_MAC_NOTARIZATION_APPLE_PASS) == "") { 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(p_preset->get_or_env("notarization/apple_id_name", ENV_MAC_NOTARIZATION_APPLE_ID)); args.push_back("--password"); - args.push_back(p_preset->get("notarization/apple_id_password")); + args.push_back(p_preset->get_or_env("notarization/apple_id_password", ENV_MAC_NOTARIZATION_APPLE_PASS)); } else { - if (p_preset->get("notarization/api_key") == "") { + if (p_preset->get_or_env("notarization/api_key", ENV_MAC_NOTARIZATION_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")); + args.push_back(p_preset->get_or_env("notarization/api_uuid", ENV_MAC_NOTARIZATION_UUID)); args.push_back("--apiKey"); - args.push_back(p_preset->get("notarization/api_key_id")); + args.push_back(p_preset->get_or_env("notarization/api_key_id", ENV_MAC_NOTARIZATION_KEY_ID)); } args.push_back("--type"); @@ -1032,8 +1032,8 @@ Error EditorExportPlatformMacOS::_code_sign(const Ref &p_pre args.push_back(p_ent_path); } - String certificate_file = p_preset->get("codesign/certificate_file"); - String certificate_pass = p_preset->get("codesign/certificate_password"); + String certificate_file = p_preset->get_or_env("codesign/certificate_file", ENV_MAC_CODESIGN_CERT_FILE); + String certificate_pass = p_preset->get_or_env("codesign/certificate_password", ENV_MAC_CODESIGN_CERT_PASS); if (!certificate_file.is_empty() && !certificate_pass.is_empty()) { args.push_back("--p12-file"); args.push_back(certificate_file); @@ -1763,7 +1763,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref &p 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(); + ad_hoc = p_preset->get_or_env("codesign/certificate_file", ENV_MAC_CODESIGN_CERT_FILE).operator String().is_empty() || p_preset->get_or_env("codesign/certificate_password", ENV_MAC_CODESIGN_CERT_PASS).operator String().is_empty(); } break; #ifdef MACOS_ENABLED case 3: { // "codesign" @@ -1857,7 +1857,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref &p int dist_type = p_preset->get("export/distribution_type"); if (dist_type == 2) { - String pprof = p_preset->get("codesign/provisioning_profile"); + String pprof = p_preset->get_or_env("codesign/provisioning_profile", ENV_MAC_CODESIGN_PROFILE); String teamid = p_preset->get("codesign/apple_team_id"); String bid = p_preset->get("application/bundle_identifier"); if (!pprof.is_empty() && !teamid.is_empty()) { @@ -1990,7 +1990,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref &p if (err == OK && sign_enabled) { int dist_type = p_preset->get("export/distribution_type"); if (dist_type == 2) { - String pprof = p_preset->get("codesign/provisioning_profile").operator String(); + String pprof = p_preset->get_or_env("codesign/provisioning_profile", ENV_MAC_CODESIGN_PROFILE).operator String(); if (!pprof.is_empty()) { Ref da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); err = da->copy(pprof, tmp_app_path_name + "/Contents/embedded.provisionprofile"); @@ -2147,7 +2147,7 @@ bool EditorExportPlatformMacOS::has_valid_project_configuration(const Refget("codesign/certificate_file").operator String().is_empty() || p_preset->get("codesign/certificate_password").operator String().is_empty(); + ad_hoc = p_preset->get_or_env("codesign/certificate_file", ENV_MAC_CODESIGN_CERT_FILE).operator String().is_empty() || p_preset->get_or_env("codesign/certificate_password", ENV_MAC_CODESIGN_CERT_PASS).operator String().is_empty(); } break; #ifdef MACOS_ENABLED case 3: { // "codesign" diff --git a/platform/macos/export/export_plugin.h b/platform/macos/export/export_plugin.h index a8caf535c49a..0477a8c0cc03 100644 --- a/platform/macos/export/export_plugin.h +++ b/platform/macos/export/export_plugin.h @@ -43,6 +43,17 @@ #include +// Optional environment variables for defining confidential information. If any +// of these is set, they will override the values set in the credentials file. +const String ENV_MAC_CODESIGN_CERT_FILE = "GODOT_MACOS_CODESIGN_CERTIFICATE_FILE"; +const String ENV_MAC_CODESIGN_CERT_PASS = "GODOT_MACOS_CODESIGN_CERTIFICATE_PASSWORD"; +const String ENV_MAC_CODESIGN_PROFILE = "GODOT_MACOS_CODESIGN_PROVISIONING_PROFILE"; +const String ENV_MAC_NOTARIZATION_UUID = "GODOT_MACOS_NOTARIZATION_API_UUID"; +const String ENV_MAC_NOTARIZATION_KEY = "GODOT_MACOS_NOTARIZATION_API_KEY"; +const String ENV_MAC_NOTARIZATION_KEY_ID = "GODOT_MACOS_NOTARIZATION_API_KEY_ID"; +const String ENV_MAC_NOTARIZATION_APPLE_ID = "GODOT_MACOS_NOTARIZATION_APPLE_ID_NAME"; +const String ENV_MAC_NOTARIZATION_APPLE_PASS = "GODOT_MACOS_NOTARIZATION_APPLE_ID_PASSWORD"; + class EditorExportPlatformMacOS : public EditorExportPlatform { GDCLASS(EditorExportPlatformMacOS, EditorExportPlatform); diff --git a/platform/uwp/export/export_plugin.cpp b/platform/uwp/export/export_plugin.cpp index 163236e50642..aac61184b113 100644 --- a/platform/uwp/export/export_plugin.cpp +++ b/platform/uwp/export/export_plugin.cpp @@ -80,8 +80,8 @@ void EditorExportPlatformUWP::get_export_options(List *r_options) r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "identity/product_guid", PROPERTY_HINT_PLACEHOLDER_TEXT, "00000000-0000-0000-0000-000000000000"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "identity/publisher_guid", PROPERTY_HINT_PLACEHOLDER_TEXT, "00000000-0000-0000-0000-000000000000"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "signing/certificate", PROPERTY_HINT_GLOBAL_FILE, "*.pfx"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "signing/password"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "signing/certificate", PROPERTY_HINT_GLOBAL_FILE, "*.pfx", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "signing/password", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "signing/algorithm", PROPERTY_HINT_ENUM, "MD5,SHA1,SHA256"), 2)); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/major"), 1)); @@ -465,8 +465,8 @@ Error EditorExportPlatformUWP::export_project(const Ref &p_p int cert_alg = EDITOR_GET("export/uwp/debug_algorithm"); if (!p_debug) { - cert_path = p_preset->get("signing/certificate"); - cert_pass = p_preset->get("signing/password"); + cert_path = p_preset->get_or_env("signing/certificate", ENV_UWP_SIGNING_CERT); + cert_pass = p_preset->get_or_env("signing/password", ENV_UWP_SIGNING_PASS); cert_alg = p_preset->get("signing/algorithm"); } diff --git a/platform/uwp/export/export_plugin.h b/platform/uwp/export/export_plugin.h index 37a32b1f7f7e..b42a2ae6d99e 100644 --- a/platform/uwp/export/export_plugin.h +++ b/platform/uwp/export/export_plugin.h @@ -85,6 +85,11 @@ static const char *uwp_device_capabilities[] = { nullptr }; +// Optional environment variables for defining confidential information. If any +// of these is set, they will override the values set in the credentials file. +const String ENV_UWP_SIGNING_CERT = "GODOT_UWP_SIGNING_CERTIFICATE"; +const String ENV_UWP_SIGNING_PASS = "GODOT_UWP_SIGNING_PASSWORD"; + class EditorExportPlatformUWP : public EditorExportPlatform { GDCLASS(EditorExportPlatformUWP, EditorExportPlatform); diff --git a/platform/windows/doc_classes/EditorExportPlatformWindows.xml b/platform/windows/doc_classes/EditorExportPlatformWindows.xml index fee8a118bc56..ec2b105f5809 100644 --- a/platform/windows/doc_classes/EditorExportPlatformWindows.xml +++ b/platform/windows/doc_classes/EditorExportPlatformWindows.xml @@ -64,12 +64,15 @@ PKCS #12 certificate file used to sign executable or certificate SHA-1 hash (if [member codesign/identity_type] is set to "Use certificate store"). See [url=https://learn.microsoft.com/en-us/dotnet/framework/tools/signtool-exe]Sign Tool[/url]. + Can be overridden with the environment variable [code]GODOT_WINDOWS_CODESIGN_IDENTITY[/code]. Type of identity to use. See [url=https://learn.microsoft.com/en-us/dotnet/framework/tools/signtool-exe]Sign Tool[/url]. + Can be overridden with the environment variable [code]GODOT_WINDOWS_CODESIGN_IDENTITY_TYPE[/code]. Password for the certificate file used to sign executable. See [url=https://learn.microsoft.com/en-us/dotnet/framework/tools/signtool-exe]Sign Tool[/url]. + Can be overridden with the environment variable [code]GODOT_WINDOWS_CODESIGN_PASSWORD[/code]. If [code]true[/code], time-stamp is added to the signature. See [url=https://learn.microsoft.com/en-us/dotnet/framework/tools/signtool-exe]Sign Tool[/url]. diff --git a/platform/windows/export/export_plugin.cpp b/platform/windows/export/export_plugin.cpp index 1863a3083b71..ca390236fb77 100644 --- a/platform/windows/export/export_plugin.cpp +++ b/platform/windows/export/export_plugin.cpp @@ -328,9 +328,9 @@ void EditorExportPlatformWindows::get_export_options(List *r_optio r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "binary_format/architecture", PROPERTY_HINT_ENUM, "x86_64,x86_32,arm64"), "x86_64")); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/enable"), false, true)); - 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 SHA-1 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", PROPERTY_HINT_PASSWORD), "")); + 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 SHA-1 hash)", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), 0)); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/identity", PROPERTY_HINT_GLOBAL_FILE, "*.pfx,*.p12", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/password", PROPERTY_HINT_PASSWORD, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "")); 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)); @@ -518,21 +518,21 @@ Error EditorExportPlatformWindows::_code_sign(const Ref &p_p //identity #ifdef WINDOWS_ENABLED - int id_type = p_preset->get("codesign/identity_type"); + int id_type = p_preset->get_or_env("codesign/identity_type", ENV_WIN_CODESIGN_ID_TYPE); if (id_type == 0) { //auto select args.push_back("/a"); } else if (id_type == 1) { //pkcs12 - if (p_preset->get("codesign/identity") != "") { + if (p_preset->get_or_env("codesign/identity", ENV_WIN_CODESIGN_ID) != "") { args.push_back("/f"); - args.push_back(p_preset->get("codesign/identity")); + args.push_back(p_preset->get_or_env("codesign/identity", ENV_WIN_CODESIGN_ID)); } else { add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("No identity found.")); return FAILED; } } else if (id_type == 2) { //Windows certificate store - if (p_preset->get("codesign/identity") != "") { + if (p_preset->get_or_env("codesign/identity", ENV_WIN_CODESIGN_ID) != "") { args.push_back("/sha1"); - args.push_back(p_preset->get("codesign/identity")); + args.push_back(p_preset->get_or_env("codesign/identity", ENV_WIN_CODESIGN_ID)); } else { add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("No identity found.")); return FAILED; @@ -543,9 +543,9 @@ Error EditorExportPlatformWindows::_code_sign(const Ref &p_p } #else int id_type = 1; - if (p_preset->get("codesign/identity") != "") { + if (p_preset->get_or_env("codesign/identity", ENV_WIN_CODESIGN_ID) != "") { args.push_back("-pkcs12"); - args.push_back(p_preset->get("codesign/identity")); + args.push_back(p_preset->get_or_env("codesign/identity", ENV_WIN_CODESIGN_ID)); } else { add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("No identity found.")); return FAILED; @@ -553,13 +553,13 @@ Error EditorExportPlatformWindows::_code_sign(const Ref &p_p #endif //password - if ((id_type == 1) && (p_preset->get("codesign/password") != "")) { + if ((id_type == 1) && (p_preset->get_or_env("codesign/password", ENV_WIN_CODESIGN_PASS) != "")) { #ifdef WINDOWS_ENABLED args.push_back("/p"); #else args.push_back("-pass"); #endif - args.push_back(p_preset->get("codesign/password")); + args.push_back(p_preset->get_or_env("codesign/password", ENV_WIN_CODESIGN_PASS)); } //timestamp diff --git a/platform/windows/export/export_plugin.h b/platform/windows/export/export_plugin.h index c466971202bf..184b2f96f8c5 100644 --- a/platform/windows/export/export_plugin.h +++ b/platform/windows/export/export_plugin.h @@ -36,6 +36,12 @@ #include "editor/editor_settings.h" #include "editor/export/editor_export_platform_pc.h" +// Optional environment variables for defining confidential information. If any +// of these is set, they will override the values set in the credentials file. +const String ENV_WIN_CODESIGN_ID_TYPE = "GODOT_WINDOWS_CODESIGN_IDENTITY_TYPE"; +const String ENV_WIN_CODESIGN_ID = "GODOT_WINDOWS_CODESIGN_IDENTITY"; +const String ENV_WIN_CODESIGN_PASS = "GODOT_WINDOWS_CODESIGN_PASSWORD"; + class EditorExportPlatformWindows : public EditorExportPlatformPC { GDCLASS(EditorExportPlatformWindows, EditorExportPlatformPC);