Compare commits

73 Commits

Author SHA1 Message Date
b58173837b bugfix, giving id to dependency resolver 2025-10-11 21:00:22 -03:00
97408da348 bugfix, starting a empty map for dependencies in GetPackage function 2025-10-11 19:39:20 -03:00
be96001d78 bugfix, fix command fixing leaving after remove 1 package 2025-10-11 19:38:50 -03:00
7c4fba5c86 now upgradeCmd is being used, message when downloading, and upgrade need to run as root 2025-10-11 18:50:45 -03:00
4cee062889 bugfix, fix missing wg.Add() and wg and go for upgrade async functions 2025-10-07 19:35:19 -03:00
93093382f4 bugfix, now ResolvDependencies check if depnList map is empty 2025-10-07 16:46:21 -03:00
e4b4d43163 progress doing upgrade all function 2025-10-07 11:56:24 -04:00
b89abb31df now sync needs to run as root 2025-10-06 11:55:51 -03:00
0a965c67c2 creating packets home dir 2025-10-05 18:16:15 -03:00
147fca375e implemented upgrade, and fixed some bugs 2025-10-05 15:47:21 -03:00
afc19b6e4d removing images 2025-10-05 14:31:50 -03:00
690f180687 removing web from this repository 2025-10-05 12:18:48 -03:00
7ef7b60cf5 fixed databaseschema again 2025-10-05 12:17:33 -03:00
4e2d506a01 fixing duplicate column 2025-10-05 11:42:56 -03:00
df4c76bd99 Refactor Manifest struct to change Dependencies from slice to map for better dependency management, and removing somethings from manifest struct too 2025-10-03 18:45:49 -03:00
af24fa84a2 don't need to verify index.db integrity anymore 2025-10-03 17:04:04 -03:00
4b54a9c74b Refactor database schema and update dependency handling in code 2025-10-03 17:03:23 -03:00
f25366d40c Refactor database schema and update dependency handling in code 2025-10-01 22:19:02 -03:00
cadf5fedcb Improving packets with better dependencie resolution, adding a function to auto resolve dependencies. 2025-10-01 18:11:53 -03:00
cfb11cf6e6 New database schema need to change all code files 2025-10-01 17:32:08 -03:00
bb4f221fc9 Adding "-r", to create a system user to not show up on user login screen 2025-09-29 19:21:24 -03:00
9cf5ae61d8 removing the second and useless exec.Command of useradd 2025-09-29 16:37:13 -03:00
ff4c61315e Removing unecessary param and variable on GetSandbox 2025-09-28 21:58:55 -03:00
76450789b0 io can be used, require too, and package 2025-09-28 21:55:50 -03:00
0e8db8b40e Enhance permission handling in package installation and removal commands; add user management functions for improved security. Now for every time packets will execute lua scripts, it will change process euid to an unprivileged user; Now lua scripts can execute more lua default functions 2025-09-28 21:55:13 -03:00
3591460214 Update search command description for clarity 2025-09-28 17:55:52 -03:00
96db4572b4 Add list command to manage installed packages, and search to see all packages avaiable 2025-09-28 17:55:36 -03:00
17e1b4b3ab Refactor logging and variable names for consistency; update log messages for clarity 2025-09-28 17:24:17 -03:00
73171424e4 Update dependencies: remove indirect reference to gin-gonic and add new dependencies for go-cmp, assert, and testify 2025-09-28 17:24:02 -03:00
b4f55ad36f Fixing some huge bugs, and implemented remove function 2025-09-28 16:45:51 -03:00
2c322d4de8 progress doing remove cmd, and removing GetPackage function from the pkg package, now GetPackage function can be found on package utils 2025-09-27 00:39:49 -03:00
2735749b12 Added a function to read manifest from the file manifest.toml and not only from a package file 2025-09-23 19:12:08 -03:00
05fbbde194 Setting data_dir variable to lua scripts to a string with the package data folder 2025-09-23 19:11:11 -03:00
fe81e6bf22 Revert "setting data_dir variable to a string with the package data folder"
This reverts commit 2cfe78721a.
2025-09-23 19:09:50 -03:00
2cfe78721a setting data_dir variable to a string with the package data folder 2025-09-23 19:08:21 -03:00
ff986ef943 now InstallPackage function from packets package don't try to read a config.toml, it get the path to install by a param; added async dependency install process 2025-09-21 22:52:03 -03:00
f34308367e Implement UDP socket server and add package installation check utility 2025-09-21 10:34:49 -03:00
68b394523d Add ed25519 public key and enhance package installation error handling
- Embed ed25519 public key for signature verification when doing sync prcess with servidordomal.fun
- Improve error handling in AddToInstalledDB to rollback on failure
- Update InstallPackage function to accept io.Reader instead of *os.File
2025-09-20 21:55:34 -03:00
b14bd1806a Zipping html files 2025-09-20 20:18:20 -03:00
3929493bfb enhance package database schema and configuration; add dependencies 2025-09-20 19:31:38 -03:00
2620ec00ab implement package synchronization and validation; update database schema and add error handling 2025-09-20 19:12:01 -03:00
0485b8325f new index.db schema, removed likes and reports 2025-09-20 16:05:53 -03:00
33d636b41d go.mod and go.sum with some indirect packages 2025-09-20 16:05:31 -03:00
ac236342b6 added web/ with some html and updated go.mod and go.sum to use gin 2025-09-20 13:04:32 -03:00
910cad2734 deleting old schema 2025-09-20 11:04:08 -03:00
fdb21aacc5 added .Execute to run cobracmds 2025-09-20 11:02:35 -03:00
a22a2a70c0 Database schemas added 2025-09-20 11:02:09 -03:00
f5399a66ba new index.db schema 2025-09-20 08:51:01 -03:00
9e09b1e3a4 renamed DownloadPackageHTTP function to GetFileHTTP 2025-09-19 23:33:12 -03:00
f8bda68a57 Added a const to index.db 2025-09-19 23:32:50 -03:00
b84d43200a index.db schema 2025-09-19 23:32:32 -03:00
35cbc2e47c Created copydir and copyfile functions in utils, now lua os.copy can copy an entire directory 2025-09-19 22:18:34 -03:00
3a068ed90b InstallPackage from pkg running luascript hook 2025-09-18 20:47:08 -03:00
bdbc580c82 GetSandbox aded on package utils_lua, it returns lua.LState with all sandboxfunctions 2025-09-18 20:40:05 -03:00
3c770c469d better file organization 2025-09-18 20:12:07 -03:00
1c00df24a4 Added ask for lan function 2025-09-13 23:11:48 -03:00
f3ccd6d683 Clean Install function and Download function 2025-09-13 22:57:52 -03:00
8de2eaced7 Doing organization improvements 2025-09-13 22:24:04 -03:00
c0057ca053 Deleting all to rewrite better 2025-09-13 20:45:07 -03:00
61149ae711 Added description for GetPackageByMirror function 2025-09-08 22:23:15 -03:00
bf10e39ffc Merge branch 'main' of https://github.com/roboogg133/packets 2025-09-08 22:22:07 -03:00
379f640f33 added Install function description 2025-09-08 22:22:03 -03:00
c7b0555076 Update README.md 2025-09-07 11:11:14 -03:00
a3d18ed3d7 Created package.lua example 2025-09-03 22:45:41 -03:00
5c39f7ab2c making LANDeadline const, more readable 2025-09-03 22:43:25 -03:00
b676ea873e Setting a global variable on lua scripts to check if is running safely or not 2025-09-03 22:26:39 -03:00
b6a67b30c5 Creating table packages on installed.db if doesn't exists 2025-09-03 22:22:18 -03:00
c0a8922c2e Setting a const variable to default deadline for lan deadline 2025-09-02 13:14:35 -03:00
fad209d23c Moving it to the test branch 2025-08-20 15:34:04 -03:00
8dd6c68a15 Moving this packages to test branch 2025-08-20 15:33:39 -03:00
0c81469566 missed return in mkdir function 2025-08-20 15:33:12 -03:00
6775002886 sorry for adding this to main branch 2025-08-20 14:47:05 -03:00
bf1f967581 test 2025-08-20 14:31:23 -03:00
21 changed files with 1931 additions and 2522 deletions

