355 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			355 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package packets
 | 
						|
 | 
						|
import (
 | 
						|
	"archive/tar"
 | 
						|
	"bytes"
 | 
						|
	"crypto/ed25519"
 | 
						|
	"database/sql"
 | 
						|
	"fmt"
 | 
						|
	"io"
 | 
						|
	"log"
 | 
						|
	"net/http"
 | 
						|
	"os"
 | 
						|
	"packets/internal/build"
 | 
						|
	"packets/internal/consts"
 | 
						|
	errors_packets "packets/internal/errors"
 | 
						|
	"packets/internal/packet"
 | 
						|
	"packets/internal/utils"
 | 
						|
	"path"
 | 
						|
 | 
						|
	utils_lua "packets/internal/utils/lua"
 | 
						|
	"path/filepath"
 | 
						|
	"strings"
 | 
						|
 | 
						|
	"github.com/klauspost/compress/zstd"
 | 
						|
	_ "modernc.org/sqlite"
 | 
						|
)
 | 
						|
 | 
						|
type Package struct {
 | 
						|
	PackageF       []byte
 | 
						|
	Version        string
 | 
						|
	ImageUrl       string
 | 
						|
	QueryName      string
 | 
						|
	Description    string
 | 
						|
	Author         string
 | 
						|
	AuthorVerified bool
 | 
						|
	OS             string
 | 
						|
	Arch           string
 | 
						|
	Filename       string
 | 
						|
	Size           int64
 | 
						|
	Dependencies   map[string]string
 | 
						|
 | 
						|
	Signature []byte
 | 
						|
	PublicKey ed25519.PublicKey
 | 
						|
 | 
						|
	Serial int
 | 
						|
 | 
						|
	Manifest packet.PacketLua
 | 
						|
}
 | 
						|
 | 
						|
// Install exctract and fully install from a package file ( tar.zst )
 | 
						|
