qssh 0.2.0__tar.gz → 0.2.2__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qssh
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: Quick SSH session manager - save your VM credentials and connect with a single command
5
5
  Author: joan-code6
6
6
  License-Expression: MIT
@@ -47,7 +47,7 @@ pip install qssh
47
47
  ### 1. Add a new session
48
48
 
49
49
  ```bash
50
- qssh add outcraft
50
+ qssh add myserver
51
51
  ```
52
52
 
53
53
  You'll be prompted for:
@@ -59,7 +59,7 @@ You'll be prompted for:
59
59
  ### 2. Connect to your VM
60
60
 
61
61
  ```bash
62
- qssh outcraft
62
+ qssh myserver
63
63
  ```
64
64
 
65
65
  That's it! You're connected.
@@ -79,8 +79,8 @@ That's it! You're connected.
79
79
  ## Examples
80
80
 
81
81
  ```bash
82
- # Add a session for your OutCraft VM
83
- qssh add outcraft
82
+ # Add a session for your myserver VM
83
+ qssh add myserver
84
84
  # Host: 192.168.1.100
85
85
  # Username: admin
86
86
  # Port [22]: 22
@@ -88,7 +88,7 @@ qssh add outcraft
88
88
  # Password: ********
89
89
 
90
90
  # Now just connect with:
91
- qssh outcraft
91
+ qssh myserver
92
92
 
93
93
  # List all your sessions
94
94
  qssh list
@@ -97,7 +97,7 @@ qssh list
97
97
  qssh remove old-server
98
98
 
99
99
  # Show details of a session
100
- qssh show outcraft
100
+ qssh show myserver
101
101
  ```
102
102
 
103
103
  ## Using SSH Keys
@@ -110,12 +110,19 @@ qssh add myserver
110
110
  # Username: deploy
111
111
  # Port [22]: 22
112
112
  # Auth type (password/key) [password]: key
113
- # Key file path: ~/.ssh/id_rsa
113
+ # Key file path [~/.ssh/id_rsa]: ~/.ssh/my_key
114
+ # Key passphrase (leave empty if none): ********
114
115
  ```
115
116
 
117
+ Supported key types:
118
+ - RSA
119
+ - Ed25519
120
+ - ECDSA
121
+ - DSS
122
+
116
123
  ## Configuration
117
124
 
118
- Sessions are stored in `~/.qssh/sessions.yaml`. Passwords are stored encoded (not plaintext) but for maximum security, consider using SSH keys instead.
125
+ Sessions are stored in `~/.qssh/sessions.yaml`. Passwords and key passphrases are stored encoded (not plaintext) but for maximum security, consider using SSH keys without passphrases or with an SSH agent.
119
126
 
120
127
  ## License
121
128
 
@@ -15,7 +15,7 @@ pip install qssh
15
15
  ### 1. Add a new session
16
16
 
17
17
  ```bash
18
- qssh add outcraft
18
+ qssh add myserver
19
19
  ```
20
20
 
21
21
  You'll be prompted for:
@@ -27,7 +27,7 @@ You'll be prompted for:
27
27
  ### 2. Connect to your VM
28
28
 
29
29
  ```bash
30
- qssh outcraft
30
+ qssh myserver
31
31
  ```
32
32
 
33
33
  That's it! You're connected.
@@ -47,8 +47,8 @@ That's it! You're connected.
47
47
  ## Examples
48
48
 
49
49
  ```bash
50
- # Add a session for your OutCraft VM
51
- qssh add outcraft
50
+ # Add a session for your myserver VM
51
+ qssh add myserver
52
52
  # Host: 192.168.1.100
53
53
  # Username: admin
54
54
  # Port [22]: 22
@@ -56,7 +56,7 @@ qssh add outcraft
56
56
  # Password: ********
57
57
 
58
58
  # Now just connect with:
59
- qssh outcraft
59
+ qssh myserver
60
60
 
61
61
  # List all your sessions
62
62
  qssh list
@@ -65,7 +65,7 @@ qssh list
65
65
  qssh remove old-server
66
66
 
67
67
  # Show details of a session
68
- qssh show outcraft
68
+ qssh show myserver
69
69
  ```
70
70
 
71
71
  ## Using SSH Keys
@@ -78,12 +78,19 @@ qssh add myserver
78
78
  # Username: deploy
79
79
  # Port [22]: 22
80
80
  # Auth type (password/key) [password]: key
81
- # Key file path: ~/.ssh/id_rsa
81
+ # Key file path [~/.ssh/id_rsa]: ~/.ssh/my_key
82
+ # Key passphrase (leave empty if none): ********
82
83
  ```
83
84
 
85
+ Supported key types:
86
+ - RSA
87
+ - Ed25519
88
+ - ECDSA
89
+ - DSS
90
+
84
91
  ## Configuration
85
92
 
86
- Sessions are stored in `~/.qssh/sessions.yaml`. Passwords are stored encoded (not plaintext) but for maximum security, consider using SSH keys instead.
93
+ Sessions are stored in `~/.qssh/sessions.yaml`. Passwords and key passphrases are stored encoded (not plaintext) but for maximum security, consider using SSH keys without passphrases or with an SSH agent.
87
94
 
