add support for config through url

This commit is contained in:
Joao Ramos 2022-09-07 18:25:43 +02:00
parent 32ad39d0e1
commit 27e16e5e2c
6 changed files with 78 additions and 3 deletions

View File

@ -1,7 +1,12 @@
from inspect import Attribute
from app.utils.misc import read_config_bool
from flask import current_app
import os
import re
from base64 import urlsafe_b64encode
import pickle
from cryptography.fernet import Fernet
import hashlib
class Config:
@ -29,6 +34,7 @@ class Config:
self.view_image = read_config_bool('WHOOGLE_CONFIG_VIEW_IMAGE')
self.get_only = read_config_bool('WHOOGLE_CONFIG_GET_ONLY')
self.anon_view = read_config_bool('WHOOGLE_CONFIG_ANON_VIEW')
self.preferences_key = os.getenv('WHOOGLE_CONFIG_PREFERENCES_KEY', '')
self.accept_language = False
self.safe_keys = [
@ -71,6 +77,15 @@ class Config:
if not name.startswith("__")
and (type(attr) is bool or type(attr) is str)}
def get_attrs(self):
return {name: attr for name, attr in self.__dict__.items()
if not name.startswith("__")
and (type(attr) is bool or type(attr) is str)}
@property
def preferences(self) -> str:
return self._encode_preferences()
def is_safe_key(self, key) -> bool:
"""Establishes a group of config options that are safe to set
in the url.
@ -109,6 +124,13 @@ class Config:
Returns:
Config -- a modified config object
"""
if 'preferences' in params:
params_new = self._decode_preferences(params['preferences'])
# if preferences leads to an empty dictionary it means preferences
# parameter was not decrypted successfully
if len(params_new):
params = params_new
for param_key in params.keys():
if not self.is_safe_key(param_key):
continue
@ -116,6 +138,8 @@ class Config:
if param_val == 'off':
param_val = False
elif isinstance(param_val, bool):
pass
elif param_val.isdigit():
param_val = int(param_val)
@ -135,3 +159,25 @@ class Config:
param_str = param_str + f'&{safe_key}={self[safe_key]}'
return param_str
def _get_fernet_key(self, password: str) -> bytes:
hash_object = hashlib.md5(password.encode())
key = urlsafe_b64encode(hash_object.hexdigest().encode())
return key
def _encode_preferences(self) -> str:
if self.preferences_key == '':
return ''
encoded_preferences = pickle.dumps(self.get_attrs())
key = self._get_fernet_key(self.preferences_key)
return Fernet(key).encrypt(encoded_preferences).decode()
def _decode_preferences(self, preferences: str) -> dict:
try:
key = self._get_fernet_key(self.preferences_key)
config = Fernet(key).decrypt(preferences.encode())
config = pickle.loads(config)
except Exception:
config = {}
return config

View File

@ -193,6 +193,9 @@ def index():
session['error_message'] = ''
return render_template('error.html', error_message=error_message)
# Update user config if specified in search args
g.user_config = g.user_config.from_params(g.request_params)
return render_template('index.html',
has_update=app.config['HAS_UPDATE'],
languages=app.config['LANGUAGES'],
@ -231,7 +234,8 @@ def opensearch():
main_url=opensearch_url,
request_type='' if get_only else 'method="post"',
search_type=request.args.get('tbm'),
search_name=get_search_name(request.args.get('tbm'))
search_name=get_search_name(request.args.get('tbm')),
preferences=g.user_config.preferences
), 200, {'Content-Type': 'application/xml'}
@ -334,6 +338,7 @@ def search():
tabs = get_tabs_content(app.config['HEADER_TABS'],
search_util.full_query,
search_util.search_type,
g.user_config.preferences,
translation)
# Feature to display currency_card
@ -342,6 +347,9 @@ def search():
html_soup = bsoup(str(response), 'html.parser')
response = add_currency_card(html_soup, conversion)
preferences = g.user_config.preferences
home_url = f"home?preferences={preferences}" if preferences else "home"
return render_template(
'display.html',
has_update=app.config['HAS_UPDATE'],
@ -365,6 +373,7 @@ def search():
version_number=app.config['VERSION_NUMBER'],
search_header=render_template(
'header.html',
home_url=home_url,
config=g.user_config,
translation=translation,
languages=app.config['LANGUAGES'],

View File

@ -4,13 +4,16 @@
<form class="search-form header"
id="search-form"
method="{{ 'GET' if config.get_only else 'POST' }}">
<a class="logo-link mobile-logo" href="home">
<a class="logo-link mobile-logo" href="{{ home_url }}">
<div id="mobile-header-logo">
{{ logo|safe }}
</div>
</a>
<div class="H0PQec mobile-input-div">
<div class="autocomplete-mobile esbc autocomplete">
{% if config.preferences %}
<input type="hidden" name="preferences" value="{{ config.preferences }}" />
{% endif %}
<input
id="search-bar"
class="mobile-search-bar"
@ -57,7 +60,7 @@
{% else %}
<header>
<div class="logo-div">
<a class="logo-link" href="home">
<a class="logo-link" href="{{ home_url }}">
<div class="desktop-header-logo">
{{ logo|safe }}
</div>
@ -70,6 +73,9 @@
method="{{ 'GET' if config.get_only else 'POST' }}">
<div class="autocomplete header-autocomplete">
<div style="width: 100%; display: flex">
{% if config.preferences %}
<input type="hidden" name="preferences" value="{{ config.preferences }}" />
{% endif %}
<input
id="search-bar"
autocapitalize="none"

View File

@ -66,6 +66,9 @@
<form id="search-form" action="search" method="{{ 'get' if config.get_only else 'post' }}">
<div class="search-fields">
<div class="autocomplete">
{% if config.preferences %}
<input type="hidden" name="preferences" value="{{ config.preferences }}" />
{% endif %}
<input
type="text"
name="q"
@ -233,6 +236,10 @@
{{ config.style.replace('\t', '') }}
</textarea>
</div>
<div class="config-div config-div-pref-url">
<label for="config-pref-url">{{ translation['config-url'] }}: </label>
<input type="text" name="pref-url" id="config-pref-url" value="{{ config.url }}?preferences={{ config.preferences }}">
</div>
</div>
<div class="config-div config-buttons">
<input type="submit" id="config-load" value="{{ translation['load'] }}">&nbsp;

View File

@ -17,6 +17,9 @@
{% if search_type %}
<Param name="tbm" value="{{ search_type }}"/>
{% endif %}
{% if preferences %}
<Param name="preferences" value="{{ preferences }}"/>
{% endif %}
</Url>
<Url type="application/x-suggestions+json" {{ request_type|safe }} template="{{ main_url }}/autocomplete">
<Param name="q" value="{searchTerms}"/>

View File

@ -393,6 +393,7 @@ def add_currency_card(soup: BeautifulSoup,
def get_tabs_content(tabs: dict,
full_query: str,
search_type: str,
preferences: str,
translation: dict) -> dict:
"""Takes the default tabs content and updates it according to the query.
@ -416,6 +417,9 @@ def get_tabs_content(tabs: dict,
if tab_content['tbm'] is not None:
query = f"{query}&tbm={tab_content['tbm']}"
if preferences:
query = f"{query}&preferences={preferences}"
tab_content['href'] = tab_content['href'].format(query=query)