148 lines
3.9 KiB
Go
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)
|
|
}
|
|
}
|
|
}
|