163
README.md
View File

@@ -1,163 +0,0 @@
# 📦 Packets Custom Package Manager for Linux
> A fast and minimal package manager written in Go with Lua hooks, local network discovery, and SQLite-based indexing.
---
## 📘 Overview
**Packets** is a lightweight package manager for Linux, written in Go. It supports:
- Installation and removal of packages
- Dependency resolution and upgrading
- `.tar.zst` compressed packages with `manifest.toml` metadata
- Lua-based install/remove hooks
- Local cache with SHA-256 validation
- Peer-to-peer discovery over LAN
- Remote package syncing via HTTP
- SQLite-based local database
---
## 📁 Directory Structure
| Path | Description |
|-----------------------|----------------------------------|
| `/etc/packets/` | Configuration files |
| `/opt/packets/` | Installed package data |
| `/var/cache/packets/` | Cached `.tar.zst` package files |
(This can be changed in `/etc/packets/config.toml`)
---
# Available Commands
| Command | Description |
|---------------------------|----------------------------------------------------------------------------|
|`packets install <name>` | Install a package (resolves dependencies, executes Lua install hook) |
|`packets remove <name>` | Remove a package (executes Lua remove hook) |
|`packets upgrade <name>` | Upgrade a package by checking family and serial in the manifest |
|`packets sync [url]` | Synchronize index.db from remote HTTP source |
|`packets serve init/stop` | Starts and stop the LAN service daemon |
|`packets list` | List all installed packages |
|`packets info` | Get technical package information |
|`packets search` | List all packages in index.db |
# 📦 Package Format
Packages must be compressed as .tar.zst and include:
- ├── manifest.toml # Package metadata
- ├── data/ # Files to install
- ├── install.lua # Lua install hook
- └── remove.lua # Lua remove hook
## Example manifest.toml
[Info]
name = "packets"
version = "1.0.0"
description = "offline and online packetmanager"
dependencies = []
author = "robo"
family = "1f84ca15-5077-4f1d-a370-0ec860766eb2"
serial = 0
[Hooks]
install = "install.lua"
remove = "remove.lua"
--
# 🔄 Installation Process
- Check if package is already cached and validated via SHA-256.
- If not, search the package:
Via LAN: Sends UDP broadcast (Q:filename) to peers.
Via HTTP: Downloads from configured mirrors.
Decompress .tar.zst, install files.
Execute Lua install hook.
# 🧩 Core Features
✅ Dependency Resolution
Installs required dependencies listed in the manifest.
## 🌐 LAN Discovery
Broadcasts package request to devices in the same network via UDP.
## 📡 Remote Download
Downloads package via HTTP if not found on LAN.
## 🔒 Security
SHA-256 checksum validation
Path validation to avoid exploits (..)
Safe, sandboxed Lua runtime with limited API
# 🌍 Global Variables Available in Lua Scripts
During the execution of install.lua and remove.lua hooks, some global variables are automatically provided to the Lua environment. These help simplify file path handling and access to package-specific directories.
## Available variables:
|Name |Type | Description
|--------------------|--------|--------------------------------------------------------------------------|
|packets_package_dir | string| Absolute path to the package's data directory (e.g., /opt/packets/...) |
| packets_bin_dir | string| Path where executables should be installed (e.g., /usr/bin) |
|script | string| Path to the currently executing script (e.g., "install.lua") |
|data_dir | string| Path to the /data folder of the current package |
### Example usage in Lua:
print("Installing into: " .. packets_bin_dir)
print("Package data in: " .. data_dir)
-- Copy a binary to /usr/bin
os.copy(path_join(data_dir, "htop"), path_join(packets_bin_dir, "htop"))
These variables are preloaded in the Lua environment—no need to manually declare or initialize them.
## 🛠️ Allowed Lua API (install/remove hooks)
To ensure security, only a limited set of safe functions are exposed in Lua hooks:
os.remove(path)
os.rename(old, new)
os.copy(source, target)
os.symlink(source, target)
io.open(path, mode)
os.mkdir(path, filemode)
path_join(...)
### Note: Dangerous functions like os.execute, os.getenv, etc. are removed.
## 🗃️ Databases
index.db: Available packages (after sync)
installed.db: Packages currently installed
# ⚠️ Restrictions & Notes
Linux only (//go:build linux)
Root permissions required for most commands
Changing dataDir triggers prompt to migrate installed packages
Binaries in binDir are not automatically moved if path changes
Do not manually edit lastDataDir
# TODO
- Auto upgrade all packages available
- Packets Universe

View File

@@ -1,37 +0,0 @@
package main
import (
"fmt"
"log"
"net/http"
"os"
"path/filepath"
"packets/internal"
"github.com/BurntSushi/toml"
)
type ConfigTOML struct {
Config struct {
DefaultHttpPort int `toml:"httpPort"`
DefaultCacheDir string `toml:"cacheDir"`
} `toml:"Config"`
}
func main() {
internal.PacketsPackageDir()
var cfg ConfigTOML
toml.Decode(filepath.Join(internal.PacketsPackageDir(), "config.toml"), &cfg)
pid := os.Getpid()
if err := os.WriteFile(filepath.Join(internal.PacketsPackageDir(), "http.pid"), []byte(fmt.Sprint(pid)), 0644); err != nil {
fmt.Println("error saving subprocess pid", err)
}
fs := http.FileServer(http.Dir(cfg.Config.DefaultCacheDir))
http.Handle("/", fs)
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", cfg.Config.DefaultHttpPort), nil))
}

36
cmd/httpsocket/main.go Normal file
View File

@@ -0,0 +1,36 @@
package main
import (
"fmt"
"log"
"net/http"
"os"
"packets/configs"
"packets/internal/consts"
"path/filepath"
)
type ConfigTOML struct {
Config struct {
DefaultHttpPort int `toml:"httpPort"`
DefaultCacheDir string `toml:"cacheDir"`
} `toml:"Config"`
}
func main() {
cfg, err := configs.GetConfigTOML()
if err != nil {
log.Fatal(err)
}
pid := os.Getpid()
if err := os.WriteFile(filepath.Join(consts.DefaultLinux_d, "http.pid"), []byte(fmt.Sprint(pid)), 0664); err != nil {
fmt.Println("error saving subprocess pid", err)
}
fs := http.FileServer(http.Dir(cfg.Config.Cache_d))
http.Handle("/", fs)
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", cfg.Config.HttpPort), nil))
}

File diff suppressed because it is too large Load Diff

View File

@@ -5,39 +5,32 @@ import (
"log" "log"
"net" "net"
"os" "os"
"packets/internal" "packets/configs"
"packets/internal/consts"
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/BurntSushi/toml"
) )
type ConfigTOML struct {
Config struct {
HttpPort int `toml:"httpPort"`
CacheDir string `toml:"cacheDir"`
} `toml:"Config"`
}
var cfg ConfigTOML
func CheckDownloaded(filename string) bool { func CheckDownloaded(filename string) bool {
_, err := os.Stat(filepath.Join(cfg.Config.CacheDir)) cfg, err := configs.GetConfigTOML()
if os.IsNotExist(err) { if err != nil {
return false log.Fatal(err)
} else {
return true
} }
_, err = os.Stat(filepath.Join(cfg.Config.Cache_d, filename))
return err == nil
} }
func main() { func main() {
pid := os.Getpid() pid := os.Getpid()
if err := os.WriteFile(filepath.Join(internal.PacketsPackageDir(), "udp.pid"), []byte(fmt.Sprint(pid)), 0644); err != nil { if err := os.WriteFile(filepath.Join(consts.DefaultLinux_d, "udp.pid"), []byte(fmt.Sprint(pid)), 0664); err != nil {
fmt.Println("error saving subprocess pid", err) fmt.Println("error saving subprocess pid", err)
} }
toml.Decode(filepath.Join(internal.PacketsPackageDir(), "config.toml"), &cfg) cfg, err := configs.GetConfigTOML()
if err != nil {
log.Fatal(err)
}
addr := net.UDPAddr{IP: net.IPv4zero, Port: 1333} addr := net.UDPAddr{IP: net.IPv4zero, Port: 1333}
conn, err := net.ListenUDP("udp", &addr) conn, err := net.ListenUDP("udp", &addr)

60
configs/main.go Normal file
View File

@@ -0,0 +1,60 @@
package configs
import (
"os"
"packets/internal/consts"
"path/filepath"
"github.com/pelletier/go-toml/v2"
)
// DefaultConfigTOML returns configTOML struct with all default values and create all directorys
func DefaultConfigTOML() (*ConfigTOML, error) {
var config ConfigTOML
_, err := os.Stat(consts.DefaultCache_d)
if err != nil {
if os.IsNotExist(err) {
err := os.MkdirAll(consts.DefaultCache_d, 0666)
if err != nil {
return nil, err
}
}
}
_, err = os.Stat(consts.DefaultCache_d)
if err != nil {
if os.IsNotExist(err) {
err := os.MkdirAll(consts.DefaultData_d, 0644)
if err != nil {
return nil, err
}
}
}
config.Config.Cache_d = consts.DefaultCache_d
config.Config.Data_d = consts.DefaultData_d
config.Config.HttpPort = consts.DefaultHttpPort
config.Config.Bin_d = consts.DefaultBin_d
config.Config.StorePackages = true
return &config, nil
}
// GetConfigTOML return settings values
func GetConfigTOML() (*ConfigTOML, error) {
f, err := os.Open(filepath.Join(consts.DefaultLinux_d, "config.toml"))
if err != nil {
return nil, err
}
decoder := toml.NewDecoder(f)
var config ConfigTOML
if err := decoder.Decode(&config); err != nil {
return nil, err
}
return &config, nil
}

26
configs/structs.go Normal file
View File

@@ -0,0 +1,26 @@
package configs
type Manifest struct {
Info struct {
Name string `toml:"name"`
Id string `toml:"id"`
Version string `toml:"version"`
Description string `toml:"description"`
Dependencies map[string]string `toml:"dependencies"`
Author string `toml:"author"`
} `toml:"Info"`
Hooks struct {
Install string `toml:"install"`
Remove string `toml:"remove"`
} `toml:"Hooks"`
}
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"`
StorePackages bool `toml:"store_packages"`
} `toml:"Config"`
}