88
95
  ## License
89
96
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "qssh"
7
- version = "0.2.0"
7
+ version = "0.2.2"
8
8
  description = "Quick SSH session manager - save your VM credentials and connect with a single command"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -1,7 +1,7 @@
1
1
  """qssh - Quick SSH session manager."""
2
2
 
3
- __version__ = "0.2.0"
4
- __author__ = "benne"
3
+ __version__ = "0.2.2"
4
+ __author__ = "bennet"
5
5
 
6
6
  from .session import SessionManager
7
7
  from .connector import SSHConnector
@@ -126,6 +126,7 @@ def add_session(name: str):
126
126
 
127
127
  password = None
128
128
  key_file = None
129
+ key_passphrase = None
129
130
 
130
131
  if auth_type == "password":
131
132
  password_raw = Prompt.ask("[bold]Password[/]", password=True)
@@ -136,6 +137,10 @@ def add_session(name: str):
136
137
  "[bold]Key file path[/]",
137
138
  default="~/.ssh/id_rsa"
138
139
  )
140
+ # Ask for passphrase (optional)
141
+ passphrase_raw = Prompt.ask("[bold]Key passphrase[/] (leave empty if none)", password=True, default="")
142
+ if passphrase_raw:
143
+ key_passphrase = Session.encode_password(passphrase_raw)
139
144
 
140
145
  # Create and save session
141
146
  session = Session(
@@ -146,6 +151,7 @@ def add_session(name: str):
146
151
  auth_type=auth_type,
147
152
  password=password,
148
153
  key_file=key_file,
154
+ key_passphrase=key_passphrase,
149
155
  )
150
156
 
151
157
  manager.add(session)
@@ -229,6 +235,7 @@ def edit_session(name: str):
229
235
 
230
236
  password = session.password
231
237
  key_file = session.key_file
238
+ key_passphrase = getattr(session, 'key_passphrase', None)
232
239
 
233
240
  if auth_type == "password":
234
241
  if Confirm.ask("Update password?", default=False):
@@ -236,11 +243,18 @@ def edit_session(name: str):
236
243
  if password_raw:
237
244
  password = Session.encode_password(password_raw)
238
245
  key_file = None
246
+ key_passphrase = None
239
247
  else:
240
248
  key_file = Prompt.ask(
241
249
  "[bold]Key file path[/]",
242
250
  default=session.key_file or "~/.ssh/id_rsa"
243
251
  )
252
+ if Confirm.ask("Update key passphrase?", default=False):
253
+ passphrase_raw = Prompt.ask("[bold]Key passphrase[/] (leave empty if none)", password=True, default="")
254
+ if passphrase_raw:
255
+ key_passphrase = Session.encode_password(passphrase_raw)
256
+ else:
257
+ key_passphrase = None
244
258
  password = None
245
259
 
246
260
  # Update session
@@ -252,6 +266,7 @@ def edit_session(name: str):
252
266
  auth_type=auth_type,
253
267
  password=password,
254
268
  key_file=key_file,
269
+ key_passphrase=key_passphrase,
255
270
  )
256
271
 
257
272
  manager.add(updated)
@@ -29,12 +29,12 @@ class SSHConnector:
29
29
  Exit code from SSH process
30
30
  """
31
31
  if session.auth_type == "key":
32
- return self._connect_with_key(session)
32
+ return self._connect_with_key_paramiko(session)
33
33
  else:
34
34
  return self._connect_with_paramiko(session)
35
35
 
36
- def _connect_with_key(self, session: Session) -> int:
37
- """Connect using SSH key authentication.
36
+ def _connect_with_key_paramiko(self, session: Session) -> int:
37
+ """Connect using SSH key authentication via paramiko.
38
38
 
39
39
  Args:
40
40
  session: Session configuration
@@ -43,19 +43,56 @@ class SSHConnector:
43
43
  Exit code
44
44
  """
45
45
  key_path = os.path.expanduser(session.key_file) if session.key_file else None
46
+ passphrase = session.get_key_passphrase() if hasattr(session, 'get_key_passphrase') else None
46
47
 
