Skip to content

Commit 760326a

Browse files
committed
fix user finding
1 parent e547a22 commit 760326a

File tree

1 file changed

+73
-34
lines changed

1 file changed

+73
-34
lines changed

tabs/clean_qgs_tab.py

Lines changed: 73 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -262,15 +262,15 @@ def preview_changes(self):
262262
# Auto-resize rows to content
263263
self.preview_table.resizeRowsToContents()
264264

265-
self.emit_log(f"Preview completed: {len(changes)} datasource(s) with credentials found")
265+
self.emit_log(f"Preview completed: {len(changes)} type(s) of credentials found")
266266
else:
267267
# Hide table and show info message
268268
self.preview_table.setVisible(False)
269269
self.preview_info_label.setVisible(True)
270-
self.preview_info_label.setText("No datasources with credentials found in this file.")
270+
self.preview_info_label.setText("No credentials found in this file.")
271271
self.preview_info_label.setStyleSheet("color: #4CAF50; font-style: italic; padding: 10px;")
272272

273-
self.emit_log("Preview completed: No datasources with credentials found")
273+
self.emit_log("Preview completed: No credentials found")
274274

275275
except Exception as e:
276276
self.show_error(f"Error previewing file: {str(e)}")
@@ -315,7 +315,7 @@ def clean_file(self):
315315
self.file_cleaned.emit(cleaned_path)
316316

317317
success_msg = (f"✓ File cleaned successfully!\n"
318-
f"• Cleaned {changes_count} datasource(s)\n"
318+
f"• Removed {changes_count} credential(s)\n"
319319
f"• Original file preserved\n"
320320
f"• Saved to: {os.path.basename(cleaned_path)}")
321321

@@ -372,46 +372,84 @@ def _write_qgs_file(self, output_path, content, is_qgz=False):
372372
def _find_datasource_changes(self, content):
373373
"""Find datasources that would be changed and return before/after pairs."""
374374
changes = []
375-
376-
# Pattern to match datasource tags with PostgreSQL connections
377-
datasource_pattern = r'<datasource>(.*?)</datasource>'
378-
379-
for match in re.finditer(datasource_pattern, content, re.DOTALL):
380-
original_datasource = match.group(1).strip()
381-
382-
# Check if it's a PostgreSQL connection with credentials
383-
if self._has_postgres_credentials(original_datasource):
384-
cleaned_datasource = self._clean_single_datasource(original_datasource)
385-
if cleaned_datasource != original_datasource:
386-
changes.append((original_datasource, cleaned_datasource))
375+
found_connections = set() # To avoid duplicates
376+
377+
# Pattern to find all PostgreSQL connection strings (containing dbname=)
378+
# This covers quoted strings, attribute values, and various formats
379+
patterns = [
380+
r'"[^"]*dbname=[^"]*"', # Double-quoted strings
381+
r"'[^']*dbname=[^']*'", # Single-quoted strings
382+
r'(?:value|source|dataSource|destinationLayerSource)="([^"]*dbname=[^"]*)"', # Attribute values
383+
r"(?:value|source|dataSource|destinationLayerSource)='([^']*dbname=[^']*)'", # Single-quoted attribute values
384+
]
385+
386+
for pattern in patterns:
387+
for match in re.finditer(pattern, content):
388+
# Get the connection string (either full match or group 1 if it's an attribute)
389+
if match.groups():
390+
connection_string = match.group(1)
391+
else:
392+
connection_string = match.group(0)
393+
394+
# Skip if we've already found this connection string
395+
if connection_string in found_connections:
396+
continue
397+
398+
# Check if this connection string has credentials we want to remove
399+
if self._has_postgres_credentials(connection_string):
400+
cleaned = self._clean_single_datasource(connection_string)
401+
if cleaned != connection_string:
402+
changes.append((connection_string, cleaned))
403+
found_connections.add(connection_string)
387404

388405
return changes
389406

390407
def _clean_datasources(self, content):
391408
"""Clean all datasources in the content and return cleaned content and count."""
392409
changes_count = 0
410+
cleaned_content = content
393411

394-
def replace_datasource(match):
395-
nonlocal changes_count
396-
original_datasource = match.group(1).strip()
412+
# Global removal of user credentials
413+
if self.remove_user_checkbox.isChecked():
414+
# Count user credentials before removing them
415+
user_matches = re.findall(r'user=[\'"][^\'\"]*[\'"]|user=[^\s]+', cleaned_content)
416+
changes_count += len(user_matches)
397417

