Fix #102300: SSL/HTTPS Request Unable to Get Local Issuer Certificate

Resolve an error with SSL using a hard coded path to certificates on
Linux causing HTTPS access to fail.
request.urlopen(..) couldn't access any HTTPS URL's.
This commit is contained in:
Campbell Barton
2023-10-17 19:05:40 +11:00
parent d7e501ce3b
commit 5ac392ca40
3 changed files with 103 additions and 0 deletions

View File

@@ -59,6 +59,13 @@ macro(path_ensure_trailing_slash
unset(_path_sep)
endmacro()
macro(path_strip_trailing_slash
path_new path_input
)
file(TO_NATIVE_PATH "/" _path_sep)
string(REGEX REPLACE "[${_path_sep}]+$" "" ${path_new} ${path_input})
endmacro()
# Our own version of `cmake_path(IS_PREFIX ..)`.
# This can be removed when 3.20 or greater is the minimum supported version.
macro(path_is_prefix
@@ -1404,6 +1411,68 @@ Path to python site-packages or dist-packages containing '${package}' module hea
endif()
endfunction()
# Find a file in Python's module path and cache it.
# Re-generating cache upon changes to the Python installation.
# `out_var_abs`: absolute path (cached).
# `out_var_rel`: `PYTHON_ROOT` relative path (not cached).
macro(find_python_module_file
module_file
out_var_abs
out_var_rel
)
# Reset if the file isn't found.
if(DEFINED ${out_var_abs})
if(NOT EXISTS ${${out_var_abs}})
unset(${out_var_abs} CACHE)
endif()
endif()
# Reset if the version number or Python path changes.
set(_python_mod_file_deps_test "${PYTHON_LIBPATH};${PYTHON_VERSION}")
if(DEFINED _${out_var_abs}_DEPS)
if(NOT (_${out_var_abs}_DEPS STREQUAL _python_mod_file_deps_test))
unset(${out_var_abs} CACHE)
endif()
else()
unset(${out_var_abs} CACHE)
endif()
path_strip_trailing_slash(_python_root "${PYTHON_LIBPATH}")
set(_python_base "${_python_root}/python${PYTHON_VERSION}")
get_filename_component(_python_root "${_python_root}" DIRECTORY)
path_ensure_trailing_slash(_python_root "${_python_root}")
if(NOT (DEFINED ${out_var_abs}))
message(STATUS "Finding Python Module File: ${module_file}")
find_file(${out_var_abs}
NAMES
"${module_file}"
PATHS
"${_python_base}"
PATH_SUFFIXES
"site-packages"
"dist-packages"
"vendor-packages"
""
NO_DEFAULT_PATH
)
if(${out_var_abs})
set(_${out_var_abs}_DEPS "${_python_mod_file_deps_test}" CACHE STRING "")
# This always moves up one level (even if there is a trailing slash).
string(LENGTH "${_python_root}" _python_root_len)
string(SUBSTRING ${${out_var_abs}} ${_python_root_len} -1 ${out_var_rel})
unset(_python_root_len)
endif()
endif()
unset(_python_mod_file_deps_test)
unset(_python_base)
unset(_python_root)
endmacro()
# like Python's 'print(dir())'
function(print_all_vars)
get_cmake_property(_vars VARIABLES)

View File

@@ -141,6 +141,28 @@ if(WITH_PYTHON_MODULE)
add_definitions(-DWITH_PYTHON_MODULE)
endif()
# Find the SSL certificate for the portable Blender installation.
# Without this, the absolute path on the builder is used, causing HTTPS access to fail.
# For example `urllib.request.urlopen("https://projects.blender.org")` fails
# (or any other HTTPS site). see: #102300 for details.
# NOTE: that this isn't necessary on WIN32.
if(WITH_PYTHON AND WITH_PYTHON_INSTALL AND WITH_INSTALL_PORTABLE AND (NOT WIN32))
# - `PYTHON_SSL_CERT_FILE` absolute path to the PEM file.
find_python_module_file("certifi/cacert.pem" PYTHON_SSL_CERT_FILE _python_ssl_cert_file_relative)
mark_as_advanced(PYTHON_SSL_CERT_FILE)
if (PYTHON_SSL_CERT_FILE)
# This always moves up one level (even if there is a trailing slash).
add_definitions(-DPYTHON_SSL_CERT_FILE="${_python_ssl_cert_file_relative}")
else()
message(WARNING
"Unable to find \"certifi/cacert.pem\" within \"${PYTHON_LIBPATH}\", "
"this build will not be able to use bundled certificates with the \"ssl\" module!"
)
endif()
unset(_python_ssl_cert_file_relative)
endif()
if(WITH_PYTHON_SAFETY)
add_definitions(-DWITH_PYTHON_SAFETY)
endif()

View File

@@ -450,6 +450,18 @@ void BPY_python_start(bContext *C, int argc, const char **argv)
status = PyConfig_SetBytesString(&config, &config.home, py_path_bundle);
pystatus_exit_on_error(status);
# ifdef PYTHON_SSL_CERT_FILE
/* Point to the portable SSL certificate to support HTTPS access, see: #102300. */
const char *ssl_cert_file_env = "SSL_CERT_FILE";
if (BLI_getenv(ssl_cert_file_env) == nullptr) {
const char *ssl_cert_file_suffix = PYTHON_SSL_CERT_FILE;
char ssl_cert_file[FILE_MAX];
BLI_path_join(
ssl_cert_file, sizeof(ssl_cert_file), py_path_bundle, ssl_cert_file_suffix);
BLI_setenv(ssl_cert_file_env, ssl_cert_file);
}
# endif /* PYTHON_SSL_CERT_FILE */
}
else {
/* Common enough to use the system Python on Linux/Unix, warn on other systems. */