Files
arinera-minecraft-tool/actions_test.go
2026-06-05 20:26:24 +08:00

148 lines
3.9 KiB
Go

package main
import (
"archive/zip"
"os"
"path/filepath"
"strings"
"testing"
)
func TestSafeJoinRejectsUnsafePaths(t *testing.T) {
versionDir := t.TempDir()
unsafePaths := []string{
"",
".",
"/outside.txt",
"\\outside.txt",
"..",
filepath.Join("..", "outside.txt"),
filepath.Join("amt", "backup", "old.txt"),
}
for _, p := range unsafePaths {
if _, _, err := safeJoin(versionDir, p); err == nil {
t.Fatalf("safeJoin(%q) returned nil error", p)
}
}
target, cleanRel, err := safeJoin(versionDir, filepath.Join("mods", "ok.jar"))
if err != nil {
t.Fatalf("safeJoin valid path failed: %v", err)
}
if cleanRel != filepath.Join("mods", "ok.jar") {
t.Fatalf("unexpected clean path: %q", cleanRel)
}
if !strings.HasPrefix(target, versionDir) {
t.Fatalf("target %q is not under %q", target, versionDir)
}
}
func TestBackupPathDoesNotOverwriteExistingBackup(t *testing.T) {
versionDir := t.TempDir()
src := filepath.Join(versionDir, "mods", "config.txt")
if err := os.MkdirAll(filepath.Dir(src), 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(src, []byte("first"), 0o644); err != nil {
t.Fatal(err)
}
backupDir := filepath.Join("amt", "backup", "run")
if err := backupPath(versionDir, filepath.Join("mods", "config.txt"), backupDir); err != nil {
t.Fatalf("first backup failed: %v", err)
}
if err := os.WriteFile(src, []byte("second"), 0o644); err != nil {
t.Fatal(err)
}
if err := backupPath(versionDir, filepath.Join("mods", "config.txt"), backupDir); err != nil {
t.Fatalf("second backup failed: %v", err)
}
first, err := os.ReadFile(filepath.Join(versionDir, backupDir, "mods", "config.txt"))
if err != nil {
t.Fatal(err)
}
second, err := os.ReadFile(filepath.Join(versionDir, backupDir, "mods", "config.txt.1"))
if err != nil {
t.Fatal(err)
}
if string(first) != "first" || string(second) != "second" {
t.Fatalf("unexpected backups: first=%q second=%q", first, second)
}
}
func TestBackupPathRejectsSelfNestedBackup(t *testing.T) {
versionDir := t.TempDir()
if err := os.MkdirAll(filepath.Join(versionDir, "amt", "data"), 0o755); err != nil {
t.Fatal(err)
}
err := backupPath(versionDir, "amt", filepath.Join("amt", "backup", "run"))
if err == nil {
t.Fatal("backupPath allowed backing up a directory into itself")
}
}
func TestUnzipBacksUpOverwrittenFiles(t *testing.T) {
versionDir := t.TempDir()
if err := os.WriteFile(filepath.Join(versionDir, "config.txt"), []byte("old"), 0o644); err != nil {
t.Fatal(err)
}
zipPath := filepath.Join(versionDir, "pack.zip")
writeTestZip(t, zipPath, map[string]string{"config.txt": "new"})
backupDir := filepath.Join("amt", "backup", "run")
if err := unzipFile(zipPath, versionDir, versionDir, backupDir); err != nil {
t.Fatalf("unzipFile failed: %v", err)
}
current, err := os.ReadFile(filepath.Join(versionDir, "config.txt"))
if err != nil {
t.Fatal(err)
}
backup, err := os.ReadFile(filepath.Join(versionDir, backupDir, "config.txt"))
if err != nil {
t.Fatal(err)
}
if string(current) != "new" || string(backup) != "old" {
t.Fatalf("unexpected files: current=%q backup=%q", current, backup)
}
}
func TestUnzipRejectsBackupTarget(t *testing.T) {
versionDir := t.TempDir()
zipPath := filepath.Join(versionDir, "pack.zip")
writeTestZip(t, zipPath, map[string]string{"amt/backup/evil.txt": "bad"})
err := unzipFile(zipPath, versionDir, versionDir, filepath.Join("amt", "backup", "run"))
if err == nil {
t.Fatal("unzipFile allowed writing into backup directory")
}
}
func writeTestZip(t *testing.T, zipPath string, files map[string]string) {
t.Helper()
out, err := os.Create(zipPath)
if err != nil {
t.Fatal(err)
}
defer out.Close()
w := zip.NewWriter(out)
defer w.Close()
for name, body := range files {
f, err := w.Create(name)
if err != nil {
t.Fatal(err)
}
if _, err := f.Write([]byte(body)); err != nil {
t.Fatal(err)
}
}
}