Files
ServerSync/lib/keyring/backends/macOS/__init__.py

86 lines
2.5 KiB
Python
Raw Normal View History

2026-02-19 00:55:27 +02:00
import functools
import os
import platform
import warnings
from ...backend import KeyringBackend
from ...compat import properties
from ...errors import KeyringError, KeyringLocked, PasswordDeleteError, PasswordSetError
try:
from . import api
except Exception:
pass
def warn_keychain(func):
@functools.wraps(func)
def wrapper(self, *args, **kwargs):
if self.keychain:
warnings.warn("Specified keychain is ignored. See #623", stacklevel=2)
return func(self, *args, **kwargs)
return wrapper
class Keyring(KeyringBackend):
"""macOS Keychain"""
keychain = os.environ.get('KEYCHAIN_PATH')
"Path to keychain file, overriding default"
@properties.classproperty
def priority(cls):
"""
Preferred for all macOS environments.
"""
if platform.system() != 'Darwin':
raise RuntimeError("macOS required")
if 'api' not in globals():
raise RuntimeError("Security API unavailable")
return 5
@warn_keychain
def set_password(self, service, username, password):
if username is None:
username = ''
try:
api.set_generic_password(self.keychain, service, username, password)
except api.KeychainDenied as e:
raise KeyringLocked(f"Can't store password on keychain: {e}") from e
except api.Error as e:
raise PasswordSetError(f"Can't store password on keychain: {e}") from e
@warn_keychain
def get_password(self, service, username):
if username is None:
username = ''
try:
return api.find_generic_password(self.keychain, service, username)
except api.NotFound:
pass
except api.KeychainDenied as e:
raise KeyringLocked(f"Can't get password from keychain: {e}") from e
except api.Error as e:
raise KeyringError(f"Can't get password from keychain: {e}") from e
@warn_keychain
def delete_password(self, service, username):
if username is None:
username = ''
try:
return api.delete_generic_password(self.keychain, service, username)
except api.Error as e:
raise PasswordDeleteError(f"Can't delete password in keychain: {e}") from e
def with_keychain(self, keychain):
warnings.warn(
"macOS.Keyring.with_keychain is deprecated. Use with_properties instead.",
DeprecationWarning,
stacklevel=2,
)
return self.with_properties(keychain=keychain)