Preference: add option allow internet access

Add a preference to "Work Offline" system preference as well as command
line options `--offline-mode` & `--online-mode`
(which overrides the preference).
This option is displayed in the initial setup screen too.

This is currently respected by:

- Check for updates on startup
- Disables running an update when enabling extensions.

When Blender is launched with `--offline-mode` the option cannot be
enabled in the preferences. This is intended for environments
where internet access is intentionally disallowed.

Background: with Blender supporting access to online-repositories
as well as 3rd party extensions themselves potentially accessing the
internet. This setting provides a way for users to disable online
functionality.

This prevents error messages when online access fails in environments
without internet access as well as the ability for users who prefer
Blender doesn't access the internet to have one place to turn this off.

While it does not enforce limitations on add-ons, 3rd party scripts
are expected to respect this setting using `bpy.app.internet_offline`.

The details for this will be handled along with other policies scripts
are expected to follow.

Ref !121994
This commit is contained in:
Campbell Barton 2024-05-20 10:32:39 +10:00
parent 3b21b0deb1
commit 57c023d580
12 changed files with 158 additions and 10 deletions

View File

@ -143,6 +143,7 @@ def repos_to_notify():
# Since it's not all that common to disable the status bar just run notifications
# if any repositories are marked to run notifications.
online_access = bpy.app.online_access
prefs = bpy.context.preferences
extension_repos = prefs.extensions.repos
for repo_item in extension_repos:
@ -152,9 +153,19 @@ def repos_to_notify():
continue
if not repo_item.use_remote_url:
continue
remote_url = repo_item.remote_url
# Invalid, if there is no remote path this can't update.
if not repo_item.remote_url:
if not remote_url:
continue
if online_access:
# All URL's may be accessed.
pass
else:
# Allow remote file-system repositories even when online access is disabled.
if not remote_url.startswith("file://"):
continue
repos_notify.append(repo_item)
return repos_notify

View File

@ -2274,10 +2274,11 @@ class BlPkgOnlineAccess(Operator):
# While not expected, we want to know if this ever occurs, don't fail silently.
self.report({'WARNING'}, "Repository \"{:s}\" not found!".format(remote_url))
# Run the first check for updates automatically.
# Invoke the modal operator so users can cancel by pressing "Escape".
assert bpy.ops.bl_pkg.repo_sync_all.poll()
bpy.ops.bl_pkg.repo_sync_all('INVOKE_DEFAULT')
if bpy.app.online_access:
# Run the first check for updates automatically.
# Invoke the modal operator so users can cancel by pressing "Escape".
assert bpy.ops.bl_pkg.repo_sync_all.poll()
bpy.ops.bl_pkg.repo_sync_all('INVOKE_DEFAULT')
prefs.extensions.use_online_access_handled = True

View File

@ -299,7 +299,7 @@ def extensions_panel_draw_online_extensions_request_impl(
"Welcome! Access community-made add-ons and themes from the",
"extensions.blender.org repository.",
"",
"This requires internet access.",
"This also requires internet access which must be enabled in \"System\" preferences.",
):
layout_panel.label(text=line)

View File

@ -3288,6 +3288,9 @@ class WM_MT_splash_quick_setup(Menu):
if hasattr(kc_prefs, "spacebar_action"):
col.row().prop(kc_prefs, "spacebar_action", text="Spacebar Action")
# Network.
col.row().prop(prefs.system, "use_online_access")
# Save Preferences.
sub = col.column()
sub.separator(factor=2)

View File

