Update for new API

This commit is contained in:
Vrganj 2021-01-23 21:31:23 +01:00
commit c10a30b69a
78 changed files with 2063 additions and 868 deletions

1
api/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
node_modules

View File

@ -1,263 +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"`
}
type Language struct {
Name string `json:"name,omitempty"`
Version string `json:"version,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#",
"d",
"deno", "denojs", "denots",
"elixir", "exs",
"emacs", "elisp", "el",
"go",
"haskell", "hs",
"java",
"jelly",
"julia", "jl",
"kotlin",
"lua",
"nasm", "asm",
"nasm64", "asm64",
"nim",
"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.Write(pres)
}
func Versions(res http.ResponseWriter, req *http.Request) {
res.Header().Set("Content-Type", "application/json")
data, _ := json.Marshal(languages)
res.Write(data)
}
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 bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
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: strings.TrimSpace(stdout.String()),
}
// 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)
}

903
api/package-lock.json generated Normal file
View File

@ -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="
}
}
}

16
api/package.json Normal file
View File

@ -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"
}
}

79
api/src/index.js Normal file
View File

@ -0,0 +1,79 @@
const express = require('express');
const { execute } = require('../../shared/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: 'No language supplied',
},
isString: {
errorMessage: 'Supplied language is not a string',
},
custom: {
options: value => value && languages.find(language => language.aliases.includes(value.toLowerCase())),
errorMessage: 'Supplied language is not supported by Piston',
},
},
source: {
in: 'body',
notEmpty: {
errorMessage: 'No source supplied',
},
isString: {
errorMessage: 'Supplied source is not a string',
},
},
args: {
in: 'body',
optional: true,
isArray: {
errorMessage: 'Supplied args is not an array',
},
},
stdin: {
in: 'body',
optional: true,
isString: {
errorMessage: 'Supplied stdin is not a string',
},
}
}),
async (req, res) => {
const errors = validationResult(req).array();
if (errors.length === 0) {
const language = languages.find(language =>
language.aliases.includes(req.body.language.toLowerCase())
);
const { stdout, stderr, output, ran } = await execute(language, req.body.source, req.body.stdin, req.body.args);
res.status(200).json({
ran,
language: language.name,
version: language.version,
stdout,
stderr,
output,
});
} 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}`));

39
api/src/languages.js Normal file
View File

@ -0,0 +1,39 @@
const { spawn } = require('child_process');
const languages = require('../../shared/languages.json');
{
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,
};

View File

@ -1,3 +1,3 @@
#!/usr/bin/env bash #!/usr/bin/env bash
go run main.go $* node src

32
cli/execute Executable file
View File

@ -0,0 +1,32 @@
#!/usr/bin/env node
const { execute } = require('../shared/execute');
const { readFileSync } = require('fs');
const languages = require('../shared/languages.json');
const [languageName, sourceFile, ...args] = process.argv.slice(2);
(async () => {
if (!languageName) {
console.error('Provide a language name');
return;
}
if (!sourceFile) {
console.error('Provide a source file');
return;
}
const source = readFileSync(sourceFile).toString();
const language = languages.find(language => language.aliases.includes(languageName.toLowerCase()));
if (!language) {
console.error(`${languageName} is not supported by Piston`);
return;
}
const { output } = await execute(language, source, '', args);
console.log(output);
})();

View File

@ -4,11 +4,7 @@ dir="$( cd "$( dirname "$0" )" && pwd )"
touch $dir/lockfile touch $dir/lockfile
if [ -z "$1" ]; then if [ -z "$1" ] || [ -z "$2" ]; then
echo "invalid args"
exit
fi
if [ -z "$2" ]; then
echo "invalid args" echo "invalid args"
exit exit
fi fi
@ -18,13 +14,15 @@ epoch=$(date +%s%N)
basepath="/var/lib/lxc/piston/rootfs" basepath="/var/lib/lxc/piston/rootfs"
filepath="/tmp/$epoch/code.code" filepath="/tmp/$epoch/code.code"
argpath="/tmp/$epoch/args.args" argpath="/tmp/$epoch/args.args"
stdinpath="/tmp/$epoch/stdin.stdin"
arg=$(basename $argpath) arg=$(basename $argpath)
# write arg file # write arg file
mkdir -p $basepath/tmp/$epoch mkdir -p $basepath/tmp/$epoch
chmod 777 $basepath/tmp/$epoch chmod 777 $basepath/tmp/$epoch
cat $2 > $basepath$filepath cat $2 > $basepath$filepath
echo "${@:3}" > $basepath$argpath echo $3 > $basepath$stdinpath
echo -n "${@:4}" > $basepath$argpath
# process incrementor # process incrementor
exec 200>$dir/lockfile exec 200>$dir/lockfile
@ -40,116 +38,24 @@ else
fi fi
exec 200>&- 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
;;
"d")
bin=d
;;
"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
;;
"nim")
bin=nim
;;
"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 # runner
timeout -s KILL 10 \ timeout -s KILL 20 \
lxc-attach --clear-env -n piston -- \ lxc-attach --clear-env -n piston -- \
/bin/bash -l -c "bash /exec/$bin $newinc $epoch 2>&1 | head -c 65536" /bin/bash -l -c "runuser runner$newinc /exec/$lang $newinc $epoch"
# process janitor # process janitor
lxc-attach --clear-env -n piston -- \ lxc-attach --clear-env -n piston -- \
/bin/bash -l -c "\ /bin/bash -l -c "
for i in {1..100}; do pkill -u runner$newinc --signal SIGKILL; done ;\ for i in {1..100}
find /tmp -user runner$newinc -exec /bin/rm -rf {} \;\ do
pkill -u runner$newinc --signal SIGKILL
done
find /tmp -user runner$newinc -delete
find /var/tmp -user runner$newinc -delete
find /var/lock -user runner$newinc -delete
find /dev/shm -user runner$newinc -delete
find /run/lock -user runner$newinc -delete
" > /dev/null 2>&1 & " > /dev/null 2>&1 &
rm -rf $basepath/tmp/$epoch rm -rf $basepath/tmp/$epoch

View File

@ -1,4 +1,4 @@
#!/bin/bash
cd /tmp/$2 cd /tmp/$2
timeout -s KILL 2 sed "/___code___/Q" code.code > code.stdin timeout -s KILL 3 xargs -a args.args -d '\n' awk -f code.code < stdin.stdin
timeout -s KILL 2 sed "1,/___code___/d" code.code > code.awk
runuser runner$1 -c "cd /tmp/$2 ; timeout -s KILL 3 awk -f code.awk < code.stdin"

View File

@ -1,2 +1,4 @@
#!/bin/bash
cd /tmp/$2 cd /tmp/$2
runuser runner$1 -c "cd /tmp/$2 ; cat args.args | xargs -d '\n' timeout -s KILL 3 bash code.code" xargs -a args.args -d '\n' timeout -s KILL 3 bash code.code < stdin.stdin

View File

@ -1,2 +1,4 @@
#!/bin/bash
cd /tmp/$2 cd /tmp/$2
runuser runner$1 -c "cd /tmp/$2 ; cat args.args | xargs -d '\n' timeout -s KILL 3 brainfuck code.code" timeout -s KILL 3 xargs -a args.args -d '\n' brainfuck code.code < stdin.stdin

View File

@ -1,3 +1,5 @@
#!/usr/bin/bash
cd /tmp/$2 cd /tmp/$2
timeout -s KILL 10 gcc -std=c11 -o binary -x c code.code gcc -std=c11 -o binary -x c code.code
runuser runner$1 -c "cd /tmp/$2 ; cat args.args | xargs -d '\n' timeout -s KILL 3 ./binary" timeout -s KILL 3 xargs -a args.args ./binary < stdin.stdin

View File

@ -1,3 +1,5 @@
#!/bin/bash
cd /tmp/$2 cd /tmp/$2
timeout -s KILL 10 g++ -std=c++17 -o binary -x c++ code.code g++ -std=c++17 -o binary -x c++ code.code
runuser runner$1 -c "cd /tmp/$2 ; cat args.args | xargs -d '\n' timeout -s KILL 3 ./binary" timeout -s KILL 3 xargs -a args.args -d '\n' ./binary < stdin.stdin

