343 lines
8.6 KiB
Python
343 lines
8.6 KiB
Python
import sys
|
|
|
|
from izzylib.enums import LogLevel
|
|
from izzylib.http_client import HttpClient
|
|
from izzylib.misc import class_name, signal_handler
|
|
from izzylib_http_async import Template
|
|
from izzylib_sql import Database
|
|
from urllib.parse import quote
|
|
|
|
from .web_context import WebContext
|
|
from .window import Window
|
|
|
|
from .. import dbus, var
|
|
from .. import __version__ as version, __software__ as swname
|
|
from ..config import get_config, get_paths, scriptpath
|
|
from ..cookies import get_cookie_db
|
|
from ..database import get_database
|
|
from ..enums import LibraryPage
|
|
from ..exceptions import AccountNotFoundError, NoAccountsError
|
|
from ..functions import connect
|
|
from ..passwords import PASSWORD_STORAGE
|
|
|
|
|
|
class Application(Gtk.Application):
|
|
def __init__(self, profile, *urls):
|
|
super().__init__()
|
|
|
|
self.profile = profile
|
|
self.http_client = HttpClient()
|
|
self.clipboard = Gtk.Clipboard.get_default(Gdk.Display.get_default())
|
|
self.startup_urls = urls
|
|
self.accounts = []
|
|
|
|
self.path = None
|
|
self.cfg = None
|
|
self.template = None
|
|
self.db = None
|
|
self.cookies = None
|
|
self.context = None
|
|
self.window = None
|
|
self.password = None
|
|
self.dbus = None
|
|
|
|
self.setup(profile)
|
|
|
|
connect(self, 'activate', self.handle_activate, urls)
|
|
connect(self, 'startup', self.handle_startup)
|
|
|
|
signal_handler(self.quit)
|
|
|
|
|
|
def setup(self, profile):
|
|
self.path = get_paths(profile)
|
|
self.cfg = get_config(self.path)
|
|
self.db = get_database(self)
|
|
|
|
with self.db.session as s:
|
|
logging.set_config('level', s.get_config('log_level'))
|
|
|
|
self.cookies = get_cookie_db(self)
|
|
self.context = WebContext(self)
|
|
|
|
proxy_resolver = Gio.ProxyResolver.get_default()
|
|
proxies = proxy_resolver.lookup('https://www.barkshark.xyz', None)
|
|
self.proxies = tuple(Url(proxy) for proxy in proxies)
|
|
|
|
self.template = Template(
|
|
autoescape = False,
|
|
context = self.handle_template_context,
|
|
search = [
|
|
self.path.localweb,
|
|
self.path.resources
|
|
]
|
|
)
|
|
|
|
self.template.update_env({
|
|
'len': len,
|
|
'str': str,
|
|
'int': int,
|
|
'float': float,
|
|
'bool': bool,
|
|
'app': self,
|
|
'var': var,
|
|
'version': version,
|
|
'swname': swname,
|
|
'quote': quote
|
|
})
|
|
|
|
|
|
def setup_password_storage(self, passtype=None):
|
|
if self.password:
|
|
self.password.stop()
|
|
self.password = None
|
|
|
|
with self.db.session as s:
|
|
config = s.get_config()
|
|
|
|
if not passtype:
|
|
passtype = config.pass_type
|
|
|
|
storeclass = PASSWORD_STORAGE[passtype]
|
|
|
|
if passtype == 'bitwarden':
|
|
self.password = storeclass(
|
|
host = config.bw_host,
|
|
port = config.bw_port,
|
|
external = config.bw_external,
|
|
session_key = config.bw_session_key
|
|
)
|
|
|
|
elif passtype == 'gnome':
|
|
self.password = storeclass('BarksharkWeb')
|
|
#self.password = storeclass(self.profile)
|
|
|
|
elif passtype == 'default':
|
|
self.password = storeclass(self.db)
|
|
|
|
else:
|
|
raise TypeError(f'Not a valid password type: {passtype}')
|
|
|
|
try:
|
|
self.password.start()
|
|
|
|
except ValueError:
|
|
logging.error(f'Failed to start password backend: {passtype}')
|
|
|
|
|
|
def get_account_by_handle(self, username, domain=None):
|
|
if not len(self.accounts):
|
|
raise NoAccountsError('No accounts')
|
|
|
|
for acct in self.accounts:
|
|
if not domain and username == acct.handle:
|
|
return acct
|
|
|
|
elif domain and username == acct.handle and domain == acct.domain:
|
|
return acct
|
|
|
|
raise AccountNotFoundError('Cannot find account')
|
|
|
|
|
|
def get_account_by_id(self, id):
|
|
if not len(self.accounts):
|
|
raise NoAccountsError('No accounts')
|
|
|
|
for acct in self.accounts:
|
|
if acct.id == id:
|
|
return acct
|
|
|
|
raise AccountNotFoundError('Cannot find account')
|
|
|
|
|
|
def get_default_account(self):
|
|
if not len(self.accounts):
|
|
raise NoAccountsError('No accounts')
|
|
|
|
with self.db.session as s:
|
|
default = s.get_config('active_acct')
|
|
|
|
for acct in self.accounts:
|
|
if default == acct.id:
|
|
return acct
|
|
|
|
s.put_config('active_acct', self.accounts[0].id)
|
|
|
|
return self.accounts[0]
|
|
|
|
|
|
def set_clipboard_text(self, *text):
|
|
self.clipboard.set_text(' '.join(text), -1)
|
|
|
|
|
|
def quit(self, *args):
|
|
self.db.unregister_all_callbacks()
|
|
|
|
if self.window:
|
|
self.window.handle_window_close()
|
|
|
|
super().quit()
|
|
|
|
|
|
def handle_activate(self, urls):
|
|
self.window = Window(self)
|
|
self.dbus = dbus.Server(self.window)
|
|
|
|
try:
|
|
if logging.get_config('level') in [LogLevel.VERBOSE, LogLevel.DEBUG]:
|
|
self.window.themes.watcher_start()
|
|
|
|
except OSError as e:
|
|
logging.warning(f'Failed to start theme watcher')
|
|
logging.error(f'{class_name(e)}: {e}')
|
|
|
|
self.add_window(self.window)
|
|
self.setup_password_storage()
|
|
|
|
with self.db.session as s:
|
|
self.accounts = s.fetch('accounts').all()
|
|
|
|
for row in s.fetch('tabs', orderby='order'):
|
|
self.window.tab_new(row=row, switch=row.active)
|
|
|
|
for url in urls:
|
|
self.window.tab_new(url, switch=True)
|
|
|
|
if len(self.window.tabdata.keys()) < 1:
|
|
self.window.tab_new(None, switch=False)
|
|
|
|
tab = list(self.window.tabdata.values())[0]
|
|
self.http_client.set_useragent(tab.settings['user-agent'])
|
|
|
|
self.window.show()
|
|
self.window.startup = False
|
|
|
|
|
|
def handle_clipboard_clear_password(self, password):
|
|
if self.clipboard.wait_for_text() == password:
|
|
logging.debug('Clear clipboard text')
|
|
self.clipboard.set_text('', 0)
|
|
|
|
|
|
def handle_startup(self, *args):
|
|
Gtk.Application.do_startup(self)
|
|
|
|
accel = Gio.SimpleAction.new('accel', GLib.VariantType.new('s'))
|
|
accel.connect('activate', self.handle_accel)
|
|
self.add_action(accel)
|
|
|
|
self.keybinds = {
|
|
'Close current tab': ('close_tab', ['<Ctrl>W']),
|
|
'Focus url bar': ('focus_urlbar', ['<Ctrl>L']),
|
|
'Force refresh page': ('force_refresh', ['<Ctrl><Shift>R', '<Shift>F5']),
|
|
'Add or edit Bookmark': ('new_bookmark', ['<Ctrl>B']),
|
|
'Open new tab': ('new_tab', ['<Ctrl>T']),
|
|
'Open file': ('open_file', ['<Ctrl>O']),
|
|
'Open help page': ('open_help', ['<Ctrl>H', 'F1']),
|
|
'Open library': ('open_library', ['<Ctrl>U']),
|
|
'Open web inspector': ('open_inspector', ['<Ctrl><Shift>I']),
|
|
'Toggle web inspector': ('toggle_inspector', ['F12']),
|
|
'Print page': ('print', ['<Ctrl>P']),
|
|
'Quit app': ('quit', ['<Ctrl>Q']),
|
|
'Refresh page': ('refresh', ['<Ctrl>R', 'F5']),
|
|
'Reopen last closed tab': ('reopen', ['<Ctrl><Shift>T']),
|
|
'Save page as MHTML': ('save_page', ['<Ctrl>S']),
|
|
'Toggle fullscreen state': ('toggle_fullscreen', ['<Alt>Return', 'F11']),
|
|
'Toggle search bar': ('toggle_search', ['<Ctrl>F', 'F3']),
|
|
'Zoom page in': ('zoom_in', [f'{Gtk.accelerator_name(ord("="), Gdk.ModifierType.CONTROL_MASK)}']),
|
|
'Zoom page out': ('zoom_out', [f'{Gtk.accelerator_name(ord("-"), Gdk.ModifierType.CONTROL_MASK)}'])
|
|
}
|
|
|
|
for action, keybind in self.keybinds.values():
|
|
self.set_accels_for_action(f'app.accel::{action}', keybind)
|
|
|
|
for idx, page in enumerate(LibraryPage):
|
|
if page == LibraryPage.HOME:
|
|
continue
|
|
|
|
self.set_accels_for_action(f'app.accel::library_page_{page.value}', [f'<Ctrl>{idx}'])
|
|
|
|
|
|
def handle_template_context(self, context):
|
|
with self.db.session as s:
|
|
context['config'] = s.get_config()
|
|
|
|
return context
|
|
|
|
|
|
def handle_accel(self, signal, action):
|
|
action = action.get_string()
|
|
tab = self.window.active_tab
|
|
|
|
if action.startswith('library_page'):
|
|
self.window.library_open(action.replace('library_page_', ''))
|
|
|
|
elif action == 'close_tab':
|
|
tab.close()
|
|
|
|
elif action == 'focus_urlbar':
|
|
tab['navbar-url'].grab_focus()
|
|
|
|
elif action == 'force_refresh':
|
|
tab.page_action('refresh', ignore_cache=True)
|
|
|
|
elif action == 'new_bookmark':
|
|
widget = self.window.statusbar['bookmark']
|
|
|
|
if widget.get_sensitive():
|
|
widget.activate()
|
|
|
|
elif action == 'new_tab':
|
|
self.window.tab_new(switch=True)
|
|
|
|
elif action == 'open_file':
|
|
self.window.file_open()
|
|
|
|
elif action == 'help':
|
|
self.window.library_open('help')
|
|
|
|
elif action == 'open_inspector':
|
|
tab.inspector_action('open')
|
|
|
|
elif action == 'toggle_inspector':
|
|
tab.inspector_action('toggle')
|
|
|
|
elif action == 'toggle_search':
|
|
tab.search_action('toggle')
|
|
|
|
elif action == 'print':
|
|
tab.page_action('print')
|
|
|
|
elif action == 'quit':
|
|
self.quit()
|
|
|
|
elif action == 'refresh':
|
|
tab.page_action('refresh')
|
|
|
|
elif action == 'reopen':
|
|
if not len(self.window.closed):
|
|
return
|
|
|
|
last_tab = list(self.window.closed.keys())[-1]
|
|
self.window.tab_reopen(last_tab)
|
|
|
|
elif action == 'save_page':
|
|
tab.page_action('save')
|
|
|
|
elif action == 'toggle_fullscreen':
|
|
self.window.fullscreen_set()
|
|
|
|
elif action == 'open_library':
|
|
self.window.library_open()
|
|
|
|
elif action == 'zoom_in':
|
|
zoom = tab.webview.get_zoom_level() + 0.1
|
|
tab.page_action('zoom', zoom=zoom)
|
|
|
|
elif action == 'zoom_out':
|
|
zoom = tab.webview.get_zoom_level() - 0.1
|
|
tab.page_action('zoom', zoom=zoom)
|
|
|
|
else:
|
|
logging.error('Unhandled keyboard shortcut action:', action)
|