def command_response(body, message):
    """
    Process a command received from an actuator
    :param body: command body
    :param message: complete message (headers, meta, ...)
    :return: None
    """
    log.info(msg=f'Message response received: {body}')
    headers = getattr(message, "headers", {})
    actuator = None

    if headers.get('error', False):
        correlation_ID = headers['source'].get('correlationID', '')
        opts = {
            '_coap_id' if isHex(correlation_ID) else 'command_id':
            correlation_ID
        }

        command = get_or_none(SentHistory, **opts)
        log.error(msg=f'Message Failure: cmd - {command.command_id}, {body}')

        response = {'error': body}

    else:
        act_host, act_port = headers.get('socket', '').split(':')[0:2]
        correlation_ID = headers.get('correlationID', '')
        opts = {
            '_coap_id' if isHex(correlation_ID) else 'command_id':
            correlation_ID
        }

        command = get_or_none(SentHistory, **opts)
        profile = headers.get('profile', '')

        encode = headers.get('encode', 'json')
        response = decode_msg(body, encode)

        actuator = get_or_none(
            model=Actuator,
            profile__iexact=profile,
            device__transport__host__iexact=act_host,
            device__transport__port=safe_cast(act_port, int),
            device__transport__protocol=get_or_none(Protocol,
                                                    name__iexact=headers.get(
                                                        'transport', '')))

        if hasattr(actuator, '__iter__'):
            log.warn(
                msg=
                f'Multiple actuators match for command response - {command.command_id}'
            )
            actuator = random.choice(actuator)

    try:
        cmd_rsp = ResponseHistory(command=command,
                                  actuator=actuator,
                                  response=response)
        cmd_rsp.save()
    except Exception as e:
        log.error(msg=f'Message response failed to save: {e}')
Ejemplo n.º 2
0
def vocab_import(request):
    bad_vocabs = []
    if request.method == 'POST':
        data = request.FILES.get('json').read()
        data_parse = json.loads(data)
        # list_screens = data_parse.keys()
        print(data_parse)
        for screen_code in data_parse:
            screen = get_or_none(Screen, screen_code=screen_code)
            if not screen:
                screen = create_screen_from_code_only(screen_code=screen_code,
                                                      user=request.user)
            list_words = data_parse[screen_code]
            for word in list_words:
                vocab = get_or_none(Vocabulary, vocab_key=word)
                if vocab:
                    if screen not in vocab.screen.all():
                        vocab.screen.add(screen)
                    else:
                        bad_vocabs.append(vocab)
                else:
                    obj = Vocabulary.objects.create(
                        vocab_key=word,
                        english_definition=list_words[word].get('en', ''),
                        vn_definition=list_words[word].get('vn', ''),
                        korean_definition=list_words[word].get('kr', ''),
                        created_by=request.user,
                        modified_by=request.user)
                    obj.screen.add(screen)
                    obj.save()
    return render(request, 'vocabulary/import.html',
                  {'bad_vocabs': bad_vocabs})
Ejemplo n.º 3
0
    def update(self, request, order_id=None):
        order = get_or_none(Order, id=order_id)
        if order is None:
            return Response({
                'error': 'Order does not exist.',
                'updated': False
            })

        data = dict()
        data = request.data.dict()
        pizza_obj = get_or_none(Pizza, id=request.data.get('pizza', None))
        customer_obj = get_or_none(Customer,
                                   id=request.data.get('customer', None))
        if pizza_obj is not None:
            data.update({'pizza': pizza_obj})

        if customer_obj is not None:
            data.update({'customer': customer_obj})

        try:
            order = self.queryset.filter(id=order_id).update(**data)
            return Response({'updated': True if order is not None else False})
        except Exception as e:
            return Response({
                'error': str(e),
                'updated': False,
            })
Ejemplo n.º 4
0
    def create(self, request):
        try:
            pizza_obj = get_or_none(Pizza, id=request.data.get('pizza', None))
            customer_obj = get_or_none(Customer,
                                       id=request.data.get('customer', None))
            size = int(request.data.get('size'))
            if size < 30 or size > 50:
                raise Exception('Invalid size. Must be beetwen 30 and 50 cms.')
            data = dict()
            data.update({
                'pizza':
                pizza_obj,
                'customer':
                customer_obj,
                'size':
                size,
                'customer_address':
                request.data.get('customer_address', ''),
            })
            order = self.queryset.create(**data)
            serializer = OrderSerializer(order)
            return Response({
                'data': serializer.data,
                'created': True,
            })

        except Exception as e:
            return Response({
                'error': str(e),
                'created': False,
            })
