diff --git a/backend/app/dto/backup.go b/backend/app/dto/backup.go index f5ab3ebd4d8c..971c06519fe0 100644 --- a/backend/app/dto/backup.go +++ b/backend/app/dto/backup.go @@ -35,6 +35,7 @@ type CommonBackup struct { Type string `json:"type" validate:"required,oneof=app mysql mariadb redis website postgresql"` Name string `json:"name"` DetailName string `json:"detailName"` + Secret string `json:"secret"` } type CommonRecover struct { Source string `json:"source" validate:"required,oneof=OSS S3 SFTP MINIO LOCAL COS KODO OneDrive WebDAV"` @@ -42,6 +43,7 @@ type CommonRecover struct { Name string `json:"name"` DetailName string `json:"detailName"` File string `json:"file"` + Secret string `json:"secret"` } type RecordSearch struct { diff --git a/backend/app/dto/cronjob.go b/backend/app/dto/cronjob.go index 9b5182d9ec6e..a8f53641ab55 100644 --- a/backend/app/dto/cronjob.go +++ b/backend/app/dto/cronjob.go @@ -1,6 +1,8 @@ package dto -import "time" +import ( + "time" +) type CronjobCreate struct { Name string `json:"name" validate:"required"` @@ -21,6 +23,7 @@ type CronjobCreate struct { BackupAccounts string `json:"backupAccounts"` DefaultDownload string `json:"defaultDownload"` RetainCopies int `json:"retainCopies" validate:"number,min=1"` + Secret string `json:"secret"` } type CronjobUpdate struct { @@ -42,6 +45,7 @@ type CronjobUpdate struct { BackupAccounts string `json:"backupAccounts"` DefaultDownload string `json:"defaultDownload"` RetainCopies int `json:"retainCopies" validate:"number,min=1"` + Secret string `json:"secret"` } type CronjobUpdateStatus struct { @@ -87,6 +91,7 @@ type CronjobInfo struct { LastRecordTime string `json:"lastRecordTime"` Status string `json:"status"` + Secret string `json:"secret"` } type SearchRecord struct { diff --git a/backend/app/dto/request/file.go b/backend/app/dto/request/file.go index 87ec2a1e8e27..82c2aadb2702 100644 --- a/backend/app/dto/request/file.go +++ b/backend/app/dto/request/file.go @@ -54,12 +54,14 @@ type FileCompress struct { Type string `json:"type" validate:"required"` Name string `json:"name" validate:"required"` Replace bool `json:"replace"` + Secret string `json:"secret"` } type FileDeCompress struct { - Dst string `json:"dst" validate:"required"` - Type string `json:"type" validate:"required"` - Path string `json:"path" validate:"required"` + Dst string `json:"dst" validate:"required"` + Type string `json:"type" validate:"required"` + Path string `json:"path" validate:"required"` + Secret string `json:"secret"` } type FileEdit struct { diff --git a/backend/app/dto/setting.go b/backend/app/dto/setting.go index 8af4fdcce6c0..b4b68666d18a 100644 --- a/backend/app/dto/setting.go +++ b/backend/app/dto/setting.go @@ -116,11 +116,13 @@ type SnapshotCreate struct { From string `json:"from" validate:"required"` DefaultDownload string `json:"defaultDownload" validate:"required"` Description string `json:"description" validate:"max=256"` + Secret string `json:"secret"` } type SnapshotRecover struct { - IsNew bool `json:"isNew"` - ReDownload bool `json:"reDownload"` - ID uint `json:"id" validate:"required"` + IsNew bool `json:"isNew"` + ReDownload bool `json:"reDownload"` + ID uint `json:"id" validate:"required"` + Secret string `json:"secret"` } type SnapshotBatchDelete struct { DeleteWithFile bool `json:"deleteWithFile"` diff --git a/backend/app/model/cronjob.go b/backend/app/model/cronjob.go index c1697ac3980c..b9ff73546c58 100644 --- a/backend/app/model/cronjob.go +++ b/backend/app/model/cronjob.go @@ -1,6 +1,8 @@ package model -import "time" +import ( + "time" +) type Cronjob struct { BaseModel @@ -31,6 +33,7 @@ type Cronjob struct { Status string `gorm:"type:varchar(64)" json:"status"` EntryIDs string `gorm:"type:varchar(64)" json:"entryIDs"` Records []JobRecords `json:"records"` + Secret string `gorm:"type:varchar(64)" json:"secret"` } type JobRecords struct { diff --git a/backend/app/service/app.go b/backend/app/service/app.go index 91d3211f8f14..b91e71d3310e 100644 --- a/backend/app/service/app.go +++ b/backend/app/service/app.go @@ -752,7 +752,7 @@ func getAppFromRepo(downloadPath string) error { if err := fileOp.DownloadFile(downloadUrl, packagePath); err != nil { return err } - if err := fileOp.Decompress(packagePath, constant.ResourceDir, files.SdkZip); err != nil { + if err := fileOp.Decompress(packagePath, constant.ResourceDir, files.SdkZip, ""); err != nil { return err } defer func() { diff --git a/backend/app/service/app_utils.go b/backend/app/service/app_utils.go index 2d3399d0372f..0c401194e109 100644 --- a/backend/app/service/app_utils.go +++ b/backend/app/service/app_utils.go @@ -765,7 +765,7 @@ func downloadApp(app model.App, appDetail model.AppDetail, appInstall *model.App global.LOG.Errorf("download app[%s] error %v", app.Name, err) return } - if err = fileOp.Decompress(filePath, appResourceDir, files.SdkTarGz); err != nil { + if err = fileOp.Decompress(filePath, appResourceDir, files.SdkTarGz, ""); err != nil { global.LOG.Errorf("decompress app[%s] error %v", app.Name, err) return } diff --git a/backend/app/service/backup_app.go b/backend/app/service/backup_app.go index 16fa6deea265..51183eaf1f82 100644 --- a/backend/app/service/backup_app.go +++ b/backend/app/service/backup_app.go @@ -40,7 +40,7 @@ func (u *BackupService) AppBackup(req dto.CommonBackup) (*model.BackupRecord, er backupDir := path.Join(localDir, itemDir) fileName := fmt.Sprintf("%s_%s.tar.gz", req.DetailName, timeNow+common.RandStrAndNum(5)) - if err := handleAppBackup(&install, backupDir, fileName, ""); err != nil { + if err := handleAppBackup(&install, backupDir, fileName, "", req.Secret); err != nil { return nil, err } @@ -78,13 +78,13 @@ func (u *BackupService) AppRecover(req dto.CommonRecover) error { if _, err := compose.Down(install.GetComposePath()); err != nil { return err } - if err := handleAppRecover(&install, req.File, false); err != nil { + if err := handleAppRecover(&install, req.File, false, req.Secret); err != nil { return err } return nil } -func handleAppBackup(install *model.AppInstall, backupDir, fileName string, excludes string) error { +func handleAppBackup(install *model.AppInstall, backupDir, fileName string, excludes string, secret string) error { fileOp := files.NewFileOp() tmpDir := fmt.Sprintf("%s/%s", backupDir, strings.ReplaceAll(fileName, ".tar.gz", "")) if !fileOp.Stat(tmpDir) { @@ -103,7 +103,7 @@ func handleAppBackup(install *model.AppInstall, backupDir, fileName string, excl } appPath := install.GetPath() - if err := handleTar(appPath, tmpDir, "app.tar.gz", excludes); err != nil { + if err := handleTar(appPath, tmpDir, "app.tar.gz", excludes, ""); err != nil { return err } @@ -129,16 +129,16 @@ func handleAppBackup(install *model.AppInstall, backupDir, fileName string, excl } } - if err := handleTar(tmpDir, backupDir, fileName, ""); err != nil { + if err := handleTar(tmpDir, backupDir, fileName, "", secret); err != nil { return err } return nil } -func handleAppRecover(install *model.AppInstall, recoverFile string, isRollback bool) error { +func handleAppRecover(install *model.AppInstall, recoverFile string, isRollback bool, secret string) error { isOk := false fileOp := files.NewFileOp() - if err := handleUnTar(recoverFile, path.Dir(recoverFile)); err != nil { + if err := handleUnTar(recoverFile, path.Dir(recoverFile), secret); err != nil { return err } tmpPath := strings.ReplaceAll(recoverFile, ".tar.gz", "") @@ -164,13 +164,13 @@ func handleAppRecover(install *model.AppInstall, recoverFile string, isRollback if !isRollback { rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("app/%s_%s.tar.gz", install.Name, time.Now().Format("20060102150405"))) - if err := handleAppBackup(install, path.Dir(rollbackFile), path.Base(rollbackFile), ""); err != nil { + if err := handleAppBackup(install, path.Dir(rollbackFile), path.Base(rollbackFile), "", ""); err != nil { return fmt.Errorf("backup app %s for rollback before recover failed, err: %v", install.Name, err) } defer func() { if !isOk { global.LOG.Info("recover failed, start to rollback now") - if err := handleAppRecover(install, rollbackFile, true); err != nil { + if err := handleAppRecover(install, rollbackFile, true, secret); err != nil { global.LOG.Errorf("rollback app %s from %s failed, err: %v", install.Name, rollbackFile, err) return } @@ -251,7 +251,7 @@ func handleAppRecover(install *model.AppInstall, recoverFile string, isRollback _ = fileOp.Rename(appDir, backPath) _ = fileOp.CreateDir(appDir, 0755) - if err := handleUnTar(tmpPath+"/app.tar.gz", install.GetAppPath()); err != nil { + if err := handleUnTar(tmpPath+"/app.tar.gz", install.GetAppPath(), ""); err != nil { global.LOG.Errorf("handle recover from app.tar.gz failed, err: %v", err) _ = fileOp.DeleteDir(appDir) _ = fileOp.Rename(backPath, appDir) diff --git a/backend/app/service/backup_mysql.go b/backend/app/service/backup_mysql.go index 5d746701fe7e..c70efeecfe2c 100644 --- a/backend/app/service/backup_mysql.go +++ b/backend/app/service/backup_mysql.go @@ -66,7 +66,7 @@ func (u *BackupService) MysqlRecoverByUpload(req dto.CommonRecover) error { return fmt.Errorf("mkdir %s failed, err: %v", dstDir, err) } } - if err := handleUnTar(req.File, dstDir); err != nil { + if err := handleUnTar(req.File, dstDir, ""); err != nil { _ = os.RemoveAll(dstDir) return err } diff --git a/backend/app/service/backup_postgresql.go b/backend/app/service/backup_postgresql.go index 65e6eeeeab60..7c32e29418e8 100644 --- a/backend/app/service/backup_postgresql.go +++ b/backend/app/service/backup_postgresql.go @@ -66,7 +66,7 @@ func (u *BackupService) PostgresqlRecoverByUpload(req dto.CommonRecover) error { return fmt.Errorf("mkdir %s failed, err: %v", dstDir, err) } } - if err := handleUnTar(req.File, dstDir); err != nil { + if err := handleUnTar(req.File, dstDir, ""); err != nil { _ = os.RemoveAll(dstDir) return err } diff --git a/backend/app/service/backup_redis.go b/backend/app/service/backup_redis.go index 694e30ec1380..ee7757e201f2 100644 --- a/backend/app/service/backup_redis.go +++ b/backend/app/service/backup_redis.go @@ -46,7 +46,7 @@ func (u *BackupService) RedisBackup(db dto.CommonBackup) error { } itemDir := fmt.Sprintf("database/redis/%s", redisInfo.Name) backupDir := path.Join(localDir, itemDir) - if err := handleRedisBackup(redisInfo, backupDir, fileName); err != nil { + if err := handleRedisBackup(redisInfo, backupDir, fileName, db.Secret); err != nil { return err } record := &model.BackupRecord{ @@ -70,13 +70,13 @@ func (u *BackupService) RedisRecover(req dto.CommonRecover) error { return err } global.LOG.Infof("recover redis from backup file %s", req.File) - if err := handleRedisRecover(redisInfo, req.File, false); err != nil { + if err := handleRedisRecover(redisInfo, req.File, false, req.Secret); err != nil { return err } return nil } -func handleRedisBackup(redisInfo *repo.RootInfo, backupDir, fileName string) error { +func handleRedisBackup(redisInfo *repo.RootInfo, backupDir, fileName string, secret string) error { fileOp := files.NewFileOp() if !fileOp.Stat(backupDir) { if err := os.MkdirAll(backupDir, os.ModePerm); err != nil { @@ -91,7 +91,7 @@ func handleRedisBackup(redisInfo *repo.RootInfo, backupDir, fileName string) err if strings.HasSuffix(fileName, ".tar.gz") { redisDataDir := fmt.Sprintf("%s/%s/%s/data/appendonlydir", constant.AppInstallDir, "redis", redisInfo.Name) - if err := handleTar(redisDataDir, backupDir, fileName, ""); err != nil { + if err := handleTar(redisDataDir, backupDir, fileName, "", secret); err != nil { return err } return nil @@ -111,7 +111,7 @@ func handleRedisBackup(redisInfo *repo.RootInfo, backupDir, fileName string) err return nil } -func handleRedisRecover(redisInfo *repo.RootInfo, recoverFile string, isRollback bool) error { +func handleRedisRecover(redisInfo *repo.RootInfo, recoverFile string, isRollback bool, secret string) error { fileOp := files.NewFileOp() if !fileOp.Stat(recoverFile) { return buserr.WithName("ErrFileNotFound", recoverFile) @@ -147,13 +147,13 @@ func handleRedisRecover(redisInfo *repo.RootInfo, recoverFile string, isRollback } } rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("database/redis/%s_%s.%s", redisInfo.Name, time.Now().Format("20060102150405"), suffix)) - if err := handleRedisBackup(redisInfo, path.Dir(rollbackFile), path.Base(rollbackFile)); err != nil { + if err := handleRedisBackup(redisInfo, path.Dir(rollbackFile), path.Base(rollbackFile), secret); err != nil { return fmt.Errorf("backup database %s for rollback before recover failed, err: %v", redisInfo.Name, err) } defer func() { if !isOk { global.LOG.Info("recover failed, start to rollback now") - if err := handleRedisRecover(redisInfo, rollbackFile, true); err != nil { + if err := handleRedisRecover(redisInfo, rollbackFile, true, secret); err != nil { global.LOG.Errorf("rollback redis from %s failed, err: %v", rollbackFile, err) return } @@ -170,7 +170,7 @@ func handleRedisRecover(redisInfo *repo.RootInfo, recoverFile string, isRollback } if appendonly == "yes" && strings.HasPrefix(redisInfo.Version, "7.") { redisDataDir := fmt.Sprintf("%s/%s/%s/data", constant.AppInstallDir, "redis", redisInfo.Name) - if err := handleUnTar(recoverFile, redisDataDir); err != nil { + if err := handleUnTar(recoverFile, redisDataDir, secret); err != nil { return err } } else { diff --git a/backend/app/service/backup_runtime.go b/backend/app/service/backup_runtime.go index b14edd4b1b61..9ac360cd69b1 100644 --- a/backend/app/service/backup_runtime.go +++ b/backend/app/service/backup_runtime.go @@ -16,7 +16,7 @@ import ( "github.com/1Panel-dev/1Panel/backend/utils/files" ) -func handleRuntimeBackup(runtime *model.Runtime, backupDir, fileName string, excludes string) error { +func handleRuntimeBackup(runtime *model.Runtime, backupDir, fileName string, excludes string, secret string) error { fileOp := files.NewFileOp() tmpDir := fmt.Sprintf("%s/%s", backupDir, strings.ReplaceAll(fileName, ".tar.gz", "")) if !fileOp.Stat(tmpDir) { @@ -35,19 +35,19 @@ func handleRuntimeBackup(runtime *model.Runtime, backupDir, fileName string, exc } appPath := runtime.GetPath() - if err := handleTar(appPath, tmpDir, "runtime.tar.gz", excludes); err != nil { + if err := handleTar(appPath, tmpDir, "runtime.tar.gz", excludes, secret); err != nil { return err } - if err := handleTar(tmpDir, backupDir, fileName, ""); err != nil { + if err := handleTar(tmpDir, backupDir, fileName, "", secret); err != nil { return err } return nil } -func handleRuntimeRecover(runtime *model.Runtime, recoverFile string, isRollback bool) error { +func handleRuntimeRecover(runtime *model.Runtime, recoverFile string, isRollback bool, secret string) error { isOk := false fileOp := files.NewFileOp() - if err := handleUnTar(recoverFile, path.Dir(recoverFile)); err != nil { + if err := handleUnTar(recoverFile, path.Dir(recoverFile), secret); err != nil { return err } tmpPath := strings.ReplaceAll(recoverFile, ".tar.gz", "") @@ -73,13 +73,13 @@ func handleRuntimeRecover(runtime *model.Runtime, recoverFile string, isRollback if !isRollback { rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("runtime/%s_%s.tar.gz", runtime.Name, time.Now().Format("20060102150405"))) - if err := handleRuntimeBackup(runtime, path.Dir(rollbackFile), path.Base(rollbackFile), ""); err != nil { + if err := handleRuntimeBackup(runtime, path.Dir(rollbackFile), path.Base(rollbackFile), "", secret); err != nil { return fmt.Errorf("backup runtime %s for rollback before recover failed, err: %v", runtime.Name, err) } defer func() { if !isOk { global.LOG.Info("recover failed, start to rollback now") - if err := handleRuntimeRecover(runtime, rollbackFile, true); err != nil { + if err := handleRuntimeRecover(runtime, rollbackFile, true, secret); err != nil { global.LOG.Errorf("rollback runtime %s from %s failed, err: %v", runtime.Name, rollbackFile, err) return } @@ -100,7 +100,7 @@ func handleRuntimeRecover(runtime *model.Runtime, recoverFile string, isRollback _ = fileOp.Rename(runtimeDir, backPath) _ = fileOp.CreateDir(runtimeDir, 0755) - if err := handleUnTar(tmpPath+"/runtime.tar.gz", fmt.Sprintf("%s/%s", constant.RuntimeDir, runtime.Type)); err != nil { + if err := handleUnTar(tmpPath+"/runtime.tar.gz", fmt.Sprintf("%s/%s", constant.RuntimeDir, runtime.Type), secret); err != nil { global.LOG.Errorf("handle recover from runtime.tar.gz failed, err: %v", err) _ = fileOp.DeleteDir(runtimeDir) _ = fileOp.Rename(backPath, runtimeDir) diff --git a/backend/app/service/backup_website.go b/backend/app/service/backup_website.go index e3461d7bd6dd..10709fc5b0f2 100644 --- a/backend/app/service/backup_website.go +++ b/backend/app/service/backup_website.go @@ -35,7 +35,7 @@ func (u *BackupService) WebsiteBackup(req dto.CommonBackup) error { itemDir := fmt.Sprintf("website/%s", req.Name) backupDir := path.Join(localDir, itemDir) fileName := fmt.Sprintf("%s_%s.tar.gz", website.PrimaryDomain, timeNow+common.RandStrAndNum(5)) - if err := handleWebsiteBackup(&website, backupDir, fileName, ""); err != nil { + if err := handleWebsiteBackup(&website, backupDir, fileName, "", req.Secret); err != nil { return err } @@ -65,16 +65,16 @@ func (u *BackupService) WebsiteRecover(req dto.CommonRecover) error { return err } global.LOG.Infof("recover website %s from backup file %s", req.Name, req.File) - if err := handleWebsiteRecover(&website, req.File, false); err != nil { + if err := handleWebsiteRecover(&website, req.File, false, req.Secret); err != nil { return err } return nil } -func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback bool) error { +func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback bool, secret string) error { fileOp := files.NewFileOp() tmpPath := strings.ReplaceAll(recoverFile, ".tar.gz", "") - if err := handleUnTar(recoverFile, path.Dir(recoverFile)); err != nil { + if err := handleUnTar(recoverFile, path.Dir(recoverFile), secret); err != nil { return err } defer func() { @@ -107,13 +107,13 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback isOk := false if !isRollback { rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("website/%s_%s.tar.gz", website.Alias, time.Now().Format("20060102150405"))) - if err := handleWebsiteBackup(website, path.Dir(rollbackFile), path.Base(rollbackFile), ""); err != nil { + if err := handleWebsiteBackup(website, path.Dir(rollbackFile), path.Base(rollbackFile), "", ""); err != nil { return fmt.Errorf("backup website %s for rollback before recover failed, err: %v", website.Alias, err) } defer func() { if !isOk { global.LOG.Info("recover failed, start to rollback now") - if err := handleWebsiteRecover(website, rollbackFile, true); err != nil { + if err := handleWebsiteRecover(website, rollbackFile, true, secret); err != nil { global.LOG.Errorf("rollback website %s from %s failed, err: %v", website.Alias, rollbackFile, err) return } @@ -141,7 +141,7 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback if err != nil { return err } - if err := handleAppRecover(&app, fmt.Sprintf("%s/%s.app.tar.gz", tmpPath, website.Alias), true); err != nil { + if err := handleAppRecover(&app, fmt.Sprintf("%s/%s.app.tar.gz", tmpPath, website.Alias), true, ""); err != nil { global.LOG.Errorf("handle recover from app.tar.gz failed, err: %v", err) return err } @@ -155,7 +155,7 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback return err } if runtime.Type == constant.RuntimeNode { - if err := handleRuntimeRecover(runtime, fmt.Sprintf("%s/%s.runtime.tar.gz", tmpPath, website.Alias), true); err != nil { + if err := handleRuntimeRecover(runtime, fmt.Sprintf("%s/%s.runtime.tar.gz", tmpPath, website.Alias), true, ""); err != nil { return err } global.LOG.Info("put runtime.tar.gz into tmp dir successful") @@ -163,7 +163,7 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback } siteDir := fmt.Sprintf("%s/openresty/%s/www/sites", constant.AppInstallDir, nginxInfo.Name) - if err := handleUnTar(fmt.Sprintf("%s/%s.web.tar.gz", tmpPath, website.Alias), siteDir); err != nil { + if err := handleUnTar(fmt.Sprintf("%s/%s.web.tar.gz", tmpPath, website.Alias), siteDir, ""); err != nil { global.LOG.Errorf("handle recover from web.tar.gz failed, err: %v", err) return err } @@ -182,7 +182,7 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback return nil } -func handleWebsiteBackup(website *model.Website, backupDir, fileName string, excludes string) error { +func handleWebsiteBackup(website *model.Website, backupDir, fileName string, excludes string, secret string) error { fileOp := files.NewFileOp() tmpDir := fmt.Sprintf("%s/%s", backupDir, strings.ReplaceAll(fileName, ".tar.gz", "")) if !fileOp.Stat(tmpDir) { @@ -216,7 +216,7 @@ func handleWebsiteBackup(website *model.Website, backupDir, fileName string, exc if err != nil { return err } - if err := handleAppBackup(&app, tmpDir, fmt.Sprintf("%s.app.tar.gz", website.Alias), excludes); err != nil { + if err := handleAppBackup(&app, tmpDir, fmt.Sprintf("%s.app.tar.gz", website.Alias), excludes, ""); err != nil { return err } global.LOG.Info("put app.tar.gz into tmp dir successful") @@ -226,7 +226,7 @@ func handleWebsiteBackup(website *model.Website, backupDir, fileName string, exc return err } if runtime.Type == constant.RuntimeNode { - if err := handleRuntimeBackup(runtime, tmpDir, fmt.Sprintf("%s.runtime.tar.gz", website.Alias), excludes); err != nil { + if err := handleRuntimeBackup(runtime, tmpDir, fmt.Sprintf("%s.runtime.tar.gz", website.Alias), excludes, ""); err != nil { return err } global.LOG.Info("put runtime.tar.gz into tmp dir successful") @@ -234,11 +234,11 @@ func handleWebsiteBackup(website *model.Website, backupDir, fileName string, exc } websiteDir := fmt.Sprintf("%s/openresty/%s/www/sites/%s", constant.AppInstallDir, nginxInfo.Name, website.Alias) - if err := handleTar(websiteDir, tmpDir, fmt.Sprintf("%s.web.tar.gz", website.Alias), excludes); err != nil { + if err := handleTar(websiteDir, tmpDir, fmt.Sprintf("%s.web.tar.gz", website.Alias), excludes, ""); err != nil { return err } global.LOG.Info("put web.tar.gz into tmp dir successful, now start to tar tmp dir") - if err := handleTar(tmpDir, backupDir, fileName, ""); err != nil { + if err := handleTar(tmpDir, backupDir, fileName, "", secret); err != nil { return err } diff --git a/backend/app/service/cornjob.go b/backend/app/service/cornjob.go index 6ab42d8bab65..fd27fcc538fb 100644 --- a/backend/app/service/cornjob.go +++ b/backend/app/service/cornjob.go @@ -173,6 +173,7 @@ func (u *CronjobService) Create(cronjobDto dto.CronjobCreate) error { if cronjob.ID != 0 { return constant.ErrRecordExist } + cronjob.Secret = cronjobDto.Secret if err := copier.Copy(&cronjob, &cronjobDto); err != nil { return errors.WithMessage(constant.ErrStructTransform, err.Error()) } @@ -279,6 +280,7 @@ func (u *CronjobService) Update(id uint, req dto.CronjobUpdate) error { upMap["backup_accounts"] = req.BackupAccounts upMap["default_download"] = req.DefaultDownload upMap["retain_copies"] = req.RetainCopies + upMap["secret"] = req.Secret return cronjobRepo.Update(id, upMap) } diff --git a/backend/app/service/cronjob_backup.go b/backend/app/service/cronjob_backup.go index 08a0959ddd70..688a7d3e5347 100644 --- a/backend/app/service/cronjob_backup.go +++ b/backend/app/service/cronjob_backup.go @@ -41,7 +41,7 @@ func (u *CronjobService) handleApp(cronjob model.Cronjob, startTime time.Time) e record.Source, record.BackupType = loadRecordPath(cronjob, accountMap) backupDir := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("app/%s/%s", app.App.Key, app.Name)) record.FileName = fmt.Sprintf("app_%s_%s.tar.gz", app.Name, startTime.Format("20060102150405")+common.RandStrAndNum(5)) - if err := handleAppBackup(&app, backupDir, record.FileName, cronjob.ExclusionRules); err != nil { + if err := handleAppBackup(&app, backupDir, record.FileName, cronjob.ExclusionRules, cronjob.Secret); err != nil { return err } downloadPath, err := u.uploadCronjobBackFile(cronjob, accountMap, path.Join(backupDir, record.FileName)) @@ -74,7 +74,7 @@ func (u *CronjobService) handleWebsite(cronjob model.Cronjob, startTime time.Tim record.Source, record.BackupType = loadRecordPath(cronjob, accountMap) backupDir := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("website/%s", web.PrimaryDomain)) record.FileName = fmt.Sprintf("website_%s_%s.tar.gz", web.PrimaryDomain, startTime.Format("20060102150405")+common.RandStrAndNum(5)) - if err := handleWebsiteBackup(&web, backupDir, record.FileName, cronjob.ExclusionRules); err != nil { + if err := handleWebsiteBackup(&web, backupDir, record.FileName, cronjob.ExclusionRules, cronjob.Secret); err != nil { return err } downloadPath, err := u.uploadCronjobBackFile(cronjob, accountMap, path.Join(backupDir, record.FileName)) @@ -138,7 +138,7 @@ func (u *CronjobService) handleDirectory(cronjob model.Cronjob, startTime time.T } fileName := fmt.Sprintf("directory%s_%s.tar.gz", strings.ReplaceAll(cronjob.SourceDir, "/", "_"), startTime.Format("20060102150405")+common.RandStrAndNum(5)) backupDir := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("%s/%s", cronjob.Type, cronjob.Name)) - if err := handleTar(cronjob.SourceDir, backupDir, fileName, cronjob.ExclusionRules); err != nil { + if err := handleTar(cronjob.SourceDir, backupDir, fileName, cronjob.ExclusionRules, cronjob.Secret); err != nil { return err } var record model.BackupRecord @@ -169,7 +169,7 @@ func (u *CronjobService) handleSystemLog(cronjob model.Cronjob, startTime time.T nameItem := startTime.Format("20060102150405") + common.RandStrAndNum(5) fileName := fmt.Sprintf("system_log_%s.tar.gz", nameItem) backupDir := path.Join(global.CONF.System.TmpDir, "log", nameItem) - if err := handleBackupLogs(backupDir, fileName); err != nil { + if err := handleBackupLogs(backupDir, fileName, cronjob.Secret); err != nil { return err } var record model.BackupRecord @@ -210,7 +210,7 @@ func (u *CronjobService) handleSnapshot(cronjob model.Cronjob, startTime time.Ti From: record.BackupType, DefaultDownload: cronjob.DefaultDownload, } - name, err := NewISnapshotService().HandleSnapshot(true, logPath, req, startTime.Format("20060102150405")+common.RandStrAndNum(5)) + name, err := NewISnapshotService().HandleSnapshot(true, logPath, req, startTime.Format("20060102150405")+common.RandStrAndNum(5), cronjob.Secret) if err != nil { return err } @@ -303,7 +303,7 @@ func loadRecordPath(cronjob model.Cronjob, accountMap map[string]cronjobUploadHe return source, backupType } -func handleBackupLogs(targetDir, fileName string) error { +func handleBackupLogs(targetDir, fileName string, secret string) error { websites, err := websiteRepo.List() if err != nil { return err @@ -376,7 +376,7 @@ func handleBackupLogs(targetDir, fileName string) error { } global.LOG.Debug("backup ssh log successful!") - if err := handleTar(targetDir, path.Dir(targetDir), fileName, ""); err != nil { + if err := handleTar(targetDir, path.Dir(targetDir), fileName, "", secret); err != nil { return err } defer func() { diff --git a/backend/app/service/cronjob_helper.go b/backend/app/service/cronjob_helper.go index f2cc619455d4..c4bf920c6351 100644 --- a/backend/app/service/cronjob_helper.go +++ b/backend/app/service/cronjob_helper.go @@ -130,7 +130,7 @@ func (u *CronjobService) handleNtpSync() error { return nil } -func handleTar(sourceDir, targetDir, name, exclusionRules string) error { +func handleTar(sourceDir, targetDir, name, exclusionRules string, secret string) error { if _, err := os.Stat(targetDir); err != nil && os.IsNotExist(err) { if err = os.MkdirAll(targetDir, os.ModePerm); err != nil { return err @@ -158,8 +158,14 @@ func handleTar(sourceDir, targetDir, name, exclusionRules string) error { path = sourceDir } - commands := fmt.Sprintf("tar --warning=no-file-changed --ignore-failed-read -zcf %s %s %s", targetDir+"/"+name, excludeRules, path) - global.LOG.Debug(commands) + commands := "" + if secret != "" { + extraCmd := "| openssl enc -aes-256-cbc -salt -k " + secret + " -out" + commands = fmt.Sprintf("tar --warning=no-file-changed --ignore-failed-read -zcf %s %s %s %s", " -"+excludeRules, path, extraCmd, targetDir+"/"+name) + } else { + commands = fmt.Sprintf("tar --warning=no-file-changed --ignore-failed-read -zcf %s %s %s", targetDir+"/"+name, excludeRules, path) + } + global.LOG.Debug(strings.ReplaceAll(commands, secret, "******")) stdout, err := cmd.ExecWithTimeOut(commands, 24*time.Hour) if err != nil { if len(stdout) != 0 { @@ -170,15 +176,20 @@ func handleTar(sourceDir, targetDir, name, exclusionRules string) error { return nil } -func handleUnTar(sourceFile, targetDir string) error { +func handleUnTar(sourceFile, targetDir string, secret string) error { if _, err := os.Stat(targetDir); err != nil && os.IsNotExist(err) { if err = os.MkdirAll(targetDir, os.ModePerm); err != nil { return err } } - - commands := fmt.Sprintf("tar zxvfC %s %s", sourceFile, targetDir) - global.LOG.Debug(commands) + commands := "" + if secret != "" { + extraCmd := "openssl enc -d -aes-256-cbc -k " + secret + " -in " + sourceFile + " | " + commands = fmt.Sprintf("%s tar -zxvf - -C %s", extraCmd, targetDir+" > /dev/null 2>&1") + } else { + commands = fmt.Sprintf("tar -zxvf %s %s", sourceFile+" -C ", targetDir+" > /dev/null 2>&1") + } + global.LOG.Debug(strings.ReplaceAll(commands, secret, "******")) stdout, err := cmd.ExecWithTimeOut(commands, 24*time.Hour) if err != nil { global.LOG.Errorf("do handle untar failed, stdout: %s, err: %v", stdout, err) diff --git a/backend/app/service/file.go b/backend/app/service/file.go index 44a872107c04..e9c67a2e19ca 100644 --- a/backend/app/service/file.go +++ b/backend/app/service/file.go @@ -218,12 +218,12 @@ func (f *FileService) Compress(c request.FileCompress) error { if !c.Replace && fo.Stat(filepath.Join(c.Dst, c.Name)) { return buserr.New(constant.ErrFileIsExit) } - return fo.Compress(c.Files, c.Dst, c.Name, files.CompressType(c.Type)) + return fo.Compress(c.Files, c.Dst, c.Name, files.CompressType(c.Type), c.Secret) } func (f *FileService) DeCompress(c request.FileDeCompress) error { fo := files.NewFileOp() - return fo.Decompress(c.Path, c.Dst, files.CompressType(c.Type)) + return fo.Decompress(c.Path, c.Dst, files.CompressType(c.Type), c.Secret) } func (f *FileService) GetContent(op request.FileContentReq) (response.FileInfo, error) { @@ -325,7 +325,7 @@ func (f *FileService) FileDownload(d request.FileDownload) (string, error) { return "", err } fo := files.NewFileOp() - if err := fo.Compress(d.Paths, tempPath, d.Name, files.CompressType(d.Type)); err != nil { + if err := fo.Compress(d.Paths, tempPath, d.Name, files.CompressType(d.Type), ""); err != nil { return "", err } filePath = filepath.Join(tempPath, d.Name) diff --git a/backend/app/service/snapshot.go b/backend/app/service/snapshot.go index 667920a31a4a..d20083e2449c 100644 --- a/backend/app/service/snapshot.go +++ b/backend/app/service/snapshot.go @@ -39,7 +39,7 @@ type ISnapshotService interface { UpdateDescription(req dto.UpdateDescription) error readFromJson(path string) (SnapshotJson, error) - HandleSnapshot(isCronjob bool, logPath string, req dto.SnapshotCreate, timeNow string) (string, error) + HandleSnapshot(isCronjob bool, logPath string, req dto.SnapshotCreate, timeNow string, secret string) (string, error) } func NewISnapshotService() ISnapshotService { @@ -123,7 +123,7 @@ type SnapshotJson struct { } func (u *SnapshotService) SnapshotCreate(req dto.SnapshotCreate) error { - if _, err := u.HandleSnapshot(false, "", req, time.Now().Format("20060102150405")); err != nil { + if _, err := u.HandleSnapshot(false, "", req, time.Now().Format("20060102150405"), req.Secret); err != nil { return err } return nil @@ -180,7 +180,7 @@ func (u *SnapshotService) readFromJson(path string) (SnapshotJson, error) { return snap, nil } -func (u *SnapshotService) HandleSnapshot(isCronjob bool, logPath string, req dto.SnapshotCreate, timeNow string) (string, error) { +func (u *SnapshotService) HandleSnapshot(isCronjob bool, logPath string, req dto.SnapshotCreate, timeNow string, secret string) (string, error) { localDir, err := loadLocalDir() if err != nil { return "", err @@ -274,7 +274,7 @@ func (u *SnapshotService) HandleSnapshot(isCronjob bool, logPath string, req dto return } if snapStatus.Compress != constant.StatusDone { - snapCompress(itemHelper, rootDir) + snapCompress(itemHelper, rootDir, secret) } if snapStatus.Compress != constant.StatusDone { _ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusFailed}) @@ -305,7 +305,7 @@ func (u *SnapshotService) HandleSnapshot(isCronjob bool, logPath string, req dto return snap.Name, fmt.Errorf("snapshot %s 1panel data failed", snap.Name) } loadLogByStatus(snapStatus, logPath) - snapCompress(itemHelper, rootDir) + snapCompress(itemHelper, rootDir, secret) if snapStatus.Compress != constant.StatusDone { _ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusFailed}) loadLogByStatus(snapStatus, logPath) @@ -383,15 +383,20 @@ func updateRecoverStatus(id uint, isRecover bool, interruptStep, status, message } } -func (u *SnapshotService) handleUnTar(sourceDir, targetDir string) error { +func (u *SnapshotService) handleUnTar(sourceDir, targetDir string, secret string) error { if _, err := os.Stat(targetDir); err != nil && os.IsNotExist(err) { if err = os.MkdirAll(targetDir, os.ModePerm); err != nil { return err } } - - commands := fmt.Sprintf("tar -zxf %s -C %s .", sourceDir, targetDir) - global.LOG.Debug(commands) + commands := "" + if secret != "" { + extraCmd := "openssl enc -d -aes-256-cbc -k " + secret + " -in " + sourceDir + " | " + commands = fmt.Sprintf("%s tar -zxvf - -C %s", extraCmd, targetDir+" > /dev/null 2>&1") + } else { + commands = fmt.Sprintf("tar -zxvf %s %s", sourceDir+" -C ", targetDir+" > /dev/null 2>&1") + } + global.LOG.Debug(strings.ReplaceAll(commands, secret, "******")) stdout, err := cmd.ExecWithTimeOut(commands, 30*time.Minute) if err != nil { if len(stdout) != 0 { diff --git a/backend/app/service/snapshot_create.go b/backend/app/service/snapshot_create.go index 5ea82adb3dc7..3926f5bc5fde 100644 --- a/backend/app/service/snapshot_create.go +++ b/backend/app/service/snapshot_create.go @@ -131,7 +131,7 @@ func snapBackup(snap snapHelper, localDir, targetDir string) { defer snap.Wg.Done() _ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"backup_data": constant.Running}) status := constant.StatusDone - if err := handleSnapTar(localDir, targetDir, "1panel_backup.tar.gz", "./system;./system_snapshot;"); err != nil { + if err := handleSnapTar(localDir, targetDir, "1panel_backup.tar.gz", "./system;./system_snapshot;", ""); err != nil { status = err.Error() } snap.Status.BackupData = status @@ -158,7 +158,7 @@ func snapPanelData(snap snapHelper, localDir, targetDir string) { sysIP, _ := settingRepo.Get(settingRepo.WithByKey("SystemIP")) _ = settingRepo.Update("SystemIP", "") checkPointOfWal() - if err := handleSnapTar(dataDir, targetDir, "1panel_data.tar.gz", exclusionRules); err != nil { + if err := handleSnapTar(dataDir, targetDir, "1panel_data.tar.gz", exclusionRules, ""); err != nil { status = err.Error() } _ = snapshotRepo.Update(snap.SnapID, map[string]interface{}{"status": constant.StatusWaiting}) @@ -168,11 +168,11 @@ func snapPanelData(snap snapHelper, localDir, targetDir string) { _ = settingRepo.Update("SystemIP", sysIP.Value) } -func snapCompress(snap snapHelper, rootDir string) { +func snapCompress(snap snapHelper, rootDir string, secret string) { _ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"compress": constant.StatusRunning}) tmpDir := path.Join(global.CONF.System.TmpDir, "system") fileName := fmt.Sprintf("%s.tar.gz", path.Base(rootDir)) - if err := snap.FileOp.Compress([]string{rootDir}, tmpDir, fileName, files.TarGz); err != nil { + if err := handleSnapTar(rootDir, tmpDir, fileName, "", secret); err != nil { snap.Status.Compress = err.Error() _ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"compress": err.Error()}) return @@ -221,7 +221,7 @@ func snapUpload(snap snapHelper, accounts string, file string) { _ = os.Remove(source) } -func handleSnapTar(sourceDir, targetDir, name, exclusionRules string) error { +func handleSnapTar(sourceDir, targetDir, name, exclusionRules string, secret string) error { if _, err := os.Stat(targetDir); err != nil && os.IsNotExist(err) { if err = os.MkdirAll(targetDir, os.ModePerm); err != nil { return err @@ -243,9 +243,25 @@ func handleSnapTar(sourceDir, targetDir, name, exclusionRules string) error { exStr += exclude exMap[exclude] = struct{}{} } - - commands := fmt.Sprintf("tar --warning=no-file-changed --ignore-failed-read -zcf %s %s -C %s .", targetDir+"/"+name, exStr, sourceDir) - global.LOG.Debug(commands) + path := "" + if strings.Contains(sourceDir, "/") { + itemDir := strings.ReplaceAll(sourceDir[strings.LastIndex(sourceDir, "/"):], "/", "") + aheadDir := sourceDir[:strings.LastIndex(sourceDir, "/")] + if len(aheadDir) == 0 { + aheadDir = "/" + } + path += fmt.Sprintf("-C %s %s", aheadDir, itemDir) + } else { + path = sourceDir + } + commands := "" + if secret != "" { + extraCmd := "| openssl enc -aes-256-cbc -salt -k " + secret + " -out" + commands = fmt.Sprintf("tar --warning=no-file-changed --ignore-failed-read -zcf %s %s %s %s", " -"+exStr, path, extraCmd, targetDir+"/"+name) + } else { + commands = fmt.Sprintf("tar --warning=no-file-changed --ignore-failed-read -zcf %s %s -C %s .", targetDir+"/"+name, exStr, sourceDir) + } + global.LOG.Debug(strings.ReplaceAll(commands, secret, "******")) stdout, err := cmd.ExecWithTimeOut(commands, 30*time.Minute) if err != nil { if len(stdout) != 0 { diff --git a/backend/app/service/snapshot_recover.go b/backend/app/service/snapshot_recover.go index 87f993cf1484..67528bc8190c 100644 --- a/backend/app/service/snapshot_recover.go +++ b/backend/app/service/snapshot_recover.go @@ -30,14 +30,6 @@ func (u *SnapshotService) HandleSnapshotRecover(snap model.Snapshot, isRecover b if _, err := os.Stat(baseDir); err != nil && os.IsNotExist(err) { _ = os.MkdirAll(baseDir, os.ModePerm) } - if req.IsNew || snap.InterruptStep == "Backup" { - if err := backupBeforeRecover(snap); err != nil { - updateRecoverStatus(snap.ID, isRecover, "Backup", constant.StatusFailed, fmt.Sprintf("handle backup before recover failed, err: %v", err)) - return - } - global.LOG.Debug("handle backup before recover successful!") - req.IsNew = true - } if req.IsNew || snap.InterruptStep == "Download" || req.ReDownload { if err := handleDownloadSnapshot(snap, baseDir); err != nil { updateRecoverStatus(snap.ID, isRecover, "Backup", constant.StatusFailed, err.Error()) @@ -47,13 +39,21 @@ func (u *SnapshotService) HandleSnapshotRecover(snap model.Snapshot, isRecover b req.IsNew = true } if req.IsNew || snap.InterruptStep == "Decompress" { - if err := handleUnTar(fmt.Sprintf("%s/%s.tar.gz", baseDir, snap.Name), baseDir); err != nil { + if err := u.handleUnTar(fmt.Sprintf("%s/%s.tar.gz", baseDir, snap.Name), baseDir, req.Secret); err != nil { updateRecoverStatus(snap.ID, isRecover, "Decompress", constant.StatusFailed, fmt.Sprintf("decompress file failed, err: %v", err)) return } global.LOG.Debug("decompress snapshot file successful!", baseDir) req.IsNew = true } + if req.IsNew || snap.InterruptStep == "Backup" { + if err := backupBeforeRecover(snap, ""); err != nil { + updateRecoverStatus(snap.ID, isRecover, "Backup", constant.StatusFailed, fmt.Sprintf("handle backup before recover failed, err: %v", err)) + return + } + global.LOG.Debug("handle backup before recover successful!") + req.IsNew = true + } snapFileDir = fmt.Sprintf("%s/%s", baseDir, snap.Name) } else { snapFileDir = fmt.Sprintf("%s/1panel_original/original_%s", global.CONF.System.BaseDir, snap.Name) @@ -114,7 +114,7 @@ func (u *SnapshotService) HandleSnapshotRecover(snap model.Snapshot, isRecover b } if req.IsNew || snap.InterruptStep == "1PanelBackups" { - if err := u.handleUnTar(path.Join(snapFileDir, "/1panel/1panel_backup.tar.gz"), snapJson.BackupDataDir); err != nil { + if err := u.handleUnTar(path.Join(snapFileDir, "/1panel/1panel_backup.tar.gz"), snapJson.BackupDataDir, ""); err != nil { updateRecoverStatus(snap.ID, isRecover, "1PanelBackups", constant.StatusFailed, err.Error()) return } @@ -124,7 +124,7 @@ func (u *SnapshotService) HandleSnapshotRecover(snap model.Snapshot, isRecover b if req.IsNew || snap.InterruptStep == "1PanelData" { checkPointOfWal() - if err := u.handleUnTar(path.Join(snapFileDir, "/1panel/1panel_data.tar.gz"), path.Join(snapJson.BaseDir, "1panel")); err != nil { + if err := u.handleUnTar(path.Join(snapFileDir, "/1panel/1panel_data.tar.gz"), path.Join(snapJson.BaseDir, "1panel"), ""); err != nil { updateRecoverStatus(snap.ID, isRecover, "1PanelData", constant.StatusFailed, err.Error()) return } @@ -146,7 +146,7 @@ func (u *SnapshotService) HandleSnapshotRecover(snap model.Snapshot, isRecover b _, _ = cmd.Exec("systemctl daemon-reload && systemctl restart 1panel.service") } -func backupBeforeRecover(snap model.Snapshot) error { +func backupBeforeRecover(snap model.Snapshot, secret string) error { baseDir := fmt.Sprintf("%s/1panel_original/original_%s", global.CONF.System.BaseDir, snap.Name) var wg sync.WaitGroup var status model.SnapshotStatus diff --git a/backend/app/service/upgrade.go b/backend/app/service/upgrade.go index e941399a33f5..0644efd35401 100644 --- a/backend/app/service/upgrade.go +++ b/backend/app/service/upgrade.go @@ -117,7 +117,7 @@ func (u *UpgradeService) Upgrade(req dto.Upgrade) error { defer func() { _ = os.Remove(rootDir) }() - if err := handleUnTar(rootDir+"/"+fileName, rootDir); err != nil { + if err := handleUnTar(rootDir+"/"+fileName, rootDir, ""); err != nil { global.LOG.Errorf("decompress file failed, err: %v", err) _ = settingRepo.Update("SystemStatus", "Free") return @@ -175,7 +175,7 @@ func (u *UpgradeService) handleBackup(fileOp files.FileOp, originalDir string) e return err } checkPointOfWal() - if err := handleTar(path.Join(global.CONF.System.BaseDir, "1panel/db"), originalDir, "db.tar.gz", "db/1Panel.db-*"); err != nil { + if err := handleTar(path.Join(global.CONF.System.BaseDir, "1panel/db"), originalDir, "db.tar.gz", "db/1Panel.db-*", ""); err != nil { return err } return nil @@ -191,7 +191,7 @@ func (u *UpgradeService) handleRollback(originalDir string, errStep int) { } } if _, err := os.Stat(path.Join(originalDir, "db.tar.gz")); err == nil { - if err := handleUnTar(path.Join(originalDir, "db.tar.gz"), global.CONF.System.DbPath); err != nil { + if err := handleUnTar(path.Join(originalDir, "db.tar.gz"), global.CONF.System.DbPath, ""); err != nil { global.LOG.Errorf("rollback 1panel db failed, err: %v", err) } } diff --git a/backend/app/service/website_ssl.go b/backend/app/service/website_ssl.go index e8646b3c3b46..43be40b22334 100644 --- a/backend/app/service/website_ssl.go +++ b/backend/app/service/website_ssl.go @@ -550,7 +550,7 @@ func (w WebsiteSSLService) DownloadFile(id uint) (*os.File, error) { return nil, err } fileName := websiteSSL.PrimaryDomain + ".zip" - if err = fileOp.Compress([]string{path.Join(dir, "fullchain.pem"), path.Join(dir, "privkey.pem")}, dir, fileName, files.SdkZip); err != nil { + if err = fileOp.Compress([]string{path.Join(dir, "fullchain.pem"), path.Join(dir, "privkey.pem")}, dir, fileName, files.SdkZip, ""); err != nil { return nil, err } return os.Open(path.Join(dir, fileName)) diff --git a/backend/init/migration/migrate.go b/backend/init/migration/migrate.go index a84d17f24f0a..407634f13512 100644 --- a/backend/init/migration/migrate.go +++ b/backend/init/migration/migrate.go @@ -88,6 +88,7 @@ func Init() { migrations.AddMonitorMenu, migrations.AddFtp, migrations.AddProxy, + migrations.AddCronJobColumn, }) if err := m.Migrate(); err != nil { global.LOG.Error(err) diff --git a/backend/init/migration/migrations/v_1_10.go b/backend/init/migration/migrations/v_1_10.go index 85c131bf83bc..0d32daea03cb 100644 --- a/backend/init/migration/migrations/v_1_10.go +++ b/backend/init/migration/migrations/v_1_10.go @@ -238,3 +238,13 @@ var AddProxy = &gormigrate.Migration{ return nil }, } + +var AddCronJobColumn = &gormigrate.Migration{ + ID: "20240524-add-cronjob-command", + Migrate: func(tx *gorm.DB) error { + if err := tx.AutoMigrate(&model.Cronjob{}); err != nil { + return err + } + return nil + }, +} diff --git a/backend/utils/files/archiver.go b/backend/utils/files/archiver.go index 9affc8836671..374b500e7d4d 100644 --- a/backend/utils/files/archiver.go +++ b/backend/utils/files/archiver.go @@ -7,8 +7,8 @@ import ( ) type ShellArchiver interface { - Extract(filePath, dstDir string) error - Compress(sourcePaths []string, dstFile string) error + Extract(filePath, dstDir string, secret string) error + Compress(sourcePaths []string, dstFile string, secret string) error } func NewShellArchiver(compressType CompressType) (ShellArchiver, error) { @@ -18,6 +18,8 @@ func NewShellArchiver(compressType CompressType) (ShellArchiver, error) { return nil, err } return NewTarArchiver(compressType), nil + case TarGz: + return NewTarGzArchiver(), nil case Zip: if err := checkCmdAvailability("zip"); err != nil { return nil, err diff --git a/backend/utils/files/file_op.go b/backend/utils/files/file_op.go index 9b92ef49c949..c97ca0690186 100644 --- a/backend/utils/files/file_op.go +++ b/backend/utils/files/file_op.go @@ -476,7 +476,7 @@ func getFormat(cType CompressType) archiver.CompressedArchive { return format } -func (f FileOp) Compress(srcRiles []string, dst string, name string, cType CompressType) error { +func (f FileOp) Compress(srcRiles []string, dst string, name string, cType CompressType, secret string) error { format := getFormat(cType) fileMaps := make(map[string]string, len(srcRiles)) @@ -505,7 +505,13 @@ func (f FileOp) Compress(srcRiles []string, dst string, name string, cType Compr return nil } _ = f.DeleteFile(dstFile) - return NewZipArchiver().Compress(srcRiles, dstFile) + return NewZipArchiver().Compress(srcRiles, dstFile, "") + case TarGz: + err = NewTarGzArchiver().Compress(srcRiles, dstFile, secret) + if err != nil { + _ = f.DeleteFile(dstFile) + return err + } default: err = format.Archive(context.Background(), out, files) if err != nil { @@ -583,14 +589,22 @@ func (f FileOp) decompressWithSDK(srcFile string, dst string, cType CompressType return format.Extract(context.Background(), input, nil, handler) } -func (f FileOp) Decompress(srcFile string, dst string, cType CompressType) error { +func (f FileOp) Decompress(srcFile string, dst string, cType CompressType, secret string) error { if err := f.decompressWithSDK(srcFile, dst, cType); err != nil { - if cType == Tar || cType == Zip { - shellArchiver, err := NewShellArchiver(cType) - if err != nil { - return err + if cType == Tar || cType == Zip || cType == TarGz { + if secret != "" { + shellArchiver, err := NewShellArchiver(TarGz) + if err != nil { + return err + } + return shellArchiver.Extract(srcFile, dst, secret) + } else { + shellArchiver, err := NewShellArchiver(cType) + if err != nil { + return err + } + return shellArchiver.Extract(srcFile, dst, secret) } - return shellArchiver.Extract(srcFile, dst) } return err } diff --git a/backend/utils/files/tar.go b/backend/utils/files/tar.go index d74c6da2fac0..6aaa1f0350a9 100644 --- a/backend/utils/files/tar.go +++ b/backend/utils/files/tar.go @@ -17,11 +17,11 @@ func NewTarArchiver(compressType CompressType) ShellArchiver { } } -func (t TarArchiver) Extract(FilePath string, dstDir string) error { +func (t TarArchiver) Extract(FilePath string, dstDir string, secret string) error { return cmd.ExecCmd(fmt.Sprintf("%s %s %s -C %s", t.Cmd, t.getOptionStr("extract"), FilePath, dstDir)) } -func (t TarArchiver) Compress(sourcePaths []string, dstFile string) error { +func (t TarArchiver) Compress(sourcePaths []string, dstFile string, secret string) error { return nil } diff --git a/backend/utils/files/tar_gz.go b/backend/utils/files/tar_gz.go new file mode 100644 index 000000000000..6316898fd5c1 --- /dev/null +++ b/backend/utils/files/tar_gz.go @@ -0,0 +1,58 @@ +package files + +import ( + "fmt" + "github.com/1Panel-dev/1Panel/backend/global" + "github.com/1Panel-dev/1Panel/backend/utils/cmd" + "path/filepath" + "strings" +) + +type TarGzArchiver struct { +} + +func NewTarGzArchiver() ShellArchiver { + return &TarGzArchiver{} +} + +func (t TarGzArchiver) Extract(filePath, dstDir string, secret string) error { + var err error + commands := "" + if secret != "" { + extraCmd := "openssl enc -d -aes-256-cbc -k " + secret + " -in " + filePath + " | " + commands = fmt.Sprintf("%s tar -zxvf - -C %s", extraCmd, dstDir+" > /dev/null 2>&1") + } else { + commands = fmt.Sprintf("tar -zxvf %s %s", filePath+" -C ", dstDir+" > /dev/null 2>&1") + } + global.LOG.Debug(strings.ReplaceAll(commands, secret, "******")) + if err = cmd.ExecCmd(commands); err != nil { + return err + } + return nil +} + +func (t TarGzArchiver) Compress(sourcePaths []string, dstFile string, secret string) error { + var err error + path := "" + itemDir := "" + for _, item := range sourcePaths { + itemDir += filepath.Base(item) + " " + } + aheadDir := dstFile[:strings.LastIndex(dstFile, "/")] + if len(aheadDir) == 0 { + aheadDir = "/" + } + path += fmt.Sprintf("- -C %s %s", aheadDir, itemDir) + commands := "" + if secret != "" { + extraCmd := "| openssl enc -aes-256-cbc -salt -k " + secret + " -out" + commands = fmt.Sprintf("tar -zcf %s %s %s", path, extraCmd, dstFile) + } else { + commands = fmt.Sprintf("tar -zcf %s %s", dstFile, path) + } + global.LOG.Debug(strings.ReplaceAll(commands, secret, "******")) + if err = cmd.ExecCmd(commands); err != nil { + return err + } + return nil +} diff --git a/backend/utils/files/zip.go b/backend/utils/files/zip.go index 39f6f4ec6e37..0acd7b9bc528 100644 --- a/backend/utils/files/zip.go +++ b/backend/utils/files/zip.go @@ -17,14 +17,14 @@ func NewZipArchiver() ShellArchiver { return &ZipArchiver{} } -func (z ZipArchiver) Extract(filePath, dstDir string) error { +func (z ZipArchiver) Extract(filePath, dstDir string, secret string) error { if err := checkCmdAvailability("unzip"); err != nil { return err } return cmd.ExecCmd(fmt.Sprintf("unzip -qo %s -d %s", filePath, dstDir)) } -func (z ZipArchiver) Compress(sourcePaths []string, dstFile string) error { +func (z ZipArchiver) Compress(sourcePaths []string, dstFile string, _ string) error { var err error tmpFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("%s%s.zip", common.RandStr(50), time.Now().Format("20060102150405"))) op := NewFileOp() diff --git a/frontend/src/api/interface/backup.ts b/frontend/src/api/interface/backup.ts index 80e7b538cc5d..d87675aee5d1 100644 --- a/frontend/src/api/interface/backup.ts +++ b/frontend/src/api/interface/backup.ts @@ -57,6 +57,7 @@ export namespace Backup { type: string; name: string; detailName: string; + secret: string; } export interface Recover { source: string; @@ -64,5 +65,6 @@ export namespace Backup { name: string; detailName: string; file: string; + secret: string; } } diff --git a/frontend/src/api/interface/cronjob.ts b/frontend/src/api/interface/cronjob.ts index 8b35dfa0bfb6..ae2c033d5c86 100644 --- a/frontend/src/api/interface/cronjob.ts +++ b/frontend/src/api/interface/cronjob.ts @@ -26,6 +26,7 @@ export namespace Cronjob { backupAccountList: Array; retainCopies: number; status: string; + secret: string; } export interface CronjobCreate { name: string; @@ -44,6 +45,7 @@ export namespace Cronjob { backupAccounts: string; defaultDownload: string; retainCopies: number; + secret: string; } export interface SpecObj { specType: string; @@ -68,6 +70,7 @@ export namespace Cronjob { backupAccounts: string; defaultDownload: string; retainCopies: number; + secret: string; } export interface CronjobDelete { ids: Array; diff --git a/frontend/src/api/interface/file.ts b/frontend/src/api/interface/file.ts index fd42f64af681..7110b1692bef 100644 --- a/frontend/src/api/interface/file.ts +++ b/frontend/src/api/interface/file.ts @@ -80,12 +80,14 @@ export namespace File { dst: string; name: string; replace: boolean; + secret: string; } export interface FileDeCompress { path: string; dst: string; type: string; + secret: string; } export interface FileEdit { diff --git a/frontend/src/api/interface/setting.ts b/frontend/src/api/interface/setting.ts index 7dc0d3d4b026..87cc80a776a8 100644 --- a/frontend/src/api/interface/setting.ts +++ b/frontend/src/api/interface/setting.ts @@ -113,6 +113,7 @@ export namespace Setting { fromAccounts: Array; defaultDownload: string; description: string; + secret: string; } export interface SnapshotImport { from: string; @@ -123,6 +124,7 @@ export namespace Setting { id: number; isNew: boolean; reDownload: boolean; + secret: string; } export interface SnapshotInfo { id: number; @@ -141,6 +143,7 @@ export namespace Setting { rollbackStatus: string; rollbackMessage: string; lastRollbackedAt: string; + secret: string; } export interface SnapshotStatus { panel: string; diff --git a/frontend/src/components/backup/index.vue b/frontend/src/components/backup/index.vue index 41b2d9b6f73e..18d9ea882b6e 100644 --- a/frontend/src/components/backup/index.vue +++ b/frontend/src/components/backup/index.vue @@ -43,6 +43,14 @@ {{ $t('commons.button.delete') }} + + + @@ -105,6 +113,7 @@ const name = ref(); const detailName = ref(); const backupPath = ref(); const status = ref(); +const secret = ref(); interface DialogProps { type: string; @@ -180,6 +189,7 @@ const onBackup = async () => { type: type.value, name: name.value, detailName: detailName.value, + secret: secret.value, }; loading.value = true; await handleBackup(params) @@ -209,6 +219,7 @@ const onRecover = async (row: Backup.RecordInfo) => { name: name.value, detailName: detailName.value, file: row.fileDir + '/' + row.fileName, + secret: secret.value, }; loading.value = true; await handleRecover(params) diff --git a/frontend/src/components/upload/index.vue b/frontend/src/components/upload/index.vue index c5dd484b0799..5f835450643b 100644 --- a/frontend/src/components/upload/index.vue +++ b/frontend/src/components/upload/index.vue @@ -68,6 +68,14 @@ > {{ $t('commons.button.delete') }} + + + @@ -129,6 +137,7 @@ const type = ref(); const name = ref(); const detailName = ref(); const remark = ref(); +const secret = ref(); interface DialogProps { type: string; name: string; @@ -191,6 +200,7 @@ const onRecover = async (row: File.File) => { name: name.value, detailName: detailName.value, file: baseDir.value + row.name, + secret: secret.value, }; loading.value = true; await handleRecoverByUpload(params) diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index d92a170a4e86..acd40b01284e 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -1535,6 +1535,7 @@ const message = { ifShow: 'Whether to Show', menu: 'Menu', confirmMessage: 'The page will be refreshed to update the advanced menu list. Continue?', + compressPassword: 'Compression Password', }, license: { community: 'Community Edition: ', diff --git a/frontend/src/lang/modules/tw.ts b/frontend/src/lang/modules/tw.ts index 75b67587d952..ea9a42817885 100644 --- a/frontend/src/lang/modules/tw.ts +++ b/frontend/src/lang/modules/tw.ts @@ -1429,6 +1429,7 @@ const message = { ifShow: '是否顯示', menu: '選單', confirmMessage: '即將刷新頁面更新高級功能菜單列表,是否繼續?', + compressPassword: '壓縮密碼', }, license: { community: '社區版:', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 6b775477862c..6cd33f8f1ac7 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -1430,6 +1430,7 @@ const message = { ifShow: '是否显示', menu: '菜单', confirmMessage: '即将刷新页面更新高级功能菜单列表,是否继续?', + compressPassword: '压缩密码', }, license: { community: '社区版:', diff --git a/frontend/src/views/cronjob/operate/index.vue b/frontend/src/views/cronjob/operate/index.vue index 9e517e7413aa..82c0964b7132 100644 --- a/frontend/src/views/cronjob/operate/index.vue +++ b/frontend/src/views/cronjob/operate/index.vue @@ -300,6 +300,13 @@ + + +
diff --git a/frontend/src/views/host/file-management/compress/index.vue b/frontend/src/views/host/file-management/compress/index.vue index def0d3e99d96..d8466e09171f 100644 --- a/frontend/src/views/host/file-management/compress/index.vue +++ b/frontend/src/views/host/file-management/compress/index.vue @@ -37,6 +37,9 @@ + + + @@ -79,7 +82,7 @@ const rules = reactive({ const fileForm = ref(); const loading = ref(false); -const form = ref({ files: [], type: 'zip', dst: '', name: '', replace: false }); +const form = ref({ files: [], type: 'zip', dst: '', name: '', replace: false, secret: '' }); const options = ref([]); const open = ref(false); const title = ref(''); diff --git a/frontend/src/views/host/file-management/decompress/index.vue b/frontend/src/views/host/file-management/decompress/index.vue index fc970fce0901..23ae24ab29a5 100644 --- a/frontend/src/views/host/file-management/decompress/index.vue +++ b/frontend/src/views/host/file-management/decompress/index.vue @@ -30,6 +30,9 @@ + + + diff --git a/frontend/src/views/setting/snapshot/index.vue b/frontend/src/views/setting/snapshot/index.vue index 0395b21aeca3..f511e21ed479 100644 --- a/frontend/src/views/setting/snapshot/index.vue +++ b/frontend/src/views/setting/snapshot/index.vue @@ -146,6 +146,9 @@ /> + + + @@ -231,6 +234,7 @@ let snapInfo = reactive({ defaultDownload: '', fromAccounts: [], description: '', + secret: '', }); const cleanData = ref(); diff --git a/frontend/src/views/setting/snapshot/status/index.vue b/frontend/src/views/setting/snapshot/status/index.vue index 71f5211e9ff8..82eba64f140a 100644 --- a/frontend/src/views/setting/snapshot/status/index.vue +++ b/frontend/src/views/setting/snapshot/status/index.vue @@ -10,6 +10,9 @@ {{ $t('setting.recover') }} + + +
@@ -197,7 +200,12 @@ const handleClose = () => { const doRecover = async (isNew: boolean) => { loading.value = true; - await snapshotRecover({ id: snapInfo.value.id, isNew: isNew, reDownload: reDownload.value }) + await snapshotRecover({ + id: snapInfo.value.id, + isNew: isNew, + reDownload: reDownload.value, + secret: snapInfo.value.secret, + }) .then(() => { emit('search'); loading.value = false;