diff --git a/doc/generate_configpanel_and_formoptions_doc.py b/doc/generate_configpanel_and_formoptions_doc.py index 061ebf77c..156a769fc 100644 --- a/doc/generate_configpanel_and_formoptions_doc.py +++ b/doc/generate_configpanel_and_formoptions_doc.py @@ -1,4 +1,3 @@ -import sys import ast import datetime import subprocess @@ -22,8 +21,8 @@ def get_current_commit(): current_commit = get_current_commit() -def print_config_panel_docs(): +def print_config_panel_docs(): fname = "../src/utils/configpanel.py" content = open(fname).read() @@ -40,7 +39,6 @@ def print_config_panel_docs(): ] ) - print("## Configuration panel structure") for c in ConfigPanelClasses: @@ -54,7 +52,6 @@ def print_config_panel_docs(): def print_form_doc(): - fname = "../src/utils/form.py" content = open(fname).read() @@ -63,7 +60,9 @@ def print_form_doc(): tree = ast.parse(content) OptionClasses = [ - c for c in tree.body if isinstance(c, ast.ClassDef) and c.name.endswith("Option") + c + for c in tree.body + if isinstance(c, ast.ClassDef) and c.name.endswith("Option") ] OptionDocString = {} @@ -80,7 +79,11 @@ def print_form_doc(): elif c.body[1].target.id == "type": option_type = c.body[1].value.attr - generaltype = c.bases[0].id.replace("Option", "").replace("Base", "").lower() if c.bases else None + generaltype = ( + c.bases[0].id.replace("Option", "").replace("Base", "").lower() + if c.bases + else None + ) docstring = ast.get_docstring(c) if docstring: @@ -89,7 +92,10 @@ def print_form_doc(): #### Properties - [common properties](#common-properties)""" - OptionDocString[option_type] = {"doc": docstring, "generaltype": generaltype} + OptionDocString[option_type] = { + "doc": docstring, + "generaltype": generaltype, + } # Dirty hack to have "BaseOption" as first and "BaseInputOption" as 2nd in list @@ -111,14 +117,18 @@ def print_form_doc(): elif option_type == "BaseInputOption": print("### Common inputs properties") else: - print(f"### `{option_type}`" + (f" ({infos['generaltype']})" if infos["generaltype"] else "")) + print( + f"### `{option_type}`" + + (f" ({infos['generaltype']})" if infos["generaltype"] else "") + ) print("") print(infos["doc"]) print("") print("---") + print( - f"""--- + rf"""--- title: Technical details for config panel structure and form option types template: docs taxonomy: diff --git a/src/app.py b/src/app.py index d71051931..ddaa6bccb 100644 --- a/src/app.py +++ b/src/app.py @@ -1939,7 +1939,7 @@ def _set_app_settings(app, settings): def _parse_app_version(v): if v == "?": - return (0,0) + return (0, 0) try: if "~" in v: diff --git a/src/authenticators/ldap_ynhuser.py b/src/authenticators/ldap_ynhuser.py index 8a2b10aa0..b5f279dc4 100644 --- a/src/authenticators/ldap_ynhuser.py +++ b/src/authenticators/ldap_ynhuser.py @@ -27,6 +27,7 @@ logger = logging.getLogger("yunohostportal.authenticators.ldap_ynhuser") URI = "ldap://localhost:389" USERDN = "uid={username},ou=users,dc=yunohost,dc=org" + # We want to save the password in the cookie, but we should do so in an encrypted fashion # This is needed because the SSO later needs to possibly inject the Basic Auth header # which includes the user's password @@ -41,7 +42,6 @@ USERDN = "uid={username},ou=users,dc=yunohost,dc=org" # The result is a string formatted as | # For example: ctl8kk5GevYdaA5VZ2S88Q==|yTAzCx0Gd1+MCit4EQl9lA== def encrypt(data): - alg = algorithms.AES(session_secret.encode()) iv = os.urandom(int(alg.block_size / 8)) @@ -53,8 +53,8 @@ def encrypt(data): iv_b64 = base64.b64encode(iv).decode() return data_enc_b64 + "|" + iv_b64 -def decrypt(data_enc_and_iv_b64): +def decrypt(data_enc_and_iv_b64): data_enc_b64, iv_b64 = data_enc_and_iv_b64.split("|") data_enc = base64.b64decode(data_enc_b64) iv = base64.b64decode(iv_b64) @@ -68,20 +68,16 @@ def decrypt(data_enc_and_iv_b64): class Authenticator(BaseAuthenticator): - name = "ldap_ynhuser" def _authenticate_credentials(self, credentials=None): - try: username, password = credentials.split(":", 1) except ValueError: raise YunohostError("invalid_credentials") def _reconnect(): - con = ldap.ldapobject.ReconnectLDAPObject( - URI, retry_max=2, retry_delay=0.5 - ) + con = ldap.ldapobject.ReconnectLDAPObject(URI, retry_max=2, retry_delay=0.5) con.simple_bind_s(USERDN.format(username=username), password) return con @@ -114,7 +110,6 @@ class Authenticator(BaseAuthenticator): return {"user": username, "pwd": encrypt(password)} def set_session_cookie(self, infos): - from bottle import response, request assert isinstance(infos, dict) @@ -126,8 +121,10 @@ class Authenticator(BaseAuthenticator): # See https://pyjwt.readthedocs.io/en/latest/usage.html#registered-claim-names # for explanations regarding nbf, exp "nbf": int(datetime.datetime.now().timestamp()), - "exp": int(datetime.datetime.now().timestamp()) + (7 * 24 * 3600), # One week validity # FIXME : does it mean the session suddenly expires after a week ? Can we somehow auto-renew it at every usage or something ? - "host": request.get_header('host'), + # FIXME : does it mean the session suddenly expires after a week ? Can we somehow auto-renew it at every usage or something ? + "exp": int(datetime.datetime.now().timestamp()) + + (7 * 24 * 3600), # One week validity + "host": request.get_header("host"), } new_infos.update(infos) @@ -142,12 +139,16 @@ class Authenticator(BaseAuthenticator): ) def get_session_cookie(self, raise_if_no_session_exists=True, decrypt_pwd=False): - from bottle import request try: token = request.get_cookie("yunohost.portal", default="").encode() - infos = jwt.decode(token, session_secret, algorithms="HS256", options={"require": ["id", "user", "exp", "nbf"]}) + infos = jwt.decode( + token, + session_secret, + algorithms="HS256", + options={"require": ["id", "user", "exp", "nbf"]}, + ) except Exception: if not raise_if_no_session_exists: return {"id": random_ascii()} @@ -170,7 +171,6 @@ class Authenticator(BaseAuthenticator): return infos def delete_session_cookie(self): - from bottle import response response.delete_cookie("yunohost.portal", path="/") diff --git a/src/utils/form.py b/src/utils/form.py index 5db9afcc2..97ae93de7 100644 --- a/src/utils/form.py +++ b/src/utils/form.py @@ -120,11 +120,11 @@ def evaluate_simple_ast(node, context=None): ): # left = evaluate_simple_ast(node.left, context) right = evaluate_simple_ast(node.right, context) - if type(node.op) == ast.Add: + if type(node.op) is ast.Add: if isinstance(left, str) or isinstance(right, str): # support 'I am ' + 42 left = str(left) right = str(right) - elif type(left) != type(right): # support "111" - "1" -> 110 + elif type(left) is type(right): # support "111" - "1" -> 110 left = float(left) right = float(right) @@ -144,7 +144,7 @@ def evaluate_simple_ast(node, context=None): left = float(left) right = float(right) except ValueError: - return type(operator) == ast.NotEq + return type(operator) is ast.NotEq try: return operators[type(operator)](left, right) except TypeError: # support "e" > 1 -> False like in JS @@ -1732,8 +1732,8 @@ class UserOption(BaseChoicesOption): cls, value: Union[str, None], values: Values ) -> Union[str, None]: # TODO remove calls to resources in validators (pydantic V2 should adress this) - #from yunohost.domain import _get_maindomain - #from yunohost.user import user_list, user_info + # from yunohost.domain import _get_maindomain + # from yunohost.user import user_list, user_info if value is None: # FIXME : in the past we looked for the user holding the "root@" alias diff --git a/src/utils/resources.py b/src/utils/resources.py index 7b6fd2457..ae0ddcc76 100644 --- a/src/utils/resources.py +++ b/src/utils/resources.py @@ -1086,6 +1086,7 @@ class AptDependenciesAppResource(AppResource): packages: List = [] packages_from_raw_bash: str = "" extras: Dict[str, Dict[str, Union[str, List]]] = {} + def __init__(self, properties: Dict[str, Any], *args, **kwargs): super().__init__(properties, *args, **kwargs)