This commit is contained in:
Your Name 2024-04-30 14:51:36 +00:00
commit 0afcf2a10c
11 changed files with 587 additions and 0 deletions

47
README.md Normal file
View File

@ -0,0 +1,47 @@
Define this function in your config.py
```
import os
from qutebrowser.api import config as api_config
sCONFIG_DIR = config.configdir
def config_load_configs(lArgs: list|None = None, sDir: str = sCONFIG_DIR) -> None:
i = 0
if not lArgs: return i
for foo in lArgs:
sFile = os.path.join(sDir, 'configs', foo)
for bar in sFile, sFile+'.py':
if not os.path.exists(bar): continue
try:
# ResourceWarning: unclosed file
oFd = open(bar, 'rt')
sCode = oFd.read()
oFd.close()
exec(sCode)
except Exception as e:
log.init.warning(f'error execing {bar}\n{e}')
log.init.debug(traceback.print_exc())
else:
log.init.info(f'execed {bar}')
i = i + 1
return i
```
Then make a list of configs you want to load:
```
lCONFIGS = ['chromium-flags',
'chrome-urls',
'privacy-settings',
'tab-manager',
'search-engines',
'user-agents',
'interceptor-cloudflare',
'interceptor-ytadds',
'init_custom_plugins',
'patch-qute3.1.0',
'atexit-cleanup',
]
```
Then load the configs:
```
i = config_load_configs(lCONFIGS)
log.init.info(f'loaded {i} configs')
```

29
configs/atexit-cleanup.py Normal file
View File

@ -0,0 +1,29 @@
# -*- mode: python; python-indent-offset: 4; tab-width: 0; encoding: utf-8-unix -*-
# This should be execed in config.py
import sys
import os
import atexit
@atexit.register
def atexit_cleanup():
lDels = [os.path.join(config.datadir, 'cookies'),
os.path.join(config.datadir, 'history.sqlite'),
]
bidir = os.path.join(config.datadir, 'webengine')
lDels += [os.path.join(bidir, 'Cookies'),
os.path.join(bidir, 'Cookies-journal'),
os.path.join(bidir, 'Favicons'),
os.path.join(bidir, 'Favicons-journal'),
os.path.join(bidir, 'History'),
os.path.join(bidir, 'History-journal'),
os.path.join(bidir, 'Network Persistent State'),
os.path.join(bidir, 'TransportSecurity'),
os.path.join(bidir, 'Visited Links'),
]
i = 0
for elt in lDels:
if os.path.exists(elt):
os.unlink(elt)
i += 1
sys.stderr.write(f"Cleaned up {i} files\n")

33
configs/chrome-urls.py Normal file
View File

@ -0,0 +1,33 @@
# -*- mode: python; python-indent-offset: 4; tab-width: 0; encoding: utf-8-unix -*-
# This should be execed in config.py
# https://cnman.github.io/chrome-urls.html
# not chrome://history/"
config.unbind("cd") # download-clear
config.bind("cA", "open chrome://accessibility/")
config.bind("cB", "open chrome://blob-internals/")
config.bind("cb", "open qute://bindings/")
config.bind("cC", "open chrome://appcache-internals")
config.bind("cD", "open chrome://sandbox")
config.bind("cE", "open chrome://serviceworker-internals/")
config.bind("ce", "open qute://pyeval")
config.bind("cG", "open chrome://gpu/")
config.bind("cH", "open chrome://histograms/")
config.bind("ch", "open qute://help")
config.bind("cI", "open chrome://indexeddb-internals/")
config.bind("cl", "open qute://log")
config.bind("cM", "open chrome://media-internals/")
config.bind("cm", "open qute://bookmarks/")
config.bind("cN", "open chrome://net-internals/")
config.bind("cQ", "open chrome://quota-internals/")
#config.bind("cp", "open qute://process")
#config.bind("cr", "open qute://resource")
config.bind("cs", "open qute://settings")
config.bind("cT", "open chrome://qt")
config.bind("ct", "open qute://start")
config.bind("cU", "open chrome://user-actions/")
config.bind("cv", "open qute://version/")
config.bind("cW", "open chrome://webrtc-internals/")
config.bind("cX", "open chrome://webrtc-logs")
# There does not seem to be a way currently to disable service workers
# the feature in the Chrome browser.

