mirror of
https://github.com/0xJacky/nginx-ui.git
synced 2025-05-10 18:05:48 +02:00
135 lines
3.4 KiB
Go
135 lines
3.4 KiB
Go
package system
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"time"
|
|
|
|
"code.pfad.fr/risefront"
|
|
"github.com/0xJacky/Nginx-UI/internal/backup"
|
|
"github.com/0xJacky/Nginx-UI/internal/nginx"
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/uozi-tech/cosy"
|
|
)
|
|
|
|
// RestoreResponse contains the response data for restore operation
|
|
type 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 info
|
|
func 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
|
|
risefront.Restart()
|
|
}()
|
|
}
|
|
|
|
c.JSON(http.StatusOK, RestoreResponse{
|
|
NginxUIRestored: result.NginxUIRestored,
|
|
NginxRestored: result.NginxRestored,
|
|
HashMatch: result.HashMatch,
|
|
})
|
|
}
|