update more for 5.0+

This commit is contained in:
dharm pimsen 2024-11-10 16:35:43 +07:00
parent e4b1a90325
commit 185ecb7dc5
4 changed files with 218 additions and 160 deletions

View File

@ -1,168 +1,223 @@
### Development History of PyserSSH # History of PyserSSH
**PyserSSH Version 1.0 (Filename: "test277.py")** **PyserSSH Version 1.0 (Filename: "test277.py")**
*Date Created: September 3, 2023* *Date Created: September 3, 2023*
PyserSSH began as an experimental project aimed at addressing the lack of suitable SSH server libraries available for Python. Initially, it was developed solely for research purposes. The project was driven by the need for a customizable SSH server solution that could be tailored to specific requirements not met by existing libraries. As the project progressed, its potential to evolve into a fully functional and practical library became evident, leading to the decision to develop PyserSSH into a more robust tool for use in both software and server applications. PyserSSH began as an experimental project aimed at addressing the lack of suitable SSH server libraries available for Python. Initially, it was developed solely for research purposes. The project was driven by the need for a customizable SSH server solution that could be tailored to specific requirements not met by existing libraries. As the project progressed, its potential to evolve into a fully functional and practical library became evident, leading to the decision to develop PyserSSH into a more robust tool for use in both software and server applications.
Before creating PyserSSH, we evaluated two existing libraries: ## Before PyserSSH
Before creating PyserSSH, we evaluated several existing libraries:
1. **SSShim** ### SSHim
- **Description:** SSHim is an SSH server library designed primarily for testing SSH clients. It is discontinued and not suitable for real-world use. It allows simple interactions with the user, such as input text, but lacks ease of use for more complex scenarios. SSShim is an SSH server library designed primarily for testing SSH clients. It is discontinued and not suitable for real-world use. It allows simple interactions with the user, such as input text, but lacks ease of use for more complex scenarios.
- **Example Code:**
```python
import logging
logging.basicConfig(level='DEBUG')
logger = logging.getLogger()
import sshim, re **Example Code:**
```python
import logging
logging.basicConfig(level='DEBUG')
logger = logging.getLogger()
def hello_world(script): import sshim, re
script.write('Please enter your name: ')
groups = script.expect(re.compile('(?P<name>.*)')).groupdict()
logger.info('%(name)s just connected', **groups)
script.writeline('Hello %(name)s!' % groups)
server = sshim.Server(hello_world, port=3000) def hello_world(script):
try: script.write('Please enter your name: ')
server.run() groups = script.expect(re.compile('(?P<name>.*)')).groupdict()
except KeyboardInterrupt: logger.info('%(name)s just connected', **groups)
server.stop() script.writeline('Hello %(name)s!' % groups)
```
- **Observation:** While SSHim successfully receives user input, it is not very user-friendly or flexible for real-world applications.
2. **Twisted** server = sshim.Server(hello_world, port=3000)
- **Description:** Twisted is a comprehensive event-driven networking engine in Python. It provides an SSH server implementation but is known for its complexity, making it less accessible to new users. try:
- **Example Code:** server.run()
```python except KeyboardInterrupt:
from twisted.conch import avatar, recvline server.stop()
from twisted.conch.interfaces import IConchUser, ISession ```
from twisted.conch.ssh import factory, keys, session **Observation:** While SSHim successfully receives user input, it is not very user-friendly or flexible for real-world applications.
from twisted.conch.insults import insults
from twisted.cred import portal, checkers
from twisted.internet import reactor
from zope.interface import implements
class SSHDemoProtocol(recvline.HistoricRecvLine): ### Twisted
def __init__(self, user):
self.user = user
def connectionMade(self): Twisted is a comprehensive event-driven networking engine in Python. It provides an SSH server implementation but is known for its complexity, making it less accessible to new users.
recvline.HistoricRecvLine.connectionMade(self)
self.terminal.write("Welcome to my test SSH server.")
self.terminal.nextLine()
self.do_help()
self.showPrompt()
def showPrompt(self): **Example Code ([Thank For this gist](https://gist.github.com/michaellihs/d2070d7a6d3bb65be18c)):**
self.terminal.write("$ ") ```python
from twisted.conch import avatar, recvline
from twisted.conch.interfaces import IConchUser, ISession
from twisted.conch.ssh import factory, keys, session
from twisted.conch.insults import insults
from twisted.cred import portal, checkers
from twisted.internet import reactor
from zope.interface import implements
def getCommandFunc(self, cmd): class SSHDemoProtocol(recvline.HistoricRecvLine):
return getattr(self, 'do_' + cmd, None) def __init__(self, user):
self.user = user
def lineReceived(self, line): def connectionMade(self):
line = line.strip() recvline.HistoricRecvLine.connectionMade(self)
if line: self.terminal.write("Welcome to my test SSH server.")
print(line) self.terminal.nextLine()
with open('logfile.log', 'w') as f: self.do_help()
f.write(line + '\n') self.showPrompt()
cmdAndArgs = line.split()
cmd = cmdAndArgs[0]
args = cmdAndArgs[1:]
func = self.getCommandFunc(cmd)
if func:
try:
func(*args)
except Exception as e:
self.terminal.write("Error: %s" % e)
self.terminal.nextLine()
else:
self.terminal.write("No such command.")
self.terminal.nextLine()
self.showPrompt()
def do_help(self): def showPrompt(self):
publicMethods = [funcname for funcname in dir(self) if funcname.startswith('do_')] self.terminal.write("$ ")
commands = [cmd.replace('do_', '', 1) for cmd in publicMethods]
self.terminal.write("Commands: " + " ".join(commands))
self.terminal.nextLine()
def do_echo(self, *args): def getCommandFunc(self, cmd):
self.terminal.write(" ".join(args)) return getattr(self, 'do_' + cmd, None)
self.terminal.nextLine()
def do_whoami(self): def lineReceived(self, line):
self.terminal.write(self.user.username) line = line.strip()
self.terminal.nextLine() if line:
print(line)
with open('logfile.log', 'w') as f:
f.write(line + '\n')
cmdAndArgs = line.split()
cmd = cmdAndArgs[0]
args = cmdAndArgs[1:]
func = self.getCommandFunc(cmd)
if func:
try:
func(*args)
except Exception as e:
self.terminal.write("Error: %s" % e)
self.terminal.nextLine()
else:
self.terminal.write("No such command.")
self.terminal.nextLine()
self.showPrompt()
def do_quit(self): def do_help(self):
self.terminal.write("Thanks for playing!") publicMethods = [funcname for funcname in dir(self) if funcname.startswith('do_')]
self.terminal.nextLine() commands = [cmd.replace('do_', '', 1) for cmd in publicMethods]
self.terminal.loseConnection() self.terminal.write("Commands: " + " ".join(commands))
self.terminal.nextLine()
def do_clear(self): def do_echo(self, *args):
self.terminal.reset() self.terminal.write(" ".join(args))
self.terminal.nextLine()
class SSHDemoAvatar(avatar.ConchUser): def do_whoami(self):
implements(ISession) self.terminal.write(self.user.username)
self.terminal.nextLine()
def __init__(self, username): def do_quit(self):
avatar.ConchUser.__init__(self) self.terminal.write("Thanks for playing!")
self.username = username self.terminal.nextLine()
self.channelLookup.update({'session': session.SSHSession}) self.terminal.loseConnection()
def openShell(self, protocol): def do_clear(self):
serverProtocol = insults.ServerProtocol(SSHDemoProtocol, self) self.terminal.reset()
serverProtocol.makeConnection(protocol)
protocol.makeConnection(session.wrapProtocol(serverProtocol))
def getPty(self, terminal, windowSize, attrs): class SSHDemoAvatar(avatar.ConchUser):
return None implements(ISession)
def execCommand(self, protocol, cmd): def __init__(self, username):
raise NotImplementedError() avatar.ConchUser.__init__(self)
self.username = username
self.channelLookup.update({'session': session.SSHSession})
def closed(self): def openShell(self, protocol):
pass serverProtocol = insults.ServerProtocol(SSHDemoProtocol, self)
serverProtocol.makeConnection(protocol)
protocol.makeConnection(session.wrapProtocol(serverProtocol))
class SSHDemoRealm(object): def getPty(self, terminal, windowSize, attrs):
implements(portal.IRealm) return None
def requestAvatar(self, avatarId, mind, *interfaces): def execCommand(self, protocol, cmd):
if IConchUser in interfaces: raise NotImplementedError()
return interfaces[0], SSHDemoAvatar(avatarId), lambda: None
else:
raise NotImplementedError("No supported interfaces found.")
def getRSAKeys(): def closed(self):
with open('id_rsa') as privateBlobFile: pass
privateBlob = privateBlobFile.read()
privateKey = keys.Key.fromString(data=privateBlob)
with open('id_rsa.pub') as publicBlobFile: class SSHDemoRealm(object):
publicBlob = publicBlobFile.read() implements(portal.IRealm)
publicKey = keys.Key.fromString(data=publicBlob)
return publicKey, privateKey def requestAvatar(self, avatarId, mind, *interfaces):
if IConchUser in interfaces:
return interfaces[0], SSHDemoAvatar(avatarId), lambda: None
else:
raise NotImplementedError("No supported interfaces found.")
if __name__ == "__main__": def getRSAKeys():
sshFactory = factory.SSHFactory() with open('id_rsa') as privateBlobFile:
sshFactory.portal = portal.Portal(SSHDemoRealm()) privateBlob = privateBlobFile.read()
privateKey = keys.Key.fromString(data=privateBlob)
users = {'admin': 'aaa', 'guest': 'bbb'} with open('id_rsa.pub') as publicBlobFile:
sshFactory.portal.registerChecker( publicBlob = publicBlobFile.read()
checkers.InMemoryUsernamePasswordDatabaseDontUse(**users)) publicKey = keys.Key.fromString(data=publicBlob)
pubKey, privKey = getRSAKeys()
sshFactory.publicKeys = {'ssh-rsa': pubKey}
sshFactory.privateKeys = {'ssh-rsa': privKey}
reactor.listenTCP(22222, sshFactory)
reactor.run()
```
- **Observation:** While Twisted provides a comprehensive SSH server implementation, it is quite complex for new users and requires significant setup and configuration.
**Reconversion to PyserSSH:** return publicKey, privateKey
In contrast to SSHim and Twisted, PyserSSH aims to simplify SSH server implementation. The following example illustrates how PyserSSH makes it easier to handle user input and interactions: if __name__ == "__main__":
sshFactory = factory.SSHFactory()
sshFactory.portal = portal.Portal(SSHDemoRealm())
users = {'admin': 'aaa', 'guest': 'bbb'}
sshFactory.portal.registerChecker(
checkers.InMemoryUsernamePasswordDatabaseDontUse(**users))
pubKey, privKey = getRSAKeys()
sshFactory.publicKeys = {'ssh-rsa': pubKey}
sshFactory.privateKeys = {'ssh-rsa': privKey}
reactor.listenTCP(22222, sshFactory)
reactor.run()
```
**Observation:** While Twisted provides a comprehensive SSH server implementation, it is quite complex for new users and requires significant setup and configuration.
### Paramiko
Paramiko is a Python library for SSH protocol implementation. It supports both SSH client and server functionalities but is primarily used for SSH client tasks. It is well-documented and widely used, providing a more straightforward approach for SSH operations compared to more complex frameworks.
**Example Code:**
```python
import paramiko
class SimpleSSHServer(paramiko.ServerInterface):
def __init__(self):
self.event = paramiko.Event()
self.event.set()
def check_channel_request(self, kind, channel):
if kind == 'session':
return paramiko.OPEN_SUCCEEDED
return paramiko.FAILURE
def check_auth_password(self, username, password):
if username == 'test' and password == 'password':
return paramiko.AUTH_SUCCESSFUL
return paramiko.AUTH_FAILED
def handle_client(client_socket):
transport = paramiko.Transport(client_socket)
transport.add_server_key(paramiko.RSAKey.generate(2048))
server = SimpleSSHServer()
transport.start_server(server=server)
channel = transport.accept(20)
if channel is None:
print("No channel.")
return
channel.send("Hello from Paramiko SSH server!")
channel.recv(1024)
transport.close()
if __name__ == "__main__":
import socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('0.0.0.0', 2200))
server_socket.listen(100)
while True:
client_socket, addr = server_socket.accept()
handle_client(client_socket)
```
**Observation:** Paramiko is straightforward and well-suited for implementing SSH clients and servers. However, it requires additional code for handling specific server features and authentication mechanisms.
## Reconversion to PyserSSH
In contrast to SSHim, Twisted, and Paramiko, PyserSSH aims to simplify SSH server implementation. The following example illustrates how PyserSSH makes it easier to handle user input and interactions:
```python ```python
from PyserSSH import Server, Send, wait_input, AccountManager from PyserSSH import Server, Send, wait_input, AccountManager
@ -178,6 +233,6 @@ def hello_world(client):
server.run("your private key") server.run("your private key")
``` ```
**Advantages of PyserSSH:** ### Advantages of PyserSSH
- **Simplicity:** PyserSSH provides an intuitive and user-friendly API, making it easier for developers to create and manage SSH servers. - **Simplicity:** PyserSSH provides an intuitive and user-friendly API, making it easier for developers to create and manage SSH servers.
- **Flexibility:** PyserSSH offers the functionality needed for more complex interactions while maintaining a straightforward setup and usage. - **Flexibility:** PyserSSH offers the functionality needed for more complex interactions while maintaining a straightforward setup and usage.

