Select which add-ons to copy to the system profile (#19446)
Resolves #6305
Fixes #8274
Fixes #9020
Resolves #12879
Partially addresses #18303
### Summary of the issue:
NVDA add-ons are extremely powerful, as they run unrestricted within
NVDA. This presents a heightened security risk when running on the
secure desktop, as this allows them essentially unfettered access to the
entire system. While NVDA warns the user that copying add-ons to the
system configuration is risky, the only option is to copy all add-ons or
not copy the user configuration.
### Description of user facing changes:
When copying the user config to the system config:
* If there are no add-ons installed, there is no change.
* If no add-ons are enabled, settings are copied to the system profile
without presenting the user with the security warning.
* If the user has any add-ons installed and enabled, they are presented
with a dialog which describes the risks of using add-ons on secure
screens and allows them to choose which of them to copy:
* None of the add-ons are selected by default.
* They may retrieve further information on any of the add-ons.
* If they select to copy any of the add-ons, they will be warned again
before proceding.
### Description of developer facing changes:
`config.setSystemConfigToCurrentConfig` and `config._setSystemConfig`
now accept a list of add-on IDs to copy. If empty, no add-ons will be
copied.
`nvda_slave.exe setNvdaSystemConfig` now expects a list of add-on IDs to
be provided after the user configuration path. Only add-ons with the
given IDs will be copied.
### Description of development approach:
Modified `config._setSystemConfig` to take a list of add-on IDs to copy.
When copying the `addons` directory, it will only copy subdirectories
given in this list. To be safe, it also produces a new
`addonsState.pickle` for the system config, which only includes
compatibility override information, as all add-ons copied to the system
config are assumed to be enabled.
To facilitate this, slightly refactored `addonHandler.AddonsState.load`
and `.save` to use internal helper methods that have fewer side effects
and do not rely on external state. This allowed the same logic to be
used in `nvda_slave` where `NVDAState.WritePaths` cannot be used, and to
save the pickle to an arbitrary location.
Exposed this functionality in the API by updating
`config.setSystemConfigToCurrentConfig` and `nvda_slave.exe
setNvdaSystemConfig` to accept add-on IDs to copy.
Added a new dialog, `gui.addonGui._CopyAddonsDialog`, which handles
prompting the user for which add-ons to copy to the system config. The
dialog is largely modelled on the `IncompatibleAddonsDialog`. To work
around the fact that we need a standard return code and a returned list
of add-on IDs, the initializer takes a list to be populated with add-on
IDs that should be copied. As lists are mutable and passed by reference,
the caller can simply create a list, pass it to the dialog, then check
its contents after the dialog returns.
Created a helper function, `addonGui._getAddonsToCopy`, to isolate some
of the work of using the dialog. Used this function when updating
`gui.settingsDialogs.GeneralSettingsPanel.onCopySettings`.
### Testing strategy:
Built NVDA and installed it. Attempted copying user config to the system
config with a variety of combinations of enabled, enabled incompatible,
and disabled add-ons installed. Also checked that the dialog didn't
offer to copy pending install or pending remove add-ons.
After copying settings, checked that the selected add-ons - and only the
selected add-ons - were copied, and that the system `addonsState.Pickle`
contained the right contents. Used `alt+ctrl+del` to get a secure
desktop of NVDA and attempted to use copied add-ons.
### Known issues with pull request:
* Metadata about add-ons that haven't been selected is copied to the
system profile. Specifically, the `<add-on>.json` metadata files.