47
- cmd = [
48
- "ssh",
49
- "-o", "StrictHostKeyChecking=accept-new",
50
- "-p", str(session.port),
51
- ]
52
-
53
- if key_path:
54
- cmd.extend(["-i", key_path])
55
-
56
- cmd.append(f"{session.username}@{session.host}")
57
-
58
- return self._run_ssh(cmd)
48
+ try:
49
+ # Create SSH client
50
+ client = paramiko.SSHClient()
51
+ client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
52
+
53
+ # Load the private key
54
+ pkey = None
55
+ if key_path and os.path.exists(key_path):
56
+ try:
57
+ # Try different key types
58
+ for key_class in [paramiko.RSAKey, paramiko.Ed25519Key, paramiko.ECDSAKey, paramiko.DSSKey]:
59
+ try:
60
+ pkey = key_class.from_private_key_file(key_path, password=passphrase)
61
+ break
62
+ except paramiko.SSHException:
63
+ continue
64
+ except Exception as e:
65
+ print(f"[qssh] Error loading key: {e}")
66
+ return 1
67
+
68
+ # Connect with key
69
+ client.connect(
70
+ hostname=session.host,
71
+ port=session.port,
72
+ username=session.username,
73
+ pkey=pkey,
74
+ look_for_keys=False,
75
+ allow_agent=False,
76
+ )
77
+
78
+ # Start interactive shell
79
+ self._interactive_shell(client)
80
+
81
+ client.close()
82
+ return 0
83
+
84
+ except paramiko.AuthenticationException:
85
+ print("[qssh] Authentication failed. Check your key or passphrase.")
86
+ return 1
87
+ except paramiko.SSHException as e:
88
+ print(f"[qssh] SSH error: {e}")
89
+ return 1
90
+ except FileNotFoundError:
91
+ print(f"[qssh] Key file not found: {key_path}")
92
+ return 1
93
+ except Exception as e:
94
+ print(f"[qssh] Connection error: {e}")
95
+ return 1
59
96
 
60
97
  def _connect_with_paramiko(self, session: Session) -> int:
61
98
  """Connect using paramiko for automatic password authentication.
@@ -20,6 +20,7 @@ class Session:
20
20
  auth_type: str = "password" # "password" or "key"
21
21
  password: Optional[str] = None # base64 encoded
22
22
  key_file: Optional[str] = None
23
+ key_passphrase: Optional[str] = None # base64 encoded
23
24
 
24
25
  def to_dict(self) -> dict:
25
26
  """Convert session to dictionary for storage."""
@@ -41,6 +42,15 @@ class Session:
41
42
  return self.password
42
43
  return None
43
44
 
45
+ def get_key_passphrase(self) -> Optional[str]:
46
+ """Decode and return the key passphrase."""
47
+ if self.key_passphrase:
48
+ try:
49
+ return base64.b64decode(self.key_passphrase.encode()).decode()
50
+ except Exception:
51
+ return self.key_passphrase
52
+ return None
53
+
44
54
  @staticmethod
45
55
  def encode_password(password: str) -> str:
46
56
  """Encode password for storage."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qssh
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: Quick SSH session manager - save your VM credentials and connect with a single command
5
5
  Author: joan-code6
6
6
  License-Expression: MIT
@@ -47,7 +47,7 @@ pip install qssh
47
47
  ### 1. Add a new session
48
48
 
49
49
  ```bash
50
- qssh add outcraft
50
+ qssh add myserver
51
51
  ```
52
52
 
53
53
  You'll be prompted for:
@@ -59,7 +59,7 @@ You'll be prompted for:
59
59
  ### 2. Connect to your VM
60
60
 
61
61
  ```bash
62
- qssh outcraft
62
+ qssh myserver
63
63
  ```
64
64
 
65
65
  That's it! You're connected.
@@ -79,8 +79,8 @@ That's it! You're connected.
79
79
  ## Examples
80
80
 
81
81
  ```bash
82
- # Add a session for your OutCraft VM
83
- qssh add outcraft
82
+ # Add a session for your myserver VM
83
+ qssh add myserver
84
84
  # Host: 192.168.1.100
85
85
  # Username: admin
86
86
  # Port [22]: 22
@@ -88,7 +88,7 @@ qssh add outcraft
88
88
  # Password: ********
89
89
 
90
90
  # Now just connect with:
91
- qssh outcraft
91
+ qssh myserver
92
92
 
93
93
  # List all your sessions
94
94
  qssh list
@@ -97,7 +97,7 @@ qssh list
97
97
  qssh remove old-server
98
98
 
99
99
  # Show details of a session
100
- qssh show outcraft
100
+ qssh show myserver
101
101
  ```
102
102
 
103
103
  ## Using SSH Keys
@@ -110,12 +110,19 @@ qssh add myserver
110
110
  # Username: deploy
111
111
  # Port [22]: 22
112
112
  # Auth type (password/key) [password]: key
113
- # Key file path: ~/.ssh/id_rsa
113
+ # Key file path [~/.ssh/id_rsa]: ~/.ssh/my_key
114
+ # Key passphrase (leave empty if none): ********
114
115
  ```
115
116
 
117
+ Supported key types:
118
+ - RSA
119
+ - Ed25519
120
+ - ECDSA
121
+ - DSS
122
+
116
123
  ## Configuration
117
124
 
118
- Sessions are stored in `~/.qssh/sessions.yaml`. Passwords are stored encoded (not plaintext) but for maximum security, consider using SSH keys instead.
125
+ Sessions are stored in `~/.qssh/sessions.yaml`. Passwords and key passphrases are stored encoded (not plaintext) but for maximum security, consider using SSH keys without passphrases or with an SSH agent.
119
126
 
120
127
  ## License
121
128
 
File without changes
File without changes
File without changes
File without changes