Panel — public source drop (v0.9.0)
Self-hostable game-server control panel: controller + agent + 26 game modules. One-line install (prebuilt release, no Go required): curl -fsSL https://git.pdxtechs.com/dbledeez/panel/raw/branch/main/install.sh | sudo bash Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,180 @@
|
||||
package archive
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/ulikunitz/xz"
|
||||
)
|
||||
|
||||
// buildTar writes a small dir+file tree as a tar stream.
|
||||
func buildTar(t *testing.T, w io.Writer) {
|
||||
t.Helper()
|
||||
tw := tar.NewWriter(w)
|
||||
if err := tw.WriteHeader(&tar.Header{Name: "factorio/", Typeflag: tar.TypeDir, Mode: 0o755}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
body := []byte("#!/bin/sh\necho hi\n")
|
||||
if err := tw.WriteHeader(&tar.Header{Name: "factorio/bin/x64/factorio", Typeflag: tar.TypeReg, Mode: 0o755, Size: int64(len(body))}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := tw.Write(body); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := tw.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func makeTarXz(t *testing.T) []byte {
|
||||
t.Helper()
|
||||
var buf bytes.Buffer
|
||||
xw, err := xz.NewWriter(&buf)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
buildTar(t, xw)
|
||||
if err := xw.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
func makeTarGz(t *testing.T) []byte {
|
||||
t.Helper()
|
||||
var buf bytes.Buffer
|
||||
gw := gzip.NewWriter(&buf)
|
||||
buildTar(t, gw)
|
||||
if err := gw.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
func makeZip(t *testing.T) []byte {
|
||||
t.Helper()
|
||||
var buf bytes.Buffer
|
||||
zw := zip.NewWriter(&buf)
|
||||
f, err := zw.Create("factorio/bin/x64/factorio")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := f.Write([]byte("#!/bin/sh\necho hi\n")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := zw.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
func TestDetectFormatMagicBytes(t *testing.T) {
|
||||
// Extensionless names — magic bytes must carry detection (factorio's
|
||||
// download URL has no file extension).
|
||||
cases := []struct {
|
||||
data []byte
|
||||
want string
|
||||
}{
|
||||
{makeTarXz(t), "tar.xz"},
|
||||
{makeTarGz(t), "tar.gz"},
|
||||
{makeZip(t), "zip"},
|
||||
{[]byte("plain text, not an archive"), ""},
|
||||
}
|
||||
for _, c := range cases {
|
||||
if got := DetectFormat(c.data, "https://example.com/get-download/stable/headless/linux64"); got != c.want {
|
||||
t.Errorf("DetectFormat = %q, want %q", got, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDetectFormatExtensionFallback(t *testing.T) {
|
||||
// Content too short for magic — extension hint decides.
|
||||
if got := DetectFormat([]byte{}, "thing.tar.xz"); got != "tar.xz" {
|
||||
t.Errorf("extension fallback = %q, want tar.xz", got)
|
||||
}
|
||||
if got := DetectFormat([]byte{}, "thing.tgz"); got != "tar.gz" {
|
||||
t.Errorf("extension fallback = %q, want tar.gz", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWalkAllFormats(t *testing.T) {
|
||||
for name, data := range map[string][]byte{
|
||||
"tar.xz": makeTarXz(t),
|
||||
"tar.gz": makeTarGz(t),
|
||||
"zip": makeZip(t),
|
||||
} {
|
||||
var files []string
|
||||
var content []byte
|
||||
entries, _, err := Walk(data, "blob", func(n string, mode int64, isDir bool, body io.Reader) error {
|
||||
if isDir {
|
||||
return nil
|
||||
}
|
||||
files = append(files, n)
|
||||
b, err := io.ReadAll(body)
|
||||
content = b
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("%s: Walk: %v", name, err)
|
||||
}
|
||||
if entries == 0 || len(files) != 1 || files[0] != "factorio/bin/x64/factorio" {
|
||||
t.Fatalf("%s: unexpected entries %d files %v", name, entries, files)
|
||||
}
|
||||
if string(content) != "#!/bin/sh\necho hi\n" {
|
||||
t.Fatalf("%s: content mismatch: %q", name, content)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriteAsTarRoundTrip(t *testing.T) {
|
||||
var out bytes.Buffer
|
||||
entries, bytesOut, err := WriteAsTar(makeTarXz(t), "blob", &out)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if entries != 2 {
|
||||
t.Fatalf("entries = %d, want 2", entries)
|
||||
}
|
||||
if bytesOut == 0 {
|
||||
t.Fatal("bytesOut = 0")
|
||||
}
|
||||
// Re-walk the emitted tar and check the file mode survived.
|
||||
tr := tar.NewReader(&out)
|
||||
var sawFile bool
|
||||
for {
|
||||
hdr, err := tr.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if hdr.Typeflag == tar.TypeReg {
|
||||
sawFile = true
|
||||
if hdr.Name != "factorio/bin/x64/factorio" {
|
||||
t.Fatalf("name = %q", hdr.Name)
|
||||
}
|
||||
if hdr.Mode&0o111 == 0 {
|
||||
t.Fatalf("exec bit lost: mode %o", hdr.Mode)
|
||||
}
|
||||
}
|
||||
}
|
||||
if !sawFile {
|
||||
t.Fatal("no regular file in re-emitted tar")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSafeEntryPathRejectsTraversal(t *testing.T) {
|
||||
for _, bad := range []string{"../evil", "a/../../evil", "..", ""} {
|
||||
if got := SafeEntryPath(bad); got != "" {
|
||||
t.Errorf("SafeEntryPath(%q) = %q, want rejection", bad, got)
|
||||
}
|
||||
}
|
||||
if got := SafeEntryPath("/abs/path"); got != "abs/path" {
|
||||
t.Errorf("leading slash strip = %q", got)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user