47
doc/indexdbSchema.txt Normal file
View File

@@ -0,0 +1,47 @@
CREATE TABLE packages (
id TEXT NOT NULL UNIQUE PRIMARY KEY,
query_name TEXT NOT NULL,
version TEXT NOT NULL,
serial INTEGER NOT NULL,
description TEXT NOT NULL,
image_url TEXT NOT NULL,
package_url TEXT NOT NULL,
public_key BLOB NOT NULL,
signature BLOB NOT NULL,
author TEXT NOT NULL,
author_verified INTEGER NOT NULL DEFAULT 0,
arch TEXT NOT NULL,
os TEXT NOT NULL,
size INTEGER NOT NULL DEFAULT 0,
UNIQUE(query_name, version),
UNIQUE(query_name, serial)
);
CREATE TABLE package_dependencies(
package_id TEXT NOT NULL,
dependency_name TEXT NOT NULL,
version_constraint TEXT NOT NULL,
PRIMARY KEY (package_id, dependency_name)
);
CREATE INDEX index_dependency_name ON package_dependencies(dependency_name);
CREATE TABLE IF NOT EXISTS packages (
query_name TEXT NOT NULL UNIQUE PRIMARY KEY,
id TEXT NOT NULL UNIQUE,
version TEXT NOT NULL,
dependencies TEXT NOT NULL DEFAULT '',
description TEXT NOT NULL,
package_d TEXT NOT NULL,
filename TEXT NOT NULL,
os TEXT NOT NULL,
arch TEXT NOT NULL,
in_cache INTEGER NOT NULL DEFAULT 1,
serial INTEGER NOT NULL,
UNIQUE(query_name, version),
UNIQUE(query_name, serial)
);