Ejemplo n.º 5
0
def check_command_id(sender, instance=None, **kwargs):
    """
    Validate the command id given is a UUID
    :param sender: sender instance - SentHistory
    :param instance: SENDER instance
    :param kwargs: key/value args
    :return: None
    """
    if instance.command_id is None:
        log.info(
            msg=f"Command submitted without command id, command id generated")
        instance.command_id = uuid.uuid4()
        instance.command.update({"id": str(instance.command_id)})
    else:
        try:
            val = uuid.UUID(str(instance.command_id), version=4)
        except ValueError:
            log.info(msg=f"Invalid command id received: {instance.command_id}")
            raise ValueError("Invalid command id")

        tmp = get_or_none(sender, command_id=val)
        if val is None and tmp is not None:
            log.info(
                msg=f"Duplicate command id received: {instance.command_id}")
            raise ValueError("command id has been used")
Ejemplo n.º 6
0
    def list(self, request, *args, **kwargs):  # pylint: disable=unused-argument
        """
        Return a list of a users command history
        """
        username = kwargs.get('username', None)
        self.pagination_class.page_size_query_param = 'length'
        self.pagination_class.max_page_size = 100
        queryset = self.filter_queryset(self.get_queryset())

        username = bleach.clean(username)

        if request.user.is_staff:  # Admin User
            user = get_or_none(User, username=username)
            if user is None:
                raise Http404
            queryset = queryset.filter(user=user)

        else:  # Standard User
            if request.user.username == username:
                queryset = queryset.filter(user=request.user)
            else:
                raise PermissionDenied

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)
Ejemplo n.º 7
0
    def _val_channel(self, act: Actuator):
        if isinstance(act, list) and len(act) == 1:
            act = act[0]
            if isinstance(act, Actuator):
                proto = self._channel.get("protocol", None)
                if proto:
                    dev = get_or_none(Device, device_id=act.device.device_id)
                    proto = get_or_none(dev.transport, protocol__name=bleach.clean(str(proto)))
                    proto = proto.protocol if proto else None

                serial = self._channel.get("serialization", None)
                if serial:
                    serial = get_or_none(Serialization, name=bleach.clean(str(serial)))

                return proto, serial
        return None, None
Ejemplo n.º 8
0
    def _val_actuator(self) -> Union[Tuple[dict, int], Tuple[Tuple[dict, int], str], Tuple[List[Actuator], str]]:
        if self._actuator is None:
            # TODO: Actuator broadcast??
            log.error(usr=self._usr, msg="User attempted to send to a null actuator")
            return dict(
                detail="actuator invalid",
                response="Actuator Invalid: actuator cannot be none"
            ), 400

        act_arr = self._actuator.split("/", 1)
        if len(act_arr) != 2:
            log.error(usr=self._usr, msg=f"User attempted to send to an invalid actuator - {self._actuator}")
            return dict(
                detail="actuator invalid",
                response="Actuator Invalid: application error"
            ), 400

        act_type, act = act_arr
        act_type = bleach.clean(str(act_type))
        act = bleach.clean(str(act).replace("_", " "))

        if act_type == "actuator":  # Single Actuator
            actuators = get_or_none(Actuator, actuator_id=act)
            rtn = [actuators, ]
            if actuators is None:
                rtn = dict(
                    detail="actuator invalid",
                    response="Actuator Invalid: actuator must be specified with a command"
                ), 404
            return rtn, 'device'

        if act_type == "profile":  # Profile Actuators
            print(f'Profile: {act}')
            actuators = get_or_none(ActuatorProfile, name__iexact=act)
            if actuators is None:
                return dict(
                    detail="profile cannot be found",
                    response="Profile Invalid: profile must be a valid registered profile with the orchestrator"
                ), 400
            return list(Actuator.objects.filter(profile__iexact=act.replace(" ", "_"))), 'profile'

        return dict(
            detail="actuator invalid",
            response="Actuator Invalid: application error"
        ), 400
Ejemplo n.º 9
0
def validate_actuator(usr, act=""):
    if act is None:  # TODO: actuator broadcast??
        log.error(usr=usr, msg="User attempted to send to a null actuator")
        return dict(detail="actuator invalid",
                    response="Actuator Invalid: actuator cannot be none"), 400

    act_type = act.split("/", 1)
    if len(act_type) != 2:
        log.error(usr=usr,
                  msg=f"User attempted to send to an invalid actuator - {act}")
        return dict(detail="actuator invalid",
                    response="Actuator Invalid: application error"), 400

    _type, _act_prof = act_type
    _type = bleach.clean(str(_type))
    _act_prof = bleach.clean(str(_act_prof).replace("_", " "))

    if _type == "actuator":  # Single Actuator
        actuators = get_or_none(Actuator, actuator_id=_act_prof)
        if actuators is None:
            return dict(
                detail="actuator invalid",
                response=
                "Actuator Invalid: actuator must be specified with a command"
            ), 404
        return [
            actuators,
        ]

    elif _type == "profile":  # Profile Actuators
        actuators = get_or_none(ActuatorProfile, name__iexact=_act_prof)
        if actuators is None:
            return dict(
                detail=f"profile cannot be found",
                response=
                f"Profile Invalid: profile must be a valid registered profile with the orchestrator"
            ), 400
        return list(
            Actuator.objects.filter(
                profile__iexact=_act_prof.replace(" ", "_")))
    else:
        return dict(detail="actuator invalid",
                    response="Actuator Invalid: application error"), 400
