Skip to content

Commit

Permalink
When constructing KeyringBackend subclasses, wrap set_password to enf…
Browse files Browse the repository at this point in the history
…orce non-empty usernames.
  • Loading branch information
jaraco committed Aug 1, 2024
1 parent 1877402 commit 53ca9cc
Show file tree
Hide file tree
Showing 7 changed files with 18 additions and 11 deletions.
19 changes: 17 additions & 2 deletions keyring/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import abc
import copy
import functools
import logging
import operator
import os
Expand All @@ -30,11 +31,14 @@ class KeyringBackendMeta(abc.ABCMeta):
Specialized subclass behavior.
Keeps a registry of all (non-abstract) types.
Wraps set_password to validate the username.
"""

def __init__(cls, name, bases, dict):
super().__init__(name, bases, dict)
cls._register()
cls._validate_username_in_set_password()

def _register(cls):
if not hasattr(cls, '_classes'):
Expand All @@ -43,6 +47,19 @@ def _register(cls):
if not cls.__abstractmethods__:
classes.add(cls)

def _validate_username_in_set_password(cls):
"""
Wrap ``set_password`` such to validate the passed username.
"""
orig = cls.set_password

@functools.wraps(orig)
def wrapper(self, system, username, *args, **kwargs):
self._validate_username(username)
return orig(self, system, username, *args, **kwargs)

cls.set_password = wrapper


class KeyringBackend(metaclass=KeyringBackendMeta):
"""The abstract base class of the keyring, every backend must implement
Expand Down Expand Up @@ -121,8 +138,6 @@ def _validate_username(self, username: str) -> None:
def set_password(self, service: str, username: str, password: str) -> None:
"""Set password for the username of the service.
Implementations should call ``._validate_username``.
If the backend cannot store passwords, raise
PasswordSetError.
"""
Expand Down
1 change: 0 additions & 1 deletion keyring/backends/SecretService.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ def get_password(self, service, username):

def set_password(self, service, username, password):
"""Set password for the username of the service"""
self._validate_username(username)
collection = self.get_preferred_collection()
attributes = self._query(service, username, application=self.appid)
label = f"Password for '{username}' on '{service}'"
Expand Down
1 change: 0 additions & 1 deletion keyring/backends/Windows.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ def _get_password(self, target):
return DecodingCredential(res)

def set_password(self, service, username, password):
self._validate_username(username)
existing_pw = self._get_password(service)
if existing_pw:
# resave the existing password using a compound target
Expand Down
1 change: 0 additions & 1 deletion keyring/backends/kwallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,6 @@ def set_password(self, service, username, password):
if not self.connected(service):
# the user pressed "cancel" when prompted to unlock their keyring.
raise PasswordSetError("Cancelled by user")
self._validate_username(username)
self.iface.writePassword(self.handle, service, username, password, self.appid)

def delete_password(self, service, username):
Expand Down
1 change: 0 additions & 1 deletion keyring/backends/libsecret.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ def get_password(self, service, username):

def set_password(self, service, username, password):
"""Set password for the username of the service"""
self._validate_username(username)
attributes = self._query(service, username, application=self.appid)
label = f"Password for '{username}' on '{service}'"
try:
Expand Down
1 change: 0 additions & 1 deletion keyring/backends/macOS/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ def priority(cls):

@warn_keychain
def set_password(self, service, username, password):
self._validate_username(username)
if username is None:
username = ''

Expand Down
5 changes: 1 addition & 4 deletions keyring/backends/null.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,4 @@ def priority(cls) -> float:
def get_password(self, service, username, password=None):
pass

delete_password = get_password # type: ignore

def set_password(self, service, username, password):
self._validate_username(username)
set_password = delete_password = get_password # type: ignore

0 comments on commit 53ca9cc

Please sign in to comment.