def update_device(req, device_id): """ Updated the information about a particular device :param req: The received HTTP request, as created by Flask. :param device_id: The device to be updated. :return The updated device. :rtype JSON :raises HTTPRequestError: If no authorization token was provided (no tenant was informed) :raises HTTPRequestError: If this device could not be found in database. """ device_data, json_payload = parse_payload(req, device_schema) tenant = init_tenant_context(req, db) old_orm_device = assert_device_exists(device_id) db.session.delete(old_orm_device) db.session.flush() # handled separately by parse_template_list device_data.pop('templates') updated_orm_device = Device(**device_data) parse_template_list(json_payload.get('templates', []), updated_orm_device) auto_create_template(json_payload, updated_orm_device) updated_orm_device.id = device_id updated_orm_device.updated = datetime.now() updated_orm_device.created = old_orm_device.created db.session.add(updated_orm_device) full_device = serialize_full_device(updated_orm_device, tenant) if CONFIG.orion: # Create subscription pointing to history service # (STH, logstash based persister) subs_handler = PersistenceHandler(service=tenant) subs_handler.remove(old_orm_device.persistence) # Generating 'device type' field for subscription request type_descr = "template" for dev_type in full_device['attrs'].keys(): type_descr += "_" + str(dev_type) updated_orm_device.persistence = subs_handler.create( device_id, type_descr) ctx_broker_handler = OrionHandler(service=tenant) ctx_broker_handler.update( serialize_full_device(old_orm_device, tenant), type_descr) kafka_handler = KafkaHandler() kafka_handler.update(full_device, meta={"service": tenant}) try: db.session.commit() except IntegrityError as error: handle_consistency_exception(error) result = { 'message': 'device updated', 'device': serialize_full_device(updated_orm_device, tenant) } return result
def copy_psk(token, src_device_id, src_attr, dest_device_id, dest_attr): """ Copies a pre shared key from a device attribute to another :param token: The authorization token (JWT). :param src_device_id: The source device (from). :param src_attr: The source attribute (from). :param dest_device_id: The destination device (to). :param dest_attr: The destination attribute (to). :return None. :raises HTTPRequestError: If no authorization token was provided (no tenant was informed) todo list the others exceptions """ tenant = init_tenant_context2(token, db) src_device_orm = assert_device_exists(src_device_id, db.session) if not src_device_orm: raise HTTPRequestError(404, "No such device: {}".format(src_device_id)) src_device = serialize_full_device(src_device_orm, tenant, True) found_attr = False src_attr_ref = None for template_id in src_device["templates"]: for attr in src_device["attrs"][template_id]: if attr["label"] == src_attr: if attr["value_type"] == "psk": found_attr = True src_attr_ref = attr break else: raise HTTPRequestError(400, "Attribute {} is not a 'psk' type_value".format(src_attr)) if not found_attr: raise HTTPRequestError(404, "Not found attributes {}".format(src_attr)) dest_device_orm = assert_device_exists(dest_device_id, db.session) if not dest_device_orm: raise HTTPRequestError(404, "No such device: {}".format(dest_device_id)) dest_device = serialize_full_device(dest_device_orm, tenant, True) found_attr = False dest_attr_ref = None for template_id in dest_device["templates"]: for attr in dest_device["attrs"][template_id]: if attr["label"] == dest_attr: if attr["value_type"] == "psk": found_attr = True dest_attr_ref = attr break else: raise HTTPRequestError(400, "Attribute {} is not a 'psk' type_value".format(dest_attr)) if not found_attr: raise HTTPRequestError(404, "Not found attributes {}".format(dest_attr)) # copy the pre shared key src_psk_entry = DeviceAttrsPsk.query.filter_by(device_id=src_device["id"], attr_id=src_attr_ref["id"]).first() if not src_psk_entry: raise HTTPRequestError(400, "There is not a psk generated to {}".format(src_attr)) dest_psk_entry = DeviceAttrsPsk.query.filter_by(device_id=dest_device["id"], attr_id=dest_attr_ref["id"]).first() if not dest_psk_entry: db.session.add(DeviceAttrsPsk(device_id=dest_device["id"], attr_id=dest_attr_ref["id"], psk=src_psk_entry.psk)) else: dest_psk_entry.psk = src_psk_entry.psk dest_device_orm.updated = datetime.now() db.session.commit() dest_attr_ref['static_value'] = src_attr_ref['static_value'] # send an update message on kafka kafka_handler = KafkaHandler() kafka_handler.update(dest_device, meta={"service": tenant}) return None
def update_template(req, template_id): """ Updates a single template. :param req: The received HTTP request, as created by Flask. :param template_id: The template to be updated. :return The old version of this template (previous to the update). :rtype JSON :raises HTTPRequestError: If no authorization token was provided (no tenant was informed) :raises HTTPRequestError: If this template could not be found in database. """ service = init_tenant_context(req, db) # find old version of the template, if any old = assert_template_exists(template_id) # parse updated version from payload updated, json_payload = parse_payload(req, template_schema) LOGGER.debug(f" Current json payload: {json_payload}") old.label = updated['label'] new = json_payload['attrs'] LOGGER.debug(f" Checking old template attributes") def attrs_match(attr_from_db, attr_from_request): return ((attr_from_db.label == attr_from_request["label"]) and (attr_from_db.type == attr_from_request["type"])) def update_attr(attrs_from_db, attrs_from_request): attrs_from_db.value_type = attrs_from_request.get( 'value_type', None) attrs_from_db.static_value = attrs_from_request.get( 'static_value', None) def validate_attr(attr_from_request, is_meta): if is_meta is False: attr_schema.load(attr_from_request) else: metaattr_schema.load(attr_from_request) def analyze_attrs(attrs_from_db, attrs_from_request, parentAttr=None): for attr_from_db in attrs_from_db: found = False for idx, attr_from_request in enumerate(attrs_from_request): validate_attr(attr_from_request, parentAttr is not None) if attrs_match(attr_from_db, attr_from_request): update_attr(attr_from_db, attr_from_request) if "metadata" in attr_from_request: analyze_attrs(attr_from_db.children, attr_from_request["metadata"], attr_from_db) attrs_from_request.pop(idx) found = True break if not found: LOGGER.debug(f" Removing attribute {attr_from_db.label}") db.session.delete(attr_from_db) if parentAttr and attrs_from_request is not None: for attr_from_request in attrs_from_request: orm_child = DeviceAttr(parent=parentAttr, **attr_from_request) db.session.add(orm_child) return attrs_from_request to_be_added = analyze_attrs(old.attrs, new) for attr in to_be_added: LOGGER.debug(f" Adding new attribute {attr}") if "id" in attr: del attr["id"] child = DeviceAttr(template=old, **attr) db.session.add(child) if "metadata" in attr and attr["metadata"] is not None: for metadata in attr["metadata"]: LOGGER.debug(f" Adding new metadata {metadata}") orm_child = DeviceAttr(parent=child, **metadata) db.session.add(orm_child) try: LOGGER.debug(f" Commiting new data...") db.session.commit() LOGGER.debug("... data committed.") except IntegrityError as error: LOGGER.debug(f" ConsistencyException was thrown.") handle_consistency_exception(error) # notify interested parties that a set of devices might have been implicitly updated affected = db.session.query(DeviceTemplateMap) \ .filter(DeviceTemplateMap.template_id==template_id) \ .all() affected_devices = [] kafka_handler = KafkaHandler() for device in affected: orm_device = assert_device_exists(device.device_id) kafka_handler.update(serialize_full_device(orm_device, service), meta={"service": service}) affected_devices.append(device.device_id) event = { "event": DeviceEvent.TEMPLATE, "data": { "affected": affected_devices, "template": template_schema.dump(old) }, "meta": { "service": service } } send_raw(event, service) results = {'updated': template_schema.dump(old), 'result': 'ok'} return results
def gen_psk(token, device_id, key_length, target_attributes=None): """ Generates pre shared keys to a specifics device :param token: The authorization token (JWT). :param device_id: The target device. :param key_length: The key length to be generated. :param target_attributes: A list with the target attributes, None means all suitable attributes. :return The keys generated. :rtype JSON :raises HTTPRequestError: If no authorization token was provided (no tenant was informed) :raises HTTPRequestError: If this device could not be found in database. """ tenant = init_tenant_context2(token, db) device_orm = assert_device_exists(device_id, db.session) if not device_orm: raise HTTPRequestError(404, "No such device: {}".format(device_id)) device = serialize_full_device(device_orm, tenant, True) # checks if the key length has been specified # todo remove this magic number if key_length > 1024 or key_length <= 0: raise HTTPRequestError(400, "key_length must be greater than 0 and lesser than {}".format(1024)) is_all_psk_attr_valid = False target_attrs_data = [] # find the target attributes # first case: if there are specified attributes if target_attributes: for template_id in device["templates"]: for attr in device["attrs"][template_id]: if attr["value_type"] == "psk" and attr["label"] in target_attributes: target_attrs_data.append(attr) is_all_psk_attr_valid = True if not is_all_psk_attr_valid: raise HTTPRequestError(400, "Not found some attributes, " "please check them") if len(target_attributes) != len(target_attrs_data): if not is_all_psk_attr_valid: raise HTTPRequestError(400, "Some attribute is not a 'psk' type_value") else: raise HTTPRequestError(400, "Not found some attributes, " "please check them") else: # second case: if there are not specified attributes for template_id in device["templates"]: for attr in device["attrs"][template_id]: if attr["value_type"] == "psk": target_attrs_data.append(attr) is_all_psk_attr_valid = True if not is_all_psk_attr_valid: # there is no psk key, do not worry it is not a problem raise HTTPRequestError(204, "") # generate the pre shared key on selected attributes result = [] for attr in target_attrs_data: psk = secrets.token_hex(key_length) psk_hex = psk attr["static_value"] = psk_hex encrypted_psk = encrypt(psk) psk_entry = DeviceAttrsPsk.query.filter_by(device_id=device["id"], attr_id=attr["id"]).first() if not psk_entry: db.session.add(DeviceAttrsPsk(device_id=device["id"], attr_id=attr["id"], psk=encrypted_psk)) else: psk_entry.psk = encrypted_psk result.append( {'attribute': attr["label"], 'psk': psk_hex} ) device_orm.updated = datetime.now() db.session.commit() # send an update message on kafka kafka_handler = KafkaHandler() kafka_handler.update(device, meta={"service": tenant}) return result