@ -739,6 +739,28 @@ class USERPREF_PT_system_memory(SystemPanel, CenterAlignMixIn, Panel):
col.prop(system, "vbo_collection_rate", text="Garbage Collection Rate")
class USERPREF_PT_system_network(SystemPanel, CenterAlignMixIn, Panel):
bl_label = "Network"
def draw_centered(self, context, layout):
prefs = context.preferences
system = prefs.system
row = layout.row()
row.prop(system, "use_online_access", text="Allow Online Access")
# Show when the preference has been overridden and doesn't match the current preference.
runtime_online_access = bpy.app.online_access
if system.use_online_access != runtime_online_access:
row = layout.split(factor=0.4)
row.label(text="")
row.label(
text="{:s} on startup, overriding the preference.".format(
"Enabled" if runtime_online_access else "Disabled"
),
)
class USERPREF_PT_system_video_sequencer(SystemPanel, CenterAlignMixIn, Panel):
bl_label = "Video Sequencer"
@ -2829,6 +2851,7 @@ classes = (
USERPREF_PT_system_os_settings,
USERPREF_PT_system_memory,
USERPREF_PT_system_video_sequencer,
USERPREF_PT_system_network,
USERPREF_PT_system_sound,
USERPREF_MT_interface_theme_presets,

View File

@ -185,6 +185,26 @@ enum {
G_FLAG_EVENT_SIMULATE = (1 << 3),
G_FLAG_USERPREF_NO_SAVE_ON_EXIT = (1 << 4),
/**
* Internet access is allowed (offline mode when disabled).
*
* \note This setting doesn't prevent network access, rather it is a setting to
* disallow built-in utilities and 3rd party scripts from accessing the internet.
* While this isn't enforced, it is considered a bug when any script sends or receives
* data over the internet while this flag is set.
*/
G_FLAG_INTERNET_ALLOW = (1 << 10),
/* NOTE: storing both online/offline override is needed so changing the preference
* can be disabled when launching Blender with `--offline-mode`.
* This means that users in a controlled environment can launch
* in offline-mode and the option can't be changed afterwards. */
/** Launched with `--offline-mode` (overrides #USER_INTERNET_ALLOW when set). */
G_FLAG_INTERNET_OVERRIDE_PREF_ONLINE = (1 << 11),
/** Launched with `--offline-mode` (overrides #USER_INTERNET_ALLOW when set). */
G_FLAG_INTERNET_OVERRIDE_PREF_OFFLINE = (1 << 12),
G_FLAG_SCRIPT_AUTOEXEC = (1 << 13),
/** When this flag is set ignore the preferences #USER_SCRIPT_AUTOEXEC_DISABLE. */
G_FLAG_SCRIPT_OVERRIDE_PREF = (1 << 14),
@ -192,10 +212,14 @@ enum {
G_FLAG_SCRIPT_AUTOEXEC_FAIL_QUIET = (1 << 16),
};
#define G_FLAG_INTERNET_OVERRIDE_PREF_ANY \
(G_FLAG_INTERNET_OVERRIDE_PREF_ONLINE | G_FLAG_INTERNET_OVERRIDE_PREF_OFFLINE)
/** Don't overwrite these flags when reading a file. */
#define G_FLAG_ALL_RUNTIME \
(G_FLAG_SCRIPT_AUTOEXEC | G_FLAG_SCRIPT_OVERRIDE_PREF | G_FLAG_EVENT_SIMULATE | \
G_FLAG_USERPREF_NO_SAVE_ON_EXIT | \
(G_FLAG_SCRIPT_AUTOEXEC | G_FLAG_SCRIPT_OVERRIDE_PREF | G_FLAG_INTERNET_ALLOW | \
G_FLAG_INTERNET_OVERRIDE_PREF_ONLINE | G_FLAG_INTERNET_OVERRIDE_PREF_OFFLINE | \
G_FLAG_EVENT_SIMULATE | G_FLAG_USERPREF_NO_SAVE_ON_EXIT | \
\
/* #BPY_python_reset is responsible for resetting these flags on file load. */ \
G_FLAG_SCRIPT_AUTOEXEC_FAIL | G_FLAG_SCRIPT_AUTOEXEC_FAIL_QUIET)

View File

@ -511,7 +511,7 @@ void blo_do_versions_userdef(UserDef *userdef)
if (!USER_VERSION_ATLEAST(278, 6)) {
/* Clear preference flags for re-use. */
userdef->flag &= ~(USER_FLAG_NUMINPUT_ADVANCED | (1 << 2) | USER_FLAG_UNUSED_3 |
USER_FLAG_UNUSED_6 | USER_FLAG_UNUSED_7 | USER_FLAG_UNUSED_9 |
USER_FLAG_UNUSED_6 | USER_FLAG_UNUSED_7 | USER_INTERNET_ALLOW |
USER_DEVELOPER_UI);
userdef->uiflag &= ~(USER_HEADER_BOTTOM);
userdef->transopts &= ~(USER_TR_UNUSED_3 | USER_TR_UNUSED_4 | USER_TR_UNUSED_6 |

View File

@ -1154,7 +1154,7 @@ typedef enum eUserPref_Flag {
USER_FLAG_UNUSED_6 = (1 << 6), /* cleared */
USER_FLAG_UNUSED_7 = (1 << 7), /* cleared */
USER_MAT_ON_OB = (1 << 8),
USER_FLAG_UNUSED_9 = (1 << 9), /* cleared */
USER_INTERNET_ALLOW = (1 << 9),
USER_DEVELOPER_UI = (1 << 10),
USER_TOOLTIPS = (1 << 11),
USER_TWOBUTTONMOUSE = (1 << 12),

View File

@ -454,6 +454,33 @@ static void rna_userdef_script_autoexec_update(Main * /*bmain*/,
USERDEF_TAG_DIRTY;
}
int rna_userdef_use_online_access_editable(const PointerRNA * /*ptr*/, const char **r_info)
{
if ((G.f & G_FLAG_INTERNET_ALLOW) == 0) {
/* Return 0 when blender was invoked with `--offline-mode` "forced". */
if (G.f & G_FLAG_INTERNET_OVERRIDE_PREF_OFFLINE) {
*r_info = "Launched with \"--offline-mode\", cannot be changed";
return 0;
}
}
return PROP_EDITABLE;
}
static void rna_userdef_use_online_access_update(Main * /*bmain*/,
Scene * /*scene*/,
PointerRNA *ptr)
{
UserDef *userdef = (UserDef *)ptr->data;
if (userdef->flag & USER_INTERNET_ALLOW) {
G.f |= G_FLAG_INTERNET_ALLOW;
}
else {
G.f &= ~G_FLAG_INTERNET_ALLOW;
}
USERDEF_TAG_DIRTY;
}
static void rna_userdef_script_directory_name_set(PointerRNA *ptr, const char *value)
{
bUserScriptDirectory *script_dir = static_cast<bUserScriptDirectory *>(ptr->data);
@ -6144,6 +6171,18 @@ static void rna_def_userdef_system(BlenderRNA *brna)
"GPU Backend",
"GPU backend to use (requires restarting Blender for changes to take effect)");
/* Network. */
prop = RNA_def_property(srna, "use_online_access", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "flag", USER_INTERNET_ALLOW);
RNA_def_property_ui_text(
prop,
"Allow Online Access",
"Allow internet access. Blender may access configured online extension repositories. "
"Installed third party add-ons may access the internet for their own functionality");
RNA_def_property_editable_func(prop, "rna_userdef_use_online_access_editable");
RNA_def_property_update(prop, 0, "rna_userdef_use_online_access_update");
/* Audio */
prop = RNA_def_property(srna, "audio_mixing_buffer", PROP_ENUM, PROP_NONE);

View File

@ -253,6 +253,11 @@ static int bpy_app_debug_set(PyObject * /*self*/, PyObject *value, void *closure
return 0;
}
PyDoc_STRVAR(
/* Wrap. */
bpy_app_internet_offline_doc,
"Boolean, true when internet access is allowed by Blender & 3rd party scripts (read-only)");
PyDoc_STRVAR(
/* Wrap. */
bpy_app_global_flag_doc,
@ -487,6 +492,12 @@ static PyGetSetDef bpy_app_getsets[] = {
bpy_app_preview_render_size_doc,
(void *)ICON_SIZE_PREVIEW},
{"online_access",
bpy_app_global_flag_get,
nullptr,
bpy_app_internet_offline_doc,
(void *)G_FLAG_INTERNET_ALLOW},
/* security */
{"autoexec_fail",
bpy_app_global_flag_get,

View File

@ -489,6 +489,11 @@ static void wm_init_userdef(Main *bmain)
SET_FLAG_FROM_TEST(G.f, (U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0, G_FLAG_SCRIPT_AUTOEXEC);
}
/* Only reset "offline mode" if they weren't passes via command line arguments. */
if ((G.f & G_FLAG_INTERNET_OVERRIDE_PREF_ANY) == 0) {
SET_FLAG_FROM_TEST(G.f, U.flag & USER_INTERNET_ALLOW, G_FLAG_INTERNET_ALLOW);
}
MEM_CacheLimiter_set_maximum(size_t(U.memcachelimit) * 1024 * 1024);
BKE_sound_init(bmain);

View File

@ -705,6 +705,11 @@ static void print_help(bArgs *ba, bool all)
BLI_args_print_arg_doc(ba, "--python-use-system-env");
BLI_args_print_arg_doc(ba, "--addons");
PRINT("\n");
PRINT("Network Options:\n");
BLI_args_print_arg_doc(ba, "--online-mode");
BLI_args_print_arg_doc(ba, "--offline-mode");
PRINT("\n");
PRINT("Logging Options:\n");
BLI_args_print_arg_doc(ba, "--log");
@ -950,6 +955,27 @@ static int arg_handle_python_set(int /*argc*/, const char ** /*argv*/, void *dat
return 0;
}
static const char arg_handle_internet_allow_set_doc_online[] =
"\n\t"
"Allow internet access, overriding the preference.";
static const char arg_handle_internet_allow_set_doc_offline[] =
"\n\t"
"Disallow internet access, overriding the preference.";
static int arg_handle_internet_allow_set(int /*argc*/, const char ** /*argv*/, void *data)
{
G.f &= ~G_FLAG_INTERNET_OVERRIDE_PREF_ANY;
if (bool(data)) {
G.f |= G_FLAG_INTERNET_ALLOW;
G.f |= G_FLAG_INTERNET_OVERRIDE_PREF_ONLINE;
}
else {
G.f &= ~G_FLAG_INTERNET_ALLOW;
G.f |= G_FLAG_INTERNET_OVERRIDE_PREF_OFFLINE;
}
return 0;
}
static const char arg_handle_crash_handler_disable_doc[] =
"\n\t"
"Disable the crash handler.";
@ -2538,6 +2564,11 @@ void main_args_setup(bContext *C, bArgs *ba, bool all)
BLI_args_add(
ba, "-Y", "--disable-autoexec", CB_EX(arg_handle_python_set, disable), (void *)false);
BLI_args_add(
ba, nullptr, "--offline-mode", CB_EX(arg_handle_internet_allow_set, offline), (void *)false);
BLI_args_add(
ba, nullptr, "--online-mode", CB_EX(arg_handle_internet_allow_set, online), (void *)true);
BLI_args_add(
ba, nullptr, "--disable-crash-handler", CB(arg_handle_crash_handler_disable), nullptr);
BLI_args_add(