sshplex 1.4.0__tar.gz → 1.5.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. {sshplex-1.4.0/sshplex.egg-info → sshplex-1.5.0}/PKG-INFO +1 -1
  2. {sshplex-1.4.0 → sshplex-1.5.0}/pyproject.toml +1 -1
  3. {sshplex-1.4.0 → sshplex-1.5.0}/sshplex/lib/config.py +1 -1
  4. {sshplex-1.4.0 → sshplex-1.5.0}/sshplex/lib/multiplexer/tmux.py +4 -1
  5. {sshplex-1.4.0 → sshplex-1.5.0}/sshplex/sshplex_connector.py +30 -5
  6. {sshplex-1.4.0 → sshplex-1.5.0/sshplex.egg-info}/PKG-INFO +1 -1
  7. {sshplex-1.4.0 → sshplex-1.5.0}/LICENSE +0 -0
  8. {sshplex-1.4.0 → sshplex-1.5.0}/MANIFEST.in +0 -0
  9. {sshplex-1.4.0 → sshplex-1.5.0}/README.md +0 -0
  10. {sshplex-1.4.0 → sshplex-1.5.0}/setup.cfg +0 -0
  11. {sshplex-1.4.0 → sshplex-1.5.0}/sshplex/__init__.py +0 -0
  12. {sshplex-1.4.0 → sshplex-1.5.0}/sshplex/cli.py +0 -0
  13. {sshplex-1.4.0 → sshplex-1.5.0}/sshplex/config-template.yaml +0 -0
  14. {sshplex-1.4.0 → sshplex-1.5.0}/sshplex/lib/__init__.py +0 -0
  15. {sshplex-1.4.0 → sshplex-1.5.0}/sshplex/lib/cache.py +0 -0
  16. {sshplex-1.4.0 → sshplex-1.5.0}/sshplex/lib/logger.py +0 -0
  17. {sshplex-1.4.0 → sshplex-1.5.0}/sshplex/lib/multiplexer/__init__.py +0 -0
  18. {sshplex-1.4.0 → sshplex-1.5.0}/sshplex/lib/multiplexer/base.py +0 -0
  19. {sshplex-1.4.0 → sshplex-1.5.0}/sshplex/lib/onboarding/__init__.py +0 -0
  20. {sshplex-1.4.0 → sshplex-1.5.0}/sshplex/lib/onboarding/wizard.py +0 -0
  21. {sshplex-1.4.0 → sshplex-1.5.0}/sshplex/lib/sot/__init__.py +0 -0
  22. {sshplex-1.4.0 → sshplex-1.5.0}/sshplex/lib/sot/ansible.py +0 -0
  23. {sshplex-1.4.0 → sshplex-1.5.0}/sshplex/lib/sot/base.py +0 -0
  24. {sshplex-1.4.0 → sshplex-1.5.0}/sshplex/lib/sot/consul.py +0 -0
  25. {sshplex-1.4.0 → sshplex-1.5.0}/sshplex/lib/sot/factory.py +0 -0
  26. {sshplex-1.4.0 → sshplex-1.5.0}/sshplex/lib/sot/netbox.py +0 -0
  27. {sshplex-1.4.0 → sshplex-1.5.0}/sshplex/lib/sot/static.py +0 -0
  28. {sshplex-1.4.0 → sshplex-1.5.0}/sshplex/lib/ui/__init__.py +0 -0
  29. {sshplex-1.4.0 → sshplex-1.5.0}/sshplex/lib/ui/config_editor.py +0 -0
  30. {sshplex-1.4.0 → sshplex-1.5.0}/sshplex/lib/ui/host_selector.py +0 -0
  31. {sshplex-1.4.0 → sshplex-1.5.0}/sshplex/lib/ui/session_manager.py +0 -0
  32. {sshplex-1.4.0 → sshplex-1.5.0}/sshplex/main.py +0 -0
  33. {sshplex-1.4.0 → sshplex-1.5.0}/sshplex.egg-info/SOURCES.txt +0 -0
  34. {sshplex-1.4.0 → sshplex-1.5.0}/sshplex.egg-info/dependency_links.txt +0 -0
  35. {sshplex-1.4.0 → sshplex-1.5.0}/sshplex.egg-info/entry_points.txt +0 -0
  36. {sshplex-1.4.0 → sshplex-1.5.0}/sshplex.egg-info/requires.txt +0 -0
  37. {sshplex-1.4.0 → sshplex-1.5.0}/sshplex.egg-info/top_level.txt +0 -0
  38. {sshplex-1.4.0 → sshplex-1.5.0}/tests/test_cache.py +0 -0
  39. {sshplex-1.4.0 → sshplex-1.5.0}/tests/test_config.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sshplex
3
- Version: 1.4.0
3
+ Version: 1.5.0
4
4
  Summary: Multiplex your SSH connections with style
5
5
  Author-email: MJAHED Sabri <contact@sabrimjahed.com>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "sshplex"
7
- version = "1.4.0"
7
+ version = "1.5.0"
8
8
  description = "Multiplex your SSH connections with style"
9
9
  authors = [{name = "MJAHED Sabri", email = "contact@sabrimjahed.com"}]
10
10
  readme = "README.md"
