From 77e645beb3b9995666c24de9d5775e2d2ae0b878 Mon Sep 17 00:00:00 2001 From: Vrganj Date: Thu, 14 Jan 2021 20:14:26 +0100 Subject: [PATCH 01/14] Rip out go, add aliases to /versions --- api/.gitignore | 1 + api/main.go | 413 +++++++++---------- api/package-lock.json | 903 ++++++++++++++++++++++++++++++++++++++++++ api/package.json | 16 + api/src/index.js | 99 +++++ api/src/languages.js | 118 ++++++ api/start | 2 +- lxc/execute | 96 +---- 8 files changed, 1346 insertions(+), 302 deletions(-) create mode 100644 api/.gitignore create mode 100644 api/package-lock.json create mode 100644 api/package.json create mode 100644 api/src/index.js create mode 100644 api/src/languages.js diff --git a/api/.gitignore b/api/.gitignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/api/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/api/main.go b/api/main.go index 1fb17e5..2e7e378 100644 --- a/api/main.go +++ b/api/main.go @@ -1,302 +1,303 @@ package main import ( - "bytes" - "encoding/json" - "fmt" - "io/ioutil" - "net/http" - "os/exec" - "regexp" - "strings" - "time" + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "os/exec" + "regexp" + "strings" + "time" ) type Inbound struct { - Language string `json:"language"` - Source string `json:"source"` - Args []string `json:"args"` + Language string `json:"language"` + Source string `json:"source"` + Args []string `json:"args"` } type Problem struct { - Code string `json:"code"` - Message string `json:"message"` + Code string `json:"code"` + Message string `json:"message"` } type Outbound struct { - Ran bool `json:"ran"` - Language string `json:"language"` - Version string `json:"version"` - Output string `json:"output"` - Stdout string `json:"stdout"` - Stderr string `json:"stderr"` + Ran bool `json:"ran"` + Language string `json:"language"` + Version string `json:"version"` + Output string `json:"output"` + Stdout string `json:"stdout"` + Stderr string `json:"stderr"` } type Language struct { - Name string `json:"name,omitempty"` - Version string `json:"version,omitempty"` + Name string `json:"name,omitempty"` + Version string `json:"version,omitempty"` + Aliases []string `json:"aliases,omitempty"` } var instance int var languages []Language func main() { - port := "2000" + port := "2000" - var err error - languages, err = UpdateVersions() + var err error + languages, err = UpdateVersions() - if err != nil { - fmt.Println("could not get version info and therefore couldn't start") - fmt.Println(err) - return - } + if err != nil { + fmt.Println("could not get version info and therefore couldn't start") + fmt.Println(err) + return + } - fmt.Println("starting api on port", port) - http.HandleFunc("/execute", Execute) - http.HandleFunc("/versions", Versions) - http.ListenAndServe(":"+port, nil) + fmt.Println("starting api on port", port) + http.HandleFunc("/execute", Execute) + http.HandleFunc("/versions", Versions) + http.ListenAndServe(":"+port, nil) } func Execute(res http.ResponseWriter, req *http.Request) { - res.Header().Set("Content-Type", "application/json") + res.Header().Set("Content-Type", "application/json") - // get json - inbound := Inbound{} - message := json.NewDecoder(req.Body) - message.Decode(&inbound) + // get json + inbound := Inbound{} + message := json.NewDecoder(req.Body) + message.Decode(&inbound) - whitelist := []string{ - "awk", - "bash", - "brainfuck", "bf", - "c", - "cpp", "c++", - "csharp", "cs", "c#", - "deno", "denojs", "denots", - "elixir", "exs", - "emacs", "elisp", "el", - "go", - "haskell", "hs", - "java", - "jelly", - "julia", "jl", - "kotlin", - "lua", - "nasm", "asm", - "nasm64", "asm64", - "node", "javascript", "js", - "perl", "pl", - "php", - "python2", - "python3", "python", - "paradoc", - "ruby", - "rust", - "swift", - "typescript", "ts", - } + whitelist := []string{ + "awk", + "bash", + "brainfuck", "bf", + "c", + "cpp", "c++", + "csharp", "cs", "c#", + "deno", "denojs", "denots", + "elixir", "exs", + "emacs", "elisp", "el", + "go", + "haskell", "hs", + "java", + "jelly", + "julia", "jl", + "kotlin", + "lua", + "nasm", "asm", + "nasm64", "asm64", + "node", "javascript", "js", + "perl", "pl", + "php", + "python2", + "python3", "python", + "paradoc", + "ruby", + "rust", + "swift", + "typescript", "ts", + } - // check if the supplied language is supported - // now calls function and returns - for _, lang := range whitelist { - if lang == inbound.Language { - launch(inbound, res) - return - } - } + // check if the supplied language is supported + // now calls function and returns + for _, lang := range whitelist { + if lang == inbound.Language { + launch(inbound, res) + return + } + } - // now only called when the language is not supported - problem := Problem{ - Code: "unsupported_language", - Message: inbound.Language + " is not supported by Piston", - } + // now only called when the language is not supported + problem := Problem{ + Code: "unsupported_language", + Message: inbound.Language + " is not supported by Piston", + } - pres, _ := json.Marshal(problem) + pres, _ := json.Marshal(problem) - res.WriteHeader(http.StatusBadRequest) - res.Write(pres) + res.WriteHeader(http.StatusBadRequest) + res.Write(pres) } func Versions(res http.ResponseWriter, req *http.Request) { - res.Header().Set("Content-Type", "application/json") + res.Header().Set("Content-Type", "application/json") - data, _ := json.Marshal(languages) + data, _ := json.Marshal(languages) - res.Write(data) + res.Write(data) } type StdWriter struct { - combined *string - separate *string + combined *string + separate *string } func (writer *StdWriter) Write(data []byte) (int, error) { - *writer.combined += string(data) - *writer.separate += string(data) + *writer.combined += string(data) + *writer.separate += string(data) - return len(data), nil + return len(data), nil } func launch(request Inbound, res http.ResponseWriter) { - stamp := time.Now().UnixNano() + stamp := time.Now().UnixNano() - // write the code to temp dir - srcfile := fmt.Sprintf("/tmp/%d.code", stamp) + // write the code to temp dir + srcfile := fmt.Sprintf("/tmp/%d.code", stamp) - ioutil.WriteFile(srcfile, []byte(request.Source), 0644) + ioutil.WriteFile(srcfile, []byte(request.Source), 0644) - // set up the arguments to send to the execute command - cmd := exec.Command("../lxc/execute", request.Language, srcfile, strings.Join(request.Args, "\n")) + // set up the arguments to send to the execute command + cmd := exec.Command("../lxc/execute", request.Language, srcfile, strings.Join(request.Args, "\n")) - // capture out/err - var stdout, stderr, combined string + // capture out/err + var stdout, stderr, combined string - cmd.Stdout = &StdWriter{ - combined: &combined, - separate: &stdout, - } + cmd.Stdout = &StdWriter{ + combined: &combined, + separate: &stdout, + } - cmd.Stderr = &StdWriter{ - combined: &combined, - separate: &stderr, - } + cmd.Stderr = &StdWriter{ + combined: &combined, + separate: &stderr, + } - stdout = strings.TrimSpace(stdout) - stderr = strings.TrimSpace(stderr) - combined = strings.TrimSpace(combined) + stdout = strings.TrimSpace(stdout) + stderr = strings.TrimSpace(stderr) + combined = strings.TrimSpace(combined) - if len(stdout) > 65536 { - stdout = stdout[:65536] - } + if len(stdout) > 65536 { + stdout = stdout[:65536] + } - if len(stderr) > 65536 { - stderr = stdout[:65536] - } + if len(stderr) > 65536 { + stderr = stdout[:65536] + } - if len(combined) > 65536 { - combined = combined[:65536] - } + if len(combined) > 65536 { + combined = combined[:65536] + } - err := cmd.Run() + err := cmd.Run() - // get the executing version of the language - execlang := request.Language + // get the executing version of the language + execlang := request.Language - switch execlang { - case "bf": - execlang = "brainfuck" - case "c++": - execlang = "cpp" - case "cs", "c#": - execlang = "csharp" - case "denojs", "denots": - execlang = "deno" - case "el", "elisp": - execlang = "emacs" - case "exs": - execlang = "elixir" - case "hs": - execlang = "haskell" - case "asm": - execlang = "nasm" - case "asm64": - execlang = "nasm64" - case "js", "javascript": - execlang = "node" - case "jl": - execlang = "julia" - case "python": - execlang = "python3" - case "ts": - execlang = "typescript" - } + switch execlang { + case "bf": + execlang = "brainfuck" + case "c++": + execlang = "cpp" + case "cs", "c#": + execlang = "csharp" + case "denojs", "denots": + execlang = "deno" + case "el", "elisp": + execlang = "emacs" + case "exs": + execlang = "elixir" + case "hs": + execlang = "haskell" + case "asm": + execlang = "nasm" + case "asm64": + execlang = "nasm64" + case "js", "javascript": + execlang = "node" + case "jl": + execlang = "julia" + case "python": + execlang = "python3" + case "ts": + execlang = "typescript" + } - // prepare response - outbound := Outbound{ - Ran: err == nil, - Language: request.Language, - Version: "", - Output: combined, - Stdout: stdout, - Stderr: stderr, - } + // prepare response + outbound := Outbound{ + Ran: err == nil, + Language: request.Language, + Version: "", + Output: combined, + Stdout: stdout, + Stderr: stderr, + } - // retrieve the language version - for _, lang := range languages { - if lang.Name == execlang { - outbound.Version = lang.Version - break - } - } + // retrieve the language version + for _, lang := range languages { + if lang.Name == execlang { + outbound.Version = lang.Version + break + } + } - response, _ := json.Marshal(outbound) + response, _ := json.Marshal(outbound) - res.Write(response) + res.Write(response) } func UpdateVersions() ([]Language, error) { - langs, err := GetVersions() + langs, err := GetVersions() - if err != nil { - return nil, err - } + if err != nil { + return nil, err + } - return langs, nil + return langs, nil } // get all the language and their current version func GetVersions() ([]Language, error) { - var languages []Language + var languages []Language - res, err := ExecVersionScript() + res, err := ExecVersionScript() - if err != nil { - return nil, err - } + if err != nil { + return nil, err + } - info := strings.Split(res, "---") + info := strings.Split(res, "---") - for _, v := range info { - if len(v) < 2 { - continue - } - name, version := GetVersion(v) - languages = append(languages, Language{ - Name: name, - Version: version, - }) - } + for _, v := range info { + if len(v) < 2 { + continue + } + name, version := GetVersion(v) + languages = append(languages, Language{ + Name: name, + Version: version, + }) + } - return languages, nil + return languages, nil } // run the script that retrieves all the language versions func ExecVersionScript() (string, error) { - cmd := exec.Command("../lxc/versions") + cmd := exec.Command("../lxc/versions") - var stdout bytes.Buffer - cmd.Stdout = &stdout - cmd.Stderr = &stdout + var stdout bytes.Buffer + cmd.Stdout = &stdout + cmd.Stderr = &stdout - err := cmd.Run() + err := cmd.Run() - return strings.ToLower(stdout.String()), err + return strings.ToLower(stdout.String()), err } // return the language and its version // most of the time it is easy to get the name and version // but for some languages helper functions are used func GetVersion(s string) (string, string) { - lines := strings.Split(s, "\n") + lines := strings.Split(s, "\n") - if lines[1] == "java" { - return "java", regexp.MustCompile("([0-9]+)").FindString(lines[2]) - } + if lines[1] == "java" { + return "java", regexp.MustCompile("([0-9]+)").FindString(lines[2]) + } - if lines[1] == "emacs" { - return "emacs", regexp.MustCompile("([0-9]+\\.[0-9]+)").FindString(lines[2]) - } + if lines[1] == "emacs" { + return "emacs", regexp.MustCompile("([0-9]+\\.[0-9]+)").FindString(lines[2]) + } - return lines[1], regexp.MustCompile("([0-9]+\\.[0-9]+\\.[0-9]+)").FindString(s) + return lines[1], regexp.MustCompile("([0-9]+\\.[0-9]+\\.[0-9]+)").FindString(s) } diff --git a/api/package-lock.json b/api/package-lock.json new file mode 100644 index 0000000..4757c95 --- /dev/null +++ b/api/package-lock.json @@ -0,0 +1,903 @@ +{ + "name": "api", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "express": "^4.17.1", + "express-validator": "^6.9.2" + } + }, + "node_modules/accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "dependencies": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "node_modules/body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "dependencies": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "dependencies": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express-validator": { + "version": "6.9.2", + "resolved": "https://registry.npmjs.org/express-validator/-/express-validator-6.9.2.tgz", + "integrity": "sha512-Yqlsw2/uBobtBVkP+gnds8OMmVAEb3uTI4uXC93l0Ym5JGHgr8Vd4ws7oSo7GGYpWn5YCq4UePMEppKchURXrw==", + "dependencies": { + "lodash": "^4.17.20", + "validator": "^13.5.2" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.45.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.45.0.tgz", + "integrity": "sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.28", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.28.tgz", + "integrity": "sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ==", + "dependencies": { + "mime-db": "1.45.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "node_modules/proxy-addr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", + "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", + "dependencies": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "dependencies": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "dependencies": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + }, + "node_modules/serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/validator": { + "version": "13.5.2", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.5.2.tgz", + "integrity": "sha512-mD45p0rvHVBlY2Zuy3F3ESIe1h5X58GPfAtslBjY7EtTqGquZTj+VX/J4RnHWN8FKq0C9WRVt1oWAcytWRuYLQ==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "engines": { + "node": ">= 0.8" + } + } + }, + "dependencies": { + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + } + }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "requires": { + "safe-buffer": "5.1.2" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + } + }, + "express-validator": { + "version": "6.9.2", + "resolved": "https://registry.npmjs.org/express-validator/-/express-validator-6.9.2.tgz", + "integrity": "sha512-Yqlsw2/uBobtBVkP+gnds8OMmVAEb3uTI4uXC93l0Ym5JGHgr8Vd4ws7oSo7GGYpWn5YCq4UePMEppKchURXrw==", + "requires": { + "lodash": "^4.17.20", + "validator": "^13.5.2" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.45.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.45.0.tgz", + "integrity": "sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w==" + }, + "mime-types": { + "version": "2.1.28", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.28.tgz", + "integrity": "sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ==", + "requires": { + "mime-db": "1.45.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "proxy-addr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", + "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.1" + } + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "validator": { + "version": "13.5.2", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.5.2.tgz", + "integrity": "sha512-mD45p0rvHVBlY2Zuy3F3ESIe1h5X58GPfAtslBjY7EtTqGquZTj+VX/J4RnHWN8FKq0C9WRVt1oWAcytWRuYLQ==" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + } + } +} diff --git a/api/package.json b/api/package.json new file mode 100644 index 0000000..cf6bf15 --- /dev/null +++ b/api/package.json @@ -0,0 +1,16 @@ +{ + "name": "api", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "express": "^4.17.1", + "express-validator": "^6.9.2" + } +} diff --git a/api/src/index.js b/api/src/index.js new file mode 100644 index 0000000..1bb789f --- /dev/null +++ b/api/src/index.js @@ -0,0 +1,99 @@ +const { writeFile } = require('fs/promises'); +const express = require('express'); +const app = express(); +const languages = require('./languages'); +const { spawn, execFileSync } = require('child_process'); + +const versions = execFileSync(__dirname + '/../../lxc/versions') + .toString() + .toLowerCase() + .split('---') + .map(section => section.split('\n')) + .filter(section => section.length >= 2); + +function getVersion(language) { + return versions.find(section => section[0] === language?.name); +} + +for (const language of languages) { + // TODO: Add custom handlers for some languages + + language.version = getVersion(language); +} + +app.use(express.json()); + +app.post('/execute', (req, res) => { + const body = req.body; + + const language = languages.find(language => { + return language.aliases.includes(body.language?.toString()?.toLowerCase()); + }); + + if (!language) { + return res.status(400).json({ + code: 'unsupported_language', + message: `${body.language} is not supported by Piston`, + }); + } else if (!(body.source instanceof string)) { + return res.status(400).json({ + code: 'missing_source', + message: 'source field is invalid', + }); + } else if (body.args && !(body.args instanceof Array)) { + return res.status(400).json({ + code: 'invalid_args', + message: 'args field is not an array', + }); + } + + launch(res, language, body); +}); + +async function launch(res, language, body) { + const stamp = new Date().getTime(); + const sourceFile = `/tmp/${stamp}.code`; + + await writeFile(sourceFile, body.source); + + const process = spawn(__dirname + '/../../lxc/execute', [language.name, sourceFile, (body.args ?? []).join('\n')]); + + const result = { + ran: true, + language: language.name, + stderr: '', + stdout: '', + output: '', + }; + + if (language.version) + result.version = language.version; + + process.stderr.setEncoding('utf-8'); + process.stdout.setEncoding('utf-8'); + + process.stderr.addListener('data', chunk => { + result.stderr += chunk; + result.output += chunk; + }); + + process.stdout.addListener('data', chunk => { + result.stdout += chunk; + result.output += chunk; + }); + + result.stderr = result.stderr.substring(0, 65535); + result.stdout = result.stdout.substring(0, 65535); + result.output = result.output.substring(0, 65535); + + process.on('exit', () => { + res.json(result); + }); +} + +app.get('/versions', (req, res) => { + res.json(languages); +}); + +const PORT = 2000; +app.listen(PORT, () => console.log(`Listening on port ${PORT}`)); diff --git a/api/src/languages.js b/api/src/languages.js new file mode 100644 index 0000000..bee5db6 --- /dev/null +++ b/api/src/languages.js @@ -0,0 +1,118 @@ +module.exports = [ + { + name: 'nasm', + aliases: ['asm', 'nasm'], + }, + { + name: 'nasm64', + aliases: ['asm64', 'nasm64'], + }, + { + name: 'awk', + aliases: ['awk'], + }, + { + name: 'bash', + aliases: ['bash'], + }, + { + name: 'brainfuck', + aliases: ['bf', 'brainfuck'], + }, + { + name: 'c', + aliases: ['c'], + }, + { + name: 'csharp', + aliases: ['c#', 'cs', 'csharp'], + }, + { + name: 'cpp', + aliases: ['c++', 'cpp'], + }, + { + name: 'deno', + aliases: ['deno', 'denojs', 'denots'], + }, + { + name: 'ruby', + aliases: ['duby', 'rb', 'ruby'], + }, + { + name: 'emacs', + aliases: ['el', 'elisp', 'emacs'], + }, + { + name: 'elixir', + aliases: ['elixir'], + }, + { + name: 'haskell', + aliases: ['haskell', 'hs'], + }, + { + name: 'go', + aliases: ['go'], + }, + { + name: 'java', + aliases: ['java'], + }, + { + name: 'javascript', + aliases: ['javascript', 'js', 'node'], + }, + { + name: 'jelly', + aliases: ['jelly'], + }, + { + name: 'julia', + aliases: ['jl', 'julia'], + }, + { + name: 'kotlin', + aliases: ['kotlin'], + }, + { + name: 'lua', + aliases: ['lua'], + }, + { + name: 'paradoc', + aliases: ['paradoc'], + }, + { + name: 'perl', + aliases: ['perl'], + }, + { + name: 'php', + aliases: ['php', 'php3', 'php4', 'php5'], + }, + { + name: 'python3', + aliases: ['py', 'py3', 'python', 'python3'], + }, + { + name: 'python2', + aliases: ['python2'], + }, + { + name: 'r', + aliases: ['r'], + }, + { + name: 'rust', + aliases: ['rs', 'rust'], + }, + { + name: 'swift', + aliases: ['swift'], + }, + { + name: 'typescript', + aliases: ['ts', 'typescript'], + }, +]; diff --git a/api/start b/api/start index 9cf6e69..fe2024e 100755 --- a/api/start +++ b/api/start @@ -1,3 +1,3 @@ #!/usr/bin/env bash -go run main.go $* +node src diff --git a/lxc/execute b/lxc/execute index ba81715..c33d7f2 100755 --- a/lxc/execute +++ b/lxc/execute @@ -40,104 +40,10 @@ else fi exec 200>&- -bin= -case "$lang" in -"awk") - bin=awk - ;; -"bash") - bin=bash - ;; -"brainfuck" | "bf") - bin=brainfuck - ;; -"c") - bin=c - ;; -"cpp" | "c++") - bin=cpp - ;; -"csharp" | "cs" | "c#") - bin=csharp - ;; -"elixir" | "exs") - bin=elixir - ;; -"go") - bin=go - ;; -"haskell" | "hs") - bin=haskell - ;; -"java") - bin=java - ;; -"jelly") - bin=jelly - ;; -"julia" | "jl") - bin=julia - ;; -"kotlin") - bin=kotlin - ;; -"lua") - bin=lua - ;; -"nasm" | "asm") - bin=nasm - ;; -"nasm64" | "asm64") - bin=nasm64 - ;; -"node" | "js" | "javascript") - bin=node - ;; -"deno" | "denojs" | "denots") - bin=deno - ;; -"paradoc") - bin=paradoc - ;; -"perl") - bin=perl - ;; -"php") - bin=php - ;; -"python2") - bin=python2 - ;; -"python3" | "python") - bin=python3 - ;; -"ruby") - bin=ruby - ;; -"rust") - bin=rust - ;; -"swift") - bin=swift - ;; -"emacs" | "elisp" | "el") - bin=emacs - ;; -"bash") - bin=bash - ;; -"typescript" | "ts") - bin=typescript - ;; -*) - echo "invalid language" - exit -esac - # runner timeout -s KILL 20 \ lxc-attach --clear-env -n piston -- \ - /bin/bash -l -c "bash /exec/$bin $newinc $epoch" + /bin/bash -l -c "bash /exec/$lang $newinc $epoch" # process janitor lxc-attach --clear-env -n piston -- \ From 2bcd133edf3cf3be15934a19052074e5dee04fcb Mon Sep 17 00:00:00 2001 From: Vrganj Date: Thu, 14 Jan 2021 20:25:45 +0100 Subject: [PATCH 02/14] Fix validation, versions --- api/src/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/api/src/index.js b/api/src/index.js index 1bb789f..76c4e50 100644 --- a/api/src/index.js +++ b/api/src/index.js @@ -12,7 +12,7 @@ const versions = execFileSync(__dirname + '/../../lxc/versions') .filter(section => section.length >= 2); function getVersion(language) { - return versions.find(section => section[0] === language?.name); + return versions.find(section => section[0] === language?.name)?.slice(1).join('\n'); } for (const language of languages) { @@ -35,12 +35,12 @@ app.post('/execute', (req, res) => { code: 'unsupported_language', message: `${body.language} is not supported by Piston`, }); - } else if (!(body.source instanceof string)) { + } else if (typeof body.source !== 'string') { return res.status(400).json({ code: 'missing_source', message: 'source field is invalid', }); - } else if (body.args && !(body.args instanceof Array)) { + } else if (body.args && Array.isArray(body.args)) { return res.status(400).json({ code: 'invalid_args', message: 'args field is not an array', From 11b2520189dd936058a85c6b25b0f12bcc4789f7 Mon Sep 17 00:00:00 2001 From: Vrganj Date: Thu, 14 Jan 2021 20:26:41 +0100 Subject: [PATCH 03/14] Fix validation yet again --- api/src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/index.js b/api/src/index.js index 76c4e50..fb6ac06 100644 --- a/api/src/index.js +++ b/api/src/index.js @@ -40,7 +40,7 @@ app.post('/execute', (req, res) => { code: 'missing_source', message: 'source field is invalid', }); - } else if (body.args && Array.isArray(body.args)) { + } else if (body.args && !Array.isArray(body.args)) { return res.status(400).json({ code: 'invalid_args', message: 'args field is not an array', From 218fe8f0237bea24c6b326995b2804331006001d Mon Sep 17 00:00:00 2001 From: Vrganj Date: Thu, 14 Jan 2021 20:32:06 +0100 Subject: [PATCH 04/14] Fix versions --- api/src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/index.js b/api/src/index.js index fb6ac06..9210e16 100644 --- a/api/src/index.js +++ b/api/src/index.js @@ -8,7 +8,7 @@ const versions = execFileSync(__dirname + '/../../lxc/versions') .toString() .toLowerCase() .split('---') - .map(section => section.split('\n')) + .map(section => section.trim().split('\n')) .filter(section => section.length >= 2); function getVersion(language) { From c15f9a9942ee759c0e91ddc3c10ff328aa5367b8 Mon Sep 17 00:00:00 2001 From: Vrganj Date: Thu, 14 Jan 2021 21:06:26 +0100 Subject: [PATCH 05/14] Capture stderr when setting versions --- api/src/index.js | 47 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/api/src/index.js b/api/src/index.js index 9210e16..d510eb9 100644 --- a/api/src/index.js +++ b/api/src/index.js @@ -2,24 +2,43 @@ const { writeFile } = require('fs/promises'); const express = require('express'); const app = express(); const languages = require('./languages'); -const { spawn, execFileSync } = require('child_process'); +const { spawn } = require('child_process'); -const versions = execFileSync(__dirname + '/../../lxc/versions') - .toString() - .toLowerCase() - .split('---') - .map(section => section.trim().split('\n')) - .filter(section => section.length >= 2); +(function setVersions() { + let output = ''; -function getVersion(language) { - return versions.find(section => section[0] === language?.name)?.slice(1).join('\n'); -} + const process = spawn(__dirname + '/../../lxc/versions'); -for (const language of languages) { - // TODO: Add custom handlers for some languages + process.stdout.setEncoding('utf-8'); + process.stderr.setEncoding('utf-8'); - language.version = getVersion(language); -} + process.stdout.addListener('data', chunk => { + output += chunk; + }); + + process.stderr.addListener('data', chunk => { + output += chunk; + }); + + process.on('exit', () => { + const sections = output.toLowerCase().split('---'); + const versions = {}; + + for (let section of sections) { + section = section.trim().split('\n'); + + if (section.length >= 2) { + const language = section[0]; + + versions[language] = /\d.\d.\d/.exec(section.slice(1).join('\n'))?.[0]; + } + } + + for (const language of languages) { + language.version = versions[language.name]; + } + }); +})(); app.use(express.json()); From 3f301b8c1fe823de707282367f170d0ba777fc1a Mon Sep 17 00:00:00 2001 From: Vrganj Date: Thu, 14 Jan 2021 21:21:10 +0100 Subject: [PATCH 06/14] Fix version regex --- api/src/index.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/api/src/index.js b/api/src/index.js index d510eb9..e22b8cb 100644 --- a/api/src/index.js +++ b/api/src/index.js @@ -30,7 +30,13 @@ const { spawn } = require('child_process'); if (section.length >= 2) { const language = section[0]; - versions[language] = /\d.\d.\d/.exec(section.slice(1).join('\n'))?.[0]; + if (language === 'java') { + versions[language] = /\d+/.exec(section[2]); + } else if (language === 'emacs') { + versions[language] = /\d+\.\d+/.exec(section[2]); + } else { + versions[language] = /\d\.\d\.\d/.exec(section.slice(1).join('\n'))?.[0]; + } } } From 6fdf2d6061e0f5bc8effb667184b81c5b80786af Mon Sep 17 00:00:00 2001 From: Vrganj Date: Fri, 15 Jan 2021 20:40:18 +0100 Subject: [PATCH 07/14] Fixes --- api/src/index.js | 39 +++++++++++++++------------------------ api/src/languages.js | 6 +----- lxc/versions | 4 ++++ 3 files changed, 20 insertions(+), 29 deletions(-) diff --git a/api/src/index.js b/api/src/index.js index e22b8cb..825a472 100644 --- a/api/src/index.js +++ b/api/src/index.js @@ -4,47 +4,41 @@ const app = express(); const languages = require('./languages'); const { spawn } = require('child_process'); -(function setVersions() { - let output = ''; - +{ const process = spawn(__dirname + '/../../lxc/versions'); - process.stdout.setEncoding('utf-8'); - process.stderr.setEncoding('utf-8'); + let output = ''; + process.stderr.on('data', chunk => output += chunk); + process.stdout.on('data', chunk => output += chunk); - process.stdout.addListener('data', chunk => { - output += chunk; - }); - - process.stderr.addListener('data', chunk => { - output += chunk; - }); - process.on('exit', () => { const sections = output.toLowerCase().split('---'); const versions = {}; - for (let section of sections) { - section = section.trim().split('\n'); + for (const section of sections) { + const lines = section.trim().split('\n'); - if (section.length >= 2) { - const language = section[0]; + if (lines.length >= 2) { + const language = lines[0]; + + console.log(language); if (language === 'java') { - versions[language] = /\d+/.exec(section[2]); + versions[language] = /\d+/.exec(lines[1])?.[0]; } else if (language === 'emacs') { - versions[language] = /\d+\.\d+/.exec(section[2]); + versions[language] = /\d+\.\d+/.exec(lines[1])?.[0]; } else { - versions[language] = /\d\.\d\.\d/.exec(section.slice(1).join('\n'))?.[0]; + versions[language] = /\d+\.\d+\.\d+/.exec(section)?.[0]; } } } for (const language of languages) { + console.log(language.name, versions[language.name]) language.version = versions[language.name]; } }); -})(); +} app.use(express.json()); @@ -94,9 +88,6 @@ async function launch(res, language, body) { if (language.version) result.version = language.version; - process.stderr.setEncoding('utf-8'); - process.stdout.setEncoding('utf-8'); - process.stderr.addListener('data', chunk => { result.stderr += chunk; result.output += chunk; diff --git a/api/src/languages.js b/api/src/languages.js index bee5db6..34409cb 100644 --- a/api/src/languages.js +++ b/api/src/languages.js @@ -60,7 +60,7 @@ module.exports = [ aliases: ['java'], }, { - name: 'javascript', + name: 'node', aliases: ['javascript', 'js', 'node'], }, { @@ -99,10 +99,6 @@ module.exports = [ name: 'python2', aliases: ['python2'], }, - { - name: 'r', - aliases: ['r'], - }, { name: 'rust', aliases: ['rs', 'rust'], diff --git a/lxc/versions b/lxc/versions index d813719..583feb7 100755 --- a/lxc/versions +++ b/lxc/versions @@ -69,6 +69,10 @@ echo 'nasm' lxc-attach --clear-env -n piston -- /bin/bash -l -c "nasm -version" echo '---' +echo 'nasm64' +lxc-attach --clear-env -n piston -- /bin/bash -l -c "nasm -version" +echo '---' + echo 'node' lxc-attach --clear-env -n piston -- /bin/bash -l -c "node --version" echo '---' From bbbea5045acf2b42e46aa6ad30616a2ac7fbf3dd Mon Sep 17 00:00:00 2001 From: Vrganj Date: Fri, 15 Jan 2021 20:43:01 +0100 Subject: [PATCH 08/14] Remove debug --- api/src/index.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/api/src/index.js b/api/src/index.js index 825a472..fcbe547 100644 --- a/api/src/index.js +++ b/api/src/index.js @@ -21,8 +21,6 @@ const { spawn } = require('child_process'); if (lines.length >= 2) { const language = lines[0]; - console.log(language); - if (language === 'java') { versions[language] = /\d+/.exec(lines[1])?.[0]; } else if (language === 'emacs') { @@ -34,7 +32,6 @@ const { spawn } = require('child_process'); } for (const language of languages) { - console.log(language.name, versions[language.name]) language.version = versions[language.name]; } }); From a2457edc6fa689fdde099c1722d8cf9551d87c1d Mon Sep 17 00:00:00 2001 From: Vrganj Date: Fri, 15 Jan 2021 22:13:29 +0100 Subject: [PATCH 09/14] Trim output --- api/src/index.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/api/src/index.js b/api/src/index.js index fcbe547..a7c769f 100644 --- a/api/src/index.js +++ b/api/src/index.js @@ -95,13 +95,11 @@ async function launch(res, language, body) { result.output += chunk; }); - result.stderr = result.stderr.substring(0, 65535); - result.stdout = result.stdout.substring(0, 65535); - result.output = result.output.substring(0, 65535); + result.stderr = result.stderr.trim().substring(0, 65535); + result.stdout = result.stdout.trim().substring(0, 65535); + result.output = result.output.trim().substring(0, 65535); - process.on('exit', () => { - res.json(result); - }); + process.on('exit', () => res.json(result)); } app.get('/versions', (req, res) => { From c88abc3ac93de62466cbdc11daef87d36bd690eb Mon Sep 17 00:00:00 2001 From: Vrganj Date: Fri, 15 Jan 2021 22:47:04 +0100 Subject: [PATCH 10/14] Remove main.go, remove useless dependency --- api/main.go | 303 ----------------------------------------------- api/package.json | 3 +- 2 files changed, 1 insertion(+), 305 deletions(-) delete mode 100644 api/main.go diff --git a/api/main.go b/api/main.go deleted file mode 100644 index 2e7e378..0000000 --- a/api/main.go +++ /dev/null @@ -1,303 +0,0 @@ -package main - -import ( - "bytes" - "encoding/json" - "fmt" - "io/ioutil" - "net/http" - "os/exec" - "regexp" - "strings" - "time" -) - -type Inbound struct { - Language string `json:"language"` - Source string `json:"source"` - Args []string `json:"args"` -} - -type Problem struct { - Code string `json:"code"` - Message string `json:"message"` -} - -type Outbound struct { - Ran bool `json:"ran"` - Language string `json:"language"` - Version string `json:"version"` - Output string `json:"output"` - Stdout string `json:"stdout"` - Stderr string `json:"stderr"` -} - -type Language struct { - Name string `json:"name,omitempty"` - Version string `json:"version,omitempty"` - Aliases []string `json:"aliases,omitempty"` -} - -var instance int -var languages []Language - -func main() { - port := "2000" - - var err error - languages, err = UpdateVersions() - - if err != nil { - fmt.Println("could not get version info and therefore couldn't start") - fmt.Println(err) - return - } - - fmt.Println("starting api on port", port) - http.HandleFunc("/execute", Execute) - http.HandleFunc("/versions", Versions) - http.ListenAndServe(":"+port, nil) -} - -func Execute(res http.ResponseWriter, req *http.Request) { - res.Header().Set("Content-Type", "application/json") - - // get json - inbound := Inbound{} - message := json.NewDecoder(req.Body) - message.Decode(&inbound) - - whitelist := []string{ - "awk", - "bash", - "brainfuck", "bf", - "c", - "cpp", "c++", - "csharp", "cs", "c#", - "deno", "denojs", "denots", - "elixir", "exs", - "emacs", "elisp", "el", - "go", - "haskell", "hs", - "java", - "jelly", - "julia", "jl", - "kotlin", - "lua", - "nasm", "asm", - "nasm64", "asm64", - "node", "javascript", "js", - "perl", "pl", - "php", - "python2", - "python3", "python", - "paradoc", - "ruby", - "rust", - "swift", - "typescript", "ts", - } - - // check if the supplied language is supported - // now calls function and returns - for _, lang := range whitelist { - if lang == inbound.Language { - launch(inbound, res) - return - } - } - - // now only called when the language is not supported - problem := Problem{ - Code: "unsupported_language", - Message: inbound.Language + " is not supported by Piston", - } - - pres, _ := json.Marshal(problem) - - res.WriteHeader(http.StatusBadRequest) - res.Write(pres) -} - -func Versions(res http.ResponseWriter, req *http.Request) { - res.Header().Set("Content-Type", "application/json") - - data, _ := json.Marshal(languages) - - res.Write(data) -} - -type StdWriter struct { - combined *string - separate *string -} - -func (writer *StdWriter) Write(data []byte) (int, error) { - *writer.combined += string(data) - *writer.separate += string(data) - - return len(data), nil -} - -func launch(request Inbound, res http.ResponseWriter) { - stamp := time.Now().UnixNano() - - // write the code to temp dir - srcfile := fmt.Sprintf("/tmp/%d.code", stamp) - - ioutil.WriteFile(srcfile, []byte(request.Source), 0644) - - // set up the arguments to send to the execute command - cmd := exec.Command("../lxc/execute", request.Language, srcfile, strings.Join(request.Args, "\n")) - - // capture out/err - var stdout, stderr, combined string - - cmd.Stdout = &StdWriter{ - combined: &combined, - separate: &stdout, - } - - cmd.Stderr = &StdWriter{ - combined: &combined, - separate: &stderr, - } - - stdout = strings.TrimSpace(stdout) - stderr = strings.TrimSpace(stderr) - combined = strings.TrimSpace(combined) - - if len(stdout) > 65536 { - stdout = stdout[:65536] - } - - if len(stderr) > 65536 { - stderr = stdout[:65536] - } - - if len(combined) > 65536 { - combined = combined[:65536] - } - - err := cmd.Run() - - // get the executing version of the language - execlang := request.Language - - switch execlang { - case "bf": - execlang = "brainfuck" - case "c++": - execlang = "cpp" - case "cs", "c#": - execlang = "csharp" - case "denojs", "denots": - execlang = "deno" - case "el", "elisp": - execlang = "emacs" - case "exs": - execlang = "elixir" - case "hs": - execlang = "haskell" - case "asm": - execlang = "nasm" - case "asm64": - execlang = "nasm64" - case "js", "javascript": - execlang = "node" - case "jl": - execlang = "julia" - case "python": - execlang = "python3" - case "ts": - execlang = "typescript" - } - - // prepare response - outbound := Outbound{ - Ran: err == nil, - Language: request.Language, - Version: "", - Output: combined, - Stdout: stdout, - Stderr: stderr, - } - - // retrieve the language version - for _, lang := range languages { - if lang.Name == execlang { - outbound.Version = lang.Version - break - } - } - - response, _ := json.Marshal(outbound) - - res.Write(response) -} - -func UpdateVersions() ([]Language, error) { - langs, err := GetVersions() - - if err != nil { - return nil, err - } - - return langs, nil -} - -// get all the language and their current version -func GetVersions() ([]Language, error) { - var languages []Language - - res, err := ExecVersionScript() - - if err != nil { - return nil, err - } - - info := strings.Split(res, "---") - - for _, v := range info { - if len(v) < 2 { - continue - } - name, version := GetVersion(v) - languages = append(languages, Language{ - Name: name, - Version: version, - }) - } - - return languages, nil -} - -// run the script that retrieves all the language versions -func ExecVersionScript() (string, error) { - cmd := exec.Command("../lxc/versions") - - var stdout bytes.Buffer - cmd.Stdout = &stdout - cmd.Stderr = &stdout - - err := cmd.Run() - - return strings.ToLower(stdout.String()), err -} - -// return the language and its version -// most of the time it is easy to get the name and version -// but for some languages helper functions are used -func GetVersion(s string) (string, string) { - lines := strings.Split(s, "\n") - - if lines[1] == "java" { - return "java", regexp.MustCompile("([0-9]+)").FindString(lines[2]) - } - - if lines[1] == "emacs" { - return "emacs", regexp.MustCompile("([0-9]+\\.[0-9]+)").FindString(lines[2]) - } - - return lines[1], regexp.MustCompile("([0-9]+\\.[0-9]+\\.[0-9]+)").FindString(s) -} diff --git a/api/package.json b/api/package.json index cf6bf15..b55f17c 100644 --- a/api/package.json +++ b/api/package.json @@ -10,7 +10,6 @@ "author": "", "license": "ISC", "dependencies": { - "express": "^4.17.1", - "express-validator": "^6.9.2" + "express": "^4.17.1" } } From e80bb0372b5486bdb4276367ec97990e3dd7cd82 Mon Sep 17 00:00:00 2001 From: Vrganj Date: Sat, 16 Jan 2021 00:53:51 +0100 Subject: [PATCH 11/14] Use express-validator, refactor --- api/package.json | 3 +- api/src/execute.js | 46 ++++++++ api/src/index.js | 165 ++++++++++----------------- api/src/languages.js | 265 +++++++++++++++++++++++++------------------ lxc/execute | 6 +- readme.md | 2 +- 6 files changed, 261 insertions(+), 226 deletions(-) create mode 100644 api/src/execute.js diff --git a/api/package.json b/api/package.json index b55f17c..cf6bf15 100644 --- a/api/package.json +++ b/api/package.json @@ -10,6 +10,7 @@ "author": "", "license": "ISC", "dependencies": { - "express": "^4.17.1" + "express": "^4.17.1", + "express-validator": "^6.9.2" } } diff --git a/api/src/execute.js b/api/src/execute.js new file mode 100644 index 0000000..3642671 --- /dev/null +++ b/api/src/execute.js @@ -0,0 +1,46 @@ +const { writeFile } = require('fs/promises'); +const { spawn } = require('child_process'); + +async function execute(res, language, body) { + const stamp = new Date().getTime(); + const sourceFile = `/tmp/${stamp}.code`; + + await writeFile(sourceFile, body.source); + + const process = spawn(__dirname + '/../../lxc/execute', [ + language.name, + sourceFile, + body.args?.join('\n') ?? '', + ]); + + const result = { + ran: true, + language: language.name, + stderr: '', + stdout: '', + output: '', + }; + + if (language.version) + result.version = language.version; + + process.stderr.on('data', chunk => { + result.stderr += chunk; + result.output += chunk; + }); + + process.stdout.on('data', chunk => { + result.stdout += chunk; + result.output += chunk; + }); + + result.stderr = result.stderr.trim().substring(0, 65535); + result.stdout = result.stdout.trim().substring(0, 65535); + result.output = result.output.trim().substring(0, 65535); + + process.on('exit', () => res.json(result)); +} + +module.exports = { + execute, +}; diff --git a/api/src/index.js b/api/src/index.js index a7c769f..d0efee4 100644 --- a/api/src/index.js +++ b/api/src/index.js @@ -1,110 +1,63 @@ -const { writeFile } = require('fs/promises'); const express = require('express'); -const app = express(); -const languages = require('./languages'); -const { spawn } = require('child_process'); - -{ - const process = spawn(__dirname + '/../../lxc/versions'); - - let output = ''; - process.stderr.on('data', chunk => output += chunk); - process.stdout.on('data', chunk => output += chunk); - - process.on('exit', () => { - const sections = output.toLowerCase().split('---'); - const versions = {}; - - for (const section of sections) { - const lines = section.trim().split('\n'); - - if (lines.length >= 2) { - const language = lines[0]; - - if (language === 'java') { - versions[language] = /\d+/.exec(lines[1])?.[0]; - } else if (language === 'emacs') { - versions[language] = /\d+\.\d+/.exec(lines[1])?.[0]; - } else { - versions[language] = /\d+\.\d+\.\d+/.exec(section)?.[0]; - } - } - } - - for (const language of languages) { - language.version = versions[language.name]; - } - }); -} - -app.use(express.json()); - -app.post('/execute', (req, res) => { - const body = req.body; - - const language = languages.find(language => { - return language.aliases.includes(body.language?.toString()?.toLowerCase()); - }); - - if (!language) { - return res.status(400).json({ - code: 'unsupported_language', - message: `${body.language} is not supported by Piston`, - }); - } else if (typeof body.source !== 'string') { - return res.status(400).json({ - code: 'missing_source', - message: 'source field is invalid', - }); - } else if (body.args && !Array.isArray(body.args)) { - return res.status(400).json({ - code: 'invalid_args', - message: 'args field is not an array', - }); - } - - launch(res, language, body); -}); - -async function launch(res, language, body) { - const stamp = new Date().getTime(); - const sourceFile = `/tmp/${stamp}.code`; - - await writeFile(sourceFile, body.source); - - const process = spawn(__dirname + '/../../lxc/execute', [language.name, sourceFile, (body.args ?? []).join('\n')]); - - const result = { - ran: true, - language: language.name, - stderr: '', - stdout: '', - output: '', - }; - - if (language.version) - result.version = language.version; - - process.stderr.addListener('data', chunk => { - result.stderr += chunk; - result.output += chunk; - }); - - process.stdout.addListener('data', chunk => { - result.stdout += chunk; - result.output += chunk; - }); - - result.stderr = result.stderr.trim().substring(0, 65535); - result.stdout = result.stdout.trim().substring(0, 65535); - result.output = result.output.trim().substring(0, 65535); - - process.on('exit', () => res.json(result)); -} - -app.get('/versions', (req, res) => { - res.json(languages); -}); +const { execute } = require('./execute'); +const { languages } = require('./languages'); +const { checkSchema, validationResult } = require('express-validator'); const PORT = 2000; + +const app = express(); +app.use(express.json()); + +app.post( + '/execute', + checkSchema({ + language: { + in: 'body', + notEmpty: { + errorMessage: 'Supply a language field', + }, + isString: { + errorMessage: 'Supplied language is not a string', + }, + custom: { + options: value => languages.find(language => language.name === value?.toLowerCase()), + errorMessage: 'Supplied language is not supported by Piston', + }, + }, + source: { + in: 'body', + notEmpty: { + errorMessage: 'Supply a source field', + }, + isString: { + errorMessage: 'Supplied source is not a string', + }, + }, + args: { + in: 'body', + optional: true, + isArray: { + errorMessage: 'Supplied args is not an array', + }, + } + }), + (req, res) => { + const errors = validationResult(req).array(); + + if (errors.length === 0) { + const language = languages.find(language => + language.aliases.includes(req.body.language.toLowerCase()) + ); + + execute(res, language, req.body); + } else { + res.status(400).json({ + message: errors[0].msg, + }); + } + }, +); + +app.get('/versions', (_, res) => res.json(languages)); + app.listen(PORT, () => console.log(`Listening on port ${PORT}`)); diff --git a/api/src/languages.js b/api/src/languages.js index 34409cb..9fda547 100644 --- a/api/src/languages.js +++ b/api/src/languages.js @@ -1,114 +1,153 @@ -module.exports = [ - { - name: 'nasm', - aliases: ['asm', 'nasm'], - }, - { - name: 'nasm64', - aliases: ['asm64', 'nasm64'], - }, - { - name: 'awk', - aliases: ['awk'], - }, - { - name: 'bash', - aliases: ['bash'], - }, - { - name: 'brainfuck', - aliases: ['bf', 'brainfuck'], - }, - { - name: 'c', - aliases: ['c'], - }, - { - name: 'csharp', - aliases: ['c#', 'cs', 'csharp'], - }, - { - name: 'cpp', - aliases: ['c++', 'cpp'], - }, - { - name: 'deno', - aliases: ['deno', 'denojs', 'denots'], - }, - { - name: 'ruby', - aliases: ['duby', 'rb', 'ruby'], - }, - { - name: 'emacs', - aliases: ['el', 'elisp', 'emacs'], - }, - { - name: 'elixir', - aliases: ['elixir'], - }, - { - name: 'haskell', - aliases: ['haskell', 'hs'], - }, - { - name: 'go', - aliases: ['go'], - }, - { - name: 'java', - aliases: ['java'], - }, - { - name: 'node', - aliases: ['javascript', 'js', 'node'], - }, - { - name: 'jelly', - aliases: ['jelly'], - }, - { - name: 'julia', - aliases: ['jl', 'julia'], - }, - { - name: 'kotlin', - aliases: ['kotlin'], - }, - { - name: 'lua', - aliases: ['lua'], - }, - { - name: 'paradoc', - aliases: ['paradoc'], - }, - { - name: 'perl', - aliases: ['perl'], - }, - { - name: 'php', - aliases: ['php', 'php3', 'php4', 'php5'], - }, - { - name: 'python3', - aliases: ['py', 'py3', 'python', 'python3'], - }, - { - name: 'python2', - aliases: ['python2'], - }, - { - name: 'rust', - aliases: ['rs', 'rust'], - }, - { - name: 'swift', - aliases: ['swift'], - }, - { - name: 'typescript', - aliases: ['ts', 'typescript'], - }, +const { spawn } = require('child_process'); + +const languages = [ + { + name: 'nasm', + aliases: ['asm', 'nasm'], + }, + { + name: 'nasm64', + aliases: ['asm64', 'nasm64'], + }, + { + name: 'awk', + aliases: ['awk'], + }, + { + name: 'bash', + aliases: ['bash'], + }, + { + name: 'brainfuck', + aliases: ['bf', 'brainfuck'], + }, + { + name: 'c', + aliases: ['c'], + }, + { + name: 'csharp', + aliases: ['c#', 'cs', 'csharp'], + }, + { + name: 'cpp', + aliases: ['c++', 'cpp'], + }, + { + name: 'deno', + aliases: ['deno', 'denojs', 'denots'], + }, + { + name: 'ruby', + aliases: ['duby', 'rb', 'ruby'], + }, + { + name: 'emacs', + aliases: ['el', 'elisp', 'emacs'], + }, + { + name: 'elixir', + aliases: ['elixir'], + }, + { + name: 'haskell', + aliases: ['haskell', 'hs'], + }, + { + name: 'go', + aliases: ['go'], + }, + { + name: 'java', + aliases: ['java'], + }, + { + name: 'node', + aliases: ['javascript', 'js', 'node'], + }, + { + name: 'jelly', + aliases: ['jelly'], + }, + { + name: 'julia', + aliases: ['jl', 'julia'], + }, + { + name: 'kotlin', + aliases: ['kotlin'], + }, + { + name: 'lua', + aliases: ['lua'], + }, + { + name: 'paradoc', + aliases: ['paradoc'], + }, + { + name: 'perl', + aliases: ['perl'], + }, + { + name: 'php', + aliases: ['php', 'php3', 'php4', 'php5'], + }, + { + name: 'python3', + aliases: ['py', 'py3', 'python', 'python3'], + }, + { + name: 'python2', + aliases: ['python2'], + }, + { + name: 'rust', + aliases: ['rs', 'rust'], + }, + { + name: 'swift', + aliases: ['swift'], + }, + { + name: 'typescript', + aliases: ['ts', 'typescript'], + }, ]; + +{ + const process = spawn(__dirname + '/../../lxc/versions'); + + let output = ''; + process.stderr.on('data', chunk => output += chunk); + process.stdout.on('data', chunk => output += chunk); + + process.on('exit', () => { + const sections = output.toLowerCase().split('---'); + const versions = {}; + + for (const section of sections) { + const lines = section.trim().split('\n'); + + if (lines.length >= 2) { + const language = lines[0]; + + if (language === 'java') { + versions[language] = /\d+/.exec(lines[1])?.[0]; + } else if (language === 'emacs') { + versions[language] = /\d+\.\d+/.exec(lines[1])?.[0]; + } else { + versions[language] = /\d+\.\d+\.\d+/.exec(section)?.[0]; + } + } + } + + for (const language of languages) { + language.version = versions[language.name]; + } + }); +} + +module.exports = { + languages, +}; diff --git a/lxc/execute b/lxc/execute index c33d7f2..42d5b52 100755 --- a/lxc/execute +++ b/lxc/execute @@ -4,11 +4,7 @@ dir="$( cd "$( dirname "$0" )" && pwd )" touch $dir/lockfile -if [ -z "$1" ]; then - echo "invalid args" - exit -fi -if [ -z "$2" ]; then +if [ -z "$1" ] || [ -z "$2" ]; then echo "invalid args" exit fi diff --git a/readme.md b/readme.md index 4baecf8..5b2cb85 100644 --- a/readme.md +++ b/readme.md @@ -167,7 +167,7 @@ Content-Type: application/json - typescript #### Principle of Operation -Piston utilizes LXC as the primary mechanism for sandboxing. There is a small API written in Go which takes +Piston utilizes LXC as the primary mechanism for sandboxing. There is a small API written in Node which takes in execution requests and executes them in the container. High level, the API writes a temporary source and args file to `/tmp` and that gets mounted read-only along with the execution scripts into the container. The source file is either ran or compiled and ran (in the case of languages like c, c++, c#, go, etc.). From 420a104f5c228f2988f0b8d8908851fa30739d1b Mon Sep 17 00:00:00 2001 From: Vrganj Date: Sat, 16 Jan 2021 00:59:25 +0100 Subject: [PATCH 12/14] Check aliases instead of name directly --- api/src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/index.js b/api/src/index.js index d0efee4..c29a461 100644 --- a/api/src/index.js +++ b/api/src/index.js @@ -20,7 +20,7 @@ app.post( errorMessage: 'Supplied language is not a string', }, custom: { - options: value => languages.find(language => language.name === value?.toLowerCase()), + options: value => languages.find(language => language.aliases.includes(value?.toLowerCase())), errorMessage: 'Supplied language is not supported by Piston', }, }, From def096fbeabdbd490df05db10011fff189664402 Mon Sep 17 00:00:00 2001 From: Vrganj Date: Sat, 16 Jan 2021 01:03:49 +0100 Subject: [PATCH 13/14] Trim and subtring only after executing --- api/src/execute.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/api/src/execute.js b/api/src/execute.js index 3642671..1409a7b 100644 --- a/api/src/execute.js +++ b/api/src/execute.js @@ -34,11 +34,13 @@ async function execute(res, language, body) { result.output += chunk; }); - result.stderr = result.stderr.trim().substring(0, 65535); - result.stdout = result.stdout.trim().substring(0, 65535); - result.output = result.output.trim().substring(0, 65535); + process.on('exit', () => { + result.stderr = result.stderr.trim().substring(0, 65535); + result.stdout = result.stdout.trim().substring(0, 65535); + result.output = result.output.trim().substring(0, 65535); - process.on('exit', () => res.json(result)); + res.json(result); + }); } module.exports = { From d666e5c19d70511ed11a5a375bf8e89d219bfa42 Mon Sep 17 00:00:00 2001 From: Vrganj Date: Sat, 16 Jan 2021 01:07:34 +0100 Subject: [PATCH 14/14] Fix C/C++ versions --- lxc/versions | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lxc/versions b/lxc/versions index 583feb7..098cb92 100755 --- a/lxc/versions +++ b/lxc/versions @@ -14,11 +14,11 @@ echo '1.0.0' echo '---' echo 'c' -lxc-attach --clear-env -n piston -- /bin/bash -l -c "gcc -v" +lxc-attach --clear-env -n piston -- /bin/bash -l -c "gcc --version" echo '---' echo 'cpp' -lxc-attach --clear-env -n piston -- /bin/bash -l -c "g++ -v" +lxc-attach --clear-env -n piston -- /bin/bash -l -c "g++ --version" echo '---' echo 'csharp'