This commit is contained in:
Izalia Mae 2022-04-16 06:23:04 -04:00
parent eb2bcf4101
commit 02e78096ab
18 changed files with 329 additions and 272 deletions

View file

@ -6,6 +6,7 @@ from .. import dbus
from .. import __version__ as version from .. import __version__ as version
from ..config import var from ..config import var
from ..database import db from ..database import db
from ..exceptions import AccountNotFoundError, NoAccountsError
class Application(Gtk.Application): class Application(Gtk.Application):
@ -28,6 +29,75 @@ class Application(Gtk.Application):
self.connect('startup', self.handle_startup) self.connect('startup', self.handle_startup)
def create_tabs(self):
with db.session as s:
for row in s.fetch('tabs', orderby='order'):
self.window.new_tab(row=row)
for url in self.startup_urls:
self.window.new_tab(url, switch=row.active)
if len(self.window.tabdata.keys()) < 1:
self.window.new_tab(None, switch=False)
self.window.startup = False
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 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):
db.unregister_all_callbacks()
if self.window:
#self.window.passwords.db.disconnect()
self.window.handle_window_close()
super().quit()
def handle_activate(self, *args): def handle_activate(self, *args):
self.window = Window(self) self.window = Window(self)
self.dbus = dbus.Server(self.window) self.dbus = dbus.Server(self.window)
@ -37,6 +107,12 @@ class Application(Gtk.Application):
self.window.show() self.window.show()
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): def handle_startup(self, *args):
Gtk.Application.do_startup(self) Gtk.Application.do_startup(self)
accel = Gio.SimpleAction.new('accel', GLib.VariantType.new('s')) accel = Gio.SimpleAction.new('accel', GLib.VariantType.new('s'))
@ -82,79 +158,6 @@ class Application(Gtk.Application):
self.accounts = s.fetch('accounts').all() self.accounts = s.fetch('accounts').all()
def quit(self, *args):
db.unregister_all_callbacks()
if self.window:
#self.window.passwords.db.disconnect()
self.window.handle_window_close()
super().quit()
def create_tabs(self):
with db.session as s:
for row in s.fetch('tabs', orderby='order'):
self.window.new_tab(row=row)
for url in self.startup_urls:
self.window.new_tab(url, switch=row.active)
if len(self.window.tabdata.keys()) < 1:
self.window.new_tab(None, switch=False)
self.window.startup = False
def get_account_by_handle(self, username, domain=None):
if not len(self.accounts):
raise IndexError('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 IndexError('Cannot find account')
def get_account_by_id(self, id):
if not len(self.accounts):
raise IndexError('No accounts')
for acct in self.accounts:
if acct.id == id:
return acct
raise IndexError('Cannot find account')
def get_default_account(self):
if not len(self.accounts):
raise IndexError('No accounts')
with db.session as s:
default = s.get_config('active_acct')
for acct in self.accounts:
if default == acct.id:
return acct
return self.accounts[0]
def set_clipboard_text(self, *text):
self.clipboard.set_text(' '.join(text), -1)
def handle_clipboard_clear_password(self, password):
if self.clipboard.wait_for_text() == password:
logging.debug('Clear clipboard text')
self.clipboard.clear()
def handle_accel(self, signal, action): def handle_accel(self, signal, action):
action = action.get_string() action = action.get_string()
tab = self.window.active_tab tab = self.window.active_tab

View file

@ -1,5 +1,6 @@
from .. import fediverse from .. import fediverse
from ..database import db, default_permissions from ..database import db, default_permissions
from ..exceptions import AccountNotFoundError, NoAccountsError
from ..functions import SignalBlock, connect, get_buffer_text from ..functions import SignalBlock, connect, get_buffer_text
from ..objects.login_rows import SavedLoginRow from ..objects.login_rows import SavedLoginRow
from ..passwords import passdb from ..passwords import passdb
@ -8,12 +9,13 @@ from ..passwords import passdb
class StatusBar: class StatusBar:
def __init__(self, window): def __init__(self, window):
self.window = window self.window = window
self.app = window.app
self.siteoptions_handler_ids = [] self.siteoptions_handler_ids = []
self.bookmark_row = None self.bookmark_row = None
self.theme_enabled = False self.theme_enabled = False
self.toot_account = {} self.toot_acct = None
self.toot_post = None self.toot_post = None
self.toot_max_len = 500 self.toot_max_len = 500
@ -85,10 +87,10 @@ class StatusBar:
def toot_set_account(self): def toot_set_account(self):
with db.session as s: try:
self.toot_account = s.get_account() self.toot_account = self.app.get_default_account()
if not self.toot_account: except NoAccountsError:
self.window.notification('No active fedi accounts', 'error') self.window.notification('No active fedi accounts', 'error')
return False return False
@ -171,6 +173,7 @@ class StatusBar:
#self.window.active_tab.editing_action('select') #self.window.active_tab.editing_action('select')
#self.window.active_tab.editing_action('copy') #self.window.active_tab.editing_action('copy')
self.window.notification('Merp!', 'INFO', 0) self.window.notification('Merp!', 'INFO', 0)
print(self.window.context.get_cookie_manager().delete_cookies_for_domain(self.window.active_tab.url.domain))
#if self.window.themes.current_theme: #if self.window.themes.current_theme:
#self.window.themes.UnloadTheme() #self.window.themes.UnloadTheme()
@ -240,21 +243,21 @@ class StatusBar:
def handle_bookmark_button(self, name): def handle_bookmark_button(self, name):
if name == 'save': with db.session as s:
data = self.bookmark_get_data() if name == 'save':
data = self.bookmark_get_data()
with db.session as s:
if self.bookmark_row: if self.bookmark_row:
data['id'] = self.bookmark_row.id s.update_row(self.bookmark_row, **data)
s.put_bookmark(**data) else:
s.put_bookmark(**data)
elif name == 'delete': elif name == 'delete':
if self.bookmark_row: if self.bookmark_row:
s.remove_row(self.bookmark_row) s.remove_row(self.bookmark_row)
self.window['statusbar-bookmark-popover'].popdown() self.window['statusbar-bookmark-popover'].popdown()
self.window.bookmarks.table.refresh()
def handle_fedi_button(self, name): def handle_fedi_button(self, name):
@ -346,7 +349,7 @@ class StatusBar:
for child in login_list.get_children(): for child in login_list.get_children():
child.destroy() child.destroy()
for row in passdb.fetch(domain=self.window.active_tab.url.domain): for row in passdb.fetch(domain=self.window.active_tab.url.hostname()):
login_list.add(SavedLoginRow(row, self.window.active_tab.url)['container']) login_list.add(SavedLoginRow(row, self.window.active_tab.url)['container'])

View file

@ -282,6 +282,11 @@ default_settings = {
'name': 'Serif font', 'name': 'Serif font',
'description': 'Font to use when the page does not specify a font for pictograph fonts' 'description': 'Font to use when the page does not specify a font for pictograph fonts'
}, },
'user-agent': {
'default': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:99.0) Gecko/20100101 Firefox/99.0',
'name': 'User Agent',
'description': 'How the browser identifies itself when connecting to web servers'
},
'zoom-text-only': { 'zoom-text-only': {
'default': False, 'default': False,
'name': 'Only zoom text', 'name': 'Only zoom text',
@ -302,7 +307,7 @@ class WebSettings(WebKit2.Settings):
super().__init__() super().__init__()
self.tab = tab self.tab = tab
self.set_user_agent_with_application_details('pyWeb', version) #self.set_user_agent_with_application_details('pyWeb', version)
for k,v in default_settings.items(): for k,v in default_settings.items():
self[k] = v['default'] self[k] = v['default']

View file

@ -88,9 +88,6 @@ var.template.update_env({
logging.set_config('level', var.loglevel) logging.set_config('level', var.loglevel)
if var.loglevel in ['DEBUG', 'VERBOSE']:
izzylog.set_config('level', 'VERBOSE')
sys.path.insert(-1, dirs.extensions) sys.path.insert(-1, dirs.extensions)
if dirs.data.join('database.sqlite3').exists(): if dirs.data.join('database.sqlite3').exists():

View file

@ -120,7 +120,7 @@ default_config = {
'default_search': ('ddg', 'str'), 'default_search': ('ddg', 'str'),
'detach_inspector': (False, 'bool'), 'detach_inspector': (False, 'bool'),
'download_dir': (Path('~/Downloads').expanduser(), 'path'), 'download_dir': (Path('~/Downloads').expanduser(), 'path'),
'enable_autocomplete': (True, 'bool'), 'enable_autocomplete': (False, 'bool'),
'fullscreen': (False, 'bool'), 'fullscreen': (False, 'bool'),
'homepage': (var.local + '/', 'str'), 'homepage': (var.local + '/', 'str'),
'https_force': (True, 'bool'), 'https_force': (True, 'bool'),
@ -334,12 +334,13 @@ class CustomSession(Session):
data = DotDict( data = DotDict(
name = name, name = name,
url = url, url = url,
description = description,
category = category or 'Misc', category = category or 'Misc',
lastupdate = datetime.now() lastupdate = datetime.now()
) )
if description:
data['description'] = description
return self.insert('bookmarks', **data) return self.insert('bookmarks', **data)

View file

@ -38,11 +38,6 @@ class Search(Row):
class Account(Row): class Account(Row):
_api = None _api = None
_emojis = None _emojis = None
_db = None
def __run__(self, session):
self._db = session.db
@property @property
@ -53,6 +48,12 @@ class Account(Row):
return self._api return self._api
@property
def active(self):
with self._db.session as s:
return s.get_config('active_acct') == self.id
@property @property
def avatar(self): def avatar(self):
return dirs.avatars.join(f'{self.id}.png') return dirs.avatars.join(f'{self.id}.png')
@ -68,12 +69,6 @@ class Account(Row):
return return
@property
def active(self):
with self._db.session as s:
return s.get_config('active_acct') == self.id
@property @property
def emojis(self): def emojis(self):
if not self._emojis: if not self._emojis:
@ -186,8 +181,3 @@ class Account(Row):
def set_active(self): def set_active(self):
with self._db.session as s: with self._db.session as s:
s.put_config('active_acct', self.id) s.put_config('active_acct', self.id)
def test(self):
string = '30+ Transfem Sergal :trans_furr_white: :nbdab: :nbdab:\n\nDoes lots of Python crimes'
return self.replace_emojis(string)

View file

@ -0,0 +1,5 @@
class NoAccountsError(Exception):
'Raise when doing an action that requires a fediverse account, but none exist'
class AccountNotFoundError(Exception):
'Raise when a specific account is not found'

View file

@ -1,38 +1,34 @@
// General // General
function connect_event(name, signal, callback) { function connect_event(name, signal, callback) {
element = document.getElementById(name); const element = document.getElementById(name);
element.addEventListener(signal, callback); element.addEventListener(signal, callback);
} }
function delete_item(base_url, id) { function delete_item(base_url, id) {
request(`${base_url}/${id}`, function(xhr) { request(`${base_url}/${id}`, (response, body) => {
if (xhr.status != 200) {return;} if (response.status != 200) {return;}
var element = document.getElementById(id); const element = document.getElementById(id);
element.parentElement.removeChild(element); element.parentElement.removeChild(element);
}) });
} }
function request(url, callback, timeout=5) { function request(url, callback) {
const xhr = new XMLHttpRequest(); fetch(url).then((response) => {
xhr.timeout = 5 if (callback != null) {
xhr.open('GET', url); response.text().then((body) => {
callback(response, body)
if (callback != undefined) { });
xhr.onload = function(event) {
callback(event.target);
} }
} });
xhr.send();
} }
function toggle_all_details(class_name, state) { function toggle_all_details(class_name, state) {
var elements = document.getElementsByClassName(class_name); const elements = document.getElementsByClassName(class_name);
for (let element of elements) { for (let element of elements) {
if (state && !element.hasAttribute('open')) { if (state && !element.hasAttribute('open')) {
element.setAttribute('open', null); element.setAttribute('open', null);
@ -44,15 +40,15 @@ function toggle_all_details(class_name, state) {
function toggle_menu() { function toggle_menu() {
var menu = document.getElementById('main-menu'); const menu = document.getElementById('main-menu');
var show_text = menu.hasAttribute('show'); const show_text = menu.hasAttribute('show');
if (show_text) { if (show_text) {
menu.removeAttribute('show'); menu.removeAttribute('show');
} else { } else {
menu.setAttribute('show', null); menu.setAttribute('show', null);
} }
for (let item of document.getElementsByClassName('menu-item-text')) { for (let item of document.getElementsByClassName('menu-item-text')) {
if (show_text) { if (show_text) {
item.style.display = 'none' item.style.display = 'none'
@ -71,28 +67,24 @@ function handle_key_enter(event) {
function handle_save_config(event) { function handle_save_config(event) {
var input = event.target; const input = event.target;
let value = '';
if (input.type.toUpperCase() == 'CHECKBOX') { if (input.type.toUpperCase() == 'CHECKBOX') {
if (input.checked) { if (input.checked) {
var value = 'true'; value = 'true';
} else { } else {
var value = 'false'; value = 'false';
} }
} else { } else {
var value = input.value; value = input.value;
} }
const url = new URL(input.form.action); const url = new URL(input.form.action);
url.searchParams.set(input.id, value) url.searchParams.set(input.id, value)
request(url, function(xhr) { request(url, (response, body) => {
if (xhr.status == 200) { if (response.status == 200) {
console.log(xhr.status, url);
console.log(`Set config: ${input.id}=${value}`); console.log(`Set config: ${input.id}=${value}`);
} }
}); });
@ -102,15 +94,15 @@ function handle_save_config(event) {
// Fediverse // Fediverse
function create_account_nodes(ids) { function create_account_nodes(ids) {
for (let id of ids) { for (let id of ids) {
request(`/fediverse/acct_info/${id}`, function(xhr) { request(`/fediverse/acct_info/${id}`, (response, body) => {
if (xhr.status != 200) { if (response.status != 200) {
console.log(`Error %{xhr.status} when trying to fetch account: ${xhr.responseText}`); console.log(`Error ${response.status} when trying to fetch account: ${body}`);
return; return;
} }
const accts = document.getElementById('accounts'); const accts = document.getElementById('accounts');
const container = document.createElement('div'); const container = document.createElement('div');
container.innerHTML = xhr.responseText; container.innerHTML = body;
accts.appendChild(container.children[0]); accts.appendChild(container.children[0]);
})} })}
@ -118,8 +110,8 @@ function create_account_nodes(ids) {
function set_active(acctid) { function set_active(acctid) {
request(`/fediverse/set_active/${acctid}`, function(xhr) { request(`/fediverse/set_active/${acctid}`, (response, body) => {
if (xhr.status != 200) { if (response.status != 200) {
console.log(`Failed to set account active: ID ${acctid}`); console.log(`Failed to set account active: ID ${acctid}`);
return; return;
} }
@ -127,11 +119,10 @@ function set_active(acctid) {
for (let acct of document.getElementsByClassName('account')) { for (let acct of document.getElementsByClassName('account')) {
var active = acct.getElementsByClassName('active')[0]; var active = acct.getElementsByClassName('active')[0];
if (acct.id == `ACCT${acctid}`) { if (acct.id == acctid) {
active.style.display = 'none' active.style.display = 'none';
} else { } else {
active.style.display = 'inline-block' active.style.display = 'inline-block';
} }
} }
}); });
@ -140,8 +131,8 @@ function set_active(acctid) {
// History // History
function delete_history(histid) { function delete_history(histid) {
request(`/history/delete/${histid}`, function(xhr) { request(`/history/delete/${histid}`, (response, body) => {
if (xhr.status != 200) {return;} if (response.status != 200) {return;}
const element = document.getElementById(histid); const element = document.getElementById(histid);
const details = element.parentElement; const details = element.parentElement;
@ -157,20 +148,19 @@ function delete_history(histid) {
// Search // Search
function set_default_search(id) { function set_default_search(id) {
request(`/search/default/${id}`, function(xhr) { request(`/search/default/${id}`, (response, body) => {
if (xhr.status != 200) { if (response.status != 200) {
console.log(`Failed to set search engine active: ID ${id}`); console.log(`Failed to set search engine active: ID ${id}`);
return; return;
} }
for (let acct of document.getElementsByClassName('search-item')) { for (let acct of document.getElementsByClassName('search-item')) {
var active = acct.getElementsByClassName('default')[0]; const active = acct.getElementsByClassName('default')[0];
if (acct.id == `SEARCH${id}`) { if (acct.id == `SEARCH${id}`) {
active.style.display = 'none' active.style.display = 'none';
} else { } else {
active.style.display = 'inline-block' active.style.display = 'inline-block';
} }
} }
}); });
@ -179,9 +169,8 @@ function set_default_search(id) {
// Passwords // Passwords
function copy_password(id) { function copy_password(id) {
console.log(id); request(`/passwords/copy/${id}`, (response, body) => {
request(`/passwords/copy/${id}`, function(xhr) { if (response.status != 200) {
if (xhr.status != 200) {
console.log(`Error code when trying to copy password: ${xhr.status} ${xhr.statusText}`); console.log(`Error code when trying to copy password: ${xhr.status} ${xhr.statusText}`);
} }
}); });

View file

@ -9,9 +9,14 @@ class LoginRowBase:
return self.ui.get_object(key) return self.ui.get_object(key)
@property
def app(self):
return Gio.Application.get_default()
@property @property
def window(self): def window(self):
return Gio.Application.get_default().window return self.app.window
def connect(self, name, signal, callback, *args, original_args=False, **kwargs): def connect(self, name, signal, callback, *args, original_args=False, **kwargs):
@ -25,36 +30,39 @@ class LoginRowBase:
class SavedLoginRow(LoginRowBase): class SavedLoginRow(LoginRowBase):
def __init__(self, row, page_url): def __init__(self, row, page_url):
self.ui = Gtk.Builder.new_from_file(dirs.resources.join('password_saved.ui')) self.ui = Gtk.Builder.new_from_file(dirs.resources.join('password_saved.ui'))
self.passrow = row self.row = row
self.tab = self.window.active_tab
with db.session as s: with db.session as s:
self.dbrow = s.get_passfield(page_url) self.dbrow = s.get_passfield(page_url)
self['username'].set_text(self.passrow['username']) self['username'].set_text(self.row['username'])
if self.passrow.url != page_url or not self.dbrow: #if self.row.url != page_url or not self.dbrow:
self['fill'].set_sensitive(False) #self['fill'].set_sensitive(False)
self.connect('fill', 'clicked', self.handle_fill_password) self.connect('fill', 'clicked', self.handle_fill_password)
self.connect('copy', 'clicked', self.handle_copy_password) self.connect('copy-password', 'clicked', self.handle_copy_password)
self.connect('copy-username', 'clicked', self.row.copy_username)
self['container'].show_all() self['container'].show_all()
def handle_copy_password(self): @property
password = self.passrow.password def tab(self):
return self.window.active_tab
self.window.clipboard.set_text(password, -1)
self.window.notification('Copied password to clipboard for 30 seconds') def handle_copy_password(self):
TimeoutCallback(30, run_in_gui_thread, self.window.passwords.handle_clear_clipboard, self.window.clipboard, password).start() self.row.copy_password(60)
self.window.notification('Copied password to clipboard for 5 seconds')
self.window['statusbar-logins-popover'].popdown() self.window['statusbar-logins-popover'].popdown()
def handle_fill_password(self): def handle_fill_password(self):
self.tab.run_js(f'document.getElementsByName("{self.dbrow.userfield}")[0].value = "{self.passrow.username}"') with dirs.resources.join('ext_js/autofill.js').open() as fd:
self.tab.run_js(f'document.getElementsByName("{self.dbrow.passfield}")[0].value = "{self.passrow.password}"') self.tab.run_js(fd.read().replace('USERNAME_VALUE', self.row.username).replace('PASSWORD_VALUE', self.row.password))
self.window['statusbar-logins-popover'].popdown() self.window['statusbar-logins-popover'].popdown()

View file

@ -4,6 +4,8 @@ from datetime import datetime
from secretstorage.collection import Collection, get_collection_by_alias, create_collection from secretstorage.collection import Collection, get_collection_by_alias, create_collection
from secretstorage.exceptions import ItemNotFoundException, LockedException from secretstorage.exceptions import ItemNotFoundException, LockedException
from .functions import TimeoutCallback, get_app, run_in_gui_thread
pass_store_keys = ['username', 'domain', 'url', 'note'] pass_store_keys = ['username', 'domain', 'url', 'note']
pass_keys = [*pass_store_keys, 'created', 'modified', 'label', 'password'] pass_keys = [*pass_store_keys, 'created', 'modified', 'label', 'password']
@ -274,6 +276,18 @@ class PasswordItem:
return self.update(note=value) return self.update(note=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 as_dict(self): def as_dict(self):
return DotDict( return DotDict(
id = self.id, id = self.id,

View file

@ -178,7 +178,7 @@ def fediverse_refresh(handler, request, acctid):
return request.error(f'Account with ID not found: {acctid}', 404) return request.error(f'Account with ID not found: {acctid}', 404)
row.refresh() row.refresh()
return request.redirect('/fediverse') return request.ok_or_redirect(f'Refreshed account info: {row.fullhandle}')
@Local.route('/fediverse/set_active/{acctid:int}') @Local.route('/fediverse/set_active/{acctid:int}')
@ -190,8 +190,7 @@ def fediverse_set_active(handler, request, acctid):
return request.error(f'Account with ID not found: {acctid}', 404) return request.error(f'Account with ID not found: {acctid}', 404)
row.set_active() row.set_active()
logging.verbose('Set account as active:', row.fullhandle) return request.ok_or_redirect(f'Account set as active: {row.fullhandle}')
return request.response('OK')
@Local.route('/fediverse/logout/{acctid:int}') @Local.route('/fediverse/logout/{acctid:int}')
@ -349,10 +348,7 @@ def passwords_copy(handler, request, rowid):
except KeyError: except KeyError:
return request.error(f'Cannot find password: {rowid}', 404) return request.error(f'Cannot find password: {rowid}', 404)
handler.app.set_clipboard_text(row.password) row.copy_password()
timer = TimeoutCallback(60, run_in_gui_thread, handler.app.handle_clipboard_clear_password, row.password)
timer.start()
return request.ok_or_redirect(f'Copied password for 60 seconds') return request.ok_or_redirect(f'Copied password for 60 seconds')
@ -384,7 +380,7 @@ def preferences_home(handler, request):
@Local.route('/preferences/update') @Local.route('/preferences/update')
def preferences_update(handler, request): def preferences_update(handler, request):
if not len(request.query): if not len([key for key in request.query.keys() if key != 'redir']):
return request.error('No key/value pairs provided', 400) return request.error('No key/value pairs provided', 400)
with db.session as s: with db.session as s:
@ -395,7 +391,7 @@ def preferences_update(handler, request):
row = s.put_config(key, value) row = s.put_config(key, value)
logging.verbose(f'Updated config: {row.key} = {row.value}') logging.verbose(f'Updated config: {row.key} = {row.value}')
return request.ok_or_redirect('/preferences', 'Updated preferences') return request.ok_or_redirect('Updated preferences')
### Search ### ### Search ###

View file

@ -0,0 +1,28 @@
function fetch_fields() {
var userfield = null;
var passfield = null;
Array.from(document.forms).forEach((form) => {
Array.from(form.getElementsByTagName('input')).forEach((input) => {
if (input.type == 'password') {
passfield = input;
} else if (input.name.includes('user')) {
userfield = input;
}
if (![userfield, passfield].includes(null)) {
return;
}
});
});
return [userfield, passfield];
}
fields = fetch_fields();
if (!fields.includes(null)) {
fields[0].value = 'USERNAME_VALUE';
fields[1].value = 'PASSWORD_VALUE';
}

View file

@ -898,7 +898,7 @@ AND CONDITIONS OF THIS LICENSE.
<property name="icon-name">window-close</property> <property name="icon-name">window-close</property>
</object> </object>
<object class="GtkPopover" id="statusbar-logins-popover"> <object class="GtkPopover" id="statusbar-logins-popover">
<property name="width-request">400</property> <property name="width-request">500</property>
<property name="height-request">400</property> <property name="height-request">400</property>
<property name="can-focus">False</property> <property name="can-focus">False</property>
<child> <child>

View file

@ -20,8 +20,22 @@
</packing> </packing>
</child> </child>
<child> <child>
<object class="GtkButton" id="copy"> <object class="GtkButton" id="copy-username">
<property name="label" translatable="yes">Copy</property> <property name="label" translatable="yes">Username</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="tooltip-text" translatable="yes">Copy username to clipboard</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="copy-password">
<property name="label" translatable="yes">Password</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="can-focus">True</property> <property name="can-focus">True</property>
<property name="receives-default">True</property> <property name="receives-default">True</property>

View file

@ -49,12 +49,12 @@
"izzylib": { "izzylib": {
"version": "0.1.0", "version": "0.1.0",
"options": [], "options": [],
"url": "git+https://git.barkshark.xyz/izaliamae/izzylib_sql" "url": "git+https://git.barkshark.xyz/izaliamae/izzylib-sql"
}, },
"izzylib_http_async": { "izzylib_http_async": {
"version": "0.1.0", "version": "0.1.0",
"options": [], "options": [],
"url": "git+https://git.barkshark.xyz/izaliamae/izzylib_http_async" "url": "git+https://git.barkshark.xyz/izaliamae/izzylib-http-async"
}, },
"mastodon.py": { "mastodon.py": {
"version": "1.5.1", "version": "1.5.1",
@ -81,5 +81,25 @@
"options": [], "options": [],
"url": null "url": null
} }
},
"watcher": {
"path": "barkshark_web",
"command": "barkshark_web",
"env": {"LOG_LEVEL": "VERBOSE"},
"ext": [
"py",
"pyx",
"pyc"
],
"ignore_dirs": [
"build",
"config",
"data"
],
"ignore_files": [
"reload.py",
"test.py",
"pyvenv.py"
]
} }
} }

View file

@ -1,13 +1 @@
izzylib[dbus,http_urllib_client,sql,template] @ git+https://git.barkshark.xyz/izaliamae/izzylib@ab87e880a15b3eb2bb1420b6f169653cc00bfcd6 .
beautifulsoup4==4.9.3
configobj>=5.0.6
lxml>=4.6.3
mastodon.py==1.5.1
pillow==8.3.2
psutil==5.8.0
pygobject==3.38.0
pysftp==0.2.9
SecretStorage==3.3.1
tldextract==3.1.0
validators==0.18.2

58
setup.cfg Normal file
View file

@ -0,0 +1,58 @@
[metadata]
name = Barkshark Web
version = 0.3.8
author = Zoey Mae
author_email = zoey@barkshark.xyz
url = https://git.barkshark.xyz/izaliamae/barkshark-web
description = Python venv manager
long_description = file: README.md
long_description_content_type = text/markdown; charset=UTF-8
license = CNPL 4+
license_file = LICENSE
platform = any
keywords = python development venv
classifiers =
Development Status :: 4 - Beta
Intended Audience :: End Users/Desktop
License :: OSI Approved :: GNU General Public License v3
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
Operating System :: POSIX
Operating System :: MacOS :: MacOS X
Operating System :: Microsoft :: Windows
Topic :: Internet :: WWW/HTTP
project_urls =
Bug Tracker = https://git.barkshark.xyz/izaliamae/barkshark-web/issues
Documentation = https://git.barkshark.xyz/izaliamae/barkshark-web/wiki
Source Code = https://git.barkshark.xyz/izaliamae/barkshark-web
[options]
include_package_data = true
python_requires = >= 3.8
packages =
barkshark_web
setup_requires =
izzylib @ git+https://git.barkshark.xyz/izaliamae/izzylib@a156b3b416a9549ee439adc36785cca4131c499c
izzylib_sql @ git+https://git.barkshark.xyz/izaliamae/izzylib-sql@ebfe4fa678f16f35f650afd077a97e4a7cf45d61
izzylib_http_async @ git+https://git.barkshark.xyz/izaliamae/izzylib-http-async@216a779f221e926cd3130404bd33cb916f87d21a
beautifulsoup4==4.9.3
lxml==4.6.3
mastodon.py==1.5.1
pillow==8.3.2
psutil==5.8.0
pygobject==3.38.0
pysftp==0.2.9
SecretStorage==3.3.1
tldextract==3.1.0
validators==0.18.2
[options.entry_points]
console_scripts =
pyvenv = barkshark_web.startup:main
[bdist_wheel]
universal = false
[sdist]
formats = zip, gztar

View file

@ -1,64 +1,2 @@
#!/usr/bin/env python3 import setuptools
import os, shutil, sys setuptools.setup()
from pathlib import Path
from setuptools import setup, find_packages
scriptpath = Path(__file__).resolve().parent
extsetup = scriptpath.joinpath('webextension/build.sh')
extloader = scriptpath.joinpath('bsweb/bin/pythonloader.so')
extloader_build = scriptpath.joinpath('webextension/pythonloader.so')
with scriptpath.joinpath('requirements.txt').open() as fd:
requirements = [req.replace('\n', '') for req in fd.readlines()]
with scriptpath.joinpath('apt-requirements.txt').open() as fd:
apt_requirements = ' '.join([req.replace('\n', '') for req in fd.readlines()])
#if os.environ.get('APT_INSTALL'):
#os.system(f'sudo apt install {apt_requirements} -y --no-install-recommends')
#extloader.parent.mkdir(exist_ok=True)
#if not extloader.exists():
#os.system(f'cd {scriptpath} && git submodule init')
#os.system(extsetup)
#shutil.copy(extloader_build, extloader)
setup(
name='pyweb',
version='0.3.5',
packages=find_packages(),
entry_points={
'console_scripts': [
'bsweb = bsweb.startup:main'
]
},
python_requires='>=3.8.0',
install_requires=requirements,
include_package_data=True,
author='Zoey Mae',
author_email='admin@barkshark.xyz',
description='Barkshark Web: Simple GTK web browser',
keywords='gtk web browser gui',
url='https://git.barkshark.xyz/izaliamae/pyweb',
project_urls={
'Bug Tracker': 'https://git.barkshark.xyz/izaliamae/pyweb/issues',
'Documentation': 'https://git.barkshark.xyz/izaliamae/pyweb/wiki/Index',
'Source Code': 'https://git.barkshark.xyz/izaliamae/pyweb'
},
classifiers=[
'Development Status :: 4 - Beta',
'Intended Audience :: End Users/Desktop',
'License :: OSI Approved :: GNU General Public License v3',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Operating System :: POSIX',
'Operating System :: MacOS :: MacOS X',
'Operating System :: Microsoft :: Windows',
'Topic :: Internet :: WWW/HTTP'
]
)