update 4.3

add account autosave
fix timeout
This commit is contained in:
dharm pimsen 2024-04-07 17:10:22 +07:00
parent c9ffdf5201
commit 79353cf668
19 changed files with 201 additions and 51 deletions

View File

@ -15,8 +15,6 @@ Install from github
```bash
pip install git+https://github.com/damp11113/PyserSSH.git
```
## Optional Packages
- [damp11113-library](https://github.com/damp11113/damp11113-library)
# Quick Example
```py

View File

@ -5,20 +5,17 @@ with open('README.md', 'r', encoding='utf-8') as f:
setup(
name='PyserSSH',
version='4.2.1', # update pypi (no update for 4.3)
version='4.3',
license='MIT',
author='damp11113',
author_email='damp51252@gmail.com',
packages=find_packages('src'),
package_dir={'': 'src'},
url='https://github.com/damp11113/PyserSSH',
description="A easy ssh server",
description="python scriptable ssh server library. based on Paramiko",
long_description=long_description,
long_description_content_type='text/markdown',
install_requires=[
"paramiko"
],
extras_require={
"fullsyscom": ["damp11113"]
}
]
)

View File

@ -1,5 +1,5 @@
"""
PyserSSH - A SSH server. For more info visit https://github.com/damp11113/PyserSSH
PyserSSH - A Scriptable SSH server. For more info visit https://github.com/damp11113/PyserSSH
Copyright (C) 2023-2024 damp11113 (MIT)
Visit https://github.com/damp11113/PyserSSH
@ -60,7 +60,7 @@ try:
except:
os.environ["pyserssh_log"] = "NO"
if os.environ["pyserssh_log"]:
if os.environ["pyserssh_log"] == "NO":
logger = logging.getLogger("PyserSSH")
logger.disabled = True

View File

@ -1,5 +1,5 @@
"""
PyserSSH - A SSH server. For more info visit https://github.com/damp11113/PyserSSH
PyserSSH - A Scriptable SSH server. For more info visit https://github.com/damp11113/PyserSSH
Copyright (C) 2023-2024 damp11113 (MIT)
Visit https://github.com/damp11113/PyserSSH
@ -26,16 +26,45 @@ SOFTWARE.
"""
import pickle
import time
import atexit
import threading
class AccountManager:
def __init__(self, anyuser=False, historylimit=10):
def __init__(self, anyuser=False, historylimit=10, autosave=False, autosavedelay=60, autoload=False, autoloadfile="autosave_session.ses"):
self.accounts = {}
self.anyuser = anyuser
self.historylimit = historylimit
self.autosavedelay = autosavedelay
self.__autosavework = False
self.__autosaveworknexttime = 0
if self.anyuser:
print("history system can't work if 'anyuser' is enable")
if autoload:
self.load(autoloadfile)
if autosave:
self.__autosavethread = threading.Thread(target=self.__autosave)
self.__autosavethread.start()
atexit.register(self.__saveexit)
def __autosave(self):
self.save("autosave_session.ses")
self.__autosaveworknexttime = time.time() + self.autosavedelay
self.__autosavework = True
while self.__autosavework:
if int(self.__autosaveworknexttime) == int(time.time()):
self.save("autosave_session.ses")
self.__autosaveworknexttime = time.time() + self.autosavedelay
def __saveexit(self):
self.__autosavework = False
self.save("autosave_session.ses")
self.__autosavethread.join()
def validate_credentials(self, username, password):
if username in self.accounts and self.accounts[username]["password"] == password or self.anyuser:
return True
@ -66,11 +95,11 @@ class AccountManager:
if username in self.accounts:
self.accounts[username]["permissions"] = new_permissions
def save_to_file(self, filename):
def save(self, filename="session.ssh"):
with open(filename, 'wb') as file:
pickle.dump(self.accounts, file)
def load_from_file(self, filename):
def load(self, filename):
try:
with open(filename, 'rb') as file:
self.accounts = pickle.load(file)
@ -114,12 +143,24 @@ class AccountManager:
def get_user_timeout(self, username):
if username in self.accounts and "timeout" in self.accounts[username]:
return self.accounts[username]["timeout"]
return 0
return None
def set_user_timeout(self, username, timeout=0):
def set_user_timeout(self, username, timeout=None):
if username in self.accounts:
self.accounts[username]["timeout"] = timeout
def get_user_last_login(self, username):
if username in self.accounts and "lastlogin" in self.accounts[username]:
return self.accounts[username]["lastlogin"]
return None
def set_user_last_login(self, username, ip, timelogin=time.time()):
if username in self.accounts:
self.accounts[username]["lastlogin"] = {
"ip": ip,
"time": timelogin
}
def add_history(self, username, command):
if not self.anyuser:
if username in self.accounts:
@ -158,4 +199,4 @@ class AccountManager:
if username in self.accounts and "lastcommand" in self.accounts[username]:
command = self.accounts[username]["lastcommand"]
return command
return None # User or history not found
return None # User or history not found

View File

@ -1,3 +1,30 @@
"""
PyserSSH - A Scriptable SSH server. For more info visit https://github.com/damp11113/PyserSSH
Copyright (C) 2023-2024 damp11113 (MIT)
Visit https://github.com/damp11113/PyserSSH
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
import inspect
import shlex

View File

@ -0,0 +1,38 @@
"""
PyserSSH - A Scriptable SSH server. For more info visit https://github.com/damp11113/PyserSSH
Copyright (C) 2023-2024 damp11113 (MIT)
Visit https://github.com/damp11113/PyserSSH
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
"""
note
ansi cursor arrow
up - \x1b[A
down - \x1b[B
left - \x1b[D
right - \x1b[C
https://en.wikipedia.org/wiki/ANSI_escape_code
"""

View File

@ -1,5 +1,5 @@
"""
PyserSSH - A SSH server. For more info visit https://github.com/damp11113/PyserSSH
PyserSSH - A Scriptable SSH server. For more info visit https://github.com/damp11113/PyserSSH
Copyright (C) 2023-2024 damp11113 (MIT)
Visit https://github.com/damp11113/PyserSSH

View File

@ -1,5 +1,5 @@
"""
PyserSSH - A SSH server. For more info visit https://github.com/damp11113/PyserSSH
PyserSSH - A Scriptable SSH server. For more info visit https://github.com/damp11113/PyserSSH
Copyright (C) 2023-2024 damp11113 (MIT)
Visit https://github.com/damp11113/PyserSSH

View File

@ -1,5 +1,5 @@
"""
PyserSSH - A SSH server. For more info visit https://github.com/damp11113/PyserSSH
PyserSSH - A Scriptable SSH server. For more info visit https://github.com/damp11113/PyserSSH
Copyright (C) 2023-2024 damp11113 (MIT)
Visit https://github.com/damp11113/PyserSSH

View File

@ -1,5 +1,5 @@
"""
PyserSSH - A SSH server. For more info visit https://github.com/damp11113/PyserSSH
PyserSSH - A Scriptable SSH server. For more info visit https://github.com/damp11113/PyserSSH
Copyright (C) 2023-2024 damp11113 (MIT)
Visit https://github.com/damp11113/PyserSSH

View File

@ -1,5 +1,5 @@
"""
PyserSSH - A SSH server. For more info visit https://github.com/damp11113/PyserSSH
PyserSSH - A Scriptable SSH server. For more info visit https://github.com/damp11113/PyserSSH
Copyright (C) 2023-2024 damp11113 (MIT)
Visit https://github.com/damp11113/PyserSSH
@ -102,17 +102,18 @@ def wait_input(client, prompt="", defaultvalue=None, cursor_scroll=False, echo=T
channel.sendall(b'\r\n')
except socket.timeout:
channel.setblocking(False)
channel.settimeout(None)
channel.sendall(b'\r\n')
output = ""
except Exception:
channel.setblocking(False)
channel.settimeout(None)
channel.sendall(b'\r\n')
raise
else:
output = buffer.decode('utf-8')
if timeout != 0:
channel.settimeout(0)
channel.setblocking(False)
channel.sendall(b'\r\n')
# Return default value if specified and no input given
if defaultvalue is not None and not output.strip():
return defaultvalue
@ -144,14 +145,14 @@ def wait_inputkey(client, prompt="", raw=False, timeout=0):
return byte
except socket.timeout:
channel.settimeout(0)
channel.setblocking(False)
channel.settimeout(None)
channel.send("\r\n")
return None
except Exception:
if timeout != 0:
channel.settimeout(0)
channel.setblocking(False)
channel.setblocking(False)
channel.settimeout(None)
channel.send("\r\n")
raise
def wait_choose(client, choose, prompt="", timeout=0):
@ -193,12 +194,12 @@ def wait_choose(client, choose, prompt="", timeout=0):
if chooseindex > chooselen:
chooseindex = chooselen
except socket.timeout:
channel.settimeout(0)
channel.setblocking(False)
channel.settimeout(None)
channel.send("\r\n")
return chooseindex
except Exception:
if timeout != 0:
channel.settimeout(0)
channel.setblocking(False)
channel.setblocking(False)
channel.settimeout(None)
channel.send("\r\n")
raise

View File

@ -1,5 +1,5 @@
"""
PyserSSH - A SSH server. For more info visit https://github.com/damp11113/PyserSSH
PyserSSH - A Scriptable SSH server. For more info visit https://github.com/damp11113/PyserSSH
Copyright (C) 2023-2024 damp11113 (MIT)
Visit https://github.com/damp11113/PyserSSH
@ -147,6 +147,8 @@ class Server:
client_handler["last_activity_time"] = time.time()
client_handler["last_login_time"] = time.time()
self.accounts.set_user_last_login(self.client_handlers[channel.getpeername()]["current_user"], peername[0])
#if not any(bh_session.remote_version.split("-")[2].startswith(prefix) for prefix in sftpclient):
if not channel.out_window_size == bh_session.default_window_size:
while self.client_handlers[channel.getpeername()]["windowsize"] == {}:
@ -166,7 +168,8 @@ class Server:
client_handler["connecttype"] = "ssh"
if self.enainputsystem:
try:
if self.accounts.get_user_timeout(self.client_handlers[channel.getpeername()]["current_user"]) != 0:
if self.accounts.get_user_timeout(self.client_handlers[channel.getpeername()]["current_user"]) != None:
channel.setblocking(False)
channel.settimeout(self.accounts.get_user_timeout(self.client_handlers[channel.getpeername()]["current_user"]))
channel.send(replace_enter_with_crlf(self.accounts.get_prompt(self.client_handlers[channel.getpeername()]["current_user"]) + " ").encode('utf-8'))

View File

@ -1,5 +1,5 @@
"""
PyserSSH - A SSH server. For more info visit https://github.com/damp11113/PyserSSH
PyserSSH - A Scriptable SSH server. For more info visit https://github.com/damp11113/PyserSSH
Copyright (C) 2023-2024 damp11113 (MIT)
Visit https://github.com/damp11113/PyserSSH

View File

@ -0,0 +1,38 @@
"""
PyserSSH - A Scriptable SSH server. For more info visit https://github.com/damp11113/PyserSSH
Copyright (C) 2023-2024 damp11113 (MIT)
Visit https://github.com/damp11113/PyserSSH
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
"""
note
ansi cursor arrow
up - \x1b[A
down - \x1b[B
left - \x1b[D
right - \x1b[C
https://en.wikipedia.org/wiki/ANSI_escape_code
"""

View File

@ -1,5 +1,5 @@
"""
PyserSSH - A SSH server. For more info visit https://github.com/damp11113/PyserSSH
PyserSSH - A Scriptable SSH server. For more info visit https://github.com/damp11113/PyserSSH
Copyright (C) 2023-2024 damp11113 (MIT)
Visit https://github.com/damp11113/PyserSSH

View File

@ -1,5 +1,5 @@
"""
PyserSSH - A SSH server. For more info visit https://github.com/damp11113/PyserSSH
PyserSSH - A Scriptable SSH server. For more info visit https://github.com/damp11113/PyserSSH
Copyright (C) 2023-2024 damp11113 (MIT)
Visit https://github.com/damp11113/PyserSSH
@ -43,7 +43,14 @@ def expect(self, chan, peername, echo=True):
currentuser = self.client_handlers[chan.getpeername()]
try:
while True:
byte = chan.recv(1)
try:
byte = chan.recv(1)
except socket.timeout:
chan.setblocking(False)
chan.settimeout(None)
chan.close()
raise EOFError()
self._handle_event("onrawtype", self.client_handlers[chan.getpeername()], byte)
self.client_handlers[chan.getpeername()]["last_activity_time"] = time.time()
@ -151,9 +158,9 @@ def expect(self, chan, peername, echo=True):
self.accounts.add_history(currentuser["current_user"], command)
if command.strip() != "":
if self.accounts.get_user_timeout(self.client_handlers[chan.getpeername()]["current_user"]) != 0:
chan.settimeout(0)
if self.accounts.get_user_timeout(self.client_handlers[chan.getpeername()]["current_user"]) != None:
chan.setblocking(False)
chan.settimeout(None)
try:
if self.enasyscom:
@ -179,13 +186,13 @@ def expect(self, chan, peername, echo=True):
except:
logger.error("Send error")
if self.accounts.get_user_timeout(self.client_handlers[chan.getpeername()]["current_user"]) != 0:
chan.setblocking(False)
chan.settimeout(None)
if self.accounts.get_user_timeout(self.client_handlers[chan.getpeername()]["current_user"]) != None:
chan.setblocking(False)
chan.settimeout(self.accounts.get_user_timeout(self.client_handlers[chan.getpeername()]["current_user"]))
except socket.timeout:
chan.settimeout(0)
chan.setblocking(False)
chan.close()
except Exception as e:
logger.error(str(e))
finally:

View File

@ -1,5 +1,5 @@
"""
PyserSSH - A SSH server. For more info visit https://github.com/damp11113/PyserSSH
PyserSSH - A Scriptable SSH server. For more info visit https://github.com/damp11113/PyserSSH
Copyright (C) 2023-2024 damp11113 (MIT)
Visit https://github.com/damp11113/PyserSSH

View File

@ -1,5 +1,5 @@
"""
PyserSSH - A SSH server. For more info visit https://github.com/damp11113/PyserSSH
PyserSSH - A Scriptable SSH server. For more info visit https://github.com/damp11113/PyserSSH
Copyright (C) 2023-2024 damp11113 (MIT)
Visit https://github.com/damp11113/PyserSSH

View File

@ -1,5 +1,5 @@
"""
PyserSSH - A SSH server. For more info visit https://github.com/damp11113/PyserSSH
PyserSSH - A Scriptable SSH server. For more info visit https://github.com/damp11113/PyserSSH
Copyright (C) 2023-2024 damp11113 (MIT)
Visit https://github.com/damp11113/PyserSSH