View File

@ -1,35 +1,47 @@
# What is PyserSSH # What is PyserSSH
PyserSSH is a library for remote control your code with ssh client. The aim is to provide a scriptable SSH server which can be made to behave like any SSH-enabled device. PyserSSH is a free and open-source Python library designed to facilitate the creation of customizable SSH terminal servers. Initially developed for research purposes to address the lack of suitable SSH server libraries in Python, PyserSSH provides a flexible and user-friendly solution for implementing SSH servers, making it easier for developers to handle user interactions and command processing.
The project was started by a solo developer to create a more accessible and flexible tool for managing SSH connections and commands. It offers a simplified API compared to other libraries, such as Paramiko, SSHim, and Twisted, which are either outdated or complex for new users.
This project is part from [damp11113-library](https://github.com/damp11113/damp11113-library) This project is part from [damp11113-library](https://github.com/damp11113/damp11113-library)
This Server use port **2222** for default port ![Alt text](Images/PyserSSH.drawio.svg)
!!! warning "Cursor scroll in progress" !!! warning "Cursor scroll in progress"
This current version the Cursor scroll is in development! it very ugly! if you use right now. This current version the Cursor scroll is in development! it very ugly! if you use right now.
To try Cursor scroll you can enable by `disable_scroll_with_arrow=False` in `Server()` To try Cursor scroll you can enable by `disable_scroll_with_arrow=False` in `Server()`
(not recommend to enable on this version it very ugly!). (not recommend to enable on this version it very ugly!).
## Some small PyserSSH history
PyserSSH version [1.0](https://github.com/DPSoftware-Foundation/PyserSSH/releases/download/Legacy/PyserSSH10.py) (real filename is "test277.py") was created in 2023/9/3 for experimental purposes only. Because I couldn't find the best ssh server library for python and I started this project only for research. But I have time to develop this research into a real library for use. In software or server.
read full history from this [page](./history.html)
## Install ## Install
Install from pypi Install from pypi
```bash ```bash
pip install PyserSSH pip install PyserSSH
``` ```
Install from github Install with [openRemoDesk](https://github.com/DPSoftware-Foundation/openRemoDesk) protocol
```bash
pip install PyserSSH[RemoDesk]
```
Install from Github
```bash ```bash
pip install git+https://github.com/damp11113/PyserSSH.git pip install git+https://github.com/damp11113/PyserSSH.git
``` ```
Install from DPCloudev Git
```bash
pip install git+https://git.damp11113.xyz/DPSoftware-Foundation/PyserSSH.git
```
## Quick Example ## Quick Example
This Server use port **2222** for default port
```py linenums="1" ```py linenums="1"
import os
from PyserSSH import Server, Send, AccountManager from PyserSSH import Server, Send, AccountManager
useraccount = AccountManager() useraccount = AccountManager(anyuser=True)
useraccount.add_account("admin", "") # create user without password
ssh = Server(useraccount) ssh = Server(useraccount)
@ssh.on_user("command") @ssh.on_user("command")
@ -37,10 +49,10 @@ def command(client, command: str):
if command == "hello": if command == "hello":
Send(client, "world!") Send(client, "world!")
ssh.run(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'private_key.pem')) ssh.run("your private key file")
``` ```
This example you can connect with `ssh admin@localhost -p 2222` and press enter on login This example you can connect with `ssh localhost -p 2222`
If you input `hello` the response is `world` If you input `hello` the response is `world`
## Demo ## Demo
@ -49,25 +61,6 @@ https://github.com/damp11113/PyserSSH/assets/64675096/49bef3e2-3b15-4b64-b88e-3c
!!! warning "Need to changing" !!! warning "Need to changing"
For use in product please **generate new private key**! If you still use this demo private key maybe your product getting **hacked**! up to 90%. Please don't use this demo private key for real product. For use in product please **generate new private key**! If you still use this demo private key maybe your product getting **hacked**! up to 90%. Please don't use this demo private key for real product.
For run this demo you can use this command
```
$ python -m PyserSSH
```
then
```
Do you want to run demo? (y/n): y
```
But if no [damp11113-library](https://github.com/damp11113/damp11113-library)
```
No 'damp11113-library'
This demo is require 'damp11113-library' for run
```
you need to install [damp11113-library](https://github.com/damp11113/damp11113-library) for run this demo by choose `y` or `yes` in lowercase or uppercase
```
Do you want to install 'damp11113-library'? (y/n): y
```
For exit demo you can use `ctrl+c` or use `shutdown now` in PyserSSH shell **(not in real terminal)**
I intend to leaked private key because that key i generated new. I recommend to generate new key if you want to use on your host because that key is for demo only. I intend to leaked private key because that key i generated new. I recommend to generate new key if you want to use on your host because that key is for demo only.
why i talk about this? because when i push private key into this repo in next 5 min++ i getting new email from GitGuardian. in that email say " why i talk about this? because when i push private key into this repo in next 5 min++ i getting new email from GitGuardian. in that email say "
GitGuardian has detected the following RSA Private Key exposed within your GitHub account" i dont knows what is GitGuardian and i not install this app into my account. GitGuardian has detected the following RSA Private Key exposed within your GitHub account" i dont knows what is GitGuardian and i not install this app into my account.

View File

@ -11,7 +11,7 @@ The following project have been developed with PyserSSH by various developers an
</video> </video>
## SRT Karaoke (Demo 2) ## SRT Karaoke (Demo 2)
[Demo 2](https://github.com/damp11113/PyserSSH/blob/main/src/PyserSSH/demo/demo2.py) is simple srt file karaoke player with no sound. Build by PyserSSH v4.5 [Demo 2](https://github.com/damp11113/PyserSSH/blob/main/src/PyserSSH/demo/demo2.py) is simple srt file karaoke player with no sound. Build by PyserSSH v4.5 (v5.0)
<video controls> <video controls>
<source src="Videos/demo2.mp4" type="video/mp4"> <source src="Videos/demo2.mp4" type="video/mp4">

View File

@ -1,4 +1,14 @@
# Client # Client
!!! success "PyserSSH 5.0x"
In new version of PyserSSH or version 5.0
It very easy to use and more infomation for client
Don't worry for old code because in client it has backward compatibility for old code
Like "client["channel"]" to "client.channel"
`client` is use for infomation and control user `client` is use for infomation and control user
this is structure this is structure