0

Is there a method to get a user input with a variable from the user input?

I don't even know how to describe it.

Consider this.

I want to have a user input a string and within that string have a variable.

user_defined_command_input = "config ap {ap_name} {old_ap_name}"

The idea is, instead of me generating a template for every possible command, they can generate the command template using string interpolation without having to know python. The idea is that they have a list of commands generated for hundreds of devices and they get to manage the template of the commands they need.

user_defined_command_input = "config ap {new_AP_name} {mac_address} {description}"

OR

user_defined_command_input = "config description {short_description}

Since they should be able to name their own variables, I can't hardcode them. I understand that there are security risks with unsanitized code being injected. So I would love to learn about that too.

James
  • 33
  • 1
  • 3
  • 15
  • 1
    I don't understand entirely. Do you want to get from "config ap foo bar" to having the variables `ap_name` and `old_ap_name` set to `foo` and `bar` or the other way around? – JanLikar Nov 12 '20 at 19:39
  • Terribly sorry for the poor explanation. I want them to be able to define their own variables and insert those variables in their own strings/commands. Lets say they want to create a template from the following string - `config AP {new_name} {old_name}` OR `config AP {ap_name} {default_name}` They can define the name of the variables that will go inside their commands. So when they have a list of `new-name` `old_name` when they run the script, it will inject the value. `config AP ap01 DF32XC22` `config AP ap02 AF75CC53` ETC... – James Nov 12 '20 at 19:47
  • Why not add a command to add variables, say in a dictionary, then let the users inflate the defined variables using your example commands? Something like `'add variable VARIABLE_NAME: VARIABLE_VALUE'` – VoidTwo Nov 12 '20 at 20:13

4 Answers4

0

You can use the command .split("") for the most part and that solves a lot fo your problems.

Where command = input("What's your command").split() for the input "config ap newTestVar oldTestVar" would set the command variable to ["config", "ap", "newTestVar", "oldTestVar"]

if your user never inputs spaces to screw with your commands, you can see config and AP are always at 0 and 1 index and what your looking for is the 2nd and 3rd variable always.

Next you can use globals() and vars() which can get and create the values of variables to do

vars()[command[2]] = globals()[command[3]]

and you'll see that if you check the variable now named newTestVarit should be set to the value of oldTestVar

0

You can use eval() and do something like this:

formatter = lambda text: eval(f'f"""{text}"""')
ap_name = 'AP NAME'  # Example data
old_ap_name = 'OLD AP NAME'  # More example data

user_defined_command_input = 'config ap {ap_name}{old_ap_name}'
print(formatter(user_defined_command_input))

Output: config ap AP NAMEOLD AP NAME

But as you have mentioned, be careful with injection like this. It can be quite dangerous.

VoidTwo
  • 569
  • 1
  • 7
  • 26
  • I appreciate your response. the thing is `ap_name` can be `ap_serial` or `ap_mac` so I wouldn't be able to hardcode what the variable name is which is what I'm trying to solve. the string inside the curly brackets within the command they make should be anything they want it to be. I'm just not sure how to go about that without having to hardcode what the name of the variables. They could have 2 variables, 4 variables, they could be unrelated names, etc... – James Nov 12 '20 at 20:04
0

It's not clear to me what exactly you're asking, but here's a guess based on the accepted answer to How to postpone/defer the evaluation of f-strings?:

import inspect

class MagicFstring:
    def __init__(self, payload):
        self.payload = payload
    def __str__(self):
        vars = inspect.currentframe().f_back.f_globals.copy()
        vars.update(inspect.currentframe().f_back.f_locals)
        return self.payload.format(**vars)


user_defined_command_input = MagicFstring("config ap {ap_name} {old_ap_name}")

ap_name = 'someapp'
old_ap_name = 'oldapp'

print(user_defined_command_input)  # -> config ap someapp oldapp
martineau
  • 119,623
  • 25
  • 170
  • 301
0

Use .format()

user_defined_command = "config ap {ap_name} {old_ap_name}"
user_defined_variables = {"ap_name": "freewifi", "old_ap_name": "wifi"}

command = user_defined_command.format(**user_defined_variables)
# command == "config ap freewifi wifi"

Do not ever trust user input though! Always sanitize their input and use a whitelist of allowed values/characters. Arbitrary command injections are a huge deal and can negate any other security you have in place.

Also, in my honest opinion it would be best to reconsider implementing this, as it is very hard to get right.

JanLikar
  • 1,296
  • 9
  • 22
  • This was the answer I was looking for. In fact I'm a little dissapointed in myself as I had already thought about this and figured there would a more streamlined method. As for your security concerns, this would be in house. If there were another method to implement this without the security concern I'd do it. If you have an alternative or sanitized method I'm all ears. I'll likely validate the data to ensure the max number of chars is less than 25 or something like that. I feel that would lower the security risk. Thank you. – James Nov 12 '20 at 21:37