Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add-on store: Improve disk management for launcher and secure copies #14955

Merged
merged 2 commits into from Jun 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 10 additions & 0 deletions source/NVDAState.py
Expand Up @@ -46,6 +46,16 @@ def _setExitCode(exitCode: int) -> None:
globalVars.exitCode = exitCode


def shouldWriteToDisk() -> bool:
"""
Never save config or state if running securely or if running from the launcher.
When running from the launcher we don't save settings because the user may decide not to
install this version, and these settings may not be compatible with the already
installed version. See #7688
"""
return not (globalVars.appArgs.secure or globalVars.appArgs.launcher)


class _TrackNVDAInitialization:
"""
During NVDA initialization,
Expand Down
11 changes: 11 additions & 0 deletions source/_addonStore/dataManager.py
Expand Up @@ -22,10 +22,12 @@

import addonAPIVersion
from baseObject import AutoPropertyObject
import config
from core import callLater
import globalVars
import languageHandler
from logHandler import log
import NVDAState

from .models.addon import (
AddonStoreModel,
Expand Down Expand Up @@ -54,6 +56,9 @@

def initialize():
global addonDataManager
if config.isAppX:
log.info("Add-ons not supported when running as a Windows Store application")
return
log.debug("initializing addonStore data manager")
addonDataManager = _DataManager()

Expand Down Expand Up @@ -104,6 +109,8 @@ def _getLatestAddonsDataForVersion(self, apiVersion: str) -> Optional[bytes]:
return response.content

def _cacheCompatibleAddons(self, addonData: str, fetchTime: datetime):
if not NVDAState.shouldWriteToDisk():
return
if not addonData:
return
cacheData = {
Expand All @@ -116,6 +123,8 @@ def _cacheCompatibleAddons(self, addonData: str, fetchTime: datetime):
json.dump(cacheData, cacheFile, ensure_ascii=False)

def _cacheLatestAddons(self, addonData: str, fetchTime: datetime):
if not NVDAState.shouldWriteToDisk():
return
if not addonData:
return
cacheData = {
Expand Down Expand Up @@ -226,6 +235,8 @@ def _deleteCacheInstalledAddon(self, addonId: str):
os.remove(addonCachePath)

def _cacheInstalledAddon(self, addonData: AddonStoreModel):
if not NVDAState.shouldWriteToDisk():
return
if not addonData:
return
addonCachePath = os.path.join(self._installedAddonDataCacheDir, f"{addonData.addonId}.json")
Expand Down
10 changes: 8 additions & 2 deletions source/addonHandler/__init__.py
Expand Up @@ -38,6 +38,7 @@
import winKernel
import addonAPIVersion
import importlib
import NVDAState
from types import ModuleType

from _addonStore.models.status import AddonStateCategory, SupportsAddonState
Expand Down Expand Up @@ -131,6 +132,10 @@ def removeStateFile(self) -> None:

def save(self) -> None:
"""Saves content of the state to a file unless state is empty in which case this would be pointless."""
if not NVDAState.shouldWriteToDisk():
log.error("NVDA should not write to disk from secure mode or launcher", stack_info=True)
return

if any(self.values()):
try:
# #9038: Python 3 requires binary format when working with pickles.
Expand Down Expand Up @@ -216,8 +221,9 @@ def initialize():
# #3090: Are there add-ons that are supposed to not run for this session?
disableAddonsIfAny()
getAvailableAddons(refresh=True, isFirstLoad=True)
state.cleanupRemovedDisabledAddons()
state.save()
if NVDAState.shouldWriteToDisk():
state.cleanupRemovedDisabledAddons()
state.save()
initializeModulePackagePaths()


Expand Down
9 changes: 2 additions & 7 deletions source/config/__init__.py
Expand Up @@ -538,11 +538,6 @@ def __init__(self):
self._shouldHandleProfileSwitch: bool = True
self._pendingHandleProfileSwitch: bool = False
self._suspendedTriggers: Optional[List[ProfileTrigger]] = None
# Never save the config if running securely or if running from the launcher.
# When running from the launcher we don't save settings because the user may decide not to
# install this version, and these settings may not be compatible with the already
# installed version. See #7688
self._shouldWriteProfile: bool = not (globalVars.appArgs.secure or globalVars.appArgs.launcher)
self._initBaseConf()
#: Maps triggers to profiles.
self.triggersToProfiles: Optional[Dict[ProfileTrigger, ConfigObj]] = None
Expand Down Expand Up @@ -600,7 +595,7 @@ def _loadConfig(self, fn, fileError=False):
profile.newlines = "\r\n"
profileCopy = deepcopy(profile)
try:
writeProfileFunc = self._writeProfileToFile if self._shouldWriteProfile else None
writeProfileFunc = self._writeProfileToFile if NVDAState.shouldWriteToDisk() else None
profileUpgrader.upgrade(profile, self.validator, writeProfileFunc)
except Exception as e:
# Log at level info to ensure that the profile is logged.
Expand Down Expand Up @@ -704,7 +699,7 @@ def save(self):
"""
# #7598: give others a chance to either save settings early or terminate tasks.
pre_configSave.notify()
if not self._shouldWriteProfile:
if not NVDAState.shouldWriteToDisk():
log.info("Not writing profile, either --secure or --launcher args present")
return
try:
Expand Down
12 changes: 8 additions & 4 deletions source/gui/__init__.py
Expand Up @@ -335,6 +335,7 @@ def onAddonsManagerCommand(self, evt: wx.MenuEvent):
blockAction.Context.MODAL_DIALOG_OPEN,
blockAction.Context.WINDOWS_LOCKED,
blockAction.Context.WINDOWS_STORE_VERSION,
blockAction.Context.RUNNING_LAUNCHER,
)
def onAddonStoreCommand(self, evt: wx.MenuEvent):
self.prePopup()
Expand Down Expand Up @@ -468,13 +469,16 @@ def __init__(self, frame: MainFrame):
self.menu_tools_toggleBrailleViewer.Check(brailleViewer.isBrailleViewerActive())
brailleViewer.postBrailleViewerToolToggledAction.register(frame.onBrailleViewerChangedState)