50
go.mod
View File

@@ -1,31 +1,55 @@
module packets module packets
go 1.24.4 go 1.25.1
require ( require (
github.com/BurntSushi/toml v1.5.0 github.com/gin-gonic/gin v1.11.0
github.com/klauspost/compress v1.18.0 github.com/klauspost/compress v1.18.0
github.com/schollz/progressbar/v3 v3.18.0 github.com/pelletier/go-toml/v2 v2.2.4
github.com/spf13/cobra v1.9.1 github.com/spf13/cobra v1.10.1
github.com/yuin/gopher-lua v1.1.1 github.com/yuin/gopher-lua v1.1.1
golang.org/x/net v0.41.0 golang.org/x/net v0.44.0
modernc.org/sqlite v1.38.0 modernc.org/sqlite v1.38.2
) )
require ( require (
github.com/bytedance/sonic v1.14.0 // indirect
github.com/bytedance/sonic/loader v0.3.0 // indirect
github.com/cloudwego/base64x v0.1.6 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
github.com/gin-contrib/sse v1.1.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.27.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/goccy/go-yaml v1.18.0 // indirect
github.com/google/uuid v1.6.0 // indirect github.com/google/uuid v1.6.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/quic-go/qpack v0.5.1 // indirect
github.com/quic-go/quic-go v0.54.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rivo/uniseg v0.4.7 // indirect github.com/spf13/pflag v1.0.10 // indirect
github.com/spf13/pflag v1.0.7 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect github.com/ugorji/go/codec v1.3.0 // indirect
golang.org/x/sys v0.33.0 // indirect go.uber.org/mock v0.5.0 // indirect
golang.org/x/term v0.32.0 // indirect golang.org/x/arch v0.20.0 // indirect
modernc.org/libc v1.65.10 // indirect golang.org/x/crypto v0.42.0 // indirect
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect
golang.org/x/mod v0.27.0 // indirect
golang.org/x/sync v0.17.0 // indirect
golang.org/x/sys v0.36.0 // indirect
golang.org/x/text v0.29.0 // indirect
golang.org/x/tools v0.36.0 // indirect
google.golang.org/protobuf v1.36.9 // indirect
modernc.org/libc v1.66.3 // indirect
modernc.org/mathutil v1.7.1 // indirect modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.11.0 // indirect modernc.org/memory v1.11.0 // indirect
) )

136
go.sum
View File

