216 lines
4.7 KiB
Python
216 lines
4.7 KiB
Python
from functools import partial
|
|
from izzylib.misc import replace_strings
|
|
from mastodon import Mastodon
|
|
from random import randrange
|
|
|
|
from . import __software__
|
|
from .enums import NotificationPriority
|
|
from .functions import (
|
|
TimeoutCallback,
|
|
connect,
|
|
get_app,
|
|
run_in_gui_thread
|
|
)
|
|
|
|
|
|
class LoginRowBase:
|
|
def __getitem__(self, key):
|
|
return self.ui.get_object(key)
|
|
|
|
|
|
@property
|
|
def app(self):
|
|
return get_app()
|
|
|
|
|
|
@property
|
|
def db(self):
|
|
return self.app.db
|
|
|
|
|
|
@property
|
|
def window(self):
|
|
return self.app.window
|
|
|
|
|
|
def connect(self, name, signal, callback, *args, original_args=False, **kwargs):
|
|
if original_args:
|
|
connect(self[name], signal, lambda *origargs: callback(*origargs, *args, **kwargs))
|
|
|
|
else:
|
|
connect(self[name], signal, lambda *origargs: callback(*args, **kwargs))
|
|
|
|
|
|
class Notification(Notify.Notification):
|
|
def __init__(self, message, priority='NORMAL'):
|
|
Notify.Notification.__init__(self,
|
|
id = randrange(999999999),
|
|
icon_name = get_app().path.resources.join('icon-64.png'),
|
|
#summary = title,
|
|
body = message
|
|
)
|
|
|
|
self.callbacks = {}
|
|
|
|
|
|
def new_callback(self, name, label, func, *args, **kwargs):
|
|
callback = partial(func, name, *args, **kwargs)
|
|
self.callbacks[name] = {
|
|
'label': label,
|
|
'callback': callback
|
|
}
|
|
|
|
self.add_action(name, label, callback)
|
|
|
|
|
|
def remove_callback(self, name):
|
|
del self.callbacks[name]
|
|
self.clear_actions()
|
|
|
|
for name, data in self.callbacks.items():
|
|
self.add_action(name, data['label'], data['callback'])
|
|
|
|
|
|
def clear_callbacks(self):
|
|
self.clear_actions()
|
|
self.callbacks = {}
|
|
|
|
|
|
class SavedLoginRow(LoginRowBase):
|
|
def __init__(self, row, page_url):
|
|
self.ui = Gtk.Builder.new_from_file(self.app.path.resources.join('password_saved.ui'))
|
|
self.row = row
|
|
|
|
self['username'].set_text(self.row.get('username', ''))
|
|
self['domain'].set_text(self.row.get('domain', ''))
|
|
|
|
self.connect('fill', 'clicked', self.handle_fill_password)
|
|
self.connect('copy-password', 'clicked', self.handle_copy_password)
|
|
self.connect('copy-username', 'clicked', self.row.copy_username)
|
|
|
|
self['container'].show_all()
|
|
|
|
|
|
@property
|
|
def tab(self):
|
|
return self.window.active_tab
|
|
|
|
|
|
def handle_copy_password(self):
|
|
self.row.copy_password(60)
|
|
self.window.notification('Copied password to clipboard for 5 seconds')
|
|
|
|
self.window['statusbar-logins-popover'].popdown()
|
|
|
|
|
|
def handle_fill_password(self):
|
|
self.tab.webview.grab_focus()
|
|
|
|
with self.app.path.js.join('autofill.js').open() as fd:
|
|
data = fd.read()
|
|
|
|
username = self.row.username
|
|
password = self.row.password
|
|
|
|
self.tab.run_js(data + f'\nfill_forms("{username}", "{password}");')
|
|
|
|
self.window['statusbar-logins-popover'].popdown()
|
|
|
|
|
|
class UnsavedLoginRow(LoginRowBase):
|
|
def __init__(self, ext, form):
|
|
self.ui = Gtk.Builder.new_from_file(self.app.path.resources.join('password_unsaved.ui'))
|
|
self.ext = ext
|
|
self.form = form
|
|
|
|
self.set_data(form.username[1], form.password[1])
|
|
|
|
self.connect('save', 'clicked', self.handle_save)
|
|
self.connect('cancel', 'clicked', self.handle_cancel)
|
|
self.connect('password', 'icon-press', self.handle_pass_visibility)
|
|
|
|
self['container'].show_all()
|
|
|
|
|
|
def get_data(self):
|
|
url = Url(self.form.url)
|
|
data = DotDict(
|
|
url = url,
|
|
form_url = url.without_query,
|
|
username = self.form.username[1],
|
|
password = self.form.password[1],
|
|
userfield = self.form.username[0],
|
|
passfield = self.form.password[0],
|
|
note = None
|
|
)
|
|
|
|
if data.url.endswith('/'):
|
|
data.url = data.url[:-1]
|
|
|
|
return data
|
|
|
|
|
|
def set_data(self, username, password):
|
|
self['username'].set_text(username or '')
|
|
self['password'].set_text(password or '')
|
|
|
|
|
|
def handle_cancel(self):
|
|
self.window['statusbar-logins-unsaved-list'].remove(self['container'])
|
|
self['container'].destroy()
|
|
del self.ext.unsaved_forms[self.form.form_url]
|
|
|
|
|
|
def handle_pass_visibility(self):
|
|
self['password'].set_visibility(not self['password'].get_visibility())
|
|
|
|
|
|
def handle_save(self):
|
|
data = self.get_data()
|
|
|
|
with get_app().db.session as s:
|
|
s.put_password(data.username, data.password, data.url, name=None, note=data.note)
|
|
|
|
self.handle_cancel()
|
|
|
|
|
|
class WebviewState:
|
|
def __init__(self, tabid, title, url, session):
|
|
self.tabid = tabid
|
|
self.title = title
|
|
self.url = url
|
|
self.session = session
|
|
|
|
|
|
def __repr__(self):
|
|
return f'WebViewState(tabid="{self.tabid}", title="{self.title}", url="{self.url}")'
|
|
|
|
|
|
@classmethod
|
|
def new_from_row(cls, row):
|
|
return cls(
|
|
row.tabid,
|
|
row.title,
|
|
row.url,
|
|
WebKit2.WebViewSessionState.new(GLib.Bytes.new(row.state))
|
|
)
|
|
|
|
|
|
@classmethod
|
|
def new_from_tab(cls, tab):
|
|
return cls(
|
|
tab.id,
|
|
tab.title,
|
|
tab.url,
|
|
tab.webview.get_session_state()
|
|
)
|
|
|
|
|
|
@property
|
|
def app(self):
|
|
return get_app()
|
|
|
|
|
|
def to_bytes(self):
|
|
return self.session.serialize().get_data()
|