diff --git a/.gitignore b/.gitignore index b51ac5a..6efb47d 100644 --- a/.gitignore +++ b/.gitignore @@ -130,3 +130,6 @@ dmypy.json #clients *sync_client* + +#App +connpy-completion-helper diff --git a/README.md b/README.md index 9200ea2..c39f41c 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,8 @@ [![](https://img.shields.io/pypi/l/connpy.svg?style=flat-square)](https://github.com/fluzzi/connpy/blob/main/LICENSE) [![](https://img.shields.io/pypi/dm/connpy.svg?style=flat-square)](https://pypi.org/pypi/connpy/) -Connpy is a ssh and telnet connection manager and automation module for Linux, Mac and Docker +Connpy is a SSH, SFTP, Telnet, kubectl, and Docker pod connection manager and automation module for Linux, Mac, and Docker. + ## Installation @@ -43,33 +44,34 @@ Connpy integrates with Google services for backup purposes: For more detailed information, please read our [Privacy Policy](https://connpy.gederico.dynu.net/fluzzi32/connpy/src/branch/main/PRIVATE_POLICY.md). + ### Features - - You can generate profiles and reference them from nodes using @profilename so you dont - need to edit multiple nodes when changing password or other information. - - Nodes can be stored on @folder or @subfolder@folder to organize your devices. Then can - be referenced using node@subfolder@folder or node@folder - - If you have too many nodes. Get completion script using: conn config --completion. - Or use fzf installing pyfzf and running conn config --fzf true - - Create in bulk, copy, move, export and import nodes for easy management. - - Run automation scripts in network devices. - - use GPT AI to help you manage your devices. + - Manage connections using SSH, SFTP, Telnet, kubectl, and Docker exec. + - Set contexts to manage specific nodes from specific contexts (work/home/clients/etc). + - You can generate profiles and reference them from nodes using @profilename so you don't + need to edit multiple nodes when changing passwords or other information. + - Nodes can be stored on @folder or @subfolder@folder to organize your devices. They can + be referenced using node@subfolder@folder or node@folder. + - If you have too many nodes, get a completion script using: conn config --completion. + Or use fzf by installing pyfzf and running conn config --fzf true. + - Create in bulk, copy, move, export, and import nodes for easy management. + - Run automation scripts on network devices. + - Use GPT AI to help you manage your devices. - Add plugins with your own scripts. - Much more! ### Usage: ``` usage: conn [-h] [--add | --del | --mod | --show | --debug] [node|folder] [--sftp] - conn {profile,move,mv,copy,cp,list,ls,bulk,export,import,ai,run,api,plugin,config} ... + conn {profile,move,mv,copy,cp,list,ls,bulk,export,import,ai,run,api,plugin,config,sync,context} ... positional arguments: - node|folder node[@subfolder][@folder] - Connect to specific node or show all matching nodes - [@subfolder][@folder] - Show all available connections globaly or in specified path -``` + node|folder node[@subfolder][@folder] + Connect to specific node or show all matching nodes + [@subfolder][@folder] + Show all available connections globally or in specified path -### Options: -``` +options: -h, --help show this help message and exit -v, --version Show version -a, --add Add new node[@subfolder][@folder] or [@subfolder]@folder @@ -78,10 +80,8 @@ positional arguments: -s, --show Show node[@subfolder][@folder] -d, --debug Display all conections steps -t, --sftp Connects using sftp instead of ssh -``` -### Commands: -``` +Commands: profile Manage profiles move(mv) Move node copy(cp) Copy node @@ -95,6 +95,7 @@ positional arguments: plugin Manage plugins config Manage app config sync Sync config with Google + context Manage contexts with regex matching ``` ### Manage profiles: @@ -115,14 +116,26 @@ options: ### Examples: ``` + #Add new profile conn profile --add office-user + #Add new folder conn --add @office + #Add new subfolder conn --add @datacenter@office + #Add node to subfolder conn --add server@datacenter@office + #Add node to folder conn --add pc@office + #Show node information conn --show server@datacenter@office + #Connect to nodes conn pc@office conn server + #Create and set new context + conn context -a office .*@office + conn context --set office + #Run a command in a node + conn run server ls -la ``` ## Plugin Requirements for Connpy diff --git a/connpy/__init__.py b/connpy/__init__.py index fbe3321..e11e917 100644 --- a/connpy/__init__.py +++ b/connpy/__init__.py @@ -2,32 +2,35 @@ ''' ## Connection manager -Connpy is a connection manager that allows you to store nodes to connect them fast and password free. +Connpy is a SSH, SFTP, Telnet, kubectl, and Docker pod connection manager and automation module for Linux, Mac, and Docker. ### Features - - You can generate profiles and reference them from nodes using @profilename so you dont - need to edit multiple nodes when changing password or other information. - - Nodes can be stored on @folder or @subfolder@folder to organize your devices. Then can - be referenced using node@subfolder@folder or node@folder - - If you have too many nodes. Get completion script using: conn config --completion. - Or use fzf installing pyfzf and running conn config --fzf true - - Create in bulk, copy, move, export and import nodes for easy management. - - Run automation scripts in network devices. - - use GPT AI to help you manage your devices. + - Manage connections using SSH, SFTP, Telnet, kubectl, and Docker exec. + - Set contexts to manage specific nodes from specific contexts (work/home/clients/etc). + - You can generate profiles and reference them from nodes using @profilename so you don't + need to edit multiple nodes when changing passwords or other information. + - Nodes can be stored on @folder or @subfolder@folder to organize your devices. They can + be referenced using node@subfolder@folder or node@folder. + - If you have too many nodes, get a completion script using: conn config --completion. + Or use fzf by installing pyfzf and running conn config --fzf true. + - Create in bulk, copy, move, export, and import nodes for easy management. + - Run automation scripts on network devices. + - Use GPT AI to help you manage your devices. - Add plugins with your own scripts. - Much more! ### Usage ``` usage: conn [-h] [--add | --del | --mod | --show | --debug] [node|folder] [--sftp] - conn {profile,move,mv,copy,cp,list,ls,bulk,export,import,ai,run,api,plugin,config} ... + conn {profile,move,mv,copy,cp,list,ls,bulk,export,import,ai,run,api,plugin,config,sync,context} ... positional arguments: - node|folder node[@subfolder][@folder] - Connect to specific node or show all matching nodes - [@subfolder][@folder] - Show all available connections globaly or in specified path -Options: + node|folder node[@subfolder][@folder] + Connect to specific node or show all matching nodes + [@subfolder][@folder] + Show all available connections globally or in specified path + +options: -h, --help show this help message and exit -v, --version Show version -a, --add Add new node[@subfolder][@folder] or [@subfolder]@folder @@ -51,6 +54,7 @@ Commands: plugin Manage plugins config Manage app config sync Sync config with Google + context Manage contexts with regex matching ``` ### Manage profiles @@ -71,14 +75,26 @@ options: ### Examples ``` + #Add new profile conn profile --add office-user + #Add new folder conn --add @office + #Add new subfolder conn --add @datacenter@office + #Add node to subfolder conn --add server@datacenter@office + #Add node to folder conn --add pc@office + #Show node information conn --show server@datacenter@office + #Connect to nodes conn pc@office conn server + #Create and set new context + conn context -a office .*@office + conn context --set office + #Run a command in a node + conn run server ls -la ``` ## Plugin Requirements for Connpy ### General Structure diff --git a/connpy/_version.py b/connpy/_version.py index a34b9a9..87f75a0 100644 --- a/connpy/_version.py +++ b/connpy/_version.py @@ -1,2 +1,2 @@ -__version__ = "4.1.0b3" +__version__ = "4.1.0" diff --git a/connpy/core_plugins/context.py b/connpy/core_plugins/context.py index 6922abf..84dcc74 100644 --- a/connpy/core_plugins/context.py +++ b/connpy/core_plugins/context.py @@ -41,6 +41,9 @@ class context_manager: elif context not in self.contexts: print(f"Context {context} doesn't exist.") exit(4) + if context == self.current_context: + print(f"Can't delete current context: {self.current_context}") + exit(5) else: self.contexts.pop(context) self.connapp._change_settings("contexts", self.contexts) @@ -152,3 +155,26 @@ class Entrypoint: cm.set_context(args.context_name) elif args.show: cm.show_context(args.context_name) + +def _connpy_completion(wordsnumber, words, info=None): + if wordsnumber == 3: + result = ["--help", "--add", "--del", "--rm", "--ls", "--set", "--show", "--edit", "--mod"] + elif wordsnumber == 4 and words[1] in ["--del", "-r", "--rm", "--set", "--edit", "--mod", "-e", "--show", "-s"]: + contexts = info["config"]["config"]["contexts"].keys() + current_context = info["config"]["config"]["current_context"] + default_context = "all" + + if words[1] in ["--del", "-r", "--rm"]: + # Filter out default context and current context + result = [context for context in contexts if context not in [default_context, current_context]] + elif words[1] == "--set": + # Filter out current context + result = [context for context in contexts if context != current_context] + elif words[1] in ["--edit", "--mod", "-e"]: + # Filter out default context + result = [context for context in contexts if context != default_context] + elif words[1] in ["--show", "-s"]: + # No filter for show + result = list(contexts) + + return result diff --git a/docs/connpy/index.html b/docs/connpy/index.html index 9a843db..211056a 100644 --- a/docs/connpy/index.html +++ b/docs/connpy/index.html @@ -23,30 +23,33 @@

