Skip to content

Commit e99f2fe

Browse files
authored
Merge 73d035b into 9e7c07c
2 parents 9e7c07c + 73d035b commit e99f2fe

6 files changed

Lines changed: 71 additions & 4 deletions

File tree

pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ dependencies = [
2929
# pinned to a commit in tool.uv.sources
3030
"configobj",
3131
"requests==2.32.3",
32+
# Overrides certifi so that requests uses system certificates instead
33+
"pip_system_certs==5.2",
3234
"url-normalize==1.4.3",
3335
"schedule==1.2.2",
3436
# NVDA_DMP requires diff-match-patch

source/addonStore/dataManager.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ def _getLatestAddonsDataForVersion(self, apiVersion: str) -> Optional[bytes]:
125125
url = _getAddonStoreURL(self._preferredChannel, self._lang, apiVersion)
126126
try:
127127
log.debug(f"Fetching add-on data from {url}")
128-
response = requests.get(url, timeout=FETCH_TIMEOUT_S)
128+
response = _fetchUrlAndUpdateRootCertificates(url)
129129
except requests.exceptions.RequestException as e:
130130
log.debugWarning(f"Unable to fetch addon data: {e}")
131131
return None

source/addonStore/network.py

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# A part of NonVisual Desktop Access (NVDA)
2-
# Copyright (C) 2022-2024 NV Access Limited
2+
# Copyright (C) 2022-2025 NV Access Limited
33
# This file is covered by the GNU General Public License.
44
# See the file COPYING for more details.
55

@@ -18,6 +18,7 @@
1818
Optional,
1919
Tuple,
2020
)
21+
from urllib.parse import urlparse
2122

2223
import requests
2324

@@ -28,6 +29,7 @@
2829
from NVDAState import WritePaths
2930
import threading
3031
from utils.security import sha256_checksum
32+
from utils.networking import _is_cert_verification_error, _updateWindowsRootCertificates
3133
from config import conf
3234

3335
from .models.addon import (
@@ -236,8 +238,8 @@ def _downloadAddonToPath(
236238
return False # The download was cancelled
237239
return True
238240

239-
def _download(self, listItem: "AddonListItemVM[_AddonStoreModel]") -> Optional[os.PathLike]:
240-
from gui.message import DisplayableError
241+
def _download(self, listItem: "AddonListItemVM[_AddonStoreModel]") -> os.PathLike | None:
242+
from gui.message import DisplayableError, messageBox
241243

242244
# Translators: A title for a dialog notifying a user of an add-on download failure.
243245
_addonDownloadFailureMessageTitle = pgettext("addonStore", "Add-on download failure")
@@ -257,6 +259,40 @@ def _download(self, listItem: "AddonListItemVM[_AddonStoreModel]") -> Optional[o
257259
try:
258260
if not self._downloadAddonToPath(listItem, inProgressFilePath):
259261
return None # The download was cancelled
262+
except requests.exceptions.SSLError as e:
263+
if _is_cert_verification_error(e):
264+
import wx
265+
266+
if (
267+
messageBox(
268+
message=pgettext(
269+
"addonStore",
270+
# Translators: A message to the user if an add-on download fails.
271+
# url is replaced with the base URL of the add-on download e.g. (github.com).
272+
"The website where you are downloading the add-on from has a certificate that is not trusted. "
273+
"Do you want to trust the root certificate for {url}? "
274+
"This will allow you to download add-ons from this website in the future. "
275+
"Only do this if you trust the website. ",
276+
).format(url=urlparse(addonData.URL).netloc),
277+
caption=_addonDownloadFailureMessageTitle,
278+
style=wx.OK | wx.CANCEL | wx.CENTRE | wx.ICON_WARNING,
279+
)
280+
== wx.OK
281+
):
282+
_updateWindowsRootCertificates(addonData.URL)
283+
return self._download(listItem)
284+
else:
285+
return None # The download was cancelled
286+
else:
287+
log.debugWarning(f"Unable to download addon file: {e}")
288+
raise DisplayableError(
289+
pgettext(
290+
"addonStore",
291+
# Translators: A message to the user if an add-on download fails
292+
"Unable to download add-on: {name}",
293+
).format(name=addonData.displayName),
294+
_addonDownloadFailureMessageTitle,
295+
)
260296
except requests.exceptions.RequestException as e:
261297
log.debugWarning(f"Unable to download addon file: {e}")
262298
raise DisplayableError(

source/core.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
import NVDAState
3333
from NVDAState import WritePaths
3434

35+
import pip_system_certs.wrapt_requests
36+
3537
if TYPE_CHECKING:
3638
import wx
3739

@@ -694,6 +696,9 @@ def main():
694696
WritePaths.configDir = config.getUserDefaultConfigPath(
695697
useInstalledPathIfExists=globalVars.appArgs.launcher,
696698
)
699+
700+
# Use Windows root certificates for requests rather than certifi.
701+
pip_system_certs.wrapt_requests.inject_truststore()
697702
# Initialize the config path (make sure it exists)
698703
config.initConfigPath()
699704
log.info(f"Config dir: {WritePaths.configDir}")

user_docs/en/changes.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ There have also been a number of other fixes and improvements, including to mous
7070
* In focus mode in web browsers, it is now possible to review and spell the labels of controls when those labels are specifically provided for accessibility; e.g. via `aria-label` or `aria-labelledby`. (#15159, @jcsteh)
7171
* It is now possible to review and spell the labels of controls in Google Chrome menus and dialogs. (#11285, @jcsteh)
7272
* When typing into a cell in Microsoft Excel, the braille display is now correctly updated to show the new content. (#18391)
73+
* Fixed bug when trying to access the Add-on Store from certain environments such as corporates. (#18354)
7374

7475
### Changes for Developers
7576

uv.lock

Lines changed: 23 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)