Loading capif_backend/backoffice_service/controllers/configuration_controller.py +65 −1 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ import requests from flask import request, make_response import jsonschema from jsonschema import validate, ValidationError from ..utils.utils import is_snake_case, validate_snake_case_keys # create blueprint backoffice_routes Loading Loading @@ -58,6 +59,10 @@ def replace_configuration(): if not isinstance(new_config["settings"], dict) or not new_config["settings"]: return jsonify({"error": "'settings' debe ser un objeto con al menos una categoría"}), 400 error_response = validate_snake_case_keys(new_config["settings"]) if error_response: return error_response # Retorna el error si se encuentra una clave incorrecta return operations.replace_configuration(new_config) Loading Loading @@ -91,6 +96,37 @@ def add_new_config_setting(): return operations.add_new_config_setting(param_path, new_value) @configuration_routes.route("/configuration/remove-config-param", methods=["DELETE", "OPTIONS"]) @cross_origin() @jwt_required() def remove_configuration_param(): if request.method == "OPTIONS": return make_response("", 200) data = request.json param_path = data.get("param_path") if not param_path: return jsonify({"error": "param_path es requerido"}), 400 return operations.remove_configuration_param(param_path) @configuration_routes.route("/configuration/remove-config-category", methods=["DELETE", "OPTIONS"]) @cross_origin() @jwt_required() def remove_configuration_category(): if request.method == "OPTIONS": return make_response("", 200) data = request.json category_name = data.get("category_name") if not category_name: return jsonify({"error": "category_name es requerido"}), 400 return operations.remove_configuration_category(category_name) ### REGISTER CONFIGURATION ### Loading Loading @@ -159,3 +195,31 @@ def add_new_config_register_setting(): return jsonify({"error": "param_path y new_value son requeridos"}), 400 return operations.add_new_config_register_setting(param_path, new_value) @cross_origin() @configuration_routes.route("/configuration/register/remove-config-param", methods=["DELETE"]) @jwt_required() def remove_register_configuration_param(): """Elimina un parámetro dentro de una categoría en 'settings' en el register.""" data = request.json param_path = data.get("param_path") if not param_path: return jsonify({"error": "param_path es requerido"}), 400 return operations.remove_register_configuration_param(param_path) @cross_origin() @configuration_routes.route("/configuration/register/remove-config-category", methods=["DELETE"]) @jwt_required() def remove_register_configuration_category(): """Elimina una categoría completa en 'settings' en el register.""" data = request.json category_name = data.get("category_name") if not category_name: return jsonify({"error": "category_name es requerido"}), 400 return operations.remove_register_configuration_category(category_name) capif_backend/backoffice_service/core/operations.py +145 −1 Original line number Diff line number Diff line Loading @@ -1006,6 +1006,46 @@ class Operations: return jsonify({"error": str(e)}), 500 def remove_configuration_param(self, param_path): """ Elimina un parámetro dentro de una categoría en 'settings' """ url = "https://{}/helper/removeConfigParam".format(os.getenv('CAPIF_HOSTNAME')) payload = { "param_path": param_path } try: response = requests.delete( url, json=payload, verify="newcerts/ca_root.crt", cert=("newcerts/superadmin.crt", "newcerts/superadmin.key") ) response.raise_for_status() return jsonify(response.json()), response.status_code except requests.exceptions.RequestException as e: return jsonify({"error": str(e)}), 500 def remove_configuration_category(self, category_name): """ Elimina una categoría completa dentro de 'settings' """ url = "https://{}/helper/removeConfigCategory".format(os.getenv('CAPIF_HOSTNAME')) payload = { "category_name": category_name } try: response = requests.delete( url, json=payload, verify="newcerts/ca_root.crt", cert=("newcerts/superadmin.crt", "newcerts/superadmin.key") ) response.raise_for_status() return jsonify(response.json()), response.status_code except requests.exceptions.RequestException as e: return jsonify({"error": str(e)}), 500 ### REGISTER CONFIGURATION ### Loading Loading @@ -1292,3 +1332,107 @@ class Operations: except requests.exceptions.RequestException as e: return jsonify({"error": f"Error when adding config setting: {str(e)}"}), 500 def remove_register_configuration_param(self, param_path): """Elimina un parámetro dentro de una categoría en 'settings' en el register.""" def login(): """Obtiene el access token desde el servicio register.""" try: url = "https://{}/login".format(os.getenv('REGISTER_HOSTNAME')) response = requests.post( url, auth=HTTPBasicAuth(self.username, self.password), verify=False ) if response.status_code == 200: return response.json().get("access_token") except requests.exceptions.RequestException as e: return None return None def delete_param(token): """Realiza la solicitud DELETE para eliminar un parámetro específico.""" headers = { "Authorization": f"Bearer {token}", "Content-Type": "application/json" } payload = { "param_path": param_path } try: url = "https://{}/configuration/removeConfigParam".format(os.getenv('REGISTER_HOSTNAME')) response = requests.delete(url, json=payload, headers=headers, verify=False) return response except requests.exceptions.RequestException as e: return None try: # Obtener el token de autenticación access_token = login() if not access_token: return jsonify({"error": "No se pudo obtener el token de autenticación"}), 401 # Enviar la solicitud DELETE al servicio register response = delete_param(access_token) if response is None: return jsonify({"error": "No se pudo conectar con el servicio register"}), 500 return jsonify(response.json()), response.status_code except requests.exceptions.RequestException as e: return jsonify({"error": f"Error al eliminar el parámetro de configuración: {str(e)}"}), 500 def remove_register_configuration_category(self, category_name): """Elimina una categoría completa dentro de 'settings' en el register.""" def login(): """Obtiene el access token desde el servicio register.""" try: url = "https://{}/login".format(os.getenv('REGISTER_HOSTNAME')) response = requests.post( url, auth=HTTPBasicAuth(self.username, self.password), verify=False ) if response.status_code == 200: return response.json().get("access_token") except requests.exceptions.RequestException as e: return None return None def delete_category(token): """Realiza la solicitud DELETE para eliminar una categoría completa.""" headers = { "Authorization": f"Bearer {token}", "Content-Type": "application/json" } payload = { "category_name": category_name } try: url = "https://{}/configuration/removeConfigCategory".format(os.getenv('REGISTER_HOSTNAME')) response = requests.delete(url, json=payload, headers=headers, verify=False) return response except requests.exceptions.RequestException as e: return None try: # Obtener el token de autenticación access_token = login() if not access_token: return jsonify({"error": "No se pudo obtener el token de autenticación"}), 401 # Enviar la solicitud DELETE al servicio register response = delete_category(access_token) if response is None: return jsonify({"error": "No se pudo conectar con el servicio register"}), 500 return jsonify(response.json()), response.status_code except requests.exceptions.RequestException as e: return jsonify({"error": f"Error al eliminar la categoría de configuración: {str(e)}"}), 500 No newline at end of file capif_backend/backoffice_service/utils/utils.py 0 → 100644 +17 −0 Original line number Diff line number Diff line import re from flask import jsonify def is_snake_case(value): """Verifica si una clave está en snake_case (solo letras minúsculas, números y guiones bajos).""" return bool(re.match(r'^[a-z0-9_]+$', value)) # Verificar que TODAS las claves dentro de settings estén en snake_case def validate_snake_case_keys(obj, path="settings"): """Recorre el JSON validando que todas las claves estén en snake_case.""" for key, value in obj.items(): if not is_snake_case(key): return jsonify({"error": f"La clave '{path}.{key}' no está en snake_case"}), 400 if isinstance(value, dict): error_response = validate_snake_case_keys(value, f"{path}.{key}") if error_response: return error_response No newline at end of file capif_backend/newcerts/ca_root.crt +33 −33 Original line number Diff line number Diff line -----BEGIN CERTIFICATE----- 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 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDKDCCAhCgAwIBAgIUddmL+RrRmJYqaGCW90a7aunKX8gwDQYJKoZIhvcNAQEL BQAwEDEOMAwGA1UEAxMFY2FwaWYwHhcNMjUwMzEzMTEwNjMxWhcNMzAwMzEyMTEw NzAxWjAnMSUwIwYDVQQDExxjYXBpZiBJbnRlcm1lZGlhdGUgQXV0aG9yaXR5MIIB IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwKjD5AMkH4G0w+zCQWnziu1j CxyZ43BWZRTe75LllJ0YU3Y5SHNHZMgbY0wgLtuiMi5NLuHiOObvHcOsZR0/cYeR 9ZE22xWRfTBoHQK2lLPUX5BXaPuMCbZAI1e/A2iBJOII36o+F0Gf85qvmqv+N81j t14BwS7Kw6tYqMLVadbKWr6mSrSO8urp9ZcjVj4AXWZXWs75Rid+NXPVsyJUvO0f yUFchj9H/CH4Mh8jsw1onCQ5Eg1b2cZ9RAtJjkemxb9VlNNmZLJq1sMVyc2UHwu7 +Js4UQmkr2De+VG6GPeyCv2g7GzpnsIiIvNDo0LiBgAD8D3AdBTPToa6aBpdxQID MIIDKDCCAhCgAwIBAgIUBSmgesyprqmIkFI8uSWj66N4AkkwDQYJKoZIhvcNAQEL BQAwEDEOMAwGA1UEAxMFY2FwaWYwHhcNMjUwMzE0MDgxMDIzWhcNMzAwMzEzMDgx MDUzWjAnMSUwIwYDVQQDExxjYXBpZiBJbnRlcm1lZGlhdGUgQXV0aG9yaXR5MIIB IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtYod3Lpkqr0XmzIPMpBQtPaY nxTftboKbG/XDNVWLSYA1Tqh73RNof7i9cOFnDH3IpjrGHFyfhd9TuX276qDVIB1 sRIvb7+pprnY9FpIOEFYwOkkFeKMrh2obRwrLIj97PvUg7S2cUslfz3QXVE37GdJ zow6MGuDEdt9ICiyIsovEg93/+f/duGT1IhMUZXCjc6wTDjGVbUBBJ0sqt/idVHu RzQgiEyggRBgHvh4r9jzOjZ/11OCE8rxBH8Ya2aWedtgBSsdGRr4tArIrNw92yOZ 7qT7ZBLti26Ky7DxcwvcVCFI1nZz6w+BB5o3xyrLjfz6f1yjukEk5Dt6VRIx4QID AQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E FgQUBXH5rGoV6N566W2tuc9KTaEhPYswHwYDVR0jBBgwFoAUXcyCU8QlfEkYq9hr NVuLhi2GV2AwDQYJKoZIhvcNAQELBQADggEBANp/szFjdTGlAx13Jeut5Thyc5Co j7SlAsNJxxvEvnZiy8pekd7Bw/Rtdt+Y7+lsjDE2Eo31AbR70uxpsqNAL4Sp6KjI 7CAuQyddrY3vhybX17eOseRTBctapXMZLIRmU9JnIJdlmTRwUYWCZnkQdqpV7hy0 7oWyx3F49A7KdXLEme2c/GtkzlnDc5+6x2Ssj+1Z9y7gaShDguXTyJLEiN3a8KUF VilqY0aM02ffNqeRXuuqE+wsSZSrBCP5PIRPZPQSw1027E/5xCB8sWWjcvtqZSnL 2Wst0Np7eJQnnyQJ323UPX//6iMlchYihF9gllUN/eqRzHEc6fTiFskWL0I= FgQUideMERtvYbD0iGjSDNlM6zs1GMIwHwYDVR0jBBgwFoAUSw4fwcHvmyU96pr7 RNtUqd9m12gwDQYJKoZIhvcNAQELBQADggEBAJfhWCEwK10SIbWjgKB4rfJhyxmU PRtQ22TElZVYZXo8HvjbrL2qZbGLWVytvFPRSJjJuNiECTAcJF1zTeVXBBf8TEQ+ 9GO0ZH1Ir56utInhiJKIRKpigecUZsdWma0V+ZVKPa8oPETqsFdZ+xf51B30x1al 0cStYKy31CK25MGMNDD9PDsIn4MUhgvrJC3vvF3v3u32yEg15Pzu436Jqt7+GVO2 zO7wnK95gE2+ajQ7Nv2/ak0rdbcckLbJqDj6OkAAe67XgHsFcGUX1KdsiNJqBIJ+ fkQQkOnWyy+4eeYpWQD0606xLhrk/nclCvefcrZPytcV4PdZERC60/EZlFo= -----END CERTIFICATE----- capif_backend/newcerts/superadmin.crt +50 −50 Original line number Diff line number Diff line -----BEGIN CERTIFICATE----- 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 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDKDCCAhCgAwIBAgIUddmL+RrRmJYqaGCW90a7aunKX8gwDQYJKoZIhvcNAQEL BQAwEDEOMAwGA1UEAxMFY2FwaWYwHhcNMjUwMzEzMTEwNjMxWhcNMzAwMzEyMTEw NzAxWjAnMSUwIwYDVQQDExxjYXBpZiBJbnRlcm1lZGlhdGUgQXV0aG9yaXR5MIIB IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwKjD5AMkH4G0w+zCQWnziu1j CxyZ43BWZRTe75LllJ0YU3Y5SHNHZMgbY0wgLtuiMi5NLuHiOObvHcOsZR0/cYeR 9ZE22xWRfTBoHQK2lLPUX5BXaPuMCbZAI1e/A2iBJOII36o+F0Gf85qvmqv+N81j t14BwS7Kw6tYqMLVadbKWr6mSrSO8urp9ZcjVj4AXWZXWs75Rid+NXPVsyJUvO0f yUFchj9H/CH4Mh8jsw1onCQ5Eg1b2cZ9RAtJjkemxb9VlNNmZLJq1sMVyc2UHwu7 +Js4UQmkr2De+VG6GPeyCv2g7GzpnsIiIvNDo0LiBgAD8D3AdBTPToa6aBpdxQID MIIDKDCCAhCgAwIBAgIUBSmgesyprqmIkFI8uSWj66N4AkkwDQYJKoZIhvcNAQEL BQAwEDEOMAwGA1UEAxMFY2FwaWYwHhcNMjUwMzE0MDgxMDIzWhcNMzAwMzEzMDgx MDUzWjAnMSUwIwYDVQQDExxjYXBpZiBJbnRlcm1lZGlhdGUgQXV0aG9yaXR5MIIB IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtYod3Lpkqr0XmzIPMpBQtPaY nxTftboKbG/XDNVWLSYA1Tqh73RNof7i9cOFnDH3IpjrGHFyfhd9TuX276qDVIB1 sRIvb7+pprnY9FpIOEFYwOkkFeKMrh2obRwrLIj97PvUg7S2cUslfz3QXVE37GdJ zow6MGuDEdt9ICiyIsovEg93/+f/duGT1IhMUZXCjc6wTDjGVbUBBJ0sqt/idVHu RzQgiEyggRBgHvh4r9jzOjZ/11OCE8rxBH8Ya2aWedtgBSsdGRr4tArIrNw92yOZ 7qT7ZBLti26Ky7DxcwvcVCFI1nZz6w+BB5o3xyrLjfz6f1yjukEk5Dt6VRIx4QID AQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E FgQUBXH5rGoV6N566W2tuc9KTaEhPYswHwYDVR0jBBgwFoAUXcyCU8QlfEkYq9hr NVuLhi2GV2AwDQYJKoZIhvcNAQELBQADggEBANp/szFjdTGlAx13Jeut5Thyc5Co j7SlAsNJxxvEvnZiy8pekd7Bw/Rtdt+Y7+lsjDE2Eo31AbR70uxpsqNAL4Sp6KjI 7CAuQyddrY3vhybX17eOseRTBctapXMZLIRmU9JnIJdlmTRwUYWCZnkQdqpV7hy0 7oWyx3F49A7KdXLEme2c/GtkzlnDc5+6x2Ssj+1Z9y7gaShDguXTyJLEiN3a8KUF VilqY0aM02ffNqeRXuuqE+wsSZSrBCP5PIRPZPQSw1027E/5xCB8sWWjcvtqZSnL 2Wst0Np7eJQnnyQJ323UPX//6iMlchYihF9gllUN/eqRzHEc6fTiFskWL0I= FgQUideMERtvYbD0iGjSDNlM6zs1GMIwHwYDVR0jBBgwFoAUSw4fwcHvmyU96pr7 RNtUqd9m12gwDQYJKoZIhvcNAQELBQADggEBAJfhWCEwK10SIbWjgKB4rfJhyxmU PRtQ22TElZVYZXo8HvjbrL2qZbGLWVytvFPRSJjJuNiECTAcJF1zTeVXBBf8TEQ+ 9GO0ZH1Ir56utInhiJKIRKpigecUZsdWma0V+ZVKPa8oPETqsFdZ+xf51B30x1al 0cStYKy31CK25MGMNDD9PDsIn4MUhgvrJC3vvF3v3u32yEg15Pzu436Jqt7+GVO2 zO7wnK95gE2+ajQ7Nv2/ak0rdbcckLbJqDj6OkAAe67XgHsFcGUX1KdsiNJqBIJ+ fkQQkOnWyy+4eeYpWQD0606xLhrk/nclCvefcrZPytcV4PdZERC60/EZlFo= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- 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 -----END CERTIFICATE----- No newline at end of file Loading
capif_backend/backoffice_service/controllers/configuration_controller.py +65 −1 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ import requests from flask import request, make_response import jsonschema from jsonschema import validate, ValidationError from ..utils.utils import is_snake_case, validate_snake_case_keys # create blueprint backoffice_routes Loading Loading @@ -58,6 +59,10 @@ def replace_configuration(): if not isinstance(new_config["settings"], dict) or not new_config["settings"]: return jsonify({"error": "'settings' debe ser un objeto con al menos una categoría"}), 400 error_response = validate_snake_case_keys(new_config["settings"]) if error_response: return error_response # Retorna el error si se encuentra una clave incorrecta return operations.replace_configuration(new_config) Loading Loading @@ -91,6 +96,37 @@ def add_new_config_setting(): return operations.add_new_config_setting(param_path, new_value) @configuration_routes.route("/configuration/remove-config-param", methods=["DELETE", "OPTIONS"]) @cross_origin() @jwt_required() def remove_configuration_param(): if request.method == "OPTIONS": return make_response("", 200) data = request.json param_path = data.get("param_path") if not param_path: return jsonify({"error": "param_path es requerido"}), 400 return operations.remove_configuration_param(param_path) @configuration_routes.route("/configuration/remove-config-category", methods=["DELETE", "OPTIONS"]) @cross_origin() @jwt_required() def remove_configuration_category(): if request.method == "OPTIONS": return make_response("", 200) data = request.json category_name = data.get("category_name") if not category_name: return jsonify({"error": "category_name es requerido"}), 400 return operations.remove_configuration_category(category_name) ### REGISTER CONFIGURATION ### Loading Loading @@ -159,3 +195,31 @@ def add_new_config_register_setting(): return jsonify({"error": "param_path y new_value son requeridos"}), 400 return operations.add_new_config_register_setting(param_path, new_value) @cross_origin() @configuration_routes.route("/configuration/register/remove-config-param", methods=["DELETE"]) @jwt_required() def remove_register_configuration_param(): """Elimina un parámetro dentro de una categoría en 'settings' en el register.""" data = request.json param_path = data.get("param_path") if not param_path: return jsonify({"error": "param_path es requerido"}), 400 return operations.remove_register_configuration_param(param_path) @cross_origin() @configuration_routes.route("/configuration/register/remove-config-category", methods=["DELETE"]) @jwt_required() def remove_register_configuration_category(): """Elimina una categoría completa en 'settings' en el register.""" data = request.json category_name = data.get("category_name") if not category_name: return jsonify({"error": "category_name es requerido"}), 400 return operations.remove_register_configuration_category(category_name)
capif_backend/backoffice_service/core/operations.py +145 −1 Original line number Diff line number Diff line Loading @@ -1006,6 +1006,46 @@ class Operations: return jsonify({"error": str(e)}), 500 def remove_configuration_param(self, param_path): """ Elimina un parámetro dentro de una categoría en 'settings' """ url = "https://{}/helper/removeConfigParam".format(os.getenv('CAPIF_HOSTNAME')) payload = { "param_path": param_path } try: response = requests.delete( url, json=payload, verify="newcerts/ca_root.crt", cert=("newcerts/superadmin.crt", "newcerts/superadmin.key") ) response.raise_for_status() return jsonify(response.json()), response.status_code except requests.exceptions.RequestException as e: return jsonify({"error": str(e)}), 500 def remove_configuration_category(self, category_name): """ Elimina una categoría completa dentro de 'settings' """ url = "https://{}/helper/removeConfigCategory".format(os.getenv('CAPIF_HOSTNAME')) payload = { "category_name": category_name } try: response = requests.delete( url, json=payload, verify="newcerts/ca_root.crt", cert=("newcerts/superadmin.crt", "newcerts/superadmin.key") ) response.raise_for_status() return jsonify(response.json()), response.status_code except requests.exceptions.RequestException as e: return jsonify({"error": str(e)}), 500 ### REGISTER CONFIGURATION ### Loading Loading @@ -1292,3 +1332,107 @@ class Operations: except requests.exceptions.RequestException as e: return jsonify({"error": f"Error when adding config setting: {str(e)}"}), 500 def remove_register_configuration_param(self, param_path): """Elimina un parámetro dentro de una categoría en 'settings' en el register.""" def login(): """Obtiene el access token desde el servicio register.""" try: url = "https://{}/login".format(os.getenv('REGISTER_HOSTNAME')) response = requests.post( url, auth=HTTPBasicAuth(self.username, self.password), verify=False ) if response.status_code == 200: return response.json().get("access_token") except requests.exceptions.RequestException as e: return None return None def delete_param(token): """Realiza la solicitud DELETE para eliminar un parámetro específico.""" headers = { "Authorization": f"Bearer {token}", "Content-Type": "application/json" } payload = { "param_path": param_path } try: url = "https://{}/configuration/removeConfigParam".format(os.getenv('REGISTER_HOSTNAME')) response = requests.delete(url, json=payload, headers=headers, verify=False) return response except requests.exceptions.RequestException as e: return None try: # Obtener el token de autenticación access_token = login() if not access_token: return jsonify({"error": "No se pudo obtener el token de autenticación"}), 401 # Enviar la solicitud DELETE al servicio register response = delete_param(access_token) if response is None: return jsonify({"error": "No se pudo conectar con el servicio register"}), 500 return jsonify(response.json()), response.status_code except requests.exceptions.RequestException as e: return jsonify({"error": f"Error al eliminar el parámetro de configuración: {str(e)}"}), 500 def remove_register_configuration_category(self, category_name): """Elimina una categoría completa dentro de 'settings' en el register.""" def login(): """Obtiene el access token desde el servicio register.""" try: url = "https://{}/login".format(os.getenv('REGISTER_HOSTNAME')) response = requests.post( url, auth=HTTPBasicAuth(self.username, self.password), verify=False ) if response.status_code == 200: return response.json().get("access_token") except requests.exceptions.RequestException as e: return None return None def delete_category(token): """Realiza la solicitud DELETE para eliminar una categoría completa.""" headers = { "Authorization": f"Bearer {token}", "Content-Type": "application/json" } payload = { "category_name": category_name } try: url = "https://{}/configuration/removeConfigCategory".format(os.getenv('REGISTER_HOSTNAME')) response = requests.delete(url, json=payload, headers=headers, verify=False) return response except requests.exceptions.RequestException as e: return None try: # Obtener el token de autenticación access_token = login() if not access_token: return jsonify({"error": "No se pudo obtener el token de autenticación"}), 401 # Enviar la solicitud DELETE al servicio register response = delete_category(access_token) if response is None: return jsonify({"error": "No se pudo conectar con el servicio register"}), 500 return jsonify(response.json()), response.status_code except requests.exceptions.RequestException as e: return jsonify({"error": f"Error al eliminar la categoría de configuración: {str(e)}"}), 500 No newline at end of file
capif_backend/backoffice_service/utils/utils.py 0 → 100644 +17 −0 Original line number Diff line number Diff line import re from flask import jsonify def is_snake_case(value): """Verifica si una clave está en snake_case (solo letras minúsculas, números y guiones bajos).""" return bool(re.match(r'^[a-z0-9_]+$', value)) # Verificar que TODAS las claves dentro de settings estén en snake_case def validate_snake_case_keys(obj, path="settings"): """Recorre el JSON validando que todas las claves estén en snake_case.""" for key, value in obj.items(): if not is_snake_case(key): return jsonify({"error": f"La clave '{path}.{key}' no está en snake_case"}), 400 if isinstance(value, dict): error_response = validate_snake_case_keys(value, f"{path}.{key}") if error_response: return error_response No newline at end of file
capif_backend/newcerts/ca_root.crt +33 −33 Original line number Diff line number Diff line -----BEGIN CERTIFICATE----- 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 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDKDCCAhCgAwIBAgIUddmL+RrRmJYqaGCW90a7aunKX8gwDQYJKoZIhvcNAQEL BQAwEDEOMAwGA1UEAxMFY2FwaWYwHhcNMjUwMzEzMTEwNjMxWhcNMzAwMzEyMTEw NzAxWjAnMSUwIwYDVQQDExxjYXBpZiBJbnRlcm1lZGlhdGUgQXV0aG9yaXR5MIIB IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwKjD5AMkH4G0w+zCQWnziu1j CxyZ43BWZRTe75LllJ0YU3Y5SHNHZMgbY0wgLtuiMi5NLuHiOObvHcOsZR0/cYeR 9ZE22xWRfTBoHQK2lLPUX5BXaPuMCbZAI1e/A2iBJOII36o+F0Gf85qvmqv+N81j t14BwS7Kw6tYqMLVadbKWr6mSrSO8urp9ZcjVj4AXWZXWs75Rid+NXPVsyJUvO0f yUFchj9H/CH4Mh8jsw1onCQ5Eg1b2cZ9RAtJjkemxb9VlNNmZLJq1sMVyc2UHwu7 +Js4UQmkr2De+VG6GPeyCv2g7GzpnsIiIvNDo0LiBgAD8D3AdBTPToa6aBpdxQID MIIDKDCCAhCgAwIBAgIUBSmgesyprqmIkFI8uSWj66N4AkkwDQYJKoZIhvcNAQEL BQAwEDEOMAwGA1UEAxMFY2FwaWYwHhcNMjUwMzE0MDgxMDIzWhcNMzAwMzEzMDgx MDUzWjAnMSUwIwYDVQQDExxjYXBpZiBJbnRlcm1lZGlhdGUgQXV0aG9yaXR5MIIB IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtYod3Lpkqr0XmzIPMpBQtPaY nxTftboKbG/XDNVWLSYA1Tqh73RNof7i9cOFnDH3IpjrGHFyfhd9TuX276qDVIB1 sRIvb7+pprnY9FpIOEFYwOkkFeKMrh2obRwrLIj97PvUg7S2cUslfz3QXVE37GdJ zow6MGuDEdt9ICiyIsovEg93/+f/duGT1IhMUZXCjc6wTDjGVbUBBJ0sqt/idVHu RzQgiEyggRBgHvh4r9jzOjZ/11OCE8rxBH8Ya2aWedtgBSsdGRr4tArIrNw92yOZ 7qT7ZBLti26Ky7DxcwvcVCFI1nZz6w+BB5o3xyrLjfz6f1yjukEk5Dt6VRIx4QID AQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E FgQUBXH5rGoV6N566W2tuc9KTaEhPYswHwYDVR0jBBgwFoAUXcyCU8QlfEkYq9hr NVuLhi2GV2AwDQYJKoZIhvcNAQELBQADggEBANp/szFjdTGlAx13Jeut5Thyc5Co j7SlAsNJxxvEvnZiy8pekd7Bw/Rtdt+Y7+lsjDE2Eo31AbR70uxpsqNAL4Sp6KjI 7CAuQyddrY3vhybX17eOseRTBctapXMZLIRmU9JnIJdlmTRwUYWCZnkQdqpV7hy0 7oWyx3F49A7KdXLEme2c/GtkzlnDc5+6x2Ssj+1Z9y7gaShDguXTyJLEiN3a8KUF VilqY0aM02ffNqeRXuuqE+wsSZSrBCP5PIRPZPQSw1027E/5xCB8sWWjcvtqZSnL 2Wst0Np7eJQnnyQJ323UPX//6iMlchYihF9gllUN/eqRzHEc6fTiFskWL0I= FgQUideMERtvYbD0iGjSDNlM6zs1GMIwHwYDVR0jBBgwFoAUSw4fwcHvmyU96pr7 RNtUqd9m12gwDQYJKoZIhvcNAQELBQADggEBAJfhWCEwK10SIbWjgKB4rfJhyxmU PRtQ22TElZVYZXo8HvjbrL2qZbGLWVytvFPRSJjJuNiECTAcJF1zTeVXBBf8TEQ+ 9GO0ZH1Ir56utInhiJKIRKpigecUZsdWma0V+ZVKPa8oPETqsFdZ+xf51B30x1al 0cStYKy31CK25MGMNDD9PDsIn4MUhgvrJC3vvF3v3u32yEg15Pzu436Jqt7+GVO2 zO7wnK95gE2+ajQ7Nv2/ak0rdbcckLbJqDj6OkAAe67XgHsFcGUX1KdsiNJqBIJ+ fkQQkOnWyy+4eeYpWQD0606xLhrk/nclCvefcrZPytcV4PdZERC60/EZlFo= -----END CERTIFICATE-----
capif_backend/newcerts/superadmin.crt +50 −50 Original line number Diff line number Diff line -----BEGIN CERTIFICATE----- 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 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDKDCCAhCgAwIBAgIUddmL+RrRmJYqaGCW90a7aunKX8gwDQYJKoZIhvcNAQEL BQAwEDEOMAwGA1UEAxMFY2FwaWYwHhcNMjUwMzEzMTEwNjMxWhcNMzAwMzEyMTEw NzAxWjAnMSUwIwYDVQQDExxjYXBpZiBJbnRlcm1lZGlhdGUgQXV0aG9yaXR5MIIB IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwKjD5AMkH4G0w+zCQWnziu1j CxyZ43BWZRTe75LllJ0YU3Y5SHNHZMgbY0wgLtuiMi5NLuHiOObvHcOsZR0/cYeR 9ZE22xWRfTBoHQK2lLPUX5BXaPuMCbZAI1e/A2iBJOII36o+F0Gf85qvmqv+N81j t14BwS7Kw6tYqMLVadbKWr6mSrSO8urp9ZcjVj4AXWZXWs75Rid+NXPVsyJUvO0f yUFchj9H/CH4Mh8jsw1onCQ5Eg1b2cZ9RAtJjkemxb9VlNNmZLJq1sMVyc2UHwu7 +Js4UQmkr2De+VG6GPeyCv2g7GzpnsIiIvNDo0LiBgAD8D3AdBTPToa6aBpdxQID MIIDKDCCAhCgAwIBAgIUBSmgesyprqmIkFI8uSWj66N4AkkwDQYJKoZIhvcNAQEL BQAwEDEOMAwGA1UEAxMFY2FwaWYwHhcNMjUwMzE0MDgxMDIzWhcNMzAwMzEzMDgx MDUzWjAnMSUwIwYDVQQDExxjYXBpZiBJbnRlcm1lZGlhdGUgQXV0aG9yaXR5MIIB IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtYod3Lpkqr0XmzIPMpBQtPaY nxTftboKbG/XDNVWLSYA1Tqh73RNof7i9cOFnDH3IpjrGHFyfhd9TuX276qDVIB1 sRIvb7+pprnY9FpIOEFYwOkkFeKMrh2obRwrLIj97PvUg7S2cUslfz3QXVE37GdJ zow6MGuDEdt9ICiyIsovEg93/+f/duGT1IhMUZXCjc6wTDjGVbUBBJ0sqt/idVHu RzQgiEyggRBgHvh4r9jzOjZ/11OCE8rxBH8Ya2aWedtgBSsdGRr4tArIrNw92yOZ 7qT7ZBLti26Ky7DxcwvcVCFI1nZz6w+BB5o3xyrLjfz6f1yjukEk5Dt6VRIx4QID AQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E FgQUBXH5rGoV6N566W2tuc9KTaEhPYswHwYDVR0jBBgwFoAUXcyCU8QlfEkYq9hr NVuLhi2GV2AwDQYJKoZIhvcNAQELBQADggEBANp/szFjdTGlAx13Jeut5Thyc5Co j7SlAsNJxxvEvnZiy8pekd7Bw/Rtdt+Y7+lsjDE2Eo31AbR70uxpsqNAL4Sp6KjI 7CAuQyddrY3vhybX17eOseRTBctapXMZLIRmU9JnIJdlmTRwUYWCZnkQdqpV7hy0 7oWyx3F49A7KdXLEme2c/GtkzlnDc5+6x2Ssj+1Z9y7gaShDguXTyJLEiN3a8KUF VilqY0aM02ffNqeRXuuqE+wsSZSrBCP5PIRPZPQSw1027E/5xCB8sWWjcvtqZSnL 2Wst0Np7eJQnnyQJ323UPX//6iMlchYihF9gllUN/eqRzHEc6fTiFskWL0I= FgQUideMERtvYbD0iGjSDNlM6zs1GMIwHwYDVR0jBBgwFoAUSw4fwcHvmyU96pr7 RNtUqd9m12gwDQYJKoZIhvcNAQELBQADggEBAJfhWCEwK10SIbWjgKB4rfJhyxmU PRtQ22TElZVYZXo8HvjbrL2qZbGLWVytvFPRSJjJuNiECTAcJF1zTeVXBBf8TEQ+ 9GO0ZH1Ir56utInhiJKIRKpigecUZsdWma0V+ZVKPa8oPETqsFdZ+xf51B30x1al 0cStYKy31CK25MGMNDD9PDsIn4MUhgvrJC3vvF3v3u32yEg15Pzu436Jqt7+GVO2 zO7wnK95gE2+ajQ7Nv2/ak0rdbcckLbJqDj6OkAAe67XgHsFcGUX1KdsiNJqBIJ+ fkQQkOnWyy+4eeYpWQD0606xLhrk/nclCvefcrZPytcV4PdZERC60/EZlFo= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- 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 -----END CERTIFICATE----- No newline at end of file