Connection manager

-

Connpy is a connection manager that allows you to store nodes to connect them fast and password free.

+

Connpy is a SSH, SFTP, Telnet, kubectl, and Docker pod connection manager and automation module for Linux, Mac, and Docker.

Features

-
- You can generate profiles and reference them from nodes using @profilename so you dont
-  need to edit multiple nodes when changing password or other information.
-- Nodes can be stored on @folder or @subfolder@folder to organize your devices. Then can 
-  be referenced using node@subfolder@folder or node@folder
-- If you have too many nodes. Get completion script using: conn config --completion.
-  Or use fzf installing pyfzf and running conn config --fzf true
-- Create in bulk, copy, move, export and import nodes for easy management.
-- Run automation scripts in network devices.
-- use GPT AI to help you manage your devices.
+
- Manage connections using SSH, SFTP, Telnet, kubectl, and Docker exec.
+- Set contexts to manage specific nodes from specific contexts (work/home/clients/etc).
+- You can generate profiles and reference them from nodes using @profilename so you don't
+  need to edit multiple nodes when changing passwords or other information.
+- Nodes can be stored on @folder or @subfolder@folder to organize your devices. They can
+  be referenced using node@subfolder@folder or node@folder.
+- If you have too many nodes, get a completion script using: conn config --completion.
+  Or use fzf by installing pyfzf and running conn config --fzf true.
+- Create in bulk, copy, move, export, and import nodes for easy management.
+- Run automation scripts on network devices.
+- Use GPT AI to help you manage your devices.
 - Add plugins with your own scripts.
 - Much more!
 