398-
if self._has_postgres_credentials(original_datasource):
399-
cleaned_datasource = self._clean_single_datasource(original_datasource)
400-
if cleaned_datasource != original_datasource:
401-
changes_count += 1
402-
return f'<datasource>{cleaned_datasource}</datasource>'
418+
# Remove user credentials (being very careful about spaces)
419+
# Handle space + user= (most common case)
420+
cleaned_content = re.sub(r'\s+user=[\'"][^\'\"]*[\'"]', '', cleaned_content)
421+
cleaned_content = re.sub(r'\s+user=[^\s]+', '', cleaned_content)
422+
# Handle user= + space (when user is first parameter)
423+
cleaned_content = re.sub(r'user=[\'"][^\'\"]*[\'"]\s+', '', cleaned_content)
424+
cleaned_content = re.sub(r'user=[^\s]+\s+', '', cleaned_content)
425+
# Handle isolated user= (no surrounding spaces)
426+
cleaned_content = re.sub(r'user=[\'"][^\'\"]*[\'"]', '', cleaned_content)
427+
cleaned_content = re.sub(r'user=[^\s]+', '', cleaned_content)
428+
429+
# Global removal of password credentials
430+
if self.remove_password_checkbox.isChecked():
431+
# Count password credentials before removing them
432+
password_matches = re.findall(r'password=[\'"][^\'\"]*[\'"]|password=[^\s]+', cleaned_content)
433+
changes_count += len(password_matches)
403434

404-
return match.group(0)
405-
406-
# Pattern to match datasource tags
407-
datasource_pattern = r'<datasource>(.*?)</datasource>'
408-
cleaned_content = re.sub(datasource_pattern, replace_datasource, content, flags=re.DOTALL)
435+
# Remove password credentials (being very careful about spaces)
436+
# Handle space + password= (most common case)
437+
cleaned_content = re.sub(r'\s+password=[\'"][^\'\"]*[\'"]', '', cleaned_content)
438+
cleaned_content = re.sub(r'\s+password=[^\s]+', '', cleaned_content)
439+
# Handle password= + space (when password is first parameter)
440+
cleaned_content = re.sub(r'password=[\'"][^\'\"]*[\'"]\s+', '', cleaned_content)
441+
cleaned_content = re.sub(r'password=[^\s]+\s+', '', cleaned_content)
442+
# Handle isolated password= (no surrounding spaces)
443+
cleaned_content = re.sub(r'password=[\'"][^\'\"]*[\'"]', '', cleaned_content)
444+
cleaned_content = re.sub(r'password=[^\s]+', '', cleaned_content)
445+
446+
# NO general whitespace cleanup - preserve all XML formatting exactly as is
409447

410448
return cleaned_content, changes_count
411449

412450
def _has_postgres_credentials(self, datasource):
413451
"""Check if datasource has PostgreSQL credentials."""
414-
# Check for dbname parameter (indicates PostgreSQL) and credentials
452+
# Must have dbname= (indicates PostgreSQL) and credentials we want to remove
415453
has_dbname = 'dbname=' in datasource
416454
has_user = 'user=' in datasource and self.remove_user_checkbox.isChecked()
417455
has_password = 'password=' in datasource and self.remove_password_checkbox.isChecked()
@@ -420,15 +458,16 @@ def _has_postgres_credentials(self, datasource):
420458

421459
def _clean_single_datasource(self, datasource):
422460
"""Clean a single datasource string."""
461+
# This method is less important now, but kept for compatibility
423462
cleaned = datasource
424463

425464
if self.remove_user_checkbox.isChecked():
426-
# Remove user='...' or user="..."
427-
cleaned = re.sub(r"\s*user=['\"][^'\"]*['\"]", "", cleaned)
465+
cleaned = re.sub(r'\s*user=[\'"][^\'\"]*[\'"]', '', cleaned)
466+
cleaned = re.sub(r'\s*user=[^\s]+', '', cleaned)
428467

429468
if self.remove_password_checkbox.isChecked():
430-
# Remove password='...' or password="..."
431-
cleaned = re.sub(r"\s*password=['\"][^'\"]*['\"]", "", cleaned)
469+
cleaned = re.sub(r'\s*password=[\'"][^\'\"]*[\'"]', '', cleaned)
470+
cleaned = re.sub(r'\s*password=[^\s]+', '', cleaned)
432471

433472
# Clean up any double spaces
434473
cleaned = re.sub(r'\s+', ' ', cleaned).strip()

0 commit comments

Comments
 (0)