diff options
author | Andreas Raddau <and.rad@posteo.de> | 2023-05-10 11:40:17 +0200 |
---|---|---|
committer | Andreas Raddau <and.rad@posteo.de> | 2023-05-10 11:40:17 +0200 |
commit | fab160ce70fffa4fc1eed302c4ddd2a9c7882c93 (patch) | |
tree | 94e54926f77875477633ee3823cd520d8c0d6a25 | |
parent | 668cf3c66f42989949399f36e9faa29426e37416 (diff) | |
download | redot-engine-fab160ce70fffa4fc1eed302c4ddd2a9c7882c93.tar.gz |
Store sensitive export options in dedicated credentials file
22 files changed, 211 insertions, 105 deletions
diff --git a/core/core_constants.cpp b/core/core_constants.cpp index d88dda6609..ceab71ff2e 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 ed2c625417..2e709d6ffe 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 a0b623936a..b98d9adcec 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -2842,6 +2842,9 @@ <constant name="PROPERTY_USAGE_READ_ONLY" value="268435456" enum="PropertyUsageFlags" is_bitfield="true"> The property is read-only in the [EditorInspector]. </constant> + <constant name="PROPERTY_USAGE_SECRET" value="536870912" enum="PropertyUsageFlags" is_bitfield="true"> + An export preset property with this flag contains confidential information and is stored separately from the rest of the export preset configuration. + </constant> <constant name="PROPERTY_USAGE_DEFAULT" value="6" enum="PropertyUsageFlags" is_bitfield="true"> Default usage (storage, editor and network). </constant> diff --git a/editor/export/editor_export.cpp b/editor/export/editor_export.cpp index 3f192342a1..c6faefc45f 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<ConfigFile> config; + Ref<ConfigFile> credentials; config.instantiate(); + credentials.instantiate(); for (int i = 0; i < export_presets.size(); i++) { Ref<EditorExportPreset> 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<ConfigFile> 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<String> 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 670f5af713..65ffa45b38 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<EditorExportPreset> &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<String> EditorExportPlatform::get_forced_export_files() { Vector<String> files; @@ -946,7 +954,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & } // 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<EditorExportPreset> &p_preset, b Ref<FileAccess> 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<uint8_t> 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 df5a66f099..3b9663ebdf 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<Ref<EditorExportPlugin>> &customize_resources_plugins, LocalVector<Ref<EditorExportPlugin>> &customize_scenes_plugins, HashMap<String, FileExportCache> &export_cache, const String &export_base_path, bool p_force_save); + String _get_script_encryption_key(const Ref<EditorExportPreset> &p_preset) const; protected: struct ExportNotifier { diff --git a/editor/export/editor_export_preset.cpp b/editor/export/editor_export_preset.cpp index ac93479605..2aca19a2ad 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 003e3c05a3..194858b4e8 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<PropertyInfo> &get_properties() const { return properties; } EditorExportPreset(); diff --git a/platform/android/doc_classes/EditorExportPlatformAndroid.xml b/platform/android/doc_classes/EditorExportPlatformAndroid.xml index 1a07774287..11129ca149 100644 --- a/platform/android/doc_classes/EditorExportPlatformAndroid.xml +++ b/platform/android/doc_classes/EditorExportPlatformAndroid.xml @@ -58,21 +58,27 @@ </member> <member name="keystore/debug" type="String" setter="" getter=""> Path of the debug keystore file. + Can be overridden with the environment variable [code]GODOT_ANDROID_KEYSTORE_DEBUG_PATH[/code]. </member> <member name="keystore/debug_password" type="String" setter="" getter=""> Password for the debug keystore file. + Can be overridden with the environment variable [code]GODOT_ANDROID_KEYSTORE_DEBUG_PASSWORD[/code]. </member> <member name="keystore/debug_user" type="String" setter="" getter=""> User name for the debug keystore file. + Can be overridden with the environment variable [code]GODOT_ANDROID_KEYSTORE_DEBUG_USER[/code]. </member> <member name="keystore/release" type="String" setter="" getter=""> Path of the release keystore file. + Can be overridden with the environment variable [code]GODOT_ANDROID_KEYSTORE_RELEASE_PATH[/code]. </member> <member name="keystore/release_password" type="String" setter="" getter=""> Password for the release keystore file. + Can be overridden with the environment variable [code]GODOT_ANDROID_KEYSTORE_RELEASE_PASSWORD[/code]. </member> <member name="keystore/release_user" type="String" setter="" getter=""> User name for the release keystore file. + Can be overridden with the environment variable [code]GODOT_ANDROID_KEYSTORE_RELEASE_USER[/code]. </member> <member name="launcher_icons/adaptive_background_432x432" type="String" setter="" getter=""> 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 87f4cf2de2..d8dd453faf 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<ExportOption> *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 Ref<Edito // Validate the rest of the export configuration. - String dk = p_preset->get("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 Ref<Edito } } - String rk = p_preset->get("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<EditorExportP Error EditorExportPlatformAndroid::sign_apk(const Ref<EditorExportPreset> &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<EditorExportPreset> &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 Ref<EditorExportP if (should_sign) { if (p_debug) { - String debug_keystore = p_preset->get("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 Ref<EditorExportP cmdline.push_back("-Pdebug_keystore_password=" + debug_password); // argument to specify the debug keystore password. } else { // Pass the release keystore info as well - 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); 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 f9dad5ce5e..390b8c6465 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(<?xml version="1.0" encoding=" </layer-list> )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 ef2b0a256d..70b999eb0f 100644 --- a/platform/ios/doc_classes/EditorExportPlatformIOS.xml +++ b/platform/ios/doc_classes/EditorExportPlatformIOS.xml @@ -35,9 +35,11 @@ </member> <member name="application/provisioning_profile_uuid_debug" type="String" setter="" getter=""> 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]. </member> <member name="application/provisioning_profile_uuid_release" type="String" setter="" getter=""> 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]. </member> <member name="application/short_version" type="String" setter="" getter=""> 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 9c0e4e39e8..06741a12e4 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<ExportOption> *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<EditorExportPreset> &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<EditorExportPreset> &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<EditorExportPreset> &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 0fde3b7c0b..9afefef121 100644 --- a/platform/ios/export/export_plugin.h +++ b/platform/ios/export/export_plugin.h @@ -49,6 +49,11 @@ #include <sys/stat.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_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 f57af3bbd7..64e1efde26 100644 --- a/platform/macos/doc_classes/EditorExportPlatformMacOS.xml +++ b/platform/macos/doc_classes/EditorExportPlatformMacOS.xml @@ -50,9 +50,11 @@ </member> <member name="codesign/certificate_file" type="String" setter="" getter=""> 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]. </member> <member name="codesign/certificate_password" type="String" setter="" getter=""> 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]. </member> <member name="codesign/codesign" type="int" setter="" getter=""> Tool to use for code signing. @@ -138,6 +140,7 @@ </member> <member name="codesign/provisioning_profile" type="String" setter="" getter=""> 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]. </member> <member name="custom_template/debug" type="String" setter="" getter=""> Path to the custom export template. If left empty, default template is used. @@ -156,18 +159,23 @@ </member> <member name="notarization/api_key" type="String" setter="" getter=""> Apple App Store Connect API issuer key file. + Can be overridden with the environment variable [code]GODOT_MACOS_NOTARIZATION_API_KEY[/code]. </member> <member name="notarization/api_key_id" type="String" setter="" getter=""> Apple App Store Connect API issuer key ID. + Can be overridden with the environment variable [code]GODOT_MACOS_NOTARIZATION_API_KEY_ID[/code]. </member> <member name="notarization/api_uuid" type="String" setter="" getter=""> Apple App Store Connect API issuer UUID. + Can be overridden with the environment variable [code]GODOT_MACOS_NOTARIZATION_API_UUID[/code]. </member> <member name="notarization/apple_id_name" type="String" setter="" getter=""> Apple ID account name (email address). + Can be overridden with the environment variable [code]GODOT_MACOS_NOTARIZATION_APPLE_ID_NAME[/code]. </member> <member name="notarization/apple_id_password" type="String" setter="" getter=""> Apple ID app-specific password. + Can be overridden with the environment variable [code]GODOT_MACOS_NOTARIZATION_APPLE_ID_PASSWORD[/code]. </member> <member name="notarization/notarization" type="int" setter="" getter=""> Tool to use for notarization. diff --git a/platform/macos/export/export_plugin.cpp b/platform/macos/export/export_plugin.cpp index cd9d17dd4f..be677f4da2 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<ExportOption> *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<ExportOption> *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<EditorExportPreset> &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<EditorExportPreset> &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<EditorExportPreset> &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<EditorExportPreset> &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<EditorExportPreset> &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<EditorExportPreset> &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<EditorExportPreset> &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<DirAccess> 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 Ref<Editor 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" diff --git a/platform/macos/export/export_plugin.h b/platform/macos/export/export_plugin.h index a8caf535c4..0477a8c0cc 100644 --- a/platform/macos/export/export_plugin.h +++ b/platform/macos/export/export_plugin.h @@ -43,6 +43,17 @@ #include <sys/stat.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_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 163236e506..aac61184b1 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<ExportOption> *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<EditorExportPreset> &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 37a32b1f7f..b42a2ae6d9 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 fee8a118bc..ec2b105f58 100644 --- a/platform/windows/doc_classes/EditorExportPlatformWindows.xml +++ b/platform/windows/doc_classes/EditorExportPlatformWindows.xml @@ -64,12 +64,15 @@ </member> <member name="codesign/identity" type="String" setter="" getter=""> 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]. </member> <member name="codesign/identity_type" type="int" setter="" getter=""> 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]. </member> <member name="codesign/password" type="String" setter="" getter=""> 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]. </member> <member name="codesign/timestamp" type="bool" setter="" getter=""> 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 1863a3083b..ca390236fb 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<ExportOption> *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<EditorExportPreset> &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<EditorExportPreset> &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<EditorExportPreset> &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 c466971202..184b2f96f8 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); |