mirror of
https://github.com/bunny-lab-io/Borealis.git
synced 2025-10-26 17:41:58 -06:00
Make DPAPI secrets readable across agent contexts
This commit is contained in:
@@ -39,40 +39,55 @@ def _restrict_permissions(path: str) -> None:
|
|||||||
def _protect(data: bytes, *, scope_system: bool) -> bytes:
|
def _protect(data: bytes, *, scope_system: bool) -> bytes:
|
||||||
if not IS_WINDOWS or not win32crypt:
|
if not IS_WINDOWS or not win32crypt:
|
||||||
return data
|
return data
|
||||||
flags = 0
|
scopes = [scope_system]
|
||||||
|
# Always include the alternate scope so we can fall back if the preferred
|
||||||
|
# protection attempt fails (e.g., running under a limited account that
|
||||||
|
# lacks access to the desired DPAPI scope).
|
||||||
if scope_system:
|
if scope_system:
|
||||||
flags = getattr(win32crypt, "CRYPTPROTECT_LOCAL_MACHINE", 0x4)
|
scopes.append(False)
|
||||||
try:
|
else:
|
||||||
protected = win32crypt.CryptProtectData(data, None, None, None, None, flags) # type: ignore[attr-defined]
|
scopes.append(True)
|
||||||
except Exception:
|
for scope in scopes:
|
||||||
return data
|
flags = 0
|
||||||
blob = protected[1]
|
if scope:
|
||||||
if isinstance(blob, memoryview):
|
flags = getattr(win32crypt, "CRYPTPROTECT_LOCAL_MACHINE", 0x4)
|
||||||
return blob.tobytes()
|
try:
|
||||||
if isinstance(blob, bytearray):
|
protected = win32crypt.CryptProtectData(data, None, None, None, None, flags) # type: ignore[attr-defined]
|
||||||
return bytes(blob)
|
except Exception:
|
||||||
if isinstance(blob, bytes):
|
continue
|
||||||
return blob
|
blob = protected[1]
|
||||||
|
if isinstance(blob, memoryview):
|
||||||
|
return blob.tobytes()
|
||||||
|
if isinstance(blob, bytearray):
|
||||||
|
return bytes(blob)
|
||||||
|
if isinstance(blob, bytes):
|
||||||
|
return blob
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
def _unprotect(data: bytes, *, scope_system: bool) -> bytes:
|
def _unprotect(data: bytes, *, scope_system: bool) -> bytes:
|
||||||
if not IS_WINDOWS or not win32crypt:
|
if not IS_WINDOWS or not win32crypt:
|
||||||
return data
|
return data
|
||||||
flags = 0
|
scopes = [scope_system]
|
||||||
if scope_system:
|
if scope_system:
|
||||||
flags = getattr(win32crypt, "CRYPTPROTECT_LOCAL_MACHINE", 0x4)
|
scopes.append(False)
|
||||||
try:
|
else:
|
||||||
unwrapped = win32crypt.CryptUnprotectData(data, None, None, None, None, flags) # type: ignore[attr-defined]
|
scopes.append(True)
|
||||||
except Exception:
|
for scope in scopes:
|
||||||
return data
|
flags = 0
|
||||||
blob = unwrapped[1]
|
if scope:
|
||||||
if isinstance(blob, memoryview):
|
flags = getattr(win32crypt, "CRYPTPROTECT_LOCAL_MACHINE", 0x4)
|
||||||
return blob.tobytes()
|
try:
|
||||||
if isinstance(blob, bytearray):
|
unwrapped = win32crypt.CryptUnprotectData(data, None, None, None, None, flags) # type: ignore[attr-defined]
|
||||||
return bytes(blob)
|
except Exception:
|
||||||
if isinstance(blob, bytes):
|
continue
|
||||||
return blob
|
blob = unwrapped[1]
|
||||||
|
if isinstance(blob, memoryview):
|
||||||
|
return blob.tobytes()
|
||||||
|
if isinstance(blob, bytearray):
|
||||||
|
return bytes(blob)
|
||||||
|
if isinstance(blob, bytes):
|
||||||
|
return blob
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
@@ -213,7 +228,12 @@ class AgentKeyStore:
|
|||||||
with open(self._refresh_token_path, "rb") as fh:
|
with open(self._refresh_token_path, "rb") as fh:
|
||||||
protected = fh.read()
|
protected = fh.read()
|
||||||
raw = _unprotect(protected, scope_system=self.scope_system)
|
raw = _unprotect(protected, scope_system=self.scope_system)
|
||||||
return raw.decode("utf-8")
|
try:
|
||||||
|
return raw.decode("utf-8")
|
||||||
|
except Exception:
|
||||||
|
# Token may have been protected under the opposite DPAPI scope.
|
||||||
|
alt = _unprotect(protected, scope_system=not self.scope_system)
|
||||||
|
return alt.decode("utf-8")
|
||||||
except Exception:
|
except Exception:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user