139
configs/chromium-flags.py Normal file
View File

@ -0,0 +1,139 @@
# -*- mode: python; python-indent-offset: 4; tab-width: 0; encoding: utf-8-unix -*-
# This should be execed in config.py
# Test by visiting https://coveryourtracks.eff.org/
# https://niek.github.io/chrome-features/
# https://peter.sh/experiments/chromium-command-line-switches/
# this may interfere wuth some logins
c.content.canvas_reading = False
# just passes --disable-reading-from-canvas
# Which Chromium process model to use.
# Alternative process models use less resources, but decrease security and robustness.
# - https://www.chromium.org/developers/design-documents/process-models
# - https://doc.qt.io/qt-6/qtwebengine-features.html#process-models
c.qt.chromium.process_model = 'process-per-site'
# passes --process-per-site
# qutebrowser adds --disable-accelerated-2d-canvas
# qutebrowser starts with these:
# ['--webEngineArgs', '--enable-features=WebRTCPipeWireCapturer', '--disable-reading-from-canvas', '--touch-events=disabled', '--force-webrtc-ip-handling-policy=disable_non_proxied_udp', '--process-per-site', '--disable-accelerated-2d-canvas']
enable = ['WebRTCPipeWireCapturer']
disable = []
# I was thinking of tightening up privacy and security by adding some
# well-known flags to qt.args. I broke them up into 4 categories
# and harvested a list of suggestions from the net.
# Many may be chromium flags not used by QtWebEngine.
# https://github.com/qutebrowser/qutebrowser/issues/5378
# https://github.com/qt/qtwebengine/blob/v5.14.2/src/core/web_engine_context.cpp#L478-L690
cacheM = 100
#? are disabled for now
misc = ['log-level=3'
f"disk-cache-size={cacheM}M",
f"media-cache-size={cacheM}M"
]
# GPU tuning - YMMV
misc += [
# https://github.com/qutebrowser/qutebrowser/discussions/7917
'use-gl=desktop', # or use-gl=egl on wayland
'enable-accelerated-video-decode', # may make thing slower
#? enable-features=VaapiVideoDecoder
#? enable-features=VaapiVideoDecodeLinuxGL
#? cast-streaming-force-disable-hardware-h264
#? cast-streaming-force-disable-hardware-vp8
#? cast-streaming-force-enable-hardware-h264
#? cast-streaming-force-enable-hardware-vp8
]
#? c.qt.workarounds.disable_accelerated_2d_canvas = 'never'
## chromium security
## https://clienttest.ssllabs.com:8443/ssltest/viewMyClient.html
# # 'auth-server-whitelist=*.example.com',
security = [ 'ssl-version-min=tls1.3',
'ssl-version-fallback-min=tls1.2',
]
disable += ['EnableServiceWorkersForChromeUntrusted']
## chromium privacy
# https://www.reddit.com/r/privacytoolsIO/comments/kgqmnm/how_to_tweak_chrome_flags_for_privacy_and/
# --disable-plugins-discovery
# --disable-preconnect
# --dns-prefetch-disable
# --no-pings
# --enable-strict-powerful-feature-restrictions
privacy = [
#? 'use-dns-https-svcb-alpn=disabled',
#? 'show-autofill-type-predictions=disabled',
#? 'back-forward-cache=disabled',
'disable-plugins-discovery',
'disable-preconnect',
'dns-prefetch-disable',
'no-pings',
#? 'disable-webgl',
#? 'media-route-dial-provider',
#? 'allow-silent-push=disabled',
'disable-notificatons',
'webview-force-disable-3pcs',
]
# https://www.reddit.com/r/privacytoolsIO/comments/kgqmnm/how_to_tweak_chrome_flags_for_privacy_and/
privacy += [
'strict-origin-isolation',
'reduced-referrer-granularity'
]
# Overall, these two should be enough. You can also consider these flags but imo these doesn't add much benefits
#disallow-doc-written-script-loads
#cookies-without-same-site-must-be-secure
#force-empty-CORB-and-CORS-allowlist
#cors-for-content-scripts
#enable-noscript-previews
disable += ['DnsOverHttps', 'DnsOverHttpsUpgrade']
# a matter of taste
# https://nira.com/chrome-flags/
taste = [
#? 'proactive-tab-freeze-and-discard=enabled',
#? 'enable-lazy-image-loading=enabled',
#? 'omnibox-ui-hide-steady-state-url-scheme=enabled',
#? 'omnibox-ui-hide-steady-state-url-trivial-subdomains=enabled',
#? 'memory-saver-memory-usage-in-hovercards=enabled',
#? 'block-insecure-private-network-requests=disabled',
#no 'disable-remote-fonts',
'disable-remote-playback-api',
]
if True:
c.qt.args = security + privacy + misc + taste + \
['enable-features=' +','.join(enable),
'disable-features=' +','.join(disable)]
del security, privacy, misc, taste, enable, disable
# how to disable these?
# TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013) WEAK 128
# TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014) WEAK 256
# TLS_RSA_WITH_AES_128_GCM_SHA256 (0x9c) WEAK 128
# TLS_RSA_WITH_AES_256_GCM_SHA384 (0x9d) WEAK 256
# TLS_RSA_WITH_AES_128_CBC_SHA (0x2f) WEAK 128
# TLS_RSA_WITH_AES_256_CBC_SHA (0x35) WEAK
# See also the env variables
#QT_LOGGING_RULES=qt.webenginecontext.debug=true
#QT_QUICK_BACKEND or QMLSCENE_DEVICE # string
#QT_OPENGL # ; set or not
#QTWEBENGINE_CHROMIUM_FLAGS # space sep. string
#QTWEBENGINE_DISABLE_SANDBOX # ; set or not
#QTWEBENGINE_DISABLE_GPU_THREAD # ; set or not
# import os
# export QTWEBENGINE_DICTIONARIES_PATH /usr/share/myspell

