| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466 | package backupimport (	"os"	"path/filepath"	"testing"	"github.com/0xJacky/Nginx-UI/settings"	"github.com/stretchr/testify/assert"	cosylogger "github.com/uozi-tech/cosy/logger"	cosysettings "github.com/uozi-tech/cosy/settings")func init() {	// Initialize logging system to avoid nil pointer exceptions during tests	cosylogger.Init("debug")	// Clean up backup files at the start of tests	cleanupBackupFiles()}// cleanupBackupFiles removes all backup files in the current directoryfunc cleanupBackupFiles() {	// Get current directory	dir, err := os.Getwd()	if err != nil {		return	}	// Delete all backup files	matches, err := filepath.Glob(filepath.Join(dir, "backup-*.zip"))	if err == nil {		for _, file := range matches {			os.Remove(file)		}	}}// setupTestEnvironment creates a temporary environment for testingfunc setupTestEnvironment(t *testing.T) (string, func()) {	// Create temporary test directory	tempDir, err := os.MkdirTemp("", "backup-test-*")	assert.NoError(t, err)	// Set up necessary directories	nginxDir := filepath.Join(tempDir, "nginx")	nginxUIDir := filepath.Join(tempDir, "nginx-ui")	configDir := filepath.Join(tempDir, "config")	backupDir := filepath.Join(tempDir, "backup")	// Create directories	for _, dir := range []string{nginxDir, nginxUIDir, configDir, backupDir} {		err = os.MkdirAll(dir, 0755)		assert.NoError(t, err)	}	// Create some test files	testFiles := map[string]string{		filepath.Join(nginxDir, "nginx.conf"):    "user nginx;\nworker_processes auto;\n",		filepath.Join(nginxUIDir, "config.json"): `{"version": "1.0", "settings": {"theme": "dark"}}`,	}	for file, content := range testFiles {		err = os.WriteFile(file, []byte(content), 0644)		assert.NoError(t, err)	}	// Save original configuration	origNginxConfigDir := settings.NginxSettings.ConfigDir	origNginxUIConfigPath := cosysettings.ConfPath	// Set test configuration	settings.NginxSettings.ConfigDir = nginxDir	cosysettings.ConfPath = filepath.Join(configDir, "config.ini")	// Return cleanup function	cleanup := func() {		// Restore original configuration		settings.NginxSettings.ConfigDir = origNginxConfigDir		cosysettings.ConfPath = origNginxUIConfigPath		// Delete temporary directory		os.RemoveAll(tempDir)	}	return tempDir, cleanup}// Test backup and restore functionalityfunc TestBackupAndRestore(t *testing.T) {	// Make sure backup files are cleaned up at the start and end of the test	cleanupBackupFiles()	defer cleanupBackupFiles()	// Create test configuration	tempDir, err := os.MkdirTemp("", "nginx-ui-backup-test-*")	assert.NoError(t, err)	defer os.RemoveAll(tempDir)	// Create config file	configPath := filepath.Join(tempDir, "config.ini")	testConfig := []byte("[app]\nName = Nginx UI Test\n")	err = os.WriteFile(configPath, testConfig, 0644)	assert.NoError(t, err)	// Create database file	dbName := settings.DatabaseSettings.GetName()	dbFile := dbName + ".db"	dbPath := filepath.Join(tempDir, dbFile)	testDB := []byte("CREATE TABLE users (id INT, name TEXT);")	err = os.WriteFile(dbPath, testDB, 0644)	assert.NoError(t, err)	// Create nginx directory	nginxConfigDir := filepath.Join(tempDir, "nginx")	err = os.MkdirAll(nginxConfigDir, 0755)	assert.NoError(t, err)	// Create test nginx config	testNginxContent := []byte("server {\n    listen 80;\n    server_name example.com;\n}\n")	err = os.WriteFile(filepath.Join(nginxConfigDir, "nginx.conf"), testNginxContent, 0644)	assert.NoError(t, err)	// Setup settings for testing	originalConfPath := cosysettings.ConfPath	originalNginxConfigDir := settings.NginxSettings.ConfigDir	cosysettings.ConfPath = configPath	settings.NginxSettings.ConfigDir = nginxConfigDir	// Restore original settings after test	defer func() {		cosysettings.ConfPath = originalConfPath		settings.NginxSettings.ConfigDir = originalNginxConfigDir	}()	// Run backup	result, err := Backup()	assert.NoError(t, err)	assert.NotEmpty(t, result.BackupContent)	assert.NotEmpty(t, result.BackupName)	assert.NotEmpty(t, result.AESKey)	assert.NotEmpty(t, result.AESIv)	// Save backup content to a temporary file for restore testing	backupPath := filepath.Join(tempDir, result.BackupName)	err = os.WriteFile(backupPath, result.BackupContent, 0644)	assert.NoError(t, err)	// Test restore functionality	restoreDir, err := os.MkdirTemp("", "nginx-ui-restore-test-*")	assert.NoError(t, err)	defer os.RemoveAll(restoreDir)	// Decode AES key and IV	aesKey, err := DecodeFromBase64(result.AESKey)	assert.NoError(t, err)	aesIv, err := DecodeFromBase64(result.AESIv)	assert.NoError(t, err)	// Perform restore	restoreResult, err := Restore(RestoreOptions{		BackupPath:     backupPath,		AESKey:         aesKey,		AESIv:          aesIv,		RestoreDir:     restoreDir,		RestoreNginx:   true,		RestoreNginxUI: true,		VerifyHash:     true,	})	assert.NoError(t, err)	assert.NotEmpty(t, restoreResult.RestoreDir)	// Verify restored directories	nginxUIDir := filepath.Join(restoreDir, NginxUIDir)	nginxDir := filepath.Join(restoreDir, NginxDir)	_, err = os.Stat(nginxUIDir)	assert.NoError(t, err)	_, err = os.Stat(nginxDir)	assert.NoError(t, err)	// Verify hash info exists	_, err = os.Stat(filepath.Join(restoreDir, HashInfoFile))	assert.NoError(t, err)}// Test AES encryption/decryptionfunc TestEncryptionDecryption(t *testing.T) {	// Test data	testData := []byte("This is a test message to encrypt and decrypt")	// Create temp dir for testing	testDir, err := os.MkdirTemp("", "nginx-ui-crypto-test-*")	assert.NoError(t, err)	defer os.RemoveAll(testDir)	// Create test file	testFile := filepath.Join(testDir, "test.txt")	err = os.WriteFile(testFile, testData, 0644)	assert.NoError(t, err)	// Generate AES key and IV	key, err := GenerateAESKey()	assert.NoError(t, err)	iv, err := GenerateIV()	assert.NoError(t, err)	// Test encrypt file	err = encryptFile(testFile, key, iv)	assert.NoError(t, err)	// Read encrypted data	encryptedData, err := os.ReadFile(testFile)	assert.NoError(t, err)	assert.NotEqual(t, string(testData), string(encryptedData))	// Test decrypt file	err = decryptFile(testFile, key, iv)	assert.NoError(t, err)	// Read decrypted data	decryptedData, err := os.ReadFile(testFile)	assert.NoError(t, err)	assert.Equal(t, string(testData), string(decryptedData))}// Test AES direct encryption/decryptionfunc TestAESEncryptDecrypt(t *testing.T) {	// Generate key and IV	key, err := GenerateAESKey()	assert.NoError(t, err)	iv, err := GenerateIV()	assert.NoError(t, err)	// Test data	original := []byte("This is a test message for encryption and decryption")	// Encrypt	encrypted, err := AESEncrypt(original, key, iv)	assert.NoError(t, err)	assert.NotEqual(t, original, encrypted)	// Decrypt	decrypted, err := AESDecrypt(encrypted, key, iv)	assert.NoError(t, err)	assert.Equal(t, original, decrypted)}// Test Base64 encoding/decodingfunc TestEncodeDecodeBase64(t *testing.T) {	original := []byte("Test data for base64 encoding")	// Encode	encoded := EncodeToBase64(original)	// Decode	decoded, err := DecodeFromBase64(encoded)	assert.NoError(t, err)	assert.Equal(t, original, decoded)}func TestGenerateAESKey(t *testing.T) {	key, err := GenerateAESKey()	assert.NoError(t, err)	assert.Equal(t, 32, len(key))}func TestGenerateIV(t *testing.T) {	iv, err := GenerateIV()	assert.NoError(t, err)	assert.Equal(t, 16, len(iv))}func TestEncryptDecryptFile(t *testing.T) {	// Create temp directory	tempDir, err := os.MkdirTemp("", "encrypt-file-test-*")	assert.NoError(t, err)	defer os.RemoveAll(tempDir)	// Create test file	testFile := filepath.Join(tempDir, "test.txt")	testContent := []byte("This is test content for file encryption")	err = os.WriteFile(testFile, testContent, 0644)	assert.NoError(t, err)	// Generate key and IV	key, err := GenerateAESKey()	assert.NoError(t, err)	iv, err := GenerateIV()	assert.NoError(t, err)	// Encrypt file	err = encryptFile(testFile, key, iv)	assert.NoError(t, err)	// Read encrypted content	encryptedContent, err := os.ReadFile(testFile)	assert.NoError(t, err)	assert.NotEqual(t, testContent, encryptedContent)	// Decrypt file	err = decryptFile(testFile, key, iv)	assert.NoError(t, err)	// Read decrypted content	decryptedContent, err := os.ReadFile(testFile)	assert.NoError(t, err)	assert.Equal(t, testContent, decryptedContent)}func TestBackupRestore(t *testing.T) {	// Set up test environment	tempDir, cleanup := setupTestEnvironment(t)	defer cleanup()	// Create a config.ini file since it's required for the test	configDir := filepath.Join(tempDir, "config")	configPath := filepath.Join(configDir, "config.ini")	err := os.WriteFile(configPath, []byte("[app]\nName = Nginx UI Test\n"), 0644)	assert.NoError(t, err)	// Update Cosy settings path	originalConfPath := cosysettings.ConfPath	cosysettings.ConfPath = configPath	defer func() {		cosysettings.ConfPath = originalConfPath	}()	// Create backup	backupResult, err := Backup()	// If there's an error, log it but continue testing	if err != nil {		t.Logf("Backup failed with error: %v", err)		t.Fail()		return	}	assert.NotNil(t, backupResult.BackupContent)	assert.NotEmpty(t, backupResult.BackupName)	assert.NotEmpty(t, backupResult.AESKey)	assert.NotEmpty(t, backupResult.AESIv)	// Create temporary file for restore testing	backupPath := filepath.Join(tempDir, backupResult.BackupName)	err = os.WriteFile(backupPath, backupResult.BackupContent, 0644)	assert.NoError(t, err)	// Decode key and IV	key, err := DecodeFromBase64(backupResult.AESKey)	assert.NoError(t, err)	iv, err := DecodeFromBase64(backupResult.AESIv)	assert.NoError(t, err)	// Create restore directory	restoreDir := filepath.Join(tempDir, "restore")	err = os.MkdirAll(restoreDir, 0755)	assert.NoError(t, err)	// Create restore options	options := RestoreOptions{		BackupPath: backupPath,		AESKey:     key,		AESIv:      iv,		RestoreDir: restoreDir,		VerifyHash: true,		// Avoid modifying the system		RestoreNginx:   false,		RestoreNginxUI: false,	}	// Test restore	result, err := Restore(options)	if err != nil {		t.Logf("Restore failed with error: %v", err)		t.Fail()		return	}	assert.Equal(t, restoreDir, result.RestoreDir)	// If hash verification is enabled, check the result	if options.VerifyHash {		assert.True(t, result.HashMatch, "Hash verification should pass")	}}func TestCreateZipArchive(t *testing.T) {	// Create temp directories	tempSourceDir, err := os.MkdirTemp("", "zip-source-test-*")	assert.NoError(t, err)	defer os.RemoveAll(tempSourceDir)	// Create some test files	testFiles := []string{"file1.txt", "file2.txt", "subdir/file3.txt"}	testContent := []byte("Test content")	for _, file := range testFiles {		filePath := filepath.Join(tempSourceDir, file)		dirPath := filepath.Dir(filePath)		err = os.MkdirAll(dirPath, 0755)		assert.NoError(t, err)		err = os.WriteFile(filePath, testContent, 0644)		assert.NoError(t, err)	}	// Create zip file	zipPath := filepath.Join(tempSourceDir, "test.zip")	err = createZipArchive(zipPath, tempSourceDir)	assert.NoError(t, err)	// Verify zip file was created	_, err = os.Stat(zipPath)	assert.NoError(t, err)	// Extract to new directory to verify contents	extractDir := filepath.Join(tempSourceDir, "extract")	err = os.MkdirAll(extractDir, 0755)	assert.NoError(t, err)	err = extractZipArchive(zipPath, extractDir)	assert.NoError(t, err)	// Verify extracted files	for _, file := range testFiles {		extractedPath := filepath.Join(extractDir, file)		content, err := os.ReadFile(extractedPath)		assert.NoError(t, err)		assert.Equal(t, testContent, content)	}}func TestHashCalculation(t *testing.T) {	// Create temp file	tempFile, err := os.CreateTemp("", "hash-test-*.txt")	assert.NoError(t, err)	defer os.Remove(tempFile.Name())	// Write content	testContent := []byte("Test content for hash calculation")	_, err = tempFile.Write(testContent)	assert.NoError(t, err)	tempFile.Close()	// Calculate hash	hash, err := calculateFileHash(tempFile.Name())	assert.NoError(t, err)	assert.NotEmpty(t, hash)	// Calculate again to verify consistency	hash2, err := calculateFileHash(tempFile.Name())	assert.NoError(t, err)	assert.Equal(t, hash, hash2)	// Modify file and check hash changes	err = os.WriteFile(tempFile.Name(), []byte("Modified content"), 0644)	assert.NoError(t, err)	hash3, err := calculateFileHash(tempFile.Name())	assert.NoError(t, err)	assert.NotEqual(t, hash, hash3)}
 |