I am using glue()
to format strings. Ideally I would like to give the user the option to provide his own, potentially complex formatting patterns. These will usually be distributed as part of a yaml config file, which also contains many other settings.
library(glue)
df <- tibble(a = c(70,80,90,4,5), conversionunit = c(60,60,60,1,1))
pattern <- "{a/conversionunit} minutes" # loaded from user's config file
df <- df %>% mutate(output = glue(pattern))
# more complex alternative
pattern <- "{round(a/conversionunit, digits=2)} minutes" # loaded from user's config file
df <- df %>% mutate(output = glue(pattern))
However, there is a security risk since glue
statements may execute arbitrary code. The example here below is benign of course. The risk is developed because it will be likely that users download and use complex config files without studying them in detail, and a bad actor may distribute evil config files.
pattern <- "{shell('echo 1', intern = TRUE)} {a}"
df <- df %>% mutate(output = glue(pattern))
I am aware of glue_safe
however this is more restrictive than I want. Ideally I want to provide a list of allowed functions
safe_fun <- list(`*` = `*`, `/` = `/`, "round" = round) %>% as.environment() # etc
and allow only the use of those specified ones. Is there any way to do this?
Define the environment to hold the data and functions and set its parent to emptyenv()
.
library(glue)
library(tibble) # lst
safe_fun <- lst(`*`, `/`, round)
safe_env <- list2env(c(df, safe_fun), parent = emptyenv())
# test 1
glue("{a/conversionunit} minutes", .envir = safe_env)
## 1.16666666666667 minutes
## 1.33333333333333 minutes
## 1.5 minutes
## 4 minutes
## 5 minutes
# test 2
glue("{sqrt(a)/conversionunit} minutes", .envir = safe_env)
## Error in sqrt(a) : could not find function "sqrt"