View File

@ -0,0 +1,56 @@
import re
import sys
try:
import qutebrowser.api
from qutebrowser.api import interceptor
from qutebrowser.extensions.interceptors import Request
from qutebrowser.qt.core import QUrl
from qutebrowser.utils import debug, log
except ImportError:
sys.stderr.write('qutebrowser not imported\n')
else:
# redirect on cloudflare
def filter_cf(thereq: Request) -> None:
"""Block given request if necessary
Called by a signal"""
from qutebrowser.utils import objreg
from qutebrowser.mainwindow import mainwindow
url = thereq.request_url
if url.query().startswith('ray='):
log.network.debug(f"filter_cf thereq.first_party_url={thereq.first_party_url} {repr(thereq)}")
if thereq.is_blocked is False and (
url.query().startswith('__cf_chl_rt_tk=') or \
url.host() == 'challenges.cloudflare.com' or \
url.path().startswith('/cdn-cgi/challenge-platform/h/')):
# b/turnstile/if/ov2/av0/rcv0/0/33izj/
# g/orchestrate/chl_page/v1
url.setPath('/web' + '/*/' +thereq.first_party_url.host()
+thereq.first_party_url.path())
url.setHost('web.archive.org')
# "__cf_chl_rt_tk="[A-Za-z0-9.-]*"
url.setQuery(None)
log.network.info(f"config.filter_cf REDIRECTING to {url}")
thereq.request_url = url
thereq._redirected = True
thereq.is_blocked = True
if False:
# doesn't work at least on PyQt5 linux
thereq.redirect(url)
elif True:
#
thereq.block()
from qutebrowser.config import config
# expanded open_desktopservices_url
target = objreg.last_opened_window()
#? target = config.val.new_instance_open_target
window = mainwindow.get_window(via_ipc=False, target=target)
tab = window.tabbed_browser._current_tab()
window.tabbed_browser.tabopen(url,
background=False, related=True)
# NO window.maybe_raise()
# crimeflare tabs keep refreshing infinitely
window.tabbed_browser.close_tab(tab)
interceptor.register(filter_cf)
log.init.debug(f"loaded filter_cf interceptor")

View File

@ -0,0 +1,25 @@
import re
import sys
try:
import qutebrowser.api
from qutebrowser.api import interceptor
from qutebrowser.extensions.interceptors import Request
from qutebrowser.qt.core import QUrl
from qutebrowser.utils import debug, log
except ImportError:
sys.stderr.write('qutebrowser not imported\n')
else:
# Block youtube ads
def filter_yt(info: Request) -> None:
"""Block given request if necessary"""
lYT_URLS = ( "www.youtube.com", "youtube.com", "youtu.be" )
url = info.request_url
if url.host() in lYT_URLS \
and url.path() == "/get_video_info" \
and "&adformat=" in url.query():
log.network.info(f"Blocking to {url}")
info.block()
interceptor.register(filter_yt)
log.init.debug(f"loaded filter_yt interceptor")