Usage

usage: conn [-h] [--add | --del | --mod | --show | --debug] [node|folder] [--sftp]
-       conn {profile,move,mv,copy,cp,list,ls,bulk,export,import,ai,run,api,plugin,config} ...
+       conn {profile,move,mv,copy,cp,list,ls,bulk,export,import,ai,run,api,plugin,config,sync,context} ...
 
 positional arguments:
-  node|folder    node[@subfolder][@folder]
-                 Connect to specific node or show all matching nodes
-                 [@subfolder][@folder]
-                 Show all available connections globaly or in specified path
-Options:
+  node|folder        node[@subfolder][@folder]
+                     Connect to specific node or show all matching nodes
+                     [@subfolder][@folder]
+                     Show all available connections globally or in specified path
+
+options:
   -h, --help         show this help message and exit
   -v, --version      Show version
   -a, --add          Add new node[@subfolder][@folder] or [@subfolder]@folder
@@ -70,6 +73,7 @@ Commands:
   plugin          Manage plugins
   config          Manage app config
   sync            Sync config with Google
+  context         Manage contexts with regex matching
 

Manage profiles

usage: conn profile [-h] (--add | --del | --mod | --show) profile
@@ -86,14 +90,26 @@ options:
 
 

Examples

-
   conn profile --add office-user
