From cc842c316d0ea896c977bc71b991ac0331300449 Mon Sep 17 00:00:00 2001 From: Kevin Ushey Date: Wed, 28 Apr 2021 16:29:00 -0700 Subject: [PATCH 1/4] add 'key' parameter to askForSecret --- R/dialogs.R | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/R/dialogs.R b/R/dialogs.R index deaf4fb..1b99a73 100644 --- a/R/dialogs.R +++ b/R/dialogs.R @@ -89,6 +89,10 @@ showQuestion <- function(title, message, ok = NULL, cancel = NULL) { #' #' @param title The title to display in the dialog box. #' +#' @param key An optional key. When provided, RStudio will check to see if +#' an environment variable of the name `RSTUDIOAPI_SECRET_` is defined; +#' if so, that environment variable will be used to supply the secret. +#' #' @note The \code{askForSecret} function was added in version 1.1.419 of #' RStudio. #' @@ -96,7 +100,27 @@ showQuestion <- function(title, message, ok = NULL, cancel = NULL) { askForSecret <- function( name, message = paste(name, ":", sep = ""), - title = paste(name, "Secret")) { + title = paste(name, "Secret"), + key = NULL) { + + if (!is.null(key)) { + + # build full name of environment variable + name <- paste("RSTUDIOAPI_SECRET", toupper(key), sep = "_") + + # check for a definition + value <- Sys.getenv(name, unset = NA) + if (!is.na(value)) + return(value) + + # for non-interactive sessions, give a warning; otherwise, + # fall through an attempt to ask for a password + if (!interactive() && !isChildProcess()) { + fmt <- "The environment variable '%s' is required by this application, but is unset." + msg <- sprintf(fmt, name) + warning(msg) + } + } if (hasFun("askForSecret") || isChildProcess()) { callFun("askForSecret", name, title, message) From 6d960444479e6a5311f9aaff926da0d5e297f8d2 Mon Sep 17 00:00:00 2001 From: Kevin Ushey Date: Fri, 30 Apr 2021 09:58:58 -0700 Subject: [PATCH 2/4] add 'key' to askForPassword as well --- R/dialogs.R | 56 ----------------------- R/secrets.R | 102 ++++++++++++++++++++++++++++++++++++++++++ R/stubs.R | 26 ----------- man/askForPassword.Rd | 10 ++++- man/askForSecret.Rd | 11 ++++- 5 files changed, 119 insertions(+), 86 deletions(-) create mode 100644 R/secrets.R diff --git a/R/dialogs.R b/R/dialogs.R index 1b99a73..89ca224 100644 --- a/R/dialogs.R +++ b/R/dialogs.R @@ -73,59 +73,3 @@ showPrompt <- function(title, message, default = NULL) { showQuestion <- function(title, message, ok = NULL, cancel = NULL) { callFun("showQuestion", title, message, ok, cancel) } - - - -#' Prompt user for secret -#' -#' Request a secret from the user. If the `keyring` package is installed, it -#' will be used to cache requested secrets. -#' -#' -#' @param name The name of the secret. -#' -#' @param message A character vector with the contents to display in the main -#' dialog area. -#' -#' @param title The title to display in the dialog box. -#' -#' @param key An optional key. When provided, RStudio will check to see if -#' an environment variable of the name `RSTUDIOAPI_SECRET_` is defined; -#' if so, that environment variable will be used to supply the secret. -#' -#' @note The \code{askForSecret} function was added in version 1.1.419 of -#' RStudio. -#' -#' @export -askForSecret <- function( - name, - message = paste(name, ":", sep = ""), - title = paste(name, "Secret"), - key = NULL) { - - if (!is.null(key)) { - - # build full name of environment variable - name <- paste("RSTUDIOAPI_SECRET", toupper(key), sep = "_") - - # check for a definition - value <- Sys.getenv(name, unset = NA) - if (!is.na(value)) - return(value) - - # for non-interactive sessions, give a warning; otherwise, - # fall through an attempt to ask for a password - if (!interactive() && !isChildProcess()) { - fmt <- "The environment variable '%s' is required by this application, but is unset." - msg <- sprintf(fmt, name) - warning(msg) - } - } - - if (hasFun("askForSecret") || isChildProcess()) { - callFun("askForSecret", name, title, message) - } else { - askForPassword(message) - } - -} diff --git a/R/secrets.R b/R/secrets.R new file mode 100644 index 0000000..d5db0c4 --- /dev/null +++ b/R/secrets.R @@ -0,0 +1,102 @@ + +# returns the secret associated with a key 'key', or NULL +# if no secret is available +retrieveSecret <- function(key, label) { + + if (is.null(key)) + return(NULL) + + # build full name of environment variable + name <- paste("RSTUDIOAPI_SECRET", toupper(key), sep = "_") + + # check for a definition + value <- Sys.getenv(name, unset = NA) + if (!is.na(value)) + return(value) + + # for non-interactive sessions, give a warning; otherwise, + # fall through an attempt to ask for a password + if (!interactive() && !isChildProcess()) { + fmt <- "The %s associated with key '%s' is not set or could not be retrieved." + msg <- sprintf(fmt, label, key) + warning(msg) + } + +} + +#' Ask the user for a password interactively +#' +#' Ask the user for a password interactively. +#' +#' RStudio also sets the global \code{askpass} option to the +#' \code{rstudioapi::askForPassword} function so that it can be invoked in a +#' front-end independent manner. +#' +#' @param prompt The prompt to be shown to the user. +#' +#' @param key An optional key. When provided, RStudio will check to see if +#' an environment variable of the name `RSTUDIOAPI_SECRET_` is defined; +#' if so, that environment variable will be used to supply the password. +#' If the variable is unset, then (in interactive sessions) the user will +#' be prompted for a password; otherwise, a warning will be shown. +#' +#' @note The \code{askForPassword} function was added in version 0.99.853 of +#' RStudio. +#' +#' @examples +#' +#' \dontrun{ +#' rstudioapi::askForPassword("Please enter your password") +#' } +#' +#' @export askForPassword +askForPassword <- function(prompt = "Please enter your password", + key = NULL) +{ + password <- retrieveSecret(key, "password") + if (!is.null(password)) + return(password) + + callFun("askForPassword", prompt) +} + +#' Prompt user for secret +#' +#' Request a secret from the user. If the `keyring` package is installed, it +#' will be used to cache requested secrets. +#' +#' @param name The name of the secret. +#' +#' @param message A character vector with the contents to display in the main +#' dialog area. +#' +#' @param title The title to display in the dialog box. +#' +#' @param key An optional key. When provided, RStudio will check to see if +#' an environment variable of the name `RSTUDIOAPI_SECRET_` is defined; +#' if so, that environment variable will be used to supply the secret. +#' If the variable is unset, then (in interactive sessions) the user will +#' be prompted for a password; otherwise, a warning will be shown. +#' +#' @note The \code{askForSecret} function was added in version 1.1.419 of +#' RStudio. +#' +#' @export +askForSecret <- function( + name, + message = paste(name, ":", sep = ""), + title = paste(name, "Secret"), + key = NULL) { + + secret <- retrieveSecret(key, "secret") + if (!is.null(secret)) + return(secret) + + # use 'askForSecret' if available + if (hasFun("askForSecret") || isChildProcess()) + return(callFun("askForSecret", name, title, message)) + + # otherwise, fall back to askForPassword + askForPassword(message) + +} diff --git a/R/stubs.R b/R/stubs.R index 4eb717a..cc7fc55 100644 --- a/R/stubs.R +++ b/R/stubs.R @@ -249,32 +249,6 @@ navigateToFile <- function(file = character(0), } -#' Ask the user for a password interactively -#' -#' Ask the user for a password interactively. -#' -#' RStudio also sets the global \code{askpass} option to the -#' \code{rstudioapi::askForPassword} function so that it can be invoked in a -#' front-end independent manner. -#' -#' @param prompt The prompt to be shown to the user. -#' -#' @note The \code{askForPassword} function was added in version 0.99.853 of -#' RStudio. -#' -#' @examples -#' -#' \dontrun{ -#' rstudioapi::askForPassword("Please enter your password") -#' } -#' -#' @export askForPassword -askForPassword <- function(prompt = "Please enter your password") { - callFun("askForPassword", prompt) -} - - - #' Retrieve path to active RStudio project #' #' Get the path to the active RStudio project (if any). If the path contains diff --git a/man/askForPassword.Rd b/man/askForPassword.Rd index dc280ef..1e23f98 100644 --- a/man/askForPassword.Rd +++ b/man/askForPassword.Rd @@ -1,13 +1,19 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/stubs.R +% Please edit documentation in R/secrets.R \name{askForPassword} \alias{askForPassword} \title{Ask the user for a password interactively} \usage{ -askForPassword(prompt = "Please enter your password") +askForPassword(prompt = "Please enter your password", key = NULL) } \arguments{ \item{prompt}{The prompt to be shown to the user.} + +\item{key}{An optional key. When provided, RStudio will check to see if +an environment variable of the name \verb{RSTUDIOAPI_SECRET_} is defined; +if so, that environment variable will be used to supply the password. +If the variable is unset, then (in interactive sessions) the user will +be prompted for a password; otherwise, a warning will be shown.} } \description{ Ask the user for a password interactively. diff --git a/man/askForSecret.Rd b/man/askForSecret.Rd index bf5dde8..a95cd81 100644 --- a/man/askForSecret.Rd +++ b/man/askForSecret.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/dialogs.R +% Please edit documentation in R/secrets.R \name{askForSecret} \alias{askForSecret} \title{Prompt user for secret} @@ -7,7 +7,8 @@ askForSecret( name, message = paste(name, ":", sep = ""), - title = paste(name, "Secret") + title = paste(name, "Secret"), + key = NULL ) } \arguments{ @@ -17,6 +18,12 @@ askForSecret( dialog area.} \item{title}{The title to display in the dialog box.} + +\item{key}{An optional key. When provided, RStudio will check to see if +an environment variable of the name \verb{RSTUDIOAPI_SECRET_} is defined; +if so, that environment variable will be used to supply the secret. +If the variable is unset, then (in interactive sessions) the user will +be prompted for a password; otherwise, a warning will be shown.} } \description{ Request a secret from the user. If the \code{keyring} package is installed, it From 88f924ef13f8bd6aaecff92bce28fe742201193b Mon Sep 17 00:00:00 2001 From: Nathan Stephens Date: Mon, 10 May 2021 14:49:42 -0700 Subject: [PATCH 3/4] changed 'key' to 'getenv'. removed 'toupper'. --- R/secrets.R | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/R/secrets.R b/R/secrets.R index d5db0c4..d540e01 100644 --- a/R/secrets.R +++ b/R/secrets.R @@ -1,13 +1,13 @@ -# returns the secret associated with a key 'key', or NULL +# returns the secret associated with a getenv 'getenv', or NULL # if no secret is available -retrieveSecret <- function(key, label) { +retrieveSecret <- function(getenv, label) { - if (is.null(key)) + if (is.null(getenv)) return(NULL) # build full name of environment variable - name <- paste("RSTUDIOAPI_SECRET", toupper(key), sep = "_") + name <- paste("RSTUDIOAPI_SECRET", getenv, sep = "_") # check for a definition value <- Sys.getenv(name, unset = NA) @@ -17,8 +17,8 @@ retrieveSecret <- function(key, label) { # for non-interactive sessions, give a warning; otherwise, # fall through an attempt to ask for a password if (!interactive() && !isChildProcess()) { - fmt <- "The %s associated with key '%s' is not set or could not be retrieved." - msg <- sprintf(fmt, label, key) + fmt <- "The %s associated with getenv '%s' is not set or could not be retrieved." + msg <- sprintf(fmt, label, getenv) warning(msg) } @@ -34,8 +34,8 @@ retrieveSecret <- function(key, label) { #' #' @param prompt The prompt to be shown to the user. #' -#' @param key An optional key. When provided, RStudio will check to see if -#' an environment variable of the name `RSTUDIOAPI_SECRET_` is defined; +#' @param getenv An optional getenv. When provided, RStudio will check to see if +#' an environment variable of the name `RSTUDIOAPI_SECRET_` is defined; #' if so, that environment variable will be used to supply the password. #' If the variable is unset, then (in interactive sessions) the user will #' be prompted for a password; otherwise, a warning will be shown. @@ -51,9 +51,9 @@ retrieveSecret <- function(key, label) { #' #' @export askForPassword askForPassword <- function(prompt = "Please enter your password", - key = NULL) + getenv = NULL) { - password <- retrieveSecret(key, "password") + password <- retrieveSecret(getenv, "password") if (!is.null(password)) return(password) @@ -62,7 +62,7 @@ askForPassword <- function(prompt = "Please enter your password", #' Prompt user for secret #' -#' Request a secret from the user. If the `keyring` package is installed, it +#' Request a secret from the user. If the `getenvring` package is installed, it #' will be used to cache requested secrets. #' #' @param name The name of the secret. @@ -72,8 +72,8 @@ askForPassword <- function(prompt = "Please enter your password", #' #' @param title The title to display in the dialog box. #' -#' @param key An optional key. When provided, RStudio will check to see if -#' an environment variable of the name `RSTUDIOAPI_SECRET_` is defined; +#' @param getenv An optional getenv. When provided, RStudio will check to see if +#' an environment variable of the name `RSTUDIOAPI_SECRET_` is defined; #' if so, that environment variable will be used to supply the secret. #' If the variable is unset, then (in interactive sessions) the user will #' be prompted for a password; otherwise, a warning will be shown. @@ -86,9 +86,9 @@ askForSecret <- function( name, message = paste(name, ":", sep = ""), title = paste(name, "Secret"), - key = NULL) { + getenv = NULL) { - secret <- retrieveSecret(key, "secret") + secret <- retrieveSecret(getenv, "secret") if (!is.null(secret)) return(secret) From 8b45d0e5e9b2f5d39b21da498904e78cde67b334 Mon Sep 17 00:00:00 2001 From: Nathan Stephens Date: Mon, 10 May 2021 14:57:18 -0700 Subject: [PATCH 4/4] changed 'key' to 'getenv' in the docs. changed the error message for Connect. --- R/secrets.R | 2 +- man/askForPassword.Rd | 6 +++--- man/askForSecret.Rd | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/R/secrets.R b/R/secrets.R index d540e01..c12bea5 100644 --- a/R/secrets.R +++ b/R/secrets.R @@ -17,7 +17,7 @@ retrieveSecret <- function(getenv, label) { # for non-interactive sessions, give a warning; otherwise, # fall through an attempt to ask for a password if (!interactive() && !isChildProcess()) { - fmt <- "The %s associated with getenv '%s' is not set or could not be retrieved." + fmt <- "The %s associated with 'RSTUDIOAPI_SECRET_%s' is not set or could not be retrieved." msg <- sprintf(fmt, label, getenv) warning(msg) } diff --git a/man/askForPassword.Rd b/man/askForPassword.Rd index 1e23f98..bf7de16 100644 --- a/man/askForPassword.Rd +++ b/man/askForPassword.Rd @@ -4,13 +4,13 @@ \alias{askForPassword} \title{Ask the user for a password interactively} \usage{ -askForPassword(prompt = "Please enter your password", key = NULL) +askForPassword(prompt = "Please enter your password", getenv = NULL) } \arguments{ \item{prompt}{The prompt to be shown to the user.} -\item{key}{An optional key. When provided, RStudio will check to see if -an environment variable of the name \verb{RSTUDIOAPI_SECRET_} is defined; +\item{getenv}{An optional getenv. When provided, RStudio will check to see if +an environment variable of the name \verb{RSTUDIOAPI_SECRET_} is defined; if so, that environment variable will be used to supply the password. If the variable is unset, then (in interactive sessions) the user will be prompted for a password; otherwise, a warning will be shown.} diff --git a/man/askForSecret.Rd b/man/askForSecret.Rd index a95cd81..f123b36 100644 --- a/man/askForSecret.Rd +++ b/man/askForSecret.Rd @@ -8,7 +8,7 @@ askForSecret( name, message = paste(name, ":", sep = ""), title = paste(name, "Secret"), - key = NULL + getenv = NULL ) } \arguments{ @@ -19,14 +19,14 @@ dialog area.} \item{title}{The title to display in the dialog box.} -\item{key}{An optional key. When provided, RStudio will check to see if -an environment variable of the name \verb{RSTUDIOAPI_SECRET_} is defined; +\item{getenv}{An optional getenv. When provided, RStudio will check to see if +an environment variable of the name \verb{RSTUDIOAPI_SECRET_} is defined; if so, that environment variable will be used to supply the secret. If the variable is unset, then (in interactive sessions) the user will be prompted for a password; otherwise, a warning will be shown.} } \description{ -Request a secret from the user. If the \code{keyring} package is installed, it +Request a secret from the user. If the \code{getenvring} package is installed, it will be used to cache requested secrets. } \note{