166
configs/patch-qute3.1.0.py Normal file
View File

@ -0,0 +1,166 @@
# -*- mode: python; python-indent-offset: 4; tab-width: 0; encoding: utf-8-unix -*-
import faulthandler
import logging
import sys
from typing import Iterator, Optional
import qutebrowser
from qutebrowser.qt import core as qtcore
from qutebrowser.utils import log
from qutebrowser.utils.qtlog import qt_message_handler
def my_qt_message_handler(msg_type: qtcore.QtMsgType,
context: qtcore.QMessageLogContext,
msg: Optional[str]) -> None:
"""Qt message handler to redirect qWarning etc. to the logging system.
Args:
msg_type: The level of the message.
context: The source code location of the message.
msg: The message text.
"""
# Mapping from Qt logging levels to the matching logging module levels.
# Note we map critical to ERROR as it's actually "just" an error, and fatal
# to critical.
qt_to_logging = {
qtcore.QtMsgType.QtDebugMsg: logging.DEBUG,
qtcore.QtMsgType.QtWarningMsg: logging.WARNING,
qtcore.QtMsgType.QtCriticalMsg: logging.ERROR,
qtcore.QtMsgType.QtFatalMsg: logging.CRITICAL,
qtcore.QtMsgType.QtInfoMsg: logging.INFO,
}
# Change levels of some well-known messages to debug so they don't get
# shown to the user.
#
# If a message starts with any text in suppressed_msgs, it's not logged as
# error.
suppressed_msgs = [
# PNGs in Qt with broken color profile
# https://bugreports.qt.io/browse/QTBUG-39788
('libpng warning: iCCP: Not recognizing known sRGB profile that has '
'been edited'),
'libpng warning: iCCP: known incorrect sRGB profile',
# Hopefully harmless warning
'OpenType support missing for script ',
# Error if a QNetworkReply gets two different errors set. Harmless Qt
# bug on some pages.
# https://bugreports.qt.io/browse/QTBUG-30298
('QNetworkReplyImplPrivate::error: Internal problem, this method must '
'only be called once.'),
# Sometimes indicates missing text, but most of the time harmless
'load glyph failed ',
# Harmless, see https://bugreports.qt.io/browse/QTBUG-42479
('content-type missing in HTTP POST, defaulting to '
'application/x-www-form-urlencoded. '
'Use QNetworkRequest::setHeader() to fix this problem.'),
# https://bugreports.qt.io/browse/QTBUG-43118
'Using blocking call!',
# Hopefully harmless
('"Method "GetAll" with signature "s" on interface '
'"org.freedesktop.DBus.Properties" doesn\'t exist'),
('"Method \\"GetAll\\" with signature \\"s\\" on interface '
'\\"org.freedesktop.DBus.Properties\\" doesn\'t exist\\n"'),
'WOFF support requires QtWebKit to be built with zlib support.',
# Weird Enlightment/GTK X extensions
'QXcbWindow: Unhandled client message: "_E_',
'QXcbWindow: Unhandled client message: "_ECORE_',
'QXcbWindow: Unhandled client message: "_GTK_',
# Happens on AppVeyor CI
'SetProcessDpiAwareness failed:',
# https://bugreports.qt.io/browse/QTBUG-49174
('QObject::connect: Cannot connect (null)::stateChanged('
'QNetworkSession::State) to '
'QNetworkReplyHttpImpl::_q_networkSessionStateChanged('
'QNetworkSession::State)'),
# https://bugreports.qt.io/browse/QTBUG-53989
("Image of format '' blocked because it is not considered safe. If "
"you are sure it is safe to do so, you can white-list the format by "
"setting the environment variable QTWEBKIT_IMAGEFORMAT_WHITELIST="),
# Installing Qt from the installer may cause it looking for SSL3 or
# OpenSSL 1.0 which may not be available on the system
"QSslSocket: cannot resolve ",
"QSslSocket: cannot call unresolved function ",
# When enabling debugging with QtWebEngine
("Remote debugging server started successfully. Try pointing a "
"Chromium-based browser to "),
# https://github.com/qutebrowser/qutebrowser/issues/1287
"QXcbClipboard: SelectionRequest too old",
# https://github.com/qutebrowser/qutebrowser/issues/2071
'QXcbWindow: Unhandled client message: ""',
# https://codereview.qt-project.org/176831
"QObject::disconnect: Unexpected null parameter",
# https://bugreports.qt.io/browse/QTBUG-76391
"Attribute Qt::AA_ShareOpenGLContexts must be set before "
"QCoreApplication is created.",
# Qt 6.4 beta 1: https://bugreports.qt.io/browse/QTBUG-104741
"GL format 0 is not supported",
# added
"(python3.11:3510667): Gtk-WARNING ",
]
# not using utils.is_mac here, because we can't be sure we can successfully
# import the utils module here.
if sys.platform == 'darwin':
suppressed_msgs += [
# https://bugreports.qt.io/browse/QTBUG-47154
('virtual void QSslSocketBackendPrivate::transmit() SSLRead '
'failed with: -9805'),
]
if not msg:
msg = "Logged empty message!"
if any(msg.strip().startswith(pattern) for pattern in suppressed_msgs):
level = logging.DEBUG
elif context.category == "qt.webenginecontext" and (
msg.strip().startswith("GL Type: ") or # Qt 6.3
msg.strip().startswith("GLImplementation:") # Qt 6.2
):
level = logging.DEBUG
else:
level = qt_to_logging[msg_type]
if context.line is None:
lineno = -1 # type: ignore[unreachable]
else:
lineno = context.line
if context.function is None:
func = 'none' # type: ignore[unreachable]
elif ':' in context.function:
func = '"{}"'.format(context.function)
else:
func = context.function
if context.category is None or context.category == 'default':
name = 'qt'
else:
name = 'qt-' + context.category
if msg.splitlines()[0] == ('This application failed to start because it '
'could not find or load the Qt platform plugin '
'"xcb".'):
# Handle this message specially.
msg += ("\n\nOn Archlinux, this should fix the problem:\n"
" pacman -S libxkbcommon-x11")
faulthandler.disable()
assert _args is not None
if _args.debug:
try:
stack = ''.join(traceback.format_stack())
except Exception as e:
log.misc.warn(f"Error formatting stack: {e}")
stack = None
else:
stack = None
record = log.qt.makeRecord(name=name, level=level, fn=context.file, lno=lineno,
msg=msg, args=(), exc_info=None, func=func,
sinfo=stack)
log.qt.handle(record)
qutebrowser.utils.qtlog.qt_message_handler = my_qt_message_handler

View File

@ -0,0 +1,28 @@
# privacy
c.content.geolocation = False
c.content.dns_prefetch = False
c.content.canvas_reading = False
c.content.webrtc_ip_handling_policy = 'disable-non-proxied-udp'
c.content.webgl = False
c.content.tls.certificate_errors = 'ask'
c.content.register_protocol_handler = 'ask'
c.content.notifications.show_origin = True
c.content.hyperlink_auditing = False
c.content.plugins = False
# The content.proxy_dns_requests setting is not available with the QtWebEngine backend!
# c.content.proxy_dns_requests = True
# Allow websites to record audio.
c.content.media.audio_capture = 'ask'
# Allow websites to record audio and video.
c.content.media.audio_video_capture = 'ask'
# Allow websites to record video
c.content.media.video_capture = 'ask'
# Enable the ad/host blocker
c.content.blocking.enabled = True
c.content.blocking.hosts.block_subdomains = True

35
configs/search-engines.py Normal file
View File

@ -0,0 +1,35 @@
# -*- mode: python; python-indent-offset: 4; tab-width: 0; encoding: utf-8-unix -*-
# This should be execed in config.py
# Search engines which can be used via the address bar. Maps a search
# engine name (such as `DEFAULT`, or `ddg`) to a URL with a `{}`
# placeholder. The placeholder will be replaced by the search term, use
# `{{` and `}}` for literal `{`/`}` braces. The following further
# placeholds are defined to configure how special characters in the
# search terms are replaced by safe characters (called 'quoting'): *
# `{}` and `{semiquoted}` quote everything except slashes; this is the
# most sensible choice for almost all search engines (for the search
# term `slash/and&amp` this placeholder expands to `slash/and%26amp`).
# * `{quoted}` quotes all characters (for `slash/and&amp` this
# placeholder expands to `slash%2Fand%26amp`). * `{unquoted}` quotes
# nothing (for `slash/and&amp` this placeholder expands to
# `slash/and&amp`). The search engine named `DEFAULT` is used when
# `url.auto_search` is turned on and something else than a URL was
# entered to be opened. Other search engines can be used by prepending
# the search engine name to the search term, e.g. `:open google
# qutebrowser`.
# Type: Dict
c.url.searchengines = {
'DEFAULT': 'https://www.startpage.com/sp/search?query={}&cat=web&pl=opensearch&language=english',
'sC': 'http://cht.sh/{}',
'sD': 'https://duckduckgo.com/html?q={}',
'sG': 'https://github.com/NYANLAUNCHER?tab=repositories&q={}',
'sI': 'https://www.dictionary.com/browse/{}',
'sJ': 'https://mojeek.com/?q={}',
'sM': 'https://metager.org/meta/meta.ger3?eingabe={}&focus=web&ua=1',
'sO': 'https://odysee.com/$/search?q={}',
'sS': 'https://www.startpage.com/sp/search?query={}&cat=web&pl=opensearch&language=english',
'sX': 'https://searx.tiekoetter.com/?q={}',
'sY': 'https://www.youtube.com/results?search_query={}',
}

8
configs/tab-manager.py Normal file
View File

@ -0,0 +1,8 @@
# -*- mode: python; python-indent-offset: 4; tab-width: 0; encoding: utf-8-unix -*-
# This should be execed in config.py
config.bind("zA", "spawn --userscript $HOME/.config/qutebrowser/userscripts/tab-manager/tab-manager.py $HOME/.local/share/qutebrowser/sessions/ save-all -o -f")
config.bind("zO", "spawn --userscript $HOME/.config/qutebrowser/userscripts/tab-manager/tab-manager.py $HOME/.local/share/qutebrowser/sessions/ open -f")
config.bind("zS", "spawn --userscript $HOME/.config/qutebrowser/userscripts/tab-manager/tab-manager.py $HOME/.local/share/qutebrowser/sessions/ save -f")
config.bind("zD", "spawn --userscript $HOME/.config/qutebrowser/userscripts/tab-manager/tab-manager.py $HOME/.local/share/qutebrowser/sessions/ delete -f")
config.bind("zH", "spawn --userscript $HOME/.config/qutebrowser/userscripts/tab-manager/tab-manager.py $HOME/.local/share/qutebrowser/sessions/ help")

21
configs/user-agents.py Normal file
View File

@ -0,0 +1,21 @@
# -*- mode: python; python-indent-offset: 4; tab-width: 0; encoding: utf-8-unix -*-
# This should be execed in config.py
# User agent to send. The following placeholders are defined: *
# `{os_info}`: Something like "X11; Linux x86_64". * `{webkit_version}`:
# The underlying WebKit version (set to a fixed value with
# QtWebEngine). * `{qt_key}`: "Qt" for QtWebKit, "QtWebEngine" for
# QtWebEngine. * `{qt_version}`: The underlying Qt version. *
# `{upstream_browser_key}`: "Version" for QtWebKit, "Chrome" for
# QtWebEngine. * `{upstream_browser_version}`: The corresponding
# Safari/Chrome version. * `{qutebrowser_version}`: The currently
# running qutebrowser version. The default value is equal to the
# unchanged user agent of QtWebKit/QtWebEngine. Note that the value
# read from JavaScript is always the global value. With QtWebEngine
# between 5.12 and 5.14 (inclusive), changing the value exposed to
# JavaScript requires a restart.
# Type: FormatString
config.set('content.headers.user_agent', 'Mozilla/5.0 ({os_info}) AppleWebKit/{webkit_version} (KHTML, like Gecko) {upstream_browser_key}/{upstream_browser_version} Safari/{webkit_version}', 'https://web.whatsapp.com/')
config.set('content.headers.user_agent', 'Mozilla/5.0 ({os_info}; rv:90.0) Gecko/20100101 Firefox/90.0', 'https://accounts.google.com/*')
config.set('content.headers.user_agent', 'Mozilla/5.0 ({os_info}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99 Safari/537.36', 'https://*.slack.com/*')