View File

@ -1,3 +1,5 @@
#!/bin/bash
cd /tmp/$2 cd /tmp/$2
timeout -s KILL 10 mcs $(echo code.code | sed 's/\///') -nowarn:0219 -out:binary mcs $(echo code.code | sed 's/\///') -nowarn:0219 -out:binary
runuser runner$1 -c "cd /tmp/$2 ; cat args.args | xargs -d '\n' timeout -s KILL 3 mono binary" timeout -s KILL 3 xargs -a args.args -d '\n' mono binary < stdin.stdin

View File

@ -1,4 +1,6 @@
#!/bin/bash
cd /tmp/$2 cd /tmp/$2
cp code.code code.d cp code.code code.d
timeout -s KILL 10 dmd code.d timeout -s KILL 10 dmd code.d
runuser runner$1 -c "cd /tmp/$2 ; cat args.args | xargs -d '\n' timeout -s KILL 3 ./code" xtimeout -s KILL 3 args -a args.args -d '\n' ./code

View File

@ -1,7 +1,4 @@
cd /tmp/$2 #!/bin/bash
if [[ -z $(grep '[^[:space:]]' args.args) ]]; then cd /tmp/$2
runuser runner$1 -c "cd /tmp/$2 ; timeout -s KILL 3 deno run code.code" timeout -s KILL 3 xargs -a args.args -d '\n' deno run code.code < stdin.stdin
else
runuser runner$1 -c "cd /tmp/$2 ; cat args.args | xargs -d '\n' timeout -s KILL 3 deno run code.code"
fi

View File

@ -1,7 +1,6 @@
cd /tmp/$2 #!/bin/bash
if [[ -z $(grep '[^[:space:]]' args.args) ]]; then export LC_ALL="en_US.UTF-8"
runuser runner$1 -c "cd /tmp/$2 ; timeout -s KILL 3 elixir code.code"
else cd /tmp/$2
runuser runner$1 -c "cd /tmp/$2 ; cat args.args ; xargs -d '\n' timeout -s KILL 3 elixir code.code" timeout -s KILL 3 xargs -a args.args -d '\n' elixir code.code < stdin.stdin
fi

View File

@ -1,7 +1,4 @@
cd /tmp/$2 #!/bin/bash
if [[ -z $(grep '[^[:space:]]' args.args) ]]; then cd /tmp/$2
runuser -l runner$1 -c "cd /tmp/$2 ; timeout -s KILL 3 emacs -Q --script code.code" timeout -s KILL 3 xargs -a args.args -d '\n' emacs -Q --script code.code < stdin.stdin
else
runuser -l runner$1 -c "cd /tmp/$2 ; cat args.args | xargs -d '\n' timeout -s KILL 3 emacs -Q --script code.code"
fi

View File

@ -1,6 +1,6 @@
#!/bin/bash
cd /tmp/$2 cd /tmp/$2
cp code.code interim.go cp code.code interim.go
file="interim.go" go build interim.go
timeout -s KILL 10 go build $file timeout -s KILL 3 xargs -a args.args -d '\n' ./interim < stdin.stdin
file=${file%%.*}
runuser runner$1 -c "cd /tmp/$2 ; cat args.args | xargs -d '\n' timeout -s KILL 3 ./$file"

View File

@ -1,4 +1,6 @@
#!/bin/bash
cd /tmp/$2 cd /tmp/$2
mv code.code code.hs cp code.code code.hs
timeout -s KILL 10 ghc -dynamic -o binary code.hs > /dev/null 2>&1 ghc -dynamic -o binary code.hs > /dev/null 2>&1
runuser runner$1 -c "cd /tmp/$2 ; cat args.args | xargs -d '\n' timeout -s KILL 3 ./binary" timeout -s KILL 3 xargs -a args.args -d '\n' ./binary < stdin.stdin

View File

@ -1,6 +1,7 @@
#!/bin/bash
cd /tmp/$2 cd /tmp/$2
cp code.code interim.java name=$(grep -Po "(?<=\n|\A)\s*(public\s+)?(class|interface)\s+\K([^\/\\\\\n\s{]+)" code.code)
name=$(grep -Po "(?<=\n|\A)\s*(public\s+)?(class|interface)\s+\K([^\n\s{]+)" interim.java) cp code.code $name.java
mv interim.java $name.java javac $name.java
timeout -s KILL 10 javac $name.java timeout -s KILL 3 xargs -a args.args -d '\n' java $name < stdin.stdin
runuser runner$1 -c "cd /tmp/$2 ; cat args.args | xargs -d '\n' timeout -s KILL 3 java $name"

View File

@ -1,2 +1,4 @@
#!/bin/bash
cd /tmp/$2 cd /tmp/$2
runuser runner$1 -c "cd /tmp/$2 ; cat args.args | xargs -d '\n' timeout -s KILL 3 jelly fu code.code" timeout -s KILL 3 xargs -a args.args -d '\n' jelly fu code.code < stdin.stdin

View File

@ -1,2 +1,4 @@
#!/bin/bash
cd /tmp/$2 cd /tmp/$2
runuser runner$1 -c "cd /tmp/$2 ; cat args.args | xargs -d '\n' timeout -s KILL 3 julia code.code" timeout -s KILL 3 xargs -a args.args -d '\n' julia code.code < stdin.stdin

View File

@ -1,4 +1,6 @@
#!/bin/bash
cd /tmp/$2 cd /tmp/$2
cp code.code code.kt cp code.code code.kt
timeout -s KILL 10 kotlinc code.kt -include-runtime -d code.jar kotlinc code.kt -include-runtime -d code.jar
runuser runner$1 -c "cd /tmp/$2 ; cat args.args | xargs -d '\n' timeout -s KILL 3 java -jar code.jar" timeout -s KILL 3 xargs -a args.args -d '\n' java -jar code.jar < stdin.stdin

View File

@ -1,2 +1,4 @@
#!/bin/bash
cd /tmp/$2 cd /tmp/$2
runuser runner$1 -c "cd /tmp/$2 ; cat args.args | xargs -d '\n' timeout -s KILL 3 lua code.code" timeout -s KILL 3 xargs -a args.args -d '\n' lua code.code < stdin.stdin

View File

@ -1,4 +1,6 @@
#!/bin/bash
cd /tmp/$2 cd /tmp/$2
timeout -s KILL 10 nasm -f elf32 -o binary.o code.code nasm -f elf32 -o binary.o code.code
timeout -s KILL 10 ld -m elf_i386 binary.o -o binary ld -m elf_i386 binary.o -o binary
runuser runner$1 -c "cd /tmp/$2 ; cat args.args | xargs -d '\n' timeout -s KILL 3 ./binary" timeout -s KILL 3 xargs -a args.args -d '\n' ./binary < stdin.stdin

View File

@ -1,4 +1,6 @@
#!/bin/bash
cd /tmp/$2 cd /tmp/$2
timeout -s KILL 10 nasm -f elf64 -o binary.o code.code nasm -f elf64 -o binary.o code.code
timeout -s KILL 10 ld -m elf_x86_64 binary.o -o binary ld -m elf_x86_64 binary.o -o binary
runuser runner$1 -c "cd /tmp/$2 ; cat args.args | xargs -d '\n' timeout -s KILL 3 ./binary" timeout -s KILL 3 xargs -a args.args -d '\n' ./binary < stdin.stdin

View File

@ -1,4 +0,0 @@
cd /tmp/$2
timeout -s KILL 10 nim --hints:off c code.code
runuser runner$1 -c "cd /tmp/$2 ; cat args.args | xargs -d '\n' timeout -s KILL 3 ./code"

View File

@ -1,7 +1,4 @@
cd /tmp/$2 #!/bin/bash
if [[ -z $(grep '[^[:space:]]' args.args) ]]; then cd /tmp/$2
runuser runner$1 -c "cd /tmp/$2 ; timeout -s KILL 3 node code.code" timeout -s KILL 3 xargs -a args.args -d '\n' node code.code < stdin.stdin
else
runuser runner$1 -c "cd /tmp/$2 ; cat args.args | xargs -d '\n' timeout -s KILL 3 node code.code"
fi

View File

