def _init_(self, **kwargs): """ On startup, various libraries will need certs (webinterface, MQTT) for encryption. This module stores certificates in a directory so other programs can use certs as well. It's working data is stored in the database, while a backup is kept in the file system as well and is only used if the data is missing from the database. If a cert isn't avail for the requested sslname, it will receive a self-signed certificate. :return: """ # Since SSL generation can take some time on slower devices, we use a simple queue system. self.generate_csr_queue = self._Queue.new( 'library.sslcerts.generate_csr', self.generate_csr) self.hostname = gethostname() self.gateway_id = self._Configs.get('core', 'gwid', 'local', False) self.fqdn = self._Configs.get2('dns', 'fqdn', None, False) self.received_message_for_unknown = ExpiringDict(100, 600) self.self_signed_cert_file = self._Atoms.get( 'yombo.path') + "/usr/etc/certs/sslcert_selfsigned.cert.pem" self.self_signed_key_file = self._Atoms.get( 'yombo.path') + "/usr/etc/certs/sslcert_selfsigned.key.pem" self.self_signed_expires = self._Configs.get("sslcerts", "self_signed_expires", None, False) self.self_signed_created = self._Configs.get("sslcerts", "self_signed_created", None, False) if os.path.exists(self.self_signed_cert_file) is False or \ self.self_signed_expires is None or \ self.self_signed_expires < int(time() + (60*60*24*60)) or \ self.self_signed_created is None or \ not os.path.exists(self.self_signed_key_file): logger.info( "Generating a self signed cert for SSL. This can take a few moments." ) yield self._create_self_signed_cert() self.self_signed_cert = yield read_file(self.self_signed_cert_file) self.self_signed_key = yield read_file(self.self_signed_key_file) self.managed_certs = yield self._SQLDict.get( self, "managed_certs", serializer=self.sslcert_serializer, unserializer=self.sslcert_unserializer) # for name, data in self.managed_certs.items(): # print("cert name: %s" % name) # print(" cert data: %s" % data.__dict__) self.check_if_certs_need_update_loop = None
def _init_(self, **kwargs): """ On startup, various libraries will need certs (webinterface, MQTT) for encryption. This module stores certificates in a directory so other programs can use certs as well. It's working data is stored in the database, while a backup is kept in the file system as well and is only used if the data is missing from the database. If a cert isn't avail for the requested sslname, it will receive a self-signed certificate. :return: """ # Since SSL generation can take some time on slower devices, we use a simple queue system. self.generate_csr_queue = self._Queue.new( "library.sslcerts.generate_csr", self.generate_csr) self.hostname = gethostname() self.local_gateway = self._Gateways.local self.self_signed_cert_file = self._Atoms.get( "working_dir") + "/etc/certs/sslcert_selfsigned.cert.pem" self.self_signed_key_file = self._Atoms.get( "working_dir") + "/etc/certs/sslcert_selfsigned.key.pem" self.self_signed_expires_at = self._Configs.get( "sslcerts", "self_signed_expires_at", None, False) self.self_signed_created_at = self._Configs.get( "sslcerts", "self_signed_created_at", None, False) self.default_key_size = self._Configs.get("sslcerts", "default_key_size", 2048) if os.path.exists(self.self_signed_cert_file) is False or \ self.self_signed_expires_at is None or \ self.self_signed_expires_at < int(time() + (60*60*24*60)) or \ self.self_signed_created_at is None or \ not os.path.exists(self.self_signed_key_file): logger.info( "Generating a self signed cert for SSL. This can take a few moments." ) yield self._create_self_signed_cert() self.self_signed_cert = yield read_file(self.self_signed_cert_file) self.self_signed_key = yield read_file(self.self_signed_key_file) self.managed_certs = yield self._SQLDict.get( self, "managed_certs", serializer=self.sslcert_serializer, unserializer=self.sslcert_unserializer) for key, item in self.managed_certs.items(): print(f"Managed certs: {self.managed_certs}") self.check_if_certs_need_update_loop = None
def _init_(self, **kwargs): """ Get the GnuPG subsystem up and loaded. """ self.key_generation_status = None self._generating_key = False self._gpg_keys = {} self._generating_key_deferred = None self.sks_pools = [ # Send to a few to ensure we get our key seeded "ipv4.pool.sks-keyservers.net", "na.pool.sks-keyservers.net", "eu.pool.sks-keyservers.net", "oc.pool.sks-keyservers.net", "pool.sks-keyservers.net", "ha.pool.sks-keyservers.net" ] self.working_dir = settings.arguments["working_dir"] self.gpg = gnupg.GPG(gnupghome=f"{self.working_dir}/etc/gpg") self.__mypassphrase = None # will be loaded by sync_keyring_to_db() calls secret_file = f"{self.working_dir}/etc/gpg/last.pass" if os.path.exists(secret_file): phrase = yield read_file(secret_file) self.__mypassphrase = bytes_to_unicode(phrase)
def home_index(webinterface, request, session): if webinterface.operating_mode == "config": return webinterface.redirect(request, "/misc/config") elif webinterface.operating_mode == "first_run": logger.info( "Incoming request to /, but gateway needs setup. Redirecting to gateway_setup" ) return webinterface.redirect(request, "/misc/gateway_setup") if session is None or session.enabled is False or session.is_valid( ) is False or session.has_user is False: return webinterface.redirect(request, "/user/login") print(f"file_cache: {webinterface.file_cache}") if "index" not in webinterface.file_cache: webinterface.file_cache["index"] = {} try: webinterface.file_cache["index"]["data"] = yield read_file( f"{webinterface.working_dir}/frontend/index.html") webinterface.file_cache["index"]["headers"] = { "Cache-Control": f"max-age=7200", "Content-Type": "text/html" } except: return "Unable to process request." file = webinterface.file_cache["index"] if "headers" in file and len(file["headers"]) > 0: for header_name, header_content in file['headers'].items(): request.setHeader(header_name, header_content) return file["data"]
def home_service_worker(webinterface, request, session): """ Service worker file for authenticated users only. """ print("got sw.js request...") if "sw.js" not in webinterface.file_cache: print("sw.js - loading cache...") webinterface.file_cache["sw.js"] = {} try: webinterface.file_cache["sw.js"]["data"] = yield read_file( f"{webinterface.working_dir}/frontend/sw.js") webinterface.file_cache["sw.js"]["headers"] = { "Cache-Control": f"max-age=60", "Content-Type": "application/javascript" } except: return "Unable to process request." file = webinterface.file_cache["sw.js"] # print(webinterface.file_cache) # print(file) print("sw.js - setting headers") if "headers" in file and len(file["headers"]) > 0: for header_name, header_content in file['headers'].items(): request.setHeader(header_name, header_content) print("sw.js - send response.") return file["data"]
def load_passphrase(self, fingerprint=None): if fingerprint is None: fingerprint = self.myfingerprint() if fingerprint is not None: secret_file = f"{self.working_dir}/etc/gpg/{fingerprint}.pass" if os.path.exists(secret_file): phrase = yield read_file(secret_file) phrase = bytes_to_unicode(phrase) if fingerprint == self.myfingerprint(): self.__mypassphrase = phrase return phrase return None
def load_passphrase(self, keyid=None): if keyid is None: keyid = self.mykeyid() if keyid is not None: secret_file = "%s/usr/etc/gpg/%s.pass" % ( self._Atoms.get('yombo.path'), keyid) if os.path.exists(secret_file): phrase = yield read_file(secret_file) if keyid == self.mykeyid(): self.__mypassphrase = phrase return bytes_to_unicode(phrase) return None
def locale_to_dict(self, locale=None): if locale is None: locale = self.default_lang() if locale not in self.files: raise YomboWarning(f"Invalid locale for locale_to_dict: {locale}") po_file = f"{self.locale_save_folder}{locale}/LC_MESSAGES/yombo.po" data = yield read_file(po_file, convert_to_unicode=True) tuples = re.findall(r'msgid "(.+)"\nmsgstr "(.+)"', data) po_dict = {} for tuple in tuples: po_dict[tuple[0]] = tuple[1] return po_dict
def check_npm_running(self): """ Checks if the builder process is running. First, it checks if the PID file is found. It then inspects that file and checks to make sure the actual process is running. If the process is running, return True. If not, remove file the PID file and return False. :return: """ # Check if builder is already running: if path.isfile( f"{self.app_dir}/yombo/frontend/util/builder.pid") is False: return False pid = yield read_file( f"{self.app_dir}/yombo/frontend/util/builder.pid") try: kill(int(pid), 0) return True except OSError: unlink(f"{self.app_dir}/yombo/frontend/util/builder.pid") return False
def set(self, content): """ Set the content for the class. It can be bytes to represent the raw input, or it can be a string representing a file to load. :param content: :return: """ if isinstance(content, bytes): # we have a raw image: pass elif isinstance(content, str): # we should have a file path: if os.path.exists(self.yombo_ini_path) is False: raise YomboWarning( f"String types must be a path/filename to an file to load." ) image = yield read_file(content) else: raise YomboWarning("Unknown input type.") content_type = yield mime_type_from_buffer(content) self.content_type = content_type["content_type"] self.charset = content_type["charset"] self._content = content
def read_configs(self): try: content = yield read_file('%s/config.json' % self.module_path) except Exception as e: logger.info( "Couldn't read existing config.json file for homebridge.") return False config_file = bytes_to_unicode(json.loads(content)) if 'bridge' not in config_file: logger.warn( "'bridge' section missing from homebridge config.json file.") return False if 'username' in config_file['bridge']: self.username = config_file['bridge']['username'] else: logger.warn( "'username' missing within 'bridge' section from homebridge config.json file." ) return False if 'pin' in config_file['bridge']: self.pin_code = config_file['bridge']['pin'] else: logger.warn( "'pin' missing within 'bridge' section from homebridge config.json file." ) return False for idx, platform in enumerate(config_file['platforms']): if platform['platform'] == 'Yombo': config_file['platforms'][idx]['apiauth'] = self.apiauth.auth_id break self.config_file = config_file
def sync_from_filesystem(self): """ Reads meta data and items from the file system. This allows us to restore data incase the database goes south. This is important since only the gateway has the private key and cannot be recovered. :return: """ logger.info("Inspecting file system for certs, and loading them.") for label in ['current', 'next']: setattr(self, "%s_is_valid" % label, None) if os.path.exists('usr/etc/certs/%s.%s.meta' % (self.sslname, label)): logger.debug("SSL Meta found for: {label} - {sslname}", label=label, sslname=self.sslname) file_content = yield read_file('usr/etc/certs/%s.%s.meta' % (self.sslname, label)) meta = json.loads(file_content) # print("meta: %s" % meta) csr_read = False if label == 'next': logger.debug("Looking for 'next' information.") if os.path.exists('usr/etc/certs/%s.%s.csr.pem' % (self.sslname, label)): if getattr(self, "%s_csr" % label) is None: csr = yield read_file( 'usr/etc/certs/%s.%s.csr.pem' % (self.sslname, label), True, ) if sha256(str(csr).encode( 'utf-8')).hexdigest() == meta['csr']: csr_read = True else: # print("%s = %s" % ( # sha256(str(csr).encode('utf-8')).hexdigest(), meta['csr'] # ) # ) logger.warn( "Appears that the file system has bad meta signatures (csr). Purging." ) for file_to_delete in glob.glob( "usr/etc/certs/%s.%s.*" % (self.sslname, label)): logger.warn("Removing bad file: %s" % file_to_delete) os.remove(file_to_delete) continue cert_read = False if getattr(self, "%s_cert" % label) is None: if os.path.exists('usr/etc/certs/%s.%s.cert.pem' % (self.sslname, label)): # print("setting cert!!!") cert = yield read_file( 'usr/etc/certs/%s.%s.cert.pem' % (self.sslname, label), True) cert_read = True # print("testing with this cert: %s" % cert) if sha256(str(cert).encode( 'utf-8')).hexdigest() != meta['cert']: # print("%s != %s" % (sha256(str(cert).encode('utf-8')).hexdigest(), meta['cert'])) logger.warn( "Appears that the file system has bad meta signatures (cert). Purging." ) for file_to_delete in glob.glob( "usr/etc/certs/%s.%s.*" % (self.sslname, label)): logger.warn("Removing bad file: %s" % file_to_delete) os.remove(file_to_delete) continue chain_read = False if getattr(self, "%s_chain" % label) is None: if os.path.exists('usr/etc/certs/%s.%s.chain.pem' % (self.sslname, label)): # print("setting chain!!!") chain = yield read_file( 'usr/etc/certs/%s.%s.chain.pem' % (self.sslname, label), True) chain_read = True if sha256(str(chain).encode( 'utf-8')).hexdigest() != meta['chain']: logger.warn( "Appears that the file system has bad meta signatures (chain). Purging." ) for file_to_delete in glob.glob( "usr/etc/certs/%s.%s.*" % (self.sslname, label)): logger.warn("Removing bad file: %s" % file_to_delete) os.remove(file_to_delete) continue key_read = False if getattr(self, "%s_key" % label) is None: if os.path.exists('usr/etc/certs/%s.%s.key.pem' % (self.sslname, label)): key = yield read_file( 'usr/etc/certs/%s.%s.key.pem' % (self.sslname, label), True) key_read = True if sha256(str(key).encode( 'utf-8')).hexdigest() != meta['key']: logger.warn( "Appears that the file system has bad meta signatures (key). Purging." ) for file_to_delete in glob.glob( "usr/etc/certs/%s.%s.*" % (self.sslname, label)): logger.warn("Removing bad file: %s" % file_to_delete) os.remove(file_to_delete) continue logger.debug("Reading meta file for cert: {label}", label=label) def return_int(the_input): try: return int(the_input) except Exception as e: return the_input if csr_read: setattr(self, "%s_csr" % label, csr) if cert_read: setattr(self, "%s_cert" % label, cert) if chain_read: setattr(self, "%s_chain" % label, chain) if key_read: setattr(self, "%s_key" % label, key) setattr(self, "%s_expires" % label, return_int(meta['expires'])) setattr(self, "%s_created" % label, return_int(meta['created'])) setattr(self, "%s_signed" % label, return_int(meta['signed'])) setattr(self, "%s_submitted" % label, return_int(meta['submitted'])) setattr(self, "%s_fqdn" % label, return_int(meta['fqdn'])) self.check_is_valid(label) else: setattr(self, "%s_is_valid" % label, False)
def sync_from_filesystem(self): """ Reads meta data and items from the file system. This allows us to restore data incase the database goes south. This is important since only the gateway has the private key and cannot be recovered. :return: """ logger.debug("Inspecting file system for certs, and loading them for: {name}", name=self.sslname) for label in ["current", "next"]: setattr(self, f"{label}_is_valid", None) if os.path.exists(f"{self.working_dir}/etc/certs/{self.sslname}.{label}.meta"): logger.debug("SSL Meta found for: {label} - {sslname}", label=label, sslname=self.sslname) file_content = yield read_file(f"{self.working_dir}/etc/certs/{self.sslname}.{label}.meta") meta = json.loads(file_content) csr_read = False if label == "next": logger.debug("Looking for 'next' information.") if os.path.exists(f"{self.working_dir}/etc/certs/{self.sslname}.{label}.csr.pem"): if getattr(self, f"{label}_csr") is None: csr = yield read_file( f"{self.working_dir}/etc/certs/{self.sslname}.{label}.csr.pem", True, ) if sha256(str(csr).encode("utf-8")).hexdigest() == meta["csr"]: csr_read = True else: logger.warn("Appears that the file system has bad meta signatures (csr). Purging.") for file_to_delete in glob.glob(f"{self.working_dir}/etc/certs/{self.sslname}.{label}.*"): logger.warn("Removing bad file: {file}", file=file_to_delete) os.remove(file_to_delete) continue cert_read = False if getattr(self, f"{label}_cert") is None: if os.path.exists(f"{self.working_dir}/etc/certs/{self.sslname}.{label}.cert.pem"): # print("setting cert!!!") cert = yield read_file( f"{self.working_dir}/etc/certs/{self.sslname}.{label}.cert.pem", True ) cert_read = True # print("testing with this cert: %s" % cert) if sha256(str(cert).encode("utf-8")).hexdigest() != meta["cert"]: # print("%s != %s" % (sha256(str(cert).encode("utf-8")).hexdigest(), meta["cert"])) logger.warn("Appears that the file system has bad meta signatures (cert). Purging.") for file_to_delete in glob.glob(f"{self.working_dir}/etc/certs/{self.sslname}.{label}.*"): logger.warn("Removing bad file: {file}", file=file_to_delete) os.remove(file_to_delete) continue chain_read = False if getattr(self, f"{label}_chain") is None: if os.path.exists(f"{self.working_dir}/etc/certs/{self.sslname}.{label}.chain.pem"): # print("setting chain!!!") chain = yield read_file( f"{self.working_dir}/etc/certs/{self.sslname}.{label}.chain.pem", True ) chain_read = True if sha256(str(chain).encode("utf-8")).hexdigest() != meta["chain"]: logger.warn("Appears that the file system has bad meta signatures (chain). Purging.") for file_to_delete in glob.glob(f"{self.working_dir}/etc/certs/{self.sslname}.{label}.*"): logger.warn("Removing bad file: {file}", file=file_to_delete) os.remove(file_to_delete) continue key_read = False if getattr(self, f"{label}_key") is None: if os.path.exists(f"{self.working_dir}/etc/certs/{self.sslname}.{label}.key.pem"): key = yield read_file( f"{self.working_dir}/etc/certs/{self.sslname}.{label}.key.pem", True ) key_read = True if sha256(str(key).encode("utf-8")).hexdigest() != meta["key"]: logger.warn("Appears that the file system has bad meta signatures (key). Purging.") for file_to_delete in glob.glob(f"{self.working_dir}/etc/certs/{self.sslname}.{label}.*"): logger.warn("Removing bad file: {file}", file=file_to_delete) os.remove(file_to_delete) continue logger.debug("Reading meta file for cert: {label}", label=label) def return_int(the_input): try: return int(the_input) except Exception as e: return the_input if csr_read: setattr(self, f"{label}_csr", csr) if cert_read: setattr(self, f"{label}_cert", cert) if chain_read: setattr(self, f"{label}_chain", chain) if key_read: setattr(self, f"{label}_key", key) setattr(self, f"{label}_status", return_int(meta["status"])) setattr(self, f"{label}_status_msg", return_int(meta["status_msg"])) setattr(self, f"{label}_expires_at", return_int(meta["expires_at"])) setattr(self, f"{label}_created_at", return_int(meta["created_at"])) setattr(self, f"{label}_signed_at", return_int(meta["signed_at"])) setattr(self, f"{label}_submitted_at", return_int(meta["submitted_at"])) setattr(self, f"{label}_fqdn", return_int(meta["fqdn"])) self.check_is_valid(label) else: setattr(self, f"{label}_is_valid", False) self.set_crypto()