if not config.isAppX and NVDAState.shouldWriteToDisk():
# Translators: The label of a menu item to open the Add-on store
item = menu_tools.Append(wx.ID_ANY, _("Add-on &store..."))
self.Bind(wx.EVT_MENU, frame.onAddonStoreCommand, item)

if not globalVars.appArgs.secure and not config.isAppX:
# Translators: The label for the menu item to open NVDA Python Console.
item = menu_tools.Append(wx.ID_ANY, _("Python console"))
self.Bind(wx.EVT_MENU, frame.onPythonConsoleCommand, item)
# Translators: The label of a menu item to open the Add-on store
item = menu_tools.Append(wx.ID_ANY, _("Add-on &store..."))
self.Bind(wx.EVT_MENU, frame.onAddonStoreCommand, item)

if not globalVars.appArgs.secure and not config.isAppX and not NVDAState.isRunningAsSource():
# Translators: The label for the menu item to create a portable copy of NVDA from an installed or another portable version.
item = menu_tools.Append(wx.ID_ANY, _("Create portable copy..."))
Expand Down Expand Up @@ -632,7 +636,7 @@ def _appendConfigManagementSection(self, frame: wx.Frame) -> None:
_("Reset all settings to default state")
)
self.Bind(wx.EVT_MENU, frame.onRevertToDefaultConfigurationCommand, item)
if not (globalVars.appArgs.secure or globalVars.appArgs.launcher):
if NVDAState.shouldWriteToDisk():
item = self.menu.Append(
wx.ID_SAVE,
# Translators: The label for the menu item to save current settings.
Expand Down