@@ -1,74 +1,128 @@
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= github.com/bytedance/sonic v1.14.0 h1:/OfKt8HFw0kh2rj8N0F6C/qPGRESq0BbaNZgcNXXzQQ=
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/bytedance/sonic v1.14.0/go.mod h1:WoEbx8WTcFJfzCe0hbmyTGrfjt8PzNEBdxlNUO24NhA=
github.com/chengxilo/virtualterm v1.0.4 h1:Z6IpERbRVlfB8WkOmtbHiDbBANU7cimRIof7mk9/PwM= github.com/bytedance/sonic/loader v0.3.0 h1:dskwH8edlzNMctoruo8FPTJDF3vLtDT0sXZwvZJyqeA=
github.com/chengxilo/virtualterm v1.0.4/go.mod h1:DyxxBZz/x1iqJjFxTFcr6/x+jSpqN0iwWCOK1q10rlY= github.com/bytedance/sonic/loader v0.3.0/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= 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/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
github.com/gin-gonic/gin v1.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk=
github.com/gin-gonic/gin v1.11.0/go.mod h1:+iq/FyxlGzII0KHiBGjuNn4UNENUlKbGlNmc+W50Dls=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.27.0 h1:w8+XrWVMhGkxOaaowyKH35gFydVHOvC0/uWoy2Fzwn4=
github.com/go-playground/validator/v10 v10.27.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs= 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/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 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 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 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 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/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= 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/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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
github.com/quic-go/quic-go v0.54.0 h1:6s1YB9QotYI6Ospeiguknbp2Znb/jZYjZLRXn9kMQBg=
github.com/quic-go/quic-go v0.54.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= 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/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/schollz/progressbar/v3 v3.18.0 h1:uXdoHABRFmNIjUfte/Ex7WtuyVslrw2wVPQmCN62HpA= github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s=
github.com/schollz/progressbar/v3 v3.18.0/go.mod h1:IsO3lpbaGuzh8zIMzgY3+J8l4C8GjO0Y9S69eFvNsec= github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0=
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA=
github.com/ugorji/go/codec v1.3.0/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M= github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M=
github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM= go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8= go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= golang.org/x/arch v0.20.0 h1:dx1zTU0MAE98U+TQ8BLl7XsJbgze2WnNKF/8tGp/Q6c=
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/arch v0.20.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk=
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o=
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8=
golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ=
golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I=
golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc= golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg=
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
modernc.org/cc/v4 v4.26.1 h1:+X5NtzVBn0KgsBCBe+xkDC7twLb/jNVj9FPgiwSQO3s= modernc.org/cc/v4 v4.26.2 h1:991HMkLjJzYBIfha6ECZdjrIYz2/1ayr+FL8GN+CNzM=
modernc.org/cc/v4 v4.26.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= 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 h1:rjznn6WWehKq7dG4JtLRKxb52Ecv8OUGah8+Z/SfpNU=
modernc.org/ccgo/v4 v4.28.0/go.mod h1:JygV3+9AV6SmPhDasu4JgquwU81XAKLd3OKTUDNOiKE= modernc.org/ccgo/v4 v4.28.0/go.mod h1:JygV3+9AV6SmPhDasu4JgquwU81XAKLd3OKTUDNOiKE=
modernc.org/fileutil v1.3.3 h1:3qaU+7f7xxTUmvU1pJTZiDLAIoJVdUSSauJNHg9yXoA= modernc.org/fileutil v1.3.8 h1:qtzNm7ED75pd1C7WgAGcK4edm4fvhtBsEiI/0NQ54YM=
modernc.org/fileutil v1.3.3/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc= 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 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
modernc.org/libc v1.65.10 h1:ZwEk8+jhW7qBjHIT+wd0d9VjitRyQef9BnzlzGwMODc= modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks=
modernc.org/libc v1.65.10/go.mod h1:StFvYpx7i/mXtBAfVOjaU0PWZOvIRoZSgXhrwXzr8Po= 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 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= 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 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
@@ -77,8 +131,8 @@ modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=
modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= 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 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
modernc.org/sqlite v1.38.0 h1:+4OrfPQ8pxHKuWG4md1JpR/EYAh3Md7TdejuuzE7EUI= modernc.org/sqlite v1.38.2 h1:Aclu7+tgjgcQVShZqim41Bbw9Cho0y/7WzYptXqkEek=
modernc.org/sqlite v1.38.0/go.mod h1:1Bj+yES4SVvBZ4cBOpVZ6QgesMCKpJZDq0nxYzOpmNE= 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 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= 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 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=

Binary file not shown.

43
internal/consts/consts.go Normal file
View File

@@ -0,0 +1,43 @@
package consts
import "time"
const (
DefaultLinux_d = "/etc/packets"
DefaultCache_d = "/var/cache/packets"
DefaultHttpPort = 9123
DefaultBin_d = "/usr/local/bin"
DefaultData_d = "/opt/packets"
LANDeadline = 2 * time.Second
IndexDB = "/etc/packets/index.db"
InstalledDB = "/etc/packets/installed.db"
DefaultSyncUrl = "https://servidordomal.fun/index.db"
)
const InstalledDatabaseSchema = `CREATE TABLE IF NOT EXISTS packages (
query_name TEXT NOT NULL UNIQUE PRIMARY KEY,
id TEXT NOT NULL UNIQUE,
version TEXT NOT NULL,
dependencies TEXT NOT NULL DEFAULT '',
description TEXT NOT NULL,
package_d TEXT NOT NULL,
filename TEXT NOT NULL,
os TEXT NOT NULL,
arch TEXT NOT NULL,
in_cache INTEGER NOT NULL DEFAULT 1,
serial INTEGER NOT NULL,
UNIQUE(query_name, version),
UNIQUE(query_name, serial)
);
CREATE TABLE package_dependencies(
package_id TEXT NOT NULL,
dependency_name TEXT NOT NULL,
version_constraint TEXT NOT NULL,
PRIMARY KEY (package_id, dependency_name)
);
CREATE INDEX index_dependency_name ON package_dependencies(dependency_name);
`

11
internal/errors/errors.go Normal file
View File

@@ -0,0 +1,11 @@
package errors_packets
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")
ErrInvalidSignature = errors.New("the signature is invalid")
ErrNotInstalled = errors.New("the package isn't installed")
ErrAlredyUpToDate = errors.New("alredy up to date")
)

View File

@@ -1,552 +0,0 @@
package internal
import (
"archive/tar"
"fmt"
"io"
"io/fs"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
"github.com/BurntSushi/toml"
"github.com/klauspost/compress/zstd"
lua "github.com/yuin/gopher-lua"
)
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"
"ts": "tsc", // "TypeScript compiler"
"ruby": "rubyc", // "Ruby compiler"
}
type ConfigTOML struct {
Config struct {
HttpPort int `toml:"httpPort"`
CacheDir string `toml:"cacheDir"`
AutoDeleteCacheDir bool `toml:"dayToDeleteCacheDir"`
DaysToDelete int `toml:"daysToDelete"`
DataDir string `toml:"dataDir"`
BinDir string `toml:"binDir"`
LastDataDir string `toml:"lastDataDir"`
} `toml:"Config"`
}
type Manifest struct {
Info struct {
Name string `toml:"name"`
Version string `toml:"version"`
Description string `toml:"description"`
Dependencies []string `toml:"dependencies"`
Author string `toml:"author"`
Family string `toml:"family"`
Serial uint `toml:"serial"`
} `toml:"Info"`
Hooks struct {
Install string `toml:"install"`
Remove string `toml:"remove"`
} `toml:"Hooks"`
}
var SandboxDir string
func PacketsPackageDir() string {
out, _ := exec.Command("uname", "-s").Output()
if uname := strings.TrimSpace(string(out)); uname == "J2ME" {
_, err := os.Stat("packets.help")
if os.IsNotExist(err) {
err = nil
var thedirectory string
err := filepath.WalkDir("/mnt", func(path string, d fs.DirEntry, err error) error {
if d.IsDir() {
thedirectory = filepath.Join(path, "packets")
if err := os.Mkdir(thedirectory, 0644); err != nil {
return err
}
if err := os.WriteFile("packets.help", []byte(thedirectory), 0644); err != nil {
return err
}
if err := os.Mkdir(filepath.Join(filepath.Join(thedirectory, "cache")), 0644); err != nil {
return err
}
if err := os.Mkdir(filepath.Join(filepath.Join(thedirectory, "packages")), 0644); err != nil {
return err
}
if err := os.Mkdir(filepath.Join(filepath.Join(thedirectory, "bin")), 0644); err != nil {
return err
}
return nil
}
return nil
})
if err != nil {
log.Fatal(err)
}
return thedirectory
}
byt, err := os.ReadFile("packets.help")
if err != nil {
log.Fatal(err)
}
return string(byt)
} else {
return "/etc/packets"
}
}
func ManifestReadXZ(path string) (*Manifest, error) {
f, err := os.Open(path)
if err != nil {
return nil, err
}
defer f.Close()
zr, err := zstd.NewReader(f)
if err != nil {
return nil, err
}
defer zr.Close()
tarReader := tar.NewReader(zr)
for {
header, err := tarReader.Next()
if err == io.EOF {
break
}
if err != nil {
return nil, err
}
if filepath.Base(header.Name) == "manifest.toml" {
decoder := toml.NewDecoder(tarReader)
var manifest Manifest
if _, err := decoder.Decode(&manifest); err != nil {
log.Fatal(err)
}
return &manifest, nil
}
}
return nil, fmt.Errorf("can't find manifest.toml")
}
func DefaultConfigTOML() *ConfigTOML {
var cfg ConfigTOML
out, _ := exec.Command("uname", "-s").Output()
if uname := strings.TrimSpace(string(out)); uname == "J2ME" {
cfg.Config.HttpPort = 9123
cfg.Config.AutoDeleteCacheDir = false
cfg.Config.CacheDir = filepath.Join(PacketsPackageDir(), "cache")
cfg.Config.DataDir = filepath.Join(PacketsPackageDir(), "data")
cfg.Config.DaysToDelete = -1
cfg.Config.BinDir = filepath.Join(PacketsPackageDir(), "bin")
cfg.Config.LastDataDir = filepath.Join(PacketsPackageDir(), "data")
return &cfg
} else {
cfg.Config.HttpPort = 9123
cfg.Config.AutoDeleteCacheDir = false
cfg.Config.CacheDir = "/var/cache/packets"
cfg.Config.DataDir = "/opt/packets"
cfg.Config.DaysToDelete = -1
cfg.Config.BinDir = "/usr/bin"
cfg.Config.LastDataDir = "/opt/packets"
return &cfg
}
}
func IsSafe(str string) bool {
s, err := filepath.EvalSymlinks(filepath.Clean(str))
if err != nil {
s = filepath.Clean(str)
}
var cfg ConfigTOML
toml.DecodeFile(filepath.Join(PacketsPackageDir(), "config.toml"), &cfg)
if strings.HasPrefix(s, cfg.Config.DataDir) || strings.HasPrefix(s, cfg.Config.BinDir) {
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
}
func SafeRemove(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 SafeRename(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 SafeCopy(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 SymbolicLua(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 SafeOpen(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"))
}
if err := os.MkdirAll(path, os.FileMode(perm)); err != nil {
L.Push(lua.LFalse)
L.Push(lua.LString("[packets] mkdir failed\n" + err.Error()))
}
L.Push(lua.LTrue)
L.Push(lua.LNil)
return 2
}
func LuaCompile(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(L.CheckString(i)))
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
}
}
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 CompileRequirements(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
}

80
internal/utils/lan.go Normal file
View File

@@ -0,0 +1,80 @@
package utils
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
}

36
internal/utils/lua/lua.go Normal file
View File

@@ -0,0 +1,36 @@
package utils_lua
import (
"packets/configs"
lua "github.com/yuin/gopher-lua"
)
func GetSandBox() (lua.LState, error) {
cfg, err := configs.GetConfigTOML()
if err != nil {
return *lua.NewState(), err
}
L := lua.NewState()
osObject := L.GetGlobal("os").(*lua.LTable)
L.SetGlobal("SAFE_MODE", lua.LTrue)
L.SetGlobal("PACKETS_DATADIR", lua.LString(cfg.Config.Data_d))
L.SetGlobal("packets_bin_dir", lua.LString(cfg.Config.Bin_d))
L.SetGlobal("path_join", L.NewFunction(Ljoin))
// Packets build functions
osObject.RawSetString("remove", L.NewFunction(LSafeRemove))
osObject.RawSetString("rename", L.NewFunction(LSafeRename))
osObject.RawSetString("copy", L.NewFunction(LSafeCopy))
osObject.RawSetString("symlink", L.NewFunction(LSymlink))
osObject.RawSetString("mkdir", L.NewFunction(LMkdir))
//ioObject.RawSetString("open", L.NewFunction(LOpen))
return *L, nil
}

View File

@@ -0,0 +1,260 @@
package utils_lua
import (
"fmt"
"log"
"os"
"packets/configs"
"packets/internal/consts"
"packets/internal/utils"
"path/filepath"
"strings"
"github.com/pelletier/go-toml/v2"
lua "github.com/yuin/gopher-lua"
)
func IsSafe(str string) bool {
s, err := filepath.EvalSymlinks(filepath.Clean(str))
if err != nil {
s = filepath.Clean(str)
}
var cfg configs.ConfigTOML
f, err := os.Open(filepath.Join(consts.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)
fmt.Printf(" remove %s\n", filename)
err := os.RemoveAll(filename)
if 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 LSafeRename(L *lua.LState) int {
oldname := L.CheckString(1)
newname := L.CheckString(2)
fmt.Printf(" move %s -> %s\n", oldname, newname)
if err := os.Rename(oldname, newname); err != nil {
L.Push(lua.LFalse)
L.Push(lua.LString(err.Error()))
return 2
}
L.Push(lua.LTrue)
return 1
}
func LSafeCopy(L *lua.LState) int {
oldname := L.CheckString(1)
newname := L.CheckString(2)
fmt.Printf(" copy %s -> %s\n", oldname, newname)
if err := utils.CopyDir(oldname, newname); 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 LSymlink(L *lua.LState) int {
fileName := L.CheckString(1)
destination := L.CheckString(2)
fmt.Printf(" symlink %s -> %s\n", fileName, destination)
_ = os.RemoveAll(destination)
if err := os.Symlink(fileName, destination); 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 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")
file, err := os.OpenFile(path, modeFlags(mode), 0644)
if err != nil {
L.Push(lua.LNil)
L.Push(lua.LString(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)
fmt.Printf(" mkdir %s \n", path)
/*
if !IsSafe(path) {
L.Push(lua.LFalse)
L.Push(lua.LString("unsafe filepath"))
return 2
}
*/
if err := os.MkdirAll(path, os.FileMode(perm)); 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 LError(L *lua.LState) int {
n := L.GetTop()
parts := make([]any, 0, n)
for i := 1; i <= n; i++ {
val := L.Get(i)
parts = append(parts, val.String())
}
Llogger().Panic(parts...)
return 0
}
func Llogger() *log.Logger { return log.New(os.Stderr, " script error: ", 0) }

512
internal/utils/utils.go Normal file
View File

@@ -0,0 +1,512 @@
package utils
import (
"archive/tar"
"bytes"
"crypto/ed25519"
"database/sql"
"fmt"
"io"
"log"
"net/http"
"os"
"os/exec"
"path"
"path/filepath"
"strconv"
"strings"
"syscall"
"packets/configs"
"packets/internal/consts"
errors_packets "packets/internal/errors"
"github.com/klauspost/compress/zstd"
"github.com/pelletier/go-toml/v2"
)
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
Manifest configs.Manifest
Serial int
}
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
}
// 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 {
return err
} else {
if stats.IsDir() {
files, err := os.ReadDir(src)
if err != nil {
return err
}
if err := os.MkdirAll(dest, 0o755); err != nil {
return err
}
for _, file := range files {
if file.IsDir() {
CopyDir(filepath.Join(src, file.Name()), filepath.Join(dest, file.Name()))
continue
}
srcFile := filepath.Join(src, file.Name())
f, err := os.Create(filepath.Join(dest, file.Name()))
if err != nil {
return err
}
defer f.Close()
opennedSrcFile, err := os.Open(srcFile)
if err != nil {
return err
}
defer opennedSrcFile.Close()
if _, err := io.Copy(f, opennedSrcFile); err != nil {
return err
}
}
} else {
if err := CopyFile(src, dest); err != nil {
return err
}
}
}
return nil
}
// CopyFile copies a file from source to destination
func CopyFile(source string, destination string) error {
src, err := os.Open(source)
if err != nil {
return err
}
defer src.Close()
status, err := src.Stat()
if err != nil {
return err
}
err = os.MkdirAll(filepath.Dir(destination), 0o755)
if err != nil {
return err
}
dst, err := os.Create(destination)
if err != nil {
if !os.IsExist(err) {
dst, err = os.Open(destination)
if err != nil {
return err
}
} else {
return err
}
}
defer dst.Close()
if err := dst.Chmod(status.Mode()); err != nil {
return err
}
_, err = io.Copy(dst, src)
if err != nil {
return err
}
return nil
}
// 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))
return "", err
}
return filepath.Join(consts.DefaultCache_d, p.Filename), nil
}
func (p *Package) AddToInstalledDB(inCache int, packagePath string) error {
db, err := sql.Open("sqlite", consts.InstalledDB)
if err != nil {
return err
}
defer db.Close()
var success bool
defer func() {
if !success {
_, err := db.Exec("DELETE FROM packages WHERE id = ?", p.Manifest.Info.Id)
if err != nil {
log.Println("failed to rollback package addition:", err)
}
}
}()
_, err = db.Exec(`
INSERT INTO packages (
query_name, id, version, description,
serial, package_d, filename, os, arch, in_cache
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
p.QueryName,
p.Manifest.Info.Id,
p.Version,
p.Description,
p.Serial,
packagePath,
p.Filename,
p.OS,
p.Arch,
inCache,
)
if err != nil {
return err
}
for depnName, versionConstraint := range p.Dependencies {
_, err = db.Exec("INSERT INTO package_dependencies (package_id, dependency_name, version_constraint) VALUES (?, ?, ?)", p.Manifest.Info.Id, depnName, versionConstraint)
}
success = true
return err
}
func CheckIfPackageInstalled(name string) (bool, error) {
db, err := sql.Open("sqlite", consts.InstalledDB)
if err != nil {
return false, err
}
defer db.Close()
if strings.Contains(name, "@") {
name = strings.SplitN(name, "@", 2)[0]
}
var exists bool
err = db.QueryRow("SELECT EXISTS(SELECT 1 FROM packages WHERE query_name = ?)", name).Scan(&exists)
if err != nil {
return false, err
}
return exists, nil
}
func GetDependencies(db *sql.DB, id string) (map[string]string, error) {
rows, err := db.Query("SELECT dependency_name, version_constraint FROM package_dependencies WHERE package_id = ?", id)
if err != nil {
return map[string]string{}, err
}
defer rows.Close()
dependencies := make(map[string]string)
for rows.Next() {
var a, versionConstraint string
if err := rows.Scan(&a, &versionConstraint); err != nil {
return map[string]string{}, err
}
dependencies[a] = versionConstraint
}
return dependencies, nil
}
func ResolvDependencies(depnList map[string]string) ([]string, error) {
db, err := sql.Open("sqlite", consts.IndexDB)
if err != nil {
return []string{}, err
}
defer db.Close()
var resolved []string
for dependencieName, constraint := range depnList {
var filter, order string
value := strings.TrimLeft(constraint, "<>=")
switch {
case strings.HasPrefix(constraint, ">"):
filter = fmt.Sprintf("AND serial > %s", value)
order = "ORDER BY serial DESC LIMIT 1"
case strings.HasPrefix(constraint, "<="):
filter = fmt.Sprintf("AND serial <= %s", value)
order = "ORDER BY serial ASC LIMIT 1"
case strings.HasPrefix(constraint, "<"):
filter = fmt.Sprintf("AND serial < %s", value)
order = "ORDER BY serial ASC LIMIT 1"
case strings.HasPrefix(constraint, "="):
filter = fmt.Sprintf("AND serial = %s", value)
order = ""
}
var packageId string
err := db.QueryRow(fmt.Sprintf("SELECT id FROM packages WHERE query_name = ? %s %s", filter, order), dependencieName).Scan(&packageId)
if err != nil {
if err == sql.ErrNoRows {
continue
}
return []string{}, err
}
resolved = append(resolved, packageId)
dp, err := GetDependencies(db, packageId)
if err != nil {
return resolved, err
}
depn, err := ResolvDependencies(dp)
if err != nil {
return resolved, err
}
resolved = append(resolved, depn...)
}
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 {
return err
}
if _, err = db.Exec("DELETE FROM packages WHERE id = ? OR query_name = ?", id, id); err != nil {
return err
}
return nil
}
// GetPackage retrieves package information from the index database and downloads the package file
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 string
err = db.QueryRow("SELECT query_name, version, package_url, image_url, description, author, author_verified, os, arch, signature, public_key, serial, size 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,
)
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
}
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
}
}
}
skipping:
reader := bytes.NewReader(this.PackageF)
this.Manifest, err = ReadManifest(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 GetPacketsUID() (int, error) {
_ = exec.Command("useradd", "-M", "-N", "-r", "-s", "/bin/false", "-d", "/var/lib/packets", "packets").Run()
cmd := exec.Command("id", "-u", "packets")
out, err := cmd.CombinedOutput()
if err != nil {
return -1, err
}
s := strings.TrimSpace(string(out))
uid, err := strconv.Atoi(s)
if err != nil {
return -1, err
}
return uid, nil
}
func ChangeToNoPermission() error {
uid, err := GetPacketsUID()
if err != nil {
return err
}
_ = os.Chown("/var/lib/packets", uid, 0)
return syscall.Setresuid(0, uid, 0)
}
func ElevatePermission() error { return syscall.Setresuid(0, 0, 0) }

164
pkg/main.go Normal file
View File

@@ -0,0 +1,164 @@
package packets
import (
"archive/tar"
"bytes"
"io"
"os"
"packets/internal/utils"
"runtime"
utils_lua "packets/internal/utils/lua"
"path/filepath"
"strings"
"github.com/klauspost/compress/zstd"
lua "github.com/yuin/gopher-lua"
_ "modernc.org/sqlite"
)
// Install exctract and fully install from a package file ( tar.zst )
func InstallPackage(file []byte, destDir string) error {
manifest, err := utils.ReadManifest(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) == "manifest.toml" || filepath.Base(hdr.Name) == manifest.Hooks.Install || filepath.Base(hdr.Name) == manifest.Hooks.Remove {
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
}
L.SetGlobal("data_dir", lua.LString(filepath.Join(destDir, "data")))
L.SetGlobal("script", lua.LString(manifest.Hooks.Install))
runtime.LockOSThread()
defer runtime.UnlockOSThread()
if err := utils.ChangeToNoPermission(); err != nil {
return err
}
if err := L.DoFile(filepath.Join(destDir, manifest.Hooks.Install)); err != nil {
return err
}
if err := utils.ElevatePermission(); err != nil {
return err
}
return nil
}
// ExecuteRemoveScript executes the remove script from the package
func ExecuteRemoveScript(path string) error {
L, err := utils_lua.GetSandBox()
if err != nil {
return err
}
L.SetGlobal("data_dir", lua.LFalse)
L.SetGlobal("script", lua.LString(path))
L.SetGlobal("build", lua.LNil)
runtime.LockOSThread()
defer runtime.UnlockOSThread()
if err := utils.ChangeToNoPermission(); err != nil {
return err
}
if err := L.DoFile(path); err != nil {
return err
}
if err := utils.ElevatePermission(); err != nil {
return err
}
return nil
}

Binary file not shown.

Binary file not shown.