0

I know this is agains open source philosophy, but I would need only a temporary solution, if at all possible, to allow for source() code in R but to prevent students being able to read those functions. Is that possible at all?

As I said this is only a temporary solution: functions will be turned into package that we will be happy to openly share, but not before we tidy them up and publish related paper; however, now, I would love to let my students use them.

striatum
  • 1,428
  • 3
  • 14
  • 31
  • Not that I am aware of - if the function is being used it will be in memory somewhere and accessible. – zacdav Jun 10 '18 at 12:19
  • As long as you are using R in an interactive manner using Rterm, Rgui, or RStudio (with uses them), you are plagued with the fact that one can always see the source of R-based functions. It is more difficult to see the source of R6 and similar constructs, but a resourceful coder will still be able to find it. Rcpp functions are a bit different, and would require decompiling the object files, but my guess is that you don't want to go to this extreme. Ultimately, I think you either have to use a middleware or alter the source of R itself (non-trivial!). – r2evans Jun 10 '18 at 12:39
  • If the function is in memory, to type its name at a prompt will print it. – Rui Barradas Jun 10 '18 at 12:40

1 Answers1

0

I don't know of any way by which this is possible. You could alternatively set up a simple web service, so your function stays on your computer. If you want a bit more standard-compliance, you can setup a REST service

Your server which uses your function should be a larger computer if you want all your students access your function at the same time. Also, depending on your use-case, you might want to parallelize the computations from different requests. For example use the future package for that.

Also avoid enabling your students to send code which you execute on the server for security reasons. Make the server just accept data. Another security measure might be to limit the size of the incoming data, however, I do not know how to do this. Maybe ask a separate question if you need it. Also do not expose this to the internet without a secure way of authentication. I do not know how to write such a secure server. Use the intranet of your institution.

This is an example server. Save the script below as "simpleSrv.R" and execute on the server:

Rscript -e "source('simpleSrv.R'); server(11223)"

You can replace 11223 by another port number larger than 1024 (only accessible by root)

Your students only need the client function or similar which sends and receives the result, the port number to use and of course network access to your server.

# TOP-LEVEL FUNCTION server -------------------------------------------------

# Wait for connection and launch command loop
server <- function(port){
  con <- NULL
  on.exit({
    close(con)
    message("Connection closed.")
  })
  repeat{
    con <- listen(port)
    status <- processCommand(con)
    if(status == "closed")
      next
    # Kill with Ctrl+C
  }
}

# TOP-LEVEL FUNCTION client --------------------------------------------------
# This is the only function you need on the clients
client <- function(port){
  con <- socketConnection(host = "localhost", port, open = "a+b", blocking = TRUE)
  on.exit(close(con))
  repeat{
    cat("Enter a number > ")
    line <- readline()
    serialize(line, con)
    result <- unserialize(con)
    print(result)
  }
}

# Create the socket to accept incoming connection
listen <- function(port){
  message("Waiting for connection on localhost:",port)
  insock <- socketConnection( host = "localhost", port = port, server = TRUE, open = "a+b"
                            , blocking = FALSE, timeout = 120)
  message("Connected.")
  return(insock)
}

# Process incoming objects
processCommand <- function(con){
  status <- "next"
  while(status == "next"){
    obj <- tryCatch(unserialize(con), error = function(e) NULL)
    if(is.null(obj))
      status <- "closed"
    message("object received")
    str(obj)
    result <- try(processObj(obj))
    message("Sending result")
    str(obj)
    serialize(result, con)
  }
  return(status)
}

# Call your function here
processObj <- function(obj){
  return(as.numeric(obj) * 2)
}
akraf
  • 2,965
  • 20
  • 44