main app done
This commit is contained in:
parent
43e8325890
commit
1c6bdddbdc
@ -4,6 +4,7 @@ import yaml
|
||||
import os
|
||||
import re
|
||||
from Crypto.PublicKey import RSA
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
#functions and classes
|
||||
@ -15,8 +16,8 @@ class configfile:
|
||||
self.defaultdir = home + '/.config/conn'
|
||||
self.defaultfile = self.defaultdir + '/config.yaml'
|
||||
self.defaultkey = self.defaultdir + '/.osk'
|
||||
Path(self.defaultdir).mkdir(parents=True, exist_ok=True)
|
||||
if conf == None:
|
||||
self.dir = self.defaultdir
|
||||
self.file = self.defaultfile
|
||||
else:
|
||||
self.file = conf
|
||||
@ -42,11 +43,12 @@ class configfile:
|
||||
return yaml.load(ymlconf.read(), Loader=yaml.CLoader)
|
||||
|
||||
def createconfig(self, conf):
|
||||
defaultconfig = {'config': {'case': False, 'frun': False, 'idletime': 30}, 'connections': {}, 'profiles': { "default": { "host":"", "protocol":"ssh", "port":"", "user":"", "password":"", "options":"", "logs":"" }}}
|
||||
defaultconfig = {'config': {'case': False, 'idletime': 30}, 'connections': {}, 'profiles': { "default": { "host":"", "protocol":"ssh", "port":"", "user":"", "password":"", "options":"", "logs":"" }}}
|
||||
if not os.path.exists(conf):
|
||||
with open(conf, "w") as f:
|
||||
yaml.dump(defaultconfig, f, explicit_start=True, Dumper=yaml.CDumper)
|
||||
f.close()
|
||||
os.chmod(conf, 0o600)
|
||||
ymlconf = open(conf)
|
||||
return yaml.load(ymlconf.read(), Loader=yaml.CLoader)
|
||||
|
||||
@ -64,6 +66,7 @@ class configfile:
|
||||
with open(keyfile,'wb') as f:
|
||||
f.write(key.export_key('PEM'))
|
||||
f.close()
|
||||
os.chmod(keyfile, 0o600)
|
||||
|
||||
def _explode_unique(self, unique):
|
||||
uniques = unique.split("@")
|
||||
@ -84,6 +87,23 @@ class configfile:
|
||||
return False
|
||||
return result
|
||||
|
||||
def getitem(self, unique):
|
||||
uniques = self._explode_unique(unique)
|
||||
if unique.startswith("@"):
|
||||
if uniques.keys() >= {"folder", "subfolder"}:
|
||||
folder = self.connections[uniques["folder"]][uniques["subfolder"]]
|
||||
else:
|
||||
folder = self.connections[uniques["folder"]]
|
||||
return folder
|
||||
else:
|
||||
if uniques.keys() >= {"folder", "subfolder"}:
|
||||
node = self.connections[uniques["folder"]][uniques["subfolder"]][uniques["id"]]
|
||||
elif "folder" in uniques.keys():
|
||||
node = self.connections[uniques["folder"]][uniques["id"]]
|
||||
else:
|
||||
node = self.connections[uniques["id"]]
|
||||
return node
|
||||
|
||||
def _connections_add(self,*, id, host, folder='', subfolder='', options='', logs='', password='', port='', protocol='', user='', type = "connection" ):
|
||||
if folder == '':
|
||||
self.connections[id] = {"host": host, "options": options, "logs": logs, "password": password, "port": port, "protocol": protocol, "user": user, "type": type}
|
||||
|
233
conn/connapp.py
233
conn/connapp.py
@ -20,6 +20,7 @@ class connapp:
|
||||
self.nodes = self._getallnodes()
|
||||
self.folders = self._getallfolders()
|
||||
self.profiles = list(self.config.profiles.keys())
|
||||
self.case = self.config.config["case"]
|
||||
#DEFAULTPARSER
|
||||
defaultparser = argparse.ArgumentParser(prog = "conn", description = "SSH and Telnet connection manager", formatter_class=argparse.RawTextHelpFormatter)
|
||||
subparsers = defaultparser.add_subparsers(title="Commands")
|
||||
@ -27,19 +28,20 @@ class connapp:
|
||||
nodeparser = subparsers.add_parser("node", help=self._help("node"),formatter_class=argparse.RawTextHelpFormatter)
|
||||
nodecrud = nodeparser.add_mutually_exclusive_group()
|
||||
nodeparser.add_argument("node", metavar="node|folder", nargs='?', default=None, action=self.store_type, type=self._type_node, help=self._help("node"))
|
||||
nodecrud.add_argument("--add", dest="action", action="store_const", help="Add new node[@subfolder][@folder]", const="add", default="connect")
|
||||
nodecrud.add_argument("--del", "--rm", dest="action", action="store_const", help="Delete node[@subfolder][@folder]", const="del", default="connect")
|
||||
nodecrud.add_argument("--add", dest="action", action="store_const", help="Add new node[@subfolder][@folder] or [@subfolder]@folder", const="add", default="connect")
|
||||
nodecrud.add_argument("--del", "--rm", dest="action", action="store_const", help="Delete node[@subfolder][@folder] or [@subfolder]@folder", const="del", default="connect")
|
||||
nodecrud.add_argument("--mod", "--edit", dest="action", action="store_const", help="Modify node[@subfolder][@folder]", const="mod", default="connect")
|
||||
nodecrud.add_argument("--show", dest="action", action="store_const", help="Show node[@subfolder][@folder]", const="show", default="connect")
|
||||
nodecrud.add_argument("--debug", "-d", dest="action", action="store_const", help="Display all conections steps", const="debug", default="connect")
|
||||
nodeparser.set_defaults(func=self._func_node)
|
||||
#PROFILEPARSER
|
||||
profileparser = subparsers.add_parser("profile", help="Manage profiles")
|
||||
profileparser.add_argument("profile", nargs=1, action=self.store_type, type=self._type_profile, help="Name of profile to manage")
|
||||
profilecrud = profileparser.add_mutually_exclusive_group(required=True)
|
||||
profilecrud.add_argument("--add", dest="action", action="store_const", help="Add new profile", const="add", default="connect")
|
||||
profilecrud.add_argument("--del", "--rm", dest="action", action="store_const", help="Delete profile", const="del", default="connect")
|
||||
profilecrud.add_argument("--mod", "--edit", dest="action", action="store_const", help="Modify profile", const="mod", default="connect")
|
||||
profilecrud.add_argument("--show", dest="action", action="store_const", help="Show profile", const="show", default="connect")
|
||||
profilecrud.add_argument("--add", dest="action", action="store_const", help="Add new profile", const="add")
|
||||
profilecrud.add_argument("--del", "--rm", dest="action", action="store_const", help="Delete profile", const="del")
|
||||
profilecrud.add_argument("--mod", "--edit", dest="action", action="store_const", help="Modify profile", const="mod")
|
||||
profilecrud.add_argument("--show", dest="action", action="store_const", help="Show profile", const="show")
|
||||
profileparser.set_defaults(func=self._func_profile)
|
||||
#MOVEPARSER
|
||||
moveparser = subparsers.add_parser("move", aliases=["mv"], help="Move node")
|
||||
@ -57,8 +59,13 @@ class connapp:
|
||||
bulkparser = subparsers.add_parser("bulk", help="Add nodes in bulk")
|
||||
bulkparser.add_argument("bulk", const="bulk", nargs=0, action=self.store_type, help="Add nodes in bulk")
|
||||
bulkparser.set_defaults(func=self._func_others)
|
||||
#CONFIGPARSER
|
||||
configparser = subparsers.add_parser("config", help="Manage app config")
|
||||
configparser.add_argument("--allow-uppercase", dest="case", nargs=1, action=self.store_type, help="Allow case sensitive names", choices=["true","false"])
|
||||
configparser.add_argument("--keepalive", dest="idletime", nargs=1, action=self.store_type, help="Set keepalive time in seconds, 0 to disable", type=int, metavar="INT")
|
||||
configparser.set_defaults(func=self._func_others)
|
||||
#Set default subparser and tune arguments
|
||||
commands = ["node", "-h", "--help", "profile", "mv", "move","copy", "cp", "bulk", "ls", "list"]
|
||||
commands = ["node", "-h", "--help", "profile", "mv", "move","copy", "cp", "bulk", "ls", "list", "config"]
|
||||
profilecmds = ["--add", "--del", "--rm", "--mod", "--edit", "--show"]
|
||||
if len(sys.argv) >= 3 and sys.argv[2] == "profile" and sys.argv[1] in profilecmds:
|
||||
sys.argv[2] = sys.argv[1]
|
||||
@ -68,8 +75,16 @@ class connapp:
|
||||
args = defaultparser.parse_args()
|
||||
args.func(args)
|
||||
|
||||
class store_type(argparse.Action):
|
||||
def __call__(self, parser, args, values, option_string=None):
|
||||
setattr(args, "data", values)
|
||||
delattr(args,self.dest)
|
||||
setattr(args, "command", self.dest)
|
||||
|
||||
def _func_node(self, args):
|
||||
if args.action == "connect":
|
||||
if not self.case and args.data != None:
|
||||
args.data = args.data.lower()
|
||||
if args.action == "connect" or args.action == "debug":
|
||||
if args.data == None:
|
||||
matches = self.nodes
|
||||
else:
|
||||
@ -78,26 +93,29 @@ class connapp:
|
||||
else:
|
||||
matches = list(filter(lambda k: k.startswith(args.data), self.nodes))
|
||||
if len(matches) == 0:
|
||||
print("ERROR NO MACHEA NI FOLDER NI NODE")
|
||||
return
|
||||
print("{} not found".format(args.data))
|
||||
exit(1)
|
||||
elif len(matches) > 1:
|
||||
matches[0] = self._choose(matches,"node", "connect")
|
||||
if matches[0] == None:
|
||||
return
|
||||
node = self._get_item(matches[0])
|
||||
exit(6)
|
||||
node = self.config.getitem(matches[0])
|
||||
node = self.node(matches[0],**node, config = self.config)
|
||||
node.interact()
|
||||
if args.action == "debug":
|
||||
node.interact(debug = True)
|
||||
else:
|
||||
node.interact()
|
||||
elif args.action == "del":
|
||||
if args.data == None:
|
||||
print("MISSING ARGUMENT NODE")
|
||||
return
|
||||
print("Missing argument node")
|
||||
exit(2)
|
||||
elif args.data.startswith("@"):
|
||||
matches = list(filter(lambda k: k == args.data, self.folders))
|
||||
else:
|
||||
matches = list(filter(lambda k: k == args.data, self.nodes))
|
||||
if len(matches) == 0:
|
||||
print("ERROR NO MACHEO NI FOLDER NI NODE")
|
||||
return
|
||||
print("{} not found".format(args.data))
|
||||
exit(1)
|
||||
question = [inquirer.Confirm("delete", message="Are you sure you want to delete {}?".format(matches[0]))]
|
||||
confirm = inquirer.prompt(question)
|
||||
if confirm["delete"]:
|
||||
@ -110,28 +128,33 @@ class connapp:
|
||||
print("{} deleted succesfully".format(matches[0]))
|
||||
elif args.action == "add":
|
||||
if args.data == None:
|
||||
print("MISSING ARGUMENT NODE")
|
||||
return
|
||||
print("Missing argument node")
|
||||
exit(2)
|
||||
elif args.data.startswith("@"):
|
||||
type = "folder"
|
||||
matches = list(filter(lambda k: k == args.data, self.folders))
|
||||
reversematches = list(filter(lambda k: "@" + k == args.data, self.nodes))
|
||||
else:
|
||||
type = "node"
|
||||
matches = list(filter(lambda k: k == args.data, self.nodes))
|
||||
reversematches = list(filter(lambda k: k == "@" + args.data, self.folders))
|
||||
if len(matches) > 0:
|
||||
print(matches[0] + " ALLREADY EXIST")
|
||||
return
|
||||
print("{} already exist".format(matches[0]))
|
||||
exit(3)
|
||||
if len(reversematches) > 0:
|
||||
print("{} already exist".format(reversematches[0]))
|
||||
exit(3)
|
||||
else:
|
||||
if type == "folder":
|
||||
uniques = self.config._explode_unique(args.data)
|
||||
if uniques == False:
|
||||
print("Invalid folder {}".format(args.data))
|
||||
return
|
||||
exit(4)
|
||||
if "subfolder" in uniques.keys():
|
||||
parent = "@" + uniques["folder"]
|
||||
if parent not in self.folders:
|
||||
print("FOLDER {} DONT EXIST".format(uniques["folder"]))
|
||||
return
|
||||
print("Folder {} not found".format(uniques["folder"]))
|
||||
exit(1)
|
||||
self.config._folder_add(**uniques)
|
||||
self.config.saveconfig(self.config.file)
|
||||
print("{} added succesfully".format(args.data))
|
||||
@ -140,48 +163,48 @@ class connapp:
|
||||
nodefolder = args.data.partition("@")
|
||||
nodefolder = "@" + nodefolder[2]
|
||||
if nodefolder not in self.folders and nodefolder != "@":
|
||||
print(nodefolder + " DONT EXIST")
|
||||
return
|
||||
print(nodefolder + " not found")
|
||||
exit(1)
|
||||
uniques = self.config._explode_unique(args.data)
|
||||
if uniques == False:
|
||||
print("Invalid node {}".format(args.data))
|
||||
return False
|
||||
exit(4)
|
||||
print("You can use the configured setting in a profile using @profilename.")
|
||||
print("You can also leave empty any value except hostname/IP.")
|
||||
print("You can pass 1 or more passwords using comma separated @profiles")
|
||||
print("You can use this variables on logging file name: ${id} ${unique} ${host} ${port} ${user} ${protocol}")
|
||||
newnode = self._questions_nodes(args.data, uniques)
|
||||
if newnode == False:
|
||||
return
|
||||
exit(6)
|
||||
self.config._connections_add(**newnode)
|
||||
self.config.saveconfig(self.config.file)
|
||||
print("{} added succesfully".format(args.data))
|
||||
elif args.action == "show":
|
||||
if args.data == None:
|
||||
print("MISSING ARGUMENT NODE")
|
||||
return
|
||||
print("Missing argument node")
|
||||
exit(2)
|
||||
matches = list(filter(lambda k: k == args.data, self.nodes))
|
||||
if len(matches) == 0:
|
||||
print("ERROR NO MACHEO NODE")
|
||||
return
|
||||
node = self._get_item(matches[0])
|
||||
print("{} not found".format(args.data))
|
||||
exit(1)
|
||||
node = self.config.getitem(matches[0])
|
||||
print(yaml.dump(node, Dumper=yaml.CDumper))
|
||||
elif args.action == "mod":
|
||||
if args.data == None:
|
||||
print("MISSING ARGUMENT NODE")
|
||||
return
|
||||
print("Missing argument node")
|
||||
exit(2)
|
||||
matches = list(filter(lambda k: k == args.data, self.nodes))
|
||||
if len(matches) == 0:
|
||||
print("ERROR NO MACHEO NODE")
|
||||
return
|
||||
node = self._get_item(matches[0])
|
||||
print("{} not found".format(args.data))
|
||||
exit(1)
|
||||
node = self.config.getitem(matches[0])
|
||||
edits = self._questions_edit()
|
||||
if edits == None:
|
||||
return
|
||||
exit(6)
|
||||
uniques = self.config._explode_unique(args.data)
|
||||
updatenode = self._questions_nodes(args.data, uniques, edit=edits)
|
||||
if not updatenode:
|
||||
return
|
||||
exit(6)
|
||||
uniques.update(node)
|
||||
if sorted(updatenode.items()) == sorted(uniques.items()):
|
||||
print("Nothing to do here")
|
||||
@ -193,14 +216,16 @@ class connapp:
|
||||
|
||||
|
||||
def _func_profile(self, args):
|
||||
if not self.case:
|
||||
args.data[0] = args.data[0].lower()
|
||||
if args.action == "del":
|
||||
matches = list(filter(lambda k: k == args.data[0], self.profiles))
|
||||
if len(matches) == 0:
|
||||
print("ERROR NO MACHEO PROFILE")
|
||||
return
|
||||
print("{} not found".format(args.data[0]))
|
||||
exit(1)
|
||||
if matches[0] == "default":
|
||||
print("CANT DELETE DEFAULT PROFILE")
|
||||
return
|
||||
print("Can't delete default profile")
|
||||
exit(5)
|
||||
question = [inquirer.Confirm("delete", message="Are you sure you want to delete {}?".format(matches[0]))]
|
||||
confirm = inquirer.prompt(question)
|
||||
if confirm["delete"]:
|
||||
@ -210,35 +235,35 @@ class connapp:
|
||||
elif args.action == "show":
|
||||
matches = list(filter(lambda k: k == args.data[0], self.profiles))
|
||||
if len(matches) == 0:
|
||||
print("ERROR NO MACHEO PROFILE")
|
||||
return
|
||||
print("{} not found".format(args.data[0]))
|
||||
exit(1)
|
||||
profile = self.config.profiles[matches[0]]
|
||||
print(yaml.dump(profile, Dumper=yaml.CDumper))
|
||||
elif args.action == "add":
|
||||
matches = list(filter(lambda k: k == args.data[0], self.profiles))
|
||||
if len(matches) > 0:
|
||||
print("Profile {} Already exist".format(matches[0]))
|
||||
return
|
||||
exit(3)
|
||||
newprofile = self._questions_profiles(args.data[0])
|
||||
if newprofile == False:
|
||||
return
|
||||
exit(6)
|
||||
self.config._profiles_add(**newprofile)
|
||||
self.config.saveconfig(self.config.file)
|
||||
print("{} added succesfully".format(args.data[0]))
|
||||
elif args.action == "mod":
|
||||
matches = list(filter(lambda k: k == args.data[0], self.profiles))
|
||||
if len(matches) == 0:
|
||||
print("ERROR NO MACHEO PROFILE")
|
||||
return
|
||||
print("{} not found".format(args.data[0]))
|
||||
exit(1)
|
||||
profile = self.config.profiles[matches[0]]
|
||||
oldprofile = {"id": matches[0]}
|
||||
oldprofile.update(profile)
|
||||
edits = self._questions_edit()
|
||||
if edits == None:
|
||||
return
|
||||
exit(6)
|
||||
updateprofile = self._questions_profiles(matches[0], edit=edits)
|
||||
if not updateprofile:
|
||||
return
|
||||
exit(6)
|
||||
if sorted(updateprofile.items()) == sorted(oldprofile.items()):
|
||||
print("Nothing to do here")
|
||||
return
|
||||
@ -251,25 +276,28 @@ class connapp:
|
||||
if args.command == "ls":
|
||||
print(*getattr(self, args.data), sep="\n")
|
||||
elif args.command == "move" or args.command == "cp":
|
||||
if not self.case:
|
||||
args.data[0] = args.data[0].lower()
|
||||
args.data[1] = args.data[1].lower()
|
||||
source = list(filter(lambda k: k == args.data[0], self.nodes))
|
||||
dest = list(filter(lambda k: k == args.data[1], self.nodes))
|
||||
if len(source) != 1:
|
||||
print("ERROR NO MACHEO NODE {}".format(args.data[0]))
|
||||
return
|
||||
print("{} not found".format(args.data[0]))
|
||||
exit(1)
|
||||
if len(dest) > 0:
|
||||
print("{} ALREADY EXIST".format(args.data[1]))
|
||||
return
|
||||
print("Node {} Already exist".format(args.data[1]))
|
||||
exit(3)
|
||||
nodefolder = args.data[1].partition("@")
|
||||
nodefolder = "@" + nodefolder[2]
|
||||
if nodefolder not in self.folders and nodefolder != "@":
|
||||
print(nodefolder + " DONT EXIST")
|
||||
return
|
||||
print("{} not found".format(nodefolder))
|
||||
exit(1)
|
||||
olduniques = self.config._explode_unique(args.data[0])
|
||||
newuniques = self.config._explode_unique(args.data[1])
|
||||
if newuniques == False:
|
||||
print("Invalid node {}".format(args.data[1]))
|
||||
return False
|
||||
node = self._get_item(source[0])
|
||||
exit(4)
|
||||
node = self.config.getitem(source[0])
|
||||
newnode = {**newuniques, **node}
|
||||
self.config._connections_add(**newnode)
|
||||
if args.command == "move":
|
||||
@ -280,11 +308,60 @@ class connapp:
|
||||
if args.command == "cp":
|
||||
print("{} copied succesfully to {}".format(args.data[0],args.data[1]))
|
||||
elif args.command == "bulk":
|
||||
test = self._questions_bulk()
|
||||
print(test)
|
||||
newnodes = self._questions_bulk()
|
||||
if newnodes == False:
|
||||
exit(6)
|
||||
if not self.case:
|
||||
newnodes["location"] = newnodes["location"].lower()
|
||||
newnodes["ids"] = newnodes["ids"].lower()
|
||||
ids = newnodes["ids"].split(",")
|
||||
hosts = newnodes["host"].split(",")
|
||||
count = 0
|
||||
for n in ids:
|
||||
unique = n + newnodes["location"]
|
||||
matches = list(filter(lambda k: k == unique, self.nodes))
|
||||
reversematches = list(filter(lambda k: k == "@" + unique, self.folders))
|
||||
if len(matches) > 0:
|
||||
print("Node {} already exist, ignoring it".format(unique))
|
||||
continue
|
||||
if len(reversematches) > 0:
|
||||
print("Folder with name {} already exist, ignoring it".format(unique))
|
||||
continue
|
||||
newnode = {"id": n}
|
||||
if newnodes["location"] != "":
|
||||
location = self.config._explode_unique(newnodes["location"])
|
||||
newnode.update(location)
|
||||
if len(hosts) > 1:
|
||||
index = ids.index(n)
|
||||
newnode["host"] = hosts[index]
|
||||
else:
|
||||
newnode["host"] = hosts[0]
|
||||
newnode["protocol"] = newnodes["protocol"]
|
||||
newnode["port"] = newnodes["port"]
|
||||
newnode["options"] = newnodes["options"]
|
||||
newnode["logs"] = newnodes["logs"]
|
||||
newnode["user"] = newnodes["user"]
|
||||
newnode["password"] = newnodes["password"]
|
||||
count +=1
|
||||
self.config._connections_add(**newnode)
|
||||
self.nodes = self._getallnodes()
|
||||
if count > 0:
|
||||
self.config.saveconfig(self.config.file)
|
||||
print("Succesfully added {} nodes".format(count))
|
||||
else:
|
||||
print("0 nodes added")
|
||||
else:
|
||||
print(args.command)
|
||||
print(vars(args))
|
||||
if args.command == "case":
|
||||
if args.data[0] == "true":
|
||||
args.data[0] = True
|
||||
elif args.data[0] == "false":
|
||||
args.data[0] = False
|
||||
if args.command == "idletime":
|
||||
if args.data[0] < 0:
|
||||
args.data[0] = 0
|
||||
self.config.config[args.command] = args.data[0]
|
||||
self.config.saveconfig(self.config.file)
|
||||
print("Config saved")
|
||||
|
||||
def _choose(self, list, name, action):
|
||||
questions = [inquirer.List(name, message="Pick {} to {}:".format(name,action), choices=list)]
|
||||
@ -362,7 +439,8 @@ class connapp:
|
||||
return True
|
||||
|
||||
def _bulk_folder_validation(self, answers, current):
|
||||
|
||||
if not self.case:
|
||||
current = current.lower()
|
||||
matches = list(filter(lambda k: k == current, self.folders))
|
||||
if current != "" and len(matches) == 0:
|
||||
raise inquirer.errors.ValidationError("", reason="Location {} don't exist".format(current))
|
||||
@ -394,7 +472,7 @@ class connapp:
|
||||
|
||||
def _questions_nodes(self, unique, uniques = None, edit = None):
|
||||
try:
|
||||
defaults = self._get_item(unique)
|
||||
defaults = self.config.getitem(unique)
|
||||
except:
|
||||
defaults = { "host":"", "protocol":"", "port":"", "user":"", "options":"", "logs":"" }
|
||||
node = {}
|
||||
@ -448,23 +526,6 @@ class connapp:
|
||||
result["type"] = "connection"
|
||||
return result
|
||||
|
||||
def _get_item(self, unique):
|
||||
uniques = self.config._explode_unique(unique)
|
||||
if unique.startswith("@"):
|
||||
if uniques.keys() >= {"folder", "subfolder"}:
|
||||
folder = self.config.connections[uniques["folder"]][uniques["subfolder"]]
|
||||
else:
|
||||
folder = self.config.connections[uniques["folder"]]
|
||||
return folder
|
||||
else:
|
||||
if uniques.keys() >= {"folder", "subfolder"}:
|
||||
node = self.config.connections[uniques["folder"]][uniques["subfolder"]][uniques["id"]]
|
||||
elif "folder" in uniques.keys():
|
||||
node = self.config.connections[uniques["folder"]][uniques["id"]]
|
||||
else:
|
||||
node = self.config.connections[uniques["id"]]
|
||||
return node
|
||||
|
||||
def _questions_profiles(self, unique, edit = None):
|
||||
try:
|
||||
defaults = self.config.profiles[unique]
|
||||
@ -550,12 +611,6 @@ class connapp:
|
||||
raise argparse.ArgumentTypeError
|
||||
return arg_value
|
||||
|
||||
class store_type(argparse.Action):
|
||||
def __call__(self, parser, args, values, option_string=None):
|
||||
setattr(args, "data", values)
|
||||
delattr(args,self.dest)
|
||||
setattr(args, "command", self.dest)
|
||||
|
||||
def _help(self, type):
|
||||
if type == "node":
|
||||
return "node[@subfolder][@folder]\nConnect to specific node or show all matching nodes\n[@subfolder][@folder]\nShow all available connections globaly or in specified path"
|
||||
|
30
conn/core.py
30
conn/core.py
@ -45,11 +45,10 @@ class node:
|
||||
self.password = [password]
|
||||
|
||||
def __passtx(self, passwords, *, keyfile=None):
|
||||
keyfile = self.key
|
||||
dpass = []
|
||||
if keyfile is None:
|
||||
keyfile = self.key
|
||||
else:
|
||||
if keyfile is not None:
|
||||
key = RSA.import_key(open(keyfile).read())
|
||||
decryptor = PKCS1_OAEP.new(key)
|
||||
for passwd in passwords:
|
||||
@ -60,8 +59,7 @@ class node:
|
||||
decrypted = decryptor.decrypt(ast.literal_eval(str(passwd))).decode("utf-8")
|
||||
dpass.append(decrypted)
|
||||
except:
|
||||
print("Missing or wrong key")
|
||||
exit(1)
|
||||
raise ValueError("Missing or corrupted key")
|
||||
return dpass
|
||||
|
||||
|
||||
@ -108,15 +106,18 @@ class node:
|
||||
connect = self._connect(debug = debug)
|
||||
if connect == True:
|
||||
print("Connected to " + self.unique + " at " + self.host + (":" if self.port != '' else '') + self.port + " via: " + self.protocol)
|
||||
if debug:
|
||||
self.child.logfile_read = None
|
||||
elif 'logfile' in dir(self):
|
||||
if 'logfile' in dir(self):
|
||||
self.child.logfile_read = open(self.logfile, "wb")
|
||||
elif debug:
|
||||
self.child.logfile_read = None
|
||||
if 'missingtext' in dir(self):
|
||||
print(self.child.after.decode(), end='')
|
||||
self.child.interact()
|
||||
if "logfile" in dir(self) and not debug:
|
||||
self._logclean(self.logfile)
|
||||
else:
|
||||
print(connect)
|
||||
exit(7)
|
||||
|
||||
def run(self, commands,*, folder = '', prompt = '>$|#$|\$.$', stdout = False):
|
||||
connect = self._connect()
|
||||
@ -135,10 +136,9 @@ class node:
|
||||
output = output + self.child.before.decode() + self.child.after.decode()
|
||||
self.child.expect(prompt)
|
||||
output = output + self.child.before.decode() + self.child.after.decode()
|
||||
if folder == '':
|
||||
if stdout == True:
|
||||
print(output)
|
||||
else:
|
||||
if stdout == True:
|
||||
print(output)
|
||||
if folder != '':
|
||||
with open(folder + "/" + self.unique, "w") as f:
|
||||
f.write(output)
|
||||
f.close()
|
||||
@ -146,8 +146,6 @@ class node:
|
||||
self.output = output
|
||||
return output
|
||||
|
||||
|
||||
|
||||
def _connect(self, debug = False):
|
||||
if self.protocol == "ssh":
|
||||
cmd = "ssh"
|
||||
@ -182,8 +180,7 @@ class node:
|
||||
passwords = []
|
||||
expects = ['[u|U]sername:', 'refused', 'supported', 'cipher', 'sage', 'timeout', 'unavailable', 'closed', '[p|P]assword:', '>$|#$|\$.$', 'suspend', pexpect.EOF, "No route to host"]
|
||||
else:
|
||||
print("Invalid protocol: " + self.protocol)
|
||||
return
|
||||
raise ValueError("Invalid protocol: " + self.protocol)
|
||||
child = pexpect.spawn(cmd)
|
||||
if debug:
|
||||
child.logfile_read = sys.stdout.buffer
|
||||
@ -206,9 +203,8 @@ class node:
|
||||
self.missingtext = True
|
||||
break
|
||||
case 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12:
|
||||
print("Connection failed code:" + str(results))
|
||||
child.close()
|
||||
return
|
||||
return "Connection failed code:" + str(results)
|
||||
case 8:
|
||||
if len(passwords) > 0:
|
||||
child.sendline(passwords[i])
|
||||
|
@ -1,21 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
#Imports
|
||||
import os
|
||||
from Crypto.PublicKey import RSA
|
||||
from Crypto.Cipher import PKCS1_OAEP
|
||||
import ast
|
||||
|
||||
#functions and classes
|
||||
|
||||
def encrypt(password, keyfile=None):
|
||||
if keyfile is None:
|
||||
home = os.path.expanduser("~")
|
||||
keyfile = home + '/.config/conn/.osk'
|
||||
key = RSA.import_key(open(keyfile).read())
|
||||
publickey = key.publickey()
|
||||
encryptor = PKCS1_OAEP.new(publickey)
|
||||
password = encryptor.encrypt(password.encode("utf-8"))
|
||||
return password
|
||||
|
||||
|
||||
|
13
test.py
13
test.py
@ -19,15 +19,15 @@ conf = conn.configfile("test.yaml")
|
||||
# conf.saveconfig("test.yaml")
|
||||
# ***
|
||||
# test = conn.node("test", "10.21.96.45")
|
||||
# xr=conn.node("xr@home", **conf.connections["home"]["xr"], config=conf)
|
||||
# xr=conn.node("xr@home", **conf.getitem("xr@home"), config=conf)
|
||||
# ios=conn.node("ios@home", **conf.connections["home"]["ios"], config=conf)
|
||||
# norman = conn.node("norman@home", **conf.connections["home"]["norman"], config=conf)
|
||||
# eve = conn.node("eve@home", **conf.connections["home"]["eve"], config=conf)
|
||||
# router228 = conn.node("router228@bbva", **conf.connections["bbva"]["router228"], config=conf)
|
||||
# router228.interact()
|
||||
# router228.run(["term len 0","show ip int br"])
|
||||
# xroutput = xr.run(["show ip bgp", "show ip bgp summ"], folder="test")
|
||||
# ios.run("show run")
|
||||
# xroutput = xr.run("show run")
|
||||
# ios.run("show run", folder=".",stdout=True)
|
||||
# norman.run(["ls -la", "pwd"])
|
||||
# test = eve.run(["ls -la", "pwd"])
|
||||
# print(norman.output)
|
||||
@ -36,3 +36,10 @@ conf = conn.configfile("test.yaml")
|
||||
# test.interact()
|
||||
# ***
|
||||
conn.connapp(conf, conn.node)
|
||||
# ***
|
||||
# list = ["xr@home","ios@home","router228@bbva","router142@bbva"]
|
||||
# for i in list:
|
||||
# data = conf.getitem(i)
|
||||
# routeri = conn.node(i,**data,config=conf)
|
||||
# routeri.run(["term len 0","show run"], folder="test")
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user