Store sensitive export options in dedicated credentials file
This commit is contained in:
parent
668cf3c66f
commit
fab160ce70
22 changed files with 211 additions and 105 deletions
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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() {}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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]).
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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].
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue