diff --git a/cmd/packets/main.go b/cmd/packets/main.go index bda76ba..f12f99f 100644 --- a/cmd/packets/main.go +++ b/cmd/packets/main.go @@ -3,6 +3,7 @@ package main import ( "database/sql" "fmt" + "io" "log" "os" "path/filepath" @@ -13,11 +14,13 @@ import ( "packets/configs" "packets/internal/consts" errors_packets "packets/internal/errors" + "packets/internal/packet" "packets/internal/utils" packets "packets/pkg" "github.com/pelletier/go-toml/v2" "github.com/spf13/cobra" + lua "github.com/yuin/gopher-lua" _ "modernc.org/sqlite" ) @@ -360,18 +363,25 @@ var removeCmd = &cobra.Command{ log.Fatal(err) } - f, err := os.Open(filepath.Join(packageDir, "manifest.toml")) + f, err := os.Open(filepath.Join(packageDir, "Packet.lua")) if err != nil { log.Fatal(err) } - manifest, err := utils.ManifestFileRead(f) + fBLob, err := io.ReadAll(f) + if err != nil { + log.Fatal(err) + } + + manifest, err := packet.ReadPacket(fBLob) if err != nil { log.Fatal(err) } fmt.Println(":: Removing", pkgName) - packets.ExecuteRemoveScript(filepath.Join(packageDir, manifest.Hooks.Remove)) + if err := manifest.ExecuteRemove(lua.NewState()); err != nil { + log.Panic(err) + } if err := os.RemoveAll(packageDir); err != nil { log.Fatal(err) @@ -647,7 +657,7 @@ func UpgradeToThis(id string, installPath string, installedDB *sql.DB, storePkgF serial = ?, package_d = ?, filename = ?, os = ?, arch = ?, in_cache = ? `, p.QueryName, - p.Manifest.Package.Id, + p.Manifest.Id, p.Version, p.Description, p.Serial, diff --git a/internal/build/lua.go b/internal/build/lua.go index f454fad..9f0f648 100644 --- a/internal/build/lua.go +++ b/internal/build/lua.go @@ -2,9 +2,9 @@ package build import ( "fmt" - "io" "os" "os/exec" + "path/filepath" "strings" utils_lua "packets/internal/utils/lua" @@ -196,53 +196,11 @@ func (container Container) lpopen(L *lua.LState) int { return 2 } -func (container Container) lGet(L *lua.LState) int { - src := L.CheckString(1) - dest := L.CheckString(2) +func (container Container) lDir(L *lua.LState) int { + dir := L.CheckString(1) - file, err := container.FS.Open(src) - if err != nil { - L.Push(lua.LFalse) - L.Push(lua.LString(err.Error())) - return 2 - } - defer file.Close() - - info, err := file.Stat() - if err != nil { - L.Push(lua.LFalse) - L.Push(lua.LString(err.Error())) - return 2 - } - - fileBlob, err := io.ReadAll(file) - if err != nil { - L.Push(lua.LFalse) - L.Push(lua.LString(err.Error())) - return 2 - } - - if err := os.WriteFile(dest, fileBlob, info.Mode()); err != nil { - L.Push(lua.LFalse) - L.Push(lua.LString(err.Error())) - return 2 - } - - L.Push(lua.LTrue) - L.Push(lua.LNil) - return 2 -} - -func (container Container) lCopyToContainer(L *lua.LState) int { - - if err := container.CopyHostToContainer(L.CheckString(1), L.CheckString(2)); err != nil { - L.Push(lua.LFalse) - L.Push(lua.LString(err.Error())) - return 2 - } - L.Push(lua.LTrue) - L.Push(lua.LNil) - return 2 + L.Push(lua.LString(filepath.Join(container.Root, filepath.Clean(dir)))) + return 1 } func (container Container) GetLuaState() { diff --git a/internal/build/main.go b/internal/build/main.go index 87c8523..ae3d65f 100644 --- a/internal/build/main.go +++ b/internal/build/main.go @@ -6,8 +6,8 @@ import ( "encoding/json" "io" "os" - "packets/configs" "packets/internal/consts" + "packets/internal/packet" "path/filepath" _ "modernc.org/sqlite" @@ -20,18 +20,17 @@ type Container struct { BuildID BuildID Root string FS afero.Fs - DataDir string LuaState lua.LState - Manifest configs.Manifest + Manifest packet.PacketLua uses int DeleteAfter bool } -func NewContainer(dataDir string, manifest configs.Manifest) (Container, error) { +func NewContainer(manifest packet.PacketLua) (Container, error) { var container Container var err error - container.BuildID, err = getBuildId(manifest.Build.BuildDependencies) + container.BuildID, err = getBuildId(manifest.BuildDependencies) if err != nil { return Container{}, err } @@ -66,13 +65,8 @@ func NewContainer(dataDir string, manifest configs.Manifest) (Container, error) fileSystem := afero.NewBasePathFs(baseFs, container.Root) container.Manifest = manifest - container.DataDir = dataDir container.FS = fileSystem - if err := container.CopyHostToContainer(dataDir, "/data"); err != nil { - return Container{}, err - } - if err := container.FS.MkdirAll(BinDir, 0777); err != nil { return Container{}, err } diff --git a/internal/build/manager.go b/internal/build/manager.go index b76ed2d..f8b1fda 100644 --- a/internal/build/manager.go +++ b/internal/build/manager.go @@ -22,7 +22,7 @@ func (container Container) createNew() error { if err := os.Chown(filepath.Join(consts.BuildImagesDir, string(container.BuildID)), packetsuid, 0); err != nil { return err } - dependencies, err := utils.ResolvDependencies(container.Manifest.Build.BuildDependencies) + dependencies, err := utils.ResolvDependencies(container.Manifest.BuildDependencies) if err != nil { return err } @@ -39,6 +39,8 @@ func (container Container) createNew() error { } wg.Wait() + container.Root = filepath.Join(consts.BuildImagesDir, string(container.BuildID)) + container.saveBuild() return nil } diff --git a/internal/errors/errors.go b/internal/errors/errors.go index e97c965..657ea4e 100644 --- a/internal/errors/errors.go +++ b/internal/errors/errors.go @@ -4,7 +4,7 @@ import "errors" var ( ErrResponseNot200OK = errors.New("the request is not 200, download failed") - ErrCantFindManifestTOML = errors.New("can't find manifest.toml when trying to read the packagefile") + ErrCantFindPacketDotLua = errors.New("can't find manifest.toml when trying to read the packagefile") ErrInvalidSignature = errors.New("the signature is invalid") ErrNotInstalled = errors.New("the package isn't installed") ErrAlredyUpToDate = errors.New("alredy up to date") diff --git a/internal/packet/auxiliar_functions.go b/internal/packet/auxiliar_functions.go new file mode 100644 index 0000000..b604afc --- /dev/null +++ b/internal/packet/auxiliar_functions.go @@ -0,0 +1,55 @@ +package packet + +import lua "github.com/yuin/gopher-lua" + +func getStringFromTable(table *lua.LTable, key string) string { + value := table.RawGetString(key) + if value.Type() == lua.LTString { + return value.String() + } + return "" +} + +func getStringArrayFromTable(L *lua.LState, table *lua.LTable, key string) []string { + value := table.RawGetString(key) + if value.Type() != lua.LTTable { + return []string{} + } + + arrayTable := value.(*lua.LTable) + var result []string + + arrayTable.ForEach(func(_, value lua.LValue) { + if value.Type() == lua.LTString { + result = append(result, value.String()) + } + }) + + return result +} + +func getFunctionFromTable(table *lua.LTable, key string) *lua.LFunction { + value := table.RawGetString(key) + if value.Type() == lua.LTFunction { + return value.(*lua.LFunction) + } + return nil +} + +func getDependenciesFromTable(L *lua.LState, table *lua.LTable, key string) map[string]string { + value := table.RawGetString(key) + if value.Type() != lua.LTTable { + return map[string]string{} + } + + depsTable := value.(*lua.LTable) + dependencies := make(map[string]string) + + depsTable.ForEach(func(key, value lua.LValue) { + if key.Type() == lua.LTString && value.Type() == lua.LTString { + dependencies[key.String()] = value.String() + } + }) + + return dependencies +} diff --git a/internal/packet/main.go b/internal/packet/main.go index 15fbea2..86083c2 100644 --- a/internal/packet/main.go +++ b/internal/packet/main.go @@ -1,5 +1,19 @@ package packet +import ( + "archive/tar" + "fmt" + "io" + "packets/configs" + errors_packets "packets/internal/errors" + "path/filepath" + "runtime" + + "github.com/klauspost/compress/zstd" + "github.com/pelletier/go-toml/v2" + lua "github.com/yuin/gopher-lua" +) + type PacketLua struct { Name string Id string @@ -14,5 +28,115 @@ type PacketLua struct { GitUrl string GitBranch string - BuildDependencies string + BuildDependencies map[string]string + + Prepare *lua.LFunction + Build *lua.LFunction + Install *lua.LFunction + Remove *lua.LFunction +} + +// ReadPacket read a Packet.lua and alredy set global vars +func ReadPacket(f []byte) (PacketLua, error) { + cfg, err := configs.GetConfigTOML() + if err != nil { + return PacketLua{}, err + } + L := lua.NewState() + defer L.Close() + + osObject := L.GetGlobal("os").(*lua.LTable) + ioObject := L.GetGlobal("io").(*lua.LTable) + + L.SetGlobal("os", lua.LNil) + L.SetGlobal("io", lua.LNil) + + if err := L.DoString(string(f)); err != nil { + return PacketLua{}, err + } + L.SetGlobal("os", osObject) + L.SetGlobal("io", ioObject) + + L.SetGlobal("BIN_DIR", lua.LString(cfg.Config.Bin_d)) + L.SetGlobal("ARCH", lua.LString(runtime.GOARCH)) + L.SetGlobal("OS", lua.LString(runtime.GOOS)) + + tableLua := L.Get(-1) + + if tableLua.Type() != lua.LTTable { + return PacketLua{}, fmt.Errorf("invalid Packet.lua format: the file do not return a table") + } + + table := tableLua.(*lua.LTable) + + pkgTableLua := table.RawGetString("package") + if pkgTableLua.Type() != lua.LTTable { + return PacketLua{}, fmt.Errorf("invalid Packet.lua format: can't find package table") + } + pkgTable := pkgTableLua.(*lua.LTable) + + packetLua := &PacketLua{ + Name: getStringFromTable(pkgTable, "name"), + Id: getStringFromTable(pkgTable, "id"), + Version: getStringFromTable(pkgTable, "version"), + Author: getStringFromTable(pkgTable, "author"), + Description: getStringFromTable(pkgTable, "description"), + PkgType: getStringFromTable(pkgTable, "type"), + + Dependencies: getDependenciesFromTable(L, pkgTable, "dependencies"), + BuildDependencies: getDependenciesFromTable(L, pkgTable, "build_dependencies"), + + GitUrl: getStringFromTable(pkgTable, "git_url"), + GitBranch: getStringFromTable(pkgTable, "git_branch"), + + Prepare: getFunctionFromTable(pkgTable, "prepare"), + Build: getFunctionFromTable(pkgTable, "build"), + Install: getFunctionFromTable(pkgTable, "install"), + Remove: getFunctionFromTable(pkgTable, "remove"), + } + + if packetLua.Install == nil || packetLua.Remove == nil { + return PacketLua{}, fmt.Errorf("install or remove function is not valid") + } + + return *packetLua, nil +} + +func (packetLua PacketLua) ExecuteRemove(L *lua.LState) error { + L.Push(packetLua.Remove) + return L.PCall(0, 0, nil) +} + +func ReadPacketFromFile(file io.Reader) (PacketLua, error) { + + zstdReader, err := zstd.NewReader(file) + if err != nil { + return PacketLua{}, err + } + defer zstdReader.Close() + + tarReader := tar.NewReader(zstdReader) + for { + header, err := tarReader.Next() + if err == io.EOF { + break + } + if err != nil { + return PacketLua{}, err + } + + if filepath.Base(header.Name) == "Packet.lua" { + decoder := toml.NewDecoder(tarReader) + + var packetLua PacketLua + + if err := decoder.Decode(&packetLua); err != nil { + return PacketLua{}, err + } + + return packetLua, nil + } + + } + return PacketLua{}, errors_packets.ErrCantFindPacketDotLua } diff --git a/internal/packet/utils.go b/internal/packet/utils.go new file mode 100644 index 0000000..9c40969 --- /dev/null +++ b/internal/packet/utils.go @@ -0,0 +1 @@ +package packet diff --git a/internal/utils/lua/git.go b/internal/utils/lua/git.go index 30782ef..28fc9c4 100644 --- a/internal/utils/lua/git.go +++ b/internal/utils/lua/git.go @@ -1,9 +1,11 @@ package utils_lua import ( + "fmt" "os" - "github.com/go-git/go-git" + "github.com/go-git/go-git/v6" + "github.com/go-git/go-git/v6/plumbing" lua "github.com/yuin/gopher-lua" ) @@ -11,9 +13,15 @@ func LGitClone(L *lua.LState) int { uri := L.CheckString(1) output := L.CheckString(2) - _, err := git.PlainClone(output, false, &git.CloneOptions{ + depth := 1 + if L.GetTop() > 2 { + depth = L.CheckInt(3) + } + + _, err := git.PlainClone(output, &git.CloneOptions{ URL: uri, Progress: os.Stdout, + Depth: depth, }) if err != nil { L.Push(lua.LFalse) @@ -25,4 +33,95 @@ func LGitClone(L *lua.LState) int { return 2 } -func LGitCheckout(L) +func LGitCheckout(L *lua.LState) int { + dir := L.CheckString(1) + branchorid := L.CheckString(2) + + repo, err := git.PlainOpen(dir) + if err != nil { + L.Push(lua.LFalse) + L.Push(lua.LString(err.Error())) + return 2 + } + + worktree, err := repo.Worktree() + if err != nil { + L.Push(lua.LFalse) + L.Push(lua.LString(err.Error())) + return 2 + } + + if err := tryCheckout(*worktree, branchorid); err != nil { + L.Push(lua.LFalse) + L.Push(lua.LString(err.Error())) + return 2 + } + + L.Push(lua.LTrue) + L.Push(lua.LNil) + return 2 +} +func LGitPUll(L *lua.LState) int { + dir := L.CheckString(1) + + depth := 1 + if L.GetTop() > 1 { + depth = L.CheckInt(2) + } + + repo, err := git.PlainOpen(dir) + if err != nil { + L.Push(lua.LFalse) + L.Push(lua.LString(err.Error())) + return 2 + } + worktree, err := repo.Worktree() + if err != nil { + L.Push(lua.LFalse) + L.Push(lua.LString(err.Error())) + return 2 + } + + if err := worktree.Pull(&git.PullOptions{Depth: depth}); err != nil { + L.Push(lua.LFalse) + L.Push(lua.LString(err.Error())) + return 2 + } + + L.Push(lua.LTrue) + L.Push(lua.LNil) + return 2 +} + +func tryCheckout(worktree git.Worktree, reference string) error { + err := worktree.Checkout(&git.CheckoutOptions{ + Branch: plumbing.ReferenceName(reference), + }) + if err == nil { + return nil + } + + err = worktree.Checkout(&git.CheckoutOptions{ + Branch: plumbing.ReferenceName("refs/heads/" + reference), + }) + if err == nil { + return nil + } + + err = worktree.Checkout(&git.CheckoutOptions{ + Branch: plumbing.ReferenceName("refs/tags/" + reference), + }) + if err == nil { + return nil + } + + hash := plumbing.NewHash(reference) + err = worktree.Checkout(&git.CheckoutOptions{ + Hash: hash, + }) + if err == nil { + return nil + } + + return fmt.Errorf("cannot checkout '%s' as branch, tag, or commit", reference) +} diff --git a/internal/utils/utils.go b/internal/utils/utils.go index 6512262..c89c764 100644 --- a/internal/utils/utils.go +++ b/internal/utils/utils.go @@ -1,8 +1,6 @@ package utils import ( - "archive/tar" - "bytes" "crypto/ed25519" "database/sql" "fmt" @@ -17,12 +15,9 @@ import ( "strings" "syscall" - "packets/configs" "packets/internal/consts" errors_packets "packets/internal/errors" - - "github.com/klauspost/compress/zstd" - "github.com/pelletier/go-toml/v2" + "packets/internal/packet" ) type Package struct { @@ -39,11 +34,11 @@ type Package struct { Size int64 Dependencies map[string]string + Manifest packet.PacketLua + Signature []byte PublicKey ed25519.PublicKey - Manifest configs.Manifest - Serial int } @@ -65,40 +60,6 @@ func GetFileHTTP(url string) ([]byte, error) { return fileBytes, nil } -// ReadManifest is crucial to get package metadata it reads manifest.toml from a package file (tar.zst) -func ReadManifest(file io.Reader) (configs.Manifest, error) { - zstdReader, err := zstd.NewReader(file) - if err != nil { - return configs.Manifest{}, err - } - defer zstdReader.Close() - - tarReader := tar.NewReader(zstdReader) - for { - header, err := tarReader.Next() - if err == io.EOF { - break - } - if err != nil { - return configs.Manifest{}, err - } - - if filepath.Base(header.Name) == "manifest.toml" { - decoder := toml.NewDecoder(tarReader) - - var manifest configs.Manifest - - if err := decoder.Decode(&manifest); err != nil { - return configs.Manifest{}, nil - } - - return manifest, nil - } - - } - return configs.Manifest{}, errors_packets.ErrCantFindManifestTOML -} - // CopyDir copies a directory from source to destination func CopyDir(src string, dest string) error { if stats, err := os.Stat(src); err != nil { @@ -190,6 +151,7 @@ func CopyFile(source string, destination string) error { } // Write writes the package file to the cache directory and returns the path to it + func (p *Package) Write() (string, error) { if err := os.WriteFile(filepath.Join(consts.DefaultCache_d, p.Filename), p.PackageF, 0o644); err != nil { _ = os.Remove(filepath.Join(consts.DefaultCache_d, p.Filename)) @@ -210,7 +172,7 @@ func (p *Package) AddToInstalledDB(inCache int, packagePath string) error { defer func() { if !success { - _, err := db.Exec("DELETE FROM packages WHERE id = ?", p.Manifest.Package.Id) + _, err := db.Exec("DELETE FROM packages WHERE id = ?", p.Manifest.Id) if err != nil { log.Println("failed to rollback package addition:", err) } @@ -218,12 +180,12 @@ func (p *Package) AddToInstalledDB(inCache int, packagePath string) error { }() _, err = db.Exec(` - INSERT INTO packages ( - query_name, id, version, description, - serial, package_d, filename, os, arch, in_cache - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, + INSERT INTO packages ( + query_name, id, version, description, + serial, package_d, filename, os, arch, in_cache + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, p.QueryName, - p.Manifest.Package.Id, + p.Manifest.Id, p.Version, p.Description, p.Serial, @@ -238,7 +200,7 @@ func (p *Package) AddToInstalledDB(inCache int, packagePath string) error { } for depnName, versionConstraint := range p.Dependencies { - _, err = db.Exec("INSERT INTO package_dependencies (package_id, dependency_name, version_constraint) VALUES (?, ?, ?)", p.Manifest.Package.Id, depnName, versionConstraint) + _, err = db.Exec("INSERT INTO package_dependencies (package_id, dependency_name, version_constraint) VALUES (?, ?, ?)", p.Manifest.Id, depnName, versionConstraint) } success = true @@ -343,18 +305,6 @@ func ResolvDependencies(depnList map[string]string) ([]string, error) { return resolved, nil } -func ManifestFileRead(file io.Reader) (configs.Manifest, error) { - decoder := toml.NewDecoder(file) - - var manifest configs.Manifest - - if err := decoder.Decode(&manifest); err != nil { - return configs.Manifest{}, nil - } - - return manifest, nil -} - func RemoveFromInstalledDB(id string) error { db, err := sql.Open("sqlite", consts.InstalledDB) if err != nil { @@ -468,8 +418,7 @@ func GetPackage(id string) (Package, error) { skipping: - reader := bytes.NewReader(this.PackageF) - this.Manifest, err = ReadManifest(reader) + this.Manifest, err = packet.ReadPacket(this.PackageF) if err != nil { return Package{}, err } @@ -510,3 +459,21 @@ func ChangeToNoPermission() error { } func ElevatePermission() error { return syscall.Setresuid(0, 0, 0) } + +func getFileHTTP(url string) ([]byte, error) { + resp, err := http.Get(url) + if err != nil { + log.Fatal(err) + } + + if resp.StatusCode != http.StatusOK { + return nil, errors_packets.ErrResponseNot200OK + } + + fileBytes, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + return fileBytes, nil +} diff --git a/pkg/lan.go b/pkg/lan.go new file mode 100644 index 0000000..37cdf9d --- /dev/null +++ b/pkg/lan.go @@ -0,0 +1,80 @@ +package packets + +import ( + "fmt" + "net" + "packets/internal/consts" + "strconv" + "strings" + "time" + + "golang.org/x/net/ipv4" +) + +type Peer struct { + IP net.IP + Port int +} + +func BroadcastAddr(ip net.IP, mask net.IPMask) net.IP { + b := make(net.IP, len(ip)) + for i := range ip { + b[i] = ip[i] | ^mask[i] + } + return b +} + +func AskLAN(filename string) ([]Peer, error) { + var peers []Peer + query := []byte("Q:" + filename) + + pc, err := net.ListenPacket("udp", ":0") + if err != nil { + return []Peer{}, err + } + defer pc.Close() + + if pconn := ipv4.NewPacketConn(pc); pconn != nil { + _ = pconn.SetTTL(1) + } + + ifaces, _ := net.Interfaces() + for _, ifc := range ifaces { + if ifc.Flags&net.FlagUp == 0 || ifc.Flags&net.FlagLoopback != 0 { + continue + } + + addrs, _ := ifc.Addrs() + for _, a := range addrs { + ipnet, ok := a.(*net.IPNet) + if !ok || ipnet.IP.To4() == nil { + continue + } + + bcast := BroadcastAddr(ipnet.IP.To4(), ipnet.Mask) + dst := &net.UDPAddr{IP: bcast, Port: 1333} + + _, err = pc.WriteTo(query, dst) + if err != nil { + fmt.Printf(":: (%s) can't send to %s: %s\n", ifc.Name, bcast, err.Error()) + } + } + } + _ = pc.SetDeadline(time.Now().Add(consts.LANDeadline)) + buf := make([]byte, 1500) + + for { + n, addr, err := pc.ReadFrom(buf) + if err != nil { + break + } + msg := string(buf[:n]) + + if strings.HasPrefix(msg, "H:"+filename) { + parts := strings.Split(msg, ":") + port, _ := strconv.Atoi(parts[2]) + peers = append(peers, Peer{IP: addr.(*net.UDPAddr).IP, Port: port}) + } + } + return peers, nil +}