Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use new msg format with headers baked in, use MQTT byte header - on working branch #9

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 16 additions & 14 deletions examples/advanced_mqtt.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
)

from yuuki.openc2.oc2_types import (
OC2Response,
OC2Rsp,
OC2Cmd,
StatusCode
)
Expand All @@ -35,7 +35,8 @@
Authentication,
BrokerConfig,
Publish,
Subscription
Subscription,
OpenC2Options
)

logging.basicConfig(format='%(levelname)s:%(message)s',level=logging.INFO)
Expand All @@ -51,7 +52,7 @@ class CmdHandler(OpenC2CmdDispatchBase):

@oc2_pair(ACTUATOR_NSID, ACTION, TARGET)
def some_method(self, OC2Command):
return OC2Response
return OC2Rsp
'''
def __init__(self, validator=None):
super().__init__(validator)
Expand Down Expand Up @@ -81,7 +82,7 @@ def rate_limit(self):
return 60

@oc2_query_features
def func1(self, oc2_cmd : OC2Cmd) -> OC2Response:
def func1(self, oc2_cmd : OC2Cmd) -> OC2Rsp:
'''
Handle all calls to the OpenC2 command 'query features'.
The parent class comes with a built-in method for this.
Expand All @@ -91,7 +92,7 @@ def func1(self, oc2_cmd : OC2Cmd) -> OC2Response:
return oc2_rsp

@oc2_pair('slpf', 'deny', 'ipv4_connection')
def func2(self, oc2_cmd : OC2Cmd) -> OC2Response:
def func2(self, oc2_cmd : OC2Cmd) -> OC2Rsp:
'''
Stub for the SLPF OpenC2 Command 'deny ipv4_connection'.
'''
Expand All @@ -106,7 +107,7 @@ def func2(self, oc2_cmd : OC2Cmd) -> OC2Response:
found_other.append(key)

if len(found_keys) < 1 or len(found_other) > 0:
oc2_rsp = OC2Response(
oc2_rsp = OC2Rsp(
status=StatusCode.BAD_REQUEST,
status_text='Any of {} required for ipv4_connection'.format(str(allowed_keys)))
return oc2_rsp
Expand All @@ -116,14 +117,14 @@ def func2(self, oc2_cmd : OC2Cmd) -> OC2Response:
# For now, return what we would do.
status_text = 'Denied ipv4_connection: {}'.format(oc2_cmd.target['ipv4_connection'])

oc2_rsp = OC2Response(
oc2_rsp = OC2Rsp(
status=StatusCode.OK,
status_text=status_text)

return oc2_rsp

@oc2_pair('x-acme', 'detonate', 'x-acme:roadrunner' )
def func3(self, oc2_cmd : OC2Cmd) -> OC2Response:
def func3(self, oc2_cmd : OC2Cmd) -> OC2Rsp:
'''
Custom actuator profile implementation for Road Runner hunting.
'''
Expand All @@ -133,30 +134,30 @@ def func3(self, oc2_cmd : OC2Cmd) -> OC2Response:
if coyote_success:
raise SystemError('Example of how exceptions here are caught')
else:
return OC2Response(
return OC2Rsp(
status=StatusCode.INTERNAL_ERROR,
status_text='Coyote can never win')

@oc2_no_matching_pair
def func4(self, oc2_cmd : OC2Cmd) -> OC2Response:
def func4(self, oc2_cmd : OC2Cmd) -> OC2Rsp:
'''
We've searched all our action-target pairs from all our
actuators, and that pair doesn't exist.
'''
oc2_rsp = OC2Response(
oc2_rsp = OC2Rsp(
status=StatusCode.NOT_FOUND,
status_text='No action-target pair for {} {}'.format(oc2_cmd.action, oc2_cmd.target_name))

return oc2_rsp

@oc2_no_matching_actuator
def func5(self, oc2_cmd : OC2Cmd) -> OC2Response:
def func5(self, oc2_cmd : OC2Cmd) -> OC2Rsp:
'''
We have a matching action-target pair in our actuator(s),
but we don't have the requested actuator (nsid).
'''
actuator_name, = oc2_cmd.actuator.keys()
oc2_rsp = OC2Response(
oc2_rsp = OC2Rsp(
status=StatusCode.NOT_FOUND,
status_text='No actuator {}'.format(actuator_name))

Expand Down Expand Up @@ -190,7 +191,8 @@ def func5(self, oc2_cmd : OC2Cmd) -> OC2Response:
Publish(
topic_name='yuuki_user/oc2/rsp',
qos=1
)]
)],
oc2_options=OpenC2Options(use_oc2_mqtt_header=True)
)

consumer = Consumer(
Expand Down
18 changes: 9 additions & 9 deletions examples/simple_http.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ def rate_limit(self):
return 60

@oc2_query_features
def func1(self, oc2_cmd : OC2Cmd) -> OC2Response:
def func1(self, oc2_cmd : OC2Cmd) -> OC2Rsp:
return super().query_features(oc2_cmd)

@oc2_pair('slpf', 'deny', 'ipv4_connection')
def func2(self, oc2_cmd : OC2Cmd) -> OC2Response:
def func2(self, oc2_cmd : OC2Cmd) -> OC2Rsp:
allowed_keys = ['src_addr', 'src_port', 'dst_addr', 'dst_port', 'protocol']
found_keys = []
found_other = []
Expand All @@ -44,23 +44,23 @@ def func2(self, oc2_cmd : OC2Cmd) -> OC2Response:
found_other.append(key)

if len(found_keys) < 1 or len(found_other) > 0:
return OC2Response(status=StatusCode.BAD_REQUEST)
return OC2Rsp(status=StatusCode.BAD_REQUEST)

# Execute a real function here to deny...

return OC2Response(status=StatusCode.OK)
return OC2Rsp(status=StatusCode.OK)

@oc2_pair('x-acme', 'detonate', 'x-acme:roadrunner')
def func3(self, oc2_cmd : OC2Cmd) -> OC2Response:
def func3(self, oc2_cmd : OC2Cmd) -> OC2Rsp:
raise SystemError('Impossible! Coyote never wins!')

@oc2_no_matching_pair
def func4(self, oc2_cmd : OC2Cmd) -> OC2Response:
return OC2Response(status=StatusCode.NOT_FOUND)
def func4(self, oc2_cmd : OC2Cmd) -> OC2Rsp:
return OC2Rsp(status=StatusCode.NOT_FOUND)

@oc2_no_matching_actuator
def func5(self, oc2_cmd : OC2Cmd) -> OC2Response:
return OC2Response(status=StatusCode.NOT_FOUND)
def func5(self, oc2_cmd : OC2Cmd) -> OC2Rsp:
return OC2Rsp(status=StatusCode.NOT_FOUND)

if __name__ == '__main__':
http_config = HttpConfig()
Expand Down
4 changes: 3 additions & 1 deletion yuuki/openc2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
OC2Cmd,
Pair,
StatusCode,
OC2Response
OC2Rsp,
OC2Msg,
make_response_msg
)

2 changes: 1 addition & 1 deletion yuuki/openc2/message_dispatch/command_decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class MyDispatch(OOpenC2CmdDispatchBase):
...
@oc2_pair('slpf', 'deny', 'ipv4_connection')
def some_function(oc2_cmd):
return OC2Response()
return OC2Rsp()
"""
def _register(method):
method.is_oc2_pair = True
Expand Down
23 changes: 12 additions & 11 deletions yuuki/openc2/message_dispatch/command_dispatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from functools import partial
import logging
from .command_decorators import _OC2PairMeta
from ..oc2_types import OC2Cmd, OC2Response, StatusCode
from ..oc2_types import OC2Cmd, OC2Rsp, OC2Msg, StatusCode



Expand Down Expand Up @@ -35,7 +35,7 @@ def a_function(self, oc2_cmd):
target: {'my_target' : ...}
actuator: {my_actautor_nsid : {...}}

See the implementation of get_actuator_func for details.
See the implementation of get_actuator_callable for details.

"""
def __init__(self,validator):
Expand Down Expand Up @@ -69,11 +69,12 @@ def pairs(self):
pairs[action] = [target]
return pairs

def get_actuator_func(self,data_dict):
def get_actuator_callable(self,oc2_msg: OC2Msg):
func_name = None
func = None
logging.debug('Validating...')
oc2_cmd = self.validator(data_dict)
logging.warning('Validation is disabled in this work-in-progress branch')
#oc2_cmd = self.validator(data_dict)
oc2_cmd = oc2_msg.body.openc2.request
cmd_actuator_nsid = None

logging.debug('Determining which Consumer/Actuator function to call')
Expand Down Expand Up @@ -115,7 +116,7 @@ def get_actuator_func(self,data_dict):
else:
raise NotImplementedError('No function defined for: ',oc2_cmd)

logging.debug('Will call {}'.format(func_name))
logging.debug('Will call a method named: {}'.format(func_name))
my_callable = partial(func, oc2_cmd)
return my_callable

Expand All @@ -137,10 +138,10 @@ def query_features(self, oc2_cmd: OC2Cmd):
args_other = str(args_other) + str(key) + str(value)

if args_response_requested is not None and args_response_requested != 'complete':
return OC2Response(status=StatusCode.BAD_REQUEST,
return OC2Rsp(status=StatusCode.BAD_REQUEST,
status_text='Only arg response_requested=complete allowed')
if args_other is not None:
return OC2Response(status=StatusCode.BAD_REQUEST,
return OC2Rsp(status=StatusCode.BAD_REQUEST,
status_text='Only arg response_requested allowed')

# Target Specifiers
Expand All @@ -157,11 +158,11 @@ def query_features(self, oc2_cmd: OC2Cmd):
elif item == 'pairs':
retval_results['pairs'] = self.pairs
else:
return OC2Response(status=StatusCode.BAD_REQUEST,
return OC2Rsp(status=StatusCode.BAD_REQUEST,
status_text='features field only allows versions, profiles, rate_limit, and pairs')

if len(retval_results) > 0:
return OC2Response(status=StatusCode.OK,
return OC2Rsp(status=StatusCode.OK,
results=retval_results)
else:
return OC2Response(status=StatusCode.OK)
return OC2Rsp(status=StatusCode.OK)
Loading