From 9b089ef0c501869624fde198f46b857f8086410e Mon Sep 17 00:00:00 2001 From: nan Date: Tue, 1 Sep 2026 13:48:41 +0800 Subject: [PATCH] fix: encode slashes in connection passwords --- .../utils/connection_string_parser.py | 2 +- .../utils/test_connection_string_parser.py | 9 ++ src/lfx/src/lfx/_assets/component_index.json | 83 +++++++++++++++---- .../src/lfx/utils/connection_string_parser.py | 2 +- .../utils/test_connection_string_parser.py | 10 +++ 5 files changed, 86 insertions(+), 20 deletions(-) create mode 100644 src/lfx/tests/unit/utils/test_connection_string_parser.py diff --git a/src/backend/base/langflow/utils/connection_string_parser.py b/src/backend/base/langflow/utils/connection_string_parser.py index a334cef28e48..c4496ed3fec2 100644 --- a/src/backend/base/langflow/utils/connection_string_parser.py +++ b/src/backend/base/langflow/utils/connection_string_parser.py @@ -4,5 +4,5 @@ def transform_connection_string(connection_string) -> str: auth_part, db_url_name = connection_string.rsplit("@", 1) protocol_user, password_string = auth_part.rsplit(":", 1) - encoded_password = quote(password_string) + encoded_password = quote(password_string, safe="") return f"{protocol_user}:{encoded_password}@{db_url_name}" diff --git a/src/backend/tests/unit/utils/test_connection_string_parser.py b/src/backend/tests/unit/utils/test_connection_string_parser.py index 7492b4162c62..006a69530587 100644 --- a/src/backend/tests/unit/utils/test_connection_string_parser.py +++ b/src/backend/tests/unit/utils/test_connection_string_parser.py @@ -1,3 +1,5 @@ +from urllib.parse import urlsplit + import pytest from langflow.utils.connection_string_parser import transform_connection_string @@ -18,3 +20,10 @@ def test_transform_connection_string(connection_string, expected): result = transform_connection_string(connection_string) assert result == expected + + +def test_transform_connection_string_encodes_slash_in_password(): + result = transform_connection_string("postgresql://user:pa/ss@db.example:5432/app") + + assert result == "postgresql://user:pa%2Fss@db.example:5432/app" + assert urlsplit(result).hostname == "db.example" diff --git a/src/lfx/src/lfx/_assets/component_index.json b/src/lfx/src/lfx/_assets/component_index.json index 3dea61b1cd6d..6962f6d67f86 100644 --- a/src/lfx/src/lfx/_assets/component_index.json +++ b/src/lfx/src/lfx/_assets/component_index.json @@ -12372,7 +12372,9 @@ "tool_mode": false }, "CharacterTextSplitter": { - "base_classes": [], + "base_classes": [ + "JSON" + ], "beta": false, "conditional_paths": [], "custom_fields": {}, @@ -12416,8 +12418,11 @@ "group_outputs": false, "method": "transform_data", "name": "data", + "selected": "JSON", "tool_mode": true, - "types": [], + "types": [ + "JSON" + ], "value": "__UNDEFINED__" } ], @@ -13580,7 +13585,9 @@ "tool_mode": false }, "LanguageRecursiveTextSplitter": { - "base_classes": [], + "base_classes": [ + "JSON" + ], "beta": false, "conditional_paths": [], "custom_fields": {}, @@ -13624,8 +13631,11 @@ "group_outputs": false, "method": "transform_data", "name": "data", + "selected": "JSON", "tool_mode": true, - "types": [], + "types": [ + "JSON" + ], "value": "__UNDEFINED__" } ], @@ -13778,7 +13788,9 @@ "tool_mode": false }, "NaturalLanguageTextSplitter": { - "base_classes": [], + "base_classes": [ + "JSON" + ], "beta": false, "conditional_paths": [], "custom_fields": {}, @@ -13823,8 +13835,11 @@ "group_outputs": false, "method": "transform_data", "name": "data", + "selected": "JSON", "tool_mode": true, - "types": [], + "types": [ + "JSON" + ], "value": "__UNDEFINED__" } ], @@ -13975,7 +13990,10 @@ "tool_mode": false }, "OpenAIToolsAgent": { - "base_classes": [], + "base_classes": [ + "AgentExecutor", + "Message" + ], "beta": false, "conditional_paths": [], "custom_fields": {}, @@ -14031,8 +14049,11 @@ "group_outputs": false, "method": "message_response", "name": "response", + "selected": "Message", "tool_mode": true, - "types": [], + "types": [ + "Message" + ], "value": "__UNDEFINED__" }, { @@ -14042,8 +14063,11 @@ "group_outputs": false, "method": "build_agent", "name": "agent", + "selected": "AgentExecutor", "tool_mode": false, - "types": [], + "types": [ + "AgentExecutor" + ], "value": "__UNDEFINED__" } ], @@ -14746,7 +14770,9 @@ "tool_mode": false }, "RecursiveCharacterTextSplitter": { - "base_classes": [], + "base_classes": [ + "JSON" + ], "beta": false, "conditional_paths": [], "custom_fields": {}, @@ -14790,8 +14816,11 @@ "group_outputs": false, "method": "transform_data", "name": "data", + "selected": "JSON", "tool_mode": true, - "types": [], + "types": [ + "JSON" + ], "value": "__UNDEFINED__" } ], @@ -16478,7 +16507,10 @@ "tool_mode": false }, "ToolCallingAgent": { - "base_classes": [], + "base_classes": [ + "AgentExecutor", + "Message" + ], "beta": false, "conditional_paths": [], "custom_fields": {}, @@ -16533,8 +16565,11 @@ "group_outputs": false, "method": "message_response", "name": "response", + "selected": "Message", "tool_mode": true, - "types": [], + "types": [ + "Message" + ], "value": "__UNDEFINED__" }, { @@ -16544,8 +16579,11 @@ "group_outputs": false, "method": "build_agent", "name": "agent", + "selected": "AgentExecutor", "tool_mode": false, - "types": [], + "types": [ + "AgentExecutor" + ], "value": "__UNDEFINED__" } ], @@ -17242,7 +17280,10 @@ "tool_mode": false }, "XMLAgent": { - "base_classes": [], + "base_classes": [ + "AgentExecutor", + "Message" + ], "beta": true, "conditional_paths": [], "custom_fields": {}, @@ -17298,8 +17339,11 @@ "group_outputs": false, "method": "message_response", "name": "response", + "selected": "Message", "tool_mode": true, - "types": [], + "types": [ + "Message" + ], "value": "__UNDEFINED__" }, { @@ -17309,8 +17353,11 @@ "group_outputs": false, "method": "build_agent", "name": "agent", + "selected": "AgentExecutor", "tool_mode": false, - "types": [], + "types": [ + "AgentExecutor" + ], "value": "__UNDEFINED__" } ], @@ -30987,6 +31034,6 @@ "num_components": 127, "num_modules": 16 }, - "sha256": "7572f889a9012abfc0ecc2de7c45f5fcf7d5b85c24f7ec847afe5aa5f097754e", + "sha256": "b38dc88e6d01da028b3e0f4d2918c218e180e4c5b3d87d91cf00e18150bf8ee3", "version": "1.12.0" } diff --git a/src/lfx/src/lfx/utils/connection_string_parser.py b/src/lfx/src/lfx/utils/connection_string_parser.py index 9542c5ae15cd..8186e5385f7e 100644 --- a/src/lfx/src/lfx/utils/connection_string_parser.py +++ b/src/lfx/src/lfx/utils/connection_string_parser.py @@ -7,5 +7,5 @@ def transform_connection_string(connection_string) -> str: """Transform connection string by encoding the password part.""" auth_part, db_url_name = connection_string.rsplit("@", 1) protocol_user, password_string = auth_part.rsplit(":", 1) - encoded_password = quote(password_string) + encoded_password = quote(password_string, safe="") return f"{protocol_user}:{encoded_password}@{db_url_name}" diff --git a/src/lfx/tests/unit/utils/test_connection_string_parser.py b/src/lfx/tests/unit/utils/test_connection_string_parser.py new file mode 100644 index 000000000000..3dd25511ed14 --- /dev/null +++ b/src/lfx/tests/unit/utils/test_connection_string_parser.py @@ -0,0 +1,10 @@ +from urllib.parse import urlsplit + +from lfx.utils.connection_string_parser import transform_connection_string + + +def test_transform_connection_string_encodes_slash_in_password(): + result = transform_connection_string("postgresql://user:pa/ss@db.example:5432/app") + + assert result == "postgresql://user:pa%2Fss@db.example:5432/app" + assert urlsplit(result).hostname == "db.example"