func InstallPackage(file []byte, destDir string) error {
 | 
						|
 | 
						|
	packetLua, err := packet.ReadPacket(file)
 | 
						|
	if err == nil {
 | 
						|
		L, err := utils_lua.GetSandBox()
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		bootstrapcontainer, err := build.NewContainer(packetLua)
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		os.Chdir(destDir)
 | 
						|
 | 
						|
		if err := utils.ChangeToNoPermission(); err != nil {
 | 
						|
			return fmt.Errorf("error changing to packet user: %s", err)
 | 
						|
		}
 | 
						|
 | 
						|
		if err := bootstrapcontainer.ExecutePrepare(packetLua, &L); err != nil {
 | 
						|
			return fmt.Errorf("error executing prepare: %s", err)
 | 
						|
		}
 | 
						|
 | 
						|
		if err := bootstrapcontainer.ExecuteBuild(packetLua, &L); err != nil {
 | 
						|
			return fmt.Errorf("error executing build: %s", err)
 | 
						|
		}
 | 
						|
 | 
						|
		if err := utils.ElevatePermission(); err != nil {
 | 
						|
			return fmt.Errorf("error changing to root: %s", err)
 | 
						|
		}
 | 
						|
 | 
						|
		if err := bootstrapcontainer.ExecuteInstall(packetLua, &L); err != nil {
 | 
						|
			return fmt.Errorf("error executing build: %s", err)
 | 
						|
		}
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
 | 
						|
	manifest, err := packet.ReadPacketFromFile(bytes.NewReader(file))
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	zstdReader, err := zstd.NewReader(bytes.NewReader(file))
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	defer zstdReader.Close()
 | 
						|
 | 
						|
	tarReader := tar.NewReader(zstdReader)
 | 
						|
 | 
						|
	uid, err := utils.GetPacketsUID()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	for {
 | 
						|
		hdr, err := tarReader.Next()
 | 
						|
		if err == io.EOF {
 | 
						|
			break
 | 
						|
		}
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		rel := filepath.Clean(hdr.Name)
 | 
						|
 | 
						|
		if rel == ".." || strings.HasPrefix(rel, ".."+string(os.PathSeparator)) {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		if err := os.MkdirAll(destDir, 0775); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		if err := os.Chown(destDir, uid, 0); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		absPath := filepath.Join(destDir, rel)
 | 
						|
 | 
						|
		switch hdr.Typeflag {
 | 
						|
 | 
						|
		case tar.TypeDir:
 | 
						|
			err = os.MkdirAll(absPath, os.FileMode(hdr.Mode))
 | 
						|
			if err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
			if err := os.Chown(absPath, uid, 0); err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
 | 
						|
		case tar.TypeReg:
 | 
						|
 | 
						|
			err = os.MkdirAll(filepath.Dir(absPath), 0775)
 | 
						|
			if err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
 | 
						|
			out, err := os.Create(absPath)
 | 
						|
			if err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
 | 
						|
			_, err = io.Copy(out, tarReader)
 | 
						|
			out.Close()
 | 
						|
			if err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
 | 
						|
			err = os.Chmod(absPath, os.FileMode(0775))
 | 
						|
			if err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
 | 
						|
			if filepath.Base(hdr.Name) == "Packet.lua" {
 | 
						|
				err = os.Chmod(absPath, os.FileMode(0755))
 | 
						|
				if err != nil {
 | 
						|
					return err
 | 
						|
				}
 | 
						|
			} else {
 | 
						|
				if err := os.Chown(absPath, uid, 0); err != nil {
 | 
						|
					return err
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	L, err := utils_lua.GetSandBox()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	bootstrapcontainer, err := build.NewContainer(manifest)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	os.Chdir(destDir)
 | 
						|
 | 
						|
	if err := utils.ChangeToNoPermission(); err != nil {
 | 
						|
		return fmt.Errorf("error changing to packet user: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	if err := bootstrapcontainer.ExecutePrepare(manifest, &L); err != nil {
 | 
						|
		return fmt.Errorf("error executing prepare: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	if err := bootstrapcontainer.ExecuteBuild(manifest, &L); err != nil {
 | 
						|
		return fmt.Errorf("error executing build: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	if err := utils.ElevatePermission(); err != nil {
 | 
						|
		return fmt.Errorf("error changing to root: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	if err := bootstrapcontainer.ExecuteInstall(manifest, &L); err != nil {
 | 
						|
		return fmt.Errorf("error executing build: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func GetPackage(id string) (Package, error) {
 | 
						|
 | 
						|
	var this Package
 | 
						|
	this.Dependencies = make(map[string]string)
 | 
						|
	var peers []Peer
 | 
						|
 | 
						|
	db, err := sql.Open("sqlite", consts.IndexDB)
 | 
						|
	if err != nil {
 | 
						|
		return this, err
 | 
						|
	}
 | 
						|
	defer db.Close()
 | 
						|
 | 
						|
	var packageUrl, typePackage string
 | 
						|
	err = db.QueryRow("SELECT query_name, version, package_url, image_url, description, author, author_verified, os, arch, signature, public_key, serial, size, type FROM packages WHERE id = ?", id).
 | 
						|
		Scan(
 | 
						|
			&this.QueryName,
 | 
						|
			&this.Version,
 | 
						|
			&packageUrl,
 | 
						|
			&this.ImageUrl,
 | 
						|
			&this.Description,
 | 
						|
			&this.Author,
 | 
						|
			&this.AuthorVerified,
 | 
						|
			&this.OS,
 | 
						|
			&this.Arch,
 | 
						|
			&this.Signature,
 | 
						|
			&this.PublicKey,
 | 
						|
			&this.Serial,
 | 
						|
			&this.Size,
 | 
						|
			&typePackage,
 | 
						|
		)
 | 
						|
	if err != nil {
 | 
						|
		return Package{}, err
 | 
						|
	}
 | 
						|
 | 
						|
	rows, err := db.Query("SELECT dependency_name, version_constraint FROM package_dependencies WHERE package_id = ?", id)
 | 
						|
	if err != nil {
 | 
						|
		return Package{}, err
 | 
						|
	}
 | 
						|
	defer rows.Close()
 | 
						|
 | 
						|
	for rows.Next() {
 | 
						|
		var a, vConstraint string
 | 
						|
		if err := rows.Scan(&a, &vConstraint); err != nil {
 | 
						|
			return Package{}, err
 | 
						|
		}
 | 
						|
 | 
						|
		this.Dependencies[a] = vConstraint
 | 
						|
	}
 | 
						|
 | 
						|
	if strings.Contains(typePackage, "     ") {
 | 
						|
 | 
						|
		filename := path.Base(packageUrl)
 | 
						|
		this.Filename = filename
 | 
						|
 | 
						|
		dirEntry, err := os.ReadDir(consts.DefaultCache_d)
 | 
						|
		if err != nil {
 | 
						|
			return Package{}, err
 | 
						|
		}
 | 
						|
 | 
						|
		for _, v := range dirEntry {
 | 
						|
			if v.Name() == filename {
 | 
						|
				this.PackageF, err = os.ReadFile(filepath.Join(consts.DefaultCache_d, filename))
 | 
						|
				if err != nil {
 | 
						|
					break
 | 
						|
				}
 | 
						|
				goto skipping
 | 
						|
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		peers, err = AskLAN(filename)
 | 
						|
		if err != nil {
 | 
						|
			return Package{}, err
 | 
						|
		}
 | 
						|
 | 
						|
		if len(peers) == 0 {
 | 
						|
			fmt.Printf(":: Pulling from %s\n", packageUrl)
 | 
						|
			this.PackageF, err = getFileHTTP(packageUrl)
 | 
						|
			if err != nil {
 | 
						|
				return Package{}, err
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			var totalerrors int = 0
 | 
						|
			for _, peer := range peers {
 | 
						|
				fmt.Printf(":: Pulling from local network (%s)\n", peer.IP)
 | 
						|
				this.PackageF, err = getFileHTTP(fmt.Sprintf("http://%s:%d/%s", peer.IP, peer.Port, filename))
 | 
						|
				if err == nil {
 | 
						|
					break
 | 
						|
				} else {
 | 
						|
					totalerrors++
 | 
						|
				}
 | 
						|
			}
 | 
						|
			if totalerrors == len(peers) {
 | 
						|
				this.PackageF, err = getFileHTTP(packageUrl)
 | 
						|
				if err != nil {
 | 
						|
					return Package{}, err
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		filds := strings.Fields(typePackage)
 | 
						|
		pkt, err := packet.GetPackageDotLuaFromRemote(filds[0], filds[1])
 | 
						|
		if err != nil {
 | 
						|
			return Package{}, err
 | 
						|
		}
 | 
						|
		this.Manifest = pkt
 | 
						|
		return this, nil
 | 
						|
	}
 | 
						|
 | 
						|
skipping:
 | 
						|
 | 
						|
	reader := bytes.NewReader(this.PackageF)
 | 
						|
	this.Manifest, err = packet.ReadPacketFromFile(reader)
 | 
						|
	if err != nil {
 | 
						|
		return Package{}, err
 | 
						|
	}
 | 
						|
 | 
						|
	if !ed25519.Verify(this.PublicKey, this.PackageF, this.Signature) {
 | 
						|
		return Package{}, errors_packets.ErrInvalidSignature
 | 
						|
	}
 | 
						|
 | 
						|
	return this, nil
 | 
						|
}
 | 
						|
 | 
						|
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
 | 
						|
}
 |