Ejemplo n.º 10
0
def validate_channel(act, chan={}):
    if len(act) == 1:
        act = act[0]
        if isinstance(act, Actuator):
            dev = get_or_none(Device, device_id=act.device.device_id)

            proto = chan.get("protocol", None)
            if proto:
                proto = get_or_none(dev.transport,
                                    protocol__name=bleach.clean(str(proto)))
                proto = proto.protocol if proto else None

            serial = chan.get("serialization", None)
            if serial:
                serial = get_or_none(Serialization,
                                     name=bleach.clean(str(serial)))

            return proto, serial
    return None, None
Ejemplo n.º 11
0
    def save(self, *args, **kwargs):
        """
        Override the save function for added validation
        :param args: save args
        :param kwargs: save key/value args
        :return: None
        """
        if not self.protocol.pub_sub:
            trans = get_or_none(Transport, host=self.host, port=self.port, protocol=self.protocol)
            trans = trans if isinstance(trans, (list, QuerySet)) else [trans]
            if len(trans) > 1:
                raise DjangoValidationError("host, port, and protocol must make a unique pair unless a pub/sub protocol")

        super(Transport, self).save(*args, **kwargs)
Ejemplo n.º 12
0
    def destroy(self, request, order_id=None):
        order = get_or_none(Order, id=order_id)
        if order is None:
            return Response({
                'error': 'Order does not exist.',
                'deleted': False
            })

        try:
            order.delete()
            return Response({
                'deleted': True,
            })
        except Exception as e:
            return Response({
                'error': str(e),
            })
Ejemplo n.º 13
0
def verify_unique(sender, instance=None, **kwargs):
    """
    On Device transport change, check the updated transport is unique
    :param sender: sender instance - Device
    :param instance: SENDER instance
    :param kwargs: key/value args
    :return: None
    """
    action = kwargs.get("action", None)
    transports = [get_or_none(Transport, pk=t) for t in kwargs.get("pk_set", [])]
    transports = list(filter(None, transports))

    for trans in transports:
        count = trans.device_set.count()
        if action == "pre_add" and count > 1:
            raise IntegrityError("Transport cannot be associated with more that one device")

        if action in ("post_clear", "post_remove") and count == 0:
            trans.delete()
Ejemplo n.º 14
0
def action_send(usr=None, cmd={}, actuator="", channel={}):
    """
    Process a command prior to sending it to the specified actuator(s)/profile
    :param usr: user sending command
    :param cmd: OpenC2 command
    :param actuator: actuator/profile receiving command
    :param channel: serialization & protocol to send the command
    :return: response dict
    """
    err = validate_usr(usr)
    if err:
        return err

    err = validate_cmd(usr, cmd)
    if err:
        return err

    actuators = None
    err = validate_actuator(usr, actuator)
    if err:
        if isinstance(err, (Actuator, list)):
            actuators = err
        else:
            return err

    protocol, serialization = validate_channel(actuators, channel)

    # Store command in db
    cmd_id = cmd.get("id", uuid.uuid4())
    if get_or_none(SentHistory, command_id=cmd_id):
        return dict(command_id=["This ID is used by another command."]), 400
    else:
        com = SentHistory(command_id=cmd_id, user=usr, command=cmd)
        try:
            com.save()
        except ValueError as e:
            return dict(detail="command error", response=str(e)), 400

    orc_ip = global_preferences.get("orchestrator__host", "127.0.0.1")
    orc_id = global_preferences.get("orchestrator__id", "")
    # Process Actuators that should receive command
    processed_acts = set()

    # Process Protocols
    protocols = [protocol] if protocol else Protocol.objects.all()
    for proto in protocols:
        proto_acts = [
            a for a in actuators
            if a.device.transport.filter(protocol__name=proto.name).exists()
        ]
        proto_acts = list(
            filter(lambda a: a.id not in processed_acts, proto_acts))
        processed_acts.update({act.id for act in proto_acts})

        if len(proto_acts) >= 1:
            if proto.name.lower() == "coap" and com.coap_id is b"":
                corr_id = com.gen_coap_id()
                com.save()
            else:
                corr_id = str(com.command_id)

            header = dict(source=dict(
                orchestratorID=orc_id,
                transport=dict(type=proto.name,
                               socket=f"{orc_ip}:{proto.port}"),
                correlationID=corr_id,
                date=f"{com.received_on:%a, %d %b %Y %X %Z}"),
                          destination=[])

            for act in proto_acts:
                com.actuators.add(act)
                trans = act.device.transport.filter(
                    protocol__name=proto.name).first()
                encoding = (serialization if serialization else
                            trans.serialization.first()).name.lower()

                dev = list(
                    filter(
                        lambda d: d["deviceID"] == str(act.device.device_id),
                        header["destination"]))
                profile = str(act.profile).lower()

                if len(dev) == 1:
                    idx = header["destination"].index(dev[0])
                    header["destination"][idx]["profile"].append(profile)

                else:
                    dest = dict(deviceID=str(act.device.device_id),
                                socket=f"{trans.host}:{trans.port}",
                                profile=[profile],
                                encoding=encoding)
                    if trans.protocol.pub_sub:
                        print("PUB SUB")
                    header["destination"].append(dest)

            # Send command to transport
            log.info(
                usr=usr,
                msg=
                f"Send command {com.command_id}/{com.coap_id.hex()} to buffer")
            settings.MESSAGE_QUEUE.send(msg=json.dumps(cmd),
                                        headers=header,
                                        routing_key=proto.name.lower().replace(
                                            " ", "_"))

    wait = safe_cast(global_preferences.get("command__wait", 1), int, 1)
    rsp = None
    for _ in range(wait):
        rsp = get_or_none(ResponseHistory, command=com)
        if rsp:
            break
        else:
            time.sleep(1)

    rsp = [r.response for r in rsp] if hasattr(rsp, "__iter__") else (
        [rsp.response] if hasattr(rsp, "response") else None)

    return dict(detail=f"command {'received' if rsp is None else 'processed'}",
                response=rsp if rsp else "pending",
                command_id=com.command_id,
                command=com.command,
                wait=wait), 200
