restore.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. package system
  2. import (
  3. "encoding/base64"
  4. "net/http"
  5. "os"
  6. "path/filepath"
  7. "strings"
  8. "time"
  9. "github.com/0xJacky/Nginx-UI/internal/backup"
  10. "github.com/0xJacky/Nginx-UI/internal/nginx"
  11. "github.com/gin-gonic/gin"
  12. "github.com/jpillora/overseer"
  13. "github.com/uozi-tech/cosy"
  14. )
  15. // RestoreResponse contains the response data for restore operation
  16. type RestoreResponse struct {
  17. NginxUIRestored bool `json:"nginx_ui_restored"`
  18. NginxRestored bool `json:"nginx_restored"`
  19. HashMatch bool `json:"hash_match"`
  20. }
  21. // RestoreBackup restores from uploaded backup and security info
  22. func RestoreBackup(c *gin.Context) {
  23. // Get restore options
  24. restoreNginx := c.PostForm("restore_nginx") == "true"
  25. restoreNginxUI := c.PostForm("restore_nginx_ui") == "true"
  26. verifyHash := c.PostForm("verify_hash") == "true"
  27. securityToken := c.PostForm("security_token") // Get concatenated key and IV
  28. // Get backup file
  29. backupFile, err := c.FormFile("backup_file")
  30. if err != nil {
  31. cosy.ErrHandler(c, cosy.WrapErrorWithParams(backup.ErrBackupFileNotFound, err.Error()))
  32. return
  33. }
  34. // Validate security token
  35. if securityToken == "" {
  36. cosy.ErrHandler(c, backup.ErrInvalidSecurityToken)
  37. return
  38. }
  39. // Split security token to get Key and IV
  40. parts := strings.Split(securityToken, ":")
  41. if len(parts) != 2 {
  42. cosy.ErrHandler(c, backup.ErrInvalidSecurityToken)
  43. return
  44. }
  45. aesKey := parts[0]
  46. aesIv := parts[1]
  47. // Decode Key and IV from base64
  48. key, err := base64.StdEncoding.DecodeString(aesKey)
  49. if err != nil {
  50. cosy.ErrHandler(c, cosy.WrapErrorWithParams(backup.ErrInvalidAESKey, err.Error()))
  51. return
  52. }
  53. iv, err := base64.StdEncoding.DecodeString(aesIv)
  54. if err != nil {
  55. cosy.ErrHandler(c, cosy.WrapErrorWithParams(backup.ErrInvalidAESIV, err.Error()))
  56. return
  57. }
  58. // Create temporary directory for files
  59. tempDir, err := os.MkdirTemp("", "nginx-ui-restore-upload-*")
  60. if err != nil {
  61. cosy.ErrHandler(c, cosy.WrapErrorWithParams(backup.ErrCreateTempDir, err.Error()))
  62. return
  63. }
  64. defer os.RemoveAll(tempDir)
  65. // Save backup file
  66. backupPath := filepath.Join(tempDir, backupFile.Filename)
  67. if err := c.SaveUploadedFile(backupFile, backupPath); err != nil {
  68. cosy.ErrHandler(c, cosy.WrapErrorWithParams(backup.ErrCreateBackupFile, err.Error()))
  69. return
  70. }
  71. // Create temporary directory for restore operation
  72. restoreDir, err := os.MkdirTemp("", "nginx-ui-restore-*")
  73. if err != nil {
  74. cosy.ErrHandler(c, cosy.WrapErrorWithParams(backup.ErrCreateRestoreDir, err.Error()))
  75. return
  76. }
  77. // Set restore options
  78. options := backup.RestoreOptions{
  79. BackupPath: backupPath,
  80. AESKey: key,
  81. AESIv: iv,
  82. RestoreDir: restoreDir,
  83. RestoreNginx: restoreNginx,
  84. RestoreNginxUI: restoreNginxUI,
  85. VerifyHash: verifyHash,
  86. }
  87. // Perform restore
  88. result, err := backup.Restore(options)
  89. if err != nil {
  90. // Clean up temporary directory on error
  91. os.RemoveAll(restoreDir)
  92. cosy.ErrHandler(c, err)
  93. return
  94. }
  95. // If not actually restoring anything, clean up directory to avoid disk space waste
  96. if !restoreNginx && !restoreNginxUI {
  97. defer os.RemoveAll(restoreDir)
  98. }
  99. if restoreNginx {
  100. go func() {
  101. time.Sleep(2 * time.Second)
  102. nginx.Restart()
  103. }()
  104. }
  105. if restoreNginxUI {
  106. go func() {
  107. time.Sleep(2 * time.Second)
  108. // gracefully restart
  109. overseer.Restart()
  110. }()
  111. }
  112. c.JSON(http.StatusOK, RestoreResponse{
  113. NginxUIRestored: result.NginxUIRestored,
  114. NginxRestored: result.NginxRestored,
  115. HashMatch: result.HashMatch,
  116. })
  117. }