├── .gitignore ├── LICENSE ├── NAMESPACE ├── inst └── rstudio │ └── addins.dcf ├── .travis.yml ├── .Rbuildignore ├── R ├── zzz.R ├── proxy.R ├── password.R ├── check.R └── set.R ├── codecov.yml ├── tests ├── testthat.R └── testthat │ ├── helper-dummy-vars.R │ ├── test-proxy.R │ ├── test-zzz.R │ ├── test-check.R │ └── test-set.R ├── azure-pipelines.yml ├── proxyconfig.Rproj ├── man ├── check_proxy.Rd ├── read_password.Rd ├── is_proxy_activated.Rd ├── build_http_env.Rd ├── unset_proxy.Rd └── set_proxy.Rd ├── DESCRIPTION ├── LICENSE.md ├── README.md └── README.Rmd /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | README.html 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2019 2 | COPYRIGHT HOLDER: Christophe Dervieux 3 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(is_proxy_activated) 4 | export(set_proxy) 5 | export(unset_proxy) 6 | -------------------------------------------------------------------------------- /inst/rstudio/addins.dcf: -------------------------------------------------------------------------------- 1 | Name: Activate Proxy 2 | Description: Configure proxy and activate proxy 3 | Binding: set_proxy 4 | Interactive: false 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # R for travis: see documentation at https://docs.travis-ci.com/user/languages/r 2 | 3 | language: R 4 | cache: packages 5 | 6 | after_success: 7 | - Rscript -e 'covr::codecov()' 8 | -------------------------------------------------------------------------------- /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^LICENSE\.md$ 4 | ^\.travis\.yml$ 5 | ^README\.Rmd$ 6 | ^README\.html$ 7 | ^codecov\.yml$ 8 | ^proxyconfig\.yml$ 9 | ^azure-pipelines\.yml$ 10 | -------------------------------------------------------------------------------- /R/zzz.R: -------------------------------------------------------------------------------- 1 | # check username 2 | check_username <- function(username, regex = ".*", msg = "incorrect username format") { 3 | if (!grepl(regex, username)) { 4 | stop(msg, call. = F) 5 | } 6 | invisible(TRUE) 7 | } 8 | 9 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: false 2 | 3 | coverage: 4 | status: 5 | project: 6 | default: 7 | target: auto 8 | threshold: 1% 9 | patch: 10 | default: 11 | target: auto 12 | threshold: 1% 13 | -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library(proxyconfig) 3 | 4 | if (requireNamespace("xml2")) { 5 | test_check("proxyconfig", reporter = MultiReporter$new(reporters = list(JunitReporter$new(file = "test-results.xml"), CheckReporter$new()))) 6 | } else { 7 | test_check("proxyconfig") 8 | } 9 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | # R package 2 | # Test an R package 3 | 4 | resources: 5 | repositories: 6 | - repository: r-azure-pipelines 7 | type: github 8 | name: r-lib/r-azure-pipelines 9 | endpoint: github_con 10 | 11 | jobs: 12 | - template: azure-tidyverse.yml@r-azure-pipelines 13 | -------------------------------------------------------------------------------- /tests/testthat/helper-dummy-vars.R: -------------------------------------------------------------------------------- 1 | dummy_proxy_url <- "http://user:pwd@proxy.info:5656" 2 | 3 | dummy_env_var_lc <- c(http_proxy = dummy_proxy_url, 4 | https_proxy = dummy_proxy_url, 5 | no_proxy = ".dummy.domain") 6 | 7 | dummy_env_var_uc <- purrr::set_names(dummy_env_var_lc, toupper(names(dummy_env_var_lc))) 8 | 9 | dummy_env_var <- c(dummy_env_var_uc, dummy_env_var_lc) 10 | -------------------------------------------------------------------------------- /proxyconfig.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: No 4 | SaveWorkspace: No 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source 21 | PackageRoxygenize: rd,collate,namespace 22 | -------------------------------------------------------------------------------- /R/proxy.R: -------------------------------------------------------------------------------- 1 | #' Check if proxy url is valid 2 | #' 3 | #' Checked against perl regex `"^http(s)?://[a-zA-Z0-9\\.-]+(:[0-9]+)?$"` 4 | #' 5 | #' @param proxy a character 6 | #' 7 | #' @return `TRUE` if proxy is valide 8 | #' @keywords internal 9 | #' @examples 10 | #' \dontrun{ 11 | #' check_proxy("http://10.132.23.444:3232") 12 | #' } 13 | check_proxy <- function(proxy) { 14 | if (length(proxy) == 0) return(FALSE) 15 | # check for 16 | grepl("^http(s)?://[a-zA-Z0-9\\.-]+(:[0-9]+)?$", proxy, perl = TRUE) 17 | } 18 | 19 | -------------------------------------------------------------------------------- /man/check_proxy.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/proxy.R 3 | \name{check_proxy} 4 | \alias{check_proxy} 5 | \title{Check if proxy url is valid} 6 | \usage{ 7 | check_proxy(proxy) 8 | } 9 | \arguments{ 10 | \item{proxy}{a character} 11 | } 12 | \value{ 13 | \code{TRUE} if proxy is valide 14 | } 15 | \description{ 16 | Checked against perl regex \code{"^http(s)?://[a-zA-Z0-9\\.-]+(:[0-9]+)?$"} 17 | } 18 | \examples{ 19 | \dontrun{ 20 | check_proxy("http://10.132.23.444:3232") 21 | } 22 | } 23 | \keyword{internal} 24 | -------------------------------------------------------------------------------- /man/read_password.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/password.R 3 | \name{read_password} 4 | \alias{read_password} 5 | \title{Ask interactively for authentification} 6 | \usage{ 7 | read_password(prompt) 8 | } 9 | \arguments{ 10 | \item{prompt}{text prompt to user} 11 | } 12 | \value{ 13 | \emph{invisibly} the input of the user 14 | } 15 | \description{ 16 | This will use if available in this order 17 | \itemize{ 18 | \item RStudio IDE prompt 19 | \item Console input 20 | } 21 | } 22 | \examples{ 23 | if (interactive()) { 24 | pwd <- read_password("password") 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/testthat/test-proxy.R: -------------------------------------------------------------------------------- 1 | context("test-proxy.R") 2 | 3 | test_that("check proxy argument for correct format", { 4 | expect_equal(check_proxy("http://10.132.23"), TRUE) 5 | expect_equal(check_proxy("https://10#132+23"), FALSE) 6 | expect_equal(check_proxy("http://10.132.23.444:32"), TRUE) 7 | expect_equal(check_proxy("http:/10.132.23.444:32"), FALSE) 8 | expect_equal(check_proxy("10.132.23.444:32"), FALSE) 9 | expect_equal(check_proxy("http://10.132.23.444:hu"), FALSE) 10 | expect_equal(check_proxy("https://proxy-url.com:64"), TRUE) 11 | expect_equal(check_proxy("http://proxy-url.com#64"), FALSE) 12 | }) 13 | -------------------------------------------------------------------------------- /man/is_proxy_activated.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/check.R 3 | \name{is_proxy_activated} 4 | \alias{is_proxy_activated} 5 | \title{Verify if a proxy is configured} 6 | \usage{ 7 | is_proxy_activated(verbose = FALSE) 8 | } 9 | \arguments{ 10 | \item{verbose}{if \code{TRUE} will print a summary of configuration. Authentification 11 | is redacted for printing} 12 | } 13 | \value{ 14 | \code{TRUE} is a proxy is configured. \code{FALSE} otherwise. 15 | } 16 | \description{ 17 | This checks for any set environment variable relevant to proxy 18 | } 19 | \examples{ 20 | \dontrun{ 21 | is_proxy_activated(verbose = TRUE) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /R/password.R: -------------------------------------------------------------------------------- 1 | #' Ask interactively for authentification 2 | #' 3 | #' This will use if available in this order 4 | #' + RStudio IDE prompt 5 | #' + Console input 6 | #' 7 | #' @param prompt text prompt to user 8 | #' 9 | #' @return _invisibly_ the input of the user 10 | #' @examples 11 | #' if (interactive()) { 12 | #' pwd <- read_password("password") 13 | #' } 14 | read_password <- function(prompt) { 15 | if (requireNamespace("rstudioapi", quietly = TRUE)) { 16 | pwd <- rstudioapi::askForPassword(prompt) 17 | } else { 18 | pwd <- readline(prompt) 19 | } 20 | if (is.null(pwd)) { 21 | message("Cancelled operation") 22 | return(NULL) 23 | } 24 | invisible(pwd) 25 | } 26 | -------------------------------------------------------------------------------- /man/build_http_env.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/set.R 3 | \name{build_http_env} 4 | \alias{build_http_env} 5 | \title{Build proxy url with authentification} 6 | \usage{ 7 | build_http_env(proxy, username, password) 8 | } 9 | \arguments{ 10 | \item{proxy}{character. Proxy url} 11 | 12 | \item{username}{character} 13 | 14 | \item{password}{character} 15 | } 16 | \value{ 17 | proxy url with username and password 18 | } 19 | \description{ 20 | Build proxy url as \code{http://username:password@proxy-url.com:port} 21 | } 22 | \examples{ 23 | \dontrun{ 24 | build_http_env("http://proxy-url.com:3232", "its", "me") 25 | } 26 | } 27 | \keyword{internal} 28 | -------------------------------------------------------------------------------- /tests/testthat/test-zzz.R: -------------------------------------------------------------------------------- 1 | context("test-zzz.R") 2 | 3 | test_that("check_username is TRUE is no regex provided", { 4 | random <- c(letters, LETTERS, 1:9) 5 | username <- paste0(sample(random, sample.int(10), replace = TRUE), collapse = "") 6 | expect_true(check_username(username)) 7 | }) 8 | 9 | test_that("check_username handles error when regex provided", { 10 | # no error if correct format 11 | expect_true(check_username("A87987", "^[A-Z][0-9]{5}$")) 12 | # default message 13 | expect_error(check_username("AB8799", "^[A-Z][0-9]{5}$"), "incorrect username format") 14 | # error with custom message 15 | msg <- "username should be one uppercase letter followed by 5 integer" 16 | expect_error(check_username("AB8799", "^[A-Z][0-9]{5}$", msg), msg) 17 | }) 18 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: proxyconfig 2 | Title: Tools to Configure Proxy Interactively 3 | Version: 0.0.0.9002 4 | Authors@R: 5 | person(given = "Christophe", 6 | family = "Dervieux", 7 | role = c("aut", "cre"), 8 | email = "christophe.dervieux@gmail.com") 9 | Description: Helpers functions and Rstudio Addins to help 10 | configure proxy more easily. 11 | License: MIT + file LICENSE 12 | URL: https://github.com/cderv/proxyconfig 13 | BugReports: https://github.com/cderv/proxyconfig/issues 14 | Imports: 15 | glue, 16 | purrr, 17 | httr 18 | Suggests: 19 | testthat, 20 | withr, 21 | covr, 22 | rstudioapi, 23 | xml2 24 | ByteCompile: true 25 | Encoding: UTF-8 26 | LazyData: true 27 | Roxygen: list(markdown = TRUE) 28 | RoxygenNote: 6.0.1 29 | -------------------------------------------------------------------------------- /man/unset_proxy.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/set.R 3 | \name{unset_proxy} 4 | \alias{unset_proxy} 5 | \title{Unset proxy configuration for the session} 6 | \usage{ 7 | unset_proxy(verbose = FALSE) 8 | } 9 | \arguments{ 10 | \item{verbose}{default is \code{FALSE}.} 11 | } 12 | \value{ 13 | \code{FALSE} is no proxy configuration was set before. \code{TRUE} if 14 | configuration is unset with success. 15 | } 16 | \description{ 17 | This fonction is a helper to unset all configuration of proxy for the current 18 | session. 19 | } 20 | \examples{ 21 | \dontrun{ 22 | set_proxy(proxy = "http://10.132.23.444:3232", 23 | username = "", 24 | password = "", 25 | noproxy = ".mycompany.com", 26 | https = TRUE) 27 | is_proxy_activated(verbose = TRUE) 28 | unset_proxy(verbose = TRUE) 29 | is_proxy_activated(verbose = TRUE) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/testthat/test-check.R: -------------------------------------------------------------------------------- 1 | context("test-check.R") 2 | 3 | test_that("proxy environement variable are not set", { 4 | withr::with_envvar( 5 | c(http_proxy = NA, https_proxy = NA, no_proxy = NA), 6 | expect_false(is_proxy_activated(FALSE)) 7 | ) 8 | withr::with_envvar( 9 | c(http_proxy = dummy_proxy_url, https_proxy = NA, no_proxy = NA), 10 | expect_true(is_proxy_activated(FALSE)) 11 | ) 12 | }) 13 | 14 | test_that("proxy environment variable are set", { 15 | withr::with_envvar( 16 | c(http_proxy = dummy_proxy_url, https_proxy = dummy_proxy_url, no_proxy = ".dummy.domain"), 17 | { 18 | expect_true(is_proxy_activated(FALSE)) 19 | expect_message(is_proxy_activated(TRUE)) 20 | } 21 | ) 22 | }) 23 | 24 | test_that("hide username and password when printing", { 25 | expect_identical(redacted_proxy_url("https://its:me@user.com:3434/"), "https://***:***@user.com:3434/") 26 | expect_identical(redacted_proxy_url("https://user.com:3434/"), "https://user.com:3434/") 27 | }) 28 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) 2019 Christophe Dervieux 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /R/check.R: -------------------------------------------------------------------------------- 1 | #' Verify if a proxy is configured 2 | #' 3 | #' This checks for any set environment variable relevant to proxy 4 | #' 5 | #' @param verbose if `TRUE` will print a summary of configuration. Authentification 6 | #' is redacted for printing 7 | #' 8 | #' @return `TRUE` is a proxy is configured. `FALSE` otherwise. 9 | #' 10 | #' @examples 11 | #' \dontrun{ 12 | #' is_proxy_activated(verbose = TRUE) 13 | #' } 14 | #' @export 15 | is_proxy_activated <- function(verbose = FALSE) { 16 | proxy_env <- c("HTTP_PROXY", "HTTPS_PROXY", "NO_PROXY") 17 | # use also http_proxy, https_proxy and no_proxy 18 | proxy_env <- c(proxy_env, tolower(proxy_env)) 19 | set_proxy_env <- purrr::set_names(purrr::map(proxy_env, Sys.getenv, unset = NA_character_), proxy_env) 20 | all_empty <- purrr::map_lgl(set_proxy_env, ~ identical(.x, NA_character_)) 21 | if (all(all_empty)) return(FALSE) 22 | if (verbose) { 23 | # filter http env proxy from no_proxy 24 | http_env <- grepl("^HTTP", names(set_proxy_env), ignore.case = TRUE) 25 | # hide username and password 26 | http_env_redacted <- purrr::modify_if(set_proxy_env, http_env, redacted_proxy_url) 27 | msg <- glue::glue(" 28 | **** Proxy info 29 | HTTP_PROXY: {HTTP_PROXY} 30 | HTTPS_PROXY: {HTTPS_PROXY} 31 | NO_PROXY: {NO_PROXY} 32 | http_proxy: {http_proxy} 33 | https_proxy: {https_proxy} 34 | no_proxy: {no_proxy} 35 | **** 36 | ", 37 | .envir = http_env_redacted, 38 | .na = "", .sep = "\n") 39 | message(msg) 40 | } 41 | TRUE 42 | } 43 | 44 | # when printing proxy, redact auth with three star 45 | redacted_proxy_url <- function(proxy_url) { 46 | parsed_url <- httr::parse_url(proxy_url) 47 | parsed_url$username <- if (!is.null(parsed_url$username)) "***" 48 | parsed_url$password <- if (!is.null(parsed_url$password)) "***" 49 | httr::build_url(parsed_url) 50 | } 51 | -------------------------------------------------------------------------------- /man/set_proxy.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/set.R 3 | \name{set_proxy} 4 | \alias{set_proxy} 5 | \title{Configure the proxy for internet connection} 6 | \usage{ 7 | set_proxy(proxy = getOption("proxyconfig.proxy", default = NA_character_), 8 | username = NULL, password = NULL, noproxy = NULL, https = TRUE) 9 | } 10 | \arguments{ 11 | \item{proxy}{a character giving the proxy url. By default, it will fetch for 12 | option \code{proxyconfig.proxy} that can be set accross sessions in 13 | \emph{.Rprofile} or \emph{Rprofile.site}.} 14 | 15 | \item{username}{character. If \code{NULL}, user will be prompted} 16 | 17 | \item{password}{character. If \code{NULL}, user will be prompted} 18 | 19 | \item{noproxy}{character vector of domain that proxy should ignore} 20 | 21 | \item{https}{logical. If \code{TRUE} \emph{HTTPS_PROXY} will be used} 22 | } 23 | \value{ 24 | \code{TRUE} \emph{invisibly} if no error. Side effects are the environment 25 | variables for proxy being set for the session. You can check them with 26 | \code{\link[base:Sys.getenv]{base::Sys.getenv()}} 27 | 28 | \code{FALSE} \emph{invisibly} with a warning if a proxy configuration was already set. You need 29 | to unset the configuration with \code{\link[=unset_proxy]{unset_proxy()}} before setting a new one. 30 | } 31 | \description{ 32 | this will help to set up the proxy configuration using 33 | environment variable 34 | \itemize{ 35 | \item url of the proxy with port 36 | \item authentification if necessary (username and password) 37 | \item any domain that proxy should ignore 38 | \item activate or not https proxy 39 | } 40 | 41 | You can set a proxy url across sessions by setting option \code{"proxyconfig.proxy"}. 42 | } 43 | \section{Proxy Environment Variable}{ 44 | 45 | 46 | The proxy is set using environment variables 47 | \itemize{ 48 | \item \code{HTTP_PROXY} 49 | \item \code{HTTPS_PROXY} 50 | \item \code{NO_PROXY} 51 | The lower case version are also set because some utilities do not understand 52 | upper case environment variable. 53 | } 54 | 55 | This configuration is used by \code{curl} for internet connection and other 56 | \emph{method}. See \emph{Setting Proxies} in \code{\link[utils:download.file]{utils::download.file()}} 57 | } 58 | 59 | \examples{ 60 | \dontrun{ 61 | set_proxy(proxy = "http://10.132.23.444:3232", 62 | username = "", 63 | password = "", 64 | noproxy = ".mycompany.com", 65 | https = TRUE) 66 | is_proxy_activated(verbose = TRUE) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /tests/testthat/test-set.R: -------------------------------------------------------------------------------- 1 | context("test-set.R") 2 | 3 | test_that("set_proxy stop if wrong proxy", { 4 | unset_proxy() 5 | expect_error(set_proxy()) 6 | unset_proxy() 7 | # expect_error(set_proxy(proxy = NULL)) 8 | # unset_proxy() 9 | expect_error(set_proxy(proxy = "34#YU")) 10 | unset_proxy() 11 | }) 12 | 13 | test_that("set_proxy return false with warning if already set", { 14 | withr::with_envvar( 15 | dummy_env_var, 16 | { 17 | suppressWarnings(expect_false(set_proxy(proxy = dummy_proxy_url))) 18 | expect_warning(set_proxy(proxy = dummy_proxy_url)) 19 | }) 20 | }) 21 | 22 | test_that("build_http_env correctly", { 23 | expect_equal(build_http_env("http://proxy-url.com:3232", "its", "me"), 24 | "http://its:me@proxy-url.com:3232/") 25 | expect_equal(build_http_env("http://proxy-url.com:3232", "", ""), 26 | "http://proxy-url.com:3232/") 27 | expect_equal(suppressWarnings(build_http_env("http://proxy-url.com:3232", "", "me")), 28 | "http://proxy-url.com:3232/") 29 | expect_warning(build_http_env("http://proxy-url.com:3232", "", "me")) 30 | }) 31 | 32 | test_that("env var are set correctly", { 33 | unset_proxy() 34 | set_proxy( 35 | proxy = "http://proxy.mycompany.com:3939", 36 | username = "its", 37 | password = "me", 38 | noproxy = c(".mycompany.com", "163.104.50.180"), 39 | https = TRUE 40 | ) 41 | 42 | expect_equal(Sys.getenv("HTTP_PROXY"), "http://its:me@proxy.mycompany.com:3939/") 43 | expect_equal(Sys.getenv("HTTPS_PROXY"), "http://its:me@proxy.mycompany.com:3939/") 44 | expect_equal(Sys.getenv("http_proxy"), "http://its:me@proxy.mycompany.com:3939/") 45 | expect_equal(Sys.getenv("https_proxy"), "http://its:me@proxy.mycompany.com:3939/") 46 | expect_equal(Sys.getenv("NO_PROXY"), ".mycompany.com, 163.104.50.180") 47 | expect_equal(Sys.getenv("no_proxy"), ".mycompany.com, 163.104.50.180") 48 | unset_proxy() 49 | }) 50 | 51 | test_that("env var are set correctly if proxy url provided as options", { 52 | withr::local_options(list(`proxyconfig.proxy` = "http://proxy.mycompany.com:3939")) 53 | unset_proxy() 54 | set_proxy( 55 | username = "its", 56 | password = "me" 57 | ) 58 | expect_equal(Sys.getenv("HTTP_PROXY"), "http://its:me@proxy.mycompany.com:3939/") 59 | expect_equal(Sys.getenv("http_proxy"), "http://its:me@proxy.mycompany.com:3939/") 60 | unset_proxy() 61 | }) 62 | 63 | test_that("proxy is correctly unset", { 64 | withr::with_envvar( 65 | dummy_env_var, 66 | { 67 | expect_true(unset_proxy(FALSE)) 68 | unset_env <- purrr::map_chr(dummy_env_var, Sys.getenv, unset = "unset") 69 | purrr::walk(unset_env, expect_identical, "unset") 70 | }) 71 | withr::with_envvar( 72 | dummy_env_var, 73 | { 74 | expect_message(unset_proxy(TRUE), regexp = "Proxy unset", fixed = TRUE) 75 | } 76 | ) 77 | }) 78 | -------------------------------------------------------------------------------- /R/set.R: -------------------------------------------------------------------------------- 1 | #' Configure the proxy for internet connection 2 | #' 3 | #' @description this will help to set up the proxy configuration using 4 | #' environment variable 5 | #' + url of the proxy with port 6 | #' + authentification if necessary (username and password) 7 | #' + any domain that proxy should ignore 8 | #' + activate or not https proxy 9 | #' 10 | #' You can set a proxy url across sessions by setting option `"proxyconfig.proxy"`. 11 | #' 12 | #' @section Proxy Environment Variable: 13 | #' 14 | #' The proxy is set using environment variables 15 | #' + `HTTP_PROXY` 16 | #' + `HTTPS_PROXY` 17 | #' + `NO_PROXY` 18 | #' The lower case version are also set because some utilities do not understand 19 | #' upper case environment variable. 20 | #' 21 | #' This configuration is used by `curl` for internet connection and other 22 | #' _method_. See _Setting Proxies_ in [utils::download.file()] 23 | #' 24 | #' @param proxy a character giving the proxy url. By default, it will fetch for 25 | #' option `proxyconfig.proxy` that can be set accross sessions in 26 | #' _.Rprofile_ or _Rprofile.site_. 27 | #' @param username character. If `NULL`, user will be prompted 28 | #' @param password character. If `NULL`, user will be prompted 29 | #' @param noproxy character vector of domain that proxy should ignore 30 | #' @param https logical. If `TRUE` *HTTPS_PROXY* will be used 31 | #' 32 | #' @return `TRUE` *invisibly* if no error. Side effects are the environment 33 | #' variables for proxy being set for the session. You can check them with 34 | #' [base::Sys.getenv()] 35 | #' 36 | #' `FALSE` *invisibly* with a warning if a proxy configuration was already set. You need 37 | #' to unset the configuration with [unset_proxy()] before setting a new one. 38 | #' 39 | #' @examples 40 | #' \dontrun{ 41 | #' set_proxy(proxy = "http://10.132.23.444:3232", 42 | #' username = "", 43 | #' password = "", 44 | #' noproxy = ".mycompany.com", 45 | #' https = TRUE) 46 | #' is_proxy_activated(verbose = TRUE) 47 | #' } 48 | #' @export 49 | set_proxy <- function(proxy = getOption("proxyconfig.proxy", default = NA_character_), 50 | username = NULL, 51 | password = NULL, 52 | noproxy = NULL, 53 | https = TRUE) { 54 | # check proxy is set 55 | if (is_proxy_activated(FALSE)) { 56 | warning("A proxy configuration is already set.\n", 57 | "Please check and unset with unset_proxy() before setting a new one\n") 58 | return(invisible(FALSE)) 59 | } 60 | 61 | if (is.na(proxy) || !check_proxy(proxy)) { 62 | stop("You must provide a proxy url of the form ",call. = FALSE) 63 | } 64 | 65 | # ask for username 66 | if (is.null(username)) { 67 | username <- read_password("Username") 68 | if (is.null(username)) { 69 | message("Operation cancelled") 70 | return(invisible(FALSE)) 71 | } 72 | } 73 | # ask for password 74 | if (is.null(password)) { 75 | password <- read_password("password") 76 | if (is.null(password)) { 77 | message("Operation cancelled") 78 | return(invisible(FALSE)) 79 | } 80 | } 81 | 82 | # add habitility to check for username. All pass for now 83 | check_username(username) 84 | 85 | # build proxy url for environment variable 86 | http_proxy <- build_http_env(proxy, username, password) 87 | 88 | Sys.setenv(HTTP_PROXY = http_proxy) 89 | Sys.setenv(http_proxy = http_proxy) 90 | if (isTRUE(https)) { 91 | https_proxy <- http_proxy 92 | Sys.setenv(HTTPS_PROXY = https_proxy) 93 | Sys.setenv(https_proxy = https_proxy) 94 | } 95 | if (!is.null(noproxy)) { 96 | Sys.setenv(NO_PROXY = paste0(noproxy, collapse = ", ")) 97 | Sys.setenv(no_proxy = paste0(noproxy, collapse = ", ")) 98 | } 99 | message("Proxy configured") 100 | invisible(TRUE) 101 | } 102 | 103 | 104 | #' Build proxy url with authentification 105 | #' 106 | #' Build proxy url as `http://username:password@proxy-url.com:port` 107 | #' 108 | #' @param proxy character. Proxy url 109 | #' @param username character 110 | #' @param password character 111 | #' 112 | #' @return proxy url with username and password 113 | #' @keywords internal 114 | #' @examples 115 | #' \dontrun{ 116 | #' build_http_env("http://proxy-url.com:3232", "its", "me") 117 | #' } 118 | build_http_env <- function(proxy, username, password) { 119 | parsed_proxy <- httr::parse_url(proxy) 120 | if (username != "") { 121 | parsed_proxy$username <- username 122 | parsed_proxy$password <- password 123 | } 124 | if (username == "" && password != "") { 125 | warning("As username is empty, password is ignored\n") 126 | } 127 | httr::build_url(parsed_proxy) 128 | } 129 | 130 | 131 | #' Unset proxy configuration for the session 132 | #' 133 | #' This fonction is a helper to unset all configuration of proxy for the current 134 | #' session. 135 | #' 136 | #' @param verbose default is `FALSE`. 137 | #' 138 | #' @return `FALSE` is no proxy configuration was set before. `TRUE` if 139 | #' configuration is unset with success. 140 | #' @export 141 | #' 142 | #' @examples 143 | #' \dontrun{ 144 | #' set_proxy(proxy = "http://10.132.23.444:3232", 145 | #' username = "", 146 | #' password = "", 147 | #' noproxy = ".mycompany.com", 148 | #' https = TRUE) 149 | #' is_proxy_activated(verbose = TRUE) 150 | #' unset_proxy(verbose = TRUE) 151 | #' is_proxy_activated(verbose = TRUE) 152 | #' } 153 | unset_proxy <- function(verbose = FALSE) { 154 | if (!is_proxy_activated(FALSE)) { 155 | if (verbose) message("Proxy is not activated. Nothing to unset.") 156 | return(FALSE) 157 | } 158 | Sys.unsetenv("HTTP_PROXY") 159 | Sys.unsetenv("HTTPS_PROXY") 160 | Sys.unsetenv("NO_PROXY") 161 | Sys.unsetenv("http_proxy") 162 | Sys.unsetenv("https_proxy") 163 | Sys.unsetenv("no_proxy") 164 | if (verbose) message("Proxy unset") 165 | TRUE 166 | } 167 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # proxyconfig 5 | 6 | 7 | 8 | [![Azure pipelines build 9 | status](https://img.shields.io/azure-devops/build/cderv/proxyconfig/1)](https://dev.azure.com/cderv/proxyconfig/_build/latest?definitionId=1&branchName=master) 10 | [![Azure pipelines test 11 | status](https://img.shields.io/azure-devops/tests/cderv/proxyconfig/1?color=brightgreen&compact_message)](https://dev.azure.com/cderv/proxyconfig/_build/latest?definitionId=1&branchName=master) 12 | [![Azure pipelines coverage 13 | status](https://img.shields.io/azure-devops/coverage/cderv/proxyconfig/1)](https://dev.azure.com/cderv/proxyconfig/_build/latest?definitionId=1&branchName=master) 14 | [![Lifecycle: 15 | experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://www.tidyverse.org/lifecycle/#experimental) 16 | [![CRAN 17 | status](https://www.r-pkg.org/badges/version/proxyconfig)](https://CRAN.R-project.org/package=proxyconfig) 18 | [![License: 19 | MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE.md) 20 | [![Travis build 21 | status](https://travis-ci.com/cderv/proxyconfig.svg?branch=master)](https://travis-ci.com/cderv/proxyconfig) 22 | [![Codecov test 23 | coverage](https://codecov.io/gh/cderv/proxyconfig/branch/master/graph/badge.svg)](https://codecov.io/gh/cderv/proxyconfig?branch=master) 24 | 25 | 26 | The goal of proxyconfig is to help setting the proxy interactively. 27 | 28 | ## About proxy configuration 29 | 30 | ### Why would you need to configure a proxy ? 31 | 32 | In a corporate environment, there is often a proxy you need to pass 33 | through to escape your company network. When behind this firewall of 34 | your company, you need to first tell R that it needs to pass the proxy 35 | before trying to reach the url and not to use it when the url you want 36 | to access are inside the same network. 37 | 38 | ### Examples of when it is needed 39 | 40 | For example, behind a company proxy, 41 | 42 | - `install.package` won’t be able to reach a cran mirror that is 43 | outside like `https://https://cloud.r-project.org/` 44 | - `download.file` won’t be able to get a file from a url 45 | - `httr::GET`, `curl::curl` won’t be able to be used for web url. 46 | 47 | The first two are R base features and have a `method` argument that you 48 | can use to help configure correctly. Different methods can have 49 | different settings. The most used is *libcurl* that is also used by 50 | `httr` and `curl` :package:. 51 | 52 | ### Some words about proxy configuration in R 53 | 54 | Sometimes, proxy is automatically picked up by R. It is the case on 55 | windows where R uses the *wininet* method by default, for which the 56 | ‘Internet Options’, from Internet Explorer or Edge, are used for proxy 57 | configuration. On other system, proxy must often be explicity 58 | configured. 59 | 60 | You’ll find information about *Setting Proxies* in R in the 61 | `utils::download.file()` help page: `help("download.file", package = 62 | "utils")` or `?download.file`. 63 | 64 | ## Installation 65 | 66 | Currently, this package is only available on Github in development 67 | version : 68 | 69 | ``` r 70 | # install.packages("devtools") 71 | devtools::install_github("cderv/proxyconfig") 72 | ``` 73 | 74 | or using 75 | 76 | ``` r 77 | source("https://install-github.me/cderv/proxyconfig") 78 | ``` 79 | 80 | ## How to use `proxyconfig` 81 | 82 | ### How to set the proxy 83 | 84 | Given a proxy url, you can set the proxy interactively using `set_proxy` 85 | using `proxy` argument. Proxy url must be of the form 86 | *scheme://hostname\[:port\]*. 87 | 88 | ``` r 89 | proxyconfig::set_proxy(proxy = "http://proxy.mycompany.com:3939") 90 | ``` 91 | 92 | You can also use `options(proxyconfig.proxy = 93 | "http://proxy.mycompany.com:3939")` so that it knows which url to use as 94 | default. You can use `usethis::edit_r_profile()` to open the user 95 | *.Rprofile* and add the option. 96 | 97 | Then when in *.Rprofile*, you can call directly 98 | 99 | ``` r 100 | proxyconfig::set_proxy() 101 | ``` 102 | 103 | By default if username and password not provided, this will prompt the 104 | user for authentification. You can pass them in `set_proxy` argument too 105 | to use non-interactively. **This is not advice to pass them in clear in 106 | a script** - this is what the interactive mode with dialog box aims to 107 | prevent. 108 | 109 | If you don’t have any authentification for your proxy, use empty values 110 | explicitly. 111 | 112 | ``` r 113 | proxyconfig::set_proxy(proxy = "http://proxy.mycompany.com:3939", username = "", password = "") 114 | ``` 115 | 116 | To prevent the proxy to be used for url on internal network domain, use 117 | `noproxy` argument. (empty by default). This useful for a github 118 | entreprise server or an internal cran repos for example, respectively on 119 | `https://github.mycompany.com` and `https://cran.mycompany.com`. Both 120 | are on the same domain - `noproxy` is configured here to look for url on 121 | domain mycompany.com without exiting the internal pany network through 122 | the proxy. 123 | 124 | ``` r 125 | proxyconfig::set_proxy(proxy = "http://proxy.mycompany.com:3939", noproxy = ".mycompany.com") 126 | ``` 127 | 128 | If several domains (or IP addresses) are necessary, they will be 129 | concatenated properly. 130 | 131 | ``` r 132 | proxyconfig::set_proxy(proxy = "http://proxy.mycompany.com:3939", noproxy = c(".mycompany.com", "163.104.50.180")) 133 | ``` 134 | 135 | ### How to check what is configured ? 136 | 137 | `set_proxy()` will set the correct environment variable for the current 138 | session. You can verify if a proxy is currently configured with 139 | `is_proxy_activated()` 140 | 141 | ``` r 142 | proxyconfig::is_proxy_activated() 143 | ``` 144 | 145 | You can have more information using `verbose = TRUE`. (Note that 146 | authentification is hidden when printed) 147 | 148 | ``` r 149 | proxyconfig::is_proxy_activated(TRUE) 150 | ``` 151 | 152 | ### What if a proxy is already set ? 153 | 154 | If a proxy is already set, `set_proxy` will issue a warning (and return 155 | false invisibly) 156 | 157 | ``` r 158 | (proxyconfig::set_proxy(proxy = "https://newproxy.company.com")) 159 | ``` 160 | 161 | You can unset a proxy configuration with `unset_proxy()` 162 | 163 | ``` r 164 | proxyconfig::unset_proxy(verbose = TRUE) 165 | # proxy is correctly deactivated 166 | proxyconfig::is_proxy_activated(TRUE) 167 | ``` 168 | 169 | # TODO 170 | 171 | This is a very new package that works for me. Among the ideas I have for 172 | improvement 173 | 174 | - [ ] Use an option mechanism to make the proxy url persistent across 175 | sessions 176 | - [ ] Use [keyring](https://github.com/r-lib/keyring) to store and 177 | retrieve auth accross session 178 | - [ ] Make a templating system to use proxyconfig in an internal 179 | package. Inspiration `ghentr` and `pkgconfig` 180 | - [ ] Improve console output with `cli` 181 | - [ ] Create an add-on for better interactation (and keybinding) 182 | -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: github_document 3 | --- 4 | 5 | 6 | 7 | ```{r setup, include = FALSE} 8 | knitr::opts_chunk$set( 9 | collapse = TRUE, 10 | comment = "#>", 11 | fig.path = "man/figures/README-", 12 | out.width = "100%", 13 | eval = FALSE 14 | ) 15 | ``` 16 | # proxyconfig 17 | 18 | 19 | [![Azure pipelines build status](https://img.shields.io/azure-devops/build/cderv/proxyconfig/1)](https://dev.azure.com/cderv/proxyconfig/_build/latest?definitionId=1&branchName=master) 20 | [![Azure pipelines test status](https://img.shields.io/azure-devops/tests/cderv/proxyconfig/1?color=brightgreen&compact_message)](https://dev.azure.com/cderv/proxyconfig/_build/latest?definitionId=1&branchName=master) 21 | [![Azure pipelines coverage status](https://img.shields.io/azure-devops/coverage/cderv/proxyconfig/1)](https://dev.azure.com/cderv/proxyconfig/_build/latest?definitionId=1&branchName=master) 22 | [![Lifecycle: experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://www.tidyverse.org/lifecycle/#experimental) 23 | [![CRAN status](https://www.r-pkg.org/badges/version/proxyconfig)](https://CRAN.R-project.org/package=proxyconfig) 24 | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE.md) 25 | [![Travis build status](https://travis-ci.com/cderv/proxyconfig.svg?branch=master)](https://travis-ci.com/cderv/proxyconfig) 26 | [![Codecov test coverage](https://codecov.io/gh/cderv/proxyconfig/branch/master/graph/badge.svg)](https://codecov.io/gh/cderv/proxyconfig?branch=master) 27 | 28 | 29 | The goal of proxyconfig is to help setting the proxy interactively. 30 | 31 | ## About proxy configuration 32 | 33 | ### Why would you need to configure a proxy ? 34 | 35 | In a corporate environment, there is often a proxy you need to pass through to 36 | escape your company network. When behind this firewall of your company, you need 37 | to first tell R that it needs to pass the proxy before trying to reach the url 38 | and not to use it when the url you want to access are inside the same network. 39 | 40 | ### Examples of when it is needed 41 | 42 | For example, behind a company proxy, 43 | 44 | + `install.package` won't be able to reach a cran mirror that is outside like `https://https://cloud.r-project.org/` 45 | + `download.file` won't be able to get a file from a url 46 | + `httr::GET`, `curl::curl` won't be able to be used for web url. 47 | 48 | The first two are R base features and have a `method` argument that you can use to help configure correctly. Different methods can have different settings. The most used is _libcurl_ that is also used by `httr` and `curl` :package:. 49 | 50 | ### Some words about proxy configuration in R 51 | 52 | Sometimes, proxy is automatically picked up by R. It is the case on windows 53 | where R uses the _wininet_ method by default, for which the 'Internet Options', 54 | from Internet Explorer or Edge, are used for proxy configuration. 55 | On other system, proxy must often be explicity configured. 56 | 57 | You'll find information about _Setting Proxies_ in R in the `utils::download.file()` help page: 58 | `help("download.file", package = "utils")` or `?download.file`. 59 | 60 | 61 | ## Installation 62 | 63 | Currently, this package is only available on Github in development version : 64 | 65 | ```r 66 | # install.packages("devtools") 67 | devtools::install_github("cderv/proxyconfig") 68 | ``` 69 | 70 | or using 71 | 72 | ```r 73 | source("https://install-github.me/cderv/proxyconfig") 74 | ``` 75 | 76 | ## How to use `proxyconfig` 77 | 78 | ### How to set the proxy 79 | 80 | Given a proxy url, you can set the proxy interactively using `set_proxy` using `proxy` argument. Proxy 81 | url must be of the form _scheme://hostname[:port]_. 82 | 83 | ```{r set_proxy, eval = FALSE} 84 | proxyconfig::set_proxy(proxy = "http://proxy.mycompany.com:3939") 85 | ``` 86 | 87 | You can also use `options(proxyconfig.proxy = "http://proxy.mycompany.com:3939")` 88 | so that it knows which url to use as default. You can use `usethis::edit_r_profile()` to open the user 89 | _.Rprofile_ and add the option. 90 | 91 | Then when in _.Rprofile_, you can call directly 92 | ```{r eval = FALSE} 93 | proxyconfig::set_proxy() 94 | ``` 95 | 96 | By default if username and password not provided, this will prompt the user for authentification. You can pass them in `set_proxy` argument too to use non-interactively. **This is not advice to pass them in clear in a script** - this is what the interactive mode with dialog box aims to prevent. 97 | 98 | 99 | If you don't have any authentification for your proxy, use empty values explicitly. 100 | ```{r set_proxy_without_auth, eval = FALSE} 101 | proxyconfig::set_proxy(proxy = "http://proxy.mycompany.com:3939", username = "", password = "") 102 | ``` 103 | 104 | To prevent the proxy to be used for url on internal network domain, use `noproxy` argument. (empty by default). This useful for a github entreprise server or an internal cran repos for example, respectively on `https://github.mycompany.com` and `https://cran.mycompany.com`. Both are on the same domain - `noproxy` is configured here to look for url on domain mycompany.com without exiting the internal pany network through the proxy. 105 | 106 | ```{r eval = FALSE} 107 | proxyconfig::set_proxy(proxy = "http://proxy.mycompany.com:3939", noproxy = ".mycompany.com") 108 | ``` 109 | 110 | If several domains (or IP addresses) are necessary, they will be concatenated properly. 111 | 112 | ```{r eval = FALSE} 113 | proxyconfig::set_proxy(proxy = "http://proxy.mycompany.com:3939", noproxy = c(".mycompany.com", "163.104.50.180")) 114 | ``` 115 | 116 | 117 | ```{r include = FALSE} 118 | # for readme demo - not an example to follow as password is in clear 119 | proxyconfig::set_proxy(proxy = "http://proxy.mycompany.com:3939", username = "its", password = "me", noproxy = c(".mycompany.com", "163.104.50.180"), https = TRUE) 120 | ``` 121 | 122 | ### How to check what is configured ? 123 | 124 | `set_proxy()` will set the correct environment variable for the current session. You can verify if a proxy is currently configured with `is_proxy_activated()` 125 | 126 | ```{r check-proxy, eval = FALSE} 127 | proxyconfig::is_proxy_activated() 128 | ``` 129 | 130 | You can have more information using `verbose = TRUE`. (Note that authentification is hidden when printed) 131 | 132 | ```{r check-proxy-verbose, eval = FALSE} 133 | proxyconfig::is_proxy_activated(TRUE) 134 | ``` 135 | 136 | ### What if a proxy is already set ? 137 | 138 | If a proxy is already set, `set_proxy` will issue a warning (and return false invisibly) 139 | ```{r, eval = FALSE} 140 | (proxyconfig::set_proxy(proxy = "https://newproxy.company.com")) 141 | ``` 142 | 143 | You can unset a proxy configuration with `unset_proxy()` 144 | ```{r, eval= FALSE} 145 | proxyconfig::unset_proxy(verbose = TRUE) 146 | # proxy is correctly deactivated 147 | proxyconfig::is_proxy_activated(TRUE) 148 | ``` 149 | 150 | 151 | # TODO 152 | 153 | This is a very new package that works for me. Among the ideas I have for improvement 154 | 155 | - [ ] Use an option mechanism to make the proxy url persistent across sessions 156 | - [ ] Use [keyring](https://github.com/r-lib/keyring) to store and retrieve auth accross session 157 | - [ ] Make a templating system to use proxyconfig in an internal package. Inspiration `ghentr` and `pkgconfig` 158 | - [ ] Improve console output with `cli` 159 | - [ ] Create an add-on for better interactation (and keybinding) 160 | 161 | --------------------------------------------------------------------------------