def send_server_information(ip, port, spread=True): # Validates the ip or domain (syntax only) if validators.domain(ip) is not True: if validators.ip_address.ipv4(ip) is not True: if validators.ip_address.ipv6(ip) is not True: print( f"Failed to validate ip or domain: {ip}. Check for typing mistakes." ) return False # Validates port number if validators.between(port, min=1, max=65535) is not True: print(f"Invalid port number: {port} is not between 1 and 65535") return False if not registry.exists(settings.ADDRESS_ID_REGISTRY): print( f"Address ID was not found in the registry! (Location: {settings.ADDRESS_ID_REGISTRY})" ) return False if not registry.exists(settings.RSA_PRIVATE_REGISTRY): print( f"RSA Private Key was not found in the registry! (Location: {settings.RSA_PRIVATE_REGISTRY})" ) return False address_id = registry.get_value(settings.ADDRESS_ID_REGISTRY) # Creates server message server_update_dict = dict( type=MessageType.SERVER_UPDATE, signature=0, address_id=address_id + 1, # Increases the address id, to indicate the information is new and up to date. address_size=len(ip), address=ip.encode("ascii"), port=port, spread=spread) # Calculate signature of message try: server_update_message = messages.SERVER_UPDATE_MESSAGE.build( server_update_dict) # Update signature server_update_dict["signature"] = messages.sign_message( server_update_message) server_update_message = messages.SERVER_UPDATE_MESSAGE.build( server_update_dict) except construct.ConstructError as e: # Should never occur print(f"Failed to build server update message: {e.args}") return False # Sends server information update (should also update local server information) updater.send_broadcast(server_update_message) print("Server information was sent to services!") return True
def generate_rsa_keys(display_keys=True): key_pair = RSA.generate(bits=settings.RSA_KEY_SIZE) # Adds the keys to settings file rsa_settings = dict( RSA_MODULO=hex(key_pair.n), PUBLIC_KEY=hex(key_pair.e), ) if not add_to_settings(rsa_settings): print(f"Failed to add rsa key to {DEFAULT_SETTINGS_PATH}") return False # Adds the keys to registry if not registry.exists(settings.REGISTRY_PATH): registry.create_key(settings.REGISTRY_PATH) registry.set_value(settings.RSA_MODULO_REGISTRY, hex(key_pair.n)) registry.set_value(settings.RSA_PUBLIC_REGISTRY, hex(key_pair.e)) registry.set_value(settings.RSA_PRIVATE_REGISTRY, hex(key_pair.d)) # Displays the keys to the user print("RSA keys were generated!") print("") if display_keys: show_rsa_keys() return True
def show_server_information(): address_id = "Not available" if registry.exists(settings.ADDRESS_ID_REGISTRY): address_id = registry.get_value(settings.ADDRESS_ID_REGISTRY) ip = "Not available" if registry.exists(settings.UPDATING_SERVER_REGISTRY): ip = registry.get_value(settings.UPDATING_SERVER_REGISTRY) port = "Not available" if registry.exists(settings.PORT_REGISTRY): port = registry.get_value(settings.PORT_REGISTRY) print(f"Address ID: \t{address_id}") print(f"Domain (IP): \t{ip}") print(f"Port: \t\t{port}") return True
def show_rsa_keys(): print("RSA Modulo (n):") if registry.exists(settings.RSA_MODULO_REGISTRY): print(registry.get_value(settings.RSA_MODULO_REGISTRY)) else: print("Not available.") print("") print("RSA Public Key (e):") if registry.exists(settings.RSA_PUBLIC_REGISTRY): print(registry.get_value(settings.RSA_PUBLIC_REGISTRY)) else: print("Not available.") print("") print("RSA Private Key (d):") if registry.exists(settings.RSA_PRIVATE_REGISTRY): print(registry.get_value(settings.RSA_PRIVATE_REGISTRY)) else: print("Not available.") return True
def load_settings(): global __values__ if "SETTINGS_REGISTRY" in __values__ and registry.exists( __values__["SETTINGS_REGISTRY"]): settings_path = registry.get_value(__values__["SETTINGS_REGISTRY"]) else: settings_path = __values__[ "SETTINGS_PATH"] if "SETTINGS_PATH" in __values__ else INITIAL_SETTINGS_PATH try: with open(settings_path, "r") as settings_file: data = settings_file.read() __values__.update(json.loads(data)) except FileNotFoundError: # If settings file is not found, use default settings pass
def save_settings(): global __values__ if "SETTINGS_REGISTRY" in __values__ and registry.exists( __values__["SETTINGS_REGISTRY"]): settings_path = registry.get_value(__values__["SETTINGS_REGISTRY"]) else: settings_path = __values__[ "SETTINGS_PATH"] if "SETTINGS_PATH" in __values__ else INITIAL_SETTINGS_PATH try: with open(settings_path, "w") as settings_file: data = json.dumps(__values__) settings_file.write(data) except PermissionError: logging.critical( f"Failed to write settings file due to PermissionError: {__values__['SETTINGS_PATH']}", exc_info=True)
def init_settings(save=True, load=True): global __values__ # Default settings that are needed before load __values__.setdefault( "REGISTRY_PATH", rf"Software\{__values__['SOFTWARE_NAME']}\{__values__['UPDATER_NAME']}" ) __values__.setdefault("SETTINGS_REGISTRY", rf"{__values__['REGISTRY_PATH']}\settings") if registry.exists(__values__['SETTINGS_REGISTRY']): settings_path = registry.get_value(__values__['SETTINGS_REGISTRY']) software_path = os.path.dirname(os.path.dirname(settings_path)) __values__['SOFTWARE_PATH'] = software_path # Load existing settings if load: load_settings() # Setting default settings values, if they don't appear in the settings.json file already __values__.setdefault( "SOFTWARE_PATH", rf"{PROGRAM_FILES}{os.path.sep}{__values__['SOFTWARE_NAME']}") __values__.setdefault( "UPDATER_PATH", rf"{__values__['SOFTWARE_PATH']}{os.path.sep}{__values__['UPDATER_NAME']}" ) __values__.setdefault( "PROGRAM_PATH", rf"{__values__['SOFTWARE_PATH']}{os.path.sep}{__values__['SOFTWARE_NAME']}" ) __values__.setdefault( "LAUNCHER_PATH", rf"{__values__['SOFTWARE_PATH']}{os.path.sep}{__values__['LAUNCHER_NAME']}" ) __values__.setdefault( "SETTINGS_PATH", rf"{__values__['UPDATER_PATH']}{os.path.sep}settings.json") __values__.setdefault( "LOGGER_PATH", rf"{__values__['UPDATER_PATH']}{os.path.sep}log.txt") __values__.setdefault( "UPDATE_PATH", rf"{__values__['UPDATER_PATH']}{os.path.sep}update.zip") __values__.setdefault("AUTO_INSTALLATIONS_REGISTRY", rf"{__values__['REGISTRY_PATH']}\auto_update") __values__.setdefault("UPDATING_SERVER_REGISTRY", rf"{__values__['REGISTRY_PATH']}\update_server") __values__.setdefault("PORT_REGISTRY", rf"{__values__['REGISTRY_PATH']}\port") __values__.setdefault("RSA_MODULO_REGISTRY", rf"{__values__['REGISTRY_PATH']}\rsa_modulo") __values__.setdefault("RSA_PUBLIC_REGISTRY", rf"{__values__['REGISTRY_PATH']}\rsa_public") __values__.setdefault("RSA_PRIVATE_REGISTRY", rf"{__values__['REGISTRY_PATH']}\rsa_private") __values__.setdefault("UPDATE_MAJOR_REGISTRY", rf"{__values__['REGISTRY_PATH']}\update_major") __values__.setdefault("UPDATE_MINOR_REGISTRY", rf"{__values__['REGISTRY_PATH']}\update_minor") __values__.setdefault("VERSION_MAJOR_REGISTRY", rf"{__values__['REGISTRY_PATH']}\version_major") __values__.setdefault("VERSION_MINOR_REGISTRY", rf"{__values__['REGISTRY_PATH']}\version_minor") __values__.setdefault("ADDRESS_ID_REGISTRY", rf"{__values__['REGISTRY_PATH']}\address_id") __values__.setdefault("UPDATE_REGISTRY_FORMAT", rf"{__values__['REGISTRY_PATH']}\Update_{{}}") # Saves the settings, if they should be saved if save: save_settings()
def init_registry(): if not registry.exists(settings.REGISTRY_PATH): registry.create_key(settings.REGISTRY_PATH) if not registry.exists(settings.AUTO_INSTALLATIONS_REGISTRY): registry.set_value(settings.AUTO_INSTALLATIONS_REGISTRY, settings.AUTO_INSTALLATIONS) if not registry.exists(settings.UPDATING_SERVER_REGISTRY): registry.set_value(settings.UPDATING_SERVER_REGISTRY, settings.UPDATING_SERVER) if not registry.exists(settings.PORT_REGISTRY): registry.set_value(settings.PORT_REGISTRY, settings.PORT) if not registry.exists(settings.RSA_MODULO_REGISTRY): registry.set_value(settings.RSA_MODULO_REGISTRY, settings.RSA_MODULO) if not registry.exists(settings.RSA_PUBLIC_REGISTRY): registry.set_value(settings.RSA_PUBLIC_REGISTRY, settings.PUBLIC_KEY) if not registry.exists(settings.UPDATE_MAJOR_REGISTRY): registry.set_value(settings.UPDATE_MAJOR_REGISTRY, settings.UPDATE_MAJOR) if not registry.exists(settings.UPDATE_MINOR_REGISTRY): registry.set_value(settings.UPDATE_MINOR_REGISTRY, settings.UPDATE_MINOR) if not registry.exists(settings.VERSION_MAJOR_REGISTRY): registry.set_value(settings.VERSION_MAJOR_REGISTRY, settings.VERSION_MAJOR) if not registry.exists(settings.VERSION_MINOR_REGISTRY): registry.set_value(settings.VERSION_MINOR_REGISTRY, settings.VERSION_MINOR) if not registry.exists(settings.ADDRESS_ID_REGISTRY): registry.set_value(settings.ADDRESS_ID_REGISTRY, settings.ADDRESS_ID) if not registry.exists(settings.SETTINGS_REGISTRY): registry.set_value(settings.SETTINGS_REGISTRY, settings.SETTINGS_PATH)
def send_version_update(message, requester): if len(message) != messages.REQUEST_VERSION_MESSAGE.sizeof(): # The message has an incorrect size... logging.warning(f"Incorrect message size: {len(message)}") return # Parse the message try: message = messages.REQUEST_VERSION_MESSAGE.parse(message) except construct.ConstructError: # Should never occur logging.critical( f"Failed to parse request update message: {message.hex()}", exc_info=True) return # Check if the version file exists requested_version = Version(message.major, message.minor) version_registry = requested_version.get_update_registry_path() if not registry.exists(version_registry): # Version not exists... abort logging.info( f"Version {requested_version} was requested but wasn't found in the registry" ) return # Retrieve the update filepath version_filepath = registry.get_value(version_registry) try: update_file = open(version_filepath, "rb") except OSError: logging.error(f"Unable to open version file: {version_filepath}", exc_info=True) return logging.info(f"Sending update of version {requested_version}") sender = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: # Connect to the TCP server of the receiver sender.settimeout(settings.CONNECTION_TIMEOUT) sender.connect((requester[0], message.listening_port)) # Send the update file with update_file: chunk = update_file.read(settings.VERSION_CHUNK_SIZE) while len(chunk) != 0: sender.send(chunk) chunk = update_file.read(settings.VERSION_CHUNK_SIZE) logging.info( f"Finished sending update of version {requested_version}") except socket.timeout: # Connection was timed-out, too bad... abort logging.info("Connection timed out") except socket.error: # Socket error logging.info("Socket error has occurred") finally: sender.shutdown(socket.SHUT_WR) sender.close()
def is_server(): # The updater can be run as an official updates server # An update server is distinguished from a normal client only by the # fact that it knows the private RSA key return registry.exists(settings.RSA_PRIVATE_REGISTRY)