From 79353cf668662f52e35ce3e0e11edca3665167f9 Mon Sep 17 00:00:00 2001 From: damp11113 Date: Sun, 7 Apr 2024 17:10:22 +0700 Subject: [PATCH] update 4.3 add account autosave fix timeout --- README.md | 2 - setup.py | 9 ++--- src/PyserSSH/__init__.py | 4 +- src/PyserSSH/account.py | 55 ++++++++++++++++++++++---- src/PyserSSH/extensions/XHandler.py | 27 +++++++++++++ src/PyserSSH/extensions/__init__.py | 38 ++++++++++++++++++ src/PyserSSH/extensions/dialog.py | 2 +- src/PyserSSH/extensions/moredisplay.py | 2 +- src/PyserSSH/extensions/processbar.py | 2 +- src/PyserSSH/extensions/ptop.py | 2 +- src/PyserSSH/interactive.py | 29 +++++++------- src/PyserSSH/server.py | 7 +++- src/PyserSSH/system/SFTP.py | 2 +- src/PyserSSH/system/__init__.py | 38 ++++++++++++++++++ src/PyserSSH/system/info.py | 2 +- src/PyserSSH/system/inputsystem.py | 25 +++++++----- src/PyserSSH/system/interface.py | 2 +- src/PyserSSH/system/syscom.py | 2 +- src/PyserSSH/system/sysfunc.py | 2 +- 19 files changed, 201 insertions(+), 51 deletions(-) create mode 100644 src/PyserSSH/extensions/__init__.py create mode 100644 src/PyserSSH/system/__init__.py diff --git a/README.md b/README.md index fca31ba..b8b9072 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/setup.py b/setup.py index 23dce92..f46ebfc 100644 --- a/setup.py +++ b/setup.py @@ -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"] - } + ] ) \ No newline at end of file diff --git a/src/PyserSSH/__init__.py b/src/PyserSSH/__init__.py index 2f66e1b..ee37312 100644 --- a/src/PyserSSH/__init__.py +++ b/src/PyserSSH/__init__.py @@ -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 diff --git a/src/PyserSSH/account.py b/src/PyserSSH/account.py index f84701b..292cc31 100644 --- a/src/PyserSSH/account.py +++ b/src/PyserSSH/account.py @@ -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 \ No newline at end of file + return None # User or history not found diff --git a/src/PyserSSH/extensions/XHandler.py b/src/PyserSSH/extensions/XHandler.py index 6098262..34e82ac 100644 --- a/src/PyserSSH/extensions/XHandler.py +++ b/src/PyserSSH/extensions/XHandler.py @@ -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 diff --git a/src/PyserSSH/extensions/__init__.py b/src/PyserSSH/extensions/__init__.py new file mode 100644 index 0000000..a30a409 --- /dev/null +++ b/src/PyserSSH/extensions/__init__.py @@ -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 +""" \ No newline at end of file diff --git a/src/PyserSSH/extensions/dialog.py b/src/PyserSSH/extensions/dialog.py index 6fe78ad..61049bf 100644 --- a/src/PyserSSH/extensions/dialog.py +++ b/src/PyserSSH/extensions/dialog.py @@ -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 diff --git a/src/PyserSSH/extensions/moredisplay.py b/src/PyserSSH/extensions/moredisplay.py index e3ad84f..7339117 100644 --- a/src/PyserSSH/extensions/moredisplay.py +++ b/src/PyserSSH/extensions/moredisplay.py @@ -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 diff --git a/src/PyserSSH/extensions/processbar.py b/src/PyserSSH/extensions/processbar.py index b23c6b7..2b592f2 100644 --- a/src/PyserSSH/extensions/processbar.py +++ b/src/PyserSSH/extensions/processbar.py @@ -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 diff --git a/src/PyserSSH/extensions/ptop.py b/src/PyserSSH/extensions/ptop.py index 3c97851..d45232f 100644 --- a/src/PyserSSH/extensions/ptop.py +++ b/src/PyserSSH/extensions/ptop.py @@ -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 diff --git a/src/PyserSSH/interactive.py b/src/PyserSSH/interactive.py index f7522ab..125e975 100644 --- a/src/PyserSSH/interactive.py +++ b/src/PyserSSH/interactive.py @@ -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 \ No newline at end of file diff --git a/src/PyserSSH/server.py b/src/PyserSSH/server.py index 16ee3da..f80c493 100644 --- a/src/PyserSSH/server.py +++ b/src/PyserSSH/server.py @@ -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')) diff --git a/src/PyserSSH/system/SFTP.py b/src/PyserSSH/system/SFTP.py index de125cd..d3143af 100644 --- a/src/PyserSSH/system/SFTP.py +++ b/src/PyserSSH/system/SFTP.py @@ -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 diff --git a/src/PyserSSH/system/__init__.py b/src/PyserSSH/system/__init__.py new file mode 100644 index 0000000..a30a409 --- /dev/null +++ b/src/PyserSSH/system/__init__.py @@ -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 +""" \ No newline at end of file diff --git a/src/PyserSSH/system/info.py b/src/PyserSSH/system/info.py index 84edfcd..4acfae7 100644 --- a/src/PyserSSH/system/info.py +++ b/src/PyserSSH/system/info.py @@ -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 diff --git a/src/PyserSSH/system/inputsystem.py b/src/PyserSSH/system/inputsystem.py index 6b23479..95e8550 100644 --- a/src/PyserSSH/system/inputsystem.py +++ b/src/PyserSSH/system/inputsystem.py @@ -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: diff --git a/src/PyserSSH/system/interface.py b/src/PyserSSH/system/interface.py index 7a05bda..c789c6d 100644 --- a/src/PyserSSH/system/interface.py +++ b/src/PyserSSH/system/interface.py @@ -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 diff --git a/src/PyserSSH/system/syscom.py b/src/PyserSSH/system/syscom.py index f1fa82c..9b5bf5d 100644 --- a/src/PyserSSH/system/syscom.py +++ b/src/PyserSSH/system/syscom.py @@ -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 diff --git a/src/PyserSSH/system/sysfunc.py b/src/PyserSSH/system/sysfunc.py index ae12805..c1b6999 100644 --- a/src/PyserSSH/system/sysfunc.py +++ b/src/PyserSSH/system/sysfunc.py @@ -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