diff --git a/cmd/packets/main.go b/cmd/packets/main.go new file mode 100644 index 0000000..7b9ddcf --- /dev/null +++ b/cmd/packets/main.go @@ -0,0 +1,103 @@ +package main + +import ( + "database/sql" + "errors" + "fmt" + "log" + "os" + "packets/internal" + "path/filepath" + "time" + + "github.com/pelletier/go-toml/v2" + "github.com/spf13/cobra" + _ "modernc.org/sqlite" +) + +// Consts + +const DefaultLinux_d = "/etc/packets" +const DefaultLANDeadline = 2 * time.Second + +// Errors + +var ErrResponseNot200OK = errors.New("the request is not 200, download failed") + +// Types + +type ConfigTOML struct { + Config struct { + HttpPort int `toml:"httpPort"` + Cache_d string `toml:"cache_d"` + Data_d string `toml:"data_d"` + Bin_d string `toml:"bin_d"` + } `toml:"Config"` +} + +// init is doing some verifications +func init() { + + _, err := os.Stat(DefaultLinux_d) + if os.IsNotExist(err) { + err := os.Mkdir(DefaultLinux_d, 0644) + if err != nil { + if os.IsPermission(err) { + fmt.Println("can't create packets root directory, please run as root") + os.Exit(1) + } else { + log.Fatal(err) + } + } + } + + _, err = os.Stat(filepath.Join(DefaultLinux_d, "index.db")) + if err != nil { + + if os.IsNotExist(err) { + fmt.Println("index.db does not exist use \"packets sync\"") + } else { + log.Fatal(err) + } + } + + _, err = os.Stat(filepath.Join(DefaultLinux_d, "installed.db")) + if err != nil { + if os.IsNotExist(err) { + db, err := sql.Open("sqlite", filepath.Join(DefaultLinux_d, "installed.db")) + if err != nil { + log.Fatal(db) + } + defer db.Close() + db.Exec("CREATE TABLE IF NOT EXISTS packages (realname TEXT NOT NULL UNIQUE PRIMARY KEY, version TEXT NOT NULL, dependencies TEXT, name TEXT, family TEXT NOT NULL, serial INTEGER, package_d TEXT NOT NULL)") + } else { + log.Fatal(err) + } + } + + _, err = os.Stat(filepath.Join(DefaultLinux_d, "config.toml")) + if os.IsNotExist(err) { + f, err := os.Create(filepath.Join(DefaultLinux_d, "config.toml")) + if err != nil { + log.Fatal(err) + } + + defer f.Close() + + encoder := toml.NewEncoder(f) + + cfg, err := internal.DefaultConfigTOML() + if err != nil { + log.Fatal(err) + } + + if err = encoder.Encode(*cfg); err != nil { + log.Fatal(err) + } + } +} + +// COBRA CMDS + +var rootCmd = &cobra.Command{Use: "packets"} +var installCmd = &cobra.Command{} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..371f8c3 --- /dev/null +++ b/go.mod @@ -0,0 +1,25 @@ +module packets + +go 1.25.1 + +require ( + github.com/pelletier/go-toml/v2 v2.2.4 + github.com/spf13/cobra v1.10.1 + github.com/yuin/gopher-lua v1.1.1 + modernc.org/sqlite v1.38.2 +) + +require ( + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/ncruces/go-strftime v0.1.9 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + github.com/spf13/pflag v1.0.10 // indirect + golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect + golang.org/x/sys v0.34.0 // indirect + modernc.org/libc v1.66.3 // indirect + modernc.org/mathutil v1.7.1 // indirect + modernc.org/memory v1.11.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..11a25b1 --- /dev/null +++ b/go.sum @@ -0,0 +1,64 @@ +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs= +github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= +github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= +github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= +github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= +github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= +github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M= +github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= +golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o= +golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8= +golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= +golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= +golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= +golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +modernc.org/cc/v4 v4.26.2 h1:991HMkLjJzYBIfha6ECZdjrIYz2/1ayr+FL8GN+CNzM= +modernc.org/cc/v4 v4.26.2/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= +modernc.org/ccgo/v4 v4.28.0 h1:rjznn6WWehKq7dG4JtLRKxb52Ecv8OUGah8+Z/SfpNU= +modernc.org/ccgo/v4 v4.28.0/go.mod h1:JygV3+9AV6SmPhDasu4JgquwU81XAKLd3OKTUDNOiKE= +modernc.org/fileutil v1.3.8 h1:qtzNm7ED75pd1C7WgAGcK4edm4fvhtBsEiI/0NQ54YM= +modernc.org/fileutil v1.3.8/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc= +modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI= +modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= +modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks= +modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI= +modernc.org/libc v1.66.3 h1:cfCbjTUcdsKyyZZfEUKfoHcP3S0Wkvz3jgSzByEWVCQ= +modernc.org/libc v1.66.3/go.mod h1:XD9zO8kt59cANKvHPXpx7yS2ELPheAey0vjIuZOhOU8= +modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= +modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= +modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI= +modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw= +modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8= +modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= +modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= +modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= +modernc.org/sqlite v1.38.2 h1:Aclu7+tgjgcQVShZqim41Bbw9Cho0y/7WzYptXqkEek= +modernc.org/sqlite v1.38.2/go.mod h1:cPTJYSlgg3Sfg046yBShXENNtPrWrDX8bsbAQBzgQ5E= +modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= +modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= +modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= +modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= diff --git a/internal/internal.go b/internal/internal.go new file mode 100644 index 0000000..da86e33 --- /dev/null +++ b/internal/internal.go @@ -0,0 +1,79 @@ +package internal + +import ( + "errors" + "io" + "log" + "net/http" + "os" +) + +// const + +const DefaultLinux_d = "/etc/packets" +const DefaultCache_d = "/var/cache/packets" +const DefaultHttpPort = 9123 +const DefaultData_d = "/opt/packets" + +// errors +var ErrResponseNot200OK = errors.New("the request is not 200, download failed") + +type ConfigTOML struct { + Config struct { + HttpPort int `toml:"httpPort"` + Cache_d string `toml:"cache_d"` + Data_d string `toml:"data_d"` + Bin_d string `toml:"bin_d"` + } `toml:"Config"` +} + +func DownloadPackageHTTP(url string) (*[]byte, error) { + + resp, err := http.Get(url) + if err != nil { + log.Fatal(err) + } + + if resp.StatusCode != http.StatusOK { + return nil, ErrResponseNot200OK + } + + fileBytes, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + return &fileBytes, nil +} + +// DefaultConfigTOML generate a default toml and create the directorys +func DefaultConfigTOML() (*ConfigTOML, error) { + + var config ConfigTOML + + _, err := os.Stat(DefaultCache_d) + if err != nil { + if os.IsNotExist(err) { + err := os.MkdirAll(DefaultCache_d, 0666) + if err != nil { + return nil, err + } + } + } + + _, err = os.Stat(DefaultCache_d) + if err != nil { + if os.IsNotExist(err) { + err := os.MkdirAll(DefaultData_d, 0644) + if err != nil { + return nil, err + } + } + } + + config.Config.Cache_d = DefaultCache_d + config.Config.Data_d = DefaultData_d + config.Config.HttpPort = DefaultHttpPort + + return &config, nil +} diff --git a/internal/lua.go b/internal/lua.go new file mode 100644 index 0000000..803c010 --- /dev/null +++ b/internal/lua.go @@ -0,0 +1,421 @@ +package internal + +import ( + "fmt" + "io" + "log" + "os" + "os/exec" + "path/filepath" + "strings" + + "github.com/pelletier/go-toml/v2" + lua "github.com/yuin/gopher-lua" +) + +var SandboxDir string + +var AllowedCmds = map[string]string{ + "go": "go", // "Go code compiler" + "gcc": "gcc", // "C" + "g++": "g++", // "C++" + "rustc": "rustc", // "Rust" + "javac": "javac", // "Java" + "luac": "luac", // "Lua" + "pyinstaller": "pyinstaller", // "Python" + "kotlinc": "kotlinc", // "Kotlin" + "mcs": "mcs", // "C# compiler" + "swiftc": "swiftc", // "Swift compiler" + "tsc": "tsc", // "TypeScript compiler" + "rubyc": "rubyc", // "Ruby compiler" +} + +func IsSafe(str string) bool { + s, err := filepath.EvalSymlinks(filepath.Clean(str)) + if err != nil { + s = filepath.Clean(str) + } + + var cfg ConfigTOML + + f, err := os.Open(filepath.Join(DefaultLinux_d, "config.toml")) + if err != nil { + log.Println("error here opening config.toml") + return false + } + + defer f.Close() + + decoder := toml.NewDecoder(f) + + if err := decoder.Decode(&cfg); err != nil { + log.Println("error decoding") + return false + } + + if strings.HasPrefix(s, cfg.Config.Data_d) || strings.HasPrefix(s, cfg.Config.Bin_d) { + return true + + } else if strings.Contains(s, ".ssh") { + return false + + } else if strings.HasPrefix(s, "/etc") { + return false + + } else if strings.HasPrefix(s, "/usr") || strings.HasPrefix(s, "/bin") { + fmt.Println(s, "está dentro de usr") + return strings.HasPrefix(s, "/usr/share") + + } else if strings.HasPrefix(s, "/var/mail") { + return false + + } else if strings.HasPrefix(s, "/proc") { + return false + + } else if strings.HasPrefix(s, "/sys") { + return false + + } else if strings.HasPrefix(s, "/var/run") || strings.HasPrefix(s, "/run") { + return false + + } else if strings.HasPrefix(s, "/tmp") { + return false + + } else if strings.HasPrefix(s, "/dev") { + return false + + } else if strings.HasPrefix(s, "/boot") { + return false + + } else if strings.HasPrefix(s, "/home") { + if strings.Contains(s, "/Pictures") || strings.Contains(s, "/Videos") || strings.Contains(s, "/Documents") || strings.Contains(s, "/Downloads") { + return false + } + + } else if strings.HasPrefix(s, "/lib") || strings.HasPrefix(s, "/lib64") || strings.HasPrefix(s, "/var/lib64") || strings.HasPrefix(s, "/lib") { + return false + + } else if strings.HasPrefix(s, "/sbin") { + return false + + } else if strings.HasPrefix(s, "/srv") { + return false + + } else if strings.HasPrefix(s, "/mnt") { + return false + + } else if strings.HasPrefix(s, "/media") { + return false + } else if strings.HasPrefix(s, "/snap") { + return false + } + + return true +} + +// lua functions + +func LSafeRemove(L *lua.LState) int { + filename := L.CheckString(1) + if !IsSafe(filename) { + L.Push(lua.LFalse) + L.Push(lua.LString("[packets] unsafe filepath")) + return 2 + } + err := os.RemoveAll(filename) + if err != nil { + L.Push(lua.LFalse) + L.Push(lua.LString("[packets] remove failed\n" + err.Error())) + return 2 + } + L.Push(lua.LTrue) + L.Push(lua.LNil) + return 2 +} + +func LSafeRename(L *lua.LState) int { + oldname := L.CheckString(1) + newname := L.CheckString(2) + + if !IsSafe(oldname) || !IsSafe(newname) { + L.Push(lua.LFalse) + L.Push(lua.LString("[packets] unsafe filepath")) + return 2 + } + + if err := os.Rename(oldname, newname); err != nil { + L.Push(lua.LFalse) + L.Push(lua.LString("[packets] rename failed\n" + err.Error())) + return 2 + } + + L.Push(lua.LTrue) + return 1 +} +func LSafeCopy(L *lua.LState) int { + oldname := L.CheckString(1) + newname := L.CheckString(2) + + if !IsSafe(oldname) || !IsSafe(newname) { + L.Push(lua.LFalse) + L.Push(lua.LString("[packets] unsafe filepath")) + return 2 + } + + src, err := os.Open(oldname) + if err != nil { + L.Push(lua.LFalse) + L.Push(lua.LString("[packets] copy failed\n" + err.Error())) + return 2 + + } + defer src.Close() + + status, err := src.Stat() + if err != nil { + L.Push(lua.LFalse) + L.Push(lua.LString("[packets] copy failed\n" + err.Error())) + return 2 + } + + err = os.MkdirAll(filepath.Dir(newname), 0755) + if err != nil { + L.Push(lua.LFalse) + L.Push(lua.LString("[packets] copy failed\n" + err.Error())) + return 2 + } + + dst, err := os.Create(newname) + if err != nil { + if !os.IsExist(err) { + dst, err = os.Open(newname) + if err != nil { + L.Push(lua.LFalse) + L.Push(lua.LString("[packets] copy failed\n" + err.Error())) + return 2 + } + } else { + L.Push(lua.LFalse) + L.Push(lua.LString("[packets] copy failed\n" + err.Error())) + return 2 + } + } + + defer dst.Close() + if err := dst.Chmod(status.Mode()); err != nil { + L.Push(lua.LFalse) + L.Push(lua.LString("[packets] copy failed\n" + err.Error())) + return 2 + } + + _, err = io.Copy(dst, src) + if err != nil { + L.Push(lua.LFalse) + L.Push(lua.LString("[packets] copy failed\n" + err.Error())) + return 2 + } + + L.Push(lua.LTrue) + L.Push(lua.LNil) + return 2 +} + +func LSymlink(L *lua.LState) int { + fileName := L.CheckString(1) + destination := L.CheckString(2) + + if !IsSafe(fileName) || !IsSafe(destination) { + L.Push(lua.LFalse) + L.Push(lua.LString("[packets] unsafe filepath")) + return 2 + } + + _ = os.RemoveAll(destination) + if err := os.Symlink(fileName, destination); err != nil { + L.Push(lua.LFalse) + L.Push(lua.LString("[packets] symlink failed\n" + err.Error())) + return 2 + } + + L.Push(lua.LTrue) + L.Push(lua.LNil) + return 2 +} + +func modeFlags(mode string) int { + switch mode { + case "r", "rb": + return os.O_RDONLY + case "w", "wb": + return os.O_CREATE | os.O_WRONLY | os.O_TRUNC + case "a", "ab": + return os.O_CREATE | os.O_WRONLY | os.O_APPEND + case "r+", "r+b", "rb+", "br+": + return os.O_RDWR + case "w+", "w+b", "wb+", "bw+": + return os.O_CREATE | os.O_RDWR | os.O_TRUNC + case "a+", "a+b", "ab+", "ba+": + return os.O_CREATE | os.O_RDWR | os.O_APPEND + default: + return os.O_RDONLY + } +} + +func LOpen(L *lua.LState) int { + path := L.CheckString(1) + mode := L.OptString(2, "r") + + if !IsSafe(path) { + L.Push(lua.LNil) + L.Push(lua.LString("[packets] unsafe filepath")) + return 2 + } + file, err := os.OpenFile(path, modeFlags(mode), 0644) + if err != nil { + L.Push(lua.LNil) + L.Push(lua.LString("[packets] open failed\n" + err.Error())) + return 2 + } + + ud := L.NewUserData() + ud.Value = file + L.SetMetatable(ud, L.GetTypeMetatable("file")) + L.Push(ud) + L.Push(lua.LNil) + return 2 +} + +func Ljoin(L *lua.LState) int { + + n := L.GetTop() + parts := make([]string, 0, n) + + for i := 1; i <= n; i++ { + val := L.Get(i) + parts = append(parts, val.String()) + } + + result := filepath.Join(parts...) + L.Push(lua.LString(result)) + return 1 +} + +func LMkdir(L *lua.LState) int { + path := L.CheckString(1) + perm := L.CheckInt(2) + + if !IsSafe(path) { + L.Push(lua.LFalse) + L.Push(lua.LString("[packets] unsafe filepath\n")) + return 2 + } + + if err := os.MkdirAll(path, os.FileMode(perm)); err != nil { + L.Push(lua.LFalse) + L.Push(lua.LString("[packets] mkdir failed\n" + err.Error())) + return 2 + } + + L.Push(lua.LTrue) + L.Push(lua.LNil) + return 2 +} + +func LCompile(L *lua.LState) int { + lang := L.CheckString(1) + args := []string{} + for i := 2; i <= L.GetTop(); i++ { + + if strings.Contains(L.CheckString(i), "/") { + + tryintoacess, err := filepath.Abs(filepath.Clean(filepath.Join(SandboxDir, L.CheckString(i)))) + if err != nil { + L.Push(lua.LFalse) + L.Push(lua.LString("[packets] invalid filepath\n" + err.Error())) + return 2 + } + + fmt.Printf("sandboxdir: (%s) acessto: (%s)\n", SandboxDir, tryintoacess) + rel, err := filepath.Rel(SandboxDir, tryintoacess) + if err != nil || strings.HasPrefix(rel, "..") { + L.Push(lua.LFalse) + L.Push(lua.LString("[packets] unsafe filepath")) + return 2 + } + } + + args = append(args, L.CheckString(i)) + } + + bin, suc := AllowedCmds[lang] + if !suc { + L.Push(lua.LFalse) + L.Push(lua.LString("[packets] unsupported language")) + return 2 + } + + cmd := exec.Command(bin, args...) + cmd.Dir = SandboxDir + out, err := cmd.CombinedOutput() + if err != nil { + L.Push(lua.LFalse) + L.Push(lua.LString("[packets] compile failed\n" + err.Error() + "\n" + string(out))) + return 2 + } + if err := cmd.Run(); err != nil { + L.Push(lua.LFalse) + L.Push(lua.LString("[packets] compile failed\n" + err.Error())) + return 2 + } + + L.Push(lua.LTrue) + L.Push(lua.LString(string(out))) + return 2 +} + +func LCompileRequirements(L *lua.LState) int { + + cmdLang := L.CheckString(1) + + if strings.Contains(L.CheckString(2), "/") { + + tryintoacess, err := filepath.Abs(filepath.Clean(L.CheckString(2))) + if err != nil { + L.Push(lua.LFalse) + L.Push(lua.LString("[packets] invalid filepath\n" + err.Error())) + return 2 + } + if !strings.HasPrefix(tryintoacess, SandboxDir) { + L.Push(lua.LFalse) + L.Push(lua.LString("[packets] unsafe filepath")) + return 2 + } + } + + var err error + + switch cmdLang { + case "python": + cmd := exec.Command("pip", "install", "--target", filepath.Join(SandboxDir, "tmp/build"), "-r", L.CheckString(2)) + cmd.Dir = filepath.Join(SandboxDir, "data") + err = cmd.Run() + case "java": + cmd := exec.Command("mvn", "dependency:copy-dependencies", "-DoutputDirectory="+filepath.Join(SandboxDir, "tmp/build")) + cmd.Dir = L.CheckString(2) + err = cmd.Run() + case "ruby": + cmd := exec.Command("bundle", "install", "--path", filepath.Join(SandboxDir, "tmp/build")) + cmd.Dir = L.CheckString(2) + err = cmd.Run() + } + + if err != nil { + L.Push(lua.LFalse) + L.Push(lua.LString("[packets] requirements install failed\n" + err.Error())) + return 2 + } + + L.Push(lua.LTrue) + L.Push(lua.LNil) + return 2 +}