def encode_message(self, destination_id=None, component_type=None, component_name=None, payload=None, reply_to=None): """ Creates a basic dictionary to represent the message and then pickles it using JSON. :param payload: Dictionary to send. :param destination_id: :return: """ if destination_id is None: destination_id = "all" message_id = random_string(length=20) body = { "payload": payload, "time_sent": time(), "source_id": self.gateway_id, "destination_id": destination_id, "message_id": message_id, "component_type": component_type, "component_name": component_name, "reply_to": reply_to, "protocol_version": 2, } message_out = { "body": data_pickle(body, "msgpack_base85"), } message_out["hash"] = sha256_compact(message_out["body"]) message = { "body": body, "hash": message_out["hash"], } return message_id, message, data_pickle(message_out, "msgpack_base85")
def get_device_hash(self, discover_id, source=None): if discover_id in self.discovered: return discover_id if source is None: source = "unknown" return sha256_compact(str(source + discover_id).encode("utf-8"))
def get_idempotence(self, request, session): """ Check if idempotence is in the request and if that key has already been processed for the given user. If it has, return the same response. :param self: :param request: :param session: :return: """ request.setHeader("Content-Type", CONTENT_TYPE_JSON) idempotence = request.getHeader("x-idempotence") if idempotence is None: arguments = args_to_dict(request.args) idempotence = arguments.get("_idempotence", None) if idempotence is not None: request.idempotence = idempotence idempotence = sha256_compact(f"{session.auth_id}:{idempotence}") if idempotence in self.idempotence: results = msgpack.loads(zlib.uncompress(self.idempotence[idempotence])) print(f"get_idempotence results {results}") return False request.setHeader("Idempotence", "true") request.setResponseCode(results["response_code"]) return results["data"] return False
def render_api(self, request, session, data_type, attributes=None, meta=None, included=None, response_code=None): """ Renders content to an API based client. :param request: :param session: :param data_type: :param attributes: A dictionary or list of dictionaries :param meta: :param included: :param response_code: :return: """ if attributes is None: raise YomboWarning("Attributes is required for rendering to API.") response = {} if isinstance(attributes, list): response["data"] = [] for item in attributes: response["data"].append({ "type": data_type, "id": item["id"], "attributes": item, }) elif isinstance(attributes, dict): response["data"] = { "type": data_type, "id": attributes["id"], "attributes": attributes, } else: raise YomboWarning("Attributes must be a dictionary or list of dictionaries.") if included is not None: response["included"] = included if meta is not None: response["meta"] = meta if response_code is None: response_code = 200 request.setResponseCode(response_code) request.setHeader("Content-Type", CONTENT_TYPE_JSON) idempotence = request.getHeader("x-idempotence") if idempotence is None: arguments = args_to_dict(request.args) idempotence = arguments.get("_idempotence", None) if idempotence is not None: idempotence = sha256_compact(f"{session.auth_id}:{idempotence}") self.idempotence[idempotence] = zlib.compress(msgpack.packb(json.dumps( { "data": response, "response_code": response_code, } ))) return json.dumps(response)
def check_destination(self, destination, file_id, mangle_name): """ Checks the destinations and returns three items within a list: 1) urlparsed results from the destination 2) urlparse results from destination meant for thumbnails. 3) an extra random id that is used to further hide the URL of the resource. :param destination: :param file_id: :param mangle_name: :return: """ # print(f"storage: save file dest: {destination}") # print(f"storage: manglename: {mangle_name}") mangle_id = sha224_compact(random_string(length=100))[0:20] if mangle_name > 0: folder, filename = ntpath.split(destination) file, extension = path.splitext(filename) if mangle_name == 1: destination = f"{folder}/{file}_{file_id}_{mangle_id}{extension}" destination_thumb = f"{folder}/{file}_{file_id}_{mangle_id}_thumb{extension}" if mangle_name == 2: destination = f"{folder}/{file_id}_{mangle_id}{extension}" destination_thumb = f"{folder}/{file_id}_{mangle_id}_thumb{extension}" if mangle_name == 3: destination = f"{folder}/{file_id}_{mangle_id}" destination_thumb = f"{folder}/{file_id}_{mangle_id}_thumb" if mangle_name == 4: new_filename = sha256_compact(random_string(length=200)) destination = f"{folder}/{new_filename}{extension}" destination_thumb = f"{folder}/{new_filename}{extension}_thumb" if mangle_name >= 5: new_filename = sha256_compact(random_string(length=200)) destination = f"{folder}/{new_filename}" destination_thumb = f"{folder}/{new_filename}_thumb" # print(f"storage: save file new dest: {destination}") dest_parts = urlparse(destination) scheme = dest_parts.scheme if scheme not in self.storage: raise KeyError(f"Unknown file storage location type: {scheme}") dest_parts_thumb = urlparse(destination_thumb) return dest_parts, dest_parts_thumb, mangle_id
def decode_message(self, topic, raw_message): """ Decode a message from another gateway. :param payload: Dictionary to send. :param destination_id: :return: """ # ybo_req/src_gwid/dest_gwid topic_parts = topic.split("/", 3) message = data_unpickle(raw_message, encoder="msgpack_base85") required_keys = ("body", "hash") if all(required in message for required in required_keys) is False: raise YomboWarning("MQTT Gateway is dropping message, missing a required message field.") message_hash = message["hash"] generated_hash = sha256_compact(message["body"]) if message_hash != generated_hash: raise YomboWarning("Invalid incoming check hash.") message["body"] = data_unpickle(message["body"], encoder="msgpack_base85") message["body"]["time_received"] = time() required_keys = ("payload", "time_sent", "source_id", "destination_id", "message_id", "component_type", "component_name", "reply_to", "protocol_version") if all(required in message["body"] for required in required_keys) is False: raise YomboWarning("MQTT Gateway is dropping message, missing a required body field.") body = message["body"] if body["source_id"] != topic_parts[1]: raise YomboWarning("Gateway source_id doesn't match topic source_id") if body["destination_id"] != topic_parts[2]: raise YomboWarning("Gateway destination_id doesn't match topic destination_id") return message
def _do_sync_config(self): print("auth key: do_sync_config") tosave = { "source": self.source, "label": self.label, "description": self.description, # "auth_data": self.auth_data, "enabled": self.enabled, "roles": list(self.roles), "auth_id": self.auth_id, "created_by": self.created_by, "created_by_type": self.created_by_type, "last_access_at": self.last_access_at, "created_at": self.created_at, "updated_at": self.updated_at, "item_permissions": self.item_permissions, "saved_permissions": self.item_permissions } self._Parent._Configs.set("rbac_authkeys", sha256_compact(self.auth_id), data_pickle(tosave, encoder="msgpack_base64", local=True), ignore_case=True)
def generate_csr(self, args): """ This function shouldn't be called directly. Instead, use the queue "self.generate_csr_queue.put(request, callback, callback_args)" or "self._SSLCerts.generate_csr_queue.put()". Requests certs to be made. Will return right away with a request ID. A callback can be set to return the cert once it's complete. :return: """ logger.debug("Generate_CSR called with args: {args}", args=args) kwargs = self.check_csr_input(args) if kwargs["key_type"] == "rsa": kwargs["key_type"] = crypto.TYPE_RSA else: kwargs["key_type"] = crypto.TYPE_DSA req = crypto.X509Req() req.get_subject().CN = kwargs["cn"] req.get_subject().countryName = "US" req.get_subject().stateOrProvinceName = "California" req.get_subject().localityName = "Sacramento" req.get_subject().organizationName = "Yombo" req.get_subject( ).organizationalUnitName = "Gateway " + self.gateway_id[0:15] # Appends SAN to have "DNS:" if kwargs["sans"] is not None: san_string = [] for i in kwargs["sans"]: san_string.append(f"DNS: {i}") san_string = ", ".join(san_string) x509_extensions = [ crypto.X509Extension(b"subjectAltName", False, unicode_to_bytes(san_string)) ] req.add_extensions(x509_extensions) start = time() key = yield threads.deferToThread( self._generate_key, **{ "key_type": kwargs["key_type"], "key_size": kwargs["key_size"] }) duration = round(float(time()) - start, 4) self._Events.new("sslcerts", "generate_new", (args["sslname"], kwargs["cn"], san_string, duration)) req.set_pubkey(key) req.sign(key, "sha256") csr = crypto.dump_certificate_request(crypto.FILETYPE_PEM, req) key_file = crypto.dump_privatekey(crypto.FILETYPE_PEM, key) if kwargs["csr_file"] is not None: yield save_file(kwargs["csr_file"], csr) if kwargs["key_file"] is not None: yield save_file(kwargs["key_file"], key_file) return { "csr": csr, "csr_hash": sha256_compact(unicode_to_bytes(csr)), "key": key_file }
def update_attributes(self, attributes): """ Update various attributes. Should only be used by the SQLCerts system when loading updated things from a library or module. The attributes have already been screened by the parent. :param attributes: :return: """ if "update_callback" in attributes: self.update_callback = attributes["update_callback"] if "update_callback_type" in attributes: self.update_callback_type = attributes["update_callback_type"] if "update_callback_component" in attributes: self.update_callback_component = attributes["update_callback_component"] if "update_callback_function" in attributes: self.update_callback_function = attributes["update_callback_function"] if "key_size" in attributes: self.key_size = int(attributes["key_size"]) if attributes["key_size"] else None if "key_type" in attributes: self.key_type = attributes["key_type"] if "current_cert" in attributes: self.current_cert = attributes["current_cert"] if "current_chain" in attributes: self.current_chain = attributes["current_chain"] if "current_key" in attributes: self.current_key = attributes["current_key"] self.set_crypto() if "current_status" in attributes: self.current_status = attributes["current_status"] if "current_status_msg" in attributes: self.current_status_msg = attributes["current_status_msg"] if "current_csr_hash" in attributes: self.current_csr_hash = attributes["current_csr_hash"] if "current_created_at" in attributes: self.current_created_at = int(attributes["current_created_at"]) if attributes["current_created_at"] else None if "current_expires_at" in attributes: self.current_expires_at = int(attributes["current_expires_at"]) if attributes["current_expires_at"] else None if "current_signed_at" in attributes: self.current_signed_at = int(attributes["current_signed_at"]) if attributes["current_signed_at"] else None if "current_submitted_at" in attributes: self.current_submitted_at = int(attributes["current_submitted_at"]) if attributes["current_submitted_at"] else None if "current_fqdn" in attributes: self.current_fqdn = attributes["current_fqdn"] if "current_is_valid" in attributes: self.current_is_valid = attributes["current_is_valid"] if "next_status" in attributes: self.next_status = attributes["next_status"] if "next_status_msg" in attributes: self.next_status_msg = attributes["next_status_msg"] if "next_csr_hash" in attributes: self.next_csr_hash = attributes["next_csr_hash"] if "next_csr" in attributes: self.next_csr = attributes["next_csr"] if "next_cert" in attributes: self.next_cert = attributes["next_cert"] if "next_chain" in attributes: self.next_chain = attributes["next_chain"] if "next_key" in attributes: self.next_key = attributes["next_key"] if "next_created_at" in attributes: self.next_created_at = int(attributes["next_created_at"]) if attributes["next_created_at"] else None if "next_expires_at" in attributes: self.next_expires_at = int(attributes["next_expires_at"]) if attributes["next_expires_at"] else None if "next_signed_at" in attributes: self.next_signed_at = int(attributes["next_signed_at"]) if attributes["next_signed_at"] else None if "next_submitted_at" in attributes: self.next_submitted_at = int(attributes["next_submitted_at"]) if attributes["next_submitted_at"] else None if "next_fqdn" in attributes: self.next_fqdn = attributes["next_fqdn"] if "next_is_valid" in attributes: self.next_is_valid = attributes["next_is_valid"] # do some back checks. if self.next_csr is not None and self.next_csr_hash is None: self.next_csr_hash = sha256_compact(unicode_to_bytes(self.next_csr)) self.dirty = True