This repository has been archived on 2023-02-02. You can view files and clone it, but cannot push or open issues or pull requests.
barkshark-web/barkshark_web/component/application.py
2022-09-24 06:57:21 -04:00

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)