139 lines
4.3 KiB
Go
139 lines
4.3 KiB
Go
package handler
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"accounting-app/pkg/api"
|
|
"accounting-app/internal/service"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
// BackupHandler handles HTTP requests for backup operations
|
|
type BackupHandler struct {
|
|
service *service.BackupService
|
|
}
|
|
|
|
// NewBackupHandler creates a new BackupHandler instance
|
|
func NewBackupHandler(service *service.BackupService) *BackupHandler {
|
|
return &BackupHandler{
|
|
service: service,
|
|
}
|
|
}
|
|
|
|
// ExportBackup handles POST /api/v1/backup/export
|
|
// @Summary Export encrypted database backup
|
|
// @Description Creates an encrypted backup of the database with SHA256 integrity checking
|
|
// @Tags backup
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body service.BackupRequest true "Backup request"
|
|
// @Success 200 {object} service.BackupResponse
|
|
// @Failure 400 {object} api.ErrorResponse
|
|
// @Failure 500 {object} api.ErrorResponse
|
|
// @Router /api/v1/backup/export [post]
|
|
func (h *BackupHandler) ExportBackup(c *gin.Context) {
|
|
var req service.BackupRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
api.Error(c, http.StatusBadRequest, "INVALID_REQUEST", "Invalid request: "+err.Error())
|
|
return
|
|
}
|
|
|
|
response, err := h.service.ExportBackup(req)
|
|
if err != nil {
|
|
if err == service.ErrInvalidPassword {
|
|
api.Error(c, http.StatusBadRequest, "INVALID_PASSWORD", err.Error())
|
|
return
|
|
}
|
|
api.Error(c, http.StatusInternalServerError, "BACKUP_FAILED", "Failed to create backup: "+err.Error())
|
|
return
|
|
}
|
|
|
|
api.Success(c, response)
|
|
}
|
|
|
|
// ImportBackup handles POST /api/v1/backup/import
|
|
// @Summary Import and restore from encrypted backup
|
|
// @Description Restores the database from an encrypted backup file with integrity verification
|
|
// @Tags backup
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body service.RestoreRequest true "Restore request"
|
|
// @Success 200 {object} api.SuccessResponse
|
|
// @Failure 400 {object} api.ErrorResponse
|
|
// @Failure 500 {object} api.ErrorResponse
|
|
// @Router /api/v1/backup/import [post]
|
|
func (h *BackupHandler) ImportBackup(c *gin.Context) {
|
|
var req service.RestoreRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
api.Error(c, http.StatusBadRequest, "INVALID_REQUEST", "Invalid request: "+err.Error())
|
|
return
|
|
}
|
|
|
|
err := h.service.ImportBackup(req)
|
|
if err != nil {
|
|
switch err {
|
|
case service.ErrInvalidBackupFile:
|
|
api.Error(c, http.StatusBadRequest, "INVALID_BACKUP_FILE", "Invalid backup file format")
|
|
return
|
|
case service.ErrChecksumMismatch:
|
|
api.Error(c, http.StatusBadRequest, "CHECKSUM_MISMATCH", "Backup file integrity check failed")
|
|
return
|
|
case service.ErrDecryptionFailed:
|
|
api.Error(c, http.StatusBadRequest, "DECRYPTION_FAILED", "Failed to decrypt backup - incorrect password")
|
|
return
|
|
default:
|
|
api.Error(c, http.StatusInternalServerError, "RESTORE_FAILED", "Failed to restore backup: "+err.Error())
|
|
return
|
|
}
|
|
}
|
|
|
|
api.Success(c, gin.H{
|
|
"message": "Database restored successfully from backup",
|
|
})
|
|
}
|
|
|
|
// VerifyBackup handles POST /api/v1/backup/verify
|
|
// @Summary Verify backup file integrity
|
|
// @Description Verifies the integrity of a backup file without restoring it
|
|
// @Tags backup
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body map[string]string true "Verify request with file_path"
|
|
// @Success 200 {object} map[string]interface{}
|
|
// @Failure 400 {object} api.ErrorResponse
|
|
// @Failure 500 {object} api.ErrorResponse
|
|
// @Router /api/v1/backup/verify [post]
|
|
func (h *BackupHandler) VerifyBackup(c *gin.Context) {
|
|
var req struct {
|
|
FilePath string `json:"file_path" binding:"required"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
api.Error(c, http.StatusBadRequest, "INVALID_REQUEST", "Invalid request: "+err.Error())
|
|
return
|
|
}
|
|
|
|
isValid, checksum, err := h.service.VerifyBackup(req.FilePath)
|
|
if err != nil {
|
|
if err == service.ErrInvalidBackupFile {
|
|
api.Error(c, http.StatusBadRequest, "INVALID_BACKUP_FILE", "Invalid backup file format")
|
|
return
|
|
}
|
|
api.Error(c, http.StatusInternalServerError, "VERIFY_FAILED", "Failed to verify backup: "+err.Error())
|
|
return
|
|
}
|
|
|
|
api.Success(c, gin.H{
|
|
"valid": isValid,
|
|
"checksum": checksum,
|
|
"message": getVerificationMessage(isValid),
|
|
})
|
|
}
|
|
|
|
func getVerificationMessage(isValid bool) string {
|
|
if isValid {
|
|
return "Backup file integrity verified successfully"
|
|
}
|
|
return "Backup file integrity check failed - file may be corrupted"
|
|
}
|