def delete(self, alias=None): # check specific. if self.specific: if alias == None: alias = self.alias # check. response = self.check(alias) if not response["success"]: return response del CONFIG["aliases"][alias] utils.save_config_safely() return r3sponse.success(f"Successfully deleted alias {alias}.")
def check( self, # the alias to check. alias=None, # the info to check. # adds / replaces the current (except the exceptions). info={}, # the info key exceptions. exceptions=[], # the info value exceptions. value_exceptions=[], # create if not present (must also specify all required info when enabled). create=False, ): # check specific. if self.specific: if alias == None: alias = self.alias # get info. current_info, exists, edits = {}, True, 0 try: current_info = CONFIG["aliases"][alias] except KeyError: exists = False if not create: return r3sponse.error(f"Alias [{alias}] does not exist.") # check existing config. if exists: edits, current_info_keys = 0, list(current_info.keys()) for info_key, info_value in info.items(): do = False if info_key not in exceptions and info_key not in current_info_keys: do = True elif info_value not in value_exceptions and info_key in current_info_keys and info_value != current_info[ info_key]: do = True if do: current_info[info_key] = info_value edits += 1 # create non existant. elif not exists and create: username, public_ip, private_ip, public_port, private_port, private_key, public_key, passphrase, smartcard, pin, save, checks = Dictionary( info).unpack({ "username": None, "public_ip": None, "private_ip": None, "public_port": None, "private_port": None, "private_key": None, "public_key": None, "passphrase": None, "smartcard": None, "pin": None, "save": True, "checks": True, }) return self.create( alias=alias, # the users. username=username, # the ip of the server. public_ip=public_ip, private_ip=private_ip, # the port of the server. public_port=public_port, private_port=private_port, # the path to the private & public key. private_key=private_key, public_key=public_key, # the keys passphrase. passphrase=passphrase, # smart card. smartcard=smartcard, # the smart cards pincode. pin=pin, # save to configuration. save=save, # do checks. checks=checks, ) # save edits. if edits > 0: CONFIG["aliases"][alias] = current_info utils.save_config_safely() # handler. return r3sponse.success(f"Successfully checked alias {alias}.")
def sync(self, aliases=["*"], interactive=None): if interactive == None: interactive = INTERACTIVE # all aliases. if "*" in aliases or "all" in aliases: if self.specific: aliases = [self.alias] else: aliases = list(CONFIG["aliases"].keys()) _aliases_ = list(aliases) # check ssh dir. if not Files.exists(f"{syst3m.defaults.vars.home}/.ssh"): os.system( f"mkdir {syst3m.defaults.vars.home}/.ssh && chown -R {syst3m.defaults.vars.user}:{syst3m.defaults.vars.group} {syst3m.defaults.vars.home}/.ssh && chmod 700 {syst3m.defaults.vars.home}/.ssh" ) # check include. include = f"include ~/.ssht00ls/lib/aliases" if not Files.exists(f"{syst3m.defaults.vars.home}/.ssh/config"): Files.save(f"{syst3m.defaults.vars.home}/.ssh/config", include) os.system( f"chown {syst3m.defaults.vars.user}:{syst3m.defaults.vars.group} {syst3m.defaults.vars.home}/.ssh/config && chmod 770 {syst3m.defaults.vars.home}/.ssh/config" ) if include not in Files.load( f"{syst3m.defaults.vars.home}/.ssh/config"): data = Files.load(f"{syst3m.defaults.vars.home}/.ssh/config") new, included = "", False for line in data.split("\n"): if len(line) > 0 and line[0] == "#": a = 1 elif not included: new += include + "\n" included = True new += line + "\n" Files.save(f"{syst3m.defaults.vars.home}/.ssh/config", new) # iterate. aliases, c = "", 0 for alias in _aliases_: info = CONFIG["aliases"][alias] if "example.com " not in alias: # deprications. if "user" in info: user = info["user"] del info["user"] info["username"] = user CONFIG["aliases"][alias]["user"] = user utils.save_config_safely() # check existance. response = self.check(alias=alias) if not response.success: return response # proceed. checked = Dictionary(path=False, dictionary=info).check( default={ "username": None, "public_ip": None, "private_ip": None, "public_port": None, "private_port": None, "private_key": None, "public_key": None, "passphrase": None, "smartcard": None, "pin": None, }) if Dictionary(checked) != Dictionary(CONFIG["aliases"][alias]): CONFIG["aliases"][alias] = checked utils.save_config_safely() if isinstance(checked["private_key"], str): checked["private_key"] = syst3m.env.fill( checked["private_key"]) Files.chmod(checked["private_key"], permission=700) if isinstance(checked["public_key"], str): checked["public_key"] = syst3m.env.fill( checked["public_key"]) Files.chmod(checked["public_key"], permission=700) if interactive: passphrase, has_passphrase, new_passphrase = None, True, True if checked["smartcard"] == True: if checked["pin"] in [False, None, "", "none", "None"]: if checked["pin"] in [False, "", "none", "None"]: has_passphrase = False else: passphrase = getpass.getpass( f"Enter the passphrase of key {checked['private_key']}:" ) else: # check encryption activated. if not encryption.activated: return r3sponse.error( "The encryption requires to be activated.") new_passphrase = False response = encryption.encryption.decrypt( checked["pin"]) if not response.success: return response passphrase = response.decrypted.decode() else: if checked["passphrase"] in [ False, None, "", "none", "None" ]: if checked["passphrase"] in [ False, "", "none", "None" ]: has_passphrase = False else: passphrase = getpass.getpass( f"Enter the passphrase of key {checked['private_key']}:" ) else: # check encryption activated. if not encryption.activated: return r3sponse.error( "The encryption requires to be activated.") new_passphrase = False response = encryption.encryption.decrypt( checked["passphrase"]) if not response.success: return response passphrase = response.decrypted.decode() if has_passphrase: if checked["smartcard"] == True: response = agent.check( public_key=checked["public_key"], raw=True) else: response = agent.check( public_key=checked["public_key"], raw=False) if not response["success"]: if "is not added" not in response["error"]: return response elif "is not added" in response["error"]: if checked["smartcard"]: response = agent.add( private_key=checked["private_key"], smartcard=True, pin=passphrase) if not response["success"]: return response else: response = agent.add( private_key=checked["private_key"], passphrase=passphrase) if not response["success"]: return response if new_passphrase: # check encryption activated. if not encryption.activated: return r3sponse.error( "The encryption requires to be activated.") response = encryption.encryption.encrypt( passphrase) if not response.success: return response if checked["smartcard"] == True: CONFIG["aliases"][alias][ "pin"] = response.encrypted.decode() else: CONFIG["aliases"][alias][ "passphrase"] = response.encrypted.decode( ) utils.save_config_safely() response = self.create( save=False, checks=False, serialized=Dictionary(dictionary=checked).append( {"alias": alias})) if not response["success"]: return response aliases += response["str"] c += 1 # save lib. Files.save(f"{syst3m.defaults.vars.home}/.ssht00ls/lib/aliases", aliases) # handler. return r3sponse.success(f"Successfully synchronized {c} alias(es).")
def create( self, # the alias. alias=None, # the users. username=None, # the ip of the server. public_ip=None, private_ip=None, # the port of the server. public_port=None, private_port=None, # the path to the private & public key. private_key=None, public_key=None, # the keys passphrase. passphrase=None, # smart card. smartcard=None, # the smart cards pincode. pin=None, # save to configuration. save=True, # do checks. checks=True, # serialized all parameters as dict, except: [save]. serialized={}, ): # check specific. if self.specific: if alias == None: alias = self.alias if username == None: username = self.username if public_ip == None: public_ip = self.public_ip if private_ip == None: private_ip = self.private_ip if public_port == None: public_port = self.public_port if private_port == None: private_port = self.private_port if private_key == None: private_key = self.private_key if public_key == None: public_key = self.public_key if smartcard == None: smartcard = self.smartcard # serialized if serialized != {}: username, public_ip, private_ip, public_port, private_port, private_key, public_key, passphrase, smartcard, pin, alias = Dictionary( serialized).unpack({ "username": None, "public_ip": None, "private_ip": None, "public_port": None, "private_port": None, "private_key": None, "public_key": None, "passphrase": None, "smartcard": None, "pin": None, "alias": None, }) # check specific. if self.specific: if alias == None: alias = self.alias # checks. response = r3sponse.check_parameters( { "alias": alias, "username": username, "public_ip": public_ip, "private_ip": private_ip, "public_port": public_port, "private_port": private_port, "private_key": private_key, "public_key": public_key, #"smartcard:bool":smartcard, }, empty_value=None) if not response["success"]: return response if smartcard: response = r3sponse.check_parameters({ "pin": pin, }, empty_value=None) if not response["success"]: return response else: response = r3sponse.check_parameters({ "passphrase": passphrase, }, empty_value=None) if not response["success"]: return response # check encryption activated. if checks and not encryption.activated: return r3sponse.error("The encryption requires to be activated.") # duplicate. if checks: response = self.check_duplicate(alias) if not response["success"]: return response # keys. private_key = syst3m.env.fill(private_key) public_key = syst3m.env.fill(public_key) if not Files.exists(private_key): return r3sponse.error(f"Private key {private_key} does not exist.") if not Files.exists(public_key): return r3sponse.error(f"Public key {public_key} does not exist.") # info. json_config, config = {}, "" if not self.public(public_ip=public_ip, private_ip=private_ip): ip = private_ip port = private_port else: ip = public_ip port = public_port # create config. config += f"\nHost {alias}" json_config["public_ip"] = public_ip json_config["private_ip"] = private_ip config += "\n HostName {}".format(ip) json_config["public_port"] = public_port json_config["private_port"] = private_port config += "\n Port {}".format(port) json_config["username"] = username config += "\n User {}".format(username) config += "\n ForwardAgent yes" config += "\n PubKeyAuthentication yes" #config += "\n IdentitiesOnly yes" json_config["public_key"] = public_key if not smartcard: json_config["private_key"] = private_key json_config["smartcard"] = False config += "\n IdentityFile {}".format(private_key) else: json_config["private_key"] = smartcards.path json_config["smartcard"] = True config += "\n PKCS11Provider {}".format(smartcards.path) # passphrase. if save: if passphrase not in [False, "", "none", None, "None"]: if smartcard: response = encryption.encryption.encrypt(str(pin)) if not response["success"]: return response json_config["pin"] = response["encrypted"].decode() else: response = encryption.encryption.encrypt(str(passphrase)) if not response["success"]: return response json_config["passphrase"] = response["encrypted"].decode() else: json_config["passphrase"] = "" json_config["pin"] = "" # save. if save: CONFIG["aliases"][alias] = json_config utils.save_config_safely() # response. return r3sponse.success(f"Successfully created alias [{alias}].", { "json": json_config, "str": config, })
def edit( self, # the alias. alias=None, # the edits (dict). # adds / replaces the current (except the exceptions). edits={}, # the edits key exceptions. exceptions=[], # the edits value exceptions. value_exceptions=[None], # save the edits. save=True, # the log level. log_level=syst3m.defaults.options.log_level, ): def edit_dict(dictionary={}, edits={}): c = 0 for key, value in edits.items(): if isinstance(value, dict): found = True try: dictionary[key] except KeyError: found = False if found: dictionary[key], lc = edit_dict( dictionary=dictionary[key], edits=value) c += lc else: if log_level >= 0: print(f"Editing {alias} config {key}: {value}.") dictionary[key] = value c += 1 elif key not in exceptions and value not in value_exceptions: if log_level >= 0: print(f"Editing {alias} config {key}: {value}.") dictionary[key] = value c += 1 return dictionary, c # check specific. if self.specific: if alias == None: alias = self.alias # passphrase. edits = 0 if "passphrase" in list( edits.keys()) and edits["passphrase"] not in value_exceptions: # check encryption activated. if edits["passphrase"] not in [False, "", "none", "None"]: if not encryption.activated: return r3sponse.error( "The encryption requires to be activated.") response = encryption.encryption.encrypt(edits["passphrase"]) if not response["success"]: return response CONFIG["aliases"][alias]["smartcard"] = False CONFIG["aliases"][alias][ "passphrase"] = response.encrypted.decode() else: CONFIG["aliases"][alias]["smartcard"] = True CONFIG["aliases"][alias]["passphrase"] = "" edits += 1 del edits["passphrase"] # pin. if "pin" in list( edits.keys()) and edits["pin"] not in value_exceptions: # check encryption activated. if edits["pin"] not in [False, "", "none", "None"]: if not encryption.activated: return r3sponse.error( "The encryption requires to be activated.") response = encryption.encryption.encrypt(edits["pin"]) if not response["success"]: return response CONFIG["aliases"][alias]["smartcard"] = True CONFIG["aliases"][alias]["pin"] = response.encrypted.decode() else: CONFIG["aliases"][alias]["pin"] = "" del edits["pin"] # check. response = self.check(alias) if not response["success"]: return response dictionary, c = edit_dict(dictionary=CONFIG["aliases"][alias], edits=edits) if (edits > 0 or c > 0) and save: CONFIG["aliases"][alias] = dictionary utils.save_config_safely() if edits > 0 or c > 0: return r3sponse.success( f"Successfully saved {c} edits for alias {alias}.") else: return r3sponse.error(f"No edits were specified.")
def sync(self, aliases=["*"], interactive=None, log_level=None): if interactive == None: interactive = dev0s.defaults.options.interactive if log_level == None: log_level = self.log_level # all aliases. if "*" in aliases or "all" in aliases: if self.specific: aliases = [self.alias] else: aliases = self.list()["array"] _aliases_ = list(aliases) # loader. if log_level >= 0: loader = dev0s.console.Loader( f"Synchronizing {len(_aliases_)} aliases.") # check ssh dir. if not Files.exists(f"{dev0s.defaults.vars.home}/.ssh"): os.system( f"mkdir {dev0s.defaults.vars.home}/.ssh && chown -R {dev0s.defaults.vars.user}:{dev0s.defaults.vars.group} {dev0s.defaults.vars.home}/.ssh && chmod 700 {dev0s.defaults.vars.home}/.ssh" ) # check include. include = f"include ~/.ssht00ls/lib/aliases" if not Files.exists(f"{dev0s.defaults.vars.home}/.ssh/config"): Files.save(f"{dev0s.defaults.vars.home}/.ssh/config", include) os.system( f"chown {dev0s.defaults.vars.user}:{dev0s.defaults.vars.group} {dev0s.defaults.vars.home}/.ssh/config && chmod 770 {dev0s.defaults.vars.home}/.ssh/config" ) if include not in Files.load( f"{dev0s.defaults.vars.home}/.ssh/config"): data = Files.load(f"{dev0s.defaults.vars.home}/.ssh/config") new, included = "", False for line in data.split("\n"): if len(line) > 0 and line[0] == "#": a = 1 elif not included: new += include + "\n" included = True new += line + "\n" Files.save(f"{dev0s.defaults.vars.home}/.ssh/config", new) # iterate. aliases, c = "", 0 for alias in _aliases_: info = CONFIG["aliases"][alias] if "example.com " not in alias: # check existance. response = self.check(alias=alias) if not response.success: if log_level >= 0: loader.stop(success=False) return response # proceed. checked = Dictionary(path=False, dictionary=info).check( default={ "username": None, "public_ip": None, "private_ip": None, "public_port": None, "private_port": None, "private_key": None, "public_key": None, "passphrase": None, "smartcard": None, "serial_numbers": [], "pin": None, }) if checked["smartcard"] not in [True, False]: checked["smartcard"] = False if Dictionary(checked) != Dictionary(CONFIG["aliases"][alias]): CONFIG["aliases"][alias] = checked utils.save_config_safely() if isinstance(checked["private_key"], str): checked["private_key"] = dev0s.env.fill( checked["private_key"]) Files.chmod(checked["private_key"], permission=700) if isinstance(checked["public_key"], str): checked["public_key"] = dev0s.env.fill( checked["public_key"]) Files.chmod(checked["public_key"], permission=700) if interactive: passphrase, has_passphrase, new_passphrase = None, True, True # smart card. if checked["smartcard"] == True: # pin disabled. if checked["pin"] in [False, None, "", "none", "None"]: # skip when passphrase is False. if checked["pin"] in [False]: has_passphrase = False # prompt when passphrase is invalid. else: if log_level >= 0: loader.hold() passphrase = getpass.getpass( f"Enter the pin of smartcard [{gfp.clean(checked['private_key'])}]:" ) if log_level >= 0: loader.release() # prompt for pin. elif str(checked["pin"]).lower() in ["prompt"]: loader.hold() passphrase = dev0s.console.input( f"Enter the pin code for smartcard {alias}:", password=True) loader.release() # has pincode cached. else: # check encryption activated. if not ssht00ls_agent.activated: if log_level >= 0: loader.stop(success=False) return dev0s.response.error( f"The {ssht00ls_agent.id} encryption requires to be activated." ) # retrieve pass. new_passphrase = False response = ssht00ls_agent.encryption.decrypt( checked["pin"]) if not response.success: if log_level >= 0: loader.stop(success=False) return response passphrase = response.decrypted.decode() # no smart card. else: if checked["passphrase"] in [ False, None, "", "none", "None" ]: if checked["passphrase"] in [ False, "", "none", "None" ]: has_passphrase = False else: if log_level >= 0: loader.hold() passphrase = getpass.getpass( f"Enter the passphrase of key [{gfp.clean(checked['private_key'])}] (leave '' for no passphrase):" ) if log_level >= 0: loader.release() if checked["passphrase"] in [ False, "", "none", "None" ]: has_passphrase = False CONFIG["aliases"][alias]["passphrase"] = "" utils.save_config_safely() else: # check encryption activated. if not ssht00ls_agent.activated: if log_level >= 0: loader.stop(success=False) return dev0s.response.error( f"The {ssht00ls_agent.id} encryption requires to be activated." ) new_passphrase = False response = ssht00ls_agent.encryption.decrypt( checked["passphrase"]) if not response.success: if log_level >= 0: loader.stop(success=False) return response passphrase = response.decrypted.decode() # add to agent. if has_passphrase: if checked["smartcard"] == True: response = agent.check( public_key=checked["public_key"], raw=True) else: response = agent.check( public_key=checked["public_key"], raw=False) if not response["success"]: if "is not added" not in response["error"]: if log_level >= 0: loader.stop(success=False) return response elif "is not added" in response["error"]: if checked["smartcard"]: response = agent.add( private_key=checked["private_key"], smartcard=True, pin=passphrase) if not response["success"]: if log_level >= 0: loader.stop(success=False) return response else: response = agent.add( private_key=checked["private_key"], passphrase=passphrase) if not response["success"]: if log_level >= 0: loader.stop(success=False) return response if new_passphrase: # check encryption activated. if not ssht00ls_agent.activated: if log_level >= 0: loader.stop(success=False) return dev0s.response.error( f"The {ssht00ls_agent.id} encryption requires to be activated." ) response = ssht00ls_agent.encryption.encrypt( passphrase) if not response.success: if log_level >= 0: loader.stop(success=False) return response if checked["smartcard"] == True: CONFIG["aliases"][alias][ "pin"] = response.encrypted.decode() else: CONFIG["aliases"][alias][ "passphrase"] = response.encrypted.decode( ) utils.save_config_safely() response = self.create( save=False, checks=False, serialized=Dictionary(dictionary=checked).append( {"alias": alias})) if not response["success"]: if log_level >= 0: loader.stop(success=False) return response self.__edit_alias_lib__(alias, response["str"]) aliases += response["str"] c += 1 # handler. if log_level >= 0: loader.stop() return dev0s.response.success( f"Successfully synchronized {c} alias(es).")