@@ -88,7 +88,7 @@ class ConsulConfig(BaseModel):
88
88
  port: int = Field(443, description="Consul port number")
89
89
  token: str = Field("default_token", description="Consul token for authentication")
90
90
  scheme: str = Field("https", description="URL scheme (e.g., 'https')")
91
- verify: bool = Field(False, description="Whether to verify SSL certificates")
91
+ verify: bool = Field(True, description="Whether to verify SSL certificates (default: True for security)")
92
92
  dc: str = Field("dc1", description="Datacenter name")
93
93
  cert: str = Field("", description="Path to SSL certificate")
94
94
 
@@ -1,6 +1,7 @@
1
1
  """SSHplex tmux multiplexer implementation."""
2
2
 
3
3
  import platform
4
+ import re
4
5
  import subprocess
5
6
  import uuid
6
7
  from datetime import datetime
@@ -261,8 +262,10 @@ class TmuxManager(MultiplexerBase):
261
262
  return False
262
263
 
263
264
  pane = self.panes[hostname]
265
+ # Sanitize title to prevent injection - only allow safe characters
266
+ safe_title = re.sub(r'[^\w\s.-]', '', title)[:50] # Remove dangerous chars, limit length
264
267
  # Set pane title using printf escape sequence
265
- pane.send_keys(f'printf "\\033]2;{title}\\033\\\\"', enter=True)
268
+ pane.send_keys(f'printf "\\033]2;{safe_title}\\033\\\\"', enter=True)
266
269
  return True
267
270
 
268
271
  except Exception as e:
@@ -1,6 +1,9 @@
1
1
  """SSHplex Connector - SSH connections and tmux session management."""
2
2
 
3
+ import os
3
4
  import platform
5
+ import re
6
+ import shlex
4
7
  import time
5
8
  from datetime import datetime
6
9
  from typing import Any, List, Optional
@@ -50,6 +53,10 @@ class SSHplexConnector:
50
53
 
51
54
  if not username or not username.strip():
52
55
  raise ValueError("SSH username cannot be empty")
56
+
57
+ # Validate username format to prevent injection
58
+ if not re.match(r'^[a-zA-Z0-9._-]+$', username):
59
+ raise ValueError(f"Invalid username format: {username}")
53
60
 
54
61
  if port < 1 or port > 65535:
55
62
  raise ValueError(f"SSH port must be between 1 and 65535, got {port}")
@@ -75,6 +82,12 @@ class SSHplexConnector:
75
82
  for _i, host in enumerate(hosts):
76
83
  hostname = host.ip if host.ip else host.name
77
84
 
85
+ # Validate hostname format to prevent injection
86
+ if not re.match(r'^[a-zA-Z0-9.-]+$', hostname):
87
+ self.logger.warning(f"Invalid hostname format (potential injection): {hostname}")
88
+ self.logger.warning("Skipping potentially malicious host")
89
+ continue
90
+
78
91
  # Build SSH command
79
92
  ssh_command = self._build_ssh_command(host, username, key_path, port)
80
93
 
@@ -194,9 +207,21 @@ class SSHplexConnector:
194
207
  None
195
208
  )
196
209
  if proxy:
197
- cmd_parts.extend([
198
- "-o", f"ProxyCommand=ssh -i {proxy.key_path} -W %h:%p {proxy.username}@{proxy.host}"
199
- ])
210
+ # Sanitize proxy credentials to prevent injection
211
+ proxy_host = proxy.host or ''
212
+ proxy_user = proxy.username or ''
213
+ proxy_key = proxy.key_path or ''
214
+
215
+ # Validate proxy values format
216
+ if (re.match(r'^[a-zA-Z0-9.-]+$', proxy_host) and
217
+ re.match(r'^[a-zA-Z0-9._-]+$', proxy_user) and
218
+ os.path.isabs(proxy_key) and '..' not in proxy_key):
219
+ # Use shlex.quote for safe shell escaping
220
+ cmd_parts.extend([
221
+ "-o", f"ProxyCommand=ssh -i {shlex.quote(proxy_key)} -W %h:%p {shlex.quote(proxy_user)}@{shlex.quote(proxy_host)}"
222
+ ])
223
+ else:
224
+ self.logger.warning("Proxy configuration contains invalid values, skipping proxy")
200
225
  except Exception:
201
226
  # Proxy not configured for this host, continue without it
202
227
  pass
@@ -233,8 +258,8 @@ class SSHplexConnector:
233
258
  timeout = getattr(self.config.ssh, 'timeout', 10) if self.config else 10
234
259
  cmd_parts.extend(["-o", f"ConnectTimeout={timeout}"])
235
260
 
236
- # Add user@hostname
237
- cmd_parts.append(f"{username}@{hostname}")
261
+ # Add user@hostname with proper escaping
262
+ cmd_parts.append(f"{shlex.quote(username)}@{shlex.quote(hostname)}")
238
263
 
239
264
  return " ".join(cmd_parts)
240
265
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sshplex
3
- Version: 1.4.0
3
+ Version: 1.5.0
4
4
  Summary: Multiplex your SSH connections with style
5
5
  Author-email: MJAHED Sabri <contact@sabrimjahed.com>
6
6
  License: MIT
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes