From a657b530f33267e5e1237355db4a79d40c914baf Mon Sep 17 00:00:00 2001 From: Jeremy Stanley Date: Sat, 28 Dec 2019 21:01:32 +0000 Subject: [PATCH] Replace eval() and exec() use for menu functions Add a new misc.call_hook_function() routine based on the existing command execution in misc.handler_active() to eliminate all use of eval() and exec() built-ins in menu operations. --- mudpy/misc.py | 44 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/mudpy/misc.py b/mudpy/misc.py index dc37b6e..2cd7992 100644 --- a/mudpy/misc.py +++ b/mudpy/misc.py @@ -1585,16 +1585,15 @@ def get_menu_choices(user): state = universe.groups["menu"][user.state] create_choices = state.get("create") if create_choices: - choices = eval(create_choices) + choices = call_hook_function(create_choices, (user,)) else: choices = {} ignores = [] options = {} creates = {} for facet in state.facets(): - if facet.startswith("demand_") and not eval( - universe.groups["menu"][user.state].get(facet) - ): + if facet.startswith("demand_") and not call_hook_function( + universe.groups["menu"][user.state].get(facet), (user,)): ignores.append(facet.split("_", 2)[1]) elif facet.startswith("create_"): creates[facet] = facet.split("_", 2)[1] @@ -1602,7 +1601,8 @@ def get_menu_choices(user): options[facet] = facet.split("_", 2)[1] for facet in creates.keys(): if not creates[facet] in ignores: - choices[creates[facet]] = eval(state.get(facet)) + choices[creates[facet]] = call_hook_function( + state.get(facet), (user,)) for facet in options.keys(): if not options[facet] in ignores: choices[options[facet]] = state.get(facet) @@ -1677,6 +1677,35 @@ def get_choice_action(user): return "" +def call_hook_function(fname, arglist): + """Safely execute named function with supplied arguments, return result.""" + + # strip any explicit leader or parameter + # TODO(fungi) remove this once the menu functions transition is complete + if fname.startswith("mudpy."): + fname = fname[6:] + if fname.endswith("(user)"): + fname = fname[:-6] + + # all functions relative to mudpy package + function = mudpy + + for component in fname.split("."): + try: + function = getattr(function, component) + except AttributeError: + log('Could not find mudpy.%s() for arguments "%s"' + % (fname, arglist), 7) + function = None + break + if function: + try: + return function(*arglist) + except Exception: + log('Calling mudpy.%s(%s) raised an exception...\n%s' + % (fname, (*arglist,), traceback.format_exc()), 7) + + def handle_user_input(user): """The main handler, branches to a state-specific handler.""" @@ -1711,7 +1740,9 @@ def generic_menu_handler(user): if not user.choice: user.choice = get_default_menu_choice(user.state) if user.choice in user.menu_choices: - exec(get_choice_action(user)) + action = get_choice_action(user) + if action: + call_hook_function(action, (user,)) new_state = get_choice_branch(user) if new_state: user.state = new_state @@ -1890,6 +1921,7 @@ def handler_active(user): ran = False if actor.can_run(command): # dereference the relative object path for the requested function + # TODO(fungi) use call_hook_function() here instead action = mudpy action_fname = command.get("action", command.key) for component in action_fname.split("."): -- 2.11.0