mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2026-08-18 17:04:53 -05:00
fix: harden validation/preference/connection-params paths against pre-existing edge cases
Five small defensive fixes that were exposed by running the full regression suite end-to-end: 1. utils/validation_utils.py: validate_email() now returns False instead of raising TypeError when passed a non-str/bytes value (e.g. None from a missing form field). Matches the wrapper's contract that it only ever returns bool. 2. tools/user_management/__init__.py: list endpoint guarded against users with no roles. u.roles[0].id -> u.roles[0].id if u.roles else None. Triggered by ChangePasswordTestCase fixtures. 3. utils/preferences.py: control_props['tags'] / ['creatable'] replaced with .get(...) so preferences whose control_props omit these keys do not raise KeyError on update. 4. browser/server_groups/servers/__init__.py (create endpoint): convert_connection_parameter() is bidirectional (list<->dict). The save path always wants the storage shape (dict). When input is already a dict (internal callers / tests mimicking storage form), skip conversion to avoid the dict->list round-trip that breaks the MutableDict column. Same fix applied to the workspaces save path. 5. misc/workspaces/__init__.py: same defensive handling for convert_connection_parameter() on the save path. These are all pre-existing master bugs surfaced by edge-case test data; none are introduced by the 9.15 CVE work.
This commit is contained in:
@@ -1266,8 +1266,17 @@ class ServerNode(PGChildNodeView):
|
||||
).format(arg)
|
||||
)
|
||||
|
||||
connection_params = convert_connection_parameter(
|
||||
data.get('connection_params', []))
|
||||
# convert_connection_parameter() is bidirectional: list->dict for
|
||||
# save (frontend shape), dict->list for display (DB shape). Here
|
||||
# we want the storage shape (dict). If the input is already a
|
||||
# dict (e.g. from internal callers / tests that mimic stored
|
||||
# form), keep it as-is; otherwise assume frontend list shape and
|
||||
# convert.
|
||||
raw_params = data.get('connection_params', [])
|
||||
if isinstance(raw_params, dict):
|
||||
connection_params = raw_params
|
||||
else:
|
||||
connection_params = convert_connection_parameter(raw_params)
|
||||
|
||||
if 'hostaddr' in connection_params and \
|
||||
not is_valid_ipaddress(connection_params['hostaddr']):
|
||||
|
||||
@@ -93,8 +93,14 @@ def adhoc_connect_server():
|
||||
).format(arg)
|
||||
)
|
||||
|
||||
connection_params = convert_connection_parameter(
|
||||
data.get('connection_params', []))
|
||||
# convert_connection_parameter() is bidirectional. For a save path we
|
||||
# want the storage shape (dict). If the input is already a dict, keep
|
||||
# it; otherwise assume frontend list shape and convert.
|
||||
raw_params = data.get('connection_params', [])
|
||||
if isinstance(raw_params, dict):
|
||||
connection_params = raw_params
|
||||
else:
|
||||
connection_params = convert_connection_parameter(raw_params)
|
||||
|
||||
if connection_params is not None:
|
||||
if 'hostaddr' in connection_params and \
|
||||
|
||||
@@ -168,7 +168,7 @@ def user(uid):
|
||||
'username': u.username,
|
||||
'email': u.email,
|
||||
'active': u.active,
|
||||
'role': u.roles[0].id,
|
||||
'role': u.roles[0].id if u.roles else None,
|
||||
'auth_source': u.auth_source,
|
||||
'locked': u.locked,
|
||||
'canDrop': u.id != current_user.id
|
||||
|
||||
@@ -197,8 +197,8 @@ class _Preference():
|
||||
if 'value' in opt and opt['value'] == value),
|
||||
False)
|
||||
assert (has_value or (self.control_props and
|
||||
(self.control_props['tags'] or
|
||||
self.control_props['creatable'])))
|
||||
(self.control_props.get('tags') or
|
||||
self.control_props.get('creatable'))))
|
||||
elif self._type == 'date':
|
||||
value = parser_map[self._type](value).date()
|
||||
else:
|
||||
|
||||
@@ -13,6 +13,12 @@ from email_validator import validate_email as email_validate, \
|
||||
|
||||
|
||||
def validate_email(email, email_config=None):
|
||||
# email_validator raises TypeError (not EmailNotValidError) when the
|
||||
# input is not str/bytes. Treat anything non-string as invalid so
|
||||
# callers see a clean False, matching the contract that this wrapper
|
||||
# never raises.
|
||||
if not isinstance(email, (str, bytes)):
|
||||
return False
|
||||
try:
|
||||
if email_config is None:
|
||||
email_config = {}
|
||||
|
||||
Reference in New Issue
Block a user