From ecd9b25e75f2a5fa53af8ea0111549119858bc70 Mon Sep 17 00:00:00 2001 From: Shulhan Date: Fri, 6 Dec 2024 00:27:35 +0700 Subject: lib/play: add custom request to run unsafe directory directly As exceptional, the Run and HTTPHandleRun accept the following request for running program inside custom "go.mod", { "unsafe_run": } The "unsafe_run" define the path to directory relative to HTTP server working directory. Once request accepted it will change the directory into "unsafe_run" first and then run "go run ." directly. Go code that executed inside "unsafe_run" should be not modifiable and safe from mallicious execution. --- lib/play/play.go | 37 ++++++++++++++++++++++++-- lib/play/play_test.go | 18 +++++++++++++ lib/play/request.go | 4 +++ lib/play/testdata/unsafe_run/cmd/forum/main.go | 7 +++++ lib/play/testdata/unsafe_run/forum/forum.go | 7 +++++ lib/play/testdata/unsafe_run/go.mod | 3 +++ 6 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 lib/play/testdata/unsafe_run/cmd/forum/main.go create mode 100644 lib/play/testdata/unsafe_run/forum/forum.go create mode 100644 lib/play/testdata/unsafe_run/go.mod diff --git a/lib/play/play.go b/lib/play/play.go index 068a52c2..3f01035d 100644 --- a/lib/play/play.go +++ b/lib/play/play.go @@ -20,11 +20,11 @@ // used to compile the code. // The default "goversion" is defined as global variable [GoVersion] in this // package. -// If "without_race" is false, the Run command will not run with "-race" +// If "without_race" is true, the Run command will not run with "-race" // option. // The "body" field contains the Go code to be formatted or run. // -// Both have the following response format, +// Both return the following JSON response format, // // { // "code": , @@ -38,6 +38,20 @@ // For the [HTTPHandleRun], the response "data" contains the output from // running the Go code, the "message" contains an error pre-Run, like bad // request or file system related error. +// +// As exceptional, the [Run] and [HTTPHandleRun] accept the following +// request for running program inside custom "go.mod", +// +// { +// "unsafe_run": +// } +// +// The "unsafe_run" define the path to directory relative to HTTP server +// working directory. +// Once request accepted it will change the directory into "unsafe_run" first +// and then run "go run ." directly. +// Go code that executed inside "unsafe_run" should be not modifiable and +// safe from mallicious execution. package play import ( @@ -253,6 +267,10 @@ func Run(req *Request) (out []byte, err error) { runningCmd.delete(req.cookieSid.Value) } + if len(req.UnsafeRun) != 0 { + return unsafeRun(req) + } + if len(req.Body) == 0 { return nil, nil } @@ -296,3 +314,18 @@ func Run(req *Request) (out []byte, err error) { return out, nil } + +func unsafeRun(req *Request) (out []byte, err error) { + var logp = `unsafeRun` + + var cmd *command + cmd, err = newCommand(req, req.UnsafeRun) + if err != nil { + return nil, fmt.Errorf(`%s: %w`, logp, err) + } + runningCmd.store(req.cookieSid.Value, cmd) + + out = cmd.run() + + return out, nil +} diff --git a/lib/play/play_test.go b/lib/play/play_test.go index 4172c506..f9acf460 100644 --- a/lib/play/play_test.go +++ b/lib/play/play_test.go @@ -320,3 +320,21 @@ func testRunOverlap(t *testing.T, runwg *sync.WaitGroup, tdata *test.Data, exp, string(out)) } } + +func TestRunUnsafeRun(t *testing.T) { + var req = &Request{ + UnsafeRun: `testdata/unsafe_run/cmd/forum`, + } + + var ( + out []byte + err error + ) + out, err = Run(req) + if err != nil { + t.Fatal(err) + } + + var exp = "Hello...\n" + test.Assert(t, `unsafeRun`, exp, string(out)) +} diff --git a/lib/play/request.go b/lib/play/request.go index 18c210bd..3bd8cfb5 100644 --- a/lib/play/request.go +++ b/lib/play/request.go @@ -29,6 +29,10 @@ type Request struct { // Body contains the Go code to be Format-ed or Run. Body string `json:"body"` + // UnsafeRun define the working directory where "go run ." will be + // executed directly. + UnsafeRun string `json:"unsafe_run"` + // WithoutRace define option opt out "-race" when running Go code. WithoutRace bool `json:"without_race"` } diff --git a/lib/play/testdata/unsafe_run/cmd/forum/main.go b/lib/play/testdata/unsafe_run/cmd/forum/main.go new file mode 100644 index 00000000..c8fb90ef --- /dev/null +++ b/lib/play/testdata/unsafe_run/cmd/forum/main.go @@ -0,0 +1,7 @@ +package main + +import "forum.local/forum" + +func main() { + forum.Write("Hello...") +} diff --git a/lib/play/testdata/unsafe_run/forum/forum.go b/lib/play/testdata/unsafe_run/forum/forum.go new file mode 100644 index 00000000..4401b9da --- /dev/null +++ b/lib/play/testdata/unsafe_run/forum/forum.go @@ -0,0 +1,7 @@ +package forum + +import "fmt" + +func Write(text string) { + fmt.Println(text) +} diff --git a/lib/play/testdata/unsafe_run/go.mod b/lib/play/testdata/unsafe_run/go.mod new file mode 100644 index 00000000..f0a7067f --- /dev/null +++ b/lib/play/testdata/unsafe_run/go.mod @@ -0,0 +1,3 @@ +module forum.local + +go 1.23.2 -- cgit v1.3