@ -1,2 +1,5 @@
#!/bin/bash
cd /tmp/$2 cd /tmp/$2
runuser runner$1 -c "cd /tmp/$2 ; timeout -s KILL 3 python3 -m paradoc code.code <<< args.args" export PYTHONPATH=$PYTHONPATH:/opt/paradoc
timeout -s KILL 3 python3.8 -m paradoc code.code < args.args

View File

@ -1,2 +1,4 @@
#!/bin/bash
cd /tmp/$2 cd /tmp/$2
runuser runner$1 -c "cd /tmp/$2 ; cat args.args | xargs -d '\n' timeout -s KILL 3 perl code.code" timeout -s KILL 3 xargs -a args.args -d '\n' perl code.code < stdin.stdin

View File

@ -1,2 +1,4 @@
#!/bin/bash
cd /tmp/$2 cd /tmp/$2
runuser runner$1 -c "cd /tmp/$2 ; cat args.args | xargs -d '\n' timeout -s KILL 3 php code.code" timeout -s KILL 3 xargs -a args.args -d '\n' php code.code < stdin.stdin

View File

@ -1,2 +1,4 @@
#!/bin/bash
cd /tmp/$2 cd /tmp/$2
runuser runner$1 -c "cd /tmp/$2 ; cat args.args | xargs -d '\n' timeout -s KILL 3 python code.code" timeout -s KILL 3 xargs -a args.args -d '\n' python code.code < stdin.stdin

View File

@ -1,2 +1,4 @@
#!/bin/bash
cd /tmp/$2 cd /tmp/$2
runuser runner$1 -c "cd /tmp/$2 ; cat args.args | xargs -d '\n' timeout -s KILL 3 python3.8 code.code" timeout -s KILL 3 xargs -a args.args -d '\n' python3.8 code.code < stdin.stdin

View File

@ -1,2 +1,4 @@
#!/bin/bash
cd /tmp/$2 cd /tmp/$2
runuser runner$1 -c "cd /tmp/$2 ; cat args.args | xargs -d '\n' timeout -s KILL 3 ruby code.code" timeout -s KILL 3 xargs -a args.args -d '\n' ruby code.code < stdin.stdin

View File

@ -1,3 +1,5 @@
#!/bin/bash
cd /tmp/$2 cd /tmp/$2
timeout -s KILL 10 rustc -o binary code.code rustc -o binary code.code
runuser runner$1 -c "cd /tmp/$2 ; cat args.args | xargs -d '\n' timeout -s KILL 3 ./binary" timeout -s KILL 3 xargs -a args.args -d '\n' ./binary < stdin.stdin

View File

@ -1,2 +1,4 @@
#!/bin/bash
cd /tmp/$2 cd /tmp/$2
runuser runner$1 -c "cd /tmp/$2 ; cat args.args | xargs -d '\n' timeout -s KILL 3 swift code.code" timeout -s KILL 3 xargs -a args.args -d '\n' swift code.code < stdin.stdin

View File

@ -1,6 +1,8 @@
#!/bin/bash
cd /tmp/$2 cd /tmp/$2
mv code.code interim.ts mv code.code interim.ts
timeout -s KILL 10 tsc interim.ts tsc interim.ts
rm interim.ts rm -f interim.ts
mv interim.js code.code mv interim.js code.code
runuser runner$1 -c "cd /tmp/$2 ; cat args.args | xargs -d '\n' timeout -s KILL 3 node code.code" timeout -s KILL 3 xargs -a args.args -d '\n' node code.code < stdin.stdin

View File