Ejemplo n.º 15
0
def action_send(usr: User, cmd: dict, actuator: str, channel: dict):
    """
    Process a command prior to sending it to the specified actuator(s)/profile
    :param usr: user sending command
    :param cmd: OpenC2 command
    :param actuator: actuator/profile receiving command
    :param channel: serialization & protocol to send the command
    :return: response Tuple(dict, int)
    """
    val = Validator(usr, cmd, actuator, channel)
    acts, protocol, serialization = val.validate()
    (actuators, fmt) = acts

    # Store command in db
    if "id" in cmd:
        cmd_id = cmd.get("id", uuid.uuid4())
        try:
            cmd_id = uuid.UUID(cmd_id, version=4)
        except ValueError:
            cmd_id = uuid.uuid4()
            cmd["id"] = str(cmd_id)
    else:
        cmd_id = uuid.uuid4()

    if get_or_none(SentHistory, command_id=cmd_id):
        return dict(
            command_id=[
                "This ID is used by another command."
            ]
        ), 400

    com = SentHistory(command_id=cmd_id, user=usr, command=cmd)
    try:
        com.save()
    except ValueError as e:
        return dict(
            detail="command error",
            response=str(e)
        ), 400

    # Process Actuators that should receive command
    processed_acts = set()

    # Process Protocols
    for proto in [protocol] if protocol else Protocol.objects.all():
        proto_acts = [a for a in actuators if a.device.transport.filter(protocol__name=proto.name).exists()]
        proto_acts = list(filter(lambda a: a.id not in processed_acts, proto_acts))
        processed_acts.update({act.id for act in proto_acts})

        if len(proto_acts) >= 1:
            if proto.name.lower() == "coap" and com.coap_id == b"":
                com.gen_coap_id()
                com.save()

            # Send command to transport
            log.info(usr=usr, msg=f"Send command {com.command_id}/{com.coap_id.hex()} to buffer")
            settings.MESSAGE_QUEUE.send(
                msg=json.dumps(cmd),
                headers=get_headers(proto, com, proto_acts, serialization, fmt),
                routing_key=proto.name.lower().replace(" ", "_")
            )

    wait = safe_cast(global_preferences.get("command__wait", 1), int, 1)
    rsp = None
    for _ in range(wait):
        rsp = get_or_none(ResponseHistory, command=com)
        if rsp:
            break
        time.sleep(1)

    rsp = [r.response for r in rsp] if hasattr(rsp, "__iter__") else ([rsp.response] if hasattr(rsp, "response") else None)

    return dict(
        detail=f"command {'received' if rsp is None else 'processed'}",
        response=rsp if rsp else "pending",
        command_id=com.command_id,
        command=com.command,
        wait=wait
    ), 200
Ejemplo n.º 16
0
 def retrieve(self, request, order_id=None):
     order = get_or_none(Order, id=order_id)
     if order is None:
         return Response({'error': 'Order does not exist.'})
     serializer = OrderSerializer(order)
     return Response({'data': serializer.data})