| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 | package systemimport (	"encoding/base64"	"net/http"	"os"	"path/filepath"	"strings"	"time"	"github.com/0xJacky/Nginx-UI/internal/backup"	"github.com/0xJacky/Nginx-UI/internal/nginx"	"github.com/gin-gonic/gin"	"github.com/jpillora/overseer"	"github.com/uozi-tech/cosy")// RestoreResponse contains the response data for restore operationtype RestoreResponse struct {	NginxUIRestored bool `json:"nginx_ui_restored"`	NginxRestored   bool `json:"nginx_restored"`	HashMatch       bool `json:"hash_match"`}// RestoreBackup restores from uploaded backup and security infofunc RestoreBackup(c *gin.Context) {	// Get restore options	restoreNginx := c.PostForm("restore_nginx") == "true"	restoreNginxUI := c.PostForm("restore_nginx_ui") == "true"	verifyHash := c.PostForm("verify_hash") == "true"	securityToken := c.PostForm("security_token") // Get concatenated key and IV	// Get backup file	backupFile, err := c.FormFile("backup_file")	if err != nil {		cosy.ErrHandler(c, cosy.WrapErrorWithParams(backup.ErrBackupFileNotFound, err.Error()))		return	}	// Validate security token	if securityToken == "" {		cosy.ErrHandler(c, backup.ErrInvalidSecurityToken)		return	}	// Split security token to get Key and IV	parts := strings.Split(securityToken, ":")	if len(parts) != 2 {		cosy.ErrHandler(c, backup.ErrInvalidSecurityToken)		return	}	aesKey := parts[0]	aesIv := parts[1]	// Decode Key and IV from base64	key, err := base64.StdEncoding.DecodeString(aesKey)	if err != nil {		cosy.ErrHandler(c, cosy.WrapErrorWithParams(backup.ErrInvalidAESKey, err.Error()))		return	}	iv, err := base64.StdEncoding.DecodeString(aesIv)	if err != nil {		cosy.ErrHandler(c, cosy.WrapErrorWithParams(backup.ErrInvalidAESIV, err.Error()))		return	}	// Create temporary directory for files	tempDir, err := os.MkdirTemp("", "nginx-ui-restore-upload-*")	if err != nil {		cosy.ErrHandler(c, cosy.WrapErrorWithParams(backup.ErrCreateTempDir, err.Error()))		return	}	defer os.RemoveAll(tempDir)	// Save backup file	backupPath := filepath.Join(tempDir, backupFile.Filename)	if err := c.SaveUploadedFile(backupFile, backupPath); err != nil {		cosy.ErrHandler(c, cosy.WrapErrorWithParams(backup.ErrCreateBackupFile, err.Error()))		return	}	// Create temporary directory for restore operation	restoreDir, err := os.MkdirTemp("", "nginx-ui-restore-*")	if err != nil {		cosy.ErrHandler(c, cosy.WrapErrorWithParams(backup.ErrCreateRestoreDir, err.Error()))		return	}	// Set restore options	options := backup.RestoreOptions{		BackupPath:     backupPath,		AESKey:         key,		AESIv:          iv,		RestoreDir:     restoreDir,		RestoreNginx:   restoreNginx,		RestoreNginxUI: restoreNginxUI,		VerifyHash:     verifyHash,	}	// Perform restore	result, err := backup.Restore(options)	if err != nil {		// Clean up temporary directory on error		os.RemoveAll(restoreDir)		cosy.ErrHandler(c, err)		return	}	// If not actually restoring anything, clean up directory to avoid disk space waste	if !restoreNginx && !restoreNginxUI {		defer os.RemoveAll(restoreDir)	}	if restoreNginx {		go func() {			time.Sleep(2 * time.Second)			nginx.Restart()		}()	}	if restoreNginxUI {		go func() {			time.Sleep(2 * time.Second)			// gracefully restart			overseer.Restart()		}()	}	c.JSON(http.StatusOK, RestoreResponse{		NginxUIRestored: result.NginxUIRestored,		NginxRestored:   result.NginxRestored,		HashMatch:       result.HashMatch,	})}
 |