Skip to content

Commit

Permalink
rename _isSecureObjectWhileLockScreenActivated, mark as stable API (#…
Browse files Browse the repository at this point in the history
…14044)

Follow up of GHSA-rmq3-vvhq-gp32

Summary of the issue:
The function _isSecureObjectWhileLockScreenActivated may be useful to add-on authors.
Therefore the API should become stable, i.e. not prefixed with an underscore.

The function is also not named in a way that makes it clear what a "secure object" is.

Description of user facing changes
None

Description of development approach
Rename _isSecureObjectWhileLockScreenActivated to objectBelowLockScreenAndWindowsIsLocked
  • Loading branch information
seanbudd authored Aug 30, 2022
1 parent 6fdabfe commit 0b72324
Show file tree
Hide file tree
Showing 7 changed files with 48 additions and 34 deletions.
2 changes: 1 addition & 1 deletion source/NVDAObjects/lockscreen.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
class LockScreenObject(NVDAObject):
"""
Prevent users from object navigating outside of the lock screen.
While usages of `_isSecureObjectWhileLockScreenActivated` in the api module prevent
While usages of `api.objectBelowLockScreenAndWindowsIsLocked` prevent
the user from moving to the object, this overlay class prevents reading neighbouring objects.
"""

Expand Down
14 changes: 7 additions & 7 deletions source/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
import appModuleHandler
import cursorManager
from typing import Any, Optional
from utils.security import _isSecureObjectWhileLockScreenActivated
from utils.security import objectBelowLockScreenAndWindowsIsLocked

if typing.TYPE_CHECKING:
import documentBase
Expand Down Expand Up @@ -66,7 +66,7 @@ def setForegroundObject(obj: NVDAObjects.NVDAObject) -> bool:
if not isinstance(obj, NVDAObjects.NVDAObject):
log.error("Object is not a valid NVDAObject")
return False
if _isSecureObjectWhileLockScreenActivated(obj):
if objectBelowLockScreenAndWindowsIsLocked(obj):
return False
globalVars.foregroundObject=obj
return True
Expand All @@ -86,7 +86,7 @@ def setFocusObject(obj: NVDAObjects.NVDAObject) -> bool: # noqa: C901
if not isinstance(obj, NVDAObjects.NVDAObject):
log.error("Object is not a valid NVDAObject")
return False
if _isSecureObjectWhileLockScreenActivated(obj):
if objectBelowLockScreenAndWindowsIsLocked(obj):
return False
if globalVars.focusObject:
eventHandler.executeEvent("loseFocus",globalVars.focusObject)
Expand Down Expand Up @@ -194,7 +194,7 @@ def setMouseObject(obj: NVDAObjects.NVDAObject) -> bool:
if not isinstance(obj, NVDAObjects.NVDAObject):
log.error("Object is not a valid NVDAObject")
return False
if _isSecureObjectWhileLockScreenActivated(obj):
if objectBelowLockScreenAndWindowsIsLocked(obj):
return False
globalVars.mouseObject=obj
return True
Expand All @@ -207,7 +207,7 @@ def getDesktopObject() -> NVDAObjects.NVDAObject:

def setDesktopObject(obj: NVDAObjects.NVDAObject) -> None:
"""Tells NVDA to remember the given object as the desktop object.
We cannot prevent setting this when _isSecureObjectWhileLockScreenActivated is True,
We cannot prevent setting this when objectBelowLockScreenAndWindowsIsLocked is True,
as NVDA needs to set the desktopObject on start, and NVDA may start from the lockscreen.
"""
globalVars.desktopObject=obj
Expand Down Expand Up @@ -270,7 +270,7 @@ def getNavigatorObject() -> NVDAObjects.NVDAObject:
except (NotImplementedError, LookupError):
obj = globalVars.reviewPosition.obj
nextObj = getattr(obj, 'rootNVDAObject', None) or obj
if _isSecureObjectWhileLockScreenActivated(nextObj):
if objectBelowLockScreenAndWindowsIsLocked(nextObj):
return globalVars.navigatorObject
globalVars.navigatorObject = nextObj
return globalVars.navigatorObject
Expand All @@ -289,7 +289,7 @@ def setNavigatorObject(obj: NVDAObjects.NVDAObject, isFocus: bool = False) -> bo
if not isinstance(obj, NVDAObjects.NVDAObject):
log.error("Object is not a valid NVDAObject")
return False
if _isSecureObjectWhileLockScreenActivated(obj):
if objectBelowLockScreenAndWindowsIsLocked(obj):
return False
globalVars.navigatorObject=obj
globalVars.reviewPosition=None
Expand Down
20 changes: 10 additions & 10 deletions source/braille.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
import queueHandler
import brailleViewer
from autoSettingsUtils.driverSetting import BooleanDriverSetting, NumericDriverSetting
from utils.security import _isSecureObjectWhileLockScreenActivated
from utils.security import objectBelowLockScreenAndWindowsIsLocked