+
   #Add new profile
+   conn profile --add office-user
+   #Add new folder
    conn --add @office
+   #Add new subfolder
    conn --add @datacenter@office
+   #Add node to subfolder
    conn --add server@datacenter@office
+   #Add node to folder
    conn --add pc@office
+   #Show node information
    conn --show server@datacenter@office
+   #Connect to nodes
    conn pc@office
    conn server
+   #Create and set new context
+   conn context -a office .*@office
+   conn context --set office
+   #Run a command in a node
+   conn run server ls -la
 

Plugin Requirements for Connpy

General Structure

@@ -416,32 +432,35 @@ print(result) ''' ## Connection manager -Connpy is a connection manager that allows you to store nodes to connect them fast and password free. +Connpy is a SSH, SFTP, Telnet, kubectl, and Docker pod connection manager and automation module for Linux, Mac, and Docker. ### Features - - You can generate profiles and reference them from nodes using @profilename so you dont - need to edit multiple nodes when changing password or other information. - - Nodes can be stored on @folder or @subfolder@folder to organize your devices. Then can - be referenced using node@subfolder@folder or node@folder - - If you have too many nodes. Get completion script using: conn config --completion. - Or use fzf installing pyfzf and running conn config --fzf true - - Create in bulk, copy, move, export and import nodes for easy management. - - Run automation scripts in network devices. - - use GPT AI to help you manage your devices. + - Manage connections using SSH, SFTP, Telnet, kubectl, and Docker exec. + - Set contexts to manage specific nodes from specific contexts (work/home/clients/etc). + - You can generate profiles and reference them from nodes using @profilename so you don't + need to edit multiple nodes when changing passwords or other information. + - Nodes can be stored on @folder or @subfolder@folder to organize your devices. They can + be referenced using node@subfolder@folder or node@folder. + - If you have too many nodes, get a completion script using: conn config --completion. + Or use fzf by installing pyfzf and running conn config --fzf true. + - Create in bulk, copy, move, export, and import nodes for easy management. + - Run automation scripts on network devices. + - Use GPT AI to help you manage your devices. - Add plugins with your own scripts. - Much more! ### Usage ``` usage: conn [-h] [--add | --del | --mod | --show | --debug] [node|folder] [--sftp] - conn {profile,move,mv,copy,cp,list,ls,bulk,export,import,ai,run,api,plugin,config} ... + conn {profile,move,mv,copy,cp,list,ls,bulk,export,import,ai,run,api,plugin,config,sync,context} ... positional arguments: - node|folder node[@subfolder][@folder] - Connect to specific node or show all matching nodes - [@subfolder][@folder] - Show all available connections globaly or in specified path -Options: + node|folder node[@subfolder][@folder] + Connect to specific node or show all matching nodes + [@subfolder][@folder] + Show all available connections globally or in specified path + +options: -h, --help show this help message and exit -v, --version Show version -a, --add Add new node[@subfolder][@folder] or [@subfolder]@folder @@ -465,6 +484,7 @@ Commands: plugin Manage plugins config Manage app config sync Sync config with Google + context Manage contexts with regex matching ``` ### Manage profiles @@ -485,14 +505,26 @@ options: ### Examples ``` + #Add new profile conn profile --add office-user + #Add new folder conn --add @office + #Add new subfolder conn --add @datacenter@office + #Add node to subfolder conn --add server@datacenter@office + #Add node to folder conn --add pc@office + #Show node information conn --show server@datacenter@office + #Connect to nodes conn pc@office conn server + #Create and set new context + conn context -a office .*@office + conn context --set office + #Run a command in a node + conn run server ls -la ``` ## Plugin Requirements for Connpy ### General Structure @@ -2497,7 +2529,7 @@ def getitems(self, uniques): - port (str): Port to connect to node, default 22 for ssh and 23 for telnet. -- protocol (str): Select ssh or telnet. Default is ssh. +- protocol (str): Select ssh, telnet, kubectl or docker. Default is ssh. - user (str): Username to of the node. @@ -2555,7 +2587,7 @@ class node: - port (str): Port to connect to node, default 22 for ssh and 23 for telnet. - - protocol (str): Select ssh or telnet. Default is ssh. + - protocol (str): Select ssh, telnet, kubectl or docker. Default is ssh. - user (str): Username to of the node. @@ -2824,6 +2856,14 @@ class node: connect = self._connect(timeout = timeout) now = datetime.datetime.now().strftime('%Y-%m-%d_%H%M%S') if connect == True: + # Attempt to set the terminal size + try: + self.child.setwinsize(65535, 65535) + except Exception: + try: + self.child.setwinsize(10000, 10000) + except Exception: + pass if "prompt" in self.tags: prompt = self.tags["prompt"] expects = [prompt, pexpect.EOF, pexpect.TIMEOUT] @@ -2911,6 +2951,14 @@ class node: ''' connect = self._connect(timeout = timeout) if connect == True: + # Attempt to set the terminal size + try: + self.child.setwinsize(65535, 65535) + except Exception: + try: + self.child.setwinsize(10000, 10000) + except Exception: + pass if "prompt" in self.tags: prompt = self.tags["prompt"] expects = [prompt, pexpect.EOF, pexpect.TIMEOUT] @@ -2966,47 +3014,101 @@ class node: return connect @MethodHook - def _connect(self, debug = False, timeout = 10, max_attempts = 3): - # Method to connect to the node, it parse all the information, create the ssh/telnet command and login to the node. + def _generate_ssh_sftp_cmd(self): + cmd = self.protocol + if self.idletime > 0: + cmd += " -o ServerAliveInterval=" + str(self.idletime) + if self.port: + if self.protocol == "ssh": + cmd += " -p " + self.port + elif self.protocol == "sftp": + cmd += " -P " + self.port + if self.options: + cmd += " " + self.options + if self.jumphost: + cmd += " " + self.jumphost + user_host = f"{self.user}@{self.host}" if self.user else self.host + cmd += f" {user_host}" + return cmd + + @MethodHook + def _generate_telnet_cmd(self): + cmd = f"telnet {self.host}" + if self.port: + cmd += f" {self.port}" + if self.options: + cmd += f" {self.options}" + return cmd + + @MethodHook + def _generate_kube_cmd(self): + cmd = f"kubectl exec {self.options} {self.host} -it --" + kube_command = self.tags.get("kube_command", "/bin/bash") if isinstance(self.tags, dict) else "/bin/bash" + cmd += f" {kube_command}" + return cmd + + @MethodHook + def _generate_docker_cmd(self): + cmd = f"docker {self.options} exec -it {self.host}" + docker_command = self.tags.get("docker_command", "/bin/bash") if isinstance(self.tags, dict) else "/bin/bash" + cmd += f" {docker_command}" + return cmd + + @MethodHook + def _get_cmd(self): if self.protocol in ["ssh", "sftp"]: - cmd = self.protocol - if self.idletime > 0: - cmd = cmd + " -o ServerAliveInterval=" + str(self.idletime) - if self.port != '': - if self.protocol == "ssh": - cmd = cmd + " -p " + self.port - elif self.protocol == "sftp": - cmd = cmd + " -P " + self.port - if self.options != '': - cmd = cmd + " " + self.options - if self.logs != '': - self.logfile = self._logfile() - if self.jumphost != '': - cmd = cmd + " " + self.jumphost - if self.password[0] != '': - passwords = self._passtx(self.password) - else: - passwords = [] - if self.user == '': - cmd = cmd + " {}".format(self.host) - else: - cmd = cmd + " {}".format("@".join([self.user,self.host])) - expects = ['yes/no', 'refused', 'supported', 'Invalid|[u|U]sage: (ssh|sftp)', 'ssh-keygen.*\"', 'timeout|timed.out', 'unavailable', 'closed', '[p|P]assword:|[u|U]sername:', r'>$|#$|\$$|>.$|#.$|\$.$', 'suspend', pexpect.EOF, pexpect.TIMEOUT, "No route to host", "resolve hostname", "no matching", "[b|B]ad (owner|permissions)"] + return self._generate_ssh_sftp_cmd() elif self.protocol == "telnet": - cmd = "telnet " + self.host - if self.port != '': - cmd = cmd + " " + self.port - if self.options != '': - cmd = cmd + " " + self.options - if self.logs != '': - self.logfile = self._logfile() - if self.password[0] != '': - passwords = self._passtx(self.password) - else: - passwords = [] - expects = ['[u|U]sername:', 'refused', 'supported', 'invalid option', 'ssh-keygen.*\"', 'timeout|timed.out', 'unavailable', 'closed', '[p|P]assword:', r'>$|#$|\$$|>.$|#.$|\$.$', 'suspend', pexpect.EOF, pexpect.TIMEOUT, "No route to host", "resolve hostname", "no matching", "[b|B]ad (owner|permissions)"] + return self._generate_telnet_cmd() + elif self.protocol == "kubectl": + return self._generate_kube_cmd() + elif self.protocol == "docker": + return self._generate_docker_cmd() else: - raise ValueError("Invalid protocol: " + self.protocol) + raise ValueError(f"Invalid protocol: {self.protocol}") + + @MethodHook + def _connect(self, debug=False, timeout=10, max_attempts=3): + cmd = self._get_cmd() + passwords = self._passtx(self.password) if self.password[0] else [] + if self.logs != '': + self.logfile = self._logfile() + default_prompt = r'>$|#$|\$$|>.$|#.$|\$.$' + prompt = self.tags.get("prompt", default_prompt) if isinstance(self.tags, dict) else default_prompt + password_prompt = '[p|P]assword:|[u|U]sername:' if self.protocol != 'telnet' else '[p|P]assword:' + + expects = { + "ssh": ['yes/no', 'refused', 'supported', 'Invalid|[u|U]sage: ssh', 'ssh-keygen.*\"', 'timeout|timed.out', 'unavailable', 'closed', password_prompt, prompt, 'suspend', pexpect.EOF, pexpect.TIMEOUT, "No route to host", "resolve hostname", "no matching", "[b|B]ad (owner|permissions)"], + "sftp": ['yes/no', 'refused', 'supported', 'Invalid|[u|U]sage: sftp', 'ssh-keygen.*\"', 'timeout|timed.out', 'unavailable', 'closed', password_prompt, prompt, 'suspend', pexpect.EOF, pexpect.TIMEOUT, "No route to host", "resolve hostname", "no matching", "[b|B]ad (owner|permissions)"], + "telnet": ['[u|U]sername:', 'refused', 'supported', 'invalid|unrecognized option', 'ssh-keygen.*\"', 'timeout|timed.out', 'unavailable', 'closed', password_prompt, prompt, 'suspend', pexpect.EOF, pexpect.TIMEOUT, "No route to host", "resolve hostname", "no matching", "[b|B]ad (owner|permissions)"], + "kubectl": ['[u|U]sername:', '[r|R]efused', '[E|e]rror', 'DEPRECATED', pexpect.TIMEOUT, password_prompt, prompt, pexpect.EOF, "expired|invalid"], + "docker": ['[u|U]sername:', 'Cannot', '[E|e]rror', 'failed', 'not a docker command', 'unknown', 'unable to resolve', pexpect.TIMEOUT, password_prompt, prompt, pexpect.EOF] + } + + error_indices = { + "ssh": [1, 2, 3, 4, 5, 6, 7, 12, 13, 14, 15, 16], + "sftp": [1, 2, 3, 4, 5, 6, 7, 12, 13, 14, 15, 16], + "telnet": [1, 2, 3, 4, 5, 6, 7, 12, 13, 14, 15, 16], + "kubectl": [1, 2, 3, 4, 8], # Define error indices for kube + "docker": [1, 2, 3, 4, 5, 6, 7] # Define error indices for docker + } + + eof_indices = { + "ssh": [8, 9, 10, 11], + "sftp": [8, 9, 10, 11], + "telnet": [8, 9, 10, 11], + "kubectl": [5, 6, 7], # Define eof indices for kube + "docker": [8, 9, 10] # Define eof indices for docker + } + + initial_indices = { + "ssh": [0], + "sftp": [0], + "telnet": [0], + "kubectl": [0], # Define special indices for kube + "docker": [0] # Define special indices for docker + } + attempts = 1 while attempts <= max_attempts: child = pexpect.spawn(cmd) @@ -3014,54 +3116,55 @@ class node: print(cmd) self.mylog = io.BytesIO() child.logfile_read = self.mylog - if len(passwords) > 0: - loops = len(passwords) - else: - loops = 1 + endloop = False - for i in range(0, loops): + for i in range(len(passwords) if passwords else 1): while True: - results = child.expect(expects, timeout=timeout) - if results == 0: + results = child.expect(expects[self.protocol], timeout=timeout) + results_value = expects[self.protocol][results] + + if results in initial_indices[self.protocol]: if self.protocol in ["ssh", "sftp"]: child.sendline('yes') - elif self.protocol == "telnet": - if self.user != '': + elif self.protocol in ["telnet", "kubectl"]: + if self.user: child.sendline(self.user) else: self.missingtext = True break - if results in [1, 2, 3, 4, 5, 6, 7, 12, 13, 14, 15, 16]: + + elif results in error_indices[self.protocol]: child.terminate() - if results == 12 and attempts != max_attempts: + if results_value == pexpect.TIMEOUT and attempts != max_attempts: attempts += 1 endloop = True break else: - if results == 12: - after = "Connection timeout" + after = "Connection timeout" if results_value == pexpect.TIMEOUT else child.after.decode() + return f"Connection failed code: {results}\n{child.before.decode().lstrip()}{after}{child.readline().decode()}".rstrip() + + elif results in eof_indices[self.protocol]: + if results_value == password_prompt: + if passwords: + child.sendline(passwords[i]) else: - after = child.after.decode() - return ("Connection failed code:" + str(results) + "\n" + child.before.decode().lstrip() + after + child.readline().decode()).rstrip() - if results == 8: - if len(passwords) > 0: - child.sendline(passwords[i]) + self.missingtext = True + break + elif results_value == "suspend": + child.sendline("\r") + sleep(2) else: - self.missingtext = True - break - if results in [9, 11]: - endloop = True - child.sendline() - break - if results == 10: - child.sendline("\r") - sleep(2) + endloop = True + child.sendline() + break + if endloop: break - if results == 12: + if results_value == pexpect.TIMEOUT: continue else: break + child.readline(0) self.child = child return True
@@ -3208,6 +3311,14 @@ def run(self, commands, vars = None,*, folder = '', prompt = r'>$ connect = self._connect(timeout = timeout) now = datetime.datetime.now().strftime('%Y-%m-%d_%H%M%S') if connect == True: + # Attempt to set the terminal size + try: + self.child.setwinsize(65535, 65535) + except Exception: + try: + self.child.setwinsize(10000, 10000) + except Exception: + pass if "prompt" in self.tags: prompt = self.tags["prompt"] expects = [prompt, pexpect.EOF, pexpect.TIMEOUT] @@ -3336,6 +3447,14 @@ def test(self, commands, expected, vars = None,*, prompt = r'>$|#$|\$$|&g ''' connect = self._connect(timeout = timeout) if connect == True: + # Attempt to set the terminal size + try: + self.child.setwinsize(65535, 65535) + except Exception: + try: + self.child.setwinsize(10000, 10000) + except Exception: + pass if "prompt" in self.tags: prompt = self.tags["prompt"] expects = [prompt, pexpect.EOF, pexpect.TIMEOUT] diff --git a/requirements.txt b/requirements.txt index 2bd3233..abaa405 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,10 +1,11 @@ Flask>=2.3.2 +Flask_Cors>=4.0.1 google_api_python_client>=2.125.0 google_auth_oauthlib>=1.2.0 -inquirer>=3.2.4 +inquirer>=3.3.0 openai>=0.27.8 pexpect>=4.8.0 -protobuf>=5.26.1 +protobuf>=5.27.2 pycryptodome>=3.18.0 pyfzf>=0.3.1 PyYAML>=6.0.1 diff --git a/setup.cfg b/setup.cfg index 95c98a1..28a9aef 100644 --- a/setup.cfg +++ b/setup.cfg @@ -29,6 +29,7 @@ install_requires = pexpect pycryptodome Flask + Flask_Cors pyfzf waitress PyYAML