@ -3,7 +3,7 @@
mkdir -p /var/lib/lxc/piston/rootfs/exec mkdir -p /var/lib/lxc/piston/rootfs/exec
rm -f /var/lib/lxc/piston/rootfs/exec/* rm -f /var/lib/lxc/piston/rootfs/exec/*
cp -f executors/* /var/lib/lxc/piston/rootfs/exec cp -f executors/* /var/lib/lxc/piston/rootfs/exec
chmod 700 /var/lib/lxc/piston/rootfs/exec/* chmod 555 /var/lib/lxc/piston/rootfs/exec/*
chown -R root:root /var/lib/lxc/piston/rootfs/exec chown -R root:root /var/lib/lxc/piston/rootfs/exec
lxc-start -n piston -d lxc-start -n piston -d

View File

@ -1,57 +1,57 @@
#!/usr/bin/env bash #!/usr/bin/env bash
cd tests cd tests
echo 'testing awk' echo -n 'testing awk = '
../execute awk test.awk ../../cli/execute awk awk.awk
echo 'testing c' echo -n 'testing bash = '
../execute c test.c ../../cli/execute bash bash.sh
echo 'testing cpp' echo -n 'testing c = '
../execute cpp test.cpp ../../cli/execute c c.c
echo 'testing cs' echo -n 'testing cpp = '
../execute cs test.cs ../../cli/execute cpp cpp.cpp
echo 'testing d' echo -n 'testing csharp = '
../execute d test.d ../../cli/execute csharp csharp.cs
echo 'testing deno ts' echo -n 'testing d = '
../execute deno testdeno.ts ../../cli/execute d test.d
echo 'testing elisp' echo -n 'testing deno = '
../execute elisp test.el ../../cli/execute deno deno.ts
echo 'testing elixir' echo -n 'testing elixir = '
../execute exs test.exs ../../cli/execute elixir elixir.exs
echo 'testing go' echo -n 'testing emacs = '
../execute go test.go ../../cli/execute emacs emacs.el
echo 'testing haskell' echo -n 'testing go = '
../execute haskell test.hs ../../cli/execute go go.go
echo 'testing java' echo -n 'testing haskell = '
../execute java test.java ../../cli/execute haskell haskell.hs
echo 'testing jl' echo -n 'testing java = '
../execute jl test.jl ../../cli/execute java java.java
echo 'testing js' echo -n 'testing jelly = '
../execute js test.js ../../cli/execute jelly jelly.jelly good
echo 'testing kotlin' echo -n 'testing julia = '
../execute kotlin test.kt ../../cli/execute julia julia.jl
echo 'testing asm 32 bit' echo -n 'testing kotlin = '
../execute asm test.nasm ../../cli/execute kotlin kotlin.kt
echo 'testing asm 64 bit' echo -n 'testing nasm 32 bit = '
../execute asm64 test64.nasm ../../cli/execute nasm nasm.nasm
echo 'testing nim' echo -n 'testing nasm 64 bit = '
../execute nim test.nim ../../cli/execute nasm64 nasm64.nasm
echo 'testing php' echo -n 'testing node = '
../execute php test.php ../../cli/execute node node.js
echo 'testing perl' echo -n 'testing paradoc = '
../execute perl test.pl ../../cli/execute bash paradoc.sh
echo 'testing ruby' echo -n 'testing perl = '
../execute ruby test.rb ../../cli/execute perl perl.pl
echo 'testing rust' echo -n 'testing php = '
../execute rust test.rs ../../cli/execute php php.php
echo 'testing bash' echo -n 'testing python2 = '
../execute bash test.sh ../../cli/execute python2 python2.py
echo 'testing swift' echo -n 'testing python3 = '
../execute swift test.swift ../../cli/execute python3 python3.py
echo 'testing typescript' echo -n 'testing ruby = '
../execute typescript test.ts ../../cli/execute ruby ruby.rb
echo 'testing python2' echo -n 'testing rust = '
../execute python2 test2.py ../../cli/execute rust rust.rs
echo 'testing python3' echo -n 'testing swift = '
../execute python3 test3.py ../../cli/execute swift swift.swift
echo 'testing paradoc' echo -n 'testing typescript = '
../execute python3 test_paradoc.py ../../cli/execute typescript typescript.ts

1
lxc/tests/awk.awk Normal file
View File

@ -0,0 +1 @@
{ print "good" }

1
lxc/tests/jelly.jelly Normal file
View File

@ -0,0 +1 @@
³

3
lxc/tests/kotlin.kt Normal file
View File

@ -0,0 +1,3 @@
fun main() {
println("good")
}

18
lxc/tests/nasm64.nasm Normal file
View File

@ -0,0 +1,18 @@
SECTION .data
good: db "good", 0x0
txtlen: equ $ - good
SECTION .text
GLOBAL _start
_start:
;sys_write
mov rax, 1
mov rdi, 1
mov rsi, good
mov rdx, txtlen
syscall
;sys_exit
mov rax, 60
mov rdi, 0
syscall

11
lxc/tests/paradoc.sh Normal file
View File

@ -0,0 +1,11 @@
#!/usr/bin/env bash
# add paradoc module to python python
export PYTHONPATH=$PYTHONPATH:/opt/paradoc
# file for test code
test_code=/tmp/paradoc.test
# save test code to file
echo -n iP>$test_code
# pass param to paradoc module and have it print it
echo good | python3.8 -m paradoc $test_code
# clean test code
rm -f $test_code

View File

@ -1,3 +0,0 @@
good
___code___
{ print }

View File

@ -1,3 +0,0 @@
fun main(args: Array<String>) {
println("good")
}

View File

@ -1,18 +0,0 @@
SECTION .data
good: db "good", 0x0a, 0x0
txtlen: equ $ - good
SECTION .text
GLOBAL _start
_start:
;sys_write
mov rax, 1
mov rdi, 1
mov rsi, good
mov rdx, txtlen
syscall
;sys_exit
mov rax, 60
mov rdi, 0
syscall

View File

@ -1,5 +0,0 @@
try:
import paradoc
print('good')
except:
pass

View File

@ -14,11 +14,11 @@ echo '1.0.0'
echo '---' echo '---'
echo 'c' 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 '---'
echo 'cpp' 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 '---'
echo 'csharp' echo 'csharp'
@ -73,8 +73,8 @@ echo 'nasm'
lxc-attach --clear-env -n piston -- /bin/bash -l -c "nasm -version" lxc-attach --clear-env -n piston -- /bin/bash -l -c "nasm -version"
echo '---' echo '---'
echo 'nim' echo 'nasm64'
lxc-attach --clear-env -n piston -- /bin/bash -l -c "nim -v | head -n1" lxc-attach --clear-env -n piston -- /bin/bash -l -c "nasm -version"
echo '---' echo '---'
echo 'node' echo 'node'
@ -94,11 +94,11 @@ lxc-attach --clear-env -n piston -- /bin/bash -l -c "python -V"
echo '---' echo '---'
echo 'python3' echo 'python3'
lxc-attach --clear-env -n piston -- /bin/bash -l -c "python3 -V" lxc-attach --clear-env -n piston -- /bin/bash -l -c "python3.8 -V"
echo '---' echo '---'
echo 'paradoc' echo 'paradoc'
lxc-attach --clear-env -n piston -- /bin/bash -l -c "python3 -m paradoc --version" lxc-attach --clear-env -n piston -- /bin/bash -l -c "python3.8 -m paradoc --version"
echo '---' echo '---'
echo 'ruby' echo 'ruby'

547
readme.md
View File

@ -1,348 +1,220 @@
## Piston <h1 align="center">
Piston is the underlying engine for running untrusted and possibly malicious <a href="https://github.com/engineer-man/piston"><img src="https://emkc.org/images/icon_circle_24.png" alt="engineer-man piston"></a>
code that originates from EMKC contests and challenges. It's also used in the Piston
Engineer Man Discord server via [I Run Code](https://github.com/engineer-man/piston-bot) bot as well as 1000+ other servers. </h1>
<h3 align="center">A high performance general purpose code execution engine.</h3>
<br>
<p align="center">
<a href="https://github.com/ArmynC/ArminC-AutoExec/commits/master">
<img src="https://img.shields.io/github/last-commit/engineer-man/piston.svg?style=for-the-badge&logo=github&logoColor=white"
alt="GitHub last commit">
<a href="https://github.com/engineer-man/piston/issues">
<img src="https://img.shields.io/github/issues/engineer-man/piston.svg?style=for-the-badge&logo=github&logoColor=white"
alt="GitHub issues">
<a href="https://github.com/engineer-man/piston/pulls">
<img src="https://img.shields.io/github/issues-pr-raw/engineer-man/piston.svg?style=for-the-badge&logo=github&logoColor=white"
alt="GitHub pull requests">
</p>
---
<h4 align="center">
<a href="#About">About</a>
<a href="#Public-API">Public API</a>
<a href="#Getting-Started">Getting Started</a>
<a href="#Usage">Usage</a>
<a href="#Supported-Languages">Supported Languages</a>
<a href="#Principle-of-Operation">Principles</a>
<a href="#Security">Security</a>
<a href="#License">License</a>
</h4>
---
<br>
# About
<h4>
Piston is a high performance general purpose code execution engine. It excels at running untrusted and
possibly malicious code without fear from any harmful effects.
</h4>
<br>
It's used in numerous places including:
* [EMKC Challenges](https://emkc.org/challenges),
* [EMKC Weekly Contests](https://emkc.org/contests),
* [Engineer Man Discord Server](https://discord.gg/engineerman),
* [I Run Code (Discord Bot)](https://github.com/engineer-man/piston-bot) bot as well as 1300+ other servers
and 100+ direct integrations.
To get it in your own server, go here: https://emkc.org/run. To get it in your own server, go here: https://emkc.org/run.
#### Use Public API (new) <br>
Requires no installation and you can use it immediately. Reference the API Usage section below to learn
about the request format but rather than using the local URLs, use the following URLs:
- `GET` `https://emkc.org/api/v1/piston/versions`
- `POST` `https://emkc.org/api/v1/piston/execute`
Important Note: The Piston API is rate limited to 5 requests per second # Public API
- Requires no installation and you can use it immediately.
- Reference the Versions/Execute sections below to learn about the request and response formats.
<br>
When using the public Piston API, use the base URL:
#### Installation
``` ```
# clone and enter repo https://emkc.org/api/v1/piston
git clone https://github.com/engineer-man/piston ```
cd piston/lxc
# install dependencies #### GET
```
https://emkc.org/api/v1/piston/versions
```
#### POST
```
https://emkc.org/api/v1/piston/execute
```
> Important Note: The Piston API is rate limited to 5 requests per second. If you have a need for more requests than that
and it's for a good cause, please reach out to me (EngineerMan#0001) on [Discord](https://discord.gg/engineerman)
so we can discuss potentially getting you an unlimited key.
<br>
# Getting Started
### Host System Package Dependencies
* NodeJS
* lxc
* libvirt
<br>
If your OS is not documented below, please open pull requests with the correct commands for your OS.
<details>
<summary><span style="font-size:1.43em;">CentOS / RHEL</span></summary>
```sh
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.37.2/install.sh | bash
nvm install --lts
nvm use --lts
# centos:
yum install -y epel-release yum install -y epel-release
yum install -y lxc lxc-templates debootstrap libvirt yum install -y lxc lxc-templates debootstrap libvirt
systemctl start libvirtd systemctl start libvirtd
```
</details>
# ubuntu server 18.04: <details>
apt install lxc lxc-templates debootstrap libvirt0 <summary><span style="font-size:1.43em;">Ubuntu (18.04)</span></summary>
# arch: ```sh
sudo pacman -S lxc libvirt unzip curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.37.2/install.sh | bash
nvm install --lts
nvm use --lts
# everything else: apt install -y lxc lxc-templates debootstrap libvirt0
# not documented, please open pull requests with commands for debian/arch/macos ```
</details>
# create and start container <details>
lxc-create -t download -n piston -- --dist ubuntu --release bionic --arch amd64 <summary><span style="font-size:1.43em;">Arch Linux</span></summary>
./start
# open a shell to the container ```sh
./shell curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.37.2/install.sh | bash
nvm install --lts
nvm use --lts
# install all necessary piston dependencies pacman -S lxc libvirt unzip
echo 'source /opt/.profile' >> /opt/.bashrc ```
echo 'export HOME=/opt' >> /opt/.profile </details>
echo 'export TERM=linux' >> /opt/.profile
echo 'export PATH=$PATH:/opt/.local/bin' >> /opt/.profile
export HOME=/opt
export TERM=linux
sed -i 's/\/root/\/opt/' /etc/passwd
sed -i \
's/http:\/\/archive.ubuntu.com\/ubuntu/http:\/\/mirror.math.princeton.edu\/pub\/ubuntu/' \
/etc/apt/sources.list
apt-get update
apt-get install -y \
nano wget build-essential pkg-config libxml2-dev \
libsqlite3-dev mono-complete curl cmake libpython2.7-dev \
ruby libtinfo-dev unzip
# install python2 #### After system dependencies are installed, clone this repository:
# final binary: /opt/python2/Python-2.7.17/python
# get version: /opt/python2/Python-2.7.17/python -V
cd /opt && mkdir python2 && cd python2
wget https://www.python.org/ftp/python/2.7.17/Python-2.7.17.tar.xz
unxz Python-2.7.17.tar.xz
tar -xf Python-2.7.17.tar
cd Python-2.7.17
./configure
# open Modules/Setup and uncomment zlib line
make
echo 'export PATH=$PATH:/opt/python2/Python-2.7.17' >> /opt/.profile
source /opt/.profile
# install python3 ```sh
# final binary: /opt/python3/Python-3.8.2/python # clone and enter repo
# get version: /opt/python3/Python-3.8.2/python -V git clone https://github.com/engineer-man/piston
cd /opt && mkdir python3 && cd python3 cd piston/lxc
wget https://www.python.org/ftp/python/3.8.2/Python-3.8.2.tar.xz
unxz Python-3.8.2.tar.xz
tar -xf Python-3.8.2.tar
cd Python-3.8.2
./configure
make
ln -s python python3.8
echo 'export PATH=$PATH:/opt/python3/Python-3.8.2' >> /opt/.profile
source /opt/.profile
# install paradoc
# this is not a binary, it is a python module
# therefore it cannot be run directly as it requires python3 to be installed
cd /opt && mkdir paradoc && cd paradoc
git clone https://github.com/betaveros/paradoc.git
echo 'export PYTHONPATH=$PYTHONPATH:/opt/paradoc/paradoc' >> /opt/.profile
source /opt/.profile
# install node.js
# final binary: /opt/nodejs/node-v12.16.1-linux-x64/bin/node
# get version: /opt/nodejs/node-v12.16.1-linux-x64/bin/node -v
cd /opt && mkdir nodejs && cd nodejs
wget https://nodejs.org/dist/v12.16.1/node-v12.16.1-linux-x64.tar.xz
unxz node-v12.16.1-linux-x64.tar.xz
tar -xf node-v12.16.1-linux-x64.tar
echo 'export PATH=$PATH:/opt/nodejs/node-v12.16.1-linux-x64/bin' >> /opt/.profile
source /opt/.profile
# install typescript
# final binary: /opt/nodejs/node-v12.16.1-linux-x64/bin/tsc
# get version: /opt/nodejs/node-v12.16.1-linux-x64/bin/tsc -v
/opt/nodejs/node-v12.16.1-linux-x64/bin/npm i -g typescript
# install golang
# final binary: /opt/go/go/bin/go
# get version: /opt/go/go/bin/go version
cd /opt && mkdir go && cd go
wget https://dl.google.com/go/go1.14.1.linux-amd64.tar.gz
tar -xzf go1.14.1.linux-amd64.tar.gz
echo 'export PATH=$PATH:/opt/go/go/bin' >> /opt/.profile
echo 'export GOROOT=/opt/go/go' >> /opt/.profile
echo 'export GOCACHE=/tmp' >> /opt/.profile
source /opt/.profile
# install php
# final binary: /usr/local/bin/php
# get version: /usr/local/bin/php -v
cd /opt && mkdir php && cd php
wget https://www.php.net/distributions/php-7.4.4.tar.gz
tar -xzf php-7.4.4.tar.gz
cd php-7.4.4
./configure
make
make install
# install rust
# final binary: /opt/.cargo/bin/rustc
# get version: /opt/.cargo/bin/rustc --version
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
echo 'export PATH=$PATH:/opt/.cargo/bin' >> /opt/.profile
source /opt/.profile
# install swift
# final binary: /opt/swift/swift-5.1.5-RELEASE-ubuntu18.04/usr/bin/swift
# get version: /opt/swift/swift-5.1.5-RELEASE-ubuntu18.04/usr/bin/swift --version
cd /opt && mkdir swift && cd swift
wget https://swift.org/builds/swift-5.1.5-release/ubuntu1804/swift-5.1.5-RELEASE/swift-5.1.5-RELEASE-ubuntu18.04.tar.gz
tar -xzf swift-5.1.5-RELEASE-ubuntu18.04.tar.gz
echo 'export PATH=$PATH:/opt/swift/swift-5.1.5-RELEASE-ubuntu18.04/usr/bin' >> /opt/.profile
source /opt/.profile
# install nasm
# final binary: /opt/nasm/nasm-2.14.02/nasm
# get version: /opt/nasm/nasm-2.14.02/nasm -v
cd /opt && mkdir nasm && cd nasm
wget https://www.nasm.us/pub/nasm/releasebuilds/2.14.02/nasm-2.14.02.tar.gz
tar -xzf nasm-2.14.02.tar.gz
cd nasm-2.14.02
./configure
make
echo 'export PATH=$PATH:/opt/nasm/nasm-2.14.02' >> /opt/.profile
source /opt/.profile
# install java
# final binary: /opt/java/jdk-14/bin/java
# get version: /opt/java/jdk-14/bin/java -version
cd /opt && mkdir java && cd java
wget https://download.java.net/java/GA/jdk14/076bab302c7b4508975440c56f6cc26a/36/GPL/openjdk-14_linux-x64_bin.tar.gz
tar -xzf openjdk-14_linux-x64_bin.tar.gz
echo 'export PATH=$PATH:/opt/java/jdk-14/bin' >> /opt/.profile
source /opt/.profile
# install jelly
cd /opt && mkdir jelly && cd jelly
wget https://github.com/DennisMitchell/jellylanguage/archive/master.zip
unzip master.zip
cd jellylanguage-master
pip3.8 install .
# install julia
# final binary: /opt/julia/julia-1.5.0/bin/julia
# get version: /opt/julia/julia-1.5.0/bin/julia --version
cd /opt && mkdir julia && cd julia
wget https://julialang-s3.julialang.org/bin/linux/x64/1.5/julia-1.5.0-linux-x86_64.tar.gz
tar -xzf julia-1.5.0-linux-x86_64.tar.gz
echo 'export PATH=$PATH:/opt/julia/julia-1.5.0/bin' >> /opt/.profile
source /opt/.profile
# install kotlin
# final binary: /opt/kotlinc/bin/kotlinc
# get version: /opt/kotlinc/bin/kotlinc -version
cd /opt
wget https://github.com/JetBrains/kotlin/releases/download/v1.4.10/kotlin-compiler-1.4.10.zip
unzip kotlin-compiler-1.4.10.zip
rm kotlin-compiler-1.4.10.zip
echo 'export PATH=$PATH:/opt/kotlinc/bin' >> /opt/.profile
source /opt/.profile
# install elixir and erlang
# final binary: /opt/elixir/bin/elixir
# get version: /opt/elixir/bin/elixir --version
# erlang
cd /opt && mkdir erlang && cd erlang
wget http://erlang.org/download/otp_src_23.0.tar.gz
gunzip -c otp_src_23.0.tar.gz | tar xf -
cd otp_src_23.0 && ./configure
make
echo 'export PATH=$PATH:/opt/erlang/otp_src_23.0/bin' >> /opt/.profile
source /opt/.profile
# elixir
cd /opt && mkdir elixir && cd elixir
wget https://github.com/elixir-lang/elixir/releases/download/v1.10.3/Precompiled.zip
mkdir elixir-1.10.3 && unzip Precompiled.zip -d elixir-1.10.3/
echo 'export PATH=$PATH:/opt/elixir/elixir-1.10.3/bin' >> /opt/.profile
source /opt/.profile
# install emacs
# final binary: /opt/emacs/emacs-26.3/src/emacs
# get version: /opt/emacs/emacs-26.3/src/emacs --version
cd /opt && mkdir emacs && cd emacs
wget https://mirrors.ocf.berkeley.edu/gnu/emacs/emacs-26.3.tar.xz
tar -xf emacs-26.3.tar.xz
cd emacs-26.3
./configure --with-gnutls=no
make
echo 'export PATH=$PATH:/opt/emacs/emacs-26.3/src' >> /opt/.profile
source /opt/.profile
# install lua
# final binary: /opt/lua/lua54/src/lua
# get version: /opt/lua/lua54/src/lua -v
cd /opt && mkdir lua && cd lua
wget https://sourceforge.net/projects/luabinaries/files/5.4.0/Docs%20and%20Sources/lua-5.4.0_Sources.tar.gz/download
tar -xzf download
cd lua54
make
echo 'export PATH=$PATH:/opt/lua/lua54/src' >> /opt/.profile
source /opt/.profile
# install haskell
# final binary: /usr/bin/ghc
# get version: /usr/bin/ghc --version
apt install -y ghc
# install deno
# final binary: /opt/.deno/bin/deno
# get version: /opt/.deno/bin/deno --version
cd /opt && mkdir deno && cd deno
curl -fsSL https://deno.land/x/install/install.sh | sh
echo 'export DENO_INSTALL="/opt/.deno"' >> /opt/.profile
echo 'export PATH="$DENO_INSTALL/bin:$PATH"' >> /opt/.profile
source /opt/.profile
# install nim
# final binary: /opt/nim/bin/nim
# get version: /opt/nim/bin/nim -v
cd /opt && mkdir nim && cd nim
wget https://nim-lang.org/download/nim-1.4.0-linux_x64.tar.xz
unxz nim-1.4.0-linux_x64.tar.xz
tar -xf nim-1.4.0-linux_x64.tar
cd nim-1.4.0
./install.sh /opt
echo 'export PATH=$PATH:/opt/nim/bin' >> /opt/.profile
source /opt/.profile
# install d
# final binary: /opt/d/dmd2/linux/bin64/dmd
# get version: /opt/d/dmd2/linux/bin64/dmd --version
cd /opt && mkdir d && cd d
wget http://downloads.dlang.org/releases/2.x/2.095.0/dmd.2.095.0.linux.tar.xz
unxz dmd.2.095.0.linux.tar.xz
tar -xf dmd.2.095.0.linux.tar
echo 'export PATH=$PATH:/opt/d/dmd2/linux/bin64' >> /opt/.profile
source /opt/.profile
# create runnable users and apply limits
for i in {1..150}; do
useradd -M runner$i
usermod -d /tmp runner$i
echo "runner$i soft nproc 64" >> /etc/security/limits.conf
echo "runner$i hard nproc 64" >> /etc/security/limits.conf
echo "runner$i soft nofile 2048" >> /etc/security/limits.conf
echo "runner$i hard nofile 2048" >> /etc/security/limits.conf
done
# cleanup
rm -rf /home/ubuntu
chmod 777 /tmp
# leave container
exit
# optionally run tests
cd ../tests
./test_all_lxc
``` ```
#### CLI Usage #### Installation (simple)
- `lxc/execute [language] [file path] [arg]...`
- Coming soon.
#### Installation (advanced)
- See `var/install.txt` for how to create a new LXC container and install all of the required
software.
#### CLI Usage
- `cli/execute [language] [file path] [args]`
<br>
# Usage
### CLI
```sh
lxc/execute [language] [file path] [args]
```
### API
To use the API, it must first be started. Please note that if root is required to access
LXC then the API must also be running as root. To start the API, run the following:
#### API Usage
To use the API, it must first be started. To start the API, run the following:
``` ```
cd api cd api
./start ./start
``` ```
#### Base URLs For your own local installation, the API is available at:
For your own local installation, use:
``` ```
http://127.0.0.1:2000 http://127.0.0.1:2000
``` ```
When using the public Piston API, use:
```
https://emkc.org/api/v1/piston
```
#### Versions Endpoint #### Versions Endpoint
`GET /versions` `GET /versions`
This endpoint takes no input and returns a JSON array of the currently installed languages. This endpoint will return the supported languages along with the current version and aliases. To execute
code for a particular language using the `/execute` endpoint, either the name or one of the aliases must
Truncated response sample: be provided.
```json ```json
HTTP/1.1 200 OK
Content-Type: application/json
[ [
{ {
"name": "awk", "name": "awk",
"aliases": ["awk"],
"version": "1.3.3" "version": "1.3.3"
}, },
{ {
"name": "bash", "name": "bash",
"aliases": ["bash"],
"version": "4.4.20" "version": "4.4.20"
}, },
{ {
"name": "c", "name": "c",
"aliases": ["c"],
"version": "7.5.0" "version": "7.5.0"
} }
] ]
``` ```
#### Execution Endpoint #### Execute Endpoint
`POST /execute` `POST /execute`
This endpoint takes the following JSON payload and expects at least the language and source. If This endpoint requests execution of some arbitrary code.
source is not provided, a blank file is passed as the source. - `language` (**required**) The language to use for execution, must be a string and supported by Piston (see list below).
- `source` (**required**) The source code to execute, must be a string.
- `stdin` (*optional*) The text to pass as stdin to the program. Must be a string or left out of the request.
- `args` (*optional*) The arguments to pass to the program. Must be an array or left out of the request.
```json ```json
{ {
"language": "js", "language": "js",
"source": "console.log(process.argv)", "source": "console.log(process.argv)",
"stdin": "",
"args": [ "args": [
"1", "1",
"2", "2",
@ -350,58 +222,76 @@ source is not provided, a blank file is passed as the source.
] ]
} }
``` ```
A typical response when everything succeeds will be similar to the following: A typical response upon successful execution will contain the `language`, `version`, `output` which
is a combination of both `stdout` and `stderr` but in chronological order according to program output,
as well as separate `stdout` and `stderr`.
```json ```json
HTTP/1.1 200 OK
Content-Type: application/json
{ {
"ran": true, "ran": true,
"language": "js", "language": "js",
"version": "12.13.0", "version": "12.13.0",
"output": "[ '/usr/bin/node',\n '/tmp/code.code',\n '1',\n '2',\n '3' ]" "output": "[ '/usr/bin/node',\n '/tmp/code.code',\n '1',\n '2',\n '3' ]",
"stdout": "[ '/usr/bin/node',\n '/tmp/code.code',\n '1',\n '2',\n '3' ]",
"stderr": ""
} }
``` ```
If an invalid language is supplied, a typical response will look like the following: If a problem exists with the request, a `400` status code is returned and the reason in the `message` key.
```json ```json
HTTP/1.1 400 Bad Request
Content-Type: application/json
{ {
"code": "unsupported_language", "message": "Supplied language is not supported by Piston"
"message": "whatever is not supported by Piston"
} }
``` ```
#### Supported Languages <br>
- awk
- bash
- c
- cpp
- csharp
- d
- deno
- elixir
- emacs
- go
- haskell
- java
- jelly
- julia
- kotlin
- nasm
- node
- perl
- php
- python2
- python3
- paradoc
- ruby
- rust
- swift
- typescript
#### Principle of Operation # Supported Languages
Piston utilizes LXC as the primary mechanism for sandboxing. There is a small API written in Go which takes `awk`,
`bash`,
`brainfuck`,
`c`,
`cpp`,
`csharp`,
`d`,
`deno`,
`elixir`,
`emacs`,
`elisp`,
`go`,
`haskell`,
`java`,
`jelly`,
`julia`,
`kotlin`,
`lua`,
`nasm`,
`node`,
`paradoc`,
`perl`,
`php`,
`python2`,
`python3`,
`ruby`,
`rust`,
`swift`,
`typescript`,
<br>
# Principle of Operation
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 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. 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.). The source file is either ran or compiled and ran (in the case of languages like c, c++, c#, go, etc.).
#### Security <br>
# Security
LXC provides a great deal of security out of the box in that it's separate from the system. LXC provides a great deal of security out of the box in that it's separate from the system.
Piston takes additional steps to make it resistant to Piston takes additional steps to make it resistant to
various privilege escalation, denial-of-service, and resource saturation threats. These steps include: various privilege escalation, denial-of-service, and resource saturation threats. These steps include:
@ -409,10 +299,13 @@ various privilege escalation, denial-of-service, and resource saturation threats
- Capping max processes at 64 (resists `:(){ :|: &}:;`, `while True: os.fork()`, etc.) - Capping max processes at 64 (resists `:(){ :|: &}:;`, `while True: os.fork()`, etc.)
- Capping max files at 2048 (resists various file based attacks) - Capping max files at 2048 (resists various file based attacks)
- Mounting all resources read-only (resists `sudo rm -rf --no-preserve-root /`) - Mounting all resources read-only (resists `sudo rm -rf --no-preserve-root /`)
- Cleaning up all temp space after each execution (resists out of drive space attacks)
- Running as a variety of unprivileged users - Running as a variety of unprivileged users
- Capping runtime execution at 3 seconds - Capping runtime execution at 3 seconds
- Capping stdout to 65536 characters (resists yes/no bombs and runaway output) - Capping stdout to 65536 characters (resists yes/no bombs and runaway output)
- SIGKILLing misbehaving code - SIGKILLing misbehaving code
#### License <br>
# License
Piston is licensed under the MIT license. Piston is licensed under the MIT license.

57
shared/execute.js Normal file
View File

@ -0,0 +1,57 @@
const { writeFileSync, unlinkSync } = require('fs');
const { spawn } = require('child_process');
const OUTPUT_LIMIT = 65535;
function execute(language, source, stdin = '', args = []) {
return new Promise(resolve => {
const stamp = new Date().getTime();
const sourceFile = `/tmp/${stamp}.code`;
writeFileSync(sourceFile, source);
const process = spawn(__dirname + '/../lxc/execute', [
language.name,
sourceFile,
stdin,
args.join('\n'),
]);
let stdout = '';
let stderr = '';
let output = '';
process.stderr.on('data', chunk => {
if (stderr.length >= OUTPUT_LIMIT) return;
stderr += chunk;
output += chunk;
});
process.stdout.on('data', chunk => {
if (stdout.length >= OUTPUT_LIMIT) return;
stdout += chunk;
output += chunk;
});
process.on('exit', code => {
unlinkSync(sourceFile);
stderr = stderr.trim().substring(0, OUTPUT_LIMIT);
stdout = stdout.trim().substring(0, OUTPUT_LIMIT);
output = output.trim().substring(0, OUTPUT_LIMIT);
resolve({
stdout,
stderr,
output,
ran: code === 0,
});
});
});
}
module.exports = {
execute,
};

209
shared/languages.json Normal file
View File

@ -0,0 +1,209 @@
[
{
"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",
"cc",
"cxx"
]
},
{
"name": "d",
"aliases": [
"dlang",
"d"
]
},
{
"name": "deno",
"aliases": [
"deno",
"denojs",
"denots"
]
},
{
"name": "ruby",
"aliases": [
"duby",
"rb",
"ruby"
]
},
{
"name": "emacs",
"aliases": [
"el",
"elisp",
"emacs"
]
},
{
"name": "elixir",
"aliases": [
"elixir",
"exs"
]
},
{
"name": "haskell",
"aliases": [
"haskell",
"hs"
]
},
{
"name": "go",
"aliases": [
"go",
"golang"
]
},
{
"name": "java",
"aliases": [
"java"
]
},
{
"name": "node",
"aliases": [
"javascript",
"js",
"node",
"node.js"
]
},
{
"name": "jelly",
"aliases": [
"jelly"
]
},
{
"name": "julia",
"aliases": [
"jl",
"julia"
]
},
{
"name": "kotlin",
"aliases": [
"kotlin",
"kt"
]
},
{
"name": "lua",
"aliases": [
"lua"
]
},
{
"name": "paradoc",
"aliases": [
"paradoc"
]
},
{
"name": "perl",
"aliases": [
"perl",
"pl"
]
},
{
"name": "php",
"aliases": [
"php",
"php3",
"php4",
"php5"
]
},
{
"name": "python3",
"aliases": [
"py",
"py3",
"python",
"python3"
]
},
{
"name": "python2",
"aliases": [
"python2",
"py2"
]
},
{
"name": "rust",
"aliases": [
"rs",
"rust"
]
},
{
"name": "swift",
"aliases": [
"swift"
]
},
{
"name": "typescript",
"aliases": [
"ts",
"typescript"
]
}
]

262
var/install.txt Normal file
View File

@ -0,0 +1,262 @@
# create and start container
lxc-create -t download -n piston -- --dist ubuntu --release bionic --arch amd64
./start
# open a shell to the container
./shell
# install all necessary piston dependencies
echo 'source /opt/.profile' >> /opt/.bashrc
echo 'export HOME=/opt' >> /opt/.profile
echo 'export TERM=linux' >> /opt/.profile
echo 'export PATH=$PATH:/opt/.local/bin' >> /opt/.profile
export HOME=/opt
export TERM=linux
sed -i 's/\/root/\/opt/' /etc/passwd
sed -i \
's/http:\/\/archive.ubuntu.com\/ubuntu/http:\/\/mirror.math.princeton.edu\/pub\/ubuntu/' \
/etc/apt/sources.list
apt-get update
apt-get install -y \
nano wget build-essential pkg-config libxml2-dev \
libsqlite3-dev mono-complete curl cmake libpython2.7-dev \
ruby libtinfo-dev unzip git openssl libssl-dev
# install python2
# final binary: /opt/python2/Python-2.7.17/python
# get version: /opt/python2/Python-2.7.17/python -V
cd /opt && mkdir python2 && cd python2
wget https://www.python.org/ftp/python/2.7.17/Python-2.7.17.tar.xz
unxz Python-2.7.17.tar.xz
tar -xf Python-2.7.17.tar
cd Python-2.7.17
./configure
# open Modules/Setup and uncomment zlib line
make
echo 'export PATH=$PATH:/opt/python2/Python-2.7.17' >> /opt/.profile
source /opt/.profile
# install python3
# final binary: /opt/python3/Python-3.8.2/python
# get version: /opt/python3/Python-3.8.2/python -V
cd /opt && mkdir python3 && cd python3
wget https://www.python.org/ftp/python/3.8.2/Python-3.8.2.tar.xz
unxz Python-3.8.2.tar.xz
tar -xf Python-3.8.2.tar
cd Python-3.8.2
./configure
make
ln -s python python3.8
echo 'export PATH=$PATH:/opt/python3/Python-3.8.2' >> /opt/.profile
source /opt/.profile
# install paradoc
# this is not a binary, it is a python module
# therefore it cannot be run directly as it requires python3 to be installed
cd /opt && mkdir paradoc && cd paradoc
git clone https://github.com/betaveros/paradoc.git
# install node.js
# final binary: /opt/nodejs/node-v12.16.1-linux-x64/bin/node
# get version: /opt/nodejs/node-v12.16.1-linux-x64/bin/node -v
cd /opt && mkdir nodejs && cd nodejs
wget https://nodejs.org/dist/v12.16.1/node-v12.16.1-linux-x64.tar.xz
unxz node-v12.16.1-linux-x64.tar.xz
tar -xf node-v12.16.1-linux-x64.tar
echo 'export PATH=$PATH:/opt/nodejs/node-v12.16.1-linux-x64/bin' >> /opt/.profile
source /opt/.profile
# install typescript
# final binary: /opt/nodejs/node-v12.16.1-linux-x64/bin/tsc
# get version: /opt/nodejs/node-v12.16.1-linux-x64/bin/tsc -v
/opt/nodejs/node-v12.16.1-linux-x64/bin/npm i -g typescript
# install golang
# final binary: /opt/go/go/bin/go
# get version: /opt/go/go/bin/go version
cd /opt && mkdir go && cd go
wget https://dl.google.com/go/go1.14.1.linux-amd64.tar.gz
tar -xzf go1.14.1.linux-amd64.tar.gz
echo 'export PATH=$PATH:/opt/go/go/bin' >> /opt/.profile
echo 'export GOROOT=/opt/go/go' >> /opt/.profile
echo 'export GOCACHE=/tmp' >> /opt/.profile
source /opt/.profile
# install php
# final binary: /usr/local/bin/php
# get version: /usr/local/bin/php -v
cd /opt && mkdir php && cd php
wget https://www.php.net/distributions/php-7.4.4.tar.gz
tar -xzf php-7.4.4.tar.gz
cd php-7.4.4
./configure
make
make install
# install rust
# final binary: /usr/local/bin/rustc
# get version: /usr/local/bin/rustc --version
cd /opt && mkdir rust && cd rust
wget https://static.rust-lang.org/dist/rust-1.49.0-x86_64-unknown-linux-gnu.tar.gz
tar -xzf rust-1.49.0-x86_64-unknown-linux-gnu.tar.gz
cd rust-1.49.0-x86_64-unknown-linux-gnu
./install.sh
# install swift
# final binary: /opt/swift/swift-5.1.5-RELEASE-ubuntu18.04/usr/bin/swift
# get version: /opt/swift/swift-5.1.5-RELEASE-ubuntu18.04/usr/bin/swift --version
cd /opt && mkdir swift && cd swift
wget https://swift.org/builds/swift-5.1.5-release/ubuntu1804/swift-5.1.5-RELEASE/swift-5.1.5-RELEASE-ubuntu18.04.tar.gz
tar -xzf swift-5.1.5-RELEASE-ubuntu18.04.tar.gz
echo 'export PATH=$PATH:/opt/swift/swift-5.1.5-RELEASE-ubuntu18.04/usr/bin' >> /opt/.profile
source /opt/.profile
# install nasm
# final binary: /opt/nasm/nasm-2.14.02/nasm
# get version: /opt/nasm/nasm-2.14.02/nasm -v
cd /opt && mkdir nasm && cd nasm
wget https://www.nasm.us/pub/nasm/releasebuilds/2.14.02/nasm-2.14.02.tar.gz
tar -xzf nasm-2.14.02.tar.gz
cd nasm-2.14.02
./configure
make
echo 'export PATH=$PATH:/opt/nasm/nasm-2.14.02' >> /opt/.profile
source /opt/.profile
# install java
# final binary: /opt/java/jdk-14/bin/java
# get version: /opt/java/jdk-14/bin/java -version
cd /opt && mkdir java && cd java
wget https://download.java.net/java/GA/jdk14/076bab302c7b4508975440c56f6cc26a/36/GPL/openjdk-14_linux-x64_bin.tar.gz
tar -xzf openjdk-14_linux-x64_bin.tar.gz
echo 'export PATH=$PATH:/opt/java/jdk-14/bin' >> /opt/.profile
source /opt/.profile
# install jelly
cd /opt && mkdir jelly && cd jelly
wget https://github.com/DennisMitchell/jellylanguage/archive/master.zip
unzip master.zip
cd jellylanguage-master
python3.8 -m pip install .
sed -i 's/\/usr\/local\/bin\/python3.8/\/opt\/python3\/Python-3.8.2\/python3.8/' /usr/local/bin/jelly
# install julia
# final binary: /opt/julia/julia-1.5.0/bin/julia
# get version: /opt/julia/julia-1.5.0/bin/julia --version
cd /opt && mkdir julia && cd julia
wget https://julialang-s3.julialang.org/bin/linux/x64/1.5/julia-1.5.0-linux-x86_64.tar.gz
tar -xzf julia-1.5.0-linux-x86_64.tar.gz
echo 'export PATH=$PATH:/opt/julia/julia-1.5.0/bin' >> /opt/.profile
source /opt/.profile
# install kotlin
# final binary: /opt/kotlinc/bin/kotlinc
# get version: /opt/kotlinc/bin/kotlinc -version
cd /opt
wget https://github.com/JetBrains/kotlin/releases/download/v1.4.10/kotlin-compiler-1.4.10.zip
unzip kotlin-compiler-1.4.10.zip
rm kotlin-compiler-1.4.10.zip
echo 'export PATH=$PATH:/opt/kotlinc/bin' >> /opt/.profile
source /opt/.profile
# install elixir and erlang
# final binary: /opt/elixir/bin/elixir
# get version: /opt/elixir/bin/elixir --version
# erlang
cd /opt && mkdir erlang && cd erlang
wget http://erlang.org/download/otp_src_23.0.tar.gz
gunzip -c otp_src_23.0.tar.gz | tar xf -
cd otp_src_23.0 && ./configure
make
echo 'export PATH=$PATH:/opt/erlang/otp_src_23.0/bin' >> /opt/.profile
source /opt/.profile
# elixir
cd /opt && mkdir elixir && cd elixir
wget https://github.com/elixir-lang/elixir/releases/download/v1.10.3/Precompiled.zip
mkdir elixir-1.10.3 && unzip Precompiled.zip -d elixir-1.10.3/
echo 'export PATH=$PATH:/opt/elixir/elixir-1.10.3/bin' >> /opt/.profile
source /opt/.profile
# install emacs
# final binary: /opt/emacs/emacs-26.3/src/emacs
# get version: /opt/emacs/emacs-26.3/src/emacs --version
cd /opt && mkdir emacs && cd emacs
wget https://mirrors.ocf.berkeley.edu/gnu/emacs/emacs-26.3.tar.xz
tar -xf emacs-26.3.tar.xz
rm emacs-26.3.tar.xz
cd emacs-26.3
./configure --with-gnutls=no
make
echo 'export PATH=$PATH:/opt/emacs/emacs-26.3/src' >> /opt/.profile
source /opt/.profile
# install lua
# final binary: /opt/lua/lua54/src/lua
# get version: /opt/lua/lua54/src/lua -v
cd /opt && mkdir lua && cd lua
wget https://sourceforge.net/projects/luabinaries/files/5.4.0/Docs%20and%20Sources/lua-5.4.0_Sources.tar.gz/download
tar -xzf download
cd lua54
make
echo 'export PATH=$PATH:/opt/lua/lua54/src' >> /opt/.profile
source /opt/.profile
# install haskell
# final binary: /usr/bin/ghc
# get version: /usr/bin/ghc --version
apt install -y ghc
# install deno
# final binary: /opt/.deno/bin/deno
# get version: /opt/.deno/bin/deno --version
cd /opt && mkdir deno && cd deno
curl -fsSL https://deno.land/x/install/install.sh | sh
echo 'export DENO_INSTALL="/opt/.deno"' >> /opt/.profile
echo 'export PATH="$DENO_INSTALL/bin:$PATH"' >> /opt/.profile
source /opt/.profile
# install brainfuck
cd /opt && mkdir bf && cd bf
git clone https://github.com/texus/Brainfuck-interpreter
cd Brainfuck-interpreter
echo 'export PATH=$PATH:/opt/bf/Brainfuck-interpreter' >> /opt/.profile
source /opt/.profile
# install d
# final binary: /opt/d/dmd2/linux/bin64/dmd
# get version: /opt/d/dmd2/linux/bin64/dmd --version
cd /opt && mkdir d && cd d
wget http://downloads.dlang.org/releases/2.x/2.095.0/dmd.2.095.0.linux.tar.xz
unxz dmd.2.095.0.linux.tar.xz
tar -xf dmd.2.095.0.linux.tar
echo 'export PATH=$PATH:/opt/d/dmd2/linux/bin64' >> /opt/.profile
source /opt/.profile
# create runnable users and apply limits
for i in {1..150}; do
useradd -M runner$i
usermod -d /tmp runner$i
echo "runner$i soft nproc 64" >> /etc/security/limits.conf
echo "runner$i hard nproc 64" >> /etc/security/limits.conf
echo "runner$i soft nofile 2048" >> /etc/security/limits.conf
echo "runner$i hard nofile 2048" >> /etc/security/limits.conf
done
# remove any lingering write access to others
cd /opt
chown -R root: *
chmod -R o-w *
# cleanup
rm -rf /home/ubuntu
chmod 777 /tmp
# disable cron
systemctl stop cron
systemctl disable cron
# leave container
exit
# optionally run tests
./test_all_lxc

24
var/notes.txt Normal file
View File

@ -0,0 +1,24 @@
# make piston image
lxc-clone -KMP /mnt/piston_image piston piston
sed -i 's/\/mnt\/piston_image/\/var\/lib\/lxc/' piston/config
tar -czf piston.tar.gz piston/
# restore piston image
cd /var/lib/lxc
tar -xzf piston.tar.gz
```
# get piston image
cd /var/lib/lxc
wget whatever url
tar -xzf piston.tar.gz
sed -i "s/virtbr0/$(ip a | grep br0: | cut -d' ' -f2 | sed 's/://gi')/" piston/config
# start piston
cd /path/to/piston/lxc
./start
```