if TYPE_CHECKING:
from NVDAObjects import NVDAObject
Expand Down Expand Up @@ -343,7 +343,7 @@


def NVDAObjectHasUsefulText(obj: "NVDAObject") -> bool:
if _isSecureObjectWhileLockScreenActivated(obj):
if objectBelowLockScreenAndWindowsIsLocked(obj):
return False
import displayModel
if issubclass(obj.TextInfo,displayModel.DisplayModelTextInfo):
Expand Down Expand Up @@ -643,7 +643,7 @@ def __init__(self, obj: "NVDAObject", appendText: str = ""):
@param obj: The associated NVDAObject.
@param appendText: Text which should always be appended to the NVDAObject text, useful if this region will always precede other regions.
"""
if _isSecureObjectWhileLockScreenActivated(obj):
if objectBelowLockScreenAndWindowsIsLocked(obj):
raise RuntimeError("NVDA object is secure and should not be initialized as a braille region")
super().__init__()
self.obj = obj
Expand Down Expand Up @@ -915,7 +915,7 @@ class TextInfoRegion(Region):
allowPageTurns=True #: True if a page turn should be tried when a TextInfo cannot move anymore and the object supports page turns.

def __init__(self, obj: "NVDAObject"):
if _isSecureObjectWhileLockScreenActivated(obj):
if objectBelowLockScreenAndWindowsIsLocked(obj):
raise RuntimeError("NVDA object is secure and should not be initialized as a braille region")
super().__init__()
self.obj = obj
Expand Down Expand Up @@ -1629,7 +1629,7 @@ def getFocusContextRegions(
obj: "NVDAObject",
oldFocusRegions: Optional[List[Region]] = None,
) -> Generator[Region, None, None]:
if _isSecureObjectWhileLockScreenActivated(obj):
if objectBelowLockScreenAndWindowsIsLocked(obj):
return
global _cachedFocusAncestorsEnd
# Late import to avoid circular import.
Expand Down Expand Up @@ -1702,7 +1702,7 @@ def getFocusRegions(
obj: "NVDAObject",
review: bool = False,
) -> Generator[Region, None, None]:
if _isSecureObjectWhileLockScreenActivated(obj):
if objectBelowLockScreenAndWindowsIsLocked(obj):
return
# Allow objects to override normal behaviour.
try:
Expand Down Expand Up @@ -2069,7 +2069,7 @@ def _dismissMessage(self):
def handleGainFocus(self, obj: "NVDAObject", shouldAutoTether: bool = True) -> None:
if not self.enabled:
return
if _isSecureObjectWhileLockScreenActivated(obj):
if objectBelowLockScreenAndWindowsIsLocked(obj):
return
if shouldAutoTether:
self.setTether(self.TETHER_FOCUS, auto=True)
Expand Down Expand Up @@ -2111,7 +2111,7 @@ def handleCaretMove(
) -> None:
if not self.enabled:
return
if _isSecureObjectWhileLockScreenActivated(obj):
if objectBelowLockScreenAndWindowsIsLocked(obj):
return
prevTether = self._tether
if shouldAutoTether:
Expand Down Expand Up @@ -2162,7 +2162,7 @@ def _handleProgressBarUpdate(
self,
obj: "NVDAObject",
) -> None:
if _isSecureObjectWhileLockScreenActivated(obj):
if objectBelowLockScreenAndWindowsIsLocked(obj):
return
oldTime = getattr(self, "_lastProgressBarUpdateTime", None)
newTime = time.time()
Expand All @@ -2178,7 +2178,7 @@ def _handleProgressBarUpdate(
def handleUpdate(self, obj: "NVDAObject") -> None:
if not self.enabled:
return
if _isSecureObjectWhileLockScreenActivated(obj):
if objectBelowLockScreenAndWindowsIsLocked(obj):
return
# Optimisation: It is very likely that it is the focus object that is being updated.
# If the focus object is in the braille buffer, it will be the last region, so scan the regions backwards.
Expand Down
8 changes: 4 additions & 4 deletions source/eventHandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import winUser
import extensionPoints
import oleacc
from utils.security import _isSecureObjectWhileLockScreenActivated
from utils.security import objectBelowLockScreenAndWindowsIsLocked

if typing.TYPE_CHECKING:
import NVDAObjects
Expand Down Expand Up @@ -158,7 +158,7 @@ def _trackFocusObject(eventName: str, obj: "NVDAObjects.NVDAObject") -> None:

if (
eventName == "gainFocus"
and not _isSecureObjectWhileLockScreenActivated(
and not objectBelowLockScreenAndWindowsIsLocked(
obj,
shouldLog=config.conf["debugLog"]["events"],
)
Expand Down Expand Up @@ -282,7 +282,7 @@ def executeEvent(
@param obj: the object the event is for
@param kwargs: Additional event parameters as keyword arguments.
"""
if _isSecureObjectWhileLockScreenActivated(
if objectBelowLockScreenAndWindowsIsLocked(
obj,
shouldLog=config.conf["debugLog"]["events"],
):
Expand All @@ -304,7 +304,7 @@ def executeEvent(


def doPreGainFocus(obj: "NVDAObjects.NVDAObject", sleepMode: bool = False) -> bool:
if _isSecureObjectWhileLockScreenActivated(
if objectBelowLockScreenAndWindowsIsLocked(
obj,
shouldLog=config.conf["debugLog"]["events"],
):
Expand Down
4 changes: 2 additions & 2 deletions source/mathPres/mathPlayer.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
CharacterModeCommand,
PhonemeCommand,
)
from utils.security import _isSecureObjectWhileLockScreenActivated
from utils.security import objectBelowLockScreenAndWindowsIsLocked


RE_MP_SPEECH = re.compile(
Expand Down Expand Up @@ -103,7 +103,7 @@ def getBrailleRegions(
self,
review: bool = False,
) -> Generator[braille.Region, None, None]:
if _isSecureObjectWhileLockScreenActivated(self):
if objectBelowLockScreenAndWindowsIsLocked(self):
return
yield braille.NVDAObjectRegion(self, appendText=" ")
region = braille.Region()
Expand Down
6 changes: 3 additions & 3 deletions source/speech/speech.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
from enum import IntEnum
from dataclasses import dataclass
from copy import copy
from utils.security import _isSecureObjectWhileLockScreenActivated
from utils.security import objectBelowLockScreenAndWindowsIsLocked

if typing.TYPE_CHECKING:
import NVDAObjects
Expand Down Expand Up @@ -457,7 +457,7 @@ def getObjectPropertiesSpeech( # noqa: C901
_prefixSpeechCommand: Optional[SpeechCommand] = None,
**allowedProperties
) -> SpeechSequence:
if _isSecureObjectWhileLockScreenActivated(obj):
if objectBelowLockScreenAndWindowsIsLocked(obj):
return []
#Fetch the values for all wanted properties
newPropertyValues={}
Expand Down Expand Up @@ -621,7 +621,7 @@ def getObjectSpeech( # noqa: C901
reason: OutputReason = OutputReason.QUERY,
_prefixSpeechCommand: Optional[SpeechCommand] = None,
) -> SpeechSequence:
if _isSecureObjectWhileLockScreenActivated(obj):
if objectBelowLockScreenAndWindowsIsLocked(obj):
return []
role=obj.role
# Choose when we should report the content of this object's textInfo, rather than just the object's value
Expand Down
28 changes: 21 additions & 7 deletions source/utils/security.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,17 +78,23 @@ def _isLockAppAndAlive(appModule: "appModuleHandler.AppModule") -> bool:
return appModule.appName == "lockapp" and appModule.isAlive


# TODO: mark this API as public when it becomes stable (i.e. remove the underscore).
# Add-on authors may require this function to make their code secure.
# Consider renaming (e.g. objectOutsideOfLockScreenAndWindowsIsLocked).
def _isSecureObjectWhileLockScreenActivated(
def objectBelowLockScreenAndWindowsIsLocked(
obj: "NVDAObjects.NVDAObject",
shouldLog: bool = True,
) -> bool:
"""
While Windows is locked, Windows 10 and 11 doesn't prevent object navigation outside of the lockscreen.
As such, NVDA must prevent accessing and reading objects outside of the lockscreen when Windows is locked.
@return: C{True} if the Windows 10/11 lockscreen is active and C{obj} is outside of the lock screen.
While Windows is locked, the current user session is still running, and below the lockscreen
exists the current user's desktop.
Windows 10 and 11 doesn't prevent object navigation below the lockscreen.
If an object is above the lockscreen, it is accessible and visible to the user
through the Windows UX while Windows is locked.
An object below the lockscreen should only be accessible when Windows is unlocked,
as it may contain sensitive information.
As such, NVDA must prevent accessing and reading objects below the lockscreen when Windows is locked.
@return: C{True} if the Windows 10/11 lockscreen is active and C{obj} is below the lock screen.
"""
if isWindowsLocked() and not isObjectAboveLockScreen(obj):
if shouldLog and log.isEnabledFor(log.DEBUG):
Expand All @@ -101,8 +107,16 @@ def _isSecureObjectWhileLockScreenActivated(

def isObjectAboveLockScreen(obj: "NVDAObjects.NVDAObject") -> bool:
"""
While Windows is locked, the current user session is still running, and below the lockscreen
exists the current user's desktop.
When Windows is locked, the foreground Window is usually LockApp,
but other Windows can be focused (e.g. Windows Magnifier).
If an object is above the lockscreen, it is accessible and visible to the user
through the Windows UX while Windows is locked.
An object below the lockscreen should only be accessible when Windows is unlocked,
as it may contain sensitive information.
"""
import appModuleHandler
from NVDAObjects.IAccessible import TaskListIcon
Expand Down

0 comments on commit 0b72324

Please sign in to comment.