258 lines
4.5 KiB
Python
258 lines
4.5 KiB
Python
from izzylib.misc import class_name
|
|
|
|
from . import PASSWORD_STORAGE
|
|
|
|
from ..functions import TimeoutCallback, get_app, run_in_gui_thread
|
|
|
|
|
|
PASSWORD_KEYS = [
|
|
'id',
|
|
'label',
|
|
'username',
|
|
'password',
|
|
'domain',
|
|
'url',
|
|
'note',
|
|
'created',
|
|
'modified'
|
|
]
|
|
|
|
|
|
class PasswordResult:
|
|
def __init__(self, storage, items):
|
|
self._storage = storage
|
|
self._items = items
|
|
|
|
|
|
def __iter__(self):
|
|
for item in self._items:
|
|
yield self._storage.item_class(self._storage, item)
|
|
|
|
|
|
def all(self):
|
|
return tuple(item for item in self)
|
|
|
|
|
|
def one(self):
|
|
for item in self:
|
|
return item
|
|
|
|
|
|
class PasswordItem:
|
|
def __init__(self, storage, item):
|
|
self._storage = storage
|
|
self._data = item
|
|
|
|
|
|
def __repr__(self):
|
|
return f'{class_name(self)}("{self.label}", username="{self.username}", domain="{self.domain}")'
|
|
|
|
|
|
def __getitem__(self, key):
|
|
if key not in self.keys():
|
|
raise KeyError(key)
|
|
|
|
value = self._get_value(key)
|
|
return self.__default_parse(key, value)
|
|
|
|
|
|
def __setitem__(self, key, value):
|
|
if key in ['id', 'created', 'modified'] or key not in self.keys():
|
|
raise KeyError(key)
|
|
|
|
value = self.__default_parse(key, value)
|
|
self._set_value(key, value)
|
|
|
|
|
|
def __delitem__(self, key):
|
|
raise AttributeError('Cannot delete item values')
|
|
|
|
|
|
def __getattr__(self, key):
|
|
try:
|
|
return self.__getitem__(key)
|
|
|
|
except KeyError:
|
|
return object.__getattribute__(self, key)
|
|
|
|
|
|
def __setattr__(self, key, value):
|
|
try:
|
|
self.__setitem__(key, value)
|
|
|
|
except KeyError:
|
|
object.__setattr__(self, key, value)
|
|
|
|
|
|
def __default_parse(self, key, value):
|
|
if key == 'url' and not isinstance(value, (Url, type(None))):
|
|
return Url(value)
|
|
|
|
elif key in ['created', 'modified'] and not isinstance(value, (DateString, type(None))):
|
|
return DateString.new_http(value)
|
|
|
|
return self._parse_value(key, value)
|
|
|
|
|
|
def _parse_value(self, key, value):
|
|
return value
|
|
|
|
|
|
def _get_value(self, key):
|
|
return self._item[key]
|
|
|
|
|
|
def _set_value(self, key, value):
|
|
self._item[key] = value
|
|
|
|
|
|
def copy_password(self, timeout=60):
|
|
app = get_app()
|
|
app.set_clipboard_text(self.password)
|
|
|
|
timer = TimeoutCallback(timeout, run_in_gui_thread, app.handle_clipboard_clear_password, self.password)
|
|
timer.start()
|
|
|
|
|
|
def copy_username(self):
|
|
get_app().set_clipboard_text(self.username)
|
|
|
|
|
|
def insert_row(self, storage=None):
|
|
if self.id:
|
|
raise RuntimeError('Row already has an ID and is probably in the DB')
|
|
|
|
if storage:
|
|
return storage.insert(**self.to_dict())
|
|
|
|
return self._storage.insert(**self.to_dict())
|
|
|
|
|
|
def update_row(self, **kwargs):
|
|
self.update(**kwargs)
|
|
self._storage.update(self.id, **kwargs)
|
|
|
|
|
|
def remove_row(self):
|
|
self._storage.remove(self.id)
|
|
|
|
|
|
def to_dict(self, indent=None):
|
|
return DotDict({key: self[key] for key in self.keys()})
|
|
|
|
|
|
## dict methods
|
|
def items(self):
|
|
for key in self.keys():
|
|
yield (key, self[key])
|
|
|
|
|
|
def keys(self):
|
|
return PASSWORD_KEYS.copy()
|
|
|
|
|
|
def values(self):
|
|
return tuple(self[key] for key in self.keys())
|
|
|
|
|
|
def update(self, _data={}, **kwargs):
|
|
for key, value in [*_data.items(), *kwargs.items()]:
|
|
if key not in self.keys():
|
|
raise KeyError(f'Invalid PasswordItem key: {key}')
|
|
|
|
self[key] = value
|
|
|
|
|
|
class PasswordStorage:
|
|
result_class = PasswordResult
|
|
item_class = PasswordItem
|
|
|
|
|
|
@property
|
|
def app(self):
|
|
return get_app()
|
|
|
|
|
|
@property
|
|
def window(self):
|
|
return self.app.window
|
|
|
|
|
|
@property
|
|
def storage_type(self):
|
|
for key, value in PASSWORD_STORAGE.items():
|
|
if self.__class__ == value:
|
|
return key
|
|
|
|
|
|
def start(self):
|
|
pass
|
|
|
|
|
|
def stop(self):
|
|
pass
|
|
|
|
|
|
def _fetch(self, **kwargs):
|
|
pass
|
|
|
|
|
|
def lock(self):
|
|
pass
|
|
|
|
|
|
def unlock(self, password=None):
|
|
pass
|
|
|
|
|
|
def create_row(self, *args, **kwargs):
|
|
return self.item_class.new(*args, **kwargs, storage=self)
|
|
|
|
|
|
def parse_data(self, username=None, domain=None, password=None, url=None, note=None, label=None, **kwargs):
|
|
kwargs.update(
|
|
username = username,
|
|
domain = domain,
|
|
url = url,
|
|
note = note,
|
|
password = password,
|
|
label = label
|
|
)
|
|
|
|
for key, value in tuple(kwargs.items()):
|
|
if not value:
|
|
del kwargs[key]
|
|
|
|
elif key == 'url':
|
|
kwargs['url'] = Url(url)
|
|
|
|
return kwargs
|
|
|
|
|
|
def fetch(self, label=None, username=None, domain=None, **kwargs):
|
|
if not any((name, username, domain)):
|
|
raise ValueError('Name, username, or domain not provided')
|
|
|
|
if name:
|
|
kwargs['name'] = name
|
|
|
|
if username:
|
|
kwargs['username'] = username
|
|
|
|
if domain:
|
|
kwargs['domain'] = domain
|
|
|
|
return self.result_class(self, self._fetch(**kwargs))
|
|
|
|
|
|
def insert(self, name, username, domain, **kwargs):
|
|
pass
|
|
|
|
|
|
def update(self, row_id, **kwargs):
|
|
pass
|
|
|
|
|
|
def remove(self, row_id):
|
|
pass
|